Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Grid] Add PQLQuery Filter #429

Merged
merged 2 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading