Passed
Branch master (31dbc0)
by Wilder
01:22
created

Option::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 4
rs 10
1
<?php
2
3
namespace ElePHPant\Cookie\ValueObjects;
4
5
use ElePHPant\Cookie\Strategies\Encryption\EncryptionStrategyInterface;
6
use ElePHPant\Cookie\Exceptions\{
7
    EmptyValuesException,
8
    InvalidOptionException,
9
    InvalidValueException,
10
    MissingDriversException
11
};
12
13
/**
14
 * Class Option
15
 *
16
 * Please report bugs on https://github.com/wilderamorim/cookie/issues
17
 *
18
 * @author Wilder Amorim <https://github.com/wilderamorim>
19
 * @link https://www.linkedin.com/in/wilderamorim/
20
 */
21
final class Option
22
{
23
    /** @var array */
24
    private array $options = [];
25
26
    /** @var array */
27
    private array $requiredDrivers = [];
28
29
    /**
30
     * @param array $options The options to be validated.
31
     * @throws MissingDriversException If any required driver is missing.
32
     * @throws EmptyValuesException If any required driver has an empty value.
33
     * @throws InvalidOptionException If there are invalid option keys.
34
     * @throws InvalidValueException If there are invalid option values.
35
     */
36
    public function __construct(array $options)
37
    {
38
        $this->validate($options);
39
        $this->options = $options;
40
    }
41
42
    /**
43
     * @return array
44
     */
45
    public function toArray(): array
46
    {
47
        return $this->options;
48
    }
49
50
    /**
51
     * Validate the options by performing various validation checks.
52
     *
53
     * @param array $options The options to be validated.
54
     * @throws MissingDriversException If any required driver is missing.
55
     * @throws EmptyValuesException If any required driver has an empty value.
56
     * @throws InvalidOptionException If there are invalid option keys.
57
     * @throws InvalidValueException If there are invalid option values.
58
     * @return void
59
     */
60
    private function validate(array $options): void
61
    {
62
        $this->validateRequiredDrivers($options);
63
        $this->validateEmptyValues($options);
64
        $this->validateOptions($options);
65
        $this->validateValues($options);
66
    }
67
68
    /**
69
     * Validate the presence of required drivers in the options.
70
     *
71
     * @param array $options The options to be validated.
72
     * @throws MissingDriversException If any required driver is missing.
73
     * @return void
74
     */
75
    private function validateRequiredDrivers(array $options): void
76
    {
77
        $missingDrivers = array_diff($this->requiredDrivers, array_keys($options));
78
        if (!empty($missingDrivers)) {
79
            throw new MissingDriversException($missingDrivers);
80
        }
81
    }
82
83
    /**
84
     * Validate the absence of empty values for required drivers in the options.
85
     *
86
     * @param array $options The options to be validated.
87
     * @throws EmptyValuesException If any required driver has an empty value.
88
     * @return void
89
     */
90
    private function validateEmptyValues(array $options): void
91
    {
92
        $emptyValues = array_filter(
93
            $options, fn($value, $key) => empty($value) && in_array($key, $this->requiredDrivers), ARRAY_FILTER_USE_BOTH
94
        );
95
        if (!empty($emptyValues)) {
96
            throw new EmptyValuesException(array_keys($emptyValues));
97
        }
98
    }
99
100
    /**
101
     * Validate the options by checking if the keys are valid and expected.
102
     *
103
     * @param array $options The options to be validated.
104
     * @throws InvalidOptionException If there are invalid option keys.
105
     * @return void
106
     */
107
    private function validateOptions(array $options): void
108
    {
109
        $invalidOptions = array_diff_key($options, $this->getValidations($options));
110
        if (!empty($invalidOptions)) {
111
            throw new InvalidOptionException(array_keys($invalidOptions));
112
        }
113
    }
114
115
    /**
116
     * Validate the values of the options based on the defined validations.
117
     *
118
     * @param array $options The options to be validated.
119
     * @throws InvalidValueException If there are invalid option values.
120
     * @return void
121
     */
122
    private function validateValues(array $options): void
123
    {
124
        $validations = $this->getValidations($options);
125
        $invalidValues = array_filter($options, fn($value, $key) => !$validations[$key]($value), ARRAY_FILTER_USE_BOTH);
126
        if (!empty($invalidValues)) {
127
            throw new InvalidValueException(array_keys($invalidValues));
128
        }
129
    }
130
131
    /**
132
     * Get the array of validations for the options.
133
     *
134
     * @param array $options The options for which to retrieve validations.
135
     * @return \Closure[] An array of validations for the options.
136
     */
137
    private function getValidations(array $options): array
138
    {
139
        return [
140
            'expiration' => fn($value) => new Expiration($value),
141
            'encryption' => fn($value) => (new $value($options) instanceof EncryptionStrategyInterface),
142
            'encrypt_key' => fn($value) => is_string($value),
143
            'path' => fn($value) => is_string($value) && strpos($value, '/') === 0,
144
            'domain' => fn($value) => filter_var($value, FILTER_VALIDATE_DOMAIN),
145
            'secure' => fn($value) => is_bool($value),
146
            'httponly' => fn($value) => is_bool($value),
147
        ];
148
    }
149
}
150