Completed
Push — master ( 83cb67...d32f9d )
by
unknown
20:24
created

GridDataService::getObjectManager()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the TYPO3 CMS project.
5
 *
6
 * It is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License, either version 2
8
 * of the License, or any later version.
9
 *
10
 * For the full copyright and license information, please read the
11
 * LICENSE.txt file that was distributed with this source code.
12
 *
13
 * The TYPO3 project - inspiring people to share!
14
 */
15
16
namespace TYPO3\CMS\Workspaces\Service;
17
18
use Psr\EventDispatcher\EventDispatcherInterface;
19
use Psr\Log\LoggerAwareInterface;
20
use Psr\Log\LoggerAwareTrait;
21
use TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider;
22
use TYPO3\CMS\Backend\Utility\BackendUtility;
23
use TYPO3\CMS\Core\Cache\CacheManager;
24
use TYPO3\CMS\Core\Imaging\Icon;
25
use TYPO3\CMS\Core\Imaging\IconFactory;
26
use TYPO3\CMS\Core\Utility\GeneralUtility;
27
use TYPO3\CMS\Core\Versioning\VersionState;
28
use TYPO3\CMS\Workspaces\Domain\Model\CombinedRecord;
29
use TYPO3\CMS\Workspaces\Event\AfterCompiledCacheableDataForWorkspaceEvent;
30
use TYPO3\CMS\Workspaces\Event\AfterDataGeneratedForWorkspaceEvent;
31
use TYPO3\CMS\Workspaces\Event\GetVersionedDataEvent;
32
use TYPO3\CMS\Workspaces\Event\SortVersionedDataEvent;
33
use TYPO3\CMS\Workspaces\Preview\PreviewUriBuilder;
34
use TYPO3\CMS\Workspaces\Service\Dependency\CollectionService;
35
36
/**
37
 * Grid data service
38
 */
39
class GridDataService implements LoggerAwareInterface
40
{
41
    use LoggerAwareTrait;
42
43
    const GridColumn_Collection = 'Workspaces_Collection';
0 ignored issues
show
Coding Style introduced by
This class constant is not uppercase (expected GRIDCOLUMN_COLLECTION).
Loading history...
44
    const GridColumn_CollectionLevel = 'Workspaces_CollectionLevel';
0 ignored issues
show
Coding Style introduced by
This class constant is not uppercase (expected GRIDCOLUMN_COLLECTIONLEVEL).
Loading history...
45
    const GridColumn_CollectionParent = 'Workspaces_CollectionParent';
0 ignored issues
show
Coding Style introduced by
This class constant is not uppercase (expected GRIDCOLUMN_COLLECTIONPARENT).
Loading history...
46
    const GridColumn_CollectionCurrent = 'Workspaces_CollectionCurrent';
0 ignored issues
show
Coding Style introduced by
This class constant is not uppercase (expected GRIDCOLUMN_COLLECTIONCURRENT).
Loading history...
47
    const GridColumn_CollectionChildren = 'Workspaces_CollectionChildren';
0 ignored issues
show
Coding Style introduced by
This class constant is not uppercase (expected GRIDCOLUMN_COLLECTIONCHILDREN).
Loading history...
48
49
    /**
50
     * Id of the current active workspace.
51
     *
52
     * @var int
53
     */
54
    protected $currentWorkspace;
55
56
    /**
57
     * Version record information (filtered, sorted and limited)
58
     *
59
     * @var array
60
     */
61
    protected $dataArray = [];
62
63
    /**
64
     * Name of the field used for sorting.
65
     *
66
     * @var string
67
     */
68
    protected $sort = '';
69
70
    /**
71
     * Direction used for sorting (ASC, DESC).
72
     *
73
     * @var string
74
     */
75
    protected $sortDir = '';
76
77
    /**
78
     * @var \TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
79
     */
80
    protected $workspacesCache;
81
82
    /**
83
     * @var IntegrityService
84
     */
85
    protected $integrityService;
86
87
    /**
88
     * @var EventDispatcherInterface
89
     */
90
    protected $eventDispatcher;
91
92
    public function __construct(EventDispatcherInterface $eventDispatcher)
93
    {
94
        $this->eventDispatcher = $eventDispatcher;
95
    }
96
97
    /**
98
     * Generates grid list array from given versions.
99
     *
100
     * @param array $versions All records uids etc. First key is table name, second key incremental integer. Records are associative arrays with uid and t3ver_oid fields. The pid of the online record is found as "livepid" the pid of the offline record is found in "wspid
101
     * @param \stdClass $parameter Parameters as submitted by JavaScript component
102
     * @param int $currentWorkspace The current workspace
103
     * @return array Version record information (filtered, sorted and limited)
104
     * @throws \InvalidArgumentException
105
     */
106
    public function generateGridListFromVersions($versions, $parameter, $currentWorkspace)
107
    {
108
        // Read the given parameters from grid. If the parameter is not set use default values.
109
        $filterTxt = $parameter->filterTxt ?? '';
110
        $start = isset($parameter->start) ? (int)$parameter->start : 0;
111
        $limit = isset($parameter->limit) ? (int)$parameter->limit : 30;
112
        $this->sort = $parameter->sort ?? 't3ver_oid';
113
        $this->sortDir = $parameter->dir ?? 'ASC';
114
        if (is_int($currentWorkspace)) {
0 ignored issues
show
introduced by
The condition is_int($currentWorkspace) is always true.
Loading history...
115
            $this->currentWorkspace = $currentWorkspace;
116
        } else {
117
            throw new \InvalidArgumentException('No such workspace defined', 1476048304);
118
        }
119
        $data = [];
120
        $data['data'] = [];
121
        $this->generateDataArray($versions, $filterTxt);
122
        $data['total'] = count($this->dataArray);
123
        $data['data'] = $this->getDataArray($start, $limit);
124
        return $data;
125
    }
126
127
    /**
128
     * Generates grid list array from given versions.
129
     *
130
     * @param array $versions All available version records
131
     * @param string $filterTxt Text to be used to filter record result
132
     */
133
    protected function generateDataArray(array $versions, $filterTxt)
134
    {
135
        $workspaceAccess = $GLOBALS['BE_USER']->checkWorkspace($GLOBALS['BE_USER']->workspace);
136
        $swapStage = $workspaceAccess['publish_access'] & 1 ? StagesService::STAGE_PUBLISH_ID : 0;
137
        $swapAccess = $GLOBALS['BE_USER']->workspacePublishAccess($GLOBALS['BE_USER']->workspace) && $GLOBALS['BE_USER']->workspaceSwapAccess();
138
        $this->initializeWorkspacesCachingFramework();
139
        $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
140
        // check for dataArray in cache
141
        if ($this->getDataArrayFromCache($versions, $filterTxt) === false) {
142
            $stagesObj = GeneralUtility::makeInstance(StagesService::class);
143
            $defaultGridColumns = [
144
                self::GridColumn_Collection => 0,
145
                self::GridColumn_CollectionLevel => 0,
146
                self::GridColumn_CollectionParent => '',
147
                self::GridColumn_CollectionCurrent => '',
148
                self::GridColumn_CollectionChildren => 0,
149
            ];
150
            foreach ($versions as $table => $records) {
151
                $hiddenField = $this->getTcaEnableColumnsFieldName($table, 'disabled');
152
                $isRecordTypeAllowedToModify = $GLOBALS['BE_USER']->check('tables_modify', $table);
153
154
                foreach ($records as $record) {
155
                    $origRecord = BackendUtility::getRecord($table, $record['t3ver_oid']);
156
                    $versionRecord = BackendUtility::getRecord($table, $record['uid']);
157
                    $combinedRecord = CombinedRecord::createFromArrays($table, $origRecord, $versionRecord);
0 ignored issues
show
Bug introduced by
It seems like $versionRecord can also be of type null; however, parameter $versionRow of TYPO3\CMS\Workspaces\Dom...ord::createFromArrays() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

157
                    $combinedRecord = CombinedRecord::createFromArrays($table, $origRecord, /** @scrutinizer ignore-type */ $versionRecord);
Loading history...
Bug introduced by
It seems like $origRecord can also be of type null; however, parameter $liveRow of TYPO3\CMS\Workspaces\Dom...ord::createFromArrays() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

157
                    $combinedRecord = CombinedRecord::createFromArrays($table, /** @scrutinizer ignore-type */ $origRecord, $versionRecord);
Loading history...
158
                    $this->getIntegrityService()->checkElement($combinedRecord);
159
160
                    if ($hiddenField !== null) {
161
                        $recordState = $this->workspaceState($versionRecord['t3ver_state'], $origRecord[$hiddenField], $versionRecord[$hiddenField]);
162
                    } else {
163
                        $recordState = $this->workspaceState($versionRecord['t3ver_state']);
164
                    }
165
166
                    $isDeletedPage = $table === 'pages' && $recordState === 'deleted';
167
                    $pageId = $table === 'pages' ? $record['uid'] : $record['pid'];
168
                    $viewUrl = GeneralUtility::makeInstance(PreviewUriBuilder::class)->buildUriForElement($table, $record['uid'], $origRecord, $versionRecord);
169
                    $versionArray = [];
170
                    $versionArray['table'] = $table;
171
                    $versionArray['id'] = $table . ':' . $record['uid'];
172
                    $versionArray['uid'] = $record['uid'];
173
                    $versionArray = array_merge($versionArray, $defaultGridColumns);
174
                    $versionArray['label_Workspace'] = htmlspecialchars(BackendUtility::getRecordTitle($table, $versionRecord));
175
                    $versionArray['label_Live'] = htmlspecialchars(BackendUtility::getRecordTitle($table, $origRecord));
176
                    $versionArray['label_Stage'] = htmlspecialchars($stagesObj->getStageTitle($versionRecord['t3ver_stage']));
177
                    $tempStage = $stagesObj->getNextStage($versionRecord['t3ver_stage']);
178
                    $versionArray['label_nextStage'] = htmlspecialchars($stagesObj->getStageTitle($tempStage['uid']));
179
                    $versionArray['value_nextStage'] = (int)$tempStage['uid'];
180
                    $tempStage = $stagesObj->getPrevStage($versionRecord['t3ver_stage']);
181
                    $versionArray['label_prevStage'] = htmlspecialchars($stagesObj->getStageTitle($tempStage['uid']));
182
                    $versionArray['value_prevStage'] = (int)$tempStage['uid'];
183
                    $versionArray['path_Live'] = htmlspecialchars(BackendUtility::getRecordPath($record['livepid'], '', 999));
0 ignored issues
show
Bug introduced by
It seems like TYPO3\CMS\Backend\Utilit...rd['livepid'], '', 999) can also be of type array<integer,string>; however, parameter $string of htmlspecialchars() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

183
                    $versionArray['path_Live'] = htmlspecialchars(/** @scrutinizer ignore-type */ BackendUtility::getRecordPath($record['livepid'], '', 999));
Loading history...
184
                    // no htmlspecialchars necessary as this is only used in JS via text function
185
                    $versionArray['path_Workspace'] = BackendUtility::getRecordPath($record['wspid'], '', 999);
186
                    $versionArray['workspace_Title'] = htmlspecialchars(WorkspaceService::getWorkspaceTitle($versionRecord['t3ver_wsid']));
187
                    $versionArray['workspace_Tstamp'] = $versionRecord['tstamp'];
188
                    $versionArray['workspace_Formated_Tstamp'] = BackendUtility::datetime($versionRecord['tstamp']);
189
                    $versionArray['t3ver_wsid'] = $versionRecord['t3ver_wsid'];
190
                    $versionArray['t3ver_oid'] = $record['t3ver_oid'];
191
                    $versionArray['livepid'] = $record['livepid'];
192
                    $versionArray['stage'] = $versionRecord['t3ver_stage'];
193
                    $versionArray['icon_Live'] = $iconFactory->getIconForRecord($table, $origRecord, Icon::SIZE_SMALL)->render();
194
                    $versionArray['icon_Workspace'] = $iconFactory->getIconForRecord($table, $versionRecord, Icon::SIZE_SMALL)->render();
195
                    $languageValue = $this->getLanguageValue($table, $versionRecord);
0 ignored issues
show
Bug introduced by
It seems like $versionRecord can also be of type null; however, parameter $record of TYPO3\CMS\Workspaces\Ser...ice::getLanguageValue() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

195
                    $languageValue = $this->getLanguageValue($table, /** @scrutinizer ignore-type */ $versionRecord);
Loading history...
196
                    $versionArray['languageValue'] = $languageValue;
197
                    $versionArray['language'] = [
198
                        'icon' => $iconFactory->getIcon($this->getSystemLanguageValue($languageValue, $pageId, 'flagIcon'), Icon::SIZE_SMALL)->render()
199
                    ];
200
                    $versionArray['allowedAction_nextStage'] = $isRecordTypeAllowedToModify && $stagesObj->isNextStageAllowedForUser($versionRecord['t3ver_stage']);
201
                    $versionArray['allowedAction_prevStage'] = $isRecordTypeAllowedToModify && $stagesObj->isPrevStageAllowedForUser($versionRecord['t3ver_stage']);
202
                    if ($swapAccess && $swapStage != 0 && $versionRecord['t3ver_stage'] == $swapStage) {
203
                        $versionArray['allowedAction_swap'] = $isRecordTypeAllowedToModify && $stagesObj->isNextStageAllowedForUser($swapStage);
204
                    } elseif ($swapAccess && $swapStage == 0) {
205
                        $versionArray['allowedAction_swap'] = $isRecordTypeAllowedToModify;
206
                    } else {
207
                        $versionArray['allowedAction_swap'] = false;
208
                    }
209
                    $versionArray['allowedAction_delete'] = $isRecordTypeAllowedToModify;
210
                    // preview and editing of a deleted page won't work ;)
211
                    $versionArray['allowedAction_view'] = !$isDeletedPage && $viewUrl;
212
                    $versionArray['allowedAction_edit'] = $isRecordTypeAllowedToModify && !$isDeletedPage;
213
                    $versionArray['allowedAction_editVersionedPage'] = $isRecordTypeAllowedToModify && !$isDeletedPage;
214
                    $versionArray['state_Workspace'] = $recordState;
215
216
                    $versionArray = array_merge(
217
                        $versionArray,
218
                        $this->getAdditionalColumnService()->getData($combinedRecord)
219
                    );
220
221
                    if ($filterTxt == '' || $this->isFilterTextInVisibleColumns($filterTxt, $versionArray)) {
222
                        $versionIdentifier = $versionArray['id'];
223
                        $this->dataArray[$versionIdentifier] = $versionArray;
224
                    }
225
                }
226
            }
227
228
            // Trigger a PSR-14 event
229
            $event = new AfterCompiledCacheableDataForWorkspaceEvent($this, $this->dataArray, $versions);
230
            $this->eventDispatcher->dispatch($event);
231
            $this->dataArray = $event->getData();
232
            $versions = $event->getVersions();
233
            // Enrich elements after everything has been processed:
234
            foreach ($this->dataArray as &$element) {
235
                $identifier = $element['table'] . ':' . $element['t3ver_oid'];
236
                $element['integrity'] = [
237
                    'status' => $this->getIntegrityService()->getStatusRepresentation($identifier),
238
                    'messages' => htmlspecialchars($this->getIntegrityService()->getIssueMessages($identifier, true))
239
                ];
240
            }
241
            $this->setDataArrayIntoCache($versions, $filterTxt);
242
        }
243
244
        // Trigger a PSR-14 event
245
        $event = new AfterDataGeneratedForWorkspaceEvent($this, $this->dataArray, $versions);
246
        $this->eventDispatcher->dispatch($event);
247
        $this->dataArray = $event->getData();
248
        $this->sortDataArray();
249
        $this->resolveDataArrayDependencies();
250
    }
251
252
    /**
253
     * Resolves dependencies of nested structures
254
     * and sort data elements considering these dependencies.
255
     */
256
    protected function resolveDataArrayDependencies()
257
    {
258
        $collectionService = $this->getDependencyCollectionService();
259
        $dependencyResolver = $collectionService->getDependencyResolver();
260
261
        foreach ($this->dataArray as $dataElement) {
262
            $dependencyResolver->addElement($dataElement['table'], $dataElement['uid']);
263
        }
264
265
        $this->dataArray = $collectionService->process($this->dataArray);
266
    }
267
268
    /**
269
     * Gets the data array by considering the page to be shown in the grid view.
270
     *
271
     * @param int $start
272
     * @param int $limit
273
     * @return array
274
     */
275
    protected function getDataArray($start, $limit)
276
    {
277
        $dataArrayPart = [];
278
        $dataArrayCount = count($this->dataArray);
279
        $end = ($start + $limit < $dataArrayCount ? $start + $limit : $dataArrayCount);
280
281
        // Ensure that there are numerical indexes
282
        $this->dataArray = array_values($this->dataArray);
283
        for ($i = $start; $i < $end; $i++) {
284
            $dataArrayPart[] = $this->dataArray[$i];
285
        }
286
287
        // Ensure that collections are not cut for the pagination
288
        if (!empty($this->dataArray[$i][self::GridColumn_Collection])) {
289
            $collectionIdentifier = $this->dataArray[$i][self::GridColumn_Collection];
290
            for ($i = $i + 1; $i < $dataArrayCount && $collectionIdentifier === $this->dataArray[$i][self::GridColumn_Collection]; $i++) {
291
                $dataArrayPart[] = $this->dataArray[$i];
292
            }
293
        }
294
295
        // Trigger a PSR-14 event
296
        $event = new GetVersionedDataEvent($this, $this->dataArray, $start, $limit, $dataArrayPart);
297
        $this->eventDispatcher->dispatch($event);
298
        $this->dataArray = $event->getData();
299
        return $event->getDataArrayPart();
300
    }
301
302
    /**
303
     * Initializes the workspace cache
304
     */
305
    protected function initializeWorkspacesCachingFramework()
306
    {
307
        $this->workspacesCache = GeneralUtility::makeInstance(CacheManager::class)->getCache('workspaces_cache');
308
    }
309
310
    /**
311
     * Puts the generated dataArray into the workspace cache.
312
     *
313
     * @param array $versions All records uids etc. First key is table name, second key incremental integer. Records are associative arrays with uid and t3ver_oid fields. The pid of the online record is found as "livepid" the pid of the offline record is found in "wspid
314
     * @param string $filterTxt The given filter text from the grid.
315
     */
316
    protected function setDataArrayIntoCache(array $versions, $filterTxt)
317
    {
318
        $hash = $this->calculateHash($versions, $filterTxt);
319
        $this->workspacesCache->set($hash, $this->dataArray, [(string)$this->currentWorkspace, 'user_' . $GLOBALS['BE_USER']->user['uid']]);
320
    }
321
322
    /**
323
     * Checks if a cache entry is given for given versions and filter text and tries to load the data array from cache.
324
     *
325
     * @param array $versions All records uids etc. First key is table name, second key incremental integer. Records are associative arrays with uid and t3ver_oid fields. The pid of the online record is found as "livepid" the pid of the offline record is found in "wspid
326
     * @param string $filterTxt The given filter text from the grid.
327
     * @return bool TRUE if cache entry was successfully fetched from cache and content put to $this->dataArray
328
     */
329
    protected function getDataArrayFromCache(array $versions, $filterTxt)
330
    {
331
        $cacheEntry = false;
332
        $hash = $this->calculateHash($versions, $filterTxt);
333
        $content = $this->workspacesCache->get($hash);
334
        if ($content !== false) {
335
            $this->dataArray = $content;
336
            $cacheEntry = true;
337
        }
338
        return $cacheEntry;
339
    }
340
341
    /**
342
     * Calculates the hash value of the used workspace, the user id, the versions array, the filter text, the sorting attribute, the workspace selected in grid and the sorting direction.
343
     *
344
     * @param array $versions All records uids etc. First key is table name, second key incremental integer. Records are associative arrays with uid and t3ver_oid fields. The pid of the online record is found as "livepid" the pid of the offline record is found in "wspid
345
     * @param string $filterTxt The given filter text from the grid.
346
     * @return string
347
     */
348
    protected function calculateHash(array $versions, $filterTxt)
349
    {
350
        $hashArray = [
351
            $GLOBALS['BE_USER']->workspace,
352
            $GLOBALS['BE_USER']->user['uid'],
353
            $versions,
354
            $filterTxt,
355
            $this->sort,
356
            $this->sortDir,
357
            $this->currentWorkspace
358
        ];
359
        $hash = md5(serialize($hashArray));
360
        return $hash;
361
    }
362
363
    /**
364
     * Performs sorting on the data array accordant to the
365
     * selected column in the grid view to be used for sorting.
366
     */
367
    protected function sortDataArray()
368
    {
369
        if (is_array($this->dataArray)) {
0 ignored issues
show
introduced by
The condition is_array($this->dataArray) is always true.
Loading history...
370
            switch ($this->sort) {
371
                case 'uid':
372
                case 'change':
373
                case 'workspace_Tstamp':
374
                case 't3ver_oid':
375
                case 'liveid':
376
                case 'livepid':
377
                case 'languageValue':
378
                    uasort($this->dataArray, [$this, 'intSort']);
379
                    break;
380
                case 'label_Workspace':
381
                case 'label_Live':
382
                case 'label_Stage':
383
                case 'workspace_Title':
384
                case 'path_Live':
385
                    // case 'path_Workspace': This is the first sorting attribute
386
                    uasort($this->dataArray, [$this, 'stringSort']);
387
                    break;
388
                default:
389
                    // Do nothing
390
            }
391
        } else {
392
            $this->logger->critical('Try to sort "' . $this->sort . '" in "\\TYPO3\\CMS\\Workspaces\\Service\\GridDataService::sortDataArray" but $this->dataArray is empty! This might be the bug #26422 which could not be reproduced yet.');
393
        }
394
        // Trigger an event for extensibility
395
        $event = new SortVersionedDataEvent($this, $this->dataArray, $this->sort, $this->sortDir);
396
        $this->eventDispatcher->dispatch($event);
397
        $this->dataArray = $event->getData();
398
        $this->sort = $event->getSortColumn();
399
        $this->sortDir = $event->getSortDirection();
400
    }
401
402
    /**
403
     * Implements individual sorting for columns based on integer comparison.
404
     *
405
     * @param array $a First value
406
     * @param array $b Second value
407
     * @return int
408
     */
409
    protected function intSort(array $a, array $b)
410
    {
411
        if (!$this->isSortable($a, $b)) {
412
            return 0;
413
        }
414
        // First sort by using the page-path in current workspace
415
        $path_cmp = strcasecmp($a['path_Workspace'], $b['path_Workspace']);
416
        if ($path_cmp < 0) {
417
            return $path_cmp;
418
        }
419
        if ($path_cmp == 0) {
420
            if ($a[$this->sort] == $b[$this->sort]) {
421
                return 0;
422
            }
423
            if ($this->sortDir === 'ASC') {
424
                return $a[$this->sort] < $b[$this->sort] ? -1 : 1;
425
            }
426
            if ($this->sortDir === 'DESC') {
427
                return $a[$this->sort] > $b[$this->sort] ? -1 : 1;
428
            }
429
        } elseif ($path_cmp > 0) {
430
            return $path_cmp;
431
        }
432
        return 0;
433
    }
434
435
    /**
436
     * Implements individual sorting for columns based on string comparison.
437
     *
438
     * @param string $a First value
439
     * @param string $b Second value
440
     * @return int
441
     */
442
    protected function stringSort($a, $b)
443
    {
444
        if (!$this->isSortable($a, $b)) {
0 ignored issues
show
Bug introduced by
$a of type string is incompatible with the type array expected by parameter $a of TYPO3\CMS\Workspaces\Ser...taService::isSortable(). ( Ignorable by Annotation )

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

444
        if (!$this->isSortable(/** @scrutinizer ignore-type */ $a, $b)) {
Loading history...
Bug introduced by
$b of type string is incompatible with the type array expected by parameter $b of TYPO3\CMS\Workspaces\Ser...taService::isSortable(). ( Ignorable by Annotation )

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

444
        if (!$this->isSortable($a, /** @scrutinizer ignore-type */ $b)) {
Loading history...
445
            return 0;
446
        }
447
        $path_cmp = strcasecmp($a['path_Workspace'], $b['path_Workspace']);
448
        if ($path_cmp < 0) {
449
            return $path_cmp;
450
        }
451
        if ($path_cmp == 0) {
452
            if ($a[$this->sort] == $b[$this->sort]) {
453
                return 0;
454
            }
455
            if ($this->sortDir === 'ASC') {
456
                return strcasecmp($a[$this->sort], $b[$this->sort]);
457
            }
458
            if ($this->sortDir === 'DESC') {
459
                return strcasecmp($a[$this->sort], $b[$this->sort]) * -1;
460
            }
461
        } elseif ($path_cmp > 0) {
462
            return $path_cmp;
463
        }
464
        return 0;
465
    }
466
467
    /**
468
     * Determines whether dataArray elements are sortable.
469
     * Only elements on the first level (0) or below the same
470
     * parent element are directly sortable.
471
     *
472
     * @param array $a
473
     * @param array $b
474
     * @return bool
475
     */
476
    protected function isSortable(array $a, array $b)
477
    {
478
        return
479
            $a[self::GridColumn_CollectionLevel] === 0 && $b[self::GridColumn_CollectionLevel] === 0
480
            || $a[self::GridColumn_CollectionParent] === $b[self::GridColumn_CollectionParent]
481
        ;
0 ignored issues
show
Coding Style introduced by
Space found before semicolon; expected "];" but found "]
;"
Loading history...
482
    }
483
484
    /**
485
     * Determines whether the text used to filter the results is part of
486
     * a column that is visible in the grid view.
487
     *
488
     * @param string $filterText
489
     * @param array $versionArray
490
     * @return bool
491
     */
492
    protected function isFilterTextInVisibleColumns($filterText, array $versionArray)
493
    {
494
        if (is_array($GLOBALS['BE_USER']->uc['moduleData']['Workspaces'][$GLOBALS['BE_USER']->workspace]['columns'])) {
495
            $visibleColumns = $GLOBALS['BE_USER']->uc['moduleData']['Workspaces'][$GLOBALS['BE_USER']->workspace]['columns'];
496
        } else {
497
            $visibleColumns = [
498
                'workspace_Formated_Tstamp' => ['hidden' => 0],
499
                'change' => ['hidden' => 0],
500
                'path_Workspace' => ['hidden' => 0],
501
                'path_Live' => ['hidden' => 0],
502
                'label_Live' => ['hidden' => 0],
503
                'label_Stage' => ['hidden' => 0],
504
                'label_Workspace' => ['hidden' => 0],
505
            ];
506
        }
507
        foreach ($visibleColumns as $column => $value) {
508
            if (isset($value['hidden']) && isset($column) && isset($versionArray[$column])) {
509
                if ($value['hidden'] == 0) {
510
                    switch ($column) {
511
                        case 'workspace_Tstamp':
512
                            if (stripos($versionArray['workspace_Formated_Tstamp'], $filterText) !== false) {
513
                                return true;
514
                            }
515
                            break;
516
                        case 'change':
517
                            if (stripos((string)$versionArray[$column], str_replace('%', '', $filterText)) !== false) {
518
                                return true;
519
                            }
520
                            break;
521
                        default:
522
                            if (stripos((string)$versionArray[$column], $filterText) !== false) {
523
                                return true;
524
                            }
525
                    }
526
                }
527
            }
528
        }
529
        return false;
530
    }
531
532
    /**
533
     * Gets the state of a given state value.
534
     *
535
     * @param int $stateId stateId of offline record
536
     * @param bool $hiddenOnline hidden status of online record
537
     * @param bool $hiddenOffline hidden status of offline record
538
     * @return string
539
     */
540
    protected function workspaceState($stateId, $hiddenOnline = false, $hiddenOffline = false)
541
    {
542
        $hiddenState = null;
543
        if ($hiddenOnline == 0 && $hiddenOffline == 1) {
544
            $hiddenState = 'hidden';
545
        } elseif ($hiddenOnline == 1 && $hiddenOffline == 0) {
546
            $hiddenState = 'unhidden';
547
        }
548
        switch ($stateId) {
549
            case VersionState::NEW_PLACEHOLDER_VERSION:
550
                $state = 'new';
551
                break;
552
            case VersionState::DELETE_PLACEHOLDER:
553
                $state = 'deleted';
554
                break;
555
            case VersionState::MOVE_POINTER:
556
                $state = 'moved';
557
                break;
558
            default:
559
                $state = ($hiddenState ?: 'modified');
560
        }
561
        return $state;
562
    }
563
564
    /**
565
     * Gets the field name of the enable-columns as defined in $TCA.
566
     *
567
     * @param string $table Name of the table
568
     * @param string $type Type to be fetches (e.g. 'disabled', 'starttime', 'endtime', 'fe_group)
569
     * @return string|null The accordant field name or NULL if not defined
570
     */
571
    protected function getTcaEnableColumnsFieldName($table, $type)
572
    {
573
        $fieldName = null;
574
575
        if (!empty($GLOBALS['TCA'][$table]['ctrl']['enablecolumns'][$type])) {
576
            $fieldName = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns'][$type];
577
        }
578
579
        return $fieldName;
580
    }
581
582
    /**
583
     * Gets the used language value (sys_language.uid) of
584
     * a given database record.
585
     *
586
     * @param string $table Name of the table
587
     * @param array $record Database record
588
     * @return int
589
     */
590
    protected function getLanguageValue($table, array $record)
591
    {
592
        $languageValue = 0;
593
        if (BackendUtility::isTableLocalizable($table)) {
594
            $languageField = $GLOBALS['TCA'][$table]['ctrl']['languageField'];
595
            if (!empty($record[$languageField])) {
596
                $languageValue = $record[$languageField];
597
            }
598
        }
599
        return $languageValue;
600
    }
601
602
    /**
603
     * Gets a named value of the available sys_language elements.
604
     *
605
     * @param int $id sys_language uid
606
     * @param int $pageId page id of a site
607
     * @param string $key Name of the value to be fetched (e.g. title)
608
     * @return string|null
609
     * @see getSystemLanguages
610
     */
611
    protected function getSystemLanguageValue($id, $pageId, $key)
612
    {
613
        $value = null;
614
        $systemLanguages = $this->getSystemLanguages((int)$pageId);
615
        if (!empty($systemLanguages[$id][$key])) {
616
            $value = $systemLanguages[$id][$key];
617
        }
618
        return $value;
619
    }
620
621
    /**
622
     * Gets all available system languages.
623
     *
624
     * @param int $pageId
625
     * @return array
626
     */
627
    public function getSystemLanguages(int $pageId)
628
    {
629
        return GeneralUtility::makeInstance(TranslationConfigurationProvider::class)->getSystemLanguages($pageId);
630
    }
631
632
    /**
633
     * Gets an instance of the integrity service.
634
     *
635
     * @return IntegrityService
636
     */
637
    protected function getIntegrityService()
638
    {
639
        if (!isset($this->integrityService)) {
640
            $this->integrityService = GeneralUtility::makeInstance(IntegrityService::class);
641
        }
642
        return $this->integrityService;
643
    }
644
645
    /**
646
     * @return Dependency\CollectionService
647
     */
648
    protected function getDependencyCollectionService()
649
    {
650
        return GeneralUtility::makeInstance(CollectionService::class);
651
    }
652
653
    /**
654
     * @return AdditionalColumnService
655
     */
656
    protected function getAdditionalColumnService()
657
    {
658
        return GeneralUtility::makeInstance(AdditionalColumnService::class);
659
    }
660
}
661