diff --git a/CHANGELOG.md b/CHANGELOG.md index 93426b3..9220cb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ See [keep a changelog] for information about writing changes to this log. - Update composer dependencies - Added api-key auth - Added PethPrefix scope to traefik rules to allow co-hosting with legacy eventdb +- Added multi-value filtering for Lactions and Organizations [keep a changelog]: https://keepachangelog.com/en/1.1.0/ [unreleased]: https://github.com/itk-dev/event-database-imports/compare/main...develop diff --git a/public/spec.yaml b/public/spec.yaml index d529f82..efedb45 100644 --- a/public/spec.yaml +++ b/public/spec.yaml @@ -83,7 +83,7 @@ paths: explode: false allowReserved: false - - name: event.organizer.entityId + name: event.location.name in: query description: 'Search field based on value given' required: false @@ -95,27 +95,31 @@ paths: explode: false allowReserved: false - - name: event.location.name + name: event.organizer.entityId in: query - description: 'Search field based on value given' + description: 'Filter based on given entity ids' required: false deprecated: false allowEmptyValue: true schema: - type: string - style: form + type: array + items: + type: string + style: deepObject explode: false allowReserved: false - name: event.location.entityId in: query - description: 'Search field based on value given' + description: 'Filter based on given entity ids' required: false deprecated: false allowEmptyValue: true schema: - type: string - style: form + type: array + items: + type: string + style: deepObject explode: false allowReserved: false - @@ -147,7 +151,7 @@ paths: - name: start in: query - description: 'Filter base on date (greater then or equal to)' + 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)' required: false deprecated: false allowEmptyValue: true @@ -159,7 +163,7 @@ paths: - name: end in: query - description: 'Filter base on date (less then or equal to)' + 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)' required: false deprecated: false allowEmptyValue: true @@ -272,7 +276,7 @@ paths: explode: false allowReserved: false - - name: organizer.entityId + name: location.name in: query description: 'Search field based on value given' required: false @@ -284,27 +288,31 @@ paths: explode: false allowReserved: false - - name: location.name + name: organizer.entityId in: query - description: 'Search field based on value given' + description: 'Filter based on given entity ids' required: false deprecated: false allowEmptyValue: true schema: - type: string - style: form + type: array + items: + type: string + style: deepObject explode: false allowReserved: false - name: location.entityId in: query - description: 'Search field based on value given' + description: 'Filter based on given entity ids' required: false deprecated: false allowEmptyValue: true schema: - type: string - style: form + type: array + items: + type: string + style: deepObject explode: false allowReserved: false - @@ -336,7 +344,7 @@ paths: - name: occurrences.start in: query - description: 'Filter base on date (greater then or equal to)' + 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)' required: false deprecated: false allowEmptyValue: true @@ -348,7 +356,7 @@ paths: - name: occurrences.end in: query - description: 'Filter base on date (less then or equal to)' + 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)' required: false deprecated: false allowEmptyValue: true @@ -563,18 +571,6 @@ paths: style: form explode: false allowReserved: false - - - name: event.organizer.entityId - in: query - description: 'Search field based on value given' - required: false - deprecated: false - allowEmptyValue: true - schema: - type: string - style: form - explode: false - allowReserved: false - name: event.location.name in: query @@ -588,27 +584,31 @@ paths: explode: false allowReserved: false - - name: event.location.entityId + name: event.organizer.entityId in: query - description: 'Search field based on value given' + description: 'Filter based on given entity ids' required: false deprecated: false allowEmptyValue: true schema: - type: string - style: form + type: array + items: + type: string + style: deepObject explode: false allowReserved: false - - name: event.publicAccess + name: event.location.entityId in: query - description: 'Is this a public event' + description: 'Filter based on given entity ids' required: false deprecated: false allowEmptyValue: true schema: - type: boolean - style: form + type: array + items: + type: string + style: deepObject explode: false allowReserved: false - @@ -628,7 +628,7 @@ paths: - name: start in: query - description: 'Filter base on date (greater then or equal to)' + 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)' required: false deprecated: false allowEmptyValue: true @@ -640,7 +640,7 @@ paths: - name: end in: query - description: 'Filter base on date (less then or equal to)' + 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)' required: false deprecated: false allowEmptyValue: true diff --git a/src/Api/Dto/DailyOccurrence.php b/src/Api/Dto/DailyOccurrence.php index 99caf72..ee69518 100644 --- a/src/Api/Dto/DailyOccurrence.php +++ b/src/Api/Dto/DailyOccurrence.php @@ -12,8 +12,9 @@ use ApiPlatform\OpenApi\Model\Response; use App\Api\Filter\ElasticSearch\BooleanFilter; use App\Api\Filter\ElasticSearch\DateFilter; -use App\Api\Filter\ElasticSearch\EventTagFilter; +use App\Api\Filter\ElasticSearch\IdFilter; use App\Api\Filter\ElasticSearch\MatchFilter; +use App\Api\Filter\ElasticSearch\TagFilter; use App\Api\State\DailyOccurrenceRepresentationProvider; use App\Model\DateLimits; @@ -51,14 +52,18 @@ )] #[ApiFilter( MatchFilter::class, - properties: ['event.title', 'event.organizer.name', 'event.organizer.entityId', 'event.location.name', 'event.location.entityId'] + properties: ['event.title', 'event.organizer.name', 'event.location.name'] +)] +#[ApiFilter( + IdFilter::class, + properties: ['event.organizer.entityId', 'event.location.entityId'] )] #[ApiFilter( BooleanFilter::class, properties: ['event.publicAccess'] )] #[ApiFilter( - EventTagFilter::class, + TagFilter::class, properties: ['event.tags'] )] #[ApiFilter( diff --git a/src/Api/Dto/Event.php b/src/Api/Dto/Event.php index c24f5f7..21ee2c1 100644 --- a/src/Api/Dto/Event.php +++ b/src/Api/Dto/Event.php @@ -12,8 +12,9 @@ use ApiPlatform\OpenApi\Model\Response; use App\Api\Filter\ElasticSearch\BooleanFilter; use App\Api\Filter\ElasticSearch\DateFilter; -use App\Api\Filter\ElasticSearch\EventTagFilter; +use App\Api\Filter\ElasticSearch\IdFilter; use App\Api\Filter\ElasticSearch\MatchFilter; +use App\Api\Filter\ElasticSearch\TagFilter; use App\Api\State\EventRepresentationProvider; use App\Model\DateLimits; @@ -51,14 +52,18 @@ )] #[ApiFilter( MatchFilter::class, - properties: ['title', 'organizer.name', 'organizer.entityId', 'location.name', 'location.entityId'] + properties: ['title', 'organizer.name', 'location.name'] +)] +#[ApiFilter( + IdFilter::class, + properties: ['organizer.entityId', 'location.entityId'] )] #[ApiFilter( BooleanFilter::class, properties: ['publicAccess'] )] #[ApiFilter( - EventTagFilter::class, + TagFilter::class, properties: ['tags'] )] #[ApiFilter( diff --git a/src/Api/Dto/Occurrence.php b/src/Api/Dto/Occurrence.php index 4a7a202..3eace61 100644 --- a/src/Api/Dto/Occurrence.php +++ b/src/Api/Dto/Occurrence.php @@ -10,10 +10,10 @@ use ApiPlatform\OpenApi\Model\Operation; use ApiPlatform\OpenApi\Model\Parameter; use ApiPlatform\OpenApi\Model\Response; -use App\Api\Filter\ElasticSearch\BooleanFilter; use App\Api\Filter\ElasticSearch\DateFilter; -use App\Api\Filter\ElasticSearch\EventTagFilter; +use App\Api\Filter\ElasticSearch\IdFilter; use App\Api\Filter\ElasticSearch\MatchFilter; +use App\Api\Filter\ElasticSearch\TagFilter; use App\Api\State\OccurrenceRepresentationProvider; use App\Model\DateLimits; @@ -52,14 +52,14 @@ )] #[ApiFilter( MatchFilter::class, - properties: ['event.title', 'event.organizer.name', 'event.organizer.entityId', 'event.location.name', 'event.location.entityId'] + properties: ['event.title', 'event.organizer.name', 'event.location.name'] )] #[ApiFilter( - BooleanFilter::class, - properties: ['event.publicAccess'] + IdFilter::class, + properties: ['event.organizer.entityId', 'event.location.entityId'] )] #[ApiFilter( - EventTagFilter::class, + TagFilter::class, properties: ['event.tags'] )] #[ApiFilter( diff --git a/src/Api/Filter/ElasticSearch/DateFilter.php b/src/Api/Filter/ElasticSearch/DateFilter.php index b21cecd..cae55ab 100644 --- a/src/Api/Filter/ElasticSearch/DateFilter.php +++ b/src/Api/Filter/ElasticSearch/DateFilter.php @@ -74,7 +74,7 @@ public function getDescription(string $resourceClass): array 'property' => $filterParameterName, 'type' => Type::BUILTIN_TYPE_STRING, 'required' => false, - 'description' => 'Filter base on date ('.$this->config[$value]->limit->value.')', + '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.')', 'openapi' => [ 'allowReserved' => false, 'allowEmptyValue' => true, diff --git a/src/Api/Filter/ElasticSearch/IdFilter.php b/src/Api/Filter/ElasticSearch/IdFilter.php new file mode 100644 index 0000000..2b86bc9 --- /dev/null +++ b/src/Api/Filter/ElasticSearch/IdFilter.php @@ -0,0 +1,52 @@ +getProperties($resourceClass); + $terms = []; + + /** @var string $property */ + foreach ($properties as $property) { + if (empty($context['filters'][$property])) { + // If no value or empty value is set, skip it. + continue; + } + $terms[$property] = explode(',', $context['filters'][$property]); + } + + return empty($terms) ? $terms : ['terms' => $terms + ['boost' => 1.0]]; + } + + public function getDescription(string $resourceClass): array + { + if (!$this->properties) { + return []; + } + + $description = []; + foreach ($this->properties as $filterParameterName => $value) { + $description[$filterParameterName] = [ + 'property' => $filterParameterName, + 'type' => Type::BUILTIN_TYPE_ARRAY, + 'required' => false, + 'description' => 'Filter based on given entity ids', + 'is_collection' => true, + 'openapi' => [ + 'allowReserved' => false, + 'allowEmptyValue' => true, + 'explode' => false, + ], + ]; + } + + return $description; + } +} diff --git a/src/Api/Filter/ElasticSearch/EventTagFilter.php b/src/Api/Filter/ElasticSearch/TagFilter.php similarity index 96% rename from src/Api/Filter/ElasticSearch/EventTagFilter.php rename to src/Api/Filter/ElasticSearch/TagFilter.php index aef055c..67f2786 100644 --- a/src/Api/Filter/ElasticSearch/EventTagFilter.php +++ b/src/Api/Filter/ElasticSearch/TagFilter.php @@ -6,7 +6,7 @@ use ApiPlatform\Metadata\Operation; use Symfony\Component\PropertyInfo\Type; -final class EventTagFilter extends AbstractFilter +final class TagFilter extends AbstractFilter { public function apply(array $clauseBody, string $resourceClass, ?Operation $operation = null, array $context = []): array {