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