Passed
Push — hans/upgrades ( fad2b0...5115e7 )
by Simon
11:10 queued 06:11
created

SolrConfigureTask   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 170
Duplicated Lines 0 %

Test Coverage

Coverage 97.5%

Importance

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

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A createConfigForIndex() 0 7 1
A configureIndex() 0 15 1
A run() 0 30 3
A getStore() 0 8 1
A logException() 0 9 1
A getMethod() 0 14 4
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 GuzzleHttp\Exception\GuzzleException;
21
use Psr\SimpleCache\CacheInterface;
22
use Psr\SimpleCache\InvalidArgumentException;
23
use ReflectionException;
24
use SilverStripe\Control\HTTPRequest;
25
use SilverStripe\Core\Injector\Injector;
26
use SilverStripe\Dev\BuildTask;
27
use SilverStripe\ORM\ValidationException;
28
29
/**
30
 * Class SolrConfigureTask
31
 *
32
 * @package Firesphere\Solr\Search
33
 */
34
class SolrConfigureTask extends BuildTask
35
{
36
    use LoggerTrait;
37
38
    /**
39
     * @var array Available stores
40
     */
41
    protected static $storeModes = [
42
        'file' => FileConfigStore::class,
43
        'post' => PostConfigStore::class,
44
        //        'webdav' => WebdavConfigStore::class,
45
    ];
46
    /**
47
     * @var string URLSegment
48
     */
49
    private static $segment = 'SolrConfigureTask';
50
    /**
51
     * @var string Title
52
     */
53
    protected $title = 'Configure Solr cores';
54
    /**
55
     * @var string Description
56
     */
57
    protected $description = 'Create or reload a Solr Core by adding or reloading a configuration.';
58
59
    /**
60
     * SolrConfigureTask constructor.
61
     */
62 37
    public function __construct()
63
    {
64 37
        parent::__construct();
65 37
    }
66
67
    /**
68
     * Implement this method in the task subclass to
69
     * execute via the TaskRunner
70
     *
71
     * @param HTTPRequest $request Current request
72
     * @return bool|Exception
73
     * @throws ReflectionException
74
     * @throws ValidationException
75
     * @throws GuzzleException
76
     * @throws InvalidArgumentException
77
     */
78 36
    public function run($request)
79
    {
80
        /** @var CacheInterface $cache */
81 36
        $cache = Injector::inst()->get(CacheInterface::class . '.SolrCache');
82 36
        $cache->delete('ValidClasses');
83 36
        $this->extend('onBeforeSolrConfigureTask', $request);
84
85 36
        $indexes = (new SolrCoreService())->getValidIndexes();
86
87 36
        foreach ($indexes as $index) {
88
            try {
89 36
                $this->configureIndex($index);
90
            } catch (Exception $error) {
91
                // @codeCoverageIgnoreStart
92
                $this->logException($index, $error);
93
                $this->getLogger()->error(sprintf('Core loading failed for %s', $index));
94
                $this->getLogger()->error($error->getMessage()); // in browser mode, it might not always show
95
                // Continue to the next index
96
                continue;
97
                // @codeCoverageIgnoreEnd
98
            }
99 36
            $this->extend('onAfterConfigureIndex', $index);
100
        }
101
102 36
        $this->extend('onAfterSolrConfigureTask');
103
        // Grab the latest logs
104 36
        $solrLogger = new SolrLogger();
105 36
        $solrLogger->saveSolrLog('Config');
106
107 36
        return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the return type mandated by SilverStripe\Dev\BuildTask::run() of void.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
108
    }
109
110
    /**
111
     * Update the index on the given store
112
     *
113
     * @param string $index Core to index
114
     */
115 36
    protected function configureIndex($index): void
116
    {
117
        /** @var BaseIndex $instance */
118 36
        $instance = Injector::inst()->get($index, false);
119
120 36
        $index = $instance->getIndexName();
121
122
        // Then tell Solr to use those config files
123
        /** @var SolrCoreService $service */
124 36
        $service = Injector::inst()->get(SolrCoreService::class);
125
126 36
        $configStore = $this->createConfigForIndex($instance);
127 36
        $method = $this->getMethod($index, $service);
128 36
        $service->$method($index, $configStore);
129 36
        $this->getLogger()->info(sprintf('Core %s successfully loaded', $index));
130 36
    }
131
132
    /**
133
     * Get the config and load it to Solr
134
     *
135
     * @param BaseIndex $instance
136
     * @return ConfigStore
137
     */
138 36
    protected function createConfigForIndex(BaseIndex $instance): ConfigStore
139
    {
140 36
        $storeConfig = SolrCoreService::config()->get('store');
141 36
        $configStore = $this->getStore($storeConfig);
142 36
        $instance->uploadConfig($configStore);
143
144 36
        return $configStore;
145
    }
146
147
    /**
148
     * Get the store for the given config
149
     *
150
     * @param $storeConfig
151
     * @return ConfigStore
152
     */
153 36
    protected function getStore($storeConfig): ConfigStore
154
    {
155 36
        $configStore = Injector::inst()->create(ConfigStore::class, $storeConfig);
156
157
        // Allow changing the configStore if it needs to change to a different store
158 36
        $this->extend('onBeforeConfig', $configStore, $storeConfig);
159
160 36
        return $configStore;
161
    }
162
163
    /**
164
     * Figure out the method needed for the given core.
165
     *
166
     * @param $index
167
     * @param SolrCoreService $service
168
     * @return string
169
     */
170 36
    protected function getMethod($index, SolrCoreService $service): string
171
    {
172 36
        $status = $service->coreStatus($index);
173
        // Default to create
174 36
        $method = 'coreCreate';
175
        // Switch to reload if the core is loaded
176
        // Assuming a core that doesn't exist doesn't have uptime, as per Solr docs
177
        // And it has a start time.
178
        // You'd have to be pretty darn fast to hit 0 uptime and 0 starttime for an existing core!
179 36
        if ($status && ($status->getUptime() && $status->getStartTime() !== null)) {
180 36
            $method = 'coreReload';
181
        }
182
183 36
        return $method;
184
    }
185
186
    /**
187
     * Log an exception error
188
     *
189
     * @codeCoverageIgnore Can't be tested because of accessibility and the actual throw of exception
190
     * @param $index
191
     * @param Exception $error
192
     * @throws GuzzleException
193
     * @throws ValidationException
194
     */
195
    private function logException($index, Exception $error): void
196
    {
197
        $this->getLogger()->error($error);
198
        $msg = sprintf(
199
            'Error loading core %s,' . PHP_EOL .
200
            'Please log in to the CMS to find out more about Configuration errors' . PHP_EOL,
201
            $index
202
        );
203
        SolrLogger::logMessage('ERROR', $msg);
204
    }
205
}
206