Passed
Push — master ( 2ec749...6a9421 )
by Simon
06:29
created

SiteState   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 246
Duplicated Lines 0 %

Test Coverage

Coverage 96.43%

Importance

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