Passed
Push — hans/code-cleaning ( a01d48 )
by Simon
06:02
created

SolrConfigureTask::getStore()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
c 2
b 0
f 0
nc 1
nop 1
dl 0
loc 9
ccs 5
cts 5
cp 1
crap 1
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
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
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
        // Assuming a core that doesn't exist doesn't have uptime, as per Solr docs
123
        // And it has a start time.
124
        // You'd have to be pretty darn fast to hit 0 uptime and 0 starttime for an existing core!
125 35
        $status = $service->coreStatus($index);
126 35
        $configStore = $this->createConfigForIndex($instance);
127
        // Default to create
128 35
        $method = 'coreCreate';
129
        // Switch to reload if the core is loaded
130 35
        if ($status && ($status->getUptime() && $status->getStartTime() !== null)) {
131 35
            $method = 'coreReload';
132
        }
133 35
        $service->$method($index, $configStore);
134 35
        $this->getLogger()->info(sprintf('Core %s successfully loaded', $index));
135 35
    }
136
137
    /**
138
     * Get the config and load it to Solr
139
     *
140
     * @param BaseIndex $instance
141
     * @return ConfigStore
142
     */
143 35
    protected function createConfigForIndex(BaseIndex $instance): ConfigStore
144
    {
145 35
        $storeConfig = SolrCoreService::config()->get('store');
146 35
        $configStore = $this->getStore($storeConfig);
147 35
        $instance->uploadConfig($configStore);
148
149 35
        return $configStore;
150
    }
151
152
    /**
153
     * Get the store for the given config
154
     *
155
     * @param $storeConfig
156
     * @return ConfigStore
157
     */
158 35
    protected function getStore($storeConfig): ConfigStore
159
    {
160 35
        $store = static::$storeModes[$storeConfig['mode']];
161 35
        $configStore = Injector::inst()->create($store, $storeConfig);
162
163
        // Allow changing the configStore if it needs to change to a different store
164 35
        $this->extend('onBeforeConfig', $configStore, $storeConfig);
165
166 35
        return $configStore;
167
    }
168
169
    /**
170
     * Log an exception error
171
     *
172
     * @codeCoverageIgnore Can't be tested because of accessibility and the actual throw of exception
173
     * @param $index
174
     * @param Exception $error
175
     * @throws GuzzleException
176
     * @throws ValidationException
177
     */
178
    private function logException($index, Exception $error): void
179
    {
180
        $this->getLogger()->error($error);
181
        $msg = sprintf(
182
            'Error loading core %s,' . PHP_EOL .
183
            'Please log in to the CMS to find out more about Configuration errors' . PHP_EOL,
184
            $index
185
        );
186
        SolrLogger::logMessage('ERROR', $msg, $index);
187
    }
188
}
189