Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.06% covered (success)
97.06%
33 / 34
0.00% covered (danger)
0.00%
0 / 1
CRAP
0.00% covered (danger)
0.00%
0 / 1
SearchEntitiesEndpoint
97.06% covered (success)
97.06%
33 / 34
0.00% covered (danger)
0.00%
0 / 1
4
0.00% covered (danger)
0.00%
0 / 1
 handle
97.06% covered (success)
97.06%
33 / 34
0.00% covered (danger)
0.00%
0 / 1
4
1<?php
2
3namespace Olz\Api\Endpoints;
4
5use Doctrine\Common\Collections\Criteria;
6use Olz\Api\OlzTypedEndpoint;
7use Olz\Entity\Common\OlzEntity;
8use Olz\Entity\Faq\QuestionCategory;
9use Olz\Entity\Roles\Role;
10use Olz\Entity\SolvEvent;
11use Olz\Entity\Termine\TerminLocation;
12use Olz\Entity\Termine\TerminTemplate;
13use Olz\Entity\Users\User;
14
15/**
16 * TODO: Support key-of<self::SUPPORTED_ENTITY_TYPES>.
17 *
18 * @phpstan-type OlzEntityResult array{
19 *   id: int<1, max>,
20 *   title: non-empty-string,
21 * }
22 * @phpstan-type OlzSearchableEntityTypes 'QuestionCategory'|'SolvEvent'|'TerminLocation'|'TerminTemplate'|'Role'|'User'
23 *
24 * @extends OlzTypedEndpoint<
25 *   array{
26 *     entityType: OlzSearchableEntityTypes,
27 *     query?: ?string,
28 *     id?: ?int<1, max>
29 *   },
30 *   array{
31 *     result: array<OlzEntityResult>
32 *   }
33 * >
34 */
35class SearchEntitiesEndpoint extends OlzTypedEndpoint {
36    public const SUPPORTED_ENTITY_TYPES = [
37        'QuestionCategory' => QuestionCategory::class,
38        'SolvEvent' => SolvEvent::class,
39        'TerminLocation' => TerminLocation::class,
40        'TerminTemplate' => TerminTemplate::class,
41        'Role' => Role::class,
42        'User' => User::class,
43    ];
44
45    protected function handle(mixed $input): mixed {
46        $this->checkPermission('any');
47
48        $entity_type = $input['entityType'];
49        $entity_class = self::SUPPORTED_ENTITY_TYPES[$entity_type];
50
51        $search_terms = preg_split('/\s+/', $input['query'] ?? '') ?: [];
52        $matching_criterium = Criteria::expr()->andX(
53            ...array_map(function ($search_term) use ($entity_class) {
54                return $entity_class::getCriteriaForQuery($search_term);
55            }, $search_terms),
56        );
57
58        $id = $input['id'] ?? null;
59        $id_field_name = $entity_class::getIdFieldNameForSearch();
60        $id_criteria = $id ? [Criteria::expr()->eq($id_field_name, $id)] : [];
61
62        $repo = $this->entityManager()->getRepository($entity_class);
63        $on_off_criteria = is_subclass_of($entity_class, OlzEntity::class) ? [
64            Criteria::expr()->eq('on_off', 1),
65        ] : [];
66        $criteria = Criteria::create()
67            ->where(Criteria::expr()->andX(
68                $matching_criterium,
69                ...$on_off_criteria,
70                ...$id_criteria,
71            ))
72            ->setFirstResult(0)
73            ->setMaxResults(10)
74        ;
75        $matching_entities = $repo->matching($criteria);
76
77        return [
78            'result' => array_map(function ($entity) {
79                return [
80                    'id' => $entity->getIdForSearch(),
81                    'title' => $entity->getTitleForSearch(),
82                ];
83            }, [...$matching_entities]),
84        ];
85    }
86}