/** * {@inheritdoc} * * Orders collection by properties. The order of the ordered properties is the same as the order specified in the * query. * For each property passed, if the resource does not have such property or if the order value is different from * `asc` or `desc` (case insensitive), the property is ignored. */ public function apply(ResourceInterface $resource, QueryBuilder $queryBuilder) { $request = $this->requestStack->getCurrentRequest(); if (null === $request) { return; } $properties = $this->extractProperties($request); foreach ($properties as $property => $order) { if (!$this->isPropertyEnabled($property) || !$this->isPropertyMapped($property, $resource)) { continue; } if (empty($order) && isset($this->properties[$property])) { $order = $this->properties[$property]; } $order = strtoupper($order); if (!in_array($order, ['ASC', 'DESC'])) { continue; } $alias = 'o'; $field = $property; if ($this->isPropertyNested($property)) { $propertyParts = $this->splitPropertyParts($property); $parentAlias = $alias; foreach ($propertyParts['associations'] as $association) { $alias = QueryNameGenerator::generateJoinAlias($association); $queryBuilder->leftJoin(sprintf('%s.%s', $parentAlias, $association), $alias); $parentAlias = $alias; } $field = $propertyParts['field']; } $queryBuilder->addOrderBy(sprintf('%s.%s', $alias, $field), $order); } }
/** * Determines whether the query builder has ORDER BY on entity joined through * to-many association. * * @param QueryBuilder $queryBuilder * @param ManagerRegistry $managerRegistry * * @return bool */ public static function hasOrderByOnToManyJoin(QueryBuilder $queryBuilder, ManagerRegistry $managerRegistry) { if (empty($orderByParts = $queryBuilder->getDQLPart('orderBy')) || empty($joinParts = $queryBuilder->getDQLPart('join'))) { return false; } $orderByAliases = []; foreach ($orderByParts as $orderBy) { $parts = QueryNameGenerator::getOrderByParts($orderBy); foreach ($parts as $part) { if (false !== ($pos = strpos($part, '.'))) { $alias = substr($part, 0, $pos); $orderByAliases[$alias] = true; } } } if (!empty($orderByAliases)) { foreach ($joinParts as $rootAlias => $joins) { foreach ($joins as $join) { $alias = QueryNameGenerator::getJoinAlias($join); if (isset($orderByAliases[$alias])) { $relationship = QueryNameGenerator::getJoinRelationship($join); $relationshipParts = explode('.', $relationship); $parentAlias = $relationshipParts[0]; $association = $relationshipParts[1]; $parentMetadata = QueryNameGenerator::getClassMetadataFromJoinAlias($parentAlias, $queryBuilder, $managerRegistry); if ($parentMetadata->isCollectionValuedAssociation($association)) { return true; } } } } } return false; }
/** * Adds where clause according to the strategy. * * @param string $strategy * @param QueryBuilder $queryBuilder * @param string $alias * @param string $field * @param string $value * * @return string * * @throws InvalidArgumentException If strategy does not exist */ private function addWhereByStrategy($strategy, QueryBuilder $queryBuilder, $alias, $field, $value) { $valueParameter = QueryNameGenerator::generateParameterName($field); switch ($strategy) { case null: case self::STRATEGY_EXACT: return $queryBuilder->andWhere(sprintf('%s.%s = :%s', $alias, $field, $valueParameter))->setParameter($valueParameter, $value); case self::STRATEGY_PARTIAL: return $queryBuilder->andWhere(sprintf('%s.%s LIKE :%s', $alias, $field, $valueParameter))->setParameter($valueParameter, sprintf('%%%s%%', $value)); case self::STRATEGY_START: return $queryBuilder->andWhere(sprintf('%s.%s LIKE :%s', $alias, $field, $valueParameter))->setParameter($valueParameter, sprintf('%s%%', $value)); case self::STRATEGY_END: return $queryBuilder->andWhere(sprintf('%s.%s LIKE :%s', $alias, $field, $valueParameter))->setParameter($valueParameter, sprintf('%%%s', $value)); case self::STRATEGY_WORD_START: return $queryBuilder->andWhere(sprintf('%1$s.%2$s LIKE :%3$s_1 OR %1$s.%2$s LIKE :%3$s_2', $alias, $field, $valueParameter))->setParameter(sprintf('%s_1', $valueParameter), sprintf('%s%%', $value))->setParameter(sprintf('%s_2', $valueParameter), sprintf('%% %s%%', $value)); } throw new InvalidArgumentException(sprintf('strategy %s does not exist.', $strategy)); }
/** * Adds the where clause according to the chosen null management. * * @param QueryBuilder $queryBuilder * @param string $alias * @param string $field * @param string $operator * @param string $value * @param int|null $nullManagement */ private function addWhere(QueryBuilder $queryBuilder, $alias, $field, $operator, $value, $nullManagement) { $valueParameter = QueryNameGenerator::generateParameterName(sprintf('%s_%s', $field, $operator)); $baseWhere = sprintf('%s.%s %s :%s', $alias, $field, self::PARAMETER_BEFORE === $operator ? '<=' : '>=', $valueParameter); if (null === $nullManagement || self::EXCLUDE_NULL === $nullManagement) { $queryBuilder->andWhere($baseWhere); } elseif (self::PARAMETER_BEFORE === $operator && self::INCLUDE_NULL_BEFORE === $nullManagement || self::PARAMETER_AFTER === $operator && self::INCLUDE_NULL_AFTER === $nullManagement) { $queryBuilder->andWhere($queryBuilder->expr()->orX($baseWhere, $queryBuilder->expr()->isNull(sprintf('%s.%s', $alias, $field)))); } else { $queryBuilder->andWhere($queryBuilder->expr()->andX($baseWhere, $queryBuilder->expr()->isNotNull(sprintf('%s.%s', $alias, $field)))); } $queryBuilder->setParameter($valueParameter, new \DateTime($value)); }