From eeda40068e44b7e9a25be11888d78b02187eee58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petar=20=C5=A0panja?= Date: Mon, 1 Feb 2021 06:20:49 +0100 Subject: [PATCH 1/5] NGSTACK-361: implement sibling range resolver --- lib/API/Repository/SiblingRangeResolver.php | 492 +++++ .../Repository/SiblingRangeResolverTest.php | 1638 +++++++++++++++++ 2 files changed, 2130 insertions(+) create mode 100644 lib/API/Repository/SiblingRangeResolver.php create mode 100644 tests/lib/Unit/API/Repository/SiblingRangeResolverTest.php diff --git a/lib/API/Repository/SiblingRangeResolver.php b/lib/API/Repository/SiblingRangeResolver.php new file mode 100644 index 00000000..976f9e4f --- /dev/null +++ b/lib/API/Repository/SiblingRangeResolver.php @@ -0,0 +1,492 @@ +repository = $repository; + } + + /** + * @throws \Exception + */ + public function resolveQuery(ValueObject $value, Query $query, string $rangeType): Query + { + $query = clone $query; + + $this->modifyQuery($value, $query, $rangeType); + + return $query; + } + + /** + * @throws \Exception + */ + public function modifyQuery(ValueObject $value, Query $query, string $rangeType): void + { + $query->filter = new LogicalAnd([ + $query->filter, + $this->resolveCriterion( + $value, + $query->sortClauses, + $rangeType + ) + ]); + + $query->sortClauses = $this->resolveSortClauses( + $value, + $query->sortClauses, + $rangeType + ); + } + + /** + * @throws \Exception + */ + public function resolveCriterion(ValueObject $value, array $sortClauses, string $rangeType): CriterionInterface + { + $tieBreaker = $this->getTieBreakerCriterion($value, $rangeType); + + if (empty($sortClauses)) { + return $tieBreaker; + } + + $count = count($sortClauses); + $criteria = []; + + for ($i = $count; $i >= 1; $i--) { + $groupCriteria = $this->resolveGroupCriteria($value, $sortClauses, $rangeType, $i); + $groupCriteria[] = $tieBreaker; + + $criteria[] = new LogicalAnd($groupCriteria); + } + + $primarySortClause = $sortClauses[0]; + $operator = $this->resolveOperator($primarySortClause, $rangeType, false); + $criteria[] = $this->resolveCriterionForSortClause($value, $primarySortClause, $operator); + + return new LogicalOr($criteria); + } + + /** + * @param \eZ\Publish\API\Repository\Values\Content\Query\SortClause[] $sortClauses + * + * @return \eZ\Publish\API\Repository\Values\Content\Query\SortClause[] + */ + public function resolveSortClauses(ValueObject $value, array $sortClauses, string $rangeType): array + { + $newSortClauses = []; + + foreach ($sortClauses as $sortClause) { + $newSortClause = clone $sortClause; + + if ($rangeType === self::RangeTypePreceding) { + $newSortClause->direction = $this->reverseDirection($sortClause); + } + + $sortClauses[] = $newSortClause; + } + + $newSortClauses[] = $this->getTieBreakerSortClause($value, $rangeType); + + return $newSortClauses; + } + + /** + * @throws \Exception + */ + private function resolveGroupCriteria(ValueObject $value, array $sortClauses, string $rangeType, int $count): array + { + $criteria = []; + + for ($i = 0; $i < $count; $i++) { + $sortClause = $sortClauses[$i]; + $operator = $this->resolveOperator($sortClause, $rangeType, true); + + $criteria[] = $this->resolveCriterionForSortClause($value, $sortClause, $operator); + } + + return $criteria; + } + + /** + * @throws \Exception + */ + private function resolveCriterionForSortClause( + ValueObject $value, + SortClause $sortClause, + string $operator + ): CriterionInterface { + $sortClauseClass = get_class($sortClause); + + switch ($sortClauseClass) { + case ContentId::class: + return new ContentIdCriterion($operator, $this->getContentInfo($value)->id); + case ContentName::class: + return new ContentNameCriterion($operator, $this->getContentName($value)); + case DateModified::class: + return new DateMetadata( + DateMetadata::MODIFIED, + $operator, + $this->getContentInfo($value)->modificationDate->getTimestamp() + ); + case DatePublished::class: + return new DateMetadata( + DateMetadata::CREATED, + $operator, + $this->getContentInfo($value)->modificationDate->getTimestamp() + ); + case Depth::class: + return new DepthCriterion($operator, $this->getLocation($value)->depth); + case Field::class: + /** @var \eZ\Publish\API\Repository\Values\Content\Query\SortClause\Target\FieldTarget $targetData */ + $targetData = $sortClause->targetData; + + // todo logical and with content type identifier? + return new FieldCriterion( + $targetData->fieldIdentifier, + $operator, + $this->getFieldValue($value, $targetData->fieldIdentifier) + ); + case LocationId::class: + return new LocationIdCriterion($operator, $this->getLocation($value)->id); + case Priority::class: + return new PriorityCriterion($operator, $this->getLocation($value)->priority); + } + + throw new RuntimeException( + 'Sort clause "' . $sortClauseClass . '" is not supported' + ); + } + + /** + * @throws \Exception + */ + private function getLocation(ValueObject $value): Location + { + if ($value instanceof Location) { + return $value; + } + + if ($value instanceof SiteLocation) { + return $value->innerLocation; + } + + if ($value instanceof Content) { + return $this->repository->sudo( + function (Repository $repository) use ($value): Location { + return $repository->getLocationService()->loadLocation( + $value->contentInfo->mainLocationId + ); + } + ); + } + + if ($value instanceof SiteContent) { + return $value->mainLocation->innerLocation; + } + + throw new RuntimeException( + 'Value "' . get_class($value) . '" is not supported' + ); + } + + private function getContent(ValueObject $value): Content + { + if ($value instanceof Location) { + return $value->getContent(); + } + + if ($value instanceof SiteLocation) { + return $value->content->innerContent; + } + + if ($value instanceof Content) { + return $value; + } + + if ($value instanceof SiteContent) { + return $value->innerContent; + } + + throw new RuntimeException( + 'Value "' . get_class($value) . '" is not supported' + ); + } + + private function getContentInfo(ValueObject $value): ContentInfo + { + if ($value instanceof Location || $value instanceof Content) { + return $value->contentInfo; + } + + if ($value instanceof SiteLocation || $value instanceof SiteContent) { + return $value->contentInfo->innerContentInfo; + } + + throw new RuntimeException( + 'Value "' . get_class($value) . '" is not supported' + ); + } + + private function getContentName(ValueObject $value): string + { + return $this->getContent($value)->getName(); + } + + /** + * @return mixed + */ + private function getFieldValue(ValueObject $value, string $identifier) + { + $content = $this->getContent($value); + + $field = $content->getField($identifier); + + if ($field === null) { + throw new RuntimeException( + 'Field "' . $identifier . '" not found on the given Content' + ); + } + + switch ($field->fieldTypeIdentifier) { + case 'ezstring': + /** @var \eZ\Publish\Core\FieldType\TextLine\Value $value */ + $value = $field->value; + + return $value->text; + case 'eztext': + /** @var \eZ\Publish\Core\FieldType\TextBlock\Value $value */ + $value = $field->value; + + return $value->text; + case 'ezdate': + /** @var \eZ\Publish\Core\FieldType\Date\Value $value */ + $value = $field->value; + + if ($value->date === null) { + return null; + } + + return $value->date->format('Y-m-d\\Z'); + case 'ezdatetime': + /** @var \eZ\Publish\Core\FieldType\DateAndTime\Value $value */ + $value = $field->value; + + if ($value->value === null) { + return null; + } + + return $value->value->getTimestamp(); + case 'eztime': + /** @var \eZ\Publish\Core\FieldType\Time\Value $value */ + $value = $field->value; + + return $value->time; + case 'ezemail': + /** @var \eZ\Publish\Core\FieldType\EmailAddress\Value $value */ + $value = $field->value; + + return $value->email; + case 'ezinteger': + /** @var \eZ\Publish\Core\FieldType\Integer\Value $value */ + $value = $field->value; + + return $value->value; + case 'ezfloat': + /** @var \eZ\Publish\Core\FieldType\Float\Value $value */ + $value = $field->value; + + return $value->value; + case 'ezboolean': + /** @var \eZ\Publish\Core\FieldType\Checkbox\Value $value */ + $value = $field->value; + + return $value->bool; + case 'ezisbn': + /** @var \eZ\Publish\Core\FieldType\ISBN\Value $value */ + $value = $field->value; + + return $value->isbn; + } + + throw new RuntimeException( + 'Field type "' . $field->fieldTypeIdentifier . '" is not supported' + ); + } + + private function resolveOperator(SortClause $sortClause, string $rangeType, bool $inclusive): string + { + if ($rangeType === self::RangeTypeFollowing) { + return $this->resolveOperatorForFollowing($sortClause, $inclusive); + } + + if ($rangeType === self::RangeTypePreceding) { + return $this->resolveOperatorForPreceding($sortClause, $inclusive); + } + + throw new RuntimeException( + 'Unknown range "' . $rangeType . '"' + ); + } + + private function resolveOperatorForFollowing(SortClause $sortClause, bool $inclusive): string + { + if ($sortClause->direction === Query::SORT_ASC) { + return $inclusive ? Operator::GTE : Operator::GT; + } + + return $inclusive ? Operator::LTE : Operator::LT; + } + + private function resolveOperatorForPreceding(SortClause $sortClause, bool $inclusive): string + { + if ($sortClause->direction === Query::SORT_ASC) { + return $inclusive ? Operator::LTE : Operator::LT; + } + + return $inclusive ? Operator::GTE : Operator::GT; + } + + private function getTieBreakerCriterion(ValueObject $value, string $rangeType): CriterionInterface + { + $operator = $this->getTieBreakerCriterionOperator($rangeType); + + if ($value instanceof Content || $value instanceof SiteContent) { + return new ContentIdCriterion($operator, $value->id); + } + + if ($value instanceof Location || $value instanceof SiteLocation) { + return new LocationIdCriterion($operator, $value->id); + } + + throw new RuntimeException( + 'Unknown range "' . $rangeType . '"' + ); + } + + private function getTieBreakerCriterionOperator(string $rangeType): string + { + if ($rangeType === self::RangeTypeFollowing) { + return Operator::GT; + } + + if ($rangeType === self::RangeTypePreceding) { + return Operator::LT; + } + + throw new RuntimeException( + 'Unknown range "' . $rangeType . '"' + ); + } + + private function reverseDirection(SortClause $sortClause): string + { + if ($sortClause->direction === Query::SORT_ASC) { + return Query::SORT_DESC; + } + + return Query::SORT_ASC; + } + + private function getTieBreakerSortClause(ValueObject $value, string $rangeType): SortClause + { + $direction = $this->getSortClauseDirection($rangeType); + + if ($value instanceof Content || $value instanceof SiteContent) { + return new ContentId($direction); + } + + if ($value instanceof Location || $value instanceof SiteLocation) { + return new LocationId($direction); + } + + throw new RuntimeException( + 'Unknown range "' . $rangeType . '"' + ); + } + + private function getSortClauseDirection(string $rangeType): string + { + if ($rangeType === self::RangeTypeFollowing) { + return Query::SORT_ASC; + } + + if ($rangeType === self::RangeTypePreceding) { + return Query::SORT_DESC; + } + + throw new RuntimeException( + 'Unknown range "' . $rangeType . '"' + ); + } +} diff --git a/tests/lib/Unit/API/Repository/SiblingRangeResolverTest.php b/tests/lib/Unit/API/Repository/SiblingRangeResolverTest.php new file mode 100644 index 00000000..93e63151 --- /dev/null +++ b/tests/lib/Unit/API/Repository/SiblingRangeResolverTest.php @@ -0,0 +1,1638 @@ + 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [], + SiblingRangeResolver::RangeTypeFollowing, + new ContentId(Operator::GT, 42), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [], + SiblingRangeResolver::RangeTypePreceding, + new ContentId(Operator::LT, 42), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\ContentName(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new ContentName(Operator::GTE, 'Netgen'), + new ContentId(Operator::GT, 42), + ]), + new ContentName(Operator::GT, 'Netgen'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\ContentName(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new ContentName(Operator::LTE, 'Netgen'), + new ContentId(Operator::GT, 42), + ]), + new ContentName(Operator::LT, 'Netgen'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\ContentName(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new ContentName(Operator::LTE, 'Netgen'), + new ContentId(Operator::LT, 42), + ]), + new ContentName(Operator::LT, 'Netgen'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\ContentName(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new ContentName(Operator::GTE, 'Netgen'), + new ContentId(Operator::LT, 42), + ]), + new ContentName(Operator::GT, 'Netgen'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\ContentId(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new ContentId(Operator::GTE, 42), + new ContentId(Operator::GT, 42), + ]), + new ContentId(Operator::GT, 42), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\ContentId(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new ContentId(Operator::LTE, 42), + new ContentId(Operator::GT, 42), + ]), + new ContentId(Operator::LT, 42), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\ContentId(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new ContentId(Operator::LTE, 42), + new ContentId(Operator::LT, 42), + ]), + new ContentId(Operator::LT, 42), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\ContentId(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new ContentId(Operator::GTE, 42), + new ContentId(Operator::LT, 42), + ]), + new ContentId(Operator::GT, 42), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\DateModified(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new DateMetadata(DateMetadata::MODIFIED, Operator::GTE, self::Timestamp), + new ContentId(Operator::GT, 42), + ]), + new DateMetadata(DateMetadata::MODIFIED, Operator::GT, self::Timestamp), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\DateModified(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new DateMetadata(DateMetadata::MODIFIED, Operator::LTE, self::Timestamp), + new ContentId(Operator::GT, 42), + ]), + new DateMetadata(DateMetadata::MODIFIED, Operator::LT, self::Timestamp), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\DateModified(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new DateMetadata(DateMetadata::MODIFIED, Operator::LTE, self::Timestamp), + new ContentId(Operator::LT, 42), + ]), + new DateMetadata(DateMetadata::MODIFIED, Operator::LT, self::Timestamp), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\DateModified(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new DateMetadata(DateMetadata::MODIFIED, Operator::GTE, self::Timestamp), + new ContentId(Operator::LT, 42), + ]), + new DateMetadata(DateMetadata::MODIFIED, Operator::GT, self::Timestamp), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\DatePublished(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new DateMetadata(DateMetadata::CREATED, Operator::GTE, self::Timestamp), + new ContentId(Operator::GT, 42), + ]), + new DateMetadata(DateMetadata::CREATED, Operator::GT, self::Timestamp), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\DatePublished(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new DateMetadata(DateMetadata::CREATED, Operator::LTE, self::Timestamp), + new ContentId(Operator::GT, 42), + ]), + new DateMetadata(DateMetadata::CREATED, Operator::LT, self::Timestamp), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\DatePublished(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new DateMetadata(DateMetadata::CREATED, Operator::LTE, self::Timestamp), + new ContentId(Operator::LT, 42), + ]), + new DateMetadata(DateMetadata::CREATED, Operator::LT, self::Timestamp), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\DatePublished(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new DateMetadata(DateMetadata::CREATED, Operator::GTE, self::Timestamp), + new ContentId(Operator::LT, 42), + ]), + new DateMetadata(DateMetadata::CREATED, Operator::GT, self::Timestamp), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\Location\Depth(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Depth(Operator::GTE, 6), + new ContentId(Operator::GT, 42), + ]), + new Depth(Operator::GT, 6), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\Location\Depth(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Depth(Operator::LTE, 6), + new ContentId(Operator::GT, 42), + ]), + new Depth(Operator::LT, 6), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\Location\Depth(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Depth(Operator::LTE, 6), + new ContentId(Operator::LT, 42), + ]), + new Depth(Operator::LT, 6), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\Location\Depth(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Depth(Operator::GTE, 6), + new ContentId(Operator::LT, 42), + ]), + new Depth(Operator::GT, 6), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::GTE, 'Zagreb'), + new ContentId(Operator::GT, 42), + ]), + new Criterion\Field('field', Operator::GT, 'Zagreb'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::LTE, 'Zagreb'), + new ContentId(Operator::GT, 42), + ]), + new Criterion\Field('field', Operator::LT, 'Zagreb'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::LTE, 'Zagreb'), + new ContentId(Operator::LT, 42), + ]), + new Criterion\Field('field', Operator::LT, 'Zagreb'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::GTE, 'Zagreb'), + new ContentId(Operator::LT, 42), + ]), + new Criterion\Field('field', Operator::GT, 'Zagreb'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\Location\Id(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new LocationId(Operator::GTE, 24), + new ContentId(Operator::GT, 42), + ]), + new LocationId(Operator::GT, 24), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\Location\Id(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new LocationId(Operator::LTE, 24), + new ContentId(Operator::GT, 42), + ]), + new LocationId(Operator::LT, 24), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\Location\Id(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new LocationId(Operator::LTE, 24), + new ContentId(Operator::LT, 42), + ]), + new LocationId(Operator::LT, 24), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\Location\Id(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new LocationId(Operator::GTE, 24), + new ContentId(Operator::LT, 42), + ]), + new LocationId(Operator::GT, 24), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\Location\Priority(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Priority(Operator::GTE, 4), + new ContentId(Operator::GT, 42), + ]), + new Priority(Operator::GT, 4), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\Location\Priority(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Priority(Operator::LTE, 4), + new ContentId(Operator::GT, 42), + ]), + new Priority(Operator::LT, 4), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\Location\Priority(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Priority(Operator::LTE, 4), + new ContentId(Operator::LT, 42), + ]), + new Priority(Operator::LT, 4), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\Location\Priority(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Priority(Operator::GTE, 4), + new ContentId(Operator::LT, 42), + ]), + new Priority(Operator::GT, 4), + ]), + ], + ]; + } + + /** + * @dataProvider providerForTestResolveCriterion + * + * @throws \Exception + */ + public function testResolveCriterion( + int $id, + Field $field, + array $sortClauses, + string $rangeType, + CriterionInterface $expectedCriterion + ): void { + $content = $this->getContent($id, $field); + + $actualCriterion = $this->getServiceUnderTest()->resolveCriterion( + $content, + $sortClauses, + $rangeType + ); + + self::assertEquals($expectedCriterion, $actualCriterion); + } + + /** + * @throws \Exception + */ + public function providerForTestResolveCriterionField(): array + { + return [ + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::GTE, 'Zagreb'), + new ContentId(Operator::GT, 42), + ]), + new Criterion\Field('field', Operator::GT, 'Zagreb'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::LTE, 'Zagreb'), + new ContentId(Operator::GT, 42), + ]), + new Criterion\Field('field', Operator::LT, 'Zagreb'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::LTE, 'Zagreb'), + new ContentId(Operator::LT, 42), + ]), + new Criterion\Field('field', Operator::LT, 'Zagreb'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::GTE, 'Zagreb'), + new ContentId(Operator::LT, 42), + ]), + new Criterion\Field('field', Operator::GT, 'Zagreb'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'eztext', + 'languageCode' => 'cro-HR', + 'value' => new TextBlockValue('Zagreb'), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::GTE, 'Zagreb'), + new ContentId(Operator::GT, 42), + ]), + new Criterion\Field('field', Operator::GT, 'Zagreb'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'eztext', + 'languageCode' => 'cro-HR', + 'value' => new TextBlockValue('Zagreb'), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::LTE, 'Zagreb'), + new ContentId(Operator::GT, 42), + ]), + new Criterion\Field('field', Operator::LT, 'Zagreb'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'eztext', + 'languageCode' => 'cro-HR', + 'value' => new TextBlockValue('Zagreb'), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::LTE, 'Zagreb'), + new ContentId(Operator::LT, 42), + ]), + new Criterion\Field('field', Operator::LT, 'Zagreb'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'eztext', + 'languageCode' => 'cro-HR', + 'value' => new TextBlockValue('Zagreb'), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::GTE, 'Zagreb'), + new ContentId(Operator::LT, 42), + ]), + new Criterion\Field('field', Operator::GT, 'Zagreb'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezdate', + 'languageCode' => 'cro-HR', + 'value' => new DateValue(new DateTime('@' . self::Timestamp)), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::GTE, '2021-01-31Z'), + new ContentId(Operator::GT, 42), + ]), + new Criterion\Field('field', Operator::GT, '2021-01-31Z'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezdate', + 'languageCode' => 'cro-HR', + 'value' => new DateValue(new DateTime('@' . self::Timestamp)), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::LTE, '2021-01-31Z'), + new ContentId(Operator::GT, 42), + ]), + new Criterion\Field('field', Operator::LT, '2021-01-31Z'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezdate', + 'languageCode' => 'cro-HR', + 'value' => new DateValue(new DateTime('@' . self::Timestamp)), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::LTE, '2021-01-31Z'), + new ContentId(Operator::LT, 42), + ]), + new Criterion\Field('field', Operator::LT, '2021-01-31Z'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezdate', + 'languageCode' => 'cro-HR', + 'value' => new DateValue(new DateTime('@' . self::Timestamp)), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::GTE, '2021-01-31Z'), + new ContentId(Operator::LT, 42), + ]), + new Criterion\Field('field', Operator::GT, '2021-01-31Z'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezdatetime', + 'languageCode' => 'cro-HR', + 'value' => new DateAndTimeValue(new DateTime('@' . self::Timestamp)), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::GTE, self::Timestamp), + new ContentId(Operator::GT, 42), + ]), + new Criterion\Field('field', Operator::GT, self::Timestamp), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezdatetime', + 'languageCode' => 'cro-HR', + 'value' => new DateAndTimeValue(new DateTime('@' . self::Timestamp)), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::LTE, self::Timestamp), + new ContentId(Operator::GT, 42), + ]), + new Criterion\Field('field', Operator::LT, self::Timestamp), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezdatetime', + 'languageCode' => 'cro-HR', + 'value' => new DateAndTimeValue(new DateTime('@' . self::Timestamp)), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::LTE, self::Timestamp), + new ContentId(Operator::LT, 42), + ]), + new Criterion\Field('field', Operator::LT, self::Timestamp), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezdatetime', + 'languageCode' => 'cro-HR', + 'value' => new DateAndTimeValue(new DateTime('@' . self::Timestamp)), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::GTE, self::Timestamp), + new ContentId(Operator::LT, 42), + ]), + new Criterion\Field('field', Operator::GT, self::Timestamp), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'eztime', + 'languageCode' => 'cro-HR', + 'value' => TimeValue::fromDateTime(new DateTime('@' . self::Timestamp)), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::GTE, 35938), + new ContentId(Operator::GT, 42), + ]), + new Criterion\Field('field', Operator::GT, 35938), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'eztime', + 'languageCode' => 'cro-HR', + 'value' => TimeValue::fromDateTime(new DateTime('@' . self::Timestamp)), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::LTE, 35938), + new ContentId(Operator::GT, 42), + ]), + new Criterion\Field('field', Operator::LT, 35938), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'eztime', + 'languageCode' => 'cro-HR', + 'value' => TimeValue::fromDateTime(new DateTime('@' . self::Timestamp)), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::LTE, 35938), + new ContentId(Operator::LT, 42), + ]), + new Criterion\Field('field', Operator::LT, 35938), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'eztime', + 'languageCode' => 'cro-HR', + 'value' => TimeValue::fromDateTime(new DateTime('@' . self::Timestamp)), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::GTE, 35938), + new ContentId(Operator::LT, 42), + ]), + new Criterion\Field('field', Operator::GT, 35938), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezemail', + 'languageCode' => 'cro-HR', + 'value' => new EmailAddressValue('spam@invalid.asdf'), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::GTE, 'spam@invalid.asdf'), + new ContentId(Operator::GT, 42), + ]), + new Criterion\Field('field', Operator::GT, 'spam@invalid.asdf'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezemail', + 'languageCode' => 'cro-HR', + 'value' => new EmailAddressValue('spam@invalid.asdf'), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::LTE, 'spam@invalid.asdf'), + new ContentId(Operator::GT, 42), + ]), + new Criterion\Field('field', Operator::LT, 'spam@invalid.asdf'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezemail', + 'languageCode' => 'cro-HR', + 'value' => new EmailAddressValue('spam@invalid.asdf'), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::LTE, 'spam@invalid.asdf'), + new ContentId(Operator::LT, 42), + ]), + new Criterion\Field('field', Operator::LT, 'spam@invalid.asdf'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezemail', + 'languageCode' => 'cro-HR', + 'value' => new EmailAddressValue('spam@invalid.asdf'), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::GTE, 'spam@invalid.asdf'), + new ContentId(Operator::LT, 42), + ]), + new Criterion\Field('field', Operator::GT, 'spam@invalid.asdf'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezinteger', + 'languageCode' => 'cro-HR', + 'value' => new IntegerValue(22), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::GTE, 22), + new ContentId(Operator::GT, 42), + ]), + new Criterion\Field('field', Operator::GT, 22), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezinteger', + 'languageCode' => 'cro-HR', + 'value' => new IntegerValue(22), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::LTE, 22), + new ContentId(Operator::GT, 42), + ]), + new Criterion\Field('field', Operator::LT, 22), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezinteger', + 'languageCode' => 'cro-HR', + 'value' => new IntegerValue(22), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::LTE, 22), + new ContentId(Operator::LT, 42), + ]), + new Criterion\Field('field', Operator::LT, 22), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezinteger', + 'languageCode' => 'cro-HR', + 'value' => new IntegerValue(22), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::GTE, 22), + new ContentId(Operator::LT, 42), + ]), + new Criterion\Field('field', Operator::GT, 22), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezfloat', + 'languageCode' => 'cro-HR', + 'value' => new FloatValue(3.14), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::GTE, 3.14), + new ContentId(Operator::GT, 42), + ]), + new Criterion\Field('field', Operator::GT, 3.14), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezfloat', + 'languageCode' => 'cro-HR', + 'value' => new FloatValue(3.14), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::LTE, 3.14), + new ContentId(Operator::GT, 42), + ]), + new Criterion\Field('field', Operator::LT, 3.14), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezfloat', + 'languageCode' => 'cro-HR', + 'value' => new FloatValue(3.14), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::LTE, 3.14), + new ContentId(Operator::LT, 42), + ]), + new Criterion\Field('field', Operator::LT, 3.14), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezfloat', + 'languageCode' => 'cro-HR', + 'value' => new FloatValue(3.14), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::GTE, 3.14), + new ContentId(Operator::LT, 42), + ]), + new Criterion\Field('field', Operator::GT, 3.14), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezboolean', + 'languageCode' => 'cro-HR', + 'value' => new CheckboxValue(true), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::GTE, true), + new ContentId(Operator::GT, 42), + ]), + new Criterion\Field('field', Operator::GT, true), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezboolean', + 'languageCode' => 'cro-HR', + 'value' => new CheckboxValue(true), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::LTE, true), + new ContentId(Operator::GT, 42), + ]), + new Criterion\Field('field', Operator::LT, true), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezboolean', + 'languageCode' => 'cro-HR', + 'value' => new CheckboxValue(true), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::LTE, true), + new ContentId(Operator::LT, 42), + ]), + new Criterion\Field('field', Operator::LT, true), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezboolean', + 'languageCode' => 'cro-HR', + 'value' => new CheckboxValue(true), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::GTE, true), + new ContentId(Operator::LT, 42), + ]), + new Criterion\Field('field', Operator::GT, true), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezisbn', + 'languageCode' => 'cro-HR', + 'value' => new ISBNValue('9780061936456'), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::GTE, '9780061936456'), + new ContentId(Operator::GT, 42), + ]), + new Criterion\Field('field', Operator::GT, '9780061936456'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezisbn', + 'languageCode' => 'cro-HR', + 'value' => new ISBNValue('9780061936456'), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::LTE, '9780061936456'), + new ContentId(Operator::GT, 42), + ]), + new Criterion\Field('field', Operator::LT, '9780061936456'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezisbn', + 'languageCode' => 'cro-HR', + 'value' => new ISBNValue('9780061936456'), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::LTE, '9780061936456'), + new ContentId(Operator::LT, 42), + ]), + new Criterion\Field('field', Operator::LT, '9780061936456'), + ]), + ], + [ + 42, + new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezisbn', + 'languageCode' => 'cro-HR', + 'value' => new ISBNValue('9780061936456'), + ]), + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + new LogicalOr([ + new LogicalAnd([ + new Criterion\Field('field', Operator::GTE, '9780061936456'), + new ContentId(Operator::LT, 42), + ]), + new Criterion\Field('field', Operator::GT, '9780061936456'), + ]), + ], + ]; + } + + /** + * @dataProvider providerForTestResolveCriterionField + * + * @throws \Exception + */ + public function testResolveCriterionField( + int $id, + Field $field, + array $sortClauses, + string $rangeType, + CriterionInterface $expectedCriterion + ): void { + $content = $this->getContent($id, $field); + + $actualCriterion = $this->getServiceUnderTest()->resolveCriterion( + $content, + $sortClauses, + $rangeType + ); + + self::assertEquals($expectedCriterion, $actualCriterion); + } + + public function testResolveSortClauses(): void + { + + } + + public function testModifyQuery(): void + { + + } + + public function testResolveQuery(): void + { + + } + + /** + * @throws \Exception + */ + protected function getContent(int $id, Field $field): APIContent + { + return new Content([ + 'versionInfo' => new VersionInfo([ + 'contentInfo' => new ContentInfo([ + 'id' => $id, + 'modificationDate' => new DateTime('@' . self::Timestamp), + 'mainLanguageCode' => 'cro-HR', + ]), + 'initialLanguageCode' => 'cro-HR', + 'names' => [ + 'cro-HR' => 'Netgen', + ], + + ]), + 'internalFields' => [ + 'field' => $field, + ], + ]); + } + + protected function getLocation(): APILocation + { + return new Location([ + 'id' => 24, + 'depth' => 6, + 'priority' => 4, + ]); + } + + protected function getServiceUnderTest(): SiblingRangeResolver + { + return new SiblingRangeResolver($this->getRepositoryMock()); + } + + protected function getRepositoryMock() + { + $repositoryMock = $this + ->getMockBuilder(CoreRepository::class) + ->disableOriginalConstructor() + ->getMock(); + + $repoContent = $this->getLocation(); + $repositoryMock->method('sudo')->willReturn($repoContent); + + return $repositoryMock; + } +} From 3ead4d719ddca13ae51e91982352f9e7741b5293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petar=20=C5=A0panja?= Date: Wed, 10 Feb 2021 06:40:38 +0100 Subject: [PATCH 2/5] NGSTACK-361: test and refactor --- lib/API/Repository/SiblingRangeResolver.php | 33 +- .../Repository/SiblingRangeResolverTest.php | 1112 ++++++++++------- 2 files changed, 674 insertions(+), 471 deletions(-) diff --git a/lib/API/Repository/SiblingRangeResolver.php b/lib/API/Repository/SiblingRangeResolver.php index 976f9e4f..ed8c4882 100644 --- a/lib/API/Repository/SiblingRangeResolver.php +++ b/lib/API/Repository/SiblingRangeResolver.php @@ -114,6 +114,7 @@ public function modifyQuery(ValueObject $value, Query $query, string $rangeType) */ public function resolveCriterion(ValueObject $value, array $sortClauses, string $rangeType): CriterionInterface { + $this->validateRange($rangeType); $tieBreaker = $this->getTieBreakerCriterion($value, $rangeType); if (empty($sortClauses)) { @@ -144,6 +145,7 @@ public function resolveCriterion(ValueObject $value, array $sortClauses, string */ public function resolveSortClauses(ValueObject $value, array $sortClauses, string $rangeType): array { + $this->validateRange($rangeType); $newSortClauses = []; foreach ($sortClauses as $sortClause) { @@ -390,13 +392,7 @@ private function resolveOperator(SortClause $sortClause, string $rangeType, bool return $this->resolveOperatorForFollowing($sortClause, $inclusive); } - if ($rangeType === self::RangeTypePreceding) { - return $this->resolveOperatorForPreceding($sortClause, $inclusive); - } - - throw new RuntimeException( - 'Unknown range "' . $rangeType . '"' - ); + return $this->resolveOperatorForPreceding($sortClause, $inclusive); } private function resolveOperatorForFollowing(SortClause $sortClause, bool $inclusive): string @@ -430,7 +426,7 @@ private function getTieBreakerCriterion(ValueObject $value, string $rangeType): } throw new RuntimeException( - 'Unknown range "' . $rangeType . '"' + 'Value "' . get_class($value) . '" is not supported' ); } @@ -440,13 +436,7 @@ private function getTieBreakerCriterionOperator(string $rangeType): string return Operator::GT; } - if ($rangeType === self::RangeTypePreceding) { - return Operator::LT; - } - - throw new RuntimeException( - 'Unknown range "' . $rangeType . '"' - ); + return Operator::LT; } private function reverseDirection(SortClause $sortClause): string @@ -471,7 +461,7 @@ private function getTieBreakerSortClause(ValueObject $value, string $rangeType): } throw new RuntimeException( - 'Unknown range "' . $rangeType . '"' + 'Value "' . get_class($value) . '" is not supported' ); } @@ -481,8 +471,17 @@ private function getSortClauseDirection(string $rangeType): string return Query::SORT_ASC; } + return Query::SORT_DESC; + } + + private function validateRange(string $rangeType): void + { + if ($rangeType === self::RangeTypeFollowing) { + return; + } + if ($rangeType === self::RangeTypePreceding) { - return Query::SORT_DESC; + return; } throw new RuntimeException( diff --git a/tests/lib/Unit/API/Repository/SiblingRangeResolverTest.php b/tests/lib/Unit/API/Repository/SiblingRangeResolverTest.php index 93e63151..9296ad21 100644 --- a/tests/lib/Unit/API/Repository/SiblingRangeResolverTest.php +++ b/tests/lib/Unit/API/Repository/SiblingRangeResolverTest.php @@ -1,6 +1,5 @@ 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]); + return [ [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [], SiblingRangeResolver::RangeTypeFollowing, new ContentId(Operator::GT, 42), ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [], SiblingRangeResolver::RangeTypePreceding, new ContentId(Operator::LT, 42), ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\ContentName(Query::SORT_ASC), ], @@ -94,12 +87,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\ContentName(Query::SORT_DESC), ], @@ -114,12 +102,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\ContentName(Query::SORT_ASC), ], @@ -134,12 +117,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\ContentName(Query::SORT_DESC), ], @@ -154,12 +132,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\ContentId(Query::SORT_ASC), ], @@ -174,12 +147,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\ContentId(Query::SORT_DESC), ], @@ -194,12 +162,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\ContentId(Query::SORT_ASC), ], @@ -214,12 +177,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\ContentId(Query::SORT_DESC), ], @@ -234,12 +192,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\DateModified(Query::SORT_ASC), ], @@ -254,12 +207,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\DateModified(Query::SORT_DESC), ], @@ -274,12 +222,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\DateModified(Query::SORT_ASC), ], @@ -294,12 +237,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\DateModified(Query::SORT_DESC), ], @@ -314,12 +252,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\DatePublished(Query::SORT_ASC), ], @@ -334,12 +267,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\DatePublished(Query::SORT_DESC), ], @@ -354,12 +282,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\DatePublished(Query::SORT_ASC), ], @@ -374,12 +297,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\DatePublished(Query::SORT_DESC), ], @@ -394,12 +312,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\Location\Depth(Query::SORT_ASC), ], @@ -414,12 +327,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\Location\Depth(Query::SORT_DESC), ], @@ -434,12 +342,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\Location\Depth(Query::SORT_ASC), ], @@ -454,12 +357,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\Location\Depth(Query::SORT_DESC), ], @@ -474,12 +372,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\Field('type', 'field', Query::SORT_ASC), ], @@ -494,12 +387,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\Field('type', 'field', Query::SORT_DESC), ], @@ -514,12 +402,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\Field('type', 'field', Query::SORT_ASC), ], @@ -534,12 +417,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\Field('type', 'field', Query::SORT_DESC), ], @@ -554,12 +432,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\Location\Id(Query::SORT_ASC), ], @@ -574,12 +447,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\Location\Id(Query::SORT_DESC), ], @@ -594,12 +462,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\Location\Id(Query::SORT_ASC), ], @@ -614,12 +477,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\Location\Id(Query::SORT_DESC), ], @@ -634,12 +492,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\Location\Priority(Query::SORT_ASC), ], @@ -654,12 +507,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\Location\Priority(Query::SORT_DESC), ], @@ -674,12 +522,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\Location\Priority(Query::SORT_ASC), ], @@ -694,12 +537,7 @@ public function providerForTestResolveCriterion(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $field, [ new SortClause\Location\Priority(Query::SORT_DESC), ], @@ -743,15 +581,71 @@ public function testResolveCriterion( */ public function providerForTestResolveCriterionField(): array { + $textLineField = new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]); + $textBlockField = new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'eztext', + 'languageCode' => 'cro-HR', + 'value' => new TextBlockValue('Zagreb'), + ]); + $dateField = new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezdate', + 'languageCode' => 'cro-HR', + 'value' => new DateValue(new DateTime('@' . self::Timestamp)), + ]); + $dateAndTimeField = new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezdatetime', + 'languageCode' => 'cro-HR', + 'value' => new DateAndTimeValue(new DateTime('@' . self::Timestamp)), + ]); + $timeField = new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'eztime', + 'languageCode' => 'cro-HR', + 'value' => TimeValue::fromDateTime(new DateTime('@' . self::Timestamp)), + ]); + $mailAddressField = new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezemail', + 'languageCode' => 'cro-HR', + 'value' => new EmailAddressValue('test@netgen.io'), + ]); + $integerField = new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezinteger', + 'languageCode' => 'cro-HR', + 'value' => new IntegerValue(22), + ]); + $floatField = new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezfloat', + 'languageCode' => 'cro-HR', + 'value' => new FloatValue(3.14), + ]); + $checkboxField = new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezboolean', + 'languageCode' => 'cro-HR', + 'value' => new CheckboxValue(true), + ]); + $isbnField = new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezisbn', + 'languageCode' => 'cro-HR', + 'value' => new ISBNValue('9780061936456'), + ]); + return [ [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $textLineField, [ new SortClause\Field('type', 'field', Query::SORT_ASC), ], @@ -766,12 +660,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $textLineField, [ new SortClause\Field('type', 'field', Query::SORT_DESC), ], @@ -786,12 +675,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $textLineField, [ new SortClause\Field('type', 'field', Query::SORT_ASC), ], @@ -806,12 +690,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezstring', - 'languageCode' => 'cro-HR', - 'value' => new TextLineValue('Zagreb'), - ]), + $textLineField, [ new SortClause\Field('type', 'field', Query::SORT_DESC), ], @@ -826,12 +705,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'eztext', - 'languageCode' => 'cro-HR', - 'value' => new TextBlockValue('Zagreb'), - ]), + $textBlockField, [ new SortClause\Field('type', 'field', Query::SORT_ASC), ], @@ -846,12 +720,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'eztext', - 'languageCode' => 'cro-HR', - 'value' => new TextBlockValue('Zagreb'), - ]), + $textBlockField, [ new SortClause\Field('type', 'field', Query::SORT_DESC), ], @@ -866,12 +735,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'eztext', - 'languageCode' => 'cro-HR', - 'value' => new TextBlockValue('Zagreb'), - ]), + $textBlockField, [ new SortClause\Field('type', 'field', Query::SORT_ASC), ], @@ -886,12 +750,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'eztext', - 'languageCode' => 'cro-HR', - 'value' => new TextBlockValue('Zagreb'), - ]), + $textBlockField, [ new SortClause\Field('type', 'field', Query::SORT_DESC), ], @@ -906,12 +765,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezdate', - 'languageCode' => 'cro-HR', - 'value' => new DateValue(new DateTime('@' . self::Timestamp)), - ]), + $dateField, [ new SortClause\Field('type', 'field', Query::SORT_ASC), ], @@ -926,12 +780,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezdate', - 'languageCode' => 'cro-HR', - 'value' => new DateValue(new DateTime('@' . self::Timestamp)), - ]), + $dateField, [ new SortClause\Field('type', 'field', Query::SORT_DESC), ], @@ -946,12 +795,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezdate', - 'languageCode' => 'cro-HR', - 'value' => new DateValue(new DateTime('@' . self::Timestamp)), - ]), + $dateField, [ new SortClause\Field('type', 'field', Query::SORT_ASC), ], @@ -966,12 +810,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezdate', - 'languageCode' => 'cro-HR', - 'value' => new DateValue(new DateTime('@' . self::Timestamp)), - ]), + $dateField, [ new SortClause\Field('type', 'field', Query::SORT_DESC), ], @@ -986,12 +825,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezdatetime', - 'languageCode' => 'cro-HR', - 'value' => new DateAndTimeValue(new DateTime('@' . self::Timestamp)), - ]), + $dateAndTimeField, [ new SortClause\Field('type', 'field', Query::SORT_ASC), ], @@ -1006,12 +840,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezdatetime', - 'languageCode' => 'cro-HR', - 'value' => new DateAndTimeValue(new DateTime('@' . self::Timestamp)), - ]), + $dateAndTimeField, [ new SortClause\Field('type', 'field', Query::SORT_DESC), ], @@ -1026,12 +855,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezdatetime', - 'languageCode' => 'cro-HR', - 'value' => new DateAndTimeValue(new DateTime('@' . self::Timestamp)), - ]), + $dateAndTimeField, [ new SortClause\Field('type', 'field', Query::SORT_ASC), ], @@ -1046,12 +870,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezdatetime', - 'languageCode' => 'cro-HR', - 'value' => new DateAndTimeValue(new DateTime('@' . self::Timestamp)), - ]), + $dateAndTimeField, [ new SortClause\Field('type', 'field', Query::SORT_DESC), ], @@ -1066,12 +885,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'eztime', - 'languageCode' => 'cro-HR', - 'value' => TimeValue::fromDateTime(new DateTime('@' . self::Timestamp)), - ]), + $timeField, [ new SortClause\Field('type', 'field', Query::SORT_ASC), ], @@ -1086,12 +900,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'eztime', - 'languageCode' => 'cro-HR', - 'value' => TimeValue::fromDateTime(new DateTime('@' . self::Timestamp)), - ]), + $timeField, [ new SortClause\Field('type', 'field', Query::SORT_DESC), ], @@ -1106,12 +915,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'eztime', - 'languageCode' => 'cro-HR', - 'value' => TimeValue::fromDateTime(new DateTime('@' . self::Timestamp)), - ]), + $timeField, [ new SortClause\Field('type', 'field', Query::SORT_ASC), ], @@ -1126,12 +930,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'eztime', - 'languageCode' => 'cro-HR', - 'value' => TimeValue::fromDateTime(new DateTime('@' . self::Timestamp)), - ]), + $timeField, [ new SortClause\Field('type', 'field', Query::SORT_DESC), ], @@ -1146,92 +945,67 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezemail', - 'languageCode' => 'cro-HR', - 'value' => new EmailAddressValue('spam@invalid.asdf'), - ]), + $mailAddressField, [ new SortClause\Field('type', 'field', Query::SORT_ASC), ], SiblingRangeResolver::RangeTypeFollowing, new LogicalOr([ new LogicalAnd([ - new Criterion\Field('field', Operator::GTE, 'spam@invalid.asdf'), + new Criterion\Field('field', Operator::GTE, 'test@netgen.io'), new ContentId(Operator::GT, 42), ]), - new Criterion\Field('field', Operator::GT, 'spam@invalid.asdf'), + new Criterion\Field('field', Operator::GT, 'test@netgen.io'), ]), ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezemail', - 'languageCode' => 'cro-HR', - 'value' => new EmailAddressValue('spam@invalid.asdf'), - ]), + $mailAddressField, [ new SortClause\Field('type', 'field', Query::SORT_DESC), ], SiblingRangeResolver::RangeTypeFollowing, new LogicalOr([ new LogicalAnd([ - new Criterion\Field('field', Operator::LTE, 'spam@invalid.asdf'), + new Criterion\Field('field', Operator::LTE, 'test@netgen.io'), new ContentId(Operator::GT, 42), ]), - new Criterion\Field('field', Operator::LT, 'spam@invalid.asdf'), + new Criterion\Field('field', Operator::LT, 'test@netgen.io'), ]), ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezemail', - 'languageCode' => 'cro-HR', - 'value' => new EmailAddressValue('spam@invalid.asdf'), - ]), + $mailAddressField, [ new SortClause\Field('type', 'field', Query::SORT_ASC), ], SiblingRangeResolver::RangeTypePreceding, new LogicalOr([ new LogicalAnd([ - new Criterion\Field('field', Operator::LTE, 'spam@invalid.asdf'), + new Criterion\Field('field', Operator::LTE, 'test@netgen.io'), new ContentId(Operator::LT, 42), ]), - new Criterion\Field('field', Operator::LT, 'spam@invalid.asdf'), + new Criterion\Field('field', Operator::LT, 'test@netgen.io'), ]), ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezemail', - 'languageCode' => 'cro-HR', - 'value' => new EmailAddressValue('spam@invalid.asdf'), - ]), + $mailAddressField, [ new SortClause\Field('type', 'field', Query::SORT_DESC), ], SiblingRangeResolver::RangeTypePreceding, new LogicalOr([ new LogicalAnd([ - new Criterion\Field('field', Operator::GTE, 'spam@invalid.asdf'), + new Criterion\Field('field', Operator::GTE, 'test@netgen.io'), new ContentId(Operator::LT, 42), ]), - new Criterion\Field('field', Operator::GT, 'spam@invalid.asdf'), + new Criterion\Field('field', Operator::GT, 'test@netgen.io'), ]), ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezinteger', - 'languageCode' => 'cro-HR', - 'value' => new IntegerValue(22), - ]), + $integerField, [ new SortClause\Field('type', 'field', Query::SORT_ASC), ], @@ -1246,12 +1020,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezinteger', - 'languageCode' => 'cro-HR', - 'value' => new IntegerValue(22), - ]), + $integerField, [ new SortClause\Field('type', 'field', Query::SORT_DESC), ], @@ -1266,12 +1035,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezinteger', - 'languageCode' => 'cro-HR', - 'value' => new IntegerValue(22), - ]), + $integerField, [ new SortClause\Field('type', 'field', Query::SORT_ASC), ], @@ -1286,12 +1050,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezinteger', - 'languageCode' => 'cro-HR', - 'value' => new IntegerValue(22), - ]), + $integerField, [ new SortClause\Field('type', 'field', Query::SORT_DESC), ], @@ -1306,12 +1065,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezfloat', - 'languageCode' => 'cro-HR', - 'value' => new FloatValue(3.14), - ]), + $floatField, [ new SortClause\Field('type', 'field', Query::SORT_ASC), ], @@ -1326,12 +1080,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezfloat', - 'languageCode' => 'cro-HR', - 'value' => new FloatValue(3.14), - ]), + $floatField, [ new SortClause\Field('type', 'field', Query::SORT_DESC), ], @@ -1346,12 +1095,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezfloat', - 'languageCode' => 'cro-HR', - 'value' => new FloatValue(3.14), - ]), + $floatField, [ new SortClause\Field('type', 'field', Query::SORT_ASC), ], @@ -1366,12 +1110,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezfloat', - 'languageCode' => 'cro-HR', - 'value' => new FloatValue(3.14), - ]), + $floatField, [ new SortClause\Field('type', 'field', Query::SORT_DESC), ], @@ -1386,12 +1125,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezboolean', - 'languageCode' => 'cro-HR', - 'value' => new CheckboxValue(true), - ]), + $checkboxField, [ new SortClause\Field('type', 'field', Query::SORT_ASC), ], @@ -1406,12 +1140,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezboolean', - 'languageCode' => 'cro-HR', - 'value' => new CheckboxValue(true), - ]), + $checkboxField, [ new SortClause\Field('type', 'field', Query::SORT_DESC), ], @@ -1426,12 +1155,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezboolean', - 'languageCode' => 'cro-HR', - 'value' => new CheckboxValue(true), - ]), + $checkboxField, [ new SortClause\Field('type', 'field', Query::SORT_ASC), ], @@ -1446,12 +1170,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezboolean', - 'languageCode' => 'cro-HR', - 'value' => new CheckboxValue(true), - ]), + $checkboxField, [ new SortClause\Field('type', 'field', Query::SORT_DESC), ], @@ -1466,12 +1185,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezisbn', - 'languageCode' => 'cro-HR', - 'value' => new ISBNValue('9780061936456'), - ]), + $isbnField, [ new SortClause\Field('type', 'field', Query::SORT_ASC), ], @@ -1486,12 +1200,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezisbn', - 'languageCode' => 'cro-HR', - 'value' => new ISBNValue('9780061936456'), - ]), + $isbnField, [ new SortClause\Field('type', 'field', Query::SORT_DESC), ], @@ -1506,12 +1215,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezisbn', - 'languageCode' => 'cro-HR', - 'value' => new ISBNValue('9780061936456'), - ]), + $isbnField, [ new SortClause\Field('type', 'field', Query::SORT_ASC), ], @@ -1526,12 +1230,7 @@ public function providerForTestResolveCriterionField(): array ], [ 42, - new Field([ - 'fieldDefIdentifier' => 'field', - 'fieldTypeIdentifier' => 'ezisbn', - 'languageCode' => 'cro-HR', - 'value' => new ISBNValue('9780061936456'), - ]), + $isbnField, [ new SortClause\Field('type', 'field', Query::SORT_DESC), ], @@ -1570,9 +1269,514 @@ public function testResolveCriterionField( self::assertEquals($expectedCriterion, $actualCriterion); } - public function testResolveSortClauses(): void + /** + * @throws \Exception + */ + public function testResolveCriterionWithNonExistentField(): void { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Field "field" not found on the given Content'); + $field = new Field([ + 'fieldDefIdentifier' => 'hill', + 'fieldTypeIdentifier' => 'ezisbn', + 'languageCode' => 'cro-HR', + 'value' => new ISBNValue('9780061936456'), + ]); + + $content = $this->getContent(42, $field); + + $this->getServiceUnderTest()->resolveCriterion( + $content, + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing + ); + } + + /** + * @throws \Exception + */ + public function testResolveCriterionWithUnsupportedFieldType(): void + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Field type "ezobjectrelationlist" is not supported'); + + $field = new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezobjectrelationlist', + 'languageCode' => 'cro-HR', + 'value' => new RelationListValue(), + ]); + + $content = $this->getContent(42, $field); + + $this->getServiceUnderTest()->resolveCriterion( + $content, + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing + ); + } + + public function providerForTestResolveSortClauses(): array + { + $field = new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]); + + return [ + [ + 42, + $field, + [], + SiblingRangeResolver::RangeTypeFollowing, + [ + new SortClause\ContentId(Query::SORT_ASC), + ], + ], + [ + 42, + $field, + [], + SiblingRangeResolver::RangeTypePreceding, + [ + new SortClause\ContentId(Query::SORT_DESC), + ], + ], + [ + 42, + $field, + [ + new SortClause\ContentName(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + [ + new SortClause\ContentId(Query::SORT_ASC), + ], + ], + [ + 42, + $field, + [ + new SortClause\ContentName(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + [ + new SortClause\ContentId(Query::SORT_ASC), + ], + ], + [ + 42, + $field, + [ + new SortClause\ContentName(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + [ + new SortClause\ContentId(Query::SORT_DESC), + ], + ], + [ + 42, + $field, + [ + new SortClause\ContentName(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + [ + new SortClause\ContentId(Query::SORT_DESC), + ], + ], + [ + 42, + $field, + [ + new SortClause\ContentId(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + [ + new SortClause\ContentId(Query::SORT_ASC), + ], + ], + [ + 42, + $field, + [ + new SortClause\ContentId(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + [ + new SortClause\ContentId(Query::SORT_ASC), + ], + ], + [ + 42, + $field, + [ + new SortClause\ContentId(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + [ + new SortClause\ContentId(Query::SORT_ASC), + ], + ], + [ + 42, + $field, + [ + new SortClause\ContentId(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + [ + new SortClause\ContentId(Query::SORT_DESC), + ], + ], + [ + 42, + $field, + [ + new SortClause\DateModified(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + [ + new SortClause\ContentId(Query::SORT_ASC), + ], + ], + [ + 42, + $field, + [ + new SortClause\DateModified(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + [ + new SortClause\ContentId(Query::SORT_ASC), + ], + ], + [ + 42, + $field, + [ + new SortClause\DateModified(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + [ + new SortClause\ContentId(Query::SORT_DESC), + ], + ], + [ + 42, + $field, + [ + new SortClause\DateModified(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + [ + new SortClause\ContentId(Query::SORT_DESC), + ], + ], + [ + 42, + $field, + [ + new SortClause\DatePublished(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + [ + new SortClause\ContentId(Query::SORT_ASC), + ], + ], + [ + 42, + $field, + [ + new SortClause\DatePublished(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + [ + new SortClause\ContentId(Query::SORT_ASC), + ], + ], + [ + 42, + $field, + [ + new SortClause\DatePublished(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + [ + new SortClause\ContentId(Query::SORT_DESC), + ], + ], + [ + 42, + $field, + [ + new SortClause\DatePublished(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + [ + new SortClause\ContentId(Query::SORT_DESC), + ], + ], + [ + 42, + $field, + [ + new SortClause\Location\Depth(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + [ + new SortClause\ContentId(Query::SORT_ASC), + ], + ], + [ + 42, + $field, + [ + new SortClause\Location\Depth(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + [ + new SortClause\ContentId(Query::SORT_ASC), + ], + ], + [ + 42, + $field, + [ + new SortClause\Location\Depth(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + [ + new SortClause\ContentId(Query::SORT_DESC), + ], + ], + [ + 42, + $field, + [ + new SortClause\Location\Depth(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + [ + new SortClause\ContentId(Query::SORT_DESC), + ], + ], + [ + 42, + $field, + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + [ + new SortClause\ContentId(Query::SORT_ASC), + ], + ], + [ + 42, + $field, + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + [ + new SortClause\ContentId(Query::SORT_ASC), + ], + ], + [ + 42, + $field, + [ + new SortClause\Field('type', 'field', Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + [ + new SortClause\ContentId(Query::SORT_DESC), + ], + ], + [ + 42, + $field, + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + [ + new SortClause\ContentId(Query::SORT_DESC), + ], + ], + [ + 42, + $field, + [ + new SortClause\Location\Id(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + [ + new SortClause\ContentId(Query::SORT_ASC), + ], + ], + [ + 42, + $field, + [ + new SortClause\Location\Id(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + [ + new SortClause\ContentId(Query::SORT_ASC), + ], + ], + [ + 42, + $field, + [ + new SortClause\Location\Id(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + [ + new SortClause\ContentId(Query::SORT_DESC), + ], + ], + [ + 42, + $field, + [ + new SortClause\Location\Id(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + [ + new SortClause\ContentId(Query::SORT_DESC), + ], + ], + [ + 42, + $field, + [ + new SortClause\Location\Priority(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypeFollowing, + [ + new SortClause\ContentId(Query::SORT_ASC), + ], + ], + [ + 42, + $field, + [ + new SortClause\Location\Priority(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypeFollowing, + [ + new SortClause\ContentId(Query::SORT_ASC), + ], + ], + [ + 42, + $field, + [ + new SortClause\Location\Priority(Query::SORT_ASC), + ], + SiblingRangeResolver::RangeTypePreceding, + [ + new SortClause\ContentId(Query::SORT_DESC), + ], + ], + [ + 42, + $field, + [ + new SortClause\Location\Priority(Query::SORT_DESC), + ], + SiblingRangeResolver::RangeTypePreceding, + [ + new SortClause\ContentId(Query::SORT_DESC), + ], + ], + ]; + } + + /** + * @dataProvider providerForTestResolveSortClauses + * + * @throws \Exception + */ + public function testResolveSortClauses( + int $id, + Field $field, + array $sortClauses, + string $rangeType, + array $expectedSortClauses + ): void { + $content = $this->getContent($id, $field); + + $actualSortClauses = $this->getServiceUnderTest()->resolveSortClauses( + $content, + $sortClauses, + $rangeType + ); + + self::assertEquals($expectedSortClauses, $actualSortClauses); + } + + /** + * @throws \Exception + */ + public function testResolverCriterionWithUnsupportedSortClause(): void + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Sort clause "' . SortClause\MapLocationDistance::class . '" is not supported'); + + $field = new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]); + + $content = $this->getContent(42, $field); + + $this->getServiceUnderTest()->resolveCriterion( + $content, + [ + new SortClause\MapLocationDistance('type', 'field', 16, 42), + ], + SiblingRangeResolver::RangeTypeFollowing + ); + } + + /** + * @throws \Exception + */ + public function testResolverCriterionWithUnsupportedRange(): void + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Unknown range "SomeRange"'); + + $field = new Field([ + 'fieldDefIdentifier' => 'field', + 'fieldTypeIdentifier' => 'ezstring', + 'languageCode' => 'cro-HR', + 'value' => new TextLineValue('Zagreb'), + ]); + + $content = $this->getContent(42, $field); + + $this->getServiceUnderTest()->resolveCriterion( + $content, + [ + new SortClause\Field('type', 'field', Query::SORT_DESC), + ], + 'SomeRange' + ); } public function testModifyQuery(): void From d3eaa2cf34c929b3dddb0146840d02a44791bd6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petar=20=C5=A0panja?= Date: Wed, 17 Feb 2021 11:53:57 +0100 Subject: [PATCH 3/5] NGSTACK-361: complete tests for resolveSortClauses() --- .../Repository/SiblingRangeResolverTest.php | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/lib/Unit/API/Repository/SiblingRangeResolverTest.php b/tests/lib/Unit/API/Repository/SiblingRangeResolverTest.php index 9296ad21..7d8f7be5 100644 --- a/tests/lib/Unit/API/Repository/SiblingRangeResolverTest.php +++ b/tests/lib/Unit/API/Repository/SiblingRangeResolverTest.php @@ -1357,6 +1357,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypeFollowing, [ + new SortClause\ContentName(Query::SORT_ASC), new SortClause\ContentId(Query::SORT_ASC), ], ], @@ -1368,6 +1369,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypeFollowing, [ + new SortClause\ContentName(Query::SORT_DESC), new SortClause\ContentId(Query::SORT_ASC), ], ], @@ -1379,6 +1381,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypePreceding, [ + new SortClause\ContentName(Query::SORT_DESC), new SortClause\ContentId(Query::SORT_DESC), ], ], @@ -1390,6 +1393,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypePreceding, [ + new SortClause\ContentName(Query::SORT_ASC), new SortClause\ContentId(Query::SORT_DESC), ], ], @@ -1402,6 +1406,7 @@ public function providerForTestResolveSortClauses(): array SiblingRangeResolver::RangeTypeFollowing, [ new SortClause\ContentId(Query::SORT_ASC), + new SortClause\ContentId(Query::SORT_ASC), ], ], [ @@ -1412,6 +1417,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypeFollowing, [ + new SortClause\ContentId(Query::SORT_DESC), new SortClause\ContentId(Query::SORT_ASC), ], ], @@ -1424,6 +1430,7 @@ public function providerForTestResolveSortClauses(): array SiblingRangeResolver::RangeTypeFollowing, [ new SortClause\ContentId(Query::SORT_ASC), + new SortClause\ContentId(Query::SORT_ASC), ], ], [ @@ -1434,6 +1441,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypePreceding, [ + new SortClause\ContentId(Query::SORT_ASC), new SortClause\ContentId(Query::SORT_DESC), ], ], @@ -1445,6 +1453,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypeFollowing, [ + new SortClause\DateModified(Query::SORT_ASC), new SortClause\ContentId(Query::SORT_ASC), ], ], @@ -1456,6 +1465,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypeFollowing, [ + new SortClause\DateModified(Query::SORT_DESC), new SortClause\ContentId(Query::SORT_ASC), ], ], @@ -1467,6 +1477,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypePreceding, [ + new SortClause\DateModified(Query::SORT_DESC), new SortClause\ContentId(Query::SORT_DESC), ], ], @@ -1478,6 +1489,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypePreceding, [ + new SortClause\DateModified(Query::SORT_ASC), new SortClause\ContentId(Query::SORT_DESC), ], ], @@ -1489,6 +1501,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypeFollowing, [ + new SortClause\DatePublished(Query::SORT_ASC), new SortClause\ContentId(Query::SORT_ASC), ], ], @@ -1500,6 +1513,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypeFollowing, [ + new SortClause\DatePublished(Query::SORT_DESC), new SortClause\ContentId(Query::SORT_ASC), ], ], @@ -1511,6 +1525,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypePreceding, [ + new SortClause\DatePublished(Query::SORT_DESC), new SortClause\ContentId(Query::SORT_DESC), ], ], @@ -1522,6 +1537,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypePreceding, [ + new SortClause\DatePublished(Query::SORT_ASC), new SortClause\ContentId(Query::SORT_DESC), ], ], @@ -1533,6 +1549,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypeFollowing, [ + new SortClause\Location\Depth(Query::SORT_ASC), new SortClause\ContentId(Query::SORT_ASC), ], ], @@ -1544,6 +1561,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypeFollowing, [ + new SortClause\Location\Depth(Query::SORT_DESC), new SortClause\ContentId(Query::SORT_ASC), ], ], @@ -1555,6 +1573,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypePreceding, [ + new SortClause\Location\Depth(Query::SORT_DESC), new SortClause\ContentId(Query::SORT_DESC), ], ], @@ -1566,6 +1585,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypePreceding, [ + new SortClause\Location\Depth(Query::SORT_ASC), new SortClause\ContentId(Query::SORT_DESC), ], ], @@ -1577,6 +1597,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypeFollowing, [ + new SortClause\Field('type', 'field', Query::SORT_ASC), new SortClause\ContentId(Query::SORT_ASC), ], ], @@ -1588,6 +1609,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypeFollowing, [ + new SortClause\Field('type', 'field', Query::SORT_DESC), new SortClause\ContentId(Query::SORT_ASC), ], ], @@ -1599,6 +1621,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypePreceding, [ + new SortClause\Field('type', 'field', Query::SORT_DESC), new SortClause\ContentId(Query::SORT_DESC), ], ], @@ -1610,6 +1633,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypePreceding, [ + new SortClause\Field('type', 'field', Query::SORT_ASC), new SortClause\ContentId(Query::SORT_DESC), ], ], @@ -1621,6 +1645,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypeFollowing, [ + new SortClause\Location\Id(Query::SORT_ASC), new SortClause\ContentId(Query::SORT_ASC), ], ], @@ -1632,6 +1657,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypeFollowing, [ + new SortClause\Location\Id(Query::SORT_DESC), new SortClause\ContentId(Query::SORT_ASC), ], ], @@ -1643,6 +1669,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypePreceding, [ + new SortClause\Location\Id(Query::SORT_DESC), new SortClause\ContentId(Query::SORT_DESC), ], ], @@ -1654,6 +1681,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypePreceding, [ + new SortClause\Location\Id(Query::SORT_ASC), new SortClause\ContentId(Query::SORT_DESC), ], ], @@ -1665,6 +1693,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypeFollowing, [ + new SortClause\Location\Priority(Query::SORT_ASC), new SortClause\ContentId(Query::SORT_ASC), ], ], @@ -1676,6 +1705,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypeFollowing, [ + new SortClause\Location\Priority(Query::SORT_DESC), new SortClause\ContentId(Query::SORT_ASC), ], ], @@ -1687,6 +1717,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypePreceding, [ + new SortClause\Location\Priority(Query::SORT_DESC), new SortClause\ContentId(Query::SORT_DESC), ], ], @@ -1698,6 +1729,7 @@ public function providerForTestResolveSortClauses(): array ], SiblingRangeResolver::RangeTypePreceding, [ + new SortClause\Location\Priority(Query::SORT_ASC), new SortClause\ContentId(Query::SORT_DESC), ], ], From a88b56d087c78e2b41223444e6c3b5d5adbac9ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petar=20=C5=A0panja?= Date: Wed, 17 Feb 2021 12:39:52 +0100 Subject: [PATCH 4/5] NGSTACK-361: fix collecting sort clauses --- lib/API/Repository/SiblingRangeResolver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/API/Repository/SiblingRangeResolver.php b/lib/API/Repository/SiblingRangeResolver.php index ed8c4882..7997ef9d 100644 --- a/lib/API/Repository/SiblingRangeResolver.php +++ b/lib/API/Repository/SiblingRangeResolver.php @@ -155,7 +155,7 @@ public function resolveSortClauses(ValueObject $value, array $sortClauses, strin $newSortClause->direction = $this->reverseDirection($sortClause); } - $sortClauses[] = $newSortClause; + $newSortClauses[] = $newSortClause; } $newSortClauses[] = $this->getTieBreakerSortClause($value, $rangeType); From e4a0804e45c17522bb35d884b0964b7a591c992a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petar=20=C5=A0panja?= Date: Tue, 23 Feb 2021 11:52:00 +0100 Subject: [PATCH 5/5] TMP: comment out empty facet data check --- lib/Core/Search/Solr/ResultExtractor.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Core/Search/Solr/ResultExtractor.php b/lib/Core/Search/Solr/ResultExtractor.php index 9ff759ef..7290793b 100644 --- a/lib/Core/Search/Solr/ResultExtractor.php +++ b/lib/Core/Search/Solr/ResultExtractor.php @@ -16,9 +16,9 @@ public function extract($data, array $facetBuilders = []) { $searchResult = $this->extractSearchResult($data, $facetBuilders); - if (!isset($data->facets) || $data->facets->count === 0) { - return $searchResult; - } +// if (!isset($data->facets) || $data->facets->count === 0) { +// return $searchResult; +// } foreach ($this->filterNewFacetBuilders($facetBuilders) as $facetBuilder) { $identifier = \spl_object_hash($facetBuilder);