Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitcfcf764

Browse files
author
Iltar van der Berg
committed
Added an ArgumentResolver with clean extension point
1 parent360fc5f commitcfcf764

File tree

30 files changed

+1083
-104
lines changed

30 files changed

+1083
-104
lines changed

‎UPGRADE-3.1.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,12 @@ HttpKernel
6565
* Passing objects as URI attributes to the ESI and SSI renderers has been
6666
deprecated and will be removed in Symfony 4.0. The inline fragment
6767
renderer should be used with object attributes.
68+
6869
* The`ControllerResolver::getArguments()` method is deprecated and will be
6970
removed in 4.0. If you have your own`ControllerResolverInterface`
7071
implementation, you should replace this method by implementing the
71-
`ArgumentResolverInterface` and injecting it in the HttpKernel.
72+
`ArgumentResolverInterface` and injecting it in the`HttpKernel`, or using
73+
the`ArgumentResolver` and injecting this in the`HttpKernel`.
7274

7375
Serializer
7476
----------
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespaceSymfony\Bundle\FrameworkBundle\DependencyInjection\Compiler;
13+
14+
useSymfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
15+
useSymfony\Component\DependencyInjection\ContainerBuilder;
16+
useSymfony\Component\DependencyInjection\Reference;
17+
18+
/**
19+
* Gathers and configures the argument value resolvers.
20+
*
21+
* @author Iltar van der Berg <kjarli@gmail.com>
22+
*/
23+
class ControllerArgumentValueResolverPassimplements CompilerPassInterface
24+
{
25+
publicfunctionprocess(ContainerBuilder$container)
26+
{
27+
if (!$container->hasDefinition('argument_resolver')) {
28+
return;
29+
}
30+
31+
$definition =$container->getDefinition('argument_resolver');
32+
$argumentResolvers =$this->findAndSortTaggedServices('controller_argument.value_resolver',$container);
33+
$definition->replaceArgument(1,$argumentResolvers);
34+
}
35+
36+
/**
37+
* Finds all services with the given tag name and order them by their priority.
38+
*
39+
* @param string $tagName
40+
* @param ContainerBuilder $container
41+
*
42+
* @return array
43+
*/
44+
privatefunctionfindAndSortTaggedServices($tagName,ContainerBuilder$container)
45+
{
46+
$services =$container->findTaggedServiceIds($tagName);
47+
48+
$sortedServices =array();
49+
foreach ($servicesas$serviceId =>$tags) {
50+
foreach ($tagsas$attributes) {
51+
$priority =isset($attributes['priority']) ?$attributes['priority'] :0;
52+
$sortedServices[$priority][] =newReference($serviceId);
53+
}
54+
}
55+
56+
if (empty($sortedServices)) {
57+
returnarray();
58+
}
59+
60+
krsort($sortedServices);
61+
62+
// Flatten the array
63+
returncall_user_func_array('array_merge',$sortedServices);
64+
}
65+
}

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ public function load(array $configs, ContainerBuilder $container)
171171
'Symfony\\Component\\HttpKernel\\EventListener\\RouterListener',
172172
'Symfony\\Component\\HttpKernel\\Controller\\ControllerResolver',
173173
'Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver',
174+
'Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata',
175+
'Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadataFactory',
174176
'Symfony\\Component\\HttpKernel\\Event\\KernelEvent',
175177
'Symfony\\Component\\HttpKernel\\Event\\FilterControllerEvent',
176178
'Symfony\\Component\\HttpKernel\\Event\\FilterResponseEvent',

‎src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
useSymfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConstraintValidatorsPass;
1515
useSymfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddValidatorInitializersPass;
1616
useSymfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConsoleCommandPass;
17+
useSymfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ControllerArgumentValueResolverPass;
1718
useSymfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\FormPass;
1819
useSymfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\PropertyInfoPass;
1920
useSymfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TemplatingPass;
@@ -87,6 +88,7 @@ public function build(ContainerBuilder $container)
8788
$container->addCompilerPass(newFragmentRendererPass(), PassConfig::TYPE_AFTER_REMOVING);
8889
$container->addCompilerPass(newSerializerPass());
8990
$container->addCompilerPass(newPropertyInfoPass());
91+
$container->addCompilerPass(newControllerArgumentValueResolverPass());
9092

9193
if ($container->getParameter('kernel.debug')) {
9294
$container->addCompilerPass(newUnusedTagsPass(), PassConfig::TYPE_AFTER_REMOVING);

‎src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml‎

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,28 @@
1717
<argumenttype="service"id="logger"on-invalid="ignore" />
1818
</service>
1919

20-
<serviceid="argument_resolver"class="Symfony\Component\HttpKernel\Controller\ArgumentResolver"public="false" />
20+
<serviceid="argument_resolver"class="Symfony\Component\HttpKernel\Controller\ArgumentResolver"public="false">
21+
<argumenttype="service"id="argument_metadata_factory" />
22+
<argumenttype="collection" />
23+
</service>
24+
25+
<serviceid="argument_metadata_factory"class="Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactory"public="false" />
26+
27+
<serviceid="argument_value_resolver.argument_from_attribute"class="Symfony\Component\HttpKernel\Controller\ArgumentValueResolver\ArgumentFromAttributeResolver"public="false">
28+
<tagname="controller_argument.value_resolver"priority="100" />
29+
</service>
30+
31+
<serviceid="argument_value_resolver.argument_is_request"class="Symfony\Component\HttpKernel\Controller\ArgumentValueResolver\RequestResolver"public="false">
32+
<tagname="controller_argument.value_resolver"priority="50" />
33+
</service>
34+
35+
<serviceid="argument_value_resolver.default_argument_value"class="Symfony\Component\HttpKernel\Controller\ArgumentValueResolver\DefaultArgumentValueResolver"public="false">
36+
<tagname="controller_argument.value_resolver"priority="-100" />
37+
</service>
38+
39+
<serviceid="argument_value_resolver.variadic_argument_from_attribute"class="Symfony\Component\HttpKernel\Controller\ArgumentValueResolver\VariadicArgumentValueResolver"public="false">
40+
<tagname="controller_argument.value_resolver"priority="-150" />
41+
</service>
2142

2243
<serviceid="response_listener"class="Symfony\Component\HttpKernel\EventListener\ResponseListener">
2344
<tagname="kernel.event_subscriber" />

‎src/Symfony/Component/HttpKernel/CHANGELOG.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ CHANGELOG
44
3.1.0
55
-----
66
* deprecated passing objects as URI attributes to the ESI and SSI renderers
7-
* Added an`ArgumentResolver` with`getArguments()` and the respective interface`ArgumentResolverInterface`
8-
* Deprecated`ControllerResolver::getArguments()`, which uses the`ArgumentResolver` as BC layer by extending it
9-
* The`HttpKernel` now accepts an additional argument for an`ArgumentResolver`
7+
* Added a`LegacyArgumentResolver` with`getArguments()` and the corresponding interface`ArgumentResolverInterface`
8+
* Deprecated`ControllerResolver::getArguments()`, which uses the`LegacyArgumentResolver` as BC layer by extending it
9+
* The`HttpKernel` now accepts an additional argument for an`ArgumentResolverInterface`
10+
* Added the`ArgumentResolver` which features an extension point to resolve arguments in a more dynamic way
1011

1112
3.0.0
1213
-----

‎src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php‎

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -12,57 +12,64 @@
1212
namespaceSymfony\Component\HttpKernel\Controller;
1313

1414
useSymfony\Component\HttpFoundation\Request;
15+
useSymfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactoryInterface;
1516

1617
/**
17-
* Responsible for thecreation ofthe action arguments.
18+
* Responsible for theresolving ofarguments passed to an action.
1819
*
19-
* @authorFabien Potencier <fabien@symfony.com>
20+
* @authorIltar van der Berg <kjarli@gmail.com>
2021
*/
21-
class ArgumentResolverimplements ArgumentResolverInterface
22+
finalclass ArgumentResolverimplements ArgumentResolverInterface
2223
{
24+
private$argumentMetadataFactory;
25+
2326
/**
24-
*{@inheritdoc}
27+
*@var ArgumentValueResolverInterface[]
2528
*/
26-
publicfunctiongetArguments(Request$request,$controller)
27-
{
28-
if (is_array($controller)) {
29-
$r =new \ReflectionMethod($controller[0],$controller[1]);
30-
}elseif (is_object($controller) && !$controllerinstanceof \Closure) {
31-
$r =new \ReflectionObject($controller);
32-
$r =$r->getMethod('__invoke');
33-
}else {
34-
$r =new \ReflectionFunction($controller);
35-
}
29+
private$argumentValueResolvers;
3630

37-
return$this->doGetArguments($request,$controller,$r->getParameters());
31+
publicfunction__construct(ArgumentMetadataFactoryInterface$argumentMetadataFactory =null,array$argumentValueResolvers =array())
32+
{
33+
$this->argumentMetadataFactory =$argumentMetadataFactory;
34+
$this->argumentValueResolvers =$argumentValueResolvers;
3835
}
3936

40-
protectedfunctiondoGetArguments(Request$request,$controller,array$parameters)
37+
/**
38+
* {@inheritdoc}
39+
*/
40+
publicfunctiongetArguments(Request$request,$controller)
4141
{
42-
$attributes =$request->attributes->all();
4342
$arguments =array();
44-
foreach ($parametersas$param) {
45-
if (array_key_exists($param->name,$attributes)) {
46-
if (PHP_VERSION_ID >=50600 &&$param->isVariadic() &&is_array($attributes[$param->name])) {
47-
$arguments =array_merge($arguments,array_values($attributes[$param->name]));
48-
}else {
49-
$arguments[] =$attributes[$param->name];
43+
44+
foreach ($this->argumentMetadataFactory->createArgumentMetadata($controller)as$metadata) {
45+
foreach ($this->argumentValueResolversas$resolver) {
46+
if (!$resolver->supports($request,$metadata)) {
47+
continue;
5048
}
51-
}elseif ($param->getClass() &&$param->getClass()->isInstance($request)) {
52-
$arguments[] =$request;
53-
}elseif ($param->isDefaultValueAvailable()) {
54-
$arguments[] =$param->getDefaultValue();
55-
}else {
56-
if (is_array($controller)) {
57-
$repr =sprintf('%s::%s()',get_class($controller[0]),$controller[1]);
58-
}elseif (is_object($controller)) {
59-
$repr =get_class($controller);
60-
}else {
61-
$repr =$controller;
49+
50+
$resolved =$resolver->resolve($request,$metadata);
51+
52+
if (!$resolvedinstanceof \Generator) {
53+
thrownew \InvalidArgumentException(sprintf('%s::resolve() must yield at least one value.',get_class($resolver)));
54+
}
55+
56+
foreach ($resolvedas$append) {
57+
$arguments[] =$append;
6258
}
6359

64-
thrownew \RuntimeException(sprintf('Controller "%s" requires that you provide a value for the "$%s" argument (because there is no default value or because there is a non optional argument after this one).',$repr,$param->name));
60+
// continue to the next controller argument
61+
continue2;
6562
}
63+
64+
$representative =$controller;
65+
66+
if (is_array($representative)) {
67+
$representative =sprintf('%s::%s()',get_class($representative[0]),$representative[1]);
68+
}elseif (is_object($representative)) {
69+
$representative =get_class($representative);
70+
}
71+
72+
thrownew \RuntimeException(sprintf('Controller "%s" requires that you provide a value for the "$%s" argument (because there is no default value or because there is a non optional argument after this one).',$representative,$metadata->getName()));
6673
}
6774

6875
return$arguments;

‎src/Symfony/Component/HttpKernel/Controller/ArgumentResolverInterface.php‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ interface ArgumentResolverInterface
2424
/**
2525
* Returns the arguments to pass to the controller.
2626
*
27-
* @param Request $request A Request instance
28-
* @param callable $controller A PHP callable
27+
* @param Request $request
28+
* @param callable $controller
2929
*
3030
* @return array An array of arguments to pass to the controller
3131
*
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespaceSymfony\Component\HttpKernel\Controller\ArgumentValueResolver;
13+
14+
useSymfony\Component\HttpFoundation\Request;
15+
useSymfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
16+
useSymfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
17+
18+
/**
19+
* Grabs a non-variadic value from the request and returns it.
20+
*
21+
* @author Iltar van der Berg <kjarli@gmail.com>
22+
*/
23+
finalclass ArgumentFromAttributeResolverimplements ArgumentValueResolverInterface
24+
{
25+
/**
26+
* {@inheritdoc}
27+
*/
28+
publicfunctionsupports(Request$request,ArgumentMetadata$argument)
29+
{
30+
return !$argument->isVariadic() &&$request->attributes->has($argument->getName());
31+
}
32+
33+
/**
34+
* {@inheritdoc}
35+
*/
36+
publicfunctionresolve(Request$request,ArgumentMetadata$argument)
37+
{
38+
yield$request->attributes->get($argument->getName());
39+
}
40+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespaceSymfony\Component\HttpKernel\Controller\ArgumentValueResolver;
13+
14+
useSymfony\Component\HttpFoundation\Request;
15+
useSymfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
16+
useSymfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
17+
18+
/**
19+
* Returns the default value defined in the action signature if present and no value has been given.
20+
*
21+
* @author Iltar van der Berg <kjarli@gmail.com>
22+
*/
23+
finalclass DefaultArgumentValueResolverimplements ArgumentValueResolverInterface
24+
{
25+
/**
26+
* {@inheritdoc}
27+
*/
28+
publicfunctionsupports(Request$request,ArgumentMetadata$argument)
29+
{
30+
return$argument->hasDefaultValue() && !$request->attributes->has($argument->getName());
31+
}
32+
33+
/**
34+
* {@inheritdoc}
35+
*/
36+
publicfunctionresolve(Request$request,ArgumentMetadata$argument)
37+
{
38+
yield$argument->getDefaultValue();
39+
}
40+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp