Skip to content

Commit

Permalink
[Grid] Add PQLQuery Filter (#429)
Browse files Browse the repository at this point in the history
* Add PQL Query Filter.

* Apply php-cs-fixer changes

---------

Co-authored-by: martineiber <[email protected]>
  • Loading branch information
martineiber and martineiber authored Sep 19, 2024
1 parent e8718f4 commit 83dc3bd
Show file tree
Hide file tree
Showing 17 changed files with 139 additions and 62 deletions.
3 changes: 3 additions & 0 deletions config/data_index_filters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ services:
Pimcore\Bundle\StudioBackendBundle\DataIndex\Filter\TagFilter:
tags: [ 'pimcore.studio_backend.open_search.filter' ]

Pimcore\Bundle\StudioBackendBundle\DataIndex\Filter\PqlFilter:
tags: [ 'pimcore.studio_backend.open_search.filter' ]

# DataObject
Pimcore\Bundle\StudioBackendBundle\DataIndex\Filter\DataObject\ClassNameFilter:
tags: [ 'pimcore.studio_backend.open_search.data_object.filter' ]
Expand Down
30 changes: 16 additions & 14 deletions doc/03_Grid.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,25 @@ Here you can define `page`, `pageSize` and `includeDescendants`.

### ColumnFilter
It is also possible to filter the data by a column. This is done by adding a `columnFilter` to the `filter` property.
A `columnFilter` has a reference to the column and the value you want to filter by.
A `columnFilter` has a reference to the column and the value you want to filter by. Some filters do not require a
specific column, like the `system.tag` filter. This filters will be applied to the general search query.

Available filters are:

| Type | filterValue | Options |
|:-----------------:|:-------------------:|:---------------------------:|
| metadata.select | string | |
| metadata.date | object of timestamp | `from`, `to`, or `on` |
| metadata.input | string | |
| metadata.checkbox | boolean | |
| metadata.textarea | string | |
| metadata.object | integer | ID of the object |
| metadata.document | integer | ID fo the document |
| metadata.asset | integer | ID fo the asset |
| system.string | string | Wildcard search can be used |
| system.datetime | integer | `from`, `to`, or `on` |
| system.tag | object | `considerChildTags`, `tags` |
| Type | filterValue | Options | `key` required |
|:-----------------:|:-------------------:|:---------------------------:|:--------------:|
| metadata.select | string | | true |
| metadata.date | object of timestamp | `from`, `to`, or `on` | true |
| metadata.input | string | | true |
| metadata.checkbox | boolean | | true |
| metadata.textarea | string | | true |
| metadata.object | integer | ID of the object | true |
| metadata.document | integer | ID fo the document | true |
| metadata.asset | integer | ID fo the asset | true |
| system.string | string | Wildcard search can be used | true |
| system.datetime | integer | `from`, `to`, or `on` | true |
| system.tag | object | `considerChildTags`, `tags` | false |
| system.pql | string | PQL Query | false |



Expand Down
6 changes: 5 additions & 1 deletion src/DataIndex/Adapter/AssetSearchAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

namespace Pimcore\Bundle\StudioBackendBundle\DataIndex\Adapter;

use Exception;
use Pimcore\Bundle\GenericDataIndexBundle\Exception\AssetSearchException;
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Asset\AssetSearch;
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Sort\Tree\OrderByFullPath;
Expand All @@ -26,6 +27,7 @@
use Pimcore\Bundle\StudioBackendBundle\DataIndex\AssetSearchResult;
use Pimcore\Bundle\StudioBackendBundle\DataIndex\Hydrator\HydratorServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\DataIndex\Query\QueryInterface;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidArgumentException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotFoundException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\SearchException;
use function sprintf;
Expand All @@ -41,14 +43,16 @@ public function __construct(
}

/**
* @throws SearchException
* @throws SearchException|InvalidArgumentException
*/
public function searchAssets(QueryInterface $assetQuery): AssetSearchResult
{
try {
$searchResult = $this->searchService->search($assetQuery->getSearch());
} catch (AssetSearchException) {
throw new SearchException('assets');
} catch (Exception $e) {
throw new InvalidArgumentException($e->getMessage());
}

$result = [];
Expand Down
3 changes: 2 additions & 1 deletion src/DataIndex/Adapter/AssetSearchAdapterInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@
use Pimcore\Bundle\StudioBackendBundle\Asset\Schema\Asset;
use Pimcore\Bundle\StudioBackendBundle\DataIndex\AssetSearchResult;
use Pimcore\Bundle\StudioBackendBundle\DataIndex\Query\QueryInterface;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidArgumentException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotFoundException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\SearchException;

interface AssetSearchAdapterInterface
{
/**
* @throws SearchException
* @throws SearchException|InvalidArgumentException
*/
public function searchAssets(QueryInterface $assetQuery): AssetSearchResult;

Expand Down
3 changes: 2 additions & 1 deletion src/DataIndex/AssetSearchService.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
use Pimcore\Bundle\StudioBackendBundle\DataIndex\Adapter\AssetSearchAdapterInterface;
use Pimcore\Bundle\StudioBackendBundle\DataIndex\Provider\AssetQueryProviderInterface;
use Pimcore\Bundle\StudioBackendBundle\DataIndex\Query\QueryInterface;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidArgumentException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotFoundException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\SearchException;
use function count;
Expand All @@ -42,7 +43,7 @@ public function __construct(
}

/**
* @throws SearchException
* @throws SearchException|InvalidArgumentException
*/
public function searchAssets(QueryInterface $assetQuery): AssetSearchResult
{
Expand Down
3 changes: 2 additions & 1 deletion src/DataIndex/AssetSearchServiceInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@
use Pimcore\Bundle\StudioBackendBundle\Asset\Schema\Type\Unknown;
use Pimcore\Bundle\StudioBackendBundle\Asset\Schema\Type\Video;
use Pimcore\Bundle\StudioBackendBundle\DataIndex\Query\QueryInterface;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidArgumentException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotFoundException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\SearchException;

interface AssetSearchServiceInterface
{
/**
* @throws SearchException
* @throws SearchException|InvalidArgumentException
*/
public function searchAssets(QueryInterface $assetQuery): AssetSearchResult;

Expand Down
50 changes: 50 additions & 0 deletions src/DataIndex/Filter/PqlFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);

/**
* Pimcore
*
* This source file is available under two different licenses:
* - GNU General Public License version 3 (GPLv3)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license http://www.pimcore.org/license GPLv3 and PCL
*/

namespace Pimcore\Bundle\StudioBackendBundle\DataIndex\Filter;

use Pimcore\Bundle\StudioBackendBundle\DataIndex\Query\QueryInterface;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidArgumentException;
use Pimcore\Bundle\StudioBackendBundle\Grid\Column\ColumnType;
use Pimcore\Bundle\StudioBackendBundle\MappedParameter\Filter\SimpleColumnFiltersParameterInterface;
use function is_string;

/**
* @internal
*/
final class PqlFilter implements FilterInterface
{
public function apply(mixed $parameters, QueryInterface $query): QueryInterface
{
if (!$parameters instanceof SimpleColumnFiltersParameterInterface) {
return $query;
}

$filter = $parameters->getSimpleColumnFilterByType(ColumnType::SYSTEM_PQL_QUERY->value);

if (!$filter) {
return $query;
}

if (!is_string($filter->getFilterValue())) {
throw new InvalidArgumentException('Invalid PQL filter. Filter value must be a string.');
}

$filterValue = $filter->getFilterValue();

return $query->filterByPql($filterValue);
}
}
16 changes: 12 additions & 4 deletions src/DataIndex/Filter/TagFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
namespace Pimcore\Bundle\StudioBackendBundle\DataIndex\Filter;

use Pimcore\Bundle\StudioBackendBundle\DataIndex\Query\QueryInterface;
use Pimcore\Bundle\StudioBackendBundle\MappedParameter\Filter\TagFilterParameterInterface;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidArgumentException;
use Pimcore\Bundle\StudioBackendBundle\Grid\Column\ColumnType;
use Pimcore\Bundle\StudioBackendBundle\MappedParameter\Filter\SimpleColumnFiltersParameterInterface;

/**
* @internal
Expand All @@ -26,16 +28,22 @@ final class TagFilter implements FilterInterface
{
public function apply(mixed $parameters, QueryInterface $query): QueryInterface
{
if (!$parameters instanceof TagFilterParameterInterface) {
if (!$parameters instanceof SimpleColumnFiltersParameterInterface) {
return $query;
}

$filter = $parameters->getTagFilter();
$filter = $parameters->getSimpleColumnFilterByType(ColumnType::SYSTEM_TAG->value);

if (!$filter) {
return $query;
}

return $query->filterTags($filter->getTags(), $filter->considerChildTags());
$filterValue = $filter->getFilterValue();

if (!isset($filterValue['tags'], $filterValue['considerChildTags'])) {
throw new InvalidArgumentException('Invalid tag filter');
}

return $query->filterTags($filterValue['tags'], $filterValue['considerChildTags']);
}
}
3 changes: 2 additions & 1 deletion src/DataIndex/Grid/GridSearch.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Pimcore\Bundle\StudioBackendBundle\DataIndex\AssetSearchResult;
use Pimcore\Bundle\StudioBackendBundle\DataIndex\AssetSearchServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\DataIndex\OpenSearchFilterInterface;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidArgumentException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotFoundException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\SearchException;
use Pimcore\Bundle\StudioBackendBundle\Filter\Service\FilterServiceProviderInterface;
Expand All @@ -39,7 +40,7 @@ public function __construct(
}

/**
* @throws NotFoundException|SearchException
* @throws NotFoundException|SearchException|InvalidArgumentException
*/
public function searchAssets(GridParameter $gridParameter): AssetSearchResult
{
Expand Down
10 changes: 9 additions & 1 deletion src/DataIndex/Query/AssetQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\Tree\TagFilter;
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\FullTextSearch\ElementKeySearch;
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\FullTextSearch\WildcardSearch;
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\QueryLanguage\PqlFilter;
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Sort\OrderByField;
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Sort\Tree\OrderByFullPath;

Expand Down Expand Up @@ -150,10 +151,17 @@ public function filterDatetime(
/**
* @param array<int> $tags
*/
public function filterTags(array $tags, bool $considerChildTags): QueryInterface
public function filterTags(array $tags, bool $considerChildTags): self
{
$this->search->addModifier(new TagFilter($tags, $considerChildTags));

return $this;
}

public function filterByPql(string $pqlQuery): self
{
$this->search->addModifier(new PqlFilter($pqlQuery));

return $this;
}
}
10 changes: 9 additions & 1 deletion src/DataIndex/Query/DataObjectQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\Tree\PathFilter;
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\Tree\TagFilter;
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\FullTextSearch\ElementKeySearch;
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\QueryLanguage\PqlFilter;
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Sort\Tree\OrderByFullPath;
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Sort\Tree\OrderByIndexField;
use Pimcore\Bundle\StaticResolverBundle\Models\DataObject\ClassDefinitionResolverInterface;
Expand Down Expand Up @@ -129,10 +130,17 @@ public function orderByIndex(): self
/**
* @param array<int> $tags
*/
public function filterTags(array $tags, bool $considerChildTags): QueryInterface
public function filterTags(array $tags, bool $considerChildTags): self
{
$this->search->addModifier(new TagFilter($tags, $considerChildTags));

return $this;
}

public function filterByPql(string $pqlQuery): self
{
$this->search->addModifier(new PqlFilter($pqlQuery));

return $this;
}
}
2 changes: 2 additions & 0 deletions src/DataIndex/Query/QueryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,6 @@ public function searchByIds(array $ids): self;
* @param array<int> $tags
*/
public function filterTags(array $tags, bool $considerChildTags): self;

public function filterByPql(string $pqlQuery): self;
}
24 changes: 10 additions & 14 deletions src/Filter/MappedParameter/FilterParameter.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,15 @@
namespace Pimcore\Bundle\StudioBackendBundle\Filter\MappedParameter;

use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidArgumentException;
use Pimcore\Bundle\StudioBackendBundle\Grid\Column\ColumnType;
use Pimcore\Bundle\StudioBackendBundle\MappedParameter\CollectionParametersInterface;
use Pimcore\Bundle\StudioBackendBundle\MappedParameter\Filter\ColumnFilter;
use Pimcore\Bundle\StudioBackendBundle\MappedParameter\Filter\ColumnFiltersParameterInterface;
use Pimcore\Bundle\StudioBackendBundle\MappedParameter\Filter\ExcludeFolderParameterInterface;
use Pimcore\Bundle\StudioBackendBundle\MappedParameter\Filter\PathParameterInterface;
use Pimcore\Bundle\StudioBackendBundle\MappedParameter\Filter\SimpleColumnFilter;
use Pimcore\Bundle\StudioBackendBundle\MappedParameter\Filter\SimpleColumnFiltersParameterInterface;
use Pimcore\Bundle\StudioBackendBundle\MappedParameter\Filter\SortFilter;
use Pimcore\Bundle\StudioBackendBundle\MappedParameter\Filter\SortFilterParameterInterface;
use Pimcore\Bundle\StudioBackendBundle\MappedParameter\Filter\TagFilterParameter;
use Pimcore\Bundle\StudioBackendBundle\MappedParameter\Filter\TagFilterParameterInterface;
use function count;

/**
Expand All @@ -37,8 +36,8 @@ final class FilterParameter implements
ExcludeFolderParameterInterface,
PathParameterInterface,
ColumnFiltersParameterInterface,
SortFilterParameterInterface,
TagFilterParameterInterface
SimpleColumnFiltersParameterInterface,
SortFilterParameterInterface
{
private ?string $path = null;

Expand Down Expand Up @@ -106,24 +105,21 @@ public function getColumnFilterByType(string $type): iterable
}
}

public function getTagFilter(): ?TagFilterParameter
public function getSimpleColumnFilterByType(string $type): ?SimpleColumnFilter
{
$columns = array_filter(
$this->columnFilters,
static fn ($columnFilter) => $columnFilter['type'] === ColumnType::SYSTEM_TAG->value
static fn ($columnFilter) => $columnFilter['type'] === $type
);

if (count($columns) > 1) {
throw new InvalidArgumentException('More than one tag filter is not allowed');
throw new InvalidArgumentException('More than one filter of same type is not allowed');
}

if (isset($columns[0]['filterValue'])) {
$filterValue = $columns[0]['filterValue'];
if (!isset($filterValue['tags'], $filterValue['considerChildTags'])) {
throw new InvalidArgumentException('Invalid tag filter');
}
$column = reset($columns);

return new TagFilterParameter($filterValue['tags'], $filterValue['considerChildTags']);
if (isset($column['filterValue'])) {
return new SimpleColumnFilter($type, $column['filterValue']);
}

return null;
Expand Down
1 change: 1 addition & 0 deletions src/Grid/Column/ColumnType.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ enum ColumnType: string
case SYSTEM_INTEGER = 'system.integer';
case SYSTEM_DATETIME = 'system.datetime';
case SYSTEM_TAG = 'system.tag';
case SYSTEM_PQL_QUERY = 'system.pql';
case METADATA_SELECT = 'metadata.select';
case METADATA_INPUT = 'metadata.input';
case METADATA_DATE = 'metadata.date';
Expand Down
13 changes: 2 additions & 11 deletions src/MappedParameter/Filter/ColumnFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,18 @@
/**
* @internal
*/
final readonly class ColumnFilter
final readonly class ColumnFilter extends SimpleColumnFilter
{
public function __construct(
private string $key,
private string $type,
private mixed $filterValue,
) {
parent::__construct($this->type, $this->filterValue);
}

public function getKey(): string
{
return $this->key;
}

public function getType(): string
{
return $this->type;
}

public function getFilterValue(): mixed
{
return $this->filterValue;
}
}
Loading

0 comments on commit 83dc3bd

Please sign in to comment.