Completed
Push — master ( 818496...5be7b8 )
by
unknown
16:18
created

SortSubPagesController::mainAction()   B

Complexity

Conditions 11
Paths 5

Size

Total Lines 71
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Importance

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