onPostRetrieveResource()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 7
rs 10
c 1
b 0
f 0
1
<?php
2
3
4
namespace W2w\Laravel\Apie\Plugins\IlluminateDispatcher;
5
6
use Illuminate\Auth\AuthManager;
7
use Illuminate\Contracts\Auth\Access\Gate;
8
use Illuminate\Contracts\Events\Dispatcher;
9
use Illuminate\Support\Str;
10
use Illuminate\Validation\Factory;
11
use ReflectionClass;
12
use W2w\Laravel\Apie\Contracts\HasApieRulesContract;
13
use W2w\Lib\Apie\Events\DecodeEvent;
14
use W2w\Lib\Apie\Events\DeleteResourceEvent;
15
use W2w\Lib\Apie\Events\ModifySingleResourceEvent;
16
use W2w\Lib\Apie\Events\NormalizeEvent;
17
use W2w\Lib\Apie\Events\ResponseEvent;
18
use W2w\Lib\Apie\Events\RetrievePaginatedResourcesEvent;
19
use W2w\Lib\Apie\Events\RetrieveSingleResourceEvent;
20
use W2w\Lib\Apie\Events\StoreExistingResourceEvent;
21
use W2w\Lib\Apie\Events\StoreNewResourceEvent;
22
use W2w\Lib\Apie\PluginInterfaces\ResourceLifeCycleInterface;
23
24
/**
25
 * Link the Apie resource life cycle methods Laravel:
26
 * - event dispatcher
27
 * - validation rules with adding 'rules' in context.
28
 * - if the api resource is linked to a policy, check the policy.
29
 */
30
class IlluminateDispatcherPlugin implements ResourceLifeCycleInterface
31
{
32
    /**
33
     * @var Dispatcher
34
     */
35
    private $dispatcher;
36
37
    /**
38
     * @var Factory
39
     */
40
    private $validator;
41
42
    /**
43
     * @var AuthManager
44
     */
45
    private $gate;
46
47
    /**
48
     * @param Dispatcher $dispatcher
49
     * @param Factory $validator
50
     * @param Gate $gate
51
     */
52
    public function __construct(Dispatcher $dispatcher, Factory $validator, Gate $gate)
53
    {
54
        $this->dispatcher = $dispatcher;
55
        $this->validator = $validator;
56
        $this->gate = $gate;
0 ignored issues
show
Documentation Bug introduced by
It seems like $gate of type Illuminate\Contracts\Auth\Access\Gate is incompatible with the declared type Illuminate\Auth\AuthManager of property $gate.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
57
    }
58
59
    /**
60
     * @param string $methodName
61
     * @param object $event
62
     */
63
    private function dispatch(string $methodName, object $event)
64
    {
65
        $eventName = 'apie.' . Str::snake(substr($methodName, 2));
66
        $this->dispatcher->dispatch($eventName, $event);
67
    }
68
69
    /**
70
     * {@inheritDoc}
71
     */
72
    public function onPreDeleteResource(DeleteResourceEvent $event)
73
    {
74
        if ($this->gate->getPolicyFor($event->getResourceClass())) {
75
            $this->gate->authorize('remove', [$event->getResourceClass(), $event->getId()]);
76
        }
77
        $this->dispatch(__FUNCTION__, $event);
78
    }
79
80
    /**
81
     * {@inheritDoc}
82
     */
83
    public function onPostDeleteResource(DeleteResourceEvent $event)
84
    {
85
        $this->dispatch(__FUNCTION__, $event);
86
    }
87
88
    /**
89
     * {@inheritDoc}
90
     */
91
    public function onPreRetrieveResource(RetrieveSingleResourceEvent $event)
92
    {
93
        $this->dispatch(__FUNCTION__, $event);
94
    }
95
96
    /**
97
     * {@inheritDoc}
98
     */
99
    public function onPostRetrieveResource(RetrieveSingleResourceEvent $event)
100
    {
101
        if ($this->gate->getPolicyFor($event->getResource())) {
102
            $this->gate->authorize('view', $event->getResource());
103
        }
104
105
        $this->dispatch(__FUNCTION__, $event);
106
    }
107
108
    /**
109
     * {@inheritDoc}
110
     */
111
    public function onPreRetrieveAllResources(RetrievePaginatedResourcesEvent $event)
112
    {
113
        $this->dispatch(__FUNCTION__, $event);
114
    }
115
116
    /**
117
     * {@inheritDoc}
118
     */
119
    public function onPostRetrieveAllResources(RetrievePaginatedResourcesEvent $event)
120
    {
121
        $resources = $event->getResources();
122
123
        $event->setResources($this->iterateList($resources));
0 ignored issues
show
Bug introduced by
It seems like $resources can also be of type null; however, parameter $resourceList of W2w\Laravel\Apie\Plugins...erPlugin::iterateList() does only seem to accept iterable, 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

123
        $event->setResources($this->iterateList(/** @scrutinizer ignore-type */ $resources));
Loading history...
124
        $this->dispatch(__FUNCTION__, $event);
125
    }
126
127
    private function iterateList(iterable $resourceList)
128
    {
129
        foreach ($resourceList as $resource) {
130
            // do policy check for every individual item because of polymorphic item list.
131
            if (!$this->gate->getPolicyFor($resource) || $this->gate->allows('view', $resource)) {
132
                yield $resource;
133
            }
134
        }
135
    }
136
137
    /**
138
     * {@inheritDoc}
139
     */
140
    public function onPrePersistExistingResource(StoreExistingResourceEvent $event)
141
    {
142
        if ($this->gate->getPolicyFor($event->getResource())) {
143
            $this->gate->authorize('update', $event->getResource());
144
        }
145
        $this->dispatch(__FUNCTION__, $event);
146
    }
147
148
    /**
149
     * {@inheritDoc}
150
     */
151
    public function onPostPersistExistingResource(StoreExistingResourceEvent $event)
152
    {
153
        $this->dispatch(__FUNCTION__, $event);
154
    }
155
156
    /**
157
     * {@inheritDoc}
158
     */
159
    public function onPreModifyResource(ModifySingleResourceEvent $event)
160
    {
161
        $this->dispatch(__FUNCTION__, $event);
162
    }
163
164
    /**
165
     * {@inheritDoc}
166
     */
167
    public function onPostModifyResource(ModifySingleResourceEvent $event)
168
    {
169
        $this->dispatch(__FUNCTION__, $event);
170
    }
171
172
    /**
173
     * {@inheritDoc}
174
     */
175
    public function onPreCreateResource(StoreNewResourceEvent $event)
176
    {
177
        $this->dispatch(__FUNCTION__, $event);
178
    }
179
180
    /**
181
     * {@inheritDoc}
182
     */
183
    public function onPostCreateResource(StoreNewResourceEvent $event)
184
    {
185
        $this->dispatch(__FUNCTION__, $event);
186
    }
187
188
    /**
189
     * {@inheritDoc}
190
     */
191
    public function onPrePersistNewResource(StoreExistingResourceEvent $event)
192
    {
193
        if ($this->gate->getPolicyFor($event->getResource())) {
194
            $this->gate->authorize('create', $event->getResource());
195
        }
196
        $this->dispatch(__FUNCTION__, $event);
197
    }
198
199
    /**
200
     * {@inheritDoc}
201
     */
202
    public function onPostPersistNewResource(StoreExistingResourceEvent $event)
203
    {
204
        $this->dispatch(__FUNCTION__, $event);
205
    }
206
207
    /**
208
     * {@inheritDoc}
209
     */
210
    public function onPreCreateResponse(ResponseEvent $event)
211
    {
212
        $this->dispatch(__FUNCTION__, $event);
213
    }
214
215
    /**
216
     * {@inheritDoc}
217
     */
218
    public function onPostCreateResponse(ResponseEvent $event)
219
    {
220
        $this->dispatch(__FUNCTION__, $event);
221
    }
222
223
    /**
224
     * {@inheritDoc}
225
     */
226
    public function onPreCreateNormalizedData(NormalizeEvent $event)
227
    {
228
        $this->dispatch(__FUNCTION__, $event);
229
    }
230
231
    /**
232
     * {@inheritDoc}
233
     */
234
    public function onPostCreateNormalizedData(NormalizeEvent $event)
235
    {
236
        $this->dispatch(__FUNCTION__, $event);
237
    }
238
239
    /**
240
     * {@inheritDoc}
241
     */
242
    public function onPreDecodeRequestBody(DecodeEvent $event)
243
    {
244
        $this->dispatch(__FUNCTION__, $event);
245
    }
246
247
    /**
248
     * {@inheritDoc}
249
     */
250
    public function onPostDecodeRequestBody(DecodeEvent $event)
251
    {
252
        $refl = new ReflectionClass($event->getResourceClass());
253
        if ($refl->implementsInterface(HasApieRulesContract::class)) {
254
            // maybe move this to a listener?
255
            $rules = $refl->getMethod('getApieRules')->invoke(null);
256
            $decodedData = json_decode(json_encode($event->getDecodedData()), true);
257
            $validation = $this->validator->make($decodedData, $rules);
258
            $validation->validate();
259
        }
260
        $this->dispatch(__FUNCTION__, $event);
261
    }
262
}
263