Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
95.00% covered (success)
95.00%
19 / 20
CRAP
98.91% covered (success)
98.91%
91 / 92
AustinHeap\Database\Encryption\EncryptionHelper
0.00% covered (danger)
0.00%
0 / 1
95.00% covered (success)
95.00%
19 / 20
57
98.91% covered (success)
98.91%
91 / 92
 __construct
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
 reset
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
7 / 7
 getVersion
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
3 / 3
 setEnabled
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
2 / 2
 isEnabled
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
4 / 4
 setDisabled
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
1 / 1
 isDisabled
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 setVersioning
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
3 / 3
 isVersioning
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
4 / 4
 setVersionless
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
1 / 1
 isVersionless
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 getVersionParts
100.00% covered (success)
100.00%
1 / 1
10
100.00% covered (success)
100.00%
13 / 13
 getVersionForPrefix
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 setHeaderPrefix
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
4 / 4
 getHeaderPrefix
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
7 / 7
 buildHeader
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
17 / 17
 setPrefix
100.00% covered (success)
100.00%
1 / 1
5
100.00% covered (success)
100.00%
6 / 6
 getPrefix
0.00% covered (danger)
0.00%
0 / 1
5.07
85.71% covered (warning)
85.71%
6 / 7
 getControlCharacters
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
7 / 7
 getInstance
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
<?php
/**
 * src/EncryptionHelper.php.
 *
 * @author      Austin Heap <me@austinheap.com>
 * @version     v0.2.0
 */
declare(strict_types=1);
namespace AustinHeap\Database\Encryption;
use RuntimeException;
use Illuminate\Support\Facades\Config;
/**
 * EncryptionHelper.
 *
 * @link        https://github.com/austinheap/laravel-database-encryption
 * @link        https://packagist.org/packages/austinheap/laravel-database-encryption
 * @link        https://austinheap.github.io/laravel-database-encryption/classes/AustinHeap.Database.Encryption.EncryptionHelper.html
 */
class EncryptionHelper extends EncryptionDefaults
{
    /**
     * Internal version number.
     *
     * @var string
     */
    public const VERSION = '0.1.2';
    /**
     * Private enable flag cache.
     *
     * @var null|bool
     */
    private $enabledCache = null;
    /**
     * Private versioning flag cache.
     *
     * @var null|bool
     */
    private $versioningCache = null;
    /**
     * Private version parts cache.
     *
     * @var null|array
     */
    private $versionPartsCache = null;
    /**
     * Private control characters cache.
     *
     * @var null|array
     */
    private $controlCharactersCache = null;
    /**
     * Private prefix cache.
     *
     * @var null|string
     */
    private $prefixCache = null;
    /**
     * Private header prefix cache.
     *
     * @var null|string
     */
    private $headerPrefixCache = null;
    /**
     * EncryptionHelper constructor.
     */
    public function __construct()
    {
        $this->reset();
    }
    /**
     * Reset the class; mostly the cache.
     *
     * @return EncryptionHelper
     */
    public function reset(): self
    {
        $this->enabledCache =
        $this->versioningCache =
        $this->versionPartsCache =
        $this->controlCharactersCache =
        $this->prefixCache =
        $this->headerPrefixCache = null;
        return $this;
    }
    /**
     * Get the package version.
     *
     * @return string
     */
    public function getVersion(): string
    {
        throw_if(! defined('LARAVEL_DATABASE_ENCRYPTION_VERSION'), RuntimeException::class,
                 'The provider did not boot.');
        return LARAVEL_DATABASE_ENCRYPTION_VERSION;
    }
    /**
     * Set the enabled flag.
     *
     * @return bool
     */
    public function setEnabled(?bool $value = null): self
    {
        $this->enabledCache = $value;
        return $this;
    }
    /**
     * Check the enabled flag.
     *
     * @return bool
     */
    public function isEnabled(): bool
    {
        if (is_null($this->enabledCache)) {
            $enabled = Config('database-encryption.enabled', null);
            $this->enabledCache = ! is_null($enabled) && is_bool($enabled) ? $enabled : self::isEnabledDefault();
        }
        return $this->enabledCache;
    }
    /**
     * Set the enabled flag inverse.
     *
     * @return bool
     */
    public function setDisabled(?bool $value = null): self
    {
        return $this->setEnabled(is_bool($value) ? ! $value : null);
    }
    /**
     * Check the enabled flag inverse.
     *
     * @return bool
     */
    public function isDisabled(): bool
    {
        return ! $this->isEnabled();
    }
    /**
     * Set the versioning flag.
     *
     * @return null|bool
     */
    public function setVersioning(?bool $value = null): self
    {
        $this->reset();
        $this->versioningCache = $value;
        return $this;
    }
    /**
     * Check the versioning flag.
     *
     * @return bool
     */
    public function isVersioning(): bool
    {
        if (is_null($this->versioningCache)) {
            $versioning = Config('database-encryption.versioning', null);
            $this->versioningCache = ! is_null($versioning) && is_bool($versioning) ? $versioning : self::isVersioningDefault();
        }
        return $this->versioningCache;
    }
    /**
     * Set the enabled flag inverse.
     *
     * @return null|bool
     */
    public function setVersionless(?bool $value = null): self
    {
        return $this->setVersioning(is_bool($value) ? ! $value : null);
    }
    /**
     * Check the versioning flag inverse.
     *
     * @return bool
     */
    public function isVersionless(): bool
    {
        return ! $this->isVersioning();
    }
    /**
     * Get the package version in parts.
     *
     * @return array
     */
    public function getVersionParts(?int $padding = null): array
    {
        if (! is_array($this->versionPartsCache)) {
            $this->versionPartsCache = [];
        }
        $padding = is_int($padding) && $padding === 0 ? null : $padding;
        $key = 'padding-'.(is_null($padding) ? 'null' : (string) $padding);
        if (! array_key_exists($key, $this->versionPartsCache)) {
            $parts = explode('.', $this->getVersion());
            $this->versionPartsCache[$key] = array_map(function ($part) use ($padding) {
                $part = (string) $part;
                if (is_null($padding)) {
                    return $part;
                }
                $length = strlen(is_string($part) ? $part : (string) $part);
                return $length == $padding ? $part : str_repeat('0', $padding - $length).$part;
            }, $parts);
        }
        return $this->versionPartsCache[$key];
    }
    /**
     * Get the package version for a prefix.
     *
     * @return string
     */
    public function getVersionForPrefix(int $padding = 2, string $glue = '-'): string
    {
        return 'VERSION-'.implode($glue, $this->getVersionParts($padding));
    }
    /**
     * Set the configured header prefix.
     *
     * @return EncryptionHelper
     */
    public function setHeaderPrefix(?string $value = null): self
    {
        throw_if(is_string($value) && strlen(trim($value)) == 0, RuntimeException::class,
                 'Cannot use empty string as header prefix.');
        $this->headerPrefixCache = $value;
        return $this;
    }
    /**
     * Get the configured header prefix.
     *
     * @return string
     */
    public function getHeaderPrefix(): string
    {
        if (is_null($this->headerPrefixCache)) {
            $characters = $this->getControlCharacters();
            $this->headerPrefixCache = $characters['header']['start']['string'].
                                       $characters['prefix']['start']['string'].
                                       $this->getPrefix().
                                       $characters['prefix']['stop']['string'];
        }
        return $this->headerPrefixCache;
    }
    /**
     * Build a header string, optionally with an object.
     *
     * @return string
     */
    public function buildHeader($object = null): string
    {
        $characters = $this->getControlCharacters();
        return $characters['header']['start']['string'].
               $characters['prefix']['start']['string'].
               $this->getPrefix().
               $characters['prefix']['stop']['string'].
               $characters['field']['start']['string'].
               'version'.
               $characters['field']['delimiter']['string'].
               self::getVersionForPrefix().
               $characters['field']['stop']['string'].
               (is_null($object) ? '' :
                   $characters['field']['start']['string'].
                   'type'.
                   $characters['field']['delimiter']['string'].
                   gettype($object).'['.(is_object($object) ? get_class($object) : 'native').']'.
                   $characters['field']['stop']['string']
               ).
               $characters['header']['stop']['string'];
    }
    /**
     * Set the configured prefix.
     *
     * @return EncryptionHelper
     */
    public function setPrefix(?string $value = null): self
    {
        throw_if(is_string($value) && strlen(trim($value)) == 0, RuntimeException::class,
                 'Cannot use empty string as prefix.');
        $this->prefixCache = is_string($value) && $this->isVersioning() ?
            str_replace('%VERSION%', $this->getVersionForPrefix(), $value) :
            $value;
        return $this;
    }
    /**
     * Get the configured prefix.
     *
     * @return string
     */
    public function getPrefix(): string
    {
        if (is_null($this->prefixCache)) {
            $prefix = Config::get('database-encryption.prefix', null);
            $prefix = ! empty($prefix) && is_string($prefix) ? $prefix : self::getPrefixDefault();
            $this->prefixCache = $this->isVersioning() ?
                str_replace('%VERSION%', $this->getVersionForPrefix(), $prefix) :
                $prefix;
        }
        return $this->prefixCache;
    }
    /**
     * Get the configured control characters.
     *
     * @return array
     */
    public function getControlCharacters(?string $type = null): array
    {
        $defaults = self::getControlCharactersDefault();
        $characters = self::getControlCharactersDefault();
        if (! is_null($type)) {
            throw_if(! array_key_exists($type, $characters),
                     'Control characters do not exist for $type: "'.(empty($type) ? '(empty)' : $type).'".');
            return $characters[$type];
        }
        return $characters;
    }
    /**
     * Get the singleton of this class.
     *
     * @return EncryptionHelper
     */
    public static function getInstance(): self
    {
        return EncryptionFacade::getInstance();
    }
}