Passed
Push — hans/code-cleaning ( c17c72...470e6d )
by Simon
05:48
created

SiteState   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 246
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 45
c 1
b 0
f 0
dl 0
loc 246
ccs 56
cts 56
cp 1
rs 10
wmc 28

15 Methods

Rating   Name   Duplication   Size   Complexity  
A setDefaultStates() 0 3 1
A variants() 0 12 4
A currentStates() 0 7 2
A addStates() 0 3 1
A addState() 0 3 1
A setEnabled() 0 3 1
A getDefaultStates() 0 3 1
A alterQuery() 0 8 2
A appliesToEnvironment() 0 3 1
A hasExtension() 0 10 3
A withState() 0 11 4
A isEnabled() 0 3 1
A getStates() 0 3 1
A setStates() 0 3 1
A isApplicable() 0 14 4
1
<?php
2
/**
3
 * class SiteState|Firesphere\SolrSearch\States\SiteState Base implementation of SiteState to be used by e.g.
4
 * the Fluent extension
5
 *
6
 * @package Firesphere\SolrSearch\States
7
 * @author Simon `Firesphere` Erkelens; Marco `Sheepy` Hermo
8
 * @copyright Copyright (c) 2018 - now() Firesphere & Sheepy
9
 */
10
11
12
namespace Firesphere\SolrSearch\States;
13
14
use Firesphere\SolrSearch\Helpers\FieldResolver;
15
use Firesphere\SolrSearch\Interfaces\SiteStateInterface;
16
use Firesphere\SolrSearch\Queries\BaseQuery;
17
use ReflectionClass;
18
use ReflectionException;
19
use SilverStripe\Core\ClassInfo;
20
use SilverStripe\Core\Config\Configurable;
21
use SilverStripe\Core\Injector\Injectable;
22
use SilverStripe\ORM\DataObject;
23
24
/**
25
 * Class SiteState
26
 *
27
 * Determine and apply the state of the site currently. This is used at index-time to figure out what state to index.
28
 * An example of this is the FluentSearchVariant extension from Fluent.
29
 *
30
 * Fluent uses the old SearchVariant method, which is actually not that bad a concept. These "Variants", now called
31
 * "States" set the state of the site to a required setting for each available state.
32
 *
33
 * States SHOULD add their own states through an extension of this class and implement {@link SiteStateInterface},
34
 * otherwise it won't be called.
35
 * {@link FluentIndexExtension::onBeforeInit()}
36
 *
37
 * States, options, etc. are simplified for a more streamlined approach
38
 *
39
 * @package Firesphere\SolrSearch\States
40
 */
41
abstract class SiteState
42
{
43
    use Configurable;
44
    use Injectable;
45
46
    const DEFAULT_STATE = 'default';
47
    /**
48
     * States that can be applied
49
     *
50
     * @var array
51
     */
52
    public static $states = [
53
        self::DEFAULT_STATE,
54
    ];
55
    /**
56
     * Variants of SiteState that can be activated
57
     *
58
     * @var array
59
     */
60
    public static $variants = [];
61
    /**
62
     * @var array Default states
63
     */
64
    protected static $defaultStates = [];
65
    /**
66
     * @var bool Is this State enabled
67
     */
68
    public $enabled = true;
69
    /**
70
     * @var string current state
71
     */
72
    protected $state;
73
74
    /**
75
     * Get available states
76
     *
77
     * @static
78
     * @return array
79
     */
80 14
    public static function getStates(): array
81
    {
82 14
        return self::$states;
83
    }
84
85
    /**
86
     * Set states
87
     *
88
     * @static
89
     * @param array $states
90
     */
91 1
    public static function setStates(array $states): void
92
    {
93 1
        self::$states = $states;
94 1
    }
95
96
    /**
97
     * Add a state
98
     *
99
     * @static
100
     * @param $state
101
     */
102 1
    public static function addState($state): void
103
    {
104 1
        self::$states[] = $state;
105 1
    }
106
107
    /**
108
     * Add multiple states
109
     *
110
     * @static
111
     * @param array $states
112
     */
113 1
    public static function addStates(array $states): void
114
    {
115 1
        self::$states = array_merge(self::$states, $states);
116 1
    }
117
118
    /**
119
     * Does this class, it's parent (or optionally one of it's children) have the passed extension attached?
120
     *
121
     * @static
122
     * @param $class
123
     * @param $extension
124
     * @return bool
125
     * @throws ReflectionException
126
     */
127 1
    public static function hasExtension($class, $extension): bool
128
    {
129
        /** @var DataObject $relatedclass */
130 1
        foreach (FieldResolver::gethierarchy($class) as $relatedclass) {
131 1
            if ($relatedclass::has_extension($extension)) {
132 1
                return true;
133
            }
134
        }
135
136 1
        return false;
137
    }
138
139
    /**
140
     * Get the current state of every variant
141
     *
142
     * @static
143
     * @return array
144
     * @throws ReflectionException
145
     */
146 17
    public static function currentStates(): array
147
    {
148 17
        foreach (self::variants() as $variant => $instance) {
149 17
            self::$defaultStates[$variant] = $instance->currentState();
150
        }
151
152 17
        return self::$defaultStates;
153
    }
154
155
    /**
156
     * Returns an array of variants.
157
     *
158
     * @static
159
     * @param bool $force Force updating the variants
160
     * @return array - An array of (string)$variantClassName => (Object)$variantInstance pairs
161
     * @throws ReflectionException
162
     */
163 22
    public static function variants($force = false): array
164
    {
165
        // Build up and cache a list of all search variants (subclasses of SearchVariant)
166 22
        if (empty(self::$variants) || $force) {
167 8
            $classes = ClassInfo::subclassesFor(static::class);
168
169 8
            foreach ($classes as $variantclass) {
170 8
                self::isApplicable($variantclass);
171
            }
172
        }
173
174 22
        return self::$variants;
175
    }
176
177
    /**
178
     * Is this extension applied and instantiable
179
     *
180
     * @static
181
     * @param $variantClass
182
     * @return bool
183
     * @throws ReflectionException
184
     */
185 9
    public static function isApplicable($variantClass): bool
186
    {
187 9
        $ref = new ReflectionClass($variantClass);
188 9
        if ($ref->isInstantiable()) {
189
            /** @var SiteState $variant */
190 9
            $variant = singleton($variantClass);
191 9
            if ($variant->appliesToEnvironment() && $variant->isEnabled()) {
192 9
                self::$variants[$variantClass] = $variant;
193
194 9
                return true;
195
            }
196
        }
197
198 9
        return false;
199
    }
200
201
    /**
202
     * Does this state apply to the current object/environment settings
203
     *
204
     * @return bool
205
     */
206 9
    public function appliesToEnvironment(): bool
207
    {
208 9
        return $this->enabled;
209
    }
210
211
    /**
212
     * Is this state enabled
213
     *
214
     * @return bool
215
     */
216 9
    public function isEnabled(): bool
217
    {
218 9
        return $this->enabled;
219
    }
220
221
    /**
222
     * Set the state to whatever is required. Most commonly true
223
     *
224
     * @param bool $enabled
225
     */
226 1
    public function setEnabled(bool $enabled): void
227
    {
228 1
        $this->enabled = $enabled;
229 1
    }
230
231
    /**
232
     * Activate a site state for indexing
233
     *
234
     * @param $state
235
     * @throws ReflectionException
236
     */
237 14
    public static function withState($state): void
238
    {
239
        /**
240
         * @var string $variant
241
         * @var SiteStateInterface $instance
242
         */
243 14
        foreach (self::variants() as $variant => $instance) {
244 14
            if ($state === self::DEFAULT_STATE) {
245 14
                $instance->setDefaultState(self::$defaultStates[$variant]);
246 1
            } elseif ($instance->stateIsApplicable($state)) {
247 14
                $instance->activateState($state);
248
            }
249
        }
250 14
    }
251
252
    /**
253
     * Alter the query for each instance
254
     *
255
     * @param BaseQuery $query
256
     * @throws ReflectionException
257
     */
258 6
    public static function alterQuery(&$query): void
259
    {
260
        /**
261
         * @var string $variant
262
         * @var SiteStateInterface $instance
263
         */
264 6
        foreach (self::variants(true) as $variant => $instance) {
265 6
            $instance->updateQuery($query);
266
        }
267 6
    }
268
269
    /**
270
     * Get the states set as default
271
     *
272
     * @return array
273
     */
274 1
    public static function getDefaultStates(): array
275
    {
276 1
        return self::$defaultStates;
277
    }
278
279
    /**
280
     * Set the default states
281
     *
282
     * @param array $defaultStates
283
     */
284 15
    public static function setDefaultStates(array $defaultStates): void
285
    {
286 15
        self::$defaultStates = $defaultStates;
287 15
    }
288
}
289