Test Failed
Push — master ( f043ce...f1785b )
by Antonio Carlos
04:03
created

ResourceChecker   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 327
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 81.39%

Importance

Changes 0
Metric Value
dl 0
loc 327
ccs 70
cts 86
cp 0.8139
rs 10
c 0
b 0
f 0
wmc 28
lcom 1
cbo 5

16 Methods

Rating   Name   Duplication   Size   Complexity  
A getCurrentAction() 0 4 1
A __construct() 0 6 1
A makeResult() 0 20 3
A setResources() 0 4 1
A checkResources() 0 26 3
A checkResource() 0 17 2
A getCachedResources() 0 12 3
A allResourcesAreGood() 0 8 1
A getNonGlobalResources() 0 6 1
A getGlobalResources() 0 6 1
A getResources() 0 4 1
A setCurrentAction() 0 4 1
A loadResources() 0 14 3
A makeResource() 0 8 2
A sortResources() 0 16 3
A getResourceBySlug() 0 6 1
1
<?php
2
3
namespace PragmaRX\Health\Support;
4
5
use Exception;
6
use Illuminate\Support\Collection;
7
use PragmaRX\Health\Support\Traits\HandleExceptions;
8
9
class ResourceChecker
10
{
11
    use HandleExceptions;
12
13
    /**
14
     * Unknown error.
15
     */
16
    const UNKNOWN_ERROR = 'Unknown error.';
17
18
    /**
19
     * The current action.
20
     *
21
     * @var
22
     */
23
    protected $currentAction = 'check';
24
25
    /**
26
     * All resources.
27
     *
28
     * @var
29
     */
30
    protected $resources;
31
32
    /**
33
     * Was checked?
34
     *
35
     * @var
36
     */
37
    protected $checked;
38
39
    /**
40
     * Services already notified of error.
41
     *
42
     * @var
43
     */
44
    protected $notified = [];
45
46
    /**
47
     * The cache service.
48
     *
49
     * @var Cache
50
     */
51
    protected $cache;
52
53
    /**
54
     * Resource loader.
55
     *
56
     * @var ResourceLoader
57
     */
58
    protected $resourceLoader;
59
60
    /**
61
     * ResourceChecker constructor.
62
     *
63
     * @param ResourceLoader $resourceLoader
64
     * @param Cache $cache
65
     */
66 10
    public function __construct(ResourceLoader $resourceLoader, Cache $cache)
67
    {
68 10
        $this->cache = $cache;
69
70 10
        $this->resourceLoader = $resourceLoader;
71 10
    }
72
73
    /**
74
     * Check all resources.
75
     *
76
     * @param bool $force
77
     * @return \Illuminate\Support\Collection
78
     * @throws Exception
79
     */
80 8
    public function checkResources($force = false)
81
    {
82 8
        if (! ($resources = $this->getCachedResources($force))->isEmpty()) {
83 5
            return $resources;
84
        }
85
86 3
        if (! $this->allResourcesAreGood()) {
87
            return $this->resources = collect();
88
        }
89
90 3
        $resources = $this->sortResources(
91 3
            $this->getNonGlobalResources()
92
                ->each(function ($resource) {
93 3
                    $this->checkResource($resource);
94 3
                })
95 3
                ->merge(
96
                    $this->getGlobalResources()->each(function ($resource) {
97
                        return $resource->checkGlobal($this->getResources());
98 3
                    })
99
                )
100
        );
101
102 3
        $this->checked = true;
103
104 3
        return $this->resources = $this->cache->cacheResources($resources);
105
    }
106
107
    /**
108
     * Check a resource.
109
     *
110
     * @param $resource
111
     * @return array
112
     * @throws Exception
113
     */
114 4
    public function checkResource($resource)
115
    {
116
        $resource =
117 4
            $resource instanceof Resource
118 3
                ? $resource
119 4
                : $this->getResourceBySlug($resource);
120
121
        $checked = $this->cache->remember($resource->slug, function () use (
122 1
            $resource
123
        ) {
124 1
            return $resource->check($this->getCurrentAction());
125 4
        });
126
127 4
        $resource->targets = $checked->targets;
128
129 4
        return $resource;
130
    }
131
132
    /**
133
     * Get cached resources.
134
     *
135
     * @param bool $force
136
     * @return \Illuminate\Support\Collection
137
     * @throws Exception
138
     */
139 8
    protected function getCachedResources($force = false)
140
    {
141 8
        if ($force) {
142 2
            return collect();
143
        }
144
145 6
        if ($this->checked) {
146
            return $this->getResources();
147
        }
148
149 6
        return $this->resources = $this->cache->getCachedResources();
150
    }
151
152
    /**
153
     * Get current action.
154
     *
155
     * @return mixed
156
     */
157 1
    public function getCurrentAction()
158
    {
159 1
        return $this->currentAction;
160
    }
161
162
    /**
163
     * Get all non global resources.
164
     *
165
     * @return bool
166
     * @throws Exception
167
     */
168 3
    protected function allResourcesAreGood()
169
    {
170 3
        return ! $this->getResources()
171
            ->reject(function ($resource) {
172 3
                return ! $resource instanceof Resource;
173 3
            })
174 3
            ->isEmpty();
175
    }
176
177
    /**
178
     * Get all non global resources.
179
     *
180
     * @return Collection
181
     * @throws Exception
182
     */
183 3
    protected function getNonGlobalResources()
184
    {
185
        return $this->getResources()->filter(function (Resource $resource) {
186 3
            return ! $resource->isGlobal;
187 3
        });
188
    }
189
190
    /**
191
     * Get all global resources.
192
     *
193
     * @return Collection
194
     * @throws Exception
195
     */
196 3
    protected function getGlobalResources()
197
    {
198
        return $this->getResources()->filter(function (Resource $resource) {
199 3
            return $resource->isGlobal;
200 3
        });
201
    }
202
203
    /**
204
     * Get a resource by slug.
205
     *
206
     * @param $slug
207
     * @return mixed
208
     * @throws Exception
209
     */
210 1
    public function getResourceBySlug($slug)
211
    {
212 1
        return $this->getResources()
213 1
            ->where('slug', $slug)
214 1
            ->first();
215
    }
216
217
    /**
218
     * Make the result array.
219
     *
220
     * @param $exception
221
     * @param $resourceChecker
222
     * @return array
223
     */
224
    protected function makeResult($exception, $resourceChecker)
225
    {
226
        $message = $exception->getMessage()
227
            ? $exception->getMessage()
228
            : static::UNKNOWN_ERROR;
229
230
        if (! isset($resourceChecker)) {
231
            return [
232
                null,
233
                [
234
                    'healthy' => false,
235
                    'message' => $message,
236
                ],
237
            ];
238
        }
239
240
        $resourceChecker->makeResult(false, $message);
241
242
        return [$resourceChecker, null];
243
    }
244
245
    /**
246
     * Get all resources.
247
     *
248
     * @return \Illuminate\Support\Collection
249
     * @throws Exception
250
     */
251 4
    public function getResources()
252
    {
253 4
        return $this->sortResources($this->loadResources());
254
    }
255
256
    /**
257
     * Set the current action.
258
     *
259
     * @param mixed $currentAction
260
     */
261 1
    public function setCurrentAction($currentAction)
262
    {
263 1
        $this->currentAction = $currentAction;
264 1
    }
265
266
    /**
267
     * Resources setter.
268
     *
269
     * @param mixed $resources
270
     */
271
    public function setResources($resources)
272
    {
273
        $this->resources = $resources;
274
    }
275
276
    /**
277
     * Load all resources.
278
     *
279
     * @return \Illuminate\Support\Collection
280
     * @throws Exception
281
     */
282 4
    public function loadResources()
283
    {
284 4
        if (is_null($this->resources) || $this->resources->isEmpty()) {
285 3
            $this->resources = $this->resourceLoader->loadResources()->map(
286
                function ($resource) {
287
                    return $this->handleExceptions(function () use ($resource) {
288 3
                        return $this->makeResource($resource);
289 3
                    });
290 3
                }
291
            );
292
        }
293
294 4
        return $this->resources;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->resources; (object|integer|double|string|array|boolean) is incompatible with the return type documented by PragmaRX\Health\Support\...eChecker::loadResources of type Illuminate\Support\Collection.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
295
    }
296
297
    /**
298
     * Get one resource.
299
     *
300
     * @param resource|Collection $resource
301
     * @return resource
302
     * @throws Exception
303
     */
304 3
    public function makeResource($resource)
305
    {
306 3
        if ($resource instanceof Resource) {
307
            return $resource;
308
        }
309
310 3
        return Resource::factory($resource);
0 ignored issues
show
Bug introduced by
It seems like $resource defined by parameter $resource on line 304 can also be of type resource; however, PragmaRX\Health\Support\Resource::factory() does only seem to accept object<Illuminate\Support\Collection>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
311
    }
312
313
    /**
314
     * Sort resources.
315
     *
316
     * @param $resources
317
     * @return \Illuminate\Support\Collection
318
     */
319 4
    protected function sortResources($resources)
320
    {
321 4
        if ($sortBy = config('health.sort_by')) {
322
            return $resources->sortBy(function ($resource) use ($sortBy) {
323
                return $this->handleExceptions(function () use (
324 3
                    $resource,
325 3
                    $sortBy
326
                ) {
327
                    return
328 3
                        ($resource->isGlobal ? 'a-' : 'z-').$resource->$sortBy;
329 3
                });
330 3
            });
331
        }
332
333 1
        return $resources;
334
    }
335
}
336