vendor/lexik/form-filter-bundle/Event/Subscriber/DoctrineORMSubscriber.php line 67

Open in your IDE?
  1. <?php
  2. namespace Lexik\Bundle\FormFilterBundle\Event\Subscriber;
  3. use Doctrine\Common\Collections\Collection;
  4. use Doctrine\DBAL\Connection;
  5. use Doctrine\DBAL\Types\Types;
  6. use Doctrine\ORM\EntityManagerInterface;
  7. use Doctrine\ORM\QueryBuilder;
  8. use Doctrine\ORM\Mapping\ClassMetadataInfo;
  9. use Lexik\Bundle\FormFilterBundle\Event\GetFilterConditionEvent;
  10. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  11. /**
  12. * Register listeners to compute conditions to be applied on a Doctrine ORM query builder.
  13. *
  14. * @author Cédric Girard <[email protected]>
  15. */
  16. class DoctrineORMSubscriber extends AbstractDoctrineSubscriber implements EventSubscriberInterface
  17. {
  18. /**
  19. * @return array
  20. */
  21. public static function getSubscribedEvents()
  22. {
  23. return array(
  24. // Lexik form filter types
  25. 'lexik_form_filter.apply.orm.filter_boolean' => array('filterBoolean'),
  26. 'lexik_form_filter.apply.orm.filter_checkbox' => array('filterCheckbox'),
  27. 'lexik_form_filter.apply.orm.filter_choice' => array('filterValue'),
  28. 'lexik_form_filter.apply.orm.filter_date' => array('filterDate'),
  29. 'lexik_form_filter.apply.orm.filter_date_range' => array('filterDateRange'),
  30. 'lexik_form_filter.apply.orm.filter_datetime' => array('filterDateTime'),
  31. 'lexik_form_filter.apply.orm.filter_datetime_range' => array('filterDateTimeRange'),
  32. 'lexik_form_filter.apply.orm.filter_entity' => array('filterEntity'),
  33. 'lexik_form_filter.apply.orm.filter_number' => array('filterNumber'),
  34. 'lexik_form_filter.apply.orm.filter_number_range' => array('filterNumberRange'),
  35. 'lexik_form_filter.apply.orm.filter_text' => array('filterText'),
  36. // Symfony types
  37. 'lexik_form_filter.apply.orm.text' => array('filterText'),
  38. 'lexik_form_filter.apply.orm.email' => array('filterValue'),
  39. 'lexik_form_filter.apply.orm.integer' => array('filterValue'),
  40. 'lexik_form_filter.apply.orm.money' => array('filterValue'),
  41. 'lexik_form_filter.apply.orm.number' => array('filterValue'),
  42. 'lexik_form_filter.apply.orm.percent' => array('filterValue'),
  43. 'lexik_form_filter.apply.orm.search' => array('filterValue'),
  44. 'lexik_form_filter.apply.orm.url' => array('filterValue'),
  45. 'lexik_form_filter.apply.orm.choice' => array('filterValue'),
  46. 'lexik_form_filter.apply.orm.entity' => array('filterEntity'),
  47. 'lexik_form_filter.apply.orm.country' => array('filterValue'),
  48. 'lexik_form_filter.apply.orm.language' => array('filterValue'),
  49. 'lexik_form_filter.apply.orm.locale' => array('filterValue'),
  50. 'lexik_form_filter.apply.orm.timezone' => array('filterValue'),
  51. 'lexik_form_filter.apply.orm.date' => array('filterDate'),
  52. 'lexik_form_filter.apply.orm.datetime' => array('filterDate'),
  53. 'lexik_form_filter.apply.orm.birthday' => array('filterDate'),
  54. 'lexik_form_filter.apply.orm.checkbox' => array('filterValue'),
  55. 'lexik_form_filter.apply.orm.radio' => array('filterValue'),
  56. );
  57. }
  58. /**
  59. * @param GetFilterConditionEvent $event
  60. * @throws \Exception
  61. */
  62. public function filterEntity(GetFilterConditionEvent $event)
  63. {
  64. $expr = $event->getFilterQuery()->getExpr();
  65. $values = $event->getValues();
  66. if (is_object($values['value'])) {
  67. $paramName = $this->generateParameterName($event->getField());
  68. $filterField = $event->getField();
  69. /** @var QueryBuilder $queryBuilder */
  70. $queryBuilder = $event->getQueryBuilder();
  71. if ($dqlFrom = $event->getQueryBuilder()->getDQLPart('from')) {
  72. $rootPart = reset($dqlFrom);
  73. $fieldName = ltrim($event->getField(), $rootPart->getAlias() . '.');
  74. $metadata = $queryBuilder->getEntityManager()->getClassMetadata($rootPart->getFrom());
  75. if (isset($metadata->associationMappings[$fieldName]) && (!$metadata->associationMappings[$fieldName]['isOwningSide'] || $metadata->associationMappings[$fieldName]['type'] === ClassMetadataInfo::MANY_TO_MANY)) {
  76. if (!$event->getFilterQuery()->hasJoinAlias($fieldName)) {
  77. $queryBuilder->leftJoin($event->getField(), $fieldName);
  78. }
  79. $filterField = $fieldName;
  80. }
  81. }
  82. if ($values['value'] instanceof Collection) {
  83. $ids = array();
  84. foreach ($values['value'] as $value) {
  85. $ids[] = $this->getEntityIdentifier($value, $queryBuilder->getEntityManager());
  86. }
  87. if (count($ids) > 0) {
  88. $event->setCondition(
  89. $expr->in($filterField, ':'.$paramName),
  90. array($paramName => array($ids, Connection::PARAM_INT_ARRAY))
  91. );
  92. }
  93. } else {
  94. $event->setCondition(
  95. $expr->eq($filterField, ':'.$paramName),
  96. array($paramName => array(
  97. $this->getEntityIdentifier($values['value'], $queryBuilder->getEntityManager()),
  98. Types::INTEGER
  99. ))
  100. );
  101. }
  102. }
  103. }
  104. /**
  105. * @param object $value
  106. * @return integer
  107. * @throws \RuntimeException
  108. */
  109. protected function getEntityIdentifier($value, EntityManagerInterface $em)
  110. {
  111. $class = get_class($value);
  112. $metadata = $em->getClassMetadata($class);
  113. if ($metadata->isIdentifierComposite) {
  114. throw new \RuntimeException(sprintf('Composite identifier is not supported by FilterEntityType.', $class));
  115. }
  116. $identifierValues = $metadata->getIdentifierValues($value);
  117. if (empty($identifierValues)) {
  118. throw new \RuntimeException(sprintf('Can\'t get identifier value for class "%s".', $class));
  119. }
  120. return array_shift($identifierValues);
  121. }
  122. }