DecoderWorker::arrayAddChilds()   C
last analyzed

Complexity

Conditions 12
Paths 12

Size

Total Lines 54
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 23
CRAP Score 14.4758

Importance

Changes 0
Metric Value
cc 12
eloc 33
c 0
b 0
f 0
nc 12
nop 4
dl 0
loc 54
ccs 23
cts 31
cp 0.7419
crap 14.4758
rs 6.9666

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Xml\Worker;
26
27
use Derafu\Lib\Core\Foundation\Abstract\AbstractWorker;
28
use Derafu\Lib\Core\Package\Prime\Component\Xml\Contract\DecoderWorkerInterface;
29
use Derafu\Lib\Core\Package\Prime\Component\Xml\Contract\XmlInterface;
30
use DOMElement;
31
use DOMNodeList;
32
use DOMText;
33
34
/**
35
 * Clase que crea un arreglo PHP a partir de un documento XML.
36
 */
37
class DecoderWorker extends AbstractWorker implements DecoderWorkerInterface
38
{
39
    /**
40
     * {@inheritDoc}
41
     */
42 21
    public function decode(
43
        XmlInterface|DOMElement $documentElement,
44
        ?array &$data = null,
45
        bool $twinsAsArray = false
46
    ): array {
47
        // Si no viene un tagElement se busca uno, si no se obtiene se termina
48
        // la generación.
49 21
        $tagElement = $documentElement instanceof DOMElement
50 18
            ? $documentElement
51 21
            : $documentElement->getDocumentElement()
52 21
        ;
53 21
        if ($tagElement === null) {
54 1
            return [];
55
        }
56
57
        // Índice en el arreglo que representa al tag. Además es un nombre de
58
        // variable más corto :)
59 20
        $key = $tagElement->tagName;
60
61
        // Si no hay un arreglo de destino para los datos se crea un arreglo
62
        // con el índice del nodo principal con valor vacío.
63 20
        if ($data === null) {
64
            //$data = [$key => self::getEmptyValue()];
65 20
            $data = [$key => null];
66
        }
67
68
        // Si el tagElement tiene atributos se agregan al arreglo dentro del
69
        // índice especial '@attributes'.
70 20
        if ($tagElement->hasAttributes()) {
71 7
            $data[$key]['@attributes'] = [];
72 7
            foreach ($tagElement->attributes as $attribute) {
73 7
                $data[$key]['@attributes'][$attribute->name] = $attribute->value;
74
            }
75
        }
76
77
        // Si el tagElement tiene nodos hijos se agregan al valor del tag.
78 20
        if ($tagElement->hasChildNodes()) {
79 20
            self::arrayAddChilds(
0 ignored issues
show
Bug Best Practice introduced by
The method Derafu\Lib\Core\Package\...orker::arrayAddChilds() is not static, but was called statically. ( Ignorable by Annotation )

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

79
            self::/** @scrutinizer ignore-call */ 
80
                  arrayAddChilds(
Loading history...
80 20
                $data,
81 20
                $tagElement,
82 20
                $tagElement->childNodes,
83 20
                $twinsAsArray
84 20
            );
85
        }
86
87
        // Entregar los datos del documento XML como un arreglo.
88 20
        return $data;
89
    }
90
91
    /**
92
     * Agrega nodos hijos de un documento XML a un arreglo PHP.
93
     *
94
     * @param array &$data Arreglo donde se agregarán los nodos hijos.
95
     * @param DOMElement $tagElement Nodo padre del que se extraerán los nodos
96
     * hijos.
97
     * @param DOMNodeList $childs Lista de nodos hijos del nodo padre.
98
     * @param bool $twinsAsArray Indica si se deben tratar los nodos gemelos
99
     * como un arreglo.
100
     * @return void
101
     */
102 20
    private function arrayAddChilds(
103
        array &$data,
104
        DOMElement $tagElement,
105
        DOMNodeList $childs,
106
        bool $twinsAsArray,
107
    ): void {
108 20
        $key = $tagElement->tagName;
109
        // Se recorre cada uno de los nodos hijos.
110 20
        foreach ($childs as $child) {
111 20
            if ($child instanceof DOMText) {
112 16
                $textContent = trim($child->textContent);
113 16
                if ($textContent !== '') {
114 16
                    if ($tagElement->hasAttributes()) {
115 2
                        $data[$key]['@value'] = $textContent;
116 14
                    } elseif ($childs->length === 1 && empty($data[$key])) {
117 14
                        $data[$key] = $textContent;
118
                    } else {
119
                        $array[$key]['@value'] = $textContent;
120
                    }
121
                }
122 20
            } elseif ($child instanceof DOMElement) {
123 20
                $n_twinsNodes = self::nodeCountTwins(
0 ignored issues
show
Bug Best Practice introduced by
The method Derafu\Lib\Core\Package\...orker::nodeCountTwins() is not static, but was called statically. ( Ignorable by Annotation )

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

123
                /** @scrutinizer ignore-call */ 
124
                $n_twinsNodes = self::nodeCountTwins(
Loading history...
124 20
                    $tagElement,
125 20
                    $child->tagName
126 20
                );
127 20
                if ($n_twinsNodes === 1) {
128 18
                    if ($twinsAsArray) {
129
                        self::decode($child, $data);
0 ignored issues
show
Bug Best Practice introduced by
The method Derafu\Lib\Core\Package\...DecoderWorker::decode() is not static, but was called statically. ( Ignorable by Annotation )

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

129
                        self::/** @scrutinizer ignore-call */ 
130
                              decode($child, $data);
Loading history...
130
                    } else {
131 18
                        self::decode($child, $data[$key]);
132
                    }
133
                } else {
134
                    // Se crea una lista para el nodo hijo, pues tiene varios
135
                    // nodos iguales el XML.
136 2
                    if (!isset($data[$key][$child->tagName])) {
137 2
                        $data[$key][$child->tagName] = [];
138
                    }
139
140
                    // Se revisa si el nodo hijo es escalar. Si lo es, se añade
141
                    // a la lista directamente.
142 2
                    $textContent = trim($child->textContent);
143 2
                    if ($textContent !== '') {
144 2
                        $data[$key][$child->tagName][] = $textContent;
145
                    }
146
                    // Si el nodo hijo es un escalar, sino que es una lista de
147
                    // nodos, se construye como si fuese un arreglo normal con
148
                    // la llamada a decode().
149
                    else {
150
                        $siguiente = count($data[$key][$child->tagName]);
151
                        $data[$key][$child->tagName][$siguiente] = [];
152
                        self::decode(
153
                            $child,
154
                            $data[$key][$child->tagName][$siguiente],
155
                            true
156
                        );
157
                    }
158
                }
159
            }
160
        }
161
    }
162
163
    /**
164
     * Cuenta los nodos con el mismo nombre hijos de un DOMElement.
165
     *
166
     * @param DOMElement $dom Elemento DOM donde se buscarán los nodos.
167
     * @param string $tagName Nombre del tag a contar.
168
     * @return int Cantidad de nodos hijos con el mismo nombre.
169
     */
170 20
    private function nodeCountTwins(DOMElement $dom, string $tagName): int
171
    {
172 20
        $twins = 0;
173 20
        foreach ($dom->childNodes as $child) {
174 20
            if ($child instanceof DOMElement && $child->tagName === $tagName) {
175 20
                $twins++;
176
            }
177
        }
178
179 20
        return $twins;
180
    }
181
}
182