Passed
Push — master ( d81008...ac8897 )
by Esteban De La Fuente
05:19
created

DataFormatter   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 151
Duplicated Lines 0 %

Test Coverage

Coverage 58.54%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 39
dl 0
loc 151
ccs 24
cts 41
cp 0.5854
rs 10
c 1
b 0
f 0
wmc 19

8 Methods

Rating   Name   Duplication   Size   Complexity  
A setHandlers() 0 5 1
A getHandlers() 0 3 1
A toString() 0 21 6
A addHandler() 0 7 1
A getHandler() 0 3 1
A __construct() 0 6 1
A handle() 0 11 3
A format() 0 24 5
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\Package\Prime\Component\Template\Service;
26
27
use Derafu\Lib\Core\Package\Prime\Component\Template\Contract\DataFormatterInterface;
28
use Derafu\Lib\Core\Package\Prime\Component\Template\Contract\DataHandlerInterface;
29
use Derafu\Lib\Core\Support\Store\Contract\RepositoryInterface;
30
use Throwable;
31
32
/**
33
 * Servicio de formateo de datos.
34
 *
35
 * Permite recibir un valor y formatearlo según un mapa de handlers predefinido
36
 * mediante su identificador.
37
 */
38
class DataFormatter implements DataFormatterInterface
39
{
40
    /**
41
     * Mapeo de identificadores a la forma que se usará para darle formato a los
42
     * valores asociados al identificador.
43
     *
44
     * @var array<string,string|array|callable|DataHandlerInterface|RepositoryInterface>
45
     */
46
    private array $handlers;
47
48
    /**
49
     * Handler por defecto de los formatos.
50
     *
51
     * @var DataHandlerInterface
52
     */
53
    private DataHandlerInterface $handler;
54
55
    /**
56
     * Constructor del servicio.
57
     *
58
     * @param array $handlers Mapa de handlers para los formatos.
59
     * @param DataHandlerInterface|null $handler Handler por defecto a usar.
60
     */
61 2
    public function __construct(
62
        array $handlers = [],
63
        ?DataHandlerInterface $handler = null
64
    ) {
65 2
        $this->setHandlers($handlers);
66 2
        $this->handler = $handler ?? new DataHandler();
67
    }
68
69
    /**
70
     * {@inheritDoc}
71
     */
72 2
    public function setHandlers(array $handlers): static
73
    {
74 2
        $this->handlers = $handlers;
75
76 2
        return $this;
77
    }
78
79
    /**
80
     * {@inheritDoc}
81
     */
82
    public function getHandlers(): array
83
    {
84
        return $this->handlers;
85
    }
86
87
    /**
88
     * {@inheritDoc}
89
     */
90 2
    public function addHandler(
91
        string $id,
92
        string|array|callable|DataHandlerInterface|RepositoryInterface $handler
93
    ): static {
94 2
        $this->handlers[$id] = $handler;
95
96 2
        return $this;
97
    }
98
99
    /**
100
     * {@inheritDoc}
101
     */
102
    public function getHandler(string $id): string|array|callable|DataHandlerInterface|RepositoryInterface|null
103
    {
104
        return $this->handlers[$id] ?? null;
105
    }
106
107
    /**
108
     * {@inheritDoc}
109
     */
110 2
    public function format(string $id, mixed $data): string
111
    {
112
        // El ID es el formato.
113 2
        if (isset($this->handlers[$id])) {
114 2
            return $this->handle($id, $id, $data);
115
        }
116
117
        // Si no hay handler exacto revisar si el ID tiene partes. Si el ID
118
        // tiene partes se busca si la primera parte está definida como handler.
119 2
        if (str_contains($id, '.')) {
120
            // Separar en handler e ID y si existe el formato se usa.
121
            [$handler, $id] = explode('.', $id, 2);
122
            if (isset($this->handlers[$handler])) {
123
                return $this->handle($handler, $id, $data);
124
            }
125
        }
126
127
        // Buscar si hay un handler genérico (comodín).
128 2
        if (isset($this->handlers['*'])) {
129
            return $this->handle('*', $id, $data);
130
        }
131
132
        // Si no hay handler para manejar se tratará de convertir a string.
133 2
        return $this->toString($data);
134
    }
135
136
    /**
137
     * Maneja el formateo de los datos según cierto handler.
138
     *
139
     * @param string $name Nombre del handler registrado que se debe utilizar.
140
     * @param string $id Identificador pasado del formato.
141
     * @param mixed $data Datos a formatear.
142
     * @return string Datos formateados.
143
     */
144 2
    private function handle(string $name, string $id, mixed $data): string
145
    {
146 2
        $handler = $this->handlers[$name];
147
148 2
        if ($handler instanceof DataHandlerInterface) {
149
            return $handler->handle($id, $data);
150
        } else {
151 2
            if ($this->handler instanceof DataHandler) {
152 2
                return $this->handler->handle($id, $data, $handler);
0 ignored issues
show
Unused Code introduced by
The call to Derafu\Lib\Core\Package\...dlerInterface::handle() has too many arguments starting with $handler. ( Ignorable by Annotation )

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

152
                return $this->handler->/** @scrutinizer ignore-call */ handle($id, $data, $handler);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
153
            } else {
154
                return $this->handler->handle($id, $data);
155
            }
156
        }
157
    }
158
159
    /**
160
     * Hace el mejor esfuerzo para tratar de convertir los datos a string.
161
     *
162
     * Si falla al serializar a string se entregará un string con el tipo de
163
     * dato de lo que se trató de serializar y el error por el cual falló.
164
     *
165
     * @param mixed $data
166
     * @return string
167
     */
168 2
    private function toString(mixed $data): string
169
    {
170
        // Si se puede convertir fácilmente, retornar los datos casteados.
171 2
        if (is_scalar($data) || $data === null) {
172
            return (string) $data;
173
        }
174
175
        // Si es objeto e implementa __toString() se usa.
176 2
        if (is_object($data) && method_exists($data, '__toString')) {
177
            return (string) $data;
178
        }
179
180
        // Para arreglos, objetos que no tengan __toString() y otros tipos,
181
        // serializar con JSON.
182
        try {
183 2
            return json_encode($data, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR);
184
        } catch (Throwable $e) {
185
            return sprintf(
186
                'La serialización para el tipo de dato %s falló: %s',
187
                get_debug_type($data),
188
                $e->getMessage()
189
            );
190
        }
191
    }
192
}
193