Pohoda::getTransformerListing()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
/**
4
 * This file is part of riesenia/pohoda package.
5
 *
6
 * Licensed under the MIT License
7
 * (c) RIESENIA.com
8
 */
9
10
declare(strict_types=1);
11
12
namespace Riesenia;
13
14
use Riesenia\Pohoda\AbstractAgenda;
15
use Riesenia\Pohoda\Common\OneDirectionalVariablesTrait;
16
17
/**
18
 * Factory for Pohoda objects.
19
 *
20
 * @method Pohoda\AddressBook   createAddressBook(array $data = [])
21
 * @method Pohoda\Bank          createBank(array $data = [])
22
 * @method Pohoda\CashSlip      createCashSlip(array $data = [])
23
 * @method Pohoda\Category      createCategory(array $data = [])
24
 * @method Pohoda\Contract      createContract(array $data = [])
25
 * @method Pohoda\IntDoc        createIntDoc(array $data = [])
26
 * @method Pohoda\IntParam      createIntParam(array $data = [])
27
 * @method Pohoda\Invoice       createInvoice(array $data = [])
28
 * @method Pohoda\IssueSlip     createIssueSlip(array $data = [])
29
 * @method Pohoda\ListRequest   createListRequest(array $data = [])
30
 * @method Pohoda\ListResponse  createListResponse(array $data = [])
31
 * @method Pohoda\Offer         createOffer(array $data = [])
32
 * @method Pohoda\Order         createOrder(array $data = [])
33
 * @method Pohoda\PrintRequest  createPrintRequest(array $data = [])
34
 * @method Pohoda\Receipt       createReceipt(array $data = [])
35
 * @method Pohoda\Stock         createStock(array $data = [])
36
 * @method Pohoda\StockTransfer createStockTransfer(array $data = [])
37
 * @method Pohoda\Storage       createStorage(array $data = [])
38
 * @method Pohoda\Supplier      createSupplier(array $data = [])
39
 * @method Pohoda\UserList      createUserList(array $data = [])
40
 * @method Pohoda\Voucher       createVoucher(array $data = [])
41
 * @method \bool loadAddressBook(string $filename)
42
 * @method \bool loadBank(string $filename)
43
 * @method \bool loadCashSlip(string $filename)
44
 * @method \bool loadCategory(string $filename)
45
 * @method \bool loadContract(string $filename)
46
 * @method \bool loadIntDoc(string $filename)
47
 * @method \bool loadIntParam(string $filename)
48
 * @method \bool loadInvoice(string $filename)
49
 * @method \bool loadIssueSlip(string $filename)
50
 * @method \bool loadListRequest(string $filename)
51
 * @method \bool loadListResponse(string $filename)
52
 * @method \bool loadOffer(string $filename)
53
 * @method \bool loadOrder(string $filename)
54
 * @method \bool loadPrintRequest(string $filename)
55
 * @method \bool loadReceipt(string $filename)
56
 * @method \bool loadStock(string $filename)
57
 * @method \bool loadStockTransfer(string $filename)
58
 * @method \bool loadStorage(string $filename)
59
 * @method \bool loadSupplier(string $filename)
60
 * @method \bool loadUserList(string $filename)
61
 * @method \bool loadVoucher(string $filename)
62
 *
63
 * @link https://www.stormware.cz/pohoda/xml/seznamschemat/   schemas
64
 */
65
class Pohoda
66
{
67
    use OneDirectionalVariablesTrait;
68
69
    protected string $application = 'Pohoda connector';
70
71
    protected bool $isInMemory;
72
73
    protected \XMLWriter $xmlWriter;
74
75
    protected \XMLReader $xmlReader;
76
77
    protected Pohoda\AgendaFactory $agendaFactory;
78
79
    protected string $elementName;
80
81
    protected bool $importRecursive = false;
82
83
    protected readonly Pohoda\Common\CompanyRegistrationNumberInterface $companyRegistrationNumber;
84
85 18
    public function __construct(
86
        string|Pohoda\Common\CompanyRegistrationNumberInterface $companyRegistrationNumber,
87
        protected Pohoda\ValueTransformer\SanitizeEncoding $sanitizeEncoding = new Pohoda\ValueTransformer\SanitizeEncoding(new Pohoda\ValueTransformer\Listing()),
88
        protected readonly Pohoda\Common\NamespacesPaths $namespacesPaths = new Pohoda\Common\NamespacesPaths(),
89
    ) {
90 18
        $this->companyRegistrationNumber = is_object($companyRegistrationNumber) ? $companyRegistrationNumber : Pohoda\Common\CompanyRegistrationNumber::init($companyRegistrationNumber);
0 ignored issues
show
Bug introduced by
The property companyRegistrationNumber is declared read-only in Riesenia\Pohoda.
Loading history...
91 18
        $this->agendaFactory = new Pohoda\AgendaFactory($this->namespacesPaths, $this->sanitizeEncoding);
92
    }
93
94
    /**
95
     * Set the name of the application.
96
     *
97
     * @param string $name
98
     *
99
     * @return void
100
     */
101 1
    public function setApplicationName(string $name): void
102
    {
103 1
        $this->application = $name;
104
    }
105
106
    /**
107
     * Get class listing transformers for content serialization
108
     *
109
     * @return Pohoda\ValueTransformer\Listing
110
     */
111 2
    public function getTransformerListing(): Pohoda\ValueTransformer\Listing
112
    {
113 2
        return $this->sanitizeEncoding->getListing();
114
    }
115
116
    /**
117
     * Create and return instance of requested agenda.
118
     *
119
     * @param string              $name
120
     * @param array<string,mixed> $data
121
     *
122
     * @return AbstractAgenda
123
     */
124 3
    public function create(string $name, array $data = []): AbstractAgenda
125
    {
126 3
        return $this->agendaFactory->getAgenda($name)->setDirectionalVariable($this->useOneDirectionalVariables)->setResolveOptions(true)->setData($data);
127
    }
128
129
    /**
130
     * Open new XML file for writing.
131
     *
132
     * @param string|null $filename path to output file or null for memory
133
     * @param string      $id
134
     * @param string      $note
135
     *
136
     * @return bool
137
     */
138 4
    public function open(?string $filename, string $id, string $note = ''): bool
139
    {
140 4
        $this->xmlWriter = new \XMLWriter();
141
142 4
        if (is_null($filename)) {
143 3
            $this->isInMemory = true;
144 3
            $this->xmlWriter->openMemory();
145
        } else {
146 1
            $this->isInMemory = false;
147
148 1
            if (!$this->xmlWriter->openUri($filename)) {
149
                // @codeCoverageIgnoreStart
150
                // I cannot test this, because it needs source file somewhere online
151
                return false;
152
            }
153
            // @codeCoverageIgnoreEnd
154
        }
155
156 4
        $this->xmlWriter->startDocument('1.0', $this->sanitizeEncoding->getEncoding());
157 4
        $this->xmlWriter->startElementNs('dat', 'dataPack', null);
158
159 4
        $this->xmlWriter->writeAttribute('id', $id);
160 4
        $this->xmlWriter->writeAttribute('ico', $this->companyRegistrationNumber->getCompanyNumber());
161 4
        $this->xmlWriter->writeAttribute('application', $this->application);
162 4
        $this->xmlWriter->writeAttribute('version', '2.0');
163 4
        $this->xmlWriter->writeAttribute('note', $note);
164
165 4
        foreach ($this->namespacesPaths->allNamespaces() as $k => $v) {
166
            // put all known namespaces into base element attributes
167 4
            $this->xmlWriter->writeAttributeNs('xmlns', $k, null, $v);
168
        }
169
170 4
        return true;
171
    }
172
173
    /**
174
     * Add item.
175
     *
176
     * @param string $id
177
     * @param AbstractAgenda $agenda
178
     *
179
     * @return void
180
     */
181 4
    public function addItem(string $id, AbstractAgenda $agenda): void
182
    {
183 4
        $this->xmlWriter->startElementNs('dat', 'dataPackItem', null);
184
185 4
        $this->xmlWriter->writeAttribute('id', $id);
186 4
        $this->xmlWriter->writeAttribute('version', '2.0');
187 4
        $this->xmlWriter->writeRaw((string) $agenda->getXML()->asXML());
188 4
        $this->xmlWriter->endElement();
189
190 4
        if (!$this->isInMemory) {
191 1
            $this->xmlWriter->flush();
192
        }
193
    }
194
195
    /**
196
     * End and close XML file.
197
     *
198
     * @return int|string written bytes for file or XML string for memory
199
     */
200 8
    public function close(): int|string
201
    {
202 8
        $this->xmlWriter->endElement();
203
204 8
        return $this->xmlWriter->flush();
205
    }
206
207
    /**
208
     * Load XML file.
209
     *
210
     * @param string $name
211
     * @param string $filename filename or current xml content
212
     *
213
     * @return bool
214
     */
215 4
    public function load(string $name, string $filename): bool
216
    {
217 4
        $this->xmlReader = new \XMLReader();
218
219 4
        if ($this->detectXmlFileHeader($filename)) {
220 1
            if (!@$this->xmlReader->XML($filename)) {
221
                // @codeCoverageIgnoreStart
222
                // cannot create string which will be parsed as XML and crash itself afterward
223
                return false;
224
            }
225
            // @codeCoverageIgnoreEnd
226
        } else {
227 3
            if (!@$this->xmlReader->open($filename)) {
228 1
                return false;
229
            }
230
        }
231
232 3
        $class = $this->agendaFactory->getAgenda($name);
233 3
        $class->setResolveOptions(false);
234 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 Riesenia\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...
235 3
        $this->importRecursive = $class->canImportRecursive();
236
237 3
        return true;
238
    }
239
240
    /**
241
     * Detect if passed file is in fact XML and not just path
242
     * A bit simple, but it is enough for now
243
     *
244
     * @param string $string
245
     *
246
     * @return bool
247
     */
248 4
    protected function detectXmlFileHeader(string $string): bool
249
    {
250 4
        return str_contains(substr($string, 0, 64), '<?xml');
251
    }
252
253
    /**
254
     * Get next item in loaded file.
255
     *
256
     * @return \SimpleXMLElement|null
257
     */
258 3
    public function next(): ?\SimpleXMLElement
259
    {
260 3
        while (\XMLReader::ELEMENT != $this->xmlReader->nodeType || $this->xmlReader->name !== $this->elementName) {
261 3
            if (!$this->xmlReader->read()) {
262 3
                return null;
263
            }
264
        }
265
266 3
        $xml = new \SimpleXMLElement($this->xmlReader->readOuterXml());
267 3
        $this->importRecursive ? $this->xmlReader->next() : $this->xmlReader->read();
268
269 3
        return $xml;
270
    }
271
272
    /**
273
     * Handle dynamic method calls.
274
     *
275
     * @param string  $method
276
     * @param mixed[] $arguments
277
     *
278
     * @return mixed
279
     */
280 6
    public function __call(string $method, array $arguments)
281
    {
282
        // create<Agenda> method
283 6
        if (\preg_match('/create([A-Z][a-zA-Z0-9]*)/', $method, $matches)) {
284 1
            return \call_user_func([$this, 'create'], $matches[1], $arguments[0] ?? []);
285
        }
286
287
        // load<Agenda> method
288 5
        if (\preg_match('/load([A-Z][a-zA-Z0-9]*)/', $method, $matches)) {
289 4
            if (!isset($arguments[0])) {
290 1
                throw new \DomainException('Filename not set.');
291
            }
292
293 3
            return \call_user_func([$this, 'load'], $matches[1], $arguments[0]);
294
        }
295
296 1
        throw new \BadMethodCallException('Unknown method: ' . $method);
297
    }
298
}
299