Passed
Push — master ( 8d6a0a...7f13ff )
by Timo
32:07 queued 24s
created

isTaskInstanceofReIndexTask()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 0
cts 0
cp 0
rs 9.6666
c 0
b 0
f 0
cc 3
eloc 5
nc 2
nop 1
crap 12
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\Site;
31
use TYPO3\CMS\Core\Page\PageRenderer;
32
use TYPO3\CMS\Core\Utility\GeneralUtility;
33
use TYPO3\CMS\Scheduler\AdditionalFieldProviderInterface;
34
use TYPO3\CMS\Scheduler\Controller\SchedulerModuleController;
35
use TYPO3\CMS\Scheduler\Task\AbstractTask;
36
37
/**
38
 * Adds an additional field to specify the Solr server to initialize the index queue for
39
 *
40
 * @author Christoph Moeller <[email protected]>
41
 */
42
class ReIndexTaskAdditionalFieldProvider implements AdditionalFieldProviderInterface
43
{
44
45
    /**
46
     * Task information
47
     *
48
     * @var array
49
     */
50
    protected $taskInformation;
51
52
    /**
53
     * Scheduler task
54
     *
55
     * @var AbstractTask|ReIndexTask|NULL
56
     */
57
    protected $task = null;
58
59
    /**
60
     * Scheduler Module
61
     *
62
     * @var SchedulerModuleController
63
     */
64
    protected $schedulerModule;
65
66
    /**
67
     * Selected site
68
     *
69
     * @var Site
70
     */
71
    protected $site = null;
72
73
    /**
74
     * @var PageRenderer
75
     */
76
    protected $pageRenderer = null;
77
78
    /**
79
     *
80
     * @param array $taskInfo
81
     * @param \TYPO3\CMS\Scheduler\Task\AbstractTask|NULL $task
82
     * @param \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $schedulerModule
83
     */
84
    protected function initialize(
85
        array $taskInfo,
86
        AbstractTask $task = null,
87
        SchedulerModuleController $schedulerModule
88
    ) {
89
        $this->taskInformation = $taskInfo;
90
        $this->task = $task;
91
        $this->schedulerModule = $schedulerModule;
92
93
        if ($schedulerModule->CMD == 'edit') {
94
            $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...
95
        }
96
    }
97
98
    /**
99
     * Used to define fields to provide the Solr server address when adding
100
     * or editing a task.
101
     *
102
     * @param array $taskInfo reference to the array containing the info used in the add/edit form
103
     * @param AbstractTask $task when editing, reference to the current task object. Null when adding.
104
     * @param SchedulerModuleController $schedulerModule reference to the calling object (Scheduler's BE module)
105
     * @return array Array containing all the information pertaining to the additional fields
106
     *                        The array is multidimensional, keyed to the task class name and each field's id
107
     *                        For each field it provides an associative sub-array with the following:
108
     */
109
    public function getAdditionalFields(
110
        array &$taskInfo,
111
        $task,
112
        SchedulerModuleController $schedulerModule
113
    ) {
114
        $this->isTaskInstanceofReIndexTask($task);
115
116
        $this->initialize($taskInfo, $task, $schedulerModule);
117
        $additionalFields = [];
118
119
        $additionalFields['site'] = [
120
            'code' => Site::getAvailableSitesSelector('tx_scheduler[site]',
121
                $this->site),
122
            'label' => 'LLL:EXT:solr/Resources/Private/Language/locallang.xlf:field_site',
123
            'cshKey' => '',
124
            'cshLabel' => ''
125
        ];
126
127
        $additionalFields['indexingConfigurations'] = [
128
            'code' => $this->getIndexingConfigurationSelector(),
129
            'label' => 'Index Queue configurations to re-index',
130
            'cshKey' => '',
131
            'cshLabel' => ''
132
        ];
133
134
        return $additionalFields;
135
    }
136
137
    protected function getIndexingConfigurationSelector()
138
    {
139
        $selectorMarkup = 'Please select a site first.';
140
        $this->getPageRenderer()->addCssFile('../typo3conf/ext/solr/Resources/Css/Backend/indexingconfigurationselectorfield.css');
141
142
        if (is_null($this->site)) {
143
            return $selectorMarkup;
144
        }
145
146
        $selectorField = GeneralUtility::makeInstance(IndexingConfigurationSelectorField::class, $this->site);
147
148
        $selectorField->setFormElementName('tx_scheduler[indexingConfigurations]');
149
        $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...
150
151
        $selectorMarkup = $selectorField->render();
152
153
        return $selectorMarkup;
154
    }
155
156
    /**
157
     * Checks any additional data that is relevant to this task. If the task
158
     * class is not relevant, the method is expected to return TRUE
159
     *
160
     * @param array $submittedData reference to the array containing the data submitted by the user
161
     * @param SchedulerModuleController $schedulerModule reference to the calling object (Scheduler's BE module)
162
     * @return bool True if validation was ok (or selected class is not relevant), FALSE otherwise
163
     */
164
    public function validateAdditionalFields(
165
        array &$submittedData,
166
        SchedulerModuleController $schedulerModule
167
    ) {
168
        $result = false;
169
170
        // validate site
171
        $sites = Site::getAvailableSites();
172
        if (array_key_exists($submittedData['site'], $sites)) {
173
            $result = true;
174
        }
175
176
        return $result;
177
    }
178
179
    /**
180
     * Saves any additional input into the current task object if the task
181
     * class matches.
182
     *
183
     * @param array $submittedData array containing the data submitted by the user
184
     * @param AbstractTask $task reference to the current task object
185
     */
186
    public function saveAdditionalFields(
187
        array $submittedData,
188
        AbstractTask $task
189
    ) {
190
        $this->isTaskInstanceofReIndexTask($task);
191
192
        $task->setSite(GeneralUtility::makeInstance(Site::class, $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...
193
194
        $indexingConfigurations = [];
195
        if (!empty($submittedData['indexingConfigurations'])) {
196
            $indexingConfigurations = $submittedData['indexingConfigurations'];
197
        }
198
        $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...
199
    }
200
201
    /**
202
     * @return PageRenderer
203
     */
204
    protected function getPageRenderer()
205
    {
206
        if (!isset($this->pageRenderer)) {
207
            $this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
208
        }
209
        return $this->pageRenderer;
210
    }
211
212
    /**
213
     * Check that a task is an instance of ReIndexTask
214
     *
215
     * @param $task
216
     * @throws \LogicException
217
     */
218
    protected function isTaskInstanceofReIndexTask($task)
219
    {
220
        if ((!is_null($task)) && (!($task instanceof ReIndexTask))) {
221
            throw new \LogicException(
222
                '$task must be an instance of ReIndexTask, '
223
                . 'other instances are not supported.', 1487500366
224
            );
225
        }
226
    }
227
}
228