Operator::EQ, 'gt' => Operator::GT, 'gte' => Operator::GTE, 'lt' => Operator::LT, 'lte' => Operator::LTE, 'in' => Operator::IN, 'between' => Operator::BETWEEN, 'like' => Operator::LIKE, 'contains' => Operator::CONTAINS, Operator::EQ => Operator::EQ, Operator::GT => Operator::GT, Operator::GTE => Operator::GTE, Operator::LT => Operator::LT, Operator::LTE => Operator::LTE, ); /** @var KeyMatcherInterface $groupMatcher */ protected $groupMatcher; /** @var KeyMatcherInterface $sectionMatcher */ protected $sectionMatcher; /** @var KeyMatcherInterface $stateMatcher */ protected $stateMatcher; /** @var KeyMatcherInterface $userMatcher */ protected $userMatcher; /** @var int $queryLimit */ protected $queryLimit; /** * @param Repository $repository * @param KeyMatcherInterface $groupMatcher * @param KeyMatcherInterface $sectionMatcher * @param KeyMatcherInterface $stateMatcher * @param KeyMatcherInterface $userMatcher * @param int $queryLimit passed to the repo as max. number of results to fetch. Important to avoid SOLR errors * @todo inject the services needed, not the whole repository */ public function __construct(Repository $repository, KeyMatcherInterface $groupMatcher = null, KeyMatcherInterface $sectionMatcher = null, KeyMatcherInterface $stateMatcher = null, KeyMatcherInterface $userMatcher = null, $queryLimit = null) { parent::__construct($repository); $this->groupMatcher = $groupMatcher; $this->sectionMatcher = $sectionMatcher; $this->stateMatcher = $stateMatcher; $this->userMatcher = $userMatcher; if ($queryLimit !== null) { $this->queryLimit = (int)$queryLimit; } else { $this->queryLimit = self::INT_MAX_16BIT; } } /** * @param $key * @param $values * @return mixed should it be \eZ\Publish\API\Repository\Values\Content\Query\CriterionInterface ? * @throws InvalidMatchConditionsException for unsupported keys */ protected function getQueryCriterion($key, $values) { if (!is_array($values)) { $values = array($values); } switch ($key) { case self::MATCH_CONTENT_ID: return new Query\Criterion\ContentId($values); case self::MATCH_LOCATION_ID: // NB: seems to cause problems with EZP 2014.3 return new Query\Criterion\LocationId(reset($values)); case self::MATCH_CONTENT_REMOTE_ID: return new Query\Criterion\RemoteId($values); case self::MATCH_LOCATION_REMOTE_ID: return new Query\Criterion\LocationRemoteId($values); case self::MATCH_ATTRIBUTE: $spec = reset($values); $attribute = key($values); $match = reset($spec); $operator = key($spec); if (!isset(self::$operatorsMap[$operator])) { throw new InvalidMatchConditionsException("Can not use '$operator' as comparison operator for attributes"); } return new Query\Criterion\Field($attribute, self::$operatorsMap[$operator], $match); case 'content_type_id': case self::MATCH_CONTENT_TYPE_ID: return new Query\Criterion\ContentTypeId($values); case 'content_type_identifier': case self::MATCH_CONTENT_TYPE_IDENTIFIER: return new Query\Criterion\ContentTypeIdentifier($values); case self::MATCH_CREATION_DATE: $match = reset($values); $operator = key($values); if (!isset(self::$operatorsMap[$operator])) { throw new InvalidMatchConditionsException("Can not use '$operator' as comparison operator for dates"); } return new Query\Criterion\DateMetadata(Query\Criterion\DateMetadata::CREATED, self::$operatorsMap[$operator], $match); case self::MATCH_GROUP: foreach($values as &$value) { if (!ctype_digit($value)) { $value = $this->groupMatcher->matchOneByKey($value)->id; } } return new Query\Criterion\UserMetadata(Query\Criterion\UserMetadata::GROUP, Operator::IN, $values); case self::MATCH_LANGUAGE_CODE: return new Query\Criterion\LanguageCode($values); case self::MATCH_MODIFICATION_DATE: $match = reset($values); $operator = key($values); if (!isset(self::$operatorsMap[$operator])) { throw new InvalidMatchConditionsException("Can not use '$operator' as comparison operator for dates"); } return new Query\Criterion\DateMetadata(Query\Criterion\DateMetadata::MODIFIED, self::$operatorsMap[$operator], $match); case self::MATCH_OBJECT_STATE: foreach($values as &$value) { if (!ctype_digit($value)) { $value = $this->stateMatcher->matchOneByKey($value)->id; } } return new Query\Criterion\ObjectStateId($values); case self::MATCH_OWNER: foreach($values as &$value) { if (!ctype_digit($value)) { $value = $this->userMatcher->matchOneByKey($value)->id; } } return new Query\Criterion\UserMetadata(Query\Criterion\UserMetadata::OWNER, Operator::IN, $values); case self::MATCH_PARENT_LOCATION_ID: return new Query\Criterion\ParentLocationId($values); case self::MATCH_PARENT_LOCATION_REMOTE_ID: $locationIds = []; foreach ($values as $remoteParentLocationId) { $location = $this->repository->getLocationService()->loadLocationByRemoteId($remoteParentLocationId); // unique locations $locationIds[$location->id] = $location->id; } return new Query\Criterion\ParentLocationId($locationIds); case self::MATCH_SECTION: foreach($values as &$value) { if (!ctype_digit($value)) { $value = $this->sectionMatcher->matchOneByKey($value)->id; } } return new Query\Criterion\SectionId($values); case self::MATCH_SUBTREE: return new Query\Criterion\Subtree($values); case self::MATCH_VISIBILITY: /// @todo error/warning if there is more than 1 value... $value = reset($values); if ($value) { return new Query\Criterion\Visibility(Query\Criterion\Visibility::VISIBLE); } else { return new Query\Criterion\Visibility(Query\Criterion\Visibility::HIDDEN); } case self::MATCH_AND: $subCriteria = array(); foreach($values as $subCriterion) { $value = reset($subCriterion); $subCriteria[] = $this->getQueryCriterion(key($subCriterion), $value); } return new Query\Criterion\LogicalAnd($subCriteria); case self::MATCH_OR: $subCriteria = array(); foreach($values as $subCriterion) { $value = reset($subCriterion); $subCriteria[] = $this->getQueryCriterion(key($subCriterion), $value); } return new Query\Criterion\LogicalOr($subCriteria); case self::MATCH_NOT: /// @todo throw if more than one sub-criteria found $value = reset($values); $subCriterion = $this->getQueryCriterion(key($values), $value); return new Query\Criterion\LogicalNot($subCriterion); default: throw new InvalidMatchConditionsException($this->returns . " can not be matched because matching condition '$key' is not supported. Supported conditions are: " . implode(', ', $this->allowedConditions)); } } /** * @param array $sortDefinition * @return array * @throws InvalidSortConditionsException */ protected function getSortClauses(array $sortDefinition) { $out = array(); foreach ($sortDefinition as $sortItem) { if (is_string($sortItem)) { $sortItem = array('sort_field' => $sortItem); } if (!is_array($sortItem) || !isset($sortItem['sort_field'])) { throw new InvalidSortConditionsException("Missing sort_field element in sorting definition"); } if (!isset($sortItem['sort_order'])) { // we have to pick a default ;-) $sortItem['sort_order'] = 'ASC'; } $direction = $this->hash2SortOrder($sortItem['sort_order']); switch($sortItem['sort_field']) { case self::SORT_CONTENT_ID: $out[] = new SortClause\ContentId($direction); break; case self::SORT_CONTENT_NAME: $out[] = new SortClause\ContentName($direction); break; case self::SORT_DATE_MODIFIED: $out[] = new SortClause\DateModified($direction); break; case self::SORT_DATE_PUBLISHED: $out[] = new SortClause\DatePublished($direction); break; /// @todo //case self::SORT_FIELD: // $out[] = new SortClause\Field($direction); // break; case self::SORT_LOCATION_DEPTH: $out[] = new SortClause\Location\Depth($direction); break; case self::SORT_LOCATION_ID: $out[] = new SortClause\Location\Id($direction); break; case self::SORT_LOCATION_ISMAIN: $out[] = new SortClause\Location\IsMainLocation($direction); break; case self::SORT_LOCATION_PATH: $out[] = new SortClause\Location\Path($direction); break; case self::SORT_LOCATION_PRIORITY: $out[] = new SortClause\Location\Priority($direction); break; case self::SORT_LOCATION_VISIBILITY: $out[] = new SortClause\Location\Visibility($direction); break; case self::SORT_SECTION_IDENTIFIER: $out[] = new SortClause\SectionIdentifier($direction); break; case self::SORT_SECTION_NAME: $out[] = new SortClause\SectionName($direction); break; default: throw new InvalidSortConditionsException("Sort field '{$sortItem['sort_field']}' not implemented"); } } return $out; } protected function hash2SortOrder($value) { $sortOrder = null; if ($value !== null) { if (strtoupper($value) === 'ASC') { $sortOrder = Query::SORT_ASC; } else { $sortOrder = Query::SORT_DESC; } } return $sortOrder; } /** * @param int $value * @return string */ protected function sortOrder2Hash($value) { if ($value === Query::SORT_ASC) { return 'ASC'; } else { return 'DESC'; } } }