DocumentBagManagerWorker::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 0
c 1
b 0
f 0
nc 1
nop 9
dl 0
loc 11
ccs 1
cts 1
cp 1
crap 1
rs 10

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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 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
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\Package\Billing\Component\Document\Worker;
26
27
use Derafu\Lib\Core\Foundation\Abstract\AbstractWorker;
28
use Derafu\Lib\Core\Package\Prime\Component\Entity\Contract\EntityComponentInterface;
29
use Derafu\Lib\Core\Package\Prime\Component\Xml\Contract\XmlComponentInterface;
30
use Derafu\Lib\Core\Package\Prime\Component\Xml\Contract\XmlInterface;
31
use libredte\lib\Core\Package\Billing\Component\Document\Contract\BuilderWorkerInterface;
32
use libredte\lib\Core\Package\Billing\Component\Document\Contract\DocumentBagInterface;
33
use libredte\lib\Core\Package\Billing\Component\Document\Contract\DocumentBagManagerWorkerInterface;
34
use libredte\lib\Core\Package\Billing\Component\Document\Contract\DocumentInterface;
35
use libredte\lib\Core\Package\Billing\Component\Document\Contract\NormalizerWorkerInterface;
36
use libredte\lib\Core\Package\Billing\Component\Document\Contract\ParserWorkerInterface;
37
use libredte\lib\Core\Package\Billing\Component\Document\Contract\SanitizerWorkerInterface;
38
use libredte\lib\Core\Package\Billing\Component\Document\Contract\TipoDocumentoInterface;
39
use libredte\lib\Core\Package\Billing\Component\Document\Contract\ValidatorWorkerInterface;
40
use libredte\lib\Core\Package\Billing\Component\Document\Exception\DocumentBagManagerException;
41
use libredte\lib\Core\Package\Billing\Component\Document\Support\DocumentBag;
42
use libredte\lib\Core\Package\Billing\Component\TradingParties\Contract\EmisorFactoryInterface;
43
use libredte\lib\Core\Package\Billing\Component\TradingParties\Contract\ReceptorFactoryInterface;
44
45
/**
46
 * Clase para el administrador de la bolsa con los datos de un DTE.
47
 */
48
class DocumentBagManagerWorker extends AbstractWorker implements DocumentBagManagerWorkerInterface
49
{
50
    protected $documentBagClass = DocumentBag::class;
51
52 120
    public function __construct(
53
        private XmlComponentInterface $xmlComponent,
54
        private BuilderWorkerInterface $builderWorker,
55
        private ParserWorkerInterface $parserWorker,
56
        private NormalizerWorkerInterface $normalizerWorker,
57
        private SanitizerWorkerInterface $sanitizerWorker,
58
        private ValidatorWorkerInterface $validatorWorker,
59
        private EntityComponentInterface $entityComponent,
60
        private EmisorFactoryInterface $emisorFactory,
61
        private ReceptorFactoryInterface $receptorFactory
62
    ) {
63 120
    }
64
65
    /**
66
     * {@inheritDoc}
67
     */
68 112
    public function create(
69
        string|array|XmlInterface|DocumentInterface $source,
70
        bool $normalizeAll = true
71
    ): DocumentBagInterface {
72
        // Asignar (si se pasó) o crear la bolsa.
73 112
        $class = $this->documentBagClass;
74 112
        $bag = new $class();
75
76
        // Si los datos vienen como string se deben parsear para asignar.
77
        // Además se normalizarán.
78 112
        if (is_string($source)) {
0 ignored issues
show
introduced by
The condition is_string($source) is always false.
Loading history...
79
            $aux = explode(':', $source, 1);
80
            $parserStrategy = str_replace('parser.strategy.', '', $aux[0]);
81
            $inputData = $aux[1] ?? '';
82
            $bag->setInputData($inputData);
83
            $bag->getOptions()->set('parser.strategy', $parserStrategy);
84
            $$this->parserWorker->parse($bag);
85
        }
86
87
        // Si los datos vienen como arreglo son los datos normalizados.
88 112
        if (is_array($source)) {
0 ignored issues
show
introduced by
The condition is_array($source) is always true.
Loading history...
89 1
            $bag->setNormalizedData($source);
90
        }
91
92
        // Si los datos vienen como documento XML es un XML cargado desde un
93
        // string XML (carga realizada por LoaderWorker). Ya viene normalizado.
94 112
        if ($source instanceof XmlInterface) {
0 ignored issues
show
introduced by
$source is never a sub-type of Derafu\Lib\Core\Package\...l\Contract\XmlInterface.
Loading history...
95 112
            $bag->setXmlDocument($source);
96
        }
97
98
        // Si los datos vienen como documento tributario entonces es un
99
        // documento que ya está creado. Puede estar o no timbrado y firmado,
100
        // eso no se determina ni valida acá. Si debe estará normalizado.
101 112
        if ($source instanceof DocumentInterface) {
0 ignored issues
show
introduced by
$source is never a sub-type of libredte\lib\Core\Packag...tract\DocumentInterface.
Loading history...
102
            $bag->setDocument($source);
103
        }
104
105
        // Normalizar los datos de la bolsa según otros datos que contenga.
106 112
        $bag = $this->normalize($bag, all: $normalizeAll);
107
108
        // Entregar la bolsa creada.
109 112
        return $bag;
110
    }
111
112
    /**
113
     * {@inheritDoc}
114
     */
115 120
    public function normalize(
116
        DocumentBagInterface $bag,
117
        bool $all = false
118
    ): DocumentBagInterface {
119
        // Datos esenciales que se normalizan.
120 120
        $this->ensureParsedData($bag);
121 120
        $this->ensureTipoDocumento($bag);
122
123
        // Datos extras que se pueden normalizar si se solicitó normalizar todo.
124 118
        if ($all === true) {
125 116
            $this->ensureNormalizedData($bag);
126 116
            $this->ensureXmlDocument($bag);
127 116
            $this->ensureDocument($bag);
128 116
            $this->ensureEmisor($bag);
129 116
            $this->ensureReceptor($bag);
130
        }
131
132
        // Entregar la bolsa normalizada.
133 118
        return $bag;
134
    }
135
136
    /**
137
     * Asegura que existan datos parseados en la bolsa si existen datos de
138
     * entrada para poder determinarlo y no está asignado previamente.
139
     *
140
     * Requiere: $bag->getInputData().
141
     *
142
     * Además, si los datos no usan la estrategia por defecto de parseo se debe
143
     * indicar en las opciones de la bolsa.
144
     *
145
     * @param DocumentBagInterface $bag
146
     * @return void
147
     */
148 120
    protected function ensureParsedData(DocumentBagInterface $bag): void
149
    {
150
        // Verificar si es necesario, y se puede, asignar.
151 120
        if ($bag->getParsedData() || !$bag->getInputData()) {
152 116
            return;
153
        }
154
155
        // Parsear los datos.
156 60
        $this->parserWorker->parse($bag);
157
    }
158
159
    /**
160
     * Asegura que exista un tipo de documento en la bolsa si existen datos para
161
     * poder determinarlo y no está asignado previamente.
162
     *
163
     * Requiere: $bag->getParsedData().
164
     *
165
     * @param DocumentBagInterface $bag
166
     * @return void
167
     */
168 120
    protected function ensureTipoDocumento(DocumentBagInterface $bag): void
169
    {
170
        // Verificar si es necesario, y se puede, asignar.
171 120
        if ($bag->getTipoDocumento() || !$bag->getCodigoTipoDocumento()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $bag->getCodigoTipoDocumento() of type integer|null is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
172 108
            return;
173
        }
174
175
        // Buscar el tipo de documento tributario que se desea construir.
176 117
        $codigoTipoDocumento = $bag->getCodigoTipoDocumento();
177 117
        $tipoDocumento = $this->entityComponent
178 117
            ->getRepository(TipoDocumentoInterface::class)
179 117
            ->find($codigoTipoDocumento)
180 117
        ;
181
182
        // Si el documento no existe error.
183 117
        if (!$tipoDocumento) {
184
            throw new DocumentBagManagerException(sprintf(
185
                'No se encontró un código de documento tributario válido en los datos del DTE.'
186
            ));
187
        }
188
189
        // Asignar el tipo documento a la bolsa.
190 117
        $bag->setTipoDocumento($tipoDocumento);
191
    }
192
193
    /**
194
     * Asegura que existan los datos normalizados en la bolsa si existen datos
195
     * parseados para poder determinarlo y no está asignado previamente.
196
     *
197
     * Los datos normalizados también se pueden crear si existe un XmlDocument
198
     * o un DTE.
199
     *
200
     * Requiere: $bag->getParsedData() o $bag->getXmlDocument() o $bag->getDocument().
201
     *
202
     * @param DocumentBagInterface $bag
203
     * @return void
204
     */
205 116
    protected function ensureNormalizedData(DocumentBagInterface $bag): void
206
    {
207
        // Verificar si es necesario, y se puede, asignar.
208 116
        if ($bag->getNormalizedData()) {
209 107
            return;
210
        }
211
212
        // Construir los datos normalizados a partir de los datos parseados.
213 9
        if ($bag->getParsedData()) {
214
            // Normalizar los datos del documento de la bolsa si corresponde.
215
            $normalize = $bag->getNormalizerOptions()['normalize'] ?? true;
216
            if ($normalize) {
217
                // Normalizar los datos parseados de la bolsa.
218
                $this->normalizerWorker->normalize($bag);
219
220
                // Sanitizar los datos normalizados de la bolsa.
221
                $this->sanitizerWorker->sanitize($bag);
222
223
                // Validar los datos normalizados y sanitizados de la bolsa.
224
                $this->validatorWorker->validate($bag);
225
            }
226
        }
227
228
        // Construir los datos normalizados a partir del documento XML.
229
        // Importante: se asume que el documento XML se cargó desde un XML que
230
        // es válido y por ende normalizado.
231 9
        elseif ($bag->getXmlDocument()) {
232 9
            $normalizedData = $this->xmlComponent->getDecoderWorker()->decode(
233 9
                $bag->getXmlDocument()
234 9
            );
235 9
            $bag->setNormalizedData($normalizedData);
236
        }
237
238
        // Construir los datos normalizados a partir del DTE.
239
        // Importante: se asume que el DTE se cargó desde un XML que
240
        // es válido y por ende normalizado.
241
        elseif ($bag->getDocument()) {
242
            $normalizedData = $this->xmlComponent->getDecoderWorker()->decode(
243
                $bag->getDocument()->getXmlDocument()
244
            );
245
            $bag->setNormalizedData($normalizedData);
246
        }
247
    }
248
249
    /**
250
     * Asegura que existan un documento XML en la bolsa si existen datos
251
     * normalizados para poder determinarlo y no está asignado previamente.
252
     *
253
     * El XmlDocument también se puede crear si existe DTE.
254
     *
255
     * Requiere: $bag->getNormalizedData() o $bag->getDocument().
256
     *
257
     * @param DocumentBagInterface $bag
258
     * @return void
259
     */
260 116
    protected function ensureXmlDocument(DocumentBagInterface $bag): void
261
    {
262
        // Verificar si es necesario, y se puede, asignar.
263 116
        if ($bag->getXmlDocument()) {
264 116
            return;
265
        }
266
267
        // Construir el XmlDocument a partir de los datos normalizados.
268 1
        if ($bag->getNormalizedData()) {
269 1
            $tagXml = $bag->getTipoDocumento()->getTagXml()->getNombre();
270 1
            $xmlDocumentData = [
271 1
                'DTE' => [
272 1
                    '@attributes' => [
273 1
                        'version' => '1.0',
274 1
                        'xmlns' => 'http://www.sii.cl/SiiDte',
275 1
                    ],
276 1
                    $tagXml => array_merge([
277 1
                        '@attributes' => [
278 1
                            'ID' => $bag->getId(),
279 1
                        ],
280 1
                    ], $bag->getNormalizedData()),
281 1
                ],
282 1
            ];
283 1
            $xmlDocument = $this->xmlComponent->getEncoderWorker()->encode(
284 1
                $xmlDocumentData
285 1
            );
286 1
            $bag->setXmlDocument($xmlDocument);
287
        }
288
289
        // Asignar el XmlDocument a partir del DTE.
290
        elseif ($bag->getDocument()) {
291
            $bag->setXmlDocument($bag->getDocument()->getXmlDocument());
292
        }
293
    }
294
295
    /**
296
     * Asegura que existan un DTE en la bolsa si existe un XmlDocument
297
     * para poder crearlo y no está asignado previamente.
298
     *
299
     * Requiere: $bag->getXmlDocument() y $bag->getTipoDocumento().
300
     *
301
     * @param DocumentBagInterface $bag
302
     * @return void
303
     */
304 116
    protected function ensureDocument(DocumentBagInterface $bag): void
305
    {
306
        // Verificar si es necesario, y se puede, asignar.
307 116
        if ($bag->getDocument() || !$bag->getXmlDocument() || !$bag->getTipoDocumento()) {
308 107
            return;
309
        }
310
311
        // Crear el DTE.
312 10
        $document = $this->builderWorker->create($bag);
313 10
        $bag->setDocument($document);
314
    }
315
316
    /**
317
     * Asegura que existan el emisor en la bolsa si existe el dTE
318
     * para poder determinarlo y no está asignado previamente.
319
     *
320
     * El emisor también se pueden crear si existen un XmlDocument, datos
321
     * normalizados o datos parseados.
322
     *
323
     * Requiere: $bag->getDocument(), $bag->getXmlDocument(),
324
     * $bag->getNormalizedData() o $bag->getParsedData().
325
     *
326
     * @param DocumentBagInterface $bag
327
     * @return void
328
     */
329 116
    protected function ensureEmisor(DocumentBagInterface $bag): void
330
    {
331
        // Verificar si es necesario, y se puede, asignar.
332 116
        if ($bag->getEmisor()) {
333 53
            return;
334
        }
335
336
        // Crear a partir de los datos del DTE (sería lo más normal).
337 115
        if ($bag->getDocument()) {
338 115
            $emisor = $this->emisorFactory->create(
339 115
                $bag->getDocument()->getEmisor()
340 115
            );
341 115
            $bag->setEmisor($emisor);
342
        }
343
344
        // Crear a partir de los datos del XmlDocument.
345
        elseif ($bag->getXmlDocument()) {
346
            $emisor = $this->emisorFactory->create(
347
                $bag->getXmlDocument()->query(
0 ignored issues
show
Bug introduced by
It seems like $bag->getXmlDocument()->...y('/Encabezado/Emisor') can also be of type null and string; however, parameter $data of libredte\lib\Core\Packag...toryInterface::create() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

347
                /** @scrutinizer ignore-type */ $bag->getXmlDocument()->query(
Loading history...
348
                    '/Encabezado/Emisor'
349
                )
350
            );
351
            $bag->setEmisor($emisor);
352
        }
353
354
        // Crear a partir de los datos normalizados.
355
        elseif ($bag->getNormalizedData()) {
356
            $emisor = $this->emisorFactory->create(
357
                $bag->getNormalizedData()['Encabezado']['Emisor']
358
            );
359
            $bag->setEmisor($emisor);
360
        }
361
362
        // Crear a partir de los datos parseados.
363
        elseif ($bag->getParsedData()) {
364
            $emisor = $this->emisorFactory->create(
365
                $bag->getParsedData()['Encabezado']['Emisor']
366
            );
367
            $bag->setEmisor($emisor);
368
        }
369
    }
370
371
    /**
372
     * Asegura que existan el emisor en la bolsa si existen datos
373
     * normalizados para poder determinarlo y no está asignado previamente.
374
     *
375
     * El emisor también se pueden crear si existe un XmlDocument o un DTE.
376
     *
377
     * Requiere: $bag->getNormalizedData() o $bag->getXmlDocument() o $bag->getDocument().
378
     *
379
     * @param DocumentBagInterface $bag
380
     * @return void
381
     */
382 116
    protected function ensureReceptor(DocumentBagInterface $bag): void
383
    {
384
        // Si ya está asignado el receptor no se hace nada.
385 116
        if ($bag->getReceptor()) {
386 52
            return;
387
        }
388
389
        // Crear a partir de los datos del DTE (sería lo más normal).
390 116
        if ($bag->getDocument()) {
391 116
            $emisor = $this->receptorFactory->create(
392 116
                $bag->getDocument()->getReceptor()
393 116
            );
394 116
            $bag->setReceptor($emisor);
395
        }
396
397
        // Crear a partir de los datos del XmlDocument.
398
        elseif ($bag->getXmlDocument()) {
399
            $emisor = $this->receptorFactory->create(
400
                $bag->getXmlDocument()->query(
0 ignored issues
show
Bug introduced by
It seems like $bag->getXmlDocument()->...'/Encabezado/Receptor') can also be of type null and string; however, parameter $data of libredte\lib\Core\Packag...toryInterface::create() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

400
                /** @scrutinizer ignore-type */ $bag->getXmlDocument()->query(
Loading history...
401
                    '/Encabezado/Receptor'
402
                )
403
            );
404
            $bag->setReceptor($emisor);
405
        }
406
407
        // Crear a partir de los datos normalizados.
408
        elseif ($bag->getNormalizedData()) {
409
            $emisor = $this->receptorFactory->create(
410
                $bag->getNormalizedData()['Encabezado']['Receptor']
411
            );
412
            $bag->setReceptor($emisor);
413
        }
414
415
        // Crear a partir de los datos parseados.
416
        elseif ($bag->getParsedData()) {
417
            $emisor = $this->receptorFactory->create(
418
                $bag->getParsedData()['Encabezado']['Receptor']
419
            );
420
            $bag->setReceptor($emisor);
421
        }
422
    }
423
}
424