Skip to content

Commit 37fe99c

Browse files
committedNov 20, 2024
feature #6546 Make constructors expect Interfaces for final classes instead of fina… (bytes-commerce)
This PR was squashed before being merged into the 4.x branch. Discussion ---------- Make constructors expect Interfaces for final classes instead of fina… …l classes themselves. This solves an issue where we cannot Mock (or rebuild) controller classes for PHPUnit tests. Also, if a class is final, it should have an Interface. In an ideal world, all classes are final that must be final with exceptions to abstracts. All finals should at least have one Interface. Naturally, there should be 0 instance of a class that is neither final or abstract, and the only exception to Interfaces with Final Classes are DTOs (= Getter-Only Classes with absolutely 0 logic and a constructor receiving values). This PR fixes some developer-experience issues and also makes future refactoring much easier. Commits ------- 18c4783 Make constructors expect Interfaces for final classes instead of fina…
2 parents f5c8249 + 18c4783 commit 37fe99c

24 files changed

+365
-232
lines changed
 

‎src/ArgumentResolver/AdminContextResolver.php

+3-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
66
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider;
7+
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProviderInterface;
78
use Symfony\Component\HttpFoundation\Request;
89
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
910
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
@@ -17,7 +18,7 @@ final class AdminContextResolver implements ValueResolverInterface
1718
{
1819
private AdminContextProvider $adminContextProvider;
1920

20-
public function __construct(AdminContextProvider $adminContextProvider)
21+
public function __construct(AdminContextProviderInterface $adminContextProvider)
2122
{
2223
$this->adminContextProvider = $adminContextProvider;
2324
}
@@ -36,7 +37,7 @@ final class AdminContextResolver implements ArgumentValueResolverInterface
3637
{
3738
private AdminContextProvider $adminContextProvider;
3839

39-
public function __construct(AdminContextProvider $adminContextProvider)
40+
public function __construct(AdminContextProviderInterface $adminContextProvider)
4041
{
4142
$this->adminContextProvider = $adminContextProvider;
4243
}

‎src/ArgumentResolver/BatchActionDtoResolver.php

+6-8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
88
use EasyCorp\Bundle\EasyAdminBundle\Dto\BatchActionDto;
99
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider;
10+
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProviderInterface;
1011
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGeneratorInterface;
1112
use Symfony\Component\HttpFoundation\Request;
1213
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
@@ -19,13 +20,10 @@
1920
if (interface_exists(ValueResolverInterface::class)) {
2021
final class BatchActionDtoResolver implements ValueResolverInterface
2122
{
22-
private AdminContextProvider $adminContextProvider;
23-
private AdminUrlGeneratorInterface $adminUrlGenerator;
24-
25-
public function __construct(AdminContextProvider $adminContextProvider, AdminUrlGeneratorInterface $adminUrlGenerator)
26-
{
27-
$this->adminContextProvider = $adminContextProvider;
28-
$this->adminUrlGenerator = $adminUrlGenerator;
23+
public function __construct(
24+
private readonly AdminContextProviderInterface $adminContextProvider,
25+
private readonly AdminUrlGeneratorInterface $adminUrlGenerator,
26+
) {
2927
}
3028

3129
public function resolve(Request $request, ArgumentMetadata $argument): iterable
@@ -75,7 +73,7 @@ final class BatchActionDtoResolver implements ArgumentValueResolverInterface
7573
private AdminContextProvider $adminContextProvider;
7674
private AdminUrlGeneratorInterface $adminUrlGenerator;
7775

78-
public function __construct(AdminContextProvider $adminContextProvider, AdminUrlGeneratorInterface $adminUrlGenerator)
76+
public function __construct(AdminContextProviderInterface $adminContextProvider, AdminUrlGeneratorInterface $adminUrlGenerator)
7977
{
8078
$this->adminContextProvider = $adminContextProvider;
8179
$this->adminUrlGenerator = $adminUrlGenerator;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace EasyCorp\Bundle\EasyAdminBundle\Contracts\Field;
6+
7+
use EasyCorp\Bundle\EasyAdminBundle\Config\Asset;
8+
use Symfony\Contracts\Translation\TranslatableInterface;
9+
10+
interface FieldTraitAwareInterface extends FieldInterface
11+
{
12+
public function setFieldFqcn(string $fieldFqcn): self;
13+
14+
public function setProperty(string $propertyName): self;
15+
16+
public function setLabel(TranslatableInterface|string|false|null $label): self;
17+
18+
public function setValue($value): self;
19+
20+
public function setFormattedValue($value): self;
21+
22+
public function formatValue(?callable $callable): self;
23+
24+
public function setVirtual(bool $isVirtual): self;
25+
26+
public function setDisabled(bool $disabled = true): self;
27+
28+
public function setRequired(bool $isRequired): self;
29+
30+
public function setEmptyData($emptyData = null): self;
31+
32+
public function setFormType(string $formTypeFqcn): self;
33+
34+
public function setFormTypeOptions(array $options): self;
35+
36+
/**
37+
* @param string $optionName You can use "dot" notation to set nested options (e.g. 'attr.class')
38+
*/
39+
public function setFormTypeOption(
40+
string $optionName,
41+
$optionValue,
42+
): self;
43+
44+
/**
45+
* @param string $optionName You can use "dot" notation to set nested options (e.g. 'attr.class')
46+
*/
47+
public function setFormTypeOptionIfNotSet(
48+
string $optionName,
49+
$optionValue,
50+
): self;
51+
52+
public function setSortable(bool $isSortable): self;
53+
54+
public function setPermission(string $permission): self;
55+
56+
/**
57+
* @param string $textAlign It can be 'left', 'center' or 'right'
58+
*/
59+
public function setTextAlign(string $textAlign): self;
60+
61+
public function setHelp(TranslatableInterface|string $help): self;
62+
63+
public function addCssClass(string $cssClass): self;
64+
65+
public function setCssClass(string $cssClass): self;
66+
67+
public function setTranslationParameters(array $parameters): self;
68+
69+
public function setTemplateName(string $name): self;
70+
71+
public function setTemplatePath(string $path): self;
72+
73+
public function addFormTheme(string ...$formThemePaths): self;
74+
75+
public function addWebpackEncoreEntries(Asset|string ...$entryNamesOrAssets,
76+
): self;
77+
78+
public function addCssFiles(Asset|string ...$pathsOrAssets): self;
79+
80+
public function addJsFiles(Asset|string ...$pathsOrAssets): self;
81+
82+
public function addHtmlContentsToHead(string ...$contents): self;
83+
84+
public function addHtmlContentsToBody(string ...$contents): self;
85+
86+
public function setCustomOption(
87+
string $optionName,
88+
$optionValue,
89+
): self;
90+
91+
public function setCustomOptions(array $options): self;
92+
93+
public function hideOnDetail(): self;
94+
95+
public function hideOnForm(): self;
96+
97+
public function hideWhenCreating(): self;
98+
99+
public function hideWhenUpdating(): self;
100+
101+
public function hideOnIndex(): self;
102+
103+
public function onlyOnDetail(): self;
104+
105+
public function onlyOnForms(): self;
106+
107+
public function onlyOnIndex(): self;
108+
109+
public function onlyWhenCreating(): self;
110+
111+
public function onlyWhenUpdating(): self;
112+
113+
/**
114+
* @param int|string $cols An integer with the number of columns that this field takes (e.g. 6),
115+
* or a string with responsive col CSS classes (e.g. 'col-6 col-sm-4 col-lg-3')
116+
*/
117+
public function setColumns(int|string $cols): self;
118+
119+
/**
120+
* Used to define the columns of fields when users don't define the
121+
* columns explicitly using the setColumns() method.
122+
* This should only be used if you create a custom EasyAdmin field,
123+
* not when configuring fields in your backend.
124+
*
125+
* @internal
126+
*/
127+
public function setDefaultColumns(int|string $cols): self;
128+
129+
public function setIcon(?string $iconCssClass, string $invokingMethod = 'FormField::setIcon()'): self;
130+
}

‎src/EventListener/CrudResponseListener.php

+6-9
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace EasyCorp\Bundle\EasyAdminBundle\EventListener;
44

55
use EasyCorp\Bundle\EasyAdminBundle\Config\KeyValueStore;
6-
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider;
6+
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProviderInterface;
77
use Symfony\Component\Form\FormInterface;
88
use Symfony\Component\HttpFoundation\Response;
99
use Symfony\Component\HttpKernel\Event\ViewEvent;
@@ -14,19 +14,16 @@
1414
*/
1515
final class CrudResponseListener
1616
{
17-
private AdminContextProvider $adminContextProvider;
18-
private Environment $twig;
19-
20-
public function __construct(AdminContextProvider $adminContextProvider, Environment $twig)
21-
{
22-
$this->adminContextProvider = $adminContextProvider;
23-
$this->twig = $twig;
17+
public function __construct(
18+
private readonly AdminContextProviderInterface $adminContextProvider,
19+
private Environment $twig,
20+
) {
2421
}
2522

2623
public function onKernelView(ViewEvent $event): void
2724
{
2825
$responseParameters = $event->getControllerResult();
29-
if (null === $responseParameters || !$responseParameters instanceof KeyValueStore) {
26+
if (!$responseParameters instanceof KeyValueStore) {
3027
return;
3128
}
3229

‎src/EventListener/ExceptionListener.php

+7-11
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use EasyCorp\Bundle\EasyAdminBundle\Exception\BaseException;
66
use EasyCorp\Bundle\EasyAdminBundle\Exception\FlattenException;
7-
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider;
7+
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProviderInterface;
88
use Symfony\Component\HttpFoundation\Response;
99
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
1010
use Twig\Environment;
@@ -21,18 +21,14 @@
2121
*/
2222
final class ExceptionListener
2323
{
24-
private bool $kernelDebug;
25-
private AdminContextProvider $adminContextProvider;
26-
private Environment $twig;
27-
28-
public function __construct(bool $kernelDebug, AdminContextProvider $adminContextProvider, Environment $twig)
29-
{
30-
$this->kernelDebug = $kernelDebug;
31-
$this->adminContextProvider = $adminContextProvider;
32-
$this->twig = $twig;
24+
public function __construct(
25+
private readonly bool $kernelDebug,
26+
private readonly AdminContextProviderInterface $adminContextProvider,
27+
private readonly Environment $twig,
28+
) {
3329
}
3430

35-
public function onKernelException(ExceptionEvent $event)
31+
public function onKernelException(ExceptionEvent $event): void
3632
{
3733
$exception = $event->getThrowable();
3834

‎src/Factory/ActionFactory.php

+7-12
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
use EasyCorp\Bundle\EasyAdminBundle\Dto\ActionConfigDto;
1010
use EasyCorp\Bundle\EasyAdminBundle\Dto\ActionDto;
1111
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
12-
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider;
12+
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProviderInterface;
1313
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGeneratorInterface;
1414
use EasyCorp\Bundle\EasyAdminBundle\Security\Permission;
1515
use EasyCorp\Bundle\EasyAdminBundle\Translation\TranslatableMessageBuilder;
@@ -24,17 +24,12 @@
2424
*/
2525
final class ActionFactory
2626
{
27-
private AdminContextProvider $adminContextProvider;
28-
private AuthorizationCheckerInterface $authChecker;
29-
private AdminUrlGeneratorInterface $adminUrlGenerator;
30-
private ?CsrfTokenManagerInterface $csrfTokenManager;
31-
32-
public function __construct(AdminContextProvider $adminContextProvider, AuthorizationCheckerInterface $authChecker, AdminUrlGeneratorInterface $adminUrlGenerator, ?CsrfTokenManagerInterface $csrfTokenManager = null)
33-
{
34-
$this->adminContextProvider = $adminContextProvider;
35-
$this->authChecker = $authChecker;
36-
$this->adminUrlGenerator = $adminUrlGenerator;
37-
$this->csrfTokenManager = $csrfTokenManager;
27+
public function __construct(
28+
private readonly AdminContextProviderInterface $adminContextProvider,
29+
private readonly AuthorizationCheckerInterface $authChecker,
30+
private readonly AdminUrlGeneratorInterface $adminUrlGenerator,
31+
private readonly ?CsrfTokenManagerInterface $csrfTokenManager = null,
32+
) {
3833
}
3934

4035
public function processEntityActions(EntityDto $entityDto, ActionConfigDto $actionsDto): void

‎src/Factory/FieldFactory.php

+6-11
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
2020
use EasyCorp\Bundle\EasyAdminBundle\Field\TimeField;
2121
use EasyCorp\Bundle\EasyAdminBundle\Form\Type\EaFormRowType;
22-
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider;
22+
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProviderInterface;
2323
use EasyCorp\Bundle\EasyAdminBundle\Security\Permission;
2424
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
2525

@@ -55,17 +55,12 @@ final class FieldFactory
5555
Types::TIME_IMMUTABLE => TimeField::class,
5656
];
5757

58-
private AdminContextProvider $adminContextProvider;
59-
private AuthorizationCheckerInterface $authorizationChecker;
60-
private iterable $fieldConfigurators;
61-
private FormLayoutFactory $fieldLayoutFactory;
62-
63-
public function __construct(AdminContextProvider $adminContextProvider, AuthorizationCheckerInterface $authorizationChecker, iterable $fieldConfigurators, FormLayoutFactory $fieldLayoutFactory)
58+
public function __construct(
59+
private readonly AdminContextProviderInterface $adminContextProvider,
60+
private readonly AuthorizationCheckerInterface $authorizationChecker,
61+
private readonly iterable $fieldConfigurators,
62+
private readonly FormLayoutFactory $fieldLayoutFactory)
6463
{
65-
$this->adminContextProvider = $adminContextProvider;
66-
$this->authorizationChecker = $authorizationChecker;
67-
$this->fieldConfigurators = $fieldConfigurators;
68-
$this->fieldLayoutFactory = $fieldLayoutFactory;
6964
}
7065

7166
public function processFields(EntityDto $entityDto, FieldCollection $fields): void

‎src/Factory/FilterFactory.php

+5-7
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,14 @@
1515
use EasyCorp\Bundle\EasyAdminBundle\Filter\EntityFilter;
1616
use EasyCorp\Bundle\EasyAdminBundle\Filter\NumericFilter;
1717
use EasyCorp\Bundle\EasyAdminBundle\Filter\TextFilter;
18-
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider;
18+
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProviderInterface;
1919

2020
/**
2121
* @author Yonel Ceruto <yonelceruto@gmail.com>
2222
* @author Javier Eguiluz <javier.eguiluz@gmail.com>
2323
*/
2424
final class FilterFactory
2525
{
26-
private AdminContextProvider $adminContextProvider;
27-
private iterable $filterConfigurators;
2826
private static array $doctrineTypeToFilterClass = [
2927
'json_array' => ArrayFilter::class,
3028
Types::SIMPLE_ARRAY => ArrayFilter::class,
@@ -52,10 +50,10 @@ final class FilterFactory
5250
Types::TEXT => TextFilter::class,
5351
];
5452

55-
public function __construct(AdminContextProvider $adminContextProvider, iterable $filterConfigurators)
56-
{
57-
$this->adminContextProvider = $adminContextProvider;
58-
$this->filterConfigurators = $filterConfigurators;
53+
public function __construct(
54+
private readonly AdminContextProviderInterface $adminContextProvider,
55+
private readonly iterable $filterConfigurators,
56+
) {
5957
}
6058

6159
public function create(FilterConfigDto $filterConfig, FieldCollection $fields, EntityDto $entityDto): FilterCollection

‎src/Factory/MenuFactory.php

+8-14
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
use EasyCorp\Bundle\EasyAdminBundle\Dto\MainMenuDto;
1313
use EasyCorp\Bundle\EasyAdminBundle\Dto\MenuItemDto;
1414
use EasyCorp\Bundle\EasyAdminBundle\Dto\UserMenuDto;
15-
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider;
15+
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProviderInterface;
1616
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGeneratorInterface;
1717
use EasyCorp\Bundle\EasyAdminBundle\Security\Permission;
1818
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
@@ -25,19 +25,13 @@
2525
*/
2626
final class MenuFactory implements MenuFactoryInterface
2727
{
28-
private AdminContextProvider $adminContextProvider;
29-
private AuthorizationCheckerInterface $authChecker;
30-
private LogoutUrlGenerator $logoutUrlGenerator;
31-
private AdminUrlGeneratorInterface $adminUrlGenerator;
32-
private MenuItemMatcherInterface $menuItemMatcher;
33-
34-
public function __construct(AdminContextProvider $adminContextProvider, AuthorizationCheckerInterface $authChecker, LogoutUrlGenerator $logoutUrlGenerator, AdminUrlGeneratorInterface $adminUrlGenerator, MenuItemMatcherInterface $menuItemMatcher)
35-
{
36-
$this->adminContextProvider = $adminContextProvider;
37-
$this->authChecker = $authChecker;
38-
$this->logoutUrlGenerator = $logoutUrlGenerator;
39-
$this->adminUrlGenerator = $adminUrlGenerator;
40-
$this->menuItemMatcher = $menuItemMatcher;
28+
public function __construct(
29+
private readonly AdminContextProviderInterface $adminContextProvider,
30+
private readonly AuthorizationCheckerInterface $authChecker,
31+
private readonly LogoutUrlGenerator $logoutUrlGenerator,
32+
private readonly AdminUrlGeneratorInterface $adminUrlGenerator,
33+
private readonly MenuItemMatcherInterface $menuItemMatcher,
34+
) {
4135
}
4236

4337
/**

0 commit comments

Comments
 (0)
Please sign in to comment.