Passed
Push — master ( 8fffdc...3ef9a2 )
by Austin
03:09
created

src/EncryptionHelper.php (4 issues)

1
<?php
2
/**
3
 * src/EncryptionHelper.php.
4
 *
5
 * @author      Austin Heap <[email protected]>
6
 * @version     v0.2.0
7
 */
8
declare(strict_types=1);
9
10
namespace AustinHeap\Database\Encryption;
11
12
use RuntimeException;
13
use Illuminate\Support\Facades\Config;
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 47
    public function __construct()
77
    {
78 47
        $this->reset();
79 47
    }
80
81
    /**
82
     * Reset the class; mostly the cache.
83
     *
84
     * @return EncryptionHelper
85
     */
86 47
    public function reset(): self
87
    {
88 47
        $this->enabledCache =
89 47
        $this->versioningCache =
90 47
        $this->versionPartsCache =
91 47
        $this->controlCharactersCache =
92 47
        $this->prefixCache =
93 47
        $this->headerPrefixCache = null;
94
95 47
        return $this;
96
    }
97
98
    /**
99
     * Get the package version.
100
     *
101
     * @return string
102
     */
103 26
    public function getVersion(): string
104
    {
105 26
        throw_if(! defined('LARAVEL_DATABASE_ENCRYPTION_VERSION'), RuntimeException::class,
106 26
                 'The provider did not boot.');
107
108 26
        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 25
    public function isEnabled(): bool
129
    {
130 25
        if (is_null($this->enabledCache)) {
131 21
            $enabled = Config('database-encryption.enabled', null);
132 21
            $this->enabledCache = ! is_null($enabled) && is_bool($enabled) ? $enabled : self::isEnabledDefault();
133
        }
134
135 25
        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 29
    public function isVersioning(): bool
177
    {
178 29
        if (is_null($this->versioningCache)) {
179 24
            $versioning = Config('database-encryption.versioning', null);
180 24
            $this->versioningCache = ! is_null($versioning) && is_bool($versioning) ? $versioning : self::isVersioningDefault();
181
        }
182
183 29
        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 25
    public function getVersionParts(?int $padding = null): array
212
    {
213 25
        if (! is_array($this->versionPartsCache)) {
214 25
            $this->versionPartsCache = [];
215
        }
216
217 25
        $padding = is_int($padding) && $padding === 0 ? null : $padding;
218 25
        $key = 'padding-'.(is_null($padding) ? 'null' : (string) $padding);
219
220 25
        if (! array_key_exists($key, $this->versionPartsCache)) {
221 25
            $parts = explode('.', $this->getVersion());
222
223
            $this->versionPartsCache[$key] = array_map(function ($part) use ($padding) {
224 25
                $part = (string) $part;
225
226 25
                if (is_null($padding)) {
227 2
                    return $part;
228
                }
229
230 23
                $length = strlen(is_string($part) ? $part : (string) $part);
231
232 23
                return $length == $padding ? $part : str_repeat('0', $padding - $length).$part;
233 25
            }, $parts);
234
        }
235
236 25
        return $this->versionPartsCache[$key];
237
    }
238
239
    /**
240
     * Get the package version for a prefix.
241
     *
242
     * @return string
243
     */
244 22
    public function getVersionForPrefix(int $padding = 2, string $glue = '-'): string
245
    {
246 22
        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 20
    public function getHeaderPrefix(): string
270
    {
271 20
        if (is_null($this->headerPrefixCache)) {
272 19
            $characters = $this->getControlCharacters();
273
274 19
            $this->headerPrefixCache = $characters['header']['start']['string'].
275 19
                                       $characters['prefix']['start']['string'].
276 19
                                       $this->getPrefix().
277 19
                                       $characters['prefix']['stop']['string'];
278
        }
279
280 20
        return $this->headerPrefixCache;
281
    }
282
283
    /**
284
     * Build a header string, optionally with an object.
285
     *
286
     * @return string
287
     */
288 19
    public function buildHeader($object = null): string
289
    {
290 19
        $characters = $this->getControlCharacters();
291
292 19
        return $characters['header']['start']['string'].
293 19
               $characters['prefix']['start']['string'].
294 19
               $this->getPrefix().
295 19
               $characters['prefix']['stop']['string'].
296 19
               $characters['field']['start']['string'].
297 19
               'version'.
298 19
               $characters['field']['delimiter']['string'].
299 19
               self::getVersionForPrefix().
300 19
               $characters['field']['stop']['string'].
301 19
               (is_null($object) ? '' :
302 19
                   $characters['field']['start']['string'].
303 19
                   'type'.
304 19
                   $characters['field']['delimiter']['string'].
305 19
                   gettype($object).'['.(is_object($object) ? get_class($object) : 'native').']'.
306 19
                   $characters['field']['stop']['string']
307
               ).
308 19
               $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 23
    public function getPrefix(): string
334
    {
335 23
        if (is_null($this->prefixCache)) {
336 19
            $prefix = Config::get('database-encryption.prefix', null);
337 19
            $prefix = ! empty($prefix) && is_string($prefix) ? $prefix : self::getPrefixDefault();
338
339 19
            $this->prefixCache = $this->isVersioning() ?
340 19
                str_replace('%VERSION%', $this->getVersionForPrefix(), $prefix) :
341
                $prefix;
342
        }
343
344 23
        return $this->prefixCache;
345
    }
346
347
    /**
348
     * Get the configured control characters.
349
     *
350
     * @return array
351
     */
352 19
    public function getControlCharacters(?string $type = null): array
353
    {
354 19
        $defaults = self::getControlCharactersDefault();
355 19
        $characters = self::getControlCharactersDefault();
356
357 19
        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 19
        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