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

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. use Symfony\Component\PropertyAccess\PropertyPathInterface;
  19. /**
  20.  * Adds property path support to a choice list factory.
  21.  *
  22.  * Pass the decorated factory to the constructor:
  23.  *
  24.  *     $decorator = new PropertyAccessDecorator($factory);
  25.  *
  26.  * You can now pass property paths for generating choice values, labels, view
  27.  * indices, HTML attributes and for determining the preferred choices and the
  28.  * choice groups:
  29.  *
  30.  *     // extract values from the $value property
  31.  *     $list = $createListFromChoices($objects, 'value');
  32.  *
  33.  * @author Bernhard Schussek <bschussek@gmail.com>
  34.  */
  35. class PropertyAccessDecorator implements ChoiceListFactoryInterface
  36. {
  37.     private $decoratedFactory;
  38.     private $propertyAccessor;
  39.     public function __construct(ChoiceListFactoryInterface $decoratedFactoryPropertyAccessorInterface $propertyAccessor null)
  40.     {
  41.         $this->decoratedFactory $decoratedFactory;
  42.         $this->propertyAccessor $propertyAccessor ?: PropertyAccess::createPropertyAccessor();
  43.     }
  44.     /**
  45.      * Returns the decorated factory.
  46.      */
  47.     public function getDecoratedFactory(): ChoiceListFactoryInterface
  48.     {
  49.         return $this->decoratedFactory;
  50.     }
  51.     /**
  52.      * {@inheritdoc}
  53.      */
  54.     public function createListFromChoices(iterable $choicesmixed $value nullmixed $filter null): ChoiceListInterface
  55.     {
  56.         if (\is_string($value)) {
  57.             $value = new PropertyPath($value);
  58.         }
  59.         if ($value instanceof PropertyPathInterface) {
  60.             $accessor $this->propertyAccessor;
  61.             $value = function ($choice) use ($accessor$value) {
  62.                 // The callable may be invoked with a non-object/array value
  63.                 // when such values are passed to
  64.                 // ChoiceListInterface::getValuesForChoices(). Handle this case
  65.                 // so that the call to getValue() doesn't break.
  66.                 return \is_object($choice) || \is_array($choice) ? $accessor->getValue($choice$value) : null;
  67.             };
  68.         }
  69.         if (\is_string($filter)) {
  70.             $filter = new PropertyPath($filter);
  71.         }
  72.         if ($filter instanceof PropertyPath) {
  73.             $accessor $this->propertyAccessor;
  74.             $filter = static function ($choice) use ($accessor$filter) {
  75.                 return (\is_object($choice) || \is_array($choice)) && $accessor->getValue($choice$filter);
  76.             };
  77.         }
  78.         return $this->decoratedFactory->createListFromChoices($choices$value$filter);
  79.     }
  80.     /**
  81.      * {@inheritdoc}
  82.      */
  83.     public function createListFromLoader(ChoiceLoaderInterface $loadermixed $value nullmixed $filter null): ChoiceListInterface
  84.     {
  85.         if (\is_string($value)) {
  86.             $value = new PropertyPath($value);
  87.         }
  88.         if ($value instanceof PropertyPathInterface) {
  89.             $accessor $this->propertyAccessor;
  90.             $value = function ($choice) use ($accessor$value) {
  91.                 // The callable may be invoked with a non-object/array value
  92.                 // when such values are passed to
  93.                 // ChoiceListInterface::getValuesForChoices(). Handle this case
  94.                 // so that the call to getValue() doesn't break.
  95.                 return \is_object($choice) || \is_array($choice) ? $accessor->getValue($choice$value) : null;
  96.             };
  97.         }
  98.         if (\is_string($filter)) {
  99.             $filter = new PropertyPath($filter);
  100.         }
  101.         if ($filter instanceof PropertyPath) {
  102.             $accessor $this->propertyAccessor;
  103.             $filter = static function ($choice) use ($accessor$filter) {
  104.                 return (\is_object($choice) || \is_array($choice)) && $accessor->getValue($choice$filter);
  105.             };
  106.         }
  107.         return $this->decoratedFactory->createListFromLoader($loader$value$filter);
  108.     }
  109.     /**
  110.      * {@inheritdoc}
  111.      */
  112.     public function createView(ChoiceListInterface $listmixed $preferredChoices nullmixed $label nullmixed $index nullmixed $groupBy nullmixed $attr nullmixed $labelTranslationParameters = []): ChoiceListView
  113.     {
  114.         $accessor $this->propertyAccessor;
  115.         if (\is_string($label)) {
  116.             $label = new PropertyPath($label);
  117.         }
  118.         if ($label instanceof PropertyPathInterface) {
  119.             $label = function ($choice) use ($accessor$label) {
  120.                 return $accessor->getValue($choice$label);
  121.             };
  122.         }
  123.         if (\is_string($preferredChoices)) {
  124.             $preferredChoices = new PropertyPath($preferredChoices);
  125.         }
  126.         if ($preferredChoices instanceof PropertyPathInterface) {
  127.             $preferredChoices = function ($choice) use ($accessor$preferredChoices) {
  128.                 try {
  129.                     return $accessor->getValue($choice$preferredChoices);
  130.                 } catch (UnexpectedTypeException $e) {
  131.                     // Assume not preferred if not readable
  132.                     return false;
  133.                 }
  134.             };
  135.         }
  136.         if (\is_string($index)) {
  137.             $index = new PropertyPath($index);
  138.         }
  139.         if ($index instanceof PropertyPathInterface) {
  140.             $index = function ($choice) use ($accessor$index) {
  141.                 return $accessor->getValue($choice$index);
  142.             };
  143.         }
  144.         if (\is_string($groupBy)) {
  145.             $groupBy = new PropertyPath($groupBy);
  146.         }
  147.         if ($groupBy instanceof PropertyPathInterface) {
  148.             $groupBy = function ($choice) use ($accessor$groupBy) {
  149.                 try {
  150.                     return $accessor->getValue($choice$groupBy);
  151.                 } catch (UnexpectedTypeException $e) {
  152.                     // Don't group if path is not readable
  153.                     return null;
  154.                 }
  155.             };
  156.         }
  157.         if (\is_string($attr)) {
  158.             $attr = new PropertyPath($attr);
  159.         }
  160.         if ($attr instanceof PropertyPathInterface) {
  161.             $attr = function ($choice) use ($accessor$attr) {
  162.                 return $accessor->getValue($choice$attr);
  163.             };
  164.         }
  165.         if (\is_string($labelTranslationParameters)) {
  166.             $labelTranslationParameters = new PropertyPath($labelTranslationParameters);
  167.         }
  168.         if ($labelTranslationParameters instanceof PropertyPath) {
  169.             $labelTranslationParameters = static function ($choice) use ($accessor$labelTranslationParameters) {
  170.                 return $accessor->getValue($choice$labelTranslationParameters);
  171.             };
  172.         }
  173.         return $this->decoratedFactory->createView(
  174.             $list,
  175.             $preferredChoices,
  176.             $label,
  177.             $index,
  178.             $groupBy,
  179.             $attr,
  180.             $labelTranslationParameters
  181.         );
  182.     }
  183. }