Passed
Push — master ( 221c35...fdb910 )
by Petr
02:59
created

Pohoda   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 244
Duplicated Lines 0 %

Test Coverage

Coverage 97.3%

Importance

Changes 7
Bugs 0 Features 1
Metric Value
wmc 27
eloc 77
c 7
b 0
f 1
dl 0
loc 244
ccs 72
cts 74
cp 0.973
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
A next() 0 12 5
A __construct() 0 14 3
A addItem() 0 11 2
A setApplicationName() 0 3 1
A getTransformerListing() 0 3 1
A __call() 0 17 4
A detectXmlFileHeader() 0 3 1
A load() 0 23 4
A close() 0 5 1
A create() 0 8 1
A open() 0 33 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace kalanis;
6
7
use Psr\Container\ContainerInterface;
8
use kalanis\Pohoda\AbstractAgenda;
9
use kalanis\Pohoda\Common\OneDirectionalVariablesTrait;
10
11
/**
12
 * Factory for Pohoda objects.
13
 *
14
 * @method Pohoda\AddressBook   createAddressBook(Pohoda\Common\Dtos\AbstractDto $data)
15
 * @method Pohoda\Bank          createBank(Pohoda\Common\Dtos\AbstractDto $data)
16
 * @method Pohoda\CashSlip      createCashSlip(Pohoda\Common\Dtos\AbstractDto $data)
17
 * @method Pohoda\Category      createCategory(Pohoda\Common\Dtos\AbstractDto $data)
18
 * @method Pohoda\Contract      createContract(Pohoda\Common\Dtos\AbstractDto $data)
19
 * @method Pohoda\IntDoc        createIntDoc(Pohoda\Common\Dtos\AbstractDto $data)
20
 * @method Pohoda\IntParam      createIntParam(Pohoda\Common\Dtos\AbstractDto $data)
21
 * @method Pohoda\Invoice       createInvoice(Pohoda\Common\Dtos\AbstractDto $data)
22
 * @method Pohoda\IssueSlip     createIssueSlip(Pohoda\Common\Dtos\AbstractDto $data)
23
 * @method Pohoda\ListRequest   createListRequest(Pohoda\Common\Dtos\AbstractDto $data)
24
 * @method Pohoda\ListResponse  createListResponse(Pohoda\Common\Dtos\AbstractDto $data)
25
 * @method Pohoda\Offer         createOffer(Pohoda\Common\Dtos\AbstractDto $data)
26
 * @method Pohoda\Order         createOrder(Pohoda\Common\Dtos\AbstractDto $data)
27
 * @method Pohoda\PrintRequest  createPrintRequest(Pohoda\Common\Dtos\AbstractDto $data)
28
 * @method Pohoda\Receipt       createReceipt(Pohoda\Common\Dtos\AbstractDto $data)
29
 * @method Pohoda\Stock         createStock(Pohoda\Common\Dtos\AbstractDto $data)
30
 * @method Pohoda\StockTransfer createStockTransfer(Pohoda\Common\Dtos\AbstractDto $data)
31
 * @method Pohoda\Storage       createStorage(Pohoda\Common\Dtos\AbstractDto $data)
32
 * @method Pohoda\Supplier      createSupplier(Pohoda\Common\Dtos\AbstractDto $data)
33
 * @method Pohoda\UserList      createUserList(Pohoda\Common\Dtos\AbstractDto $data)
34
 * @method Pohoda\Voucher       createVoucher(Pohoda\Common\Dtos\AbstractDto $data)
35
 * @method \bool loadAddressBook(string $filename)
36
 * @method \bool loadBank(string $filename)
37
 * @method \bool loadCashSlip(string $filename)
38
 * @method \bool loadCategory(string $filename)
39
 * @method \bool loadContract(string $filename)
40
 * @method \bool loadIntDoc(string $filename)
41
 * @method \bool loadIntParam(string $filename)
42
 * @method \bool loadInvoice(string $filename)
43
 * @method \bool loadIssueSlip(string $filename)
44
 * @method \bool loadListRequest(string $filename)
45
 * @method \bool loadListResponse(string $filename)
46
 * @method \bool loadOffer(string $filename)
47
 * @method \bool loadOrder(string $filename)
48
 * @method \bool loadPrintRequest(string $filename)
49
 * @method \bool loadReceipt(string $filename)
50
 * @method \bool loadStock(string $filename)
51
 * @method \bool loadStockTransfer(string $filename)
52
 * @method \bool loadStorage(string $filename)
53
 * @method \bool loadSupplier(string $filename)
54
 * @method \bool loadUserList(string $filename)
55
 * @method \bool loadVoucher(string $filename)
56
 *
57
 * @link https://www.stormware.cz/pohoda/xml/seznamschemat/   schemas
58
 */
59
class Pohoda
60
{
61
    use OneDirectionalVariablesTrait;
62
63
    protected string $application = 'Pohoda connector';
64
65
    protected bool $isInMemory;
66
67
    protected \XMLWriter $xmlWriter;
68
69
    protected \XMLReader $xmlReader;
70
71
    protected Pohoda\DI\DependenciesFactory $dependenciesFactory;
72
73
    protected string $elementName;
74
75
    protected bool $importRecursive = false;
76
77
    protected readonly Pohoda\Common\CompanyRegistrationNumberInterface $companyRegistrationNumber;
78
79 18
    public function __construct(
80
        string|Pohoda\Common\CompanyRegistrationNumberInterface $companyRegistrationNumber,
81
        ?Pohoda\DI\DependenciesFactory $dependenciesFactory = null,
82
        ?Pohoda\ValueTransformer\SanitizeEncoding $sanitizeEncoding = new Pohoda\ValueTransformer\SanitizeEncoding(new Pohoda\ValueTransformer\Listing()),
83
        ?Pohoda\Common\NamespacesPaths $namespacesPaths = new Pohoda\Common\NamespacesPaths(),
84
        ?Pohoda\Common\OptionsResolver\Normalizers\NormalizerFactory $normalizerFactory = new Pohoda\Common\OptionsResolver\Normalizers\NormalizerFactory(),
85
        ?ContainerInterface $container = null,
86
    ) {
87 18
        $this->companyRegistrationNumber = is_object($companyRegistrationNumber)
0 ignored issues
show
Bug introduced by
The property companyRegistrationNumber is declared read-only in kalanis\Pohoda.
Loading history...
88
            ? $companyRegistrationNumber
89 18
            : Pohoda\Common\CompanyRegistrationNumber::init($companyRegistrationNumber);
90 18
        $this->dependenciesFactory = is_object($dependenciesFactory)
91 18
            ? $dependenciesFactory
92
            : new Pohoda\DI\DependenciesFactory($namespacesPaths, $sanitizeEncoding, $normalizerFactory, $container);
93
    }
94
95
    /**
96
     * Set the name of the application.
97
     *
98
     * @param string $name
99
     *
100
     * @return void
101
     */
102 1
    public function setApplicationName(string $name): void
103
    {
104 1
        $this->application = $name;
105
    }
106
107
    /**
108
     * Get class listing transformers for content serialization
109
     *
110
     * @return Pohoda\ValueTransformer\Listing
111
     */
112 2
    public function getTransformerListing(): Pohoda\ValueTransformer\Listing
113
    {
114 2
        return $this->dependenciesFactory->getSanitizeEncoding()->getListing();
115
    }
116
117
    /**
118
     * Create and return instance of requested agenda.
119
     *
120
     * @param string              $name
121
     * @param Pohoda\Common\Dtos\AbstractDto $data
122
     *
123
     * @return AbstractAgenda
124
     */
125 3
    public function create(string $name, Pohoda\Common\Dtos\AbstractDto $data = new Pohoda\Common\Dtos\EmptyDto()): AbstractAgenda
126
    {
127 3
        return $this->dependenciesFactory
128 3
            ->getAgendaFactory()
129 3
            ->getAgenda($name)
130 3
            ->setDirectionalVariable($this->useOneDirectionalVariables)
131 3
            ->setResolveOptions(true)
132 3
            ->setData($data);
133
    }
134
135
    /**
136
     * Open new XML file for writing.
137
     *
138
     * @param string|null $filename path to output file or null for memory
139
     * @param string      $id
140
     * @param string      $note
141
     *
142
     * @return bool
143
     */
144 4
    public function open(?string $filename, string $id, string $note = ''): bool
145
    {
146 4
        $this->xmlWriter = new \XMLWriter();
147
148 4
        if (is_null($filename)) {
149 3
            $this->isInMemory = true;
150 3
            $this->xmlWriter->openMemory();
151
        } else {
152 1
            $this->isInMemory = false;
153
154 1
            if (!$this->xmlWriter->openUri($filename)) {
155
                // @codeCoverageIgnoreStart
156
                // I cannot test this, because it needs source file somewhere online
157
                return false;
158
            }
159
            // @codeCoverageIgnoreEnd
160
        }
161
162 4
        $this->xmlWriter->startDocument('1.0', $this->dependenciesFactory->getSanitizeEncoding()->getEncoding());
163 4
        $this->xmlWriter->startElementNs('dat', 'dataPack', null);
164
165 4
        $this->xmlWriter->writeAttribute('id', $id);
166 4
        $this->xmlWriter->writeAttribute('ico', $this->companyRegistrationNumber->getCompanyNumber());
167 4
        $this->xmlWriter->writeAttribute('application', $this->application);
168 4
        $this->xmlWriter->writeAttribute('version', '2.0');
169 4
        $this->xmlWriter->writeAttribute('note', $note);
170
171 4
        foreach ($this->dependenciesFactory->getNamespacePaths()->allNamespaces() as $k => $v) {
172
            // put all known namespaces into base element attributes
173 4
            $this->xmlWriter->writeAttributeNs('xmlns', $k, null, $v);
174
        }
175
176 4
        return true;
177
    }
178
179
    /**
180
     * Add item.
181
     *
182
     * @param string $id
183
     * @param AbstractAgenda $agenda
184
     *
185
     * @return void
186
     */
187 4
    public function addItem(string $id, AbstractAgenda $agenda): void
188
    {
189 4
        $this->xmlWriter->startElementNs('dat', 'dataPackItem', null);
190
191 4
        $this->xmlWriter->writeAttribute('id', $id);
192 4
        $this->xmlWriter->writeAttribute('version', '2.0');
193 4
        $this->xmlWriter->writeRaw((string) $agenda->getXML()->asXML());
194 4
        $this->xmlWriter->endElement();
195
196 4
        if (!$this->isInMemory) {
197 1
            $this->xmlWriter->flush();
198
        }
199
    }
200
201
    /**
202
     * End and close XML file.
203
     *
204
     * @return int|string written bytes for file or XML string for memory
205
     */
206 8
    public function close(): int|string
207
    {
208 8
        $this->xmlWriter->endElement();
209
210 8
        return $this->xmlWriter->flush();
211
    }
212
213
    /**
214
     * Load XML file.
215
     *
216
     * @param string $name
217
     * @param string $filename filename or current xml content
218
     *
219
     * @return bool
220
     */
221 4
    public function load(string $name, string $filename): bool
222
    {
223 4
        $this->xmlReader = new \XMLReader();
224
225 4
        if ($this->detectXmlFileHeader($filename)) {
226 1
            if (!@$this->xmlReader->XML($filename)) {
227
                // @codeCoverageIgnoreStart
228
                // cannot create string which will be parsed as XML and crash itself afterward
229
                return false;
230
            }
231
            // @codeCoverageIgnoreEnd
232
        } else {
233 3
            if (!@$this->xmlReader->open($filename)) {
234 1
                return false;
235
            }
236
        }
237
238 3
        $class = $this->dependenciesFactory->getAgendaFactory()->getAgenda($name);
239 3
        $class->setResolveOptions(false);
240 3
        $this->elementName = $class->getImportRoot() ?? throw new \DomainException('Not allowed entity: ' . $name);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $class->getImportRoot() targeting kalanis\Pohoda\AbstractAgenda::getImportRoot() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
241 3
        $this->importRecursive = $class->canImportRecursive();
242
243 3
        return true;
244
    }
245
246
    /**
247
     * Detect if passed file is in fact XML and not just path
248
     * A bit simple, but it is enough for now
249
     *
250
     * @param string $string
251
     *
252
     * @return bool
253
     */
254 4
    protected function detectXmlFileHeader(string $string): bool
255
    {
256 4
        return str_contains(substr($string, 0, 64), '<?xml');
257
    }
258
259
    /**
260
     * Get next item in loaded file.
261
     *
262
     * @return \SimpleXMLElement|null
263
     */
264 3
    public function next(): ?\SimpleXMLElement
265
    {
266 3
        while (\XMLReader::ELEMENT != $this->xmlReader->nodeType || $this->xmlReader->name !== $this->elementName) {
267 3
            if (!$this->xmlReader->read()) {
268 3
                return null;
269
            }
270
        }
271
272 3
        $xml = new \SimpleXMLElement($this->xmlReader->readOuterXml());
273 3
        $this->importRecursive ? $this->xmlReader->next() : $this->xmlReader->read();
274
275 3
        return $xml;
276
    }
277
278
    /**
279
     * Handle dynamic method calls.
280
     *
281
     * @param string  $method
282
     * @param mixed[] $arguments
283
     *
284
     * @return mixed
285
     */
286 6
    public function __call(string $method, array $arguments)
287
    {
288
        // create<Agenda> method
289 6
        if (\preg_match('/create([A-Z][a-zA-Z0-9]*)/', $method, $matches)) {
290 1
            return \call_user_func([$this, 'create'], $matches[1], $arguments[0] ?? []);
291
        }
292
293
        // load<Agenda> method
294 5
        if (\preg_match('/load([A-Z][a-zA-Z0-9]*)/', $method, $matches)) {
295 4
            if (!isset($arguments[0])) {
296 1
                throw new \DomainException('Filename not set.');
297
            }
298
299 3
            return \call_user_func([$this, 'load'], $matches[1], $arguments[0]);
300
        }
301
302 1
        throw new \BadMethodCallException('Unknown method: ' . $method);
303
    }
304
}
305