EncryptionHelper   B
last analyzed

Complexity

Total Complexity 49

Size/Duplication

Total Lines 353
Duplicated Lines 0 %

Test Coverage

Coverage 99.11%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 100
c 1
b 0
f 0
dl 0
loc 353
rs 8.48
ccs 111
cts 112
cp 0.9911
wmc 49

20 Methods

Rating   Name   Duplication   Size   Complexity  
A getControlCharacters() 0 13 3
A getVersion() 0 6 1
A setEnabled() 0 5 1
A setPrefix() 0 10 4
A isDisabled() 0 3 1
A isVersionless() 0 3 1
A getPrefix() 0 12 5
A isEnabled() 0 8 4
A setVersionless() 0 3 2
A setVersioning() 0 6 1
A isVersioning() 0 8 4
A buildHeader() 0 21 3
A getInstance() 0 3 1
A getHeaderPrefix() 0 12 2
A setDisabled() 0 3 2
A reset() 0 10 1
A setHeaderPrefix() 0 8 2
A __construct() 0 3 1
B getVersionParts() 0 26 9
A getVersionForPrefix() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like EncryptionHelper often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EncryptionHelper, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * src/EncryptionHelper.php.
4
 *
5
 * @author      Austin Heap <[email protected]>
6
 * @version     v0.2.1
7
 */
8
declare(strict_types=1);
9
10
namespace AustinHeap\Database\Encryption;
11
12
use Illuminate\Support\Facades\Config;
13
use RuntimeException;
14
15
/**
16
 * EncryptionHelper.
17
 *
18
 * @link        https://github.com/austinheap/laravel-database-encryption
19
 * @link        https://packagist.org/packages/austinheap/laravel-database-encryption
20
 * @link        https://austinheap.github.io/laravel-database-encryption/classes/AustinHeap.Database.Encryption.EncryptionHelper.html
21
 */
22
class EncryptionHelper extends EncryptionDefaults
23
{
24
    /**
25
     * Internal version number.
26
     *
27
     * @var string
28
     */
29
    public const VERSION = '0.1.2';
30
31
    /**
32
     * Private enable flag cache.
33
     *
34
     * @var null|bool
35
     */
36
    private $enabledCache = null;
37
38
    /**
39
     * Private versioning flag cache.
40
     *
41
     * @var null|bool
42
     */
43
    private $versioningCache = null;
44
45
    /**
46
     * Private version parts cache.
47
     *
48
     * @var null|array
49
     */
50
    private $versionPartsCache = null;
51
52
    /**
53
     * Private control characters cache.
54
     *
55
     * @var null|array
56
     */
57
    private $controlCharactersCache = null;
58
59
    /**
60
     * Private prefix cache.
61
     *
62
     * @var null|string
63
     */
64
    private $prefixCache = null;
65
66
    /**
67
     * Private header prefix cache.
68
     *
69
     * @var null|string
70
     */
71
    private $headerPrefixCache = null;
72
73
    /**
74
     * EncryptionHelper constructor.
75
     */
76 49
    public function __construct()
77
    {
78 49
        $this->reset();
79 49
    }
80
81
    /**
82
     * Reset the class; mostly the cache.
83
     *
84
     * @return EncryptionHelper
85
     */
86 49
    public function reset(): self
87
    {
88 49
        $this->enabledCache =
89 49
        $this->versioningCache =
90 49
        $this->versionPartsCache =
91 49
        $this->controlCharactersCache =
92 49
        $this->prefixCache =
93 49
        $this->headerPrefixCache = null;
94
95 49
        return $this;
96
    }
97
98
    /**
99
     * Get the package version.
100
     *
101
     * @return string
102
     */
103 28
    public function getVersion(): string
104
    {
105 28
        throw_if(! defined('LARAVEL_DATABASE_ENCRYPTION_VERSION'), RuntimeException::class,
106 28
                 'The provider did not boot.');
107
108 28
        return LARAVEL_DATABASE_ENCRYPTION_VERSION;
109
    }
110
111
    /**
112
     * Set the enabled flag.
113
     *
114
     * @return bool
115
     */
116 6
    public function setEnabled(?bool $value = null): self
117
    {
118 6
        $this->enabledCache = $value;
119
120 6
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type AustinHeap\Database\Encryption\EncryptionHelper which is incompatible with the documented return type boolean.
Loading history...
121
    }
122
123
    /**
124
     * Check the enabled flag.
125
     *
126
     * @return bool
127
     */
128 27
    public function isEnabled(): bool
129
    {
130 27
        if (is_null($this->enabledCache)) {
131 23
            $enabled = Config('database-encryption.enabled', null);
132 23
            $this->enabledCache = ! is_null($enabled) && is_bool($enabled) ? $enabled : self::isEnabledDefault();
133
        }
134
135 27
        return $this->enabledCache;
136
    }
137
138
    /**
139
     * Set the enabled flag inverse.
140
     *
141
     * @return bool
142
     */
143 3
    public function setDisabled(?bool $value = null): self
144
    {
145 3
        return $this->setEnabled(is_bool($value) ? ! $value : null);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->setEnabled...lue) ? ! $value : null) returns the type AustinHeap\Database\Encryption\EncryptionHelper which is incompatible with the documented return type boolean.
Loading history...
146
    }
147
148
    /**
149
     * Check the enabled flag inverse.
150
     *
151
     * @return bool
152
     */
153 3
    public function isDisabled(): bool
154
    {
155 3
        return ! $this->isEnabled();
156
    }
157
158
    /**
159
     * Set the versioning flag.
160
     *
161
     * @return null|bool
162
     */
163 7
    public function setVersioning(?bool $value = null): self
164
    {
165 7
        $this->reset();
166 7
        $this->versioningCache = $value;
167
168 7
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type AustinHeap\Database\Encryption\EncryptionHelper which is incompatible with the documented return type boolean|null.
Loading history...
169
    }
170
171
    /**
172
     * Check the versioning flag.
173
     *
174
     * @return bool
175
     */
176 31
    public function isVersioning(): bool
177
    {
178 31
        if (is_null($this->versioningCache)) {
179 26
            $versioning = Config('database-encryption.versioning', null);
180 26
            $this->versioningCache = ! is_null($versioning) && is_bool($versioning) ? $versioning : self::isVersioningDefault();
181
        }
182
183 31
        return $this->versioningCache;
184
    }
185
186
    /**
187
     * Set the enabled flag inverse.
188
     *
189
     * @return null|bool
190
     */
191 4
    public function setVersionless(?bool $value = null): self
192
    {
193 4
        return $this->setVersioning(is_bool($value) ? ! $value : null);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->setVersion...lue) ? ! $value : null) returns the type AustinHeap\Database\Encryption\EncryptionHelper which is incompatible with the documented return type boolean|null.
Loading history...
194
    }
195
196
    /**
197
     * Check the versioning flag inverse.
198
     *
199
     * @return bool
200
     */
201 3
    public function isVersionless(): bool
202
    {
203 3
        return ! $this->isVersioning();
204
    }
205
206
    /**
207
     * Get the package version in parts.
208
     *
209
     * @return array
210
     */
211 27
    public function getVersionParts(?int $padding = null): array
212
    {
213 27
        if (! is_array($this->versionPartsCache)) {
214 27
            $this->versionPartsCache = [];
215
        }
216
217 27
        $padding = is_int($padding) && $padding === 0 ? null : $padding;
218 27
        $key = 'padding-'.(is_null($padding) ? 'null' : (string) $padding);
219
220 27
        if (! array_key_exists($key, $this->versionPartsCache)) {
221 27
            $parts = explode('.', $this->getVersion());
222
223
            $this->versionPartsCache[$key] = array_map(function ($part) use ($padding) {
224 27
                $part = (string) $part;
225
226 27
                if (is_null($padding)) {
227 2
                    return $part;
228
                }
229
230 25
                $length = strlen(is_string($part) ? $part : (string) $part);
0 ignored issues
show
introduced by
The condition is_string($part) is always true.
Loading history...
231
232 25
                return $length == $padding ? $part : str_repeat('0', $padding - $length).$part;
233 27
            }, $parts);
234
        }
235
236 27
        return $this->versionPartsCache[$key];
237
    }
238
239
    /**
240
     * Get the package version for a prefix.
241
     *
242
     * @return string
243
     */
244 24
    public function getVersionForPrefix(int $padding = 2, string $glue = '-'): string
245
    {
246 24
        return 'VERSION-'.implode($glue, $this->getVersionParts($padding));
247
    }
248
249
    /**
250
     * Set the configured header prefix.
251
     *
252
     * @return EncryptionHelper
253
     */
254 3
    public function setHeaderPrefix(?string $value = null): self
255
    {
256 3
        throw_if(is_string($value) && strlen(trim($value)) == 0, RuntimeException::class,
257 3
                 'Cannot use empty string as header prefix.');
258
259 2
        $this->headerPrefixCache = $value;
260
261 2
        return $this;
262
    }
263
264
    /**
265
     * Get the configured header prefix.
266
     *
267
     * @return string
268
     */
269 22
    public function getHeaderPrefix(): string
270
    {
271 22
        if (is_null($this->headerPrefixCache)) {
272 21
            $characters = $this->getControlCharacters();
273
274 21
            $this->headerPrefixCache = $characters['header']['start']['string'].
275 21
                                       $characters['prefix']['start']['string'].
276 21
                                       $this->getPrefix().
277 21
                                       $characters['prefix']['stop']['string'];
278
        }
279
280 22
        return $this->headerPrefixCache;
281
    }
282
283
    /**
284
     * Build a header string, optionally with an object.
285
     *
286
     * @return string
287
     */
288 21
    public function buildHeader($object = null): string
289
    {
290 21
        $characters = $this->getControlCharacters();
291
292 21
        return $characters['header']['start']['string'].
293 21
               $characters['prefix']['start']['string'].
294 21
               $this->getPrefix().
295 21
               $characters['prefix']['stop']['string'].
296 21
               $characters['field']['start']['string'].
297 21
               'version'.
298 21
               $characters['field']['delimiter']['string'].
299 21
               self::getVersionForPrefix().
0 ignored issues
show
Bug Best Practice introduced by
The method AustinHeap\Database\Encr...::getVersionForPrefix() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

299
               self::/** @scrutinizer ignore-call */ 
300
                     getVersionForPrefix().
Loading history...
300 21
               $characters['field']['stop']['string'].
301 21
               (is_null($object) ? '' :
302 21
                   $characters['field']['start']['string'].
303 21
                   'type'.
304 21
                   $characters['field']['delimiter']['string'].
305 21
                   gettype($object).'['.(is_object($object) ? get_class($object) : 'native').']'.
306 21
                   $characters['field']['stop']['string']
307
               ).
308 21
               $characters['header']['stop']['string'];
309
    }
310
311
    /**
312
     * Set the configured prefix.
313
     *
314
     * @return EncryptionHelper
315
     */
316 5
    public function setPrefix(?string $value = null): self
317
    {
318 5
        throw_if(is_string($value) && strlen(trim($value)) == 0, RuntimeException::class,
319 5
                 'Cannot use empty string as prefix.');
320
321 4
        $this->prefixCache = is_string($value) && $this->isVersioning() ?
322 3
            str_replace('%VERSION%', $this->getVersionForPrefix(), $value) :
323 2
            $value;
324
325 4
        return $this;
326
    }
327
328
    /**
329
     * Get the configured prefix.
330
     *
331
     * @return string
332
     */
333 25
    public function getPrefix(): string
334
    {
335 25
        if (is_null($this->prefixCache)) {
336 21
            $prefix = Config::get('database-encryption.prefix', null);
337 21
            $prefix = ! empty($prefix) && is_string($prefix) ? $prefix : self::getPrefixDefault();
338
339 21
            $this->prefixCache = $this->isVersioning() ?
340 21
                str_replace('%VERSION%', $this->getVersionForPrefix(), $prefix) :
341
                $prefix;
342
        }
343
344 25
        return $this->prefixCache;
345
    }
346
347
    /**
348
     * Get the configured control characters.
349
     *
350
     * @return array
351
     */
352 21
    public function getControlCharacters(?string $type = null): array
353
    {
354 21
        $defaults = self::getControlCharactersDefault();
0 ignored issues
show
Unused Code introduced by
The assignment to $defaults is dead and can be removed.
Loading history...
355 21
        $characters = self::getControlCharactersDefault();
356
357 21
        if (! is_null($type)) {
358 11
            throw_if(! array_key_exists($type, $characters),
359 11
                     'Control characters do not exist for $type: "'.(empty($type) ? '(empty)' : $type).'".');
360
361 11
            return $characters[$type];
362
        }
363
364 21
        return $characters;
365
    }
366
367
    /**
368
     * Get the singleton of this class.
369
     *
370
     * @return EncryptionHelper
371
     */
372 4
    public static function getInstance(): self
373
    {
374 4
        return EncryptionFacade::getInstance();
375
    }
376
}
377