Passed
Push — master ( a7bade...f16b47 )
by
unknown
17:39
created

SortSubPagesController::mainAction()   C

Complexity

Conditions 11
Paths 5

Size

Total Lines 74
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 53
nc 5
nop 1
dl 0
loc 74
rs 6.8787
c 0
b 0
f 0

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\Routing\PreviewUriBuilder;
23
use TYPO3\CMS\Backend\Template\ModuleTemplate;
24
use TYPO3\CMS\Backend\Utility\BackendUtility;
25
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
26
use TYPO3\CMS\Core\Database\ConnectionPool;
27
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
28
use TYPO3\CMS\Core\DataHandling\DataHandler;
29
use TYPO3\CMS\Core\Http\HtmlResponse;
30
use TYPO3\CMS\Core\Imaging\Icon;
31
use TYPO3\CMS\Core\Imaging\IconFactory;
32
use TYPO3\CMS\Core\Localization\LanguageService;
33
use TYPO3\CMS\Core\Type\Bitmask\Permission;
34
use TYPO3\CMS\Core\Utility\GeneralUtility;
35
use TYPO3\CMS\Fluid\View\StandaloneView;
36
37
/**
38
 * "Sort sub pages" controller - reachable from context menu "more" on page records
39
 * @internal This class is a specific Backend controller implementation and is not considered part of the Public TYPO3 API.
40
 */
41
class SortSubPagesController
42
{
43
    /**
44
     * ModuleTemplate object
45
     *
46
     * @var ModuleTemplate
47
     */
48
    protected $moduleTemplate;
49
50
    /**
51
     * Constructor Method
52
     *
53
     * @var ModuleTemplate $moduleTemplate
54
     */
55
    public function __construct(ModuleTemplate $moduleTemplate = null)
56
    {
57
        $this->moduleTemplate = $moduleTemplate ?? GeneralUtility::makeInstance(ModuleTemplate::class);
58
    }
59
60
    /**
61
     * Main function Handling input variables and rendering main view
62
     *
63
     * @param ServerRequestInterface $request
64
     * @return ResponseInterface Response
65
     */
66
    public function mainAction(ServerRequestInterface $request): ResponseInterface
67
    {
68
        $backendUser = $this->getBackendUser();
69
        $parentPageUid = (int)$request->getQueryParams()['id'];
70
71
        // Show only if there is a valid page and if this page may be viewed by the user
72
        $pageInformation = BackendUtility::readPageAccess($parentPageUid, $backendUser->getPagePermsClause(Permission::PAGE_SHOW));
73
        if (!is_array($pageInformation)) {
74
            // User has no permission on parent page, should not happen, just render an empty page
75
            $this->moduleTemplate->setContent('');
76
            return new HtmlResponse($this->moduleTemplate->renderContent());
77
        }
78
79
        // Doc header handling
80
        $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
81
        $this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($pageInformation);
82
        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
83
        $cshButton = $buttonBar->makeHelpButton()
84
            ->setModuleName('pages_sort')
85
            ->setFieldName('pages_sort');
86
        $previewDataAttributes = PreviewUriBuilder::create($parentPageUid)
87
            ->withRootLine(BackendUtility::BEgetRootLine($parentPageUid))
88
            ->buildDispatcherDataAttributes();
89
        $viewButton = $buttonBar->makeLinkButton()
90
            ->setDataAttributes($previewDataAttributes ?? [])
91
            ->setTitle($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.showPage'))
92
            ->setIcon($iconFactory->getIcon('actions-view-page', Icon::SIZE_SMALL))
93
            ->setHref('#');
94
        $buttonBar->addButton($cshButton)->addButton($viewButton);
95
96
        // Main view setup
97
        $view = GeneralUtility::makeInstance(StandaloneView::class);
98
        $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName(
99
            'EXT:backend/Resources/Private/Templates/Page/SortSubPages.html'
100
        ));
101
102
        $isInWorkspace = $backendUser->workspace !== 0;
103
        $view->assign('isInWorkspace', $isInWorkspace);
104
        $view->assign('maxTitleLength', $backendUser->uc['titleLen'] ?? 20);
105
        $view->assign('parentPageUid', $parentPageUid);
106
        $view->assign('dateFormat', $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy']);
107
        $view->assign('timeFormat', $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm']);
108
109
        if (!$isInWorkspace) {
110
            // Apply new sorting if given
111
            $newSortBy = $request->getQueryParams()['newSortBy'] ?? null;
112
            if ($newSortBy && in_array($newSortBy, ['title', 'subtitle', 'nav_title', 'crdate', 'tstamp'], true)) {
113
                $this->sortSubPagesByField($parentPageUid, (string)$newSortBy);
114
            } elseif ($newSortBy && $newSortBy === 'reverseCurrentSorting') {
115
                $this->reverseSortingOfPages($parentPageUid);
116
            }
117
118
            // Get sub pages, loop through them and add page/user specific permission details
119
            $pageRecords = $this->getSubPagesOfPage($parentPageUid);
120
            $hasInvisiblePage = false;
121
            $subPages = [];
122
            foreach ($pageRecords as $page) {
123
                $pageWithPermissions = [];
124
                $pageWithPermissions['record'] = $page;
125
                $calculatedPermissions = new Permission($backendUser->calcPerms($page));
126
                $pageWithPermissions['canEdit'] = $backendUser->isAdmin() || $calculatedPermissions->editPagePermissionIsGranted();
127
                $canSeePage = $backendUser->isAdmin() || $calculatedPermissions->showPagePermissionIsGranted();
128
                if ($canSeePage) {
129
                    $subPages[] = $pageWithPermissions;
130
                } else {
131
                    $hasInvisiblePage = true;
132
                }
133
            }
134
            $view->assign('subPages', $subPages);
135
            $view->assign('hasInvisiblePage', $hasInvisiblePage);
136
        }
137
138
        $this->moduleTemplate->setContent($view->render());
139
        return new HtmlResponse($this->moduleTemplate->renderContent());
140
    }
141
142
    /**
143
     * Sort sub pages of given uid by field name alphabetically
144
     *
145
     * @param int $parentPageUid Parent page uid
146
     * @param string $newSortBy Field name to sort by
147
     * @throws \RuntimeException If $newSortBy does not validate
148
     */
149
    protected function sortSubPagesByField(int $parentPageUid, string $newSortBy)
150
    {
151
        if (!in_array($newSortBy, ['title', 'subtitle', 'nav_title', 'crdate', 'tstamp'], true)) {
152
            throw new \RuntimeException(
153
                'New sort by must be one of "title", "subtitle", "nav_title", "crdate" or tstamp',
154
                1498924810
155
            );
156
        }
157
        $subPages = $this->getSubPagesOfPage($parentPageUid, $newSortBy);
158
        if (!empty($subPages)) {
159
            $subPages = array_reverse($subPages);
160
            $this->persistNewSubPageOrder($parentPageUid, $subPages);
161
        }
162
    }
163
164
    /**
165
     * Reverse current sorting of sub pages
166
     *
167
     * @param int $parentPageUid Parent page uid
168
     */
169
    protected function reverseSortingOfPages(int $parentPageUid)
170
    {
171
        $subPages = $this->getSubPagesOfPage($parentPageUid);
172
        if (!empty($subPages)) {
173
            $this->persistNewSubPageOrder($parentPageUid, $subPages);
174
        }
175
    }
176
177
    /**
178
     * Store new sub page order
179
     *
180
     * @param int $parentPageUid Parent page uid
181
     * @param array $subPages List of sub pages in new order
182
     */
183
    protected function persistNewSubPageOrder(int $parentPageUid, array $subPages)
184
    {
185
        $commandArray = [];
186
        foreach ($subPages as $subPage) {
187
            $commandArray['pages'][$subPage['uid']]['move'] = $parentPageUid;
188
        }
189
        $dataHandler = GeneralUtility::makeInstance(DataHandler::class);
190
        $dataHandler->start([], $commandArray);
191
        $dataHandler->process_cmdmap();
192
        BackendUtility::setUpdateSignal('updatePageTree');
193
    }
194
195
    /**
196
     * Get a list of sub pages with some all fields from given page.
197
     * Fetch all data fields for full page icon display
198
     *
199
     * @param int $parentPageUid Get sub pages from this pages
200
     * @param string $orderBy Order pages by this field
201
     * @return array
202
     */
203
    protected function getSubPagesOfPage(int $parentPageUid, string $orderBy = 'sorting'): array
204
    {
205
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
206
        $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
207
        return $queryBuilder->select('*')
208
            ->from('pages')
209
            ->where(
210
                $queryBuilder->expr()->eq('sys_language_uid', 0),
211
                $queryBuilder->expr()->eq(
212
                    'pid',
213
                    $queryBuilder->createNamedParameter($parentPageUid, \PDO::PARAM_INT)
214
                )
215
            )
216
            ->orderBy($orderBy)
217
            ->execute()
218
            ->fetchAll();
219
    }
220
221
    /**
222
     * Returns LanguageService
223
     *
224
     * @return LanguageService
225
     */
226
    protected function getLanguageService()
227
    {
228
        return $GLOBALS['LANG'];
229
    }
230
231
    /**
232
     * Returns current BE user
233
     *
234
     * @return BackendUserAuthentication
235
     */
236
    protected function getBackendUser()
237
    {
238
        return $GLOBALS['BE_USER'];
239
    }
240
}
241