Failed Conditions
Push — task/2976_TYPO3.11_compatibili... ( 14c9f4...2d3a36 )
by Rafael
23:17
created

AbstractModuleController::setSelectedSite()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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

278
        /** @scrutinizer ignore-call */ 
279
        $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...
279
        foreach ($cores as $core) {
280
            $coreAdmin = $core->getAdminService();
281
            $menuItem = $this->coreSelectorMenu->makeMenuItem();
282
            $menuItem->setTitle($coreAdmin->getCorePath());
283
            $uri = $this->uriBuilder->reset()->uriFor(
284
                'switchCore',
285
                [
286
                    'corePath' => $coreAdmin->getCorePath(),
287
                    'uriToRedirectTo' => $uriToRedirectTo
288
                ]
289
            );
290
            $menuItem->setHref($uri);
291
292
            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

292
            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...
293
                $menuItem->setActive(true);
294
            }
295
            $this->coreSelectorMenu->addMenuItem($menuItem);
296
        }
297
298
        $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($this->coreSelectorMenu);
299
    }
300
301
    /**
302
     * Empties the Index Queue
303
     *
304
     * @return void
305
     *
306
     * @noinspection PhpUnused Used in IndexQueue- and IndexAdministration- controllers
307
     */
308
    public function clearIndexQueueAction(): ResponseInterface
309
    {
310
        $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

310
        $this->indexQueue->deleteItemsBySite(/** @scrutinizer ignore-type */ $this->selectedSite);
Loading history...
311
        $this->addFlashMessage(
312
            LocalizationUtility::translate(
313
                'solr.backend.index_administration.success.queue_emptied',
314
                'Solr',
315
                [$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

315
                [$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...
316
            )
317
        );
318
319
        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...
320
    }
321
322
    /**
323
     * Switches used core.
324
     *
325
     * Note: Does not check availability of core in site. All this stuff is done in the generation step.
326
     *
327
     * @param string $corePath
328
     * @param string $uriToRedirectTo
329
     * @return ResponseInterface
330
     */
331
    public function switchCoreAction(string $corePath, string $uriToRedirectTo): ResponseInterface
332
    {
333
        $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

333
        /** @scrutinizer ignore-call */ 
334
        $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...
334
        $moduleData->setCore($corePath);
335
336
        $this->moduleDataStorageService->persistModuleData($moduleData);
337
        $message = LocalizationUtility::translate('coreselector_switched_successfully', 'solr', [$corePath]);
338
        $this->addFlashMessage($message);
339
        return new RedirectResponse($uriToRedirectTo, 303);
340
    }
341
342
    /**
343
     * Initializes the solr core connection considerately to the components state.
344
     * Uses and persists default core connection if persisted core in Site does not exist.
345
     *
346
     */
347
    private function initializeSelectedSolrCoreConnection()
348
    {
349
        $moduleData = $this->moduleDataStorageService->loadModuleData();
350
351
        $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

351
        $solrCoreConnections = $this->solrConnectionManager->getConnectionsBySite(/** @scrutinizer ignore-type */ $this->selectedSite);
Loading history...
352
        $currentSolrCorePath = $moduleData->getCore();
353
        if (empty($currentSolrCorePath)) {
354
            $this->initializeFirstAvailableSolrCoreConnection($solrCoreConnections, $moduleData);
355
            return;
356
        }
357
        foreach ($solrCoreConnections as $solrCoreConnection) {
358
            if ($solrCoreConnection->getAdminService()->getCorePath() == $currentSolrCorePath) {
359
                $this->selectedSolrCoreConnection = $solrCoreConnection;
360
            }
361
        }
362
        if (!$this->selectedSolrCoreConnection instanceof SolrCoreConnection && count($solrCoreConnections) > 0) {
363
            $this->initializeFirstAvailableSolrCoreConnection($solrCoreConnections, $moduleData);
364
            $message = LocalizationUtility::translate('coreselector_switched_to_default_core', 'solr', [$currentSolrCorePath, $this->selectedSite->getLabel(), $this->selectedSolrCoreConnection->getAdminService()->getCorePath()]);
365
            $this->addFlashMessage($message, '', AbstractMessage::NOTICE);
366
        }
367
    }
368
369
    /**
370
     * @param SolrCoreConnection[] $solrCoreConnections
371
     */
372
    private function initializeFirstAvailableSolrCoreConnection(array $solrCoreConnections, $moduleData)
373
    {
374
        if (empty($solrCoreConnections)) {
375
            return;
376
        }
377
        $this->selectedSolrCoreConnection = $solrCoreConnections[0];
378
        $moduleData->setCore($this->selectedSolrCoreConnection->getAdminService()->getCorePath());
379
        $this->moduleDataStorageService->persistModuleData($moduleData);
380
    }
381
}
382