DataContainer::getSchema()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Derafu: Biblioteca PHP (Núcleo).
7
 * Copyright (C) Derafu <https://www.derafu.org>
8
 *
9
 * Este programa es software libre: usted puede redistribuirlo y/o modificarlo
10
 * bajo los términos de la Licencia Pública General Affero de GNU publicada por
11
 * la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, o
12
 * (a su elección) cualquier versión posterior de la misma.
13
 *
14
 * Este programa se distribuye con la esperanza de que sea útil, pero SIN
15
 * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD
16
 * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la Licencia Pública
17
 * General Affero de GNU para obtener una información más detallada.
18
 *
19
 * Debería haber recibido una copia de la Licencia Pública General Affero de GNU
20
 * junto a este programa.
21
 *
22
 * En caso contrario, consulte <http://www.gnu.org/licenses/agpl.html>.
23
 */
24
25
namespace Derafu\Lib\Core\Support\Store;
26
27
use ArrayAccess;
28
use ArrayObject;
29
use Derafu\Lib\Core\Support\Store\Abstract\AbstractStore;
30
use Derafu\Lib\Core\Support\Store\Contract\DataContainerInterface;
31
use Symfony\Component\OptionsResolver\Options;
32
use Symfony\Component\OptionsResolver\OptionsResolver;
33
34
/**
35
 * Clase para contenedor de datos estructurados con schema.
36
 */
37
class DataContainer extends AbstractStore implements DataContainerInterface
38
{
39
    /**
40
     * Configuración del schema de datos.
41
     *
42
     * @var array
43
     */
44
    protected array $schema = [];
45
46
    /**
47
     * Constructor del contenedor.
48
     *
49
     * @param array|ArrayAccess|ArrayObject $data Datos iniciales.
50
     * @param array $schema Schema inicial.
51
     * @param bool $allowUndefinedKeys Permitir o no índices no definidos.
52
     */
53 69
    public function __construct(
54
        array|ArrayAccess|ArrayObject $data = [],
55
        array $schema = [],
56
        bool $allowUndefinedKeys = false
57
    ) {
58 69
        $this->setSchema($schema);
59 69
        if (!is_array($data)) {
0 ignored issues
show
introduced by
The condition is_array($data) is always true.
Loading history...
60 2
            $data = $this->createFrom($data)->toArray();
61
        }
62 69
        $data = $this->resolve($data, $this->schema, $allowUndefinedKeys);
63 66
        $this->data = $this->createFrom($data);
64
    }
65
66
    /**
67
     * {@inheritDoc}
68
     */
69 69
    public function setSchema(array $schema): static
70
    {
71 69
        $this->schema = $schema;
72
73 69
        return $this;
74
    }
75
76
    /**
77
     * {@inheritDoc}
78
     */
79 1
    public function getSchema(): array
80
    {
81 1
        return $this->schema;
82
    }
83
84
    /**
85
     * {@inheritDoc}
86
     */
87 38
    public function validate(bool $allowUndefinedKeys = false): void
88
    {
89 38
        $this->resolve($this->toArray(), $this->schema, $allowUndefinedKeys);
90
    }
91
92
    /**
93
     * Valida datos usando un esquema específico.
94
     *
95
     * @param array $data Datos a validar.
96
     * @param array $schema Esquema a usar.
97
     * @param bool $allowUndefinedKeys Permitir o no índices no definidos.
98
     * @return array Datos validados y normalizados.
99
     */
100 69
    private function resolve(
101
        array $data,
102
        array $schema,
103
        bool $allowUndefinedKeys = false
104
    ): array {
105
        // Si no hay esquema los datos son válidos como vienen.
106 69
        if (empty($schema)) {
107 13
            return $data;
108
        }
109
110
        // Determinar si se permitirán opciones no definidas en el esquema.
111 64
        $allowUndefinedKeys = $schema['__allowUndefinedKeys']
112 64
            ?? $allowUndefinedKeys
113 64
        ;
114 64
        unset($schema['__allowUndefinedKeys']);
115
116
        // Crear resolver y configurar.
117 64
        $resolver = new OptionsResolver();
118 64
        foreach ($schema as $key => $config) {
119
            // Configurar el nivel actual.
120 64
            if (!empty($config['types'])) {
121 64
                $resolver->setDefined([$key]);
122 64
                $resolver->setAllowedTypes($key, $config['types']);
123
            }
124
125 64
            if (!empty($config['required'])) {
126 7
                $resolver->setRequired([$key]);
127
            }
128
129 64
            if (!empty($config['choices'])) {
130 3
                $resolver->setAllowedValues($key, $config['choices']);
131
            }
132
133 64
            if (array_key_exists('default', $config)) {
134 59
                $resolver->setDefault($key, $config['default']);
135
            }
136
137
            // Si hay un schema anidado, configurar el normalizador.
138 64
            if (!empty($config['schema'])) {
139 20
                $resolver->setDefault($key, []);
140 20
                $resolver->setAllowedTypes($key, 'array');
141
142 20
                $resolver->setNormalizer(
143 20
                    $key,
144 20
                    fn (Options $options, $value) =>
145 20
                        $this->resolve(
146 20
                            $value ?? [],
147 20
                            $config['schema'],
148 20
                            $allowUndefinedKeys
149 20
                        )
150 20
                );
151 64
            } elseif (!empty($config['normalizer'])) {
152 3
                $resolver->setNormalizer($key, $config['normalizer']);
153
            }
154
        }
155
156
        // Permitir opciones adicionales no definidas.
157 64
        if ($allowUndefinedKeys) {
158
            $resolver->setDefined(array_keys($data));
159
        }
160
161
        // Resolver las opciones.
162 64
        return $resolver->resolve($data);
163
    }
164
}
165