Passed
Push — master ( 356300...b0b364 )
by
unknown
40:51 queued 26:12
created

TreeController::pagesToFlatArray()   F

Complexity

Conditions 42
Paths > 20000

Size

Total Lines 124
Code Lines 87

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 87
dl 0
loc 124
rs 0
c 0
b 0
f 0
cc 42
nc 42467330
nop 4

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
declare(strict_types=1);
4
5
/*
6
 * This file is part of the TYPO3 CMS project.
7
 *
8
 * It is free software; you can redistribute it and/or modify it under
9
 * the terms of the GNU General Public License, either version 2
10
 * of the License, or any later version.
11
 *
12
 * For the full copyright and license information, please read the
13
 * LICENSE.txt file that was distributed with this source code.
14
 *
15
 * The TYPO3 project - inspiring people to share!
16
 */
17
18
namespace TYPO3\CMS\Backend\Controller\Page;
19
20
use Psr\Http\Message\ResponseInterface;
21
use Psr\Http\Message\ServerRequestInterface;
22
use TYPO3\CMS\Backend\Configuration\BackendUserConfiguration;
23
use TYPO3\CMS\Backend\Routing\UriBuilder;
24
use TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository;
25
use TYPO3\CMS\Backend\Utility\BackendUtility;
26
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
27
use TYPO3\CMS\Core\Database\Query\Restriction\DocumentTypeExclusionRestriction;
28
use TYPO3\CMS\Core\Exception\Page\RootLineException;
29
use TYPO3\CMS\Core\Exception\SiteNotFoundException;
30
use TYPO3\CMS\Core\Http\JsonResponse;
31
use TYPO3\CMS\Core\Imaging\Icon;
32
use TYPO3\CMS\Core\Imaging\IconFactory;
33
use TYPO3\CMS\Core\Localization\LanguageService;
34
use TYPO3\CMS\Core\Site\SiteFinder;
35
use TYPO3\CMS\Core\Type\Bitmask\JsConfirmation;
36
use TYPO3\CMS\Core\Type\Bitmask\Permission;
37
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
38
use TYPO3\CMS\Core\Utility\GeneralUtility;
39
use TYPO3\CMS\Core\Utility\RootlineUtility;
40
use TYPO3\CMS\Core\Versioning\VersionState;
41
use TYPO3\CMS\Workspaces\Service\WorkspaceService;
42
43
/**
44
 * Controller providing data to the page tree
45
 * @internal This class is a specific Backend controller implementation and is not considered part of the Public TYPO3 API.
46
 */
47
class TreeController
48
{
49
    /**
50
     * Option to use the nav_title field for outputting in the tree items, set via userTS.
51
     *
52
     * @var bool
53
     */
54
    protected $useNavTitle = false;
55
56
    /**
57
     * Option to prefix the page ID when outputting the tree items, set via userTS.
58
     *
59
     * @var bool
60
     */
61
    protected $addIdAsPrefix = false;
62
63
    /**
64
     * Option to prefix the domain name of sys_domains when outputting the tree items, set via userTS.
65
     *
66
     * @var bool
67
     */
68
    protected $addDomainName = false;
69
70
    /**
71
     * Option to add the rootline path above each mount point, set via userTS.
72
     *
73
     * @var bool
74
     */
75
    protected $showMountPathAboveMounts = false;
76
77
    /**
78
     * An array of background colors for a branch in the tree, set via userTS.
79
     *
80
     * @var array
81
     */
82
    protected $backgroundColors = [];
83
84
    /**
85
     * A list of pages not to be shown.
86
     *
87
     * @var array
88
     */
89
    protected $hiddenRecords = [];
90
91
    /**
92
     * Contains the state of all items that are expanded.
93
     *
94
     * @var array
95
     */
96
    protected $expandedState = [];
97
98
    /**
99
     * Instance of the icon factory, to be used for generating the items.
100
     *
101
     * @var IconFactory
102
     */
103
    protected $iconFactory;
104
105
    /**
106
     * Number of tree levels which should be returned on the first page tree load
107
     *
108
     * @var int
109
     */
110
    protected $levelsToFetch = 2;
111
112
    /**
113
     * When set to true all nodes returend by API will be expanded
114
     * @var bool
115
     */
116
    protected $expandAllNodes = false;
117
118
    /**
119
     * Used in the record link picker to limit the page tree only to a specific list
120
     * of alternative entry points for selecting only from a list of pages
121
     */
122
    protected array $alternativeEntryPoints = [];
123
124
    protected UriBuilder $uriBuilder;
125
126
    /**
127
     * Constructor to set up common objects needed in various places.
128
     */
129
    public function __construct()
130
    {
131
        $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
132
        $this->uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
133
    }
134
135
    protected function initializeConfiguration(ServerRequestInterface $request)
136
    {
137
        if ($request->getQueryParams()['readOnly'] ?? false) {
138
            $this->getBackendUser()->initializeWebmountsForElementBrowser();
139
        }
140
        if ($request->getQueryParams()['alternativeEntryPoints'] ?? false) {
141
            $this->alternativeEntryPoints = $request->getQueryParams()['alternativeEntryPoints'];
142
            $this->alternativeEntryPoints = array_filter($this->alternativeEntryPoints, function ($pageId) {
143
                return $this->getBackendUser()->isInWebMount($pageId) !== null;
144
            });
145
            $this->alternativeEntryPoints = array_map('intval', $this->alternativeEntryPoints);
146
            $this->alternativeEntryPoints = array_unique($this->alternativeEntryPoints);
147
        }
148
        $userTsConfig = $this->getBackendUser()->getTSConfig();
149
        $this->hiddenRecords = GeneralUtility::intExplode(
150
            ',',
151
            $userTsConfig['options.']['hideRecords.']['pages'] ?? '',
152
            true
153
        );
154
        $this->backgroundColors = $userTsConfig['options.']['pageTree.']['backgroundColor.'] ?? [];
155
        $this->addIdAsPrefix = (bool)($userTsConfig['options.']['pageTree.']['showPageIdWithTitle'] ?? false);
156
        $this->addDomainName = (bool)($userTsConfig['options.']['pageTree.']['showDomainNameWithTitle'] ?? false);
157
        $this->useNavTitle = (bool)($userTsConfig['options.']['pageTree.']['showNavTitle'] ?? false);
158
        $this->showMountPathAboveMounts = (bool)($userTsConfig['options.']['pageTree.']['showPathAboveMounts'] ?? false);
159
        $backendUserConfiguration = GeneralUtility::makeInstance(BackendUserConfiguration::class);
160
        $this->expandedState = $backendUserConfiguration->get('BackendComponents.States.Pagetree');
161
        if (is_object($this->expandedState) && is_object($this->expandedState->stateHash)) {
162
            $this->expandedState = (array)$this->expandedState->stateHash;
163
        } else {
164
            $this->expandedState = $this->expandedState['stateHash'] ?: [];
165
        }
166
    }
167
168
    /**
169
     * Returns page tree configuration in JSON
170
     *
171
     * @return ResponseInterface
172
     */
173
    public function fetchConfigurationAction(): ResponseInterface
174
    {
175
        $configuration = [
176
            'allowDragMove' => $this->isDragMoveAllowed(),
177
            'doktypes' => $this->getDokTypes(),
178
            'displayDeleteConfirmation' => $this->getBackendUser()->jsConfirmation(JsConfirmation::DELETE),
179
            'temporaryMountPoint' => $this->getMountPointPath((int)($this->getBackendUser()->uc['pageTree_temporaryMountPoint'] ?? 0)),
180
            'showIcons' => true,
181
            'dataUrl' => (string)$this->uriBuilder->buildUriFromRoute('ajax_page_tree_data'),
182
            'filterUrl' => (string)$this->uriBuilder->buildUriFromRoute('ajax_page_tree_filter'),
183
            'setTemporaryMountPointUrl' => (string)$this->uriBuilder->buildUriFromRoute('ajax_page_tree_set_temporary_mount_point')
184
        ];
185
186
        return new JsonResponse($configuration);
187
    }
188
189
    public function fetchReadOnlyConfigurationAction(ServerRequestInterface $request): ResponseInterface
190
    {
191
        $entryPoints = $request->getQueryParams()['alternativeEntryPoints'] ?? '';
192
        $entryPoints = GeneralUtility::intExplode(',', $entryPoints, true);
193
        $additionalArguments = [
194
            'readOnly' => 1
195
        ];
196
        if (!empty($entryPoints)) {
197
            $additionalArguments['alternativeEntryPoints'] = $entryPoints;
198
        }
199
        $configuration = [
200
            'displayDeleteConfirmation' => $this->getBackendUser()->jsConfirmation(JsConfirmation::DELETE),
201
            'temporaryMountPoint' => $this->getMountPointPath((int)($this->getBackendUser()->uc['pageTree_temporaryMountPoint'] ?? 0)),
202
            'showIcons' => true,
203
            'dataUrl' => (string)$this->uriBuilder->buildUriFromRoute('ajax_page_tree_data', $additionalArguments),
204
            'filterUrl' => (string)$this->uriBuilder->buildUriFromRoute('ajax_page_tree_filter', $additionalArguments),
205
            'setTemporaryMountPointUrl' => (string)$this->uriBuilder->buildUriFromRoute('ajax_page_tree_set_temporary_mount_point'),
206
        ];
207
        return new JsonResponse($configuration);
208
    }
209
210
    /**
211
     * Returns the list of doktypes to display in page tree toolbar drag area
212
     *
213
     * Note: The list can be filtered by the user TypoScript
214
     * option "options.pageTree.doktypesToShowInNewPageDragArea".
215
     *
216
     * @return array
217
     */
218
    protected function getDokTypes(): array
219
    {
220
        $backendUser = $this->getBackendUser();
221
        $doktypeLabelMap = [];
222
        foreach ($GLOBALS['TCA']['pages']['columns']['doktype']['config']['items'] as $doktypeItemConfig) {
223
            if ($doktypeItemConfig[1] === '--div--') {
224
                continue;
225
            }
226
            $doktypeLabelMap[$doktypeItemConfig[1]] = $doktypeItemConfig[0];
227
        }
228
        $doktypes = GeneralUtility::intExplode(',', $backendUser->getTSConfig()['options.']['pageTree.']['doktypesToShowInNewPageDragArea'] ?? '', true);
229
        $doktypes = array_unique($doktypes);
230
        $output = [];
231
        $allowedDoktypes = GeneralUtility::intExplode(',', $backendUser->groupData['pagetypes_select'], true);
232
        $isAdmin = $backendUser->isAdmin();
233
        // Early return if backend user may not create any doktype
234
        if (!$isAdmin && empty($allowedDoktypes)) {
235
            return $output;
236
        }
237
        foreach ($doktypes as $doktype) {
238
            if (!$isAdmin && !in_array($doktype, $allowedDoktypes, true)) {
239
                continue;
240
            }
241
            $label = htmlspecialchars($this->getLanguageService()->sL($doktypeLabelMap[$doktype]));
242
            $output[] = [
243
                'nodeType' => $doktype,
244
                'icon' => $GLOBALS['TCA']['pages']['ctrl']['typeicon_classes'][$doktype] ?? '',
245
                'title' => $label,
246
                'tooltip' => $label
247
            ];
248
        }
249
        return $output;
250
    }
251
252
    /**
253
     * Returns JSON representing page tree
254
     *
255
     * @param ServerRequestInterface $request
256
     * @return ResponseInterface
257
     */
258
    public function fetchDataAction(ServerRequestInterface $request): ResponseInterface
259
    {
260
        $this->initializeConfiguration($request);
261
262
        $items = [];
263
        if (!empty($request->getQueryParams()['pid'])) {
264
            // Fetching a part of a page tree
265
            $entryPoints = $this->getAllEntryPointPageTrees((int)$request->getQueryParams()['pid']);
266
            $mountPid = (int)($request->getQueryParams()['mount'] ?? 0);
267
            $parentDepth = (int)($request->getQueryParams()['pidDepth'] ?? 0);
268
            $this->levelsToFetch = $parentDepth + $this->levelsToFetch;
269
            foreach ($entryPoints as $page) {
270
                $items = array_merge($items, $this->pagesToFlatArray($page, $mountPid, $parentDepth));
271
            }
272
        } else {
273
            $entryPoints = $this->getAllEntryPointPageTrees();
274
            foreach ($entryPoints as $page) {
275
                $items = array_merge($items, $this->pagesToFlatArray($page, (int)$page['uid']));
276
            }
277
        }
278
279
        return new JsonResponse($items);
280
    }
281
282
    /**
283
     * Returns JSON representing page tree filtered by keyword
284
     *
285
     * @param ServerRequestInterface $request
286
     * @return ResponseInterface
287
     */
288
    public function filterDataAction(ServerRequestInterface $request): ResponseInterface
289
    {
290
        $searchQuery = $request->getQueryParams()['q'] ?? '';
291
        if (trim($searchQuery) === '') {
292
            return new JsonResponse([]);
293
        }
294
295
        $this->initializeConfiguration($request);
296
        $this->expandAllNodes = true;
297
298
        $items = [];
299
        $entryPoints = $this->getAllEntryPointPageTrees(0, $searchQuery);
300
301
        foreach ($entryPoints as $page) {
302
            if (!empty($page)) {
303
                $items = array_merge($items, $this->pagesToFlatArray($page, (int)$page['uid']));
304
            }
305
        }
306
307
        return new JsonResponse($items);
308
    }
309
310
    /**
311
     * Sets a temporary mount point
312
     *
313
     * @param ServerRequestInterface $request
314
     * @return ResponseInterface
315
     * @throws \RuntimeException
316
     */
317
    public function setTemporaryMountPointAction(ServerRequestInterface $request): ResponseInterface
318
    {
319
        if (empty($request->getParsedBody()['pid'])) {
320
            throw new \RuntimeException(
321
                'Required "pid" parameter is missing.',
322
                1511792197
323
            );
324
        }
325
        $pid = (int)$request->getParsedBody()['pid'];
326
327
        $this->getBackendUser()->uc['pageTree_temporaryMountPoint'] = $pid;
328
        $this->getBackendUser()->writeUC();
329
        $response = [
330
            'mountPointPath' => $this->getMountPointPath($pid)
331
        ];
332
        return new JsonResponse($response);
333
    }
334
335
    /**
336
     * Converts nested tree structure produced by PageTreeRepository to a flat, one level array
337
     * and also adds visual representation information to the data.
338
     *
339
     * @param array $page
340
     * @param int $entryPoint
341
     * @param int $depth
342
     * @param array $inheritedData
343
     * @return array
344
     */
345
    protected function pagesToFlatArray(array $page, int $entryPoint, int $depth = 0, array $inheritedData = []): array
346
    {
347
        $backendUser = $this->getBackendUser();
348
        $pageId = (int)$page['uid'];
349
        if (in_array($pageId, $this->hiddenRecords, true)) {
350
            return [];
351
        }
352
        if ($pageId === 0 && !$backendUser->isAdmin()) {
353
            return [];
354
        }
355
356
        $stopPageTree = !empty($page['php_tree_stop']) && $depth > 0;
357
        $identifier = $entryPoint . '_' . $pageId;
358
        $expanded = !empty($page['expanded'])
359
            || (isset($this->expandedState[$identifier]) && $this->expandedState[$identifier])
360
            || $this->expandAllNodes;
361
362
        $backgroundColor = !empty($this->backgroundColors[$pageId]) ? $this->backgroundColors[$pageId] : ($inheritedData['backgroundColor'] ?? '');
363
364
        $suffix = '';
365
        $prefix = '';
366
        $nameSourceField = 'title';
367
        $visibleText = $page['title'];
368
        $tooltip = BackendUtility::titleAttribForPages($page, '', false);
369
        if ($pageId !== 0) {
370
            $icon = $this->iconFactory->getIconForRecord('pages', $page, Icon::SIZE_SMALL);
371
        } else {
372
            $icon = $this->iconFactory->getIcon('apps-pagetree-root', Icon::SIZE_SMALL);
373
        }
374
375
        if ($this->useNavTitle && trim($page['nav_title'] ?? '') !== '') {
376
            $nameSourceField = 'nav_title';
377
            $visibleText = $page['nav_title'];
378
        }
379
        if (trim($visibleText) === '') {
380
            $visibleText = htmlspecialchars('[' . $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.no_title') . ']');
381
        }
382
383
        if ($this->addDomainName && $page['is_siteroot']) {
384
            $domain = $this->getDomainNameForPage($pageId);
385
            $suffix = $domain !== '' ? ' [' . $domain . ']' : '';
386
        }
387
388
        $lockInfo = BackendUtility::isRecordLocked('pages', $pageId);
389
        if (is_array($lockInfo)) {
390
            $tooltip .= ' - ' . $lockInfo['msg'];
391
        }
392
        if ($this->addIdAsPrefix) {
393
            $prefix = htmlspecialchars('[' . $pageId . '] ');
394
        }
395
396
        $items = [];
397
        $item = [
398
            // Used to track if the tree item is collapsed or not
399
            'stateIdentifier' => $identifier,
400
            // identifier is not only used for pages, therefore it's a string
401
            'identifier' => (string)$pageId,
402
            'depth' => $depth,
403
            'tip' => htmlspecialchars($tooltip),
404
            'icon' => $icon->getIdentifier(),
405
            'name' => $visibleText,
406
            'type' => (int)$page['doktype'],
407
            'nameSourceField' => $nameSourceField,
408
            'mountPoint' => $entryPoint,
409
            'workspaceId' => !empty($page['t3ver_oid']) ? $page['t3ver_oid'] : $pageId,
410
            'siblingsCount' => $page['siblingsCount'] ?? 1,
411
            'siblingsPosition' => $page['siblingsPosition'] ?? 1,
412
            'allowDelete' => $backendUser->doesUserHaveAccess($page, Permission::PAGE_DELETE),
413
            'allowEdit' => $backendUser->doesUserHaveAccess($page, Permission::PAGE_EDIT)
414
                && $backendUser->check('tables_modify', 'pages')
415
                && $backendUser->checkLanguageAccess(0)
416
        ];
417
418
        if (!empty($page['_children']) || $this->getPageTreeRepository()->hasChildren($pageId)) {
419
            $item['hasChildren'] = true;
420
            if ($depth >= $this->levelsToFetch) {
421
                $page = $this->getPageTreeRepository()->getTreeLevels($page, 1);
422
            }
423
        }
424
        if (!empty($prefix)) {
425
            $item['prefix'] = htmlspecialchars($prefix);
426
        }
427
        if (!empty($suffix)) {
428
            $item['suffix'] = htmlspecialchars($suffix);
429
        }
430
        if (is_array($lockInfo)) {
431
            $item['locked'] = true;
432
        }
433
        if ($icon->getOverlayIcon()) {
434
            $item['overlayIcon'] = $icon->getOverlayIcon()->getIdentifier();
435
        }
436
        if ($expanded && is_array($page['_children']) && !empty($page['_children'])) {
437
            $item['expanded'] = $expanded;
438
        }
439
        if ($backgroundColor) {
440
            $item['backgroundColor'] = htmlspecialchars($backgroundColor);
441
        }
442
        if ($stopPageTree) {
443
            $item['stopPageTree'] = $stopPageTree;
444
        }
445
        $class = $this->resolvePageCssClassNames($page);
446
        if (!empty($class)) {
447
            $item['class'] = $class;
448
        }
449
        if ($depth === 0) {
450
            $item['isMountPoint'] = true;
451
452
            if ($this->showMountPathAboveMounts) {
453
                $item['readableRootline'] = $this->getMountPointPath($pageId);
454
            }
455
        }
456
457
        $items[] = $item;
458
        if (!$stopPageTree && is_array($page['_children']) && !empty($page['_children']) && ($depth < $this->levelsToFetch || $expanded)) {
459
            $siblingsCount = count($page['_children']);
460
            $siblingsPosition = 0;
461
            $items[key($items)]['loaded'] = true;
462
            foreach ($page['_children'] as $child) {
463
                $child['siblingsCount'] = $siblingsCount;
464
                $child['siblingsPosition'] = ++$siblingsPosition;
465
                $items = array_merge($items, $this->pagesToFlatArray($child, $entryPoint, $depth + 1, ['backgroundColor' => $backgroundColor]));
466
            }
467
        }
468
        return $items;
469
    }
470
471
    protected function getPageTreeRepository(): PageTreeRepository
472
    {
473
        $backendUser = $this->getBackendUser();
474
        $userTsConfig = $backendUser->getTSConfig();
475
        $excludedDocumentTypes = GeneralUtility::intExplode(',', $userTsConfig['options.']['pageTree.']['excludeDoktypes'] ?? '', true);
476
477
        $additionalQueryRestrictions = [];
478
        if (!empty($excludedDocumentTypes)) {
479
            $additionalQueryRestrictions[] = GeneralUtility::makeInstance(DocumentTypeExclusionRestriction::class, $excludedDocumentTypes);
480
        }
481
482
        return GeneralUtility::makeInstance(
483
            PageTreeRepository::class,
484
            (int)$backendUser->workspace,
485
            [],
486
            $additionalQueryRestrictions
487
        );
488
    }
489
490
    /**
491
     * Fetches all pages for all tree entry points the user is allowed to see
492
     *
493
     * @param int $startPid
494
     * @param string $query The search query can either be a string to be found in the title or the nav_title of a page or the uid of a page.
495
     * @return array
496
     */
497
    protected function getAllEntryPointPageTrees(int $startPid = 0, string $query = ''): array
498
    {
499
        $backendUser = $this->getBackendUser();
500
        $entryPointId = $startPid > 0 ? $startPid : (int)($backendUser->uc['pageTree_temporaryMountPoint'] ?? 0);
501
        if ($entryPointId > 0) {
502
            $entryPointIds = [$entryPointId];
503
        } elseif (!empty($this->alternativeEntryPoints)) {
504
            $entryPointIds = $this->alternativeEntryPoints;
505
        } else {
506
            //watch out for deleted pages returned as webmount
507
            $entryPointIds = array_map('intval', $backendUser->returnWebmounts());
508
            $entryPointIds = array_unique($entryPointIds);
509
            if (empty($entryPointIds)) {
510
                // use a virtual root
511
                // the real mount points will be fetched in getNodes() then
512
                // since those will be the "sub pages" of the virtual root
513
                $entryPointIds = [0];
514
            }
515
        }
516
        if (empty($entryPointIds)) {
517
            return [];
518
        }
519
        $repository = $this->getPageTreeRepository();
520
521
        $permClause = $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW);
522
        if ($query !== '') {
523
            $this->levelsToFetch = 999;
524
            $repository->fetchFilteredTree(
525
                $query,
526
                $this->getAllowedMountPoints(),
527
                $permClause
528
            );
529
        }
530
531
        $entryPointRecords = [];
532
        foreach ($entryPointIds as $k => $entryPointId) {
533
            if (in_array($entryPointId, $this->hiddenRecords, true)) {
534
                continue;
535
            }
536
537
            if (!empty($this->backgroundColors) && is_array($this->backgroundColors)) {
538
                try {
539
                    $entryPointRootLine = GeneralUtility::makeInstance(RootlineUtility::class, $entryPointId)->get();
540
                } catch (RootLineException $e) {
541
                    $entryPointRootLine = [];
542
                }
543
                foreach ($entryPointRootLine as $rootLineEntry) {
544
                    $parentUid = $rootLineEntry['uid'];
545
                    if (!empty($this->backgroundColors[$parentUid]) && empty($this->backgroundColors[$entryPointId])) {
546
                        $this->backgroundColors[$entryPointId] = $this->backgroundColors[$parentUid];
547
                    }
548
                }
549
            }
550
            if ($entryPointId === 0) {
551
                $entryPointRecord = [
552
                    'uid' => 0,
553
                    'title' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] ?: 'TYPO3'
554
                ];
555
            } else {
556
                $entryPointRecord = BackendUtility::getRecordWSOL('pages', $entryPointId, '*', $permClause);
557
558
                if ($entryPointRecord !== null && !$this->getBackendUser()->isInWebMount($entryPointId)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->getBackendUser()-...WebMount($entryPointId) of type integer|null is loosely compared to false; this is ambiguous if the integer can be 0. 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 integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
559
                    $entryPointRecord = null;
560
                }
561
            }
562
            if ($entryPointRecord) {
563
                $entryPointRecord['uid'] = (int)$entryPointRecord['uid'];
564
                if ($query === '') {
565
                    $entryPointRecord = $repository->getTreeLevels($entryPointRecord, $this->levelsToFetch);
566
                } else {
567
                    $entryPointRecord = $repository->getTree((int)$entryPointRecord['uid'], null, $entryPointIds, true);
568
                }
569
            }
570
571
            if (is_array($entryPointRecord) && !empty($entryPointRecord)) {
572
                $entryPointRecords[$k] = $entryPointRecord;
573
            }
574
        }
575
576
        return $entryPointRecords;
577
    }
578
579
    /**
580
     * Returns the first configured domain name for a page
581
     *
582
     * @param int $pageId
583
     * @return string
584
     */
585
    protected function getDomainNameForPage(int $pageId): string
586
    {
587
        $domain = '';
588
        $siteFinder = GeneralUtility::makeInstance(SiteFinder::class);
589
        try {
590
            $site = $siteFinder->getSiteByRootPageId($pageId);
591
            $domain = (string)$site->getBase();
592
        } catch (SiteNotFoundException $e) {
593
            // No site found
594
        }
595
596
        return $domain;
597
    }
598
599
    /**
600
     * Returns the mount point path for a temporary mount or the given id
601
     *
602
     * @param int $uid
603
     * @return string
604
     */
605
    protected function getMountPointPath(int $uid): string
606
    {
607
        if ($uid <= 0) {
608
            return '';
609
        }
610
        $rootline = array_reverse(BackendUtility::BEgetRootLine($uid));
611
        array_shift($rootline);
612
        $path = [];
613
        foreach ($rootline as $rootlineElement) {
614
            $record = BackendUtility::getRecordWSOL('pages', $rootlineElement['uid'], 'title, nav_title', '', true, true);
615
            $text = $record['title'];
616
            if ($this->useNavTitle && trim($record['nav_title'] ?? '') !== '') {
617
                $text = $record['nav_title'];
618
            }
619
            $path[] = htmlspecialchars($text);
620
        }
621
        return '/' . implode('/', $path);
622
    }
623
624
    /**
625
     * Fetches possible css class names to be used when a record was modified in a workspace
626
     *
627
     * @param array $page Page record (workspace overlaid)
628
     * @return string CSS class names to be applied
629
     */
630
    protected function resolvePageCssClassNames(array $page): string
631
    {
632
        $classes = [];
633
634
        if ($page['uid'] === 0) {
635
            return '';
636
        }
637
        $workspaceId = (int)$this->getBackendUser()->workspace;
638
        if ($workspaceId > 0 && ExtensionManagementUtility::isLoaded('workspaces')) {
639
            if ((int)$page['t3ver_wsid'] === $workspaceId
640
                && ((int)$page['t3ver_oid'] > 0 || (int)$page['t3ver_state'] === VersionState::NEW_PLACEHOLDER)
641
            ) {
642
                $classes[] = 'ver-element';
643
                $classes[] = 'ver-versions';
644
            } elseif (
645
                $this->getWorkspaceService()->hasPageRecordVersions(
646
                    $workspaceId,
647
                    $page['t3ver_oid'] ?: $page['uid']
648
                )
649
            ) {
650
                $classes[] = 'ver-versions';
651
            }
652
        }
653
654
        return implode(' ', $classes);
655
    }
656
657
    /**
658
     * Check if drag-move in the svg tree is allowed for the user
659
     *
660
     * @return bool
661
     */
662
    protected function isDragMoveAllowed(): bool
663
    {
664
        $backendUser = $this->getBackendUser();
665
        return $backendUser->isAdmin()
666
            || ($backendUser->check('tables_modify', 'pages') && $backendUser->checkLanguageAccess(0));
667
    }
668
669
    /**
670
     * Get allowed mountpoints. Returns temporary mountpoint when temporary mountpoint is used.
671
     *
672
     * @return int[]
673
     */
674
    protected function getAllowedMountPoints(): array
675
    {
676
        $mountPoints = (int)($this->getBackendUser()->uc['pageTree_temporaryMountPoint'] ?? 0);
677
        if (!$mountPoints) {
678
            if (!empty($this->alternativeEntryPoints)) {
679
                return $this->alternativeEntryPoints;
680
            }
681
            $mountPoints = array_map('intval', $this->getBackendUser()->returnWebmounts());
682
            return array_unique($mountPoints);
683
        }
684
        return [$mountPoints];
685
    }
686
687
    /**
688
     * @return WorkspaceService
689
     */
690
    protected function getWorkspaceService(): WorkspaceService
691
    {
692
        return GeneralUtility::makeInstance(WorkspaceService::class);
693
    }
694
695
    /**
696
     * @return BackendUserAuthentication
697
     */
698
    protected function getBackendUser(): BackendUserAuthentication
699
    {
700
        return $GLOBALS['BE_USER'];
701
    }
702
703
    /**
704
     * @return LanguageService|null
705
     */
706
    protected function getLanguageService(): ?LanguageService
707
    {
708
        return $GLOBALS['LANG'] ?? null;
709
    }
710
}
711