Passed
Push — master ( bc16c5...fce4c6 )
by Simon
06:43
created

SolrConfigureTask   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 160
Duplicated Lines 0 %

Test Coverage

Coverage 79.55%

Importance

Changes 6
Bugs 0 Features 0
Metric Value
eloc 51
c 6
b 0
f 0
dl 0
loc 160
ccs 35
cts 44
cp 0.7955
rs 10
wmc 12

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A getStore() 0 9 1
A createConfigForIndex() 0 7 1
A configureIndex() 0 29 5
A run() 0 26 3
A logException() 0 9 1
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 RuntimeException;
23
use SilverStripe\Control\HTTPRequest;
24
use SilverStripe\Core\Injector\Injector;
25
use SilverStripe\Dev\BuildTask;
26
use SilverStripe\ORM\ValidationException;
27
28
/**
29
 * Class SolrConfigureTask
30
 *
31
 * @package Firesphere\SolrSearch\Tasks
32
 */
33
class SolrConfigureTask extends BuildTask
34
{
35
    use LoggerTrait;
36
37
    /**
38
     * @var array Available stores
39
     */
40
    protected static $storeModes = [
41
        'file' => FileConfigStore::class,
42
        'post' => PostConfigStore::class,
43
        //        'webdav' => WebdavConfigStore::class,
44
    ];
45
    /**
46
     * @var string URLSegment
47
     */
48
    private static $segment = 'SolrConfigureTask';
49
    /**
50
     * @var string Title
51
     */
52
    protected $title = 'Configure Solr cores';
53
    /**
54
     * @var string Description
55
     */
56
    protected $description = 'Create or reload a Solr Core by adding or reloading a configuration.';
57
58
    /**
59
     * SolrConfigureTask constructor.
60
     */
61 36
    public function __construct()
62
    {
63 36
        parent::__construct();
64 36
    }
65
66
    /**
67
     * Implement this method in the task subclass to
68
     * execute via the TaskRunner
69
     *
70
     * @param HTTPRequest $request
71
     * @return bool|Exception
72
     * @throws ReflectionException
73
     * @throws ValidationException
74
     * @throws GuzzleException
75
     */
76 35
    public function run($request)
77
    {
78 35
        $this->extend('onBeforeSolrConfigureTask', $request);
79
80 35
        $indexes = (new SolrCoreService())->getValidIndexes();
81
82 35
        foreach ($indexes as $index) {
83
            try {
84 35
                $this->configureIndex($index);
85
            } catch (Exception $error) {
86
                // @codeCoverageIgnoreStart
87
                $this->getLogger()->error(sprintf('Core loading failed for %s', $index));
88
                $this->getLogger()->error($error); // 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
        try {
134 35
            $service->$method($index, $configStore);
135 35
            $this->getLogger()->info(sprintf('Core %s successfully loaded', $index));
136
        } catch (Exception $error) {
137
            // @codeCoverageIgnoreStart
138
            $this->logException($index, $error);
139
            throw new RuntimeException($error);
140
            // @codeCoverageIgnoreEnd
141
        }
142 35
    }
143
144
    /**
145
     * Get the config and load it to Solr
146
     *
147
     * @param BaseIndex $instance
148
     * @return ConfigStore
149
     */
150 35
    protected function createConfigForIndex(BaseIndex $instance): ConfigStore
151
    {
152 35
        $storeConfig = SolrCoreService::config()->get('store');
153 35
        $configStore = $this->getStore($storeConfig);
154 35
        $instance->uploadConfig($configStore);
155
156 35
        return $configStore;
157
    }
158
159
    /**
160
     * Get the store for the given config
161
     *
162
     * @param $storeConfig
163
     * @return ConfigStore
164
     */
165 35
    protected function getStore($storeConfig): ConfigStore
166
    {
167 35
        $store = static::$storeModes[$storeConfig['mode']];
168 35
        $configStore = Injector::inst()->create($store, $storeConfig);
169
170
        // Allow changing the configStore if it needs to change to a different store
171 35
        $this->extend('onBeforeConfig', $configStore, $storeConfig);
172
173 35
        return $configStore;
174
    }
175
176
    /**
177
     * Log an exception error
178
     *
179
     * @param $index
180
     * @param Exception $error
181
     * @throws GuzzleException
182
     * @throws ValidationException
183
     */
184
    private function logException($index, Exception $error): void
185
    {
186
        $this->getLogger()->error($error);
187
        $msg = sprintf(
188
            'Error loading core %s,' . PHP_EOL .
189
            'Please log in to the CMS to find out more about Configuration errors' . PHP_EOL,
190
            $index
191
        );
192
        SolrLogger::logMessage('ERROR', $msg, $index);
193
    }
194
}
195