Skip to content

Commit

Permalink
Support for getting the results for a location (#38)
Browse files Browse the repository at this point in the history
  • Loading branch information
Bertrand Dunogier authored Jan 13, 2021
1 parent 2ebe523 commit e3de453
Show file tree
Hide file tree
Showing 9 changed files with 300 additions and 87 deletions.
70 changes: 54 additions & 16 deletions spec/API/QueryFieldServiceSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
class QueryFieldServiceSpec extends ObjectBehavior
{
const CONTENT_TYPE_ID = 1;
const CONTENT_TYPE_ID_WITHOUT_PAGINATION = 2;
const LOCATION_ID = 1;
const QUERY_TYPE_IDENTIFIER = 'query_type_identifier';
const FIELD_DEFINITION_IDENTIFIER = 'test';
Expand All @@ -46,24 +47,16 @@ function let(
'param2' => 'value2',
];

$contentType = new Values\ContentType\ContentType([
'fieldDefinitions' => new Values\ContentType\FieldDefinitionCollection([
new Values\ContentType\FieldDefinition([
'identifier' => self::FIELD_DEFINITION_IDENTIFIER,
'fieldTypeIdentifier' => 'ezcontentquery',
'fieldSettings' => [
'ReturnedType' => 'folder',
'QueryType' => self::QUERY_TYPE_IDENTIFIER,
'Parameters' => $parameters,
],
]),
]),
]);
$location = new Values\Content\Location([
'id' => self::LOCATION_ID,
]);

$contentTypeService->loadContentType(self::CONTENT_TYPE_ID)->willReturn($contentType);
$contentTypeWithPagination = $this->getContentType($parameters);
$contentTypeService->loadContentType(self::CONTENT_TYPE_ID)->willReturn($contentTypeWithPagination);

$contentTypeWithoutPagination = $this->getContentType($parameters, false, 10);
$contentTypeService->loadContentType(self::CONTENT_TYPE_ID_WITHOUT_PAGINATION)->willReturn($contentTypeWithoutPagination);

$locationService->loadLocation(self::LOCATION_ID)->willReturn($location);
$queryTypeRegistry->getQueryType(self::QUERY_TYPE_IDENTIFIER)->willReturn($queryType);
$queryType->getQuery(Argument::any())->willReturn(new ApiQuery());
Expand Down Expand Up @@ -113,18 +106,63 @@ function it_returns_zero_if_offset_is_bigger_than_count(QueryType $queryType, Se
$this->countContentItems($this->getContent(), self::FIELD_DEFINITION_IDENTIFIER)->shouldBe(0);
}

function it_returns_0_as_pagination_configuration_if_pagination_is_disabled()
{
$this->getPaginationConfiguration(
$this->getContent(self::CONTENT_TYPE_ID_WITHOUT_PAGINATION),
self::FIELD_DEFINITION_IDENTIFIER
)->shouldBe(0);
}

function it_returns_the_items_per_page_number_as_pagination_configuration_if_pagination_is_enabled()
{
$this->getPaginationConfiguration(
$this->getContent(),
self::FIELD_DEFINITION_IDENTIFIER
)->shouldBe(10);
}

/**
* @return \eZ\Publish\Core\Repository\Values\Content\Content
*/
private function getContent(): Values\Content\Content
private function getContent(int $contentTypeId = self::CONTENT_TYPE_ID): Values\Content\Content
{
return new Values\Content\Content([
'versionInfo' => new Values\Content\VersionInfo([
'contentInfo' => new ContentInfo([
'contentTypeId' => self::CONTENT_TYPE_ID,
'contentTypeId' => $contentTypeId,
'mainLocationId' => self::LOCATION_ID,
'mainLocation' => new Values\Content\Location([
'id' => self::LOCATION_ID,
]),
]),
]),
]);
}

/**
* @param array $parameters
*
* @return \eZ\Publish\API\Repository\Values\ContentType\ContentType
*/
private function getContentType(array $parameters, bool $enablePagination = true, $itemsPerPage = 10): \eZ\Publish\API\Repository\Values\ContentType\ContentType
{
$contentType = new Values\ContentType\ContentType([
'fieldDefinitions' => new Values\ContentType\FieldDefinitionCollection([
new Values\ContentType\FieldDefinition([
'identifier' => self::FIELD_DEFINITION_IDENTIFIER,
'fieldTypeIdentifier' => 'ezcontentquery',
'fieldSettings' => [
'ReturnedType' => 'folder',
'QueryType' => self::QUERY_TYPE_IDENTIFIER,
'EnablePagination' => $enablePagination,
'ItemsPerPage' => $itemsPerPage,
'Parameters' => $parameters,
],
]),
]),
]);

return $contentType;
}
}
34 changes: 34 additions & 0 deletions src/API/QueryFieldLocationService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

/**
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
namespace EzSystems\EzPlatformQueryFieldType\API;

use eZ\Publish\API\Repository\Values\Content\Location;

/**
* Executes queries for a query field for a given a location.
*/
interface QueryFieldLocationService
{
/**
* Returns the query results for the given location.
*
* @return iterable An iterable that yields Content items.
*/
public function loadContentItemsForLocation(Location $location, string $fieldDefinitionIdentifier): iterable;

/**
* Returns a slice of the query results for the given location.
*
* @return iterable An iterable that yields Content items.
*/
public function loadContentItemsSliceForLocation(Location $location, string $fieldDefinitionIdentifier, int $offset, int $limit): iterable;

/**
* Counts the results for the given location.
*/
public function countContentItemsForLocation(Location $location, string $fieldDefinitionIdentifier): int;
}
104 changes: 53 additions & 51 deletions src/API/QueryFieldService.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use eZ\Publish\API\Repository\LocationService;
use eZ\Publish\API\Repository\SearchService;
use eZ\Publish\API\Repository\Values\Content\Content;
use eZ\Publish\API\Repository\Values\Content\Location;
use eZ\Publish\API\Repository\Values\Content\Query;
use eZ\Publish\API\Repository\Values\Content\Search\SearchHit;
use eZ\Publish\API\Repository\Values\ContentType\FieldDefinition;
Expand All @@ -21,7 +22,7 @@
/**
* Executes a query and returns the results.
*/
final class QueryFieldService implements QueryFieldServiceInterface
final class QueryFieldService implements QueryFieldServiceInterface, QueryFieldLocationService
{
/** @var \eZ\Publish\Core\QueryType\QueryTypeRegistry */
private $queryTypeRegistry;
Expand All @@ -48,29 +49,33 @@ public function __construct(
$this->queryTypeRegistry = $queryTypeRegistry;
}

/**
* @param \eZ\Publish\API\Repository\Values\Content\Content $content
* @param string $fieldDefinitionIdentifier
*
* @return \eZ\Publish\API\Repository\Values\Content\Content[]
*
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
*/
public function loadContentItems(Content $content, string $fieldDefinitionIdentifier): iterable
{
$query = $this->prepareQuery($content, $fieldDefinitionIdentifier);
$query = $this->prepareQuery($content, $content->contentInfo->getMainLocation(), $fieldDefinitionIdentifier);

return array_map(
function (SearchHit $searchHit) {
return $searchHit->valueObject;
},
$this->searchService->findContent($query)->searchHits
);
return $this->executeQueryAndMapResult($query);
}

public function loadContentItemsForLocation(Location $location, string $fieldDefinitionIdentifier): iterable
{
$query = $this->prepareQuery($location->getContent(), $location, $fieldDefinitionIdentifier);

return $this->executeQueryAndMapResult($query);
}

public function countContentItems(Content $content, string $fieldDefinitionIdentifier): int
{
$query = $this->prepareQuery($content, $fieldDefinitionIdentifier);
$query = $this->prepareQuery($content, $content->contentInfo->getMainLocation(), $fieldDefinitionIdentifier);
$query->limit = 0;

$count = $this->searchService->findContent($query)->totalCount - $query->offset;

return $count < 0 ? 0 : $count;
}

public function countContentItemsForLocation(Location $location, string $fieldDefinitionIdentifier): int
{
$query = $this->prepareQuery($location->getContent(), $location, $fieldDefinitionIdentifier);
$query->limit = 0;

$count = $this->searchService->findContent($query)->totalCount - $query->offset;
Expand All @@ -80,34 +85,35 @@ public function countContentItems(Content $content, string $fieldDefinitionIdent

public function loadContentItemsSlice(Content $content, string $fieldDefinitionIdentifier, int $offset, int $limit): iterable
{
$query = $this->prepareQuery($content, $fieldDefinitionIdentifier);
$query->offset += $offset;
$query = $this->prepareQuery($content, $content->contentInfo->getMainLocation(), $fieldDefinitionIdentifier);
$query->offset = $offset;
$query->limit = $limit;

return array_map(
function (SearchHit $searchHit) {
return $searchHit->valueObject;
},
$this->searchService->findContent($query)->searchHits
);
return $this->executeQueryAndMapResult($query);
}

public function loadContentItemsSliceForLocation(Location $location, string $fieldDefinitionIdentifier, int $offset, int $limit): iterable
{
$query = $this->prepareQuery($location->getContent(), $location, $fieldDefinitionIdentifier);
$query->offset = $offset;
$query->limit = $limit;

return $this->executeQueryAndMapResult($query);
}

public function getPaginationConfiguration(Content $content, string $fieldDefinitionIdentifier): int
{
$fieldDefinition = $this->loadFieldDefinition($content, $fieldDefinitionIdentifier);

if ($fieldDefinition->fieldSettings['EnablePagination'] === false) {
return false;
return 0;
}

return $fieldDefinition->fieldSettings['ItemsPerPage'];
}

/**
* @param array $expressions parameters that may include expressions to be resolved
* @param array $variables
*
* @return array
*/
private function resolveParameters(array $expressions, array $variables): array
{
Expand All @@ -130,11 +136,6 @@ private function isExpression($expression): bool
}

/**
* @param string $expression
* @param array $variables
*
* @return mixed
*
* @throws \eZ\Publish\Core\Base\Exceptions\InvalidArgumentException if $expression is not an expression.
*/
private function resolveExpression(string $expression, array $variables)
Expand All @@ -146,20 +147,10 @@ private function resolveExpression(string $expression, array $variables)
return (new ExpressionLanguage())->evaluate(substr($expression, 2), $variables);
}

/**
* @param \eZ\Publish\API\Repository\Values\Content\Content $content
* @param string $fieldDefinitionIdentifier
*
* @return \eZ\Publish\API\Repository\Values\Content\Query
*
* @throws \eZ\Publish\Core\Base\Exceptions\InvalidArgumentException
* @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
*/
private function prepareQuery(Content $content, string $fieldDefinitionIdentifier, array $extraParameters = []): Query
private function prepareQuery(Content $content, Location $location, string $fieldDefinitionIdentifier, array $extraParameters = []): Query
{
$fieldDefinition = $this->loadFieldDefinition($content, $fieldDefinitionIdentifier);

$location = $this->locationService->loadLocation($content->contentInfo->mainLocationId);
$queryType = $this->queryTypeRegistry->getQueryType($fieldDefinition->fieldSettings['QueryType']);
$parameters = $this->resolveParameters(
$fieldDefinition->fieldSettings['Parameters'],
Expand All @@ -168,7 +159,8 @@ private function prepareQuery(Content $content, string $fieldDefinitionIdentifie
[
'content' => $content,
'contentInfo' => $content->contentInfo,
'mainLocation' => $location,
'location' => $location,
'mainLocation' => $location->id === $content->contentInfo->mainLocationId ? $location : $content->contentInfo->getMainLocation(),
'returnedType' => $fieldDefinition->fieldSettings['ReturnedType'],
]
)
Expand All @@ -178,11 +170,6 @@ private function prepareQuery(Content $content, string $fieldDefinitionIdentifie
}

/**
* @param \eZ\Publish\API\Repository\Values\Content\Content $content
* @param string $fieldDefinitionIdentifier
*
* @return \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition|null
*
* @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
*/
private function loadFieldDefinition(Content $content, string $fieldDefinitionIdentifier): FieldDefinition
Expand All @@ -199,4 +186,19 @@ private function loadFieldDefinition(Content $content, string $fieldDefinitionId

return $fieldDefinition;
}

/**
* @return \eZ\Publish\API\Repository\Values\Content\Content[]
*
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
*/
private function executeQueryAndMapResult(Query $query): array
{
return array_map(
static function (SearchHit $searchHit): Content {
return $searchHit->valueObject;
},
$this->searchService->findContent($query)->searchHits
);
}
}
30 changes: 27 additions & 3 deletions src/API/QueryFieldServiceInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
use eZ\Publish\API\Repository\Values\Content\Content;

/**
* Executes a query and returns the results.
* Executes queries for a query field.
*/
interface QueryFieldServiceInterface
{
/**
* @param \eZ\Publish\API\Repository\Values\Content\Content $content
* Executes the query without pagination and returns the content items.
*
* @param \eZ\Publish\API\Repository\Values\Content\Location $content
* @param string $fieldDefinitionIdentifier
*
* @return \eZ\Publish\API\Repository\Values\Content\Content[]
Expand All @@ -24,16 +26,38 @@ interface QueryFieldServiceInterface
public function loadContentItems(Content $content, string $fieldDefinitionIdentifier): iterable;

/**
* Counts the total results of a query.
*
* @param \eZ\Publish\API\Repository\Values\Content\Content $content
* @param string $fieldDefinitionIdentifier
*
* @return \eZ\Publish\API\Repository\Values\Content\Content[]
* @return int
*
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
*/
public function countContentItems(Content $content, string $fieldDefinitionIdentifier): int;

/**
* Executes a paginated query and return the requested content items slice.
*
* @param \eZ\Publish\API\Repository\Values\Content\Content $content
* @param string $fieldDefinitionIdentifier
* @param int $offset
* @param int $limit
*
* @return \eZ\Publish\API\Repository\Values\Content\Content[]
*
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
*/
public function loadContentItemsSlice(Content $content, string $fieldDefinitionIdentifier, int $offset, int $limit): iterable;

/**
* @param \eZ\Publish\API\Repository\Values\Content\Content $content
* @param string $fieldDefinitionIdentifier
*
* @return int The page size, or 0 if pagination is disabled.
*
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
*/
public function getPaginationConfiguration(Content $content, string $fieldDefinitionIdentifier): int;
}
Loading

0 comments on commit e3de453

Please sign in to comment.