• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

FluidTYPO3 / vhs / 4336554914

pending completion
4336554914

Pull #1848

github

GitHub
Merge 066fbcf95 into 05bec6cab
Pull Request #1848: [BUGFIX] Fix notice

1 of 1 new or added line in 1 file covered. (100.0%)

4697 of 7499 relevant lines covered (62.64%)

1.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

35.34
/Classes/ViewHelpers/Menu/AbstractMenuViewHelper.php
1
<?php
2
namespace FluidTYPO3\Vhs\ViewHelpers\Menu;
3

4
/*
5
 * This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
6
 *
7
 * For the full copyright and license information, please read the
8
 * LICENSE.md file that was distributed with this source code.
9
 */
10

11
use FluidTYPO3\Vhs\Service\PageService;
12
use FluidTYPO3\Vhs\Traits\PageRecordViewHelperTrait;
13
use FluidTYPO3\Vhs\Traits\TagViewHelperTrait;
14
use TYPO3\CMS\Core\Utility\GeneralUtility;
15
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;
16

17
/**
18
 * Base class for menu rendering ViewHelpers.
19
 */
20
abstract class AbstractMenuViewHelper extends AbstractTagBasedViewHelper
21
{
22
    use PageRecordViewHelperTrait;
23
    use TagViewHelperTrait;
24

25
    /**
26
     * @var string
27
     */
28
    protected $tagName = 'ul';
29

30
    /**
31
     * @var PageService
32
     */
33
    protected $pageService;
34

35
    /**
36
     * @var boolean
37
     */
38
    private $original = true;
39

40
    /**
41
     * @var array
42
     */
43
    private $backupValues = [];
44

45
    /**
46
     * @var boolean
47
     */
48
    protected $escapeOutput = false;
49

50
    /**
51
     * @param PageService $pageService
52
     * @return void
53
     */
54
    public function injectPageService(PageService $pageService)
55
    {
56
        $this->pageService = $pageService;
×
57
    }
58

59
    /**
60
     * Initialize
61
     * @return void
62
     */
63
    public function initializeArguments()
64
    {
65
        parent::initializeArguments();
6✔
66
        $this->registerUniversalTagAttributes();
6✔
67
        $this->registerPageRecordArguments();
6✔
68
        $this->registerArgument('tagName', 'string', 'Tag name to use for enclosing container', false, 'ul');
6✔
69
        $this->registerArgument(
6✔
70
            'tagNameChildren',
6✔
71
            'string',
6✔
72
            'Tag name to use for child nodes surrounding links. If set to "a" enables non-wrapping mode.',
6✔
73
            false,
6✔
74
            'li'
6✔
75
        );
6✔
76
        $this->registerArgument('entryLevel', 'integer', 'Optional entryLevel TS equivalent of the menu', false, 0);
6✔
77
        $this->registerArgument(
6✔
78
            'levels',
6✔
79
            'integer',
6✔
80
            'Number of levels to render - setting this to a number higher than 1 (one) will expand menu ' .
6✔
81
            'items that are active, to a depth of $levels starting from $entryLevel',
6✔
82
            false,
6✔
83
            1
6✔
84
        );
6✔
85
        $this->registerArgument(
6✔
86
            'expandAll',
6✔
87
            'boolean',
6✔
88
            'If TRUE and $levels > 1 then expands all (not just the active) menu items which have submenus',
6✔
89
            false,
6✔
90
            false
6✔
91
        );
6✔
92
        $this->registerArgument('classFirst', 'string', 'Optional class name for the first menu elment', false, '');
6✔
93
        $this->registerArgument('classLast', 'string', 'Optional class name for the last menu elment', false, '');
6✔
94
        $this->registerArgument('classActive', 'string', 'Optional class name to add to active links', false, 'active');
6✔
95
        $this->registerArgument(
6✔
96
            'classCurrent',
6✔
97
            'string',
6✔
98
            'Optional class name to add to current link',
6✔
99
            false,
6✔
100
            'current'
6✔
101
        );
6✔
102
        $this->registerArgument(
6✔
103
            'classHasSubpages',
6✔
104
            'string',
6✔
105
            'Optional class name to add to links which have subpages',
6✔
106
            false,
6✔
107
            'sub'
6✔
108
        );
6✔
109
        $this->registerArgument(
6✔
110
            'substElementUid',
6✔
111
            'boolean',
6✔
112
            'Optional parameter for wrapping the link with the uid of the page',
6✔
113
            false,
6✔
114
            false
6✔
115
        );
6✔
116
        $this->registerArgument(
6✔
117
            'showHiddenInMenu',
6✔
118
            'boolean',
6✔
119
            'Include pages that are set to be hidden in menus',
6✔
120
            false,
6✔
121
            false
6✔
122
        );
6✔
123
        $this->registerArgument('showCurrent', 'boolean', 'If FALSE, does not display the current page', false, true);
6✔
124
        $this->registerArgument(
6✔
125
            'linkCurrent',
6✔
126
            'boolean',
6✔
127
            'If FALSE, does not wrap the current page in a link',
6✔
128
            false,
6✔
129
            true
6✔
130
        );
6✔
131
        $this->registerArgument(
6✔
132
            'linkActive',
6✔
133
            'boolean',
6✔
134
            'If FALSE, does not wrap with links the titles of pages that are active in the rootline',
6✔
135
            false,
6✔
136
            true
6✔
137
        );
6✔
138
        $this->registerArgument(
6✔
139
            'titleFields',
6✔
140
            'string',
6✔
141
            'CSV list of fields to use as link label - default is "nav_title,title", change to for example ' .
6✔
142
            '"tx_myext_somefield,subtitle,nav_title,title". The first field that contains text will be used. ' .
6✔
143
            'Field value resolved AFTER page field overlays.',
6✔
144
            false,
6✔
145
            'nav_title,title'
6✔
146
        );
6✔
147
        $this->registerArgument(
6✔
148
            'includeAnchorTitle',
6✔
149
            'boolean',
6✔
150
            'If TRUE, includes the page title as title attribute on the anchor.',
6✔
151
            false,
6✔
152
            true
6✔
153
        );
6✔
154
        $this->registerArgument(
6✔
155
            'includeSpacers',
6✔
156
            'boolean',
6✔
157
            'Wether or not to include menu spacers in the page select query',
6✔
158
            false,
6✔
159
            false
6✔
160
        );
6✔
161
        $this->registerArgument(
6✔
162
            'deferred',
6✔
163
            'boolean',
6✔
164
            'If TRUE, does not output the tag content UNLESS a v:page.menu.deferred child ViewHelper is both used ' .
6✔
165
            'and triggered. This allows you to create advanced conditions while still using automatic rendering',
6✔
166
            false,
6✔
167
            false
6✔
168
        );
6✔
169
        $this->registerArgument(
6✔
170
            'as',
6✔
171
            'string',
6✔
172
            'If used, stores the menu pages as an array in a variable named after this value and renders the tag ' .
6✔
173
            'content. If the tag content is empty automatic rendering is triggered.',
6✔
174
            false,
6✔
175
            'menu'
6✔
176
        );
6✔
177
        $this->registerArgument(
6✔
178
            'rootLineAs',
6✔
179
            'string',
6✔
180
            'If used, stores the menu root line as an array in a variable named according to this value and renders ' .
6✔
181
            'the tag content - which means automatic rendering is disabled if this attribute is used',
6✔
182
            false,
6✔
183
            'rootLine'
6✔
184
        );
6✔
185
        $this->registerArgument(
6✔
186
            'excludePages',
6✔
187
            'mixed',
6✔
188
            'Page UIDs to exclude from the menu. Can be CSV, array or an object implementing Traversable.',
6✔
189
            false,
6✔
190
            ''
6✔
191
        );
6✔
192
        $this->registerArgument(
6✔
193
            'forceAbsoluteUrl',
6✔
194
            'boolean',
6✔
195
            'If TRUE, the menu will be rendered with absolute URLs',
6✔
196
            false,
6✔
197
            false
6✔
198
        );
6✔
199
        $this->registerArgument(
6✔
200
            'doktypes',
6✔
201
            'mixed',
6✔
202
            'DEPRECATED: Please use typical doktypes for starting points like shortcuts.',
6✔
203
            false,
6✔
204
            ''
6✔
205
        );
6✔
206
        $this->registerArgument(
6✔
207
            'divider',
6✔
208
            'string',
6✔
209
            'Optional divider to insert between each menu item. Note that this does not mix well with automatic ' .
6✔
210
            'rendering due to the use of an ul > li structure'
6✔
211
        );
6✔
212
    }
213

214
    /**
215
     * @return string
216
     */
217
    public function render()
218
    {
219
        $pages = $this->getMenu($this->arguments['pageUid'], $this->arguments['entryLevel']);
×
220
        $menu = $this->parseMenu($pages);
×
221
        $rootLine = $this->pageService->getRootLine(
×
222
            $this->arguments['pageUid'],
×
223
            $this->arguments['reverse'] ?? false,
×
224
            $this->arguments['showAccessProtected']
×
225
        );
×
226
        $this->cleanupSubmenuVariables();
×
227
        $this->cleanTemplateVariableContainer();
×
228
        $this->backupVariables();
×
229
        $this->renderingContext->getVariableProvider()->add($this->arguments['as'], $menu);
×
230
        $this->renderingContext->getVariableProvider()->add($this->arguments['rootLineAs'], $rootLine);
×
231
        $this->initalizeSubmenuVariables();
×
232
        $output = $this->renderContent($menu);
×
233
        $this->cleanupSubmenuVariables();
×
234
        $this->renderingContext->getVariableProvider()->remove($this->arguments['as']);
×
235
        $this->renderingContext->getVariableProvider()->remove($this->arguments['rootLineAs']);
×
236
        $this->restoreVariables();
×
237

238
        return $output;
×
239
    }
240

241
    /**
242
     * Renders the tag's content or if omitted auto
243
     * renders the menu for the provided arguments
244
     *
245
     * @param array $menu
246
     * @return string
247
     */
248
    public function renderContent(array $menu)
249
    {
250
        $deferredRendering = (boolean) $this->arguments['deferred'];
×
251
        if (0 === count($menu) && false === $deferredRendering) {
×
252
            return '';
×
253
        }
254
        if (true === $deferredRendering) {
×
255
            $tagContent = $this->autoRender($menu);
×
256
            $this->tag->setContent($tagContent);
×
257
            $deferredContent = $this->tag->render();
×
258
            $this->renderingContext->getViewHelperVariableContainer()->addOrUpdate(
×
259
                'FluidTYPO3\Vhs\ViewHelpers\Menu\AbstractMenuViewHelper',
×
260
                'deferredString',
×
261
                $deferredContent
×
262
            );
×
263
            $this->renderingContext->getViewHelperVariableContainer()->addOrUpdate(
×
264
                'FluidTYPO3\Vhs\ViewHelpers\Menu\AbstractMenuViewHelper',
×
265
                'deferredArray',
×
266
                $menu
×
267
            );
×
268
            $output = $this->renderChildren();
×
269
            $this->unsetDeferredVariableStorage();
×
270
        } else {
271
            $content = $this->renderChildren();
×
272
            if (!is_scalar($content)) {
×
273
                $content = '';
×
274
            } else {
275
                $content = (string) $content;
×
276
            }
277
            if (0 < mb_strlen(trim($content))) {
×
278
                $output = $content;
×
279
            } elseif ((boolean) $this->arguments['hideIfEmpty'] === true) {
×
280
                $output = '';
×
281
            } else {
282
                $output = $this->renderTag($this->getWrappingTagName(), $this->autoRender($menu));
×
283
            }
284
        }
285

286
        return is_scalar($output) ? (string) $output : '';
×
287
    }
288

289
    /**
290
     * @param array $menu
291
     * @param integer $level
292
     * @return string
293
     */
294
    protected function autoRender(array $menu, $level = 1)
295
    {
296
        $tagName = $this->arguments['tagNameChildren'];
×
297
        $this->tag->setTagName($this->getWrappingTagName());
×
298
        $html = [];
×
299
        $levels = (integer) $this->arguments['levels'];
×
300
        $showCurrent = (boolean) $this->arguments['showCurrent'];
×
301
        $expandAll = (boolean) $this->arguments['expandAll'];
×
302
        $itemsRendered = 0;
×
303
        $numberOfItems = count($menu);
×
304
        foreach ($menu as $page) {
×
305
            if ($page['current'] && !$showCurrent) {
×
306
                continue;
×
307
            }
308
            $class = (trim($page['class']) !== '') ? ' class="' . trim($page['class']) . '"' : '';
×
309
            $elementId = ($this->arguments['substElementUid']) ? ' id="elem_' . $page['uid'] . '"' : '';
×
310
            if (!$this->isNonWrappingMode()) {
×
311
                $html[] = '<' . $tagName . $elementId . $class . '>';
×
312
            }
313
            $html[] = $this->renderItemLink($page);
×
314
            if (($page['active'] || $expandAll) && ($page['hasSubPages'] ?? false) && $level < $levels) {
×
315
                $subPages = $this->getMenu($page['uid']);
×
316
                $subMenu = $this->parseMenu($subPages);
×
317
                if (0 < count($subMenu)) {
×
318
                    $renderedSubMenu = $this->autoRender($subMenu, $level + 1);
×
319
                    $parentTagId = $this->tag->getAttribute('id');
×
320
                    if (!empty($parentTagId)) {
×
321
                        $this->tag->addAttribute('id', $parentTagId . '-lvl-' . $level);
×
322
                    }
323
                    $this->tag->setTagName($this->getWrappingTagName());
×
324
                    $this->tag->setContent($renderedSubMenu);
×
325
                    $this->tag->addAttribute(
×
326
                        'class',
×
327
                        (!empty($this->arguments['class']) ? $this->arguments['class'] . ' lvl-' : 'lvl-') . $level
×
328
                    );
×
329
                    $html[] = $this->tag->render();
×
330
                    $this->tag->addAttribute('class', $this->arguments['class']);
×
331
                    if (!empty($parentTagId)) {
×
332
                        $this->tag->addAttribute('id', $parentTagId);
×
333
                    }
334
                }
335
            }
336
            if (false === $this->isNonWrappingMode()) {
×
337
                $html[] = '</' . $tagName . '>';
×
338
            }
339
            $itemsRendered++;
×
340
            if (true === isset($this->arguments['divider']) && $itemsRendered < $numberOfItems) {
×
341
                $divider = $this->arguments['divider'];
×
342
                if (!$this->isNonWrappingMode()) {
×
343
                    $html[] = '<' . $tagName . '>' . $divider . '</' . $tagName . '>';
×
344
                } else {
345
                    $html[] = $divider;
×
346
                }
347
            }
348
        }
349

350
        return implode(LF, $html);
×
351
    }
352

353
    /**
354
     * @param array $page
355
     * @return string
356
     */
357
    protected function renderItemLink(array $page)
358
    {
359
        $isSpacer = ($page['doktype'] === $this->pageService->readPageRepositoryConstant('DOKTYPE_SPACER'));
×
360
        $isCurrent = (boolean) $page['current'];
×
361
        $isActive = (boolean) $page['active'];
×
362
        $linkCurrent = (boolean) $this->arguments['linkCurrent'];
×
363
        $linkActive = (boolean) $this->arguments['linkActive'];
×
364
        $includeAnchorTitle = (boolean) $this->arguments['includeAnchorTitle'];
×
365
        $target = (!empty($page['target'])) ? ' target="' . $page['target'] . '"' : '';
×
366
        $class = (trim($page['class']) !== '') ? ' class="' . trim($page['class']) . '"' : '';
×
367
        if ($isSpacer || ($isCurrent && !$linkCurrent) || ($isActive && !$linkActive)) {
×
368
            $html = htmlspecialchars($page['linktext']);
×
369
        } elseif ($includeAnchorTitle) {
×
370
            $html = sprintf(
×
371
                '<a href="%s" title="%s"%s%s>%s</a>',
×
372
                $page['link'],
×
373
                htmlspecialchars($page['title']),
×
374
                $class,
×
375
                $target,
×
376
                htmlspecialchars($page['linktext'])
×
377
            );
×
378
        } else {
379
            $html = sprintf(
×
380
                '<a href="%s"%s%s>%s</a>',
×
381
                $page['link'],
×
382
                $class,
×
383
                $target,
×
384
                htmlspecialchars($page['linktext'])
×
385
            );
×
386
        }
387

388
        return $html;
×
389
    }
390

391
    /**
392
     * @param null|integer $pageUid
393
     * @param integer|null $entryLevel
394
     * @return null|integer
395
     */
396
    protected function determineParentPageUid($pageUid = null, $entryLevel = 0)
397
    {
398
        $rootLineData = $this->pageService->getRootLine();
×
399
        if (null === $pageUid) {
×
400
            if (null !== $entryLevel) {
×
401
                if ($entryLevel < 0) {
×
402
                    $entryLevel = count($rootLineData) - 1 + $entryLevel;
×
403
                }
404
                $pageUid = $rootLineData[$entryLevel]['uid'];
×
405
            } else {
406
                $pageUid = $GLOBALS['TSFE']->id;
×
407
            }
408
        }
409

410
        return $pageUid;
×
411
    }
412

413
    /**
414
     * @param null|integer $pageUid
415
     * @param integer $entryLevel
416
     * @return array
417
     */
418
    public function getMenu($pageUid = null, $entryLevel = 0)
419
    {
420
        $pageUid = $this->determineParentPageUid($pageUid, $entryLevel);
×
421
        if ($pageUid === null) {
×
422
            return [];
×
423
        }
424
        $showHiddenInMenu = (boolean) $this->arguments['showHiddenInMenu'];
×
425
        $showAccessProtected = (boolean) $this->arguments['showAccessProtected'];
×
426
        $includeSpacers = (boolean) $this->arguments['includeSpacers'];
×
427
        $excludePages = $this->processPagesArgument($this->arguments['excludePages']);
×
428

429
        return $this->pageService->getMenu(
×
430
            $pageUid,
×
431
            $excludePages,
×
432
            $showHiddenInMenu,
×
433
            $includeSpacers,
×
434
            $showAccessProtected
×
435
        );
×
436
    }
437

438
    /**
439
     * @param array $pages
440
     * @return array
441
     */
442
    public function parseMenu(array $pages)
443
    {
444
        $count = 0;
×
445
        $total = count($pages);
×
446
        $processedPages = [];
×
447
        foreach ($pages as $index => $page) {
×
448
            $count++;
×
449
            $class = [];
×
450
            $originalPageUid = $page['uid'];
×
451
            $showAccessProtected = (boolean) $this->arguments['showAccessProtected'];
×
452
            if ($showAccessProtected) {
×
453
                $pages[$index]['accessProtected'] = $this->pageService->isAccessProtected($page);
×
454
                if (true === $pages[$index]['accessProtected']) {
×
455
                    $class[] = $this->arguments['classAccessProtected'];
×
456
                }
457
                $pages[$index]['accessGranted'] = $this->pageService->isAccessGranted($page);
×
458
                if (true === $pages[$index]['accessGranted'] && true === $this->pageService->isAccessProtected($page)) {
×
459
                    $class[] = $this->arguments['classAccessGranted'];
×
460
                }
461
            }
462
            $targetPage = $this->pageService->getShortcutTargetPage($page);
×
463
            if ($targetPage !== null) {
×
464
                if ($this->pageService->shouldUseShortcutTarget($this->arguments)) {
×
465
                    $pages[$index] = $targetPage;
×
466
                }
467
                if ($this->pageService->shouldUseShortcutUid($this->arguments)) {
×
468
                    $pages[$index]['uid'] = $targetPage['uid'];
×
469
                }
470
            }
471
            if (true === $this->pageService->isActive($originalPageUid, $showAccessProtected)) {
×
472
                $pages[$index]['active'] = true;
×
473
                $class[] = $this->arguments['classActive'];
×
474
            } else {
475
                $pages[$index]['active'] = false;
×
476
            }
477
            if (true === $this->pageService->isCurrent($targetPage['uid'] ?? $page['uid'])) {
×
478
                $pages[$index]['current'] = true;
×
479
                $class[] = $this->arguments['classCurrent'];
×
480
            } else {
481
                 $pages[$index]['current'] = false;
×
482
            }
483
            if (0 < count($this->getMenu($originalPageUid))) {
×
484
                $pages[$index]['hasSubPages'] = true;
×
485
                //TODO: Remove deprecated argument in next major version
486
                $class[] = $this->arguments[
×
487
                    $this->hasArgument('classHasSubpages') ? 'classHasSubpages' : 'classHasSubPages'
×
488
                ];
×
489
            }
490
            if (1 === $count) {
×
491
                $class[] = $this->arguments['classFirst'];
×
492
            }
493
            if ($count === $total) {
×
494
                $class[] = $this->arguments['classLast'];
×
495
            }
496
            $pages[$index]['class'] = implode(' ', $class);
×
497
            $pages[$index]['linktext'] = $this->getItemTitle($pages[$index]);
×
498
            $forceAbsoluteUrl = $this->arguments['forceAbsoluteUrl'];
×
499
            $pages[$index]['link'] = $this->pageService->getItemLink($pages[$index], $forceAbsoluteUrl);
×
500
            $processedPages[$index] = $pages[$index];
×
501
        }
502

503
        return $processedPages;
×
504
    }
505

506
    /**
507
     * @param array $page
508
     * @return string
509
     */
510
    protected function getItemTitle(array $page)
511
    {
512
        $titleFieldList = GeneralUtility::trimExplode(',', $this->arguments['titleFields']);
×
513
        foreach ($titleFieldList as $titleFieldName) {
×
514
            if (false === empty($page[$titleFieldName])) {
×
515
                return $page[$titleFieldName];
×
516
            }
517
        }
518

519
        return $page['title'];
×
520
    }
521

522
    /**
523
     * Initialize variables used by the submenu instance recycler. Variables set here
524
     * may be read by the Page / Menu / Sub ViewHelper which then automatically repeats
525
     * rendering using the exact same arguments but with a new page UID as starting page.
526
     * Note that the submenu VieWHelper is only capable of recycling one type of menu at
527
     * a time - for example, a List menu nested inside a regular Menu ViewHelper will
528
     * simply start another menu rendering completely separate from the parent menu.
529
     *
530
     * @return void
531
     */
532
    protected function initalizeSubmenuVariables()
533
    {
534
        if (false === $this->original) {
×
535
            return;
×
536
        }
537
        $variables = $this->renderingContext->getVariableProvider()->getAll();
×
538
        $this->renderingContext->getViewHelperVariableContainer()->addOrUpdate(
×
539
            'FluidTYPO3\Vhs\ViewHelpers\Menu\AbstractMenuViewHelper',
×
540
            'parentInstance',
×
541
            $this
×
542
        );
×
543
        $this->renderingContext->getViewHelperVariableContainer()->addOrUpdate(
×
544
            'FluidTYPO3\Vhs\ViewHelpers\Menu\AbstractMenuViewHelper',
×
545
            'variables',
×
546
            $variables
×
547
        );
×
548
    }
549

550
    /**
551
     * @param boolean $original
552
     * @return void
553
     */
554
    public function setOriginal($original)
555
    {
556
        $this->original = (boolean) $original;
×
557
    }
558

559
    /**
560
     * @return void
561
     */
562
    protected function cleanupSubmenuVariables()
563
    {
564
        if (false === $this->original) {
×
565
            return;
×
566
        }
567
        $viewHelperVariableContainer = $this->renderingContext->getViewHelperVariableContainer();
×
568
        if (false === $viewHelperVariableContainer->exists(AbstractMenuViewHelper::class, 'parentInstance')) {
×
569
            return;
×
570
        }
571
        $viewHelperVariableContainer->remove(AbstractMenuViewHelper::class, 'parentInstance');
×
572
        $viewHelperVariableContainer->remove(AbstractMenuViewHelper::class, 'variables');
×
573
    }
574

575
    /**
576
     * Saves copies of all template variables while rendering
577
     * the menu
578
     *
579
     * @return void
580
     */
581
    public function backupVariables()
582
    {
583
        $backups = [$this->arguments['as'], $this->arguments['rootLineAs']];
×
584
        foreach ($backups as $var) {
×
585
            if (true === $this->renderingContext->getVariableProvider()->exists($var)) {
×
586
                $this->backupValues[$var] = $this->renderingContext->getVariableProvider()->get($var);
×
587
                $this->renderingContext->getVariableProvider()->remove($var);
×
588
            }
589
        }
590
    }
591

592
    /**
593
     * Restores all saved template variables
594
     *
595
     * @return void
596
     */
597
    public function restoreVariables()
598
    {
599
        if (0 < count($this->backupValues)) {
×
600
            foreach ($this->backupValues as $var => $value) {
×
601
                if (false === $this->renderingContext->getVariableProvider()->exists($var)) {
×
602
                    $this->renderingContext->getVariableProvider()->add($var, $value);
×
603
                }
604
            }
605
        }
606
    }
607

608
    /**
609
     * Retrieves a stored, if any, parent instance of a menu. Although only implemented by
610
     * the Page / Menu / Sub ViewHelper, placing this method in this abstract class instead
611
     * will allow custom menu ViewHelpers to work as sub menu ViewHelpers without being
612
     * forced to implement their own variable retrieval or subclass Page / Menu / Sub.
613
     * Returns NULL if no parent exists.
614
     * @param integer $pageUid UID of page that's the new parent page, overridden in arguments of cloned and
615
     *                         recycled menu ViewHelper instance
616
     * @return AbstractMenuViewHelper|null
617
     */
618
    protected function retrieveReconfiguredParentMenuInstance($pageUid)
619
    {
620
        if (false === $this->renderingContext->getViewHelperVariableContainer()->exists(
×
621
            AbstractMenuViewHelper::class,
×
622
            'parentInstance'
×
623
        )) {
×
624
            return null;
×
625
        }
626
        /** @var AbstractMenuViewHelper $parentInstance */
627
        $parentInstance = $this->renderingContext->getViewHelperVariableContainer()->get(
×
628
            AbstractMenuViewHelper::class,
×
629
            'parentInstance'
×
630
        );
×
631
        $arguments = $parentInstance->getMenuArguments();
×
632
        $arguments['pageUid'] = $pageUid;
×
633
        $parentInstance->setArguments($arguments);
×
634

635
        return $parentInstance;
×
636
    }
637

638
    /**
639
     * @return void
640
     */
641
    protected function cleanTemplateVariableContainer()
642
    {
643
        if (false === $this->renderingContext->getViewHelperVariableContainer()->exists(
×
644
            AbstractMenuViewHelper::class,
×
645
            'variables'
×
646
        )) {
×
647
            return;
×
648
        }
649
        /** @var iterable $storedVariables */
650
        $storedVariables = $this->renderingContext->getViewHelperVariableContainer()->get(
×
651
            AbstractMenuViewHelper::class,
×
652
            'variables'
×
653
        );
×
654
        $variableProvider = $this->renderingContext->getVariableProvider();
×
655
        /** @var iterable $allVariables */
656
        $allVariables = $variableProvider->getAll();
×
657
        foreach ($allVariables as $variableName => $value) {
×
658
            $this->backupValues[$variableName] = $value;
×
659
            $variableProvider->remove($variableName);
×
660
        }
661
        foreach ($storedVariables as $variableName => $value) {
×
662
            /** @var string $variableName */
663
            $variableProvider->add($variableName, $value);
×
664
        }
665
    }
666

667
    /**
668
     * @return array
669
     */
670
    public function getMenuArguments()
671
    {
672
        if (!is_array($this->arguments)) {
×
673
            return $this->arguments->toArray();
×
674
        }
675
        return $this->arguments;
×
676
    }
677

678
    /**
679
     * @return void
680
     */
681
    protected function unsetDeferredVariableStorage()
682
    {
683
        $viewHelperVariableContainer = $this->renderingContext->getViewHelperVariableContainer();
×
684
        if ($viewHelperVariableContainer->exists(AbstractMenuViewHelper::class, 'deferredString')) {
×
685
            $viewHelperVariableContainer->remove(AbstractMenuViewHelper::class, 'deferredString');
×
686
            $viewHelperVariableContainer->remove(AbstractMenuViewHelper::class, 'deferredArray');
×
687
        }
688
    }
689

690
    /**
691
     * Returns the wrapping tag to use
692
     *
693
     * @return string
694
     */
695
    public function getWrappingTagName()
696
    {
697
        return $this->isNonWrappingMode() ? 'nav' : $this->arguments['tagName'];
×
698
    }
699

700
    /**
701
     * Returns TRUE for non-wrapping mode which is triggered
702
     * by setting tagNameChildren to 'a'
703
     *
704
     * @return boolean
705
     */
706
    public function isNonWrappingMode()
707
    {
708
        return ('a' === strtolower($this->arguments['tagNameChildren']));
×
709
    }
710

711
    /**
712
     * Returns array of page UIDs from provided pages
713
     *
714
     * @param mixed $pages
715
     * @return array
716
     */
717
    public function processPagesArgument($pages = null)
718
    {
719
        if (null === $pages) {
×
720
            $pages = $this->arguments['pages'];
×
721
        }
722
        if (true === $pages instanceof \Traversable) {
×
723
            $pages = iterator_to_array($pages);
×
724
        } elseif (true === is_string($pages)) {
×
725
            $pages = GeneralUtility::trimExplode(',', $pages, true);
×
726
        } elseif (true === is_int($pages)) {
×
727
            $pages = (array) $pages;
×
728
        }
729
        if (false === is_array($pages)) {
×
730
            return [];
×
731
        }
732

733
        return $pages;
×
734
    }
735
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc