Skip to content

Commit 346b16d

Browse files
authored
Merge pull request #11 from itk-dev/feature/1339_API_multi_value_filtering
1339: Added multi-value filtering for Lactions and Organizations
2 parents 25464d8 + 0ebe6b9 commit 346b16d

File tree

8 files changed

+119
-56
lines changed

8 files changed

+119
-56
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ See [keep a changelog] for information about writing changes to this log.
2323
- Update composer dependencies
2424
- Added api-key auth
2525
- Added PethPrefix scope to traefik rules to allow co-hosting with legacy eventdb
26+
- Added multi-value filtering for Lactions and Organizations
2627

2728
[keep a changelog]: https://keepachangelog.com/en/1.1.0/
2829
[unreleased]: https://github.com/itk-dev/event-database-imports/compare/main...develop

public/spec.yaml

Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ paths:
8383
explode: false
8484
allowReserved: false
8585
-
86-
name: event.organizer.entityId
86+
name: event.location.name
8787
in: query
8888
description: 'Search field based on value given'
8989
required: false
@@ -95,27 +95,31 @@ paths:
9595
explode: false
9696
allowReserved: false
9797
-
98-
name: event.location.name
98+
name: event.organizer.entityId
9999
in: query
100-
description: 'Search field based on value given'
100+
description: 'Filter based on given entity ids'
101101
required: false
102102
deprecated: false
103103
allowEmptyValue: true
104104
schema:
105-
type: string
106-
style: form
105+
type: array
106+
items:
107+
type: string
108+
style: deepObject
107109
explode: false
108110
allowReserved: false
109111
-
110112
name: event.location.entityId
111113
in: query
112-
description: 'Search field based on value given'
114+
description: 'Filter based on given entity ids'
113115
required: false
114116
deprecated: false
115117
allowEmptyValue: true
116118
schema:
117-
type: string
118-
style: form
119+
type: array
120+
items:
121+
type: string
122+
style: deepObject
119123
explode: false
120124
allowReserved: false
121125
-
@@ -147,7 +151,7 @@ paths:
147151
-
148152
name: start
149153
in: query
150-
description: 'Filter base on date (greater then or equal to)'
154+
description: 'Filter base on ISO 8601 datetime (yyyy-MM-dd''T''HH:mm:ssz), e.g. "2004-02-12T15:19:21+00:00" (greater then or equal to)'
151155
required: false
152156
deprecated: false
153157
allowEmptyValue: true
@@ -159,7 +163,7 @@ paths:
159163
-
160164
name: end
161165
in: query
162-
description: 'Filter base on date (less then or equal to)'
166+
description: 'Filter base on ISO 8601 datetime (yyyy-MM-dd''T''HH:mm:ssz), e.g. "2004-02-12T15:19:21+00:00" (less then or equal to)'
163167
required: false
164168
deprecated: false
165169
allowEmptyValue: true
@@ -272,7 +276,7 @@ paths:
272276
explode: false
273277
allowReserved: false
274278
-
275-
name: organizer.entityId
279+
name: location.name
276280
in: query
277281
description: 'Search field based on value given'
278282
required: false
@@ -284,27 +288,31 @@ paths:
284288
explode: false
285289
allowReserved: false
286290
-
287-
name: location.name
291+
name: organizer.entityId
288292
in: query
289-
description: 'Search field based on value given'
293+
description: 'Filter based on given entity ids'
290294
required: false
291295
deprecated: false
292296
allowEmptyValue: true
293297
schema:
294-
type: string
295-
style: form
298+
type: array
299+
items:
300+
type: string
301+
style: deepObject
296302
explode: false
297303
allowReserved: false
298304
-
299305
name: location.entityId
300306
in: query
301-
description: 'Search field based on value given'
307+
description: 'Filter based on given entity ids'
302308
required: false
303309
deprecated: false
304310
allowEmptyValue: true
305311
schema:
306-
type: string
307-
style: form
312+
type: array
313+
items:
314+
type: string
315+
style: deepObject
308316
explode: false
309317
allowReserved: false
310318
-
@@ -336,7 +344,7 @@ paths:
336344
-
337345
name: occurrences.start
338346
in: query
339-
description: 'Filter base on date (greater then or equal to)'
347+
description: 'Filter base on ISO 8601 datetime (yyyy-MM-dd''T''HH:mm:ssz), e.g. "2004-02-12T15:19:21+00:00" (greater then or equal to)'
340348
required: false
341349
deprecated: false
342350
allowEmptyValue: true
@@ -348,7 +356,7 @@ paths:
348356
-
349357
name: occurrences.end
350358
in: query
351-
description: 'Filter base on date (less then or equal to)'
359+
description: 'Filter base on ISO 8601 datetime (yyyy-MM-dd''T''HH:mm:ssz), e.g. "2004-02-12T15:19:21+00:00" (less then or equal to)'
352360
required: false
353361
deprecated: false
354362
allowEmptyValue: true
@@ -563,18 +571,6 @@ paths:
563571
style: form
564572
explode: false
565573
allowReserved: false
566-
-
567-
name: event.organizer.entityId
568-
in: query
569-
description: 'Search field based on value given'
570-
required: false
571-
deprecated: false
572-
allowEmptyValue: true
573-
schema:
574-
type: string
575-
style: form
576-
explode: false
577-
allowReserved: false
578574
-
579575
name: event.location.name
580576
in: query
@@ -588,27 +584,31 @@ paths:
588584
explode: false
589585
allowReserved: false
590586
-
591-
name: event.location.entityId
587+
name: event.organizer.entityId
592588
in: query
593-
description: 'Search field based on value given'
589+
description: 'Filter based on given entity ids'
594590
required: false
595591
deprecated: false
596592
allowEmptyValue: true
597593
schema:
598-
type: string
599-
style: form
594+
type: array
595+
items:
596+
type: string
597+
style: deepObject
600598
explode: false
601599
allowReserved: false
602600
-
603-
name: event.publicAccess
601+
name: event.location.entityId
604602
in: query
605-
description: 'Is this a public event'
603+
description: 'Filter based on given entity ids'
606604
required: false
607605
deprecated: false
608606
allowEmptyValue: true
609607
schema:
610-
type: boolean
611-
style: form
608+
type: array
609+
items:
610+
type: string
611+
style: deepObject
612612
explode: false
613613
allowReserved: false
614614
-
@@ -628,7 +628,7 @@ paths:
628628
-
629629
name: start
630630
in: query
631-
description: 'Filter base on date (greater then or equal to)'
631+
description: 'Filter base on ISO 8601 datetime (yyyy-MM-dd''T''HH:mm:ssz), e.g. "2004-02-12T15:19:21+00:00" (greater then or equal to)'
632632
required: false
633633
deprecated: false
634634
allowEmptyValue: true
@@ -640,7 +640,7 @@ paths:
640640
-
641641
name: end
642642
in: query
643-
description: 'Filter base on date (less then or equal to)'
643+
description: 'Filter base on ISO 8601 datetime (yyyy-MM-dd''T''HH:mm:ssz), e.g. "2004-02-12T15:19:21+00:00" (less then or equal to)'
644644
required: false
645645
deprecated: false
646646
allowEmptyValue: true

src/Api/Dto/DailyOccurrence.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
use ApiPlatform\OpenApi\Model\Response;
1313
use App\Api\Filter\ElasticSearch\BooleanFilter;
1414
use App\Api\Filter\ElasticSearch\DateFilter;
15-
use App\Api\Filter\ElasticSearch\EventTagFilter;
15+
use App\Api\Filter\ElasticSearch\IdFilter;
1616
use App\Api\Filter\ElasticSearch\MatchFilter;
17+
use App\Api\Filter\ElasticSearch\TagFilter;
1718
use App\Api\State\DailyOccurrenceRepresentationProvider;
1819
use App\Model\DateLimits;
1920

@@ -51,14 +52,18 @@
5152
)]
5253
#[ApiFilter(
5354
MatchFilter::class,
54-
properties: ['event.title', 'event.organizer.name', 'event.organizer.entityId', 'event.location.name', 'event.location.entityId']
55+
properties: ['event.title', 'event.organizer.name', 'event.location.name']
56+
)]
57+
#[ApiFilter(
58+
IdFilter::class,
59+
properties: ['event.organizer.entityId', 'event.location.entityId']
5560
)]
5661
#[ApiFilter(
5762
BooleanFilter::class,
5863
properties: ['event.publicAccess']
5964
)]
6065
#[ApiFilter(
61-
EventTagFilter::class,
66+
TagFilter::class,
6267
properties: ['event.tags']
6368
)]
6469
#[ApiFilter(

src/Api/Dto/Event.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
use ApiPlatform\OpenApi\Model\Response;
1313
use App\Api\Filter\ElasticSearch\BooleanFilter;
1414
use App\Api\Filter\ElasticSearch\DateFilter;
15-
use App\Api\Filter\ElasticSearch\EventTagFilter;
15+
use App\Api\Filter\ElasticSearch\IdFilter;
1616
use App\Api\Filter\ElasticSearch\MatchFilter;
17+
use App\Api\Filter\ElasticSearch\TagFilter;
1718
use App\Api\State\EventRepresentationProvider;
1819
use App\Model\DateLimits;
1920

@@ -51,14 +52,18 @@
5152
)]
5253
#[ApiFilter(
5354
MatchFilter::class,
54-
properties: ['title', 'organizer.name', 'organizer.entityId', 'location.name', 'location.entityId']
55+
properties: ['title', 'organizer.name', 'location.name']
56+
)]
57+
#[ApiFilter(
58+
IdFilter::class,
59+
properties: ['organizer.entityId', 'location.entityId']
5560
)]
5661
#[ApiFilter(
5762
BooleanFilter::class,
5863
properties: ['publicAccess']
5964
)]
6065
#[ApiFilter(
61-
EventTagFilter::class,
66+
TagFilter::class,
6267
properties: ['tags']
6368
)]
6469
#[ApiFilter(

src/Api/Dto/Occurrence.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
use ApiPlatform\OpenApi\Model\Operation;
1111
use ApiPlatform\OpenApi\Model\Parameter;
1212
use ApiPlatform\OpenApi\Model\Response;
13-
use App\Api\Filter\ElasticSearch\BooleanFilter;
1413
use App\Api\Filter\ElasticSearch\DateFilter;
15-
use App\Api\Filter\ElasticSearch\EventTagFilter;
14+
use App\Api\Filter\ElasticSearch\IdFilter;
1615
use App\Api\Filter\ElasticSearch\MatchFilter;
16+
use App\Api\Filter\ElasticSearch\TagFilter;
1717
use App\Api\State\OccurrenceRepresentationProvider;
1818
use App\Model\DateLimits;
1919

@@ -52,14 +52,14 @@
5252
)]
5353
#[ApiFilter(
5454
MatchFilter::class,
55-
properties: ['event.title', 'event.organizer.name', 'event.organizer.entityId', 'event.location.name', 'event.location.entityId']
55+
properties: ['event.title', 'event.organizer.name', 'event.location.name']
5656
)]
5757
#[ApiFilter(
58-
BooleanFilter::class,
59-
properties: ['event.publicAccess']
58+
IdFilter::class,
59+
properties: ['event.organizer.entityId', 'event.location.entityId']
6060
)]
6161
#[ApiFilter(
62-
EventTagFilter::class,
62+
TagFilter::class,
6363
properties: ['event.tags']
6464
)]
6565
#[ApiFilter(

src/Api/Filter/ElasticSearch/DateFilter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public function getDescription(string $resourceClass): array
7474
'property' => $filterParameterName,
7575
'type' => Type::BUILTIN_TYPE_STRING,
7676
'required' => false,
77-
'description' => 'Filter base on date ('.$this->config[$value]->limit->value.')',
77+
'description' => 'Filter base on ISO 8601 datetime (yyyy-MM-dd\'T\'HH:mm:ssz), e.g. "2004-02-12T15:19:21+00:00" ('.$this->config[$value]->limit->value.')',
7878
'openapi' => [
7979
'allowReserved' => false,
8080
'allowEmptyValue' => true,
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
namespace App\Api\Filter\ElasticSearch;
4+
5+
use ApiPlatform\Elasticsearch\Filter\AbstractFilter;
6+
use ApiPlatform\Metadata\Operation;
7+
use Symfony\Component\PropertyInfo\Type;
8+
9+
final class IdFilter extends AbstractFilter
10+
{
11+
public function apply(array $clauseBody, string $resourceClass, ?Operation $operation = null, array $context = []): array
12+
{
13+
$properties = $this->getProperties($resourceClass);
14+
$terms = [];
15+
16+
/** @var string $property */
17+
foreach ($properties as $property) {
18+
if (empty($context['filters'][$property])) {
19+
// If no value or empty value is set, skip it.
20+
continue;
21+
}
22+
$terms[$property] = explode(',', $context['filters'][$property]);
23+
}
24+
25+
return empty($terms) ? $terms : ['terms' => $terms + ['boost' => 1.0]];
26+
}
27+
28+
public function getDescription(string $resourceClass): array
29+
{
30+
if (!$this->properties) {
31+
return [];
32+
}
33+
34+
$description = [];
35+
foreach ($this->properties as $filterParameterName => $value) {
36+
$description[$filterParameterName] = [
37+
'property' => $filterParameterName,
38+
'type' => Type::BUILTIN_TYPE_ARRAY,
39+
'required' => false,
40+
'description' => 'Filter based on given entity ids',
41+
'is_collection' => true,
42+
'openapi' => [
43+
'allowReserved' => false,
44+
'allowEmptyValue' => true,
45+
'explode' => false,
46+
],
47+
];
48+
}
49+
50+
return $description;
51+
}
52+
}

src/Api/Filter/ElasticSearch/EventTagFilter.php renamed to src/Api/Filter/ElasticSearch/TagFilter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
use ApiPlatform\Metadata\Operation;
77
use Symfony\Component\PropertyInfo\Type;
88

9-
final class EventTagFilter extends AbstractFilter
9+
final class TagFilter extends AbstractFilter
1010
{
1111
public function apply(array $clauseBody, string $resourceClass, ?Operation $operation = null, array $context = []): array
1212
{

0 commit comments

Comments
 (0)