Issues (38)

src/Pohoda.php (2 issues)

Labels
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
        ?ContainerInterface $container = null,
85
    ) {
86 18
        $this->companyRegistrationNumber = is_object($companyRegistrationNumber)
0 ignored issues
show
The property companyRegistrationNumber is declared read-only in kalanis\Pohoda.
Loading history...
87
            ? $companyRegistrationNumber
88 18
            : Pohoda\Common\CompanyRegistrationNumber::init($companyRegistrationNumber);
89 18
        $this->dependenciesFactory = is_object($dependenciesFactory)
90 18
            ? $dependenciesFactory
91
            : new Pohoda\DI\DependenciesFactory($namespacesPaths, $sanitizeEncoding, $container);
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->dependenciesFactory->getSanitizeEncoding()->getListing();
114
    }
115
116
    /**
117
     * Create and return instance of requested agenda.
118
     *
119
     * @param string              $name
120
     * @param Pohoda\Common\Dtos\AbstractDto $data
121
     *
122
     * @return AbstractAgenda
123
     */
124 3
    public function create(string $name, Pohoda\Common\Dtos\AbstractDto $data = new Pohoda\Common\Dtos\EmptyDto()): AbstractAgenda
125
    {
126 3
        return $this->dependenciesFactory
127 3
            ->getAgendaFactory()
128 3
            ->getAgenda($name)
129 3
            ->setDirectionalVariable($this->useOneDirectionalVariables)
130 3
            ->setResolveOptions(true)
131 3
            ->setData($data);
132
    }
133
134
    /**
135
     * Open new XML file for writing.
136
     *
137
     * @param string|null $filename path to output file or null for memory
138
     * @param string      $id
139
     * @param string      $note
140
     *
141
     * @return bool
142
     */
143 4
    public function open(?string $filename, string $id, string $note = ''): bool
144
    {
145 4
        $this->xmlWriter = new \XMLWriter();
146
147 4
        if (is_null($filename)) {
148 3
            $this->isInMemory = true;
149 3
            $this->xmlWriter->openMemory();
150
        } else {
151 1
            $this->isInMemory = false;
152
153 1
            if (!$this->xmlWriter->openUri($filename)) {
154
                // @codeCoverageIgnoreStart
155
                // I cannot test this, because it needs source file somewhere online
156
                return false;
157
            }
158
            // @codeCoverageIgnoreEnd
159
        }
160
161 4
        $this->xmlWriter->startDocument('1.0', $this->dependenciesFactory->getSanitizeEncoding()->getEncoding());
162 4
        $this->xmlWriter->startElementNs('dat', 'dataPack', null);
163
164 4
        $this->xmlWriter->writeAttribute('id', $id);
165 4
        $this->xmlWriter->writeAttribute('ico', $this->companyRegistrationNumber->getCompanyNumber());
166 4
        $this->xmlWriter->writeAttribute('application', $this->application);
167 4
        $this->xmlWriter->writeAttribute('version', '2.0');
168 4
        $this->xmlWriter->writeAttribute('note', $note);
169
170 4
        foreach ($this->dependenciesFactory->getNamespacePaths()->allNamespaces() as $k => $v) {
171
            // put all known namespaces into base element attributes
172 4
            $this->xmlWriter->writeAttributeNs('xmlns', $k, null, $v);
173
        }
174
175 4
        return true;
176
    }
177
178
    /**
179
     * Add item.
180
     *
181
     * @param string $id
182
     * @param AbstractAgenda $agenda
183
     *
184
     * @return void
185
     */
186 4
    public function addItem(string $id, AbstractAgenda $agenda): void
187
    {
188 4
        $this->xmlWriter->startElementNs('dat', 'dataPackItem', null);
189
190 4
        $this->xmlWriter->writeAttribute('id', $id);
191 4
        $this->xmlWriter->writeAttribute('version', '2.0');
192 4
        $this->xmlWriter->writeRaw((string) $agenda->getXML()->asXML());
193 4
        $this->xmlWriter->endElement();
194
195 4
        if (!$this->isInMemory) {
196 1
            $this->xmlWriter->flush();
197
        }
198
    }
199
200
    /**
201
     * End and close XML file.
202
     *
203
     * @return int|string written bytes for file or XML string for memory
204
     */
205 8
    public function close(): int|string
206
    {
207 8
        $this->xmlWriter->endElement();
208
209 8
        return $this->xmlWriter->flush();
210
    }
211
212
    /**
213
     * Load XML file.
214
     *
215
     * @param string $name
216
     * @param string $filename filename or current xml content
217
     *
218
     * @return bool
219
     */
220 4
    public function load(string $name, string $filename): bool
221
    {
222 4
        $this->xmlReader = new \XMLReader();
223
224 4
        if ($this->detectXmlFileHeader($filename)) {
225 1
            if (!@$this->xmlReader->XML($filename)) {
226
                // @codeCoverageIgnoreStart
227
                // cannot create string which will be parsed as XML and crash itself afterward
228
                return false;
229
            }
230
            // @codeCoverageIgnoreEnd
231
        } else {
232 3
            if (!@$this->xmlReader->open($filename)) {
233 1
                return false;
234
            }
235
        }
236
237 3
        $class = $this->dependenciesFactory->getAgendaFactory()->getAgenda($name);
238 3
        $class->setResolveOptions(false);
239 3
        $this->elementName = $class->getImportRoot() ?? throw new PohodaException('Not allowed entity: ' . $name);
0 ignored issues
show
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...
240 3
        $this->importRecursive = $class->canImportRecursive();
241
242 3
        return true;
243
    }
244
245
    /**
246
     * Detect if passed file is in fact XML and not just path
247
     * A bit simple, but it is enough for now
248
     *
249
     * @param string $string
250
     *
251
     * @return bool
252
     */
253 4
    protected function detectXmlFileHeader(string $string): bool
254
    {
255 4
        return str_contains(substr($string, 0, 64), '<?xml');
256
    }
257
258
    /**
259
     * Get next item in loaded file.
260
     *
261
     * @return \SimpleXMLElement|null
262
     */
263 3
    public function next(): ?\SimpleXMLElement
264
    {
265 3
        while (\XMLReader::ELEMENT != $this->xmlReader->nodeType || $this->xmlReader->name !== $this->elementName) {
266 3
            if (!$this->xmlReader->read()) {
267 3
                return null;
268
            }
269
        }
270
271 3
        $xml = new \SimpleXMLElement($this->xmlReader->readOuterXml());
272 3
        $this->importRecursive ? $this->xmlReader->next() : $this->xmlReader->read();
273
274 3
        return $xml;
275
    }
276
277
    /**
278
     * Handle dynamic method calls.
279
     *
280
     * @param string  $method
281
     * @param mixed[] $arguments
282
     *
283
     * @return mixed
284
     */
285 6
    public function __call(string $method, array $arguments)
286
    {
287
        // create<Agenda> method
288 6
        if (\preg_match('/create([A-Z][a-zA-Z0-9]*)/', $method, $matches)) {
289 1
            return \call_user_func([$this, 'create'], $matches[1], $arguments[0] ?? []);
290
        }
291
292
        // load<Agenda> method
293 5
        if (\preg_match('/load([A-Z][a-zA-Z0-9]*)/', $method, $matches)) {
294 4
            if (!isset($arguments[0])) {
295 1
                throw new PohodaException('Filename not set.');
296
            }
297
298 3
            return \call_user_func([$this, 'load'], $matches[1], $arguments[0]);
299
        }
300
301 1
        throw new \BadMethodCallException('Unknown method: ' . $method);
302
    }
303
}
304