Failed Conditions
Push — task/2976_TYPO3.11_compatibili... ( 165ace...c614ef )
by Rafael
43:34
created

autoSelectFirstSiteAndRootPageWhenOnlyOneSiteIsAvailable()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
eloc 8
dl 0
loc 15
ccs 0
cts 8
cp 0
rs 10
c 0
b 0
f 0
cc 4
nc 3
nop 0
crap 20
1
<?php
2
3
namespace ApacheSolrForTypo3\Solr\Controller\Backend\Search;
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
use ApacheSolrForTypo3\Solr\ConnectionManager;
19
use ApacheSolrForTypo3\Solr\Domain\Site\SiteRepository;
20
use ApacheSolrForTypo3\Solr\Domain\Site\Site;
21
use ApacheSolrForTypo3\Solr\IndexQueue\Queue;
22
use ApacheSolrForTypo3\Solr\System\Solr\SolrConnection as SolrCoreConnection;
23
use ApacheSolrForTypo3\Solr\System\Mvc\Backend\Component\Exception\InvalidViewObjectNameException;
24
use ApacheSolrForTypo3\Solr\System\Mvc\Backend\Service\ModuleDataStorageService;
25
use Doctrine\DBAL\Driver\Exception as DBALDriverException;
26
use InvalidArgumentException;
27
use Psr\Http\Message\ResponseInterface;
28
use Throwable;
29
use TYPO3\CMS\Backend\Template\Components\Menu\Menu;
30
use TYPO3\CMS\Backend\Template\ModuleTemplate;
31
use TYPO3\CMS\Backend\Template\ModuleTemplateFactory;
32
use TYPO3\CMS\Backend\Utility\BackendUtility;
33
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
34
use TYPO3\CMS\Core\Http\RedirectResponse;
35
use TYPO3\CMS\Core\Messaging\AbstractMessage;
36
use TYPO3\CMS\Core\Site\SiteFinder;
37
use TYPO3\CMS\Core\Utility\GeneralUtility;
38
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
39
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
40
use TYPO3Fluid\Fluid\View\ViewInterface;
41
42
/**
43
 * Abstract Module
44
 */
45
abstract class AbstractModuleController extends ActionController
46
{
47
    /**
48
     * In the pagetree selected page UID
49
     *
50
     * @var int
51
     */
52
    protected int $selectedPageUID;
53
54
    /**
55
     * Holds the requested page UID because the selected page uid,
56
     * might be overwritten by the automatic site selection.
57
     *
58
     * @var int
59
     */
60
    protected int $requestedPageUID;
61
62
    /**
63
     * @var ?Site
64
     */
65
    protected ?Site $selectedSite = null;
66
67
    /**
68
     * @var SiteRepository
69
     */
70
    protected SiteRepository $siteRepository;
71
72
    /**
73
     * @var SolrCoreConnection|null
74
     */
75
    protected ?SolrCoreConnection $selectedSolrCoreConnection = null;
76
77
    /**
78
     * @var Menu|null
79
     */
80
    protected ?Menu $coreSelectorMenu = null;
81
82
    /**
83
     * @var ConnectionManager|null
84
     */
85
    protected ?ConnectionManager $solrConnectionManager = null;
86
87
    /**
88
     * @var ModuleDataStorageService|null
89
     */
90
    protected ?ModuleDataStorageService $moduleDataStorageService = null;
91
92
    /**
93
     * @var Queue
94
     */
95
    protected Queue $indexQueue;
96
97
    /**
98
     * @var SiteFinder
99
     */
100
    protected SiteFinder $siteFinder;
101
102
    /**
103
     * @var ModuleTemplateFactory
104
     */
105
    protected ModuleTemplateFactory $moduleTemplateFactory;
106
107
    /**
108
     * @var ModuleTemplate
109
     */
110
    protected ModuleTemplate $moduleTemplate;
111
112
    /**
113
     * Constructor for dependency injection
114
     *
115
     * @param ModuleTemplateFactory $moduleTemplateFactory
116
     */
117
    public function __construct(ModuleTemplateFactory $moduleTemplateFactory) {
118
        $this->moduleTemplateFactory = $moduleTemplateFactory;
119
    }
120
121 3
    /**
122
     * @param Site $selectedSite
123 3
     */
124 3
    public function setSelectedSite(Site $selectedSite)
125
    {
126
        $this->selectedSite = $selectedSite;
127
    }
128
129
    /**
130
     * @param SiteRepository $siteRepository
131
     */
132
    public function injectSiteRepository(SiteRepository $siteRepository)
133
    {
134
        $this->siteRepository = $siteRepository;
135
    }
136
137
    /**
138
     * Initializes the controller and sets needed vars.
139
     * @todo: Make DI for class properties.
140
     */
141
    protected function initializeAction()
142
    {
143
        parent::initializeAction();
144
        $this->indexQueue = GeneralUtility::makeInstance(Queue::class);
145
        $this->solrConnectionManager = GeneralUtility::makeInstance(ConnectionManager::class);
146
        $this->moduleDataStorageService = GeneralUtility::makeInstance(ModuleDataStorageService::class);
147
        $this->siteFinder = GeneralUtility::makeInstance(SiteFinder::class);
148
149
        $this->selectedPageUID = (int)GeneralUtility::_GP('id');
150
        if ($this->request->hasArgument('id')) {
151
            $this->selectedPageUID = (int)$this->request->getArgument('id');
152
        }
153
154
        $this->requestedPageUID = $this->selectedPageUID;
155
156
        if ($this->autoSelectFirstSiteAndRootPageWhenOnlyOneSiteIsAvailable()) {
157
            return;
158
        }
159
160
        if ($this->selectedPageUID < 1) {
161
            return;
162
        }
163
164
        try {
165
            $this->selectedSite = $this->siteRepository->getSiteByPageId($this->selectedPageUID);
166
        } catch (InvalidArgumentException $exception) {
167
            return;
168
        }
169
    }
170
171
    /**
172
     * @return bool
173
     */
174
    protected function autoSelectFirstSiteAndRootPageWhenOnlyOneSiteIsAvailable(): bool
175
    {
176
        $solrConfiguredSites = $this->siteRepository->getAvailableSites();
177
        $availableSites = $this->siteFinder->getAllSites();
178
        if (count($solrConfiguredSites) === 1 && count($availableSites) === 1) {
179
            $this->selectedSite = $this->siteRepository->getFirstAvailableSite();
180
181
            // we only overwrite the selected pageUid when no id was passed
182
            if ($this->selectedPageUID === 0) {
183
                $this->selectedPageUID = $this->selectedSite->getRootPageId();
184
            }
185
            return true;
186
        }
187
188
        return false;
189
    }
190
191
    /**
192
     * Set up the doc header properly here
193
     *
194
     * @param ViewInterface $view
195
     * @return void
196
     * @throws DBALDriverException
197
     * @throws Throwable
198
     */
199
    protected function initializeView($view)
200
    {
201
        $sites = $this->siteRepository->getAvailableSites();
202
203
        $selectOtherPage = count($sites) > 0 || $this->selectedPageUID < 1;
204
        $this->view->assign('showSelectOtherPage', $selectOtherPage);
205
        $this->view->assign('pageUID', $this->selectedPageUID);
206
        if ($this->selectedPageUID < 1) {
207
            return;
208
        }
209
        $this->moduleTemplate = $this->moduleTemplateFactory->create($this->request);
210
        $this->moduleTemplate->addJavaScriptCode('mainJsFunctions', '
211
                top.fsMod.recentIds["searchbackend"] = ' . (int)$this->selectedPageUID . ';'
212
        );
213
        if (null === $this->selectedSite) {
214
            return;
215
        }
216
217
        /* @var BackendUserAuthentication $beUser */
218
        $beUser = $GLOBALS['BE_USER'];
219
        $permissionClause = $beUser->getPagePermsClause(1);
220
        $pageRecord = BackendUtility::readPageAccess($this->selectedSite->getRootPageId(), $permissionClause);
221
222
        if (false === $pageRecord) {
223
            throw new InvalidArgumentException(vsprintf('There is something wrong with permissions for page "%s" for backend user "%s".', [$this->selectedSite->getRootPageId(), $beUser->user['username']]), 1496146317);
224
        }
225
        $this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($pageRecord);
226
    }
227
228
    /**
229
     * Generates selector menu in backends doc header using selected page from page tree.
230
     *
231
     * @param string|null $uriToRedirectTo
232
     * @throws InvalidViewObjectNameException
233
     */
234
    public function generateCoreSelectorMenuUsingPageTree(string $uriToRedirectTo = null)
235
    {
236
        if ($this->selectedPageUID < 1 || null === $this->selectedSite) {
237
            return;
238
        }
239
240
        $this->generateCoreSelectorMenu($this->selectedSite, $uriToRedirectTo);
241
    }
242
243
    /**
244
     * Generates Core selector Menu for given Site.
245
     *
246
     * @param Site $site
247
     * @param string|null $uriToRedirectTo
248
     */
249
    protected function generateCoreSelectorMenu(Site $site, string $uriToRedirectTo = null)
250
    {
251
        $this->coreSelectorMenu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
252
        $this->coreSelectorMenu->setIdentifier('component_core_selector_menu');
253
254
        if (!isset($uriToRedirectTo)) {
255
            $uriToRedirectTo = $this->uriBuilder->reset()->uriFor();
256
        }
257
258
        $this->initializeSelectedSolrCoreConnection();
259
        $cores = $this->solrConnectionManager->getConnectionsBySite($site);
0 ignored issues
show
Bug introduced by
The method getConnectionsBySite() does not exist on null. ( Ignorable by Annotation )

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

259
        /** @scrutinizer ignore-call */ 
260
        $cores = $this->solrConnectionManager->getConnectionsBySite($site);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
260
        foreach ($cores as $core) {
261
            $coreAdmin = $core->getAdminService();
262
            $menuItem = $this->coreSelectorMenu->makeMenuItem();
263
            $menuItem->setTitle($coreAdmin->getCorePath());
264
            $uri = $this->uriBuilder->reset()->uriFor('switchCore',
265
                [
266
                    'corePath' => $coreAdmin->getCorePath(),
267
                    'uriToRedirectTo' => $uriToRedirectTo
268
                ]
269
            );
270
            $menuItem->setHref($uri);
271
272
            if ($coreAdmin->getCorePath() == $this->selectedSolrCoreConnection->getAdminService()->getCorePath()) {
0 ignored issues
show
Bug introduced by
The method getAdminService() does not exist on null. ( Ignorable by Annotation )

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

272
            if ($coreAdmin->getCorePath() == $this->selectedSolrCoreConnection->/** @scrutinizer ignore-call */ getAdminService()->getCorePath()) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
273
                $menuItem->setActive(true);
274
            }
275
            $this->coreSelectorMenu->addMenuItem($menuItem);
276
        }
277
278
        $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($this->coreSelectorMenu);
279
    }
280
281
    /**
282
     * Empties the Index Queue
283
     *
284
     * @return void
285
     *
286
     * @noinspection PhpUnused Used in IndexQueue- and IndexAdministration- controllers
287
     */
288
    public function clearIndexQueueAction(): ResponseInterface
289
    {
290
        $this->indexQueue->deleteItemsBySite($this->selectedSite);
0 ignored issues
show
Bug introduced by
It seems like $this->selectedSite can also be of type null; however, parameter $site of ApacheSolrForTypo3\Solr\...ue::deleteItemsBySite() does only seem to accept ApacheSolrForTypo3\Solr\Domain\Site\Site, 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

290
        $this->indexQueue->deleteItemsBySite(/** @scrutinizer ignore-type */ $this->selectedSite);
Loading history...
291
        $this->addFlashMessage(
292
            LocalizationUtility::translate('solr.backend.index_administration.success.queue_emptied', 'Solr',
293
                [$this->selectedSite->getLabel()])
0 ignored issues
show
Bug introduced by
The method getLabel() does not exist on null. ( Ignorable by Annotation )

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

293
                [$this->selectedSite->/** @scrutinizer ignore-call */ getLabel()])

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
294
        );
295
296
        return new RedirectResponse($this->uriBuilder->uriFor('index'), 303);
0 ignored issues
show
Bug Best Practice introduced by
The expression return new TYPO3\CMS\Cor...->uriFor('index'), 303) returns the type TYPO3\CMS\Core\Http\RedirectResponse which is incompatible with the documented return type void.
Loading history...
297
    }
298
299
    /**
300
     * Switches used core.
301
     *
302
     * Note: Does not check availability of core in site. All this stuff is done in the generation step.
303
     *
304
     * @param string $corePath
305
     * @param string $uriToRedirectTo
306
     * @return ResponseInterface
307
     */
308
    public function switchCoreAction(string $corePath, string $uriToRedirectTo): ResponseInterface
309
    {
310
        $moduleData = $this->moduleDataStorageService->loadModuleData();
0 ignored issues
show
Bug introduced by
The method loadModuleData() does not exist on null. ( Ignorable by Annotation )

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

310
        /** @scrutinizer ignore-call */ 
311
        $moduleData = $this->moduleDataStorageService->loadModuleData();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
311
        $moduleData->setCore($corePath);
312
313
        $this->moduleDataStorageService->persistModuleData($moduleData);
314
        $message = LocalizationUtility::translate('coreselector_switched_successfully', 'solr', [$corePath]);
315
        $this->addFlashMessage($message);
316
        return new RedirectResponse($uriToRedirectTo, 303);
317
    }
318
319
    /**
320
     * Initializes the solr core connection considerately to the components state.
321
     * Uses and persists default core connection if persisted core in Site does not exist.
322
     *
323
     */
324
    private function initializeSelectedSolrCoreConnection()
325
    {
326
        $moduleData = $this->moduleDataStorageService->loadModuleData();
327
328
        $solrCoreConnections = $this->solrConnectionManager->getConnectionsBySite($this->selectedSite);
0 ignored issues
show
Bug introduced by
It seems like $this->selectedSite can also be of type null; however, parameter $site of ApacheSolrForTypo3\Solr\...:getConnectionsBySite() does only seem to accept ApacheSolrForTypo3\Solr\Domain\Site\Site, 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

328
        $solrCoreConnections = $this->solrConnectionManager->getConnectionsBySite(/** @scrutinizer ignore-type */ $this->selectedSite);
Loading history...
329
        $currentSolrCorePath = $moduleData->getCore();
330
        if (empty($currentSolrCorePath)) {
331
            $this->initializeFirstAvailableSolrCoreConnection($solrCoreConnections, $moduleData);
332
            return;
333
        }
334
        foreach ($solrCoreConnections as $solrCoreConnection) {
335
            if ($solrCoreConnection->getAdminService()->getCorePath() == $currentSolrCorePath) {
336
                $this->selectedSolrCoreConnection = $solrCoreConnection;
337
            }
338
        }
339
        if (!$this->selectedSolrCoreConnection instanceof SolrCoreConnection && count($solrCoreConnections) > 0) {
340
            $this->initializeFirstAvailableSolrCoreConnection($solrCoreConnections, $moduleData);
341
            $message = LocalizationUtility::translate('coreselector_switched_to_default_core', 'solr', [$currentSolrCorePath, $this->selectedSite->getLabel(), $this->selectedSolrCoreConnection->getAdminService()->getCorePath()]);
342
            $this->addFlashMessage($message, '', AbstractMessage::NOTICE);
343
        }
344
    }
345
346
    /**
347
     * @param SolrCoreConnection[] $solrCoreConnections
348
     */
349
    private function initializeFirstAvailableSolrCoreConnection(array $solrCoreConnections, $moduleData)
350
    {
351
        if (empty($solrCoreConnections)) {
352
            return;
353
        }
354
        $this->selectedSolrCoreConnection = $solrCoreConnections[0];
355
        $moduleData->setCore($this->selectedSolrCoreConnection->getAdminService()->getCorePath());
356
        $this->moduleDataStorageService->persistModuleData($moduleData);
357
    }
358
}
359