Skip to content

Commit 8c13f9e

Browse files
authored
[Modifier] Add Time Filter (#372)
* Add Time Filter * Fix Test * Fix Test * Fix Test
1 parent 22e5346 commit 8c13f9e

File tree

7 files changed

+300
-3
lines changed

7 files changed

+300
-3
lines changed

docker-compose.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
version: '3.0'
21
services:
32
php-generic-data-index-bundle:
43
image: pimcore/pimcore:php8.3-latest
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
/**
5+
* This source file is available under the terms of the
6+
* Pimcore Open Core License (POCL)
7+
* Full copyright and license information is available in
8+
* LICENSE.md which is distributed with this source code.
9+
*
10+
* @copyright Copyright (c) Pimcore GmbH (https://www.pimcore.com)
11+
* @license Pimcore Open Core License (POCL)
12+
*/
13+
14+
namespace Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\Query;
15+
16+
use Carbon\Carbon;
17+
use DateTimeInterface;
18+
use Pimcore\Bundle\GenericDataIndexBundle\Enum\SearchIndex\DefaultSearch\QueryType;
19+
use Pimcore\Bundle\GenericDataIndexBundle\Exception\InvalidArgumentException;
20+
21+
final readonly class TimeFilter implements QueryInterface
22+
{
23+
public function __construct(
24+
private string $field,
25+
private string|null $startTime = null,
26+
private string|null $endTime = null,
27+
private string|null $onTime = null,
28+
) {
29+
}
30+
31+
public function getType(): QueryType|string
32+
{
33+
return 'range';
34+
}
35+
36+
public function isEmpty(): bool
37+
{
38+
return empty($this->getParams());
39+
}
40+
41+
public function getParams(): array
42+
{
43+
$params = [];
44+
45+
if ($this->onTime) {
46+
$params['gte'] = $this->onTime;
47+
$params['lte'] = $this->onTime;
48+
49+
return [$this->field => $params];
50+
}
51+
52+
$params = $this->addStartParams($params);
53+
$params = $this->addEndParams($params);
54+
55+
return [$this->field => $params];
56+
}
57+
58+
public function toArray(bool $withType = false): array
59+
{
60+
if ($withType) {
61+
return [$this->getType() => $this->getParams()];
62+
}
63+
64+
return $this->getParams();
65+
}
66+
67+
public function getField(): string
68+
{
69+
return $this->field;
70+
}
71+
72+
private function addStartParams(array $params): array
73+
{
74+
if (!$this->startTime) {
75+
return $params;
76+
}
77+
78+
$params['gte'] = $this->startTime;
79+
80+
return $params;
81+
}
82+
83+
private function addEndParams(array $params): array
84+
{
85+
if (!$this->endTime) {
86+
return $params;
87+
}
88+
89+
$params['lte'] = $this->endTime;
90+
91+
return $params;
92+
}
93+
}

src/Model/Search/Modifier/Filter/FieldType/ClassificationStoreFilter.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public function __construct(
2727
private string $fieldName,
2828
private string $group,
2929
private BooleanFilter|DateFilter|FullTextSearch|IntegerFilter|MultiSelectFilter|BooleanMultiSelectFilter|
30-
NumberFilter|NumberRangeFilter|WildcardSearch $subModifier,
30+
NumberFilter|NumberRangeFilter|WildcardSearch|TimeFilter $subModifier,
3131
private string $locale = MappingProperty::NOT_LOCALIZED_KEY,
3232
) {
3333
}
@@ -43,7 +43,7 @@ public function getGroup(): string
4343
}
4444

4545
public function getSubModifier(): BooleanFilter|DateFilter|FullTextSearch|IntegerFilter|
46-
MultiSelectFilter|BooleanMultiSelectFilter|NumberFilter|NumberRangeFilter|WildcardSearch
46+
MultiSelectFilter|BooleanMultiSelectFilter|NumberFilter|NumberRangeFilter|WildcardSearch|TimeFilter
4747
{
4848
return $this->subModifier;
4949
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
/**
5+
* This source file is available under the terms of the
6+
* Pimcore Open Core License (POCL)
7+
* Full copyright and license information is available in
8+
* LICENSE.md which is distributed with this source code.
9+
*
10+
* @copyright Copyright (c) Pimcore GmbH (https://www.pimcore.com)
11+
* @license Pimcore Open Core License (POCL)
12+
*/
13+
14+
namespace Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\FieldType;
15+
16+
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\SearchModifierInterface;
17+
18+
final readonly class TimeFilter implements SearchModifierInterface
19+
{
20+
public function __construct(
21+
private string $field,
22+
private string|null $startTime = null,
23+
private string|null $endTime = null,
24+
private string|null $onTime = null,
25+
private bool $enablePqlFieldNameResolution = true,
26+
) {
27+
}
28+
29+
public function getStartTime(): ?string
30+
{
31+
return $this->startTime;
32+
}
33+
34+
public function getEndTime(): ?string
35+
{
36+
return $this->endTime;
37+
}
38+
39+
public function getOnTime(): ?string
40+
{
41+
return $this->onTime;
42+
}
43+
44+
public function getField(): string
45+
{
46+
return $this->field;
47+
}
48+
49+
public function isPqlFieldNameResolutionEnabled(): bool
50+
{
51+
return $this->enablePqlFieldNameResolution;
52+
}
53+
}

src/SearchIndexAdapter/DefaultSearch/Search/Modifier/Filter/FieldTypeFilters.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\Modifier\SearchModifierContextInterface;
1818
use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\Query\BoolExistsQuery;
1919
use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\Query\DateFilter as DateFilterQuery;
20+
use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\Query\TimeFilter as TimeFilterQuery;
2021
use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\Query\MultiBoolQuery;
2122
use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\Query\Query as QueryFilter;
2223
use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\Query\TermsFilter as TermsFilterQuery;
@@ -25,6 +26,7 @@
2526
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\FieldType\DateFilter;
2627
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\FieldType\MultiSelectFilter;
2728
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\FieldType\NumberRangeFilter;
29+
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\FieldType\TimeFilter;
2830
use Pimcore\Bundle\GenericDataIndexBundle\Service\Search\SearchService\SearchPqlFieldNameTransformationServiceInterface;
2931

3032
/**
@@ -71,6 +73,39 @@ public function getDateFilterQuery(
7173
);
7274
}
7375

76+
#[AsSearchModifierHandler]
77+
public function handleTimeFilter(
78+
TimeFilter $timeFilter,
79+
SearchModifierContextInterface $context
80+
): void {
81+
$context->getSearch()->addQuery($this->getTimeFilterQuery(
82+
$timeFilter,
83+
null,
84+
$context->getOriginalSearch())
85+
);
86+
}
87+
88+
public function getTimeFilterQuery(
89+
TimeFilter $timeFilter,
90+
?string $prefix = null,
91+
?SearchInterface $search = null
92+
): TimeFilterQuery {
93+
$fieldName = $timeFilter->getField();
94+
if ($prefix) {
95+
$fieldName = $prefix . '.' . $fieldName;
96+
}
97+
if ($search && $timeFilter->isPqlFieldNameResolutionEnabled()) {
98+
$fieldName = $this->fieldNameTransformationService->transformFieldnameForSearch($search, $fieldName);
99+
}
100+
101+
return new TimeFilterQuery(
102+
$fieldName,
103+
$timeFilter->getStartTime(),
104+
$timeFilter->getEndTime(),
105+
$timeFilter->getOnTime(),
106+
);
107+
}
108+
74109
#[AsSearchModifierHandler]
75110
public function handleMultiSelectFilter(
76111
MultiSelectFilter $multiSelectFilter,

src/SearchIndexAdapter/DefaultSearch/Search/Modifier/Filter/NestedTypeFilters.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\FieldType\MultiSelectFilter;
2929
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\FieldType\NestedFilter as NestedFilterParam;
3030
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\FieldType\NumberRangeFilter;
31+
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\Filter\FieldType\TimeFilter;
3132
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\FullTextSearch\FullTextSearch;
3233
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Modifier\FullTextSearch\WildcardSearch;
3334
use Pimcore\Bundle\GenericDataIndexBundle\SearchIndexAdapter\DefaultSearch\Search\Modifier\FullTextSearch\FullTextSearchHandlers;
@@ -92,6 +93,9 @@ private function getSubQuery(ClassificationStoreFilter|NestedFilterParam $filter
9293
$modifier instanceof DateFilter =>
9394
$this->fieldTypeFilters->getDateFilterQuery($modifier, $fieldName, $search)->toArray(true),
9495

96+
$modifier instanceof TimeFilter =>
97+
$this->fieldTypeFilters->getTimeFilterQuery($modifier, $fieldName, $search)->toArray(true),
98+
9599
$modifier instanceof MultiSelectFilter =>
96100
$this->fieldTypeFilters->getMultiSelectQuery($modifier, $fieldName, $search)->toArrayAsSubQuery(),
97101

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
/**
5+
* This source file is available under the terms of the
6+
* Pimcore Open Core License (POCL)
7+
* Full copyright and license information is available in
8+
* LICENSE.md which is distributed with this source code.
9+
*
10+
* @copyright Copyright (c) Pimcore GmbH (https://www.pimcore.com)
11+
* @license Pimcore Open Core License (POCL)
12+
*/
13+
14+
namespace Pimcore\Bundle\GenericDataIndexBundle\Tests\Unit\Model\DefaultSearch\Query;
15+
16+
use Codeception\Test\Unit;
17+
use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\Query\TimeFilter;
18+
19+
/**
20+
* @internal
21+
*/
22+
final class TimeFilterTest extends Unit
23+
{
24+
25+
public function testToArray(): void
26+
{
27+
$timeFilter = new TimeFilter('datefield', '12:15', '13:15');
28+
29+
self::assertSame([
30+
'range' => [
31+
'datefield' => [
32+
'gte' => '12:15',
33+
'lte' => '13:15',
34+
],
35+
],
36+
], $timeFilter->toArray(true));
37+
38+
$timeFilter = new TimeFilter('datefield', '12:45');
39+
40+
self::assertSame([
41+
'range' => [
42+
'datefield' => [
43+
'gte' => '12:45',
44+
],
45+
],
46+
], $timeFilter->toArray(true));
47+
48+
$timeFilter = new TimeFilter('datefield', null, '13:00');
49+
50+
self::assertSame([
51+
'range' => [
52+
'datefield' => [
53+
'lte' => '13:00',
54+
],
55+
],
56+
], $timeFilter->toArray(true));
57+
58+
$timeFilter = new TimeFilter('datefield', null, null, '12:30');
59+
60+
self::assertSame([
61+
'range' => [
62+
'datefield' => [
63+
'gte' => '12:30',
64+
'lte' => '12:30',
65+
],
66+
],
67+
], $timeFilter->toArray(true));
68+
}
69+
70+
public function testGetType(): void
71+
{
72+
$dateFilter = new TimeFilter('datefield', "12:30", "12:45");
73+
74+
self::assertSame('range', $dateFilter->getType());
75+
}
76+
77+
public function testGetParams(): void
78+
{
79+
$timeFilter = new TimeFilter('datefield', '12:15', '13:15');
80+
81+
self::assertSame([
82+
'datefield' => [
83+
'gte' => '12:15',
84+
'lte' => '13:15',
85+
],
86+
], $timeFilter->getParams());
87+
88+
$timeFilter = new TimeFilter('datefield', '12:45');
89+
90+
self::assertSame([
91+
'datefield' => [
92+
'gte' => '12:45',
93+
],
94+
], $timeFilter->getParams());
95+
96+
$timeFilter = new TimeFilter('datefield', null, '13:00');
97+
98+
self::assertSame([
99+
'datefield' => [
100+
'lte' => '13:00',
101+
],
102+
], $timeFilter->getParams());
103+
104+
$timeFilter = new TimeFilter('datefield', null, null, '12:30');
105+
106+
self::assertSame([
107+
'datefield' => [
108+
'gte' => '12:30',
109+
'lte' => '12:30',
110+
],
111+
], $timeFilter->getParams());
112+
}
113+
}

0 commit comments

Comments
 (0)