GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 3477bc...5637b4 )
by Sebastian
02:27
created

Menu::determineFirstParameterType()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 10
rs 9.4285
cc 2
eloc 6
nc 1
nop 1
1
<?php
2
3
namespace Spatie\Menu;
4
5
use ReflectionFunction;
6
use ReflectionParameter;
7
use Spatie\HtmlElement\Html;
8
use Spatie\Menu\Items\Link;
9
use Spatie\Menu\Traits\HtmlAttributes;
10
use Spatie\Menu\Traits\ParentAttributes;
11
12
class Menu implements Item
13
{
14
    use HtmlAttributes, ParentAttributes;
15
16
    /** @var array */
17
    protected $items = [];
18
19
    /** @var string */
20
    protected $prepend = '';
21
22
    /** @var string */
23
    protected $append = '';
24
25
    /** @var array */
26
    protected $filters = [];
27
28
    /**
29
     * @param \Spatie\Menu\Item[] ...$items
30
     */
31
    protected function __construct(Item ...$items)
32
    {
33
        $this->items = $items;
34
    }
35
36
    /**
37
     * Create a new menu, optionally prefilled with items.
38
     *
39
     * @param array $items
40
     *
41
     * @return static
42
     */
43
    public static function new(array $items = [])
44
    {
45
        return new static(...$items);
46
    }
47
48
    /**
49
     * Add an item to the menu. This also applies all registered filters on the item. If a filter
50
     * returns false, the item won't be added.
51
     *
52
     * @param \Spatie\Menu\Item $item
53
     *
54
     * @return $this
55
     */
56
    public function add(Item $item)
57
    {
58
        if ($this->applyFilters($item) === false) {
59
            return $this;
60
        }
61
62
        $this->items[] = $item;
63
64
        return $this;
65
    }
66
67
    /**
68
     * Applies all the currently registered filters to an item.
69
     *
70
     * @param \Spatie\Menu\Item $item
71
     *
72
     * @return bool
73
     */
74
    protected function applyFilters(Item $item) : bool
75
    {
76
        foreach ($this->filters as $filter) {
77
            $type = $this->determineFirstParameterType($filter);
78
79
            if ($type !== null && !$item instanceof $type) {
80
                continue;
81
            }
82
83
            if ($filter($item) === false) {
84
                return false;
85
            }
86
        }
87
88
        return true;
89
    }
90
91
    /**
92
     * Map through all the items and return an array containing the result. If you typehint the
93
     * item parameter in the callable, it wil only be applied to items of that type.
94
     *
95
     * @param callable $callable
96
     *
97
     * @return array
98
     */
99
    public function map(callable $callable) : array
100
    {
101
        $type = $this->determineFirstParameterType($callable);
102
103
        $items = $this->items;
104
105
        if ($type !== null) {
106
            $items = array_filter($items, function (Item $item) use ($type) {
107
                return $item instanceof $type;
108
            });
109
        }
110
111
        return array_map($callable, $items);
112
    }
113
114
    /**
115
     * Iterate over all the items and apply a callback. If you typehint the
116
     * item parameter in the callable, it wil only be applied to items of that type.
117
     *
118
     * @param callable $callable
119
     *
120
     * @return $this
121
     */
122 View Code Duplication
    public function each(callable $callable)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
123
    {
124
        $type = $this->determineFirstParameterType($callable);
125
126
        foreach ($this->items as $item) {
127
            if ($type !== null && !$item instanceof $type) {
128
                continue;
129
            }
130
131
            $callable($item);
132
        }
133
134
        return $this;
135
    }
136
137
    /**
138
     * Register a filter to the menu. When an item is added, all filters will be applied to the
139
     * item. If a filter returns false, the item won't be added. If you typehint the item
140
     * parameter in the callable, it wil only be applied to items of that type.
141
     *
142
     * @param callable $callable
143
     *
144
     * @return $this
145
     */
146
    public function registerFilter(callable $callable)
147
    {
148
        $this->filters[] = $callable;
149
150
        return $this;
151
    }
152
153
    /**
154
     * Apply a callable to all existing items, and register it as a filter so it will get applied
155
     * to all new items too. If you typehint the item parameter in the callable, it wil only be
156
     * applied to items of that type.
157
     *
158
     * @param callable $callable
159
     *
160
     * @return $this
161
     */
162
    public function applyToAll(callable $callable)
163
    {
164
        $this->each($callable);
165
        $this->registerFilter($callable);
166
167
        return $this;
168
    }
169
170
    /**
171
     * Determine the type of the first parameter of a callable.
172
     *
173
     * @param callable $callable
174
     *
175
     * @return string|null
176
     */
177
    protected function determineFirstParameterType(callable $callable)
178
    {
179
        $reflection = new ReflectionFunction($callable);
180
181
        $parameterTypes = array_map(function (ReflectionParameter $parameter) {
182
            return $parameter->getClass() ? $parameter->getClass()->name : null;
183
        }, $reflection->getParameters());
184
185
        return $parameterTypes[0] ?? null;
186
    }
187
188
    /**
189
     * Prepend a string of html to the menu on render.
190
     *
191
     * @param string $prefix
192
     *
193
     * @return $this
194
     */
195
    public function prefixLinks(string $prefix)
196
    {
197
        return $this->applyToAll(function (Link $link) use ($prefix) {
198
            $link->prefix($prefix);
199
        });
200
    }
201
202
    /**
203
     * Prepend the menu with a string of html on render.
204
     *
205
     * @param string $prepend
206
     *
207
     * @return $this
208
     */
209
    public function prepend(string $prepend)
210
    {
211
        $this->prepend = $prepend;
212
213
        return $this;
214
    }
215
216
    /**
217
     * Append a string of html to the menu on render.
218
     *
219
     * @param string $append
220
     *
221
     * @return $this
222
     */
223
    public function append(string $append)
224
    {
225
        $this->append = $append;
226
227
        return $this;
228
    }
229
230
    /**
231
     * Determine whether the menu is active.
232
     *
233
     * @return bool
234
     */
235
    public function isActive() : bool
236
    {
237
        foreach ($this->items as $item) {
238
            if ($item->isActive()) {
239
                return true;
240
            }
241
        }
242
243
        return false;
244
    }
245
246
    /**
247
     * Set multiple items in the menu as active based on a callable that filters through items.
248
     * If you typehint the item parameter in the callable, it wil only be applied to items of
249
     * that type.
250
     *
251
     * @param callable $callable
252
     *
253
     * @return $this
254
     */
255 View Code Duplication
    public function setActive(callable $callable)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
256
    {
257
        $type = $this->determineFirstParameterType($callable);
258
259
        foreach ($this->items as $item) {
260
            if ($type && !$item instanceof $type) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $type of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
261
                continue;
262
            }
263
264
            if ($callable($item)) {
265
                $item->setActive();
266
            }
267
        }
268
269
        return $this;
270
    }
271
272
    /**
273
     * Render the menu in html.
274
     *
275
     * @return string
276
     */
277
    public function render() : string
278
    {
279
        $menu = Html::el(
280
            'ul',
281
            $this->attributes()->toArray(),
282
            $this->map(function (Item $item) {
283
                return Html::el(
284
                    $item->isActive() ? 'li.active' : 'li',
285
                    $item->getParentAttributes(),
286
                    $item->render()
287
                );
288
            })
289
        );
290
291
        return "{$this->prepend}{$menu}{$this->append}";
292
    }
293
294
    public function __toString() : string
295
    {
296
        return $this->render();
297
    }
298
}
299