Skip to content

Commit 7a8cfae

Browse files
committed
Refactored argument resolving out of the ControllerResolver
1 parent 7baeaa2 commit 7a8cfae

16 files changed

+464
-21
lines changed

src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass;
3434
use Symfony\Component\HttpFoundation\Request;
3535
use Symfony\Component\HttpKernel\Bundle\Bundle;
36+
use Symfony\Component\HttpKernel\DependencyInjection\RegisterArgumentResolversPass;
3637

3738
/**
3839
* Bundle.
@@ -81,6 +82,7 @@ public function build(ContainerBuilder $container)
8182
$container->addCompilerPass(new TranslationDumperPass());
8283
$container->addCompilerPass(new FragmentRendererPass(), PassConfig::TYPE_AFTER_REMOVING);
8384
$container->addCompilerPass(new SerializerPass());
85+
$container->addCompilerPass(new RegisterArgumentResolversPass());
8486

8587
if ($container->getParameter('kernel.debug')) {
8688
$container->addCompilerPass(new ContainerBuilderDebugDumpPass(), PassConfig::TYPE_AFTER_REMOVING);

src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
<argument type="service" id="service_container" />
2626
<argument type="service" id="controller_resolver" />
2727
<argument type="service" id="request_stack" />
28+
<argument type="service" id="argument_resolver.manager" />
2829
</service>
2930

3031
<service id="request_stack" class="%request_stack.class%" />

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
<parameters>
88
<parameter key="controller_resolver.class">Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver</parameter>
9+
<parameter key="argument_resolver.manager.class">Symfony\Component\HttpKernel\Controller\ArgumentResolverManager</parameter>
10+
<parameter key="argument_resolver.request.class">Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestArgumentResolver</parameter>
11+
<parameter key="argument_resolver.request_attributes.class">Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestAttributesArgumentResolver</parameter>
912
<parameter key="controller_name_converter.class">Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser</parameter>
1013
<parameter key="response_listener.class">Symfony\Component\HttpKernel\EventListener\ResponseListener</parameter>
1114
<parameter key="streamed_response_listener.class">Symfony\Component\HttpKernel\EventListener\StreamedResponseListener</parameter>
@@ -25,6 +28,16 @@
2528
<argument type="service" id="logger" on-invalid="ignore" />
2629
</service>
2730

31+
<service id="argument_resolver.manager" class="%argument_resolver.manager.class%" />
32+
33+
<service id="argument_resolver.request" class="%argument_resolver.request.class%">
34+
<tag name="kernel.argument_resolver" />
35+
</service>
36+
37+
<service id="argument_resolver.request_attributes" class="%argument_resolver.request_attributes.class%">
38+
<tag name="kernel.argument_resolver" />
39+
</service>
40+
2841
<service id="response_listener" class="%response_listener.class%">
2942
<tag name="kernel.event_subscriber" />
3043
<argument>%kernel.charset%</argument>

src/Symfony/Component/HttpKernel/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
CHANGELOG
22
=========
33

4+
* added argument resolvers
5+
* deprecated `Symfony\Component\HttpKernel\Controller\ControllerResolver#getArguments()` and `doGetArguments()`, use argument resolvers instead
6+
47
2.5.0
58
-----
69

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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+
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
13+
14+
use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface;
15+
use Symfony\Component\HttpFoundation\Request;
16+
17+
/**
18+
* Resolves arguments typehinting for the Request object.
19+
*
20+
* @author Wouter J <wouter@wouterj.nl>
21+
*/
22+
class RequestArgumentResolver implements ArgumentResolverInterface
23+
{
24+
/**
25+
* {@inheritDoc}
26+
*/
27+
public function accepts(Request $request, \ReflectionParameter $parameter)
28+
{
29+
$class = $parameter->getClass();
30+
31+
return $class && $class->isInstance($request);
32+
}
33+
34+
/**
35+
* {@inheritDoc}
36+
*/
37+
public function resolve(Request $request, \ReflectionParameter $parameter)
38+
{
39+
return $request;
40+
}
41+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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+
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
13+
14+
use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface;
15+
use Symfony\Component\HttpFoundation\Request;
16+
17+
/**
18+
* Resolves arguments which names are equal to the name of a request attribute.
19+
*
20+
* @author Wouter J <wouter@wouterj.nl>
21+
*/
22+
class RequestAttributesArgumentResolver implements ArgumentResolverInterface
23+
{
24+
/**
25+
* {@inheritDoc}
26+
*/
27+
public function accepts(Request $request, \ReflectionParameter $parameter)
28+
{
29+
return array_key_exists($parameter->name, $request->attributes->all());
30+
}
31+
32+
/**
33+
* {@inheritDoc}
34+
*/
35+
public function resolve(Request $request, \ReflectionParameter $parameter)
36+
{
37+
$attributes = $request->attributes->all();
38+
39+
return $attributes[$parameter->name];
40+
}
41+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
namespace Symfony\Component\HttpKernel\Controller;
13+
14+
use Symfony\Component\HttpFoundation\Request;
15+
16+
/**
17+
* An ArgumentResolverInterface implementation resolves the arguments of
18+
* controllers.
19+
*
20+
* @author Wouter J <wouter@wouterj.nl>
21+
*/
22+
interface ArgumentResolverInterface
23+
{
24+
/**
25+
* Checks if the current parameter can be resolved by this argument
26+
* resolver.
27+
*
28+
* @param Request $request
29+
* @param \ReflectionParameter $parameter
30+
*
31+
* @return Boolean
32+
*/
33+
public function accepts(Request $request, \ReflectionParameter $parameter);
34+
35+
/**
36+
* Resolves the current parameter into an argument.
37+
*
38+
* @param Request $request
39+
* @param \ReflectionParameter $parameter
40+
*
41+
* @return mixed The resolved argument
42+
*/
43+
public function resolve(Request $request, \ReflectionParameter $parameter);
44+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
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+
namespace Symfony\Component\HttpKernel\Controller;
13+
14+
use Symfony\Component\HttpFoundation\Request;
15+
16+
/**
17+
* The ArgumentResolverManager chains over the registered argument resolvers to
18+
* resolve all controller arguments.
19+
*
20+
* @author Wouter J <wouter@wouterj.nl>
21+
*/
22+
class ArgumentResolverManager
23+
{
24+
/**
25+
* @var ArgumentResolverInterface[]
26+
*/
27+
protected $resolvers = array();
28+
29+
/**
30+
* Adds an argument resolver.
31+
*
32+
* @param ArgumentResolverInterface $resolver
33+
*/
34+
public function addResolver(ArgumentResolverInterface $resolver)
35+
{
36+
$this->resolvers[] = $resolver;
37+
}
38+
39+
/**
40+
* Returns the arguments to pass to the controller.
41+
*
42+
* @param Request $request A Request instance
43+
* @param callable $controller A PHP callable
44+
*
45+
* @return array an array of arguments to pass to the controller
46+
*
47+
* @throws \RuntimeException When a parameter cannot be resolved
48+
*/
49+
public function getArguments(Request $request, $controller)
50+
{
51+
if (is_array($controller)) {
52+
$controllerReflection = new \ReflectionMethod($controller[0], $controller[1]);
53+
} elseif (is_object($controller) && !$controller instanceof \Closure) {
54+
$controllerReflection = new \ReflectionObject($controller);
55+
$controllerReflection = $controllerReflection->getMethod('__invoke');
56+
} else {
57+
$controllerReflection = new \ReflectionFunction($controller);
58+
}
59+
60+
$parameters = $controllerReflection->getParameters();
61+
$arguments = array();
62+
63+
foreach ($parameters as $parameter) {
64+
foreach ($this->resolvers as $argumentResolver) {
65+
if ($argumentResolver->accepts($request, $parameter)) {
66+
$arguments[] = $argumentResolver->resolve($request, $parameter);
67+
continue 2;
68+
}
69+
}
70+
71+
if ($parameter->isDefaultValueAvailable()) {
72+
$arguments[] = $parameter->getDefaultValue();
73+
} else {
74+
if (is_array($controller)) {
75+
$repr = sprintf('%s::%s()', get_class($controller[0]), $controller[1]);
76+
} elseif (is_object($controller)) {
77+
$repr = get_class($controller);
78+
} else {
79+
$repr = $controller;
80+
}
81+
82+
throw new \RuntimeException(sprintf('Controller "%s" requires that you provide a value for the "$%s" argument (because there is no default value and none of the argument resolvers could resolve its value).', $repr, $parameter->name));
83+
}
84+
}
85+
86+
return $arguments;
87+
}
88+
}

src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ public function getController(Request $request)
8282
* {@inheritdoc}
8383
*
8484
* @api
85+
*
86+
* @deprecated Deprecated since Symfony 2.6, will be removed in Symfony 3.0. Use ArgumentResolvers instead
8587
*/
8688
public function getArguments(Request $request, $controller)
8789
{
@@ -97,6 +99,9 @@ public function getArguments(Request $request, $controller)
9799
return $this->doGetArguments($request, $controller, $r->getParameters());
98100
}
99101

102+
/**
103+
* @deprecated Deprecated since Symfony 2.6, will be removed in Symfony 3.0. Use ArgumentResolvers instead
104+
*/
100105
protected function doGetArguments(Request $request, $controller, array $parameters)
101106
{
102107
$attributes = $request->attributes->all();

src/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\HttpFoundation\RequestStack;
1616
use Symfony\Component\HttpKernel\HttpKernelInterface;
1717
use Symfony\Component\HttpKernel\HttpKernel;
18+
use Symfony\Component\HttpKernel\Controller\ArgumentResolverManager;
1819
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
1920
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
2021
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -37,10 +38,11 @@ class ContainerAwareHttpKernel extends HttpKernel
3738
* @param ContainerInterface $container A ContainerInterface instance
3839
* @param ControllerResolverInterface $controllerResolver A ControllerResolverInterface instance
3940
* @param RequestStack $requestStack A stack for master/sub requests
41+
* @param ArgumentResolverManager $argumentResolver An ArgumentResolverManager instance
4042
*/
41-
public function __construct(EventDispatcherInterface $dispatcher, ContainerInterface $container, ControllerResolverInterface $controllerResolver, RequestStack $requestStack = null)
43+
public function __construct(EventDispatcherInterface $dispatcher, ContainerInterface $container, ControllerResolverInterface $controllerResolver, RequestStack $requestStack = null, ArgumentResolverManager $argumentResolver = null)
4244
{
43-
parent::__construct($dispatcher, $controllerResolver, $requestStack);
45+
parent::__construct($dispatcher, $controllerResolver, $requestStack, $argumentResolver);
4446

4547
$this->container = $container;
4648

0 commit comments

Comments
 (0)