Passed
Push — sheepy/introspection ( 69e16c...c6c7ca )
by Marco
05:28
created

SolrIndexTask::getLogger()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 2

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 3
c 3
b 0
f 0
dl 0
loc 8
rs 10
ccs 1
cts 1
cp 1
cc 2
nc 2
nop 0
crap 2
1
<?php
2
3
4
namespace Firesphere\SolrSearch\Tasks;
5
6
use Exception;
7
use Firesphere\SolrSearch\Factories\DocumentFactory;
8
use Firesphere\SolrSearch\Indexes\BaseIndex;
9
use Firesphere\SolrSearch\Services\SolrCoreService;
10
use Firesphere\SolrSearch\Traits\LoggerTrait;
11
use GuzzleHttp\Exception\RequestException;
12
use Psr\Log\LoggerInterface;
13
use SilverStripe\Control\Director;
14
use SilverStripe\Control\HTTPRequest;
15
use SilverStripe\Core\Injector\Injector;
16
use SilverStripe\Dev\BuildTask;
17
use SilverStripe\ORM\ArrayList;
18
use SilverStripe\ORM\DataList;
19
use SilverStripe\ORM\DataObject;
20
use SilverStripe\Versioned\Versioned;
21
22
class SolrIndexTask extends BuildTask
23
{
24
    use LoggerTrait;
25
    /**
26
     * @var string
27
     */
28
    private static $segment = 'SolrIndexTask';
29
30
    /**
31
     * @var string
32
     */
33
    protected $title = 'Solr Index update';
34
35
    /**
36
     * @var string
37
     */
38
    protected $description = 'Add or update documents to an existing Solr core.';
39
40
    /**
41
     * @var bool
42
     */
43
    protected $debug = false;
44
45
    /**
46
     * @var SolrCoreService
47
     */
48
    protected $service;
49
50
    /**
51
     * SolrIndexTask constructor. Sets up the document factory
52
     */
53
    public function __construct()
54
    {
55
        parent::__construct();
56 13
        // Only index live items.
57
        // The old FTS module also indexed Draft items. This is unnecessary
58 13
        Versioned::set_reading_mode(Versioned::DRAFT . '.' . Versioned::LIVE);
59
        $this->setService(Injector::inst()->get(SolrCoreService::class));
60
        $this->setLogger(Injector::inst()->get(LoggerInterface::class));
61 13
        $this->setDebug(Director::isDev() || Director::is_cli());
62 13
    }
63 13
64 13
    /**
65 13
     * @param SolrCoreService $service
66
     * @return SolrIndexTask
67
     */
68
    public function setService(SolrCoreService $service): SolrIndexTask
69
    {
70
        $this->service = $service;
71 13
72
        return $this;
73 13
    }
74
75 13
    /**
76
     * @param bool $debug
77
     * @return SolrIndexTask
78
     */
79
    public function setDebug(bool $debug): SolrIndexTask
80
    {
81
        $this->debug = $debug;
82 13
83
        return $this;
84 13
    }
85
86 13
    /**
87
     * Implement this method in the task subclass to
88
     * execute via the TaskRunner
89
     *
90
     * @param HTTPRequest $request
91
     * @return int|bool
92
     * @throws Exception
93
     * @todo defer to background because it may run out of memory
94
     */
95
    public function run($request)
96
    {
97
        $startTime = time();
98 12
        [$vars, $group, $isGroup] = $this->taskSetup($request);
99
        $groups = 0;
100 12
        $indexes = $this->service->getValidIndexes($request->getVar('index'));
101 12
102 12
        foreach ($indexes as $indexName) {
103 12
            /** @var BaseIndex $index */
104
            $index = Injector::inst()->get($indexName);
105 12
106
            $indexClasses = $index->getClasses();
107 12
            $classes = $this->getClasses($vars, $indexClasses);
108
            if (!count($classes)) {
109 12
                continue;
110 12
            }
111 12
112
            $vars = $this->clearIndex($vars, $indexName, $index);
113
114
            $groups = $this->indexClassForIndex($classes, $isGroup, $index, $group);
115 12
        }
116 1
        $this->getLogger()->info(
117 1
            sprintf('It took me %d seconds to do all the indexing%s', (time() - $startTime), PHP_EOL)
118
        );
119
120 12
        return $groups;
121 12
    }
122
123
    /**
124 12
     * @param HTTPRequest $request
125 12
     * @return array
126
     */
127
    protected function taskSetup($request): array
128 12
    {
129
        $vars = $request->getVars();
130
        $this->debug = $this->debug || isset($vars['debug']);
131
        $group = $vars['group'] ?? 0;
132
        $start = $vars['start'] ?? 0;
133
        $group = ($start > $group) ? $start : $group;
134
        $isGroup = isset($vars['group']);
135 12
136
        return [$vars, $group, $isGroup];
137 12
    }
138 12
139 12
    /**
140 12
     * @param $vars
141 12
     * @param array $classes
142 12
     * @return bool|array
143
     */
144 12
    protected function getClasses($vars, array $classes): array
145
    {
146
        if (isset($vars['class'])) {
147
            return array_intersect($classes, [$vars['class']]);
148
        }
149
150
        return $classes;
151
    }
152 12
153
    /**
154 12
     * @param $vars
155 1
     * @param $indexName
156
     * @param BaseIndex $index
157
     * @return mixed
158 11
     * @throws Exception
159
     */
160
    protected function clearIndex($vars, $indexName, BaseIndex $index)
161
    {
162
        if (!empty($vars['clear'])) {
163
            $this->getLogger()->info(sprintf('Clearing index %s', $indexName));
164 13
            $this->service->doManipulate(ArrayList::create([]), SolrCoreService::DELETE_TYPE_ALL, $index);
165
        }
166
167 13
        return $vars;
168 1
    }
169
170
    /**
171 13
     * @param $classes
172
     * @param $isGroup
173
     * @param BaseIndex $index
174
     * @param $group
175
     * @return int
176
     * @throws Exception
177
     */
178 13
    protected function indexClassForIndex($classes, $isGroup, BaseIndex $index, $group): int
179
    {
180 13
        $groups = 0;
181
        foreach ($classes as $class) {
182 13
            $groups = $this->indexClass($isGroup, $class, $index, $group);
183
        }
184
185
        return $groups;
186
    }
187
188
    /**
189
     * @param bool $isGroup
190
     * @param string $class
191
     * @param BaseIndex $index
192
     * @param int $group
193 12
     * @return int
194
     * @throws Exception
195 12
     */
196
    private function indexClass($isGroup, $class, BaseIndex $index, int $group): int
197 12
    {
198 12
        $this->getLogger()->info(sprintf('Indexing %s for %s', $class, $index->getIndexName()), []);
199 12
200
        $batchLength = DocumentFactory::config()->get('batchLength');
201 12
        $groups = (int)ceil($class::get()->count() / $batchLength);
202 12
        $groups = $isGroup ? $group : $groups;
203
        while ($group <= $groups) { // Run from oldest to newest
204
            try {
205
                $this->doReindex($group, $class, $batchLength, $index);
206
            } catch (Exception $e) {
207
                $this->getLogger()->error($e->getMessage());
208 12
                continue;
209 2
            }
210
            $group++;
211 11
            $this->getLogger()->info(sprintf('Indexed group %s', $group));
212
        }
213
214 12
        return $groups;
215
    }
216
217
    /**
218
     * @param int $group
219
     * @param string $class
220
     * @param int $batchLength
221
     * @param BaseIndex $index
222
     * @throws Exception
223
     */
224 12
    private function doReindex($group, $class, $batchLength, BaseIndex $index): void
225
    {
226
        // Generate filtered list of local records
227 12
        $baseClass = DataObject::getSchema()->baseDataClass($class);
228 12
        $client = $index->getClient();
229 12
        /** @var DataList|DataObject[] $items */
230
        $items = DataObject::get($baseClass)
231 12
            ->sort('ID ASC')
232 12
            ->limit($batchLength, ($group * $batchLength));
233 12
        $update = $client->createUpdate();
234 12
        if ($items->count()) {
235 12
            $this->service->setInDebugMode($this->debug);
236 12
            $this->service->updateIndex($index, $items, $update);
237 11
            $update->addCommit();
238 11
            $client->update($update);
239 11
        }
240 11
    }
241
}
242