alex-kalanis /
pohoda
| 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); |
|
| 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
|
|||
| 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 |
This check looks for function or method calls that always return null and whose return value is used.
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.