Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added converter manager and converter interface incl. tests
- Loading branch information
Showing
7 changed files
with
310 additions
and
0 deletions.
There are no files selected for viewing
79 changes: 79 additions & 0 deletions
79
src/Symfony/Bundle/FrameworkBundle/Controller/ParamConverterListener.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
<?php | ||
|
||
namespace Symfony\Bundle\FrameworkBundle\Controller; | ||
|
||
use Symfony\Bundle\FrameworkBundle\ParamConverter\ConverterManager; | ||
|
||
use Symfony\Component\HttpFoundation\Request; | ||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; | ||
use Symfony\Component\DependencyInjection\ContainerInterface; | ||
use Symfony\Component\EventDispatcher\EventDispatcher; | ||
use Symfony\Component\EventDispatcher\Event; | ||
|
||
/** | ||
* Converts \ReflectionParameters for Controller actions into Objects if the ReflectionParameter have a class | ||
* (Typehinted). | ||
* | ||
* @author Fabien Potencier <fabien.potencier@symfony-project.org> | ||
* @author Henrik Bjornskov <hb@peytz.dk> | ||
*/ | ||
class ParamConverterListener | ||
{ | ||
/** | ||
* @var ConverterManager | ||
*/ | ||
protected $manager; | ||
|
||
/** | ||
* @param ConverterManager $manager | ||
* @param ContainerInterface $container | ||
*/ | ||
public function __construct(ConverterManager $manager, ContainerInterface $container) | ||
{ | ||
foreach ($container->findTaggedServiceIds('param_converter.converter') as $id => $attributes) { | ||
$priority = isset($attributes['priority']) ? (integer) $attributes['priority'] : 0; | ||
$manager->add($container->get($id), $priority); | ||
} | ||
|
||
$this->manager = $manager; | ||
} | ||
|
||
/** | ||
* @param EventDispatcher $dispatcher | ||
* @param integer $priority = 0 | ||
*/ | ||
public function register(EventDispatcher $dispatcher, $priority = 0) | ||
{ | ||
$dispatcher->connect('core.controller', array($this, 'filterController'), $priority); | ||
} | ||
|
||
/** | ||
* @param Event $event | ||
* @param mixed $controller | ||
* @throws NotFoundHttpException | ||
* @return mixed | ||
*/ | ||
public function filterController(Event $event, $controller) | ||
{ | ||
if (!is_array($controller)) { | ||
return $controller; | ||
} | ||
|
||
$request = $event->get('request'); | ||
$method = new \ReflectionMethod($controller[0], $controller[1]); | ||
|
||
foreach ($method->getParameters() as $param) { | ||
if (null !== $param->getClass() && false === $request->attributes->has($param->getName())) { | ||
try { | ||
$this->manager->apply($request, $param); | ||
} catch (\InvalidArgumentException $e) { | ||
if (false == $param->isOptional()) { | ||
throw new NotFoundHttpException($e->getMessage()); | ||
} | ||
} | ||
} | ||
} | ||
|
||
return $controller; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
src/Symfony/Bundle/FrameworkBundle/ParamConverter/Converter/ConverterInterface.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?php | ||
|
||
namespace Symfony\Bundle\FrameworkBundle\ParamConverter\Converter; | ||
|
||
use Symfony\Component\HttpFoundation\Request; | ||
|
||
interface ConverterInterface | ||
{ | ||
/** | ||
* Convert the \ReflectionPropertt to something else. | ||
* | ||
* @param Request $request | ||
* @param \ReflectionParameter $property | ||
*/ | ||
function apply(Request $request, \ReflectionParameter $parameter); | ||
|
||
/** | ||
* Returns boolean true if the ReflectionProperty is supported. Else false | ||
* | ||
* @param \ReflectionParameter $parameter | ||
* @return boolean | ||
*/ | ||
function supports(\ReflectionClass $class); | ||
} |
81 changes: 81 additions & 0 deletions
81
src/Symfony/Bundle/FrameworkBundle/ParamConverter/ConverterManager.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
<?php | ||
|
||
namespace Symfony\Bundle\FrameworkBundle\ParamConverter; | ||
|
||
use Symfony\Bundle\FrameworkBundle\ParamConverter\Converter\ConverterInterface; | ||
use Symfony\Component\HttpFoundation\Request; | ||
|
||
/** | ||
* ConverterManager | ||
* Keeps track of converters | ||
* | ||
* @author Fabien Potencier <fabien.potencier@symfony-project.com> | ||
* @author Henrik Bjornskov <hb@peytz.dk> | ||
*/ | ||
class ConverterManager | ||
{ | ||
/** | ||
* @var array | ||
*/ | ||
protected $converters = array(); | ||
|
||
/** | ||
* Cycles through all converters and if a converter supports the class it applies | ||
* the converter. If no converter matches the ReflectionParameters::getClass() value | ||
* a InvalidArgumentException is thrown. | ||
* | ||
* @param Request $request | ||
* @param array $reflectionParam An array of ReflectionParameter objects | ||
* @throws InvalidArgumentException | ||
*/ | ||
public function apply(Request $request, \ReflectionParameter $reflectionParam) | ||
{ | ||
$converted = false; | ||
$converters = $this->all(); | ||
$reflectionClass = $reflectionParam->getClass(); | ||
|
||
foreach ($this->all() as $converter) { | ||
if ($converter->supports($reflectionClass)) { | ||
$converter->apply($request, $reflectionParam); | ||
$converted = true; | ||
} | ||
} | ||
|
||
if (true !== $converted) { | ||
throw new \InvalidArgumentException(sprintf('Could not convert attribute "%s" into an instance of "%s"', $reflectionParam->getName(), $reflectionClass->getName())); | ||
} | ||
} | ||
|
||
/** | ||
* Add a converter | ||
* | ||
* @param ConverterInterface $converter | ||
* @param integer $prioriry = 0 | ||
*/ | ||
public function add(ConverterInterface $converter, $priority = 0) | ||
{ | ||
if (!isset($this->converters[$priority])) { | ||
$this->converters[$priority] = array(); | ||
} | ||
|
||
$this->converters[$priority][] = $converter; | ||
} | ||
|
||
/** | ||
* Returns all converters sorted after their priorities | ||
* | ||
* @return array | ||
*/ | ||
public function all() | ||
{ | ||
$all = $this->converters; | ||
$converters = array(); | ||
krsort($this->converters); | ||
|
||
foreach ($all as $c) { | ||
$converters = array_merge($converters, $c); | ||
} | ||
|
||
return $converters; | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
src/Symfony/Bundle/FrameworkBundle/Resources/config/param_converter.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?xml version="1.0" ?> | ||
|
||
<container xmlns="http://www.symfony-project.org/schema/dic/services" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://www.symfony-project.org/schema/dic/services http://www.symfony-project.org/schema/dic/services/services-1.0.xsd"> | ||
|
||
<parameters> | ||
<parameter key="param_converter.converter_manager.class">Symfony\Bundle\FrameworkBundle\ParamConverter\ConverterManager</parameter> | ||
<parameter key="param_converter.controller.param_converter_listener.class">Symfony\Bundle\FrameworkBundle\Controller\ParamConverterListener</parameter> | ||
</parameters> | ||
|
||
<services> | ||
<!-- ConverterManager --> | ||
<service id="param_converter.converter_manager" class="%param_converter.converter_manager.class%" /> | ||
|
||
<!-- ParamConverterListener --> | ||
<service id="param_converter.controller.param_converter_listener" class="%param_converter.controller.param_converter_listener.class%"> | ||
<tag name="kernel.listener" /> | ||
<argument type="service" id="param_converter.converter_manager" /> | ||
<argument type="service" id="service_container" /> | ||
</service> | ||
</services> | ||
</container> |
77 changes: 77 additions & 0 deletions
77
src/Symfony/Bundle/FrameworkBundle/Tests/ParamConverter/ConverterManagerTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
<?php | ||
|
||
namespace Symfony\Bundle\FrameworkBundle\Tests\ParamConverter; | ||
|
||
use Symfony\Component\HttpFoundation\Request; | ||
use Symfony\Bundle\FrameworkBundle\ParamConverter\ConverterManager; | ||
|
||
class ConverterManagerTest extends \PHPUnit_Framework_TestCase | ||
{ | ||
public function testManagerCanContainerConverters() | ||
{ | ||
$manager = new ConverterManager(); | ||
$importantConverter = $this->getConverterInterfaceMock(); | ||
$lessImportantConverter = $this->getConverterInterfaceMock(); | ||
|
||
$manager->add($importantConverter, 10); | ||
|
||
$this->assertEquals($manager->all(), array($importantConverter)); | ||
|
||
$manager->add($lessImportantConverter); | ||
|
||
$this->assertEquals($manager->all(), array( | ||
$importantConverter, | ||
$lessImportantConverter, | ||
)); | ||
} | ||
|
||
/** | ||
* @expectedException InvalidArgumentException | ||
*/ | ||
public function testManagerCantApplyConvertersAndThrowsException() | ||
{ | ||
$request = new Request(); | ||
$parameter = $this->getReflectionParameter(); | ||
|
||
$converter = $this->getConverterInterfaceMock(); | ||
$converter->expects($this->once()) | ||
->method('supports') | ||
->with($parameter->getClass()) | ||
->will($this->returnValue(false)); | ||
|
||
$manager = new ConverterManager(); | ||
$manager->add($converter); | ||
$manager->apply($request, $parameter); | ||
} | ||
|
||
public function testManagerWillApplyConvertersSuccessfully() | ||
{ | ||
$request = new Request(); | ||
$parameter = $this->getReflectionParameter(); | ||
|
||
$converter = $this->getConverterInterfaceMock(); | ||
$converter->expects($this->once()) | ||
->method('supports') | ||
->with($parameter->getClass()) | ||
->will($this->returnValue(true)); | ||
|
||
$converter->expects($this->once()) | ||
->method('apply') | ||
->with($request, $parameter) | ||
->will($this->returnValue(null)); | ||
|
||
$manager = new ConverterManager(); | ||
$manager->add($converter); | ||
$manager->apply($request, $parameter); | ||
} | ||
|
||
private function getReflectionParameter() | ||
{ | ||
return new \ReflectionParameter(array('Symfony\Bundle\FrameworkBundle\Tests\ParamConverter\Fixtures\ConvertableObject', 'typehintedMethod'), 'object'); | ||
} | ||
|
||
private function getConverterInterfaceMock() | ||
{ | ||
return $this->getMock('Symfony\Bundle\FrameworkBundle\ParamConverter\Converter\ConverterInterface'); | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
src/Symfony/Bundle/FrameworkBundle/Tests/ParamConverter/Fixtures/ConvertableObject.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?php | ||
|
||
namespace Symfony\Bundle\FrameworkBundle\Tests\ParamConverter\Fixtures; | ||
|
||
class ConvertableObject | ||
{ | ||
public function typehintedMethod(ConvertableObject $object) | ||
{ | ||
} | ||
} |