SolrIndexJob   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 187
Duplicated Lines 0 %

Test Coverage

Coverage 98.46%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 60
c 1
b 0
f 0
dl 0
loc 187
ccs 64
cts 65
cp 0.9846
rs 10
wmc 19

9 Methods

Rating   Name   Duplication   Size   Complexity  
A getTitle() 0 3 1
A getClassToIndex() 0 3 1
A process() 0 29 3
A configureRun() 0 12 4
A getIndexes() 0 3 1
A setIndexes() 0 5 1
A setClassToIndex() 0 5 1
A afterComplete() 0 17 2
A getNextSteps() 0 25 5
1
<?php
2
/**
3
 * class SolrIndexJob|Firesphere\SolrSearch\Jobs\SolrIndexJob Index items from the CMS through a QueuedJob
4
 *
5
 * @package Firesphere\Solr\Search
6
 * @author Simon `Firesphere` Erkelens; Marco `Sheepy` Hermo
7
 * @copyright Copyright (c) 2018 - now() Firesphere & Sheepy
8
 */
9
10
namespace Firesphere\SolrSearch\Jobs;
11
12
use Exception;
13
use Firesphere\SolrSearch\Services\SolrCoreService;
14
use Firesphere\SolrSearch\Tasks\SolrIndexTask;
15
use ReflectionException;
16
use SilverStripe\Control\Director;
17
use SilverStripe\Control\HTTPRequest;
18
use SilverStripe\Core\Injector\Injector;
19
use stdClass;
20
use Symbiote\QueuedJobs\Services\AbstractQueuedJob;
21
use Symbiote\QueuedJobs\Services\QueuedJobService;
22
use Solarium\Exception\HttpException;
23
24
/**
25
 * Class SolrIndexJob is a queued job to index all existing indexes and their classes.
26
 *
27
 * It always runs on all indexes, to make sure all indexes are up to date.
28
 *
29
 * @package Firesphere\Solr\Search
30
 */
31
class SolrIndexJob extends AbstractQueuedJob
32
{
33
34
    /**
35
     * The class that should be indexed.
36
     * If set, the task should run the given class with the given group
37
     * The class should be popped off the array at the end of each subset
38
     * so the next class becomes the class to index.
39
     *
40
     * Rinse and repeat for each class in the index, until this array is empty
41
     *
42
     * @var array
43
     */
44
    protected $classToIndex = [];
45
    /**
46
     * The indexes that need to run.
47
     *
48
     * @var array
49
     */
50
    protected $indexes;
51
52
    /**
53
     * My name
54
     *
55
     * @return string
56
     */
57 2
    public function getTitle()
58
    {
59 2
        return 'Index groups to Solr search';
60
    }
61
62
    /**
63
     * Process this job
64
     *
65
     * @return self
66
     * @throws Exception
67
     * @throws HTTPException
68
     */
69 1
    public function process()
70
    {
71 1
        $data = $this->jobData;
72
73 1
        $this->configureRun($data);
74
75 1
        $this->currentStep = $this->currentStep ?: 0;
76 1
        $index = Injector::inst()->get($this->indexes[0]);
77 1
        $this->classToIndex = count($this->classToIndex) ? $this->classToIndex : $index->getClasses();
78
        $indexArgs = [
79 1
            'group' => $this->currentStep,
80 1
            'index' => $this->indexes[0],
81 1
            'class' => $this->classToIndex[0],
82
        ];
83
        /** @var SolrIndexTask $task */
84 1
        $task = Injector::inst()->get(SolrIndexTask::class);
85 1
        $request = new HTTPRequest(
86 1
            'GET',
87 1
            '/dev/tasks/SolrIndexTask',
88 1
            $indexArgs
89
        );
90
91 1
        $result = $task->run($request);
92 1
        $this->totalSteps = $result;
93
        // If the result is false, the job should fail too
94
        // Thus, only set to true if the result isn't false :)
95 1
        $this->isComplete = true;
96
97
        return $this;
98 1
    }
99
100
    /**
101
     * Configure the run for the valid indexes
102
     *
103
     * @param stdClass|null $data
104
     */
105
    protected function configureRun($data)
106
    {
107 1
        // If null gets passed in, it goes a bit wonky with the check for indexes
108
        if (!$data) {
109
            $data = new stdClass();
110 1
            $data->indexes = null;
111 1
        }
112 1
        if (!isset($data->indexes) || !count($data->indexes)) { // If indexes are set, don't load them.
113
            $this->indexes = (new SolrCoreService())->getValidIndexes();
114 1
        } else {
115 1
            $this->setIndexes($data->indexes);
116
            $this->setClassToIndex($data->classToIndex);
117 1
        }
118 1
    }
119
120 1
    /**
121
     * Set up the next job if needed
122
     */
123
    public function afterComplete()
124
    {
125 1
        [$currentStep, $totalSteps] = $this->getNextSteps();
126
        // If there are no indexes left to run, let's call it a day
127 1
        if (count($this->indexes)) {
128
            $nextJob = new self();
129 1
            $jobData = new stdClass();
130 1
131 1
            $jobData->classToIndex = $this->getClassToIndex();
132
            $jobData->indexes = $this->getIndexes();
133 1
            $nextJob->setJobData($totalSteps, $currentStep, false, $jobData, []);
134 1
135 1
            // Add a wee break to let the system recover from this heavy operation
136
            Injector::inst()->get(QueuedJobService::class)
137
                ->queueJob($nextJob, date('Y-m-d H:i:00', strtotime('+1 minutes')));
138 1
        }
139 1
        parent::afterComplete();
140
    }
141 1
142 1
    /**
143
     * Get the next step to execute
144
     *
145
     * @return array
146
     */
147
    protected function getNextSteps(): array
148
    {
149 1
        $cores = SolrCoreService::config()->get('cpucores') ?: 1;
150
        // Force a single count for when the job is not run from CLI
151 1
        if (!Director::is_cli()) {
152
            $cores = 1;
153 1
        }
154
        $currentStep = $this->currentStep + $cores; // Add the amount of cores
155
        $totalSteps = $this->totalSteps;
156 1
        // No more steps to execute on this class, let's go to the next class
157 1
        if ($currentStep >= $totalSteps) {
158
            array_shift($this->classToIndex);
159 1
            // Reset the current step, a complete new set of data is coming
160 1
            $currentStep = 0;
161
            $totalSteps = 1;
162 1
        }
163 1
        // If there are no classes left in this index, go to the next index
164
        if (!count($this->classToIndex)) {
165
            array_shift($this->indexes);
166 1
            // Reset the current step, a complete new set of data is coming
167 1
            $currentStep = 0;
168
            $totalSteps = 1;
169 1
        }
170 1
171
        return [$currentStep, $totalSteps];
172
    }
173 1
174
    /**
175
     * Which Indexes should I index
176
     *
177
     * @return array
178
     */
179
    public function getClassToIndex(): array
180
    {
181 3
        return $this->classToIndex;
182
    }
183 3
184
    /**
185
     * Which classes should I index
186
     *
187
     * @param array $classToIndex
188
     * @return SolrIndexJob
189
     */
190
    public function setClassToIndex($classToIndex)
191
    {
192 3
        $this->classToIndex = $classToIndex;
193
194 3
        return $this;
195
    }
196 3
197
    /**
198
     * Get the indexes
199
     *
200
     * @return array
201
     */
202
    public function getIndexes(): array
203
    {
204 3
        return $this->indexes;
205
    }
206 3
207
    /**
208
     * Set the indexes if needed
209
     *
210
     * @param array $indexes
211
     * @return SolrIndexJob
212
     */
213
    public function setIndexes($indexes)
214
    {
215 3
        $this->indexes = $indexes;
216
217 3
        return $this;
218
    }
219
}
220