Skip to content

Commit 76b6449

Browse files
committed
merged branch fabpot/fragments-with-non-scalars (PR #8437)
This PR was merged into the master branch. Discussion ---------- [HttpKernel] changed the fragment handler to explicitely disallow non-scalar in generated URIs (refs #8263) | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #8263 | License | MIT | Doc PR | n/a When using the `render()` function in Twig with a `controller()` reference, the attributes can contain non-scalar. That's fine for the inline strategy, but it cannot work for other strategies as it then involves a proper HTTP request. So, this PR properly throw an exception in such situations to avoid difficult to find bugs. Commits ------- 43ce368 [HttpKernel] added a unit test to demonstrate that passing objects works for inline controllers 70f3399 [HttpKernel] changed the fragment handler to explicitely disallow non-scalar in generated URIs (refs #8263)
2 parents 63e6368 + 43ce368 commit 76b6449

File tree

4 files changed

+77
-13
lines changed

4 files changed

+77
-13
lines changed

src/Symfony/Component/HttpKernel/Fragment/InlineFragmentRenderer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public function render($uri, Request $request, array $options = array())
5959
// below instead)
6060
$attributes = $reference->attributes;
6161
$reference->attributes = array();
62-
$uri = $this->generateFragmentUri($uri, $request);
62+
$uri = $this->generateFragmentUri($uri, $request, false);
6363
$reference->attributes = array_merge($attributes, $reference->attributes);
6464
}
6565

src/Symfony/Component/HttpKernel/Fragment/RoutableFragmentRenderer.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,17 @@ public function setFragmentPath($path)
4040
* Generates a fragment URI for a given controller.
4141
*
4242
* @param ControllerReference $reference A ControllerReference instance
43-
* @param Request $request A Request instance
43+
* @param Request $request A Request instance
44+
* @param Boolean $strict Whether to allow non-scalar attributes or not
4445
*
4546
* @return string A fragment URI
4647
*/
47-
protected function generateFragmentUri(ControllerReference $reference, Request $request)
48+
protected function generateFragmentUri(ControllerReference $reference, Request $request, $strict = true)
4849
{
50+
if ($strict) {
51+
$this->checkNonScalar($reference->attributes);
52+
}
53+
4954
if (!isset($reference->attributes['_format'])) {
5055
$reference->attributes['_format'] = $request->getRequestFormat();
5156
}
@@ -56,4 +61,15 @@ protected function generateFragmentUri(ControllerReference $reference, Request $
5661

5762
return $request->getUriForPath($this->fragmentPath.'?'.http_build_query($reference->query, '', '&'));
5863
}
64+
65+
private function checkNonScalar($values)
66+
{
67+
foreach ($values as $key => $value) {
68+
if (is_array($value)) {
69+
$this->checkNonScalar($value);
70+
} elseif (!is_scalar($value)) {
71+
throw new \LogicException(sprintf('Controller attributes cannot contain non-scalar values (value for key "%s" is not a scalar).', $key));
72+
}
73+
}
74+
}
5975
}

src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,24 @@ public function testRenderWithObjectsAsAttributes()
6767
$strategy->render(new ControllerReference('main_controller', array('object' => $object), array()), Request::create('/'));
6868
}
6969

70+
public function testRenderWithObjectsAsAttributesPassedAsObjectsInTheController()
71+
{
72+
$resolver = $this->getMock('Symfony\\Component\\HttpKernel\\Controller\\ControllerResolver', array('getController'));
73+
$resolver
74+
->expects($this->once())
75+
->method('getController')
76+
->will($this->returnValue(function (\stdClass $object, Bar $object1) {
77+
return new Response($object1->getBar());
78+
}))
79+
;
80+
81+
$kernel = new HttpKernel(new EventDispatcher(), $resolver);
82+
$renderer = new InlineFragmentRenderer($kernel);
83+
84+
$response = $renderer->render(new ControllerReference('main_controller', array('object' => new \stdClass(), 'object1' => new Bar()), array()), Request::create('/'));
85+
$this->assertEquals('bar', $response->getContent());
86+
}
87+
7088
/**
7189
* @expectedException \RuntimeException
7290
*/
@@ -164,3 +182,12 @@ public function testESIHeaderIsKeptInSubrequest()
164182
$strategy->render('/', $request);
165183
}
166184
}
185+
186+
class Bar {
187+
public $bar = 'bar';
188+
189+
public function getBar()
190+
{
191+
return $this->bar;
192+
}
193+
}

src/Symfony/Component/HttpKernel/Tests/Fragment/RoutableFragmentRendererTest.php

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
use Symfony\Component\HttpFoundation\Request;
1515
use Symfony\Component\HttpKernel\Controller\ControllerReference;
16-
use Symfony\Component\HttpKernel\Fragment\RoutableFragmentRenderer;
1716

1817
class RoutableFragmentRendererTest extends \PHPUnit_Framework_TestCase
1918
{
@@ -22,7 +21,7 @@ class RoutableFragmentRendererTest extends \PHPUnit_Framework_TestCase
2221
*/
2322
public function testGenerateFragmentUri($uri, $controller)
2423
{
25-
$this->assertEquals($uri, $this->getRenderer()->doGenerateFragmentUri($controller, Request::create('/')));
24+
$this->assertEquals($uri, $this->callGenerateFragmentUriMethod($controller, Request::create('/')));
2625
}
2726

2827
public function getGenerateFragmentUriData()
@@ -33,6 +32,7 @@ public function getGenerateFragmentUriData()
3332
array('http://localhost/_fragment?_path=foo%3Dfoo%26_format%3Djson%26_controller%3Dcontroller', new ControllerReference('controller', array('foo' => 'foo', '_format' => 'json'), array())),
3433
array('http://localhost/_fragment?bar=bar&_path=foo%3Dfoo%26_format%3Dhtml%26_controller%3Dcontroller', new ControllerReference('controller', array('foo' => 'foo'), array('bar' => 'bar'))),
3534
array('http://localhost/_fragment?foo=foo&_path=_format%3Dhtml%26_controller%3Dcontroller', new ControllerReference('controller', array(), array('foo' => 'foo'))),
35+
array('http://localhost/_fragment?_path=foo%255B0%255D%3Dfoo%26foo%255B1%255D%3Dbar%26_format%3Dhtml%26_controller%3Dcontroller', new ControllerReference('controller', array('foo' => array('foo', 'bar')), array())),
3636
);
3737
}
3838

@@ -42,22 +42,43 @@ public function testGenerateFragmentUriWithARequest()
4242
$request->attributes->set('_format', 'json');
4343
$controller = new ControllerReference('controller', array(), array());
4444

45-
$this->assertEquals('http://localhost/_fragment?_path=_format%3Djson%26_controller%3Dcontroller', $this->getRenderer()->doGenerateFragmentUri($controller, $request));
45+
$this->assertEquals('http://localhost/_fragment?_path=_format%3Djson%26_controller%3Dcontroller', $this->callGenerateFragmentUriMethod($controller, $request));
4646
}
4747

48-
private function getRenderer()
48+
/**
49+
* @expectedException LogicException
50+
* @dataProvider getGenerateFragmentUriDataWithNonScalar
51+
*/
52+
public function testGenerateFragmentUriWithNonScalar($controller)
53+
{
54+
$this->callGenerateFragmentUriMethod($controller, Request::create('/'));
55+
}
56+
57+
public function getGenerateFragmentUriDataWithNonScalar()
4958
{
50-
return new Renderer();
59+
return array(
60+
array(new ControllerReference('controller', array('foo' => new Foo(), 'bar' => 'bar'), array())),
61+
array(new ControllerReference('controller', array('foo' => array('foo' => 'foo'), 'bar' => array('bar' => new Foo())), array())),
62+
);
63+
}
64+
65+
private function callGenerateFragmentUriMethod(ControllerReference $reference, Request $request)
66+
{
67+
$renderer = $this->getMockForAbstractClass('Symfony\Component\HttpKernel\Fragment\RoutableFragmentRenderer');
68+
$r = new \ReflectionObject($renderer);
69+
$m = $r->getMethod('generateFragmentUri');
70+
$m->setAccessible(true);
71+
72+
return $m->invoke($renderer, $reference, $request);
5173
}
5274
}
5375

54-
class Renderer extends RoutableFragmentRenderer
76+
class Foo
5577
{
56-
public function render($uri, Request $request, array $options = array()) {}
57-
public function getName() {}
78+
public $foo;
5879

59-
public function doGenerateFragmentUri(ControllerReference $reference, Request $request)
80+
public function getFoo()
6081
{
61-
return parent::generateFragmentUri($reference, $request);
82+
return $this->foo;
6283
}
6384
}

0 commit comments

Comments
 (0)