Passed
Push — hans/code-cleaning ( c70517...3be4e2 )
by Simon
04:40
created

SolrConfigureTask::getMethod()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 14
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 5
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 14
ccs 6
cts 6
cp 1
crap 4
rs 10
1
<?php
2
/**
3
 * Class SolrConfigureTask|Firesphere\SolrSearch\Tasks\SolrConfigureTask Configure Solr cores
4
 *
5
 * @package Firesphere\SolrSearch\Tasks
6
 * @author Simon `Firesphere` Erkelens; Marco `Sheepy` Hermo
7
 * @copyright Copyright (c) 2018 - now() Firesphere & Sheepy
8
 */
9
10
namespace Firesphere\SolrSearch\Tasks;
11
12
use Exception;
13
use Firesphere\SolrSearch\Helpers\SolrLogger;
14
use Firesphere\SolrSearch\Indexes\BaseIndex;
15
use Firesphere\SolrSearch\Interfaces\ConfigStore;
16
use Firesphere\SolrSearch\Services\SolrCoreService;
17
use Firesphere\SolrSearch\Stores\FileConfigStore;
18
use Firesphere\SolrSearch\Stores\PostConfigStore;
19
use Firesphere\SolrSearch\Traits\LoggerTrait;
20
use GuzzleHttp\Exception\GuzzleException;
21
use ReflectionException;
22
use SilverStripe\Control\HTTPRequest;
23
use SilverStripe\Core\Injector\Injector;
24
use SilverStripe\Dev\BuildTask;
25
use SilverStripe\ORM\ValidationException;
26
27
/**
28
 * Class SolrConfigureTask
29
 *
30
 * @package Firesphere\SolrSearch\Tasks
31
 */
32
class SolrConfigureTask extends BuildTask
33
{
34
    use LoggerTrait;
35
36
    /**
37
     * @var array Available stores
38
     */
39
    protected static $storeModes = [
40
        'file' => FileConfigStore::class,
41
        'post' => PostConfigStore::class,
42
        //        'webdav' => WebdavConfigStore::class,
43
    ];
44
    /**
45
     * @var string URLSegment
46
     */
47
    private static $segment = 'SolrConfigureTask';
48
    /**
49
     * @var string Title
50
     */
51
    protected $title = 'Configure Solr cores';
52
    /**
53
     * @var string Description
54
     */
55
    protected $description = 'Create or reload a Solr Core by adding or reloading a configuration.';
56
57
    /**
58
     * SolrConfigureTask constructor.
59
     */
60 36
    public function __construct()
61
    {
62 36
        parent::__construct();
63 36
    }
64
65
    /**
66
     * Implement this method in the task subclass to
67
     * execute via the TaskRunner
68
     *
69
     * @param HTTPRequest $request Current request
70
     * @return bool|Exception
71
     * @throws ReflectionException
72
     * @throws ValidationException
73
     * @throws GuzzleException
74
     */
75 35
    public function run($request)
76
    {
77 35
        $this->extend('onBeforeSolrConfigureTask', $request);
78
79 35
        $indexes = (new SolrCoreService())->getValidIndexes();
80
81 35
        foreach ($indexes as $index) {
82
            try {
83 35
                $this->configureIndex($index);
84
            } catch (Exception $error) {
85
                // @codeCoverageIgnoreStart
86
                $this->logException($index, $error);
87
                $this->getLogger()->error(sprintf('Core loading failed for %s', $index));
88
                $this->getLogger()->error($error->getMessage()); // in browser mode, it might not always show
89
                // Continue to the next index
90
                continue;
91
                // @codeCoverageIgnoreEnd
92
            }
93 35
            $this->extend('onAfterConfigureIndex', $index);
94
        }
95
96 35
        $this->extend('onAfterSolrConfigureTask');
97
        // Grab the latest logs
98 35
        $solrLogger = new SolrLogger();
99 35
        $solrLogger->saveSolrLog('Config');
100
101 35
        return true;
102
    }
103
104
    /**
105
     * Update the index on the given store
106
     *
107
     * @param string $index Core to index
108
     * @throws ValidationException
109
     * @throws GuzzleException
110
     */
111 35
    protected function configureIndex($index): void
112
    {
113
        /** @var BaseIndex $instance */
114 35
        $instance = Injector::inst()->get($index, false);
115
116 35
        $index = $instance->getIndexName();
117
118
        // Then tell Solr to use those config files
119
        /** @var SolrCoreService $service */
120 35
        $service = Injector::inst()->get(SolrCoreService::class);
121
122 35
        $configStore = $this->createConfigForIndex($instance);
123 35
        $method = $this->getMethod($index, $service);
124 35
        $service->$method($index, $configStore);
125 35
        $this->getLogger()->info(sprintf('Core %s successfully loaded', $index));
126 35
    }
127
128
    /**
129
     * Get the config and load it to Solr
130
     *
131
     * @param BaseIndex $instance
132
     * @return ConfigStore
133
     */
134 35
    protected function createConfigForIndex(BaseIndex $instance): ConfigStore
135
    {
136 35
        $storeConfig = SolrCoreService::config()->get('store');
137 35
        $configStore = $this->getStore($storeConfig);
138 35
        $instance->uploadConfig($configStore);
139
140 35
        return $configStore;
141
    }
142
143
    /**
144
     * Get the store for the given config
145
     *
146
     * @param $storeConfig
147
     * @return ConfigStore
148
     */
149 35
    protected function getStore($storeConfig): ConfigStore
150
    {
151 35
        $store = static::$storeModes[$storeConfig['mode']];
152 35
        $configStore = Injector::inst()->create($store, $storeConfig);
153
154
        // Allow changing the configStore if it needs to change to a different store
155 35
        $this->extend('onBeforeConfig', $configStore, $storeConfig);
156
157 35
        return $configStore;
158
    }
159
160
    /**
161
     * Log an exception error
162
     *
163
     * @codeCoverageIgnore Can't be tested because of accessibility and the actual throw of exception
164
     * @param $index
165
     * @param Exception $error
166
     * @throws GuzzleException
167
     * @throws ValidationException
168
     */
169
    private function logException($index, Exception $error): void
170
    {
171
        $this->getLogger()->error($error);
172
        $msg = sprintf(
173
            'Error loading core %s,' . PHP_EOL .
174
            'Please log in to the CMS to find out more about Configuration errors' . PHP_EOL,
175
            $index
176
        );
177
        SolrLogger::logMessage('ERROR', $msg, $index);
178
    }
179
180
    /**
181
     * @param $index
182
     * @param SolrCoreService $service
183
     * @return string
184
     */
185 35
    protected function getMethod($index, SolrCoreService $service): string
186
    {
187 35
        $status = $service->coreStatus($index);
188
        // Default to create
189 35
        $method = 'coreCreate';
190
        // Switch to reload if the core is loaded
191
        // Assuming a core that doesn't exist doesn't have uptime, as per Solr docs
192
        // And it has a start time.
193
        // You'd have to be pretty darn fast to hit 0 uptime and 0 starttime for an existing core!
194 35
        if ($status && ($status->getUptime() && $status->getStartTime() !== null)) {
195 35
            $method = 'coreReload';
196
        }
197
198 35
        return $method;
199
    }
200
}
201