Skip to content

Commit 1b31207

Browse files
committed
Integrate Respect/Config and Respect/Parameter
Replace the PHP-DI container with Respect/Config: ContainerRegistry now builds a Respect\Config\Container, registering the rules' external dependencies (PHP ISO Codes, libphonenumber, ramsey/uuid) and a ParameterResolver. Instantiate rules through a new AutowiringLookup: a Respect\Fluent FluentFactory that resolves the rule name and autowires its constructor dependencies from the container via Respect\Parameter, wrapped by FluentValidatorFactory. The dead NamespacedValidatorFactory is removed. Drop static ContainerRegistry access from CountryCode, CurrencyCode, LanguageCode, SubdivisionCode, Phone and Uuid: each accepts its external dependency and otherwise constructs it directly, guarded by class_exists for the missing-package error. Inject a ParameterResolver into Attributes so attribute-declared rules are autowired too. Fix Email: drop the func_num_args() guard, which autowiring defeats (the resolver always passes the defaulted argument), so v::email() uses egulias again instead of silently falling back to filter_var. Exclude the autowired dependency types from the generated mixins, update the docs, and add AutowiringLookupTest.
1 parent 42f08d7 commit 1b31207

30 files changed

Lines changed: 477 additions & 547 deletions

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@
2121
},
2222
"require": {
2323
"php": ">=8.5",
24-
"php-di/php-di": "^7.1",
2524
"psr/container": "^2.0",
25+
"respect/config": "^3.0",
2626
"respect/fluent": "^2.0",
27+
"respect/parameter": "^3.0",
2728
"respect/string-formatter": "^1.7",
2829
"respect/stringifier": "^3.0",
2930
"symfony/polyfill-intl-idn": "^1.33",

composer.lock

Lines changed: 113 additions & 184 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/configuration.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ SPDX-FileContributor: Alexandre Gomes Gaigalas <alganet@gmail.com>
88

99
## Container configuration
1010

11-
The `ContainerRegistry::createContainer()` method returns a [PHP-DI](https://php-di.org/) container. The definitions array follows the [PHP-DI definitions format](https://php-di.org/doc/php-definitions.html).
11+
The `ContainerRegistry::createContainer()` method returns a [Respect\Config](https://github.com/Respect/Config) container, which is [PSR-11](https://www.php-fig.org/psr/psr-11/) compatible. Definitions may be plain values, closures, or Respect\Config's `Autowire`, `Instantiator`, and `Ref` helpers.
1212

13-
If you prefer to use a different container, `ContainerRegistry::setContainer()` accepts any [PSR-11](https://www.php-fig.org/psr/psr-11/) compatible container:
13+
If you prefer to use a different container, `ContainerRegistry::setContainer()` accepts any PSR-11 compatible container:
1414

1515
```php
1616
use Respect\Validation\ContainerRegistry;

docs/messages/placeholder-conversion.md

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,16 @@ You can add custom modifiers by providing a custom `PlaceholderFormatter` to the
1616
`ContainerRegistry`:
1717

1818
```php
19-
use DI\Container;
19+
use Respect\Config\Container;
2020
use Respect\StringFormatter\Modifier;
2121
use Respect\StringFormatter\PlaceholderFormatter;
2222
use Respect\Validation\ContainerRegistry;
2323

24-
use function DI\factory;
25-
2624
ContainerRegistry::setContainer(
2725
ContainerRegistry::createContainer([
28-
PlaceholderFormatter::class => factory(
29-
fn(Container $container) => new PlaceholderFormatter(
30-
[],
31-
new MyCustomModifier($container->get(Modifier::class)),
32-
),
26+
PlaceholderFormatter::class => static fn(Container $container) => new PlaceholderFormatter(
27+
[],
28+
new MyCustomModifier($container->get(Modifier::class)),
3329
),
3430
])
3531
);

docs/migrating-from-v2-to-v3.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ The `Factory` class has been replaced by a dependency injection container approa
504504
+ ContainerRegistry::setContainer($container);
505505
```
506506

507-
The `ContainerRegistry::createContainer()` returns a [PHP-DI](https://php-di.org/) container. You can also use any PSR-11 compatible container with `ContainerRegistry::setContainer()`.
507+
The `ContainerRegistry::createContainer()` returns a [Respect\Config](https://github.com/Respect/Config) container, which is [PSR-11](https://www.php-fig.org/psr/psr-11/) compatible. You can also use any PSR-11 compatible container with `ContainerRegistry::setContainer()`.
508508

509509
### Custom validators
510510

docs/validators/Attributes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ SPDX-FileContributor: Henrique Moody <henriquemoody@gmail.com>
88
# Attributes
99

1010
- `Attributes()`
11+
- `Attributes(Resolver $resolver)`
1112

1213
Validates the PHP attributes defined in the properties of the input.
1314

docs/validators/Uuid.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ SPDX-FileContributor: steven.lewis <stevenlewis@gowebprint.com>
1212

1313
- `Uuid()`
1414
- `Uuid(int $version)`
15+
- `Uuid(int $version, UuidFactory $uuidFactory)`
1516

1617
Validates whether the input is a valid UUID. It also supports validation of
1718
specific versions 1 to 8.

src-dev/Commands/LintMixinCommand.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
7474
config: $config,
7575
scanner: $scanner,
7676
methodBuilder: new MethodBuilder(
77-
excludedTypePrefixes: ['Sokil', 'Egulias'],
78-
excludedTypeNames: ['finfo'],
77+
excludedTypePrefixes: ['Sokil', 'Egulias', 'Ramsey', 'libphonenumber'],
78+
excludedTypeNames: ['Respect\\Parameter\\Resolver'],
7979
),
8080
interfaces: [
8181
new InterfaceConfig(

src/AutowiringLookup.php

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
/*
4+
* SPDX-License-Identifier: MIT
5+
* SPDX-FileCopyrightText: (c) Respect Project Contributors
6+
* SPDX-FileContributor: Alexandre Gomes Gaigalas <alganet@gmail.com>
7+
*/
8+
9+
declare(strict_types=1);
10+
11+
namespace Respect\Validation;
12+
13+
use Respect\Fluent\Exceptions\CouldNotCreate;
14+
use Respect\Fluent\Factories\NamespaceLookup;
15+
use Respect\Fluent\FluentFactory;
16+
use Respect\Fluent\FluentNode;
17+
use Respect\Fluent\FluentResolver;
18+
use Respect\Parameter\Resolver;
19+
use Throwable;
20+
21+
use function sprintf;
22+
23+
final readonly class AutowiringLookup implements FluentFactory
24+
{
25+
public function __construct(
26+
private NamespaceLookup $lookup,
27+
private FluentResolver $resolver,
28+
private Resolver $parameterResolver,
29+
) {
30+
}
31+
32+
public function withNamespace(string $namespace): static
33+
{
34+
return clone ($this, ['lookup' => $this->lookup->withNamespace($namespace)]);
35+
}
36+
37+
/** @param array<int|string, mixed> $arguments */
38+
public function create(string $name, array $arguments = []): object
39+
{
40+
$spec = $this->resolver->resolve(new FluentNode($name, $arguments));
41+
42+
$instance = $this->instantiate($spec->name, $spec->arguments);
43+
44+
$wrapper = $spec->wrapper;
45+
while ($wrapper !== null) {
46+
$instance = $this->instantiate($wrapper->name, [...$wrapper->arguments, $instance]);
47+
$wrapper = $wrapper->wrapper;
48+
}
49+
50+
return $instance;
51+
}
52+
53+
/** @param array<int|string, mixed> $arguments */
54+
private function instantiate(string $name, array $arguments): object
55+
{
56+
$reflection = $this->lookup->resolve($name);
57+
58+
$constructor = $reflection->getConstructor();
59+
try {
60+
if ($constructor === null) {
61+
return $reflection->newInstanceArgs($arguments);
62+
}
63+
64+
return $reflection->newInstanceArgs($this->parameterResolver->resolve($constructor, $arguments));
65+
} catch (Throwable $exception) {
66+
throw new CouldNotCreate(
67+
sprintf('Could not instantiate "%s": %s', $name, $exception->getMessage()),
68+
previous: $exception,
69+
);
70+
}
71+
}
72+
}

src/ContainerRegistry.php

Lines changed: 48 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,17 @@
1111

1212
namespace Respect\Validation;
1313

14-
use DI\Container;
1514
use libphonenumber\PhoneNumberUtil;
1615
use Psr\Container\ContainerInterface;
17-
use Respect\Fluent\Factories\ComposingLookup;
16+
use Ramsey\Uuid\UuidFactory;
17+
use Respect\Config\Autowire;
18+
use Respect\Config\Container;
19+
use Respect\Config\Instantiator;
1820
use Respect\Fluent\Factories\NamespaceLookup;
1921
use Respect\Fluent\Resolvers\ComposableMap;
2022
use Respect\Fluent\Resolvers\Ucfirst;
23+
use Respect\Parameter\ContainerResolver;
24+
use Respect\Parameter\Resolver;
2125
use Respect\StringFormatter\BypassTranslator;
2226
use Respect\StringFormatter\Modifier;
2327
use Respect\StringFormatter\Modifiers\FormatterModifier;
@@ -45,12 +49,12 @@
4549
use Respect\Validation\Message\Renderer;
4650
use Respect\Validation\Message\TemplateRegistry;
4751
use Respect\Validation\Mixins\PrefixConstants;
52+
use Sokil\IsoCodes\Database\Countries;
53+
use Sokil\IsoCodes\Database\Currencies;
54+
use Sokil\IsoCodes\Database\Languages;
55+
use Sokil\IsoCodes\Database\Subdivisions;
4856
use Symfony\Contracts\Translation\TranslatorInterface;
4957

50-
use function DI\autowire;
51-
use function DI\create;
52-
use function DI\factory;
53-
5458
final class ContainerRegistry
5559
{
5660
private static ContainerInterface|null $container = null;
@@ -59,50 +63,56 @@ final class ContainerRegistry
5963
public static function createContainer(array $definitions = []): Container
6064
{
6165
return new Container($definitions + [
62-
PhoneNumberUtil::class => factory(static fn() => PhoneNumberUtil::getInstance()),
63-
TemplateRegistry::class => create(TemplateRegistry::class),
64-
TemplateResolver::class => autowire(TemplateResolver::class),
65-
TranslatorInterface::class => autowire(BypassTranslator::class),
66-
Renderer::class => autowire(InterpolationRenderer::class),
67-
ResultFilter::class => create(OnlyFailedChildrenResultFilter::class),
68-
'respect.validation.formatter.message' => autowire(FirstResultStringFormatter::class),
69-
'respect.validation.formatter.full_message' => autowire(NestedListStringFormatter::class),
70-
'respect.validation.formatter.messages' => autowire(NestedArrayFormatter::class),
66+
Countries::class => new Instantiator(Countries::class),
67+
Currencies::class => new Instantiator(Currencies::class),
68+
Languages::class => new Instantiator(Languages::class),
69+
Subdivisions::class => new Instantiator(Subdivisions::class),
70+
UuidFactory::class => new Instantiator(UuidFactory::class),
71+
PhoneNumberUtil::class => static fn() => PhoneNumberUtil::getInstance(),
72+
TemplateRegistry::class => new Instantiator(TemplateRegistry::class),
73+
TemplateResolver::class => new Autowire(TemplateResolver::class),
74+
TranslatorInterface::class => new Autowire(BypassTranslator::class),
75+
Renderer::class => new Autowire(InterpolationRenderer::class),
76+
ResultFilter::class => new Instantiator(OnlyFailedChildrenResultFilter::class),
77+
'respect.validation.formatter.message' => new Autowire(FirstResultStringFormatter::class),
78+
'respect.validation.formatter.full_message' => new Autowire(NestedListStringFormatter::class),
79+
'respect.validation.formatter.messages' => new Autowire(NestedArrayFormatter::class),
7180
'respect.validation.ignored_backtrace_paths' => [__DIR__ . '/ValidatorBuilder.php'],
7281
'respect.validation.rule_factory.namespaces' => ['Respect\\Validation\\Validators'],
73-
ValidatorFactory::class => factory(static function (Container $container) {
82+
Resolver::class => static fn(Container $container) => new ContainerResolver($container),
83+
ValidatorFactory::class => static function (Container $container) {
84+
$lookup = new NamespaceLookup(
85+
new Ucfirst(),
86+
Validator::class,
87+
...$container->get('respect.validation.rule_factory.namespaces'),
88+
);
89+
7490
return new FluentValidatorFactory(
75-
new ComposingLookup(
76-
new NamespaceLookup(
77-
new Ucfirst(),
78-
Validator::class,
79-
...$container->get('respect.validation.rule_factory.namespaces'),
80-
),
81-
new ComposableMap(
82-
PrefixConstants::COMPOSABLE,
83-
PrefixConstants::COMPOSABLE_WITH_ARGUMENT,
84-
),
91+
new AutowiringLookup(
92+
$lookup,
93+
new ComposableMap(PrefixConstants::COMPOSABLE, PrefixConstants::COMPOSABLE_WITH_ARGUMENT),
94+
$container->get(Resolver::class),
8595
),
8696
);
87-
}),
88-
Quoter::class => create(CodeQuoter::class)->constructor(120),
89-
Handler::class => factory(static function (Container $container) {
97+
},
98+
Quoter::class => new Instantiator(CodeQuoter::class, ['maximumLength' => 120]),
99+
Handler::class => static function (Container $container) {
90100
$handler = CompositeHandler::create();
91101
$handler->prependHandler(new PathHandler($container->get(Quoter::class)));
92102
$handler->prependHandler(new NameHandler());
93103
$handler->prependHandler(new ResultHandler($handler));
94104

95105
return $handler;
96-
}),
97-
PlaceholderFormatter::class => factory(static fn(Container $container) => new PlaceholderFormatter(
106+
},
107+
PlaceholderFormatter::class => static fn(Container $container) => new PlaceholderFormatter(
98108
[],
99109
$container->get(Modifier::class),
100-
)),
101-
Stringifier::class => factory(static fn(Container $container) => new HandlerStringifier(
110+
),
111+
Stringifier::class => static fn(Container $container) => new HandlerStringifier(
102112
$container->get(Handler::class),
103113
new DumpStringifier(),
104-
)),
105-
Modifier::class => factory(static fn(Container $container) => new TransModifier(
114+
),
115+
Modifier::class => static fn(Container $container) => new TransModifier(
106116
new ListModifier(
107117
new QuoteModifier(
108118
new RawModifier(
@@ -112,16 +122,16 @@ public static function createContainer(array $definitions = []): Container
112122
$container->get(TranslatorInterface::class),
113123
),
114124
$container->get(TranslatorInterface::class),
115-
)),
116-
ValidatorBuilder::class => factory(static fn(Container $container) => new ValidatorBuilder(
125+
),
126+
ValidatorBuilder::class => static fn(Container $container) => new ValidatorBuilder(
117127
$container->get(ValidatorFactory::class),
118128
$container->get(Renderer::class),
119129
$container->get('respect.validation.formatter.message'),
120130
$container->get('respect.validation.formatter.full_message'),
121131
$container->get('respect.validation.formatter.messages'),
122132
$container->get(ResultFilter::class),
123133
$container->get('respect.validation.ignored_backtrace_paths'),
124-
)),
134+
),
125135
]);
126136
}
127137

0 commit comments

Comments
 (0)