vendor/symfony/doctrine-bridge/Form/ChoiceList/ORMQueryBuilderLoader.php line 49

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <[email protected]>
  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\DBAL\ArrayParameterType;
  12. use Doctrine\DBAL\Connection;
  13. use Doctrine\DBAL\Types\ConversionException;
  14. use Doctrine\DBAL\Types\Type;
  15. use Doctrine\ORM\QueryBuilder;
  16. use Symfony\Component\Form\Exception\TransformationFailedException;
  17. /**
  18. * Loads entities using a {@link QueryBuilder} instance.
  19. *
  20. * @author Benjamin Eberlei <[email protected]>
  21. * @author Bernhard Schussek <[email protected]>
  22. */
  23. class ORMQueryBuilderLoader implements EntityLoaderInterface
  24. {
  25. /**
  26. * Contains the query builder that builds the query for fetching the
  27. * entities.
  28. *
  29. * This property should only be accessed through queryBuilder.
  30. *
  31. * @var QueryBuilder
  32. */
  33. private $queryBuilder;
  34. public function __construct(QueryBuilder $queryBuilder)
  35. {
  36. $this->queryBuilder = $queryBuilder;
  37. }
  38. /**
  39. * {@inheritdoc}
  40. */
  41. public function getEntities()
  42. {
  43. return $this->queryBuilder->getQuery()->execute();
  44. }
  45. /**
  46. * {@inheritdoc}
  47. */
  48. public function getEntitiesByIds(string $identifier, array $values)
  49. {
  50. if (null !== $this->queryBuilder->getMaxResults() || 0 < (int) $this->queryBuilder->getFirstResult()) {
  51. // an offset or a limit would apply on results including the where clause with submitted id values
  52. // that could make invalid choices valid
  53. $choices = [];
  54. $metadata = $this->queryBuilder->getEntityManager()->getClassMetadata(current($this->queryBuilder->getRootEntities()));
  55. foreach ($this->getEntities() as $entity) {
  56. if (\in_array((string) current($metadata->getIdentifierValues($entity)), $values, true)) {
  57. $choices[] = $entity;
  58. }
  59. }
  60. return $choices;
  61. }
  62. $qb = clone $this->queryBuilder;
  63. $alias = current($qb->getRootAliases());
  64. $parameter = 'ORMQueryBuilderLoader_getEntitiesByIds_'.$identifier;
  65. $parameter = str_replace('.', '_', $parameter);
  66. $where = $qb->expr()->in($alias.'.'.$identifier, ':'.$parameter);
  67. // Guess type
  68. $entity = current($qb->getRootEntities());
  69. $metadata = $qb->getEntityManager()->getClassMetadata($entity);
  70. if (\in_array($type = $metadata->getTypeOfField($identifier), ['integer', 'bigint', 'smallint'])) {
  71. $parameterType = class_exists(ArrayParameterType::class) ? ArrayParameterType::INTEGER : Connection::PARAM_INT_ARRAY;
  72. // Filter out non-integer values (e.g. ""). If we don't, some
  73. // databases such as PostgreSQL fail.
  74. $values = array_values(array_filter($values, function ($v) {
  75. return (string) $v === (string) (int) $v || ctype_digit($v);
  76. }));
  77. } elseif (\in_array($type, ['ulid', 'uuid', 'guid'])) {
  78. $parameterType = class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY;
  79. // Like above, but we just filter out empty strings.
  80. $values = array_values(array_filter($values, function ($v) {
  81. return '' !== (string) $v;
  82. }));
  83. // Convert values into right type
  84. if (Type::hasType($type)) {
  85. $doctrineType = Type::getType($type);
  86. $platform = $qb->getEntityManager()->getConnection()->getDatabasePlatform();
  87. foreach ($values as &$value) {
  88. try {
  89. $value = $doctrineType->convertToDatabaseValue($value, $platform);
  90. } catch (ConversionException $e) {
  91. throw new TransformationFailedException(sprintf('Failed to transform "%s" into "%s".', $value, $type), 0, $e);
  92. }
  93. }
  94. unset($value);
  95. }
  96. } else {
  97. $parameterType = class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY;
  98. }
  99. if (!$values) {
  100. return [];
  101. }
  102. return $qb->andWhere($where)
  103. ->getQuery()
  104. ->setParameter($parameter, $values, $parameterType)
  105. ->getResult();
  106. }
  107. }