diff --git a/Request/ParamConverter/PropelParamConverter.php b/Request/ParamConverter/PropelParamConverter.php index c895aa3..e6128ea 100644 --- a/Request/ParamConverter/PropelParamConverter.php +++ b/Request/ParamConverter/PropelParamConverter.php @@ -10,27 +10,75 @@ use Symfony\Component\HttpFoundation\Request; /** - * PropelConverter. + * PropelParamConverter + * + * This convert action parameter to a Propel Object + * there is two option for this converter: + * + * mapping : take an array of routeParam => column + * exclude : take an array of routeParam to exclude from the conversion process + * * * @author Jérémie Augustin */ class PropelParamConverter implements ParamConverterInterface { + /** + * the pk column (e.g. id) + * @var string + */ + protected $pk; + + /** + * list of column/value to use with filterBy + * @var array + */ + protected $filters = array(); + + /** + * list of route parameters to exclude from the conversion process + * @var array + */ + protected $exclude = array(); public function apply(Request $request, ConfigurationInterface $configuration) { $classQuery = $configuration->getClass() . 'Query'; + $classPeer = $configuration->getClass() . 'Peer'; if (!class_exists($classQuery)) { throw new \Exception(sprintf('The %s Query class does not exist', $classQuery)); } + + $tableMap = $classPeer::getTableMap(); + $pkColumns = $tableMap->getPrimaryKeyColumns(); + + if (count($pkColumns) == 1) { + $this->pk = strtolower($pkColumns[0]->getName()); + } + $options = $configuration->getOptions(); - $exclude = isset($options['exclude'])? $options['exclude'] : array(); + + if (isset($options['mapping'])) { + // We use the mapping for calling findPk or filterBy + foreach ($options['mapping'] as $routeParam => $column) { + if ($request->attributes->has($routeParam)) { + if ($this->pk === $column) { + $this->pk = $routeParam; + } else { + $this->filters[$column] = $request->attributes->get($routeParam); + } + } + } + } else { + $this->exclude = isset($options['exclude'])? $options['exclude'] : array(); + $this->filters = $request->attributes->all(); + } // find by Pk - if (in_array('id', $exclude) || false === $object = $this->findPk($classQuery, $request)) { + if (false === $object = $this->findPk($classQuery, $request)) { // find by criteria - if (false === $object = $this->findOneBy($classQuery, $request, $exclude)) { + if (false === $object = $this->findOneBy($classQuery, $request)) { if ($configuration->isOptional()) { //we find nothing but the object is optional $object = null; @@ -45,25 +93,27 @@ class PropelParamConverter implements ParamConverterInterface } $request->attributes->set($configuration->getName(), $object); + + return true; } protected function findPk($classQuery, Request $request) { - if (!$request->attributes->has('id')) { + if (in_array($this->pk, $this->exclude) || !$request->attributes->has($this->pk)) { return false; } - return $classQuery::create()->findPk($request->attributes->get('id')); + return $classQuery::create()->findPk($request->attributes->get($this->pk)); } - protected function findOneBy($classQuery, Request $request, $exclude) + protected function findOneBy($classQuery, Request $request) { $query = $classQuery::create(); $hasCriteria = false; - foreach ($request->attributes->all() as $key => $value) { - if (!in_array($key, $exclude)) { + foreach ($this->filters as $column => $value) { + if (!in_array($column, $this->exclude)) { try { - $query->{'filterBy' . PropelInflector::camelize($key)}($value); + $query->{'filterBy' . PropelInflector::camelize($column)}($value); $hasCriteria = true; } catch (\PropelException $e) { } } diff --git a/Resources/doc/param_converter.markdown b/Resources/doc/param_converter.markdown index 14b92ed..549431f 100644 --- a/Resources/doc/param_converter.markdown +++ b/Resources/doc/param_converter.markdown @@ -45,5 +45,23 @@ public function myAction(Post $post) } ``` +#### Custom mapping #### + +You can map route parameters directly to model column to be use for filtering. + +If you have a route like `/my-route/{postUniqueName}/{AuthorId}` +Mapping option overwrite any other automatic mapping. + +``` php +assertNull($request->attributes->get('book'), 'param "book" should be null if book is not found and the parameter is optional'); } + + public function testParamConverterFindWithMapping() + { + $paramConverter = new PropelParamConverter(); + $request = new Request(array(), array(), array('toto' => 1, 'book' => null)); + $configuration = new ParamConverter(array('class' => 'Propel\PropelBundle\Tests\Fixtures\Model\Book', + 'name' => 'book', + 'options' => array('mapping' => array('toto' => 'id')) + )); + $paramConverter->apply($request, $configuration); + $this->assertInstanceOf('Propel\PropelBundle\Tests\Fixtures\Model\Book',$request->attributes->get('book'), + 'param "book" should be an instance of "Propel\PropelBundle\Tests\Fixtures\Model\Book"'); + } + + public function testParamConverterFindSlugWithMapping() + { + $paramConverter = new PropelParamConverter(); + $request = new Request(array(), array(), array('slugParam_special' => 'my-book', 'book' => null)); + $configuration = new ParamConverter(array('class' => 'Propel\PropelBundle\Tests\Fixtures\Model\Book', + 'name' => 'book', + 'options' => array('mapping' => array('slugParam_special' => 'slug')) + )); + $paramConverter->apply($request, $configuration); + $this->assertInstanceOf('Propel\PropelBundle\Tests\Fixtures\Model\Book',$request->attributes->get('book'), + 'param "book" should be an instance of "Propel\PropelBundle\Tests\Fixtures\Model\Book"'); + } }