/** * Add a sort rule for this query * * If called without a specific column, the repository's defaul sort rules will be applied. * This notifies the repository about each column being required as filter column. * * @param string $field The name of the column by which to sort the query's result * @param string $direction The direction to use when sorting (asc or desc, default is asc) * @param bool $ignoreDefault Whether to ignore any default sort rules if $field is given * * @return $this */ public function order($field = null, $direction = null, $ignoreDefault = false) { $sortRules = $this->getSortRules(); if ($field === null) { // Use first available sort rule as default if (empty($sortRules)) { // Return early in case of no sort defaults and no given $field return $this; } $sortColumns = reset($sortRules); if (!array_key_exists('columns', $sortColumns)) { $sortColumns['columns'] = array(key($sortRules)); } if ($direction !== null || !array_key_exists('order', $sortColumns)) { $sortColumns['order'] = $direction ?: static::SORT_ASC; } } else { $alias = $this->repository->reassembleQueryColumnAlias($this->target, $field) ?: $field; if (!$ignoreDefault && array_key_exists($alias, $sortRules)) { $sortColumns = $sortRules[$alias]; if (!array_key_exists('columns', $sortColumns)) { $sortColumns['columns'] = array($alias); } if ($direction !== null || !array_key_exists('order', $sortColumns)) { $sortColumns['order'] = $direction ?: static::SORT_ASC; } } else { $sortColumns = array('columns' => array($alias), 'order' => $direction); } } $baseDirection = strtoupper($sortColumns['order']) === static::SORT_DESC ? static::SORT_DESC : static::SORT_ASC; foreach ($sortColumns['columns'] as $column) { list($column, $specificDirection) = $this->splitOrder($column); if ($this->hasLimit() && $this->repository->providesValueConversion($this->target, $column)) { Logger::debug('Cannot order by column "%s" in repository "%s". The query is' . ' limited and applies value conversion rules on the column', $column, $this->repository->getName()); continue; } try { $this->query->order($this->repository->requireFilterColumn($this->target, $column, $this), $specificDirection ?: $baseDirection); } catch (QueryException $_) { Logger::info('Cannot order by column "%s" in repository "%s"', $column, $this->repository->getName()); } } return $this; }
/** * Validate that the given column is a valid filter target and return it or the actual name if it's an alias * * Attempts to join the given column from a different table if its association to the given table cannot be * verified. In case of a PostgreSQL connection and if a COLLATE SQL-instruction is part of the resolved column, * this applies LOWER() on the column and, if given, strtolower() on the filter's expression. * * @param string $table The table where to look for the column or alias * @param string $name The name or alias of the column to validate * @param RepositoryQuery $query An optional query to pass as context, * if not given the column is considered being used for a statement filter * @param FilterExpression $filter An optional filter to pass as context * * @return string The given column's name * * @throws QueryException In case the given column is not a valid filter column * @throws ProgrammingError In case the given column is not found in $table and cannot be joined in */ public function requireFilterColumn($table, $name, RepositoryQuery $query = null, FilterExpression $filter = null) { if ($name instanceof Zend_Db_Expr) { return $name; } $joined = false; if ($query === null) { $column = $this->requireStatementColumn($table, $name); } elseif ($this->validateQueryColumnAssociation($table, $name)) { $column = parent::requireFilterColumn($table, $name, $query, $filter); } else { $column = $this->joinColumn($name, $table, $query); if ($column === null) { if ($query !== null) { // It may be an aliased Zend_Db_Expr $desiredColumns = $query->getColumns(); if (isset($desiredColumns[$name]) && $desiredColumns[$name] instanceof Zend_Db_Expr) { $column = $desiredColumns[$name]; } } if ($column === null) { throw new ProgrammingError('Unable to find a valid table for column "%s" to join into "%s"', $name, $table); } } else { $joined = true; } } if (!empty($this->caseInsensitiveColumns)) { if ($joined) { $table = $this->findTableName($name); } if ($column === $name) { if ($query === null) { $name = $this->reassembleStatementColumnAlias($table, $name); } else { $name = $this->reassembleQueryColumnAlias($table, $name); } } if (isset($this->caseInsensitiveColumns[$table][$name])) { $column = 'LOWER(' . $column . ')'; if ($filter !== null) { $expression = $filter->getExpression(); if (is_array($expression)) { $filter->setExpression(array_map('strtolower', $expression)); } else { $filter->setExpression(strtolower($expression)); } } } } return $column; }
/** * Validate that the given column is a valid filter target and return it or the actual name if it's an alias * * Attempts to join the given column from a different table if its association to the given table cannot be * verified. * * @param string $table The table where to look for the column or alias * @param string $name The name or alias of the column to validate * @param RepositoryQuery $query An optional query to pass as context, * if not given the column is considered being used for a statement filter * * @return string The given column's name * * @throws QueryException In case the given column is not a valid filter column */ public function requireFilterColumn($table, $name, RepositoryQuery $query = null) { if ($query === null) { return $this->requireStatementColumn($table, $name); } if ($this->validateQueryColumnAssociation($table, $name)) { return parent::requireFilterColumn($table, $name, $query); } return $this->joinColumn($name, $table, $query); }
/** * Validate that the given column is a valid filter target and return it or the actual name if it's an alias * * Attempts to join the given column from a different table if its association to the given table cannot be * verified. In case of a PostgreSQL connection and if a COLLATE SQL-instruction is part of the resolved column, * this applies LOWER() on the column and, if given, strtolower() on the filter's expression. * * @param string $table The table where to look for the column or alias * @param string $name The name or alias of the column to validate * @param RepositoryQuery $query An optional query to pass as context, * if not given the column is considered being used for a statement filter * @param FilterExpression $filter An optional filter to pass as context * * @return string The given column's name * * @throws QueryException In case the given column is not a valid filter column */ public function requireFilterColumn($table, $name, RepositoryQuery $query = null, FilterExpression $filter = null) { $joined = false; if ($query === null) { $column = $this->requireStatementColumn($table, $name); } elseif ($this->validateQueryColumnAssociation($table, $name)) { $column = parent::requireFilterColumn($table, $name, $query, $filter); } else { $column = $this->joinColumn($name, $table, $query); $joined = true; } if (!empty($this->caseInsensitiveColumns)) { if ($joined) { $table = $this->findTableName($name); } if ($column === $name) { if ($query === null) { $name = $this->reassembleStatementColumnAlias($table, $name); } else { $name = $this->reassembleQueryColumnAlias($table, $name); } } if (isset($this->caseInsensitiveColumns[$table][$name])) { $column = 'LOWER(' . $column . ')'; if ($filter !== null) { $expression = $filter->getExpression(); if (is_array($expression)) { $filter->setExpression(array_map('strtolower', $expression)); } else { $filter->setExpression(strtolower($expression)); } } } } return $column; }