Skip to content

Commit

Permalink
Prototyped an improved way to filter content
Browse files Browse the repository at this point in the history
The collection field for a type (`articles`, `blogPosts`) will expose an argument
for each searchable field:

```
{
  media {
    images(name: "~norway") {
      name
      uri
    }
  }
}
```

Supported operators (as first characters of the string): ~ (like, with automatic wildcards), <, >, <=, >=).
  • Loading branch information
Bertrand Dunogier committed Jan 24, 2019
1 parent 2416fc9 commit 6a6073f
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 22 deletions.
30 changes: 15 additions & 15 deletions src/GraphQL/InputMapper/SearchQueryMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
namespace EzSystems\EzPlatformGraphQL\GraphQL\InputMapper;

use eZ\Publish\API\Repository\Values\Content\Query;
use GraphQL\Error\UserError;
use InvalidArgumentException;

class SearchQueryMapper
Expand All @@ -29,21 +30,20 @@ public function mapInputToQuery(array $inputArray)
$criteria[] = new Query\Criterion\FullText($inputArray['Text']);
}

if (isset($inputArray['Field']))
{
if (isset($inputArray['Field']['target'])) {
$criteria[] = $this->mapInputToFieldCriterion($inputArray['Field']);
} else {
$criteria = array_merge(
$criteria,
array_map(
function($input) {
return $this->mapInputToFieldCriterion($input);
},
$inputArray['Field']
)
);
}
if (isset($inputArray['Field'])) {
$inputArray['Fields'] = [$inputArray['Field']];
}

if (isset($inputArray['Fields'])) {
$criteria = array_merge(
$criteria,
array_map(
function($input) {
return $this->mapInputToFieldCriterion($input);
},
$inputArray['Fields']
)
);
}

$criteria = array_merge($criteria, $this->mapDateMetadata($inputArray, 'Modified'));
Expand Down
69 changes: 62 additions & 7 deletions src/GraphQL/Resolver/DomainContentResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,8 @@

use EzSystems\EzPlatformGraphQL\GraphQL\InputMapper\SearchQueryMapper;
use EzSystems\EzPlatformGraphQL\GraphQL\Value\ContentFieldValue;
use eZ\Publish\API\Repository\LocationService;
use eZ\Publish\API\Repository\Repository;
use eZ\Publish\Core\FieldType;
use eZ\Publish\API\Repository\ContentService;
use eZ\Publish\API\Repository\ContentTypeService;
use eZ\Publish\API\Repository\SearchService;
use eZ\Publish\API\Repository\Values\Content\Content;
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
use eZ\Publish\API\Repository\Values\Content\Query;
Expand Down Expand Up @@ -50,13 +46,13 @@ public function __construct(
$this->queryMapper = $queryMapper;
}

public function resolveDomainContentItems($contentTypeIdentifier, $query = null)
public function resolveDomainContentItems($contentTypeIdentifier, $args = null)
{
return array_map(
function (Content $content) {
return $content->contentInfo;
},
$this->findContentItemsByTypeIdentifier($contentTypeIdentifier, $query)
$this->findContentItemsByTypeIdentifier($contentTypeIdentifier, $args)
);
}

Expand Down Expand Up @@ -93,11 +89,29 @@ public function resolveDomainContentItem(Argument $args, $contentTypeIdentifier)
*/
private function findContentItemsByTypeIdentifier($contentTypeIdentifier, Argument $args): array
{
$queryArg = $args['query'];
$contentType = $this->repository->getContentTypeService()->loadContentTypeByIdentifier($contentTypeIdentifier);
$fieldsArgument = [];
foreach ($args->getRawArguments() as $argument => $value) {
if (($fieldDefinition = $contentType->getFieldDefinition($argument)) === null) {
continue;
}

if (!$fieldDefinition->isSearchable) {
continue;
}

$fieldFilter = $this->buildFieldFilter($argument, $value);
if ($fieldFilter !== null) {
$fieldsArgument[] = $fieldFilter;
}
}

$queryArg = [];
$queryArg['ContentTypeIdentifier'] = $contentTypeIdentifier;
if (isset($args['sortBy'])) {
$queryArg['sortBy'] = $args['sortBy'];
}
$queryArg['Fields'] = $fieldsArgument;
$args['query'] = $queryArg;

$query = $this->queryMapper->mapInputToQuery($args['query']);
Expand Down Expand Up @@ -229,4 +243,45 @@ private function getSearchService()
{
return $this->repository->getSearchService();
}

private function buildFieldFilter($fieldDefinitionIdentifier, $value)
{
if (is_array($value) && count($value) === 1) {
$value = $value[0];
}
$operator = 'eq';

// @todo if 3 items, and first item is 'between', use next two items as value
if (is_array($value)) {
$operator = 'in';
} else if (is_string($value)) {
if ($value[0] === '~') {
$operator = 'like';
$value = substr($value, 1);
if (strpos($value, '%') === false) {
$value = "%$value%";
}
} elseif ($value[0] === '<') {
$value = substr($value, 1);
if ($value[0] === '=') {
$operator = 'lte';
$value = substr($value, 2);
} else {
$operator = 'lt';
$value = substr($value, 1);
}
} elseif ($value[0] === '<') {
$value = substr($value, 1);
if ($value[0] === '=') {
$operator = 'gte';
$value = substr($value, 2);
} else {
$operator = 'gt';
$value = substr($value, 1);
}
}
}

return ['target' => $fieldDefinitionIdentifier, $operator => trim($value)];
}
}

0 comments on commit 6a6073f

Please sign in to comment.