PaginationPlugin::onPreDeleteResource()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 0
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 2
rs 10
1
<?php
2
3
namespace Apie\PaginationPlugin;
4
5
use Apie\Core\Events\DecodeEvent;
6
use Apie\Core\Events\DeleteResourceEvent;
7
use Apie\Core\Events\ModifySingleResourceEvent;
8
use Apie\Core\Events\NormalizeEvent;
9
use Apie\Core\Events\ResponseAllEvent;
10
use Apie\Core\Events\ResponseEvent;
11
use Apie\Core\Events\RetrievePaginatedResourcesEvent;
12
use Apie\Core\Events\RetrieveSingleResourceEvent;
13
use Apie\Core\Events\StoreExistingResourceEvent;
14
use Apie\Core\Events\StoreNewResourceEvent;
15
use Apie\Core\PluginInterfaces\ApieAwareInterface;
16
use Apie\Core\PluginInterfaces\ApieAwareTrait;
17
use Apie\Core\PluginInterfaces\NormalizerProviderInterface;
18
use Apie\Core\PluginInterfaces\OpenApiEventProviderInterface;
19
use Apie\Core\PluginInterfaces\ResourceLifeCycleInterface;
20
use Apie\Core\SearchFilters\SearchFilterRequest;
21
use Apie\OpenapiSchema\Map\HeaderMap;
22
use Apie\OpenapiSchema\Spec\Components;
23
use Apie\OpenapiSchema\Spec\Document;
24
use Apie\OpenapiSchema\Spec\Operation;
25
use Apie\OpenapiSchema\Spec\PathItem;
26
use Apie\OpenapiSchema\Spec\Reference;
27
use Apie\PaginationPlugin\Normalizers\PaginatorNormalizer;
28
use Pagerfanta\Adapter\ArrayAdapter;
29
use Pagerfanta\Pagerfanta;
30
31
class PaginationPlugin implements ResourceLifeCycleInterface, NormalizerProviderInterface, OpenApiEventProviderInterface, ApieAwareInterface
32
{
33
    use ApieAwareTrait;
34
35
    const PREV_HEADER = 'x-pagination-previous';
36
37
    const NEXT_HEADER = 'x-pagination-next';
38
39
    const FIRST_HEADER = 'x-pagination-first';
40
41
    const LAST_HEADER = 'x-pagination-last';
42
43
    const COUNT_HEADER = 'x-pagination-count';
44
45
    public function getNormalizers(): array
46
    {
47
        return [new PaginatorNormalizer()];
48
    }
49
50
    public function onOpenApiDocGenerated(Document $document): Document
51
    {
52
        $paths = $document->getPaths();
53
        $added = false;
54
        foreach ($paths as $url => $path) {
55
            if (strpos($url, '{id}', 0) === false && $path instanceof PathItem && $path->getGet() && $this->patch($path->getGet())) {
56
                $added = true;
57
            }
58
        }
59
        if ($added) {
60
            $components = $document->getComponents();
61
            if (!$components) {
62
                $components = Components::fromNative([]);
63
            }
64
            $headers = $components->getHeaders();
65
            $headers = $headers->with('Count', ['description' => 'Number of results', 'schema' => ['type' => 'number', 'format' => 'int']])
0 ignored issues
show
Bug introduced by
The method with() does not exist on Apie\OpenapiSchema\Map\HeaderMap. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

65
            $headers = $headers->/** @scrutinizer ignore-call */ with('Count', ['description' => 'Number of results', 'schema' => ['type' => 'number', 'format' => 'int']])

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
66
                ->with('Url', ['description' => 'pagination url', 'schema' => ['type' => 'string', 'format' => 'url']]);
67
            $components = $components->with('headers', $headers);
68
            return $document->with('components', $components);
69
        }
70
        return $document;
71
    }
72
73
    private function patch(Operation $operation): bool
74
    {
75
        $added = false;
76
        foreach ($operation->getResponses() as $key => $response) {
77
            if ($response instanceof Reference) {
78
                continue;
79
            }
80
            $added = true;
81
            $countSchema = new Reference('#/components/headers/Count');
82
            $urlSchema = new Reference('#/components/headers/Url');
83
            $headers = ($response->getHeaders() ?? new HeaderMap())->toNative();
84
            $headers[self::COUNT_HEADER] = $countSchema;
85
            $headers[self::PREV_HEADER] = $urlSchema;
86
            $headers[self::NEXT_HEADER] = $urlSchema;
87
            $headers[self::FIRST_HEADER] = $urlSchema;
88
            $headers[self::LAST_HEADER] = $urlSchema;
89
            $response = $response->with('headers', $headers);
90
            $operation = $operation->with($key, $response);
91
        }
92
        return $added;
93
    }
94
95
    public function onPreDeleteResource(DeleteResourceEvent $event)
96
    {
97
    }
98
99
    public function onPostDeleteResource(DeleteResourceEvent $event)
100
    {
101
    }
102
103
    public function onPreRetrieveResource(RetrieveSingleResourceEvent $event)
104
    {
105
    }
106
107
    public function onPostRetrieveResource(RetrieveSingleResourceEvent $event)
108
    {
109
    }
110
111
    public function onPreRetrieveAllResources(RetrievePaginatedResourcesEvent $event)
112
    {
113
    }
114
115
    public function onPostRetrieveAllResources(RetrievePaginatedResourcesEvent $event)
116
    {
117
    }
118
119
    public function onPrePersistExistingResource(StoreExistingResourceEvent $event)
120
    {
121
    }
122
123
    public function onPostPersistExistingResource(StoreExistingResourceEvent $event)
124
    {
125
    }
126
127
    public function onPreDecodeRequestBody(DecodeEvent $event)
128
    {
129
    }
130
131
    public function onPostDecodeRequestBody(DecodeEvent $event)
132
    {
133
    }
134
135
    public function onPreModifyResource(ModifySingleResourceEvent $event)
136
    {
137
    }
138
139
    public function onPostModifyResource(ModifySingleResourceEvent $event)
140
    {
141
    }
142
143
    public function onPreCreateResource(StoreNewResourceEvent $event)
144
    {
145
    }
146
147
    public function onPostCreateResource(StoreNewResourceEvent $event)
148
    {
149
    }
150
151
    public function onPrePersistNewResource(StoreExistingResourceEvent $event)
152
    {
153
    }
154
155
    public function onPostPersistNewResource(StoreExistingResourceEvent $event)
156
    {
157
    }
158
159
    public function onPreCreateResponse(ResponseEvent $event)
160
    {
161
    }
162
163
    public function onPostCreateResponse(ResponseEvent $event)
164
    {
165
        if (!($event instanceof ResponseAllEvent)) {
166
            return;
167
        }
168
        $resource = $event->getResource();
169
        if (!($resource instanceof Pagerfanta)) {
170
            if (is_array($resource)) {
171
                $resource = new Pagerfanta(new ArrayAdapter($resource));
172
            } else if (is_iterable($resource)) {
173
                $resource = new Pagerfanta(new ArrayAdapter(iterator_to_array($resource)));
174
            } else {
175
                return;
176
            }
177
            $event->getSearchFilterRequest()->updatePaginator($resource);
178
        }
179
        $response = $event->getResponse()
180
            ->withHeader(self::FIRST_HEADER, $this->generateUrl($event, 0))
181
            ->withHeader(self::LAST_HEADER, $this->generateUrl($event, $resource->getNbPages() - 1))
182
            ->withHeader(self::COUNT_HEADER, $resource->getNbResults());
183
        if ($resource->hasPreviousPage()) {
184
            $response = $response->withHeader(self::PREV_HEADER, $this->generateUrl($event, $resource->getPreviousPage() - 1));
185
        }
186
        if ($resource->hasNextPage()) {
187
            $response = $response->withHeader(self::NEXT_HEADER, $this->generateUrl($event, $resource->getNextPage() - 1));
188
        }
189
        $event->setResponse($response);
0 ignored issues
show
Bug introduced by
It seems like $response can also be of type null; however, parameter $response of Apie\Core\Events\ResponseEvent::setResponse() does only seem to accept Psr\Http\Message\ResponseInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

189
        $event->setResponse(/** @scrutinizer ignore-type */ $response);
Loading history...
190
    }
191
192
    private function generateUrl(ResponseAllEvent  $event, int $page)
193
    {
194
        $filterRequest = new SearchFilterRequest($page, $event->getSearchFilterRequest()->getNumberOfItems());
195
        return $this->getApie()->getOverviewUrlForResourceClass($event->getResourceClass(), $filterRequest);
196
    }
197
198
    public function onPreCreateNormalizedData(NormalizeEvent $event)
199
    {
200
    }
201
202
    public function onPostCreateNormalizedData(NormalizeEvent $event)
203
    {
204
    }
205
}
206