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 ( d2d60b...ff9598 )
by Sebastian
02:00
created

Menu::setActiveClass()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace Spatie\Menu;
4
5
use Spatie\HtmlElement\HtmlElement;
6
use Spatie\Menu\Traits\HtmlAttributes;
7
use Spatie\Menu\Traits\ParentAttributes;
8
9
class Menu implements Item
10
{
11
    use HtmlAttributes, ParentAttributes;
12
13
    /** @var array */
14
    protected $items = [];
15
16
    /** @var string */
17
    protected $prepend = '';
18
19
    /** @var string */
20
    protected $append = '';
21
22
    /** @var array */
23
    protected $filters = [];
24
25
    /** @var string */
26
    protected $activeClass = 'active';
27
28
    /**
29
     * @param \Spatie\Menu\Item[] ...$items
30
     */
31
    protected function __construct(Item ...$items)
32
    {
33
        $this->items = $items;
34
35
        $this->bootHtmlAttributes();
36
        $this->bootParentAttributes();
37
    }
38
39
    /**
40
     * Create a new menu, optionally prefilled with items.
41
     *
42
     * @param array $items
43
     *
44
     * @return static
45
     */
46
    public static function new(array $items = [])
47
    {
48
        return new static(...array_values($items));
49
    }
50
51
    /**
52
     * Add an item to the menu. This also applies all registered filters on the item. If a filter
53
     * returns false, the item won't be added.
54
     *
55
     * @param \Spatie\Menu\Item $item
56
     *
57
     * @return $this
58
     */
59
    public function add(Item $item)
60
    {
61
        foreach ($this->filters as $filter) {
62
            $this->applyFilter($filter, $item);
63
        }
64
65
        $this->items[] = $item;
66
67
        return $this;
68
    }
69
70
    /**
71
     * Shortcut function to add a plain link to the menu.
72
     *
73
     * @param string $url
74
     * @param string $text
75
     *
76
     * @return \Spatie\Menu\Menu
77
     */
78
    public function link(string $url, string $text)
79
    {
80
        return $this->add(Link::to($url, $text));
81
    }
82
83
    /**
84
     * Apply a filter to an item. Returns the result of the filter.
85
     *
86
     * @param callable $filter
87
     * @param \Spatie\Menu\Item $item
88
     */
89
    protected function applyFilter(callable $filter, Item $item)
90
    {
91
        $type = first_parameter_type($filter);
92
93
        if (!item_matches_type($item, $type)) {
94
            return;
95
        }
96
97
        $filter($item);
98
    }
99
100
    /**
101
     * Iterate over all the items and apply a callback. If you typehint the
102
     * item parameter in the callable, it wil only be applied to items of that type.
103
     *
104
     * @param callable $callable
105
     *
106
     * @return $this
107
     */
108
    public function each(callable $callable)
109
    {
110
        $type = first_parameter_type($callable);
111
112
        foreach ($this->items as $item) {
113
            if (!item_matches_type($item, $type)) {
114
                continue;
115
            }
116
117
            $callable($item);
118
        }
119
120
        return $this;
121
    }
122
123
    /**
124
     * Register a filter to the menu. When an item is added, all filters will be applied to the
125
     * item. If you typehint the item
126
     * parameter in the callable, it wil only be applied to items of that type.
127
     *
128
     * @param callable $callable
129
     *
130
     * @return $this
131
     */
132
    public function registerFilter(callable $callable)
133
    {
134
        $this->filters[] = $callable;
135
136
        return $this;
137
    }
138
139
    /**
140
     * Apply a callable to all existing items, and register it as a filter so it will get applied
141
     * to all new items too. If you typehint the item parameter in the callable, it wil only be
142
     * applied to items of that type.
143
     *
144
     * @param callable $callable
145
     *
146
     * @return $this
147
     */
148
    public function applyToAll(callable $callable)
149
    {
150
        $this->each($callable);
151
        $this->registerFilter($callable);
152
153
        return $this;
154
    }
155
156
    /**
157
     * Prepend a string of html to the menu on render.
158
     *
159
     * @param string $prefix
160
     *
161
     * @return $this
162
     */
163
    public function prefixLinks(string $prefix)
164
    {
165
        return $this->applyToAll(function (Link $link) use ($prefix) {
166
            $link->prefix($prefix);
167
        });
168
    }
169
170
    /**
171
     * Prepend the menu with a string of html on render.
172
     *
173
     * @param string $prepend
174
     *
175
     * @return $this
176
     */
177
    public function prepend(string $prepend)
178
    {
179
        $this->prepend = $prepend;
180
181
        return $this;
182
    }
183
184
    /**
185
     * Prepend the menu with a string of html on render if a certain condition is met.
186
     *
187
     * @param bool $condition
188
     * @param string $prepend
189
     *
190
     * @return $this
191
     */
192
    public function prependIf(bool $condition, string $prepend)
193
    {
194
        if ($condition) {
195
            return $this->prepend($prepend);
196
        }
197
198
        return $this;
199
    }
200
201
    /**
202
     * Append a string of html to the menu on render.
203
     *
204
     * @param string $append
205
     *
206
     * @return $this
207
     */
208
    public function append(string $append)
209
    {
210
        $this->append = $append;
211
212
        return $this;
213
    }
214
215
    /**
216
     * Append the menu with a string of html on render if a certain condition is met.
217
     *
218
     * @param bool $condition
219
     * @param string $append
220
     *
221
     * @return static
222
     */
223
    public function appendIf(bool $condition, string $append)
224
    {
225
        if ($condition) {
226
            return $this->append($append);
227
        }
228
229
        return $this;
230
    }
231
232
    /**
233
     * Determine whether the menu is active.
234
     *
235
     * @return bool
236
     */
237
    public function isActive() : bool
238
    {
239
        foreach ($this->items as $item) {
240
            if ($item->isActive()) {
241
                return true;
242
            }
243
        }
244
245
        return false;
246
    }
247
248
    /**
249
     * Set multiple items in the menu as active based on a callable that filters through items.
250
     * If you typehint the item parameter in the callable, it wil only be applied to items of
251
     * that type.
252
     *
253
     * @param callable|string $patternOrCallable
254
     * @param string $root
255
     *
256
     * @return $this
257
     */
258
    public function setActive($patternOrCallable, string $root = '/')
259
    {
260
        if (is_string($patternOrCallable)) {
261
            return $this->setActiveFromUrl($patternOrCallable, $root);
262
        }
263
264
        if (is_callable($patternOrCallable)) {
265
            return $this->setActiveFromCallable($patternOrCallable);
266
        }
267
268
        throw new \InvalidArgumentException('`setActive` requires a pattern or a callable');
269
    }
270
271
    /**
272
     * Set all relevant children active based on the current request's URL.
273
     *
274
     * /, /about, /contact => request to /about will set the about link active.
275
     *
276
     * /en, /en/about, /en/contact => request to /en won't set /en active if the request root
277
     *                                is set to /en.
278
     *
279
     * @param string $url The current request url.
280
     * @param string $root If the link's URL is an exact match with the request root, the
281
     *                            link won't be set active. This behavior is to avoid having home
282
     *                            links active on every request.
283
     *
284
     * @return $this
285
     */
286
    public function setActiveFromUrl(string $url, string $root = '/')
287
    {
288
        $requestUrl = url_parts($url);
289
        $requestRoot = strip_trailing_slashes($root, '/');
290
291
        $this->applyToAll(function (Link $link) use ($requestUrl, $requestRoot) {
292
293
            $url = url_parts($link->getUrl());
294
295
            // If the menu item is on a different host it can't be active.
296
            if ($url['host'] !== '' && $url['host'] !== $requestUrl['host']) {
297
                return;
298
            }
299
300
            // If the request url or the link url is on the root, only set exact matches active.
301
            if (
302
                $requestUrl['path'] === $requestRoot ||
303
                $url['path'] === $requestRoot
304
            ) {
305
                if ($url['path'] === $requestUrl['path']) {
306
                    $link->setActive();
307
                }
308
309
                return;
310
            }
311
312
            // The menu item is active if it's path starts with the request path.
313
            if (strpos($url['path'], $requestUrl['path']) === 0) {
314
                $link->setActive();
315
            };
316
        });
317
318
        return $this;
319
    }
320
321
    /**
322
     * @param callable $callable
323
     *
324
     * @return $this
325
     */
326
    public function setActiveFromCallable(callable $callable)
327
    {
328
        $type = first_parameter_type($callable);
329
330
        return $this->applyToAll(function (Item $item) use ($callable, $type) {
331
            if (!item_matches_type($item, $type)) {
332
                return;
333
            }
334
335
            if ($callable($item)) {
336
                $item->setActive();
337
            }
338
        });
339
    }
340
341
    /**
342
     * @param string $class
343
     */
344
    public function setActiveClass(string $class)
345
    {
346
        $this->activeClass = $class;
347
    }
348
349
    /**
350
     * @return string
351
     */
352
    public function render() : string
353
    {
354
        $contents = HtmlElement::render(
355
            'ul',
356
            $this->htmlAttributes->toArray(),
357
            array_map(function (Item $item) {
358
                return HtmlElement::render(
359
                    $item->isActive() ? "li.{$this->activeClass}" : 'li',
360
                    $item->getParentAttributes(),
361
                    $item->render()
362
                );
363
            }, $this->items)
364
        );
365
366
        return "{$this->prepend}{$contents}{$this->append}";
367
    }
368
369
    /**
370
     * @return string
371
     */
372
    public function __toString() : string
373
    {
374
        return $this->render();
375
    }
376
}
377