Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.97% covered (success)
96.97%
32 / 33
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
AddNoVarySearchHeaderEventSubscriber
96.97% covered (success)
96.97%
32 / 33
50.00% covered (danger)
50.00%
1 / 2
10
0.00% covered (danger)
0.00%
0 / 1
 getSubscribedEvents
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 onApieResponseCreated
96.67% covered (success)
96.67%
29 / 30
0.00% covered (danger)
0.00%
0 / 1
9
1<?php
2namespace Apie\RestApi\EventListeners;
3
4use Apie\Common\Actions\GetListAction;
5use Apie\Common\Events\ApieResponseCreated;
6use Apie\Core\BoundedContext\BoundedContextId;
7use Apie\Core\ContextConstants;
8use Apie\Core\Datalayers\ApieDatalayer;
9use Apie\Core\Datalayers\ApieDatalayerWithFilters;
10use ReflectionClass;
11use Symfony\Component\EventDispatcher\EventSubscriberInterface;
12
13class AddNoVarySearchHeaderEventSubscriber implements EventSubscriberInterface
14{
15    public static function getSubscribedEvents(): array
16    {
17        return [
18            ApieResponseCreated::class => 'onApieResponseCreated',
19        ];
20    }
21
22    public function onApieResponseCreated(ApieResponseCreated $event): void
23    {
24        $context = $event->context;
25        if (
26            !$context->getContext(ContextConstants::REST_API, false)
27            || $context->getContext(ContextConstants::APIE_ACTION, false) !== GetListAction::class
28        ) {
29            return;
30        }
31
32        $dataLayer = $context->getContext(ApieDatalayer::class, false);
33        $resourceName = $context->getContext(ContextConstants::RESOURCE_NAME, false);
34        if (
35            !$dataLayer instanceof ApieDatalayerWithFilters
36            || !is_string($resourceName)
37            || !class_exists($resourceName)
38        ) {
39            return;
40        }
41
42        $resourceClass = new ReflectionClass($resourceName);
43        $boundedContextId = new BoundedContextId(
44            $context->getContext(ContextConstants::BOUNDED_CONTEXT_ID, false) ?? 'default'
45        );
46        $filterColumns = $dataLayer->getFilterColumns($resourceClass, $boundedContextId);
47        if ($filterColumns === null) {
48            return;
49        }
50
51        $parameters = ['page', 'items_per_page', 'search'];
52        foreach ($filterColumns as $filterColumn) {
53            $parameters[] = 'query[' . $filterColumn . ']';
54        }
55
56        if ($dataLayer->getOrderByColumns($resourceClass, $boundedContextId)?->count()) {
57            $parameters[] = 'order_by';
58        }
59
60        $except = array_map(
61            static fn (string $parameter): string => '"' . addcslashes($parameter, '"\\') . '"',
62            $parameters
63        );
64        $event->response = $event->response->withHeader(
65            'No-Vary-Search',
66            'params, except=(' . implode(' ', $except) . ')'
67        );
68    }
69}