vendor/symfony/doctrine-bridge/Form/ChoiceList/DoctrineChoiceLoader.php line 55

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\Bridge\Doctrine\Form\ChoiceList;
  11. use Doctrine\Persistence\ObjectManager;
  12. use Symfony\Component\Form\ChoiceList\Loader\AbstractChoiceLoader;
  13. /**
  14.  * Loads choices using a Doctrine object manager.
  15.  *
  16.  * @author Bernhard Schussek <bschussek@gmail.com>
  17.  */
  18. class DoctrineChoiceLoader extends AbstractChoiceLoader
  19. {
  20.     private $manager;
  21.     private $class;
  22.     private $idReader;
  23.     private $objectLoader;
  24.     /**
  25.      * Creates a new choice loader.
  26.      *
  27.      * Optionally, an implementation of {@link EntityLoaderInterface} can be
  28.      * passed which optimizes the object loading for one of the Doctrine
  29.      * mapper implementations.
  30.      *
  31.      * @param string $class The class name of the loaded objects
  32.      */
  33.     public function __construct(ObjectManager $managerstring $classIdReader $idReader nullEntityLoaderInterface $objectLoader null)
  34.     {
  35.         $classMetadata $manager->getClassMetadata($class);
  36.         if ($idReader && !$idReader->isSingleId()) {
  37.             throw new \InvalidArgumentException(sprintf('The second argument `$idReader` of "%s" must be null when the query cannot be optimized because of composite id fields.'__METHOD__));
  38.         }
  39.         $this->manager $manager;
  40.         $this->class $classMetadata->getName();
  41.         $this->idReader $idReader;
  42.         $this->objectLoader $objectLoader;
  43.     }
  44.     /**
  45.      * {@inheritdoc}
  46.      */
  47.     protected function loadChoices(): iterable
  48.     {
  49.         return $this->objectLoader
  50.             $this->objectLoader->getEntities()
  51.             : $this->manager->getRepository($this->class)->findAll();
  52.     }
  53.     /**
  54.      * @internal to be remove in Symfony 6
  55.      */
  56.     protected function doLoadValuesForChoices(array $choices): array
  57.     {
  58.         // Optimize performance for single-field identifiers. We already
  59.         // know that the IDs are used as values
  60.         // Attention: This optimization does not check choices for existence
  61.         if ($this->idReader) {
  62.             trigger_deprecation('symfony/doctrine-bridge''5.1''Not defining explicitly the IdReader as value callback when query can be optimized is deprecated. Don\'t pass the IdReader to "%s" or define the "choice_value" option instead.'__CLASS__);
  63.             // Maintain order and indices of the given objects
  64.             $values = [];
  65.             foreach ($choices as $i => $object) {
  66.                 if ($object instanceof $this->class) {
  67.                     $values[$i] = $this->idReader->getIdValue($object);
  68.                 }
  69.             }
  70.             return $values;
  71.         }
  72.         return parent::doLoadValuesForChoices($choices);
  73.     }
  74.     protected function doLoadChoicesForValues(array $values, ?callable $value): array
  75.     {
  76.         $legacy $this->idReader && null === $value;
  77.         if ($legacy) {
  78.             trigger_deprecation('symfony/doctrine-bridge''5.1''Not defining explicitly the IdReader as value callback when query can be optimized is deprecated. Don\'t pass the IdReader to "%s" or define the "choice_value" option instead.'__CLASS__);
  79.         }
  80.         $idReader null;
  81.         if (\is_array($value) && $value[0] instanceof IdReader) {
  82.             $idReader $value[0];
  83.         } elseif ($value instanceof \Closure && ($rThis = (new \ReflectionFunction($value))->getClosureThis()) instanceof IdReader) {
  84.             $idReader $rThis;
  85.         } elseif ($legacy) {
  86.             $idReader $this->idReader;
  87.         }
  88.         // Optimize performance in case we have an object loader and
  89.         // a single-field identifier
  90.         if ($idReader && $this->objectLoader) {
  91.             $objects = [];
  92.             $objectsById = [];
  93.             // Maintain order and indices from the given $values
  94.             // An alternative approach to the following loop is to add the
  95.             // "INDEX BY" clause to the Doctrine query in the loader,
  96.             // but I'm not sure whether that's doable in a generic fashion.
  97.             foreach ($this->objectLoader->getEntitiesByIds($idReader->getIdField(), $values) as $object) {
  98.                 $objectsById[$idReader->getIdValue($object)] = $object;
  99.             }
  100.             foreach ($values as $i => $id) {
  101.                 if (isset($objectsById[$id])) {
  102.                     $objects[$i] = $objectsById[$id];
  103.                 }
  104.             }
  105.             return $objects;
  106.         }
  107.         return parent::doLoadChoicesForValues($values$value);
  108.     }
  109. }