Issue #2031487 by fubhy, dawehner, pwolanin: When replacing the upcasted values in the request attributes array, retain the original raw value too.
parent
d3c5919d17
commit
58afd192b8
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Drupal\Core\Controller;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Controller\ControllerResolver as BaseControllerResolver;
|
||||
use Symfony\Component\HttpKernel\Log\LoggerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||
|
@ -98,4 +99,27 @@ class ControllerResolver extends BaseControllerResolver {
|
|||
return array($controller, $method);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function doGetArguments(Request $request, $controller, array $parameters) {
|
||||
$arguments = parent::doGetArguments($request, $controller, $parameters);
|
||||
|
||||
// The parameter converter overrides the raw request attributes with the
|
||||
// upcasted objects. However, it keeps a backup copy of the original, raw
|
||||
// values in a special request attribute ('_raw_variables'). If a controller
|
||||
// argument has a type hint, we pass it the upcasted object, otherwise we
|
||||
// pass it the original, raw value.
|
||||
if ($request->attributes->has('_raw_variables') && $raw = $request->attributes->get('_raw_variables')->all()) {
|
||||
foreach ($parameters as $parameter) {
|
||||
// Use the raw value if a parameter has no typehint.
|
||||
if (!$parameter->getClass() && isset($raw[$parameter->name])) {
|
||||
$position = $parameter->getPosition();
|
||||
$arguments[$position] = $raw[$parameter->name];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Drupal\Core\ParamConverter;
|
|||
use Symfony\Component\DependencyInjection\ContainerAware;
|
||||
use Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface;
|
||||
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
@ -151,7 +152,11 @@ class ParamConverterManager extends ContainerAware implements RouteEnhancerInter
|
|||
* The modified defaults.
|
||||
*/
|
||||
public function enhance(array $defaults, Request $request) {
|
||||
// Store a backup of the raw $defaults values corresponding to
|
||||
// variables in the route path pattern.
|
||||
$route = $defaults[RouteObjectInterface::ROUTE_OBJECT];
|
||||
$variables = array_flip($route->compile()->getVariables());
|
||||
$defaults['_raw_variables'] = new ParameterBag(array_intersect_key($defaults, $variables));
|
||||
|
||||
// Skip this enhancer if there are no parameter definitions.
|
||||
if (!$parameters = $route->getOption('parameters')) {
|
||||
|
|
|
@ -8,20 +8,21 @@
|
|||
namespace Drupal\paramconverter_test;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\node\NodeInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Controller routine for testing the paramconverter.
|
||||
*/
|
||||
class TestControllers {
|
||||
|
||||
public function testUserNodeFoo($user, $node, $foo) {
|
||||
$retval = "user: " . (is_object($user) ? $user->label() : $user);
|
||||
$retval .= ", node: " . (is_object($node) ? $node->label() : $node);
|
||||
$retval .= ", foo: " . (is_object($foo) ? $foo->label() : $foo);
|
||||
return $retval;
|
||||
public function testUserNodeFoo(EntityInterface $user, NodeInterface $node, Request $request) {
|
||||
$foo = $request->attributes->get('foo');
|
||||
$foo = is_object($foo) ? $foo->label() : $foo;
|
||||
return "user: {$user->label()}, node: {$node->label()}, foo: $foo";
|
||||
}
|
||||
|
||||
public function testNodeSetParent(EntityInterface $node, EntityInterface $parent) {
|
||||
return "Setting '{$parent->title}' as parent of '{$node->title}'.";
|
||||
public function testNodeSetParent(NodeInterface $node, NodeInterface $parent) {
|
||||
return "Setting '{$parent->label()}' as parent of '{$node->label()}'.";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\Core\Controller\ControllerResolverTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\Core\Controller;
|
||||
|
||||
use Drupal\Core\Controller\ControllerResolver;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\user\UserInterface;
|
||||
use Guzzle\Http\Message\Request;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
|
||||
/**
|
||||
* Tests that the Drupal-extended ControllerResolver is functioning properly.
|
||||
*
|
||||
* @see \Drupal\Core\Controller\ControllerResolver
|
||||
*/
|
||||
class ControllerResolverTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The tested controller resolver.
|
||||
*
|
||||
* @var \Drupal\Core\Controller\ControllerResolver
|
||||
*/
|
||||
public $controllerResolver;
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Controller Resolver tests',
|
||||
'description' => 'Tests that the Drupal-extended ControllerResolver is functioning properly.',
|
||||
'group' => 'Routing',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$this->controllerResolver = new ControllerResolver($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests getArguments().
|
||||
*
|
||||
* Ensure that doGetArguments uses converted arguments if available.
|
||||
*
|
||||
* @see \Drupal\Core\Controller\ControllerResolver::getArguments()
|
||||
* @see \Drupal\Core\Controller\ControllerResolver::doGetArguments()
|
||||
*/
|
||||
public function testGetArguments() {
|
||||
$controller = function(EntityInterface $entity, $user) {
|
||||
};
|
||||
$mock_entity = $this->getMockBuilder('Drupal\Core\Entity\Entity')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$mock_account = $this->getMock('Drupal\Core\Session\AccountInterface');
|
||||
$request = new \Symfony\Component\HttpFoundation\Request(array(), array(), array(
|
||||
'entity' => $mock_entity,
|
||||
'user' => $mock_account,
|
||||
'_raw_variables' => new ParameterBag(array('entity' => 1, 'user' => 1)),
|
||||
));
|
||||
$arguments = $this->controllerResolver->getArguments($request, $controller);
|
||||
|
||||
$this->assertEquals($mock_entity, $arguments[0], 'Type hinted variables should use upcasted values.');
|
||||
$this->assertEquals(1, $arguments[1], 'Not type hinted variables should use not upcasted values.');
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue