SolrConfigureTask   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 168
Duplicated Lines 0 %

Test Coverage

Coverage 97.5%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 51
dl 0
loc 168
ccs 39
cts 40
cp 0.975
rs 10
c 4
b 0
f 0
wmc 12

7 Methods

Rating   Name   Duplication   Size   Complexity  
A getStore() 0 8 1
A __construct() 0 3 1
A getMethod() 0 14 4
A createConfigForIndex() 0 7 1
A configureIndex() 0 15 1
A run() 0 28 3
A logException() 0 10 1
1
<?php
2
/**
3
 * Class SolrConfigureTask|Firesphere\SolrSearch\Tasks\SolrConfigureTask Configure Solr cores
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\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 Psr\SimpleCache\CacheInterface;
21
use Psr\SimpleCache\InvalidArgumentException;
22
use SilverStripe\Control\HTTPRequest;
23
use SilverStripe\Core\Injector\Injector;
24
use SilverStripe\Dev\BuildTask;
25
use SilverStripe\ORM\ValidationException;
26
use Solarium\Exception\HttpException;
27
28
/**
29
 * Class SolrConfigureTask
30
 *
31
 * @package Firesphere\Solr\Search
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
    public function __construct()
62 37
    {
63
        parent::__construct();
64 37
    }
65 37
66
    /**
67
     * Implement this method in the task subclass to
68
     * execute via the TaskRunner
69
     *
70
     * @param HTTPRequest $request Current request
71
     * @return void
72
     * @throws HTTPException
73
     * @throws InvalidArgumentException
74
     * @throws ValidationException
75
     */
76
    public function run($request)
77 36
    {
78
        /** @var CacheInterface $cache */
79
        $cache = Injector::inst()->get(CacheInterface::class . '.SolrCache');
80 36
        $cache->delete('ValidClasses');
81 36
        $this->extend('onBeforeSolrConfigureTask', $request);
82 36
83
        $indexes = (new SolrCoreService())->getValidIndexes();
84 36
85
        foreach ($indexes as $index) {
86 36
            try {
87
                $this->configureIndex($index);
88 36
            } catch (Exception $error) {
89
                // @codeCoverageIgnoreStart
90
                $this->logException($index, $error);
91
                $this->getLogger()->error(sprintf('Core loading failed for %s', $index));
92
                $this->getLogger()->error($error->getMessage()); // in browser mode, it might not always show
93
                // Continue to the next index
94
                continue;
95
                // @codeCoverageIgnoreEnd
96
            }
97
            $this->extend('onAfterConfigureIndex', $index);
98 36
        }
99
100
        $this->extend('onAfterSolrConfigureTask');
101 36
        // Grab the latest logs
102
        $solrLogger = new SolrLogger();
103 36
        $solrLogger->saveSolrLog('Config');
104 36
    }
105 36
106
    /**
107
     * Update the index on the given store
108
     *
109
     * @param string $index Core to index
110
     */
111
    protected function configureIndex($index): void
112 36
    {
113
        /** @var BaseIndex $instance */
114
        $instance = Injector::inst()->get($index, false);
115 36
116
        $index = $instance->getIndexName();
117 36
118
        // Then tell Solr to use those config files
119
        /** @var SolrCoreService $service */
120
        $service = Injector::inst()->get(SolrCoreService::class);
121 36
122
        $configStore = $this->createConfigForIndex($instance);
123 36
        $method = $this->getMethod($index, $service);
124 36
        $service->$method($index, $configStore);
125 36
        $this->getLogger()->info(sprintf('Core %s successfully loaded', $index));
126 36
    }
127 36
128
    /**
129
     * Get the config and load it to Solr
130
     *
131
     * @param BaseIndex $instance
132
     * @return ConfigStore
133
     */
134
    protected function createConfigForIndex(BaseIndex $instance): ConfigStore
135 36
    {
136
        $storeConfig = SolrCoreService::config()->get('store');
137 36
        $configStore = $this->getStore($storeConfig);
138 36
        $instance->uploadConfig($configStore);
139 36
140
        return $configStore;
141 36
    }
142
143
    /**
144
     * Get the store for the given config
145
     *
146
     * @param $storeConfig
147
     * @return ConfigStore
148
     */
149
    protected function getStore($storeConfig): ConfigStore
150 36
    {
151
        $configStore = Injector::inst()->create(ConfigStore::class, $storeConfig);
152 36
153
        // Allow changing the configStore if it needs to change to a different store
154
        $this->extend('onBeforeConfig', $configStore, $storeConfig);
155 36
156
        return $configStore;
157 36
    }
158
159
    /**
160
     * Figure out the method needed for the given core.
161
     *
162
     * @param $index
163
     * @param SolrCoreService $service
164
     * @return string
165
     */
166
    protected function getMethod($index, SolrCoreService $service): string
167 36
    {
168
        $status = $service->coreStatus($index);
169 36
        // Default to create
170
        $method = 'coreCreate';
171 36
        // Switch to reload if the core is loaded
172
        // Assuming a core that doesn't exist doesn't have uptime, as per Solr docs
173
        // And it has a start time.
174
        // You'd have to be pretty darn fast to hit 0 uptime and 0 starttime for an existing core!
175
        if ($status && ($status->getUptime() && $status->getStartTime() !== null)) {
176 36
            $method = 'coreReload';
177 36
        }
178
179
        return $method;
180 36
    }
181
182
    /**
183
     * Log an exception error
184
     *
185
     * @codeCoverageIgnore Can't be tested because of accessibility and the actual throw of exception
186
     * @param string $index Name of the index
187
     * @param Exception $error
188
     * @throws HTTPException
189
     * @throws ValidationException
190
     */
191
    private function logException($index, Exception $error): void
192
    {
193
        $this->getLogger()->error($error);
194
        $msg = sprintf(
195
            'Error loading core %s%s, Please log in to the CMS to find out more about Configuration errors %s',
196
            $index,
197
            PHP_EOL,
198
            PHP_EOL
199
        );
200
        SolrLogger::logMessage('ERROR', $msg);
201
    }
202
}
203