Passed
Push — master ( 0b1d58...abb35c )
by Timo
55s
created

ReIndexTaskAdditionalFieldProvider::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 0
cts 4
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
namespace ApacheSolrForTypo3\Solr\Task;
3
4
/***************************************************************
5
 *  Copyright notice
6
 *
7
 *  (c) 2011-2015 Christoph Moeller <[email protected]>
8
 *  (c) 2012-2015 Ingo Renner <[email protected]>
9
 *
10
 *  All rights reserved
11
 *
12
 *  This script is part of the TYPO3 project. The TYPO3 project is
13
 *  free software; you can redistribute it and/or modify
14
 *  it under the terms of the GNU General Public License as published by
15
 *  the Free Software Foundation; either version 2 of the License, or
16
 *  (at your option) any later version.
17
 *
18
 *  The GNU General Public License can be found at
19
 *  http://www.gnu.org/copyleft/gpl.html.
20
 *
21
 *  This script is distributed in the hope that it will be useful,
22
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 *  GNU General Public License for more details.
25
 *
26
 *  This copyright notice MUST APPEAR in all copies of the script!
27
 ***************************************************************/
28
29
use ApacheSolrForTypo3\Solr\Backend\IndexingConfigurationSelectorField;
30
use ApacheSolrForTypo3\Solr\Backend\SiteSelectorField;
31
use ApacheSolrForTypo3\Solr\Domain\Site\SiteRepository;
32
use ApacheSolrForTypo3\Solr\Site;
33
use TYPO3\CMS\Core\Page\PageRenderer;
34
use TYPO3\CMS\Core\Utility\GeneralUtility;
35
use TYPO3\CMS\Scheduler\AdditionalFieldProviderInterface;
36
use TYPO3\CMS\Scheduler\Controller\SchedulerModuleController;
37
use TYPO3\CMS\Scheduler\Task\AbstractTask;
38
39
/**
40
 * Adds an additional field to specify the Solr server to initialize the index queue for
41
 *
42
 * @author Christoph Moeller <[email protected]>
43
 */
44
class ReIndexTaskAdditionalFieldProvider implements AdditionalFieldProviderInterface
45
{
46
47
    /**
48
     * Task information
49
     *
50
     * @var array
51
     */
52
    protected $taskInformation;
53
54
    /**
55
     * Scheduler task
56
     *
57
     * @var AbstractTask|ReIndexTask|NULL
58
     */
59
    protected $task = null;
60
61
    /**
62
     * Scheduler Module
63
     *
64
     * @var SchedulerModuleController
65
     */
66
    protected $schedulerModule;
67
68
    /**
69
     * Selected site
70
     *
71
     * @var Site
72
     */
73
    protected $site = null;
74
75
76
    /**
77
     * SiteRepository
78
     *
79
     * @var SiteRepository
80
     */
81
    protected $siteRepository;
82
83
    /**
84
     * @var PageRenderer
85
     */
86
    protected $pageRenderer = null;
87
88
    /**
89
     * ReIndexTaskAdditionalFieldProvider constructor.
90
     */
91
    public function __construct()
92
    {
93
        $this->siteRepository = GeneralUtility::makeInstance(SiteRepository::class);
94
    }
95
96
    /**
97
     *
98
     * @param array $taskInfo
99
     * @param \TYPO3\CMS\Scheduler\Task\AbstractTask|NULL $task
100
     * @param \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $schedulerModule
101
     */
102
    protected function initialize(
103
        array $taskInfo = [],
104
        AbstractTask $task = null,
105
        SchedulerModuleController $schedulerModule
106
    ) {
107
        $this->taskInformation = $taskInfo;
108
        $this->task = $task;
109
        $this->schedulerModule = $schedulerModule;
110
111
        if ($schedulerModule->CMD == 'edit') {
112
            $this->site = $task->getSite();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class TYPO3\CMS\Scheduler\Task\AbstractTask as the method getSite() does only exist in the following sub-classes of TYPO3\CMS\Scheduler\Task\AbstractTask: ApacheSolrForTypo3\Solr\Task\IndexQueueWorkerTask, ApacheSolrForTypo3\Solr\Task\ReIndexTask. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
113
        }
114
    }
115
116
    /**
117
     * Used to define fields to provide the Solr server address when adding
118
     * or editing a task.
119
     *
120
     * @param array $taskInfo reference to the array containing the info used in the add/edit form
121
     * @param AbstractTask $task when editing, reference to the current task object. Null when adding.
122
     * @param SchedulerModuleController $schedulerModule reference to the calling object (Scheduler's BE module)
123
     * @return array Array containing all the information pertaining to the additional fields
124
     *                        The array is multidimensional, keyed to the task class name and each field's id
125
     *                        For each field it provides an associative sub-array with the following:
126
     */
127
    public function getAdditionalFields(
128
        array &$taskInfo,
129
        $task,
130
        SchedulerModuleController $schedulerModule
131
    ) {
132
        $additionalFields = [];
133
134
        if (!$this->isTaskInstanceofReIndexTask($task)) {
135
            return $additionalFields;
136
        }
137
138
        $this->initialize($taskInfo, $task, $schedulerModule);
139
        $siteSelectorField = GeneralUtility::makeInstance(SiteSelectorField::class);
140
141
        $additionalFields['site'] = [
142
            'code' => $siteSelectorField->getAvailableSitesSelector('tx_scheduler[site]',
143
                $this->site),
144
            'label' => 'LLL:EXT:solr/Resources/Private/Language/locallang.xlf:field_site',
145
            'cshKey' => '',
146
            'cshLabel' => ''
147
        ];
148
149
        $additionalFields['indexingConfigurations'] = [
150
            'code' => $this->getIndexingConfigurationSelector(),
151
            'label' => 'Index Queue configurations to re-index',
152
            'cshKey' => '',
153
            'cshLabel' => ''
154
        ];
155
156
        return $additionalFields;
157
    }
158
159
    protected function getIndexingConfigurationSelector()
160
    {
161
        $selectorMarkup = 'Please select a site first.';
162
        $this->getPageRenderer()->addCssFile('../typo3conf/ext/solr/Resources/Css/Backend/indexingconfigurationselectorfield.css');
163
164
        if (is_null($this->site)) {
165
            return $selectorMarkup;
166
        }
167
168
        $selectorField = GeneralUtility::makeInstance(IndexingConfigurationSelectorField::class, $this->site);
169
170
        $selectorField->setFormElementName('tx_scheduler[indexingConfigurations]');
171
        $selectorField->setSelectedValues($this->task->getIndexingConfigurationsToReIndex());
0 ignored issues
show
Bug introduced by
The method getIndexingConfigurationsToReIndex does only exist in ApacheSolrForTypo3\Solr\Task\ReIndexTask, but not in TYPO3\CMS\Scheduler\Task\AbstractTask.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
172
173
        $selectorMarkup = $selectorField->render();
174
175
        return $selectorMarkup;
176
    }
177
178
    /**
179
     * Checks any additional data that is relevant to this task. If the task
180
     * class is not relevant, the method is expected to return TRUE
181
     *
182
     * @param array $submittedData reference to the array containing the data submitted by the user
183
     * @param SchedulerModuleController $schedulerModule reference to the calling object (Scheduler's BE module)
184
     * @return bool True if validation was ok (or selected class is not relevant), FALSE otherwise
185
     */
186
    public function validateAdditionalFields(
187
        array &$submittedData,
188
        SchedulerModuleController $schedulerModule
189
    ) {
190
        $result = false;
191
192
        // validate site
193
        $sites = $this->siteRepository->getAvailableSites();
194
        if (array_key_exists($submittedData['site'], $sites)) {
195
            $result = true;
196
        }
197
198
        return $result;
199
    }
200
201
    /**
202
     * Saves any additional input into the current task object if the task
203
     * class matches.
204
     *
205
     * @param array $submittedData array containing the data submitted by the user
206
     * @param AbstractTask $task reference to the current task object
207
     */
208
    public function saveAdditionalFields(
209
        array $submittedData,
210
        AbstractTask $task
211
    ) {
212
        if (!$this->isTaskInstanceofReIndexTask($task)) {
213
            return;
214
        }
215
216
        $task->setSite($this->siteRepository->getSiteByRootPageId($submittedData['site']));
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class TYPO3\CMS\Scheduler\Task\AbstractTask as the method setSite() does only exist in the following sub-classes of TYPO3\CMS\Scheduler\Task\AbstractTask: ApacheSolrForTypo3\Solr\Task\IndexQueueWorkerTask, ApacheSolrForTypo3\Solr\Task\ReIndexTask. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
217
218
        $indexingConfigurations = [];
219
        if (!empty($submittedData['indexingConfigurations'])) {
220
            $indexingConfigurations = $submittedData['indexingConfigurations'];
221
        }
222
        $task->setIndexingConfigurationsToReIndex($indexingConfigurations);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class TYPO3\CMS\Scheduler\Task\AbstractTask as the method setIndexingConfigurationsToReIndex() does only exist in the following sub-classes of TYPO3\CMS\Scheduler\Task\AbstractTask: ApacheSolrForTypo3\Solr\Task\ReIndexTask. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
223
    }
224
225
    /**
226
     * @return PageRenderer
227
     */
228
    protected function getPageRenderer()
229
    {
230
        if (!isset($this->pageRenderer)) {
231
            $this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
232
        }
233
        return $this->pageRenderer;
234
    }
235
236
    /**
237
     * Check that a task is an instance of ReIndexTask
238
     *
239
     * @param AbstractTask $task
240
     * @return boolean
241
     * @throws \LogicException
242
     */
243
    protected function isTaskInstanceofReIndexTask($task)
244
    {
245
        if ((!is_null($task)) && (!($task instanceof ReIndexTask))) {
246
            throw new \LogicException(
247
                '$task must be an instance of ReIndexTask, '
248
                . 'other instances are not supported.', 1487500366
249
            );
250
        }
251
        return true;
252
    }
253
}
254