vendor/symfony/form/ChoiceList/Factory/PropertyAccessDecorator.php line 190

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\Form\ChoiceList\Factory;
  11. use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
  12. use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface;
  13. use Symfony\Component\Form\ChoiceList\View\ChoiceListView;
  14. use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException;
  15. use Symfony\Component\PropertyAccess\PropertyAccess;
  16. use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
  17. use Symfony\Component\PropertyAccess\PropertyPath;
  18. /**
  19.  * Adds property path support to a choice list factory.
  20.  *
  21.  * Pass the decorated factory to the constructor:
  22.  *
  23.  *     $decorator = new PropertyAccessDecorator($factory);
  24.  *
  25.  * You can now pass property paths for generating choice values, labels, view
  26.  * indices, HTML attributes and for determining the preferred choices and the
  27.  * choice groups:
  28.  *
  29.  *     // extract values from the $value property
  30.  *     $list = $createListFromChoices($objects, 'value');
  31.  *
  32.  * @author Bernhard Schussek <bschussek@gmail.com>
  33.  */
  34. class PropertyAccessDecorator implements ChoiceListFactoryInterface
  35. {
  36.     private $decoratedFactory;
  37.     private $propertyAccessor;
  38.     public function __construct(ChoiceListFactoryInterface $decoratedFactoryPropertyAccessorInterface $propertyAccessor null)
  39.     {
  40.         $this->decoratedFactory $decoratedFactory;
  41.         $this->propertyAccessor $propertyAccessor ?: PropertyAccess::createPropertyAccessor();
  42.     }
  43.     /**
  44.      * Returns the decorated factory.
  45.      *
  46.      * @return ChoiceListFactoryInterface The decorated factory
  47.      */
  48.     public function getDecoratedFactory()
  49.     {
  50.         return $this->decoratedFactory;
  51.     }
  52.     /**
  53.      * {@inheritdoc}
  54.      *
  55.      * @param callable|string|PropertyPath|null $value The callable or path for
  56.      *                                                 generating the choice values
  57.      *
  58.      * @return ChoiceListInterface The choice list
  59.      */
  60.     public function createListFromChoices(iterable $choices$value null)
  61.     {
  62.         if (\is_string($value)) {
  63.             $value = new PropertyPath($value);
  64.         }
  65.         if ($value instanceof PropertyPath) {
  66.             $accessor $this->propertyAccessor;
  67.             $value = function ($choice) use ($accessor$value) {
  68.                 // The callable may be invoked with a non-object/array value
  69.                 // when such values are passed to
  70.                 // ChoiceListInterface::getValuesForChoices(). Handle this case
  71.                 // so that the call to getValue() doesn't break.
  72.                 return \is_object($choice) || \is_array($choice) ? $accessor->getValue($choice$value) : null;
  73.             };
  74.         }
  75.         return $this->decoratedFactory->createListFromChoices($choices$value);
  76.     }
  77.     /**
  78.      * {@inheritdoc}
  79.      *
  80.      * @param callable|string|PropertyPath|null $value The callable or path for
  81.      *                                                 generating the choice values
  82.      *
  83.      * @return ChoiceListInterface The choice list
  84.      */
  85.     public function createListFromLoader(ChoiceLoaderInterface $loader$value null)
  86.     {
  87.         if (\is_string($value)) {
  88.             $value = new PropertyPath($value);
  89.         }
  90.         if ($value instanceof PropertyPath) {
  91.             $accessor $this->propertyAccessor;
  92.             $value = function ($choice) use ($accessor$value) {
  93.                 // The callable may be invoked with a non-object/array value
  94.                 // when such values are passed to
  95.                 // ChoiceListInterface::getValuesForChoices(). Handle this case
  96.                 // so that the call to getValue() doesn't break.
  97.                 return \is_object($choice) || \is_array($choice) ? $accessor->getValue($choice$value) : null;
  98.             };
  99.         }
  100.         return $this->decoratedFactory->createListFromLoader($loader$value);
  101.     }
  102.     /**
  103.      * {@inheritdoc}
  104.      *
  105.      * @param array|callable|string|PropertyPath|null $preferredChoices The preferred choices
  106.      * @param callable|string|PropertyPath|null       $label            The callable or path generating the choice labels
  107.      * @param callable|string|PropertyPath|null       $index            The callable or path generating the view indices
  108.      * @param callable|string|PropertyPath|null       $groupBy          The callable or path generating the group names
  109.      * @param array|callable|string|PropertyPath|null $attr             The callable or path generating the HTML attributes
  110.      *
  111.      * @return ChoiceListView The choice list view
  112.      */
  113.     public function createView(ChoiceListInterface $list$preferredChoices null$label null$index null$groupBy null$attr null)
  114.     {
  115.         $accessor $this->propertyAccessor;
  116.         if (\is_string($label)) {
  117.             $label = new PropertyPath($label);
  118.         }
  119.         if ($label instanceof PropertyPath) {
  120.             $label = function ($choice) use ($accessor$label) {
  121.                 return $accessor->getValue($choice$label);
  122.             };
  123.         }
  124.         if (\is_string($preferredChoices)) {
  125.             $preferredChoices = new PropertyPath($preferredChoices);
  126.         }
  127.         if ($preferredChoices instanceof PropertyPath) {
  128.             $preferredChoices = function ($choice) use ($accessor$preferredChoices) {
  129.                 try {
  130.                     return $accessor->getValue($choice$preferredChoices);
  131.                 } catch (UnexpectedTypeException $e) {
  132.                     // Assume not preferred if not readable
  133.                     return false;
  134.                 }
  135.             };
  136.         }
  137.         if (\is_string($index)) {
  138.             $index = new PropertyPath($index);
  139.         }
  140.         if ($index instanceof PropertyPath) {
  141.             $index = function ($choice) use ($accessor$index) {
  142.                 return $accessor->getValue($choice$index);
  143.             };
  144.         }
  145.         if (\is_string($groupBy)) {
  146.             $groupBy = new PropertyPath($groupBy);
  147.         }
  148.         if ($groupBy instanceof PropertyPath) {
  149.             $groupBy = function ($choice) use ($accessor$groupBy) {
  150.                 try {
  151.                     return $accessor->getValue($choice$groupBy);
  152.                 } catch (UnexpectedTypeException $e) {
  153.                     // Don't group if path is not readable
  154.                     return null;
  155.                 }
  156.             };
  157.         }
  158.         if (\is_string($attr)) {
  159.             $attr = new PropertyPath($attr);
  160.         }
  161.         if ($attr instanceof PropertyPath) {
  162.             $attr = function ($choice) use ($accessor$attr) {
  163.                 return $accessor->getValue($choice$attr);
  164.             };
  165.         }
  166.         return $this->decoratedFactory->createView($list$preferredChoices$label$index$groupBy$attr);
  167.     }
  168. }