midcom_helper_toolbar::render()   C
last analyzed

Complexity

Conditions 11
Paths 201

Size

Total Lines 55
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 29
CRAP Score 11.2154

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
eloc 33
c 1
b 0
f 0
nc 201
nop 0
dl 0
loc 55
ccs 29
cts 33
cp 0.8788
crap 11.2154
rs 6.4708

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @package midcom.helper
4
 * @author The Midgard Project, http://www.midgard-project.org
5
 * @copyright The Midgard Project, http://www.midgard-project.org
6
 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
7
 */
8
9
/**
10
 * This class is a generic toolbar class. It supports enabling
11
 * and disabling of buttons, icons and hover-helptexts (currently
12
 * rendered using TITLE tags).
13
 *
14
 * A single button in the toolbar is represented using an associative
15
 * array with the following elements:
16
 *
17
 * <code>
18
 * $item = [
19
 *     MIDCOM_TOOLBAR_URL => $url,
20
 *     MIDCOM_TOOLBAR_LABEL => $label,
21
 *     MIDCOM_TOOLBAR_HELPTEXT => $helptext,
22
 *     MIDCOM_TOOLBAR_ICON => $icon,
23
 *     MIDCOM_TOOLBAR_ENABLED => $enabled,
24
 *     MIDCOM_TOOLBAR_HIDDEN => $hidden
25
 *     MIDCOM_TOOLBAR_OPTIONS => array $options,
26
 *     MIDCOM_TOOLBAR_SUBMENU => midcom_helper_toolbar $submenu,
27
 *     MIDCOM_TOOLBAR_ACCESSKEY => (char) 'a',
28
 *     MIDCOM_TOOLBAR_POST => true,
29
 *     MIDCOM_TOOLBAR_POST_HIDDENARGS => array $args,
30
 * ];
31
 * </code>
32
 *
33
 * The URL parameter can be interpreted in three different ways:
34
 * If it is a relative URL (not starting with 'http[s]://' or at least
35
 * a '/') it will be interpreted relative to the current Anchor
36
 * Prefix as defined in the active MidCOM context. Otherwise, the URL
37
 * is used as-is. Note, that the Anchor-Prefix is appended immediately
38
 * when the item is added, not when the toolbar is rendered.
39
 *
40
 * The original URL (before prepending anything) is stored internally;
41
 * so in all places where you reference an element by-URL, you can use
42
 * the original URL if you wish (actually, both URLs are recognized
43
 * during the translation into an id).
44
 *
45
 * The label is the text shown as the button, the helptext is used as
46
 * TITLE value to the anchor, and will be shown when hovering over the
47
 * link therefore. Set it to null, to suppress this feature (this is the
48
 * default).
49
 *
50
 * The icon is a relative URL within the static MidCOM tree, for example
51
 * 'stock-icons/16x16/attach.png'. Set it to null, to suppress the display
52
 * of an icon (this is the default)
53
 *
54
 * By default, as shown below, the toolbar system renders a standard Hyperlink.
55
 * If you set MIDCOM_TOOLBAR_POST to true however, a form is used instead.
56
 * This is important if you want to provide operations directly behind the
57
 * toolbar entries - you'd run into problems with HTTP Link Prefetching
58
 * otherwise. It is also useful if you want to pass complex operations
59
 * to the URL target, as the option MIDCOM_TOOLBAR_POST_HIDDENARGS allows
60
 * you to add HIDDEN variables to the form. These arguments will be automatically
61
 * run through htmlspecialchars when rendering. By default, standard links will
62
 * be rendered, POST versions will only be used if explicitly requested.
63
 *
64
 * Note, that while this should prevent link prefetching on the POST entries,
65
 * this is a big should. Due to its lack of standardization, it is strongly
66
 * recommended to check for a POST request when processing such toolbar
67
 * targets, using something like this:
68
 *
69
 * <code>
70
 * if ($_SERVER['REQUEST_METHOD'] != 'post')
71
 * {
72
 *     throw new midcom_error_forbidden('Only POST requests are allowed here.');
73
 * }
74
 * </code>
75
 *
76
 * The enabled boolean flag is set to true (the default) if the link should
77
 * be clickable, or to false otherwise.
78
 *
79
 * The hidden boolean flag is very similar to the enabled one: Instead of
80
 * having unclickable links, it just hides the toolbar button entirely.
81
 * This is useful for access control checks, where you want to completely
82
 * hide items without access. The difference from just not adding the
83
 * corresponding variable is that you can have a consistent set of
84
 * toolbar options in a "template" which you just need to tweak by
85
 * setting this flag. (Note, that there is no explicit access
86
 * control checks in the toolbar helper itself, as this would mean that
87
 * the corresponding content objects need to be passed into the toolbar,
88
 * which is not feasible with the large number of toolbars in use in NAP
89
 * for example.)
90
 *
91
 * The midcom_toolbar_submenu can be used to create nested submenus by adding a pointer
92
 * to a new toolbar object.
93
 *
94
 * The toolbar gets rendered as an unordered list, letting you define the
95
 * CSS id and/or class tags of the list itself. The default class for
96
 * example used the well-known horizontal-UL approach to transform this
97
 * into a real toolbar. The output of the draw call therefore looks like
98
 * this:
99
 *
100
 * The <b>accesskey</b> option is used to assign an accesskey to the toolbar item.
101
 * It will be rendered in the toolbar text as either underlining the key or stated in
102
 * parentheses behind the text.
103
 *
104
 * <pre>
105
 * &lt;ul [class="$class"] [id="$id"]&gt;
106
 *   &lt;li class="(enabled|disabled)"&gt;
107
 *     [&lt;a href="$url" [title="$helptext"] [ $options as $key =&gt; $val ]&gt;]
108
 *       [&lt;img src="$calculated_image_url"&gt;]
109
 *       $label
110
 *      [new submenu here]
111
 *     [&lt;/a&gt;]
112
 *   &lt;/li&gt;
113
 * &lt;/ul&gt;
114
 * </pre>
115
 *
116
 * Both class and id can be null, indicating no style should be selected.
117
 * By default, the class will use "midcom_toolbar" and no id style, which
118
 * will yield a traditional MidCOM toolbar. Of course, the
119
 * style sheet must be loaded to support this. Note, that this style assumes
120
 * 16x16 height icons in its toolbar rendering. Larger or smaller icons
121
 * will look ugly in the layout.
122
 *
123
 * The options array. You can use the options array to make simple changes to the toolbar items.
124
 * Here's a quick example to remove the underlining.
125
 * <code>
126
 * foreach ($toolbar->items as $index => $item) {
127
 *     $toolbar->items[$index][MIDCOM_TOOLBAR_OPTIONS] = [ "style" => "text-decoration:none;"];
128
 * }
129
 * </code>
130
 * This will add style="text-decoration:none;" to all the links in the toolbar.
131
 *
132
 * @package midcom.helper
133
 */
134
class midcom_helper_toolbar
135
{
136
    /**
137
     * The CSS ID-Style rule that should be used for the toolbar.
138
     * Set to null if none should be used.
139
     */
140
    public ?string $id_style;
141
142
    /**
143
     * The CSS class-Style rule that should be used for the toolbar.
144
     * Set to null if none should be used.
145
     */
146
    public string $class_style;
147
148
    /**
149
     * The toolbar's label
150
     */
151
    protected string $label = '';
152
153
    /**
154
     * The items in the toolbar.
155
     *
156
     * The array consists of Arrays outlined in the class introduction.
157
     * You can modify existing items in this collection but you should use
158
     * the class methods to add or delete existing items. Also note that
159
     * relative URLs are processed upon the invocation of add_item(), if
160
     * you change URL manually, you have to ensure a valid URL by yourself
161
     * or use update_item_url, which is recommended.
162
     */
163
    public array $items = [];
164
165
    /**
166
     * Allow our users to add arbitrary data to the toolbar.
167
     *
168
     * This is for example used to track which items have been added to a toolbar
169
     * when it is possible that the adders are called repeatedly.
170
     *
171
     * The entries should be namespaced according to the usual MidCOM
172
     * Namespacing rules.
173
     */
174
    public array $customdata = [];
175
176
    private bool $rendered = false;
177
178
    /**
179
     * Basic constructor, initializes the class and sets defaults for the
180
     * CSS style if omitted.
181
     *
182
     * Note that the styles can be changed after construction by updating
183
     * the id_style and class_style members.
184
     */
185 353
    public function __construct(string $class_style = 'midcom_toolbar', ?string $id_style = null)
186
    {
187 353
        $this->id_style = $id_style;
188 353
        $this->class_style = $class_style;
189
    }
190
191 7
    public function is_rendered() : bool
192
    {
193 7
        return $this->rendered;
194
    }
195
196 7
    public function get_label() : string
197
    {
198 7
        return $this->label;
199
    }
200
201 52
    public function set_label(string $label)
202
    {
203 52
        $this->label = $label;
204
    }
205
206
    /**
207
     * Add an item to the toolbar.
208
     *
209
     * Set before to the index of the element before which you want to insert
210
     * the item or use -1 if you want to append an item. Alternatively,
211
     * instead of specifying an index, you can specify a URL instead.
212
     *
213
     * This member will process the URL and append the anchor prefix in case
214
     * the URL is a relative one.
215
     *
216
     * Invalid positions will result in a MidCOM Error.
217
     *
218
     * @param string|int $before The index before which the item should be inserted.
219
     *     Use -1 for appending at the end, use a string to insert
220
     *     it before a URL, an integer will insert it before a
221
     *     given index.
222
     * @see midcom_helper_toolbar::get_index_from_url()
223
     * @see midcom_helper_toolbar::_check_index()
224
     * @see midcom_helper_toolbar::clean_item()
225
     */
226 188
    public function add_item(array $item, string|int $before = -1)
227
    {
228 188
        if ($before != -1) {
229 1
            $before = $this->_check_index($before, false);
230
        }
231 188
        $item = $this->clean_item($item);
232
233 188
        if ($before == -1) {
234 188
            $this->items[] = $item;
235 1
        } elseif ($before == 0) {
236 1
            array_unshift($this->items, $item);
237
        } else {
238 1
            $start = array_slice($this->items, 0, $before);
239 1
            $start[] = $item;
240 1
            $this->items = array_merge($start, array_slice($this->items, $before));
241
        }
242
    }
243
244
    /**
245
     * Convenience shortcut to add multiple buttons at the same item
246
     *
247
     * @param string|int $before The index before which the item should be inserted.
248
     *     Use -1 for appending at the end, use a string to insert
249
     *     it before a URL, an integer will insert it before a
250
     *     given index.
251
     */
252 117
    public function add_items(array $items, string|int $before = -1)
253
    {
254 117
        foreach ($items as $item) {
255 112
            $this->add_item($item, $before);
256
        }
257
    }
258
259
    /**
260
     * Clean up an item that is added, making sure that the item has all the
261
     * needed options and indexes.
262
     */
263 189
    public function clean_item(array $item) : array
264
    {
265 189
        static $used_access_keys = [];
266
267 189
        $defaults = [
268 189
            MIDCOM_TOOLBAR_URL => './',
269 189
            MIDCOM_TOOLBAR_OPTIONS => [],
270 189
            MIDCOM_TOOLBAR_HIDDEN => false,
271 189
            MIDCOM_TOOLBAR_HELPTEXT => '',
272 189
            MIDCOM_TOOLBAR_ICON => null,
273 189
            MIDCOM_TOOLBAR_GLYPHICON => null,
274 189
            MIDCOM_TOOLBAR_ENABLED => true,
275 189
            MIDCOM_TOOLBAR_POST => false,
276 189
            MIDCOM_TOOLBAR_POST_HIDDENARGS => [],
277 189
            MIDCOM_TOOLBAR_ACCESSKEY => null
278 189
        ];
279
280 189
        $item = array_replace($defaults, $item);
281
282 189
        if (   !empty($item[MIDCOM_TOOLBAR_ACCESSKEY])
283 189
            && !array_key_exists($item[MIDCOM_TOOLBAR_ACCESSKEY], $used_access_keys)) {
284
            // We have valid access key, add it to help text
285 6
            $prefix = 'Alt-';
286 6
            if (str_contains($_SERVER['HTTP_USER_AGENT'] ?? '', 'Macintosh')) {
287
                // Mac users
288
                $prefix = 'Ctrl-Alt-';
289
            }
290 6
            $hotkey = $prefix . strtoupper($item[MIDCOM_TOOLBAR_ACCESSKEY]);
291
292 6
            if ($item[MIDCOM_TOOLBAR_HELPTEXT] == '') {
293 6
                $item[MIDCOM_TOOLBAR_HELPTEXT] = $hotkey;
294
            } else {
295
                $item[MIDCOM_TOOLBAR_HELPTEXT] .= " ({$hotkey})";
296
            }
297 6
            $used_access_keys[$item[MIDCOM_TOOLBAR_ACCESSKEY]] = true;
298
        }
299
300 189
        $this->set_url($item, $item[MIDCOM_TOOLBAR_URL]);
301 189
        return $item;
302
    }
303
304 189
    private function set_url(array &$item, string $url)
305
    {
306 189
        $item[MIDCOM_TOOLBAR__ORIGINAL_URL] = $url;
307 189
        if (   (   empty($item[MIDCOM_TOOLBAR_OPTIONS]["rel"])
308
                // Some items may want to keep their links unmutilated
309 189
                || $item[MIDCOM_TOOLBAR_OPTIONS]["rel"] != "directlink")
310 189
            && !str_starts_with($url, '/')
311 189
            && !preg_match('|^https?://|', $url)) {
312 161
            $url = midcom_core_context::get()->get_key(MIDCOM_CONTEXT_ANCHORPREFIX) . $url;
0 ignored issues
show
Bug introduced by
Are you sure midcom_core_context::get...M_CONTEXT_ANCHORPREFIX) of type false|mixed can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

312
            $url = /** @scrutinizer ignore-type */ midcom_core_context::get()->get_key(MIDCOM_CONTEXT_ANCHORPREFIX) . $url;
Loading history...
313
        }
314 189
        $item[MIDCOM_TOOLBAR_URL] = $url;
315
    }
316
317
    /**
318
     * Removes a toolbar item based on its index or its URL
319
     *
320
     * It will trigger a MidCOM Error upon an invalid index.
321
     *
322
     * @param string|int $index The (integer) index or URL to remove.
323
     * @see midcom_helper_toolbar::get_index_from_url()
324
     * @see midcom_helper_toolbar::_check_index()
325
     */
326 1
    public function remove_item(string|int $index)
327
    {
328 1
        $index = $this->_check_index($index);
329
330 1
        if ($index == 0) {
331
            array_shift($this->items);
332 1
        } elseif ($index == count($this->items) -1) {
333
            array_pop($this->items);
334
        } else {
335 1
            $this->items = array_merge(array_slice($this->items, 0, $index),
336 1
                array_slice($this->items, $index + 1));
337
        }
338
    }
339
340
    /**
341
     * Clears the complete toolbar.
342
     */
343
    public function remove_all_items()
344
    {
345
        $this->items = [];
346
    }
347
348
    /**
349
     * Set's an item's enabled flag to true.
350
     *
351
     * @param string|int $index The integer index or URL of the item to enable.
352
     */
353
    public function enable_item(string|int $index)
354
    {
355
        $index = $this->_check_index($index);
356
        $this->items[$index][MIDCOM_TOOLBAR_ENABLED] = true;
357
    }
358
359
    /**
360
     * Set's an item's enabled flag to false.
361
     *
362
     * @param string|int $index The integer index or URL of the item to disable.
363
     */
364 12
    public function disable_item(string|int $index)
365
    {
366 12
        $index = $this->_check_index($index, false);
367
368 12
        if ($index !== null) {
369 12
            $this->items[$index][MIDCOM_TOOLBAR_ENABLED] = false;
370
        }
371
    }
372
373
    /**
374
     * Set's an item's hidden flag to true.
375
     *
376
     * @param string|int $index The integer index or URL of the item to hide.
377
     */
378 5
    public function hide_item(string|int $index)
379
    {
380 5
        $index = $this->_check_index($index, false);
381
382 5
        if ($index !== null) {
383 5
            $this->items[$index][MIDCOM_TOOLBAR_HIDDEN] = true;
384
        }
385
    }
386
387
    /**
388
     * Set's an item's hidden flag to false.
389
     *
390
     * @param string|int $index The integer index or URL of the item to show.
391
     */
392
    public function show_item(string|int $index)
393
    {
394
        $index = $this->_check_index($index);
395
        $this->items[$index][MIDCOM_TOOLBAR_HIDDEN] = false;
396
    }
397
398
    /**
399
     * Updates an items URL using the same rules as in add_item.
400
     *
401
     * @param mixed $index The integer index or URL of the item to update.
402
     * @see midcom_helper_toolbar::get_index_from_url()
403
     * @see midcom_helper_toolbar::_check_index()
404
     * @see midcom_helper_toolbar::add_item()
405
     */
406
    public function update_item_url(string|int $index, string $url)
407
    {
408
        $index = $this->_check_index($index);
409
        $this->set_url($this->items[$index], $url);
410
    }
411
412
    /**
413
     * Renders the toolbar and returns it as a string.
414
     */
415 20
    public function render() : string
416
    {
417 20
        $visible_items = array_filter($this->items, function ($item) {
418 15
            return !$item[MIDCOM_TOOLBAR_HIDDEN];
419 20
        });
420 20
        $this->rendered = true;
421
422 20
        if (empty($visible_items)) {
423 12
            debug_add('Tried to render an empty toolbar, returning an empty string.');
424 12
            return '';
425
        }
426
427
        // List header
428 15
        $output = '<ul';
429 15
        if ($this->class_style !== null) {
430 15
            $output .= " class='{$this->class_style}'";
431
        }
432 15
        if ($this->id_style !== null) {
433
            $output .= " id='{$this->id_style}'";
434
        }
435 15
        $output .= '>';
436
437 15
        $last = count($visible_items);
438 15
        $first_class = ($last === 1) ? 'only_item' : 'first_item';
439
        // List items
440 15
        foreach ($visible_items as $i => $item) {
441 15
            $output .= '<li class="';
442 15
            if ($i == 0) {
443 15
                $output .= $first_class . ' ';
444 13
            } elseif ($i == $last) {
445
                $output .= 'last_item ';
446
            }
447
448 15
            if ($item[MIDCOM_TOOLBAR_ENABLED]) {
449 15
                $output .= 'enabled">';
450
            } else {
451 11
                $output .= 'disabled">';
452
            }
453
454 15
            if ($item[MIDCOM_TOOLBAR_POST]) {
455
                $output .= $this->_render_post_item($item);
456
            } else {
457 15
                $output .= $this->_render_link_item($item);
458
            }
459 15
            if (!empty($item[MIDCOM_TOOLBAR_SUBMENU])) {
460
                $output .= $item[MIDCOM_TOOLBAR_SUBMENU]->render();
461
            }
462
463 15
            $output .= '</li>';
464
        }
465
466
        // List footer
467 15
        $output .= '</ul>';
468
469 15
        return $output;
470
    }
471
472
    /**
473
     * Generate a label for the item that includes its accesskey
474
     */
475 15
    private function _generate_item_label(array $item) : string
476
    {
477 15
        $label = htmlentities($item[MIDCOM_TOOLBAR_LABEL], ENT_COMPAT, "UTF-8");
478
479 15
        if (!empty($item[MIDCOM_TOOLBAR_ACCESSKEY])) {
480
            // Try finding uppercase version of the accesskey first
481 8
            $accesskey = strtoupper($item[MIDCOM_TOOLBAR_ACCESSKEY]);
482 8
            $position = strpos($label, $accesskey);
483 8
            if (   $position === false
484 8
                && midcom::get()->i18n->get_current_language() == 'en') {
485
                // Try lowercase, too
486 7
                $accesskey = strtolower($accesskey);
487 7
                $position = strpos($label, $accesskey);
488
            }
489 8
            if ($position !== false) {
490 8
                $label = substr_replace($label, "<span style=\"text-decoration: underline;\">{$accesskey}</span>", $position, 1);
491
            }
492
        }
493
494 15
        return $label;
495
    }
496
497
    /**
498
     * Render a regular a href... based link target.
499
     */
500 15
    private function _render_link_item(array $item) : string
501
    {
502 15
        $attributes = $this->get_item_attributes($item);
503
504 15
        if ($item[MIDCOM_TOOLBAR_ENABLED]) {
505 15
            $tagname = 'a';
506 15
            $attributes['href'] = $item[MIDCOM_TOOLBAR_URL];
507
        } else {
508 11
            $tagname = !empty($attributes['title']) ? 'abbr' : 'span';
509
        }
510
511 15
        $output = '<' . $tagname;
512 15
        foreach ($attributes as $key => $val) {
513 15
            $output .= ' ' . $key . '="' . htmlspecialchars($val) . '"';
514
        }
515 15
        $output .= '>';
516
517 15
        $output .= $this->render_icon($item);
518 15
        $output .= '&nbsp;<span class="toolbar_label">' . $this->_generate_item_label($item) . "</span>";
519 15
        return $output . '</' . $tagname . '>';
520
    }
521
522 15
    private function render_icon(array $item) : string
523
    {
524 15
        if ($item[MIDCOM_TOOLBAR_GLYPHICON] !== null) {
525 15
            $class = 'fa fa-' . $item[MIDCOM_TOOLBAR_GLYPHICON];
526 15
            return "<i class='{$class}'></i>";
527
        }
528
        if ($item[MIDCOM_TOOLBAR_ICON] !== null) {
529
            $url = MIDCOM_STATIC_URL . '/' . $item[MIDCOM_TOOLBAR_ICON];
530
            return "<img src='{$url}' alt=\"{$item[MIDCOM_TOOLBAR_HELPTEXT]}\" />";
531
        }
532
        return '';
533
    }
534
535 15
    private function get_item_attributes(array $item) : array
536
    {
537 15
        $attributes = ($item[MIDCOM_TOOLBAR_ENABLED]) ? $item[MIDCOM_TOOLBAR_OPTIONS] : [];
538
539 15
        if ($item[MIDCOM_TOOLBAR_HELPTEXT] !== null) {
540 15
            $attributes['title'] = $item[MIDCOM_TOOLBAR_HELPTEXT];
541
        }
542
543 15
        if (   $item[MIDCOM_TOOLBAR_ENABLED]
544 15
            && $item[MIDCOM_TOOLBAR_ACCESSKEY] !== null) {
545 8
            $attributes['class'] = 'accesskey';
546 8
            $attributes['accesskey'] = $item[MIDCOM_TOOLBAR_ACCESSKEY];
547
        }
548 15
        return $attributes;
549
    }
550
551
    /**
552
     * Render a form based link target.
553
     */
554
    private function _render_post_item(array $item) : string
555
    {
556
        $output = '';
557
558
        if ($item[MIDCOM_TOOLBAR_ENABLED]) {
559
            $output .= "<form method=\"post\" action=\"{$item[MIDCOM_TOOLBAR_URL]}\">";
560
            $output .= "<div><button type=\"submit\" name=\"midcom_helper_toolbar_submit\"";
561
562
            foreach ($this->get_item_attributes($item) as $key => $val) {
563
                $output .= ' ' . $key . '="' . htmlspecialchars($val) . '"';
564
            }
565
            $output .= '>';
566
        }
567
568
        $output .= $this->render_icon($item);
569
        $output .= ' ' . $this->_generate_item_label($item);
570
571
        if ($item[MIDCOM_TOOLBAR_ENABLED]) {
572
            $output .= '</button>';
573
            foreach ($item[MIDCOM_TOOLBAR_POST_HIDDENARGS] as $key => $value) {
574
                $key = htmlspecialchars($key);
575
                $value = htmlspecialchars($value);
576
                $output .= "<input type=\"hidden\" name=\"{$key}\" value=\"{$value}\"/>";
577
            }
578
            $output .= '</div></form>';
579
        }
580
581
        return $output;
582
    }
583
584
    /**
585
     * Traverse all available items and return the first
586
     * element whose URL matches the value passed to the function.
587
     *
588
     * Note, that if two items point to the same URL, only the first one
589
     * will be reported.
590
     */
591 17
    public function get_index_from_url(string $url) : ?int
592
    {
593 17
        foreach ($this->items as $i => $item) {
594 17
            if (   $item[MIDCOM_TOOLBAR_URL] == $url
595 17
                || $item[MIDCOM_TOOLBAR__ORIGINAL_URL] == $url) {
596 17
                return $i;
597
            }
598
        }
599
        return null;
600
    }
601
602
    /**
603
     * Check an index for validity.
604
     *
605
     * It will automatically convert a string-based URL into an
606
     * Index (if possible); if the URL can't be found, it will
607
     * also trigger an error. The translated URL is returned by the
608
     * function.
609
     *
610
     * @param string|int $index The integer index or URL to check
611
     */
612 19
    protected function _check_index(string|int $index, bool $raise_error = true) :?int
613
    {
614 19
        if (is_string($index)) {
615 17
            $url = $index;
616 17
            debug_add("Translating the URL '{$url}' into an index.");
617 17
            $index = $this->get_index_from_url($url);
618 17
            if ($index === null) {
619
                debug_add("Invalid URL '{$url}', URL not found.", MIDCOM_LOG_ERROR);
620
621
                if ($raise_error) {
622
                    throw new midcom_error("Invalid URL '{$url}', URL not found.");
623
                }
624
                return null;
625
            }
626
        }
627 19
        if ($index >= count($this->items)) {
628
            throw new midcom_error("Invalid index {$index}, it is off-the-end.");
629
        }
630 19
        if ($index < 0) {
631
            throw new midcom_error("Invalid index {$index}, it is negative.");
632
        }
633 19
        return $index;
634
    }
635
}
636