Passed
Push — master ( 66ce43...256ff6 )
by Esteban De La Fuente
08:40
created

DocumentoParser   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 117
Duplicated Lines 0 %

Test Coverage

Coverage 70%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 33
dl 0
loc 117
ccs 21
cts 30
cp 0.7
rs 10
c 1
b 0
f 0
wmc 8

3 Methods

Rating   Name   Duplication   Size   Complexity  
A getParserInstance() 0 21 3
A getParserClass() 0 22 2
A parse() 0 20 3
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * LibreDTE: Biblioteca PHP (Núcleo).
7
 * Copyright (C) LibreDTE <https://www.libredte.cl>
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
11
 * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia,
12
 * o (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
20
 * GNU junto a este programa.
21
 *
22
 * En caso contrario, consulte <http://www.gnu.org/licenses/agpl.html>.
23
 */
24
25
namespace libredte\lib\Core\Sii\Dte\Documento\Parser;
26
27
/**
28
 * Clase que maneja el análisis sintáctico de los datos de un documento.
29
 *
30
 * Se encarga de tomar los datos en cierto formato y transformarlos a un formato
31
 * estándarizado para ser usado en LibreDTE como un arreglo PHP con los datos en
32
 * la estructura oficial del SII.
33
 */
34
class DocumentoParser
35
{
36
    /**
37
     * Parser por defecto que se debe utilizar al analizar los datos si no se
38
     * ha especificado uno al llamar al método DocumentoParser::parse().
39
     *
40
     * @var string
41
     */
42
    protected string $defaultParser = 'sii.json';
43
44
    /**
45
     * Alias de parsers.
46
     *
47
     * Esto es por compatibilidad hacia atrás y simplificación en el uso de los
48
     * parsers estándares de LibreDTE que usan el formato oficial del SII.
49
     *
50
     * @var array
51
     */
52
    protected array $parsersAlias = [
53
        'json' => 'sii.json',
54
        'yaml' => 'sii.yaml',
55
        'xml' => 'sii.xml',
56
    ];
57
58
    /**
59
     * Listado de parsers instanciados para ser reutilizados.
60
     *
61
     * @var array<string,DocumentoParserInterface>
62
     */
63
    protected array $parsers = [];
64
65
    /**
66
     * Ejecuta el análisis sintáctico (parseo) de los datos.
67
     *
68
     * @param string|array $data Datos del documento a transformar.
69
     * @return array Arreglo con los datos transformados.
70
     * @throws DocumentoParserException Si existe un error al parsear los datos.
71
     */
72 6
    public function parse(string|array $data, string $parser = null): array
73
    {
74
        // Si no se indicó parser se usa el por defecto.
75 6
        if ($parser === null) {
76
            $parser = $this->defaultParser;
77
        }
78
79
        // Si el parser es un alias se ajusta el nombre del parser al real.
80 6
        if (isset($this->parsersAlias[$parser])) {
81
            $parser = $this->parsersAlias[$parser];
82
        }
83
84
        // Obtener la instancia del parser real.
85 6
        $parser = $this->getParserInstance($parser);
86
87
        // Llamar al parser para transformar los datos.
88 6
        $parsedData = $parser->parse($data);
0 ignored issues
show
Bug introduced by
$data of type array is incompatible with the type string expected by parameter $data of libredte\lib\Core\Sii\Dt...arserInterface::parse(). ( Ignorable by Annotation )

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

88
        $parsedData = $parser->parse(/** @scrutinizer ignore-type */ $data);
Loading history...
89
90
        // Entregar los datos transformados.
91 6
        return $parsedData;
92
    }
93
94
    /**
95
     * Obtiene la instancia de un parser.
96
     *
97
     * @param string $parser Nombre del parser que se desea obtener.
98
     * @return DocumentoParserInterface Instancia del parser.
99
     */
100 6
    private function getParserInstance(string $parser): DocumentoParserInterface
101
    {
102
        // Si el parser no está previamente cargado se carga.
103 6
        if (!isset($this->parsers[$parser])) {
104
            // Determinar la clase del parser solicitado.
105 6
            $class = $this->getParserClass($parser);
106
107
            // Si la clase del parser no existe error.
108 6
            if (!class_exists($class)) {
109
                throw new DocumentoParserException(sprintf(
110
                    'El analizador sintáctico (parser) con el formato %s no existe.',
111
                    $parser
112
                ));
113
            }
114
115
            // Instanciar el parser.
116 6
            $this->parsers[$parser] = new $class;
117
        }
118
119
        // Entregar la instancia del parser.
120 6
        return $this->parsers[$parser];
121
    }
122
123
    /**
124
     * Determina la clase del parser que se está solicitando.
125
     *
126
     * @param string $parser Nombre del parser solicitado.
127
     * @return string FQCN de la clase del parser solicitado.
128
     */
129 6
    private function getParserClass(string $parser): string
130
    {
131
        // Determinar nombre del archivo PHP y de la clase.
132 6
        $parts = array_map(function ($part) {
133 6
            return ucfirst(strtolower($part));
134 6
        }, explode('.', $parser));
135 6
        $file = __DIR__ . '/' . implode('/', $parts) . 'Parser.php';
136 6
        $class = implode('\\', $parts) . 'Parser';
137
138
        // La clase existe en el namespace actual.
139 6
        if (file_exists($file)) {
140 6
            $class = __NAMESPACE__ . '\\' . $class;
141
        }
142
        // La clase podría existir en lib-pro.
143
        else {
144
            $class = str_replace('\\Core\\', '\\Pro\\', __NAMESPACE__)
145
                . '\\' . $class
146
            ;
147
        }
148
149
        // Entregar el FQCN de la clase del parser buscado.
150 6
        return $class;
151
    }
152
}
153