From 8f048301c6878496c3d391552b0b220ae06a7278 Mon Sep 17 00:00:00 2001 From: Ralf Date: Tue, 1 Aug 2023 16:07:04 +0200 Subject: [PATCH 1/2] update php 7 > 8.1+, dependencies, phpunit10, psr12, bugfixing and code cleanup --- .gitignore | 1 + backend/class/app.php | 7 +- backend/class/datasource.php | 21 +- backend/class/datasource/arraydata.php | 149 +- backend/class/datasource/buffered.php | 391 ++-- backend/class/datasource/csv.php | 489 ++-- backend/class/datasource/database.php | 363 ++- backend/class/datasource/joined.php | 500 ++--- backend/class/datasource/model.php | 705 +++--- backend/class/datasource/multicsv.php | 323 ++- backend/class/datasource/parquet.php | 387 ++-- backend/class/datasource/raw.php | 521 +++-- backend/class/datasource/remap.php | 348 +-- backend/class/datasource/spreadsheet.php | 633 +++--- backend/class/datasource/xml.php | 319 +-- backend/class/export.php | 5 +- backend/class/export/pdf.php | 104 +- backend/class/export/pdf/dompdf.php | 159 +- backend/class/helper/deepaccess.php | 9 - backend/class/helper/pipeline.php | 445 ++-- backend/class/pipeline.php | 1993 ++++++++--------- backend/class/process.php | 202 +- backend/class/process/target.php | 41 +- backend/class/process/target/model.php | 34 +- backend/class/process/target/model/delete.php | 58 +- backend/class/process/target/model/update.php | 85 +- backend/class/progressInterface.php | 25 +- .../class/setPipelineInstanceInterface.php | 18 +- backend/class/target.php | 357 ++- backend/class/target/arraydata.php | 90 +- backend/class/target/arraydata/tagged.php | 65 +- backend/class/target/buffered.php | 182 +- backend/class/target/buffered/file.php | 173 +- backend/class/target/buffered/file/csv.php | 688 +++--- backend/class/target/buffered/file/json.php | 266 +-- .../class/target/buffered/file/parquet.php | 697 +++--- backend/class/target/buffered/file/raw.php | 314 +-- .../target/buffered/file/spreadsheet.php | 574 ++--- backend/class/target/buffered/file/xml.php | 341 +-- backend/class/target/createArchiveTrait.php | 206 +- backend/class/target/dummy.php | 127 +- .../class/target/fileResultArrayInterface.php | 18 +- backend/class/target/fileResultInterface.php | 18 +- backend/class/target/model.php | 226 +- backend/class/target/model/complex.php | 545 +++-- .../target/structureResultArrayInterface.php | 18 +- .../class/target/textResultArrayInterface.php | 18 +- backend/class/target/textResultInterface.php | 18 +- backend/class/target/virtual.php | 178 +- .../class/target/virtualTargetInterface.php | 31 +- backend/class/target/xml.php | 208 +- backend/class/target/xml/text.php | 33 +- backend/class/targetModelInterface.php | 11 +- backend/class/targetStoreTagInterface.php | 16 +- backend/class/transform.php | 528 ++--- backend/class/transform/calculate.php | 7 +- backend/class/transform/calculate/divide.php | 108 +- .../class/transform/calculate/multiply.php | 108 +- .../class/transform/calculate/subtract.php | 129 +- backend/class/transform/calculate/sum.php | 121 +- backend/class/transform/compare.php | 46 +- .../class/transform/compare/beginswith.php | 52 +- backend/class/transform/compare/datetime.php | 92 +- backend/class/transform/compare/isday.php | 60 +- backend/class/transform/compare/isequal.php | 50 +- backend/class/transform/compare/isholiday.php | 77 +- backend/class/transform/compare/number.php | 117 +- backend/class/transform/contains.php | 97 +- backend/class/transform/convert.php | 10 +- backend/class/transform/convert/boolean.php | 109 +- backend/class/transform/convert/datetime.php | 309 ++- backend/class/transform/convert/encoding.php | 63 +- backend/class/transform/convert/json.php | 64 +- .../class/transform/convert/numberformat.php | 330 ++- .../transform/convert/numberformat/format.php | 54 +- backend/class/transform/count.php | 51 +- backend/class/transform/deepaccess.php | 108 +- backend/class/transform/dummy.php | 58 +- backend/class/transform/explode.php | 130 +- backend/class/transform/get.php | 9 +- backend/class/transform/get/arraycolumn.php | 71 +- backend/class/transform/get/arrayvalue.php | 276 +-- backend/class/transform/get/conditioned.php | 178 +- .../class/transform/get/conditioned/all.php | 99 +- .../class/transform/get/currentdatetime.php | 48 +- .../class/transform/get/easterdatetime.php | 59 +- backend/class/transform/get/fallback.php | 93 +- backend/class/transform/get/filtered.php | 85 +- .../transform/get/filtered/arrayfilter.php | 93 +- .../transform/get/filtered/validated.php | 113 +- backend/class/transform/get/number.php | 31 +- .../class/transform/get/number/fraction.php | 84 +- backend/class/transform/get/number/whole.php | 55 +- backend/class/transform/get/onetime.php | 77 +- backend/class/transform/get/option.php | 93 +- backend/class/transform/get/randomstring.php | 41 +- backend/class/transform/get/strcase.php | 114 +- backend/class/transform/get/strreplace.php | 219 +- backend/class/transform/get/substr.php | 106 +- backend/class/transform/get/value.php | 49 +- backend/class/transform/get/valuearray.php | 140 +- backend/class/transform/hash.php | 67 +- backend/class/transform/implode.php | 153 +- .../class/transform/implode/arrayvalue.php | 80 +- backend/class/transform/math/round.php | 132 +- backend/class/transform/model.php | 480 ++-- backend/class/transform/model/map.php | 9 +- backend/class/transform/model/map/single.php | 76 +- .../transform/model/map/single/onetime.php | 39 +- backend/class/transform/model/result.php | 9 +- backend/class/transform/model/result/all.php | 40 +- .../transform/model/result/all/onetime.php | 39 +- backend/class/transform/model/result/one.php | 53 +- .../transform/model/result/one/onetime.php | 42 +- backend/class/transform/model/save.php | 76 +- .../class/transform/model/save/onetime.php | 48 +- backend/class/transform/model/save/unique.php | 96 +- backend/class/transform/pad.php | 26 +- backend/class/transform/pad/left.php | 28 +- backend/class/transform/pad/right.php | 28 +- backend/class/transform/regex.php | 166 +- backend/class/transform/set.php | 37 +- backend/class/transform/trim.php | 94 +- backend/class/transform/trim/left.php | 33 +- backend/class/transform/trim/right.php | 33 +- backend/class/transform/value.php | 42 +- backend/class/transformer.php | 189 +- backend/class/transformerInterface.php | 17 +- .../validator/structure/config/import.php | 76 +- .../structure/config/import/source.php | 38 +- .../structure/config/import/target.php | 38 +- .../structure/config/import/transform.php | 38 +- backend/class/value/structure/tagged.php | 56 +- .../class/value/text/fileabsolute/tagged.php | 46 +- backend/class/value/text/tagged.php | 46 +- composer.json | 68 +- phpcs.xml | 26 +- phpunit.xml | 12 +- psalm.xml | 21 +- tests/autoload.php | 45 +- tests/datasource/arraydataTest.php | 71 + tests/datasource/bufferedTest.php | 156 ++ tests/datasource/csvTest.php | 168 ++ tests/datasource/joinedTest.php | 249 ++ tests/datasource/model/datasourceentry.php | 58 +- tests/datasource/model/datasourceentryj.php | 72 +- tests/datasource/modelTest.php | 387 ++++ tests/datasource/multicsvTest.php | 101 + tests/datasource/parquetTest.php | 136 ++ tests/datasource/rawTest.php | 242 ++ tests/datasource/remapTest.php | 242 ++ tests/datasource/spreadsheetTest.php | 161 ++ tests/datasource/testArraydata.php | 62 - tests/datasource/testBuffered.php | 137 -- tests/datasource/testCsv.php | 222 -- tests/datasource/testJoined.php | 232 -- tests/datasource/testModel.php | 356 --- tests/datasource/testMulticsv.php | 100 - tests/datasource/testParquet.php | 121 - tests/datasource/testRaw.php | 232 -- tests/datasource/testRemap.php | 272 --- tests/datasource/testSpreadsheet.php | 194 -- tests/datasource/testXml.php | 95 - tests/datasource/testXml1.xml | 30 +- tests/datasource/xmlTest.php | 102 + tests/helper/model/helperjmodel.php | 96 +- tests/helper/model/helpermodel.php | 54 +- tests/helper/pipelineTest.php | 354 +++ tests/helper/testDeepaccess.php | 56 - tests/helper/testPipeline.php | 347 --- tests/pipeline/abstractPipelineTest.php | 254 ++- tests/pipeline/genericPipelineTest.php | 497 ++-- tests/pipeline/model/pipelinemodel.php | 66 +- tests/pipeline/pipelineModelTargetTest.php | 244 +- tests/pipelineTest.php | 359 +++ .../model/abstractProcessTargetModelTest.php | 273 +-- tests/process/target/model/deleteTest.php | 459 ++-- .../target/model/model/processmodel.php | 66 +- tests/process/target/model/updateTest.php | 609 ++--- tests/target/abstractWriteReadTest.php | 210 +- tests/target/arraydata/taggedTest.php | 171 +- tests/target/arraydataTest.php | 52 +- .../CsvBufferingAndSplittingWriteReadTest.php | 400 ++-- .../file/csvArchivedWriteReadTest.php | 171 +- tests/target/buffered/file/csvTest.php | 628 +++--- .../target/buffered/file/csvWriteReadTest.php | 95 +- tests/target/buffered/file/jsonTest.php | 337 +-- .../buffered/file/multicsvWriteReadTest.php | 108 +- .../file/parquetBufferedWriteReadTest.php | 244 +- tests/target/buffered/file/parquetTest.php | 115 +- .../buffered/file/parquetWriteReadTest.php | 381 ++-- tests/target/buffered/file/rawTest.php | 297 +-- .../target/buffered/file/rawWriteReadTest.php | 114 +- .../file/spreadsheetCsvWriteReadTest.php | 131 +- .../target/buffered/file/spreadsheetTest.php | 348 +-- .../file/spreadsheetXlsWriteReadTest.php | 101 +- .../file/spreadsheetXlsxWriteReadTest.php | 101 +- tests/target/buffered/file/xmlTest.php | 281 +-- .../target/buffered/file/xmlWriteReadTest.php | 109 +- tests/target/buffered/fileTest.php | 131 +- tests/target/dummyTest.php | 99 +- tests/target/filterTest.php | 144 +- tests/target/model/complexTest.php | 1078 ++++----- tests/target/model/testmodel.php | 104 +- tests/target/model/testmodelj.php | 100 +- tests/target/modelTest.php | 496 ++-- tests/target/virtualTest.php | 426 ++-- tests/target/xml/textTest.php | 224 +- tests/testImport.php | 17 - tests/testPipeline.json | 61 +- tests/testPipeline.php | 332 --- tests/testPipeline2.json | 65 +- tests/testTransformer.php | 79 - tests/testTransformer1.json | 24 +- tests/transform/abstractTransformTest.php | 145 +- tests/transform/calculate/divideTest.php | 91 +- tests/transform/calculate/multiplyTest.php | 91 +- tests/transform/calculate/subtractTest.php | 91 +- tests/transform/calculate/sumTest.php | 87 +- tests/transform/compare/beginswithTest.php | 79 +- tests/transform/compare/datetimeTest.php | 203 +- tests/transform/compare/isdayTest.php | 112 +- tests/transform/compare/isequalTest.php | 79 +- tests/transform/compare/isholidayTest.php | 410 ++-- tests/transform/compare/model/holidays.php | 78 +- tests/transform/compare/numberTest.php | 371 +-- tests/transform/containsTest.php | 177 +- tests/transform/convert/booleanTest.php | 376 ++-- tests/transform/convert/datetimeTest.php | 405 ++-- tests/transform/convert/encodingTest.php | 150 +- tests/transform/convert/jsonTest.php | 180 +- .../convert/numberformat/formatTest.php | 209 +- tests/transform/convert/numberformatTest.php | 398 ++-- tests/transform/countTest.php | 101 +- tests/transform/deepaccessTest.php | 129 +- tests/transform/dummyTest.php | 60 +- tests/transform/explodeTest.php | 241 +- tests/transform/get/arraycolumnTest.php | 198 +- tests/transform/get/arrayvalueTest.php | 288 +-- tests/transform/get/conditioned/allTest.php | 192 +- tests/transform/get/conditionedTest.php | 549 ++--- tests/transform/get/currentdatetimeTest.php | 72 +- tests/transform/get/easterdatetimeTest.php | 119 +- tests/transform/get/fallbackTest.php | 170 +- .../get/filtered/arrayfilterTest.php | 289 +-- .../transform/get/filtered/validatedTest.php | 118 +- tests/transform/get/filteredTest.php | 201 +- tests/transform/get/number/fractionTest.php | 176 +- tests/transform/get/number/wholeTest.php | 145 +- tests/transform/get/onetimeTest.php | 135 +- tests/transform/get/optionTest.php | 207 +- tests/transform/get/randomstringTest.php | 59 +- tests/transform/get/strcaseTest.php | 178 +- tests/transform/get/strreplaceTest.php | 134 +- tests/transform/get/substrTest.php | 118 +- tests/transform/get/valueTest.php | 75 +- tests/transform/get/valuearrayTest.php | 261 ++- tests/transform/hashTest.php | 106 +- tests/transform/implode/arrayvalueTest.php | 87 +- tests/transform/implodeTest.php | 318 +-- tests/transform/math/roundTest.php | 437 ++-- tests/transform/model/tjsample.php | 76 +- tests/transform/model/transformmodel.php | 58 +- tests/transform/modelTest.php | 1966 ++++++++-------- tests/transform/pad/leftTest.php | 188 +- tests/transform/pad/rightTest.php | 188 +- tests/transform/regexTest.php | 308 +-- tests/transform/setTest.php | 58 +- tests/transform/transformGetValueTest.php | 371 +-- tests/transform/trim/leftTest.php | 108 +- tests/transform/trim/rightTest.php | 108 +- tests/transform/trimTest.php | 105 +- tests/transform/valueTest.php | 70 +- tests/transformerTest.php | 95 + tests/validator.php | 81 +- tests/validator/structure.php | 46 - tests/validator/structure/config/import.php | 73 - .../structure/config/import/source.php | 27 - .../structure/config/import/sourceTest.php | 38 + .../structure/config/import/target.php | 27 - .../structure/config/import/targetTest.php | 38 + .../structure/config/import/transform.php | 27 - .../structure/config/import/transformTest.php | 38 + .../validator/structure/config/importTest.php | 90 + tests/validator/structureTest.php | 60 + tests/value/structure/taggedTest.php | 28 + tests/value/structure/testTagged.php | 22 - tests/value/text/fileabsolute/taggedTest.php | 28 + tests/value/text/fileabsolute/testTagged.php | 22 - tests/value/text/taggedTest.php | 28 + tests/value/text/testTagged.php | 22 - 291 files changed, 25984 insertions(+), 24417 deletions(-) delete mode 100644 backend/class/helper/deepaccess.php create mode 100644 tests/datasource/arraydataTest.php create mode 100644 tests/datasource/bufferedTest.php create mode 100644 tests/datasource/csvTest.php create mode 100644 tests/datasource/joinedTest.php create mode 100644 tests/datasource/modelTest.php create mode 100644 tests/datasource/multicsvTest.php create mode 100644 tests/datasource/parquetTest.php create mode 100644 tests/datasource/rawTest.php create mode 100644 tests/datasource/remapTest.php create mode 100644 tests/datasource/spreadsheetTest.php delete mode 100644 tests/datasource/testArraydata.php delete mode 100644 tests/datasource/testBuffered.php delete mode 100644 tests/datasource/testCsv.php delete mode 100644 tests/datasource/testJoined.php delete mode 100644 tests/datasource/testModel.php delete mode 100644 tests/datasource/testMulticsv.php delete mode 100644 tests/datasource/testParquet.php delete mode 100644 tests/datasource/testRaw.php delete mode 100644 tests/datasource/testRemap.php delete mode 100644 tests/datasource/testSpreadsheet.php delete mode 100644 tests/datasource/testXml.php create mode 100644 tests/datasource/xmlTest.php create mode 100644 tests/helper/pipelineTest.php delete mode 100644 tests/helper/testDeepaccess.php delete mode 100644 tests/helper/testPipeline.php create mode 100644 tests/pipelineTest.php delete mode 100644 tests/testImport.php delete mode 100644 tests/testPipeline.php delete mode 100644 tests/testTransformer.php create mode 100644 tests/transformerTest.php delete mode 100644 tests/validator/structure.php delete mode 100644 tests/validator/structure/config/import.php delete mode 100644 tests/validator/structure/config/import/source.php create mode 100644 tests/validator/structure/config/import/sourceTest.php delete mode 100644 tests/validator/structure/config/import/target.php create mode 100644 tests/validator/structure/config/import/targetTest.php delete mode 100644 tests/validator/structure/config/import/transform.php create mode 100644 tests/validator/structure/config/import/transformTest.php create mode 100644 tests/validator/structure/config/importTest.php create mode 100644 tests/validator/structureTest.php create mode 100644 tests/value/structure/taggedTest.php delete mode 100644 tests/value/structure/testTagged.php create mode 100644 tests/value/text/fileabsolute/taggedTest.php delete mode 100644 tests/value/text/fileabsolute/testTagged.php create mode 100644 tests/value/text/taggedTest.php delete mode 100644 tests/value/text/testTagged.php diff --git a/.gitignore b/.gitignore index 41d14f9..e6ed150 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ /vendor/* /vendor/ .phpunit.result.cache +.phpunit.cache .phpunit auth.json composer.lock diff --git a/backend/class/app.php b/backend/class/app.php index acacccb..d0ea624 100644 --- a/backend/class/app.php +++ b/backend/class/app.php @@ -1,9 +1,10 @@ data = $data; - $this->elementCount = count($this->data); - } +class arraydata extends datasource +{ + /** + * @var array + */ + protected array $data; - /** - * [protected description] - * @var int - */ - protected $elementCount = null; + /** + * [protected description] + * @var int + */ + protected int $elementCount; - /** - * @inheritDoc - */ - public function setConfig(array $config) - { - return; - } + /** + * [setData description] + * @param array $data [description] + */ + public function setData(array $data): void + { + $this->data = $data; + $this->elementCount = count($this->data); + } - /** - * @inheritDoc - */ - public function current() - { - return current($this->data); - } + /** + * {@inheritDoc} + */ + public function setConfig(array $config): void + { + } - /** - * @inheritDoc - */ - public function next() - { - return next($this->data); - } + /** + * {@inheritDoc} + */ + public function next(): void + { + next($this->data); + } - /** - * @inheritDoc - */ - public function key() - { - return key($this->data); - } + /** + * {@inheritDoc} + */ + public function valid(): bool + { + return $this->current() !== false; + } - /** - * @inheritDoc - */ - public function valid() - { - return $this->current() !== false; - } + /** + * {@inheritDoc} + */ + public function current(): mixed + { + return current($this->data); + } - /** - * @inheritDoc - */ - public function rewind() - { - reset($this->data); - } + /** + * {@inheritDoc} + */ + public function rewind(): void + { + reset($this->data); + } - /** - * @inheritDoc - */ - public function currentProgressPosition() : int - { - return $this->key(); - } + /** + * {@inheritDoc} + */ + public function currentProgressPosition(): int + { + return $this->key(); + } - /** - * @inheritDoc - */ - public function currentProgressLimit() : int - { - return $this->elementCount; - } + /** + * {@inheritDoc} + */ + public function key(): mixed + { + return key($this->data); + } + /** + * {@inheritDoc} + */ + public function currentProgressLimit(): int + { + return $this->elementCount; + } } diff --git a/backend/class/datasource/buffered.php b/backend/class/datasource/buffered.php index 10453cb..873c2ea 100644 --- a/backend/class/datasource/buffered.php +++ b/backend/class/datasource/buffered.php @@ -1,220 +1,219 @@ value = $value; - $this->progressPosition = $progressPosition; - } - - /** - * [public description] - * @var mixed - */ - public $value; - - /** - * [public description] - * @var [type] - */ - public $progressPosition; - +class bufferedValue +{ + /** + * [public description] + * @var mixed + */ + public mixed $value; + /** + * [public description] + * @var int [type] + */ + public int $progressPosition; + + /** + * @param mixed $value + * @param int $progressPosition + */ + public function __construct( + mixed $value, + int $progressPosition + ) { + $this->value = $value; + $this->progressPosition = $progressPosition; + } } /** * buffered datasource * that encapsulates another datasource */ -class buffered extends \codename\core\io\datasource { - - /** - * [__construct description] - * @param \codename\core\io\datasource $datasource [description] - * @param int $bufferSize [description] - */ - public function __construct(\codename\core\io\datasource $datasource, int $bufferSize) - { - if($bufferSize < 1) { - throw new exception('EXCEPTION_DATASOURCE_BUFFERED_BUFFERSIZE_TOO_LOW', exception::$ERRORLEVEL_ERROR, $bufferSize); +class buffered extends datasource +{ + /** + * size of the buffer + * @var int + */ + protected int $bufferSize = 1; + /** + * [protected description] + * @var datasource + */ + protected datasource $datasource; + /** + * [protected description] + * @var int [type] + */ + protected int $progressLimit; + /** + * index + * @var int + */ + protected int $index = -1; + /** + * [protected description] + * @var SplQueue + */ + protected SplQueue $bufferQueue; + /** + * [protected description] + * @var mixed + */ + protected mixed $currentValue = null; + + /** + * [__construct description] + * @param datasource $datasource [description] + * @param int $bufferSize [description] + * @throws exception + */ + public function __construct(datasource $datasource, int $bufferSize) + { + if ($bufferSize < 1) { + throw new exception('EXCEPTION_DATASOURCE_BUFFERED_BUFFERSIZE_TOO_LOW', exception::$ERRORLEVEL_ERROR, $bufferSize); + } + $this->bufferSize = $bufferSize; + $this->datasource = $datasource; + $this->progressLimit = $this->datasource->currentProgressLimit(); + $this->bufferQueue = new SplQueue(); } - $this->bufferSize = $bufferSize; - $this->datasource = $datasource; - $this->progressLimit = $this->datasource->currentProgressLimit(); - $this->bufferQueue = new \SplQueue(); - } - - /** - * [getBuffer description] - * @return \SplQueue [description] - */ - public function getBuffer() : \SplQueue { - return $this->bufferQueue; - } - - /** - * size of the buffer - * @var int - */ - protected $bufferSize = 1; - - /** - * [protected description] - * @var \codename\core\io\datasource - */ - protected $datasource = null; - - /** - * [protected description] - * @var [type] - */ - protected $progressLimit = null; - - /** - * index - * @var int - */ - protected $index = -1; - - /** - * [protected description] - * @var \SplQueue - */ - protected $bufferQueue = null; - - /** - * [setBufferSize description] - * @param int $size [description] - */ - public function setBufferSize(int $size) { - $this->bufferSize = $size; - } - - /** - * @inheritDoc - */ - public function setConfig(array $config) - { - // - // passthrough config - // - $this->datasource->setConfig($config); - } - - /** - * [fillBuffer description] - * @return void - */ - protected function fillBuffer() { - for ($i=0; $i < $this->bufferSize; $i++) { - if($this->datasource->valid()) { - $this->bufferQueue->enqueue( - new bufferedValue( - $this->datasource->current(), - $this->datasource->currentProgressPosition() - ) - ); - $this->datasource->next(); - } else { - break; - } + + /** + * {@inheritDoc} + */ + public function currentProgressLimit(): int + { + return $this->progressLimit ?? 1; } - } - - /** - * [protected description] - * @var bufferedValue - */ - protected $currentValue = null; - - /** - * @inheritDoc - */ - public function current() - { - return $this->currentValue ? $this->currentValue->value : $this->currentValue; - } - - /** - * @inheritDoc - */ - public function next() - { - if($this->bufferQueue->isEmpty()) { - $this->fillBuffer(); + + /** + * [getBuffer description] + * @return SplQueue [description] + */ + public function getBuffer(): SplQueue + { + return $this->bufferQueue; } - if(!$this->bufferQueue->isEmpty()) { - $this->currentValue = $this->bufferQueue->dequeue(); - $this->index++; - } else { - // end reached - $this->currentValue = false; + + /** + * [setBufferSize description] + * @param int $size [description] + */ + public function setBufferSize(int $size): void + { + $this->bufferSize = $size; } - } - - /** - * @inheritDoc - */ - public function key() - { - return $this->index; - } - - /** - * @inheritDoc - */ - public function valid() - { - return $this->currentValue !== false; // && $this->currentValue !== false && ($this->currentValue->value !== false) || $this->currentValue === null; - } - - /** - * @inheritDoc - */ - public function currentProgressPosition() : int - { - return $this->currentValue ? $this->currentValue->progressPosition : 0; - } - - /** - * @inheritDoc - */ - public function rewind() - { - $this->index = -1; - $this->datasource->rewind(); - - // empty the buffer - while(!$this->bufferQueue->isEmpty()) { - $this->bufferQueue->dequeue(); + + /** + * {@inheritDoc} + */ + public function setConfig(array $config): void + { + // + // passthrough config + // + $this->datasource->setConfig($config); } - $this->currentValue = null; + /** + * {@inheritDoc} + */ + public function key(): mixed + { + return $this->index; + } - // CHANGED 2021-04-29: missed next() call, leading to inconsistencies - // when using iteration interfaces - // NOTE: might cause side-effects with several underlying datasources. - $this->next(); - } + /** + * {@inheritDoc} + */ + public function rewind(): void + { + $this->index = -1; + $this->datasource->rewind(); + + // empty the buffer + while (!$this->bufferQueue->isEmpty()) { + $this->bufferQueue->dequeue(); + } + + $this->currentValue = null; + + // CHANGED 2021-04-29: missed next() call, leading to inconsistencies + // when using iteration interfaces + // NOTE: might cause side effects with several underlying datasource's. + $this->next(); + } - /** - * @inheritDoc - */ - public function currentProgressLimit() : int - { - return $this->progressLimit ?? 1; - } + /** + * {@inheritDoc} + */ + public function next(): void + { + if ($this->bufferQueue->isEmpty()) { + $this->fillBuffer(); + } + if (!$this->bufferQueue->isEmpty()) { + $this->currentValue = $this->bufferQueue->dequeue(); + $this->index++; + } else { + // end reached + $this->currentValue = false; + } + } + + /** + * [fillBuffer description] + * @return void + */ + protected function fillBuffer(): void + { + for ($i = 0; $i < $this->bufferSize; $i++) { + if ($this->datasource->valid()) { + $this->bufferQueue->enqueue( + new bufferedValue( + $this->datasource->current(), + $this->datasource->currentProgressPosition() + ) + ); + $this->datasource->next(); + } else { + break; + } + } + } + + /** + * {@inheritDoc} + */ + public function valid(): bool + { + return $this->currentValue !== false; // && $this->currentValue !== false && ($this->currentValue->value !== false) || $this->currentValue === null; + } + + /** + * {@inheritDoc} + */ + public function current(): mixed + { + return $this->currentValue ? $this->currentValue->value : $this->currentValue; + } + /** + * {@inheritDoc} + */ + public function currentProgressPosition(): int + { + return $this->currentValue ? $this->currentValue->progressPosition : 0; + } } diff --git a/backend/class/datasource/csv.php b/backend/class/datasource/csv.php index fe8738a..4000efc 100644 --- a/backend/class/datasource/csv.php +++ b/backend/class/datasource/csv.php @@ -1,284 +1,273 @@ setConfig($config); - /** - * [__construct description] - * @param string $filepath path to file - * @param array $config [description] - */ - public function __construct(string $filepath, array $config = array()) - { - $this->setConfig($config); + if (($this->handle = @fopen($filepath, "r")) !== false) { + $this->fstatSize = fstat($this->handle)['size']; - if (($this->handle = @fopen($filepath, "r")) !== false) - { - $this->fstatSize = fstat($this->handle)['size']; + if ($this->autodetectUtf8Bom) { + $this->handleUtf8Bom(); + } + } else { + error_clear_last(); + throw new exception('FILE_COULD_NOT_BE_OPEN', exception::$ERRORLEVEL_ERROR, [$filepath]); + } + } - if($this->autodetectUtf8Bom) { - $this->handleUtf8Bom(); - } + /** + * {@inheritDoc} + */ + public function setConfig(array $config): void + { + $this->delimiter = $config['delimiter'] ?? ','; + $this->headed = $config['headed'] ?? true; + $this->encoding = $config['encoding'] ?? null; + $this->skipRows = $config['skip_rows'] ?? 0; + $this->skipEmptyRows = $config['skip_empty_rows'] ?? false; + $this->autodetectUtf8Bom = $config['autodetect_utf8_bom'] ?? false; } - else + + /** + * this function detects UTF8-BOM, if we're at the beginning of the file + * and causes the datasource to skip these bytes + * @return void [type] [description] + */ + protected function handleUtf8Bom(): void { - error_clear_last(); - throw new exception('FILE_COULD_NOT_BE_OPEN', exception::$ERRORLEVEL_ERROR,array($filepath)); + if (ftell($this->handle) !== 0) { + return; // skip, as we are not on pos 0 (beginning of file) + } + + if (($header = fread($this->handle, 3)) !== false) { + if (strcmp($header, self::UTF8_BOM) === 0) { + // enable BOM handling + // TODO: kill existing encoding transformations + // + } else { + // rewind to start, no UTF8-BOM + fseek($this->handle, 0); + } + } else { + // nothing? error? + } } - } - /** - * this function detects UTF8-BOM, if we're at the beginning of the file - * and causes the datasource to skip these bytes - * @return [type] [description] - */ - protected function handleUtf8Bom() { - if(ftell($this->handle) !== 0) { - return; // skip, as we are not on pos 0 (beginning of file) + /** + * returns the headings retrieved for the current file + * @return string[] [description] + */ + public function getHeadings(): array + { + return $this->headings; } - if(($header = fread($this->handle, 3)) !== false) { - if(strcmp($header, self::UTF8_BOM) === 0) { - // enable BOM handling - // TODO: kill existing encoding transformations - // - } else { - // rewind to start, no UTF8-BOM + /** + * {@inheritDoc} + */ + public function rewind(): void + { fseek($this->handle, 0); - } - } else { - // nothing? error? + if ($this->autodetectUtf8Bom) { + $this->handleUtf8Bom(); + } + $this->index = 0; + $this->next(); } - } - - /** - * @inheritDoc - */ - public function setConfig(array $config) - { - $this->delimiter = $config['delimiter'] ?? ','; - $this->headed = $config['headed'] ?? true; - $this->encoding = $config['encoding'] ?? null; - $this->skipRows = $config['skip_rows'] ?? 0; - $this->skipEmptyRows = $config['skip_empty_rows'] ?? false; - $this->autodetectUtf8Bom = $config['autodetect_utf8_bom'] ?? false; - } - - /** - * detect and skip empty rows - * @var bool - */ - protected $skipEmptyRows = false; - - protected $headings = null; - - /** - * [protected description] - * @var bool - */ - protected $autodetectUtf8Bom = false; - - /** - * [UTF8_BOM description] - * see https://stackoverflow.com/questions/5601904/encoding-a-string-as-utf-8-with-bom-in-php - * @var string - */ - const UTF8_BOM = "\xEF\xBB\xBF"; // chr(239) . chr(187) . chr(191); - - /** - * returns the headings retrieved for the current file - * @return string[] [description] - */ - public function getHeadings() : array { - return $this->headings; - } - - /** - * is true if first line of csv contains heading - * @var bool - */ - protected $headed = true; - - /** - * the actuall postition - * @var int - */ - protected $index; - - /** - * [protected description] - * @var mixed - */ - protected $handle; - - /** - * current array item itself - * @var array - */ - protected $current; - /** - * [protected description] - * @var [type] - */ - public $delimiter = ';'; - - /** - * [public description] - * @var array - */ - public $encoding = null; - - /** - * @inheritDoc - */ - public function current() - { - return $this->current; - } - - /** - * @inheritDoc - */ - public function next() - { - $current = fgetcsv($this->handle, 0, $this->delimiter); + /** + * {@inheritDoc} + */ + public function next(): void + { + $current = fgetcsv($this->handle, 0, $this->delimiter); - if($this->skipRows > 0 && $this->key() === 0) { - for ($i=0; $i < $this->skipRows; $i++) { - $current = fgetcsv($this->handle, 0, $this->delimiter); + if ($this->skipRows > 0 && $this->key() === 0) { + for ($i = 0; $i < $this->skipRows; $i++) { + $current = fgetcsv($this->handle, 0, $this->delimiter); + } } - } - - // update ftell position - // $this->ftellPosition = ftell($this->handle); - // we have to stop next from running - // if fgetcsv returns false. - if($current === FALSE) { - $this->current = false; - return; - } + // we have to stop next from running + // if fgetcsv returns false. + if ($current === false) { + $this->current = false; + return; + } - if (!is_null($this->headings)) - { - if($this->skipEmptyRows) { - // check for "all-empty"-cells - // and loop forward until we reach another vital entry or the real end - while(count(array_filter($current)) === 0) { - $current = fgetcsv($this->handle, 0, $this->delimiter); - if($current === FALSE) { - $this->current = false; - return; + if (!is_null($this->headings)) { + if ($this->skipEmptyRows) { + // check for "all-empty"-cells + // and loop forward until we reach another vital entry or the real end + while (count(array_filter($current)) === 0) { + $current = fgetcsv($this->handle, 0, $this->delimiter); + if ($current === false) { + $this->current = false; + return; + } + } } - } - } - $i = 0; - $this->current = array(); - foreach($this->headings as $head) - { - if($this->encoding) { - $this->current[$head] = mb_convert_encoding($current[$i], $this->encoding['to'], $this->encoding['from']); - } else { - $this->current[$head] = $current[$i]; - } - $i++; - } - } else { - if($this->encoding) { - $this->current = array_map(function($item) { - return mb_convert_encoding($item, $this->encoding['to'], $this->encoding['from']); - }, $current); + $i = 0; + $this->current = []; + foreach ($this->headings as $head) { + if ($this->encoding) { + $this->current[$head] = mb_convert_encoding($current[$i], $this->encoding['to'], $this->encoding['from']); + } else { + $this->current[$head] = $current[$i]; + } + $i++; + } + } elseif ($this->encoding) { + $this->current = array_map(function ($item) { + return mb_convert_encoding($item, $this->encoding['to'], $this->encoding['from']); + }, $current); } else { - $this->current = $current; + $this->current = $current; } - } - - // echo "current: ".chr(10); - // print_r($this->current); - //$this->current = fgetcsv($this->handle, 0, ","); - - if ($this->valid()) - { - if ($this->key() == 0 && $this->headed) - { - //read in heading - $this->headings = $this->current(); - - // - // NOTE: decoding is performed implicitly, above. - // No need for double-decoding, this corrupts data. - // - // if($this->encoding) { - // $this->headings = array_map(function($item) { - // return mb_convert_encoding($item, $this->encoding['to'], $this->encoding['from']); - // }, $this->headings); - // } - - $this->index++; - return $this->next(); - } - $this->index++; - } - } - /** - * @inheritDoc - */ - public function key() - { - return $this->index; - } - - /** - * @inheritDoc - */ - public function valid() - { - return ($this->current !== FALSE); - } - - /** - * @inheritDoc - */ - public function rewind() - { - fseek($this->handle, 0); - if($this->autodetectUtf8Bom) { - $this->handleUtf8Bom(); + // echo "current: ".chr(10); + // print_r($this->current); + //$this->current = fgetcsv($this->handle, 0, ","); + + if ($this->valid()) { + if ($this->key() == 0 && $this->headed) { + //read in heading + $this->headings = $this->current(); + + // + // NOTE: decoding is performed implicitly, above. + // No need for double-decoding, this corrupts data. + // + // if($this->encoding) { + // $this->headings = array_map(function($item) { + // return mb_convert_encoding($item, $this->encoding['to'], $this->encoding['from']); + // }, $this->headings); + // } + + $this->index++; + $this->next(); + return; + } + $this->index++; + } } - $this->index = 0; - $this->next(); - } - protected $ftellPosition = 0; + /** + * {@inheritDoc} + */ + public function key(): mixed + { + return $this->index; + } - /** - * @inheritDoc - */ - public function currentProgressPosition(): int - { - return ftell($this->handle); - // return $this->ftellPosition; - } + /** + * {@inheritDoc} + */ + public function valid(): bool + { + return ($this->current !== false); + } - /** - * [protected description] - * @var int - */ - protected $fstatSize = 0; + /** + * {@inheritDoc} + */ + public function current(): mixed + { + return $this->current; + } - /** - * @inheritDoc - */ - public function currentProgressLimit(): int - { - return $this->fstatSize; - } + /** + * {@inheritDoc} + */ + public function currentProgressPosition(): int + { + return ftell($this->handle); + } + /** + * {@inheritDoc} + */ + public function currentProgressLimit(): int + { + return $this->fstatSize; + } } diff --git a/backend/class/datasource/database.php b/backend/class/datasource/database.php index 9915d8c..14e27f9 100644 --- a/backend/class/datasource/database.php +++ b/backend/class/datasource/database.php @@ -1,211 +1,204 @@ setConfig($config); + } - /** - * [__construct description] - * @param array $config [description] - */ - public function __construct(array $config = array()) - { - $this->setConfig($config); - } - - /** - * pipeline instance this target is connected to (optional) - * @var \codename\core\io\pipeline - */ - protected $pipelineInstance = null; - - /** - * @inheritDoc - */ - public function setPipelineInstance(\codename\core\io\pipeline $instance) - { - $this->pipelineInstance = $instance; - } - - /** - * [protected description] - * @var \codename\core\database - */ - protected $database = null; - - /** - * @inheritDoc - */ - public function setConfig(array $config) - { - if($this->pipelineInstance) { - $databaseConfig = $this->pipelineInstance->getOption('database_config') ?? []; - // merge with config - $config = array_replace($config, $databaseConfig); + /** + * {@inheritDoc} + * @param array $config + * @throws ReflectionException + * @throws exception + */ + public function setConfig(array $config): void + { + if ($this->pipelineInstance) { + $databaseConfig = $this->pipelineInstance->getOption('database_config') ?? []; + // merge with config + $config = array_replace($config, $databaseConfig); + } + + if ($config['driver'] ?? false) { + $dbClass = app::getInheritedClass('database_' . $config['driver']); + $this->database = new $dbClass($config); + + // use buffered queries when using MYSQL + // this should reduce memory usage BY A HUGE AMOUNT! + if ($this->database->getConnection()->getAttribute(PDO::ATTR_DRIVER_NAME) == 'mysql') { + $this->database->getConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true); + } + } + + if ($query = $config['query'] ?? false) { + $this->setQuery($query); + } + + if ($this->offsetBuffering = $config['offset_buffering'] ?? false) { + $this->offsetBufferSize = $config['offset_buffer_size'] ?? 100; + } } - - if($config['driver'] ?? false) { - $dbClass = app::getInheritedClass('database_'.$config['driver']); - $this->database = new $dbClass($config); - - // use buffered queries when using MYSQL - // this should reduce memory usage BY A HUGE AMOUNT! - if ($this->database->getConnection()->getAttribute(\PDO::ATTR_DRIVER_NAME) == 'mysql') { - $this->database->getConnection()->setAttribute(\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true); - } + + /** + * {@inheritDoc} + */ + public function setPipelineInstance(pipeline $instance): void + { + $this->pipelineInstance = $instance; } - if($query = $config['query'] ?? false) { - $this->setQuery($query); + /** + * {@inheritDoc} + */ + public function current(): mixed + { + return $this->currentResult; } - if($this->offsetBuffering = $config['offset_buffering'] ?? false) { - $this->offsetBufferSize = $config['offset_buffer_size'] ?? 100; + /** + * {@inheritDoc} + */ + public function key(): mixed + { + return $this->rowId; } - } - - /** - * offset-based result buffering - * @var bool - */ - protected $offsetBuffering = false; - - /** - * size of the offset buffer - * @var int - */ - protected $offsetBufferSize = null; - - /** - * current SQL query used - * @var string - */ - protected $query = null; - - /** - * [setQuery description] - * @param string $sql [description] - */ - public function setQuery(string $sql) { - $this->query = $sql; - } - - /** - * [protected description] - * @var array - */ - protected $currentResult = false; - - /** - * @inheritDoc - */ - public function current() - { - return $this->currentResult; - } - - /** - * @inheritDoc - */ - public function next() - { - $this->currentResult = $this->result->fetch(); - - if($this->offsetBuffering) { - if(!$this->valid()) { - // try next (auto-offsetting) - $this->result = $this->database->getConnection()->query($this->getQuery()); - $this->currentResult = $this->result->fetch(); - // DEBUG: - // if($this->valid()) { - // $this->currentResult['___offset_buffer_jump'] = $this->rowId; - // } - } + /** + * {@inheritDoc} + */ + public function rewind(): void + { + $this->rowId = null; + $this->result = $this->database->getConnection()->query($this->getQuery()); + $this->next(); + } - // DEBUG: - // if($this->valid()) { - // $this->currentResult['___offset_buffer_rowid'] = $this->rowId; - // } + /** + * [getQuery description] + * @return string [description] + */ + protected function getQuery(): string + { + if ($this->offsetBuffering) { + $limit = $this->offsetBufferSize; + $offset = ($this->rowId ?? 0); + return $this->query . " LIMIT $limit OFFSET $offset "; + } else { + return $this->query; + } } - $this->rowId++; - } - - /** - * @inheritDoc - */ - public function key() - { - return $this->rowId; - } - - /** - * @inheritDoc - */ - public function valid() - { - return $this->currentResult !== false; - } - - /** - * [protected description] - * @var \PDOStatement - */ - protected $result = null; - - /** - * [protected description] - * @var [type] - */ - protected $rowId = null; - - /** - * @inheritDoc - */ - public function rewind() - { - $this->rowId = null; - $this->result = $this->database->getConnection()->query($this->getQuery()); - $this->next(); - } - - /** - * [getQuery description] - * @return string [description] - */ - protected function getQuery() : string { - - if($this->offsetBuffering) { - $limit = $this->offsetBufferSize; - $offset = ($this->rowId ?? 0); - return $this->query . " LIMIT {$limit} OFFSET {$offset} "; - } else { - return $this->query; + /** + * [setQuery description] + * @param string $sql [description] + */ + public function setQuery(string $sql): void + { + $this->query = $sql; } - } - /** - * @inheritDoc - */ - public function currentProgressPosition() : int - { - return $this->rowId; - } + /** + * {@inheritDoc} + */ + public function next(): void + { + $this->currentResult = $this->result->fetch(); + + if ($this->offsetBuffering) { + if (!$this->valid()) { + // try next (auto-offsetting) + $this->result = $this->database->getConnection()->query($this->getQuery()); + $this->currentResult = $this->result->fetch(); + } + } - /** - * @inheritDoc - */ - public function currentProgressLimit() : int - { - return $this->result ? $this->result->rowCount() : 0; - } + $this->rowId++; + } + /** + * {@inheritDoc} + */ + public function valid(): bool + { + return $this->currentResult !== false; + } + /** + * {@inheritDoc} + */ + public function currentProgressPosition(): int + { + return $this->rowId; + } + + /** + * {@inheritDoc} + */ + public function currentProgressLimit(): int + { + return $this->result ? $this->result->rowCount() : 0; + } } diff --git a/backend/class/datasource/joined.php b/backend/class/datasource/joined.php index ffaa07f..76a780f 100644 --- a/backend/class/datasource/joined.php +++ b/backend/class/datasource/joined.php @@ -1,295 +1,295 @@ setConfig($config); + $this->setConfig($config); - foreach($datasources as $key => $ds) { - // We require instances of datasources here - if(!($ds instanceof \codename\core\io\datasource)) { - throw new exception('INVALID_DATASOURCE_INSTANCE_GIVEN', exception::$ERRORLEVEL_ERROR); - } + foreach ($datasources as $key => $ds) { + // We require instances of datasources here + if (!($ds instanceof datasource)) { + throw new exception('INVALID_DATASOURCE_INSTANCE_GIVEN', exception::$ERRORLEVEL_ERROR); + } - // datasources may be keyed/named - $this->datasources[$key] = $ds; + // datasources may be keyed/named + $this->datasources[$key] = $ds; - // first entry represents the main datasource - if($this->mainDatasourceKey === null) { - $this->mainDatasourceKey = $key; - } - } + // first entry represents the main datasource + if ($this->mainDatasourceKey === null) { + $this->mainDatasourceKey = $key; + } + } - // handle join configs, if defined - if($this->config->get('join')) { - foreach($this->config->get('join') as $joinIndex => $join) { - if($join['index'] ?? false) { - // create index for this datasource - $ds = $this->datasources[$join['join_datasource']]; - foreach($ds as $d) { - $indexHashValue = $d[$join['join_field']] ?? null; - if($indexHashValue) { - $this->indexes[$joinIndex][$indexHashValue][] = $d; + // handle join configs, if defined + if ($this->config->get('join')) { + foreach ($this->config->get('join') as $joinIndex => $join) { + if ($join['index'] ?? false) { + // create index for this datasource + $ds = $this->datasources[$join['join_datasource']]; + foreach ($ds as $d) { + $indexHashValue = $d[$join['join_field']] ?? null; + if ($indexHashValue) { + $this->indexes[$joinIndex][$indexHashValue][] = $d; + } + } + } } - } } - } } - } - - /** - * In-memory index - * @var array - */ - protected $indexes = []; - - /** - * [protected description] - * @var string|int - */ - protected $mainDatasourceKey = null; - - /** - * [protected description] - * @var \codename\core\config - */ - protected $config = null; - - /** - * @inheritDoc - */ - public function setConfig(array $config) { - $this->config = new \codename\core\config($config); - } - - /** - * @inheritDoc - */ - public function current() - { - return $this->current[$this->currentJoinResultIndex] ?? null; - } - - /** - * current array item itself - * @var array - */ - protected $current; - - /** - * [protected description] - * @var int - */ - protected $currentJoinResultIndex = 0; - - /** - * [protected description] - * @var int - */ - protected $currentJoinResultCount = null; - - /** - * @inheritDoc - */ - public function next() - { - if($this->currentJoinResultCount !== null) { - $this->currentJoinResultIndex++; + + /** + * {@inheritDoc} + */ + public function setConfig(array $config): void + { + $this->config = new config($config); } + /** + * {@inheritDoc} + */ + public function next(): void + { + if ($this->currentJoinResultCount !== null) { + $this->currentJoinResultIndex++; + } + + + if (($this->currentJoinResultCount !== null) && ($this->currentJoinResultIndex < $this->currentJoinResultCount)) { + $this->index++; + return; + } + $this->datasources[$this->mainDatasourceKey]->next(); - if(($this->currentJoinResultCount !== null) && ($this->currentJoinResultIndex < $this->currentJoinResultCount)) { - $this->index++; - return; + if ($this->datasources[$this->mainDatasourceKey]->valid()) { + $this->handleCurrent(); + } else { + $this->current = false; + } } - $this->datasources[$this->mainDatasourceKey]->next(); - if($this->datasources[$this->mainDatasourceKey]->valid()) { - $this->handleCurrent(); - } else { - $this->current = false; + /** + * {@inheritDoc} + */ + public function valid(): bool + { + return ($this->current !== false); } - } - /** - * handles data of the current entry - */ - protected function handleCurrent(): void { - $current = [ $this->datasources[$this->mainDatasourceKey]->current() ]; + /** + * handles data of the current entry + * @return void + */ + protected function handleCurrent(): void + { + $current = [$this->datasources[$this->mainDatasourceKey]->current()]; + + // Perform joins based on the main datasource first + $handleDatasources = [$this->mainDatasourceKey]; - // Perform joins based on the main datasource first - $handleDatasources = [ $this->mainDatasourceKey ]; + $dsAvailable = true; + $offset = count($handleDatasources) - 1; - $dsAvailable = true; - $offset = count($handleDatasources) - 1; + while ($dsAvailable) { + $dsAvailable = false; - while($dsAvailable) { - $dsAvailable = false; + $dses = []; - $dses = []; + foreach ($handleDatasources as $idx => $dsIdentifier) { + // skip already handled datasources + if ($idx < $offset) { + continue; + } - foreach($handleDatasources as $idx => $dsIdentifier) { + $offset++; - // skip already handled datasources - if($idx < $offset) { - continue; - } + // new datasource identifiers that have become available by joining + $newDatasourceIdentifiers = $this->performJoins($dsIdentifier, $current); - $offset++; + if (count($newDatasourceIdentifiers) === 0) { + continue; + } else { + $dses = array_merge($dses, $newDatasourceIdentifiers); + } + } - // new datasource identifiers that have become available by joining - $newDatasourceIdentifiers = $this->performJoins($dsIdentifier, $current); + $diffDatasourceIdentifiers = array_diff($dses, $handleDatasources); - if(count($newDatasourceIdentifiers) === 0) { - continue; - } else { - $dses = array_merge($dses, $newDatasourceIdentifiers); + // new DSes have become available + if (count($diffDatasourceIdentifiers) > 0) { + $handleDatasources = array_merge($handleDatasources, $diffDatasourceIdentifiers); + $dsAvailable = true; + } } - } - $diffDatasourceIdentifiers = array_diff($dses, $handleDatasources); + $this->currentJoinResultCount = count($current); + $this->currentJoinResultIndex = 0; + $this->index++; + $this->current = $current; + } - // new DSes have become available - if(count($diffDatasourceIdentifiers) > 0) { - $handleDatasources = array_merge($handleDatasources, $diffDatasourceIdentifiers); - $dsAvailable = true; - } + /** + * {@inheritDoc} + */ + public function current(): mixed + { + return $this->current[$this->currentJoinResultIndex] ?? null; } - $this->currentJoinResultCount = count($current); - $this->currentJoinResultIndex = 0; - $this->index++; - $this->current = $current; - } - - /** - * internally joins the various datasources - * @param string|int $baseDatasourceIdentifier - * @param array &$current - * @return array an array of handled datasource identifiers - */ - protected function performJoins($baseDatasourceIdentifier, array &$current): array { - $handledDatasources = []; - $joinedResult = []; - foreach($this->config->get('join') as $joinIndex => $join) { - if($join['base_datasource'] == $baseDatasourceIdentifier) { - - $baseField = $join['base_field']; - $joinField = $join['join_field']; - - foreach($current as $c) { - if(($c[$baseField] ?? null) === null) { - continue; - } - - if($join['index'] ?? false) { - // indexed key/column - $indexValues = $this->indexes[$joinIndex][$c[$baseField]] ?? null; - if($indexValues) { - foreach($indexValues as $d) { - $joinedResult[] = array_merge($c, $d); - // NOTE: dataset multiplication due to join ambiguity possible right here. - } - } - } else { - // only joins based on the main datasource key - $ds = $this->datasources[$join['join_datasource']]; - - // Unindexed variant - foreach($ds as $d) { - // TODO NULL handling - if($d[$joinField] == $c[$baseField]) { - $joinedResult[] = array_merge($c, $d); - // NOTE: dataset multiplication due to join ambiguity possible right here. - } + /** + * internally joins the various datasources + * @param int|string $baseDatasourceIdentifier + * @param array &$current + * @return array an array of handled datasource identifiers + */ + protected function performJoins(int|string $baseDatasourceIdentifier, array &$current): array + { + $handledDatasources = []; + $joinedResult = []; + foreach ($this->config->get('join') as $joinIndex => $join) { + if ($join['base_datasource'] == $baseDatasourceIdentifier) { + $baseField = $join['base_field']; + $joinField = $join['join_field']; + + foreach ($current as $c) { + if (($c[$baseField] ?? null) === null) { + continue; + } + + if ($join['index'] ?? false) { + // indexed key/column + $indexValues = $this->indexes[$joinIndex][$c[$baseField]] ?? null; + if ($indexValues) { + foreach ($indexValues as $d) { + $joinedResult[] = array_merge($c, $d); + // NOTE: dataset multiplication due to join ambiguity possible right here. + } + } + } else { + // only joins based on the main datasource key + $ds = $this->datasources[$join['join_datasource']]; + + // Un-Indexed variant + foreach ($ds as $d) { + // TODO NULL handling + if ($d[$joinField] == $c[$baseField]) { + $joinedResult[] = array_merge($c, $d); + // NOTE: dataset multiplication due to join ambiguity possible right here. + } + } + } + } + + // we might have had no join matches + // therefore, pass original datasets + if (count($joinedResult) > 0) { + $current = $joinedResult; + $joinedResult = []; + } + + $handledDatasources[] = $join['join_datasource']; } - } } + return $handledDatasources; + } - // we might have had no join matches - // therefore, pass original datasets - if(count($joinedResult) > 0) { - $current = $joinedResult; - $joinedResult = []; - } + /** + * {@inheritDoc} + */ + public function key(): mixed + { + return $this->index; + } + + /** + * {@inheritDoc} + */ + public function rewind(): void + { + $this->datasources[$this->mainDatasourceKey]->rewind(); + $this->index = 0; + $this->currentJoinResultIndex = 0; + $this->currentJoinResultCount = null; + $this->handleCurrent(); + } + + /** + * {@inheritDoc} + */ + public function currentProgressPosition(): int + { + return $this->index; + } - $handledDatasources[] = $join['join_datasource']; - } + /** + * {@inheritDoc} + */ + public function currentProgressLimit(): int + { + return 0; // Cannot be estimated } - return $handledDatasources; - } - - /** - * the current position - * @var int - */ - protected $index; - - /** - * @inheritDoc - */ - public function key() - { - return $this->index; - } - - /** - * @inheritDoc - */ - public function valid() - { - return ($this->current !== FALSE); - } - - /** - * @inheritDoc - */ - public function rewind() - { - $this->datasources[$this->mainDatasourceKey]->rewind(); - $this->index = 0; - $this->currentJoinResultIndex = 0; - $this->currentJoinResultCount = null; - $this->handleCurrent(); - } - - /** - * @inheritDoc - */ - public function currentProgressPosition(): int - { - return $this->index; - } - - /** - * @inheritDoc - */ - public function currentProgressLimit(): int - { - return 0; // Cannot be estimated - } } diff --git a/backend/class/datasource/model.php b/backend/class/datasource/model.php index df4c4a3..b9b2591 100644 --- a/backend/class/datasource/model.php +++ b/backend/class/datasource/model.php @@ -1,431 +1,356 @@ setConfig($config); - } - - /** - * pipeline instance this target is connected to (optional) - * @var \codename\core\io\pipeline - */ - protected $pipelineInstance = null; - - /** - * @inheritDoc - */ - public function setPipelineInstance(\codename\core\io\pipeline $instance) - { - $this->pipelineInstance = $instance; - } - - /** - * [setModel description] - * @param \codename\core\model $model [description] - */ - public function setModel(\codename\core\model $model) { - if(!$this->model) { - $this->model = $model; - } else { - throw new exception('EXCEPTION_DATASOURCE_MODEL_ALREADY_SET', exception::$ERRORLEVEL_FATAL); - } - } - - /** - * [protected description] - * @var \codename\core\model - */ - protected $model = null; - - /** - * @inheritDoc - */ - public function setConfig(array $config) - { - if($this->pipelineInstance) { - // $databaseConfig = $this->pipelineInstance->getOption('database_config') ?? []; - // // merge with config - // $config = array_replace($config, $databaseConfig); + /** + * pipeline instance this target is connected to (optional) + * @var null|pipeline + */ + protected ?pipeline $pipelineInstance = null; + /** + * [protected description] + * @var null|\codename\core\model + */ + protected ?\codename\core\model $model = null; + /** + * [protected description] + * @var array [type] + */ + protected array $separateDbConnections = []; + /** + * offset-based result buffering + * @var bool + */ + protected bool $offsetBuffering = false; + /** + * size of the offset buffer + * @var null|int + */ + protected ?int $offsetBufferSize = null; + /** + * Total limit, across all buffered runs + * This emulates a "LIMIT", if offset buffering enabled. + * @var null|int + */ + protected ?int $offsetLimit = null; + /** + * current query parameters being used + * @var null|array + */ + protected ?array $query = null; + /** + * [protected description] + * @var array|bool + */ + protected array|bool $currentResult = false; + /** + * [protected description] + * @var int + */ + protected int $tempRowId = 0; + /** + * [protected description] + * @var array|null + */ + protected ?array $result = null; + /** + * [protected description] + * @var int|null [type] + */ + protected ?int $rowId = null; + + /** + * [__construct description] + * @param array $config [description] + * @throws ReflectionException + * @throws exception + */ + public function __construct(array $config = []) + { + $this->setConfig($config); } - // - // Allow empty queries to be pre-configured - // - if(($query = ($config['query'] ?? false)) || (is_array($query = $config['query'] ?? false))) { - $this->setQuery($query); - } + /** + * {@inheritDoc} + * @param array $config + * @throws ReflectionException + * @throws exception + */ + public function setConfig(array $config): void + { + // + // Allow empty queries to be pre-configured + // + if (($query = ($config['query'] ?? false)) || (is_array($query = $config['query'] ?? false))) { + $this->setQuery($query); + } - if($this->offsetBuffering = $config['offset_buffering'] ?? false) { - $this->offsetBufferSize = $config['offset_buffer_size'] ?? 100; - $this->offsetLimit = $config['offset_limit'] ?? null; + if ($this->offsetBuffering = $config['offset_buffering'] ?? false) { + $this->offsetBufferSize = $config['offset_buffer_size'] ?? 100; + $this->offsetLimit = $config['offset_limit'] ?? null; + } + + if ($config['model'] ?? null) { + // clean connections + $this->separateDbConnections = []; + $this->model = $this->buildModelStructure($config); + } } - if($modelName = $config['model'] ?? null) { - - // clean connections - $this->separateDbConnections = []; - $this->model = $this->buildModelStructure($config); - - // $this->model = \codename\core\app::getModel($modelName); - - // - // Crazy stuff... - // if you're doing a model=>model import (same model) - // you might get into the situation of querying inside a transaction - // which leads to STRANGE stuff happending. - // we simply overcome it here by using a separate connection. BAM! - // - // if($config['connection_separate'] ?? false) { - // // get a non-stored db connection - // $db = \codename\core\app::getDb($this->model->getConfig()->get('connection'), false); - // $this->model->setConnectionOverride($db); - // } - - // if($fields = $config['fields'] ?? null) { - // $this->model->hideAllFields(); - // foreach($fields as $field) { - // $this->model->addField($field); - // } - // } - // - // if($join = $config['join'] ?? null) { - // foreach($join as $j) { - // $this->model->addModel(\codename\core\app::getModel($j['model'])); - // } - // } + /** + * [buildModelStructure description] + * @param array $config [description] + * @return \codename\core\model [description] + * @throws ReflectionException + * @throws exception + */ + protected function buildModelStructure(array $config): \codename\core\model + { + $model = app::getModel($config['model'], $config['app'] ?? '', $config['vendor'] ?? ''); + + if ($config['virtualFieldResult'] ?? false) { + $model->setVirtualFieldResult(true); + } + + // + // Crazy stuff... + // if you're doing a model=>model import (same model) + // you might get into the situation of querying inside a transaction + // which leads to STRANGE stuff happening. + // we simply overcome it here by using a separate connection. BAM! + // + if (($config['connection_separate'] ?? false) || ($this->separateDbConnections[$model->getConfig()->get('connection')] ?? false)) { + // get a non-stored db connection + $conn = $model->getConfig()->get('connection'); + // share separate connections, especially for larger joins. + $db = $this->separateDbConnections[$conn] ?? $this->separateDbConnections[$conn] = app::getDb($conn, false); + $model->setConnectionOverride($db); + } + + if ($fields = $config['fields'] ?? null) { + $model->hideAllFields(); + foreach ($fields as $field) { + $model->addField($field); + } + } + + // + // Apply source-based filters & filtercollections as default filter(collections) + // + if ($filter = $config['filter'] ?? null) { + foreach ($filter as $f) { + $model->addDefaultFilter($f['field'], $f['value'], $f['operator'] ?? '='); + } + } + if ($filtercollection = $config['filtercollection'] ?? null) { + foreach ($filtercollection as $fc) { + $model->addDefaultFilterCollection($fc['filters'], $fc['group_operator'] ?? 'AND', $fc['group_name'] ?? 'default', $fc['conjunction'] ?? 'AND'); + } + } + + if ($joins = $config['join'] ?? null) { + foreach ($joins as $join) { + $joinModel = $this->buildModelStructure($join); + if (($join['type'] ?? false) === 'collection') { + $model->addCollectionModel($joinModel, $join['modelfield'] ?? null); + } else { + $model->addModel($joinModel); + } + } + } + + return $model; } - } - - /** - * [protected description] - * @var [type] - */ - protected $separateDbConnections = []; - - /** - * [buildModelStructure description] - * @param array $config [description] - * @return \codename\core\model [description] - */ - protected function buildModelStructure(array $config) : \codename\core\model { - $model = app::getModel($config['model'], $config['app'] ?? '', $config['vendor'] ?? ''); - - if($config['virtualFieldResult'] ?? false) { - $model->setVirtualFieldResult(true); + + /** + * {@inheritDoc} + */ + public function setPipelineInstance(pipeline $instance): void + { + $this->pipelineInstance = $instance; } - // - // Crazy stuff... - // if you're doing a model=>model import (same model) - // you might get into the situation of querying inside a transaction - // which leads to STRANGE stuff happending. - // we simply overcome it here by using a separate connection. BAM! - // - if(($config['connection_separate'] ?? false) || ($this->separateDbConnections[$model->getConfig()->get('connection')] ?? false)) { - // get a non-stored db connection - $conn = $model->getConfig()->get('connection'); - // share separate connections, especially for larger joins. - $db = $this->separateDbConnections[$conn] ?? $this->separateDbConnections[$conn] = \codename\core\app::getDb($conn, false); - $model->setConnectionOverride($db); + /** + * [setModel description] + * @param \codename\core\model $model [description] + * @throws exception + */ + public function setModel(\codename\core\model $model): void + { + if (!$this->model) { + $this->model = $model; + } else { + throw new exception('EXCEPTION_DATASOURCE_MODEL_ALREADY_SET', exception::$ERRORLEVEL_FATAL); + } } - if($fields = $config['fields'] ?? null) { - $model->hideAllFields(); - foreach($fields as $field) { - $model->addField($field); - } + /** + * {@inheritDoc} + */ + public function current(): mixed + { + return $this->currentResult; } - // - // Apply source-based filters & filtercollections as default filter(collections) - // - if($filter = $config['filter'] ?? null) { - foreach($filter as $f) { - $model->addDefaultfilter($f['field'], $f['value'], $f['operator'] ?? '='); - } + /** + * {@inheritDoc} + */ + public function key(): mixed + { + return $this->rowId; } - if($filtercollection = $config['filtercollection'] ?? null) { - foreach($filtercollection as $fc) { - $model->addDefaultFilterCollection($fc['filters'], $fc['group_operator'] ?? 'AND', $fc['group_name'] ?? 'default', $fc['conjunction'] ?? 'AND'); - } + + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + public function rewind(): void + { + $this->rowId = null; + + $this->result = $this->executeModelQuery($this->getQuery()); + + $this->tempRowId = 0; + $this->next(); } - if($joins = $config['join'] ?? null) { - foreach($joins as $join) { - $joinModel = $this->buildModelStructure($join); - if(($join['type'] ?? false) === 'collection') { - $model->addCollectionModel($joinModel, $join['modelfield'] ?? null); - } else { - $model->addModel($joinModel); + /** + * [executeModelQuery description] + * @param array $query [description] + * @return array [description] + * @throws ReflectionException + * @throws exception + */ + protected function executeModelQuery(array $query): array + { + if ($filters = $query['filter'] ?? null) { + foreach ($filters as $filter) { + if ($filter['value']['option'] ?? false) { + $filter['value'] = $this->pipelineInstance->getOption($filter['value']['option']); + } + $this->model->addFilter($filter['field'], $filter['value'], $filter['operator'] ?? '='); + } + } + if ($filtercollections = $query['filtercollection'] ?? null) { + foreach ($filtercollections as $filtercollection) { + $filters = $filtercollection['filters']; + foreach ($filters as &$filter) { + if ($filter['value']['option'] ?? false) { + $filter['value'] = $this->pipelineInstance->getOption($filter['value']['option']); + } + } + $this->model->addFilterCollection($filters, $filtercollection['group_operator'] ?? 'AND', $filtercollection['group_name'] ?? 'default', $filtercollection['conjunction'] ?? null); + } } - } - } - return $model; - } - - /** - * offset-based result buffering - * @var bool - */ - protected $offsetBuffering = false; - - /** - * size of the offset buffer - * @var int - */ - protected $offsetBufferSize = null; - - /** - * Total limit, across all buffered runs - * This emulates a "LIMIT", if offset buffering enabled. - * @var int - */ - protected $offsetLimit = null; - - /** - * current query parameters being used - * @var array - */ - protected $query = null; - - /** - * [setQuery description] - * @param array $data [description] - */ - public function setQuery(array $data) { - $this->query = $data; - } - - /** - * [protected description] - * @var array - */ - protected $currentResult = false; - - /** - * @inheritDoc - */ - public function current() - { - return $this->currentResult; - } - - /** - * [protected description] - * @var [type] - */ - protected $tempRowId = 0; - - /** - * @inheritDoc - */ - public function next() - { - $this->currentResult = $this->result[$this->tempRowId] ?? false; // $this->result->fetch(); - - if($this->offsetBuffering) { - if(!$this->valid()) { - // try next (auto-offsetting) - $this->result = $this->executeModelQuery($this->getQuery()); // // $this->database->getConnection()->query($this->getQuery()); - $this->tempRowId = 0; - $this->currentResult = $this->result[$this->tempRowId] ?? false; // $this->result->fetch(); - - // \codename\core\app::getResponse()->setData('datasource_model_query_result', array_merge( - // \codename\core\app::getResponse()->getData('datasource_model_query_result') ?? [], - // [ - // [ - // 'result' => $this->result - // ] - // ] - // )); - - // DEBUG: - // if($this->valid()) { - // $this->currentResult['___offset_buffer_jump'] = $this->rowId; - // } - } - - if($this->offsetLimit !== null) { - if($this->offsetLimit <= $this->rowId) { - $this->currentResult = false; // emulate limit? + if ($order = $query['order'] ?? null) { + foreach ($order as $orderStatement) { + $this->model->addOrder($orderStatement['field'], $orderStatement['order']); + } + } + if ($limit = $query['limit'] ?? null) { + $this->model->setLimit($limit); + } + if ($offset = $query['offset'] ?? null) { + $this->model->setOffset($offset); } - } - // DEBUG: - // if($this->valid()) { - // $this->currentResult['___offset_buffer_rowid'] = $this->rowId; - // } + return $this->model->search()->getResult(); } - $this->tempRowId++; - $this->rowId++; - } - - /** - * @inheritDoc - */ - public function key() - { - return $this->rowId; - } - - /** - * @inheritDoc - */ - public function valid() - { - // \codename\core\app::getResponse()->setData('datasource_model_valid_test', array_merge( - // \codename\core\app::getResponse()->getData('datasource_model_valid_test') ?? [], - // [ - // [ - // 'tempRowId' => $this->tempRowId, - // 'rowId' => $this->rowId, - // 'currentResult' => $this->currentResult - // ] - // ] - // )); - return $this->currentResult !== false; - } - - /** - * [protected description] - * @var array - */ - protected $result = null; - - /** - * [protected description] - * @var [type] - */ - protected $rowId = null; - - /** - * @inheritDoc - */ - public function rewind() - { - $this->rowId = null; - - $this->result = $this->executeModelQuery($this->getQuery()); - - // \codename\core\app::getResponse()->setData('datasource_model_query_result', array_merge( - // \codename\core\app::getResponse()->getData('datasource_model_query_result') ?? [], - // [ - // [ - // 'result' => $this->result - // ] - // ] - // )); - - $this->tempRowId = 0; - $this->next(); - } - - /** - * [executeModelQuery description] - * @param array $query [description] - * @return array [description] - */ - protected function executeModelQuery(array $query) : array { - if($filters = $query['filter'] ?? null) { - foreach($filters as $filter) { - if($filter['value']['option'] ?? false) { - $filter['value'] = $this->pipelineInstance->getOption($filter['value']['option']); - } - $this->model->addFilter($filter['field'], $filter['value'], $filter['operator'] ?? '='); - } - } - if($filtercollections = $query['filtercollection'] ?? null) { - foreach($filtercollections as $filtercollection) { - $filters = $filtercollection['filters']; - foreach($filters as &$filter) { - if($filter['value']['option'] ?? false) { - $filter['value'] = $this->pipelineInstance->getOption($filter['value']['option']); - } + /** + * [getQuery description] + * @return array [description] + */ + protected function getQuery(): array + { + if ($this->offsetBuffering) { + $limit = $this->offsetBufferSize; + $offset = ($this->rowId ?? 0); + + return array_merge( + $this->query, + [ + 'limit' => $limit, + 'offset' => $offset, + ] + ); + } else { + return $this->query; } - $this->model->addFilterCollection($filters, $filtercollection['group_operator'] ?? 'AND', $filtercollection['group_name'] ?? 'default', $filtercollection['conjunction'] ?? null); - } } - if($order = $query['order'] ?? null) { - foreach($order as $orderStatement) { - $this->model->addOrder($orderStatement['field'], $orderStatement['order']); - } - } - if($limit = $query['limit'] ?? null) { - $this->model->setLimit($limit); - } - if($offset = $query['offset'] ?? null) { - $this->model->setOffset($offset); + /** + * [setQuery description] + * @param array $data [description] + */ + public function setQuery(array $data): void + { + $this->query = $data; } - // \codename\core\app::getResponse()->setData('datasource_model', array_merge( - // \codename\core\app::getResponse()->getData('datasource_model') ?? [], - // [ - // [ - // 'filters' => $query['filter'] ?? null, - // 'filtercollections' => $query['filtercollection'] ?? null, - // 'limit' => $query['limit'] ?? null, - // 'offset' => $query['offset'] ?? null, - // ] - // ] - // )); - - return $this->model->search()->getResult(); - } - - /** - * [getQuery description] - * @return array [description] - */ - protected function getQuery() : array { - if($this->offsetBuffering) { - $limit = $this->offsetBufferSize; - $offset = ($this->rowId ?? 0); - - return array_merge( - $this->query, - [ - 'limit' => $limit, - 'offset' => $offset - ] - ); - } else { - return $this->query; - } - } + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + public function next(): void + { + $this->currentResult = $this->result[$this->tempRowId] ?? false; + + if ($this->offsetBuffering) { + if (!$this->valid()) { + // try next (auto-offsetting) + $this->result = $this->executeModelQuery($this->getQuery()); + $this->tempRowId = 0; + $this->currentResult = $this->result[$this->tempRowId] ?? false; + } + + if ($this->offsetLimit !== null) { + if ($this->offsetLimit <= $this->rowId) { + $this->currentResult = false; // emulate limit? + } + } + } - /** - * @inheritDoc - */ - public function currentProgressPosition() : int - { - return $this->rowId; - } + $this->tempRowId++; + $this->rowId++; + } - /** - * @inheritDoc - */ - public function currentProgressLimit() : int - { - return $this->result ? count($this->result) : 0; - } + /** + * {@inheritDoc} + */ + public function valid(): bool + { + return $this->currentResult !== false; + } + /** + * {@inheritDoc} + */ + public function currentProgressPosition(): int + { + return $this->rowId; + } + /** + * {@inheritDoc} + */ + public function currentProgressLimit(): int + { + return $this->result ? count($this->result) : 0; + } } diff --git a/backend/class/datasource/multicsv.php b/backend/class/datasource/multicsv.php index a65d1e3..a081ebd 100644 --- a/backend/class/datasource/multicsv.php +++ b/backend/class/datasource/multicsv.php @@ -1,181 +1,178 @@ setConfig($config); + + $i = 0; + foreach ($files as $file) { + // CHANGED 2021-04-30: we now pass through the full config to nested datasources + $subconfig = $this->config->get(); + $this->datasources[$i] = new csv($file, $subconfig); + $i++; + } + + $this->fileindex = 0; + } + + /** + * {@inheritDoc} + */ + public function setConfig(array $config): void + { + // CHANGED 2021-04-30: we now pass through the full config to nested datasources + // and fallback configs to default + store them in a member variable + $this->delimiter = $config['delimiter'] = $config['delimiter'] ?? ';'; + $this->headed = $config['headed'] = $config['headed'] ?? true; + $this->config = new config($config); + + foreach ($this->datasources as $datasource) { + // CHANGED 2021-04-30: we now pass through the full config to nested datasources + $subconfig = $this->config->get(); + $datasource->setConfig($subconfig); + } + } + + /** + * {@inheritDoc} + */ + public function next(): void + { + $this->datasources[$this->fileindex]->next(); + if (!$this->datasources[$this->fileindex]->valid()) { + if ($this->fileindex < (count($this->datasources) - 1)) { + // move on to next datasource + $this->fileindex++; + } + } + $this->overallKey++; } - $this->setConfig($config); + /** + * {@inheritDoc} + */ + public function valid(): bool + { + return ($this->datasources[$this->fileindex]->current() !== false); + } - $i = 0; - foreach($files as $file) + /** + * {@inheritDoc} + */ + public function current(): mixed { - // CHANGED 2021-04-30: we now passthrough the full config to nested datasources - $subconfig = $this->config->get(); - $this->datasources[$i] = new \codename\core\io\datasource\csv($file, $subconfig); - $i++; + return $this->datasources[$this->fileindex]->current(); } - $this->fileindex = 0; - } - - /** - * [protected description] - * @var \codename\core\config - */ - protected $config = null; - - /** - * @inheritDoc - */ - public function setConfig(array $config) - { - // CHANGED 2021-04-30: we now passthrough the full config to nested datasources - // and fallback configs to default + store them in a member variable - $this->delimiter = $config['delimiter'] = $config['delimiter'] ?? ';'; - $this->headed = $config['headed'] = $config['headed'] ?? true; - $this->config = new \codename\core\config($config); - - foreach($this->datasources as $datasource) { - // CHANGED 2021-04-30: we now passthrough the full config to nested datasources - $subconfig = $subconfig = $this->config->get(); - $datasource->setConfig($subconfig); + /** + * {@inheritDoc} + */ + public function key(): mixed + { + return $this->overallKey; } - } - - /** - * @inheritDoc - */ - public function current() - { - return $this->datasources[$this->fileindex]->current(); - } - - /** - * @inheritDoc - */ - public function next() - { - $this->datasources[$this->fileindex]->next(); - if(!$this->datasources[$this->fileindex]->valid()) { - if ($this->fileindex < (count($this->datasources)-1)) { - // move on to next datasource - $this->fileindex++; - } else { - // end? - } - } else { + + /** + * {@inheritDoc} + */ + public function rewind(): void + { + $this->fileindex = 0; + foreach ($this->datasources as $ds) { + $ds->rewind(); + } + $this->overallKey = 0; + $this->positions = []; } - $this->overallKey++; - } - - /** - * [protected description] - * @var int - */ - protected $overallKey = 0; - - /** - * @inheritDoc - */ - public function key() - { - return $this->overallKey; // $this->datasources[$this->fileindex]->key(); - } - - /** - * @inheritDoc - */ - public function valid() - { - return ($this->datasources[$this->fileindex]->current() !== false); - } - - /** - * @inheritDoc - */ - public function rewind() - { - $this->fileindex = 0; - foreach($this->datasources as $ds) { - $ds->rewind(); + + /** + * {@inheritDoc} + */ + public function currentProgressPosition(): int + { + $this->positions[$this->fileindex] = $this->datasources[$this->fileindex]->currentProgressPosition(); + return array_sum($this->positions); } - $this->overallKey = 0; - $this->positions = []; - } - - /** - * [protected description] - * @var int[] - */ - protected $positions = []; - - /** - * @inheritDoc - */ - public function currentProgressPosition(): int - { - $this->positions[$this->fileindex] = $this->datasources[$this->fileindex]->currentProgressPosition(); - return array_sum($this->positions); - } - - /** - * just save the progress limits of the datasources - * to make sure we don't cause IO-intensive operations somehow - * @var int|null - */ - protected $cachedProgressLimit = null; - - /** - * @inheritDoc - */ - public function currentProgressLimit(): int - { - if(!$this->cachedProgressLimit) { - $count = 0; - foreach($this->datasources as $datasource) { - $count += $datasource->currentProgressLimit(); - } - $this->cachedProgressLimit = $count; + + /** + * {@inheritDoc} + */ + public function currentProgressLimit(): int + { + if (!$this->cachedProgressLimit) { + $count = 0; + foreach ($this->datasources as $datasource) { + $count += $datasource->currentProgressLimit(); + } + $this->cachedProgressLimit = $count; + } + return $this->cachedProgressLimit; } - return $this->cachedProgressLimit; - } } diff --git a/backend/class/datasource/parquet.php b/backend/class/datasource/parquet.php index 3525c5a..4468e0c 100644 --- a/backend/class/datasource/parquet.php +++ b/backend/class/datasource/parquet.php @@ -1,220 +1,217 @@ setConfig($config); - - if (($this->handle = @fopen($filepath, "r")) !== false) + /** + * [protected description] + * @var resource + */ + protected $handle; + + /** + * [protected description] + * @var ParquetReader + */ + protected ParquetReader $reader; + /** + * [protected description] + * @var int + */ + protected int $currentRowGroupIndex = 0; + /** + * [protected description] + * @var array|null + */ + protected ?array $currentRowGroupData = null; + /** + * [protected description] + * @var null|int + */ + protected ?int $currentRowCount = null; + /** + * [protected description] + * @var null|int + */ + protected ?int $currentIndex = null; + /** + * [protected description] + * @var int + */ + protected int $overallKey = 0; + + /** + * [__construct description] + * @param string $filepath path to file + * @param array $config [description] + * @throws exception + */ + public function __construct(string $filepath, array $config = []) { - $this->initParquetReader(); + $this->setConfig($config); + + if (($this->handle = @fopen($filepath, "r")) !== false) { + $this->initParquetReader(); + } else { + error_clear_last(); + throw new exception('FILE_COULD_NOT_BE_OPENED', exception::$ERRORLEVEL_ERROR, [$filepath]); + } } - else + + /** + * {@inheritDoc} + */ + public function setConfig(array $config): void { - error_clear_last(); - throw new exception('FILE_COULD_NOT_BE_OPENED', exception::$ERRORLEVEL_ERROR,array($filepath)); } - } - - /** - * @inheritDoc - */ - public function setConfig(array $config) - { - - } - - /** - * [initParquetReader description] - */ - protected function initParquetReader(): void { - // TODO: ParquetOptions - $this->reader = new ParquetReader($this->handle); - } - - /** - * [protected description] - * @var int - */ - protected $currentRowGroupIndex = 0; - - /** - * [protected description] - * @var array|null - */ - protected $currentRowGroupData = null; - - /** - * [protected description] - * @var int - */ - protected $currentRowCount = null; - - /** - * [protected description] - * @var int - */ - protected $currentIndex = null; - - /** - * [read description] - * @return bool - */ - protected function read(): bool { - - if($this->currentRowGroupData === null) { - // nothing to check, unread data - } else { - // check current read state - // or simply increment by 1 ? - $this->currentRowGroupIndex++; + + /** + * [initParquetReader description] + * @throws \Exception + */ + protected function initParquetReader(): void + { + // TODO: ParquetOptions + $this->reader = new ParquetReader($this->handle); } - if($this->reader->getRowGroupCount() <= $this->currentRowGroupIndex) { - return false; // finished reading + /** + * {@inheritDoc} + */ + public function current(): mixed + { + return $this->currentRowGroupData[$this->currentIndex] ?? null; } - $dataFields = $this->reader->schema->getDataFields(); - $rg = $this->reader->OpenRowGroupReader($this->currentRowGroupIndex); + /** + * {@inheritDoc} + */ + public function key(): mixed + { + return $this->overallKey; + } - $this->currentRowCount = $rg->getRowCount(); - $this->currentIndex = 0; - $this->currentRowGroupData = []; + /** + * {@inheritDoc} + */ + public function valid(): bool + { + return $this->currentRowGroupIndex < $this->reader->getRowGroupCount() && $this->overallKey < $this->reader->getThriftMetadata()->num_rows; + } - foreach($dataFields as $field) { - $values = $rg->ReadColumn($field)->getData(); - foreach($values as $index => $value) { - $this->currentRowGroupData[$index][$field->name] = $value; - } + /** + * {@inheritDoc} + * @throws ParquetException + */ + public function rewind(): void + { + $this->overallKey = 0; + $this->currentIndex = null; + $this->currentRowGroupIndex = 0; + $this->currentRowGroupData = null; + $this->currentRowCount = null; + $this->next(); } - return true; - } - - /** - * @inheritDoc - */ - public function current() - { - return $this->currentRowGroupData[$this->currentIndex] ?? null; - } - - /** - * @inheritDoc - */ - public function next() - { - if($this->currentIndex === null) { - // trigger read on first try or when required to advance to the next row group - if(!$this->read()) { - return; - } - - $this->currentIndex = 0; - $this->overallKey = 0; - // NOTE/CHANGED 2021-05-03: we might receive an empty datapage - // right from the start, so we have to execute the code below... - } else { - // - // we're still working on the current, already-read rowgroup/page - // move on to next key - it will automatically lead to page change, - // if required - // - $this->currentIndex++; - $this->overallKey++; + /** + * {@inheritDoc} + * @throws ParquetException + */ + public function next(): void + { + if ($this->currentIndex === null) { + // trigger read on first try or when required to advance to the next row group + if (!$this->read()) { + return; + } + + $this->currentIndex = 0; + $this->overallKey = 0; + // NOTE/CHANGED 2021-05-03: we might receive an empty datapage + // right from the start, so we have to execute the code below... + } else { + // + // we're still working on the current, already-read rowgroup/page + // move on to next key - it will automatically lead to page change, + // if required + // + $this->currentIndex++; + $this->overallKey++; + } + + if ($this->currentIndex >= $this->currentRowCount) { + if ($this->read()) { + // try to overcome empty datapage/rowgroup reading + // if the last read produced an empty result set + // continue reading + while (empty($this->currentRowGroupData)) { + // + // If we reach the end (read returning false) + // break out, we really reached the end. + // + if (!$this->read()) { + break; + } + } + } + } } - if($this->currentIndex >= $this->currentRowCount) { - - if($this->read()) { - // try to overcome empty datapage/rowgroup reading - // if the last read produced an empty result set - // continue reading - while(empty($this->currentRowGroupData)) { - // - // If we reach the end (read returning false) - // break out, we really reached the end. - // - if(!$this->read()) { - break; - } + /** + * [read description] + * @return bool + * @throws ParquetException + */ + protected function read(): bool + { + if ($this->currentRowGroupData === null) { + // nothing to check, unread data + } else { + // check current read state + // or simply increment by 1 ? + $this->currentRowGroupIndex++; + } + + if ($this->reader->getRowGroupCount() <= $this->currentRowGroupIndex) { + return false; // finished reading } - } + + $dataFields = $this->reader->schema->getDataFields(); + $rg = $this->reader->OpenRowGroupReader($this->currentRowGroupIndex); + + $this->currentRowCount = $rg->getRowCount(); + $this->currentIndex = 0; + $this->currentRowGroupData = []; + + foreach ($dataFields as $field) { + $values = $rg->ReadColumn($field)->getData(); + foreach ($values as $index => $value) { + $this->currentRowGroupData[$index][$field->name] = $value; + } + } + + return true; } - } - - /** - * [protected description] - * @var int - */ - protected $overallKey = 0; - - /** - * @inheritDoc - */ - public function key() - { - return $this->overallKey; - } - - /** - * @inheritDoc - */ - public function valid() - { - return $this->currentRowGroupIndex < $this->reader->getRowGroupCount() && $this->overallKey < $this->reader->getThriftMetadata()->num_rows; - } - - /** - * @inheritDoc - */ - public function rewind() - { - $this->overallKey = 0; - $this->currentIndex = null; - $this->currentRowGroupIndex = 0; - $this->currentRowGroupData = null; - $this->currentRowCount = null; - $this->next(); - } - - /** - * @inheritDoc - */ - public function currentProgressPosition(): int - { - return $this->overallKey; - } - - /** - * @inheritDoc - */ - public function currentProgressLimit(): int - { - return $this->reader->getThriftMetadata()->num_rows; - } + /** + * {@inheritDoc} + */ + public function currentProgressPosition(): int + { + return $this->overallKey; + } + + /** + * {@inheritDoc} + */ + public function currentProgressLimit(): int + { + return $this->reader->getThriftMetadata()->num_rows; + } } diff --git a/backend/class/datasource/raw.php b/backend/class/datasource/raw.php index 664c9d7..46eb4ed 100644 --- a/backend/class/datasource/raw.php +++ b/backend/class/datasource/raw.php @@ -1,303 +1,296 @@ [ - * 'output-key-1' => 'partial-sprintf-cmd', - * 'output-key-2' => 'partial-sprintf-cmd' - * ] - * ] - * @see http://php.net/manual/de/function.fscanf.php - * @see http://php.net/manual/de/function.sprintf.php - * @var array - */ - protected $format = null; - - /** - * mappings - * optional - * - array index specifies the fscanf output array --index-- - * - subarray: matching condition in key (fscanf output array --index value--) - * - subarray item value: new sprintf formatting - * [ - * 'inputkey' => [ - * 'someval' => [ - * 'map' => [ - * 'mapkey1' => 'sprinf-cmd', - * 'mapkey2' => 'sprinf-cmd' - * ] - * ], - * ... - * ] - * ] - * @var array - */ - protected $mappings = []; - - /** - * pre-computed format config - * @var array - */ - public $computedFormat = null; - - /** - * pre-computed mappings config - * @var array - */ - public $computedMappings = null; - - /** - * [__construct description] - * @param string $filepath [path to file] - * @param array $config [configuration of this datasource] - */ - public function __construct(string $filepath, array $config = array()) - { - $this->setConfig($config); - - if (($this->handle = @fopen($filepath, "r")) !== false) +class raw extends datasource +{ + /** + * pre-computed format config + * @var null|array + */ + public ?array $computedFormat = null; + /** + * pre-computed mappings config + * @var null|array + */ + public ?array $computedMappings = null; + /** + * input interpretation format as array + * [ + * 'map' => [ + * 'output-key-1' => 'partial-sprintf-cmd', + * 'output-key-2' => 'partial-sprintf-cmd' + * ] + * ] + * @see http://php.net/manual/de/function.fscanf.php + * @see http://php.net/manual/de/function.sprintf.php + * @var null|array + */ + protected ?array $format = null; + /** + * mappings + * optional + * - array index specifies the fscanf output array --index-- + * - subarray: matching condition in key (fscanf output array --index value--) + * - subarray item value: new sprintf formatting + * [ + * 'inputkey' => [ + * 'someval' => [ + * 'map' => [ + * 'mapkey1' => 'sprinf-cmd', + * 'mapkey2' => 'sprinf-cmd' + * ] + * ], + * ... + * ] + * ] + * @var array + */ + protected array $mappings = []; + /** + * [protected description] + * @var bool + */ + protected bool $useComputedMappings; + /** + * [protected description] + * @var bool|array|null [type] + */ + protected null|bool|array $current = null; + /** + * [protected description] + * @var int [type] + */ + protected int $index = 0; + /** + * @var resource|false + */ + protected $handle; + /** + * @var string|false + */ + protected string|false $rawCurrent; + + /** + * [__construct description] + * @param string $filepath [path to file] + * @param array $config [configuration of this datasource] + * @throws exception + */ + public function __construct(string $filepath, array $config = []) { - // load success + $this->setConfig($config); + + if (($this->handle = @fopen($filepath, "r")) !== false) { + // load success + } else { + error_clear_last(); + throw new exception('FILE_COULD_NOT_BE_OPENED', exception::$ERRORLEVEL_ERROR, [$filepath]); + } } - else + + /** + * {@inheritDoc} + * @param array $config + * @throws exception + */ + public function setConfig(array $config): void { - error_clear_last(); - throw new exception('FILE_COULD_NOT_BE_OPENED', exception::$ERRORLEVEL_ERROR,array($filepath)); - } - } - - /** - * [getSprintfMap description] - * @param array $config [description] - * @return string [sprintf/sscanf compatible string] - */ - protected function getSprintfMap(array $config) { - if($config['type'] == 'fixed') { - return '%'.$config['length']."[^".chr(10)."]"; - } else { - throw new exception('CORE_IO_DATASOURCE_INVALID_MAP_CONFIG', exception::$ERRORLEVEL_ERROR, $config); - } - } - - /** - * @inheritDoc - */ - public function setConfig(array $config) - { - $this->format = $config['format'] ?? []; - $this->mappings = $config['mappings'] ?? []; - - $computedMap = array_map(function($item) { - return $this->getSprintfMap($item); - }, $this->format['map'] ?? []); - - $this->computedFormat = [ - 'format' => isset($this->format['map']) ? implode('', array_values( $computedMap )) : '', - 'map' => isset($this->format['map']) ? array_keys( $this->format['map'] ) : [], - 'convert' => $this->format['convert'] ?? false, - 'trim' => $this->format['trim'] ?? false - ]; - - $this->computedMappings = []; - if(count($this->mappings) > 0) { - foreach($this->mappings as $conditionKey => $mappingConfig) { - $this->computedMappings[$conditionKey] = []; - foreach($mappingConfig as $conditionValue => $map) { - $computedSubMap = array_map(function($item) { + $this->format = $config['format'] ?? []; + $this->mappings = $config['mappings'] ?? []; + + $computedMap = array_map(function ($item) { return $this->getSprintfMap($item); - }, $map['map'] ?? []); - $this->computedMappings[$conditionKey][$conditionValue] = [ - 'format' => implode('', array_values($computedSubMap)), - 'map' => array_keys($map['map']), - 'convert' => $map['convert'] ?? false, - 'trim' => $map['trim'] ?? false - ]; + }, $this->format['map'] ?? []); + + $this->computedFormat = [ + 'format' => isset($this->format['map']) ? implode('', array_values($computedMap)) : '', + 'map' => isset($this->format['map']) ? array_keys($this->format['map']) : [], + 'convert' => $this->format['convert'] ?? false, + 'trim' => $this->format['trim'] ?? false, + ]; + + $this->computedMappings = []; + if (count($this->mappings) > 0) { + foreach ($this->mappings as $conditionKey => $mappingConfig) { + $this->computedMappings[$conditionKey] = []; + foreach ($mappingConfig as $conditionValue => $map) { + $computedSubMap = array_map(function ($item) { + return $this->getSprintfMap($item); + }, $map['map'] ?? []); + $this->computedMappings[$conditionKey][$conditionValue] = [ + 'format' => implode('', array_values($computedSubMap)), + 'map' => array_keys($map['map']), + 'convert' => $map['convert'] ?? false, + 'trim' => $map['trim'] ?? false, + ]; + } + } } - } + + $this->useComputedMappings = (count($this->computedMappings) > 0); } - $this->useComputedMappings = (count($this->computedMappings) > 0); - } - - /** - * [protected description] - * @var bool - */ - protected $useComputedMappings; - - /** - * @inheritDoc - */ - public function current() - { - return $this->current; - } - - /** - * [protected description] - * @var [type] - */ - protected $current = null; - - /** - * [getRawCurrent description] - * @return [type] [description] - */ - public function getRawCurrent() { - return $this->rawCurrent; - } - - /** - * @inheritDoc - */ - public function next() - { - $rawvalue = fgets($this->handle); - - $this->rawCurrent = $rawvalue; - - if($rawvalue) { - - $readvalue = $rawvalue; - - // value being worked on - $value = []; - - $scanvalue = sscanf($readvalue, $this->computedFormat['format']); - - foreach($this->computedFormat['map'] as $mapIndex => $mapField) { - if($this->computedFormat['convert']) { - // TODO: move to field mapping - $value[$mapField] = mb_convert_encoding($scanvalue[$mapIndex], $this->computedFormat['convert']['to'], $this->computedFormat['convert']['from'] ?? mb_internal_encoding()); + /** + * [getSprintfMap description] + * @param array $config [description] + * @return string [sprintf/sscanf compatible string] + * @throws exception + */ + protected function getSprintfMap(array $config): string + { + if ($config['type'] == 'fixed') { + return '%' . $config['length'] . "[^" . chr(10) . "]"; } else { - $value[$mapField] = $scanvalue[$mapIndex]; + throw new exception('CORE_IO_DATASOURCE_INVALID_MAP_CONFIG', exception::$ERRORLEVEL_ERROR, $config); } + } - if($this->computedFormat['trim']) { - $value[$mapField] = trim($value[$mapField]); - } + /** + * {@inheritDoc} + */ + public function current(): mixed + { + return $this->current; + } - } + /** + * [getRawCurrent description] + * @return mixed + */ + public function getRawCurrent(): mixed + { + return $this->rawCurrent; + } - if(!$this->useComputedMappings) { + /** + * {@inheritDoc} + */ + public function key(): mixed + { + return $this->index; + } - // current working value is our output value - $this->current = $value; + /** + * {@inheritDoc} + */ + public function rewind(): void + { + fseek($this->handle, 0); + $this->index = 0; + $this->current = false; + $this->next(); + } - } else { - // recursive parsing + /** + * {@inheritDoc} + */ + public function next(): void + { + $rawvalue = fgets($this->handle); - $found = false; + $this->rawCurrent = $rawvalue; - foreach($this->computedMappings as $mapIndex => $mapConfig) { - $mappedValue = $value[$mapIndex]; + if ($rawvalue) { + $readvalue = $rawvalue; - // we found a map config - if(!empty($mapConfig[$mappedValue])) { + // value being worked on + $value = []; - // convert encoding, if configured - // if($mapConfig[$mappedValue]['convert']) { - // $readvalue = mb_convert_encoding($readvalue, $mapConfig[$mappedValue]['convert']['to'], $mapConfig[$mappedValue]['convert']['from']); - // } + $scanvalue = sscanf($readvalue, $this->computedFormat['format']); - $formatted = sscanf($readvalue, $mapConfig[$mappedValue]['format']); + foreach ($this->computedFormat['map'] as $mapIndex => $mapField) { + if ($this->computedFormat['convert']) { + // TODO: move to field mapping + $value[$mapField] = mb_convert_encoding($scanvalue[$mapIndex], $this->computedFormat['convert']['to'], $this->computedFormat['convert']['from'] ?? mb_internal_encoding()); + } else { + $value[$mapField] = $scanvalue[$mapIndex]; + } - $value = []; - foreach($mapConfig[$mappedValue]['map'] as $mapIndex => $mapField) { - // convert encoding, if configured - if($mapConfig[$mappedValue]['convert']) { - $value[$mapField] = mb_convert_encoding($formatted[$mapIndex], $mapConfig[$mappedValue]['convert']['to'], $mapConfig[$mappedValue]['convert']['from'] ?? mb_internal_encoding()); - } else { - $value[$mapField] = $formatted[$mapIndex]; - } - - if($mapConfig[$mappedValue]['trim']) { - $value[$mapField] = trim($value[$mapField]); - } + if ($this->computedFormat['trim']) { + $value[$mapField] = trim($value[$mapField]); + } + } + if (!$this->useComputedMappings) { + // current working value is our output value + $this->current = $value; + } else { + // recursive parsing + + $found = false; + + foreach ($this->computedMappings as $mapIndex => $mapConfig) { + $mappedValue = $value[$mapIndex]; + + // we found a map config + if (!empty($mapConfig[$mappedValue])) { + $formatted = sscanf($readvalue, $mapConfig[$mappedValue]['format']); + + $value = []; + foreach ($mapConfig[$mappedValue]['map'] as $mapIndex => $mapField) { + // convert encoding, if configured + if ($mapConfig[$mappedValue]['convert']) { + $value[$mapField] = mb_convert_encoding($formatted[$mapIndex], $mapConfig[$mappedValue]['convert']['to'], $mapConfig[$mappedValue]['convert']['from'] ?? mb_internal_encoding()); + } else { + $value[$mapField] = $formatted[$mapIndex]; + } + + if ($mapConfig[$mappedValue]['trim']) { + $value[$mapField] = trim($value[$mapField]); + } + } + $this->current = $value; + $found = true; + break; + } else { + // value not found + // mapping invalid. move on to next value? + } + } + + if (!$found) { + $this->current = null; + } } - $this->current = $value; - $found = true; - break; - } else { - // value not found - // mapping invalid. move on to next value? - // $this->next(); - // $this->current = null; - } + } else { + // end of file? + $this->current = $rawvalue; } - if(!$found) { - $this->current = null; + if ($this->valid()) { + $this->index++; } - } - } else { - // end of file? - $this->current = $rawvalue; } - if ($this->valid()) + /** + * {@inheritDoc} + */ + public function valid(): bool + { + return ($this->current !== false); + } + + /** + * {@inheritDoc} + */ + public function currentProgressPosition(): int + { + return ftell($this->handle); + } + + /** + * {@inheritDoc} + */ + public function currentProgressLimit(): int { - $this->index++; + return fstat($this->handle)['size']; } - } - - /** - * [protected description] - * @var [type] - */ - protected $index = 0; - - /** - * @inheritDoc - */ - public function key() - { - return $this->index; - } - - /** - * @inheritDoc - */ - public function valid() - { - return ($this->current !== FALSE); - } - - /** - * @inheritDoc - */ - public function rewind() - { - fseek($this->handle, 0); - $this->index = 0; - $this->current = false; - $this->next(); - } - - /** - * @inheritDoc - */ - public function currentProgressPosition(): int - { - return ftell($this->handle); - } - - /** - * @inheritDoc - */ - public function currentProgressLimit(): int - { - return fstat($this->handle)['size']; - } } diff --git a/backend/class/datasource/remap.php b/backend/class/datasource/remap.php index ec49a40..2b154f8 100644 --- a/backend/class/datasource/remap.php +++ b/backend/class/datasource/remap.php @@ -1,194 +1,194 @@ datasource = $datasource; - $this->setConfig($config); - } - - /** - * @inheritDoc - */ - public function setConfig(array $config) - { - $this->config = new \codename\core\config($config); - $this->remap = $this->config->get('remap'); - - $this->invertedRemap = []; - foreach($this->remap as $oldKey => $newKey) { - if(is_array($newKey)) { - foreach($newKey as $key) { - $this->invertedRemap[$key] = $oldKey; +class remap extends datasource +{ + /** + * the underlying datasource + * @var datasource + */ + protected datasource $datasource; + + /** + * config object + * @var config + */ + protected config $config; + /** + * output value "current()" is based on the original source + * remapped keys may replace old ones + * @var bool + */ + protected bool $sourceDataReplace = false; + /** + * key to store original/source data in (null => do not store) + * @var string|null + */ + protected ?string $sourceDataKey = null; + /** + * remapping config + * @var array + */ + protected array $remap = []; + /** + * inverted remapping config, for multiple new-keys for ONE old key + * @var array + */ + protected array $invertedRemap = []; + /** + * index + * @var int + */ + protected int $index = -1; + /** + * current value + * @var mixed + */ + protected mixed $currentValue = null; + + /** + * [__construct description] + * @param datasource $datasource [description] + * @param array $config [description] + */ + public function __construct(datasource $datasource, array $config) + { + $this->datasource = $datasource; + $this->setConfig($config); + } + + /** + * {@inheritDoc} + */ + public function setConfig(array $config): void + { + $this->config = new config($config); + $this->remap = $this->config->get('remap'); + + $this->invertedRemap = []; + foreach ($this->remap as $oldKey => $newKey) { + if (is_array($newKey)) { + foreach ($newKey as $key) { + $this->invertedRemap[$key] = $oldKey; + } + } else { + $this->invertedRemap[$newKey] = $oldKey; + } + } + + $this->sourceDataReplace = $this->config->get('replace') ?? false; + $this->sourceDataKey = $this->config->get('source_data_key') ?? null; + } + + /** + * {@inheritDoc} + */ + public function next(): void + { + $this->datasource->next(); + + if ($this->datasource->valid()) { + $this->currentValue = $this->remapData($this->datasource->current()); + $this->index++; + } else { + $this->currentValue = false; + } + } + + /** + * {@inheritDoc} + */ + public function valid(): bool + { + return $this->datasource->valid(); + } + + /** + * the internal remapping function + * @param array $input [description] + * @return array [description] + */ + protected function remapData(array $input): array + { + if ($this->sourceDataReplace) { + $output = $input; + } else { + $output = []; + } + + // TODO: allow old values to be present? + if ($this->sourceDataKey) { + $output[$this->sourceDataKey] = $input; } - } else { - $this->invertedRemap[$newKey] = $oldKey; - } + + // TODO: insert complete old dataset? + // foreach($this->remap as $oldKey => $newKey) { + // // TODO: explicitly allow fallback - or check for array_key_exists? + // // throw on error? + // $output[$newKey] = $input[$oldKey] ?? null; + // } + foreach ($this->invertedRemap as $newKey => $oldKey) { + // TODO: explicitly allow fallback - or check for array_key_exists? + // throw on error? + $output[$newKey] = $input[$oldKey] ?? null; + } + return $output; } - $this->sourceDataReplace = $this->config->get('replace') ?? false; - $this->sourceDataKey = $this->config->get('source_data_key') ?? null; - } - - /** - * output value "current()" is based on the original source - * remapped keys may replace old ones - * @var bool - */ - protected $sourceDataReplace = false; - - /** - * key to store original/source data in (null => do not store) - * @var string|null - */ - protected $sourceDataKey = null; - - /** - * remapping config - * @var array - */ - protected $remap = []; - - /** - * inverted remapping config, for multiple new-keys for ONE oldkey - * @var array - */ - protected $invertedRemap = []; - - /** - * index - * @var int - */ - protected $index = -1; - - /** - * current value - * @var array - */ - protected $currentValue = null; - - /** - * @inheritDoc - */ - public function current() - { - return $this->currentValue; - } - - /** - * @inheritDoc - */ - public function next() - { - $this->datasource->next(); - - if($this->datasource->valid()) { - $this->currentValue = $this->remapData($this->datasource->current()); - $this->index++; - } else { - $this->currentValue = false; + /** + * {@inheritDoc} + */ + public function current(): mixed + { + return $this->currentValue; } - } - - /** - * the internal remapping function - * @param array $input [description] - * @return array [description] - */ - protected function remapData(array $input) : array { - if($this->sourceDataReplace) { - $output = $input; - } else { - $output = []; + + /** + * {@inheritDoc} + */ + public function key(): mixed + { + return $this->datasource->key(); } - // TODO: allow old values to be present? - if($this->sourceDataKey) { - $output[$this->sourceDataKey] = $input; + /** + * {@inheritDoc} + */ + public function rewind(): void + { + $this->index = -1; + $this->datasource->rewind(); + + if ($this->datasource->valid()) { + $this->currentValue = $this->remapData($this->datasource->current()); + } else { + $this->currentValue = false; + } } - // TODO: insert complete old dataset? - // foreach($this->remap as $oldKey => $newKey) { - // // TODO: explicitly allow fallback - or check for array_key_exists? - // // throw on error? - // $output[$newKey] = $input[$oldKey] ?? null; - // } - foreach($this->invertedRemap as $newKey => $oldKey) { - // TODO: explicitly allow fallback - or check for array_key_exists? - // throw on error? - $output[$newKey] = $input[$oldKey] ?? null; + /** + * {@inheritDoc} + */ + public function currentProgressPosition(): int + { + return $this->datasource->currentProgressPosition(); } - return $output; - } - - /** - * @inheritDoc - */ - public function key() - { - return $this->datasource->key(); - } - - /** - * @inheritDoc - */ - public function valid() - { - return $this->datasource->valid(); - } - - /** - * @inheritDoc - */ - public function rewind() - { - $this->index = -1; - $this->datasource->rewind(); - - if($this->datasource->valid()) { - $this->currentValue = $this->remapData($this->datasource->current()); - } else { - $this->currentValue = false; + + /** + * {@inheritDoc} + */ + public function currentProgressLimit(): int + { + return $this->datasource->currentProgressLimit(); } - } - - /** - * @inheritDoc - */ - public function currentProgressPosition() : int - { - return $this->datasource->currentProgressPosition(); - } - - /** - * @inheritDoc - */ - public function currentProgressLimit() : int - { - return $this->datasource->currentProgressLimit(); - } } diff --git a/backend/class/datasource/spreadsheet.php b/backend/class/datasource/spreadsheet.php index ae2d8ff..108b9a1 100644 --- a/backend/class/datasource/spreadsheet.php +++ b/backend/class/datasource/spreadsheet.php @@ -1,347 +1,342 @@ setConfig($config); - - $this->filename = $file; - - set_time_limit(0); - - // Increase memory limit to heavenly heights. - ini_set('memory_limit', '2048M'); - - // use \DateTime Objects by default - \PhpOffice\PhpSpreadsheet\Calculation\Functions::setReturnDateType(\PhpOffice\PhpSpreadsheet\Calculation\Functions::RETURNDATE_PHP_OBJECT); - - // this automatically creates the matching reader for the file. - $this->reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReaderForFile($this->filename); - - // skip empty cells - $this->reader->setReadEmptyCells(false); - - $this->sheet = $this->reader->load($this->filename); - - if($this->sheet->getSheetCount() > 0) { - if($this->customSheetIndex) { - // custom sheet index - $this->customSheetIndex = intval($this->customSheetIndex); - } else { - // fallback to first sheet - $this->customSheetIndex = 0; - } - $this->activeSheet = $this->sheet->getSheet($this->customSheetIndex); - $this->activeSheetRowIterator = $this->activeSheet->getRowIterator(); - } +class spreadsheet extends datasource +{ + /** + * [protected description] + * @var IReader + */ + protected IReader $reader; + + /** + * [protected description] + * @var null|string + */ + protected ?string $filename = null; + + /** + * true if the given sheet(s) are headed + * @var bool + */ + protected bool $headed = true; + + /** + * [protected description] + * @var bool + */ + protected bool $includeSpreadsheetColumns = false; + + /** + * [protected description] + * @var null|\PhpOffice\PhpSpreadsheet\Spreadsheet + */ + protected ?\PhpOffice\PhpSpreadsheet\Spreadsheet $sheet = null; + + /** + * [protected description] + * @var null|Worksheet|\PhpOffice\PhpSpreadsheet\Spreadsheet + */ + protected null|Worksheet|\PhpOffice\PhpSpreadsheet\Spreadsheet $activeSheet = null; + + /** + * [protected description] + * @var null|RowIterator + */ + protected ?RowIterator $activeSheetRowIterator = null; + + /** + * [protected description] + * @var bool + */ + protected bool $includeEmptyRows = false; + + /** + * [__construct description] + * @param string $file [description] + * @param bool $headed [description] + * @param bool $includeSpreadsheetColumns [description] + */ + /** + * specific sheet index to use + * @var int|string|null + */ + protected string|int|null $customSheetIndex = null; + /** + * Let the reader read across multiple sheets + * as one continuous dataset + * @var bool + */ + protected bool $multisheet = false; + /** + * skip until this row number + * @var int + */ + protected int $skipRows = 0; + /** + * number of header row + * @var int + */ + protected int $headerRow = 1; + /** + * [protected description] + * @var mixed + */ + protected mixed $currentValue = null; + /** + * [protected description] + * @var array + */ + protected array $currentColumnMapping = []; + /** + * [protected description] + * @var int + */ + protected int $sheetIndex = 0; + /** + * [protected description] + * @var int + */ + protected int $globalRowIndex = 0; + + /** + * [__construct description] + * @param string $file [description] + * @param array $config [description] + * @throws Exception + * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception + */ + public function __construct(string $file = '', array $config = [] /* bool $headed = true, bool $includeSpreadsheetColumns = false*/) + { + $this->setConfig($config); + + $this->filename = $file; + + set_time_limit(0); + + // Increase memory limit to heavenly heights. + ini_set('memory_limit', '2048M'); + + // use \DateTime Objects by default + Functions::setReturnDateType(Functions::RETURNDATE_PHP_OBJECT); + + // this automatically creates the matching reader for the file. + $this->reader = IOFactory::createReaderForFile($this->filename); + + // skip empty cells + $this->reader->setReadEmptyCells(false); + + $this->sheet = $this->reader->load($this->filename); + + if ($this->sheet->getSheetCount() > 0) { + if ($this->customSheetIndex) { + // custom sheet index + $this->customSheetIndex = intval($this->customSheetIndex); + } else { + // fallback to first sheet + $this->customSheetIndex = 0; + } + $this->activeSheet = $this->sheet->getSheet($this->customSheetIndex); + $this->activeSheetRowIterator = $this->activeSheet->getRowIterator(); + } + // count of sheets: $this->reader->getSheetCount() + // get/activate a specific sheet: $this->reader->getSheet($sheetIndex); + // alternative: $this->reader->getSheetByName('some-string'); - // count of sheets: $this->reader->getSheetCount() - // get/activate a specific sheet: $this->reader->getSheet($sheetIndex); - // alternative: $this->reader->getSheetByName('some-string'); - - // $this->activeSheetRowIterator = $this->reader->getActiveSheet()->getRowIterator(); - - // if ... $this->reader->canRead($this->filename) - } - - /** - * specific sheet index to use - * @var int|string|null - */ - protected $customSheetIndex = null; - - /** - * Let the reader read across multiple sheets - * as one continuous dataset - * @var bool - */ - protected $multisheet = false; - - /** - * skip until this row number - * @var int - */ - protected $skipRows = 0; - - /** - * number of header row - * @var int - */ - protected $headerRow = 1; - - /** - * @inheritDoc - */ - public function setConfig(array $config) - { - $this->headed = $config['headed'] ?? true; - $this->includeSpreadsheetColumns = $config['include_spreadsheet_columns'] ?? false; - $this->skipRows = $config['skip_rows'] ?? 0; - $this->headerRow = $config['header_row'] ?? 1; - $this->customSheetIndex = $config['custom_sheet_index'] ?? null; - $this->multisheet = $config['multisheet'] ?? false; - } - - - /** - * @inheritDoc - */ - public function current() - { - return $this->currentValue; - } - - /** - * [protected description] - * @var mixed - */ - protected $currentValue = null; - - /** - * [protected description] - * @var array - */ - protected $currentColumnMapping = []; - - /** - * @inheritDoc - */ - public function next() - { - // reset current value - $this->currentValue = null; - - if($this->skipRows) { - while($this->activeSheetRowIterator->key() < ($this->skipRows)) { - $this->activeSheetRowIterator->next(); - } - } + // $this->activeSheetRowIterator = $this->reader->getActiveSheet()->getRowIterator(); - if($this->headed) { - while($this->activeSheetRowIterator->key() < ($this->headerRow)) { - $this->activeSheetRowIterator->next(); - } + // if ... $this->reader->canRead($this->filename) } - // NOTE: RowIterator starts its index at 1 - // Therefore, we are getting the headed data columns at index 2 - if($this->headed && $this->activeSheetRowIterator->valid() && $this->activeSheetRowIterator->key() === ($this->headerRow)) { - - // use first row in each sheet for mapping the values - // get current row. - $row = $this->activeSheetRowIterator->current(); - - // iterate over cells. - $cellIterator = $row->getCellIterator(); - - // reset old column mapping - $this->currentColumnMapping = []; - - // create a new column mapping - foreach($cellIterator as $cell) { - $cellValue = $cell->getValue(); - if(!empty($cellValue)) { - $this->currentColumnMapping[$cell->getColumn()] = $cellValue; - } - } + /** + * {@inheritDoc} + */ + public function setConfig(array $config): void + { + $this->headed = $config['headed'] ?? true; + $this->includeSpreadsheetColumns = $config['include_spreadsheet_columns'] ?? false; + $this->skipRows = $config['skip_rows'] ?? 0; + $this->headerRow = $config['header_row'] ?? 1; + $this->customSheetIndex = $config['custom_sheet_index'] ?? null; + $this->multisheet = $config['multisheet'] ?? false; } - $this->activeSheetRowIterator->next(); - - if($this->activeSheetRowIterator->valid()) { + /** + * {@inheritDoc} + * @throws Exception + */ + public function rewind(): void + { + $this->currentValue = null; + $this->sheetIndex = $this->customSheetIndex ?? 0; + $this->activeSheet = $this->sheet->getSheet($this->sheetIndex); + $this->activeSheetRowIterator = $this->activeSheet->getRowIterator(); + $this->globalRowIndex = 0; + $this->next(); + } - // get current row. - $row = $this->activeSheetRowIterator->current(); + /** + * {@inheritDoc} + * @throws Exception + * @throws \PhpOffice\PhpSpreadsheet\Calculation\Exception + */ + public function next(): void + { + // reset current value + $this->currentValue = null; + + if ($this->skipRows) { + while ($this->activeSheetRowIterator->key() < ($this->skipRows)) { + $this->activeSheetRowIterator->next(); + } + } - // iterate over cells. - $cellIterator = $row->getCellIterator(); + if ($this->headed) { + while ($this->activeSheetRowIterator->key() < ($this->headerRow)) { + $this->activeSheetRowIterator->next(); + } + } - $newCurrentValue = []; - $valueCount = 0; + // NOTE: RowIterator starts its index at 1 + // Therefore, we are getting the headed data columns at index 2 + if ($this->headed && $this->activeSheetRowIterator->valid() && $this->activeSheetRowIterator->key() === ($this->headerRow)) { + // use first row in each sheet for mapping the values + // get current row. + $row = $this->activeSheetRowIterator->current(); + + // iterate over cells. + $cellIterator = $row->getCellIterator(); + + // reset old column mapping + $this->currentColumnMapping = []; + + // create a new column mapping + foreach ($cellIterator as $cell) { + $cellValue = $cell->getValue(); + if (!empty($cellValue)) { + $this->currentColumnMapping[$cell->getColumn()] = $cellValue; + } + } + } - foreach($cellIterator as $cell) { - // we may distinguish formulas from formatted datetime values or others. - // $cellValue = $cell->getFormattedValue(); // $cell->isFormula() || $cell->getDataType == \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE ? $cell->getCalculatedValue() : $cell->getFormattedValue(); + $this->activeSheetRowIterator->next(); - $cellValue = null; - if($cell instanceof \PhpOffice\PhpSpreadsheet\Cell\Cell) { - if($cell->isFormula()) { - $cellValue = $cell->getCalculatedValue(); - } else { - // $cellValue = $cell->getValue(); - $cellValue = $cell->getFormattedValue(); - } + if ($this->activeSheetRowIterator->valid()) { + // get current row. + $row = $this->activeSheetRowIterator->current(); + + // iterate over cells. + $cellIterator = $row->getCellIterator(); + + $newCurrentValue = []; + $valueCount = 0; + + foreach ($cellIterator as $cell) { + // we may distinguish formulas from formatted datetime values or others. + // $cellValue = $cell->getFormattedValue(); // $cell->isFormula() || $cell->getDataType == \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE ? $cell->getCalculatedValue() : $cell->getFormattedValue(); + + $cellValue = null; + if ($cell instanceof Cell) { + if ($cell->isFormula()) { + $cellValue = $cell->getCalculatedValue(); + } else { + // $cellValue = $cell->getValue(); + $cellValue = $cell->getFormattedValue(); + } + } + + if (!empty($cellValue)) { + $valueCount++; + } + + $cellColumn = $cell->getColumn(); + + // check for a mapping match: + if ($this->headed && isset($this->currentColumnMapping[$cellColumn])) { + $newCurrentValue[$this->currentColumnMapping[$cellColumn]] = $cellValue; + } else { + // Skip empty values that are not mapped in any way + // if(!empty($cellValue)) { + // CHANGED 2021-04-29: handling of empty-row-skipping done below + // otherwise, we can't handle empty cells/null values + $newCurrentValue[$cellColumn] = $cellValue; + // } + } + } + + if (!$this->includeEmptyRows && $valueCount === 0) { + // if we have no values in this row (valueCount === 0) + // and we want to skip empty rows, simply move on to next row. + $this->next(); + } else { + $this->globalRowIndex++; + $this->currentValue = $newCurrentValue; + } + } elseif ($this->multisheet) { + // we may go to the next sheet + // if there's at least one more + if ($this->sheetIndex < ($this->sheet->getSheetCount() - 1)) { + $this->sheetIndex++; + $this->activeSheet = $this->sheet->getSheet($this->sheetIndex); + $this->activeSheetRowIterator = $this->activeSheet->getRowIterator(); + $this->next(); + } } + } - if(!empty($cellValue)) { - $valueCount++; - } + /** + * {@inheritDoc} + */ + public function key(): mixed + { + return $this->globalRowIndex; + } - $cellColumn = $cell->getColumn(); - - // check for a mapping match: - if($this->headed && isset($this->currentColumnMapping[$cellColumn])) { - $newCurrentValue[$this->currentColumnMapping[$cellColumn]] = $cellValue; - } else { - // Skip empty values that are not mapped in any way - // if(!empty($cellValue)) { - // CHANGED 2021-04-29: handling of empty-row-skipping done below - // otherwise, we can't handle empty cells/null values - $newCurrentValue[$cellColumn] = $cellValue; - // } - } - } + /** + * {@inheritDoc} + */ + public function valid(): bool + { + // is this check enough? + return $this->currentValue != null && $this->activeSheetRowIterator->valid(); + } - if(!$this->includeEmptyRows && $valueCount === 0) { - // if we have no values in this row (valueCount === 0) - // and we want to skip empty rows, simply move on to next row. - $this->next(); - } else { - $this->globalRowIndex++; - $this->currentValue = $newCurrentValue; - } - - } else { - - // we may go to the next sheet - // if there's at least one more - if($this->multisheet) { - if($this->sheetIndex < ($this->sheet->getSheetCount()-1)) { - $this->sheetIndex++; - $this->activeSheet = $this->sheet->getSheet($this->sheetIndex); - $this->activeSheetRowIterator = $this->activeSheet->getRowIterator(); - $this->next(); - } - } + /** + * {@inheritDoc} + */ + public function current(): mixed + { + return $this->currentValue; } - } - - /** - * [protected description] - * @var [type] - */ - protected $sheetIndex = 0; - - /** - * [protected description] - * @var [type] - */ - protected $globalRowIndex = 0; - - /** - * @inheritDoc - */ - public function key() - { - return $this->globalRowIndex; - } - - /** - * @inheritDoc - */ - public function valid() - { - // is this check enough? - return $this->currentValue != null && $this->activeSheetRowIterator->valid(); - } - - /** - * @inheritDoc - */ - public function rewind() - { - $this->currentValue = null; - $this->sheetIndex = $this->customSheetIndex ?? 0; - $this->activeSheet = $this->sheet->getSheet($this->sheetIndex); - $this->activeSheetRowIterator = $this->activeSheet->getRowIterator(); - $this->globalRowIndex = 0; - $this->next(); - } - - /** - * @inheritDoc - */ - public function currentProgressPosition() : int - { - return $this->globalRowIndex; - } - - /** - * @inheritDoc - */ - public function currentProgressLimit() : int - { - return 0; - } + /** + * {@inheritDoc} + */ + public function currentProgressPosition(): int + { + return $this->globalRowIndex; + } + /** + * {@inheritDoc} + */ + public function currentProgressLimit(): int + { + return 0; + } } diff --git a/backend/class/datasource/xml.php b/backend/class/datasource/xml.php index af7dd11..f92885e 100644 --- a/backend/class/datasource/xml.php +++ b/backend/class/datasource/xml.php @@ -1,170 +1,175 @@ -setConfig($config); - $this->xmlIterator = new \SimpleXMLIterator($file, 0, true); - $this->xmlIterator->rewind(); - } - - /** - * [doXPathQuery description] - * @return void - */ - protected function doXPathQuery() { - $this->xpathQueryResult = $this->xmlIterator->xpath($this->xpathQuery); - // TODO: neither count(...) nor ->count() work correctly. - $this->itemCount = 0; // $this->xpathQueryResult->count(); - } - - /** - * [protected description] - * @var \SimpleXMLElement[] - */ - protected $xpathQueryResult = null; - - /** - * xpath query - * @see https://msdn.microsoft.com/en-us/library/ms256086(v=vs.110).aspx - * @var string - */ - protected $xpathQuery = null; - - /** - * @inheritDoc - */ - public function setConfig(array $config) - { - $this->xpathQuery = $config['xpath_query'] ?? null; - $this->xpathMapping = $config['xpath_mapping'] ?? null; - } - - /** - * [protected description] - * @var mixed|bool - */ - protected $current = false; - - /** - * [protected description] - * @var \SimpleXMLElement - */ - protected $currentRaw = null; - - /** - * @inheritDoc - */ - public function current() - { - return $this->current; - } - - /** - * if next had been called on the underlying iterator before - * @var bool - */ - protected $firstCall = true; - - /** - * [protected description] - * @var int|null - */ - protected $index = null; - - /** - * @inheritDoc - */ - public function next() - { - if($this->xpathQueryResult == null) { - $this->doXPathQuery(); + /** + * [protected description] + * @var SimpleXMLIterator + */ + protected SimpleXMLIterator $xmlIterator; + + /** + * some count caching + * @var null|int + */ + protected ?int $itemCount = null; + /** + * [protected description] + * @var SimpleXMLElement[] + */ + protected ?array $xpathQueryResult = null; + /** + * xpath query + * @see https://msdn.microsoft.com/en-us/library/ms256086(v=vs.110).aspx + * @var null|string + */ + protected ?string $xpathQuery = null; + /** + * [protected description] + * @var mixed + */ + protected mixed $current = false; + /** + * [protected description] + * @var null|bool|SimpleXMLElement + */ + protected null|bool|SimpleXMLElement $currentRaw = null; + /** + * if next had been called on the underlying iterator before + * @var bool + */ + protected bool $firstCall = true; + /** + * [protected description] + * @var int|null + */ + protected ?int $index = null; + /** + * @var mixed + */ + protected mixed $xpathMapping; + + /** + * [__construct description] + * @param string $file [description] + * @param array $config [description] + * @throws Exception + */ + public function __construct(string $file = '', array $config = []) + { + $this->setConfig($config); + $this->xmlIterator = new SimpleXMLIterator($file, 0, true); + $this->xmlIterator->rewind(); + } + + /** + * {@inheritDoc} + */ + public function setConfig(array $config): void + { + $this->xpathQuery = $config['xpath_query'] ?? null; + $this->xpathMapping = $config['xpath_mapping'] ?? null; + } + + /** + * {@inheritDoc} + */ + public function rewind(): void + { + $this->index = null; + $this->current = false; + $this->currentRaw = null; + $this->doXPathQuery(); + $this->next(); + } + + /** + * [doXPathQuery description] + * @return void + */ + protected function doXPathQuery(): void + { + $this->xpathQueryResult = $this->xmlIterator->xpath($this->xpathQuery); + // TODO: neither count(...) nor ->count() work correctly. + $this->itemCount = 0; } - if($this->index === null) { - $this->index = 0; - } else { - $this->index++; + /** + * {@inheritDoc} + */ + public function next(): void + { + if ($this->xpathQueryResult == null) { + $this->doXPathQuery(); + } + + if ($this->index === null) { + $this->index = 0; + } else { + $this->index++; + } + + if (isset($this->xpathQueryResult[$this->index])) { + $this->currentRaw = $this->xpathQueryResult[$this->index]; + $res = []; + foreach ($this->xpathMapping as $key => $query) { + $res[$key] = (string)$this->currentRaw->xpath($query)[0]; + } + $this->current = $res; + } else { + $this->currentRaw = false; + $this->current = false; + } } - if(isset($this->xpathQueryResult[$this->index])) { - $this->currentRaw = $this->xpathQueryResult[$this->index]; - $res = []; - foreach($this->xpathMapping as $key => $query) { - $res[$key] = (string) $this->currentRaw->xpath($query)[0]; - } - $this->current = $res; - } else { - $this->currentRaw = false; - $this->current = false; + /** + * {@inheritDoc} + */ + public function current(): mixed + { + return $this->current; } - } - - /** - * @inheritDoc - */ - public function key() - { - return $this->index; - } - - /** - * @inheritDoc - */ - public function valid() - { - return $this->current !== false; - } - - /** - * @inheritDoc - */ - public function rewind() - { - $this->index = null; - $this->current = false; - $this->currentRaw = null; - $this->doXPathQuery(); - $this->next(); - } - - /** - * @inheritDoc - */ - public function currentProgressPosition() : int - { - return $this->index ?? 0; - } - - /** - * @inheritDoc - */ - public function currentProgressLimit() : int - { - return $this->itemCount ?? 0; - } + /** + * {@inheritDoc} + */ + public function key(): mixed + { + return $this->index; + } + + /** + * {@inheritDoc} + */ + public function valid(): bool + { + return $this->current !== false; + } + + /** + * {@inheritDoc} + */ + public function currentProgressPosition(): int + { + return $this->index ?? 0; + } + + /** + * {@inheritDoc} + */ + public function currentProgressLimit(): int + { + return $this->itemCount ?? 0; + } } diff --git a/backend/class/export.php b/backend/class/export.php index 5ac6cf2..f9ed2cd 100644 --- a/backend/class/export.php +++ b/backend/class/export.php @@ -1,9 +1,10 @@ - 'Helvetica', + 'page_size' => 'A4', + 'page_orientation' => 'portrait', + ]; + /** + * [protected description] + * @var datacontainer + */ + protected datacontainer $config; - /** - * [protected description] - * @var \codename\core\datacontainer - */ - protected $config = null; + /** + * [__construct description] + * @param array $config [description] + */ + public function __construct(array $config = []) + { + $this->config = new datacontainer($config); - /** - * default configuration values - * @var array - */ - protected static $defaults = [ - 'default_font' => 'Helvetica', - 'pape_size' => 'A4', - 'page_orientation' => 'portrait' - ]; + // set defaults + foreach (self::$defaults as $key => $value) { + if (!$this->config->isDefined($key)) { + $this->config->setData($key, $value); + } + } - /** - * [__construct description] - * @param array $config [description] - */ - public function __construct(array $config = array()) - { - $this->config = new \codename\core\datacontainer($config); + // @TODO: check configuration! - // set defaults - foreach(self::$defaults as $key => $value) { - if(!$this->config->isDefined($key)) { - $this->config->setData($key, $value); - } + // init! + $this->initClient(); } - // @TODO: check configuration! - - // init! - $this->initClient(); - } - - /** - * main initialization routine - */ - protected abstract function initClient(); - - /** - * sets the input data (html) - * @param string $html - */ - public abstract function setHtml(string $html); + /** + * main initialization routine + */ + abstract protected function initClient(); - /** - * renders/executes the rendering process - */ - public abstract function render(); + /** + * sets the input data (html) + * @param string $html + */ + abstract public function setHtml(string $html); - /** - * gets the absolute file path to the rendered file (output) - * @return fileabsolute - */ - public abstract function getFilepath() : fileabsolute; + /** + * renders/executes the rendering process + */ + abstract public function render(); + /** + * gets the absolute file path to the rendered file (output) + * @return fileabsolute + */ + abstract public function getFilepath(): fileabsolute; } diff --git a/backend/class/export/pdf/dompdf.php b/backend/class/export/pdf/dompdf.php index 8bd689d..0eb18fd 100644 --- a/backend/class/export/pdf/dompdf.php +++ b/backend/class/export/pdf/dompdf.php @@ -1,86 +1,103 @@ set('defaultFont', $this->config->getData('default_font')); - - $this->dompdf = new \Dompdf\Dompdf(); - - $this->dompdf->set_option('isRemoteEnabled', $this->config->getData('remote_enabled') ?? false); - $this->dompdf->set_option('isHtml5ParserEnabled', true); - // set page size and orientation - $this->dompdf->setPaper($this->config->getData('page_size'), $this->config->getData('page_orientation')); - - if($chroot = $this->config->getData('chroot')) { - $this->dompdf->getOptions()->setChroot($chroot); +class dompdf extends pdf +{ + /** + * [protected description] + * @var null|\Dompdf\Dompdf + */ + protected ?\Dompdf\Dompdf $dompdf = null; + /** + * path to file which was last created by render() + * @var null|fileabsolute + */ + protected ?fileabsolute $outputFile = null; + + /** + * {@inheritDoc} + */ + public function setHtml(string $html): void + { + // @TODO: clean html? + $this->dompdf->loadHtml($html); } - if($dpi = $this->config->getData('dpi')) { - $this->dompdf->set_option('dpi', $dpi); + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws DOMException + * @throws \Dompdf\Exception + * @throws exception + */ + public function render(): void + { + $this->dompdf->render(); + + $generatedPdfData = $this->dompdf->output(); + + // generate tempfile + $outputPath = tempnam(sys_get_temp_dir(), 'dompdf_'); + + if (!file_put_contents($outputPath, $generatedPdfData)) { + throw new exception('EXCEPTION_EXPORT_PDF_DOMPDF_COULD_NOT_WRITE_FILE', exception::$ERRORLEVEL_ERROR, [$outputPath]); + } else { + $this->outputFile = new fileabsolute($outputPath); + } } - } - /** - * @inheritDoc - */ - public function setHtml(string $html) - { - // @TODO: clean html? - $this->dompdf->loadHtml($html); - } - - /** - * @inheritDoc - */ - public function render() - { - $this->dompdf->render(); - - $generatedPdfData = $this->dompdf->output(); - - // generate tempfile - $outputPath = tempnam(sys_get_temp_dir(), 'dompdf_'); - - if(!file_put_contents($outputPath, $generatedPdfData)) { - throw new exception('EXCEPTION_EXPORT_PDF_DOMPDF_COULD_NOT_WRITE_FILE', exception::$ERRORLEVEL_ERROR, array($outputPath)); - } else { - $this->outputFile = new \codename\core\value\text\fileabsolute($outputPath); + /** + * {@inheritDoc} + */ + public function getFilepath(): fileabsolute + { + return $this->outputFile; } - } - - /** - * path to file which was last created by render() - * @var \codename\core\value\text\fileabsolute - */ - protected $outputFile = null; - - /** - * @inheritDoc - */ - public function getFilepath(): \codename\core\value\text\fileabsolute - { - return $this->outputFile; - } + /** + * {@inheritDoc} + */ + protected function initClient(): void + { + $options = new Options(); + + // translate some configs + $options->set('defaultFont', $this->config->getData('default_font')); + + $options->set('isRemoteEnabled', $this->config->getData('remote_enabled') ?? false); + $options->set('isHtml5ParserEnabled', true); + + if ($this->config->getData('chroot') ?? false) { + $options->set('chroot', $this->config->getData('chroot')); + } + if ($this->config->getData('dpi') ?? false) { + $options->set('dpi', $this->config->getData('dpi')); + } + if ($this->config->getData('tempDir') ?? false) { + $options->set('tempDir', $this->config->getData('tempDir')); + } + if ($this->config->getData('fontDir') ?? false) { + $options->set('fontDir', $this->config->getData('fontDir')); + } + if ($this->config->getData('fontCache') ?? false) { + $options->set('fontCache', $this->config->getData('fontCache')); + } + + $this->dompdf = new \Dompdf\Dompdf($options); + + // set page size and orientation + $this->dompdf->setPaper($this->config->getData('page_size'), $this->config->getData('page_orientation')); + } } diff --git a/backend/class/helper/deepaccess.php b/backend/class/helper/deepaccess.php deleted file mode 100644 index 9573795..0000000 --- a/backend/class/helper/deepaccess.php +++ /dev/null @@ -1,9 +0,0 @@ - [ - 'name' => 'generated', - 'description' => null - ], - 'source' => [ - 'type' => 'model', - 'query' => [] - ], - 'transform' => [], - 'target' => [ - ], - ]; - - $targetName = 'generated_target_'.$targetType; - $config['target'][$targetName] = [ - 'type' => $targetType, - ]; - - if($targetType === 'buffered_file_parquet') { - // parquet optimizations - $config['target'][$targetName]['buffer'] = true; - $config['target'][$targetName]['buffer_size'] = 10000; - - $config['target'][$targetName]['compression'] = 'gzip'; - } + /** + * [createModelToModelPipelineConfig description] + * @param model $model [description] + * @param string $targetType + * @return config + * @throws exception + */ + public static function createModelToModelPipelineConfig(model $model, string $targetType): config + { + $config = [ + 'info' => [ + 'name' => 'generated', + 'description' => null, + ], + 'source' => [ + 'type' => 'model', + 'query' => [], + ], + 'transform' => [], + 'target' => [ + ], + ]; + + $targetName = 'generated_target_' . $targetType; + $config['target'][$targetName] = [ + 'type' => $targetType, + ]; - // use by-ref - $target = &$config['target']['generated_target_'.$targetType]; + if ($targetType === 'buffered_file_parquet') { + // parquet optimizations + $config['target'][$targetName]['buffer'] = true; + $config['target'][$targetName]['buffer_size'] = 10000; + $config['target'][$targetName]['compression'] = 'gzip'; + } - $fieldlist = []; + // use by-ref + $target = &$config['target']['generated_target_' . $targetType]; - $recursiveModels = static::getRecursiveModelList($model); - foreach($recursiveModels as $index => $currentModel) { - foreach($currentModel->getFields() as $field) { + $fieldlist = []; - if($currentModel->config->get('datatype>'.$field) === 'virtual') { - // Skip virtual fields for now. - continue; - } + $recursiveModels = static::getRecursiveModelList($model); - if(in_array($field, $fieldlist)) { - // duplicate name in fieldlist - skip - continue; - } + foreach ($recursiveModels as $index => $currentModel) { + foreach ($currentModel->getFields() as $field) { + if ($currentModel->config->get('datatype>' . $field) === 'virtual') { + // Skip virtual fields for now. + continue; + } - $fieldlist[] = $field; + if (in_array($field, $fieldlist)) { + // duplicate name in fieldlist - skip + continue; + } + $fieldlist[] = $field; - // base: source == target field (name) - $mappingEntry = [ - 'type' => 'source', - 'field' => $field, - ]; - if($targetType == 'buffered_file_parquet') { - $transforms = []; - $params = static::convertModelfieldToParquetEquivalentParams($currentModel, $field, $mappingEntry, $transforms); + // base: source == target field (name) + $mappingEntry = [ + 'type' => 'source', + 'field' => $field, + ]; - // prevent joined models' PKEY - // to be required, if there's NULL ref - if($index > 0) { - if($field == $currentModel->getPrimarykey()) { - $params['is_nullable'] = true; // ? - } - } + if ($targetType == 'buffered_file_parquet') { + $transforms = []; + $params = static::convertModelfieldToParquetEquivalentParams($currentModel, $field, $mappingEntry, $transforms); + + // prevent joined models' PKEY + // to be required, if there's NULL ref + if ($index > 0) { + if ($field == $currentModel->getPrimaryKey()) { + $params['is_nullable'] = true; // ? + } + } + + if (count($transforms) > 0) { + $config['transform'] = array_merge($config['transform'], $transforms); + } + $mappingEntry = array_merge($mappingEntry, $params); + } - if(count($transforms) > 0) { - $config['transform'] = array_merge($config['transform'], $transforms); - } - $mappingEntry = array_merge($mappingEntry, $params); + $target['mapping'][$field] = $mappingEntry; + } } - $target['mapping'][$field] = $mappingEntry; - } + return new config($config); } - // foreach($model->getFields() as $field) { - // - // if($model->config->get('datatype>'.$field) === 'virtual') { - // // Skip virtual fields for now. - // continue; - // } - // - // if(in_array($field, $fieldlist)) { - // // duplicate name in fieldlist? - // } - // - // - // - // // base: source == target field (name) - // $mappingEntry = [ - // 'type' => 'source', - // 'field' => $field, - // ]; - // - // if($targetType == 'buffered_file_parquet') { - // $transforms = []; - // $params = static::convertModelfieldToParquetEquivalentParams($model, $field, $mappingEntry, $transforms); - // - // if(count($transforms) > 0) { - // $config['transform'] = array_merge($config['transform'], $transforms); - // } - // $mappingEntry = array_merge($mappingEntry, $params); - // } - // - // $target['mapping'][$field] = $mappingEntry; - // } - - return new \codename\core\config($config); - } - - /** - * [getRecursiveModelList description] - * @param model $model [description] - * @return model[] - */ - protected static function getRecursiveModelList(model $model): array { - $result = [ $model ]; - foreach($model->getNestedJoins() as $join) { - $nested = static::getRecursiveModelList($join->model); - $result = array_merge($result, $nested); - } - return $result; - } - - /** - * [convertModelfieldToParquetEquivalentParams description] - * @param model $model [description] - * @param string $field [description] - * @return array [description] - */ - protected static function convertModelfieldToParquetEquivalentParams(model $model, string $field, array &$mappingEntry, array &$transforms): array { - $options = $model->config->get('options>'.$field); - $datatype = $model->config->get('datatype>'.$field); - - $isPkey = in_array($field, $model->config->get('primary')); - - $isNullable = !$isPkey; // PKEYs are not nullable by default - - if($isNullable) { - // explicit (not-)nullable state - $isNullable = !in_array($field, $model->config->get('not_null') ?? []); + /** + * [getRecursiveModelList description] + * @param model $model [description] + * @return model[] + */ + protected static function getRecursiveModelList(model $model): array + { + $result = [$model]; + foreach ($model->getNestedJoins() as $join) { + $nested = static::getRecursiveModelList($join->model); + $result = array_merge($result, $nested); + } + return $result; } - // Additional implicit required => not null. Might be overkill. - // if($isNullable) { - // $isNullable = !in_array($field, $model->config->get('required') ?? []); - // } - - $phpType = null; - $phpClass = null; - $precision = null; - $scale = null; - $typeLength = null; - $logicalType = null; - - $returnval = [ - ]; - - switch($datatype) { - case 'structure': - // highly dependent on usage... - // F.e. if FKEY to model, it's the Foreign model's pkey type - // Otherwise: JSON data - // Which might be mapped otherwise. - // For now: fallback to string. - - // TODO: prefixes, if recursion? - $transformField = $field.'_to_json'; - $transforms[$transformField] = [ - 'type' => 'convert_json', - 'config' => [ - 'source' => 'source', - 'field' => $field, - 'mode' => 'encode', - ] - ]; - $logicalType = 'JSON'; // ?? - $mappingEntry['type'] = 'transform'; - $mappingEntry['field'] = $transformField; - - $returnval['php_type'] = 'string'; - break; - case 'text': - // check length? - $returnval['php_type'] = 'string'; - break; - case 'number_natural': - // Int32, 64, 96 or arbitrary? - $returnval['php_type'] = 'integer'; - break; - case 'text_timestamp': - $returnval['php_type'] = 'object'; - $returnval['php_class'] = \DateTimeImmutable::class; - $returnval['datetime_format'] = \codename\parquet\data\DateTimeFormat::DateAndTime; - - // TODO: prefixes, if recursion? - $transformField = $field.'_to_dti'; - $transforms[$transformField] = [ - 'type' => 'convert_datetime', - 'config' => [ - 'source' => 'source', - 'field' => $field, - 'source_format' => 'Y-m-d H:i:s', - 'target_format' => 'DateTimeImmutable', - ] - ]; - $mappingEntry['type'] = 'transform'; - $mappingEntry['field'] = $transformField; - // TODO: set Datetime Format (parquet) - break; - case 'text_date': - $returnval['php_type'] = 'object'; - $returnval['php_class'] = \DateTimeImmutable::class; - $returnval['datetime_format'] = \codename\parquet\data\DateTimeFormat::Date; - // TODO extra data - - // TODO: prefixes, if recursion? - $transformField = $field.'_to_dti'; - $transforms[$transformField] = [ - 'type' => 'convert_datetime', - 'config' => [ - 'source' => 'source', - 'field' => $field, - 'source_format' => 'Y-m-d', - 'target_format' => 'DateTimeImmutable', - ] + /** + * [convertModelfieldToParquetEquivalentParams description] + * @param model $model [description] + * @param string $field [description] + * @return array [description] + */ + protected static function convertModelfieldToParquetEquivalentParams(model $model, string $field, array &$mappingEntry, array &$transforms): array + { + $datatype = $model->config->get('datatype>' . $field); + + $isPkey = in_array($field, $model->config->get('primary')); + + $isNullable = !$isPkey; // PKEYs are not nullable by default + + if ($isNullable) { + // explicit (not-)nullable state + $isNullable = !in_array($field, $model->config->get('not_null') ?? []); + } + + $returnval = [ ]; - // TODO: set Datetime Format (parquet) - $mappingEntry['type'] = 'transform'; - $mappingEntry['field'] = $transformField; - break; - case 'number': - // Float, Double or Decimal - $returnval['php_type'] = 'double'; - // $phpType = 'decimal'; // pseudo-type - // $precision = $options['length']; - // $scale = $options['precision']; - break; - case 'boolean': - $returnval['php_type'] = 'boolean'; - break; - } + + switch ($datatype) { + case 'structure': + // highly dependent on usage... + // F.e. if FKEY to model, it's the Foreign model's pkey type + // Otherwise: JSON data + // Which might be mapped otherwise. + // For now: fallback to string. + + // TODO: prefixes, if recursion? + $transformField = $field . '_to_json'; + $transforms[$transformField] = [ + 'type' => 'convert_json', + 'config' => [ + 'source' => 'source', + 'field' => $field, + 'mode' => 'encode', + ], + ]; + $mappingEntry['type'] = 'transform'; + $mappingEntry['field'] = $transformField; + + $returnval['php_type'] = 'string'; + break; + case 'text': + // check length? + $returnval['php_type'] = 'string'; + break; + case 'number_natural': + // Int32, 64, 96 or arbitrary? + $returnval['php_type'] = 'integer'; + break; + case 'text_timestamp': + $returnval['php_type'] = 'object'; + $returnval['php_class'] = DateTimeImmutable::class; + $returnval['datetime_format'] = DateTimeFormat::DateAndTime; + + // TODO: prefixes, if recursion? + $transformField = $field . '_to_dti'; + $transforms[$transformField] = [ + 'type' => 'convert_datetime', + 'config' => [ + 'source' => 'source', + 'field' => $field, + 'source_format' => 'Y-m-d H:i:s', + 'target_format' => 'DateTimeImmutable', + ], + ]; + $mappingEntry['type'] = 'transform'; + $mappingEntry['field'] = $transformField; + // TODO: set Datetime Format (parquet) + break; + case 'text_date': + $returnval['php_type'] = 'object'; + $returnval['php_class'] = DateTimeImmutable::class; + $returnval['datetime_format'] = DateTimeFormat::Date; + // TODO extra data + + // TODO: prefixes, if recursion? + $transformField = $field . '_to_dti'; + $transforms[$transformField] = [ + 'type' => 'convert_datetime', + 'config' => [ + 'source' => 'source', + 'field' => $field, + 'source_format' => 'Y-m-d', + 'target_format' => 'DateTimeImmutable', + ], + ]; + // TODO: set Datetime Format (parquet) + $mappingEntry['type'] = 'transform'; + $mappingEntry['field'] = $transformField; + break; + case 'number': + // Float, Double or Decimal + $returnval['php_type'] = 'double'; + break; + case 'boolean': + $returnval['php_type'] = 'boolean'; + break; + } - $returnval['is_nullable'] = $isNullable; - // $returnval = [ - // 'php_type' => $phpType, - // 'php_class' => $phpClass, - // 'precision' => $precision, - // 'scale' => $scale, - // 'type_length' => $typeLength, - // 'is_nullable' => $isNullable, - // ]; + $returnval['is_nullable'] = $isNullable; - // filter, additionally, to omit all empty/null values - return array_filter($returnval, function($v) { return $v !== null; }); - } + // filter, additionally, to omit all empty/null values + return array_filter($returnval, function ($v) { + return $v !== null; + }); + } } diff --git a/backend/class/pipeline.php b/backend/class/pipeline.php index 62e3247..bf42d7f 100644 --- a/backend/class/pipeline.php +++ b/backend/class/pipeline.php @@ -1,885 +1,1079 @@ -config; - } - + public const EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_INSTANCE_OF_WRONG_BASE_CLASS = 'EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_INSTANCE_OF_WRONG_BASE_CLASS'; /** - * @param string|null $config_pipeline_file [pipeline config / definition] - * @param array|null $configData [optional, explicit configuration] + * [EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_NOTFOUND description] + * @var string */ - public function __construct(string $config_pipeline_file = null, array $configData = null) - { - if($config_pipeline_file !== null) { - // NOTE: 2018-08-30 changed json config to use appstack, but no inheritance between config file hierarchies - // load a config file - $this->config = (new json($config_pipeline_file, true, false)); - } else if($configData !== null) { - // load a config object/array - $this->config = new \codename\core\config($configData); - } - - if($this->config->get('config>datasource_buffering')) { - $this->setDatasourceBuffering(true, $this->config->get('config>datasource_buffer_size') ?? 1000); - } - } - + public const EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_NOTFOUND = 'EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_NOTFOUND'; + /** + * [EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_MISSING_CLASS description] + * @var string + */ + public const EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_MISSING_CLASS = 'EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_MISSING_CLASS'; + /** + * [EXCEPTION_CORE_IO_PIPELINE_GETTARGET_CONFIG_MISSING_TARGET description] + * @var string + */ + public const EXCEPTION_CORE_IO_PIPELINE_GETTARGET_CONFIG_MISSING_TARGET = 'EXCEPTION_CORE_IO_PIPELINE_GETTARGET_CONFIG_MISSING_TARGET'; + /** + * [EXCEPTION_CORE_IO_PIPELINE_GETTARGET_MISSING_CLASS description] + * @var string + */ + public const EXCEPTION_CORE_IO_PIPELINE_GETTARGET_MISSING_CLASS = 'EXCEPTION_CORE_IO_PIPELINE_GETTARGET_MISSING_CLASS'; + /** + * debug flag + * @var bool + */ + public bool $debug = false; + /** + * pipeline configuration + * @var config|json|null + */ + protected json|config|null $config = null; /** * data sources for specifier(s) - * @var datasource + * @var null|datasource */ - protected $datasource = null; - + protected ?datasource $datasource = null; /** * [protected description] - * @var transform[] + * @var array */ - protected $transforms = []; - + protected array $transforms = []; /** * [protected description] - * @var process[] + * @var array */ - protected $preprocessors = []; - + protected array $preprocessors = []; /** - * [setDatasource description] - * @param datasource $datasource [description] + * [protected description] + * @var bool */ - public function setDatasource(datasource $datasource) { - - if($datasource instanceof \codename\core\io\setPipelineInstanceInterface) { - $datasource->setPipelineInstance($this); - } - - // - // If datasource buffering is enabled - // encapsulate the datasource - // - if($this->datasourceBuffering) { - $this->datasource = new \codename\core\io\datasource\buffered($datasource, $this->datasourceBufferSize); - } else { - $this->datasource = $datasource; - } - - $this->itemCount = $this->datasource->currentProgressLimit(); - } - + protected bool $datasourceBuffering = false; /** * [protected description] - * @var bool + * @var int */ - protected $datasourceBuffering = false; - + protected int $datasourceBufferSize = 1000; + /** + * options + * @var null|config + */ + protected ?config $options = null; + /** + * stores the count of items in the current datasource + * @var null|int + */ + protected ?int $itemCount = null; + /** + * stores the current index that is processed + * @var null|int + */ + protected ?int $itemIndex = null; /** * [protected description] * @var int */ - protected $datasourceBufferSize = 1000; + protected int $storedItemCount = 0; + /** + * callback for tracking status/progress + * @var callable|null + */ + protected $processCallback = null; + /** + * targets (as model instances) + * @var model[] + */ + protected array $targetModelInstances = []; + /** + * the bottom limit (start, index) of pipeline source + * @var null|int + */ + protected ?int $startIndex = null; + /** + * the top limit (end, index) of pipeline source + * @var null|int + */ + protected ?int $endIndex = null; + /** + * whether to throw an exception if an erroneous dataset is detected + * @var bool + */ + protected bool $throwExceptionOnErroneousData = false; + /** + * whether to track errors in a global pipeline errorstack + * @var bool + */ + protected bool $errorstackEnabled = false; + /** + * the global pipeline errorstack + * @var null|errorstack + */ + protected ?errorstack $errorstack = null; + /** + * whether to skip erroneous processes + * which means: if any of the target fails/runs into erroneous state + * do not handle the whole source entry it originates from + * so neither of the targets gets to really STORE data for this entry. + * @var bool + */ + protected bool $skipErroneous = false; + /** + * track erroneous entries to be stored in targets + * @var bool + */ + protected bool $trackErroneous = false; + /** + * [protected description] + * @var array + */ + protected array $erroneousEntries = []; + /** + * active PDO connections + * for handling open transactions + * on a per-database connection basis + * @var array + */ + protected array $activeConnections = []; + /** + * [protected description] + * @var null|transaction + */ + protected ?transaction $transaction = null; + /** + * determines, if the pipeline is running in dryRun mode + * (no real stores/saves happening) + * + * @var bool + */ + protected bool $dryRun = true; + /** + * @var array + */ + protected array $target = []; + + /** + * @param string|null $config_pipeline_file [pipeline config / definition] + * @param array|null $configData [optional, explicit configuration] + * @throws ReflectionException + * @throws exception + */ + public function __construct(string $config_pipeline_file = null, array $configData = null) + { + if ($config_pipeline_file !== null) { + // NOTE: 2018-08-30 changed json config to use appstack, but no inheritance between config file hierarchies + // load a config file + $this->config = (new json($config_pipeline_file, true, false)); + } elseif ($configData !== null) { + // load a config object/array + $this->config = new config($configData); + } + + if ($this->config->get('config>datasource_buffering')) { + $this->setDatasourceBuffering(true, $this->config->get('config>datasource_buffer_size') ?? 1000); + } + } /** * enables buffering of the main datasource * has to be enabled before setting the datasource * - * @param bool $state [description] - * @param int $bufferSize [description] + * @param bool $state [description] + * @param int $bufferSize [description] + */ + public function setDatasourceBuffering(bool $state, int $bufferSize = 1000): void + { + $this->datasourceBuffering = $state; + $this->datasourceBufferSize = $bufferSize; + } + + /** + * [getConfig description] + * @return config [description] */ - public function setDatasourceBuffering(bool $state, int $bufferSize = 1000) { - $this->datasourceBuffering = $state; - $this->datasourceBufferSize = $bufferSize; + public function getConfig(): config + { + return $this->config; } /** * [getDatasource description] * @return datasource [description] */ - public function getDatasource() : datasource { - return $this->datasource; + public function getDatasource(): datasource + { + return $this->datasource; } /** - * options - * @var \codename\core\config + * [setDatasource description] + * @param datasource $datasource [description] + * @throws exception */ - protected $options = null; + public function setDatasource(datasource $datasource): void + { + if ($datasource instanceof setPipelineInstanceInterface) { + $datasource->setPipelineInstance($this); + } + + // + // If datasource buffering is enabled + // encapsulate the datasource + // + if ($this->datasourceBuffering) { + $this->datasource = new buffered($datasource, $this->datasourceBufferSize); + } else { + $this->datasource = $datasource; + } + + $this->itemCount = $this->datasource->currentProgressLimit(); + } /** * [setOptions description] * @param array $options [description] */ - public function setOptions(array $options) { - $this->options = new \codename\core\config($options); + public function setOptions(array $options): void + { + $this->options = new config($options); } - /** - * stores the count of items in the current datasource - * @var int - */ - protected $itemCount = null; - /** * [getItemCount description] * @return int [description] */ - public function getItemCount() : int { - return $this->itemCount; + public function getItemCount(): int + { + return $this->itemCount; } /** - * stores the current index that is processed - * @var int + * @return int */ - protected $itemIndex = null; - - public function getItemIndex() : int { - return $this->datasource->currentProgressPosition(); - // return $this->itemIndex; + public function getItemIndex(): int + { + return $this->datasource->currentProgressPosition(); } - /** - * [protected description] - * @var int - */ - protected $storedItemCount = 0; - /** * returns the number of how many times store() on a target has been called * @return int [description] */ - public function getStoredItemCount() : int { - return $this->storedItemCount; + public function getStoredItemCount(): int + { + return $this->storedItemCount; } - /** - * callback for tracking status/progress - * @var callable|null - */ - protected $processCallback = null; - /** * [setProcessCallback description] * @param callable $callback [description] */ - public function setProcessCallback(callable $callback) { - $this->processCallback = $callback; + public function setProcessCallback(callable $callback): void + { + $this->processCallback = $callback; } /** * create a datasource matching the configured type - * @param mixed $args + * @param mixed $args * @return datasource [the freshly created datasource] + * @throws ReflectionException + * @throws exception */ - public function createDatasource($args) : datasource { - $class = app::getInheritedClass('datasource_'.$this->config->get('source>type')); - $datasource = new $class($args); - - if($datasource instanceof \codename\core\io\setPipelineInstanceInterface) { - $datasource->setPipelineInstance($this); - } - - $datasource->setConfig($this->config->get('source>config')); - return $datasource; - } + public function createDatasource(mixed $args): datasource + { + $class = app::getInheritedClass('datasource_' . $this->config->get('source>type')); + $datasource = new $class($args); - /** - * targets (as model instances) - * @var model[] - */ - protected $targetModelInstances = []; + if ($datasource instanceof setPipelineInstanceInterface) { + $datasource->setPipelineInstance($this); + } - /** - * [getTargetModel description] - * @param string $targetName [description] - * @param string $model [description] - * @param string $app [description] - * @param string $vendor [description] - * @return model [description] - */ - protected function getTargetModel(string $targetName, string $model = '', $app = '', $vendor = '') : model { - if(!isset($this->targetModelInstances[$targetName])) { - $this->targetModelInstances[$targetName] = app::getModel($model, $app, $vendor); - } - return $this->targetModelInstances[$targetName]; + $datasource->setConfig($this->config->get('source>config')); + return $datasource; } - /** - * debug flag - * @var bool - */ - public $debug = false; - /** * enable or disable debugging * @param bool $debug [true/false] */ - public function setDebug(bool $debug) { - $this->debug = $debug; + public function setDebug(bool $debug): void + { + $this->debug = $debug; } - /** - * the bottom limit (start, index) of pipeline source - * @var int - */ - protected $startIndex = null; - - /** - * the top limit (end, index) of pipeline source - * @var int - */ - protected $endIndex = null; - /** * hard limit the pipeline source * @param int|null $startIndex [start index or null for none] - * @param int|null $endIndex [end index or null for none] + * @param int|null $endIndex [end index or null for none] */ - public function setLimit($startIndex, $endIndex) { - $this->startIndex = $startIndex; - $this->endIndex = $endIndex; + public function setLimit(?int $startIndex, ?int $endIndex): void + { + $this->startIndex = $startIndex; + $this->endIndex = $endIndex; } /** * perform pipeline processes/transforms - * @return [type] [description] + * @return void [type] [description] + * @throws ReflectionException + * @throws exception */ - public function run() { - - if(app::getResponse() instanceof \codename\core\response\cli) { - echo("[PIPELINE] starting pipeline..." . chr(10)); - } - - if($this->errorstackEnabled) { - $this->errorstack = new \codename\core\errorstack('PIPELINE'); - } else { - $this->errorstack = null; - } + public function run(): void + { + if (app::getResponse() instanceof cli) { + echo("[PIPELINE] starting pipeline..." . chr(10)); + } - // first step: validate source(s)! - // foreach($this->config->get('source') as $sourceName => $sourceConfig) { - $sourceConfig = $this->config->get('source'); + if ($this->errorstackEnabled) { + $this->errorstack = new errorstack('PIPELINE'); + } else { + $this->errorstack = null; + } - if(isset($sourceConfig['type'])) { - // $sourceConfig['type'] - // explicitly check datasource type - } + // first step: validate source(s)! + $sourceConfig = $this->config->get('source'); - // explicitly configure datasource - if(isset($sourceConfig['config']) && !($this->datasource instanceof \codename\core\io\datasource\remap)) { - $this->datasource->setConfig($sourceConfig['config']); - } + if (isset($sourceConfig['type'])) { + // $sourceConfig['type'] + // explicitly check datasource type + } - $modelconfig = null; - if(!empty($sourceConfig['schema']) && !empty($sourceConfig['model'])) { - // $modelconfig = (new json(app::getInheritedPath("config/model/{$source['schema']}_{$source['model']}.json"))); + // explicitly configure datasource + if (isset($sourceConfig['config']) && !($this->datasource instanceof remap)) { + $this->datasource->setConfig($sourceConfig['config']); + } - $dynamicModel = new dynamic(); - $dynamicModel->setConfig($sourceConfig['schema'], $sourceConfig['model']); + if (!empty($sourceConfig['schema']) && !empty($sourceConfig['model'])) { + $dynamicModel = new dynamic(); + $dynamicModel->setConfig($sourceConfig['schema'], $sourceConfig['model']); - $datasource = $this->datasource; + $datasource = $this->datasource; - // - // TODO: FIX! - // - $i = 0; - $max = 5500; + // + // TODO: FIX! + // + $i = 0; + $max = 5500; - $start = microtime(true); + $start = microtime(true); - foreach($datasource as $data) { - $dynamicModel->validate($data); - $errors = $dynamicModel->getErrors(); + foreach ($datasource as $data) { + $dynamicModel->validate($data); + $errors = $dynamicModel->getErrors(); - if(count($errors) > 0) { - echo("
" . print_r($data,true) . "\nErrors: ".print_r($errors, true)."
"); - } + if (count($errors) > 0) { + echo("
" . print_r($data, true) . "\nErrors: " . print_r($errors, true) . "
"); + } - $dynamicModel->reset(); + $dynamicModel->reset(); - $i++; + $i++; - if($i >= $max) { - break; - } + if ($i >= $max) { + break; + } + } + //todo: save loop + $end = microtime(true); + echo("Validated $i entries in " . ($end - $start) . " seconds."); } - //todo: save loop - $end = microtime(true); - echo("Validated {$i} entries in " . ($end-$start) . " seconds."); - } - - // @TODO: cancel if $datasource is null or invalid + // @TODO: cancel if $datasource is null or invalid - // pre-instanciate transforms - $this->createTransforms(); + // pre-instance transforms + $this->createTransforms(); - // simply target names - $targets = array_keys($this->config->get('target')); + // simply target names + $targets = array_keys($this->config->get('target')); - // start at item index - $itemIndex = 0; + // start at item index + $itemIndex = 0; - // count stored items cross-target - $storedItemTargets = 0; + // count stored items cross-target + $storedItemTargets = 0; - $start = microtime(true); + $start = microtime(true); - $timings = []; - $timingsMaxIndex = null; - $timingsMax = 0.0; - $timingsMaxData = null; + $timings = []; + $timingsMaxIndex = null; + $timingsMax = 0.0; + $timingsMaxData = null; - // reset global item index - $this->itemIndex = 0; - $this->storedItemCount = 0; + // reset global item index + $this->itemIndex = 0; + $this->storedItemCount = 0; - $this->beginTransactions($targets); + $this->beginTransactions($targets); - // - // do preprocessing - // - if($this->config->exists('preprocess')) { - foreach($this->config->get('preprocess') as $name => $config) { - $preprocessor_class = app::getInheritedClass('process_' . $config['type']); - $preprocessor = new $preprocessor_class($config['config']); - if($preprocessor instanceof \codename\core\io\process) { - $preprocessor->setPipelineInstance($this); + // + // do preprocessing + // + if ($this->config->exists('preprocess')) { + foreach ($this->config->get('preprocess') as $name => $config) { + $preprocessor_class = app::getInheritedClass('process_' . $config['type']); + $preprocessor = new $preprocessor_class($config['config']); + if ($preprocessor instanceof process) { + $preprocessor->setPipelineInstance($this); + + if (app::getResponse() instanceof cli) { + echo("[PIPELINE] starting preprocessor '$name'..." . chr(10)); + } - if(app::getResponse() instanceof \codename\core\response\cli) { - echo("[PIPELINE] starting preprocessor '$name'..." . chr(10)); + $preprocessor->run(); + } else { + throw new exception('EXCEPTION_CORE_IO_PIPELINE_PREPROCESSOR_INVALID_CLASS', exception::$ERRORLEVEL_FATAL, $preprocessor_class); + } } - - $preprocessor->run(); - } else { - throw new exception('EXCEPTION_CORE_IO_PIPELINE_PREPROCESSOR_INVALID_CLASS', exception::$ERRORLEVEL_FATAL, $preprocessor_class); - } } - } - if(app::getResponse() instanceof \codename\core\response\cli) { - echo("[PIPELINE] starting main pipeline..." . chr(10)); - } + if (app::getResponse() instanceof cli) { + echo("[PIPELINE] starting main pipeline..." . chr(10)); + } - // create a dummy transform for accessing pipeline internals - $dummyTransform = new \codename\core\io\transform\dummy([]); - $dummyTransform->setPipelineInstance($this); - $dummyTransform->setTransformerInstance($this); + // create a dummy transform for accessing pipeline internals + $dummyTransform = new transform\dummy([]); + $dummyTransform->setPipelineInstance($this); + $dummyTransform->setTransformerInstance($this); - // reset this thing: - $this->erroneousEntries = []; + // reset this thing: + $this->erroneousEntries = []; - // get some tagging information, if available - $targetTags = []; - foreach($targets as $target) { - if($tagMappings = $this->config->get('target>'.$target.'>tags')) { - $targetTags[$target] = $tagMappings; + // get some tagging information, if available + $targetTags = []; + foreach ($targets as $target) { + if ($tagMappings = $this->config->get('target>' . $target . '>tags')) { + $targetTags[$target] = $tagMappings; + } } - } - foreach($this->datasource as $data) { + foreach ($this->datasource as $data) { + // + // Debugging + // + $dataStart = null; + if ($this->debug) { + $dataStart = microtime(true); + } - // - // Debugging - // - if($this->debug) { - $dataStart = microtime(true); - } + $itemIndex++; - $itemIndex++; + // increase global item index + $this->itemIndex++; - // increase global item index - $this->itemIndex++; + // + // skip first x items + // + if ($this->startIndex != null && $itemIndex < $this->startIndex) { + continue; + } - // - // skip first x items - // - if($this->startIndex != null && $itemIndex < $this->startIndex) { - continue; - } + // + // omit if we have a null value in-between + // + if ($data == null) { + continue; + } - // - // omit if we have a null value in-between - // - if($data == null) { - continue; - } - - // - // reset all transforms (cache + errorstack) - // this is very important - // as we're not performing a multi-value, hash-based in-memory caching - // but instead, simply store the last transform result, respectively - // - foreach($this->transforms as $transform) { - $transform->reset(); - } + // + // reset all transforms (cache + errorstack) + // this is very important + // as we're not performing a multi-value, hash-based in-memory caching + // but instead, simply store the last transform result, respectively + // + foreach ($this->transforms as $transform) { + $transform->reset(); + } - $targetsStored = 0; + // buffer each target, before calling store() + // which means: we wait for each target to complete + // data generation/transformation, + // so we're able to cancel a whole source entry, + // if any target fails to get the data correctly. + $targetDataBuffer = []; + $targetTagsBuffer = []; + $targetErroneousBuffer = []; + + // handle targets + foreach ($targets as $targetname) { + $target = $this->getTarget($targetname); + + // + // continue, if the current dataset doesn't match the source filters for this target + // before beginning the pipeline run + // + if ($target->matchesSourceFilters($data) === false) { + continue; + } - // buffer each target, before calling store() - // which means: we wait for each target to complete - // data generation/transformation - // so we're able to cancel a whole source entry, - // if any target fails to get the data correctly. - $targetDataBuffer = []; - $targetTagsBuffer = []; - $targetErroneousBuffer = []; + // perform the final mapping + $mapped = []; - // handle targets - foreach($targets as $targetname) { + // optional: for use with tagging + $tags = null; - $target = $this->getTarget($targetname); + $erroneous = [ + 'erroneous' => false, + // 'value' => null, // set later + 'errors' => [], + ]; + $errorMap = []; - // - // continue, if the current dataset doesn't match the source filters for this target - // before beginning the pipeline run - // - if($target->matchesSourceFilters($data) === false) { - continue; - } + foreach ($target->getMapping() as $map => $mapconfig) { + $processed = null; - // perform the final mapping - $mapped = []; + if ($mapconfig['type'] == 'source') { + $processed = $data[$mapconfig['field']] ?? null; + } - // optional: for use with tagging - $tags = null; + if ($mapconfig['type'] == 'source_deep') { + $processed = deepaccess::get($data, $mapconfig['field']); + } - $erroneous = [ - 'erroneous' => false, - // 'value' => null, // set later - 'errors' => [] - ]; - $errorMap = []; + if ($mapconfig['type'] == 'transform') { + if (!isset($this->transforms[$mapconfig['field']])) { + throw new exception('EXCEPTION_CORE_IO_PIPELINE_MISSING_TRANSFORM', exception::$ERRORLEVEL_ERROR, $mapconfig['field']); + } + $transformInstance = $this->transforms[$mapconfig['field']]; + $processed = $transformInstance->transform($data); + + // track errorstate and errors + if (count($transformInstance->getErrors()) > 0) { + if (!$erroneous['erroneous']) { + $erroneous['erroneous'] = true; + } + $erroneous['errors'] = array_merge($erroneous['errors'], $transformInstance->getErrors()); + } + + // do not reset errors here - we handle it when we start handling a new data item + // $transformInstance->resetErrors(); + } - foreach($target->getMapping() as $map => $mapconfig) { + if ($mapconfig['type'] == 'transform_deep') { + $field = $mapconfig['field'][0]; + $path = array_slice($mapconfig['field'], 1); + + if (!isset($this->transforms[$field])) { + throw new exception('EXCEPTION_CORE_IO_PIPELINE_MISSING_TRANSFORM', exception::$ERRORLEVEL_ERROR, $field); + } + $transformInstance = $this->transforms[$field]; + $transformed = $transformInstance->transform($data); + + if (count($path) > 0) { + $processed = deepaccess::get($transformed, $path); + } else { + // only one object path item specified - transform name itself + $processed = $transformed; + } + + // track errorstate and errors + if (count($transformInstance->getErrors()) > 0) { + if (!$erroneous['erroneous']) { + $erroneous['erroneous'] = true; + } + $erroneous['errors'] = array_merge($erroneous['errors'], $transformInstance->getErrors()); + } + + // do not reset errors here - we handle it when we start handling a new data item + // $transformInstance->resetErrors(); + } - $processed = null; + if ($mapconfig['type'] == 'constant') { + $field = $mapconfig['field']; + if (is_array($field)) { + $processed = deepaccess::get($this->config->get('constants'), $field); + } else { + $processed = $this->config->get('constants>' . $field); + } + } - if($mapconfig['type'] == 'source') { - $processed = $data[$mapconfig['field']]; - } + if ($mapconfig['type'] == 'erroneous') { + // add an error value to be handled after this loop + $errorMap[$map] = $mapconfig; + } else { + $mapped[$map] = $processed; + } + } - if($mapconfig['type'] == 'source_deep') { - $processed = \codename\core\io\helper\deepaccess::get($data, $mapconfig['field']); - } + if ($erroneous['erroneous']) { + // + // set error value + // and handle error maps + // + foreach ($errorMap as $map => $mapconfig) { + if (isset($erroneous[$mapconfig['field']])) { + $mapped[$map] = $erroneous[$mapconfig['field']] ?? null; // set or null + } elseif ($mapconfig['field'] == 'data') { + // $mapped[$map] = $data; + $dataUtf8 = []; + foreach ($data as $k => $v) { + if (mb_check_encoding($k, 'UTF-8') === false) { + $k = utf8_encode($k); + } + if (!is_array($v) && mb_check_encoding($v, 'UTF-8') === false) { + $v = utf8_encode($v); + } + $dataUtf8[$k] = $v; + } + $mapped[$map] = $dataUtf8; + } elseif ($mapconfig['field'] == 'errorstack') { + $mapped[$map] = $erroneous; + } + } - if($mapconfig['type'] == 'transform') { + // also keep track of erroneous states + $targetErroneousBuffer[$targetname] = $erroneous; - if(!isset($this->transforms[$mapconfig['field']])) { - throw new exception('EXCEPTION_CORE_IO_PIPELINE_MISSING_TRANSFORM', exception::$ERRORLEVEL_ERROR, $mapconfig['field']); - } - $transformInstance = $this->transforms[$mapconfig['field']]; - $processed = $transformInstance->transform($data); + if ($this->errorstackEnabled) { + $this->errorstack->addErrors($erroneous['errors']); + } - // track errorstate and errors - if(\count($transformInstance->getErrors()) > 0 ) { - if(!$erroneous['erroneous']) { - $erroneous['erroneous'] = true; + if ($this->throwExceptionOnErroneousData) { + throw new exception('EXCEPTION_PIPELINE_ERRONEOUS_DATA', exception::$ERRORLEVEL_ERROR, $erroneous); + } + } else { + // + // if not erroneous, map null values + // + foreach ($errorMap as $map => $mapconfig) { + if (($mapconfig['field'] ?? null) === 'erroneous') { + $mapped[$map] = null; + } elseif ($mapconfig['field'] == 'data') { + $mapped[$map] = null; + } + } } - $erroneous['errors'] = array_merge($erroneous['errors'], $transformInstance->getErrors()); - } - - // do not reset errors here - we handle it when we start handling a new data item - // $transformInstance->resetErrors(); - } - if($mapconfig['type'] == 'transform_deep') { + // + // CHANGED 2019-07-14: + // tags are now generated/transformed AFTER target pipeline process + // to get erroneous data, optionally. + // + if ($targetTags[$targetname] ?? false) { + // tags are not part of the final mapped data + // instead, store() is invoked with it as the 2nd parameter + $tags = $tags ?? []; + + // use the previously created dummy transform to get the value + foreach ($targetTags[$targetname] as $map => $config) { + $tags[$map] = $dummyTransform->getInternalPipelineValue($config['type'], $config['field'], $data); + } + } - $field = $mapconfig['field'][0]; - $path = array_slice($mapconfig['field'], 1); + // + // continue, if the current dataset doesn't match the target data filters + // after receiving the complete, transformed result + // + if ($target->matchesTargetFilters($mapped) === false) { + continue; + } - if(!isset($this->transforms[$field])) { - throw new exception('EXCEPTION_CORE_IO_PIPELINE_MISSING_TRANSFORM', exception::$ERRORLEVEL_ERROR, $field); - } - $transformInstance = $this->transforms[$field]; - $transformed = $transformInstance->transform($data); + // save! - if(count($path) > 0) { - $processed = \codename\core\io\helper\deepaccess::get($transformed, $path); - } else { - // only one object path item specified - transform name itself - $processed = $transformed; - } + $storedItemTargets++; - // track errorstate and errors - if(count($transformInstance->getErrors()) > 0 ) { - if(!$erroneous['erroneous']) { - $erroneous['erroneous'] = true; + if ($this->dryRun) { + if ($this->debug && $erroneous['erroneous']) { + $end = microtime(true); + echo("
");
+                        echo("ERRONEOUS");
+                        print_r($mapped);
+                        echo("Item: $itemIndex Time: " . ($end - $start));
+                        echo("
"); + } } - $erroneous['errors'] = array_merge($erroneous['errors'], $transformInstance->getErrors()); - } - - // do not reset errors here - we handle it when we start handling a new data item - // $transformInstance->resetErrors(); + $targetDataBuffer[$targetname] = $mapped; + $targetTagsBuffer[$targetname] = $tags; } - if($mapconfig['type'] == 'constant') { - $field = $mapconfig['field']; - if(is_array($field)) { - $processed = \codename\core\io\helper\deepaccess::get($this->config->get('constants'), $field); - } else { - $processed = $this->config->get('constants>'.$field); - } - } - if($mapconfig['type'] == 'erroneous') { - // add an error value to be handled after this loop - $errorMap[$map] = $mapconfig; - } else { - $mapped[$map] = $processed; + $anyErroneous = false; + if ($this->skipErroneous || $this->trackErroneous) { + foreach ($targets as $targetName) { + if ($targetErroneousBuffer[$targetName]['erroneous'] ?? null) { + // we have at least ONE erroneous entry + $anyErroneous = true; + + if ($this->trackErroneous) { + $this->erroneousEntries[$targetName][] = [ + 'data' => $targetDataBuffer[$targetName] ?? null, + 'tags' => $targetTagsBuffer[$targetName] ?? null, + 'erroneous' => $targetErroneousBuffer[$targetName] ?? null, + ]; + } + } + } } - } - if($erroneous['erroneous']) { // - // set error value - // and handle error maps + // if not advised to skip the entries, + // store the data // - foreach($errorMap as $map => $mapconfig) { - if(isset($erroneous[$mapconfig['field']])) { - $mapped[$map] = $erroneous[$mapconfig['field']] ?? null; // set or null - } else { - if($mapconfig['field'] == 'data') { - // $mapped[$map] = $data; - $dataUtf8 = []; - foreach($data as $k => $v) { - if (mb_check_encoding($k,'UTF-8') === false) { - $k = utf8_encode($k); + if ((!$anyErroneous) || (!$this->skipErroneous)) { + // + // Final loop to ->store() the data + // + foreach ($targets as $targetName) { + if (!($targetDataBuffer[$targetName] ?? null)) { + continue; } - if (!\is_array($v) && mb_check_encoding($v,'UTF-8') === false) { - $v = utf8_encode($v); + if ($this->dryRun) { + // only use target, if virtual + $targetInstance = $this->getTarget($targetName); + if (($targetInstance instanceof virtualTargetInterface)) { + if ($targetInstance->getVirtualStoreEnabled()) { + $targetInstance->store($targetDataBuffer[$targetName], $targetTagsBuffer[$targetName]); + $this->storedItemCount++; + } + } else { + $targetInstance->store($targetDataBuffer[$targetName], $targetTagsBuffer[$targetName]); + $this->storedItemCount++; + } + } else { + $this->getTarget($targetName)->store($targetDataBuffer[$targetName], $targetTagsBuffer[$targetName]); + $this->storedItemCount++; } - $dataUtf8[$k] = $v; - } - $mapped[$map] = $dataUtf8; - } else if($mapconfig['field'] == 'errorstack') { - $mapped[$map] = $erroneous; } - } } - // also keep track of erroneous states - $targetErroneousBuffer[$targetname] = $erroneous; - - if($this->errorstackEnabled) { - $this->errorstack->addErrors($erroneous['errors']); + if ($this->endIndex != null && $itemIndex > $this->endIndex) { + break; } - if($this->throwExceptionOnErroneousData) { - throw new exception('EXCEPTION_PIPELINE_ERRONEOUS_DATA', exception::$ERRORLEVEL_ERROR, $erroneous); - } - } else { - // - // if not erroneous, map null values - // - foreach($errorMap as $map => $mapconfig) { - if(($mapconfig['field'] ?? null) === 'erroneous') { - $mapped[$map] = null; - } else if($mapconfig['field'] == 'data') { - $mapped[$map] = null; - } - } - } - - // - // CHANGED 2019-07-14: - // tags are now generated/transformed AFTER target pipeline process - // to get erroneous data, optionally. - // - if($targetTags[$targetname] ?? false) { - // tags are not part of the final mapped data - // instead, store() is invoked with it as the 2nd parameter - $tags = $tags ?? []; - - // use the previously created dummy transform to get the value - foreach($targetTags[$targetname] as $map => $config) { - $tags[$map] = $dummyTransform->getInternalPipelineValue($config['type'], $config['field'], $data); - } - } - - // - // continue, if the current dataset doesn't match the target data filters - // after receiving the complete, transformed result - // - if($target->matchesTargetFilters($mapped) === false) { - continue; - } - - // save! - - // debug: - /* - echo("
");
-          print_r($mapped);
-          echo("
"); - die(); - */ - - $targetsStored++; - $storedItemTargets++; - - if($this->dryRun) { - // simply normalize? - // $mapped = $this->getTargetModel($targetname, $targetconfig['model'], $targetconfig['app'] ?? '', $targetconfig['vendor'] ?? '')->normalizeData($mapped); - /* - echo("
");
-            print_r($mapped);
-            echo("
"); - */ - if($this->debug && $erroneous['erroneous']) { - $end = microtime(true); - echo("
");
-              echo("ERRONEOUS");
-              print_r($mapped);
-              echo("Item: $itemIndex Time: " . ($end-$start));
-              echo("
"); + if ($this->debug) { + $timings[$itemIndex] = (microtime(true) - $dataStart); + + if ($timings[$itemIndex] > $timingsMax) { + $timingsMaxIndex = $itemIndex; + $timingsMax = $timings[$itemIndex]; + $timingsMaxData = [ + 'source' => $data, + // 'transforms' => $this->transforms + 'transforms' => (array_map(function (string $key, transform $item) { + return [ + 'name' => $key, + 'cacheHash' => $item->cacheHash, + 'cacheValue' => $item->cacheValue, + 'durationMeasured_msec' => round($item->durationMeasured * 1000, 4), + 'durations_measured' => $item->durationsMeasured, + 'durationsMeasured_avg_msec' => count($item->durationsMeasured) > 0 ? round((array_sum($item->durationsMeasured) / count($item->durationsMeasured)) * 1000, 4) : null, + 'debugInfo' => $item->debugInfo, + ]; + }, array_keys($this->transforms), $this->transforms)), + ]; + } } - - if($this->debug && $this->endIndex != null && $itemIndex > $this->endIndex) { - $end = microtime(true); - // echo("
");
-              // echo("stopped. testing.");
-              // print_r($mapped);
-              // echo("Targets stored: $targetsStored - ItemTargets stored: $storedItemTargets ");
-              // echo("Item: $itemIndex Time: " . ($end-$start));
-              // echo("
"); + // call the callback to track progress or so. + if ($this->processCallback != null) { + $cb = $this->processCallback; + $cb($this); } - - $targetDataBuffer[$targetname] = $mapped; - $targetTagsBuffer[$targetname] = $tags; - - // // only use target, if virtual - // $targetInstance = $this->getTarget($targetname); - // - // if(($targetInstance instanceof \codename\core\io\target\virtual) || ($targetInstance instanceof \codename\core\io\target\dummy) || ($targetInstance instanceof \codename\core\io\target\virtualTargetInterface)) { - // if($targetInstance instanceof \codename\core\io\target\virtualTargetInterface) { - // if($targetInstance->getVirtualStoreEnabled()) { - // $targetInstance->store($mapped, $tags); - // $this->storedItemCount++; - // } - // } else { - // $targetInstance->store($mapped, $tags); - // $this->storedItemCount++; - // } - // } - - } else { - - $targetDataBuffer[$targetname] = $mapped; - $targetTagsBuffer[$targetname] = $tags; - - // $this->getTarget($targetname)->store($mapped, $tags); - // $this->storedItemCount++; - } } + if ($this->options && $this->options->get('preview')) { + $this->rollbackTransactions(); + } else { + $this->endTransactions(); + } - $anyErroneous = false; - if($this->skipErroneous || $this->trackErroneous) { - foreach($targets as $targetName) { - if($targetErroneousBuffer[$targetName]['erroneous'] ?? null) { - // we have at least ONE erroneous entry - $anyErroneous = true; - - if($this->trackErroneous) { - $this->erroneousEntries[$targetName][] = [ - 'data' => $targetDataBuffer[$targetName], - 'tags' => $targetTagsBuffer[$targetName], - 'erroneous' => $targetErroneousBuffer[$targetName] - ]; - } - + if ($this->debug) { + $end = microtime(true); + app::getResponse()->setData('pipeline_run', ($end - $start)); + app::getResponse()->setData('pipeline_items', ($itemIndex)); + app::getResponse()->setData('pipeline_avg_items_per_sec', ($storedItemTargets / ($end - $start))); + + app::getResponse()->setData('timings_max', (max($timings))); + app::getResponse()->setData('timings_max_index', $timingsMaxIndex); + app::getResponse()->setData('timings_max_running', ($timingsMax)); + app::getResponse()->setData('timings_max_data', $timingsMaxData); + + // find the slowest transforms + $transformsStats = $timingsMaxData['transforms']; + $sortSuccess = usort($transformsStats, function (array $a, array $b) { + // echo("
Compare $a['durationsMeasured_avg_msec'] <> ") + return bccomp(($a['durationsMeasured_avg_msec'] ?? 0), ($b['durationsMeasured_avg_msec'] ?? 0), 8); + }); + app::getResponse()->setData('timings_transforms_sorted', $sortSuccess ? $transformsStats : 'error'); + + app::getResponse()->setData('timings_avg', (array_sum($timings) / $itemIndex)); + } + } - // \codename\core\app::getLog('debug')->info(print_r($targetErroneousBuffer,true)); + /** + * resets and creates a new collection of named transforms + * @return void + * @throws ReflectionException + * @throws exception + */ + protected function createTransforms(): void + { + $this->transforms = []; + if ($this->config->get('transform')) { + foreach ($this->config->get('transform') as $name => $transform) { + $this->transforms[$name] = $this->getTransform($transform); } - } } + } - // - // if not advised to skip the entries, - // store the data - // - if((!$anyErroneous) || (!$this->skipErroneous)) { - // - // Final loop to ->store() the data - // - foreach($targets as $targetName) { - if(!($targetDataBuffer[$targetName] ?? null)) { - continue; - } - if($this->dryRun) { - // only use target, if virtual - $targetInstance = $this->getTarget($targetName); - if(($targetInstance instanceof \codename\core\io\target\virtual) || ($targetInstance instanceof \codename\core\io\target\dummy) || ($targetInstance instanceof \codename\core\io\target\virtualTargetInterface)) { - if($targetInstance instanceof \codename\core\io\target\virtualTargetInterface) { - if($targetInstance->getVirtualStoreEnabled()) { - $targetInstance->store($targetDataBuffer[$targetName], $targetTagsBuffer[$targetName]); - $this->storedItemCount++; - } - } else { - $targetInstance->store($targetDataBuffer[$targetName], $targetTagsBuffer[$targetName]); - $this->storedItemCount++; - } - } + /** + * [getTransform description] + * @param [type] $transformconfig [description] + * @return transform [description] + * @throws ReflectionException + * @throws exception + */ + protected function getTransform($transformconfig): transform + { + $class = app::getInheritedClass('transform_' . $transformconfig['type']); + if (class_exists($class)) { + $transform = new $class($transformconfig['config']); + if ($transform instanceof transform) { + $transform->setPipelineInstance($this); + $transform->setTransformerInstance($this); } else { - $this->getTarget($targetName)->store($targetDataBuffer[$targetName], $targetTagsBuffer[$targetName]); - $this->storedItemCount++; + throw new exception(self::EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_INSTANCE_OF_WRONG_BASE_CLASS, exception::$ERRORLEVEL_ERROR, $transformconfig['type']); } - } + return $transform; + } else { + throw new exception(self::EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_MISSING_CLASS, exception::$ERRORLEVEL_ERROR, $transformconfig['type']); } + } - if($this->endIndex != null && $itemIndex > $this->endIndex) { - break; + /** + * open transactions for a given collection of targets (by name) + * @param string[] $targets [array of target names] + * @return void + * @throws ReflectionException + * @throws exception + */ + protected function beginTransactions(array $targets): void + { + // disallow double-calling beginTransactions + if (count($this->activeConnections) > 0) { + throw new exception(self::EXCEPTION_CORE_IO_PIPELINE_BEGINTRANSACTIONS_CALLED_TWICE, exception::$ERRORLEVEL_FATAL, $this->config); } + $this->transaction = new transaction('pipeline', []); + foreach ($targets as $targetname) { + $target = $this->getTarget($targetname); + if ($target instanceof targetModelInterface) { + $model = $target->getModel(); - if($this->debug) { - $dataEnd = microtime(true); - $timings[$itemIndex] = ($dataEnd-$dataStart); - - if($timings[$itemIndex] > $timingsMax) { - $timingsMaxIndex = $itemIndex; - $timingsMax = $timings[$itemIndex]; - $timingsMaxData = [ - 'source' => $data, - // 'transforms' => $this->transforms - 'transforms' => (array_map(function(string $key, \codename\core\io\transform $item) { - return [ - 'name' => $key, - 'cacheHash' => $item->cacheHash, - 'cacheValue' => $item->cacheValue, - 'durationMeasured_msec' => round($item->durationMeasured * 1000, 4), - 'durations_measured' => $item->durationsMeasured, - 'durationsMeasured_avg_msec' => count($item->durationsMeasured) > 0 ? round((array_sum($item->durationsMeasured)/count($item->durationsMeasured)) * 1000, 4) : null, - 'debugInfo' => $item->debugInfo - ]; - }, array_keys($this->transforms), $this->transforms )) - ]; - } - } + // only mysql and pgsql supported + if ($model instanceof sql) { + $found = false; - // call the callback to track progress or so. - if($this->processCallback != null) { - $cb = $this->processCallback; - $cb($this); + $this->transaction->addTransactionable($model); + + foreach ($this->activeConnections as $conn) { + if ($conn === $model->getConnection()->getConnection()) { + $found = true; + break; + } + } + + if (!$found) { + $conn = $model->getConnection()->getConnection(); + if (!$conn->inTransaction()) { + // $conn->beginTransaction(); + + // SQLite: PRAGMA foreign_keys = OFF; + // MySQL: SET foreign_key_checks = 0; + + // Determine driver via connection + $driver = $model->getConnection()->driver; + + if ($driver == 'mysql') { + $conn->exec('SET foreign_key_checks = 0;'); + // $conn->exec('SET unique_checks = 0;'); // Disabled! + $conn->exec('SET autocommit = 0;'); + } elseif ($driver == 'sqlite') { + // SQLite autocommit is handled automatically + // by beginning, ending or rollback of a transaction + $conn->exec('PRAGMA foreign_keys = OFF;'); + } else { + // Throw an exception to avoid uninitiated transaction run + throw new exception('EXCEPTION_PIPELINE_BEGINTRANSACTIONS_UNSUPPORTED_CONNECTION_DRIVER', exception::$ERRORLEVEL_ERROR, $driver); + } + + $this->activeConnections[] = $conn; + } else { + throw new exception('EXCEPTION_PIPELINE_BEGINTRANSACTIONS_ALREADY_ACTIVE_TRANSACTION', exception::$ERRORLEVEL_ERROR); + } + } + } + } } - } - - if($this->options && $this->options->get('preview')) { - $this->rollbackTransactions(); - } else { - $this->endTransactions(); - } - - if($this->debug) { - $end = microtime(true); - app::getResponse()->setData('pipeline_run', ($end-$start)); - app::getResponse()->setData('pipeline_items', ($itemIndex)); - app::getResponse()->setData('pipeline_avg_items_per_sec', ($storedItemTargets/($end-$start))); - - app::getResponse()->setData('timings_max', (max($timings))); - app::getResponse()->setData('timings_max_index', $timingsMaxIndex); - app::getResponse()->setData('timings_max_running', ($timingsMax)); - app::getResponse()->setData('timings_max_data', $timingsMaxData); - - // find slowest transforms - $transformsStats = $timingsMaxData['transforms']; - $sortSuccess = usort ( $transformsStats , function(array $a, array $b) { - // echo("
Compare $a['durationsMeasured_avg_msec'] <> ") - return bccomp("" .( $a['durationsMeasured_avg_msec'] ?? 0) . "", "". ($b['durationsMeasured_avg_msec'] ?? 0) . "", 8); - }); - app::getResponse()->setData('timings_transforms_sorted', $sortSuccess ? $transformsStats : 'error'); - - app::getResponse()->setData('timings_avg', (array_sum($timings)/$itemIndex)); - - // // TARGETS DEBUG - // app::getResponse()->setData('target_filter_called_count', \codename\core\io\target::$filterCalledCount); - // app::getResponse()->setData('target_filter_called_duration', \codename\core\io\target::$filterCalledDuration); - // if(\codename\core\io\target::$filterCalledCount > 0) { - // app::getResponse()->setData('target_filter_called_avg', \codename\core\io\target::$filterCalledDuration / (\codename\core\io\target::$filterCalledCount)); - // } - } + $this->transaction->start(); } /** - * whether to throw an exception if an erroneous dataset is detected - * @var bool + * get a target instance + * by name + * + * @param string $name [description] + * @return target [description] + * @throws ReflectionException + * @throws exception */ - protected $throwExceptionOnErroneousData = false; + public function getTarget(string $name): target + { + if (!isset($this->target[$name])) { + // auto-init target + if ($this->config->exists('target>' . $name)) { + $config = $this->config->get('target>' . $name); + + $class = \codename\core\app::getInheritedClass('target_' . $config['type']); + + if (class_exists($class)) { + $this->target[$name] = new $class($name, $config); + } else { + throw new exception(self::EXCEPTION_CORE_IO_PIPELINE_GETTARGET_MISSING_CLASS, exception::$ERRORLEVEL_ERROR, [ + 'type' => $config['type'], + 'class' => $class, + ]); + } + } else { + throw new exception(self::EXCEPTION_CORE_IO_PIPELINE_GETTARGET_CONFIG_MISSING_TARGET, exception::$ERRORLEVEL_ERROR, $name); + } + } + return $this->target[$name]; + } /** - * enables exception throwing on detecting an erroneous dataset - * @param bool $state [description] + * rollback all open transactions + * @return void + * @throws exception */ - public function setThrowExceptionOnErroneousData(bool $state = true) { - $this->throwExceptionOnErroneousData = $state; + protected function rollbackTransactions(): void + { + foreach ($this->activeConnections as $conn) { + $conn->rollback(); + + $driver = $conn->getAttribute(PDO::ATTR_DRIVER_NAME); + if ($driver == 'mysql') { + // Autocommit re-enabling on MySQL + $conn->exec('SET autocommit = 1;'); + // CHANGED: wasn't commented-in before... + $conn->exec('SET foreign_key_checks = 1;'); + } elseif ($driver == 'sqlite') { + // NOTE: For SQLite, we do not re-enable autocommit, as it is done per transaction + // Re-enable FKEY checks + $conn->exec('PRAGMA foreign_keys = ON;'); + } else { + // Throw an exception to avoid rollback failure? + throw new exception('EXCEPTION_PIPELINE_ROLLBACKTRANSACTIONS_UNSUPPORTED_CONNECTION_DRIVER', exception::$ERRORLEVEL_ERROR, $driver); + } + } + $this->activeConnections = []; } /** - * whether to track errors in a global pipeline errorstack - * @var bool + * end/commit all open transactions + * @return void + * @throws exception */ - protected $errorstackEnabled = false; + protected function endTransactions(): void + { + // end transactions for all connections that + // we're included in the previous call to $this->beginTransactions() + + $this->transaction->end(); + + foreach ($this->activeConnections as $conn) { + // transactions should have ended + // $conn->commit(); + + $driver = $conn->getAttribute(PDO::ATTR_DRIVER_NAME); + + if ($driver == 'mysql') { + // Autocommit re-enabling on MySQL + $conn->exec('SET autocommit = 1;'); + // CHANGED: wasn't commented-in before... + $conn->exec('SET foreign_key_checks = 1;'); + } elseif ($driver == 'sqlite') { + // NOTE: For SQLite, we do not re-enable autocommit, as it is done per transaction + // Re-enable FKEY checks + $conn->exec('PRAGMA foreign_keys = ON;'); + } else { + // error or skip? + // Throw an exception to avoid uninitiated transaction run + throw new exception('EXCEPTION_PIPELINE_ENDTRANSACTIONS_UNSUPPORTED_CONNECTION_DRIVER', exception::$ERRORLEVEL_ERROR, $driver); + } + } + $this->activeConnections = []; + } /** - * enable/disable the pipeline errorstack + * enables exception throwing on detecting an erroneous dataset * @param bool $state [description] */ - public function setErrorstackEnabled(bool $state = true) { - $this->errorstackEnabled = $state; + public function setThrowExceptionOnErroneousData(bool $state = true): void + { + $this->throwExceptionOnErroneousData = $state; } /** - * the global pipeline errorstack - * @var \codename\core\errorstack + * enable/disable the pipeline errorstack + * @param bool $state [description] */ - protected $errorstack = null; + public function setErrorstackEnabled(bool $state = true): void + { + $this->errorstackEnabled = $state; + } /** * [getErrorstack description] - * @return \codename\core\errorstack [description] + * @return errorstack [description] */ - public function getErrorstack() : \codename\core\errorstack { - return $this->errorstack; + public function getErrorstack(): errorstack + { + return $this->errorstack; } - /** - * whether to skip erroneous processes - * which means: if any of the target fails/runs into erroneous state - * do not handle the whole source entry it originates from - * so neither of the targets gets to really STORE data for this entry. - * @var bool - */ - protected $skipErroneous = false; - /** * whether to skip erroneous processes * which means: if any of the target fails/runs into erroneous state @@ -887,22 +1081,11 @@ public function getErrorstack() : \codename\core\errorstack { * so neither of the targets gets to really STORE data for this entry. * @param bool $state [description] */ - public function setSkipErroneous(bool $state = true) { - $this->skipErroneous = $state; + public function setSkipErroneous(bool $state = true): void + { + $this->skipErroneous = $state; } - /** - * track erroneous entries to be stored in targets - * @var bool - */ - protected $trackErroneous = false; - - /** - * [protected description] - * @var array - */ - protected $erroneousEntries = []; - /** * whether to skip erroneous processes * which means: if any of the target fails/runs into erroneous state @@ -910,408 +1093,160 @@ public function setSkipErroneous(bool $state = true) { * so neither of the targets gets to really STORE data for this entry. * @param bool $state [description] */ - public function setTrackErroneous(bool $state = true) { - $this->trackErroneous = $state; + public function setTrackErroneous(bool $state = true): void + { + $this->trackErroneous = $state; } /** * returns collected erroneous entries * @return array [description] */ - public function getErroneousEntries() : array { - return $this->erroneousEntries; - } - - /** - * active PDO connections - * for handling open transactions - * on a per-databaseconnection basis - * @var \PDO[] - */ - protected $activeConnections = []; - - /** - * [EXCEPTION_CORE_IO_PIPELINE_BEGINTRANSACTIONS_CALLED_TWICE description] - * @var string - */ - const EXCEPTION_CORE_IO_PIPELINE_BEGINTRANSACTIONS_CALLED_TWICE = 'EXCEPTION_CORE_IO_PIPELINE_BEGINTRANSACTIONS_CALLED_TWICE'; - - /** - * [protected description] - * @var \codename\core\transaction - */ - protected $transaction = null; - - /** - * open transactions for a given collection of targets (by name) - * @param string[] $targets [array of target names] - * @return void - */ - protected function beginTransactions(array $targets) { - - // disallow double-calling beginTransactions - if(count($this->activeConnections) > 0) { - throw new exception(self::EXCEPTION_CORE_IO_PIPELINE_BEGINTRANSACTIONS_CALLED_TWICE, exception::$ERRORLEVEL_FATAL, $this->config); - } - - $this->transaction = new \codename\core\transaction('pipeline', []); - - foreach($targets as $targetname) { - - $target = $this->getTarget($targetname); - if($target instanceof \codename\core\io\targetModelInterface) { - $model = $target->getModel(); - - // only mysql and pgsql supported - if($model instanceof \codename\core\model\schematic\sql) { - $found = false; - - $this->transaction->addTransactionable($model); - - foreach($this->activeConnections as $conn) { - if($conn === $model->getConnection()->getConnection()) { - $found = true; - break; - } - } - - if(!$found) { - $conn = $model->getConnection()->getConnection(); - if(!$conn->inTransaction()) { - // $conn->beginTransaction(); - - // SQLite: PRAGMA foreign_keys = OFF; - // MySQL: SET foreign_key_checks = 0; - - // Determine driver via connection - $driver = $model->getConnection()->driver; - - if($driver == 'mysql') { - $conn->exec('SET foreign_key_checks = 0;'); - // $conn->exec('SET unique_checks = 0;'); // Disabled! - $conn->exec('SET autocommit = 0;'); - } else if($driver == 'sqlite') { - // SQLite autocommit is handled automatically - // by beginning, ending or rollback of a transaction - $conn->exec('PRAGMA foreign_keys = OFF;'); - } else { - // Throw an exception to avoid uninitiated transaction run - throw new exception('EXCEPTION_PIPELINE_BEGINTRANSACTIONS_UNSUPPORTED_CONNECTION_DRIVER', exception::$ERRORLEVEL_ERROR, $driver); - } - - $this->activeConnections[] = $conn; - } else { - throw new exception('EXCEPTION_PIPELINE_BEGINTRANSACTIONS_ALREADY_ACTIVE_TRANSACTION', exception::$ERRORLEVEL_ERROR); - } - } - } - } - } - - $this->transaction->start(); - } - - /** - * end/commit all open transactions - * @return void - */ - protected function endTransactions() { - // end transactions for all connections that - // we're included in the previous call to $this->beginTransactions() - - $this->transaction->end(); - - foreach($this->activeConnections as $conn) { - // transactions should have ended - // $conn->commit(); - - $driver = $conn->getAttribute(\PDO::ATTR_DRIVER_NAME); - - if($driver == 'mysql') { - // Autocommit re-enabling on MySQL - $conn->exec('SET autocommit = 1;'); - // CHANGED: wasn't commented-in before... - $conn->exec('SET foreign_key_checks = 1;'); - } else if($driver == 'sqlite') { - // NOTE: For SQLite, we do not re-enable autocommit, as it is done per transaction - // Re-enable FKEY checks - $conn->exec('PRAGMA foreign_keys = ON;'); - } else { - // error or skip? - // Throw an exception to avoid uninitiated transaction run - throw new exception('EXCEPTION_PIPELINE_ENDTRANSACTIONS_UNSUPPORTED_CONNECTION_DRIVER', exception::$ERRORLEVEL_ERROR, $driver); - } - } - $this->activeConnections = []; + public function getErroneousEntries(): array + { + return $this->erroneousEntries; } /** - * rollback all open transactions - * @return void + * gets the dryRun state of this instance + * @return bool [dry run state] */ - protected function rollbackTransactions() { - foreach($this->activeConnections as $conn) { - $conn->rollback(); - $driver = $conn->getAttribute(\PDO::ATTR_DRIVER_NAME); - if($driver == 'mysql') { - // Autocommit re-enabling on MySQL - $conn->exec('SET autocommit = 1;'); - // CHANGED: wasn't commented-in before... - $conn->exec('SET foreign_key_checks = 1;'); - } else if($driver == 'sqlite') { - // NOTE: For SQLite, we do not re-enable autocommit, as it is done per transaction - // Re-enable FKEY checks - $conn->exec('PRAGMA foreign_keys = ON;'); - } else { - // Throw an exception to avoid rollback failure? - throw new exception('EXCEPTION_PIPELINE_ROLLBACKTRANSACTIONS_UNSUPPORTED_CONNECTION_DRIVER', exception::$ERRORLEVEL_ERROR, $driver); - } - } - $this->activeConnections = []; + public function getDryRun(): bool + { + return $this->dryRun; } - - /** - * determines, if the pipeline is running in dryRun mode - * (no real stores/saves happending) - * - * @var bool - */ - protected $dryRun = true; - /** * enables or disables the dryRun option * * @param bool $dryRun [description] */ - public function setDryRun(bool $dryRun = true) { - $this->dryRun = $dryRun; - } - - /** - * gets the dryRun state of this instance - * @return bool [dry run state] - */ - public function getDryRun() : bool { - return $this->dryRun; - } - - /** - * resets and creates a new collection of named transforms - * @return void - */ - protected function createTransforms() { - $this->transforms = []; - if($this->config->get('transform')) { - foreach($this->config->get('transform') as $name => $transform) { - $this->transforms[$name] = $this->getTransform($transform); - } - } - } - - /** - * [getTransform description] - * @param [type] $transformconfig [description] - * @return \codename\core\io\transform [description] - */ - protected function getTransform($transformconfig) : \codename\core\io\transform { - $class = app::getInheritedClass('transform_' . $transformconfig['type']); - if(class_exists($class)) { - $transform = new $class($transformconfig['config']); - if($transform instanceof \codename\core\io\transform) { - $transform->setPipelineInstance($this); - $transform->setTransformerInstance($this); - } else { - throw new exception(self::EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_INSTANCE_OF_WRONG_BASE_CLASS, exception::$ERRORLEVEL_ERROR, $transformconfig['type']); - } - return $transform; - } else { - throw new exception(self::EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_MISSING_CLASS, exception::$ERRORLEVEL_ERROR, $transformconfig['type']); - } - } - - /** - * [EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_INSTANCE_OF_WRONG_BASE_CLASS description] - * @var string - */ - const EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_INSTANCE_OF_WRONG_BASE_CLASS = 'EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_INSTANCE_OF_WRONG_BASE_CLASS'; - - /** - * get a transform instance - * by name - * (has to be already initialized during ->run() ) - * - * @param string $name [transform name from config] - * @return \codename\core\io\transform [transform instance] - */ - public function getTransformInstance(string $name) : \codename\core\io\transform { - if(!isset($this->transforms[$name])) { - throw new exception(self::EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_NOTFOUND, exception::$ERRORLEVEL_ERROR, $name); - } - return $this->transforms[$name]; + public function setDryRun(bool $dryRun = true): void + { + $this->dryRun = $dryRun; } - /** - * [EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_NOTFOUND description] - * @var string - */ - const EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_NOTFOUND = 'EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_NOTFOUND'; - - /** - * [EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_MISSING_CLASS description] - * @var string - */ - const EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_MISSING_CLASS = 'EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_MISSING_CLASS'; - /** * [setTarget description] - * @param string $name [description] - * @param \codename\core\io\target $target [description] + * @param string $name [description] + * @param target $target [description] */ - public function setTarget(string $name, \codename\core\io\target $target) + public function setTarget(string $name, target $target): void { $this->target[$name] = $target; } - /** - * get a target instance - * by name - * - * @param string $name [description] - * @return \codename\core\io\target [description] - */ - public function getTarget(string $name) : \codename\core\io\target { - if(!isset($this->target[$name])) { - // auto-init target - if($this->config->exists('target>' . $name)) { - $config = $this->config->get('target>' . $name); - - $class = \codename\core\app::getInheritedClass('target_'.$config['type']); - - if(class_exists($class)) { - $this->target[$name] = new $class($name, $config); - } else { - throw new exception(self::EXCEPTION_CORE_IO_PIPELINE_GETTARGET_MISSING_CLASS, exception::$ERRORLEVEL_ERROR, [ - 'type' => $config['type'], - 'class' => $class - ]); - } - - } else { - throw new exception(self::EXCEPTION_CORE_IO_PIPELINE_GETTARGET_CONFIG_MISSING_TARGET, exception::$ERRORLEVEL_ERROR, $name); - } - } - return $this->target[$name]; - } - - /** - * [EXCEPTION_CORE_IO_PIPELINE_GETTARGET_CONFIG_MISSING_TARGET description] - * @var string - */ - const EXCEPTION_CORE_IO_PIPELINE_GETTARGET_CONFIG_MISSING_TARGET = 'EXCEPTION_CORE_IO_PIPELINE_GETTARGET_CONFIG_MISSING_TARGET'; - - /** - * [EXCEPTION_CORE_IO_PIPELINE_GETTARGET_MISSING_CLASS description] - * @var string - */ - const EXCEPTION_CORE_IO_PIPELINE_GETTARGET_MISSING_CLASS = 'EXCEPTION_CORE_IO_PIPELINE_GETTARGET_MISSING_CLASS'; - - /** * [getOption description] - * @param string $key [description] + * @param string $key [description] * @return mixed [description] */ - public function getOption(string $key) { - if($key === null) { - die("Meh"); - } - if($this->options !== null) { - return $this->options->get($key); - } else { - return null; - } + public function getOption(string $key): mixed + { + return $this->options?->get($key); } /** * returns the current pipeline specification * @return array + * @throws ReflectionException + * @throws exception */ - public function getSpecification() : array { - - $this->createTransforms(); + public function getSpecification(): array + { + $this->createTransforms(); - // spec object: - $obj = [ - 'type.name' => [ - 'type' => 'target|target.mapping|source|transform', - 'source' => ['array-of-named-sources', 'source.fieldname', 'transform.sometransform'] - ] - ]; + $spec = []; + // loop through each target + foreach ($this->config->get('target') as $targetName => $targetConfig) { + $sources = []; + // parse mappings + foreach ($targetConfig['mapping'] as $mapName => $mapConfig) { + $targetMappingName = "target.$targetName.$mapName"; - $spec = []; + // sources - for mappings, this is either source, transform or erroneous (at the moment) + $field = is_array($mapConfig['field']) ? implode('.', $mapConfig['field']) : $mapConfig['field']; + $targetMappingSources = [ + "{$mapConfig['type']}.$field", + ]; - // loop through each target - foreach($this->config->get('target') as $targetName => $targetConfig) { - $sources = []; - // parse mappings - foreach($targetConfig['mapping'] as $mapName => $mapConfig) { - $targetMappingName = "target.{$targetName}.{$mapName}"; + $spec[$targetMappingName] = [ + 'type' => 'target.mapping', + 'source' => $targetMappingSources, + ]; + $sources[] = $targetMappingName; + } + $spec["target.$targetName"] = [ + 'type' => 'target', + 'source' => $sources, + ]; + } - // sources - for mappings, this is either source, transform or erroneous (at the moment) - $field = is_array($mapConfig['field']) ? implode('.', $mapConfig['field']) : $mapConfig['field']; - $targetMappingSources = [ - "{$mapConfig['type']}.{$field}" - ]; + // loop through each transform + if ($this->config->exists('transform')) { + foreach ($this->config->get('transform') as $transformName => $transformConfig) { + $spec["transform.$transformName"] = $this->getTransformInstance($transformName)->getSpecification(); + } + } - $spec[$targetMappingName] = [ - 'type' => 'target.mapping', - 'source' => $targetMappingSources - ]; - $sources[] = $targetMappingName; + foreach ($spec as $specItem) { + foreach ($specItem['source'] as $specItemSource) { + if (str_starts_with($specItemSource, 'source.')) { + $spec[$specItemSource] = [ + 'type' => 'source', + ]; + } + if (str_starts_with($specItemSource, 'model.')) { + $spec[$specItemSource] = [ + 'type' => 'model', + ]; + } + } } - $spec["target.{$targetName}"] = [ - 'type' => 'target', - 'source' => $sources + + $spec['erroneous.erroneous'] = [ + 'type' => 'erroneous', + ]; + $spec['erroneous.data'] = [ + 'type' => 'erroneous', ]; - } - // loop through each transform - if($this->config->exists('transform')) { - foreach($this->config->get('transform') as $transformName => $transformConfig) { - // try { - $spec["transform.{$transformName}"] = $this->getTransformInstance($transformName)->getSpecification(); - // } catch (\Exception $e) { + return $spec; + } - // } + /** + * get a transform instance + * by name + * (has to be already initialized during ->run() ) + * + * @param string $name [transform name from config] + * @return transform [transform instance] + * @throws exception + */ + public function getTransformInstance(string $name): transform + { + if (!isset($this->transforms[$name])) { + throw new exception(self::EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_NOTFOUND, exception::$ERRORLEVEL_ERROR, $name); } - } + return $this->transforms[$name]; + } - foreach($spec as $specItem) { - foreach($specItem['source'] as $specItemSource) { - if(strpos($specItemSource, 'source.') === 0) { - $spec[$specItemSource] = [ - 'type' => 'source' - ]; - } - if(strpos($specItemSource, 'model.') === 0) { - $spec[$specItemSource] = [ - 'type' => 'model' - ]; - } + /** + * [getTargetModel description] + * @param string $targetName [description] + * @param string $model [description] + * @param string $app [description] + * @param string $vendor [description] + * @return model [description] + * @throws ReflectionException + * @throws exception + */ + protected function getTargetModel(string $targetName, string $model = '', string $app = '', string $vendor = ''): model + { + if (!isset($this->targetModelInstances[$targetName])) { + $this->targetModelInstances[$targetName] = app::getModel($model, $app, $vendor); } - } - - $spec['erroneous.erroneous'] = [ - 'type' => 'erroneous' - ]; - $spec['erroneous.data'] = [ - 'type' => 'erroneous' - ]; - - return $spec; + return $this->targetModelInstances[$targetName]; } - } - ?> diff --git a/backend/class/process.php b/backend/class/process.php index c345b8b..cc12f9e 100644 --- a/backend/class/process.php +++ b/backend/class/process.php @@ -1,109 +1,109 @@ -errorstack = new errorstack('PROCESS'); - $this->config = $config; - $this->debug = $this->config['debug'] ?? false; - } - - /** - * [getErrors description] - * @return array [description] - */ - public function getErrors() : array { - return $this->errorstack->getErrors(); - } - - /** - * [resetErrors description] - */ - public function resetErrors () { - $this->errorstack->reset(); - } - - /** - * [private description] - * @var \codename\core\io\pipeline - */ - private $pipelineInstance = null; - - /** - * [getPipelineInstance description] - * @return \codename\core\io\pipeline [description] - */ - protected function getPipelineInstance() : \codename\core\io\pipeline { - return $this->pipelineInstance; - } - - /** - * [isDryRun description] - * @return bool [description] - */ - protected function isDryRun() : bool { - return $this->pipelineInstance->getDryRun(); - } - - /** - * [setPipelineInstance description] - * @param \codename\core\io\pipeline $instance [description] - */ - public function setPipelineInstance(\codename\core\io\pipeline $instance) { - $this->pipelineInstance = $instance; - } - - /** - * [run description] - * @return [type] [description] - */ - public abstract function run(); - - /** - * debug info: - * measure duration for the transform itself - * @var [type] - */ - public $durationMeasured = null; - - /** - * debug info, optional - * @var mixed - */ - public $debugInfo = null; - - /** - * debug mode - * @var bool - */ - protected $debug = false; - - /** - * returns the specification for this transform - * @return array - */ - public abstract function getSpecification() : array; - + /** + * debug info: + * measure duration for the transform itself + * @var null|int + */ + public ?int $durationMeasured = null; + /** + * debug info, optional + * @var mixed + */ + public mixed $debugInfo = null; + /** + * [protected description] + * @var array + */ + protected array $config; + /** + * [protected description] + * @var errorstack + */ + protected errorstack $errorstack; + /** + * debug mode + * @var bool + */ + protected bool $debug = false; + /** + * [private description] + * @var null|pipeline + */ + private ?pipeline $pipelineInstance = null; + + /** + * @param array $config + */ + public function __construct(array $config) + { + $this->errorstack = new errorstack('PROCESS'); + $this->config = $config; + $this->debug = $this->config['debug'] ?? false; + } + + /** + * [getErrors description] + * @return array [description] + */ + public function getErrors(): array + { + return $this->errorstack->getErrors(); + } + + /** + * [resetErrors description] + */ + public function resetErrors(): void + { + $this->errorstack->reset(); + } + + /** + * [run description] + * @return void [type] [description] + */ + abstract public function run(): void; + + /** + * returns the specification for this transform + * @return array + */ + abstract public function getSpecification(): array; + + /** + * [getPipelineInstance description] + * @return pipeline [description] + */ + protected function getPipelineInstance(): pipeline + { + return $this->pipelineInstance; + } + + /** + * [setPipelineInstance description] + * @param pipeline $instance [description] + */ + public function setPipelineInstance(pipeline $instance): void + { + $this->pipelineInstance = $instance; + } + + /** + * [isDryRun description] + * @return bool [description] + */ + protected function isDryRun(): bool + { + return $this->pipelineInstance->getDryRun(); + } } - ?> diff --git a/backend/class/process/target.php b/backend/class/process/target.php index 9e2c16e..e8d925f 100644 --- a/backend/class/process/target.php +++ b/backend/class/process/target.php @@ -1,26 +1,33 @@ getPipelineInstance()->getTarget($this->config['target']); - } +abstract class target extends process +{ + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + throw new LogicException('Not implemented'); // TODO + } - /** - * @inheritDoc - */ - public function getSpecification(): array - { - throw new \LogicException('Not implemented'); // TODO - } + /** + * [getTarget description] + * @return \codename\core\io\target [description] + * @throws ReflectionException + * @throws exception + */ + protected function getTarget(): \codename\core\io\target + { + return $this->getPipelineInstance()->getTarget($this->config['target']); + } } diff --git a/backend/class/process/target/model.php b/backend/class/process/target/model.php index e263edf..7de3cba 100644 --- a/backend/class/process/target/model.php +++ b/backend/class/process/target/model.php @@ -1,24 +1,30 @@ getTarget(); - if($target instanceof \codename\core\io\targetModelInterface) { - return $target->getModel(); - } else { - throw new exception('EXCEPTION_CORE_IO_PROCESS_TARGET_MODEL_UNSUPPORTED', exception::$ERRORLEVEL_FATAL, $this->config); +abstract class model extends target +{ + /** + * [getModel description] + * @return \codename\core\model [description] + * @throws ReflectionException + * @throws exception + */ + protected function getModel(): \codename\core\model + { + $target = $this->getTarget(); + if ($target instanceof targetModelInterface) { + return $target->getModel(); + } else { + throw new exception('EXCEPTION_CORE_IO_PROCESS_TARGET_MODEL_UNSUPPORTED', exception::$ERRORLEVEL_FATAL, $this->config); + } } - } } diff --git a/backend/class/process/target/model/delete.php b/backend/class/process/target/model/delete.php index f4acd46..cd3be43 100644 --- a/backend/class/process/target/model/delete.php +++ b/backend/class/process/target/model/delete.php @@ -1,39 +1,43 @@ getModel(); - // apply filters - foreach($this->config['filter'] as $filter) { - if($filter['value'] && isset($filter['value']['source'])) { - if($filter['value']['source'] == 'transform') { - $useValue = $this->getPipelineInstance()->getTransformInstance($filter['value']['field'])->transform(null); +class delete extends model +{ + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + public function run(): void + { + $model = $this->getModel(); + // apply filters + foreach ($this->config['filter'] as $filter) { + if ($filter['value'] && isset($filter['value']['source'])) { + if ($filter['value']['source'] == 'transform') { + $useValue = $this->getPipelineInstance()->getTransformInstance($filter['value']['field'])->transform(null); + } else { + throw new exception('EXCEPTION_CORE_IO_PROCESS_TARGET_MODEL_DELETE_UNSUPPORTED_SOURCE', exception::$ERRORLEVEL_FATAL, $filter); + } + } else { + $useValue = $filter['value']; + } + $model->addFilter($filter['field'], $useValue, $filter['operator']); + } + // perform delete. may be a large query result... + if (!$this->getPipelineInstance()->getDryRun()) { + $model->delete(); } else { - throw new exception('EXCEPTION_CORE_IO_PROCESS_TARGET_MODEL_DELETE_UNSUPPORTED_SOURCE', exception::$ERRORLEVEL_FATAL, $filter); + // do nothing + // app::getResponse()->setData('debug_process', $useValue); } - } else { - $useValue = $filter['value']; - } - $model->addFilter($filter['field'], $useValue, $filter['operator']); - } - // perform delete. may be a large query result... - if(!$this->getPipelineInstance()->getDryRun()) { - $model->delete(); - } else { - // do nothing - // app::getResponse()->setData('debug_process', $useValue); } - } } diff --git a/backend/class/process/target/model/update.php b/backend/class/process/target/model/update.php index 0f19460..562f3bb 100644 --- a/backend/class/process/target/model/update.php +++ b/backend/class/process/target/model/update.php @@ -1,56 +1,61 @@ getModel(); + // apply filters + foreach ($this->config['filter'] as $filter) { + if ($filter['value'] && isset($filter['value']['source'])) { + if ($filter['value']['source'] == 'transform') { + $useValue = $this->getPipelineInstance()->getTransformInstance($filter['value']['field'])->transform(null); + } else { + throw new exception('EXCEPTION_CORE_IO_PROCESS_TARGET_MODEL_UPDATE_UNSUPPORTED_SOURCE', exception::$ERRORLEVEL_FATAL, $filter); + } + } else { + $useValue = $filter['value']; + } + $model->addFilter($filter['field'], $useValue, $filter['operator']); + } - /** - * @inheritDoc - */ - public function run() - { - $model = $this->getModel(); - // apply filters - foreach($this->config['filter'] as $filter) { - if($filter['value'] && isset($filter['value']['source'])) { - if($filter['value']['source'] == 'transform') { - $useValue = $this->getPipelineInstance()->getTransformInstance($filter['value']['field'])->transform(null); - } else { - throw new exception('EXCEPTION_CORE_IO_PROCESS_TARGET_MODEL_UPDATE_UNSUPPORTED_SOURCE', exception::$ERRORLEVEL_FATAL, $filter); + $data = []; + foreach ($this->config['data'] as $field => $dataEntry) { + if (is_array($dataEntry)) { + if ($dataEntry['source'] == 'option') { + $data[$field] = $this->getPipelineInstance()->getOption($dataEntry['field']); + } elseif ($dataEntry['source'] == 'transform') { + $data[$field] = $this->getPipelineInstance()->getTransformInstance($dataEntry['field'])->transform(null); + } else { + throw new exception('EXCEPTION_CORE_IO_PROCESS_TARGET_MODEL_UPDATE_UNSUPPORTED_SOURCE', exception::$ERRORLEVEL_FATAL, [$field, $dataEntry]); + } + } else { + $data[$field] = $dataEntry; + } } - } else { - $useValue = $filter['value']; - } - $model->addFilter($filter['field'], $useValue, $filter['operator']); - } - $data = []; - foreach($this->config['data'] as $field => $dataEntry) { - if(is_array($dataEntry)) { - if($dataEntry['source'] == 'option') { - $data[$field] = $this->getPipelineInstance()->getOption($dataEntry['field']); - } elseif($dataEntry['source'] == 'transform') { - $data[$field] = $this->getPipelineInstance()->getTransformInstance($dataEntry['field'])->transform(null); + // perform update + if (!$this->getPipelineInstance()->getDryRun()) { + $model->update($data); } else { - throw new exception('EXCEPTION_CORE_IO_PROCESS_TARGET_MODEL_UPDATE_UNSUPPORTED_SOURCE', exception::$ERRORLEVEL_FATAL, [ $field, $dataEntry ]); + // do nothing + app::getLog('devlog')->debug("target_model_update: " . print_r($data, true)); + // app::getResponse()->setData('debug_process', $useValue); } - } else { - $data[$field] = $dataEntry; - } - } - - // perform update - if(!$this->getPipelineInstance()->getDryRun()) { - $model->update($data); - } else { - // do nothing - app::getLog('devlog')->debug("target_model_update: " . print_r($data, true)); - // app::getResponse()->setData('debug_process', $useValue); } - } } diff --git a/backend/class/progressInterface.php b/backend/class/progressInterface.php index 80bf6ce..7cca195 100644 --- a/backend/class/progressInterface.php +++ b/backend/class/progressInterface.php @@ -1,20 +1,21 @@ setPipelineInstance() on an object */ -interface setPipelineInstanceInterface { - - /** - * sets the corresponding pipeline instance - * - * @param \codename\core\io\pipeline $instance [description] - */ - public function setPipelineInstance(\codename\core\io\pipeline $instance); - +interface setPipelineInstanceInterface +{ + /** + * sets the corresponding pipeline instance + * + * @param pipeline $instance [description] + */ + public function setPipelineInstance(pipeline $instance); } diff --git a/backend/class/target.php b/backend/class/target.php index 426bbfa..e92aa15 100644 --- a/backend/class/target.php +++ b/backend/class/target.php @@ -1,202 +1,189 @@ -name = $name; - $this->config = $config; - - if(isset($this->config['source_filter'])) { - $this->sourceFilters = $this->config['source_filter']; - $this->sourceFilterFunctions = self::buildFilterFunctions($this->sourceFilters); - } - - if(isset($this->config['target_filter'])) { - $this->targetFilters = $this->config['target_filter']; - $this->targetFilterFunctions = self::buildFilterFunctions($this->targetFilters); +abstract class target +{ + /** + * target name + * @var null|string + */ + public ?string $name = null; + + /** + * filters that are executed on the source data + * @var array[] + */ + protected mixed $sourceFilters = []; + + /** + * filters that are executed on the target data + * @var array[] + */ + protected array $targetFilters = []; + /** + * callable source filter functions + * @var callable[] + */ + protected array $sourceFilterFunctions = []; + /** + * callable target filter functions + * @var callable[] + */ + protected array $targetFilterFunctions = []; + /** + * [protected description] + * @var array + */ + protected array $config = []; + + /** + * [__construct description] + * @param string $name [description] + * @param array $config [description] + */ + public function __construct(string $name, array $config) + { + $this->name = $name; + $this->config = $config; + + if (isset($this->config['source_filter'])) { + $this->sourceFilters = $this->config['source_filter']; + $this->sourceFilterFunctions = self::buildFilterFunctions($this->sourceFilters); + } + + if (isset($this->config['target_filter'])) { + $this->targetFilters = $this->config['target_filter']; + $this->targetFilterFunctions = self::buildFilterFunctions($this->targetFilters); + } } - } - /** - * builds an array of executable filter functions - * - * @param array $filters [description] - * @return callable[] - */ - protected static function buildFilterFunctions(array $filters) : array { - $filterFunctions = []; - foreach($filters as $filter) { - switch ($filter['operator']) { - case '=': - if($filter['value'] === null) { - // - // We want the value to be null, - // so we return !isset(value) - positive, if not set or null. - // - $filterFunctions[] = function(array $data) use ($filter) { - return (!isset($data[$filter['field']])); - }; - } else { - // - // We want the value to be not null and specify an explicit value. - // So we check for the value being set (via isset() and perform a simple == comparison) - // - $filterFunctions[] = function(array $data) use ($filter) { - return (isset($data[$filter['field']]) && ($data[$filter['field']] == $filter['value'])); - }; - } - // LEGACY/Old code: - // $filterFunctions[] = function(array $data) use ($filter) { - // return (!isset($data[$filter['field']]) && $filter['value'] == null) || (isset($data[$filter['field']]) && ($data[$filter['field']] == $filter['value'])); - // }; - break; - case '!=': - if($filter['value'] === null) { - // - // We want the value to be != null, - // so we check for isset - and this already fulfills our requirements (and returns true) - // - $filterFunctions[] = function(array $data) use ($filter) { - return (isset($data[$filter['field']])); - }; - } else { - // - // We want the value to be not equal to a specific value. - // This is the more complicated on. - // By definition, 1!=2, at least for integers. We also perform this for strings. - // But it depends on the personal point of view, if we want the value != 123 - // and we provide NULL. For some RDBMS, this might not be defined. - // But we interpret it as a "falsy" value. - // The !=NULL case is handled above. - // - // So, we want the value to be SOME value (except NULL) - // - isset() kicks out the NULLs - // - and we simply compare via != later on. - // - // filter.value != VALUE - $filterFunctions[] = function(array $data) use ($filter) { - return (isset($data[$filter['field']]) && $data[$filter['field']] != $filter['value']); - }; - } - // LEGACY/Old code: - // $filterFunctions[] = function(array $data) use ($filter) { - // // unset == null => !false, otherwise detail check - // return (!(!isset($data[$filter['field']]) && $filter['value'] == null)) || (isset($data[$filter['field']]) && $data[$filter['field']] != $filter['value']); - // }; - break; - default: - # code... - break; - } + /** + * builds an array of executable filter functions + * + * @param array $filters [description] + * @return callable[] + */ + protected static function buildFilterFunctions(array $filters): array + { + $filterFunctions = []; + foreach ($filters as $filter) { + switch ($filter['operator']) { + case '=': + if ($filter['value'] === null) { + // + // We want the value to be null, + // so we return !isset(value) - positive, if not set or null. + // + $filterFunctions[] = function (array $data) use ($filter) { + return (!isset($data[$filter['field']])); + }; + } else { + // + // We want the value to be not null and specify an explicit value. + // So we check for the value being set (via isset() and perform a simple == comparison) + // + $filterFunctions[] = function (array $data) use ($filter) { + return (isset($data[$filter['field']]) && ($data[$filter['field']] == $filter['value'])); + }; + } + break; + case '!=': + if ($filter['value'] === null) { + // + // We want the value to be != null, + // so we check for isset - and this already fulfills our requirements (and returns true) + // + $filterFunctions[] = function (array $data) use ($filter) { + return (isset($data[$filter['field']])); + }; + } else { + // + // We want the value to be not equal to a specific value. + // This is the more complicated on. + // By definition, 1!=2, at least for integers. We also perform this for strings. + // But it depends on the personal point of view, if we want the value != 123, + // and we provide NULL. For some RDBMS, this might not be defined. + // But we interpret it as a "falsy" value. + // The !=NULL case is handled above. + // + // So, we want the value to be SOME value (except NULL) + // - isset() kicks out the NULLs + // - and we simply compare via != later on. + // + // filter.value != VALUE + $filterFunctions[] = function (array $data) use ($filter) { + return (isset($data[$filter['field']]) && $data[$filter['field']] != $filter['value']); + }; + } + break; + default: + # code... + break; + } + } + return $filterFunctions; } - return $filterFunctions; - } - - /** - * callable source filter functions - * @var callable[] - */ - protected $sourceFilterFunctions = []; - /** - * callable target filter functions - * @var callable[] - */ - protected $targetFilterFunctions = []; - - /** - * [protected description] - * @var array - */ - protected $config = []; - - /** - * [store description] - * @param array $data [description] - * @return bool [success] - */ - public abstract function store(array $data) : bool; - - // public static $filterCalledCount = 0.0; - // public static $filterCalledDuration = 0.0; - - - /** - * returns true, if the source filters matches the current dataset - * (before transforming stuff) - * @param array $data [description] - * @return bool [description] - */ - public function matchesSourceFilters(array $data) : bool { - $matches = true; - foreach($this->sourceFilterFunctions as $filter) { - $matches = $filter($data); - if(!$matches) { + /** + * [store description] + * @param array $data [description] + * @return bool [success] + */ + abstract public function store(array $data): bool; + + /** + * returns true, if the source filters matches the current dataset + * (before transforming stuff) + * @param array $data [description] + * @return bool [description] + */ + public function matchesSourceFilters(array $data): bool + { + $matches = true; + foreach ($this->sourceFilterFunctions as $filter) { + $matches = $filter($data); + if (!$matches) { + return $matches; + } + } return $matches; - } } - return $matches; - } - /** - * returns true, if the target filters matches the current dataset - * (after applying transforms and stuff) - * @param array $data [description] - * @return bool [description] - */ - public function matchesTargetFilters(array $data) : bool { - $matches = true; - foreach($this->targetFilterFunctions as $filter) { - $matches = $filter($data); - if(!$matches) { + /** + * returns true, if the target filters matches the current dataset + * (after applying transforms and stuff) + * @param array $data [description] + * @return bool [description] + */ + public function matchesTargetFilters(array $data): bool + { + $matches = true; + foreach ($this->targetFilterFunctions as $filter) { + $matches = $filter($data); + if (!$matches) { + return $matches; + } + } return $matches; - } } - return $matches; - } - - /** - * [getMapping description] - * @return array [description] - */ - public function getMapping() : array { - return $this->config['mapping']; - } - /** - * close/finish with this target - * - * @return void - */ - public abstract function finish(); + /** + * [getMapping description] + * @return array [description] + */ + public function getMapping(): array + { + return $this->config['mapping']; + } + /** + * close/finish with this target + * + * @return void + */ + abstract public function finish(): void; } diff --git a/backend/class/target/arraydata.php b/backend/class/target/arraydata.php index ab55d1e..1f40c77 100644 --- a/backend/class/target/arraydata.php +++ b/backend/class/target/arraydata.php @@ -1,53 +1,53 @@ virtualStore[] = $data; - return true; - } - - /** - * returns data stored virtually in this instance - * @return array [description] - */ - public function getVirtualStoreData() : array { - return $this->virtualStore; - } - - /** - * @inheritDoc - */ - public function finish() - { - // nothing. lock storing? - } - - +class arraydata extends target +{ + /** + * data storage + * @var array + */ + protected array $virtualStore = []; + + /** + * [__construct description] + * @param string $name [description] + * @param array $config [description] + */ + public function __construct(string $name, array $config) + { + parent::__construct($name, $config); + } + + /** + * {@inheritDoc} + */ + public function store(array $data): bool + { + $this->virtualStore[] = $data; + return true; + } + + /** + * returns data stored virtually in this instance + * @return array [description] + */ + public function getVirtualStoreData(): array + { + return $this->virtualStore; + } + + /** + * {@inheritDoc} + */ + public function finish(): void + { + // nothing. lock storing? + } } diff --git a/backend/class/target/arraydata/tagged.php b/backend/class/target/arraydata/tagged.php index ffb6a84..6572ad7 100644 --- a/backend/class/target/arraydata/tagged.php +++ b/backend/class/target/arraydata/tagged.php @@ -1,56 +1,67 @@ finished ?? false) { - throw new exception('EXCEPTION_CORE_IO_TARGET_BUFFERED_ALREADY_FINISHED', exception::$ERRORLEVEL_ERROR); - } - - if($tags) { - $tagsChunk = [ $tags ]; - $this->resultObjects[] = new \codename\core\io\value\structure\tagged($data, $tagsChunk); - } else { - $this->resultObjects[] = new \codename\core\value\structure($data); - } - - return true; + if ($this->finished ?? false) { + throw new exception('EXCEPTION_CORE_IO_TARGET_BUFFERED_ALREADY_FINISHED', exception::$ERRORLEVEL_ERROR); + } + + if ($tags) { + $tagsChunk = [$tags]; + $this->resultObjects[] = new \codename\core\io\value\structure\tagged($data, $tagsChunk); + } else { + $this->resultObjects[] = new structure($data); + } + + return true; } /** * returns data stored virtually in this instance * @return array [description] */ - public function getVirtualStoreData() : array { - $result = []; - foreach($this->resultObjects as $obj) { - $result[] = $obj->get(); - } - return $result; + public function getVirtualStoreData(): array + { + $result = []; + foreach ($this->resultObjects as $obj) { + $result[] = $obj->get(); + } + return $result; } /** - * @inheritDoc + * {@inheritDoc} */ public function getStructureResultArray(): array { - return $this->resultObjects; + return $this->resultObjects; } } diff --git a/backend/class/target/buffered.php b/backend/class/target/buffered.php index e035cca..6635832 100644 --- a/backend/class/target/buffered.php +++ b/backend/class/target/buffered.php @@ -1,106 +1,104 @@ bufferSize = $this->config['buffer_size'] ?? null; - } - - /** - * buffer size until forced writeout, if SupportsPartialWriteout = true - * and if bufferSize != null OR > 0 - * @var int|null - */ - protected $bufferSize = null; - - /** - * Current count of entries in buffer - * @var int - */ - protected $currentStoredCount = 0; - - /** - * Whether this target supports partial write-outs - * (buffer flushing) - * This constant must be overridden in order to use it. - * @var bool - */ - const SupportsPartialWriteout = false; - - /** - * @inheritDoc - */ - public function store(array $data, ?array $tags = null) : bool - { - if($this->finished) { - throw new exception('EXCEPTION_CORE_IO_TARGET_BUFFERED_ALREADY_FINISHED', exception::$ERRORLEVEL_ERROR); +abstract class buffered extends target implements targetStoreTagInterface +{ + /** + * Whether this target supports partial write-outs + * (buffer flushing) + * This constant must be overridden in order to use it. + * @var bool + */ + public const SupportsPartialWriteout = false; + /** + * buffered entries + * @var array + */ + protected array $bufferArray = []; + /** + * [protected description] + * @var array + */ + protected array $tagsArray = []; + /** + * buffer size until forced writeout, if SupportsPartialWriteout = true + * and if bufferSize != null OR > 0 + * @var int|null + */ + protected $bufferSize = null; + + /** + * Current count of entries in buffer + * @var int + */ + protected int $currentStoredCount = 0; + /** + * [protected description] + * @var bool + */ + protected bool $finished = false; + + /** + * {@inheritDoc} + */ + public function __construct(string $name, array $config) + { + parent::__construct($name, $config); + $this->bufferSize = $this->config['buffer_size'] ?? null; } - $this->bufferArray[] = $data; - $this->tagsArray[] = $tags; - - $this->currentStoredCount++; - // - // Buffer flush, depending on current size - // - if(static::SupportsPartialWriteout && $this->bufferSize && (($this->currentStoredCount % $this->bufferSize) === 0)) { - // forced write-out - $this->storeBufferedData(); - $this->bufferArray = []; // clear buffer array to release memory + /** + * {@inheritDoc} + * @param array $data + * @param array|null $tags + * @return bool + * @throws exception + */ + public function store(array $data, ?array $tags = null): bool + { + if ($this->finished) { + throw new exception('EXCEPTION_CORE_IO_TARGET_BUFFERED_ALREADY_FINISHED', exception::$ERRORLEVEL_ERROR); + } + $this->bufferArray[] = $data; + $this->tagsArray[] = $tags; + + $this->currentStoredCount++; + + // + // Buffer flush, depending on current size + // + if (static::SupportsPartialWriteout && $this->bufferSize && (($this->currentStoredCount % $this->bufferSize) === 0)) { + // forced write-out + $this->storeBufferedData(); + $this->bufferArray = []; // clear buffer array to release memory + } + return true; } - return true; - } - - /** - * perform the real store routine - * -> store the buffered data - * - * @return void - */ - protected abstract function storeBufferedData(); - /** - * [protected description] - * @var bool - */ - protected $finished = false; - - /** - * @inheritDoc - */ - public function finish() - { - if(!$this->finished) { - $this->finished = true; - $this->storeBufferedData(); + /** + * perform the real store routine + * -> store the buffered data + * + * @return void + */ + abstract protected function storeBufferedData(): void; + + /** + * {@inheritDoc} + */ + public function finish(): void + { + if (!$this->finished) { + $this->finished = true; + $this->storeBufferedData(); + } } - - // \codename\core\app::getResponse()->setData('buffered_tags_debug', $this->tagsArray); - } - } diff --git a/backend/class/target/buffered/file.php b/backend/class/target/buffered/file.php index 899cad8..4651438 100644 --- a/backend/class/target/buffered/file.php +++ b/backend/class/target/buffered/file.php @@ -1,104 +1,111 @@ targetFilePath = $config['filepath'] ?? null; - $this->append = $config['append'] ?? false; - $this->splitCount = $config['split_count'] ?? null; - } + /** + * count after which we begin a new file + * @var null|int + */ + protected ?int $splitCount = null; + /** + * [protected description] + * @var fileabsolute[] + */ + protected ?array $fileResults = null; - /** - * legacy method returning a new file handle using the currently set targetFilePath - * @deprecated - * @return resource - */ - protected function getFileHandle() { - if(!$this->targetFilePath) { - $this->targetFilePath = $this->getNewFilePath(); + /** + * {@inheritDoc} + */ + public function __construct(string $name, array $config) + { + parent::__construct($name, $config); + $this->targetFilePath = $config['filepath'] ?? null; + $this->append = $config['append'] ?? false; + $this->splitCount = $config['split_count'] ?? null; } - return $this->getNewFileHandle($this->targetFilePath); - } - /** - * returns a new, temporary file path - * @return [type] [description] - */ - protected function getNewFilePath() { - return tempnam(sys_get_temp_dir(), '_bf_'); - } - - /** - * returns a new file handle for the given filepath - * to be opened in write or append mode - * @param string $targetFilePath [description] - * @return resource [a file handle resource] - */ - protected function getNewFileHandle(string $targetFilePath) { - $handle = @fopen($targetFilePath, ($this->append ? 'a+' : 'w+')); - if($handle === false) { - throw new exception('CORE_IO_TARGET_BUFFERED_FILE_HANDLE_ERROR', exception::$ERRORLEVEL_ERROR, $targetFilePath); + /** + * {@inheritDoc} + * @return array + * @throws ReflectionException + * @throws exception + */ + public function getFileResultArray(): array + { + if ($this->fileResults ?? false) { + if ($this->config['config']['archive'] ?? false) { + return $this->archiveResults ?? $this->archiveResults = $this->createArchive(); + } else { + return $this->fileResults; + } + } else { + // invalid, exception! + } + return []; + // throw new \LogicException('Not implemented'); // TODO } - return $handle; - } - /** - * [protected description] - * @var \codename\core\value\text\fileabsolute[] - */ - protected $fileResults = null; + /** + * legacy method returning a new file handle using the currently set targetFilePath + * @return resource + * @throws exception + */ + protected function getFileHandle() + { + if (!$this->targetFilePath) { + $this->targetFilePath = $this->getNewFilePath(); + } + return $this->getNewFileHandle($this->targetFilePath); + } - /** - * @inheritDoc - */ - public function getFileResultArray() : array - { - if($this->fileResults) { - if($this->config['config']['archive'] ?? false) { - return $this->archiveResults ?? $this->archiveResults = $this->createArchive(); - } else { - return $this->fileResults; - } - } else { - // invalid, exception! + /** + * returns a new, temporary file path + * @return false|string [type] [description] + */ + protected function getNewFilePath(): bool|string + { + return tempnam(sys_get_temp_dir(), '_bf_'); } - return []; - // throw new \LogicException('Not implemented'); // TODO - } + /** + * returns a new file handle for the given filepath + * to be opened in write or append mode + * @param string $targetFilePath [description] + * @return resource [a file handle resource] + * @throws exception + */ + protected function getNewFileHandle(string $targetFilePath) + { + $handle = @fopen($targetFilePath, ($this->append ? 'a+' : 'w+')); + if ($handle === false) { + throw new exception('CORE_IO_TARGET_BUFFERED_FILE_HANDLE_ERROR', exception::$ERRORLEVEL_ERROR, $targetFilePath); + } + return $handle; + } } diff --git a/backend/class/target/buffered/file/csv.php b/backend/class/target/buffered/file/csv.php index 3445d77..4ed1d66 100644 --- a/backend/class/target/buffered/file/csv.php +++ b/backend/class/target/buffered/file/csv.php @@ -1,390 +1,372 @@ value based mappings - * this needs "column" defined per mapping entry - * @var bool - */ - protected $numericIndexes = false; - - /** - * [protected description] - * @var int - */ - protected $numericIndexStart = 0; - - /** - * count after which we begin a new file - * @var int - */ - protected $splitCount = null; - - /** - * [protected description] - * @var [type] - */ - protected $lineBreak = "\n"; - - /** - * @inheritDoc - */ - public function __construct(string $name, array $config) - { - parent::__construct($name, $config); - - $this->delimiter = $config['delimiter'] ?? $this->delimiter; - $this->enclosure = array_key_exists('enclosure',$config) ? $config['enclosure'] : $this->enclosure; - $this->escapeChar = $config['escape_char'] ?? $this->escapeChar; - $this->headed = $config['headed'] ?? $this->headed; - $this->numericIndexes = $config['numeric_indexes'] ?? false; - $this->numericIndexStart = $config['numeric_index_start'] ?? 0; - $this->encoding = $config['encoding'] ?? 'UTF-8'; - $this->encodingUtf8BOM = $config['encoding_utf8bom'] ?? true; - $this->splitCount = $config['split_count'] ?? null; - $this->lineBreak = $config['lineBreak'] ?? $this->lineBreak; - } - - /** - * output encoding - * @var string - */ - protected $encoding = 'UTF-8'; - - /** - * Use BOM, if using encoding == UTF-8 - * @var string - */ - protected $encodingUtf8BOM = true; - - /** - * [UTF8_BOM description] - * see https://stackoverflow.com/questions/5601904/encoding-a-string-as-utf-8-with-bom-in-php - * @var string - */ - const UTF8_BOM = "\xEF\xBB\xBF"; // chr(239) . chr(187) . chr(191); - - /** - * Array of currently used file handles - * @var array - */ - protected $filesCreated = []; - - /** - * Handle of currently opened file, if any. - * @var resource|null - */ - protected $currentFileHandle = null; - - /** - * This target supports Partial Writeouts (buffer flushing) - * @var bool - */ - const SupportsPartialWriteout = true; - - /** - * @inheritDoc - */ - protected function storeBufferedData() - { - $dataChunks = []; - - $dataChunkIndexOffset = 0; - $dataChunkCountOffset = 0; - - if(static::SupportsPartialWriteout && $this->bufferSize) { - // By default, we target only one file (index 0) - if($this->splitCount) { - // if splitting, determine current starting data chunk index - // WARNING: (int) cast required, as floor outputs a float! - $dataChunkIndexOffset = (int)floor(($this->currentStoredCount - count($this->bufferArray)) / $this->splitCount);# - } - - // current count of elements in being-worked-on chunk - // (if any; zero if not buffering) - if($this->splitCount) { - $dataChunkCountOffset = ($this->currentStoredCount - count($this->bufferArray)) % $this->splitCount; - } else { - $dataChunkCountOffset = 0; - } - - if($dataChunkCountOffset > 0) { - $partialChunkLeftoverSize = 0; - // leftover space in current chunk - if($this->splitCount) { - $partialChunkLeftoverSize = $this->splitCount - $dataChunkCountOffset; - } - - // first chunk, partial. - if($partialChunkLeftoverSize > 0) { - $dataChunks[] = array_slice($this->bufferArray, 0, $partialChunkLeftoverSize); - } - - // more chunks, if applicable - $moreChunkableData = array_slice($this->bufferArray, $partialChunkLeftoverSize); - if(!empty($moreChunkableData)) { - $dataChunks = array_merge( - $dataChunks, - array_chunk($moreChunkableData, $this->splitCount) - ); - } - } else { - if($this->splitCount && (count($this->bufferArray) > $this->splitCount)) { - // we have to split at least one time - $dataChunks = array_chunk($this->bufferArray, $this->splitCount); - } else { - $dataChunks = [ $this->bufferArray ]; - } - } - } else { - - if($this->splitCount && (count($this->bufferArray) > $this->splitCount)) { - // we have to split at least one time - $dataChunks = array_chunk($this->bufferArray, $this->splitCount); - } else { - $dataChunks = [ $this->bufferArray ]; - } +class csv extends file +{ + /** + * [UTF8_BOM description] + * see https://stackoverflow.com/questions/5601904/encoding-a-string-as-utf-8-with-bom-in-php + * @var string + */ + public const UTF8_BOM = "\xEF\xBB\xBF"; + /** + * This target supports Partial Writeouts (buffer flushing) + * @var bool + */ + public const SupportsPartialWriteout = true; + /** + * the delimiter used in the csv + * @var string + */ + protected string $delimiter = ';'; + /** + * the enclosure char used in the csv + * @var null|string + */ + protected ?string $enclosure = '"'; + /** + * the escape char used in the CSV + * @var string [type] + */ + protected string $escapeChar = '\\'; + /** + * headed data: use mapping keys as headings + * @var bool + */ + protected bool $headed = true; + /** + * use serial columns/numeric indexes + * instead of key => value based mappings + * this needs "column" defined per mapping entry + * @var bool + */ + protected bool $numericIndexes = false; + /** + * [protected description] + * @var int + */ + protected int $numericIndexStart = 0; + /** + * count after which we begin a new file + * @var null|int + */ + protected ?int $splitCount = null; + /** + * [protected description] + * @var string [type] + */ + protected string $lineBreak = "\n"; + /** + * output encoding + * @var string + */ + protected string $encoding = 'UTF-8'; + /** + * Use BOM, if using encoding == UTF-8 + * @var bool + */ + protected bool $encodingUtf8BOM = true; // chr(239) . chr(187) . chr(191); + /** + * Array of currently used file handles + * @var array + */ + protected array $filesCreated = []; + + /** + * Handle of currently opened file, if any. + * @var resource + */ + protected $currentFileHandle; + + /** + * {@inheritDoc} + */ + public function __construct(string $name, array $config) + { + parent::__construct($name, $config); + + $this->delimiter = $config['delimiter'] ?? $this->delimiter; + $this->enclosure = array_key_exists('enclosure', $config) ? $config['enclosure'] : $this->enclosure; + $this->escapeChar = $config['escape_char'] ?? $this->escapeChar; + $this->headed = $config['headed'] ?? $this->headed; + $this->numericIndexes = $config['numeric_indexes'] ?? false; + $this->numericIndexStart = $config['numeric_index_start'] ?? 0; + $this->encoding = $config['encoding'] ?? 'UTF-8'; + $this->encodingUtf8BOM = $config['encoding_utf8bom'] ?? true; + $this->splitCount = $config['split_count'] ?? null; + $this->lineBreak = $config['lineBreak'] ?? $this->lineBreak; } - foreach ($dataChunks as $index => $dataChunk) { - - // skip empty chunks - if(count($dataChunk) === 0) { - continue; - } + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function storeBufferedData(): void + { + $dataChunks = []; + + $dataChunkIndexOffset = 0; + + if (static::SupportsPartialWriteout && $this->bufferSize) { + // By default, we target only one file (index 0) + if ($this->splitCount) { + // if splitting, determine current starting data chunk index + // WARNING: (int) cast required, as floor outputs a float! + $dataChunkIndexOffset = (int)floor(($this->currentStoredCount - count($this->bufferArray)) / $this->splitCount);# + } - $append = false; + // current count of elements in being-worked-on chunk + // (if any; zero if not buffering) + if ($this->splitCount) { + $dataChunkCountOffset = ($this->currentStoredCount - count($this->bufferArray)) % $this->splitCount; + } else { + $dataChunkCountOffset = 0; + } - if(count($this->filesCreated) === ($index + $dataChunkIndexOffset + 1)) { - // - // use currently open file handle - // target chunk is current chunk - // - if($this->currentFileHandle) { - // continue to use this file handle - $append = true; + if ($dataChunkCountOffset > 0) { + $partialChunkLeftoverSize = 0; + // leftover space in current chunk + if ($this->splitCount) { + $partialChunkLeftoverSize = $this->splitCount - $dataChunkCountOffset; + } + + // first chunk, partial. + if ($partialChunkLeftoverSize > 0) { + $dataChunks[] = array_slice($this->bufferArray, 0, $partialChunkLeftoverSize); + } + + // more chunks, if applicable + $moreChunkableData = array_slice($this->bufferArray, $partialChunkLeftoverSize); + if (!empty($moreChunkableData)) { + $dataChunks = array_merge( + $dataChunks, + array_chunk($moreChunkableData, $this->splitCount) + ); + } + } elseif ($this->splitCount && (count($this->bufferArray) > $this->splitCount)) { + // we have to split at least one time + $dataChunks = array_chunk($this->bufferArray, $this->splitCount); + } else { + $dataChunks = [$this->bufferArray]; + } + } elseif ($this->splitCount && (count($this->bufferArray) > $this->splitCount)) { + // we have to split at least one time + $dataChunks = array_chunk($this->bufferArray, $this->splitCount); } else { - throw new exception('MAJOR_FAULT_TARGET_FILEHANDLES_INVALID_OFFSET', exception::$ERRORLEVEL_FATAL); + $dataChunks = [$this->bufferArray]; } - } else { - // Close current file handle - if($this->currentFileHandle) { - // further checks...? Out-of-bounds? - fclose($this->currentFileHandle); - $this->currentFileHandle = null; - } - - // create a new file handle. - $path = $this->getNewFilePath(); - $this->currentFileHandle = $this->getNewFileHandle($path); - $this->filesCreated[] = $path; - } - - $this->internalStoreBufferedData($this->currentFileHandle, $dataChunk, $append); - } - - - // - // Finalize, tag and create result file path array - // - if($this->finished) { - - // Close the remaining open file handle. - if($this->currentFileHandle) { - fclose($this->currentFileHandle); - $this->currentFileHandle = null; - } - - $tagsChunks = []; + foreach ($dataChunks as $index => $dataChunk) { + // skip empty chunks + if (count($dataChunk) === 0) { + continue; + } - // aggregate tags chunks, if applicable - if($this->splitCount && ($this->currentStoredCount > $this->splitCount)) { - $tagsChunks = array_chunk($this->tagsArray, $this->splitCount); - } else { - $tagsChunks = [ $this->tagsArray ]; - } + $append = false; + + if (count($this->filesCreated) === ($index + $dataChunkIndexOffset + 1)) { + // + // use currently open file handle + // target chunk is current chunk + // + if ($this->currentFileHandle) { + // continue to use this file handle + $append = true; + } else { + throw new exception('MAJOR_FAULT_TARGET_FILEHANDLES_INVALID_OFFSET', exception::$ERRORLEVEL_FATAL); + } + } else { + // Close current file handle + if ($this->currentFileHandle) { + // further checks...? Out-of-bounds? + fclose($this->currentFileHandle); + $this->currentFileHandle = null; + } + + // create a new file handle. + $path = $this->getNewFilePath(); + $this->currentFileHandle = $this->getNewFileHandle($path); + $this->filesCreated[] = $path; + } - foreach($this->filesCreated as $index => $path) { + $this->internalStoreBufferedData($this->currentFileHandle, $dataChunk, $append); + } - $tagsChunk = $tagsChunks[$index] ?? null; - // if(!$tagsChunk) { - // // fill with empty array, if not set - // $tagsChunk = array_fill(0, count($dataChunk), []); - // } + // + // Finalize, tag and create result file path array + // + if ($this->finished) { + // Close the remaining open file handle. + if ($this->currentFileHandle) { + fclose($this->currentFileHandle); + $this->currentFileHandle = null; + } - if($tagsChunk) { - foreach($tagsChunk as &$tagsElement) { - // force csv extension in tag - $tagsElement['file_extension'] = 'csv'; + // aggregate tags chunks, if applicable + if ($this->splitCount && ($this->currentStoredCount > $this->splitCount)) { + $tagsChunks = array_chunk($this->tagsArray, $this->splitCount); + } else { + $tagsChunks = [$this->tagsArray]; + } - if(count($tagsChunks) > 1) { - // override filename with chunk number - if($addendum = $tagsElement['file_name_add'] ?? ('_'.($index+1))) { - // CHANGED 2021-04-30: we now fallback to an empty string as base filename - // if nothing provided. - $tagsElement['file_name'] = ($tagsElement['file_name'] ?? '') . $addendum; - } + $resultObjects = []; + foreach ($this->filesCreated as $index => $path) { + $tagsChunk = $tagsChunks[$index] ?? null; + + if ($tagsChunk) { + foreach ($tagsChunk as &$tagsElement) { + // force csv extension in tag + $tagsElement['file_extension'] = 'csv'; + + if (count($tagsChunks) > 1) { + // override filename with chunk number + if ($addendum = $tagsElement['file_name_add'] ?? ('_' . ($index + 1))) { + // CHANGED 2021-04-30: we now fall back to an empty string as base filename + // if nothing provided. + $tagsElement['file_name'] = ($tagsElement['file_name'] ?? '') . $addendum; + } + } + } + $resultObjects[] = new tagged($path, $tagsChunk); + } else { + $resultObjects[] = new fileabsolute($path); + } } - } - $resultObjects[] = new \codename\core\io\value\text\fileabsolute\tagged($path, $tagsChunk); - } else { - $resultObjects[] = new \codename\core\value\text\fileabsolute($path); - } - } - $this->fileResults = $resultObjects; - } - } - - /** - * @inheritDoc - */ - protected function internalStoreBufferedData($handle, $bufferArray, $append = false) - { - $keys = null; - if($this->numericIndexes) { - $keys = []; - $indexCheck = $this->numericIndexStart; - - $sortedMapping = $this->getMapping(); - ksort($sortedMapping); - - // - // Check index integrity first - // Indexes have to be serial - // 0, 1, 2, 3, ... - // - foreach($sortedMapping as $index => $map) { - if($index == $indexCheck) { - $indexCheck++; - } else { - throw new exception('EXCEPTION_CORE_IO_TARGET_NUMERIC_INDEX_INVALID', exception::$ERRORLEVEL_ERROR, [ - 'index' => $indexCheck - ]); + $this->fileResults = $resultObjects; } - } - - // - // Get the real mappings - // - foreach($this->getMapping() as $index => $map) { - $keys[] = $map['column']; - } - } else { - $keys = array_keys($this->getMapping()); } - // - // If appending, do not write BOM or headers - // otherwise, we writeout this stuff, if configured to do so. - // - if(!$append) { - // - // We're relying on the fact - // we're using UTF-8 for almost everything - // in our system. - // - if($this->encoding === 'UTF-8') { - if($this->encodingUtf8BOM) { - // - // write a UTF-8 BOM - // - fwrite($handle, self::UTF8_BOM); - } - } else if($this->encoding) { - if(!in_array($this->encoding, [ 'UTF-8', 'ISO-8859-1', 'ASCII', 'Windows-1252' ])) { - // change encoding? - throw new exception('EXCEPTION_TARGET_BUFFERED_FILE_CSV_UNSUPPORTED_REENCODE', exception::$ERRORLEVEL_ERROR, $this->encoding); - } - } + /** + * @param resource $handle + * @param array $bufferArray + * @param bool $append + * @return void + * @throws exception + */ + protected function internalStoreBufferedData($handle, array $bufferArray, bool $append = false): void + { + if ($this->numericIndexes) { + $keys = []; + $indexCheck = $this->numericIndexStart; + + $sortedMapping = $this->getMapping(); + ksort($sortedMapping); + + // + // Check index integrity first + // Indexes have to be serial + // 0, 1, 2, 3, ... + // + foreach ($sortedMapping as $index => $map) { + if ($index == $indexCheck) { + $indexCheck++; + } else { + throw new exception('EXCEPTION_CORE_IO_TARGET_NUMERIC_INDEX_INVALID', exception::$ERRORLEVEL_ERROR, [ + 'index' => $indexCheck, + ]); + } + } - $headings = $keys; - if($this->encoding) { - foreach($headings as &$str) { - $str = mb_convert_encoding($str, $this->encoding, 'UTF-8'); + // + // Get the real mappings + // + foreach ($this->getMapping() as $map) { + $keys[] = $map['column']; + } + } else { + $keys = array_keys($this->getMapping()); } - } - if($this->enclosure === null) { - fputs($handle, implode($this->delimiter, $headings).$this->lineBreak); - } else { - fputcsv($handle, $headings, $this->delimiter, $this->enclosure, $this->escapeChar); - } - } + // + // If appending, do not write BOM or headers + // otherwise, we writeout this stuff, if configured to do so. + // + if (!$append) { + // + // We're relying on the fact + // we're using UTF-8 for almost everything + // in our system. + // + if ($this->encoding === 'UTF-8') { + if ($this->encodingUtf8BOM) { + // + // write a UTF-8 BOM + // + fwrite($handle, self::UTF8_BOM); + } + } elseif ($this->encoding) { + if (!in_array($this->encoding, ['UTF-8', 'ISO-8859-1', 'ASCII', 'Windows-1252'])) { + // change encoding? + throw new exception('EXCEPTION_TARGET_BUFFERED_FILE_CSV_UNSUPPORTED_REENCODE', exception::$ERRORLEVEL_ERROR, $this->encoding); + } + } - if($this->numericIndexes) { - foreach($bufferArray as $buffered) { - $dataset = array_values($buffered); - if($this->encoding) { - foreach($dataset as &$str) { - $str = mb_convert_encoding($str, $this->encoding, 'UTF-8'); - } - } - if($this->enclosure === null) { - fputs($handle, implode($this->delimiter, $dataset).$this->lineBreak); - } else { - fputcsv($handle, $dataset, $this->delimiter, $this->enclosure, $this->escapeChar); - } - } - } else { - foreach($bufferArray as $buffered) { - // linearize assoc array for CSV usage - $dataset = []; - foreach($keys as $k) { - $dataset[] = $buffered[$k]; + $headings = $keys; + if ($this->encoding) { + foreach ($headings as &$str) { + $str = mb_convert_encoding($str, $this->encoding, 'UTF-8'); + } + } + if ($this->enclosure === null) { + fputs($handle, implode($this->delimiter, $headings) . $this->lineBreak); + } else { + fputcsv($handle, $headings, $this->delimiter, $this->enclosure, $this->escapeChar); + } } - if($this->encoding) { - foreach($dataset as &$str) { - $str = mb_convert_encoding($str, $this->encoding, 'UTF-8'); - } - } - if($this->enclosure === null) { - fputs($handle, implode($this->delimiter, $dataset).$this->lineBreak); + if ($this->numericIndexes) { + foreach ($bufferArray as $buffered) { + $dataset = array_values($buffered); + if ($this->encoding) { + foreach ($dataset as &$str) { + $str = mb_convert_encoding($str, $this->encoding, 'UTF-8'); + } + } + if ($this->enclosure === null) { + fputs($handle, implode($this->delimiter, $dataset) . $this->lineBreak); + } else { + fputcsv($handle, $dataset, $this->delimiter, $this->enclosure, $this->escapeChar); + } + } } else { - fputcsv($handle, $dataset, $this->delimiter, $this->enclosure, $this->escapeChar); + foreach ($bufferArray as $buffered) { + // linearize assoc array for CSV usage + $dataset = []; + foreach ($keys as $k) { + $dataset[] = $buffered[$k] ?? null; + } + + if ($this->encoding) { + foreach ($dataset as &$str) { + $str = mb_convert_encoding($str, $this->encoding, 'UTF-8'); + } + } + + if ($this->enclosure === null) { + fputs($handle, implode($this->delimiter, $dataset) . $this->lineBreak); + } else { + fputcsv($handle, $dataset, $this->delimiter, $this->enclosure, $this->escapeChar); + } + } } - } - } - // - // WARNING: do not close file handle here. - // CHANGED 2021-08-18: moved to storeBufferedData, for appending data. - // fclose($handle); - } + // + // WARNING: do not close file handle here. + // CHANGED 2021-08-18: moved to storeBufferedData, for appending data. + // fclose($handle); + } } diff --git a/backend/class/target/buffered/file/json.php b/backend/class/target/buffered/file/json.php index c1e8ab5..8dfec68 100644 --- a/backend/class/target/buffered/file/json.php +++ b/backend/class/target/buffered/file/json.php @@ -1,146 +1,156 @@ encoding = $this->config['encoding'] ?? $this->encoding; - $this->template = $this->config['template'] ?? null; - $this->templateElementsPath = $this->config['template_elements_path'] ?? null; - $this->splitCount = $config['split_count'] ?? null; - - } - - /** - * @inheritDoc - */ - protected function storeBufferedData() - { - // split the array - - $dataChunks = []; - $tagsChunks = []; - - if($this->splitCount && (count($this->bufferArray) > $this->splitCount)) { - // we have to split at least one time - $dataChunks = array_chunk($this->bufferArray, $this->splitCount); - $tagsChunks = array_chunk($this->tagsArray, $this->splitCount); - - } else { - $dataChunks = [ $this->bufferArray ]; - $tagsChunks = [ $this->tagsArray ]; +class json extends file +{ + /** + * [protected description] + * @var string|null [type] + */ + protected ?string $encoding = null; + + /** + * count after which we begin a new file + * @var null|int + */ + protected ?int $splitCount = null; + /** + * @var mixed|null + */ + private mixed $template; + /** + * @var mixed|null + */ + private mixed $templateElementsPath; + + /** + * [__construct description] + * @param string $name [description] + * @param array $config [description] + */ + public function __construct(string $name, array $config) + { + parent::__construct($name, $config); + $this->encoding = $this->config['encoding'] ?? $this->encoding; + $this->template = $this->config['template'] ?? null; + $this->templateElementsPath = $this->config['template_elements_path'] ?? null; + $this->splitCount = $config['split_count'] ?? null; } - $resultObjects = []; - - foreach ($dataChunks as $index => $dataChunk) { - - // skip empty chunks - if(count($dataChunk) === 0) { - continue; - } - - $tagsChunk = $tagsChunks[$index]; - - // create a new file handle? - $handle = null; - - $path = $this->getNewFilePath(); - $handle = $this->getNewFileHandle($path); - - $this->internalStoreBufferedData($handle, $dataChunk); - - if(!$tagsChunk) { - // fill with empty array, if not set - $tagsChunk = array_fill(0, count($dataChunk), []); - } - foreach($tagsChunk as &$tagsElement) { - // force csv extension in tag - $tagsElement['file_extension'] = 'json'; + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function storeBufferedData(): void + { + // split the array + + if ($this->splitCount && (count($this->bufferArray) > $this->splitCount)) { + // we have to split at least one time + $dataChunks = array_chunk($this->bufferArray, $this->splitCount); + $tagsChunks = array_chunk($this->tagsArray, $this->splitCount); + } else { + $dataChunks = [$this->bufferArray]; + $tagsChunks = [$this->tagsArray]; + } - if(count($dataChunks) > 1) { - // override filename with chunk number - if($addendum = $tagsElement['file_name_add'] ?? ('_'.($index+1))) { - $tagsElement['file_name'] .= $addendum; - } + $resultObjects = []; + + foreach ($dataChunks as $index => $dataChunk) { + // skip empty chunks + if (count($dataChunk) === 0) { + continue; + } + + $tagsChunk = $tagsChunks[$index]; + + // create a new file handle? + $handle = null; + + $path = $this->getNewFilePath(); + $handle = $this->getNewFileHandle($path); + + $this->internalStoreBufferedData($handle, $dataChunk); + + if (!$tagsChunk) { + // fill with empty array, if not set + $tagsChunk = array_fill(0, count($dataChunk), []); + } + foreach ($tagsChunk as &$tagsElement) { + // force csv extension in tag + $tagsElement['file_extension'] = 'json'; + + if (count($dataChunks) > 1) { + // override filename with chunk number + if ($addendum = $tagsElement['file_name_add'] ?? ('_' . ($index + 1))) { + $tagsElement['file_name'] .= $addendum; + } + } + } + + if ($tagsChunk) { + $resultObjects[] = new tagged($path, $tagsChunk); + } else { + $resultObjects[] = new fileabsolute($path); + } } - } - if($tagsChunk) { - $resultObjects[] = new \codename\core\io\value\text\fileabsolute\tagged($path, $tagsChunk); - } else { - $resultObjects[] = new \codename\core\value\text\fileabsolute($path, $tagsChunk); - } + $this->fileResults = $resultObjects; } - $this->fileResults = $resultObjects; - } - - /** - * @inheritDoc - */ - protected function internalStoreBufferedData($handle, $bufferArray) - { - $elements = []; - foreach($bufferArray as $bufferEntry) { - - $resultData = []; - - // pre-work some mapping options - foreach($this->config['mapping'] as $mapName => $mapConfig) { - if($mapConfig['path'] ?? false) { - // path is relative base for the map name - $objPath = array_merge($mapConfig['path'], [$mapName]); - $resultData = \codename\core\io\helper\deepaccess::set($resultData, $objPath, $bufferEntry[$mapName]); - } else { - $resultData[$mapName] = $bufferEntry[$mapName]; + /** + * @param $handle + * @param $bufferArray + * @return void + */ + protected function internalStoreBufferedData($handle, $bufferArray): void + { + $elements = []; + foreach ($bufferArray as $bufferEntry) { + $resultData = []; + + // pre-work some mapping options + foreach ($this->config['mapping'] as $mapName => $mapConfig) { + if ($mapConfig['path'] ?? false) { + // path is relative base for the map name + $objPath = array_merge($mapConfig['path'], [$mapName]); + $resultData = deepaccess::set($resultData, $objPath, $bufferEntry[$mapName]); + } else { + $resultData[$mapName] = $bufferEntry[$mapName] ?? null; + } + } + + $elements[] = $resultData; } - } - - $elements[] = $resultData; - } - $data = []; + $data = []; - // NOTE: no elements path results in overridden final data - if($this->template) { - $data = $this->template; - } - if($this->templateElementsPath) { - $data = \codename\core\io\helper\deepaccess::set($data, $this->templateElementsPath, $elements); - } else { - $data = $elements; // we could replace? - } + // NOTE: no elements path results in overridden final data + if ($this->template ?? false) { + $data = $this->template; + } + if ($this->templateElementsPath ?? false) { + $data = deepaccess::set($data, $this->templateElementsPath, $elements); + } else { + $data = $elements; // we could replace? + } - if($this->splitCount && count($data) === 1) { - $dataKeys = array_keys($data); - fwrite($handle, json_encode($data[$dataKeys[0]])); - } else { - fwrite($handle, json_encode($data)); + if ($this->splitCount && count($data) === 1) { + $dataKeys = array_keys($data); + fwrite($handle, json_encode($data[$dataKeys[0]])); + } else { + fwrite($handle, json_encode($data)); + } + fclose($handle); } - fclose($handle); - } - - } diff --git a/backend/class/target/buffered/file/parquet.php b/backend/class/target/buffered/file/parquet.php index 3541107..0a425ef 100644 --- a/backend/class/target/buffered/file/parquet.php +++ b/backend/class/target/buffered/file/parquet.php @@ -1,456 +1,295 @@ bufferEnabled = $config['buffer'] ?? false; - $this->bufferSize = $config['buffer_size'] ?? null; - - if($c = $config['compression'] ?? null) { - switch($c) { - case 'none': - $this->compression = CompressionMethod::None; - break; - case 'gzip': - $this->compression = CompressionMethod::Gzip; - break; - case 'snappy': - $this->compression = CompressionMethod::Snappy; - break; - default: - throw new \Exception('Invalid compression method'); - } + /** + * [protected description] + * @var null|int + */ + protected ?int $compression = null; + /** + * [protected description] + * @var bool + */ + protected bool $bufferEnabled = true; + /** + * [protected description] + * @var int + */ + protected $bufferSize = null; + /** + * [protected description] + * @var null|string + */ + protected ?string $currentFilePath = null; + /** + * [protected description] + * @var resource + */ + protected $currentFileHandle = null; + /** + * current ParquetWriter instance + * @var null|ParquetWriter + */ + protected ?ParquetWriter $parquetWriter = null; + + /** + * {@inheritDoc} + * @param string $name + * @param array $config + * @throws \Exception + */ + public function __construct(string $name, array $config) + { + parent::__construct($name, $config); + + $this->bufferEnabled = $config['buffer'] ?? false; + $this->bufferSize = $config['buffer_size'] ?? null; + + if ($c = $config['compression'] ?? null) { + $this->compression = match ($c) { + 'none' => CompressionMethod::None, + 'gzip' => CompressionMethod::Gzip, + 'snappy' => CompressionMethod::Snappy, + default => throw new \Exception('Invalid compression method'), + }; + } } - } - - /** - * [protected description] - * @var int - */ - protected $compression = null; - - /** - * [protected description] - * @var bool - */ - protected $bufferEnabled = true; - - /** - * [protected description] - * @var int - */ - protected $bufferSize = null; - - // /** - // * @inheritDoc - // */ - // public function store(array $data, ?array $tags = null): bool - // { - // print_r($data); - // return parent::store($data, $tags); - // } - - /** - * @inheritDoc - */ - public function store(array $data, ?array $tags = null): bool - { - $success = parent::store($data, $tags); - - if($this->bufferEnabled && $this->bufferSize && \count($this->bufferArray) >= $this->bufferSize) { - // immediate write-out and buffer clear - $this->writeData($this->bufferArray); - $this->bufferArray = []; - } + /** + * {@inheritDoc} + * @param array $data + * @param array|null $tags + * @return bool + * @throws ArgumentNullException + * @throws NotSupportedException + * @throws ParquetException + * @throws exception + */ + public function store(array $data, ?array $tags = null): bool + { + $success = parent::store($data, $tags); + + if ($this->bufferEnabled && $this->bufferSize && count($this->bufferArray) >= $this->bufferSize) { + // immediate write-out and buffer clear + $this->writeData($this->bufferArray); + $this->bufferArray = []; + } - return $success && true; - } - - /** - * @inheritDoc - */ - protected function storeBufferedData() - { - - // $tagsChunks = [ $this->tagsArray ]; - - // No splitting allowed for this format. At the moment. - - // $dataChunks = []; - // $tagsChunks = []; - // - // if($this->splitCount && (count($this->bufferArray) > $this->splitCount)) { - // // we have to split at least one time - // $dataChunks = array_chunk($this->bufferArray, $this->splitCount); - // $tagsChunks = array_chunk($this->tagsArray, $this->splitCount); - // - // } else { - // $dataChunks = [ $this->bufferArray ]; - // $tagsChunks = [ $this->tagsArray ]; - // } - - $resultObjects = []; - - // foreach ($dataChunks as $index => $dataChunk) { - // - // // skip empty chunks - // if(count($dataChunk) === 0) { - // continue; - // } - // - // $tagsChunk = $tagsChunks[$index]; - // - // // create a new file handle? - // $handle = null; - // - // $path = $this->getNewFilePath(); - // $handle = $this->getNewFileHandle($path); - // - // $this->internalStoreBufferedData($handle, $dataChunk); - // - // if($tagsChunk) { - // $resultObjects[] = new \codename\core\io\value\text\fileabsolute\tagged($path, $tagsChunk); - // } else { - // $resultObjects[] = new \codename\core\value\text\fileabsolute($path, $tagsChunk); - // } - // } - - - // $tagsChunk = $tagsChunks[0]; - - $path = $this->getCurrentFilePath(); - $handle = $this->getCurrentFileHandle(); - - // check for pending writes - if(count($this->bufferArray) > 0) { - $this->writeData($this->bufferArray); + return $success; } - // finish main writer - $writer = $this->getParquetWriter(); - $writer->finish(); - - fclose($handle); + /** + * write a row group/data chunk + * @param array $data [description] + * @return void [type] [description] + * @throws ArgumentNullException + * @throws NotSupportedException + * @throws ParquetException + * @throws exception + */ + protected function writeData(array $data): void + { + $writer = $this->getParquetWriter(); + $rgr = $writer->CreateRowGroup(); + // column-based + foreach ($writer->schema->getDataFields() as $field) { + $column = new DataColumn($field, array_column($data, $field->name)); + $rgr->WriteColumn($column); + } + $rgr->finish(); + } + /** + * [getParquetWriter description] + * @return ParquetWriter [description] + * @throws ParquetException + * @throws ArgumentNullException + * @throws NotSupportedException + * @throws exception + */ + protected function getParquetWriter(): ParquetWriter + { + if ($this->parquetWriter === null) { + // create a new writer instance + $handle = $this->getCurrentFileHandle(); + + + $mapping = $this->getMapping(); + + $fields = []; + + foreach ($mapping as $key => $config) { + $dataField = null; + $isNullable = $config['is_nullable'] ?? false; + + if ($config['php_class'] ?? false) { + if ($config['php_class'] === DateTimeImmutable::class) { + $dataField = DateTimeDataField::create($key, $config['datetime_format'], $config['is_nullable']); + } else { + $dataField = DataField::createFromType($key, $config['php_class']); + } + } elseif ($config['php_type'] ?? false) { + if ($config['php_type'] === 'decimal') { + $dataField = DecimalDataField::create($key, $config['precision'], $config['scale'], false, $config['is_nullable']); + } else { + $dataField = DataField::createFromType($key, $config['php_type']); + } + } else { + // guess by first X values, as long as we have some? + $values = array_column($this->bufferArray, $key); + $typesFound = []; + $classesFound = []; + + foreach ($values as $index => $value) { + // only break out > 100 items, if we have already found ANYTHING + if (count($typesFound) > 0) { + if ($index > 100) { + break; + } + } + + if ($value === null) { + $isNullable = true; + continue; + } + + $type = gettype($value); + $typesFound[] = $type; + if ($type === 'object') { + $classesFound[] = get_class($value); + } + } + + $uniqueTypes = array_values(array_unique($typesFound)); + + if (count($uniqueTypes) > 1) { + // invalid type spec by guessing + throw new exception('NOT UNIQUE TYPES', exception::$ERRORLEVEL_ERROR, $uniqueTypes); + } elseif ($uniqueTypes[0] === 'object') { + // we might have to guess class? + + $uniqueClasses = array_values(array_unique($classesFound)); + if ($uniqueClasses[0] === DateTimeImmutable::class) { + $dataField = DataField::createFromType($key, DateTimeImmutable::class); + } else { + // TODO: check count/other entries + throw new exception('UNSUPPORTED TYPE/CLASS', exception::$ERRORLEVEL_ERROR); + } + } else { + // print_r($uniqueTypes); + + $dataField = DataField::createFromType($key, $uniqueTypes[0]); + } + } + $dataField->hasNulls = $isNullable; + $fields[] = $dataField; + } - // if($tagsChunk) { - // $resultObjects[] = new \codename\core\io\value\text\fileabsolute\tagged($path, $tagsChunk); - // } else { - $resultObjects[] = new \codename\core\value\text\fileabsolute($path); - // } + // create schema + $schema = new Schema($fields); + // TODO: formatOptions + append mode? + $this->parquetWriter = new ParquetWriter($schema, $handle); - $this->fileResults = $resultObjects; - } + // Apply compression method, if defined (!== null, NOTE: there might be (int)0 as value) + if ($this->compression !== null) { + $this->parquetWriter->compressionMethod = $this->compression; + } + } + return $this->parquetWriter; + } - /** - * Gets the current (temporary?) file HANDLE to work on - * or creates a new one - * @return resource - */ - protected function getCurrentFileHandle() { - if($this->currentFileHandle === null) { - $path = $this->getCurrentFilePath(); - $this->currentFileHandle = $this->getNewFileHandle($path); + /** + * Gets the current (temporary?) file HANDLE to work on + * or creates a new one + * @return resource + * @throws exception + */ + protected function getCurrentFileHandle() + { + if ($this->currentFileHandle === null) { + $path = $this->getCurrentFilePath(); + $this->currentFileHandle = $this->getNewFileHandle($path); + } + return $this->currentFileHandle; } - return $this->currentFileHandle; - } - - /** - * Gets the current (temporary?) file path to work on - * or creates/reserves a new one - * @return string [description] - */ - protected function getCurrentFilePath(): string { - if($this->currentFilePath === null) { - $this->currentFilePath = $this->getNewFilePath(); + + /** + * Gets the current (temporary?) file path to work on + * or creates/reserves a new one + * @return string [description] + */ + protected function getCurrentFilePath(): string + { + if ($this->currentFilePath === null) { + $this->currentFilePath = $this->getNewFilePath(); + } + return $this->currentFilePath; } - return $this->currentFilePath; - } - - /** - * [protected description] - * @var string - */ - protected $currentFilePath = null; - - /** - * [protected description] - * @var resource - */ - protected $currentFileHandle = null; - - /** - * [getParquetWriter description] - * @return ParquetWriter [description] - */ - protected function getParquetWriter() : ParquetWriter { - if($this->parquetWriter === null) { - - // create a new writer instance - $handle = $this->getCurrentFileHandle(); - - - $mapping = $this->getMapping(); - - $fields = []; - - foreach($mapping as $key => $config) { - $dataField = null; - $isNullable = $config['is_nullable'] ?? false; - - if($config['php_class'] ?? false) { - if($config['php_class'] === \DateTimeImmutable::class) { - $dataField = DateTimeDataField::create($key, $config['datetime_format'], $config['is_nullable'], false); - } else { - $dataField = DataField::createFromType($key, $config['php_class']); - } - } else if($config['php_type'] ?? false) { - if($config['php_type'] === 'decimal') { - $dataField = DecimalDataField::create($key, $config['precision'], $config['scale'], false, $config['is_nullable']); - } else { - $dataField = DataField::createFromType($key, $config['php_type']); - } - } else { - // guess by first X values, as long as we have some? - $values = array_column($this->bufferArray, $key); - $typesFound = []; - $classesFound = []; - - foreach($values as $index => $value) { - - // only break out > 100 items, if we have already found ANYTHING - if(count($typesFound) > 0) { - if($index > 100) break; - } - if($value === null) { - $isNullable = true; - continue; - } + /** + * {@inheritDoc} + * @throws ArgumentNullException + * @throws NotSupportedException + * @throws ParquetException + * @throws ReflectionException + * @throws exception + */ + protected function storeBufferedData(): void + { + // No splitting allowed for this format. At the moment. + + // $dataChunks = []; + // $tagsChunks = []; + // + // if($this->splitCount && (count($this->bufferArray) > $this->splitCount)) { + // // we have to split at least one time + // $dataChunks = array_chunk($this->bufferArray, $this->splitCount); + // $tagsChunks = array_chunk($this->tagsArray, $this->splitCount); + // + // } else { + // $dataChunks = [ $this->bufferArray ]; + // $tagsChunks = [ $this->tagsArray ]; + // } + + $resultObjects = []; + + $path = $this->getCurrentFilePath(); + $handle = $this->getCurrentFileHandle(); + + // check for pending writes + if (count($this->bufferArray) > 0) { + $this->writeData($this->bufferArray); + } - $type = gettype($value); - $typesFound[] = $type; - if($type === 'object') { - $classesFound[] = get_class($value); - } - } - - $uniqueTypes = array_values(array_unique($typesFound)); - - if(count($uniqueTypes) > 1) { - // invalid type spec by guessing - throw new exception('NOT UNIQUE TYPES', exception::$ERRORLEVEL_ERROR, $uniqueTypes); ; - } else if($uniqueTypes[0] === 'object') { - // we might have to guess class? - - $uniqueClasses = array_values(array_unique($classesFound)); - if($uniqueClasses[0] === \DateTimeImmutable::class) { - $dataField = DataField::createFromType($key, \DateTimeImmutable::class); - } else { - // TODO: check count/other entries - throw new exception('UNSUPPORTED TYPE/CLASS', exception::$ERRORLEVEL_ERROR); ; - } - } else { + // finish main writer + $writer = $this->getParquetWriter(); + $writer->finish(); - // print_r($uniqueTypes); + fclose($handle); - $dataField = DataField::createFromType($key, $uniqueTypes[0]); - } - } - $dataField->hasNulls = $isNullable; - $fields[] = $dataField; - } - - // create schema - $schema = new Schema($fields); - // TODO: formatOptions + append mode? - $this->parquetWriter = new ParquetWriter($schema, $handle); - - // Apply compression method, if defined (!== null, NOTE: there might be (int)0 as value) - if($this->compression !== null) { - $this->parquetWriter->compressionMethod = $this->compression; - } - } - return $this->parquetWriter; - } - - /** - * current ParquetWriter instance - * @var ParquetWriter - */ - protected $parquetWriter = null; - - /** - * write a row group/data chunk - * @param array $data [description] - * @return [type] [description] - */ - protected function writeData(array $data) { - $writer = $this->getParquetWriter(); - $rgr = $writer->CreateRowGroup(); - // column-based - foreach($writer->schema->getDataFields() as $field) { - $column = new DataColumn($field, array_column($data, $field->name)); - $rgr->WriteColumn($column); + $resultObjects[] = new fileabsolute($path); + + $this->fileResults = $resultObjects; } - $rgr->finish(); - } - - - // /** - // * @inheritDoc - // */ - // protected function internalStoreBufferedData($handle, $bufferArray) - // { - // // $mapping = $this->getMapping(); - // // - // // $fields = []; - // // - // // foreach($mapping as $key => $config) { - // // $dataField = null; - // // $isNullable = $config['is_nullable'] ?? false; - // // - // // if($config['php_class'] ?? false) { - // // if($config['php_class'] === \DateTimeImmutable::class) { - // // $dataField = DateTimeDataField::create($key, $config['datetime_format'], $config['is_nullable'], false); - // // } else { - // // $dataField = DataField::createFromType($key, $config['php_class']); - // // } - // // } else if($config['php_type'] ?? false) { - // // if($config['php_type'] === 'decimal') { - // // $dataField = DecimalDataField::create($key, $config['precision'], $config['scale'], false, $config['is_nullable']); - // // } else { - // // $dataField = DataField::createFromType($key, $config['php_type']); - // // } - // // } else { - // // // guess by first X values - // // $values = array_column($bufferArray, $key); - // // $typesFound = []; - // // $classesFound = []; - // // - // // foreach($values as $index => $value) { - // // - // // // only break out > 100 items, if we have already found ANYTHING - // // if(count($typesFound) > 0) { - // // if($index > 100) break; - // // } - // // - // // if($value === null) { - // // $isNullable = true; - // // continue; - // // } - // // - // // $type = gettype($value); - // // $typesFound[] = $type; - // // if($type === 'object') { - // // $classesFound[] = get_class($value); - // // } - // // } - // // - // // $uniqueTypes = array_values(array_unique($typesFound)); - // // - // // if(count($uniqueTypes) > 1) { - // // // invalid type spec by guessing - // // throw new exception('NOT UNIQUE TYPES', exception::$ERRORLEVEL_ERROR, $uniqueTypes); ; - // // } else if($uniqueTypes[0] === 'object') { - // // // we might have to guess class? - // // - // // $uniqueClasses = array_values(array_unique($classesFound)); - // // if($uniqueClasses[0] === \DateTimeImmutable::class) { - // // $dataField = DataField::createFromType($key, \DateTimeImmutable::class); - // // } else { - // // // TODO: check count/other entries - // // throw new exception('UNSUPPORTED TYPE/CLASS', exception::$ERRORLEVEL_ERROR); ; - // // } - // // } else { - // // - // // // print_r($uniqueTypes); - // // - // // $dataField = DataField::createFromType($key, $uniqueTypes[0]); - // // } - // // } - // // $dataField->hasNulls = $isNullable; - // // $fields[] = $dataField; - // // } - // // - // // // create schema - // // $schema = new Schema($fields); - // // // TODO: formatOptions + append mode? - // // $writer = new ParquetWriter($schema, $handle); - // - // // finish writer? - // $writer = $this->getParquetWriter(); - // $rgr = $writer->CreateRowGroup(); - // // column-based - // - // foreach($writer->schema->getDataFields() as $field) { - // $column = new DataColumn($field, array_column($bufferArray, $field->name)); - // $rgr->WriteColumn($column); - // } - // - // $rgr->finish(); - // $writer->finish(); - // - // // foreach($bufferArray as $buffered) { - // // $data = []; - // // foreach ($this->structure as $rowIndex => $rowConfig) { - // // $data[$rowIndex] = []; - // // foreach($rowConfig as $columnIndex => $mappingKey) { - // // // $value = $value === null ? '' : $value; ?? - // // $value = $buffered[$mappingKey]; - // // $length = $mapping[$mappingKey]['length']; - // // // TODO: - // // // please change if there is an official version of php lib - // // // https://bugs.php.net/bug.php?id=21317 - // // $diff = strlen($value) - mb_strlen($value, 'UTF-8'); - // // $value = str_pad($value, $length + $diff, $this->paddingString, $this->paddingMode); - // // if($this->truncate) { - // // $value = mb_substr($value, 0, $length, 'UTF-8'); - // // } else { - // // if(mb_strlen($value, 'UTF-8') > $length) { - // // throw new exception(); - // // } - // // } - // // $data[$rowIndex][$columnIndex] = $value; - // // } - // // // Add line terminator? - // // } - // // - // // $rows = []; - // // foreach($data as $columns) { - // // $rows[] = implode('', $columns); - // // } - // // - // // $entry = implode(chr(10), $rows); - // // - // // // TODO: add line/final terminating CRLF? - // // $entry .= chr(10); - // // - // // if($this->encoding) { - // // $entry = mb_convert_encoding($entry, $this->encoding, 'UTF-8'); - // // } - // // $success = fputs($handle, $entry); - // // } - // - // fclose($handle); - // } } diff --git a/backend/class/target/buffered/file/raw.php b/backend/class/target/buffered/file/raw.php index 6be2ad4..f0e203f 100644 --- a/backend/class/target/buffered/file/raw.php +++ b/backend/class/target/buffered/file/raw.php @@ -1,185 +1,189 @@ paddingString = $config['padding_string']; - $this->truncate = $config['truncate']; - $this->encoding = $config['encoding'] ?? null; - - if($config['padding_mode'] == 'left') { - $this->paddingMode = STR_PAD_LEFT; - } else if($config['padding_mode'] == 'right') { - $this->paddingMode = STR_PAD_RIGHT; - } else { - // ERROR - throw new exception('EXCEPTION_TARGET_BUFFERED_FILE_RAW_PADDING_MODE_NOT_SUPPORTED', exception::$ERRORLEVEL_ERROR); - } +class raw extends file +{ + /** + * determines if the raw exporter uses a multiline per entry + * @var bool + */ + protected bool $multiline = false; + + /** + * structure helper + * @var array + */ + protected array $structure = []; + + /** + * padding string to be used + * @var string + */ + protected mixed $paddingString = ''; + + /** + * padding mode to be used (left or right) + * @var string|int + */ + protected string|int $paddingMode = STR_PAD_RIGHT; + + /** + * true: auto-truncate too long values + * false: throw an error on overflow + * @var bool + */ + protected bool $truncate = false; + + /** + * output encoding to use + * @var null|string + */ + protected ?string $encoding = 'ASCII'; + + /** + * count after which we begin a new file + * @var null|int + */ + protected ?int $splitCount = null; + + /** + * {@inheritDoc} + * @param string $name + * @param array $config + * @throws exception + */ + public function __construct(string $name, array $config) + { + parent::__construct($name, $config); + + $this->paddingString = $config['padding_string']; + $this->truncate = $config['truncate'] ?? $this->truncate; + $this->encoding = $config['encoding'] ?? null; + + if ($config['padding_mode'] == 'left') { + $this->paddingMode = STR_PAD_LEFT; + } elseif ($config['padding_mode'] == 'right') { + $this->paddingMode = STR_PAD_RIGHT; + } else { + // ERROR + throw new exception('EXCEPTION_TARGET_BUFFERED_FILE_RAW_PADDING_MODE_NOT_SUPPORTED', exception::$ERRORLEVEL_ERROR); + } - $mapping = $this->getMapping(); + $mapping = $this->getMapping(); + + foreach ($mapping as $index => $map) { + $this->structure[$map['rowIndex']][$map['columnIndex']] = $index; + } - foreach($mapping as $index => $map) { - $this->structure[$map['rowIndex']][$map['columnIndex']] = $index; + $this->splitCount = $config['split_count'] ?? null; } - $this->splitCount = $config['split_count'] ?? null; - } + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function storeBufferedData(): void + { + // split the array + if ($this->splitCount && (count($this->bufferArray) > $this->splitCount)) { + // we have to split at least one time + $dataChunks = array_chunk($this->bufferArray, $this->splitCount); + $tagsChunks = array_chunk($this->tagsArray, $this->splitCount); + } else { + $dataChunks = [$this->bufferArray]; + $tagsChunks = [$this->tagsArray]; + } - /** - * @inheritDoc - */ - protected function storeBufferedData() - { - // split the array + $resultObjects = []; - $dataChunks = []; - $tagsChunks = []; + foreach ($dataChunks as $index => $dataChunk) { + // skip empty chunks + if (count($dataChunk) === 0) { + continue; + } - if($this->splitCount && (count($this->bufferArray) > $this->splitCount)) { - // we have to split at least one time - $dataChunks = array_chunk($this->bufferArray, $this->splitCount); - $tagsChunks = array_chunk($this->tagsArray, $this->splitCount); + $tagsChunk = $tagsChunks[$index]; - } else { - $dataChunks = [ $this->bufferArray ]; - $tagsChunks = [ $this->tagsArray ]; - } + // create a new file handle? + $handle = null; - $resultObjects = []; + $path = $this->getNewFilePath(); + $handle = $this->getNewFileHandle($path); - foreach ($dataChunks as $index => $dataChunk) { + $this->internalStoreBufferedData($handle, $dataChunk); - // skip empty chunks - if(count($dataChunk) === 0) { - continue; - } + if ($tagsChunk) { + $resultObjects[] = new tagged($path, $tagsChunk); + } else { + $resultObjects[] = new fileabsolute($path); + } + } - $tagsChunk = $tagsChunks[$index]; + $this->fileResults = $resultObjects; + } - // create a new file handle? - $handle = null; + /** + * @param $handle + * @param $bufferArray + * @return void + * @throws exception + */ + protected function internalStoreBufferedData($handle, $bufferArray): void + { + // $handle = $this->getFileHandle(); + + $mapping = $this->getMapping(); + + foreach ($bufferArray as $buffered) { + $data = []; + foreach ($this->structure as $rowIndex => $rowConfig) { + $data[$rowIndex] = []; + foreach ($rowConfig as $columnIndex => $mappingKey) { + // $value = $value === null ? '' : $value; ?? + $value = $buffered[$mappingKey] ?? ''; + $length = $mapping[$mappingKey]['length'] ?? 0; + // TODO: + // please change if there is an official version of php lib + // https://bugs.php.net/bug.php?id=21317 + $diff = strlen($value) - mb_strlen($value, 'UTF-8'); + $value = str_pad($value, $length + $diff, $this->paddingString, $this->paddingMode); + if ($this->truncate) { + $value = mb_substr($value, 0, $length, 'UTF-8'); + } elseif (mb_strlen($value, 'UTF-8') > $length) { + throw new exception('EXCEPTION_TARGET_BUFFERED_FILE_RAW_VALUE_TOO_LONG', exception::$ERRORLEVEL_ERROR, $value); + } + $data[$rowIndex][$columnIndex] = $value; + } + // Add line terminator? + } - $path = $this->getNewFilePath(); - $handle = $this->getNewFileHandle($path); + $rows = []; + foreach ($data as $columns) { + $rows[] = implode('', $columns); + } - $this->internalStoreBufferedData($handle, $dataChunk); + $entry = implode(chr(10), $rows); - if($tagsChunk) { - $resultObjects[] = new \codename\core\io\value\text\fileabsolute\tagged($path, $tagsChunk); - } else { - $resultObjects[] = new \codename\core\value\text\fileabsolute($path, $tagsChunk); - } - } + // TODO: add line/final terminating CRLF? + $entry .= chr(10); - $this->fileResults = $resultObjects; - } - - /** - * @inheritDoc - */ - protected function internalStoreBufferedData($handle, $bufferArray) - { - // $handle = $this->getFileHandle(); - - $mapping = $this->getMapping(); - - foreach($bufferArray as $buffered) { - $data = []; - foreach ($this->structure as $rowIndex => $rowConfig) { - $data[$rowIndex] = []; - foreach($rowConfig as $columnIndex => $mappingKey) { - // $value = $value === null ? '' : $value; ?? - $value = $buffered[$mappingKey]; - $length = $mapping[$mappingKey]['length']; - // TODO: - // please change if there is an official version of php lib - // https://bugs.php.net/bug.php?id=21317 - $diff = strlen($value) - mb_strlen($value, 'UTF-8'); - $value = str_pad($value, $length + $diff, $this->paddingString, $this->paddingMode); - if($this->truncate) { - $value = mb_substr($value, 0, $length, 'UTF-8'); - } else { - if(mb_strlen($value, 'UTF-8') > $length) { - throw new exception('EXCEPTION_TARGET_BUFFERED_FILE_RAW_VALUE_TOO_LONG', exception::$ERRORLEVEL_ERROR, $value); + if ($this->encoding) { + $entry = mb_convert_encoding($entry, $this->encoding, 'UTF-8'); } - } - $data[$rowIndex][$columnIndex] = $value; + fputs($handle, $entry); } - // Add line terminator? - } - - $rows = []; - foreach($data as $columns) { - $rows[] = implode('', $columns); - } - $entry = implode(chr(10), $rows); - - // TODO: add line/final terminating CRLF? - $entry .= chr(10); - - if($this->encoding) { - $entry = mb_convert_encoding($entry, $this->encoding, 'UTF-8'); - } - $success = fputs($handle, $entry); + fclose($handle); } - - fclose($handle); - } - } diff --git a/backend/class/target/buffered/file/spreadsheet.php b/backend/class/target/buffered/file/spreadsheet.php index 87597ee..4cdf36b 100644 --- a/backend/class/target/buffered/file/spreadsheet.php +++ b/backend/class/target/buffered/file/spreadsheet.php @@ -1,315 +1,317 @@ value based mappings - * this needs "column" defined per mapping entry - * @var bool - */ - protected $numericIndexes = false; - - /** - * The current environment type configuration does not contain the desired key for the type. - *
May occur when you use multiple mail configurators. - * @var string - */ - CONST EXCEPTION_STOREBUFFERDDATA_COLUMNOTFOUND = 'EXCEPTION_STOREBUFFERDDATA_COLUMNOTFOUND'; - - /** - * @inheritDoc - */ - public function __construct(string $name, array $config) - { - parent::__construct($name, $config); - - $this->use_template_file = $this->config['use_template_file'] ?? null; - if (!is_null($this->use_template_file)) { - $this->filepath = app::getInheritedPath($this->use_template_file); - } +class spreadsheet extends file +{ + /** + * The current environment type configuration does not contain the desired key for the type. + * May occur when you use multiple mail configurators. + * @var string + */ + public const EXCEPTION_STOREBUFFERDDATA_COLUMNOTFOUND = 'EXCEPTION_STOREBUFFERDDATA_COLUMNOTFOUND'; + /** + * [protected description] + * @var string|null [type] + */ + protected ?string $use_template_file = null; + /** + * [protected description] + * @var null|string + */ + protected ?string $filepath = null; + /** + * [protected description] + * @var string|null [type] + */ + protected ?string $use_writer = null; + /** + * [protected description] + * @var [type] + */ + protected mixed $freeze = null; + /** + * [protected description] + * @var [type] + */ + protected mixed $key_row = null; + /** + * [protected description] + * @var int [type] + */ + protected int $start_row = 1; + /** + * [protected description] + * @var int [type] + */ + protected int $sheet = 0; + /** + * use serial columns/numeric indexes + * instead of key => value based mappings + * this needs "column" defined per mapping entry + * @var bool + */ + protected bool $numericIndexes = false; + + /** + * {@inheritDoc} + * @param string $name + * @param array $config + * @throws ReflectionException + * @throws exception + */ + public function __construct(string $name, array $config) + { + parent::__construct($name, $config); + + $this->use_template_file = $this->config['use_template_file'] ?? null; + if (!is_null($this->use_template_file)) { + $this->filepath = app::getInheritedPath($this->use_template_file); + } - $this->use_writer = $this->config['use_writer'] ?? null; - $this->freeze = $this->config['freeze'] ?? null; - $this->key_row = $this->config['key_row'] ?? null; - $this->start_row = $this->config['start_row'] ?? 1; - $this->sheet = $this->config['sheet'] ?? 0; - $this->numericIndexes = $config['numeric_indexes'] ?? false; - } - - /** - * @inheritDoc - */ - protected function storeBufferedData() - { - // split the array - - $dataChunks = []; - $tagsChunks = []; - - if($this->splitCount && (count($this->bufferArray) > $this->splitCount)) { - // we have to split at least one time - $dataChunks = array_chunk($this->bufferArray, $this->splitCount); - $tagsChunks = array_chunk($this->tagsArray, $this->splitCount); - - } else { - $dataChunks = [ $this->bufferArray ]; - $tagsChunks = [ $this->tagsArray ]; + $this->use_writer = $this->config['use_writer'] ?? null; + $this->freeze = $this->config['freeze'] ?? null; + $this->key_row = $this->config['key_row'] ?? null; + $this->start_row = $this->config['start_row'] ?? 1; + $this->sheet = $this->config['sheet'] ?? 0; + $this->numericIndexes = $config['numeric_indexes'] ?? false; } - $resultObjects = []; - - foreach ($dataChunks as $index => $dataChunk) { - - // skip empty chunks - if(count($dataChunk) === 0) { - continue; - } - - $tagsChunk = $tagsChunks[$index]; - - // create a new file handle? - $handle = null; - - $path = $this->getNewFilePath(); - - $this->internalStoreBufferedData($path, $dataChunk, $tagsChunk); - - if(!$tagsChunk) { - // fill with empty array, if not set - $tagsChunk = array_fill(0, count($dataChunk), []); - } - foreach($tagsChunk as &$tagsElement) { - // force csv extension in tag - - $extension = null; - if($this->use_writer == 'Xlsx') { - $extension = 'xlsx'; - } else if($this->use_writer == 'Xls') { - $extension = 'xls'; - } else if($this->use_writer == 'Csv') { - $extension = 'csv'; + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws \PhpOffice\PhpSpreadsheet\Exception + * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception + * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception + * @throws exception + */ + protected function storeBufferedData(): void + { + // split the array + if ($this->splitCount && (count($this->bufferArray) > $this->splitCount)) { + // we have to split at least one time + $dataChunks = array_chunk($this->bufferArray, $this->splitCount); + $tagsChunks = array_chunk($this->tagsArray, $this->splitCount); } else { - throw new exception('INVALID_SPREADSHEET_FILE_FORMAT_SPECIFIED', exception::$ERRORLEVEL_ERROR, $this->use_writer); + $dataChunks = [$this->bufferArray]; + $tagsChunks = [$this->tagsArray]; } - $tagsElement['file_extension'] = $extension; - } - - if($tagsChunk) { - $resultObjects[] = new \codename\core\io\value\text\fileabsolute\tagged($path, $tagsChunk); - } else { - $resultObjects[] = new \codename\core\value\text\fileabsolute($path, $tagsChunk); - } - } - - $this->fileResults = $resultObjects; - } - - /** - * @inheritDoc - */ - protected function internalStoreBufferedData($path, $bufferArray, $tagsChunk = null) - { - // this automatically creates the matching reader for the file. - if ($this->filepath) { - $reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReaderForFile($this->filepath); - $spreadsheet = $reader->load($this->filepath); - } else { - $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet(); - } - $worksheet = $spreadsheet->setActiveSheetIndex($this->sheet); - - if($this->freeze) { - $worksheet->freezePane($this->freeze); - } + $resultObjects = []; + + foreach ($dataChunks as $index => $dataChunk) { + // skip empty chunks + if (count($dataChunk) === 0) { + continue; + } + + $tagsChunk = $tagsChunks[$index]; + + $path = $this->getNewFilePath(); + + $this->internalStoreBufferedData($path, $dataChunk, $tagsChunk); + + if (!$tagsChunk) { + // fill with empty array, if not set + $tagsChunk = array_fill(0, count($dataChunk), []); + } + foreach ($tagsChunk as &$tagsElement) { + // force csv extension in tag + + if ($this->use_writer == 'Xlsx') { + $extension = 'xlsx'; + } elseif ($this->use_writer == 'Xls') { + $extension = 'xls'; + } elseif ($this->use_writer == 'Csv') { + $extension = 'csv'; + } else { + throw new exception('INVALID_SPREADSHEET_FILE_FORMAT_SPECIFIED', exception::$ERRORLEVEL_ERROR, $this->use_writer); + } + + $tagsElement['file_extension'] = $extension; + } + + if ($tagsChunk) { + $resultObjects[] = new tagged($path, $tagsChunk); + } else { + $resultObjects[] = new fileabsolute($path); + } + } - $mapping = $this->getMapping(); - $columnIndexMap = []; - - // Excel Column Index starts at 1, not 0 - $columnIndex = 1; - - foreach ($mapping as $k => $v) { - if (isset($mapping[$k]['row'])) { continue; } - // if (empty($mapping[$k]['column'])) { - // throw new \codename\core\exception(self::EXCEPTION_STOREBUFFERDDATA_COLUMNOTFOUND, \codename\core\exception::$ERRORLEVEL_FATAL); - // } - - if(!empty($mapping[$k]['column'])) { - // explicitly specified column - $columnIndexMap[$k] = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::columnIndexFromString($mapping[$k]['column']); - } else { - // fallback to linear column index - $columnIndexMap[$k] = $columnIndex; - } - - // produce a heading, if key_row is set to a value - if ($this->key_row) { - $worksheet->setCellValueByColumnAndRow( - $columnIndexMap[$k], - $this->key_row, - ($this->numericIndexes ? ($mapping[$k]['columnName'] ?? $k) : $k) - ); - } - - $columnIndex++; + $this->fileResults = $resultObjects; } - // if start_row is set, increase this index by 1 - // and start to fill data - $currentRow = $this->start_row + 1; - - foreach($bufferArray as $line) { - foreach($line as $k => $v) { - // if (empty($mapping[$k]['column'])) { - // throw new \codename\core\exception(self::EXCEPTION_STOREBUFFERDDATA_COLUMNOTFOUND, \codename\core\exception::$ERRORLEVEL_FATAL); - // } - if($mapping[$k]['setExplicitString'] ?? false) { - $worksheet->setCellValueExplicitByColumnAndRow( - $columnIndexMap[$k], - ($mapping[$k]['row'] ?? $currentRow), - $v, - \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING - ); + /** + * @param $path + * @param $bufferArray + * @param $tagsChunk + * @return void + * @throws \PhpOffice\PhpSpreadsheet\Exception + * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception + * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception + */ + protected function internalStoreBufferedData($path, $bufferArray, $tagsChunk = null): void + { + // this automatically creates the matching reader for the file. + if ($this->filepath) { + $reader = IOFactory::createReaderForFile($this->filepath); + $spreadsheet = $reader->load($this->filepath); } else { - $worksheet->setCellValueByColumnAndRow( - $columnIndexMap[$k], - ($mapping[$k]['row'] ?? $currentRow), - $v - ); + $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet(); } + $worksheet = $spreadsheet->setActiveSheetIndex($this->sheet); - if($mapping[$k]['formatCode'] ?? false) { - $worksheet - ->getStyleByColumnAndRow( - $columnIndexMap[$k], - ($mapping[$k]['row'] ?? $currentRow) - ) - ->getNumberFormat() - ->setFormatCode($mapping[$k]['formatCode']); + if ($this->freeze ?? false) { + $worksheet->freezePane($this->freeze); } - } - $currentRow++; - } - if($tagsChunk) { - $filePassword = $tagsChunk[0]['file_password'] ?? null; - if($filePassword) { - - $spreadsheet->getSecurity() - ->setLockWindows(true) - ->setLockStructure(true) - ->setWorkbookPassword($filePassword); - - // Protect sheet - $sheetNames = $spreadsheet->getSheetNames(); - foreach($sheetNames as $k => $sheetName) { - $sheet = $spreadsheet->getSheet($k); - $protection = $sheet->getProtection(); - - $protection->setPassword($filePassword); - $protection->setSheet(true); - $protection->setSort(true); - $protection->setInsertRows(true); - $protection->setFormatCells(true); + $mapping = $this->getMapping(); + $columnIndexMap = []; + + // Excel Column Index starts at 1, not 0 + $columnIndex = 1; + + foreach ($mapping as $k => $v) { + if (isset($v['row'])) { + continue; + } + + if (!empty($v['column'])) { + // explicitly specified column + $columnIndexMap[$k] = Coordinate::columnIndexFromString($v['column']); + } else { + // fallback to linear column index + $columnIndexMap[$k] = $columnIndex; + } + + // produce a heading, if key_row is set to a value + if ($this->key_row) { + $worksheet->setCellValue( + [ + $columnIndexMap[$k], + $this->key_row, + ], + ($this->numericIndexes ? ($v['columnName'] ?? $k) : $k) + ); + } + + $columnIndex++; } - } - } - // $targetFilePath = $this->targetFilePath; - // if(!$this->targetFilePath) { - // } - // $targetFilePath = tempnam(sys_get_temp_dir(), '_ma_'); - $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet,$this->use_writer); - - // save original state of those settings - $prevDecimalSeparator = null; - $prevThousandsSeparator = null; - - if($writer instanceof \PhpOffice\PhpSpreadsheet\Writer\Csv) { - $writer->setUseBOM($this->config['encoding_utf8bom'] ?? false); - if($val = $this->config['config']['decimal_separator'] ?? '.') { - // NOTE: this may cause trouble, as it is called globally, so we have to save state and re-set later - $prevDecimalSeparator = \PhpOffice\PhpSpreadsheet\Shared\StringHelper::getDecimalSeparator(); - \PhpOffice\PhpSpreadsheet\Shared\StringHelper::setDecimalSeparator($val); - } - if($val = $this->config['config']['thousands_separator'] ?? '') { - // NOTE: this may cause trouble, as it is called globally, so we have to save state and re-set later - $prevThousandsSeparator = \PhpOffice\PhpSpreadsheet\Shared\StringHelper::getThousandsSeparator(); - \PhpOffice\PhpSpreadsheet\Shared\StringHelper::setThousandsSeparator($val); - } - if($val = $this->config['config']['delimiter'] ?? ';') { - $writer->setDelimiter($val); - } - if(array_key_exists('enclosure', $this->config['config'])) { - $writer->setEnclosure($this->config['config']['enclosure']); - } - if($val = $this->config['config']['line_ending'] ?? "\r\n") { - $writer->setLineEnding($val); - } - if($val = $this->config['config']['sheet_index'] ?? 0) { - $writer->setSheetIndex($val); // pure optional... sheet index from reader? - } - } + // if start_row is set, increase this index by 1 + // and start to fill data + $currentRow = $this->start_row + 1; + + foreach ($bufferArray as $line) { + foreach ($line as $k => $v) { + if ($mapping[$k]['setExplicitString'] ?? false) { + $worksheet->setCellValueExplicit( + [ + $columnIndexMap[$k] ?? null, + ($mapping[$k]['row'] ?? $currentRow), + ], + $v, + DataType::TYPE_STRING + ); + } else { + $worksheet->setCellValue( + [ + $columnIndexMap[$k] ?? null, + ($mapping[$k]['row'] ?? $currentRow), + ], + $v + ); + } + + if ($mapping[$k]['formatCode'] ?? false) { + $worksheet + ->getStyle([ + $columnIndexMap[$k] ?? null, + ($mapping[$k]['row'] ?? $currentRow), + ]) + ->getNumberFormat() + ->setFormatCode($mapping[$k]['formatCode']); + } + } + $currentRow++; + } - $writer->save($path); + if ($tagsChunk) { + $filePassword = $tagsChunk[0]['file_password'] ?? null; + if ($filePassword) { + $spreadsheet->getSecurity() + ->setLockWindows(true) + ->setLockStructure(true) + ->setWorkbookPassword($filePassword); + + // Protect sheet + $sheetNames = $spreadsheet->getSheetNames(); + foreach ($sheetNames as $k => $sheetName) { + $sheet = $spreadsheet->getSheet($k); + $protection = $sheet->getProtection(); + + $protection->setPassword($filePassword); + $protection->setSheet(true); + $protection->setSort(true); + $protection->setInsertRows(true); + $protection->setFormatCells(true); + } + } + } + $writer = IOFactory::createWriter($spreadsheet, $this->use_writer); + + // save original state of those settings + $prevDecimalSeparator = null; + $prevThousandsSeparator = null; + + if ($writer instanceof \PhpOffice\PhpSpreadsheet\Writer\Csv) { + $writer->setUseBOM($this->config['encoding_utf8bom'] ?? false); + if ($val = $this->config['config']['decimal_separator'] ?? '.') { + // NOTE: this may cause trouble, as it is called globally, so we have to save state and re-set later + $prevDecimalSeparator = StringHelper::getDecimalSeparator(); + StringHelper::setDecimalSeparator($val); + } + if ($val = $this->config['config']['thousands_separator'] ?? '') { + // NOTE: this may cause trouble, as it is called globally, so we have to save state and re-set later + $prevThousandsSeparator = StringHelper::getThousandsSeparator(); + StringHelper::setThousandsSeparator($val); + } + if ($val = $this->config['config']['delimiter'] ?? ';') { + $writer->setDelimiter($val); + } + if (array_key_exists('enclosure', $this->config['config'])) { + $writer->setEnclosure($this->config['config']['enclosure'] ?? ''); + } + if ($val = $this->config['config']['line_ending'] ?? "\r\n") { + $writer->setLineEnding($val); + } + if ($val = $this->config['config']['sheet_index'] ?? 0) { + $writer->setSheetIndex($val); // pure optional... sheet index from reader? + } + } - // restore previous states of those settings, if changed in-between - if($prevDecimalSeparator) { - \PhpOffice\PhpSpreadsheet\Shared\StringHelper::setDecimalSeparator($prevDecimalSeparator); - } - if($prevThousandsSeparator) { - \PhpOffice\PhpSpreadsheet\Shared\StringHelper::setThousandsSeparator($prevThousandsSeparator); + $writer->save($path); + + // restore previous states of those settings, if changed in-between + if ($prevDecimalSeparator) { + StringHelper::setDecimalSeparator($prevDecimalSeparator); + } + if ($prevThousandsSeparator) { + StringHelper::setThousandsSeparator($prevThousandsSeparator); + } } - } } diff --git a/backend/class/target/buffered/file/xml.php b/backend/class/target/buffered/file/xml.php index 907f1ad..92baa70 100644 --- a/backend/class/target/buffered/file/xml.php +++ b/backend/class/target/buffered/file/xml.php @@ -1,188 +1,195 @@ xmlService = new \Sabre\Xml\Service(); - $this->version = $this->config['version'] ?? $this->version; - $this->encoding = $this->config['encoding'] ?? $this->encoding; - $this->template = $this->config['template'] ?? null; - $this->templateElementsPath = $this->config['template_elements_path'] ?? null; - - } - - /** - * @inheritDoc - */ - protected function storeBufferedData() - { - // split the array - - $dataChunks = []; - $tagsChunks = []; - - if($this->splitCount && (count($this->bufferArray) > $this->splitCount)) { - // we have to split at least one time - $dataChunks = array_chunk($this->bufferArray, $this->splitCount); - $tagsChunks = array_chunk($this->tagsArray, $this->splitCount); - - } else { - $dataChunks = [ $this->bufferArray ]; - $tagsChunks = [ $this->tagsArray ]; - } - - $resultObjects = []; - - foreach ($dataChunks as $index => $dataChunk) { - - // skip empty chunks - if(count($dataChunk) === 0) { - continue; - } - - $tagsChunk = $tagsChunks[$index]; - - // create a new file handle? - $handle = null; - - $path = $this->getNewFilePath(); - $handle = $this->getNewFileHandle($path); - - $this->internalStoreBufferedData($handle, $dataChunk); - - if(!$tagsChunk) { - // fill with empty array, if not set - $tagsChunk = array_fill(0, count($dataChunk), []); - } - foreach($tagsChunk as &$tagsElement) { - // force csv extension in tag - $tagsElement['file_extension'] = 'xml'; - - if(count($dataChunks) > 1) { - // override filename with chunk number - if($addendum = $tagsElement['file_name_add'] ?? ('_'.($index+1))) { - $tagsElement['file_name'] .= $addendum; - } - } - } - - if($tagsChunk) { - $resultObjects[] = new \codename\core\io\value\text\fileabsolute\tagged($path, $tagsChunk); - } else { - $resultObjects[] = new \codename\core\value\text\fileabsolute($path, $tagsChunk); - } + /** + * [protected description] + * @var Service + */ + protected Service $xmlService; + + /** + * [protected description] + * @var string [type] + */ + protected string $version = '1.0'; + + /** + * [protected description] + * @var string|null [type] + */ + protected ?string $encoding = null; + /** + * @var mixed|null + */ + protected mixed $template; + /** + * @var mixed|null + */ + protected mixed $templateElementsPath; + + /** + * [__construct description] + * @param string $name [description] + * @param array $config [description] + */ + public function __construct(string $name, array $config) + { + parent::__construct($name, $config); + $this->xmlService = new Service(); + $this->version = $this->config['version'] ?? $this->version; + $this->encoding = $this->config['encoding'] ?? $this->encoding; + $this->template = $this->config['template'] ?? null; + $this->templateElementsPath = $this->config['template_elements_path'] ?? null; } - $this->fileResults = $resultObjects; - } - - /** - * @inheritDoc - */ - protected function internalStoreBufferedData($handle, $bufferArray) - { - $writer = new \Sabre\Xml\Writer(); - $writer->openMemory(); - $writer->setIndent(true); - $writer->startDocument($this->version, $this->encoding); - - $elements = []; - foreach($bufferArray as $bufferEntry) { - - $resultData = []; - - // pre-work some mapping options - foreach($this->config['mapping'] as $mapName => $mapConfig) { - if($mapConfig['path'] ?? false) { - // path is relative base for the map name - $objPath = array_merge($mapConfig['path'], [$mapName]); - $resultData = \codename\core\io\helper\deepaccess::set($resultData, $objPath, $bufferEntry[$mapName]); + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function storeBufferedData(): void + { + // split the array + if ($this->splitCount && (count($this->bufferArray) > $this->splitCount)) { + // we have to split at least one time + $dataChunks = array_chunk($this->bufferArray, $this->splitCount); + $tagsChunks = array_chunk($this->tagsArray, $this->splitCount); } else { - $resultData[$mapName] = $bufferEntry[$mapName]; + $dataChunks = [$this->bufferArray]; + $tagsChunks = [$this->tagsArray]; } - } - $elements[] = $resultData; - } - - - $data = []; + $resultObjects = []; + + foreach ($dataChunks as $index => $dataChunk) { + // skip empty chunks + if (count($dataChunk) === 0) { + continue; + } + + $tagsChunk = $tagsChunks[$index]; + + // create a new file handle? + $handle = null; + + $path = $this->getNewFilePath(); + $handle = $this->getNewFileHandle($path); + + $this->internalStoreBufferedData($handle, $dataChunk); + + if (!$tagsChunk) { + // fill with empty array, if not set + $tagsChunk = array_fill(0, count($dataChunk), []); + } + foreach ($tagsChunk as &$tagsElement) { + // force csv extension in tag + $tagsElement['file_extension'] = 'xml'; + + if (count($dataChunks) > 1) { + // override filename with chunk number + if ($addendum = $tagsElement['file_name_add'] ?? ('_' . ($index + 1))) { + $tagsElement['file_name'] .= $addendum; + } + } + } + + if ($tagsChunk) { + $resultObjects[] = new tagged($path, $tagsChunk); + } else { + $resultObjects[] = new fileabsolute($path); + } + } - // NOTE: no elements path results in overridden final data - if($this->template) { - $data = $this->template; + $this->fileResults = $resultObjects; } - if($this->templateElementsPath) { - $data = \codename\core\io\helper\deepaccess::set($data, $this->templateElementsPath, $elements); - } else { - $data = $elements; // we could replace? - } - - // print_r($data); - $writer->write($data); - - $xmlString = $writer->outputMemory(); - // - // Validate, if schema_file provided - // - if($this->config['schema_file'] ?? false) { - try { + /** + * @param $handle + * @param $bufferArray + * @return void + * @throws exception + */ + protected function internalStoreBufferedData($handle, $bufferArray): void + { + $writer = new Writer(); + $writer->openMemory(); + $writer->setIndent(true); + $writer->startDocument($this->version, $this->encoding); + + $elements = []; + foreach ($bufferArray as $bufferEntry) { + $resultData = []; + + // pre-work some mapping options + foreach ($this->config['mapping'] as $mapName => $mapConfig) { + if ($mapConfig['path'] ?? false) { + // path is relative base for the map name + $objPath = array_merge($mapConfig['path'], [$mapName]); + $resultData = deepaccess::set($resultData, $objPath, $bufferEntry[$mapName]); + } else { + $resultData[$mapName] = $bufferEntry[$mapName]; + } + } + + $elements[] = $resultData; + } - $doc = new \DOMDocument(); - $doc->loadXML($xmlString); - $valid = $doc->schemaValidate(\codename\core\app::getInheritedPath($this->config['schema_file'])); - if(!$valid) { - $errors = libxml_get_errors(); - // echo("LIBXML ERRORS:".chr(10)); - // print_r($errors); + $data = []; - throw new exception('EXCEPTION_TARGET_XML_ERRORS', exception::$ERRORLEVEL_ERROR, \codename\core\app::object2array($errors)); + // NOTE: no elements path results in overridden final data + if ($this->template) { + $data = $this->template; + } + if ($this->templateElementsPath) { + $data = deepaccess::set($data, $this->templateElementsPath, $elements); } else { - // echo "VALID!"; + $data = $elements; // we could replace? } - } catch (\Exception $e) { - // print_r($e); - throw new exception('EXCEPTION_TARGET_XML_ERROR_EXCEPTION', exception::$ERRORLEVEL_ERROR, [ - 'message' => $e->getMessage(), - 'code' => $e->getCode() - ]); - // or rethrow? - } - } - - fwrite($handle, $xmlString); - fclose($handle); - } + $writer->write($data); + + $xmlString = $writer->outputMemory(); + + // + // Validate, if schema_file provided + // + if ($this->config['schema_file'] ?? false) { + try { + $doc = new DOMDocument(); + $doc->loadXML($xmlString); + $valid = $doc->schemaValidate(app::getInheritedPath($this->config['schema_file'])); + + if (!$valid) { + $errors = libxml_get_errors(); + + throw new exception('EXCEPTION_TARGET_XML_ERRORS', exception::$ERRORLEVEL_ERROR, app::object2array($errors)); + } else { + // echo "VALID!"; + } + } catch (\Exception $e) { + throw new exception('EXCEPTION_TARGET_XML_ERROR_EXCEPTION', exception::$ERRORLEVEL_ERROR, [ + 'message' => $e->getMessage(), + 'code' => $e->getCode(), + ]); + } + } + fwrite($handle, $xmlString); + fclose($handle); + } } diff --git a/backend/class/target/createArchiveTrait.php b/backend/class/target/createArchiveTrait.php index c5ae3ab..997b38c 100644 --- a/backend/class/target/createArchiveTrait.php +++ b/backend/class/target/createArchiveTrait.php @@ -1,115 +1,121 @@ fileResults as $fileResult) { - - $localName = null; - $archiveTarget = 'default'; - - $tags = null; - - $encryption = null; - $encryptionType = null; - $encryptionPassphrase = null; - - if($fileResult instanceof \codename\core\io\value\text\fileabsolute\tagged) { - $tags = $fileResult->getTags(); - $archiveTarget = $fileResult->getTags()[0]['archive_name']; - - $encryption = $fileResult->getTags()[0]['archive_encryption'] ?? false; - $encryptionType = $fileResult->getTags()[0]['archive_encryption_type'] ?? null; - $encryptionPassphrase = $fileResult->getTags()[0]['archive_encryption_passphrase'] ?? null; - - if(($fileName = $fileResult->getTags()[0]['file_name'] ?? null) && ($fileExtension = $fileResult->getTags()[0]['file_extension'] ?? null)) { - $localName = $fileName.'.'.$fileExtension; - } else { - // error? + /** + * [protected description] + * NOTE: until created, this HAS to be null. + * @var null|array + */ + protected ?array $archiveResults = null; + + /** + * [createArchive description] + * @return array + * @throws ReflectionException + * @throws exception + */ + protected function createArchive(): array + { + $tempZipInstances = []; + $tempZipTags = []; + + foreach ($this->fileResults as $fileResult) { + $localName = null; + $archiveTarget = 'default'; + + $tags = null; + + $encryption = null; + $encryptionType = null; + $encryptionPassphrase = null; + + if ($fileResult instanceof tagged) { + $tags = $fileResult->getTags(); + $archiveTarget = $fileResult->getTags()[0]['archive_name'] ?? null; + + $encryption = $fileResult->getTags()[0]['archive_encryption'] ?? false; + $encryptionType = $fileResult->getTags()[0]['archive_encryption_type'] ?? null; + $encryptionPassphrase = $fileResult->getTags()[0]['archive_encryption_passphrase'] ?? null; + + if (($fileName = $fileResult->getTags()[0]['file_name'] ?? null) && ($fileExtension = $fileResult->getTags()[0]['file_extension'] ?? null)) { + $localName = $fileName . '.' . $fileExtension; + } else { + // error? + } + } else { + // should we warn? + } + + if (!($tempZipInstances[$archiveTarget] ?? false)) { + $tempFilename = tempnam(sys_get_temp_dir(), 'zip_'); + $instance = new ZipArchive(); + $tempZipInstances[$archiveTarget] = $instance; + $tempZipInstances[$archiveTarget]->open($tempFilename, ZipArchive::CREATE | ZipArchive::OVERWRITE); + } + + $tempZipInstances[$archiveTarget]->addFile($fileResult->get(), $localName); // TODO: test, if PHP gets it ($localName == null fallback!) + + // + // NOTE: + // this requires + // - PHP 7.2+ + // - pecl zip 1.14.0+ + // + if ($encryption && $encryptionPassphrase) { + // NOTE: localName may have been set (inside archive), so we have to use this, if not null + + $encTypeConstants = [ + // 'EM_NONE' => \ZipArchive::EM_NONE, // this disables passwords + 'EM_AES_128' => ZipArchive::EM_AES_128, + 'EM_AES_192' => ZipArchive::EM_AES_192, + 'EM_AES_256' => ZipArchive::EM_AES_256, // the safe way. + ]; + + $encryptionConst = $encTypeConstants[$encryptionType] ?? ZipArchive::EM_AES_256; + $tempZipInstances[$archiveTarget]->setEncryptionName($localName ?? $fileResult->get(), $encryptionConst, $encryptionPassphrase); + } + + if ($tags) { + $tempZipTags[$archiveTarget] = array_merge($tempZipTags[$archiveTarget] ?? [], $tags); + } } - } else { - // should we warn? - } - - if(!($tempZipInstances[$archiveTarget] ?? false)) { - $tempFilename = tempnam(sys_get_temp_dir(), 'zip_'); - $instance = new \ZipArchive(); - $tempZipInstances[$archiveTarget] = $instance; - $tempZipInstances[$archiveTarget]->open($tempFilename, \ZipArchive::CREATE | \ZipArchive::OVERWRITE); - } - - $tempZipInstances[$archiveTarget]->addFile($fileResult->get(), $localName); // TODO: test, if PHP gets it ($localName == null fallback!) - - // - // NOTE: - // this requires - // - PHP 7.2+ - // - pecl zip 1.14.0+ - // - if($encryption && $encryptionPassphrase) { - // NOTE: localName may have been set (inside archive), so we have to use this, if not null - - $encTypeConstants = [ - // 'EM_NONE' => \ZipArchive::EM_NONE, // this disables passwords - 'EM_AES_128' => \ZipArchive::EM_AES_128, - 'EM_AES_192' => \ZipArchive::EM_AES_192, - 'EM_AES_256' => \ZipArchive::EM_AES_256, // the safe way. - ]; - - $encryptionConst = $encTypeConstants[$encryptionType] ?? \ZipArchive::EM_AES_256; - $tempZipInstances[$archiveTarget]->setEncryptionName($localName ?? $fileResult->get(), $encryptionConst, $encryptionPassphrase); - } - - if($tags) { - $tempZipTags[$archiveTarget] = array_merge($tempZipTags[$archiveTarget] ?? [], $tags); - } - } - $zipFileResults = []; - - foreach($tempZipInstances as $archiveTarget => $instance) { - $tags = $tempZipTags[$archiveTarget] ?? null; - $filename = $instance->filename; - if(!$instance->close()) { - throw new exception('ZIP ERROR', exception::$ERRORLEVEL_ERROR); - } - if($tags) { - // - // Just override the first element so transmission module gets it. - // - foreach($tags as &$tagSet) { - $tagSet['file_name'] = $archiveTarget; - $tagSet['file_extension'] = 'zip'; + $zipFileResults = []; + + foreach ($tempZipInstances as $archiveTarget => $instance) { + $tags = $tempZipTags[$archiveTarget] ?? null; + $filename = $instance->filename; + if (!$instance->close()) { + throw new exception('ZIP ERROR', exception::$ERRORLEVEL_ERROR); + } + if ($tags) { + // + // Just override the first element so transmission module gets it. + // + foreach ($tags as &$tagSet) { + $tagSet['file_name'] = $archiveTarget; + $tagSet['file_extension'] = 'zip'; + } + $zipFileResult = new tagged($filename, $tags); + $zipFileResults[] = $zipFileResult; + } else { + // error? + throw new LogicException('Tagless Archives not implemented'); + } } - $zipFileResult = new \codename\core\io\value\text\fileabsolute\tagged($filename, $tags); - $zipFileResults[] = $zipFileResult; - } else { - // error? - throw new \LogicException('Tagless Archives not implemented'); - } - } - return $zipFileResults; - } + return $zipFileResults; + } } diff --git a/backend/class/target/dummy.php b/backend/class/target/dummy.php index 58df6f3..702dfd6 100644 --- a/backend/class/target/dummy.php +++ b/backend/class/target/dummy.php @@ -1,78 +1,79 @@ virtualStore; - } +class dummy extends target implements virtualTargetInterface +{ + /** + * [protected description] + * @var array + */ + protected array $virtualStore = []; + /** + * determines the finished status of this target + * @var bool + */ + protected bool $finished = false; - /** - * @param string $name - * @param array $config - */ - public function __construct(string $name, array $config) - { - parent::__construct($name, $config); - } - - /** - * @inheritDoc - */ - public function setVirtualStoreEnabled(bool $state) - { - return; - } + /** + * @param string $name + * @param array $config + */ + public function __construct(string $name, array $config) + { + parent::__construct($name, $config); + } - /** - * @inheritDoc - */ - public function getVirtualStoreEnabled() : bool - { - return true; - } + /** + * returns data stored virtually in this instance + * @return array [description] + */ + public function getVirtualStoreData(): array + { + return $this->virtualStore; + } - /** - * @inheritDoc - */ - public function store(array $data) : bool - { - if($this->finished) { - throw new exception('EXCEPTION_CORE_IO_TARGET_VIRTUAL_ALREADY_FINISHED', exception::$ERRORLEVEL_ERROR); + /** + * {@inheritDoc} + */ + public function setVirtualStoreEnabled(bool $state): void + { } - $this->virtualStore[] = $data; - return true; - } - /** - * determines the finished status of this target - * @var bool - */ - protected $finished = false; + /** + * {@inheritDoc} + */ + public function getVirtualStoreEnabled(): bool + { + return true; + } - /** - * @inheritDoc - */ - public function finish() - { - $this->finished = true; - } + /** + * {@inheritDoc} + * @param array $data + * @return bool + * @throws exception + */ + public function store(array $data): bool + { + if ($this->finished) { + throw new exception('EXCEPTION_CORE_IO_TARGET_VIRTUAL_ALREADY_FINISHED', exception::$ERRORLEVEL_ERROR); + } + $this->virtualStore[] = $data; + return true; + } + /** + * {@inheritDoc} + */ + public function finish(): void + { + $this->finished = true; + } } diff --git a/backend/class/target/fileResultArrayInterface.php b/backend/class/target/fileResultArrayInterface.php index f91777b..7373aab 100644 --- a/backend/class/target/fileResultArrayInterface.php +++ b/backend/class/target/fileResultArrayInterface.php @@ -1,16 +1,18 @@ model = app::getModel($config['model'], $config['app'] ?? '', $config['vendor'] ?? ''); - $this->method = $config['method'] ?? 'save'; + /** + * @param string $name + * @param array $config + * @throws ReflectionException + * @throws exception + */ + public function __construct(string $name, array $config) + { + parent::__construct($name, $config); + $this->model = app::getModel($config['model'], $config['app'] ?? '', $config['vendor'] ?? ''); + $this->method = $config['method'] ?? 'save'; - $this->uniqueKeys = $this->model->getConfig()->get('unique') ?? null; - } + $this->uniqueKeys = $this->model->getConfig()->get('unique') ?? null; + } - /** - * [$uniqueKeys description] - * @var array - */ - protected $uniqueKeys = null; + /** + * [getModel description] + * @return \codename\core\model [description] + */ + public function getModel(): \codename\core\model + { + return $this->model; + } - /** - * @inheritDoc - */ - public function store(array $data) : bool - { - // TODO: validate? - // TODO: wrap in a try/catch and return true/false depending on error or success - if($this->method == 'replace') { - // perform a "manual" replace - $normalizedData = $this->model->normalizeData($data); + /** + * {@inheritDoc} + * @param array $data + * @return bool + * @throws ReflectionException + * @throws exception + */ + public function store(array $data): bool + { + // TODO: validate? + // TODO: wrap in a try/catch and return true/false depending on error or success + if ($this->method == 'replace') { + // perform a "manual" replace + $normalizedData = $this->model->normalizeData($data); - if($normalizedData[$this->model->getPrimarykey()] ?? false) { - // update based on supplied pkey vale - $this->model->save($normalizedData); - } else { - if($this->uniqueKeys) { - // detect existing record - $filtersAdded = false; - foreach($this->uniqueKeys as $uniqueKey) { - if(is_array($uniqueKey)) { - // multiple keys, combined unique key - $filters = []; - foreach($uniqueKey as $key) { - if($normalizedData[$key] ?? false) { - $filters[] = [ 'field' => $key, 'operator' => '=', 'value' => $normalizedData[$key]]; - } else { - // irrelevant unique key, one value is null - $filters = []; - break; + if ($normalizedData[$this->model->getPrimaryKey()] ?? false) { + // update based on supplied pkey vale + $this->model->save($normalizedData); + } elseif ($this->uniqueKeys) { + // detect existing record + $filtersAdded = false; + foreach ($this->uniqueKeys as $uniqueKey) { + if (is_array($uniqueKey)) { + // multiple keys, combined unique key + $filters = []; + foreach ($uniqueKey as $key) { + if ($normalizedData[$key] ?? false) { + $filters[] = ['field' => $key, 'operator' => '=', 'value' => $normalizedData[$key]]; + } else { + // irrelevant unique key, one value is null + $filters = []; + break; + } + } + if (count($filters) > 0) { + $filtersAdded = true; + $this->model->addFilterCollection($filters); + } + } else { + // single unique key field + $filtersAdded = true; + $this->model->addFilter($uniqueKey, $normalizedData[$uniqueKey] ?? null); + } + } + if ($filtersAdded) { + $res = $this->model->search()->getResult(); + if (count($res) === 1) { + // update using found PKEY + $normalizedData[$this->model->getPrimaryKey()] = $res[0][$this->model->getPrimaryKey()]; + $this->model->save($normalizedData); + } elseif (count($res) === 0) { + // insert + $this->model->save($normalizedData); + } else { + // error - multiple results + throw new exception('EXCEPTION_TARGET_MODEL_MULTIPLE_UNIQUE_KEY_RESULTS', exception::$ERRORLEVEL_ERROR, $res); + } + } elseif ($this->config['ignore_unique'] ?? false) { + // + // no unique key filters active, needs "ignore_unique" + // + $this->model->save($normalizedData); } - } - if(count($filters) > 0) { - $filtersAdded = true; - $this->model->addFilterCollection($filters, 'AND'); - } - } else { - // single unique key field - $filtersAdded = true; - $this->model->addFilter($uniqueKey, $normalizedData[$uniqueKey]); - } - } - if($filtersAdded) { - $res = $this->model->search()->getResult(); - if(count($res) === 1) { - // update using found PKEY - $normalizedData[$this->model->getPrimarykey()] = $res[0][$this->model->getPrimarykey()]; - $this->model->save($normalizedData); - } else if(count($res) === 0) { - // insert - $this->model->save($normalizedData); } else { - // error - multiple results - throw new exception('EXCEPTION_TARGET_MODEL_MULTIPLE_UNIQUE_KEY_RESULTS', exception::$ERRORLEVEL_ERROR, $res); - } - } else { - // - // no unique key filters active, needs "ignore_unique" - // - if($this->config['ignore_unique'] ?? false) { - $this->model->save($normalizedData); + // normal save + $this->model->save($normalizedData); } - } } else { - // normal save - $this->model->save($normalizedData); + $this->model->save($this->model->normalizeData($data)); } - } - } else { - $this->model->save($this->model->normalizeData($data)); + return true; } - return true; - } - - /** - * [getModel description] - * @return \codename\core\model [description] - */ - public function getModel() : \codename\core\model{ - return $this->model; - } - - /** - * @inheritDoc - */ - public function finish() - { - return; // end transactions? - } + /** + * {@inheritDoc} + */ + public function finish(): void + { + } } diff --git a/backend/class/target/model/complex.php b/backend/class/target/model/complex.php index 590b824..ae17c70 100644 --- a/backend/class/target/model/complex.php +++ b/backend/class/target/model/complex.php @@ -1,334 +1,293 @@ model = $this->buildModelStructure($config['structure']); - $this->method = $config['method'] ?? 'save'; - $this->uniqueKeys = $this->model->getConfig()->get('unique') ?? null; - } - - /** - * store method - * 'save' or 'replace' - * @var string - */ - protected $method = 'save'; - - /** - * [$uniqueKeys description] - * @var array - */ - protected $uniqueKeys = null; - - /** - * [protected description] - * @var array - */ - protected $virtualStore = []; +class complex extends target implements + targetModelInterface, + virtualTargetInterface +{ + /** + * target model + * @var model + */ + protected model $model; + /** + * store method + * 'save' or 'replace' + * @var string + */ + protected string $method = 'save'; + /** + * [$uniqueKeys description] + * @var array + */ + protected mixed $uniqueKeys = null; + /** + * [protected description] + * @var array + */ + protected array $virtualStore = []; + /** + * whether to store data or not + * @var bool + */ + protected bool $virtualStoreEnabled = false; + /** + * determines the finished status of this target + * @var bool + */ + protected bool $finished = false; - /** - * @inheritDoc - */ - public function getVirtualStoreData(): array - { - return $this->virtualStore; - } - - /** - * whether to store data or not - * @var bool - */ - protected $virtualStoreEnabled = false; - - /** - * @inheritDoc - */ - public function setVirtualStoreEnabled(bool $state) - { - $this->virtualStoreEnabled = $state; - } - - /** - * @inheritDoc - */ - public function getVirtualStoreEnabled(): bool - { - return $this->virtualStoreEnabled; - } + /** + * {@inheritDoc} + * @param string $name + * @param array $config + * @throws ReflectionException + * @throws exception + */ + public function __construct(string $name, array $config) + { + parent::__construct($name, $config); + $this->model = $this->buildModelStructure($config['structure']); + $this->method = $config['method'] ?? 'save'; + $this->uniqueKeys = $this->model->getConfig()->get('unique') ?? null; + } - /** - * [buildModelStructure description] - * @param array $config [description] - * @return \codename\core\model [description] - */ - protected function buildModelStructure(array $config) : \codename\core\model { - $model = app::getModel($config['model'], $config['app'] ?? '', $config['vendor'] ?? ''); - foreach($config['join'] as $join) { - $joinModel = $this->buildModelStructure($join); - if(($join['type'] ?? false) === 'collection') { - $model->addCollectionModel($joinModel, $join['modelfield'] ?? null); - } else { - $model->addModel($joinModel); - } + /** + * [buildModelStructure description] + * @param array $config [description] + * @return model [description] + * @throws ReflectionException + * @throws exception + */ + protected function buildModelStructure(array $config): model + { + $model = app::getModel($config['model'], $config['app'] ?? '', $config['vendor'] ?? ''); + foreach ($config['join'] as $join) { + $joinModel = $this->buildModelStructure($join); + if (($join['type'] ?? false) === 'collection') { + $model->addCollectionModel($joinModel, $join['modelfield'] ?? null); + } else { + $model->addModel($joinModel); + } + } + return $model; } - return $model; - } - /** - * @inheritDoc - */ - public function getModel() : \codename\core\model - { - return $this->model; - } + /** + * @return model + */ + public function getModel(): model + { + return $this->model; + } - /** - * @inheritDoc - */ - public function store(array $data) : bool - { - // \codename\core\app::getResponse()->setData( - // 'model_complex_store', - // array_merge( - // \codename\core\app::getResponse()->getData('model_complex_store') ?? [], - // [ $data ] - // ) - // ); + /** + * {@inheritDoc} + */ + public function getVirtualStoreData(): array + { + return $this->virtualStore; + } - $normalizedData = $this->handleStore($this->model, $data); + /** + * {@inheritDoc} + */ + public function getVirtualStoreEnabled(): bool + { + return $this->virtualStoreEnabled; + } - // if($this->virtualStoreEnabled) { - // $this->virtualStore[] = $normalizedData; // $this->model->normalizeData($data); - // } else { - // - // - // - // - // } + /** + * {@inheritDoc} + */ + public function setVirtualStoreEnabled(bool $state): void + { + $this->virtualStoreEnabled = $state; + } - if($this->method == 'replace') { - // perform a "manual" replace - // $normalizedData = $this->model->normalizeData($data); + /** + * {@inheritDoc} + * @param array $data + * @return bool + * @throws ReflectionException + * @throws exception + */ + public function store(array $data): bool + { + $normalizedData = $this->handleStore($this->model, $data); - if($normalizedData[$this->model->getPrimarykey()] ?? false) { - // update based on supplied pkey vale - if($this->virtualStoreEnabled) { - $this->virtualStore[] = $normalizedData; - } else { - $this->model->saveWithChildren($normalizedData); - } - } else { - if($this->uniqueKeys) { - // detect existing record - $filtersAdded = false; - foreach($this->uniqueKeys as $uniqueKey) { - if(is_array($uniqueKey)) { - // multiple keys, combined unique key - $filters = []; - foreach($uniqueKey as $key) { - if($normalizedData[$key] ?? false) { - $filters[] = [ 'field' => $key, 'operator' => '=', 'value' => $normalizedData[$key]]; + if ($this->method == 'replace') { + if ($normalizedData[$this->model->getPrimaryKey()] ?? false) { + // update based on supplied pkey vale + if ($this->virtualStoreEnabled) { + $this->virtualStore[] = $normalizedData; } else { - // irrelevant unique key, one value is null - $filters = []; - break; + $this->model->saveWithChildren($normalizedData); } - } - if(count($filters) > 0) { - $filtersAdded = true; - $this->model->addFilterCollection($filters, 'AND'); - } - } else { - // single unique key field - $filtersAdded = true; - $this->model->addFilter($uniqueKey, $normalizedData[$uniqueKey]); - } - } - if($filtersAdded) { - $res = $this->model->search()->getResult(); - if(count($res) === 1) { - // update using found PKEY - $normalizedData[$this->model->getPrimarykey()] = $res[0][$this->model->getPrimarykey()]; - if($this->virtualStoreEnabled) { - $this->virtualStore[] = $normalizedData; - } else { - $this->model->saveWithChildren($normalizedData); - } - } else if(count($res) === 0) { - // insert - if($this->virtualStoreEnabled) { + } elseif ($this->uniqueKeys) { + // detect existing record + $filtersAdded = false; + foreach ($this->uniqueKeys as $uniqueKey) { + if (is_array($uniqueKey)) { + // multiple keys, combined unique key + $filters = []; + foreach ($uniqueKey as $key) { + if ($normalizedData[$key] ?? false) { + $filters[] = ['field' => $key, 'operator' => '=', 'value' => $normalizedData[$key]]; + } else { + // irrelevant unique key, one value is null + $filters = []; + break; + } + } + if (count($filters) > 0) { + $filtersAdded = true; + $this->model->addFilterCollection($filters); + } + } else { + // single unique key field + $filtersAdded = true; + $this->model->addFilter($uniqueKey, $normalizedData[$uniqueKey] ?? null); + } + } + if ($filtersAdded) { + $res = $this->model->search()->getResult(); + if (count($res) === 1) { + // update using found PKEY + $normalizedData[$this->model->getPrimaryKey()] = $res[0][$this->model->getPrimaryKey()]; + if ($this->virtualStoreEnabled) { + $this->virtualStore[] = $normalizedData; + } else { + $this->model->saveWithChildren($normalizedData); + } + } elseif (count($res) === 0) { + // insert + if ($this->virtualStoreEnabled) { + $this->virtualStore[] = $normalizedData; + } else { + $this->model->saveWithChildren($normalizedData); + } + } else { + // error - multiple results + throw new exception('EXCEPTION_TARGET_MODEL_COMPLEX_MULTIPLE_UNIQUE_KEY_RESULTS', exception::$ERRORLEVEL_ERROR, $res); + } + } + } elseif ($this->virtualStoreEnabled) { + // normal save $this->virtualStore[] = $normalizedData; - } else { - $this->model->saveWithChildren($normalizedData); - } } else { - // error - multiple results - throw new exception('EXCEPTION_TARGET_MODEL_COMPLEX_MULTIPLE_UNIQUE_KEY_RESULTS', exception::$ERRORLEVEL_ERROR, $res); + $this->model->saveWithChildren($normalizedData); } - } - } else { - // normal save - if($this->virtualStoreEnabled) { + } elseif ($this->virtualStoreEnabled) { $this->virtualStore[] = $normalizedData; - } else { + } else { $this->model->saveWithChildren($normalizedData); - } } - } - } else { - if($this->virtualStoreEnabled) { - $this->virtualStore[] = $normalizedData; - } else { - $this->model->saveWithChildren($normalizedData); - } + return true; } - return true; - // $this->model->save($newData); - } - /** - * handles store() recursively - * - * @param \codename\core\model $model [description] - * @param array $data [description] - * @return [type] [description] - */ - protected function handleStore(\codename\core\model $model, array $data) { - foreach($model->getNestedCollections() as $collection) { - // work through each entry, modify on need - foreach($data[$collection->field->get()] as &$subData) { - // \codename\core\app::getResponse()->setData('model_complex_collection_handleStore', array_merge( - // \codename\core\app::getResponse()->getData('model_complex_collection_handleStore') ?? [], - // [ - // [ - // 'model' => $model->getIdentifier(), - // 'collectionModel' => $collection->collectionModel->getIdentifier(), - // 'subData' => $subData - // ] - // ] - // )); - $subData = $this->handleStore($collection->collectionModel, $subData); - } - } - foreach($model->getNestedJoins() as $join) { - // work through each join, modify on need - // dive deeper, first + /** + * handles store() recursively + * + * @param model $model [description] + * @param array $data [description] + * @return array [type] [description] + */ + protected function handleStore(model $model, array $data): array + { + foreach ($model->getNestedCollections() as $collection) { + // work through each entry, modify on need + foreach ($data[$collection->field->get()] as &$subData) { + $subData = $this->handleStore($collection->collectionModel, $subData); + } + } + foreach ($model->getNestedJoins() as $join) { + // work through each join, modify on need + // dive deeper, first - // \codename\core\app::getResponse()->setData('model_complex_joins_dive', array_merge( - // \codename\core\app::getResponse()->getData('model_complex_joins_dive') ?? [], - // [ - // [ - // 'model' => $model->getIdentifier(), - // 'join' => $join->model->getIdentifier(), - // 'data' => $data, - // 'registered_child' => self::isRegisteredChild($model, $join->modelField) - // ] - // ] - // )); + if (self::isRegisteredChild($model, $join->modelField)) { + // case 1: model/join has a child config - no direct action needed, dive deeper + $childVirtualField = self::getChildField($model, $join->modelField); + if (array_key_exists($childVirtualField, $data) && $data[$childVirtualField] !== null) { + $data[$childVirtualField] = $this->handleStore($join->model, $data[$childVirtualField]); + } + } else { + // case 2: model/join has no child config - dive deeper and save/normalize + $data = $this->handleStore($join->model, $data); - if(self::isRegisteredChild($model, $join->modelField)) { - // case 1: model/join has a child config - no direct action needed, dive deeper - $childVirtualField = self::getChildField($model, $join->modelField); - if(array_key_exists($childVirtualField, $data) && $data[$childVirtualField] !== null) { - $data[$childVirtualField] = $this->handleStore($join->model, $data[$childVirtualField]); + // TODO: save and get lastInsertId, modify data + // $this->model->save($data); + } } - } else { - // case 2: model/join has no child config - dive deeper and save/normalize - $data = $this->handleStore($join->model, $data); - // TODO: save and get lastInsertId, modify data - // $this->model->save($data); - } - } + if ($this->virtualStoreEnabled) { + // pseudo-save. don't perform anything + // $data[$model->getPrimaryKey()] = 'dry-run'; + } else { + // "save" the data + } - if($this->virtualStoreEnabled) { - // pseudo-save. don't perform anything - // $data[$model->getPrimarykey()] = 'dry-run'; - } else { - // "save" the data + return $data; } - return $data; - } - - - /** - * [isRegisteredChild description] - * @param \codename\core\model $model [description] - * @param string $field [description] - * @return bool [description] - */ - protected static function isRegisteredChild(\codename\core\model $model, string $field) : bool { - if($model->config->exists('children')) { - foreach($model->config->get('children') as $child => $childConfig) { - if($childConfig['type'] === 'foreign') { - if($childConfig['field'] == $field) { - return true; - } - } else if($childConfig['type'] === 'collection') { - // TODO - // if($childConfig['field'] == $field) { - // return true; - // } + /** + * [isRegisteredChild description] + * @param model $model [description] + * @param string $field [description] + * @return bool [description] + */ + protected static function isRegisteredChild(model $model, string $field): bool + { + if ($model->config->exists('children')) { + foreach ($model->config->get('children') as $childConfig) { + if ($childConfig['type'] === 'foreign') { + if ($childConfig['field'] == $field) { + return true; + } + } elseif ($childConfig['type'] === 'collection') { + // TODO + } + } } - } + return false; } - return false; - } - /** - * [getChildField description] - * @param \codename\core\model $model [description] - * @param string $field [description] - * @return string|null [description] - */ - protected static function getChildField(\codename\core\model $model, string $field) { - if($model->config->exists('children')) { - foreach($model->config->get('children') as $child => $childConfig) { - if($childConfig['type'] === 'foreign') { - if($childConfig['field'] == $field) { - return $child; - } + /** + * [getChildField description] + * @param model $model [description] + * @param string $field [description] + * @return string|null [description] + */ + protected static function getChildField(model $model, string $field): ?string + { + if ($model->config->exists('children')) { + foreach ($model->config->get('children') as $child => $childConfig) { + if ($childConfig['type'] === 'foreign') { + if ($childConfig['field'] == $field) { + return $child; + } + } + } } - } + return null; } - return null; - } - - /** - * determines the finished status of this target - * @var bool - */ - protected $finished = false; - - /** - * @inheritDoc - */ - public function finish() - { - return; // ? - } - + /** + * {@inheritDoc} + */ + public function finish(): void + { + } } diff --git a/backend/class/target/structureResultArrayInterface.php b/backend/class/target/structureResultArrayInterface.php index 4156662..abf0bbc 100644 --- a/backend/class/target/structureResultArrayInterface.php +++ b/backend/class/target/structureResultArrayInterface.php @@ -1,16 +1,18 @@ virtualStore; - } - - /** - * @inheritDoc - */ - public function setVirtualStoreEnabled(bool $state) - { - return; - } - - /** - * @inheritDoc - */ - public function getVirtualStoreEnabled() : bool - { - return true; - } - - /** - * target model - * @var \codename\core\model - */ - protected $model = null; +class virtual extends target implements + targetModelInterface, + virtualTargetInterface +{ + /** + * [protected description] + * @var array + */ + protected array $virtualStore = []; + /** + * target model + * @var \codename\core\model + */ + protected \codename\core\model $model; + /** + * store method + * 'save' or 'replace' + * @var string + */ + protected string $method = 'save'; + /** + * determines the finished status of this target + * @var bool + */ + protected bool $finished = false; - /** - * store method - * 'save' or 'replace' - * @var string - */ - protected $method = 'save'; + /** + * @param string $name + * @param array $config + * @throws ReflectionException + * @throws exception + */ + public function __construct(string $name, array $config) + { + parent::__construct($name, $config); + $this->model = app::getModel($config['model'], $config['app'] ?? '', $config['vendor'] ?? ''); + $this->method = $config['method'] ?? 'save'; + } - /** - * @param string $name - * @param array $config - */ - public function __construct(string $name, array $config) - { - parent::__construct($name, $config); - $this->model = app::getModel($config['model'], $config['app'] ?? '', $config['vendor'] ?? ''); - $this->method = $config['method'] ?? 'save'; - } + /** + * [getModel description] + * @return \codename\core\model [description] + */ + public function getModel(): \codename\core\model + { + return $this->model; + } - /** - * @inheritDoc - */ - public function store(array $data) : bool - { - if($this->finished) { - throw new exception('EXCEPTION_CORE_IO_TARGET_VIRTUAL_ALREADY_FINISHED', exception::$ERRORLEVEL_ERROR); + /** + * returns data stored virtually in this instance + * @return array [description] + */ + public function getVirtualStoreData(): array + { + return $this->virtualStore; } - $this->virtualStore[] = $this->model->normalizeData($data); - return true; - } - /** - * [getModel description] - * @return \codename\core\model [description] - */ - public function getModel() : \codename\core\model{ - return $this->model; - } + /** + * {@inheritDoc} + */ + public function setVirtualStoreEnabled(bool $state): void + { + } - /** - * determines the finished status of this target - * @var bool - */ - protected $finished = false; + /** + * {@inheritDoc} + */ + public function getVirtualStoreEnabled(): bool + { + return true; + } - /** - * @inheritDoc - */ - public function finish() - { - $this->finished = true; - } + /** + * {@inheritDoc} + * @param array $data + * @return bool + * @throws exception + */ + public function store(array $data): bool + { + if ($this->finished) { + throw new exception('EXCEPTION_CORE_IO_TARGET_VIRTUAL_ALREADY_FINISHED', exception::$ERRORLEVEL_ERROR); + } + $this->virtualStore[] = $this->model->normalizeData($data); + return true; + } + /** + * {@inheritDoc} + */ + public function finish(): void + { + $this->finished = true; + } } diff --git a/backend/class/target/virtualTargetInterface.php b/backend/class/target/virtualTargetInterface.php index cf8c0a4..769f039 100644 --- a/backend/class/target/virtualTargetInterface.php +++ b/backend/class/target/virtualTargetInterface.php @@ -1,4 +1,5 @@ xmlService = new \Sabre\Xml\Service(); - $this->version = $this->config['version'] ?? $this->version; - $this->encoding = $this->config['encoding'] ?? $this->encoding; - } - - /** - * @inheritDoc - */ - public function store(array $data) : bool - { - - $resultData = []; - - // pre-work some mapping options - foreach($this->config['mapping'] as $mapName => $mapConfig) { - if($mapConfig['path'] ?? false) { - // path is relative base for the map name - $objPath = array_merge($mapConfig['path'], [$mapName]); - $resultData = \codename\core\io\helper\deepaccess::set($resultData, $objPath, $data[$mapName]); - } else { - $resultData[$mapName] = $data[$mapName]; - } +class xml extends target +{ + /** + * [protected description] + * @var Service + */ + protected Service $xmlService; + + /** + * [protected description] + * @var string + */ + protected string $version = '1.0'; + + /** + * [protected description] + * @var null|string + */ + protected ?string $encoding = null; + /** + * store xml strings here + * @var string[] + */ + protected array $virtualXmlStore = []; + + /** + * [__construct description] + * @param string $name [description] + * @param array $config [description] + */ + public function __construct(string $name, array $config) + { + parent::__construct($name, $config); + $this->xmlService = new Service(); + $this->version = $this->config['version'] ?? $this->version; + $this->encoding = $this->config['encoding'] ?? $this->encoding; } - // print_r($resultData); - - $writer = new \Sabre\Xml\Writer(); - $writer->openMemory(); - $writer->setIndent(true); - $writer->startDocument($this->version, $this->encoding); - $writer->write($resultData); - - $xmlString = $writer->outputMemory(); - // echo $xmlString; - - if($this->config['schema_file'] ?? false) { - try { - - $doc = new \DOMDocument(); - $doc->loadXML($xmlString); - $valid = $doc->schemaValidate(\codename\core\app::getInheritedPath($this->config['schema_file'])); - - if(!$valid) { - $errors = libxml_get_errors(); - // echo("LIBXML ERRORS:".chr(10)); - // print_r($errors); - - throw new exception('EXCEPTION_TARGET_XML_ERRORS', exception::$ERRORLEVEL_ERROR, $errors); - } else { - // echo "VALID!"; + /** + * {@inheritDoc} + * @param array $data + * @return bool + * @throws exception + */ + public function store(array $data): bool + { + $resultData = []; + + // pre-work some mapping options + foreach ($this->config['mapping'] as $mapName => $mapConfig) { + if ($mapConfig['path'] ?? false) { + // path is relative base for the map name + $objPath = array_merge($mapConfig['path'], [$mapName]); + $resultData = deepaccess::set($resultData, $objPath, $data[$mapName]); + } else { + $resultData[$mapName] = $data[$mapName]; + } } - } catch (\Exception $e) { - // print_r($e); - throw new exception('EXCEPTION_TARGET_XML_ERROR_EXCEPTION', exception::$ERRORLEVEL_ERROR, [ - 'message' => $e->getMessage(), - 'code' => $e->getCode() - ]); - // or rethrow? - } - } - - $this->virtualXmlStore[] = $xmlString; - return true; - } - /** - * store xml strings here - * @var string[] - */ - protected $virtualXmlStore = []; - - // protected static function setRecursively(array $data, array $path = []) { - // - // } - - /** - * @inheritDoc - */ - public function finish() - { - // for xml strings, do nothing? - // for xml files, write them? - } + $writer = new Writer(); + $writer->openMemory(); + $writer->setIndent(true); + $writer->startDocument($this->version, $this->encoding); + $writer->write($resultData); + + $xmlString = $writer->outputMemory(); + + if ($this->config['schema_file'] ?? false) { + try { + $doc = new DOMDocument(); + $doc->loadXML($xmlString); + $valid = $doc->schemaValidate(app::getInheritedPath($this->config['schema_file'])); + + if (!$valid) { + $errors = libxml_get_errors(); + + throw new exception('EXCEPTION_TARGET_XML_ERRORS', exception::$ERRORLEVEL_ERROR, $errors); + } else { + // echo "VALID!"; + } + } catch (\Exception $e) { + throw new exception('EXCEPTION_TARGET_XML_ERROR_EXCEPTION', exception::$ERRORLEVEL_ERROR, [ + 'message' => $e->getMessage(), + 'code' => $e->getCode(), + ]); + } + } + $this->virtualXmlStore[] = $xmlString; + return true; + } + /** + * {@inheritDoc} + */ + public function finish(): void + { + // for xml strings, do nothing? + // for xml files, write them? + } } diff --git a/backend/class/target/xml/text.php b/backend/class/target/xml/text.php index 8b9aa68..34c43be 100644 --- a/backend/class/target/xml/text.php +++ b/backend/class/target/xml/text.php @@ -1,21 +1,28 @@ virtualXmlStore); - } - +class text extends xml implements textResultArrayInterface +{ + /** + * {@inheritDoc} + * @return array + * @throws ReflectionException + * @throws exception + */ + public function getTextResultArray(): array + { + return array_map(function ($item) { + return new \codename\core\value\text($item); + }, $this->virtualXmlStore); + } } diff --git a/backend/class/targetModelInterface.php b/backend/class/targetModelInterface.php index e5dcad7..3670b46 100644 --- a/backend/class/targetModelInterface.php +++ b/backend/class/targetModelInterface.php @@ -1,9 +1,16 @@ errorstack = new errorstack('TRANSFORM'); - $this->config = $config; - $this->debug = $this->config['debug'] ?? false; - } - - /** - * [getErrors description] - * @return array [description] - */ - public function getErrors() : array { - return $this->errorstack->getErrors(); - } - - /** - * [resetErrors description] - */ - public function resetErrors () { - $this->errorstack->reset(); - } - - /** - * [private description] - * @var \codename\core\io\pipeline - */ - protected $pipelineInstance = null; - - /** - * [isDryRun description] - * @return bool [description] - */ - protected function isDryRun() : bool { - return $this->pipelineInstance->getDryRun(); - } - - /** - * [setPipelineInstance description] - * @deprecated [vector] [description] - * @param \codename\core\io\pipeline $instance [description] - */ - public function setPipelineInstance(\codename\core\io\pipeline $instance) { - $this->pipelineInstance = $instance; - } - - /** - * [private description] - * @var \codename\core\io\transformerInterface - */ - protected $transformerInstance = null; - - /** - * [setTransformerInstance description] - * @param \codename\core\io\transformerInterface $instance [description] - */ - public function setTransformerInstance(\codename\core\io\transformerInterface $instance) { - $this->transformerInstance = $instance; - } - - /** - * cache hash - * @var string - */ - public $cacheHash = null; - - /** - * cached value - * @var mixed - */ - public $cacheValue = null; - - /** - * [protected description] - * @var [type] - */ - protected $cached = false; - - /** - * sets cache from current value - * and the instance's config - * @param mixed $parameters [input parameters - e.g. the current value] - * @param mixed $cacheValue [the to-be-cached value] - */ - protected function setCacheValue($parameters, $cacheValue) { - //$this->cacheHash = $this->getCacheHash($parameters); - $this->cacheValue = $cacheValue; - $this->cached = true; - } - - /** - * [isCached description] - * @param [type] $parameters [description] - * @return bool [description] - */ - protected function isCached($parameters) : bool { - // return $this->cacheHash !== null ? false : $this->getCacheHash($parameters) == $this->cacheHash; - return $this->cached; - } - - /** - * [getCacheHash description] - * @param [type] $parameters [description] - * @return [type] [description] - */ - protected function getCacheHash($parameters) { - return serialize($parameters); - } - - /** - * [reset description] - */ - public function reset() { - $this->resetErrors(); - $this->resetCache(); - } - - /** - * resets the cache - */ - public function resetCache() { - $this->cacheHash = null; - $this->cacheValue = null; - $this->cached = false; - - if($this->debug) { - $this->durationMeasured = null; + /** + * cache hash + * @var null|string + */ + public ?string $cacheHash = null; + /** + * cached value + * @var mixed + */ + public mixed $cacheValue = null; + /** + * debug info: + * measure duration for the transform itself + * @var float|null [type] + */ + public ?float $durationMeasured = null; + /** + * catch multiple durations measured + * @var float[] + */ + public array $durationsMeasured = []; + /** + * debug info, optional + * @var mixed + */ + public mixed $debugInfo = null; + /** + * [protected description] + * @var array + */ + protected array $config; + /** + * [protected description] + * @var errorstack + */ + protected errorstack $errorstack; + /** + * [private description] + * @var null|pipeline + */ + protected ?pipeline $pipelineInstance = null; + /** + * [private description] + * @var null|transformerInterface + */ + protected ?transformerInterface $transformerInstance = null; + /** + * [protected description] + * @var bool [type] + */ + protected bool $cached = false; + /** + * debug mode + * @var bool + */ + protected bool $debug = false; + + /** + * @param array $config + */ + public function __construct(array $config) + { + $this->errorstack = new errorstack('TRANSFORM'); + $this->config = $config; + $this->debug = $this->config['debug'] ?? false; } - } - - /** - * [transform description] - * @param mixed $value [input value] - * @return mixed|null [transform result] - */ - public function transform($value) { - if($this->isCached($value)) { - // use cached transform result - return $this->cacheValue; - } else { - if($this->debug || ($this->pipelineInstance && $this->pipelineInstance->debug)) { - $start = microtime(true); - } - - // - // perform the real transform - // - $transformResult = $this->internalTransform($value); + /** + * [getErrors description] + * @return array [description] + */ + public function getErrors(): array + { + return $this->errorstack->getErrors(); + } - if($this->debug || ($this->pipelineInstance && $this->pipelineInstance->debug)) { - $end = microtime(true); - $this->durationMeasured = ($end-$start); - $this->durationsMeasured[] = $this->durationMeasured; - } + /** + * @return void + */ + public function resetErrors(): void + { + $this->errorstack->reset(); + } - // - // fill instance cache - // - $this->setCacheValue($value, $transformResult); + /** + * @return void + */ + public function reset(): void + { + $this->resetErrors(); + $this->resetCache(); + } - return $transformResult; + /** + * resets the cache + * @return void + */ + public function resetCache(): void + { + $this->cacheHash = null; + $this->cacheValue = null; + $this->cached = false; + + if ($this->debug) { + $this->durationMeasured = null; + } } - } - /** - * debug info: - * measure duration for the transform itself - * @var [type] - */ - public $durationMeasured = null; + /** + * [setPipelineInstance description] + * @param pipeline $instance [description] + */ + public function setPipelineInstance(pipeline $instance): void + { + $this->pipelineInstance = $instance; + } - /** - * catch multiple durations measured - * @var float[] - */ - public $durationsMeasured = []; + /** + * [setTransformerInstance description] + * @param transformerInterface $instance [description] + */ + public function setTransformerInstance(transformerInterface $instance): void + { + $this->transformerInstance = $instance; + } - /** - * debug info, optional - * @var mixed - */ - public $debugInfo = null; + /** + * returns the specification for this transform + * @return array + */ + abstract public function getSpecification(): array; + + /** + * [isDryRun description] + * @return bool [description] + */ + protected function isDryRun(): bool + { + return $this->pipelineInstance->getDryRun(); + } - /** - * debug mode - * @var bool - */ - protected $debug = false; + /** + * [getCacheHash description] + * @param mixed $parameters [description] + * @return string [type] [description] + */ + protected function getCacheHash(mixed $parameters): string + { + return serialize($parameters); + } - /** - * internal transformation - * override this method to implement - * the 'real' transform - * - * @param mixed $value [input value] - * @return mixed|null [transform result] - */ - abstract public function internalTransform($value); + /** + * returns a value from a source (either source, the transform or else) + * name is required + * as well as the 'value', which is the current item value we're iterating over/the main parameter + * + * @param string $sourceType [source type] + * @param array|string $field [field name] + * @param mixed $value [main parameter] + * @return mixed + * @throws exception + */ + protected function getValue(string $sourceType, array|string $field, mixed $value): mixed + { + if ($sourceType == 'source') { + return $value[$field] ?? null; + } elseif ($sourceType == 'source_deep') { + return deepaccess::get($value, $field); + } elseif ($sourceType == 'transform') { + return $this->getTransformValue($field, $value); + } elseif ($sourceType == 'transform_deep') { + $transformField = $field[0]; + $path = array_slice($field, 1); + $transformed = $this->getTransformValue($transformField, $value); + if (count($path) > 0) { + return deepaccess::get($transformed, $path); + } else { + // only one object path item specified - transform name itself + return $transformed; + } + } elseif ($sourceType == 'option') { + // a value from the options + return $this->pipelineInstance->getOption($field); + } elseif ($sourceType == 'constant') { + if (is_array($field)) { + return deepaccess::get($this->pipelineInstance->getConfig()->get('constants'), $field); + } else { + return $this->pipelineInstance->getConfig()->get('constants>' . $field); + } + } elseif ($sourceType == 'erroneous') { + // a value from the error handling + throw new LogicException('Not implemented'); + } else { + // Error case. Unknown/Invalid source type + throw new exception('EXCEPTION_TRANSFORM_GETVALUE_INVALID_SOURCE_TYPE', exception::$ERRORLEVEL_ERROR); + } + } - /** - * retrieve another transform's value - * - * @param string $name [name of transform in definition] - * @param mixed $value [current value] - * @return mixed [description] - */ - protected function getTransformValue(string $name, $value) { - return $this->transformerInstance->getTransformInstance($name)->transform($value); - } + /** + * retrieve another transform's value + * + * @param string $name [name of transform in definition] + * @param mixed $value [current value] + * @return mixed [description] + */ + protected function getTransformValue(string $name, mixed $value): mixed + { + return $this->transformerInstance->getTransformInstance($name)->transform($value); + } - /** - * returns a value from a source (either source, the transform or else) - * name is required - * as well as the 'value', which is the current item value we're iterating over/the main parameter - * - * @param string $sourceType [source type] - * @param string|array $field [field name] - * @param mixed $value [main parameter] - * @return mixed - */ - protected function getValue(string $sourceType, $field, $value) { - if($sourceType == 'source') { - return $value[$field] ?? null; - } else if($sourceType == 'source_deep') { - return \codename\core\io\helper\deepaccess::get($value, $field); - } else if($sourceType == 'transform') { - return $this->getTransformValue($field, $value); - } else if($sourceType == 'transform_deep') { - $transformField = $field[0]; - $path = array_slice($field, 1); - $transformed = $this->getTransformValue($transformField, $value); - if(count($path) > 0) { - return \codename\core\io\helper\deepaccess::get($transformed, $path); - } else { - // only one object path item specified - transform name itself - return $transformed; - } - } else if($sourceType == 'option') { - // a value from the options - return $this->pipelineInstance->getOption($field); - } else if($sourceType == 'constant') { - if(is_array($field)) { - return \codename\core\io\helper\deepaccess::get($this->pipelineInstance->getConfig()->get('constants'), $field); - } else { - return $this->pipelineInstance->getConfig()->get('constants>'.$field); - } - } else if($sourceType == 'erroneous') { - // a value from the error handling - throw new \LogicException('Not implemented'); - } else { - // Error case. Unknown/Invalid source type - throw new exception('EXCEPTION_TRANSFORM_GETVALUE_INVALID_SOURCE_TYPE', exception::$ERRORLEVEL_ERROR); + /** + * [transform description] + * @param mixed $value [input value] + * @return mixed|null [transform result] + */ + public function transform(mixed $value): mixed + { + if ($this->isCached($value)) { + // use cached transform result + return $this->cacheValue; + } else { + $start = null; + if ($this->debug || ($this->pipelineInstance && $this->pipelineInstance->debug)) { + $start = microtime(true); + } + + // + // perform the real transform + // + $transformResult = $this->internalTransform($value); + + if ($this->debug || ($this->pipelineInstance && $this->pipelineInstance->debug)) { + $this->durationMeasured = (microtime(true) - $start); + $this->durationsMeasured[] = $this->durationMeasured; + } + + // + // fill instance cache + // + $this->setCacheValue($value, $transformResult); + + return $transformResult; + } } - } - /** - * returns the specification for this transform - * @return array - */ - public abstract function getSpecification() : array; + /** + * @param mixed $parameters + * @return bool + */ + protected function isCached(mixed $parameters): bool + { + return $this->cached; + } + /** + * internal transformation + * override this method to implement + * the 'real' transform + * + * @param mixed $value [input value] + * @return mixed|null [transform result] + */ + abstract public function internalTransform(mixed $value): mixed; + + /** + * sets cache from current value + * and the instance's config + * @param mixed $parameters [input parameters - e.g. the current value] + * @param mixed $cacheValue [the to-be-cached value] + */ + protected function setCacheValue(mixed $parameters, mixed $cacheValue): void + { + $this->cacheValue = $cacheValue; + $this->cached = true; + } } - ?> diff --git a/backend/class/transform/calculate.php b/backend/class/transform/calculate.php index d149dd5..d3392c3 100644 --- a/backend/class/transform/calculate.php +++ b/backend/class/transform/calculate.php @@ -1,9 +1,12 @@ precision = $this->config['precision'] ?? 15; - } + $this->precision = array_key_exists('precision', $this->config) ? $this->config['precision'] : 15; + } - /** - * @inheritDoc - */ - public function internalTransform($value) - { - $v = null; + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $v = null; - foreach($this->config['factors'] as $factor) { - if ($v === null) { - $v = is_array($factor) ? $this->getValue($factor['source'], $factor['field'], $value) : $factor; - continue; - } - if(is_array($factor)) { - $v = bcdiv($v, $this->getValue($factor['source'] ?? 'source', $factor['field'], $value), $this->precision); - } else { - $v = bcdiv($v, $factor, $this->precision); - } + foreach ($this->config['factors'] as $factor) { + if ($v === null) { + $v = is_array($factor) ? $this->getValue($factor['source'], $factor['field'], $value) : $factor; + continue; + } + if (is_array($factor)) { + $v = bcdiv($v, $this->getValue($factor['source'] ?? 'source', $factor['field'], $value), $this->precision); + } else { + $v = bcdiv($v, $factor, $this->precision); + } + } + + return $v; } - return $v; - } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + $sources = []; + foreach ($this->config['factors'] as $factor) { + if (!is_array($factor)) { + // bare value + continue; + } + $sources[] = "{$factor['source']}.{$factor['field']}"; + } - /** - * @inheritDoc - */ - public function getSpecification(): array - { - $sources = []; - foreach($this->config['factors'] as $factor) { - if(!is_array($factor)) { - // bare value - continue; - } - $sources[] = "{$factor['source']}.{$factor['field']}"; + return [ + 'type' => 'transform', + 'source' => $sources, // [ "{$this->config['source']}.{$this->config['field']}" ] + ]; } - - return [ - 'type' => 'transform', - 'source' => $sources // [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } } diff --git a/backend/class/transform/calculate/multiply.php b/backend/class/transform/calculate/multiply.php index 022be9a..044760c 100644 --- a/backend/class/transform/calculate/multiply.php +++ b/backend/class/transform/calculate/multiply.php @@ -1,61 +1,69 @@ precision = $this->config['precision'] ?? 15; - } - - /** - * @inheritDoc - */ - public function internalTransform($value) - { - $v = 1; - - foreach($this->config['factors'] as $factor) { - if(!is_array($factor)) { - $v = bcmul($v, $factor, $this->precision); - } else { - $v = bcmul($v, $this->getValue($factor['source'] ?? 'source', $factor['field'], $value), $this->precision); - } +class multiply extends calculate +{ + /** + * calculation precision + * @var int + */ + protected int $precision; + + /** + * {@inheritDoc} + */ + public function __construct(array $config) + { + parent::__construct($config); + + $this->precision = array_key_exists('precision', $this->config) ? $this->config['precision'] : 15; } - return $v; - } - - /** - * @inheritDoc - */ - public function getSpecification(): array - { - $sources = []; - foreach($this->config['factors'] as $factor) { - if(!is_array($factor)) { - // bare value - continue; - } - $sources[] = "{$factor['source']}.{$factor['field']}"; + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $v = 1; + + foreach ($this->config['factors'] as $factor) { + if (!is_array($factor)) { + $v = bcmul($v, $factor, $this->precision); + } else { + $v = bcmul($v, $this->getValue($factor['source'] ?? 'source', $factor['field'], $value), $this->precision); + } + } + + return $v; } - return [ - 'type' => 'transform', - 'source' => $sources // [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + $sources = []; + foreach ($this->config['factors'] as $factor) { + if (!is_array($factor)) { + // bare value + continue; + } + $sources[] = "{$factor['source']}.{$factor['field']}"; + } + + return [ + 'type' => 'transform', + 'source' => $sources, + ]; + } } diff --git a/backend/class/transform/calculate/subtract.php b/backend/class/transform/calculate/subtract.php index 04ccd74..b7c3323 100644 --- a/backend/class/transform/calculate/subtract.php +++ b/backend/class/transform/calculate/subtract.php @@ -1,6 +1,10 @@ fields = $config['fields']; - $this->precision = $this->config['precision'] ?? 15; - } + $this->fields = $config['fields']; + $this->precision = array_key_exists('precision', $this->config) ? $this->config['precision'] : 15; + } - /** - * @inheritDoc - */ - public function internalTransform($value) - { - // - // NOTE: - // bcmath uses strings to represent arbitrary precision numbers. - // - $sub = null; - foreach($this->fields as $field) { - if ($sub === null) { - $sub = is_array($field) ? $this->getValue($field['source'], $field['field'], $value) : $field; - continue; - } - if(is_array($field)) { - // different value source (e.g. transform or source/source_deep) - $sub = bcsub($sub, $this->getValue($field['source'], $field['field'], $value), $this->precision); - } else { - // constant value - $sub = bcsub($sub, $field, $this->precision); - } + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + // + // NOTE: + // bcmath uses strings to represent arbitrary precision numbers. + // + $sub = null; + foreach ($this->fields as $field) { + if ($sub === null) { + $sub = is_array($field) ? $this->getValue($field['source'], $field['field'], $value) : $field; + continue; + } + if (is_array($field)) { + // different value source (e.g. transform or source/source_deep) + $sub = bcsub($sub, $this->getValue($field['source'], $field['field'], $value), $this->precision); + } else { + // constant value + $sub = bcsub($sub, $field, $this->precision); + } + } + return $sub; } - return $sub; - } - /** - * @inheritDoc - */ - public function getSpecification(): array - { - $sources = []; - foreach($this->fields as $field) { - if(!is_array($field)) { - // bare value - continue; - } - $sources[] = "{$field['source']}.{$field['field']}"; + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + $sources = []; + foreach ($this->fields as $field) { + if (!is_array($field)) { + // bare value + continue; + } + $sources[] = "{$field['source']}.{$field['field']}"; + } + return [ + 'type' => 'transform', + 'source' => $sources, + ]; } - return [ - 'type' => 'transform', - 'source' => $sources - ]; - return $sources; - } } diff --git a/backend/class/transform/calculate/sum.php b/backend/class/transform/calculate/sum.php index 7305a3c..dac8c46 100644 --- a/backend/class/transform/calculate/sum.php +++ b/backend/class/transform/calculate/sum.php @@ -1,69 +1,78 @@ fields = $config['fields']; - $this->precision = $this->config['precision'] ?? 15; - } + $this->fields = $config['fields']; + $this->precision = array_key_exists('precision', $this->config) ? $this->config['precision'] : 15; + } - /** - * @inheritDoc - */ - public function internalTransform($value) - { - // - // NOTE: - // bcmath uses strings to represent arbitrary precision numbers. - // - $sum = 0; - foreach($this->fields as $field) { - if(is_array($field)) { - // different value source (e.g. transform or source/source_deep) - $sum = bcadd($sum, $this->getValue($field['source'], $field['field'], $value), $this->precision); - } else { - // constant value - $sum = bcadd($sum, $field, $this->precision); - } + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + // + // NOTE: + // bcmath uses strings to represent arbitrary precision numbers. + // + $sum = 0; + foreach ($this->fields as $field) { + if (is_array($field)) { + // different value source (e.g. transform or source/source_deep) + $sum = bcadd($sum, $this->getValue($field['source'], $field['field'], $value), $this->precision); + } else { + // constant value + $sum = bcadd($sum, $field, $this->precision); + } + } + return $sum; } - return $sum; - } - /** - * @inheritDoc - */ - public function getSpecification(): array - { - $sources = []; - foreach($this->fields as $field) { - if(!is_array($field)) { - // bare value - continue; - } - $sources[] = "{$field['source']}.{$field['field']}"; + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + $sources = []; + foreach ($this->fields as $field) { + if (!is_array($field)) { + // bare value + continue; + } + $sources[] = "{$field['source']}.{$field['field']}"; + } + return [ + 'type' => 'transform', + 'source' => $sources, + ]; } - return [ - 'type' => 'transform', - 'source' => $sources - ]; - return $sources; - } } diff --git a/backend/class/transform/compare.php b/backend/class/transform/compare.php index b685406..fc92f5a 100644 --- a/backend/class/transform/compare.php +++ b/backend/class/transform/compare.php @@ -1,31 +1,31 @@ =, >, <, <= ) */ -abstract class compare extends \codename\core\io\transform { - - /** - * the field to compare - * @var [type] - */ - protected $field; - - /** - * the value to compare to - * @var [type] - */ - protected $value; +abstract class compare extends transform +{ + /** + * the field to compare + */ + protected mixed $field; - /** - * @inheritDoc - */ - public function __construct(array $config) - { - parent::__construct($config); - $this->field = $config['field']; - $this->value = $config['value']; - } + /** + * the value to compare to + */ + protected mixed $value; -} \ No newline at end of file + /** + * {@inheritDoc} + */ + public function __construct(array $config) + { + parent::__construct($config); + $this->field = $config['field'] ?? null; + $this->value = $config['value'] ?? null; + } +} diff --git a/backend/class/transform/compare/beginswith.php b/backend/class/transform/compare/beginswith.php index 5a3d9bc..6f0429f 100644 --- a/backend/class/transform/compare/beginswith.php +++ b/backend/class/transform/compare/beginswith.php @@ -1,31 +1,37 @@ getValue($this->config['source'] ?? 'source', $this->config['field'], $value); - return substr($baseValue, 0, strlen($this->value)) === $this->value; - } - - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - // TODO: implement transform as a source! - 'source' => [ "source.{$this->config['field']}" ] - ]; - } +class beginswith extends compare +{ + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + // NOTE: fallback to source, if none defined + $baseValue = $this->getValue($this->config['source'] ?? 'source', $this->config['field'], $value); + return str_starts_with($baseValue, $this->value); + } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + // TODO: implement transform as a source! + 'source' => ["source.{$this->config['field']}"], + ]; + } } diff --git a/backend/class/transform/compare/datetime.php b/backend/class/transform/compare/datetime.php index 3e3613b..49bc253 100644 --- a/backend/class/transform/compare/datetime.php +++ b/backend/class/transform/compare/datetime.php @@ -1,61 +1,67 @@ config['left']; + $rightConfig = $this->config['right']; - /** - * @inheritDoc - */ - public function internalTransform($value) - { - $leftConfig = $this->config['left']; - $rightConfig = $this->config['right']; + $leftValue = $this->getValue($leftConfig['source'], $leftConfig['field'], $value); + $rightValue = $this->getValue($rightConfig['source'], $rightConfig['field'], $value); - $leftValue = $this->getValue($leftConfig['source'], $leftConfig['field'], $value); - $rightValue = $this->getValue($rightConfig['source'], $rightConfig['field'], $value); + $left = \DateTime::createFromFormat($leftConfig['source_format'] ?? $this->config['source_format'], $leftValue); + $right = \DateTime::createFromFormat($rightConfig['source_format'] ?? $this->config['source_format'], $rightValue); - $left = \DateTime::createFromFormat($leftConfig['source_format'] ?? $this->config['source_format'], $leftValue); - $right = \DateTime::createFromFormat($rightConfig['source_format'] ?? $this->config['source_format'], $rightValue); + if ($leftConfig['modify'] ?? false) { + $left->modify($leftConfig['modify']); + } + if ($rightConfig['modify'] ?? false) { + $right->modify($rightConfig['modify']); + } - if($leftConfig['modify'] ?? false) { - $left->modify($leftConfig['modify']); - } - if($rightConfig['modify'] ?? false) { - $right->modify($rightConfig['modify']); - } + if ($this->config['set_time_to_null'] ?? false) { + $left->setTime(0, 0); + $right->setTime(0, 0); + } - if ($this->config['set_time_to_null'] ?? false) { - $left->setTime(0,0); - $right->setTime(0,0); + /** + * results like bccomp + * @link http://php.net/manual/de/function.bccomp.php + */ + if ($left == $right) { + return 0; + } elseif ($left < $right) { + return -1; + } else { + return 1; + } } /** - * results like bccomp - * @link http://php.net/manual/de/function.bccomp.php + * {@inheritDoc} */ - if($left == $right) { - return 0; - } else if($left < $right) { - return -1; - } else { - return 1; + public function getSpecification(): array + { + return [ + 'type' => 'transform', + // TODO: implement transform as a source! + 'source' => ["TODO_SPEC"], + ]; } - } - - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - // TODO: implement transform as a source! - 'source' => [ "TODO_SPEC" ] - ]; - } - } diff --git a/backend/class/transform/compare/isday.php b/backend/class/transform/compare/isday.php index b6b66ef..24cc1ae 100644 --- a/backend/class/transform/compare/isday.php +++ b/backend/class/transform/compare/isday.php @@ -1,36 +1,42 @@ getValue($this->config['source'] ?? 'source', $this->config['field'], $value); - $datetime = new \DateTime($v); - $day = $datetime->format('l'); - if (is_array($this->value)) { - return in_array($day,$this->value); - } else { - return ($day === $this->value ? true : false); +class isday extends compare +{ + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $v = $this->getValue($this->config['source'] ?? 'source', $this->config['field'], $value); + $datetime = new \DateTime($v); + $day = $datetime->format('l'); + if (is_array($this->value)) { + return in_array($day, $this->value); + } else { + return $day === $this->value; + } } - } - - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - // TODO: implement transform as a source! - 'source' => [ "source.{$this->config['field']}" ] - ]; - } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + // TODO: implement transform as a source! + 'source' => ["source.{$this->config['field']}"], + ]; + } } diff --git a/backend/class/transform/compare/isequal.php b/backend/class/transform/compare/isequal.php index bd49612..abc6816 100644 --- a/backend/class/transform/compare/isequal.php +++ b/backend/class/transform/compare/isequal.php @@ -1,30 +1,36 @@ getValue($this->config['source'] ?? 'source', $this->config['field'], $value) == $this->value; - } - - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - // TODO: implement transform as a source! - 'source' => [ "source.{$this->config['field']}" ] - ]; - } +class isequal extends compare +{ + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + // NOTE: fallback to source, if none defined + return $this->getValue($this->config['source'] ?? 'source', $this->config['field'], $value) == $this->value; + } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + // TODO: implement transform as a source! + 'source' => ["source.{$this->config['field']}"], + ]; + } } diff --git a/backend/class/transform/compare/isholiday.php b/backend/class/transform/compare/isholiday.php index 8218068..48b87bb 100644 --- a/backend/class/transform/compare/isholiday.php +++ b/backend/class/transform/compare/isholiday.php @@ -1,44 +1,51 @@ config['country']; - $dateConfig = $this->config['date']; - - $countryValue = $this->getValue($countryConfig['source'], $countryConfig['field'], $value); - $dateValue = $this->getValue($dateConfig['source'], $dateConfig['field'], $value); - - $result = app::getModel('holidays') - ->addFilter('holidays_country', $countryValue) - ->addFilter('holidays_orderitemcommission_type', 'energy') //TODO - ->addFilter('holidays_check_date', $dateValue) - ->addFilter('holidays_can_change', false) - ->search()->getResult(); - - return (count($result) === 1 ? true : false); - } - - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - // TODO: implement transform as a source! - 'source' => [ "source.{$this->config['country']['field']}", "source.{$this->config['date']['field']}" ] - ]; - } - +class isholiday extends compare +{ + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws ReflectionException + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $countryConfig = $this->config['country']; + $dateConfig = $this->config['date']; + + $countryValue = $this->getValue($countryConfig['source'], $countryConfig['field'], $value); + $dateValue = $this->getValue($dateConfig['source'], $dateConfig['field'], $value); + + $result = app::getModel('holidays') + ->addFilter('holidays_country', $countryValue) + ->addFilter('holidays_orderitemcommission_type', 'energy') //TODO + ->addFilter('holidays_check_date', $dateValue) + ->addFilter('holidays_can_change', false) + ->search()->getResult(); + + return count($result) === 1; + } + + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + // TODO: implement transform as a source! + 'source' => ["source.{$this->config['country']['field']}", "source.{$this->config['date']['field']}"], + ]; + } } diff --git a/backend/class/transform/compare/number.php b/backend/class/transform/compare/number.php index f26acfa..82bc55f 100644 --- a/backend/class/transform/compare/number.php +++ b/backend/class/transform/compare/number.php @@ -1,71 +1,74 @@ operator = $config['operator']; - $this->precision = $config['precision']; - } - - /** - * operator to use - * @var string - */ - protected $operator = null; +class number extends compare +{ + /** + * operator to use + * @var string + */ + protected string $operator; + /** + * precision for BCMath to use + * @var int + */ + protected int $precision; - /** - * precision for BCMath to use - * @var int - */ - protected $precision = null; + /** + * {@inheritDoc} + */ + public function __construct(array $config) + { + parent::__construct($config); + $this->operator = $config['operator']; + $this->precision = $config['precision']; + } - /** - * @inheritDoc - */ - public function internalTransform($value) - { - // NOTE: fallback to source, if none defined - $v = $this->getValue($this->config['source'], $this->config['field'], $value); - $v2 = is_array($this->value) ? $this->getValue($this->value['source'], $this->value['field'], $value) : $this->value; + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + // NOTE: fallback to source, if none defined + $v = $this->getValue($this->config['source'], $this->config['field'], $value); + $v2 = is_array($this->value) ? $this->getValue($this->value['source'], $this->value['field'], $value) : $this->value; - if($this->operator === '=') { - return bccomp($v, $v2, $this->precision) === 0; - } else if($this->operator === '!=') { - return bccomp($v, $v2, $this->precision) !== 0; - } else if($this->operator === '>') { - return bccomp($v, $v2, $this->precision) === 1; - } else if($this->operator === '<') { - return bccomp($v, $v2, $this->precision) === -1; - } else if($this->operator === '>=') { - return bccomp($v, $v2, $this->precision) >= 0; - } else if($this->operator === '<=') { - return bccomp($v, $v2, $this->precision) <= 0; - } else { - throw new exception('INVALID_OPERATOR', exception::$ERRORLEVEL_ERROR, $this->operator); + if ($this->operator === '=') { + return bccomp($v, $v2, $this->precision) === 0; + } elseif ($this->operator === '!=') { + return bccomp($v, $v2, $this->precision) !== 0; + } elseif ($this->operator === '>') { + return bccomp($v, $v2, $this->precision) === 1; + } elseif ($this->operator === '<') { + return bccomp($v, $v2, $this->precision) === -1; + } elseif ($this->operator === '>=') { + return bccomp($v, $v2, $this->precision) >= 0; + } elseif ($this->operator === '<=') { + return bccomp($v, $v2, $this->precision) <= 0; + } else { + throw new exception('INVALID_OPERATOR', exception::$ERRORLEVEL_ERROR, $this->operator); + } } - } - - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - // TODO: implement transform as a source! - 'source' => [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + // TODO: implement transform as a source! + 'source' => ["{$this->config['source']}.{$this->config['field']}"], + ]; + } } diff --git a/backend/class/transform/contains.php b/backend/class/transform/contains.php index 6837112..dfcf74a 100644 --- a/backend/class/transform/contains.php +++ b/backend/class/transform/contains.php @@ -1,59 +1,66 @@ item = $config['item']; - $this->collection = $config['collection']; - } - - /** - * @inheritDoc - */ - public function internalTransform($value) - { - // NOTE: fallback to source, if none defined - if(is_array($this->item)) { - $itemValue = $this->getValue($this->item['source'], $this->item['field'], $value); - } else { - $itemValue = $this->item; - } +class contains extends transform +{ + private mixed $item; + private mixed $collection; - if(is_array($this->collection)) { - $collectionValue = $this->getValue($this->collection['source'], $this->collection['field'], $value); - } else { - throw new exception('TRANSFORM_CONTAINS_COLLECTION_MUST_BE_SOURCE_FIELD_CONFIG', exception::$ERRORLEVEL_ERROR); - } - if(!is_array($collectionValue)) { - return null; + /** + * {@inheritDoc} + */ + public function __construct(array $config) + { + parent::__construct($config); + $this->item = $config['item']; + $this->collection = $config['collection']; } - return in_array($itemValue, $collectionValue); - } - - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - // TODO: implement transform as a source! - 'source' => [ "{$this->item['source']}.{$this->item['field']}", "{$this->collection['source']}.{$this->collection['field']}" ] - ]; - } + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + // NOTE: fallback to source, if none defined + if (is_array($this->item)) { + $itemValue = $this->getValue($this->item['source'], $this->item['field'], $value); + } else { + $itemValue = $this->item; + } + + if (is_array($this->collection)) { + $collectionValue = $this->getValue($this->collection['source'], $this->collection['field'], $value); + } else { + throw new exception('TRANSFORM_CONTAINS_COLLECTION_MUST_BE_SOURCE_FIELD_CONFIG', exception::$ERRORLEVEL_ERROR); + } + if (!is_array($collectionValue)) { + return null; + } + + return in_array($itemValue, $collectionValue); + } + + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + // TODO: implement transform as a source! + 'source' => ["{$this->item['source']}.{$this->item['field']}", "{$this->collection['source']}.{$this->collection['field']}"], + ]; + } } diff --git a/backend/class/transform/convert.php b/backend/class/transform/convert.php index 5c25f2c..4fb8306 100644 --- a/backend/class/transform/convert.php +++ b/backend/class/transform/convert.php @@ -1,8 +1,12 @@ -getValue($this->config['source'], $this->config['field'], $value); - if(in_array($v, self::$positiveValues, true)) { - return true; - } else if (in_array($v, self::$negativeValues, true)) { - return false; - } else { - if($v === null && ($this->config['required'] ?? false)) { - // - // Required, but not set - case - // - $this->errorstack->addError('convert_boolean', 'MISSING_VALUE', [ - 'config' => $this->config, - 'value' => $value - ]); - } else if($v !== null) { - // - // Error case - // - $this->errorstack->addError('convert_boolean', 'INVALID_VALUE', [ - 'config' => $this->config, - 'value' => $value - ]); - } - return null; + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $v = $this->getValue($this->config['source'], $this->config['field'], $value); + if (in_array($v, self::$positiveValues, true)) { + return true; + } elseif (in_array($v, self::$negativeValues, true)) { + return false; + } else { + if ($v === null && ($this->config['required'] ?? false)) { + // + // Required, but not set - case + // + $this->errorstack->addError('convert_boolean', 'MISSING_VALUE', [ + 'config' => $this->config, + 'value' => $value, + ]); + } elseif ($v !== null) { + // + // Error case + // + $this->errorstack->addError('convert_boolean', 'INVALID_VALUE', [ + 'config' => $this->config, + 'value' => $value, + ]); + } + return null; + } } - } - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - 'source' => [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => ["{$this->config['source']}.{$this->config['field']}"], + ]; + } } diff --git a/backend/class/transform/convert/datetime.php b/backend/class/transform/convert/datetime.php index 4969817..4b99bd2 100644 --- a/backend/class/transform/convert/datetime.php +++ b/backend/class/transform/convert/datetime.php @@ -1,168 +1,167 @@ source = $this->config['source']; - $this->field = $this->config['field']; - $this->required = $this->config['required'] ?? null; - $this->sourceFormat = $this->config['source_format']; - $this->sourceFormatIsArray = is_array($this->config['source_format']); - $this->targetFormat = $this->config['target_format']; - - if(in_array($this->targetFormat, ['DateTime', 'DateTimeImmutable'])) { - $this->datetimeObjectConversion = true; - } - - if($modify = $this->config['modify'] ?? null) { - if(is_array($modify)) { - $this->modifyDynamic = $modify; - } else { - $this->modifyFixed = $modify; - } - } - $this->set_time_to_null = $this->config['set_time_to_null'] ?? null; - } - - /** - * [protected description] - * @var bool - */ - protected $datetimeObjectConversion = false; - - /** - * source type - * @var string - */ - protected $source = null; - - /** - * source field to use - * @var string - */ - protected $field = null; - - /** - * whether transform should output something non-falsy - * @var bool - */ - protected $required = null; - - /** - * whether we're using arrays for source/input format specs - * @var bool - */ - protected $sourceFormatIsArray = null; - - /** - * source format(s) allowed - * @var string|string[] - */ - protected $sourceFormat = null; - - /** - * target format to convert to - * @var string - */ - protected $targetFormat = null; - - /** - * modifier string - fixed value/modifier - * @var string|null - */ - protected $modifyFixed = null; - - /** - * modifier array - dynamic value/modifier (with transform reference) - * @var array|null - */ - protected $modifyDynamic = null; - - /** - * [protected description] - * @var bool|null - */ - protected $set_time_to_null = null; - - /** - * @inheritDoc - */ - public function internalTransform($value) - { - $v = $this->getValue($this->source, $this->field, $value); - - if($v === null) { - if($this->required) { - $this->errorstack->addError('VALUE_NULL', 0, [ - 'config' => $this->config, - 'value' => $value - ]); - } - return null; - } else { - $dt = false; - if($this->sourceFormatIsArray) { - foreach($this->sourceFormat as $sourceFormat) { - $dt = \DateTime::createFromFormat($sourceFormat, $v); - if($dt !== false) { - // first successful match - break; - } - } - } else { - $dt = \DateTime::createFromFormat($this->sourceFormat, $v); - } - if($dt !== false) { - if ($this->set_time_to_null ?? false) { - $dt->setTime(0,0); - } - if($this->modifyFixed) { - // modify using a static/fixed value - $dt->modify($this->modifyFixed); - } else if($this->modifyDynamic) { - // modify using dynamic value - $modify = $this->getValue($this->modifyDynamic['source'], $this->modifyDynamic['field'], $value); - $dt->modify($modify); +class datetime extends convert +{ + /** + * [protected description] + * @var bool + */ + protected bool $datetimeObjectConversion = false; + /** + * source type + * @var array|string + */ + protected array|string $source; + /** + * source field to use + * @var array|string + */ + protected array|string $field; + /** + * whether transform should output something non-falsy + * @var bool + */ + protected bool $required; + /** + * whether we're using arrays for source/input format specs + * @var bool + */ + protected bool $sourceFormatIsArray; + /** + * source format(s) allowed + * @var array|string + */ + protected array|string $sourceFormat; + /** + * target format to convert to + * @var string + */ + protected string $targetFormat; + /** + * modifier string - fixed value/modifier + * @var string|false + */ + protected string|false $modifyFixed = false; + /** + * modifier array - dynamic value/modifier (with transform reference) + * @var array|false + */ + protected array|false $modifyDynamic = false; + /** + * [protected description] + * @var bool + */ + protected bool $set_time_to_null; + + /** + * {@inheritDoc} + */ + public function __construct(array $config) + { + parent::__construct($config); + $this->source = $this->config['source']; + $this->field = $this->config['field']; + $this->required = $this->config['required'] ?? false; + $this->sourceFormat = $this->config['source_format']; + $this->sourceFormatIsArray = is_array($this->config['source_format']); + $this->targetFormat = $this->config['target_format']; + + if (in_array($this->targetFormat, ['DateTime', 'DateTimeImmutable'])) { + $this->datetimeObjectConversion = true; } - if($this->datetimeObjectConversion) { - if($this->targetFormat === 'DateTime') { - return $dt; - } else if($this->targetFormat === 'DateTimeImmutable') { - return \DateTimeImmutable::createFromMutable($dt); - } + if ($modify = $this->config['modify'] ?? null) { + if (is_array($modify)) { + $this->modifyDynamic = $modify; + } else { + $this->modifyFixed = $modify; + } } + $this->set_time_to_null = $this->config['set_time_to_null'] ?? false; + } - return $dt->format($this->targetFormat); - } else { - // NOTE: we have to log this error to the errorstack either way - // as we have a value (!= null) that leads to an internal conversion error - $this->errorstack->addError('convert_datetime', 'INVALID_FORMAT', [ - 'config' => $this->config, - 'value' => $value - ]); - return null; - } + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $v = $this->getValue($this->source, $this->field, $value); + + if ($v === null) { + if ($this->required) { + $this->errorstack->addError('VALUE_NULL', 0, [ + 'config' => $this->config, + 'value' => $value, + ]); + } + return null; + } else { + $dt = false; + if ($this->sourceFormatIsArray) { + foreach ($this->sourceFormat as $sourceFormat) { + $dt = \DateTime::createFromFormat($sourceFormat, $v); + if ($dt !== false) { + // first successful match + break; + } + } + } else { + $dt = \DateTime::createFromFormat($this->sourceFormat, $v); + } + if ($dt !== false) { + if ($this->set_time_to_null ?? false) { + $dt->setTime(0, 0); + } + if ($this->modifyFixed) { + // modify using a static/fixed value + $dt->modify($this->modifyFixed); + } elseif ($this->modifyDynamic) { + // modify using dynamic value + $modify = $this->getValue($this->modifyDynamic['source'], $this->modifyDynamic['field'], $value); + $dt->modify($modify); + } + + if ($this->datetimeObjectConversion) { + if ($this->targetFormat === 'DateTime') { + return $dt; + } elseif ($this->targetFormat === 'DateTimeImmutable') { + return DateTimeImmutable::createFromMutable($dt); + } + } + + return $dt->format($this->targetFormat); + } else { + // NOTE: we have to log this error to the errorstack either way + // as we have a value (!= null) that leads to an internal conversion error + $this->errorstack->addError('convert_datetime', 'INVALID_FORMAT', [ + 'config' => $this->config, + 'value' => $value, + ]); + return null; + } + } } - } - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - 'source' => [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => ["{$this->config['source']}.{$this->config['field']}"], + ]; + } } diff --git a/backend/class/transform/convert/encoding.php b/backend/class/transform/convert/encoding.php index 0861920..ff76022 100644 --- a/backend/class/transform/convert/encoding.php +++ b/backend/class/transform/convert/encoding.php @@ -1,42 +1,39 @@ getValue($this->config['source'], $this->config['field'], $value); - // TODO: Handle required field - // if($this->config['source'] == 'transform') { - // $v = $this->getTransformValue($this->config['field'], $value); - // } else if($this->config['source'] == 'source') { - // if(isset($this->config['required']) && !$this->config['required'] && !isset($value[$this->config['field']])) { - // return null; - // } else { - // $v = $value[$this->config['field']]; - // } - // } - if($v !== null) { - return mb_convert_encoding($v, $this->config['to'], $this->config['from']); - } else { - return null; +class encoding extends convert +{ + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $v = $this->getValue($this->config['source'], $this->config['field'], $value); + if ($v !== null) { + return mb_convert_encoding($v, $this->config['to'], $this->config['from']); + } else { + return null; + } } - } - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - 'source' => [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => ["{$this->config['source']}.{$this->config['field']}"], + ]; + } } diff --git a/backend/class/transform/convert/json.php b/backend/class/transform/convert/json.php index 5c5ec47..3335114 100644 --- a/backend/class/transform/convert/json.php +++ b/backend/class/transform/convert/json.php @@ -1,35 +1,43 @@ getValue($this->config['source'], $this->config['field'], $value); - if($v !== null) { - if($this->config['mode'] === 'encode') { - return json_encode($v); - } else if($this->config['mode'] === 'decode') { - return json_decode($v, true); - } else { - // error - } - } else { - return null; + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $v = $this->getValue($this->config['source'], $this->config['field'], $value); + if ($v !== null) { + if ($this->config['mode'] === 'encode') { + return json_encode($v); + } elseif ($this->config['mode'] === 'decode') { + return json_decode($v, true); + } else { + throw new LogicException('Not implemented and shouldn\'t be'); + } + } else { + return null; + } } - } - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - 'source' => [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => ["{$this->config['source']}.{$this->config['field']}"], + ]; + } } diff --git a/backend/class/transform/convert/numberformat.php b/backend/class/transform/convert/numberformat.php index e5a2b66..7141c43 100644 --- a/backend/class/transform/convert/numberformat.php +++ b/backend/class/transform/convert/numberformat.php @@ -1,197 +1,179 @@ locale = $this->config['locale']; - $this->style = $this->config['style']; - - // initialize numberformatter, only if locale & style are not arrays/objects - // and therefore static - if(!is_array($this->locale) && !is_array($this->style)) { - $this->numberFormatter = new \NumberFormatter($this->locale, self::getNumberFormatterStyle($this->style)); - } +class numberformat extends convert +{ + /** + * [EXCEPTION_CORE_IO_TRANSFORM_CONVERT_NUMBERFORMAT_INVALID_TYPE description] + * @var string + */ + public const EXCEPTION_CORE_IO_TRANSFORM_CONVERT_NUMBERFORMAT_INVALID_TYPE = 'EXCEPTION_CORE_IO_TRANSFORM_CONVERT_NUMBERFORMAT_INVALID_TYPE'; + /** + * [protected description] + * @var null|NumberFormatter + */ + protected ?NumberFormatter $numberFormatter = null; + /** + * numberformatter locale to use - or source! + * @var array|string + */ + protected array|string $locale; + /** + * numberformatter style to use - or source! + * @var array|string + */ + protected array|string $style; + /** + * [protected description] + * @var array + */ + protected array $numberFormatterInstances = []; + + /** + * {@inheritDoc} + * @param array $config + * @throws exception + */ + public function __construct(array $config) + { + parent::__construct($config); + $this->locale = $this->config['locale']; + $this->style = $this->config['style']; + + // initialize numberformatter, only if locale & style are not arrays/objects + // and therefore static + if (!is_array($this->locale) && !is_array($this->style)) { + $this->numberFormatter = new NumberFormatter($this->locale, self::getNumberFormatterStyle($this->style)); + } - if($this->numberFormatter && ($this->config['fraction_digits'] ?? null)) { - $this->numberFormatter->setAttribute(\NumberFormatter::FRACTION_DIGITS, $this->config['fraction_digits']); - } + if (($this->numberFormatter ?? false) && array_key_exists('fraction_digits', $this->config)) { + $this->numberFormatter->setAttribute(NumberFormatter::FRACTION_DIGITS, $this->config['fraction_digits']); + } - if($this->numberFormatter && ($this->config['min_fraction_digits'] ?? null)) { - $this->numberFormatter->setAttribute(\NumberFormatter::MIN_FRACTION_DIGITS, $this->config['min_fraction_digits']); - } + if (($this->numberFormatter ?? false) && array_key_exists('min_fraction_digits', $this->config)) { + $this->numberFormatter->setAttribute(NumberFormatter::MIN_FRACTION_DIGITS, $this->config['min_fraction_digits']); + } - if($this->numberFormatter && ($this->config['max_fraction_digits'] ?? null)) { - $this->numberFormatter->setAttribute(\NumberFormatter::MAX_FRACTION_DIGITS, $this->config['max_fraction_digits']); - } + if (($this->numberFormatter ?? false) && array_key_exists('max_fraction_digits', $this->config)) { + $this->numberFormatter->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $this->config['max_fraction_digits']); + } - if($this->numberFormatter && ($roundingModeStr = $this->config['rounding_mode'] ?? null)) { - $roundingMode = null; - switch($roundingModeStr) { - case 'ceiling': - $roundingMode = \NumberFormatter::ROUND_CEILING; - break; - case 'down': - $roundingMode = \NumberFormatter::ROUND_DOWN; - break; - case 'floor': - $roundingMode = \NumberFormatter::ROUND_FLOOR; - break; - case 'half_down': - $roundingMode = \NumberFormatter::ROUND_HALFDOWN; - break; - case 'half_even': - case 'symmetric': // Alias - $roundingMode = \NumberFormatter::ROUND_HALFEVEN; - break; - case 'half_up': - case 'financial': // Alias - $roundingMode = \NumberFormatter::ROUND_HALFUP; - break; - case 'up': - $roundingMode = \NumberFormatter::ROUND_UP; - break; - default: - throw new exception('INVALID_ROUNDING_MODE', exception::$ERRORLEVEL_ERROR, $roundingModeStr); - } - $this->numberFormatter->setAttribute(\NumberFormatter::ROUNDING_MODE, $roundingMode); - } + if (($this->numberFormatter ?? false) && ($roundingModeStr = $this->config['rounding_mode'] ?? null)) { + $roundingMode = match ($roundingModeStr) { + 'ceiling' => NumberFormatter::ROUND_CEILING, + 'down' => NumberFormatter::ROUND_DOWN, + 'floor' => NumberFormatter::ROUND_FLOOR, + 'half_down' => NumberFormatter::ROUND_HALFDOWN, + 'half_even', 'symmetric' => NumberFormatter::ROUND_HALFEVEN, + 'half_up', 'financial' => NumberFormatter::ROUND_HALFUP, + 'up' => NumberFormatter::ROUND_UP, + default => throw new exception('INVALID_ROUNDING_MODE', exception::$ERRORLEVEL_ERROR, $roundingModeStr), + }; + $this->numberFormatter->setAttribute(NumberFormatter::ROUNDING_MODE, $roundingMode); + } - if($this->numberFormatter && array_key_exists('grouping_separator_symbol',$this->config)) { - $this->numberFormatter->setSymbol(\NumberFormatter::GROUPING_SEPARATOR_SYMBOL, $this->config['grouping_separator_symbol']); - } - } - - /** - * [getNumberFormatter description] - * @param string $locale [description] - * @param string $style [description] - * @return [type] [description] - */ - protected function getNumberFormatter(string $locale, string $style) { - if(!isset($this->numberFormatterInstances[$locale.'-'.$style])) { - $this->numberFormatterInstances[$locale.'-'.$style] = new \NumberFormatter($locale, self::getNumberFormatterStyle($style)); + if (($this->numberFormatter ?? false) && array_key_exists('grouping_separator_symbol', $this->config)) { + $this->numberFormatter->setSymbol(NumberFormatter::GROUPING_SEPARATOR_SYMBOL, $this->config['grouping_separator_symbol']); + } } - return $this->numberFormatterInstances[$locale.'-'.$style]; - } - - /** - * [protected description] - * @var \NumberFormatter[] - */ - protected $numberFormatterInstances = []; - - /** - * [getNumberFormatterStyle description] - * @param string $style [description] - * @return int [description] - */ - protected static function getNumberFormatterStyle(string $style) { - switch ($style) { - case 'decimal': - return \NumberFormatter::DECIMAL; - default: - throw new exception('EXCEPTION_CORE_IO_TRANSFORM_CONVERT_NUMBERFORMAT_INVALID_TYPE', exception::$ERRORLEVEL_ERROR, $style); + + /** + * [getNumberFormatterStyle description] + * @param string $style [description] + * @return int [description] + * @throws exception + */ + protected static function getNumberFormatterStyle(string $style): int + { + return match ($style) { + 'decimal' => NumberFormatter::DECIMAL, + default => throw new exception('EXCEPTION_CORE_IO_TRANSFORM_CONVERT_NUMBERFORMAT_INVALID_TYPE', exception::$ERRORLEVEL_ERROR, $style), + }; } - } - - /** - * [EXCEPTION_CORE_IO_TRANSFORM_CONVERT_NUMBERFORMAT_INVALID_TYPE description] - * @var string - */ - const EXCEPTION_CORE_IO_TRANSFORM_CONVERT_NUMBERFORMAT_INVALID_TYPE = 'EXCEPTION_CORE_IO_TRANSFORM_CONVERT_NUMBERFORMAT_INVALID_TYPE'; - - /** - * @inheritDoc - */ - public function internalTransform($value) - { - $numberFormatter = null; - - if(!$this->numberFormatter) { - // - // if numberformatter isn't set, - // create one from dynamic settings - // - $locale = null; - $style = null; - // locale may be defined through a pipeline option - if(is_array($this->locale)) { - if($this->locale['source'] === 'option') { - $locale = $this->getValue($this->locale['source'], $this->locale['field'], null); + + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + if (!$this->numberFormatter) { + // + // if numberformatter isn't set, + // create one from dynamic settings + // + // locale may be defined through a pipeline option + if (is_array($this->locale)) { + if ($this->locale['source'] === 'option') { + $locale = $this->getValue($this->locale['source'], $this->locale['field'], null); + } else { + throw new exception('TRANSFORM_NUMBERFORMAT_CONFIG_LOCALE_INVALID_SOURCE', exception::$ERRORLEVEL_ERROR, $this->locale); + } + } else { + $locale = $this->config['locale']; + } + + if (is_array($this->style)) { + if ($this->style['source'] === 'option') { + $style = $this->getValue($this->style['source'], $this->style['field'], null); + } else { + throw new exception('TRANSFORM_NUMBERFORMAT_CONFIG_STYLE_INVALID_SOURCE', exception::$ERRORLEVEL_ERROR, $this->style); + } + } else { + $style = $this->config['style']; + } + + $numberFormatter = $this->getNumberFormatter($locale, $style); } else { - throw new exception('TRANSFORM_NUMBERFORMAT_CONFIG_LOCALE_INVALID_SOURCE', exception::$ERRORLEVEL_ERROR, $this->locale); + // fallback/use static numberformatter already created during .ctor + $numberFormatter = $this->numberFormatter; } - } else { - $locale = $this->config['locale']; - } - if(is_array($this->style)) { - if($this->style['source'] === 'option') { - $style = $this->getValue($this->style['source'], $this->style['field'], null); - } else { - throw new exception('TRANSFORM_NUMBERFORMAT_CONFIG_STYLE_INVALID_SOURCE', exception::$ERRORLEVEL_ERROR, $this->style); + // TODO: Handle source or transform + $parsed = $numberFormatter->parse($this->getValue($this->config['source'], $this->config['field'], $value)); + if ($parsed === false) { + // error + $this->errorstack->addError('convert_numberformat', 'INVALID_PARSE', [ + 'config' => $this->config, + 'value' => $value, + ]); + } + return $parsed; + } + + /** + * [getNumberFormatter description] + * @param string $locale [description] + * @param string $style [description] + * @return NumberFormatter [type] [description] + * @throws exception + */ + protected function getNumberFormatter(string $locale, string $style): NumberFormatter + { + if (!isset($this->numberFormatterInstances[$locale . '-' . $style])) { + $this->numberFormatterInstances[$locale . '-' . $style] = new NumberFormatter($locale, self::getNumberFormatterStyle($style)); } - } else { - $style = $this->config['style']; - } - - $numberFormatter = $this->getNumberFormatter($locale, $style); - } else { - // fallback/use static numberformatter already created during .ctor - $numberFormatter = $this->numberFormatter; + return $this->numberFormatterInstances[$locale . '-' . $style]; } - // doesn't work: - // return floatval($value); - // TODO: Handle source or transform - $parsed = $numberFormatter->parse($this->getValue($this->config['source'], $this->config['field'], $value)); - if($parsed === false) { - // error - $this->errorstack->addError('convert_numberformat', 'INVALID_PARSE', [ - 'config' => $this->config, - 'value' => $value - ]); + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => ["{$this->config['source']}.{$this->config['field']}"], + ]; } - return $parsed; - } - - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - 'source' => [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } } diff --git a/backend/class/transform/convert/numberformat/format.php b/backend/class/transform/convert/numberformat/format.php index e7320c4..bc40d02 100644 --- a/backend/class/transform/convert/numberformat/format.php +++ b/backend/class/transform/convert/numberformat/format.php @@ -1,37 +1,39 @@ getValue($this->config['source'], $this->config['field'], $value); - if($v === null && ($this->config['required'] ?? false)) { - $this->errorstack->addError('convert_numberformat_format', 'MISSING_VALUE', [ - 'config' => $this->config, - 'value' => $value - ]); - return null; - } +class format extends numberformat +{ + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $v = $this->getValue($this->config['source'], $this->config['field'], $value); + if ($v === null && ($this->config['required'] ?? false)) { + $this->errorstack->addError('convert_numberformat_format', 'MISSING_VALUE', [ + 'config' => $this->config, + 'value' => $value, + ]); + return null; + } - $formatted = $this->numberFormatter->format($v); - if($formatted === false) { - $this->errorstack->addError('convert_numberformat_format', 'INVALID_VALUE', [ - 'config' => $this->config, - 'value' => $value - ]); + $formatted = $this->numberFormatter->format($v); + if ($formatted === false) { + $this->errorstack->addError('convert_numberformat_format', 'INVALID_VALUE', [ + 'config' => $this->config, + 'value' => $value, + ]); + } + return $formatted; } - return $formatted; - } - } diff --git a/backend/class/transform/count.php b/backend/class/transform/count.php index 7ddca0d..eaa1597 100644 --- a/backend/class/transform/count.php +++ b/backend/class/transform/count.php @@ -1,33 +1,40 @@ getValue($this->config['source'], $this->config['field'], $value); + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $v = $this->getValue($this->config['source'], $this->config['field'], $value); - if(is_array($v)) { - return \count($v); - } else { - return null; + if (is_array($v)) { + return \count($v); + } else { + return null; + } } - } - /** - * @inheritDoc - */ - public function getSpecification() : array - { - return [ - 'type' => 'transform', - 'source' => [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => ["{$this->config['source']}.{$this->config['field']}"], + ]; + } } diff --git a/backend/class/transform/deepaccess.php b/backend/class/transform/deepaccess.php index 68c4725..3fceb32 100644 --- a/backend/class/transform/deepaccess.php +++ b/backend/class/transform/deepaccess.php @@ -1,63 +1,71 @@ path = $config['path']; - } else { - $this->path = explode('.', $config['path']); - } - } - - /** - * @inheritDoc - */ - public function internalTransform($value) - { - $v = null; - - // Fallback to 'source' if none provided - if(($this->config['source'] ?? 'source') == 'source' && !isset($this->config['field'])) { - $v = $value; - } else { - $v = $this->getValue($this->config['source'] ?? 'source', $this->config['field'], $value); - } + /** + * accessor/structure dive + * [ key, subkey, subsubkey, finalkey ] + * @var null|array + */ + protected ?array $path = null; + + /** + * {@inheritDoc} + */ + public function __construct(array $config) + { + parent::__construct($config); - $dive = \codename\core\io\helper\deepaccess::get($v, $this->path); + $config['path'] = $config['path'] ?? ''; - if($dive === null && ($this->config['required'] ?? false)) { - $this->errorstack->addError('VALUE_NULL', 0, [ - 'config' => $this->config, - 'value' => $value - ]); + if (is_array($config['path'])) { + $this->path = $config['path']; + } else { + $this->path = explode('.', $config['path']); + } } - return $dive; - } + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + // Fallback to 'source' if none provided + if (($this->config['source'] ?? 'source') == 'source' && !isset($this->config['field'])) { + $v = $value; + } else { + $v = $this->getValue($this->config['source'] ?? 'source', $this->config['field'], $value); + } - /** - * @inheritDoc - */ - public function getSpecification() : array - { - throw new \LogicException('Not implemented'); // TODO - } + $dive = \codename\core\helper\deepaccess::get($v, $this->path); + + if ($dive === null && ($this->config['required'] ?? false)) { + $this->errorstack->addError('VALUE_NULL', 0, [ + 'config' => $this->config, + 'value' => $value, + ]); + } + + return $dive; + } + + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + throw new LogicException('Not implemented'); // TODO + } } diff --git a/backend/class/transform/dummy.php b/backend/class/transform/dummy.php index d9d68f9..dde7cfe 100644 --- a/backend/class/transform/dummy.php +++ b/backend/class/transform/dummy.php @@ -1,38 +1,42 @@ getValue($sourceType, $field, $value); - } - - /** - * @inheritDoc - */ - public function internalTransform($value) - { - throw new \LogicException('Not implemented and shouln\'t be'); - } +class dummy extends transform +{ + /** + * returns a value from inside the pipeline + * @param string $sourceType [description] + * @param $field + * @param $value + * @return mixed [type] [description] + * @throws exception + */ + public function getInternalPipelineValue(string $sourceType, $field, $value): mixed + { + return $this->getValue($sourceType, $field, $value); + } - /** - * @inheritDoc - */ - public function getSpecification() : array - { - throw new \LogicException('Not implemented and shouln\'t be'); - } + /** + * {@inheritDoc} + */ + public function internalTransform(mixed $value): mixed + { + throw new LogicException('Not implemented and shouldn\'t be'); + } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + throw new LogicException('Not implemented and shouldn\'t be'); + } } diff --git a/backend/class/transform/explode.php b/backend/class/transform/explode.php index f9e3fdf..e943de9 100644 --- a/backend/class/transform/explode.php +++ b/backend/class/transform/explode.php @@ -1,79 +1,83 @@ delimiter = $config['delimiter'] ?? ','; + $this->limit = $config['limit'] ?? null; + $this->field = $config['field']; + } - /** - * @inheritDoc - */ - public function __construct(array $config) - { - parent::__construct($config); - $this->delimiter = $config['delimiter'] ?? ','; - $this->limit = $config['limit'] ?? null; - $this->field = $config['field']; - } + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + // NOTE: PHP's explode() with NO limit needs limit param to be omitted + // do not set it to 'null', as it equals to 0, which leads to 1 + $v = $this->getValue($this->config['source'], $this->config['field'], $value); - /** - * @inheritDoc - */ - public function internalTransform($value) - { - // NOTE: PHP's explode() with NO limit needs limit param to be omitted - // do not set it to 'null', as it equals to 0, which leads to 1 - $v = $this->getValue($this->config['source'], $this->config['field'], $value); + if (is_array($this->delimiter)) { + if (($this->delimiter['source'] ?? false) && ($this->delimiter['field'] ?? false)) { + $delimiter = $this->getValue($this->delimiter['source'], $this->delimiter['field'], $value); + } else { + throw new LogicException('Not supported: transform explode using array delimiter (non-source) or incorrect config'); + } + } else { + $delimiter = $this->delimiter; + } - $delimiter = null; - if(is_array($this->delimiter)) { - if(($this->delimiter['source'] ?? false) && ($this->delimiter['field'] ?? false)) { - $delimiter = $this->getValue($this->delimiter['source'], $this->delimiter['field'], $value); - } else { - throw new \LogicException('Not supported: transform explode using array delimiter (non-source) or incorrect config'); - } - } else { - $delimiter = $this->delimiter; + if ($this->limit !== null) { + return explode($delimiter, $v, $this->limit); + } else { + return explode($delimiter, $v); + } } - if($this->limit !== null) { - return explode($delimiter, $v, $this->limit); - } else { - return explode($delimiter, $v); + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => ["{$this->config['source']}.{$this->config['field']}"], + ]; } - - return $transformResult; - } - - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - 'source' => [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } - } diff --git a/backend/class/transform/get.php b/backend/class/transform/get.php index 654c62c..68cfb3c 100644 --- a/backend/class/transform/get.php +++ b/backend/class/transform/get.php @@ -1,9 +1,12 @@ -config['source'] == 'source') { + // special case where we need to fetch a complete array + // and access only an index later on + $v = isset($this->config['field']) ? $value[$this->config['field']] : $value; + } else { + $v = $this->getValue($this->config['source'], $this->config['field'], $value); + } - /** - * @inheritDoc - */ - public function internalTransform($value) - { - if($this->config['source'] == 'source') { - // special case where we need to fetch a complete array - // and access only an index later on - $v = isset($this->config['field']) ? $value[$this->config['field']] : $value; - } else { - $v = $this->getValue($this->config['source'], $this->config['field'], $value); + if (is_array($this->config['index'])) { + // dynamic index + $index = $this->getValue($this->config['index']['source'], $this->config['index']['field'], $value); + return array_column($v, $index); // TODO: we might use array_values additionally + } else { + return array_column($v, $this->config['index']); // TODO: we might use array_values additionally + } } - if(is_array($this->config['index'])) { - // dynamic index - $index = $this->getValue($this->config['index']['source'], $this->config['index']['field'], $value); - return array_column($v, $index); // TODO: we might use array_values additionally - } else { - return array_column($v, $this->config['index']); // TODO: we might use array_values additionally + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => $this->config['source'] == 'source' ? ["{$this->config['source']}.{$this->config['index']}"] : ["{$this->config['source']}.{$this->config['field']}"], + ]; } - } - - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - 'source' => $this->config['source'] == 'source' ? [ "{$this->config['source']}.{$this->config['index']}" ] : [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } - } diff --git a/backend/class/transform/get/arrayvalue.php b/backend/class/transform/get/arrayvalue.php index 8b6d8b0..85320d9 100644 --- a/backend/class/transform/get/arrayvalue.php +++ b/backend/class/transform/get/arrayvalue.php @@ -1,169 +1,131 @@ -source = $this->config['source'] ?? null; - $this->isSource = $this->config['source'] == 'source'; - $this->field = $this->config['field'] ?? null; - $this->indexIsArray = is_array($this->config['index']); - $this->indexValue = $this->config['index']; - $this->indexSource = $this->config['index']['source'] ?? null; - $this->indexField = $this->config['index']['field'] ?? null; - $this->required = isset($this->config['required']) && $this->config['required']; - } - - /** - * [protected description] - * @var bool - */ - protected $required = null; - - /** - * [protected description] - * @var string - */ - protected $source = null; - - /** - * [protected description] - * @var bool - */ - protected $isSource = null; - - /** - * [protected description] - * @var string - */ - protected $field = null; - - /** - * [protected description] - * @var bool - */ - protected $indexIsArray = null; - - /** - * [protected description] - * @var array|string - */ - protected $indexValue = null; - - /** - * [protected description] - * @var string - */ - protected $indexSource = null; - - /** - * [protected description] - * @var string - */ - protected $indexField = null; - - /** - * @inheritDoc - */ - public function internalTransform($value) - { - // if(!isset($this->config['source'])) { - // echo("
");
-    //   print_r($this->config);
-    //   echo("
"); - // } - - if($this->isSource) { - // special case where we need to fetch a complete array - // and access only an index later on - if($this->field) { - $v = $value[$this->field]; - } else { - $v = $value; - } - // $v = isset($this->config['field']) ? $value[$this->config['field']] : $value; - } else { - $v = $this->getValue($this->source, $this->field, $value); +class arrayvalue extends get +{ + /** + * [protected description] + * @var bool + */ + protected bool $required; + /** + * [protected description] + * @var string + */ + protected string $source; + /** + * [protected description] + * @var bool + */ + protected bool $isSource; + /** + * [protected description] + * @var null|string + */ + protected ?string $field; + /** + * [protected description] + * @var bool + */ + protected bool $indexIsArray; + /** + * [protected description] + * @var array|string + */ + protected array|string $indexValue; + /** + * [protected description] + * @var null|string + */ + protected ?string $indexSource = null; + /** + * [protected description] + * @var null|string|array + */ + protected null|string|array $indexField = null; + + /** + * {@inheritDoc} + */ + public function __construct(array $config) + { + parent::__construct($config); + + $this->source = $this->config['source'] ?? null; + $this->isSource = $this->config['source'] == 'source'; + $this->field = $this->config['field'] ?? null; + $this->indexIsArray = is_array($this->config['index']); + $this->indexValue = $this->config['index']; + $this->indexSource = $this->config['index']['source'] ?? null; + $this->indexField = $this->config['index']['field'] ?? null; + $this->required = isset($this->config['required']) && $this->config['required']; } - if($this->indexIsArray) { - // dynamic index - $index = $this->getValue($this->indexSource, $this->indexField, $value); - - if(!($v[$index] ?? false)) { - if($this->required) { - $this->errorstack->addError('GET_ARRAYVALUE_MISSING', 0, [ - 'config' => $this->config, - 'value' => $value - ]); + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + if ($this->isSource) { + // special case where we need to fetch a complete array + // and access only an index later on + if ($this->field) { + $v = $value[$this->field]; + } else { + $v = $value; + } + } else { + $v = $this->getValue($this->source, $this->field, $value); } - return null; - } - - return $v[$index]; - } else { - if(!($v[$this->indexValue] ?? false)) { - if($this->required) { - $this->errorstack->addError('GET_ARRAYVALUE_MISSING', 0, [ - 'config' => $this->config, - 'value' => $value - ]); + if ($this->indexIsArray) { + // dynamic index + $index = $this->getValue($this->indexSource, $this->indexField, $value); + + if (!($v[$index] ?? false)) { + if ($this->required) { + $this->errorstack->addError('GET_ARRAYVALUE_MISSING', 0, [ + 'config' => $this->config, + 'value' => $value, + ]); + } + return null; + } + + return $v[$index]; + } else { + if (!($v[$this->indexValue] ?? false)) { + if ($this->required) { + $this->errorstack->addError('GET_ARRAYVALUE_MISSING', 0, [ + 'config' => $this->config, + 'value' => $value, + ]); + } + return null; + } + + return $v[$this->indexValue]; } - return null; - } - - return $v[$this->indexValue]; } - - // if($this->config['source'] == 'transform') { - // $v = $this->getTransformValue($this->config['field'], $value); - // if(isset($this->config['required']) && $this->config['required'] && !isset($v[$this->config['index']])) { - // $this->errorstack->addError('GET_ARRAYVALUE_MISSING', 0, [ - // 'config' => $this->config, - // 'value' => $value - // ]); - // } - // return $v[$this->config['index']] ?? null; - // } else if($this->config['source'] == 'source') { - // // if(isset($this->config['required']) && !$this->config['required'] && !isset($value[$this->config['field']])) { - // // return null; - // // } else { - // $v = isset($this->config['field']) ? $value[$this->config['field']] : $value; - // if(!isset($v[$this->config['index']])) { - // if(isset($this->config['required']) && $this->config['required']) { - // $this->errorstack->addError('GET_ARRAYVALUE_MISSING', 0, [ - // 'config' => $this->config, - // 'value' => $value - // ]); - // } - // return null; - // } - // return $v[$this->config['index']]; - // // } - // } else { - // die("invalid transform source"); - // } - } - - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - 'source' => $this->config['source'] == 'source' ? [ "{$this->config['source']}.{$this->config['index']}" ] : [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } - + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => $this->config['source'] == 'source' ? ["{$this->config['source']}.{$this->config['index']}"] : ["{$this->config['source']}.{$this->config['field']}"], + ]; + } } diff --git a/backend/class/transform/get/conditioned.php b/backend/class/transform/get/conditioned.php index aa37e99..db2baef 100644 --- a/backend/class/transform/get/conditioned.php +++ b/backend/class/transform/get/conditioned.php @@ -1,106 +1,94 @@ -config['source'] == 'transform') { - $v = $this->getTransformValue($this->config['field'], $value); - - } else if($this->config['source'] == 'source') { - - $v = $value[$this->config['field']]; +class conditioned extends get +{ + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + // apply filter + foreach ($this->config['condition'] as $condition) { + $conditionFieldValue = $this->getValue($condition['source'], $condition['field'], $value); + // $returnFieldValue = !is_array($condition['return']) ? $condition['return'] : ($this->getValue($condition['return']['source'], $condition['return']['field'], $value)); + $comparisonValue = !is_array($condition['value']) ? $condition['value'] : ($this->getValue($condition['value']['source'], $condition['value']['field'], $value)); + switch ($condition['operator']) { + case '=': + if ($comparisonValue == $conditionFieldValue) { + return !is_array($condition['return']) ? $condition['return'] : ($this->getValue($condition['return']['source'], $condition['return']['field'], $value)); + } + break; + case '!=': + if ($comparisonValue != $conditionFieldValue) { + return !is_array($condition['return']) ? $condition['return'] : ($this->getValue($condition['return']['source'], $condition['return']['field'], $value)); + } + break; + case '>': + // NOTE: inverted order + if ($comparisonValue < $conditionFieldValue) { + return !is_array($condition['return']) ? $condition['return'] : ($this->getValue($condition['return']['source'], $condition['return']['field'], $value)); + } + break; + case '<': + // NOTE: inverted order + if ($comparisonValue > $conditionFieldValue) { + return !is_array($condition['return']) ? $condition['return'] : ($this->getValue($condition['return']['source'], $condition['return']['field'], $value)); + } + break; + default: + break; + } + } - } else { - die("invalid transform source"); - }*/ + if (isset($this->config['required']) && $this->config['required']) { + $this->errorstack->addError('GET_CONDITIONED_MISSING', 0, [ + 'config' => $this->config, + 'value' => $value, + ]); + return null; + } - - // apply filter - foreach($this->config['condition'] as $condition) { - $conditionFieldValue = $this->getValue($condition['source'], $condition['field'], $value); - // $returnFieldValue = !is_array($condition['return']) ? $condition['return'] : ($this->getValue($condition['return']['source'], $condition['return']['field'], $value)); - $comparisonValue = !is_array($condition['value']) ? $condition['value'] : ($this->getValue($condition['value']['source'], $condition['value']['field'], $value)); - switch ($condition['operator']) { - case '=': - if($comparisonValue == $conditionFieldValue) { - $returnFieldValue = !is_array($condition['return']) ? $condition['return'] : ($this->getValue($condition['return']['source'], $condition['return']['field'], $value)); - return $returnFieldValue; - } - break; - case '!=': - if($comparisonValue != $conditionFieldValue) { - $returnFieldValue = !is_array($condition['return']) ? $condition['return'] : ($this->getValue($condition['return']['source'], $condition['return']['field'], $value)); - return $returnFieldValue; - } - break; - case '>': - // NOTE: inverted order - if($comparisonValue < $conditionFieldValue) { - $returnFieldValue = !is_array($condition['return']) ? $condition['return'] : ($this->getValue($condition['return']['source'], $condition['return']['field'], $value)); - return $returnFieldValue; - } - break; - case '<': - // NOTE: inverted order - if($comparisonValue > $conditionFieldValue) { - $returnFieldValue = !is_array($condition['return']) ? $condition['return'] : ($this->getValue($condition['return']['source'], $condition['return']['field'], $value)); - return $returnFieldValue; - } - break; - default: - break; - } - } - - if(isset($this->config['required']) && $this->config['required']) { - $this->errorstack->addError('GET_CONDITIONED_MISSING', 0, [ - 'config' => $this->config, - 'value' => $value - ]); - return null; + // no filter match + // + // NOTE: $this->config['default'] MAY be FALSE => this should be the value to return in this case (see below) + // + if ($this->config['default'] ?? false) { + return !is_array($this->config['default']) ? $this->config['default'] : ($this->getValue($this->config['default']['source'], $this->config['default']['field'], $value)); + } + // NULL-coalescing using default value, which also may be null or not set. + // + // default == false => false + // default == null => null + // default undefined => null + // + return $this->config['default'] ?? null; } - // no filter match - // - // NOTE: $this->config['default'] MAY be FALSE => this should be the value to return in this case (see below) - // - if($this->config['default'] ?? false) { - return !is_array($this->config['default']) ? $this->config['default'] : ($this->getValue($this->config['default']['source'], $this->config['default']['field'], $value)); - } - // NULL-coalescing using default value, which also may be null or not set. - // - // default == false => false - // default == null => null - // default undefined => null - // - return $this->config['default'] ?? null; - } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + $sources = []; + foreach ($this->config['condition'] as $condition) { + $field = is_array($condition['field']) ? implode('.', $condition['field']) : $condition['field']; + $sources[] = "{$condition['source']}.$field"; + } - /** - * @inheritDoc - */ - public function getSpecification(): array - { - $sources = []; - foreach($this->config['condition'] as $condition) { - $field = is_array($condition['field']) ? implode('.', $condition['field']) : $condition['field']; - $sources[] = "{$condition['source']}.{$field}"; + return [ + 'type' => 'transform', + 'source' => $sources, + ]; } - - return [ - 'type' => 'transform', - 'source' => $sources - ]; - } - } diff --git a/backend/class/transform/get/conditioned/all.php b/backend/class/transform/get/conditioned/all.php index 956f3ef..b996d9c 100644 --- a/backend/class/transform/get/conditioned/all.php +++ b/backend/class/transform/get/conditioned/all.php @@ -1,55 +1,62 @@ config['condition'] as $condition) { - $conditionFieldValue = $this->getValue($condition['source'], $condition['field'], $value); - // $returnFieldValue = !is_array($condition['return']) ? $condition['return'] : ($this->getValue($condition['return']['source'], $condition['return']['field'], $value)); - $comparisonValue = !is_array($condition['value']) ? $condition['value'] : ($this->getValue($condition['value']['source'], $condition['value']['field'], $value)); - switch ($condition['operator']) { - case '=': - $evalResult &= ($comparisonValue == $conditionFieldValue); - if(!$evalResult) { - break 2; - } - break; - case '!=': - $evalResult &= ($comparisonValue != $conditionFieldValue); - if(!$evalResult) { - break 2; - } - break; - default: - break; - } - } + // apply filter + foreach ($this->config['condition'] as $condition) { + $conditionFieldValue = $this->getValue($condition['source'], $condition['field'], $value); + // $returnFieldValue = !is_array($condition['return']) ? $condition['return'] : ($this->getValue($condition['return']['source'], $condition['return']['field'], $value)); + $comparisonValue = !is_array($condition['value']) ? $condition['value'] : ($this->getValue($condition['value']['source'], $condition['value']['field'], $value)); + switch ($condition['operator']) { + case '=': + $evalResult &= ($comparisonValue == $conditionFieldValue); + if (!$evalResult) { + break 2; + } + break; + case '!=': + $evalResult &= ($comparisonValue != $conditionFieldValue); + if (!$evalResult) { + break 2; + } + break; + default: + break; + } + } - if($evalResult) { - return $this->config['return'] ?? true; - } + if ($evalResult) { + return $this->config['return'] ?? true; + } - // - // if we don't 'return' above - // we automatically have a falsy result - // - if(isset($this->config['required']) && $this->config['required']) { - $this->errorstack->addError('GET_CONDITIONED_ALL_NOMATCH', 0, [ - 'config' => $this->config, - 'value' => $value - ]); - return null; - } + // + // if we don't 'return' above + // we automatically have a falsy result + // + if (isset($this->config['required']) && $this->config['required']) { + $this->errorstack->addError('GET_CONDITIONED_ALL_NOMATCH', 0, [ + 'config' => $this->config, + 'value' => $value, + ]); + return null; + } - // no filter match - return $this->config['default'] ?? null; - } + // no filter match + return $this->config['default'] ?? null; + } } diff --git a/backend/class/transform/get/currentdatetime.php b/backend/class/transform/get/currentdatetime.php index f82618d..79fb3e5 100644 --- a/backend/class/transform/get/currentdatetime.php +++ b/backend/class/transform/get/currentdatetime.php @@ -1,31 +1,35 @@ config['modify'] ?? false) { - $datetime->modify($this->config['modify']); +class currentdatetime extends get +{ + /** + * {@inheritDoc} + */ + public function internalTransform(mixed $value): mixed + { + $datetime = new DateTime('now'); + if ($this->config['modify'] ?? false) { + $datetime->modify($this->config['modify']); + } + return $datetime->format($this->config['format']); } - return $datetime->format($this->config['format']); - } - /** - * @inheritDoc - */ - public function getSpecification() : array - { - return [ - 'type' => 'transform', - 'source' => [] - ]; - } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => [], + ]; + } } diff --git a/backend/class/transform/get/easterdatetime.php b/backend/class/transform/get/easterdatetime.php index 70eb496..5f8cf9f 100644 --- a/backend/class/transform/get/easterdatetime.php +++ b/backend/class/transform/get/easterdatetime.php @@ -1,32 +1,43 @@ getValue($this->config['source'], $this->config['field'], $value); - $datetime = new \DateTime($v); - $days = \easter_days($datetime->format('Y')); - $datetime->setDate($datetime->format('Y'), 3, 21); - $datetime->add(new \DateInterval("P{$days}D")); - return $datetime->format($this->config['format'] ?? 'Y-m-d'); - } +class easterdatetime extends get +{ + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $v = $this->getValue($this->config['source'], $this->config['field'], $value); + $datetime = new DateTime($v); + $days = easter_days($datetime->format('Y')); + $datetime->setDate($datetime->format('Y'), 3, 21); + $datetime->add(new DateInterval("P{$days}D")); + return $datetime->format($this->config['format'] ?? 'Y-m-d'); + } - /** - * @inheritDoc - */ - public function getSpecification() : array - { - return [ - 'type' => 'transform', - 'source' => [] - ]; - } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => [], + ]; + } } diff --git a/backend/class/transform/get/fallback.php b/backend/class/transform/get/fallback.php index 64ec210..20c3be6 100644 --- a/backend/class/transform/get/fallback.php +++ b/backend/class/transform/get/fallback.php @@ -1,58 +1,53 @@ -config['fallback'] as $fallback) { - $v = $this->getValue($fallback['source'], $fallback['field'], $value); - if($v !== null) { - return $v; - } - // if($fallback['source'] == 'source') { - // if(isset($value[$fallback['field']]) && $value[$fallback['field']] != null) { - // return $value[$fallback['field']]; - // } - // } else if($fallback['source'] == 'transform') { - // $v = $this->getTransformValue($fallback['field'], $value); - // if($v != null) { - // return $v; - // } - // } else { - // die("unsupported source type"); - // } - } - if(isset($this->config['required']) && $this->config['required']) { - $this->errorstack->addError('VALUE_NULL', 0, [ - 'config' => $this->config, - 'value' => $value - ]); +class fallback extends get +{ + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + foreach ($this->config['fallback'] as $fallback) { + $v = $this->getValue($fallback['source'], $fallback['field'], $value); + if ($v !== null) { + return $v; + } + } + if (isset($this->config['required']) && $this->config['required']) { + $this->errorstack->addError('VALUE_NULL', 0, [ + 'config' => $this->config, + 'value' => $value, + ]); + } + return null; } - return null; - } - /** - * @inheritDoc - */ - public function getSpecification(): array - { - $sources = []; + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + $sources = []; - foreach($this->config['fallback'] as $k => $v) { - $field = is_array($v['field']) ? implode('.', $v['field']) : $v['field']; - $sources[] = "{$v['source']}.{$field}"; - } - - return [ - 'type' => 'transform', - 'source' => $sources - ]; - } + foreach ($this->config['fallback'] as $v) { + $field = is_array($v['field']) ? implode('.', $v['field']) : $v['field']; + $sources[] = "{$v['source']}.$field"; + } + return [ + 'type' => 'transform', + 'source' => $sources, + ]; + } } diff --git a/backend/class/transform/get/filtered.php b/backend/class/transform/get/filtered.php index 50397de..9d66ff7 100644 --- a/backend/class/transform/get/filtered.php +++ b/backend/class/transform/get/filtered.php @@ -1,48 +1,55 @@ -getValue($this->config['source'], $this->config['field'], $value); - /** - * @inheritDoc - */ - public function internalTransform($value) - { - $v = $this->getValue($this->config['source'], $this->config['field'], $value); + // apply filter + foreach ($this->config['filter'] as $filter) { + switch ($filter['operator']) { + case '=': + if ($filter['value'] == $v) { + return $v; + } + break; + case '!=': + if ($filter['value'] != $v) { + return $v; + } + break; + default: + break; + } + } - // apply filter - foreach($this->config['filter'] as $filter) { - switch ($filter['operator']) { - case '=': - if($filter['value'] == $v) { - return $v; - } - break; - case '!=': - if($filter['value'] != $v) { - return $v; - } - break; - default: - break; - } + // no filter match + return null; } - // no filter match - return null; - } - - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - 'source' => [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } - + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => ["{$this->config['source']}.{$this->config['field']}"], + ]; + } } diff --git a/backend/class/transform/get/filtered/arrayfilter.php b/backend/class/transform/get/filtered/arrayfilter.php index 7394cdb..b04de54 100644 --- a/backend/class/transform/get/filtered/arrayfilter.php +++ b/backend/class/transform/get/filtered/arrayfilter.php @@ -1,59 +1,64 @@ getValue($this->config['source'], $this->config['field'], $value); + $path = $this->config['path'] ?? null; - /** - * @inheritDoc - */ - public function internalTransform($value) - { - $v = $this->getValue($this->config['source'], $this->config['field'], $value); - $path = $this->config['path'] ?? null; + $filtered = array_filter($v, function ($element) use ($path, $value) { + // we may retrieve an element's sub-key, if path is defined + $elementValue = $path ? deepaccess::get($element, $path) : $element; - $filtered = array_filter($v, function($element) use ($path, $value) { + $res = true; + // apply filter + foreach ($this->config['filter'] as $filter) { + $filterValue = is_array($filter['value']) ? $this->getValue($filter['value']['source'], $filter['value']['field'], $value) : $filter['value']; + switch ($filter['operator']) { + case '=': + $res &= ($filterValue == $elementValue); + break; + case '!=': + $res &= ($filterValue != $elementValue); + break; + default: + // TODO: Error - undefined/wrong spec? + break; + } + if (!$res) { + break; + } + } - // we may retrieve an element's sub-key, if path is defined - $elementValue = $path ? deepaccess::get($element, $path) : $element; + return $res; + }); - $res = true; - // apply filter - foreach($this->config['filter'] as $filter) { - $filterValue = is_array($filter['value']) ? $this->getValue($filter['value']['source'], $filter['value']['field'], $value) : $filter['value']; - switch ($filter['operator']) { - case '=': - $res &= ($filterValue == $elementValue); - break; - case '!=': - $res &= ($filterValue != $elementValue); - break; - default: - // TODO: Error - undefined/wrong spec? - break; + // Allow [] => null conversion + if ($this->config['null_if_empty'] ?? false) { + if (count($filtered) === 0) { + return null; + } } - if(!$res) { - break; + // return only the array values + if ($this->config['force_array'] ?? false) { + return array_values($filtered); } - } - - return $res; - }); - - // Allow [] => null conversion - if($this->config['null_if_empty'] ?? false) { - if(count($filtered) === 0) { - return null; - } - } - // return only the array values - if($this->config['force_array'] ?? false) { - return array_values($filtered); + return $filtered; } - return $filtered; - } } diff --git a/backend/class/transform/get/filtered/validated.php b/backend/class/transform/get/filtered/validated.php index a406d00..c09a740 100644 --- a/backend/class/transform/get/filtered/validated.php +++ b/backend/class/transform/get/filtered/validated.php @@ -1,71 +1,78 @@ validators = []; - foreach($validator as $validatorName) { - $this->validators[] = \codename\core\app::getValidator($validatorName); + if ($validator = $config['validator'] ?? false) { + if (is_array($validator)) { + $this->validators = []; + foreach ($validator as $validatorName) { + $this->validators[] = app::getValidator($validatorName); + } + } else { + $this->validators = [ + app::getValidator($validator), + ]; + } + } else { + throw new exception('NO_VALIDATOR_SPECIFIED', exception::$ERRORLEVEL_ERROR); } - } else { - $this->validators = [ - \codename\core\app::getValidator($validator) - ]; - } - } else { - throw new exception('NO_VALIDATOR_SPECIFIED', exception::$ERRORLEVEL_ERROR); - } - } - - /** - * @inheritDoc - */ - public function internalTransform($value) - { - // reset validators before execution - foreach($this->validators as $validatorInstance) { - $validatorInstance->reset(); } - // get value - $v = $this->getValue($this->config['source'], $this->config['field'], $value); + /** + * {@inheritDoc} + */ + public function internalTransform(mixed $value): mixed + { + // reset validators before execution + foreach ($this->validators as $validatorInstance) { + $validatorInstance->reset(); + } - $overallErrorCount = 0; + // get value + $v = $this->getValue($this->config['source'], $this->config['field'], $value); - // iterate over every validator - foreach($this->validators as $validatorInstance) { + $overallErrorCount = 0; - // validate! - $validatorInstance->validate($v); + // iterate over every validator + foreach ($this->validators as $validatorInstance) { + // validate! + $validatorInstance->validate($v); - if($errorCount = count($errors = $validatorInstance->getErrors()) > 0) { - $overallErrorCount += $errorCount; - $this->errorstack->addErrors($errors); - } - } + if (($errorCount = count($errors = $validatorInstance->getErrors())) > 0) { + $overallErrorCount += $errorCount; + $this->errorstack->addErrors($errors); + } + } - if($overallErrorCount === 0) { - return $v; - } else { - // NOTE: we already added errors before... - return null; + if ($overallErrorCount === 0) { + return $v; + } else { + // NOTE: we already added errors before... + return null; + } } - } } diff --git a/backend/class/transform/get/number.php b/backend/class/transform/get/number.php index e62cd05..919bd20 100644 --- a/backend/class/transform/get/number.php +++ b/backend/class/transform/get/number.php @@ -1,19 +1,22 @@ - 'transform', - 'source' => [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } - +abstract class number extends get +{ + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => ["{$this->config['source']}.{$this->config['field']}"], + ]; + } } diff --git a/backend/class/transform/get/number/fraction.php b/backend/class/transform/get/number/fraction.php index 8f1b82d..c9d51c9 100644 --- a/backend/class/transform/get/number/fraction.php +++ b/backend/class/transform/get/number/fraction.php @@ -1,44 +1,56 @@ -getValue($this->config['source'], $this->config['field'], $value); - - if($v === null) { - if(isset($this->config['required']) && $this->config['required']) { - $this->errorstack->addError('GET_NUMBER_REQUIRED', 0, [ - 'config' => $this->config, - 'value' => $value - ]); - } - return null; - } - - if(!is_numeric($v)) { - throw new exception('EXCEPTION_CORE_IO_TRANSFORM_GET_NUMBER_FRACTION_NOT_NUMERIC', exception::$ERRORLEVEL_ERROR, $v); - } - - // list($whole, $decimal) = sscanf($v, '%d.%d'); - // NOTE: sscanf swallowed the leading zeros - $value = explode('.', $v, 2); - - if($value[1] ?? false) { - if($this->config['fraction_digits'] ?? false) { - $value[1] = substr($value[1], 0 , $this->config['fraction_digits']); - } +class fraction extends number +{ + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $v = $this->getValue($this->config['source'], $this->config['field'], $value); + + if ($v === null) { + if (isset($this->config['required']) && $this->config['required']) { + $this->errorstack->addError('GET_NUMBER_REQUIRED', 0, [ + 'config' => $this->config, + 'value' => $value, + ]); + } + return null; + } + + if (!is_numeric($v)) { + throw new exception('EXCEPTION_CORE_IO_TRANSFORM_GET_NUMBER_FRACTION_NOT_NUMERIC', exception::$ERRORLEVEL_ERROR, $v); + } + + if ($this->config['fraction_digits'] ?? false) { + $v = round($v, $this->config['fraction_digits']); + } + + // list($whole, $decimal) = sscanf($v, '%d.%d'); + // NOTE: sscanf swallowed the leading zeros + $value = explode('.', $v, 2); + + if ($value[1] ?? false) { + if ($this->config['fraction_digits'] ?? false) { + $value[1] = substr($value[1], 0, $this->config['fraction_digits']); + $value[1] = str_pad($value[1], $this->config['fraction_digits'], 0); + } + } elseif ($this->config['fraction_digits'] ?? false) { + $value[1] = str_pad('', $this->config['fraction_digits'], 0); + } + + return $value[1] ?? null; } - - return $value[1] ?? null; // $v - floor($v); - } - } diff --git a/backend/class/transform/get/number/whole.php b/backend/class/transform/get/number/whole.php index f74477e..25661bd 100644 --- a/backend/class/transform/get/number/whole.php +++ b/backend/class/transform/get/number/whole.php @@ -1,36 +1,41 @@ -getValue($this->config['source'], $this->config['field'], $value); - /** - * @inheritDoc - */ - public function internalTransform($value) - { - $v = $this->getValue($this->config['source'], $this->config['field'], $value); - - if($v === null) { - if(isset($this->config['required']) && $this->config['required']) { - $this->errorstack->addError('GET_NUMBER_REQUIRED', 0, [ - 'config' => $this->config, - 'value' => $value - ]); - } - return null; - } + if ($v === null) { + if (isset($this->config['required']) && $this->config['required']) { + $this->errorstack->addError('GET_NUMBER_REQUIRED', 0, [ + 'config' => $this->config, + 'value' => $value, + ]); + } + return null; + } - if(!is_numeric($v)) { - throw new exception('EXCEPTION_CORE_IO_TRANSFORM_GET_NUMBER_FRACTION_NOT_NUMERIC', exception::$ERRORLEVEL_ERROR, $v); - } + if (!is_numeric($v)) { + throw new exception('EXCEPTION_CORE_IO_TRANSFORM_GET_NUMBER_FRACTION_NOT_NUMERIC', exception::$ERRORLEVEL_ERROR, $v); + } - list($whole, $decimal) = sscanf($v, '%d.%d'); - - return $whole; // floor($v); - } + [$whole, $decimal] = sscanf($v, '%d.%d'); + return $whole; + } } diff --git a/backend/class/transform/get/onetime.php b/backend/class/transform/get/onetime.php index fe6ba40..71ad70f 100644 --- a/backend/class/transform/get/onetime.php +++ b/backend/class/transform/get/onetime.php @@ -1,47 +1,54 @@ getValue($this->config['source'], $this->config['field'], $value); - } + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + return $this->getValue($this->config['source'], $this->config['field'], $value); + } - /** - * @inheritDoc - */ - public function getSpecification() : array - { - return [ - 'type' => 'transform', - 'source' => [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => ["{$this->config['source']}.{$this->config['field']}"], + ]; + } } diff --git a/backend/class/transform/get/option.php b/backend/class/transform/get/option.php index a3267e9..e7fbc96 100644 --- a/backend/class/transform/get/option.php +++ b/backend/class/transform/get/option.php @@ -1,54 +1,57 @@ -pipelineInstance->getOption($this->config['field']); - if($optionValue === null && ($this->config['required'] ?? false)) { - $this->errorstack->addError('OPTION_VALUE_NULL', 0, [ - 'config' => $this->config, - 'value' => $value, - 'option' => $this->config['field'] - ]); +class option extends get +{ + /** + * {@inheritDoc} + */ + public function internalTransform(mixed $value): mixed + { + $optionValue = $this->pipelineInstance->getOption($this->config['field']); + if ($optionValue === null && ($this->config['required'] ?? false)) { + $this->errorstack->addError('OPTION_VALUE_NULL', 0, [ + 'config' => $this->config, + 'value' => $value, + 'option' => $this->config['field'], + ]); + } + return $optionValue; } - return $optionValue; - } - - /** - * override resetCache - * to prevent cache reset - * and keep the cached value - * until destroyed - * - * @inheritDoc - */ - public function resetCache() - { - } - /** - * @inheritDoc - */ - public function resetErrors() - { - } + /** + * override resetCache + * to prevent cache reset + * and keep the cached value + * until destroyed + * + * {@inheritDoc} + */ + public function resetCache(): void + { + } - /** - * @inheritDoc - */ - public function getSpecification() : array - { - return [ - 'type' => 'transform', - 'source' => [ "option.{$this->config['field']}" ] - ]; - } + /** + * {@inheritDoc} + */ + public function resetErrors(): void + { + } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => ["option.{$this->config['field']}"], + ]; + } } diff --git a/backend/class/transform/get/randomstring.php b/backend/class/transform/get/randomstring.php index f90b70b..bfaeb50 100644 --- a/backend/class/transform/get/randomstring.php +++ b/backend/class/transform/get/randomstring.php @@ -1,25 +1,28 @@ config['chars'] ?? '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; - $length = $this->config['length']; - // @see https://stackoverflow.com/questions/4356289/php-random-string-generator - return substr(str_shuffle(str_repeat($x=$chars, ceil($length/strlen($x)) )),0,$length); - } + /** + * {@inheritDoc} + */ + public function internalTransform(mixed $value): mixed + { + $chars = $this->config['chars'] ?? '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $length = $this->config['length']; + // @see https://stackoverflow.com/questions/4356289/php-random-string-generator + return substr(str_shuffle(str_repeat($x = $chars, ceil($length / strlen($x)))), 0, $length); + } - /** - * @inheritDoc - */ - public function getSpecification() : array - { - return [ - ]; - } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + ]; + } } diff --git a/backend/class/transform/get/strcase.php b/backend/class/transform/get/strcase.php index 9721156..4977f79 100644 --- a/backend/class/transform/get/strcase.php +++ b/backend/class/transform/get/strcase.php @@ -1,76 +1,82 @@ mode = $config['mode']; - $this->mode = $config['mode']; + if (!in_array($this->mode, ['upper', 'lower'])) { + throw new exception('INVALID_STRCASE_MODE', exception::$ERRORLEVEL_ERROR, $this->mode); + } - if(!in_array($this->mode, ['upper', 'lower'])) { - throw new exception('INVALID_STRCASE_MODE', exception::$ERRORLEVEL_ERROR, $this->mode); + $this->source = $config['source']; + $this->field = $config['field']; } - $this->source = $config['source']; - $this->field = $config['field']; - } + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $v = $this->getValue($this->config['source'], $this->config['field'], $value); - /** - * @inheritDoc - */ - public function internalTransform($value) - { - $v = $this->getValue($this->config['source'], $this->config['field'], $value); + if ($v === null) { + return null; + } - if($v === null) { - return null; + if ($this->mode === 'upper') { + return strtoupper($v); + } elseif ($this->mode === 'lower') { + return strtolower($v); + } + return null; } - if($this->mode === 'upper') { - return strtoupper($v); - } else if($this->mode === 'lower') { - return strtolower($v); + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => ["{$this->config['source']}.{$this->config['field']}"], + ]; } - return null; - } - - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - 'source' => [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } - } diff --git a/backend/class/transform/get/strreplace.php b/backend/class/transform/get/strreplace.php index f21acd3..c521575 100644 --- a/backend/class/transform/get/strreplace.php +++ b/backend/class/transform/get/strreplace.php @@ -1,119 +1,124 @@ caseInsensitive = $config['case_insensitive']; - $this->source = $config['source']; - $this->field = $config['field']; - - if(is_array($search = $config['search'])) { - if($search['source'] && $search['field']) { - $this->searchDynamic = $search; - } else { - $this->searchStatic = $search; // array-based - } - } else { - $this->searchStatic = $config['search']; - } - - if(is_array($replace = $config['replace'])) { - if($replace['source'] && $replace['field']) { - $this->replaceDynamic = $replace; - } else { - $this->replaceStatic = $replace; // array-based - } - } else { - $this->replaceStatic = $config['replace']; - } - } - - /** - * static value to search for - single string or array of strings - * @var string|array|null - */ - protected $searchStatic = null; - - /** - * dynamic value to search for (other source/transform) - * @var array|null - */ - protected $searchDynamic = null; - - /** - * static value to replace with - single string or array of strings - * @var string|array|null - */ - protected $replaceStatic = null; - - /** - * dynamic value to replace with (other source/transform) - * @var array|null - */ - protected $replaceDynamic = null; - - /** - * @inheritDoc - */ - public function internalTransform($value) - { - $subject = $this->getValue($this->config['source'], $this->config['field'], $value); - - $search = $this->searchStatic; - if($this->searchDynamic) { - $search = $this->getValue($this->searchDynamic['source'], $this->searchDynamic['field'], $value); +class strreplace extends get +{ + /** + * source + * @var string + */ + protected string $source; + + /** + * field from source + * @var array|string + */ + protected array|string $field; + + + /** + * whether to work in case-insensitive mode + * @var bool + */ + protected bool $caseInsensitive = false; + /** + * static value to search for - single string or array of strings + * @var string|array|null + */ + protected string|array|null $searchStatic = null; + /** + * dynamic value to search for (other source/transform) + * @var array|null + */ + protected array|null $searchDynamic = null; + /** + * static value to replace with - single string or array of strings + * @var string|array|null + */ + protected string|array|null $replaceStatic = null; + /** + * dynamic value to replace with (other source/transform) + * @var array|null + */ + protected array|null $replaceDynamic = null; + + /** + * {@inheritDoc} + */ + public function __construct(array $config) + { + parent::__construct($config); + + $this->caseInsensitive = $config['case_insensitive'] ?? $this->caseInsensitive; + $this->source = $config['source']; + $this->field = $config['field']; + + $config['search'] = $config['search'] ?? ''; + $config['replace'] = $config['replace'] ?? ''; + + if (is_array($search = $config['search'])) { + if (($search['source'] ?? false) && ($search['field'] ?? false)) { + $this->searchDynamic = $search; + } else { + $this->searchStatic = $search; // array-based + } + } else { + $this->searchStatic = $config['search']; + } + + if (is_array($replace = $config['replace'])) { + if (($replace['source'] ?? false) && ($replace['field'] ?? false)) { + $this->replaceDynamic = $replace; + } else { + $this->replaceStatic = $replace; // array-based + } + } else { + $this->replaceStatic = $config['replace']; + } } - $replace = $this->replaceStatic; - if($this->replaceDynamic) { - $replace = $this->getValue($this->replaceDynamic['source'], $this->replaceDynamic['field'], $value); + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $subject = $this->getValue($this->config['source'], $this->config['field'], $value); + + $search = $this->searchStatic; + if ($this->searchDynamic) { + $search = $this->getValue($this->searchDynamic['source'], $this->searchDynamic['field'], $value); + } + + $replace = $this->replaceStatic; + if ($this->replaceDynamic) { + $replace = $this->getValue($this->replaceDynamic['source'], $this->replaceDynamic['field'], $value); + } + + if ($this->caseInsensitive) { + return str_ireplace($search, $replace, $subject); + } else { + return str_replace($search, $replace, $subject); + } } - if($this->caseInsensitive) { - return str_ireplace($search, $replace, $subject); - } else { - return str_replace($search, $replace, $subject); + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => ["{$this->config['source']}.{$this->config['field']}"], + ]; } - } - - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - 'source' => [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } - } diff --git a/backend/class/transform/get/substr.php b/backend/class/transform/get/substr.php index 3b26440..54147bb 100644 --- a/backend/class/transform/get/substr.php +++ b/backend/class/transform/get/substr.php @@ -1,65 +1,61 @@ start = $config['start'] ?? 0; - $this->length = $config['length'] ?? null; - $this->field = $config['field']; - } - - /** - * @inheritDoc - */ - public function internalTransform($value) - { - $v = $this->getValue($this->config['source'], $this->config['field'], $value); - - if($this->length !== null) { - return substr($v, $this->start, $this->length); - } else { - return substr($v, $this->start); +class substr extends get +{ + /** + * start + * @var int + */ + protected int $start = 0; + /** + * length + * @var null|int + */ + protected ?int $length = null; + + /** + * {@inheritDoc} + */ + public function __construct(array $config) + { + parent::__construct($config); + $this->start = $config['start'] ?? 0; + $this->length = $config['length'] ?? null; } - return $transformResult; - } - - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - 'source' => [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $v = $this->getValue($this->config['source'], $this->config['field'], $value); + + if ($this->length !== null) { + return substr($v, $this->start, $this->length); + } else { + return substr($v, $this->start); + } + } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => ["{$this->config['source']}.{$this->config['field']}"], + ]; + } } diff --git a/backend/class/transform/get/value.php b/backend/class/transform/get/value.php index a92ba86..49ffcef 100644 --- a/backend/class/transform/get/value.php +++ b/backend/class/transform/get/value.php @@ -1,27 +1,34 @@ -getValue($this->config['source'], $this->config['field'], $value); - } - - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - 'source' => ["{$this->config['source']}.{$this->config['field']}"] - ]; - } +class value extends get +{ + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + return $this->getValue($this->config['source'], $this->config['field'], $value); + } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => ["{$this->config['source']}.{$this->config['field']}"], + ]; + } } diff --git a/backend/class/transform/get/valuearray.php b/backend/class/transform/get/valuearray.php index 769ff04..d7c0738 100644 --- a/backend/class/transform/get/valuearray.php +++ b/backend/class/transform/get/valuearray.php @@ -1,89 +1,75 @@ -config['elements'] as $k => $v) { - if(!\is_array($v)) { - // bare value - $arr[$k] = $v; - } else { - $val = $this->getValue($v['source'], $v['field'], $value); - if(($v['required'] ?? false) && $val === null) { - $this->errorstack->addError('GET_VALUEARRAY_MISSING_KEY', 0, [ - 'config' => $this->config, - 'key' => $k, - 'value' => $value - ]); - continue; // ?? - } else if($val === null) { - if(!($v['allow_null'] ?? false)) { - continue; - } +class valuearray extends get +{ + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $arr = []; + foreach ($this->config['elements'] as $k => $v) { + if (!is_array($v)) { + // bare value + $arr[$k] = $v; + } else { + $val = $this->getValue($v['source'], $v['field'], $value); + if (($v['required'] ?? false) && $val === null) { + $this->errorstack->addError('GET_VALUEARRAY_MISSING_KEY', 0, [ + 'config' => $this->config, + 'key' => $k, + 'value' => $value, + ]); + continue; // ?? + } elseif ($val === null) { + if (!($v['allow_null'] ?? false)) { + continue; + } + } + $arr[$k] = $val; + } } - $arr[$k] = $val; - - // if($v['source'] == 'transform') { - // $arr[$k] = $this->getTransformValue($v['field'], $value); - // // TODO: handle required state using errorstack - // } else if($v['source'] == 'source') { - // // die("error!"); - // if(isset($v['required']) && !$this->config['required'] && !isset($value[$v['field']])) { - // // return null; - // continue; // ?? - // } else { - // if(!isset($value[$v['field']])) { - // echo("
");
-        //       print_r($value);
-        //       print_r($this);
-        //       echo("
"); - // continue; // ?? - // } - // - // $arr[$k] = $value[$v['field']]; - // } - // } else { - // die("invalid transform source"); - // } - } + return $arr; } - return $arr; - } - /** - * @inheritDoc - */ - public function getSpecification(): array - { - $sources = []; + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + $sources = []; - foreach($this->config['elements'] as $k => $v) { - if(!is_array($v)) { - // BARE VALUE! - continue; - } + foreach ($this->config['elements'] as $k => $v) { + if (!is_array($v)) { + // BARE VALUE! + continue; + } - if(is_array($v['field'])) { - $field = implode('.', $v['field']); - } else { - $field = $v['field']; - } + if (is_array($v['field'])) { + $field = implode('.', $v['field']); + } else { + $field = $v['field']; + } - $sources[$k] = "{$v['source']}.{$field}"; - } - - return [ - 'type' => 'transform', - 'source' => $sources - ]; - } + $sources[$k] = "{$v['source']}.$field"; + } + return [ + 'type' => 'transform', + 'source' => $sources, + ]; + } } diff --git a/backend/class/transform/hash.php b/backend/class/transform/hash.php index eadd37d..45fb255 100644 --- a/backend/class/transform/hash.php +++ b/backend/class/transform/hash.php @@ -1,42 +1,49 @@ config['algorithm'])) { - throw new exception('EXCEPTION_TRANSFORM_HASH_NO_ALGORITHM_SPECIFIED', exception::$ERRORLEVEL_ERROR); +class hash extends transform +{ + /** + * {@inheritDoc} + * @param array $config + * @throws exception + */ + public function __construct(array $config) + { + parent::__construct($config); + if (!isset($this->config['algorithm'])) { + throw new exception('EXCEPTION_TRANSFORM_HASH_NO_ALGORITHM_SPECIFIED', exception::$ERRORLEVEL_ERROR); + } } - } - /** - * @inheritDoc - */ - public function internalTransform($value) - { - $v = $this->getValue($this->config['source'], $this->config['field'], $value); - // TODO: handle errors / required state - return hash($this->config['algorithm'], $v); - } - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - 'source' => [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $v = $this->getValue($this->config['source'], $this->config['field'], $value); + // TODO: handle errors / required state + return hash($this->config['algorithm'], $v); + } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => ["{$this->config['source']}.{$this->config['field']}"], + ]; + } } diff --git a/backend/class/transform/implode.php b/backend/class/transform/implode.php index 5fe3aa9..80928f8 100644 --- a/backend/class/transform/implode.php +++ b/backend/class/transform/implode.php @@ -1,92 +1,99 @@ glue = $config['glue'] ?? ''; - $this->fields = $config['fields']; // array_flip($config['fields']) ?? []; - $this->allowConstants = $config['allowConstants'] ?? false; - } + /** + * {@inheritDoc} + */ + public function __construct(array $config) + { + parent::__construct($config); + $this->glue = $config['glue'] ?? ''; + $this->fields = $config['fields']; + $this->allowConstants = $config['allowConstants'] ?? false; + } - /** - * @inheritDoc - */ - public function internalTransform($value) - { - // IMPORTANT: NOTE the array_flip in the constructor + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + // IMPORTANT: NOTE the array_flip in the constructor - // implode all array field (values?) that match the given fields config - // NOTE: we may need to filter the array_values explicitly after array_intersect_key - // return implode($this->glue, array_values(array_intersect_key($value, $this->fields))); - $values = []; - foreach($this->fields as $field) { - if(\is_array($field)) { - $values[] = $this->getValue($field['source'], $field['field'], $value); - } else { - // - // CHANGED/ADDED 2019-07-17 - // supply "allowConstants" : true - // in config to enable using the bare values as array elements - // instead of trying to retrieve them from the source ($value) - // - if($this->allowConstants) { - $values[] = $field; - } else { - // NOTE: fallback to source = source - $values[] = $value[$field] ?? $this->config['fallbackValue']; + // implode all array field (values?) that match the given fields config + // NOTE: we may need to filter the array_values explicitly after array_intersect_key + // return implode($this->glue, array_values(array_intersect_key($value, $this->fields))); + $values = []; + foreach ($this->fields as $field) { + if (is_array($field)) { + $values[] = $this->getValue($field['source'], $field['field'], $value); + } elseif ($this->allowConstants) { + // + // CHANGED/ADDED 2019-07-17 + // supply "allowConstants" : true + // in config to enable using the bare values as array elements + // instead of trying to retrieve them from the source ($value) + // + $values[] = $field; + } else { + // NOTE: fallback to source = source + $values[] = $value[$field] ?? $this->config['fallbackValue']; + } } - } + return implode($this->glue, $values); } - return implode($this->glue, $values); - } - /** - * @inheritDoc - */ - public function getSpecification(): array - { - $sources = []; + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + $sources = []; - // TODO: add transform sources - foreach($this->fields as $field) { - if(is_array($field)) { - $sources[] = "{$field['source']}.{$field['field']}"; - } else { - if($this->allowConstants) { - $sources[] = "{$field}"; - } else { - // NOTE: fallback to source = source - $sources[] = "source.{$field}" ?? "fallbackValue"; + // TODO: add transform sources + foreach ($this->fields as $field) { + if (is_array($field)) { + $sources[] = "{$field['source']}.{$field['field']}"; + } elseif ($this->allowConstants) { + $sources[] = $field; + } else { + // NOTE: fallback to source = source + $sources[] = "source.$field" ?? "fallbackValue"; + } } - } - } - return [ - 'type' => 'transform', - 'source' => $sources - ]; - } + return [ + 'type' => 'transform', + 'source' => $sources, + ]; + } } diff --git a/backend/class/transform/implode/arrayvalue.php b/backend/class/transform/implode/arrayvalue.php index b0b6a18..7bc0009 100644 --- a/backend/class/transform/implode/arrayvalue.php +++ b/backend/class/transform/implode/arrayvalue.php @@ -1,43 +1,61 @@ glue = $config['glue'] ?? ''; - $this->source = $config['source'] ?? null; - $this->field = $config['field'] ?? null; - } + /** + * {@inheritDoc} + */ + public function __construct(array $config) + { + parent::__construct($config); + $this->glue = $config['glue'] ?? ''; + $this->source = $config['source']; + $this->field = $config['field']; + } - /** - * @inheritDoc - */ - public function internalTransform($value) - { - $arrayValue = $this->getValue($this->source, $this->field, $value); - return implode($this->glue, $arrayValue); - } + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $arrayValue = $this->getValue($this->source, $this->field, $value); + return implode($this->glue, $arrayValue); + } - /** - * @inheritDoc - */ - public function getSpecification(): array - { - $sources = []; - $sources[] = "{$this->source}.{$this->field}"; - return [ - 'type' => 'transform', - 'source' => $sources - ]; - } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + $sources = []; + $sources[] = "$this->source.$this->field"; + return [ + 'type' => 'transform', + 'source' => $sources, + ]; + } } diff --git a/backend/class/transform/math/round.php b/backend/class/transform/math/round.php index 535af2b..714e831 100644 --- a/backend/class/transform/math/round.php +++ b/backend/class/transform/math/round.php @@ -1,81 +1,77 @@ 10^(-1) => 0.1 - // precision 2 => 10^(-2) => 0.01 - // precision 0 => 10^0 => 1 (stripping off fraction - but will stay a float!) - // precision -1 => 10^(-(-1)) => 10 - // - $this->precision = $this->config['precision'] ?? 0; - $modeString = $this->config['mode'] ?? null; - if(!$modeString) { - $this->mode = PHP_ROUND_HALF_UP; - } else { - switch($modeString) { - case 'half_up': - case 'financial': // Alias - $this->mode = PHP_ROUND_HALF_UP; - break; - case 'half_down': - $this->mode = PHP_ROUND_HALF_DOWN; - break; - case 'half_even': - case 'symmetric': // Alias - $this->mode = PHP_ROUND_HALF_EVEN; - break; - case 'half_odd': - $this->mode = PHP_ROUND_HALF_ODD; - break; - default: - throw new exception('INVALID_ROUND_MODE', exception::$ERRORLEVEL_ERROR, $modeString); - } + // + // By default, we round to the next integer. + // in general, this is pow(10, -precision) + // e.g. + // precision 1 => 10^(-1) => 0.1 + // precision 2 => 10^(-2) => 0.01 + // precision 0 => 10^0 => 1 (stripping off fraction - but will stay a float!) + // precision -1 => 10^(-(-1)) => 10 + // + $this->precision = $this->config['precision'] ?? 0; + $modeString = $this->config['mode'] ?? null; + if (!$modeString) { + $this->mode = PHP_ROUND_HALF_UP; + } else { + $this->mode = match ($modeString) { + 'half_up', 'financial' => PHP_ROUND_HALF_UP, + 'half_down' => PHP_ROUND_HALF_DOWN, + 'half_even', 'symmetric' => PHP_ROUND_HALF_EVEN, + 'half_odd' => PHP_ROUND_HALF_ODD, + default => throw new exception('INVALID_ROUND_MODE', exception::$ERRORLEVEL_ERROR, $modeString), + }; + } } - } - /** - * @inheritDoc - */ - public function internalTransform($value) - { - $v = $this->getValue($this->config['source'] ?? 'source', $this->config['field'], $value); - return round($v, $this->precision, $this->mode); - } + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $v = $this->getValue($this->config['source'] ?? 'source', $this->config['field'], $value); + return round($v, $this->precision, $this->mode); + } - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - 'source' => [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => ["{$this->config['source']}.{$this->config['field']}"], + ]; + } } diff --git a/backend/class/transform/model.php b/backend/class/transform/model.php index abee2cb..ae1523d 100644 --- a/backend/class/transform/model.php +++ b/backend/class/transform/model.php @@ -1,242 +1,314 @@ model = app::getModel($this->config['model'], $this->config['app'] ?? '', $this->config['vendor'] ?? ''); - if($joins = $this->config['join'] ?? false) { - foreach($joins as $join) { - $this->model->addModel(app::getModel($join['model'])); - } - } - if(isset($this->config['group'])) { - foreach($this->config['group'] as $group) { - $this->model->addGroup($group); - } - } - if($calculatedFields = $this->config['calculated_fields'] ?? false) { - foreach($calculatedFields as $calculatedField) { - $this->model->addCalculatedField($calculatedField['field'], $calculatedField['calculation']); - } - } - if(isset($this->config['order'])) { - foreach($this->config['order'] as $order) { - $this->model->addOrder($order['field'], $order['order']); - } - } - } - - /** - * [doQuery description] - * @param [type] $value [description] - * @return array|null [description] - */ - protected function doQuery($value) { - $this->model->reset(); - if($this->config['filter'] ?? false) { - foreach($this->config['filter'] as $filter) { - // either use the value directly or get it from the current dataset - if($filter['value'] && isset($filter['value']['source'])) { - $useValue = $this->getValue($filter['value']['source'], $filter['value']['field'], $value); - if($useValue == null) { - // - // NOTE/CHANGED 2020-04-28: Added option "allow_null" to explicitly allow NULL values - // for filtering here - // - if($filter['value']['allow_null'] ?? false) { - // Do nothing - } else { - if($this->config['required'] ?? false) { - $this->errorstack->addError('VALUE_NULL', 0, [ - 'config' => $this->config, - 'value' => $value - ]); - } - return null; +abstract class model extends transform +{ + /** + * [protected description] + * @var \codename\core\model + */ + protected \codename\core\model $model; + + /** + * {@inheritDoc} + * @param array $config + * @throws ReflectionException + * @throws exception + */ + public function __construct(array $config) + { + parent::__construct($config); + $this->model = $this->buildModelStructure($this->config); + if (isset($this->config['group'])) { + foreach ($this->config['group'] as $group) { + $this->model->addGroup($group); } - } - } else { - $useValue = $filter['value']; } - // $value = is_array($filter['value']) && (isset($filter['value']['source']) || isset($filter['value']['transform'])) ? $value[$filter['value']['field']] : $filter['value']; - $this->model->addFilter($filter['field'], $useValue, $filter['operator']); - } - } - - if($this->config['aggregate_filter'] ?? false) { - foreach($this->config['aggregate_filter'] as $filter) { - if($filter['value'] && isset($filter['value']['source'])) { - $useValue = $this->getValue($filter['value']['source'], $filter['value']['field'], $value); - if($useValue == null) { - if($this->config['required'] ?? false) { - $this->errorstack->addError('VALUE_NULL', 0, [ - 'config' => $this->config, - 'value' => $value - ]); + if ($calculatedFields = $this->config['calculated_fields'] ?? false) { + foreach ($calculatedFields as $calculatedField) { + $this->model->addCalculatedField($calculatedField['field'], $calculatedField['calculation']); + } + } + if (isset($this->config['order'])) { + foreach ($this->config['order'] as $order) { + $this->model->addOrder($order['field'], $order['order']); } - return null; - } - } else { - $useValue = $filter['value']; } - $this->model->addAggregateFilter($filter['field'], $useValue, $filter['operator']); - } } - if($this->config['flagfilter'] ?? false) { - $flags = $this->model->config->get('flag'); + /** + * [buildModelStructure description] + * @param array $config [description] + * @return \codename\core\model [description] + * @throws ReflectionException + * @throws exception + */ + protected function buildModelStructure(array $config): \codename\core\model + { + $model = app::getModel($config['model'], $config['app'] ?? '', $config['vendor'] ?? ''); - $flagStates = $this->config['flagfilter']['states'] ?? null; - if($flagStates) { - if(is_array($flagStates) && ($flagStates['source'] ?? false)) { - // dynamic source - $flagStates = $this->getValue($flagStates['source'], $flagStates['field'], $value); + if ($config['virtualFieldResult'] ?? false) { + $model->setVirtualFieldResult(true); } - foreach($flagStates as $flagName => $state) { - if($state) { - $this->model->withFlag($flags[$flagName]); - } else { - $this->model->withoutFlag($flags[$flagName]); - } + if ($fields = $config['fields'] ?? null) { + $model->hideAllFields(); + foreach ($fields as $field) { + $model->addField($field); + } } - } - $withFlag = $this->config['flagfilter']['with_flag'] ?? null; - if($withFlag) { - if(is_array($withFlag) && ($withFlag['source'] ?? false)) { - // dynamic source - $withFlag = $this->getValue($withFlag['source'], $withFlag['field'], $value); + if ($joins = $config['join'] ?? null) { + foreach ($joins as $join) { + $joinModel = $this->buildModelStructure($join); + if (($join['type'] ?? false) === 'collection') { + $model->addCollectionModel($joinModel, $join['modelfield'] ?? null); + } else { + $model->addModel($joinModel); + } + } } - $withFlag = is_array($withFlag) ? $withFlag : [ $withFlag ]; - foreach($withFlag as $flag) { - $this->model->withFlag($flags[$flag]); - } - } + return $model; + } - $withoutFlag = $this->config['flagfilter']['without_flag'] ?? null; - if($withoutFlag) { - if(is_array($withoutFlag) && ($withoutFlag['source'] ?? false)) { - // dynamic source - $withoutFlag = $this->getValue($withoutFlag['source'], $withoutFlag['field'], $value); - } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + $sources = [ + "model.{$this->config['model']}", + ]; - $withoutFlag = is_array($withoutFlag) ? $withoutFlag : [ $withoutFlag ]; - foreach($withoutFlag as $flag) { - $this->model->withFlag($flags[$flag]); + if (isset($this->config['filter'])) { + foreach ($this->config['filter'] as $filter) { + if (isset($filter['value']['source'])) { + $field = is_array($filter['value']['field']) ? implode('.', $filter['value']['field']) : $filter['value']['field']; + $sources[] = "{$filter['value']['source']}.$field"; + } else { + // add pure value sources? + } + } } - } - } - if(isset($this->config['filtercollection'])) { - foreach($this->config['filtercollection'] as $name => $filtercollection) { - $filters = []; - foreach($filtercollection['filters'] as $filter) { - $useValue = null; - if($filter['value'] && isset($filter['value']['source'])) { - $useValue = $this->getValue($filter['value']['source'], $filter['value']['field'], $value); - if($useValue == null) { - if($this->config['required']) { - $this->errorstack->addError('VALUE_NULL', 0, [ - 'config' => $this->config, - 'value' => $value - ]); - } - // return null; + if (isset($this->config['filtercollection'])) { + foreach ($this->config['filtercollection'] as $filtercollection) { + foreach ($filtercollection['filters'] as $filter) { + if ($filter['value'] && isset($filter['value']['source'])) { + $field = is_array($filter['value']['field']) ? implode('.', $filter['value']['field']) : $filter['value']['field']; + $sources[] = "{$filter['value']['source']}.$field"; + } else { + // add pure value sources? + } + } } - } else { - $useValue = $filter['value']; - } - $filters[] = [ - 'field' => $filter['field'], - 'value' => $useValue, - 'operator' => $filter['operator'], - ]; } - $this->model->addFilterCollection($filters, $filtercollection['group_operator'], $name, $filtercollection['conjunction']); - } + + return [ + 'type' => 'transform', + 'source' => $sources, + ]; } /** - * DONT YOU EVER DARE TO ADD GROUPS EVERY TIME THIS CODE RUNS - * - * In case you still do, please follow these guidelines: - * - * 1. Pick the nearest piece of wood or wooden objects - * 2. Grab with both hands in front of the facial area - * 3. Slap until bleed. + * [doQuery description] + * @param mixed $value [description] + * @return array|null [description] + * @throws ReflectionException + * @throws exception */ - /* if(isset($this->config['group'])) { - foreach($this->config['group'] as $group) { - $this->model->addGroup($group); - } - }*/ - - if(isset($this->config['debug']) && $this->config['debug']) { - echo("
");
-      print_r($this->model);
-      echo("
"); - // die(); - } + protected function doQuery(mixed $value): ?array + { + $this->model->reset(); + if ($this->config['filter'] ?? false) { + foreach ($this->config['filter'] as $filter) { + // either use the value directly or get it from the current dataset + if ($filter['value'] && isset($filter['value']['source'])) { + $useValue = $this->getValue($filter['value']['source'], $filter['value']['field'], $value); + if ($useValue == null) { + // + // NOTE/CHANGED 2020-04-28: Added option "allow_null" to explicitly allow NULL values + // for filtering here + // + if ($filter['value']['allow_null'] ?? false) { + // Do nothing + } else { + if ($this->config['required'] ?? false) { + $this->errorstack->addError('VALUE_NULL', 0, [ + 'config' => $this->config, + 'value' => $value, + ]); + } + return null; + } + } + } else { + $useValue = $filter['value']; + } + $this->model->addFilter($filter['field'], $useValue, $filter['operator']); + } + } - return $this->model->search()->getResult(); - } - - /** - * @inheritDoc - */ - public function getSpecification(): array - { - $sources = [ - "model.{$this->config['model']}" - ]; - - if(isset($this->config['filter'])) { - foreach($this->config['filter'] as $filter) { - if($filter['value'] && isset($filter['value']['source'])) { - $field = is_array($filter['value']['field']) ? implode('.', $filter['value']['field']) : $filter['value']['field']; - $sources[] = "{$filter['value']['source']}.{$field}"; - } else { - // add pure value sources? + if ($this->config['custom_filter'] ?? false) { + foreach ($this->config['custom_filter'] as $customFilter) { + // either use the value directly or get it from the current dataset + if (isset($customFilter['value']['source'])) { + $useValue = $this->getValue($customFilter['value']['source'], $customFilter['value']['field'], $value); + if ($useValue == null) { + if ($customFilter['value']['allow_null'] ?? false) { + // Do nothing + } else { + if ($this->config['required'] ?? false) { + $this->errorstack->addError('VALUE_NULL', 0, [ + 'config' => $this->config, + 'value' => $value, + ]); + } + return null; + } + } + } else { + $useValue = $customFilter['value']; + } + + $filterPlugin = new custom( + \codename\core\value\text\modelfield\dummy::getInstance( + $customFilter['field'] + ), + $useValue, + $customFilter['operator'] + ); + $this->model->addFilterPlugin($filterPlugin); + } } - } - } - if(isset($this->config['filtercollection'])) { - foreach($this->config['filtercollection'] as $name => $filtercollection) { - foreach($filtercollection['filters'] as $filter) { - if($filter['value'] && isset($filter['value']['source'])) { - $field = is_array($filter['value']['field']) ? implode('.', $filter['value']['field']) : $filter['value']['field']; - $sources[] = "{$filter['value']['source']}.{$field}"; - } else { - // add pure value sources? - } + if ($this->config['aggregate_filter'] ?? false) { + foreach ($this->config['aggregate_filter'] as $filter) { + if ($filter['value'] && isset($filter['value']['source'])) { + $useValue = $this->getValue($filter['value']['source'], $filter['value']['field'], $value); + if ($useValue == null) { + if ($this->config['required'] ?? false) { + $this->errorstack->addError('VALUE_NULL', 0, [ + 'config' => $this->config, + 'value' => $value, + ]); + } + return null; + } + } else { + $useValue = $filter['value']; + } + $this->model->addAggregateFilter($filter['field'], $useValue, $filter['operator']); + } } - } - } - return [ - 'type' => 'transform', - 'source' => $sources - ]; - } + if ($this->config['flagfilter'] ?? false) { + $flags = $this->model->config->get('flag'); + + $flagStates = $this->config['flagfilter']['states'] ?? null; + if ($flagStates) { + if (is_array($flagStates) && ($flagStates['source'] ?? false)) { + // dynamic source + $flagStates = $this->getValue($flagStates['source'], $flagStates['field'], $value); + } + + foreach ($flagStates as $flagName => $state) { + if ($state) { + $this->model->withFlag($flags[$flagName]); + } else { + $this->model->withoutFlag($flags[$flagName]); + } + } + } + + $withFlag = $this->config['flagfilter']['with_flag'] ?? null; + if ($withFlag) { + if (is_array($withFlag) && ($withFlag['source'] ?? false)) { + // dynamic source + $withFlag = $this->getValue($withFlag['source'], $withFlag['field'], $value); + } + $withFlag = is_array($withFlag) ? $withFlag : [$withFlag]; + foreach ($withFlag as $flag) { + $this->model->withFlag($flags[$flag]); + } + } + + $withoutFlag = $this->config['flagfilter']['without_flag'] ?? null; + if ($withoutFlag) { + if (is_array($withoutFlag) && ($withoutFlag['source'] ?? false)) { + // dynamic source + $withoutFlag = $this->getValue($withoutFlag['source'], $withoutFlag['field'], $value); + } + + $withoutFlag = is_array($withoutFlag) ? $withoutFlag : [$withoutFlag]; + foreach ($withoutFlag as $flag) { + $this->model->withFlag($flags[$flag]); + } + } + } + + if (isset($this->config['filtercollection'])) { + foreach ($this->config['filtercollection'] as $name => $filtercollection) { + $filters = []; + foreach ($filtercollection['filters'] as $filter) { + $useValue = null; + if ($filter['value'] && isset($filter['value']['source'])) { + $useValue = $this->getValue($filter['value']['source'], $filter['value']['field'], $value); + if ($useValue == null) { + if ($this->config['required']) { + $this->errorstack->addError('VALUE_NULL', 0, [ + 'config' => $this->config, + 'value' => $value, + ]); + } + } + } else { + $useValue = $filter['value']; + } + $filters[] = [ + 'field' => $filter['field'], + 'value' => $useValue, + 'operator' => $filter['operator'], + ]; + } + $this->model->addFilterCollection($filters, $filtercollection['group_operator'], $name, $filtercollection['conjunction']); + } + } + + /** + * DON'T YOU EVER DARE TO ADD GROUPS EVERY TIME THIS CODE RUNS + * + * In case you still do, please follow these guidelines: + * + * 1. Pick the nearest piece of wood or wooden objects + * 2. Grab with both hands in front of the facial area + * 3. Slap until bleed. + */ + /* if(isset($this->config['group'])) { + foreach($this->config['group'] as $group) { + $this->model->addGroup($group); + } + }*/ + + if (isset($this->config['debug']) && $this->config['debug']) { + echo("
");
+            print_r($this->model);
+            echo("
"); + // die(); + } + + return $this->model->search()->getResult(); + } } diff --git a/backend/class/transform/model/map.php b/backend/class/transform/model/map.php index 3d167bc..7aa5893 100644 --- a/backend/class/transform/model/map.php +++ b/backend/class/transform/model/map.php @@ -1,9 +1,12 @@ model->saveLastQuery = true; - $result = $this->doQuery($value); - - if($result && (count($result) === 1)) { - return $result[0][$this->config['map']]; // return a specific key's value - } else { - - /* - echo("
");
-      print_r([
-        'result' => $result,
-        'config' => $this->config,
-        'value' => $value
-      ]);
-      echo("
"); - die("no or multiple results!"); - */ - if(isset($this->config['required']) && $this->config['required']) { - /* - self::$counter++; - - echo("
");
-        print_r([
-          'config' => $this->config,
-          'value' => $value
-        ]);
-        echo("
"); - - if(self::$counter == 10) { - die(); +class single extends map +{ + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws ReflectionException + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $this->model->saveLastQuery = true; + $result = $this->doQuery($value); + + if ($result && (count($result) === 1)) { + return $result[0][$this->config['map']]; // return a specific key's value + } elseif (isset($this->config['required']) && $this->config['required']) { + $this->errorstack->addError($this->config['map'], 'MAP_ERROR', [ + 'config' => $this->config, + 'value' => $value, + ]); } - */ - - $this->errorstack->addError($this->config['map'], 'MAP_ERROR', [ - 'config' => $this->config, - 'value' => $value - ]); - } + return null; } - return null; - } - } diff --git a/backend/class/transform/model/map/single/onetime.php b/backend/class/transform/model/map/single/onetime.php index d3bbf58..1f3718b 100644 --- a/backend/class/transform/model/map/single/onetime.php +++ b/backend/class/transform/model/map/single/onetime.php @@ -1,24 +1,27 @@ model->saveLastQuery = true; - $result = $this->doQuery($value); - - $this->debugInfo = [ - 'query' => $this->model->getLastQuery(), - 'result' => $result - ]; +class all extends result +{ + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws ReflectionException + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $this->model->saveLastQuery = true; + $result = $this->doQuery($value); - return $result; - } + $this->debugInfo = [ + 'query' => $this->model->getLastQuery(), + 'result' => $result, + ]; + return $result; + } } diff --git a/backend/class/transform/model/result/all/onetime.php b/backend/class/transform/model/result/all/onetime.php index 7a6f7cf..87efcb5 100644 --- a/backend/class/transform/model/result/all/onetime.php +++ b/backend/class/transform/model/result/all/onetime.php @@ -1,24 +1,27 @@ model->saveLastQuery = true; - $result = $this->doQuery($value); +class one extends result +{ + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws ReflectionException + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $this->model->saveLastQuery = true; + $result = $this->doQuery($value); - // $this->debugInfo = [ - // 'query' => $this->model->getLastQuery(), - // 'result' => $result - // ]; - - if($result && (count($result) === 1)) { - return $result[0]; // return the result row - } else { - if(isset($this->config['required']) && $this->config['required']) { - $this->errorstack->addError('model_result_one', 'RESULT_ERROR', [ - 'config' => $this->config, - 'value' => $value - ]); - } + if ($result && (count($result) === 1)) { + return $result[0]; // return the result row + } elseif (isset($this->config['required']) && $this->config['required']) { + $this->errorstack->addError('model_result_one', 'RESULT_ERROR', [ + 'config' => $this->config, + 'value' => $value, + ]); + } + return null; } - return null; - } - } diff --git a/backend/class/transform/model/result/one/onetime.php b/backend/class/transform/model/result/one/onetime.php index 031fece..cf88e6f 100644 --- a/backend/class/transform/model/result/one/onetime.php +++ b/backend/class/transform/model/result/one/onetime.php @@ -1,29 +1,31 @@ getValue($this->config['data']['source'], $this->config['data']['field'], $value); - return $this->doSave($v); - } - - /** - * performs a normalization and save() using the model - * returns the last inserted id - * - * @param array $data [description] - * @return [type] [description] - */ - protected function doSave(array $data) { - $normalizedData = $this->model->normalizeData($data); - - if(!$this->isDryRun()) { - // only save, if not a dryRun - $this->model->save($normalizedData); +class save extends model +{ + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $v = $this->getValue($this->config['data']['source'], $this->config['data']['field'], $value); + return $this->doSave($v); } - if($pkeyValue = $normalizedData[$this->model->getPrimarykey()] ?? null) { - // simply return pkey value, as we're doing a save using existing PKEY value - return $pkeyValue; - } else { - if(!$this->isDryRun()) { - // we can only return an insert ID if we're not in a dry run (see above) - return $this->model->lastInsertId(); - } + /** + * performs a normalization and save() using the model + * returns the last inserted id + * + * @param array $data [description] + * @return mixed [type] [description] + * @throws exception + */ + protected function doSave(array $data): mixed + { + $normalizedData = $this->model->normalizeData($data); + + if (!$this->isDryRun()) { + // only save, if not a dryRun + $this->model->save($normalizedData); + } + + if ($pkeyValue = $normalizedData[$this->model->getPrimaryKey()] ?? null) { + // simply return pkey value, as we're doing a save using existing PKEY value + return $pkeyValue; + } elseif (!$this->isDryRun()) { + // we can only return an insert ID if we're not in a dry run (see above) + return $this->model->lastInsertId(); + } + + return 'dry-run'; } - - return 'dry-run'; - } - } diff --git a/backend/class/transform/model/save/onetime.php b/backend/class/transform/model/save/onetime.php index 088187d..83839bf 100644 --- a/backend/class/transform/model/save/onetime.php +++ b/backend/class/transform/model/save/onetime.php @@ -1,33 +1,35 @@ uniqueByFields = $config['unique_by_fields'] ?? null; - - if(!$this->uniqueByFields || count($this->uniqueByFields) === 0) { - throw new exception('EXCEPTION_TRANSFORM_MODEL_SAVE_UNIQUE_INVALID', exception::$ERRORLEVEL_ERROR, $this->uniqueByFields); - } - } - - /** - * fields (keys) used to determine uniqueness - * @var string[] - */ - protected $uniqueByFields = null; - - /** - * [protected description] - * @var array - */ - protected $cachedIds = []; - - /** - * @inheritDoc - */ - protected function doSave(array $data) - { - $path = []; - foreach($this->uniqueByFields as $field) { - // NOTE: what to do on NULL value? does it really work? - $path[] = $data[$field]; +class unique extends save +{ + /** + * fields (keys) used to determine uniqueness + * @var null|array + */ + protected ?array $uniqueByFields = null; + /** + * [protected description] + * @var array + */ + protected array $cachedIds = []; + + /** + * {@inheritDoc} + */ + public function __construct(array $config) + { + parent::__construct($config); + $this->uniqueByFields = $config['unique_by_fields'] ?? null; + + if (!$this->uniqueByFields || count($this->uniqueByFields) === 0) { + throw new exception('EXCEPTION_TRANSFORM_MODEL_SAVE_UNIQUE_INVALID', exception::$ERRORLEVEL_ERROR, $this->uniqueByFields); + } } - $key = implode('___', $path); - - if(!($this->cachedIds[$key] ?? false)) { - $this->cachedIds[$key] = parent::doSave($data); - if($this->isDryRun()) { - // append while dryrun, to distinguish values - $this->cachedIds[$key] .= '-'.count($this->cachedIds); - } + /** + * {@inheritDoc} + */ + protected function doSave(array $data): mixed + { + $path = []; + foreach ($this->uniqueByFields as $field) { + // NOTE: what to do on NULL value? does it really work? + $path[] = $data[$field] ?? null; + } + $key = implode('___', $path); + + if (!($this->cachedIds[$key] ?? false)) { + $this->cachedIds[$key] = parent::doSave($data); + + if ($this->isDryRun()) { + // append while dryrun, to distinguish values + $this->cachedIds[$key] .= '-' . count($this->cachedIds); + } + } + + return $this->cachedIds[$key]; } - - return $this->cachedIds[$key]; - } - } diff --git a/backend/class/transform/pad.php b/backend/class/transform/pad.php index 72a2790..139e879 100644 --- a/backend/class/transform/pad.php +++ b/backend/class/transform/pad.php @@ -1,15 +1,19 @@ 'transform', - 'source' => [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } +use codename\core\io\transform; + +abstract class pad extends transform +{ + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => ["{$this->config['source']}.{$this->config['field']}"], + ]; + } } diff --git a/backend/class/transform/pad/left.php b/backend/class/transform/pad/left.php index 02f2219..92339d4 100644 --- a/backend/class/transform/pad/left.php +++ b/backend/class/transform/pad/left.php @@ -1,16 +1,26 @@ getValue($this->config['source'] ?? 'source', $this->config['field'], $value); - return '' . \str_pad($v, $this->config['length'], $this->config['string'], STR_PAD_LEFT); - } +class left extends pad +{ + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $v = $this->getValue($this->config['source'] ?? 'source', $this->config['field'], $value); + return str_pad($v, $this->config['length'], $this->config['string'], STR_PAD_LEFT); + } } diff --git a/backend/class/transform/pad/right.php b/backend/class/transform/pad/right.php index 6167c92..d41d8f6 100644 --- a/backend/class/transform/pad/right.php +++ b/backend/class/transform/pad/right.php @@ -1,16 +1,26 @@ getValue($this->config['source'] ?? 'source', $this->config['field'], $value); - return \str_pad($v, $this->config['length'], $this->config['string'], STR_PAD_RIGHT); - } +class right extends pad +{ + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $v = $this->getValue($this->config['source'] ?? 'source', $this->config['field'], $value); + return str_pad($v, $this->config['length'], $this->config['string']); + } } diff --git a/backend/class/transform/regex.php b/backend/class/transform/regex.php index 7c4d0c6..0e1086f 100644 --- a/backend/class/transform/regex.php +++ b/backend/class/transform/regex.php @@ -1,88 +1,118 @@ regexValue = $config['regex_value']; - $this->mode = $config['mode']; + /** + * [protected description] + * @var string|array + */ + protected string|array $regexValue; + /** + * [protected description] + * @var null|string|array + */ + protected null|string|array $replaceValue; + /** + * [protected description] + * @var string + */ + protected string $mode; + + /** + * {@inheritDoc} + * @param array $config + * @throws exception + */ + public function __construct(array $config) + { + parent::__construct($config); + $this->regexValue = $config['regex_value']; + $this->replaceValue = $config['replace_value'] ?? null; + $this->mode = $config['mode']; - if(!in_array($this->mode, [ - 'match_success', 'match', 'replace' - ])) { - throw new exception('TRANSFORM_REGEX_INVALID_CONFIG', exception::$ERRORLEVEL_ERROR, $config); + if (!in_array($this->mode, [ + 'match_success', + 'match', + 'replace', + ])) { + throw new exception('TRANSFORM_REGEX_INVALID_CONFIG', exception::$ERRORLEVEL_ERROR, $config); + } } - } - /** - * [protected description] - * @var string - */ - protected $regexValue = null; + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $v = $this->getValue($this->config['source'], $this->config['field'], $value); - /** - * [protected description] - * @var string - */ - protected $mode = null; + if ($this->mode === 'match' || $this->mode === 'match_success') { - /** - * @inheritDoc - */ - public function internalTransform($value) - { - $v = $this->getValue($this->config['source'], $this->config['field'], $value); + if (!is_string($this->regexValue)) { + throw new exception('TRANSFORM_REGEX_REGEX_VALUE_MUST_BE_STRING', exception::$ERRORLEVEL_ERROR); + } - if($this->mode === 'match' || $this->mode === 'match_success') { - $matches = []; - $res = preg_match($this->regexValue, $v, $matches); + $matches = []; + $res = preg_match($this->regexValue, $v, $matches); - if($res === 1) { - // match! - if($this->mode === 'match_success') { - return true; - } else { - return $matches; - } - } else if($res === 0) { - // no match - if($this->mode === 'match_success') { - return false; - } else { - return null; - } - } else { - // error - $this->errorstack->addError('REGEX_ERROR', 0, [ - 'config' => $this->config, - 'value' => $value, - ]); - return null; - } + if ($res === 1) { + // match! + if ($this->mode === 'match_success') { + return true; + } else { + return $matches; + } + } elseif ($res === 0) { + // no match + if ($this->mode === 'match_success') { + return false; + } else { + return null; + } + } else { + // error + $this->errorstack->addError('REGEX_ERROR', 0, [ + 'config' => $this->config, + 'value' => $value, + ]); + return null; + } + } elseif ($this->mode === 'replace') { + + if ($this->replaceValue === null) { + throw new exception('TRANSFORM_REGEX_REPLACE_VALUE_MUST_BE_STRING', exception::$ERRORLEVEL_ERROR); + } - } else if($this->mode === 'replace') { - // TODO + return preg_replace($this->regexValue, $this->replaceValue, $v); + } + throw new LogicException('Not implemented and shouldn\'t be'); } - } - /** - * @inheritDoc - */ - public function getSpecification() : array - { - return [ - 'type' => 'transform', - 'source' => [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => ["{$this->config['source']}.{$this->config['field']}"], + ]; + } } diff --git a/backend/class/transform/set.php b/backend/class/transform/set.php index 2236f9d..f37e336 100644 --- a/backend/class/transform/set.php +++ b/backend/class/transform/set.php @@ -1,22 +1,25 @@ -characterMask = $config['character_mask'] ?? null; - } - - /** - * @inheritDoc - */ - public function internalTransform($value) - { - $v = $this->getValue($this->config['source'], $this->config['field'], $value); - // TODO: handle errors / required state - - if($this->characterMask === null) { - return trim($v); - } else { - return trim($v, $this->characterMask); +class trim extends transform +{ + /** + * character mask to be used for trimming + * null falls back to PHP's standard/default + * @var string|null + */ + protected ?string $characterMask = null; + + /** + * {@inheritDoc} + */ + public function __construct(array $config) + { + parent::__construct($config); + + // NOTE: data that may evaluate to false, somehow + $this->characterMask = $config['character_mask'] ?? null; } - } - - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - 'source' => [ "{$this->config['source']}.{$this->config['field']}" ] - ]; - } + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $v = $this->getValue($this->config['source'], $this->config['field'], $value); + // TODO: handle errors / required state + + if ($this->characterMask === null) { + return trim($v); + } else { + return trim($v, $this->characterMask); + } + } + + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => ["{$this->config['source']}.{$this->config['field']}"], + ]; + } } diff --git a/backend/class/transform/trim/left.php b/backend/class/transform/trim/left.php index af68633..48973c2 100644 --- a/backend/class/transform/trim/left.php +++ b/backend/class/transform/trim/left.php @@ -1,20 +1,27 @@ getValue($this->config['source'], $this->config['field'], $value); - // TODO: handle errors / required state + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $v = $this->getValue($this->config['source'], $this->config['field'], $value); + // TODO: handle errors / required state - if($this->characterMask === null) { - return ltrim($v); - } else { - return ltrim($v, $this->characterMask); + if ($this->characterMask === null) { + return ltrim($v); + } else { + return ltrim($v, $this->characterMask); + } } - } } diff --git a/backend/class/transform/trim/right.php b/backend/class/transform/trim/right.php index 10f1ae3..4fb0520 100644 --- a/backend/class/transform/trim/right.php +++ b/backend/class/transform/trim/right.php @@ -1,20 +1,27 @@ getValue($this->config['source'], $this->config['field'], $value); - // TODO: handle errors / required state + /** + * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws exception + */ + public function internalTransform(mixed $value): mixed + { + $v = $this->getValue($this->config['source'], $this->config['field'], $value); + // TODO: handle errors / required state - if($this->characterMask === null) { - return rtrim($v); - } else { - return rtrim($v, $this->characterMask); + if ($this->characterMask === null) { + return rtrim($v); + } else { + return rtrim($v, $this->characterMask); + } } - } } diff --git a/backend/class/transform/value.php b/backend/class/transform/value.php index 856dae7..0c60079 100644 --- a/backend/class/transform/value.php +++ b/backend/class/transform/value.php @@ -1,29 +1,31 @@ config['value']; - } - - /** - * @inheritDoc - */ - public function getSpecification(): array - { - return [ - 'type' => 'transform', - 'source' => [] - ]; - } +class value extends transform +{ + /** + * {@inheritDoc} + */ + public function internalTransform(mixed $value): mixed + { + return $this->config['value']; + } + /** + * {@inheritDoc} + */ + public function getSpecification(): array + { + return [ + 'type' => 'transform', + 'source' => [], + ]; + } } diff --git a/backend/class/transformer.php b/backend/class/transformer.php index 615becc..e46cb96 100644 --- a/backend/class/transformer.php +++ b/backend/class/transformer.php @@ -1,107 +1,120 @@ transformConfigs = $transformConfigs; - $this->createTransforms(); - } - - /** - * [addTransform description] - * @param string $name [description] - * @param array $transformConfig [description] - */ - public function addTransform(string $name, array $transformConfig) { - $this->transforms[$name] = $this->getTransform($transformConfig); - } - - /** - * returns all non-internal transforms (key names) - * @return string[] [description] - */ - public function getAvailableTransformNames() : array { - return array_keys(array_filter($this->transformConfigs, function($item) { - return !isset($item['internal']) || $item['internal'] === false; - })); - } - - /** - * configs of the transforms - * @var array - */ - protected $transformConfigs = []; +class transformer implements transformerInterface +{ + /** + * [EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_NOTFOUND description] + * @var string + */ + public const EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_NOTFOUND = 'EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_NOTFOUND'; + /** + * [EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_MISSING_CLASS description] + * @var string + */ + public const EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_MISSING_CLASS = 'EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_MISSING_CLASS'; + /** + * configs of the transforms + * @var array + */ + protected array $transformConfigs = []; + /** + * [protected description] + * @var transform[] + */ + protected array $transforms = []; - /** - * [protected description] - * @var transform[] - */ - protected $transforms = []; - - /** - * resets and creates a new collection of named transforms - * @return void - */ - protected function createTransforms() { - $this->transforms = []; - foreach($this->transformConfigs as $name => $transform) { - $this->transforms[$name] = $this->getTransform($transform); + /** + * @param array $transformConfigs + * @throws ReflectionException + * @throws exception + */ + public function __construct(array $transformConfigs) + { + $this->transformConfigs = $transformConfigs; + $this->createTransforms(); } - } - /** - * [getTransform description] - * @param [type] $transformconfig [description] - * @return \codename\core\io\transform [description] - */ - protected function getTransform($transformconfig) : \codename\core\io\transform { - $class = app::getInheritedClass('transform_' . $transformconfig['type']); - if(class_exists($class)) { - $transform = new $class($transformconfig['config']); - $transform->setTransformerInstance($this); - return $transform; - } else { - throw new exception(self::EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_MISSING_CLASS, exception::$ERRORLEVEL_ERROR, $transformconfig['type']); + /** + * resets and creates a new collection of named transforms + * @return void + * @throws ReflectionException + * @throws exception + */ + protected function createTransforms(): void + { + $this->transforms = []; + foreach ($this->transformConfigs as $name => $transform) { + $this->transforms[$name] = $this->getTransform($transform); + } } - } - /** - * get a transform instance - * by name - * (has to be already initialized during ->run() ) - * - * @param string $name [transform name from config] - * @return \codename\core\io\transform [transform instance] - */ - public function getTransformInstance(string $name) : \codename\core\io\transform { - if(!isset($this->transforms[$name])) { - throw new exception(self::EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_NOTFOUND, exception::$ERRORLEVEL_ERROR, $name); + /** + * [getTransform description] + * @param [type] $transformconfig [description] + * @return transform [description] + * @throws ReflectionException + * @throws exception + */ + protected function getTransform($transformconfig): transform + { + $class = app::getInheritedClass('transform_' . $transformconfig['type']); + if (class_exists($class)) { + $transform = new $class($transformconfig['config']); + $transform->setTransformerInstance($this); + return $transform; + } else { + throw new exception(self::EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_MISSING_CLASS, exception::$ERRORLEVEL_ERROR, $transformconfig['type']); + } } - return $this->transforms[$name]; - } - /** - * [EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_NOTFOUND description] - * @var string - */ - const EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_NOTFOUND = 'EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_NOTFOUND'; + /** + * [addTransform description] + * @param string $name [description] + * @param array $transformConfig [description] + * @throws ReflectionException + * @throws exception + */ + public function addTransform(string $name, array $transformConfig): void + { + $this->transforms[$name] = $this->getTransform($transformConfig); + } - /** - * [EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_MISSING_CLASS description] - * @var string - */ - const EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_MISSING_CLASS = 'EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_MISSING_CLASS'; + /** + * returns all non-internal transforms (key names) + * @return string[] [description] + */ + public function getAvailableTransformNames(): array + { + return array_keys( + array_filter($this->transformConfigs, function ($item) { + return !isset($item['internal']) || $item['internal'] === false; + }) + ); + } + /** + * get a transform instance + * by name + * (has to be already initialized during ->run() ) + * + * @param string $name [transform name from config] + * @return transform [transform instance] + * @throws exception + */ + public function getTransformInstance(string $name): transform + { + if (!isset($this->transforms[$name])) { + throw new exception(self::EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_NOTFOUND, exception::$ERRORLEVEL_ERROR, $name); + } + return $this->transforms[$name]; + } } diff --git a/backend/class/transformerInterface.php b/backend/class/transformerInterface.php index c5ea298..31e6fe5 100644 --- a/backend/class/transformerInterface.php +++ b/backend/class/transformerInterface.php @@ -1,12 +1,13 @@ errorstack->getErrors(); - } +class import extends config +{ + /** + * Contains a list of array keys that MUST exist in the validated array + * @var array + */ + public $arrKeys = [ + 'source', + 'target', + ]; - if(count($sourceErrors = (new import\source)->reset()->validate($value['source'])) > 0) { - $this->errorstack->addErrors($sourceErrors); - return $this->errorstack->getErrors(); - } + /** + * {@inheritDoc} + */ + public function validate(mixed $value): array + { + if (count(parent::validate($value)) != 0) { + return $this->errorstack->getErrors(); + } - if(!empty($value['transform'])) { - if(count($transformErrors = (new import\transform)->reset()->validate($value['transform'])) > 0) { - $this->errorstack->addErrors($transformErrors); - return $this->errorstack->getErrors(); - } - } + if (count($sourceErrors = (new import\source())->reset()->validate($value['source'])) > 0) { + $this->errorstack->addErrors($sourceErrors); + return $this->errorstack->getErrors(); + } - if(count($targetErrors = (new import\target)->reset()->validate($value['target'])) > 0) { - $this->errorstack->addErrors($targetErrors); - return $this->errorstack->getErrors(); - } - // TODO: Detail validation! + if (!empty($value['transform'])) { + if (count($transformErrors = (new import\transform())->reset()->validate($value['transform'])) > 0) { + $this->errorstack->addErrors($transformErrors); + return $this->errorstack->getErrors(); + } + } - return $this->getErrors(); - } + if (count($targetErrors = (new import\target())->reset()->validate($value['target'])) > 0) { + $this->errorstack->addErrors($targetErrors); + return $this->errorstack->getErrors(); + } + // TODO: Detail validation! + + return $this->getErrors(); + } } diff --git a/backend/class/validator/structure/config/import/source.php b/backend/class/validator/structure/config/import/source.php index c24c781..b71e05f 100644 --- a/backend/class/validator/structure/config/import/source.php +++ b/backend/class/validator/structure/config/import/source.php @@ -1,28 +1,30 @@ errorstack->getErrors(); + } - /** - * @inheritDoc - */ - public function validate($value): array - { - if(count(parent::validate($value)) != 0) { - return $this->errorstack->getErrors(); - } - - return $this->getErrors(); - } + return $this->getErrors(); + } } diff --git a/backend/class/validator/structure/config/import/target.php b/backend/class/validator/structure/config/import/target.php index b565636..5f5b853 100644 --- a/backend/class/validator/structure/config/import/target.php +++ b/backend/class/validator/structure/config/import/target.php @@ -1,28 +1,30 @@ errorstack->getErrors(); + } - /** - * @inheritDoc - */ - public function validate($value): array - { - if(count(parent::validate($value)) != 0) { - return $this->errorstack->getErrors(); - } - - return $this->getErrors(); - } + return $this->getErrors(); + } } diff --git a/backend/class/validator/structure/config/import/transform.php b/backend/class/validator/structure/config/import/transform.php index 33be2dd..c5b1492 100644 --- a/backend/class/validator/structure/config/import/transform.php +++ b/backend/class/validator/structure/config/import/transform.php @@ -1,28 +1,30 @@ errorstack->getErrors(); + } - /** - * @inheritDoc - */ - public function validate($value): array - { - if(count(parent::validate($value)) != 0) { - return $this->errorstack->getErrors(); - } - - return $this->getErrors(); - } + return $this->getErrors(); + } } diff --git a/backend/class/value/structure/tagged.php b/backend/class/value/structure/tagged.php index 8b8c555..2c7272e 100644 --- a/backend/class/value/structure/tagged.php +++ b/backend/class/value/structure/tagged.php @@ -1,34 +1,38 @@ tags = $tags; - } + /** + * {@inheritDoc} + */ + public function __construct($value, ?array $tags = null) + { + parent::__construct($value); + $this->tags = $tags; + } - /** - * [getTags description] - * @return array|null - */ - public function getTags() : ?array { - return $this->tags; - } + /** + * [getTags description] + * @return array|null + */ + public function getTags(): ?array + { + return $this->tags; + } } diff --git a/backend/class/value/text/fileabsolute/tagged.php b/backend/class/value/text/fileabsolute/tagged.php index f307c2d..1b10072 100644 --- a/backend/class/value/text/fileabsolute/tagged.php +++ b/backend/class/value/text/fileabsolute/tagged.php @@ -1,28 +1,32 @@ tags = $tags; - } + /** + * {@inheritDoc} + */ + public function __construct($value, ?array $tags = null) + { + parent::__construct($value); + $this->tags = $tags; + } - /** - * [getTags description] - * @return array|null - */ - public function getTags() : ?array { - return $this->tags; - } + /** + * [getTags description] + * @return array|null + */ + public function getTags(): ?array + { + return $this->tags; + } } diff --git a/backend/class/value/text/tagged.php b/backend/class/value/text/tagged.php index 74a04f0..42c06ec 100644 --- a/backend/class/value/text/tagged.php +++ b/backend/class/value/text/tagged.php @@ -1,28 +1,32 @@ tags = $tags; - } + /** + * {@inheritDoc} + */ + public function __construct($value, ?array $tags = null) + { + parent::__construct($value); + $this->tags = $tags; + } - /** - * [getTags description] - * @return array|null - */ - public function getTags() : ?array { - return $this->tags; - } + /** + * [getTags description] + * @return array|null + */ + public function getTags(): ?array + { + return $this->tags; + } } diff --git a/composer.json b/composer.json index 9de3816..914dfa5 100644 --- a/composer.json +++ b/composer.json @@ -1,34 +1,40 @@ { - "name": "codename/core-io", - "description": "This is going to be the core input and output lib", - "type": "library", - "keywords": ["codename", "core", "io"], - "authors": [ - { - "name": "Kevin Dargel", - "role": "Software Developer" - } - ], - "require": { - "codename/core" : "*", - "sabre/xml": "^2.1", - "dompdf/dompdf" : "^1.0", - "codename/parquet" : "*", - "phpoffice/phpspreadsheet" : "^1.1" - }, - "require-dev" : { - "phpunit/phpunit" : "^9.0", - "vimeo/psalm" : "^4.0", - "codename/core-test" : "*" - }, - "autoload": { - "psr-4": { - "codename\\core\\io\\": "backend/class/" - } - }, - "autoload-dev": { - "psr-4": { - "codename\\core\\io\\tests\\": "tests/" - } + "name": "codename/core-io", + "description": "This is going to be the core input and output lib", + "type": "library", + "keywords": [ + "codename", + "core", + "io" + ], + "authors": [ + { + "name": "Kevin Dargel", + "role": "Software Developer" } + ], + "require": { + "codename/core": "*", + "codename/parquet": "*", + "dompdf/dompdf": "^2.0", + "php": "^8.1", + "phpoffice/phpspreadsheet": "^1.27.0", + "sabre/xml": "^4.0" + }, + "require-dev": { + "codename/core-test": "*", + "friendsofphp/php-cs-fixer": "^3.15", + "phpunit/phpunit": "^10.0", + "vimeo/psalm": "^5.0" + }, + "autoload": { + "psr-4": { + "codename\\core\\io\\": "backend/class/" + } + }, + "autoload-dev": { + "psr-4": { + "codename\\core\\io\\tests\\": "tests/" + } + } } diff --git a/phpcs.xml b/phpcs.xml index 73b533d..8644693 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -1,21 +1,21 @@ - The default CoreFramework coding standard + The default CoreFramework coding standard - - - + + + - - + + - - + + \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml index cdf88b3..e90e4f1 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,11 +1,17 @@ - - + + backend/class/ - + diff --git a/psalm.xml b/psalm.xml index 580e128..a1b8601 100644 --- a/psalm.xml +++ b/psalm.xml @@ -1,15 +1,14 @@ - - - - - - + + + + + + diff --git a/tests/autoload.php b/tests/autoload.php index 48a8bc2..af0dfd4 100644 --- a/tests/autoload.php +++ b/tests/autoload.php @@ -17,42 +17,45 @@ */ // Default fixed environment for unit tests -define('CORE_ENVIRONMENT', 'test'); +use codename\core\app; +use codename\core\test\overrideableApp; + +const CORE_ENVIRONMENT = 'test'; // cross-project autoloader -$globalBootstrap = realpath(__DIR__.'/../../../../bootstrap-cli.php'); -if(file_exists($globalBootstrap)) { - echo("Including autoloader at " . $globalBootstrap . chr(10) ); - require_once $globalBootstrap; +$globalBootstrap = realpath(__DIR__ . '/../../../../bootstrap-cli.php'); +if (file_exists($globalBootstrap)) { + echo("Including autoloader at " . $globalBootstrap . chr(10)); + require_once $globalBootstrap; } else { - // die("ERROR: No global bootstrap.cli.php found. You might want to initialize your cross-project autoloader using the root composer.json first." . chr(10) ); + die("ERROR: No global bootstrap.cli.php found. You might want to initialize your cross-project autoloader using the root composer.json first." . chr(10)); } // local autoloader -$localAutoload = realpath(__DIR__.'/../vendor/autoload.php'); -if(file_exists($localAutoload)) { - echo("Including autoloader at " . $localAutoload . chr(10) ); - require_once $localAutoload; +$localAutoload = realpath(__DIR__ . '/../vendor/autoload.php'); +if (file_exists($localAutoload)) { + echo("Including autoloader at " . $localAutoload . chr(10)); + require_once $localAutoload; } else { - // die("ERROR: No local vendor/autoloader.php found. Please call \"composer dump-autoload\" in this directory." . chr(10) ); + die("ERROR: No local vendor/autoloader.php found. Please call \"composer dump-autoload --dev\" in this directory." . chr(10)); } // // This allows having only a local autoloader and no global one // (e.g. single-project unit testing) // -if(!file_exists($globalBootstrap) && !file_exists($localAutoload)){ - die("ERROR: No global bootstrap.cli.php or local vendor/autoloader.php found. You might want to initialize your cross-project or single-project autoloader first." . chr(10) ); +if (!file_exists($globalBootstrap) && !file_exists($localAutoload)) { + die("ERROR: No global bootstrap.cli.php or local vendor/autoloader.php found. You might want to initialize your cross-project or single-project autoloader first." . chr(10)); } -if(!$globalBootstrap) { - // Fallback to this project's vendor dir (and add a slash at the end - because realpath doesn't add it) - DEFINE("CORE_VENDORDIR", realpath(DIRNAME(__FILE__) . '/../vendor/').'/'); +if (!$globalBootstrap) { + // Fallback to this project's vendor dir (and add a slash at the end - because realpath doesn't add it) + define("CORE_VENDORDIR", realpath(dirname(__FILE__) . '/../vendor/') . '/'); } // Explicitly reset any appdata left // or implicitly re-init base data. -\codename\core\test\overrideableApp::reset(); +overrideableApp::reset(); // // Special quirk for single-project unit testing @@ -62,8 +65,8 @@ // Additionally, we need to do this every time the appstack gets initialized in the tests // and only if this app is used, somehow. // -\codename\core\app::getHook()->add(\codename\core\app::EVENT_APP_APPSTACK_AVAILABLE, function() { - \codename\core\test\overrideableApp::__modifyAppstackEntry('codename', 'core-io', [ - 'homedir' => realpath(__DIR__.'/../'), // One dir up (project root) - ]); +app::getHook()->add(app::EVENT_APP_APPSTACK_AVAILABLE, function () { + overrideableApp::__modifyAppstackEntry('codename', 'core-io', [ + 'homedir' => realpath(__DIR__ . '/../'), // One dir up (project root) + ]); }); diff --git a/tests/datasource/arraydataTest.php b/tests/datasource/arraydataTest.php new file mode 100644 index 0000000..d3a0cf9 --- /dev/null +++ b/tests/datasource/arraydataTest.php @@ -0,0 +1,71 @@ +setData([ + [ + 'oldkey1' => 'abc', + 'oldkey2' => 'def', + 'oldkey3' => 'ghi', + ], + [ + 'oldkey1' => 'jkl', + 'oldkey2' => 'mno', + 'oldkey3' => 'pqr', + ], + [ + 'oldkey1' => 'stu', + 'oldkey2' => 'vwx', + 'oldkey3' => 'yz', + ], + ]); + + try { + $datasource->setConfig([]); + } catch (Exception) { + static::fail(); + } + + static::assertEquals('0', $datasource->currentProgressPosition()); + + static::assertEquals('3', $datasource->currentProgressLimit()); + + // rewind the datasources + $datasource->rewind(); + + static::assertEquals('0', $datasource->key()); + + static::assertTrue($datasource->valid()); + + // get current data + static::assertEquals([ + 'oldkey1' => 'abc', + 'oldkey2' => 'def', + 'oldkey3' => 'ghi', + ], $datasource->current()); + + $datasource->next(); + + static::assertEquals([ + 'oldkey1' => 'jkl', + 'oldkey2' => 'mno', + 'oldkey3' => 'pqr', + ], $datasource->current()); + } +} diff --git a/tests/datasource/bufferedTest.php b/tests/datasource/bufferedTest.php new file mode 100644 index 0000000..4d2b009 --- /dev/null +++ b/tests/datasource/bufferedTest.php @@ -0,0 +1,156 @@ +expectException(exception::class); + $this->expectExceptionMessage('EXCEPTION_DATASOURCE_BUFFERED_BUFFERSIZE_TOO_LOW'); + $source = new arraydata(); + new buffered($source, 0); + } + + /** + * [testSmallBufferOnEmptySource description] + * @return void [type] [description] + * @throws exception + */ + public function testSmallBufferOnEmptySource(): void + { + $source = new arraydata(); + $source->setData([]); + $buffered = new buffered($source, 1); + + $r = []; + foreach ($buffered as $b) { + $r[] = $b; + } + + $buffered->rewind(); + + static::assertEquals(0, $source->currentProgressLimit()); + static::assertEquals(0, $buffered->currentProgressLimit()); + static::assertEmpty($r); + } + + /** + * [testBufferReadingWithMultipleBufferSizes description] + * @throws exception + */ + public function testBufferReadingWithMultipleBufferSizes(): void + { + $source = new arraydata(); + $source->setData([ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + ]); + + for ($bufferSize = 1; $bufferSize <= 16; $bufferSize++) { + $buffered = new buffered($source, $bufferSize); + $r = []; + foreach ($buffered as $b) { + $r[] = $b; + } + static::assertEquals([1, 2, 3, 4, 5, 6, 7, 8], $r); + } + } + + /** + * [testBufferReadingWithMultipleBufferSizesDynamic description] + * @throws exception + */ + public function testBufferReadingWithMultipleBufferSizesDynamic(): void + { + $source = new arraydata(); + $source->setData([ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + ]); + + static::assertEquals(8, $source->currentProgressLimit()); + + $buffered = new buffered($source, 999); + + for ($bufferSize = 1; $bufferSize <= 16; $bufferSize++) { + // Modify buffer size of the only instance + $buffered->setBufferSize($bufferSize); + $buffered->rewind(); + + static::assertLessThanOrEqual($bufferSize, $buffered->getBuffer()->count()); + + $r = []; + $cnt = 0; + foreach ($buffered as $b) { + $r[] = $b; + static::assertEquals($cnt, $buffered->currentProgressPosition()); + static::assertEquals($cnt, $buffered->key()); + $cnt++; + } + + static::assertEquals([1, 2, 3, 4, 5, 6, 7, 8], $r); + } + } + + /** + * [testSetConfigPassthrough description] + * @throws exception + */ + public function testSetConfigPassthrough(): void + { + $source = new csv( + __DIR__ . "/" . 'testcsv2.csv', + [ + 'autodetect_utf8_bom' => true, + 'skip_empty_rows' => true, + 'skip_rows' => 11, // wrong setting + 'encoding' => ['from' => 'UTF-8', 'to' => 'UTF-8'], + ] + ); + + $buffered = new buffered($source, 999); + + $buffered->setConfig([ + 'autodetect_utf8_bom' => true, + 'skip_empty_rows' => true, + 'skip_rows' => 1, // right setting + 'encoding' => ['from' => 'UTF-8', 'to' => 'UTF-8'], + ]); + + $i = 0; + foreach ($buffered as $dataset) { + $i++; + static::assertEquals("l{$i}_d1", $dataset['head0']); + static::assertEquals("l{$i}_d2", $dataset['head1']); + } + + static::assertEquals(3, $i); + } +} diff --git a/tests/datasource/csvTest.php b/tests/datasource/csvTest.php new file mode 100644 index 0000000..3be6dcd --- /dev/null +++ b/tests/datasource/csvTest.php @@ -0,0 +1,168 @@ +currentProgressPosition()); + static::assertEquals('31', $datasource->currentProgressLimit()); + } + + /** + * test a simple csv file + * @return void [type] [description] + * @throws exception + */ + public function testDataSourceFileNotExists(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('FILE_COULD_NOT_BE_OPEN'); + new csv(__DIR__ . "/" . 'testcsv1_filenotexists.csv'); + } + + /** + * test a simple csv file + * @return void [type] [description] + * @throws exception + */ + public function testDataSourceIsValid(): void + { + $datasource = new csv(__DIR__ . "/" . 'testcsv1.csv'); + $datasource->rewind(); + + $head = $datasource->getHeadings(); + static::assertEquals('head1', $head[0]); + static::assertEquals('head2', $head[1]); + + $data = $datasource->current(); + static::assertEquals('bla', $data['head1']); + static::assertEquals('foo', $data['head2']); + } + + /** + * "head1","head2" + * "l1_d1","l1_d2" + * "l2_d1","l2_d2" + * "l3_d1","l3_d2" + * + * @return void testing the next function + * @throws exception + */ + public function testDataSourceNext(): void + { + $datasource = new csv( + __DIR__ . "/" . 'testcsv2.csv', + [ + 'autodetect_utf8_bom' => true, + 'skip_empty_rows' => true, + 'skip_rows' => 1, + 'encoding' => ['from' => 'UTF-8', 'to' => 'UTF-8'], + ] + ); + + $i = 0; + foreach ($datasource as $dataset) { + $i++; + static::assertEquals("l{$i}_d1", $dataset['head0']); + static::assertEquals("l{$i}_d2", $dataset['head1']); + } + + // + // make sure we have iterated three times + // + static::assertEquals(3, $i); + } + + /** + * "head1","head2" + * "l1_d1","l1_d2" + * "l2_d1","l2_d2" + * "l3_d1","l3_d2" + * + * @return void testing the next function + * @throws exception + */ + public function testDataSourceWrongOffset(): void + { + $datasource = new overriddenCsv( + __DIR__ . "/" . 'testcsv2.csv', + [ + 'autodetect_utf8_bom' => true, + 'skip_empty_rows' => true, + 'skip_rows' => 1, + 'encoding' => ['from' => 'UTF-8', 'to' => 'UTF-8'], + ] + ); + + $i = 0; + foreach ($datasource as $dataset) { + $i++; + static::assertEquals("l{$i}_d1", $dataset['head0']); + static::assertEquals("l{$i}_d2", $dataset['head1']); + } + + // + // make sure we have iterated three times + // + static::assertEquals(3, $i); + } + + /** + * [testDatasourceCsvWindows1252Decoding description] + * @throws exception + */ + public function testDatasourceCsvWindows1252Decoding(): void + { + $datasource = new csv( + __DIR__ . "/" . 'csv_windows1252_umlauts.csv', + [ + 'delimiter' => ';', + 'encoding' => ['from' => 'Windows-1252', 'to' => 'UTF-8'], + ] + ); + + $rows = []; + foreach ($datasource as $row) { + $rows[] = $row; + } + + static::assertEquals([ + ['NormalColumn' => 'Ä', 'ColumnWithUmlautsÄüÖö' => '1'], + ['NormalColumn' => 'Ü', 'ColumnWithUmlautsÄüÖö' => '2'], + ['NormalColumn' => 'Ö', 'ColumnWithUmlautsÄüÖö' => '3'], + ['NormalColumn' => 'ß', 'ColumnWithUmlautsÄüÖö' => '4'], + ], $rows); + } +} + +/** + * [overriddenCsv description] + */ +class overriddenCsv extends csv +{ + /** + * [rewind description] + * @return void [type] [description] + */ + public function rewind(): void + { + fseek($this->handle, 1); + if ($this->autodetectUtf8Bom) { + $this->handleUtf8Bom(); + } + $this->index = 0; + $this->next(); + } +} diff --git a/tests/datasource/joinedTest.php b/tests/datasource/joinedTest.php new file mode 100644 index 0000000..d016f72 --- /dev/null +++ b/tests/datasource/joinedTest.php @@ -0,0 +1,249 @@ + ';', + ] + ), + new csv( + __DIR__ . '/joined1_join1.csv', + [ + 'delimiter' => ';', + ] + ), + ], + [ + // CONFIG! + 'join' => [ + [ + 'index' => $indexesEnabled, + 'base_datasource' => 0, // array index-based + 'join_datasource' => 1, // array index-based + 'base_field' => 'col2', + 'join_field' => 'id2', + ], + ], + ] + ); + + $res = []; + foreach ($joinedDatasource as $d) { + $res[] = $d; + } + + static::assertCount(6, $res); + + // At the time of writing, missing values are not applied to join result datasets + // therefore, array_column will return fewer values in those cases (stipping out unset values) + static::assertEquals(['ABC', 'DEF', 'GHI', 'ABC', /*null,*/ 'GHI'], array_column($res, 'name')); + } + + /** + * Test the same with explicit names for the datasources + * @testWith [ false ] + * [ true ] + * @param bool $indexesEnabled + * @throws exception + */ + public function testSimpleJoinedCsvWithNamedDatasources(bool $indexesEnabled): void + { + $joinedDatasource = new joined( + [ + 'foo' => new csv( + __DIR__ . '/joined1_base1.csv', + [ + 'delimiter' => ';', + ] + ), + 'bar' => new csv( + __DIR__ . '/joined1_join1.csv', + [ + 'delimiter' => ';', + ] + ), + ], + [ + // CONFIG! + 'join' => [ + [ + 'index' => $indexesEnabled, + 'base_datasource' => 'foo', // key-based + 'join_datasource' => 'bar', // key-based + 'base_field' => 'col2', + 'join_field' => 'id2', + ], + ], + ] + ); + + $res = []; + foreach ($joinedDatasource as $d) { + $res[] = $d; + } + + static::assertCount(6, $res); + + // At the time of writing, missing values are not applied to join result datasets + // therefore, array_column will return fewer values in those cases (stipping out unset values) + static::assertEquals(['ABC', 'DEF', 'GHI', 'ABC', /*null,*/ 'GHI'], array_column($res, 'name')); + } + + /** + * [testMultipleJoinedCsvWithNamedDatasources description] + * @testWith [ false ] + * [ true ] + * @param bool $indexesEnabled + * @throws exception + */ + public function testMultipleJoinedCsvWithNamedDatasources(bool $indexesEnabled): void + { + $joinedDatasource = new joined( + [ + 'foo' => new csv( + __DIR__ . '/joined1_base1.csv', + [ + 'delimiter' => ';', + ] + ), + 'bar' => new csv( + __DIR__ . '/joined1_join1.csv', + [ + 'delimiter' => ';', + ] + ), + 'baz' => new csv( + __DIR__ . '/joined1_join2.csv', + [ + 'delimiter' => ';', + ] + ), + ], + [ + // CONFIG! + 'join' => [ + [ + 'index' => $indexesEnabled, + 'base_datasource' => 'foo', // key-based + 'join_datasource' => 'bar', // key-based + 'base_field' => 'col2', + 'join_field' => 'id2', + ], + [ + 'index' => $indexesEnabled, + 'base_datasource' => 'bar', // key-based + 'join_datasource' => 'baz', // key-based + 'base_field' => 'other_id', + 'join_field' => 'join2_id', + ], + ], + ] + ); + + $res = []; + foreach ($joinedDatasource as $d) { + $res[] = $d; + } + + static::assertCount(6, $res); + + // At the time of writing, missing values are not applied to join result datasets + // therefore, array_column will return fewer values in those cases (stipping out unset values) + static::assertEquals(['ABC', 'DEF', 'GHI', 'ABC', /*null,*/ 'GHI'], array_column($res, 'name')); + static::assertEquals(['BBB', 'BBB', 'CCC', 'BBB', /*null,*/ 'CCC'], array_column($res, 'value')); + } + + /** + * @testWith [ false ] + * [ true ] + * @param bool $indexesEnabled [description] + * @throws exception + */ + public function testMultipleJoinedCsvWithNamedDatasourcesAndAmbiguities(bool $indexesEnabled): void + { + $joinedDatasource = new joined( + [ + 'foo' => new csv( + __DIR__ . '/joined1_base1.csv', + [ + 'delimiter' => ';', + ] + ), + 'bar' => new csv( + __DIR__ . '/joined1_join1.csv', + [ + 'delimiter' => ';', + ] + ), + 'baz' => new csv( + __DIR__ . '/joined1_join2.csv', + [ + 'delimiter' => ';', + ] + ), + 'qux' => new csv( + __DIR__ . '/joined1_join3.csv', + [ + 'delimiter' => ';', + ] + ), + ], + [ + // CONFIG! + 'join' => [ + [ + 'index' => $indexesEnabled, + 'base_datasource' => 'foo', // key-based + 'join_datasource' => 'bar', // key-based + 'base_field' => 'col2', + 'join_field' => 'id2', + ], + [ + 'index' => $indexesEnabled, + 'base_datasource' => 'bar', // key-based + 'join_datasource' => 'baz', // key-based + 'base_field' => 'other_id', + 'join_field' => 'join2_id', + ], + [ + 'index' => $indexesEnabled, + 'base_datasource' => 'foo', // key-based + 'join_datasource' => 'qux', // key-based + 'base_field' => 'col1', + 'join_field' => 'join3_col1', + ], + ], + ] + ); + + $res = []; + foreach ($joinedDatasource as $d) { + $res[] = $d; + } + + static::assertCount(8, $res); + + static::assertEquals(['A', 'A', 'B', 'C', 'D', 'D', 'E', 'F'], array_column($res, 'col1')); + static::assertEquals(['A1', 'A2', 'B1', 'C1', 'D1', 'D2', 'F1'], array_column($res, 'join3_value')); + } +} diff --git a/tests/datasource/model/datasourceentry.php b/tests/datasource/model/datasourceentry.php index a1da1e6..d7317b0 100644 --- a/tests/datasource/model/datasourceentry.php +++ b/tests/datasource/model/datasourceentry.php @@ -1,35 +1,39 @@ [ - 'datasourceentry_id', - 'datasourceentry_created', - 'datasourceentry_modified', - 'datasourceentry_text', - 'datasourceentry_integer', - ], - 'primary' => [ - 'datasourceentry_id' - ], - 'datatype' => [ - 'datasourceentry_id' => 'number_natural', - 'datasourceentry_created' => 'text_timestamp', - 'datasourceentry_modified' => 'text_timestamp', - 'datasourceentry_text' => 'text', - 'datasourceentry_integer' => 'number_natural', - ], - 'connection' => 'default' - ]); - } +class datasourceentry extends sqlModel +{ + /** + * {@inheritDoc} + */ + public function __construct(array $modeldata = []) + { + parent::__construct('datasourcetest', 'datasourceentry', [ + 'field' => [ + 'datasourceentry_id', + 'datasourceentry_created', + 'datasourceentry_modified', + 'datasourceentry_text', + 'datasourceentry_integer', + ], + 'primary' => [ + 'datasourceentry_id', + ], + 'datatype' => [ + 'datasourceentry_id' => 'number_natural', + 'datasourceentry_created' => 'text_timestamp', + 'datasourceentry_modified' => 'text_timestamp', + 'datasourceentry_text' => 'text', + 'datasourceentry_integer' => 'number_natural', + ], + 'connection' => 'default', + ]); + } } diff --git a/tests/datasource/model/datasourceentryj.php b/tests/datasource/model/datasourceentryj.php index 5a30b76..661ff87 100644 --- a/tests/datasource/model/datasourceentryj.php +++ b/tests/datasource/model/datasourceentryj.php @@ -1,42 +1,46 @@ [ - 'datasourceentryj_id', - 'datasourceentryj_created', - 'datasourceentryj_modified', - 'datasourceentryj_datasourceentry_id', - 'datasourceentryj_text', - ], - 'primary' => [ - 'datasourceentryj_id' - ], - 'foreign' => [ - 'datasourceentryj_datasourceentry_id' => [ - 'schema' => 'datasourcetest', - 'model' => 'datasourceentry', - 'key' => 'datasourceentry_id' - ], - ], - 'datatype' => [ - 'datasourceentryj_id' => 'number_natural', - 'datasourceentryj_created' => 'text_timestamp', - 'datasourceentryj_modified' => 'text_timestamp', - 'datasourceentryj_datasourceentry_id' => 'number_natural', - 'datasourceentryj_text' => 'text', - ], - 'connection' => 'default' - ]); - } +class datasourceentryj extends sqlModel +{ + /** + * {@inheritDoc} + */ + public function __construct(array $modeldata = []) + { + parent::__construct('datasourcetest', 'datasourceentryj', [ + 'field' => [ + 'datasourceentryj_id', + 'datasourceentryj_created', + 'datasourceentryj_modified', + 'datasourceentryj_datasourceentry_id', + 'datasourceentryj_text', + ], + 'primary' => [ + 'datasourceentryj_id', + ], + 'foreign' => [ + 'datasourceentryj_datasourceentry_id' => [ + 'schema' => 'datasourcetest', + 'model' => 'datasourceentry', + 'key' => 'datasourceentry_id', + ], + ], + 'datatype' => [ + 'datasourceentryj_id' => 'number_natural', + 'datasourceentryj_created' => 'text_timestamp', + 'datasourceentryj_modified' => 'text_timestamp', + 'datasourceentryj_datasourceentry_id' => 'number_natural', + 'datasourceentryj_text' => 'text', + ], + 'connection' => 'default', + ]); + } } diff --git a/tests/datasource/modelTest.php b/tests/datasource/modelTest.php new file mode 100644 index 0000000..3ad1b85 --- /dev/null +++ b/tests/datasource/modelTest.php @@ -0,0 +1,387 @@ +expectException(exception::class); + $this->expectExceptionMessage('EXCEPTION_DATASOURCE_MODEL_ALREADY_SET'); + $datasource = new model(); + $model = $this->getModel('datasourceentry'); + $datasource->setModel($model); + $datasource->setModel($model); // second call should fail + } + + /** + * [testSimpleDatasourceModelQuery description] + * @throws ReflectionException + * @throws exception + */ + public function testSimpleDatasourceModelQuery(): void + { + $this->createTestData(); + $datasource = new model(); + $datasource->setQuery([]); + $model = $this->getModel('datasourceentry'); + $datasource->setModel($model); + $res = []; + foreach ($datasource as $d) { + $res[] = $d; + } + static::assertCount(4, $res); + } + + /** + * [createTestData description] + * @throws ReflectionException + * @throws exception + */ + protected function createTestData(): void + { + $datasets = [ + [ + 'datasourceentry_text' => 'foo', + 'datasourceentry_integer' => 111, + ], + [ + 'datasourceentry_text' => 'bar', + 'datasourceentry_integer' => 222, + ], + [ + 'datasourceentry_text' => 'baz', + 'datasourceentry_integer' => null, + ], + [ + 'datasourceentry_text' => 'qux', + 'datasourceentry_integer' => 333, + ], + ]; + $model = $this->getModel('datasourceentry'); + foreach ($datasets as $dataset) { + $model->save($dataset); + } + } + + /** + * [testSimpleDatasourceModelQueryBuffered description] + * @throws ReflectionException + * @throws exception + */ + public function testSimpleDatasourceModelQueryBuffered(): void + { + $this->createTestData(); + $datasource = new model([ + 'offset_buffering' => true, + 'offset_buffer_size' => 2, + + ]); + $datasource->setQuery([]); + $model = $this->getModel('datasourceentry'); + $datasource->setModel($model); + static::assertCount(4, $datasource); + } + + /** + * [testSimpleDatasourceModelQueryBufferedLimited description] + * @throws ReflectionException + * @throws exception + */ + public function testSimpleDatasourceModelQueryBufferedLimited(): void + { + $this->createTestData(); + $datasource = new model([ + 'offset_buffering' => true, + 'offset_buffer_size' => 2, + 'offset_limit' => 3, + + ]); + $datasource->setQuery([]); + $model = $this->getModel('datasourceentry'); + $datasource->setModel($model); + static::assertCount(3, $datasource); + } + + /** + * [testDatasourceModelComplexOne description] + * @throws ReflectionException + * @throws exception + */ + public function testDatasourceModelComplexOne(): void + { + $this->createTestData(); + $datasource = new model([ + 'model' => 'datasourceentry', + 'join' => [ + [ + 'model' => 'datasourceentryj', + 'fields' => [ + 'datasourceentryj_id', + ], + ], + ], + 'virtualFieldResult' => true, + 'fields' => [ + 'datasourceentry_text', + 'datasourceentry_integer', + ], + 'filter' => [ + ['field' => 'datasourceentry_integer', 'value' => null, 'operator' => '!='], + ], + 'filtercollection' => [ + [ + 'filters' => [ + ['field' => 'datasourceentry_integer', 'value' => 111, 'operator' => '='], + ['field' => 'datasourceentry_integer', 'value' => 222, 'operator' => '='], + ], + 'group_operator' => 'OR', + 'group_name' => 'datasourceentry_integer', + ], + ], + 'query' => [ + 'order' => [ + [ + "field" => "datasourceentry_integer", + "order" => "DESC", + ], + ], + ], + ]); + + $res = []; + foreach ($datasource as $d) { + $res[] = $d; + } + static::assertEquals([ + [ + 'datasourceentry_text' => 'bar', + 'datasourceentry_integer' => 222, + 'datasourceentryj_id' => null, + ], + [ + 'datasourceentry_text' => 'foo', + 'datasourceentry_integer' => 111, + 'datasourceentryj_id' => null, + ], + ], $res); + } + + /** + * [testDatasourceModelComplexOne description] + * @throws ReflectionException + * @throws exception + */ + public function testDatasourceModelComplexTwo(): void + { + $this->createTestData(); + $datasource = new model([ + 'model' => 'datasourceentry', + 'virtualFieldResult' => true, + 'fields' => [ + 'datasourceentry_text', + 'datasourceentry_integer', + ], + 'query' => [ + 'filter' => [ + ['field' => 'datasourceentry_integer', 'value' => ['option' => 'filter1'], 'operator' => '!='], + ], + 'filtercollection' => [ + [ + 'filters' => [ + ['field' => 'datasourceentry_integer', 'value' => ['option' => 'filtercollection1'], 'operator' => '='], + ['field' => 'datasourceentry_integer', 'value' => ['option' => 'filtercollection2'], 'operator' => '='], + ], + 'group_operator' => 'OR', + 'group_name' => 'datasourceentry_integer', + ], + ], + 'order' => [ + [ + "field" => "datasourceentry_integer", + "order" => "DESC", + ], + ], + ], + ]); + + $pipeline = new pipeline(null, []); + $pipeline->setOptions([ + 'filter1' => null, + 'filtercollection1' => 111, + 'filtercollection2' => 222, + ]); + + $datasource->setPipelineInstance($pipeline); + + $res = []; + foreach ($datasource as $d) { + $res[] = $d; + } + + static::assertEquals(3, $datasource->currentProgressPosition()); + static::assertEquals(2, $datasource->currentProgressLimit()); + static::assertEquals([ + [ + 'datasourceentry_text' => 'bar', + 'datasourceentry_integer' => 222, + ], + [ + 'datasourceentry_text' => 'foo', + 'datasourceentry_integer' => 111, + ], + ], $res); + } + + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function tearDown(): void + { + $this->getModel('datasourceentry') + ->addFilter('datasourceentry_id', 0, '>') + ->delete(); + } + + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function setUp(): void + { + $app = static::createApp(); + + // Additional overrides to get a more complete app lifecycle + // and allow static global app::getModel() to work correctly + $app::__setApp('datasourcetest'); + $app::__setVendor('codename'); + $app::__setNamespace('\\codename\\core\\io\\tests\\datasource'); + + $app::getAppstack(); + + // avoid re-init + if (static::$initialized) { + return; + } + + static::$initialized = true; + + static::setEnvironmentConfig([ + 'test' => [ + 'database' => [ + // NOTE: by default, we do these tests using + // pure in-memory sqlite. + 'default' => [ + 'driver' => 'sqlite', + // 'database_file' => 'testmodel.sqlite', + 'database_file' => ':memory:', + ], + ], + 'cache' => [ + 'default' => [ + 'driver' => 'memory', + ], + ], + 'filesystem' => [ + 'local' => [ + 'driver' => 'local', + ], + ], + 'log' => [ + 'default' => [ + 'driver' => 'system', + 'data' => [ + 'name' => 'dummy', + ], + ], + ], + ], + ]); + + static::createModel('datasourcetest', 'datasourceentry', [ + 'field' => [ + 'datasourceentry_id', + 'datasourceentry_created', + 'datasourceentry_modified', + 'datasourceentry_text', + 'datasourceentry_integer', + ], + 'primary' => [ + 'datasourceentry_id', + ], + 'datatype' => [ + 'datasourceentry_id' => 'number_natural', + 'datasourceentry_created' => 'text_timestamp', + 'datasourceentry_modified' => 'text_timestamp', + 'datasourceentry_text' => 'text', + 'datasourceentry_integer' => 'number_natural', + ], + 'connection' => 'default', + ], function ($schema, $model, $config) { + return new datasourceentry([]); + }); + + static::createModel('datasourcetest', 'datasourceentryj', [ + 'field' => [ + 'datasourceentryj_id', + 'datasourceentryj_created', + 'datasourceentryj_modified', + 'datasourceentryj_datasourceentry_id', + 'datasourceentryj_text', + ], + 'primary' => [ + 'datasourceentryj_id', + ], + 'foreign' => [ + 'datasourceentryj_datasourceentry_id' => [ + 'schema' => 'datasourcetest', + 'model' => 'datasourceentry', + 'key' => 'datasourceentry_id', + ], + ], + 'datatype' => [ + 'datasourceentryj_id' => 'number_natural', + 'datasourceentryj_created' => 'text_timestamp', + 'datasourceentryj_modified' => 'text_timestamp', + 'datasourceentryj_datasourceentry_id' => 'number_natural', + 'datasourceentryj_text' => 'text', + ], + 'connection' => 'default', + ], function ($schema, $model, $config) { + return new datasourceentryj([]); + }); + + static::architect('datasourcetest', 'codename', 'test'); + } +} diff --git a/tests/datasource/multicsvTest.php b/tests/datasource/multicsvTest.php new file mode 100644 index 0000000..c42e1e2 --- /dev/null +++ b/tests/datasource/multicsvTest.php @@ -0,0 +1,101 @@ +currentProgressPosition()); + + static::assertEquals('68', $datasource->currentProgressLimit()); + + $datasource->setConfig([ + 'delimiter' => ';', + 'headed' => true, + ]); + } + + /** + * tests key stability of the multicsv datasource + * @return void + * @throws exception + */ + public function testDatasourceMulticsvKeys(): void + { + $datasource = new multicsv([ + __DIR__ . "/" . 'testmulticsv1.csv', + __DIR__ . "/" . 'testmulticsv2.csv', + __DIR__ . "/" . 'testmulticsv3.csv', + ], [ + 'delimiter' => ',', + ]); + + $datasource->rewind(); + + // keep track of keys we've iterated over + $keysIterated = []; + $keyExpected = 0; + + $i = 0; + foreach ($datasource as $key => $dataset) { + static::assertFalse(in_array($key, $keysIterated), "Assert index/key '$key' hasn't been iterated over yet (keysIterated: " . implode(',', $keysIterated) . ")."); + static::assertEquals($keyExpected, $key, "Assert a stable and linear key progression from 0...n in a +1 manner."); + $keyExpected++; + $i++; + $keysIterated[] = $key; + } + + // + // make sure we have iterated NINE times + // + static::assertEquals(9, $i, "Asset we've iterated over the complete datasource"); + } + + + /** + * "head1","head2" + * "l1_d1","l1_d2" + * "l2_d1","l2_d2" + * "l3_d1","l3_d2" + * + * @return void testing the next function + * @throws exception + */ + public function testMultiDataSourceNext(): void + { + $datasource = new multicsv([ + __DIR__ . "/" . 'testmulticsv1.csv', + __DIR__ . "/" . 'testmulticsv2.csv', + __DIR__ . "/" . 'testmulticsv3.csv', + ], [ + 'delimiter' => ',', + ]); + + $datasource->rewind(); + + $i = 0; + foreach ($datasource as $dataset) { + $i++; + + static::assertEquals("l{$i}_d1", $dataset['head1']); + static::assertEquals("l{$i}_d2", $dataset['head2']); + } + + // + // make sure we have iterated NINE times + // + static::assertEquals(9, $i); + } +} diff --git a/tests/datasource/parquetTest.php b/tests/datasource/parquetTest.php new file mode 100644 index 0000000..c257ee1 --- /dev/null +++ b/tests/datasource/parquetTest.php @@ -0,0 +1,136 @@ +expectException(\codename\core\exception::class); + $this->expectExceptionMessage('FILE_COULD_NOT_BE_OPENED'); + new parquet(__DIR__ . "/" . 'parquet/does-not-exist.parquet'); + } + + /** + * [testReadNonParquetFile description] + * @throws \codename\core\exception + */ + public function testReadNonParquetFile(): void + { + $this->expectException(Exception::class); + new parquet(__DIR__ . "/" . 'testcsv1.csv'); + } + + /** + * [testParquetReadingStepByStep description] + * @throws \codename\core\exception + * @throws ParquetException + */ + public function testParquetReadingStepByStep(): void + { + $datasource = new parquet(__DIR__ . "/" . 'parquet/postcodes.plain.parquet'); + + // Assert we're at the start, not having read any data + static::assertEquals(0, $datasource->key()); + static::assertNull($datasource->current()); + static::assertEquals(0, $datasource->currentProgressPosition()); + $datasource->next(); + + // NOTE: key() will return 0 on the first item + // but as in every iterator, you'll have to evaluate valid() first + static::assertEquals(0, $datasource->key()); + static::assertNotNull($datasource->current()); + static::assertEquals(0, $datasource->currentProgressPosition()); + + $datasource->next(); + static::assertEquals(1, $datasource->key()); + static::assertNotNull($datasource->current()); + static::assertEquals(1, $datasource->currentProgressPosition()); + + // loop til end + while ($datasource->valid()) { + $datasource->next(); + } + $datasource->next(); + + // TODO: evaluate this situation... + // print_r([$datasource->currentProgressLimit(), $datasource->currentProgressPosition()]); + // static::assertEquals($lastKey, $datasource->currentProgressLimit()); + // static::assertEquals($lastKey, $datasource->currentProgressPosition()); + } + + /** + * [testParquetReading description] + * @throws ParquetException + * @throws \codename\core\exception + */ + public function testParquetReading(): void + { + $datasource = new parquet(__DIR__ . "/" . 'parquet/postcodes.plain.parquet'); + $rows = []; + foreach ($datasource as $row) { + $rows[] = $row; + } + + static::assertEquals(237, $datasource->key()); + static::assertCount(237, $rows); + static::assertEquals(count($rows), $datasource->currentProgressLimit()); + + // randomly call next()... + $datasource->next(); + + // At this point we reached the end of the file + static::assertFalse($datasource->valid()); + + // Try to go even further... + $datasource->next(); + static::assertFalse($datasource->valid()); + + // iterate a second time and compare results + // tests rewinding, internally + $rows2 = []; + foreach ($datasource as $row) { + $rows2[] = $row; + } + + static::assertEquals($rows, $rows2); + } + + /** + * [testParquetReadingMultipage description] + * @throws ParquetException + * @throws \codename\core\exception + */ + public function testParquetReadingMultipage(): void + { + // TODO: evaluate whether we really have a multipage parquet file here + $datasource = new parquet(__DIR__ . "/" . 'parquet/running_numbers_spark.gz.parquet'); + $rows = []; + foreach ($datasource as $row) { + $rows[] = $row; + } + + static::assertEquals(10000, $datasource->key()); + static::assertCount(10000, $rows); + + // randomly call next()... + $datasource->next(); + + // iterate a second time and compare results + // tests rewinding, internally + $rows2 = []; + foreach ($datasource as $row) { + $rows2[] = $row; + } + + static::assertEquals($rows, $rows2); + } +} diff --git a/tests/datasource/rawTest.php b/tests/datasource/rawTest.php new file mode 100644 index 0000000..355a871 --- /dev/null +++ b/tests/datasource/rawTest.php @@ -0,0 +1,242 @@ +key()); + + static::assertEquals('0', $datasource->currentProgressPosition()); + + static::assertEquals('52', $datasource->currentProgressLimit()); + + // rewind the datasources + $datasource->rewind(); + } + + /** + * test a simple raw file + * @return void [type] [description] + * @throws exception + */ + public function testDataSourceFileNotExists(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('FILE_COULD_NOT_BE_OPEN'); + new raw(__DIR__ . "/" . 'testRaw1_filenotexists.txt'); + } + + /** + * test a simple raw file + * @return void [type] [description] + * @throws exception + */ + public function testDataSourceInvalidConfig(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('CORE_IO_DATASOURCE_INVALID_MAP_CONFIG'); + + new raw( + __DIR__ . "/" . 'testRaw1.txt', + [ + 'format' => [ + 'trim' => true, + 'convert' => [ + 'from' => 'ASCII', + 'to' => 'UTF-8', + ], + 'map' => [ + 'field1' => [ + 'type' => 'wrong', + 'length' => 10, + ], + ], + ], + ] + ); + } + + /** + * test a simple raw file + * @return void [type] [description] + * @throws exception + */ + public function testDataSourceIsValid(): void + { + $datasource = new raw( + __DIR__ . "/" . 'testRaw1.txt', + [ + 'format' => [ + 'trim' => true, + 'convert' => [ + 'from' => 'ASCII', + 'to' => 'UTF-8', + ], + 'map' => [ + 'field1' => [ + 'type' => 'fixed', + 'length' => 10, + ], + 'field2' => [ + 'type' => 'fixed', + 'length' => 10, + ], + 'field3' => [ + 'type' => 'fixed', + 'length' => 10, + ], + ], + ], + ] + ); + $datasource->next(); + + static::assertNotEmpty($datasource->getRawCurrent()); + + $data = $datasource->current(); + static::assertEquals('col11', $data['field1']); + static::assertEquals('col21', $data['field2']); + static::assertEquals('col31', $data['field3']); + } + + /** + * test a simple raw file + * @return void [type] [description] + * @throws exception + */ + public function testDataSourceIsValidWithMappings(): void + { + $datasource = new raw( + __DIR__ . "/" . 'testRaw1.txt', + [ + 'format' => [ + 'trim' => true, + 'map' => [ + 'key' => [ + 'type' => 'fixed', + 'length' => 5, + ], + ], + ], + 'mappings' => [ + 'key' => [ + 'col11' => [ + 'trim' => true, + 'map' => [ + 'field1' => [ + 'type' => 'fixed', + 'length' => 10, + ], + 'field2' => [ + 'type' => 'fixed', + 'length' => 10, + ], + 'field3' => [ + 'type' => 'fixed', + 'length' => 10, + ], + ], + ], + 'col12' => [ + 'trim' => true, + 'convert' => [ + 'from' => 'ASCII', + 'to' => 'UTF-8', + ], + 'map' => [ + 'field1' => [ + 'type' => 'fixed', + 'length' => 10, + ], + 'field2' => [ + 'type' => 'fixed', + 'length' => 10, + ], + 'field3' => [ + 'type' => 'fixed', + 'length' => 10, + ], + ], + ], + ], + ], + ] + ); + $datasource->next(); + + static::assertNotEmpty($datasource->getRawCurrent()); + + $data = $datasource->current(); + static::assertEquals('col11', $data['field1']); + static::assertEquals('col21', $data['field2']); + static::assertEquals('col31', $data['field3']); + + $datasource->next(); + + $data = $datasource->current(); + static::assertEquals('col12', $data['field1']); + static::assertEquals('col22', $data['field2']); + static::assertEquals('col32', $data['field3']); + } + + /** + * "head1","head2" + * "l1_d1","l1_d2" + * "l2_d1","l2_d2" + * "l3_d1","l3_d2" + * + * @return void testing the next function + * @throws exception + */ + public function testDataSourceNext(): void + { + $datasource = new raw( + __DIR__ . "/" . 'testRaw1.txt', + [ + 'format' => [ + 'trim' => true, + 'map' => [ + 'field1' => [ + 'type' => 'fixed', + 'length' => 10, + ], + 'field2' => [ + 'type' => 'fixed', + 'length' => 10, + ], + 'field3' => [ + 'type' => 'fixed', + 'length' => 10, + ], + ], + ], + ] + ); + + $i = 0; + foreach ($datasource as $dataset) { + $i++; + static::assertEquals("col1$i", $dataset['field1']); + static::assertEquals("col2$i", $dataset['field2']); + static::assertEquals("col3$i", $dataset['field3']); + } + + // + // make sure we have iterated two times + // + static::assertEquals(2, $i); + } +} diff --git a/tests/datasource/remapTest.php b/tests/datasource/remapTest.php new file mode 100644 index 0000000..7411f2a --- /dev/null +++ b/tests/datasource/remapTest.php @@ -0,0 +1,242 @@ +setData($this->getTestData()); + $remappedDatasource = new remap( + $datasource, + [ + 'remap' => [ + 'oldkey1' => 'newkey1', + 'oldkey2' => 'newkey2', + 'oldkey3' => 'newkey3', + ], + ] + ); + + // rewind the datasources + $remappedDatasource->rewind(); + + $result = $remappedDatasource->current(); + static::assertEquals([ + 'newkey1' => 'abc', + 'newkey2' => 'def', + 'newkey3' => 'ghi', + ], $result); + + static::assertEquals('0', $remappedDatasource->currentProgressPosition()); + + static::assertEquals('3', $remappedDatasource->currentProgressLimit()); + + static::assertEquals('0', $remappedDatasource->key()); + + static::assertTrue($remappedDatasource->valid()); + } + + /** + * returns an array of basic test data + * @return array + */ + protected function getTestData(): array + { + return [ + [ + 'oldkey1' => 'abc', + 'oldkey2' => 'def', + 'oldkey3' => 'ghi', + 'oldkey4' => ['jkl', 'mno'], + ], + [ + 'oldkey1' => 'jkl', + 'oldkey2' => 'mno', + 'oldkey3' => 'pqr', + 'oldkey4' => ['stu', 'vwx'], + ], + [ + 'oldkey1' => 'stu', + 'oldkey2' => 'vwx', + 'oldkey3' => 'yz', + 'oldkey4' => ['abc', 'def'], + ], + ]; + } + + /** + * tests general function of the remap datasource + * @return void [type] [description] + */ + public function testRemapDatasource(): void + { + $datasource = new arraydata(); + $datasource->setData($this->getTestData()); + $remappedDatasource = new remap( + $datasource, + [ + 'remap' => [ + 'oldkey1' => 'newkey1', + 'oldkey2' => 'newkey2', + 'oldkey3' => 'newkey3', + 'oldkey4' => ['newarraykey1', 'newarraykey2'], + ], + ] + ); + + $comparisonDatasource = new arraydata(); + $comparisonDatasource->setData($this->getTestData()); + + // rewind the datasources + $remappedDatasource->rewind(); + $comparisonDatasource->rewind(); + + // max sure we only iterate over the count of the testdata array + $iterations = count($this->getTestData()); + $i = 0; + + while ($i < $iterations) { + $remappedDataset = $remappedDatasource->current(); + $originalDataset = $comparisonDatasource->current(); + + static::assertEquals($remappedDataset['newkey1'], $originalDataset['oldkey1']); + static::assertEquals($remappedDataset['newkey2'], $originalDataset['oldkey2']); + static::assertEquals($remappedDataset['newkey3'], $originalDataset['oldkey3']); + + $i++; + } + } + + /** + * tests outputting a dataset based on the input + * e.g. the remapped values are put ON TOP of the input (or replaced) + * @return void + */ + public function testRemapReplaceSourceInclusion(): void + { + $datasource = new arraydata(); + $datasource->setData($this->getTestData()); + + $remappedDatasource = new remap( + $datasource, + [ + 'remap' => [ + 'oldkey1' => 'newkey1', + 'oldkey2' => 'newkey2', + 'oldkey3' => 'newkey3', + ], + // the relevant config key + 'replace' => true, + ] + ); + + $originalDatasource = new arraydata(); + $originalDatasource->setData($this->getTestData()); + + $tempDatasource = new arraydata(); + $tempDatasource->setData($this->getTestData()); + $normalRemappedDatasource = new remap( + $tempDatasource, + [ + 'remap' => [ + 'oldkey1' => 'newkey1', + 'oldkey2' => 'newkey2', + 'oldkey3' => 'newkey3', + ], + ] + ); + + // rewind the datasources + $remappedDatasource->rewind(); + $originalDatasource->rewind(); + $normalRemappedDatasource->rewind(); + + // max sure we only iterate over the count of the testdata array + $iterations = count($this->getTestData()); + $i = 0; + + while ($i < $iterations) { + $remappedDataset = $remappedDatasource->current(); + + // original + $originalDataset = $originalDatasource->current(); + + // remapped without including the input data + $normallyRemappedDataset = $normalRemappedDatasource->current(); + + foreach ($originalDataset as $key => $value) { + static::assertEquals($value, $remappedDataset[$key]); + } + foreach ($normallyRemappedDataset as $key => $value) { + static::assertEquals($value, $remappedDataset[$key]); + } + + // Don't forget to move the iterator + $remappedDatasource->next(); + $originalDatasource->next(); + $normalRemappedDatasource->next(); + + $i++; + } + } + + /** + * tests the inclusion of original data in a subkey + * @return void [type] [description] + */ + public function testRemapSourceDataKey(): void + { + $datasource = new arraydata(); + $datasource->setData($this->getTestData()); + + $sourceDataKey = 'original'; + + $remappedDatasource = new remap( + $datasource, + [ + 'remap' => [ + 'oldkey1' => 'newkey1', + 'oldkey2' => 'newkey2', + 'oldkey3' => 'newkey3', + ], + 'source_data_key' => $sourceDataKey, + ] + ); + + $comparisonDatasource = new arraydata(); + $comparisonDatasource->setData($this->getTestData()); + + // rewind the datasources + $remappedDatasource->rewind(); + $comparisonDatasource->rewind(); + + // max sure we only iterate over the count of the testdata array + $iterations = count($this->getTestData()); + $i = 0; + + while ($i < $iterations) { + $remappedDataset = $remappedDatasource->current(); + $originalDataset = $comparisonDatasource->current(); + static::assertEquals($remappedDataset[$sourceDataKey], $originalDataset); + + // Don't forget to move the iterator + $remappedDatasource->next(); + $comparisonDatasource->next(); + + $i++; + } + } +} diff --git a/tests/datasource/spreadsheetTest.php b/tests/datasource/spreadsheetTest.php new file mode 100644 index 0000000..1947d73 --- /dev/null +++ b/tests/datasource/spreadsheetTest.php @@ -0,0 +1,161 @@ +key()); + + static::assertEquals('0', $datasource->currentProgressPosition()); + + static::assertEquals('0', $datasource->currentProgressLimit()); + + try { + $datasource->setConfig([]); + } catch (\Exception) { + static::fail(); + } + + static::assertTrue(true); + } + + /** + * test a simple spreadsheet file + * @return void [type] [description] + * @throws Exception + * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception + */ + public function testDataSourceIsValid(): void + { + $datasource = new spreadsheet( + __DIR__ . "/" . 'testSpreadsheet1.xlsx', + [ + 'custom_sheet_index' => 0, + 'multisheet' => 0, + 'skip_rows' => 3, + 'header_row' => 2, + ] + ); + + $datasource->next(); + + $data = $datasource->current(); + static::assertEquals('Value2-1', $data['A']); + static::assertEquals('Value2-2', $data['B']); + static::assertEquals('Value2-3', $data['C']); + } + + /** + * test a simple spreadsheet file + * @return void [type] [description] + * @throws Exception + * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception + */ + public function testDataSourceIsValidWithXls(): void + { + $datasource = new spreadsheet( + __DIR__ . "/" . 'testSpreadsheet1.xls', + [ + 'custom_sheet_index' => 0, + 'multisheet' => 0, + 'skip_rows' => 3, + 'header_row' => 2, + ] + ); + + $datasource->next(); + + $data = $datasource->current(); + static::assertEquals('Value2-1', $data['A']); + static::assertEquals('Value2-2', $data['B']); + static::assertEquals('Value2-3', $data['C']); + } + + /** + * test a simple spreadsheet file + * @return void [type] [description] + * @throws Exception + * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception + */ + public function testDataSourceNext(): void + { + $datasource = new spreadsheet( + __DIR__ . "/" . 'testSpreadsheet1.xlsx', + [ + 'skip_rows' => 1, + 'header_row' => 2, + ] + ); + + $i = 0; + foreach ($datasource as $dataset) { + $i++; + static::assertEquals("Value$i-1", $dataset['Head1']); + static::assertEquals("Value$i-2", $dataset['Head2']); + static::assertEquals("Value$i-3", $dataset['Head3']); + } + + // + // make sure we have iterated two times + // + static::assertEquals(2, $i); + } + + /** + * test a simple spreadsheet file + * @return void [type] [description] + * @throws Exception + * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception + */ + public function testDataSourceMulti(): void + { + $datasource = new spreadsheet( + __DIR__ . "/" . 'testSpreadsheet3.xlsx', + [ + 'multisheet' => true, + 'custom_sheet_index' => 1, + 'skip_rows' => 3, + 'header_row' => 2, + ] + ); + + $i = 0; + foreach ($datasource as $dataset) { + $i++; + if ($i === 1) { + static::assertEquals('12', $dataset['A']); + static::assertEquals('345', $dataset['B']); + static::assertEquals('678', $dataset['C']); + } elseif ($i === 2) { + static::assertEquals('901', $dataset['A']); + static::assertEquals('234', $dataset['B']); + static::assertEquals('567', $dataset['C']); + } elseif ($i === 3) { + static::assertEquals('jkl', $dataset['A']); + static::assertEquals('mno', $dataset['B']); + static::assertEquals('pqr', $dataset['C']); + } elseif ($i === 4) { + static::assertEquals('stu', $dataset['A']); + static::assertEquals('vwx', $dataset['B']); + static::assertEquals('yz', $dataset['C']); + } + } + } +} diff --git a/tests/datasource/testArraydata.php b/tests/datasource/testArraydata.php deleted file mode 100644 index f21c5f9..0000000 --- a/tests/datasource/testArraydata.php +++ /dev/null @@ -1,62 +0,0 @@ -setData([ - [ - 'oldkey1' => 'abc', - 'oldkey2' => 'def', - 'oldkey3' => 'ghi', - ], - [ - 'oldkey1' => 'jkl', - 'oldkey2' => 'mno', - 'oldkey3' => 'pqr', - ], - [ - 'oldkey1' => 'stu', - 'oldkey2' => 'vwx', - 'oldkey3' => 'yz', - ] - ]); - - $this->assertNull($datasource->setConfig([])); - - $this->assertEquals('0', $datasource->currentProgressPosition()); - - $this->assertEquals('3', $datasource->currentProgressLimit()); - - // rewind the datasources - $datasource->rewind(); - - $this->assertEquals('0', $datasource->key()); - - $this->assertTrue($datasource->valid()); - - // get current data - $this->assertEquals([ - 'oldkey1' => 'abc', - 'oldkey2' => 'def', - 'oldkey3' => 'ghi', - ], $datasource->current()); - - $this->assertEquals([ - 'oldkey1' => 'jkl', - 'oldkey2' => 'mno', - 'oldkey3' => 'pqr', - ], $datasource->next()); - - } - -} diff --git a/tests/datasource/testBuffered.php b/tests/datasource/testBuffered.php deleted file mode 100644 index 695c567..0000000 --- a/tests/datasource/testBuffered.php +++ /dev/null @@ -1,137 +0,0 @@ -expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_DATASOURCE_BUFFERED_BUFFERSIZE_TOO_LOW'); - $source = new \codename\core\io\datasource\arraydata(); - $buffered = new \codename\core\io\datasource\buffered($source, 0); - } - - /** - * [testSmallBufferOnEmptySource description] - * @return [type] [description] - */ - public function testSmallBufferOnEmptySource() { - $source = new \codename\core\io\datasource\arraydata(); - $source->setData([]); - $buffered = new \codename\core\io\datasource\buffered($source, 1); - - $r = []; - foreach($buffered as $b) { - $r[] = $b; - } - - // var_dump($buffered->current()); - - $buffered->rewind(); - - // var_dump([ - // '$buffered->current()' => $buffered->current(), - // '$buffered->valid()' => $buffered->valid(), - // '$buffered->key()' => $buffered->key(), - // ]); - // - // var_dump($r); - - $this->assertEquals(0, $source->currentProgressLimit()); - $this->assertEquals(0, $buffered->currentProgressLimit()); - $this->assertEmpty($r); - } - - /** - * [testBufferReadingWithMultipleBufferSizes description] - */ - public function testBufferReadingWithMultipleBufferSizes(): void { - $source = new \codename\core\io\datasource\arraydata(); - $source->setData([ - 1, 2, 3, 4, 5, 6, 7, 8 - ]); - - for ($bufferSize=1; $bufferSize <= 16; $bufferSize++) { - $buffered = new \codename\core\io\datasource\buffered($source, $bufferSize); - $r = []; - foreach($buffered as $b) { - $r[] = $b; - } - $this->assertEquals([1, 2, 3, 4, 5, 6, 7, 8], $r); - } - } - - /** - * [testBufferReadingWithMultipleBufferSizesDynamic description] - */ - public function testBufferReadingWithMultipleBufferSizesDynamic(): void { - $source = new \codename\core\io\datasource\arraydata(); - $source->setData([ - 1, 2, 3, 4, 5, 6, 7, 8 - ]); - - $resultCount = $source->currentProgressLimit(); - - $buffered = new \codename\core\io\datasource\buffered($source, 999); - - for ($bufferSize=1; $bufferSize <= 16; $bufferSize++) { - // Modify buffer size of the only instance - $buffered->setBufferSize($bufferSize); - $buffered->rewind(); - - $this->assertLessThanOrEqual($bufferSize, $buffered->getBuffer()->count()); - - $r = []; - $cnt = 0; - foreach($buffered as $b) { - $r[] = $b; - $this->assertEquals($cnt, $buffered->currentProgressPosition()); - $this->assertEquals($cnt, $buffered->key()); - $cnt++; - } - - $this->assertEquals([1, 2, 3, 4, 5, 6, 7, 8], $r); - } - } - - /** - * [testSetConfigPassthrough description] - */ - public function testSetConfigPassthrough(): void { - $source = new \codename\core\io\datasource\csv( - __DIR__ . "/" . 'testcsv2.csv', - [ - 'autodetect_utf8_bom' => true, - 'skip_empty_rows' => true, - 'skip_rows' => 11, // wrong setting - 'encoding' => [ 'from' => 'UTF-8', 'to' => 'UTF-8' ], - ] - ); - - $buffered = new \codename\core\io\datasource\buffered($source, 999); - - $buffered->setConfig([ - 'autodetect_utf8_bom' => true, - 'skip_empty_rows' => true, - 'skip_rows' => 1, // right setting - 'encoding' => [ 'from' => 'UTF-8', 'to' => 'UTF-8' ], - ]); - - $i = 0; - foreach($buffered as $dataset) { - $i++; - $this->assertEquals($dataset['head0'], "l{$i}_d1"); - $this->assertEquals($dataset['head1'], "l{$i}_d2"); - } - - $this->assertEquals(3, $i); - - } - -} diff --git a/tests/datasource/testCsv.php b/tests/datasource/testCsv.php deleted file mode 100644 index f01aff7..0000000 --- a/tests/datasource/testCsv.php +++ /dev/null @@ -1,222 +0,0 @@ -assertEquals('0', $datasource->currentProgressPosition()); - $this->assertEquals('31', $datasource->currentProgressLimit()); - } - - /** - * Test function to be moved to enshared, when available. - */ - public function testCsvStaticFormConfigProvider(): void { - $this->markTestIncomplete('Feature is to a different package.'); - $datasource = new \codename\core\io\datasource\csv(__DIR__ . "/" . 'testcsv1.csv'); - $formFieldConfigArrayStatic = $datasource->getFormFieldConfigArrayStatic([]); - $this->assertEquals([ - [ - 'field_title' => 'Trennzeichen', - 'field_name' => 'delimiter', - 'field_type' => 'input', - 'field_value' => ';' - ], - [ - 'field_title' => 'Kopfzeile vorhanden?', - 'field_name' => 'headed', - 'field_type' => 'checkbox', - 'field_datatype' => 'boolean', - 'field_value' => true - ], - [ - 'field_title' => 'UTF8-BOM automatisch erkennen', - 'field_name' => 'autodetect_utf8_bom', - 'field_type' => 'checkbox', - 'field_datatype' => 'boolean', - 'field_value' => false - ], - [ - 'field_title' => 'Leere Zeilen überspringen', - 'field_description' => 'Aktiviert die Überprüfung und Überspringen von leeren Zeilen', - 'field_name' => 'skip_empty_rows', - 'field_type' => 'checkbox', - 'field_datatype' => 'boolean', - 'field_value' => false - ], - [ - 'field_title' => 'Codierung', - 'field_name' => 'encoding', - 'field_type' => 'form', - 'form' => [ - 'config' => [ 'dummy' => true ], - 'fields' => [ - [ - 'field_title' => 'Codierung von', - 'field_name' => 'from', - 'field_type' => 'input', - 'field_value' => 'ASCII' - ], - [ - 'field_title' => 'Codierung zu', - 'field_name' => 'to', - 'field_type' => 'input', - 'field_value' => 'UTF-8' - ], - ], - ], - 'field_value' => [ 'from' => 'ASCII', 'to' => 'UTF-8' ] - ], - [ - 'field_title' => 'Zeilen von oben überspringen', - 'field_name' => 'skip_rows', - 'field_type' => 'input', - 'field_datatype' => 'number_natural', - 'field_value' => 0 - ] - ], $formFieldConfigArrayStatic); - } - - /** - * test an simple csv file - * @return [type] [description] - */ - public function testDataSourceFileNotExists() { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('FILE_COULD_NOT_BE_OPEN'); - $datasource = new \codename\core\io\datasource\csv(__DIR__ . "/" . 'testcsv1_filenotexists.csv'); - - } - - /** - * test an simple csv file - * @return [type] [description] - */ - public function testDataSourceIsValid() { - $datasource = new \codename\core\io\datasource\csv(__DIR__ . "/" . 'testcsv1.csv'); - $datasource->next(); - - $head = $datasource->getHeadings(); - $this->assertEquals($head[0], 'head1'); - $this->assertEquals($head[1], 'head2'); - - $data = $datasource->current(); - $this->assertEquals($data['head1'], 'bla'); - $this->assertEquals($data['head2'], 'foo'); - - } - - /** - * "head1","head2" - * "l1_d1","l1_d2" - * "l2_d1","l2_d2" - * "l3_d1","l3_d2" - * - * @return void testing the next function - */ - public function testDataSourceNext() { - $datasource = new \codename\core\io\datasource\csv( - __DIR__ . "/" . 'testcsv2.csv', - [ - 'autodetect_utf8_bom' => true, - 'skip_empty_rows' => true, - 'skip_rows' => 1, - 'encoding' => [ 'from' => 'UTF-8', 'to' => 'UTF-8' ], - ] - ); - - $i = 0; - foreach($datasource as $dataset) { - $i++; - $this->assertEquals($dataset['head0'], "l{$i}_d1"); - $this->assertEquals($dataset['head1'], "l{$i}_d2"); - } - - // - // make sure we have iterated three times - // - $this->assertEquals(3, $i); - } - /** - * "head1","head2" - * "l1_d1","l1_d2" - * "l2_d1","l2_d2" - * "l3_d1","l3_d2" - * - * @return void testing the next function - */ - public function testDataSourceWrongOffset() { - $datasource = new overriddenCsv( - __DIR__ . "/" . 'testcsv2.csv', - [ - 'autodetect_utf8_bom' => true, - 'skip_empty_rows' => true, - 'skip_rows' => 1, - 'encoding' => [ 'from' => 'UTF-8', 'to' => 'UTF-8' ], - ] - ); - - $i = 0; - foreach($datasource as $dataset) { - $i++; - $this->assertEquals($dataset['head0'], "l{$i}_d1"); - $this->assertEquals($dataset['head1'], "l{$i}_d2"); - } - - // - // make sure we have iterated three times - // - $this->assertEquals(3, $i); - } - - /** - * [testDatasourceCsvWindows1252Decoding description] - */ - public function testDatasourceCsvWindows1252Decoding(): void { - $datasource = new \codename\core\io\datasource\csv( - __DIR__ . "/" . 'csv_windows1252_umlauts.csv', - [ - 'delimiter' => ';', - 'encoding' => [ 'from' => 'Windows-1252', 'to' => 'UTF-8' ], - ] - ); - - $rows = []; - foreach($datasource as $key => $row) { - $rows[] = $row; - } - - $this->assertEquals([ - [ 'NormalColumn' => 'Ä', 'ColumnWithUmlautsÄüÖö' => '1' ], - [ 'NormalColumn' => 'Ü', 'ColumnWithUmlautsÄüÖö' => '2' ], - [ 'NormalColumn' => 'Ö', 'ColumnWithUmlautsÄüÖö' => '3' ], - [ 'NormalColumn' => 'ß', 'ColumnWithUmlautsÄüÖö' => '4' ], - ], $rows); - } - -} - -/** - * [overriddenCsv description] - */ -class overriddenCsv extends \codename\core\io\datasource\csv { - - /** - * [rewind description] - * @return [type] [description] - */ - public function rewind() { - fseek($this->handle, 1); - if($this->autodetectUtf8Bom) { - $this->handleUtf8Bom(); - } - $this->index = 0; - $this->next(); - } -} diff --git a/tests/datasource/testJoined.php b/tests/datasource/testJoined.php deleted file mode 100644 index 8b63e42..0000000 --- a/tests/datasource/testJoined.php +++ /dev/null @@ -1,232 +0,0 @@ - ';', - ] - ), - new \codename\core\io\datasource\csv( - __DIR__.'/joined1_join1.csv', - [ - 'delimiter' => ';', - ] - ) - ], - [ - // CONFIG! - 'join' => [ - [ - 'index' => $indexesEnabled, - 'base_datasource' => 0, // array index-based - 'join_datasource' => 1, // array index-based - 'base_field' => 'col2', - 'join_field' => 'id2', - ] - ] - ] - ); - - $res = []; - foreach($joinedDatasource as $d) { - $res[] = $d; - } - - $this->assertCount(6, $res); - - // At the time of writing, missing values are not applied to join result datasets - // therefore, array_column will return less values in those cases (stipping out unset values) - $this->assertEquals(['ABC','DEF','GHI','ABC', /*null,*/ 'GHI'], array_column($res, 'name')); - } - - /** - * Test the same with explicit names for the datasources - * @testWith [ false ] - * [ true ] - */ - public function testSimpleJoinedCsvWithNamedDatasources(bool $indexesEnabled): void { - $joinedDatasource = new \codename\core\io\datasource\joined( - [ - 'foo' => new \codename\core\io\datasource\csv( - __DIR__.'/joined1_base1.csv', - [ - 'delimiter' => ';', - ] - ), - 'bar' => new \codename\core\io\datasource\csv( - __DIR__.'/joined1_join1.csv', - [ - 'delimiter' => ';', - ] - ) - ], - [ - // CONFIG! - 'join' => [ - [ - 'index' => $indexesEnabled, - 'base_datasource' => 'foo', // key-based - 'join_datasource' => 'bar', // key-based - 'base_field' => 'col2', - 'join_field' => 'id2', - ] - ] - ] - ); - - $res = []; - foreach($joinedDatasource as $d) { - $res[] = $d; - } - - $this->assertCount(6, $res); - - // At the time of writing, missing values are not applied to join result datasets - // therefore, array_column will return less values in those cases (stipping out unset values) - $this->assertEquals(['ABC','DEF','GHI','ABC', /*null,*/ 'GHI'], array_column($res, 'name')); - } - - /** - * [testMultipleJoinedCsvWithNamedDatasources description] - * @testWith [ false ] - * [ true ] - */ - public function testMultipleJoinedCsvWithNamedDatasources(bool $indexesEnabled): void { - $joinedDatasource = new \codename\core\io\datasource\joined( - [ - 'foo' => new \codename\core\io\datasource\csv( - __DIR__.'/joined1_base1.csv', - [ - 'delimiter' => ';', - ] - ), - 'bar' => new \codename\core\io\datasource\csv( - __DIR__.'/joined1_join1.csv', - [ - 'delimiter' => ';', - ] - ), - 'baz' => new \codename\core\io\datasource\csv( - __DIR__.'/joined1_join2.csv', - [ - 'delimiter' => ';', - ] - ) - ], - [ - // CONFIG! - 'join' => [ - [ - 'index' => $indexesEnabled, - 'base_datasource' => 'foo', // key-based - 'join_datasource' => 'bar', // key-based - 'base_field' => 'col2', - 'join_field' => 'id2', - ], - [ - 'index' => $indexesEnabled, - 'base_datasource' => 'bar', // key-based - 'join_datasource' => 'baz', // key-based - 'base_field' => 'other_id', - 'join_field' => 'join2_id', - ], - ] - ] - ); - - $res = []; - foreach($joinedDatasource as $d) { - $res[] = $d; - } - - $this->assertCount(6, $res); - - // At the time of writing, missing values are not applied to join result datasets - // therefore, array_column will return less values in those cases (stipping out unset values) - $this->assertEquals(['ABC','DEF','GHI','ABC', /*null,*/ 'GHI'], array_column($res, 'name')); - $this->assertEquals(['BBB','BBB','CCC','BBB', /*null,*/ 'CCC' ], array_column($res, 'value')); - } - - /** - * @testWith [ false ] - * [ true ] - * @param bool $indexesEnabled [description] - */ - public function testMultipleJoinedCsvWithNamedDatasourcesAndAmbiguities(bool $indexesEnabled): void { - $joinedDatasource = new \codename\core\io\datasource\joined( - [ - 'foo' => new \codename\core\io\datasource\csv( - __DIR__.'/joined1_base1.csv', - [ - 'delimiter' => ';', - ] - ), - 'bar' => new \codename\core\io\datasource\csv( - __DIR__.'/joined1_join1.csv', - [ - 'delimiter' => ';', - ] - ), - 'baz' => new \codename\core\io\datasource\csv( - __DIR__.'/joined1_join2.csv', - [ - 'delimiter' => ';', - ] - ), - 'qux' => new \codename\core\io\datasource\csv( - __DIR__.'/joined1_join3.csv', - [ - 'delimiter' => ';', - ] - ) - ], - [ - // CONFIG! - 'join' => [ - [ - 'index' => $indexesEnabled, - 'base_datasource' => 'foo', // key-based - 'join_datasource' => 'bar', // key-based - 'base_field' => 'col2', - 'join_field' => 'id2', - ], - [ - 'index' => $indexesEnabled, - 'base_datasource' => 'bar', // key-based - 'join_datasource' => 'baz', // key-based - 'base_field' => 'other_id', - 'join_field' => 'join2_id', - ], - [ - 'index' => $indexesEnabled, - 'base_datasource' => 'foo', // key-based - 'join_datasource' => 'qux', // key-based - 'base_field' => 'col1', - 'join_field' => 'join3_col1', - ], - ] - ] - ); - - $res = []; - foreach($joinedDatasource as $i => $d) { - $res[] = $d; - } - - $this->assertCount(8, $res); - - $this->assertEquals(['A','A','B','C','D','D','E','F'], array_column($res, 'col1')); - $this->assertEquals(['A1','A2','B1','C1','D1','D2','F1'], array_column($res, 'join3_value')); - } -} diff --git a/tests/datasource/testModel.php b/tests/datasource/testModel.php deleted file mode 100644 index 0161314..0000000 --- a/tests/datasource/testModel.php +++ /dev/null @@ -1,356 +0,0 @@ -getModel('datasourceentry') - ->addFilter('datasourceentry_id', 0, '>') - ->delete(); - } - - /** - * @inheritDoc - */ - protected function setUp(): void - { - $app = static::createApp(); - - // Additional overrides to get a more complete app lifecycle - // and allow static global app::getModel() to work correctly - $app->__setApp('datasourcetest'); - $app->__setVendor('codename'); - $app->__setNamespace('\\codename\\core\\io\\tests\\datasource'); - - $app->getAppstack(); - - // avoid re-init - if(static::$initialized) { - return; - } - - static::$initialized = true; - - static::setEnvironmentConfig([ - 'test' => [ - 'database' => [ - // NOTE: by default, we do these tests using - // pure in-memory sqlite. - 'default' => [ - 'driver' => 'sqlite', - // 'database_file' => 'testmodel.sqlite', - 'database_file' => ':memory:', - ], - ], - 'cache' => [ - 'default' => [ - 'driver' => 'memory' - ] - ], - 'filesystem' =>[ - 'local' => [ - 'driver' => 'local', - ] - ], - 'log' => [ - 'default' => [ - 'driver' => 'system', - 'data' => [ - 'name' => 'dummy' - ] - ] - ], - ] - ]); - - static::createModel('datasourcetest', 'datasourceentry', [ - 'field' => [ - 'datasourceentry_id', - 'datasourceentry_created', - 'datasourceentry_modified', - 'datasourceentry_text', - 'datasourceentry_integer', - ], - 'primary' => [ - 'datasourceentry_id' - ], - 'datatype' => [ - 'datasourceentry_id' => 'number_natural', - 'datasourceentry_created' => 'text_timestamp', - 'datasourceentry_modified' => 'text_timestamp', - 'datasourceentry_text' => 'text', - 'datasourceentry_integer' => 'number_natural', - ], - 'connection' => 'default' - ], function($schema, $model, $config) { - return new \codename\core\io\tests\datasource\model\datasourceentry([]); - }); - - static::createModel('datasourcetest', 'datasourceentryj', [ - 'field' => [ - 'datasourceentryj_id', - 'datasourceentryj_created', - 'datasourceentryj_modified', - 'datasourceentryj_datasourceentry_id', - 'datasourceentryj_text', - ], - 'primary' => [ - 'datasourceentryj_id' - ], - 'foreign' => [ - 'datasourceentryj_datasourceentry_id' => [ - 'schema' => 'datasourcetest', - 'model' => 'datasourceentry', - 'key' => 'datasourceentry_id' - ], - ], - 'datatype' => [ - 'datasourceentryj_id' => 'number_natural', - 'datasourceentryj_created' => 'text_timestamp', - 'datasourceentryj_modified' => 'text_timestamp', - 'datasourceentryj_datasourceentry_id' => 'number_natural', - 'datasourceentryj_text' => 'text', - ], - 'connection' => 'default' - ], function($schema, $model, $config) { - return new \codename\core\io\tests\datasource\model\datasourceentryj([]); - }); - - static::architect('datasourcetest', 'codename', 'test'); - } - - /** - * [createTestData description] - */ - protected function createTestData(): void { - $datasets = [ - [ - 'datasourceentry_text' => 'foo', - 'datasourceentry_integer' => 111, - ], - [ - 'datasourceentry_text' => 'bar', - 'datasourceentry_integer' => 222, - ], - [ - 'datasourceentry_text' => 'baz', - 'datasourceentry_integer' => null, - ], - [ - 'datasourceentry_text' => 'qux', - 'datasourceentry_integer' => 333, - ], - ]; - $model = $this->getModel('datasourceentry'); - foreach ($datasets as $dataset) { - $model->save($dataset); - } - } - - /** - * [testDatasourceDoubleSetModelWillFail description] - */ - public function testDatasourceDoubleSetModelWillFail(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_DATASOURCE_MODEL_ALREADY_SET'); - $datasource = new \codename\core\io\datasource\model(); - $model = $this->getModel('datasourceentry'); - $datasource->setModel($model); - $datasource->setModel($model); // second call should fail - } - - /** - * [testSimpleDatasourceModelQuery description] - */ - public function testSimpleDatasourceModelQuery(): void { - $this->createTestData(); - $datasource = new \codename\core\io\datasource\model(); - $datasource->setQuery([]); - $model = $this->getModel('datasourceentry'); - $datasource->setModel($model); - $res = []; - foreach($datasource as $d) { - $res[] = $d; - } - $this->assertCount(4, $res); - } - - /** - * [testSimpleDatasourceModelQueryBuffered description] - */ - public function testSimpleDatasourceModelQueryBuffered(): void { - $this->createTestData(); - $datasource = new \codename\core\io\datasource\model([ - 'offset_buffering' => true, - 'offset_buffer_size' => 2, - - ]); - $datasource->setQuery([]); - $model = $this->getModel('datasourceentry'); - $datasource->setModel($model); - $this->assertCount(4, $datasource); - } - - /** - * [testSimpleDatasourceModelQueryBufferedLimited description] - */ - public function testSimpleDatasourceModelQueryBufferedLimited(): void { - $this->createTestData(); - $datasource = new \codename\core\io\datasource\model([ - 'offset_buffering' => true, - 'offset_buffer_size' => 2, - 'offset_limit' => 3, - - ]); - $datasource->setQuery([]); - $model = $this->getModel('datasourceentry'); - $datasource->setModel($model); - $this->assertCount(3, $datasource); - } - - /** - * [testDatasourceModelComplexOne description] - */ - public function testDatasourceModelComplexOne(): void { - $this->createTestData(); - $datasource = new \codename\core\io\datasource\model([ - 'model' => 'datasourceentry', - 'join' => [ - [ - 'model' => 'datasourceentryj', - 'fields' => [ - 'datasourceentryj_id' - ], - ], - ], - 'virtualFieldResult' => true, - 'fields' => [ - 'datasourceentry_text', - 'datasourceentry_integer', - ], - 'filter' => [ - [ 'field' => 'datasourceentry_integer', 'value' => null, 'operator' => '!=' ] - ], - 'filtercollection' => [ - [ - 'filters' => [ - [ 'field' => 'datasourceentry_integer', 'value' => 111, 'operator' => '=' ], - [ 'field' => 'datasourceentry_integer', 'value' => 222, 'operator' => '=' ], - ], - 'group_operator' => 'OR', - 'group_name' => 'datasourceentry_integer', - ] - ], - 'query' => [ - 'order' => [ - [ - "field" => "datasourceentry_integer", - "order" => "DESC" - ] - ] - ], - ]); - - $res = []; - foreach($datasource as $d) { - $res[] = $d; - } - $this->assertEquals([ - [ - 'datasourceentry_text' => 'bar', - 'datasourceentry_integer' => 222, - 'datasourceentryj_id' => null, - ], - [ - 'datasourceentry_text' => 'foo', - 'datasourceentry_integer' => 111, - 'datasourceentryj_id' => null, - ], - ], $res); - } - - /** - * [testDatasourceModelComplexOne description] - */ - public function testDatasourceModelComplexTwo(): void { - $this->createTestData(); - $datasource = new \codename\core\io\datasource\model([ - 'model' => 'datasourceentry', - 'virtualFieldResult' => true, - 'fields' => [ - 'datasourceentry_text', - 'datasourceentry_integer', - ], - 'query' => [ - 'filter' => [ - [ 'field' => 'datasourceentry_integer', 'value' => [ 'option' => 'filter1' ], 'operator' => '!=' ] - ], - 'filtercollection' => [ - [ - 'filters' => [ - [ 'field' => 'datasourceentry_integer', 'value' => [ 'option' => 'filtercollection1' ], 'operator' => '=' ], - [ 'field' => 'datasourceentry_integer', 'value' => [ 'option' => 'filtercollection2' ], 'operator' => '=' ], - ], - 'group_operator' => 'OR', - 'group_name' => 'datasourceentry_integer', - ] - ], - 'order' => [ - [ - "field" => "datasourceentry_integer", - "order" => "DESC" - ] - ] - ], - ]); - - $pipline = new \codename\core\io\pipeline(null, []); - $pipline->setOptions([ - 'filter1' => null, - 'filtercollection1' => 111, - 'filtercollection2' => 222, - ]); - - $datasource->setPipelineInstance($pipline); - - $res = []; - foreach($datasource as $d) { - $res[] = $d; - } - - $this->assertEquals(3, $datasource->currentProgressPosition()); - $this->assertEquals(2, $datasource->currentProgressLimit()); - $this->assertEquals([ - [ - 'datasourceentry_text' => 'bar', - 'datasourceentry_integer' => 222, - ], - [ - 'datasourceentry_text' => 'foo', - 'datasourceentry_integer' => 111, - ], - ], $res); - } - -} diff --git a/tests/datasource/testMulticsv.php b/tests/datasource/testMulticsv.php deleted file mode 100644 index 5bbc1de..0000000 --- a/tests/datasource/testMulticsv.php +++ /dev/null @@ -1,100 +0,0 @@ -assertEquals('0', $datasource->currentProgressPosition()); - - $this->assertEquals('68', $datasource->currentProgressLimit()); - - $datasource->setConfig([ - 'delimiter' => ';', - 'headed' => true, - ]); - - } - - /** - * tests key stability of the multicsv datasource - * @return void - */ - public function testDatasourceMulticsvKeys () { - $datasource = new \codename\core\io\datasource\multicsv([ - __DIR__ . "/" . 'testmulticsv1.csv', - __DIR__ . "/" . 'testmulticsv2.csv', - __DIR__ . "/" . 'testmulticsv3.csv' - ], [ - 'delimiter' => ',' - ]); - - $datasource->rewind(); - - // keep track of keys we've iterated over - $keysIterated = []; - $keyExpected = 0; - - $i = 0; - foreach($datasource as $key => $dataset) { - $this->assertFalse(in_array($key, $keysIterated), "Assert index/key '{$key}' hasn't been iterated over yet (keysIterated: ".implode(',', $keysIterated).")."); - $this->assertEquals($keyExpected, $key, "Assert a stable and linear key progression from 0...n in a +1 manner."); - $keyExpected++; - $i++; - $keysIterated[] = $key; - } - - // - // make sure we have iterated NINE times - // - $this->assertEquals(9, $i, "Asset we've iterated over the complete datasource"); - - } - - - /** - * "head1","head2" - * "l1_d1","l1_d2" - * "l2_d1","l2_d2" - * "l3_d1","l3_d2" - * - * @return void testing the next function - */ - public function testMultiDataSourceNext() - { - $datasource = new \codename\core\io\datasource\multicsv([ - __DIR__ . "/" . 'testmulticsv1.csv', - __DIR__ . "/" . 'testmulticsv2.csv', - __DIR__ . "/" . 'testmulticsv3.csv' - ], [ - 'delimiter' => ',' - ]); - - $datasource->rewind(); - - $i = 0; - foreach($datasource as $dataset) { - $i++; - - // DEBUG output - // echo(chr(10).chr(10)."testMultiDataSourceNext entry".chr(10)); - // print_r($dataset); - // echo(chr(10).chr(10)); - - $this->assertEquals($dataset['head1'], "l{$i}_d1"); - $this->assertEquals($dataset['head2'], "l{$i}_d2"); - } - - // - // make sure we have iterated NINE times - // - $this->assertEquals(9, $i); - } - -} diff --git a/tests/datasource/testParquet.php b/tests/datasource/testParquet.php deleted file mode 100644 index 4dbb865..0000000 --- a/tests/datasource/testParquet.php +++ /dev/null @@ -1,121 +0,0 @@ -expectException(\codename\core\exception::class); - $this->expectExceptionMessage('FILE_COULD_NOT_BE_OPENED'); - $datasource = new \codename\core\io\datasource\parquet(__DIR__ . "/" . 'parquet/does-not-exist.parquet'); - } - - /** - * [testReadNonParquetFile description] - */ - public function testReadNonParquetFile(): void { - $this->expectException(\Exception::class); - $datasource = new \codename\core\io\datasource\parquet(__DIR__ . "/" . 'testcsv1.csv'); - } - - /** - * [testParquetReadingStepByStep description] - */ - public function testParquetReadingStepByStep(): void { - $datasource = new \codename\core\io\datasource\parquet(__DIR__ . "/" . 'parquet/postcodes.plain.parquet'); - - // Assert we're at the start, not having read any data - $this->assertEquals(0, $datasource->key()); - $this->assertNull($datasource->current()); - $this->assertEquals(0, $datasource->currentProgressPosition()); - $datasource->next(); - - // NOTE: key() will return 0 on the first item - // but as in every iterator, you'll have to evaluate valid() first - $this->assertEquals(0, $datasource->key()); - $this->assertNotNull($datasource->current()); - $this->assertEquals(0, $datasource->currentProgressPosition()); - - $datasource->next(); - $this->assertEquals(1, $datasource->key()); - $this->assertNotNull($datasource->current()); - $this->assertEquals(1, $datasource->currentProgressPosition()); - - // loop til end - while($datasource->valid()) { - $datasource->next(); - } - $lastKey = $datasource->key(); - $datasource->next(); - - // TODO: evaluate this situation... - // print_r([$datasource->currentProgressLimit(), $datasource->currentProgressPosition()]); - // $this->assertEquals($lastKey, $datasource->currentProgressLimit()); - // $this->assertEquals($lastKey, $datasource->currentProgressPosition()); - } - - /** - * [testParquetReading description] - */ - public function testParquetReading(): void { - $datasource = new \codename\core\io\datasource\parquet(__DIR__ . "/" . 'parquet/postcodes.plain.parquet'); - $rows = []; - foreach($datasource as $row) { - $rows[] = $row; - } - - $this->assertEquals(237, $datasource->key()); - $this->assertCount(237, $rows); - $this->assertEquals(count($rows), $datasource->currentProgressLimit()); - - // randomly call next()... - $datasource->next(); - - // At this point we reached the end of the file - $this->assertFalse($datasource->valid()); - - // Try to go even further... - $datasource->next(); - $this->assertFalse($datasource->valid()); - - // iterate a second time and compare results - // tests rewinding, internally - $rows2 = []; - foreach($datasource as $row) { - $rows2[] = $row; - } - - $this->assertEquals($rows, $rows2); - } - - /** - * [testParquetReadingMultipage description] - */ - public function testParquetReadingMultipage(): void { - // TODO: evaluate whether we really have a multipage parquet file here - $datasource = new \codename\core\io\datasource\parquet(__DIR__ . "/" . 'parquet/running_numbers_spark.gz.parquet'); - $rows = []; - foreach($datasource as $row) { - $rows[] = $row; - } - - $this->assertEquals(10000, $datasource->key()); - $this->assertCount(10000, $rows); - - // randomly call next()... - $datasource->next(); - - // iterate a second time and compare results - // tests rewinding, internally - $rows2 = []; - foreach($datasource as $row) { - $rows2[] = $row; - } - - $this->assertEquals($rows, $rows2); - } - - -} diff --git a/tests/datasource/testRaw.php b/tests/datasource/testRaw.php deleted file mode 100644 index 7e7be2d..0000000 --- a/tests/datasource/testRaw.php +++ /dev/null @@ -1,232 +0,0 @@ -assertEquals('0', $datasource->key()); - - $this->assertEquals('0', $datasource->currentProgressPosition()); - - $this->assertEquals('52', $datasource->currentProgressLimit()); - - // rewind the datasources - $datasource->rewind(); - - } - - /** - * test an simple raw file - * @return [type] [description] - */ - public function testDataSourceFileNotExists() { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('FILE_COULD_NOT_BE_OPEN'); - $datasource = new \codename\core\io\datasource\raw(__DIR__ . "/" . 'testRaw1_filenotexists.txt'); - - } - - /** - * test an simple raw file - * @return [type] [description] - */ - public function testDataSourceInvalidConfig() { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('CORE_IO_DATASOURCE_INVALID_MAP_CONFIG'); - - $datasource = new \codename\core\io\datasource\raw( - __DIR__ . "/" . 'testRaw1.txt', - [ - 'format' => [ - 'trim' => true, - 'convert' => [ - 'from' => 'ASCII', - 'to' => 'UTF-8', - ], - 'map' => [ - 'field1' => [ - 'type' => 'wrong', - 'length' => 10, - ], - ], - ], - ] - ); - - } - - /** - * test an simple raw file - * @return [type] [description] - */ - public function testDataSourceIsValid() { - $datasource = new \codename\core\io\datasource\raw( - __DIR__ . "/" . 'testRaw1.txt', - [ - 'format' => [ - 'trim' => true, - 'convert' => [ - 'from' => 'ASCII', - 'to' => 'UTF-8', - ], - 'map' => [ - 'field1' => [ - 'type' => 'fixed', - 'length' => 10, - ], - 'field2' => [ - 'type' => 'fixed', - 'length' => 10, - ], - 'field3' => [ - 'type' => 'fixed', - 'length' => 10, - ], - ], - ], - ] - ); - $datasource->next(); - - $this->assertNotEmpty($datasource->getRawCurrent()); - - $data = $datasource->current(); - $this->assertEquals($data['field1'], 'col11'); - $this->assertEquals($data['field2'], 'col21'); - $this->assertEquals($data['field3'], 'col31'); - - } - - /** - * test an simple raw file - * @return [type] [description] - */ - public function testDataSourceIsValidWithMappings() { - $datasource = new \codename\core\io\datasource\raw( - __DIR__ . "/" . 'testRaw1.txt', - [ - 'format' => [ - 'trim' => true, - 'map' => [ - 'key' => [ - 'type' => 'fixed', - 'length' => 5, - ] - ], - ], - 'mappings' => [ - 'key' => [ - 'col11' => [ - 'trim' => true, - 'map' => [ - 'field1' => [ - 'type' => 'fixed', - 'length' => 10, - ], - 'field2' => [ - 'type' => 'fixed', - 'length' => 10, - ], - 'field3' => [ - 'type' => 'fixed', - 'length' => 10, - ], - ], - ], - 'col12' => [ - 'trim' => true, - 'convert' => [ - 'from' => 'ASCII', - 'to' => 'UTF-8', - ], - 'map' => [ - 'field1' => [ - 'type' => 'fixed', - 'length' => 10, - ], - 'field2' => [ - 'type' => 'fixed', - 'length' => 10, - ], - 'field3' => [ - 'type' => 'fixed', - 'length' => 10, - ], - ], - ], - ], - ], - ] - ); - $datasource->next(); - - $this->assertNotEmpty($datasource->getRawCurrent()); - - $data = $datasource->current(); - $this->assertEquals($data['field1'], 'col11'); - $this->assertEquals($data['field2'], 'col21'); - $this->assertEquals($data['field3'], 'col31'); - - $datasource->next(); - - $data = $datasource->current(); - $this->assertEquals($data['field1'], 'col12'); - $this->assertEquals($data['field2'], 'col22'); - $this->assertEquals($data['field3'], 'col32'); - - } - - /** - * "head1","head2" - * "l1_d1","l1_d2" - * "l2_d1","l2_d2" - * "l3_d1","l3_d2" - * - * @return void testing the next function - */ - public function testDataSourceNext() { - $datasource = new \codename\core\io\datasource\raw( - __DIR__ . "/" . 'testRaw1.txt', - [ - 'format' => [ - 'trim' => true, - 'map' => [ - 'field1' => [ - 'type' => 'fixed', - 'length' => 10, - ], - 'field2' => [ - 'type' => 'fixed', - 'length' => 10, - ], - 'field3' => [ - 'type' => 'fixed', - 'length' => 10, - ], - ], - ], - ] - ); - - $i = 0; - foreach($datasource as $dataset) { - $i++; - $this->assertEquals($dataset['field1'], "col1{$i}"); - $this->assertEquals($dataset['field2'], "col2{$i}"); - $this->assertEquals($dataset['field3'], "col3{$i}"); - } - - // - // make sure we have iterated two times - // - $this->assertEquals(2, $i); - } - -} diff --git a/tests/datasource/testRemap.php b/tests/datasource/testRemap.php deleted file mode 100644 index 1c15aa9..0000000 --- a/tests/datasource/testRemap.php +++ /dev/null @@ -1,272 +0,0 @@ -setData($this->getTestData()); - $remappedDatasource = new \codename\core\io\datasource\remap( - $datasource, [ - 'remap' => [ - 'oldkey1' => 'newkey1', - 'oldkey2' => 'newkey2', - 'oldkey3' => 'newkey3', - ] - ] - ); - - // rewind the datasources - $remappedDatasource->rewind(); - - $result = $remappedDatasource->current(); - $this->assertEquals([ - 'newkey1' => 'abc', - 'newkey2' => 'def', - 'newkey3' => 'ghi', - ], $result); - - $this->assertEquals('0', $remappedDatasource->currentProgressPosition()); - - $this->assertEquals('3', $remappedDatasource->currentProgressLimit()); - - $this->assertEquals('0', $remappedDatasource->key()); - - $this->assertTrue($remappedDatasource->valid()); - - } - - /** - * Test function to be moved to enshared, when available. - */ - public function testCsvStaticFormConfigProvider(): void { - $this->markTestIncomplete('Feature is to a different package.'); - $datasource = new \codename\core\io\datasource\arraydata(); - $datasource->setData($this->getTestData()); - $remappedDatasource = new \codename\core\io\datasource\remap( - $datasource, [ - 'remap' => [ - 'oldkey1' => 'newkey1', - 'oldkey2' => 'newkey2', - 'oldkey3' => 'newkey3', - ] - ] - ); - - $formFieldConfigArrayStatic = $remappedDatasource->getFormFieldConfigArrayStatic([]); - $this->assertEquals([ - [ - 'field_title' => 'Remap', - 'field_name' => 'remap', - 'field_type' => 'structure', - 'field_datatype' => 'structure', - 'field_value' => null - ], - [ - 'field_title' => 'Replace', - 'field_name' => 'replace', - 'field_type' => 'checkbox', - 'field_datatype' => 'boolean', - 'field_value' => false - ], - [ - 'field_title' => 'source_data_key', - 'field_name' => 'source_data_key', - 'field_type' => 'input', - 'field_datatype' => 'text', - 'field_value' => null - ] - ], $formFieldConfigArrayStatic); - } - - /** - * tests general function of the remap datasource - * @return [type] [description] - */ - public function testRemapDatasource () { - $datasource = new \codename\core\io\datasource\arraydata(); - $datasource->setData($this->getTestData()); - $remappedDatasource = new \codename\core\io\datasource\remap( - $datasource, [ - 'remap' => [ - 'oldkey1' => 'newkey1', - 'oldkey2' => 'newkey2', - 'oldkey3' => 'newkey3', - 'oldkey4' => [ 'newarraykey1', 'newarraykey2' ], - ] - ] - ); - - $comparisonDatasource = new \codename\core\io\datasource\arraydata(); - $comparisonDatasource->setData($this->getTestData()); - - // rewind the datasources - $remappedDatasource->rewind(); - $comparisonDatasource->rewind(); - - // max sure we only iterate over the count of the testdata array - $iterations = count($this->getTestData()); - $i = 0; - - while($i < $iterations) { - $remappedDataset = $remappedDatasource->current(); - $originalDataset = $comparisonDatasource->current(); - - $this->assertEquals($remappedDataset['newkey1'], $originalDataset['oldkey1']); - $this->assertEquals($remappedDataset['newkey2'], $originalDataset['oldkey2']); - $this->assertEquals($remappedDataset['newkey3'], $originalDataset['oldkey3']); - - $i++; - } - } - - /** - * tests outputting a dataset based on the input - * e.g. the remapped values are put ON TOP of the input (or replaced) - * @return void - */ - public function testRemapReplaceSourceInclusion () { - $datasource = new \codename\core\io\datasource\arraydata(); - $datasource->setData($this->getTestData()); - - $remappedDatasource = new \codename\core\io\datasource\remap( - $datasource, [ - 'remap' => [ - 'oldkey1' => 'newkey1', - 'oldkey2' => 'newkey2', - 'oldkey3' => 'newkey3', - ], - // the relevant config key - 'replace' => true - ] - ); - - $originalDatasource = new \codename\core\io\datasource\arraydata(); - $originalDatasource->setData($this->getTestData()); - - $tempDatasource = new \codename\core\io\datasource\arraydata(); - $tempDatasource->setData($this->getTestData()); - $normalRemappedDatasource = new \codename\core\io\datasource\remap( - $tempDatasource, [ - 'remap' => [ - 'oldkey1' => 'newkey1', - 'oldkey2' => 'newkey2', - 'oldkey3' => 'newkey3', - ] - ] - ); - - // rewind the datasources - $remappedDatasource->rewind(); - $originalDatasource->rewind(); - $normalRemappedDatasource->rewind(); - - // max sure we only iterate over the count of the testdata array - $iterations = count($this->getTestData()); - $i = 0; - - while($i < $iterations) { - $remappedDataset = $remappedDatasource->current(); - - // original - $originalDataset = $originalDatasource->current(); - - // remapped without including the input data - $normallyRemappedDataset = $normalRemappedDatasource->current(); - - foreach($originalDataset as $key => $value) { - $this->assertEquals($value, $remappedDataset[$key]); - } - foreach($normallyRemappedDataset as $key => $value) { - $this->assertEquals($value, $remappedDataset[$key]); - } - - // Don't forget to move the iterator - $remappedDatasource->next(); - $originalDatasource->next(); - $normalRemappedDatasource->next(); - - $i++; - } - } - - /** - * tests the inclusion of original data in a subkey - * @return [type] [description] - */ - public function testRemapSourceDataKey () { - $datasource = new \codename\core\io\datasource\arraydata(); - $datasource->setData($this->getTestData()); - - $sourceDataKey = 'original'; - - $remappedDatasource = new \codename\core\io\datasource\remap( - $datasource, [ - 'remap' => [ - 'oldkey1' => 'newkey1', - 'oldkey2' => 'newkey2', - 'oldkey3' => 'newkey3', - ], - 'source_data_key' => $sourceDataKey - ] - ); - - $comparisonDatasource = new \codename\core\io\datasource\arraydata(); - $comparisonDatasource->setData($this->getTestData()); - - // rewind the datasources - $remappedDatasource->rewind(); - $comparisonDatasource->rewind(); - - // max sure we only iterate over the count of the testdata array - $iterations = count($this->getTestData()); - $i = 0; - - while($i < $iterations) { - $remappedDataset = $remappedDatasource->current(); - $originalDataset = $comparisonDatasource->current(); - $this->assertEquals($remappedDataset[$sourceDataKey], $originalDataset); - - // Don't forget to move the iterator - $remappedDatasource->next(); - $comparisonDatasource->next(); - - $i++; - } - } - - /** - * returns an array of basic test data - * @return array - */ - protected function getTestData() : array { - return [ - [ - 'oldkey1' => 'abc', - 'oldkey2' => 'def', - 'oldkey3' => 'ghi', - 'oldkey4' => [ 'jkl', 'mno' ] - ], - [ - 'oldkey1' => 'jkl', - 'oldkey2' => 'mno', - 'oldkey3' => 'pqr', - 'oldkey4' => [ 'stu', 'vwx' ] - ], - [ - 'oldkey1' => 'stu', - 'oldkey2' => 'vwx', - 'oldkey3' => 'yz', - 'oldkey4' => [ 'abc', 'def' ] - ] - ]; - } -} diff --git a/tests/datasource/testSpreadsheet.php b/tests/datasource/testSpreadsheet.php deleted file mode 100644 index 88bb132..0000000 --- a/tests/datasource/testSpreadsheet.php +++ /dev/null @@ -1,194 +0,0 @@ -assertEquals('0', $datasource->key()); - - $this->assertEquals('0', $datasource->currentProgressPosition()); - - $this->assertEquals('0', $datasource->currentProgressLimit()); - - $this->assertNull($datasource->setConfig([])); - - } - - /** - * Test function to be moved to enshared, when available. - */ - public function testCsvStaticFormConfigProvider(): void { - $this->markTestIncomplete('Feature is to a different package.'); - $datasource = new \codename\core\io\datasource\spreadsheet(__DIR__ . "/" . 'testSpreadsheet2.xlsx'); - $formFieldConfigArrayStatic = $datasource->getFormFieldConfigArrayStatic([]); - $this->assertEquals([ - [ - 'field_title' => 'Multisheet', - 'field_name' => 'multisheet', - 'field_type' => 'checkbox', - 'field_datatype' => 'boolean', - 'field_value' => false - ], - [ - 'field_title' => 'Kopfzeile vorhanden?', - 'field_name' => 'headed', - 'field_type' => 'checkbox', - 'field_datatype' => 'boolean', - 'field_value' => true - ], - [ - 'field_title' => 'Kopfzeile in Zeile x', - 'field_name' => 'header_row', - 'field_type' => 'input', - 'field_datatype' => 'number_natural', - 'field_value' => 1 - ], - [ - 'field_title' => 'Spezifisches Sheet', - 'field_name' => 'custom_sheet_index', - 'field_type' => 'input', - 'field_datatype' => 'number_natural', - 'field_value' => null - ], - [ - 'field_title' => 'Tabellenspaltennamen einbeziehen', - 'field_name' => 'include_spreadsheet_columns', - 'field_type' => 'checkbox', - 'field_datatype' => 'boolean', - 'field_value' => false - ], - [ - 'field_title' => 'Zeilen von oben überspringen', - 'field_name' => 'skip_rows', - 'field_type' => 'input', - 'field_datatype' => 'number_natural', - 'field_value' => 0 - ] - ], $formFieldConfigArrayStatic); - } - - /** - * test an simple spreadsheet file - * @return [type] [description] - */ - public function testDataSourceIsValid() { - $datasource = new \codename\core\io\datasource\spreadsheet( - __DIR__ . "/" . 'testSpreadsheet1.xlsx', - [ - 'custom_sheet_index' => 0, - 'multisheet' => 0, - 'skip_rows' => 3, - 'header_row' => 2, - ] - ); - - $datasource->next(); - - $data = $datasource->current(); - $this->assertEquals($data['A'], 'Value2-1'); - $this->assertEquals($data['B'], 'Value2-2'); - $this->assertEquals($data['C'], 'Value2-3'); - - } - - /** - * test an simple spreadsheet file - * @return [type] [description] - */ - public function testDataSourceIsValidWithXls() { - $datasource = new \codename\core\io\datasource\spreadsheet( - __DIR__ . "/" . 'testSpreadsheet1.xls', - [ - 'custom_sheet_index' => 0, - 'multisheet' => 0, - 'skip_rows' => 3, - 'header_row' => 2, - ] - ); - - $datasource->next(); - - $data = $datasource->current(); - $this->assertEquals($data['A'], 'Value2-1'); - $this->assertEquals($data['B'], 'Value2-2'); - $this->assertEquals($data['C'], 'Value2-3'); - - } - - /** - * test an simple spreadsheet file - * @return [type] [description] - */ - public function testDataSourceNext() { - $datasource = new \codename\core\io\datasource\spreadsheet( - __DIR__ . "/" . 'testSpreadsheet1.xlsx', - [ - 'skip_rows' => 1, - 'header_row' => 2, - ] - ); - - $i = 0; - foreach($datasource as $dataset) { - $i++; - $this->assertEquals($dataset['Head1'], "Value{$i}-1"); - $this->assertEquals($dataset['Head2'], "Value{$i}-2"); - $this->assertEquals($dataset['Head3'], "Value{$i}-3"); - } - - // - // make sure we have iterated two times - // - $this->assertEquals(2, $i); - - } - - /** - * test an simple spreadsheet file - * @return [type] [description] - */ - public function testDataSourceMulti() { - $datasource = new \codename\core\io\datasource\spreadsheet( - __DIR__ . "/" . 'testSpreadsheet3.xlsx', - [ - 'multisheet' => true, - 'custom_sheet_index' => 1, - 'skip_rows' => 3, - 'header_row' => 2, - ] - ); - - $i = 0; - foreach($datasource as $dataset) { - $i++; - if($i === 1) { - $this->assertEquals($dataset['A'], '12'); - $this->assertEquals($dataset['B'], '345'); - $this->assertEquals($dataset['C'], '678'); - } elseif($i === 2) { - $this->assertEquals($dataset['A'], '901'); - $this->assertEquals($dataset['B'], '234'); - $this->assertEquals($dataset['C'], '567'); - } elseif($i === 3) { - $this->assertEquals($dataset['A'], 'jkl'); - $this->assertEquals($dataset['B'], 'mno'); - $this->assertEquals($dataset['C'], 'pqr'); - } elseif($i === 4) { - $this->assertEquals($dataset['A'], 'stu'); - $this->assertEquals($dataset['B'], 'vwx'); - $this->assertEquals($dataset['C'], 'yz'); - } - } - - } - -} diff --git a/tests/datasource/testXml.php b/tests/datasource/testXml.php deleted file mode 100644 index 7451723..0000000 --- a/tests/datasource/testXml.php +++ /dev/null @@ -1,95 +0,0 @@ - '/example/data', - 'xpath_mapping' => [ - 'field1' => 'field1', - 'field2' => 'field2', - 'field3' => 'field3', - ], - ] - ); - - $this->assertEquals('0', $datasource->currentProgressPosition()); - - $this->assertEquals('0', $datasource->currentProgressLimit()); - - // rewind the datasources - $datasource->rewind(); - - $this->assertEquals('0', $datasource->key()); - - } - - /** - * test an simple xml file - * @return [type] [description] - */ - public function testDataSourceIsValid() { - $datasource = new \codename\core\io\datasource\xml( - __DIR__ . "/" . 'testXml1.xml', - [ - 'xpath_query' => '/example/data', - 'xpath_mapping' => [ - 'field1' => 'field1', - 'field2' => 'field2', - 'field3' => 'field3', - ], - ] - ); - $datasource->next(); - - $data = $datasource->current(); - $this->assertEquals($data['field1'], 'example11'); - $this->assertEquals($data['field2'], 'example12'); - $this->assertEquals($data['field3'], 'example13'); - - } - - /** - * "head1","head2" - * "l1_d1","l1_d2" - * "l2_d1","l2_d2" - * "l3_d1","l3_d2" - * - * @return void testing the next function - */ - public function testDataSourceNext() { - $datasource = new \codename\core\io\datasource\xml( - __DIR__ . "/" . 'testXml1.xml', - [ - 'xpath_query' => '/example/data', - 'xpath_mapping' => [ - 'field1' => 'field1', - 'field2' => 'field2', - 'field3' => 'field3', - ], - ] - ); - - $i = 0; - foreach($datasource as $dataset) { - $i++; - $this->assertEquals($dataset['field1'], "example{$i}1"); - $this->assertEquals($dataset['field2'], "example{$i}2"); - $this->assertEquals($dataset['field3'], "example{$i}3"); - } - - // - // make sure we have iterated three times - // - $this->assertEquals(3, $i); - } - -} diff --git a/tests/datasource/testXml1.xml b/tests/datasource/testXml1.xml index ca49cb2..3450415 100644 --- a/tests/datasource/testXml1.xml +++ b/tests/datasource/testXml1.xml @@ -1,18 +1,18 @@ - - example11 - example12 - example13 - - - example21 - example22 - example23 - - - example31 - example32 - example33 - + + example11 + example12 + example13 + + + example21 + example22 + example23 + + + example31 + example32 + example33 + \ No newline at end of file diff --git a/tests/datasource/xmlTest.php b/tests/datasource/xmlTest.php new file mode 100644 index 0000000..38b1128 --- /dev/null +++ b/tests/datasource/xmlTest.php @@ -0,0 +1,102 @@ + '/example/data', + 'xpath_mapping' => [ + 'field1' => 'field1', + 'field2' => 'field2', + 'field3' => 'field3', + ], + ] + ); + + static::assertEquals('0', $datasource->currentProgressPosition()); + + static::assertEquals('0', $datasource->currentProgressLimit()); + + // rewind the datasources + $datasource->rewind(); + + static::assertEquals('0', $datasource->key()); + } + + /** + * test a simple xml file + * @return void [type] [description] + * @throws Exception + */ + public function testDataSourceIsValid(): void + { + $datasource = new xml( + __DIR__ . "/" . 'testXml1.xml', + [ + 'xpath_query' => '/example/data', + 'xpath_mapping' => [ + 'field1' => 'field1', + 'field2' => 'field2', + 'field3' => 'field3', + ], + ] + ); + $datasource->next(); + + $data = $datasource->current(); + static::assertEquals('example11', $data['field1']); + static::assertEquals('example12', $data['field2']); + static::assertEquals('example13', $data['field3']); + } + + /** + * "head1","head2" + * "l1_d1","l1_d2" + * "l2_d1","l2_d2" + * "l3_d1","l3_d2" + * + * @return void testing the next function + * @throws Exception + */ + public function testDataSourceNext(): void + { + $datasource = new xml( + __DIR__ . "/" . 'testXml1.xml', + [ + 'xpath_query' => '/example/data', + 'xpath_mapping' => [ + 'field1' => 'field1', + 'field2' => 'field2', + 'field3' => 'field3', + ], + ] + ); + + $i = 0; + foreach ($datasource as $dataset) { + $i++; + static::assertEquals("example{$i}1", $dataset['field1']); + static::assertEquals("example{$i}2", $dataset['field2']); + static::assertEquals("example{$i}3", $dataset['field3']); + } + + // + // make sure we have iterated three times + // + static::assertEquals(3, $i); + } +} diff --git a/tests/helper/model/helperjmodel.php b/tests/helper/model/helperjmodel.php index 6097584..6f31c63 100644 --- a/tests/helper/model/helperjmodel.php +++ b/tests/helper/model/helperjmodel.php @@ -1,55 +1,59 @@ [ - 'helperjmodel_id', - 'helperjmodel_created', - 'helperjmodel_modified', - 'helperjmodel_helpermodel_id', - 'helperjmodel_text', - 'helperjmodel_text_date', - 'helperjmodel_structure', - 'helperjmodel_integer', - 'helperjmodel_number', - 'helperjmodel_boolean', - 'helperjmodel_virtual', - ], - 'primary' => [ - 'helperjmodel_id' - ], - 'foreign' => [ - 'helperjmodel_helpermodel_id' => [ - 'schema' => 'helpertest', - 'model' => 'helpermodel', - 'key' => 'helpermodel_id' - ], - ], - 'datatype' => [ - 'helperjmodel_id' => 'number_natural', - 'helperjmodel_created' => 'text_timestamp', - 'helperjmodel_modified' => 'text_timestamp', - 'helperjmodel_helpermodel_id' => 'number_natural', - 'helperjmodel_text' => 'text', - 'helperjmodel_text_date' => 'text_date', - 'helperjmodel_structure' => 'structure', - 'helperjmodel_integer' => 'number_natural', - 'helperjmodel_number' => 'number', - 'helperjmodel_boolean' => 'boolean', - 'helperjmodel_virtual' => 'virtual', - ], - 'connection' => 'default' - ]); - } +class helperjmodel extends sqlModel +{ + /** + * {@inheritDoc} + */ + public function __construct(array $modeldata = []) + { + parent::__construct('helpertest', 'helperjmodel', [ + 'field' => [ + 'helperjmodel_id', + 'helperjmodel_created', + 'helperjmodel_modified', + 'helperjmodel_helpermodel_id', + 'helperjmodel_text', + 'helperjmodel_text_date', + 'helperjmodel_structure', + 'helperjmodel_integer', + 'helperjmodel_number', + 'helperjmodel_boolean', + 'helperjmodel_virtual', + ], + 'primary' => [ + 'helperjmodel_id', + ], + 'foreign' => [ + 'helperjmodel_helpermodel_id' => [ + 'schema' => 'helpertest', + 'model' => 'helpermodel', + 'key' => 'helpermodel_id', + ], + ], + 'datatype' => [ + 'helperjmodel_id' => 'number_natural', + 'helperjmodel_created' => 'text_timestamp', + 'helperjmodel_modified' => 'text_timestamp', + 'helperjmodel_helpermodel_id' => 'number_natural', + 'helperjmodel_text' => 'text', + 'helperjmodel_text_date' => 'text_date', + 'helperjmodel_structure' => 'structure', + 'helperjmodel_integer' => 'number_natural', + 'helperjmodel_number' => 'number', + 'helperjmodel_boolean' => 'boolean', + 'helperjmodel_virtual' => 'virtual', + ], + 'connection' => 'default', + ]); + } } diff --git a/tests/helper/model/helpermodel.php b/tests/helper/model/helpermodel.php index 2b94a82..705d5b2 100644 --- a/tests/helper/model/helpermodel.php +++ b/tests/helper/model/helpermodel.php @@ -1,33 +1,37 @@ [ - 'helpermodel_id', - 'helpermodel_created', - 'helpermodel_modified', - 'helpermodel_text', - ], - 'primary' => [ - 'helpermodel_id' - ], - 'datatype' => [ - 'helpermodel_id' => 'number_natural', - 'helpermodel_created' => 'text_timestamp', - 'helpermodel_modified' => 'text_timestamp', - 'helpermodel_text' => 'text', - ], - 'connection' => 'default' - ]); - } +class helpermodel extends sqlModel +{ + /** + * {@inheritDoc} + */ + public function __construct(array $modeldata = []) + { + parent::__construct('helpertest', 'helpermodel', [ + 'field' => [ + 'helpermodel_id', + 'helpermodel_created', + 'helpermodel_modified', + 'helpermodel_text', + ], + 'primary' => [ + 'helpermodel_id', + ], + 'datatype' => [ + 'helpermodel_id' => 'number_natural', + 'helpermodel_created' => 'text_timestamp', + 'helpermodel_modified' => 'text_timestamp', + 'helpermodel_text' => 'text', + ], + 'connection' => 'default', + ]); + } } diff --git a/tests/helper/pipelineTest.php b/tests/helper/pipelineTest.php new file mode 100644 index 0000000..1f8cd45 --- /dev/null +++ b/tests/helper/pipelineTest.php @@ -0,0 +1,354 @@ +getModel('helpermodel')->addModel($this->getModel('helperjmodel')); + + $example = pipeline::createModelToModelPipelineConfig($model, 'buffered_file_parquet'); + + static::assertEquals([ + 'info' => [ + 'name' => 'generated', + 'description' => null, + ], + 'source' => [ + 'type' => 'model', + 'query' => [], + ], + 'transform' => [ + 'helpermodel_created_to_dti' => [ + 'type' => 'convert_datetime', + 'config' => [ + 'source' => 'source', + 'field' => 'helpermodel_created', + 'source_format' => 'Y-m-d H:i:s', + 'target_format' => 'DateTimeImmutable', + ], + ], + 'helpermodel_modified_to_dti' => [ + 'type' => 'convert_datetime', + 'config' => [ + 'source' => 'source', + 'field' => 'helpermodel_modified', + 'source_format' => 'Y-m-d H:i:s', + 'target_format' => 'DateTimeImmutable', + ], + ], + 'helperjmodel_created_to_dti' => [ + 'type' => 'convert_datetime', + 'config' => [ + 'source' => 'source', + 'field' => 'helperjmodel_created', + 'source_format' => 'Y-m-d H:i:s', + 'target_format' => 'DateTimeImmutable', + ], + ], + 'helperjmodel_modified_to_dti' => [ + 'type' => 'convert_datetime', + 'config' => [ + 'source' => 'source', + 'field' => 'helperjmodel_modified', + 'source_format' => 'Y-m-d H:i:s', + 'target_format' => 'DateTimeImmutable', + ], + ], + 'helperjmodel_text_date_to_dti' => [ + 'type' => 'convert_datetime', + 'config' => [ + 'source' => 'source', + 'field' => 'helperjmodel_text_date', + 'source_format' => 'Y-m-d', + 'target_format' => 'DateTimeImmutable', + ], + ], + 'helperjmodel_structure_to_json' => [ + 'type' => 'convert_json', + 'config' => [ + 'source' => 'source', + 'field' => 'helperjmodel_structure', + 'mode' => 'encode', + ], + ], + ], + 'target' => [ + 'generated_target_buffered_file_parquet' => [ + 'type' => 'buffered_file_parquet', + 'buffer' => 1, + 'buffer_size' => 10000, + 'compression' => 'gzip', + 'mapping' => [ + 'helpermodel_id' => [ + 'type' => 'source', + 'field' => 'helpermodel_id', + 'php_type' => 'integer', + 'is_nullable' => false, + ], + 'helpermodel_created' => [ + 'type' => 'transform', + 'field' => 'helpermodel_created_to_dti', + 'php_type' => 'object', + 'php_class' => 'DateTimeImmutable', + 'datetime_format' => 2, + 'is_nullable' => true, + ], + 'helpermodel_modified' => [ + 'type' => 'transform', + 'field' => 'helpermodel_modified_to_dti', + 'php_type' => 'object', + 'php_class' => 'DateTimeImmutable', + 'datetime_format' => 2, + 'is_nullable' => true, + ], + 'helpermodel_text' => [ + 'type' => 'source', + 'field' => 'helpermodel_text', + 'php_type' => 'string', + 'is_nullable' => true, + ], + 'helperjmodel_id' => [ + 'type' => 'source', + 'field' => 'helperjmodel_id', + 'php_type' => 'integer', + 'is_nullable' => true, + ], + 'helperjmodel_created' => [ + 'type' => 'transform', + 'field' => 'helperjmodel_created_to_dti', + 'php_type' => 'object', + 'php_class' => 'DateTimeImmutable', + 'datetime_format' => 2, + 'is_nullable' => true, + ], + 'helperjmodel_modified' => [ + 'type' => 'transform', + 'field' => 'helperjmodel_modified_to_dti', + 'php_type' => 'object', + 'php_class' => 'DateTimeImmutable', + 'datetime_format' => 2, + 'is_nullable' => true, + ], + 'helperjmodel_helpermodel_id' => [ + 'type' => 'source', + 'field' => 'helperjmodel_helpermodel_id', + 'php_type' => 'integer', + 'is_nullable' => true, + ], + 'helperjmodel_text' => [ + 'type' => 'source', + 'field' => 'helperjmodel_text', + 'php_type' => 'string', + 'is_nullable' => true, + ], + 'helperjmodel_text_date' => [ + 'type' => 'transform', + 'field' => 'helperjmodel_text_date_to_dti', + 'php_type' => 'object', + 'php_class' => 'DateTimeImmutable', + 'datetime_format' => 4, + 'is_nullable' => true, + ], + 'helperjmodel_structure' => [ + 'type' => 'transform', + 'field' => 'helperjmodel_structure_to_json', + 'php_type' => 'string', + 'is_nullable' => true, + ], + 'helperjmodel_integer' => [ + 'type' => 'source', + 'field' => 'helperjmodel_integer', + 'php_type' => 'integer', + 'is_nullable' => true, + ], + 'helperjmodel_number' => [ + 'type' => 'source', + 'field' => 'helperjmodel_number', + 'php_type' => 'double', + 'is_nullable' => true, + ], + 'helperjmodel_boolean' => [ + 'type' => 'source', + 'field' => 'helperjmodel_boolean', + 'php_type' => 'boolean', + 'is_nullable' => true, + ], + ], + ], + ], + ], $example->get()); + } + + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function tearDown(): void + { + $this->getModel('helperjmodel') + ->addFilter('helperjmodel_id', 0, '>') + ->delete(); + + $this->getModel('helpermodel') + ->addFilter('helpermodel_id', 0, '>') + ->delete(); + } + + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function setUp(): void + { + parent::setUp(); + overrideableApp::__injectApp([ + 'vendor' => 'codename', + 'app' => 'core-io', + 'namespace' => '\\codename\\core\\io', + ]); + + $app = static::createApp(); + + // Additional overrides to get a more complete app lifecycle + // and allow static global app::getModel() to work correctly + $app::__setApp('helpermodeltest'); + $app::__setVendor('codename'); + $app::__setNamespace('\\codename\\core\\io\\tests\\helper'); + + $app::getAppstack(); + + // avoid re-init + if (static::$initialized) { + return; + } + + static::$initialized = true; + + static::setEnvironmentConfig([ + 'test' => [ + 'database' => [ + // NOTE: by default, we do these tests using + // pure in-memory sqlite. + 'default' => [ + 'driver' => 'sqlite', + 'database_file' => ':memory:', + ], + ], + 'cache' => [ + 'default' => [ + 'driver' => 'memory', + ], + ], + 'filesystem' => [ + 'local' => [ + 'driver' => 'local', + ], + ], + 'log' => [ + 'default' => [ + 'driver' => 'system', + 'data' => [ + 'name' => 'dummy', + ], + ], + ], + ], + ]); + + static::createModel('helpertest', 'helpermodel', [ + 'field' => [ + 'helpermodel_id', + 'helpermodel_created', + 'helpermodel_modified', + 'helpermodel_text', + ], + 'primary' => [ + 'helpermodel_id', + ], + 'datatype' => [ + 'helpermodel_id' => 'number_natural', + 'helpermodel_created' => 'text_timestamp', + 'helpermodel_modified' => 'text_timestamp', + 'helpermodel_text' => 'text', + ], + 'connection' => 'default', + ], function ($schema, $model, $config) { + return new helpermodel([]); + }); + + static::createModel('helpertest', 'helperjmodel', [ + 'field' => [ + 'helperjmodel_id', + 'helperjmodel_created', + 'helperjmodel_modified', + 'helperjmodel_helpermodel_id', + 'helperjmodel_text', + 'helperjmodel_text_date', + 'helperjmodel_structure', + 'helperjmodel_integer', + 'helperjmodel_number', + 'helperjmodel_boolean', + ], + 'primary' => [ + 'helperjmodel_id', + ], + 'foreign' => [ + 'helperjmodel_helpermodel_id' => [ + 'schema' => 'helpertest', + 'model' => 'helpermodel', + 'key' => 'helpermodel_id', + ], + ], + 'datatype' => [ + 'helperjmodel_id' => 'number_natural', + 'helperjmodel_created' => 'text_timestamp', + 'helperjmodel_modified' => 'text_timestamp', + 'helperjmodel_helpermodel_id' => 'number_natural', + 'helperjmodel_text' => 'text', + 'helperjmodel_text_date' => 'text_date', + 'helperjmodel_structure' => 'structure', + 'helperjmodel_integer' => 'number_natural', + 'helperjmodel_number' => 'number', + 'helperjmodel_boolean' => 'boolean', + ], + 'connection' => 'default', + ], function ($schema, $model, $config) { + return new helperjmodel([]); + }); + + static::architect('helpermodeltest', 'codename', 'test'); + } +} diff --git a/tests/helper/testDeepaccess.php b/tests/helper/testDeepaccess.php deleted file mode 100644 index 2a80cf6..0000000 --- a/tests/helper/testDeepaccess.php +++ /dev/null @@ -1,56 +0,0 @@ -assertTrue($refClass->isSubclassOf(\codename\core\helper\deepaccess::class)); - } - - /** - * [testDeepaccessNotInitializable description] - */ - public function testDeepaccessNotInitializable(): void { - // Deepaccess helper is a pure static helper - // and MUST NOT be initialized. - $this->expectException(\Error::class); - new deepaccess(); - } - - /** - * [testDeepaccessGet description] - * @return [type] [description] - */ - public function testDeepaccess () { - $example = []; - - // set example data - $example = deepaccess::set($example, [ 'example1', 'example2' ], 'example'); - - $this->assertEquals([ - 'example1' => [ - 'example2' => 'example' - ], - ], $example); - - // get example data - $result = deepaccess::get($example, [ 'example1', 'example2' ]); - - $this->assertEquals('example', $result); - - // get not exists key - $result = deepaccess::get($example, [ 'error1', 'error2' ]); - - $this->assertNull($result); - - } - -} diff --git a/tests/helper/testPipeline.php b/tests/helper/testPipeline.php deleted file mode 100644 index 15b85b7..0000000 --- a/tests/helper/testPipeline.php +++ /dev/null @@ -1,347 +0,0 @@ -getModel('helperjmodel') - ->addFilter('helperjmodel_id', 0, '>') - ->delete(); - - $this->getModel('helpermodel') - ->addFilter('helpermodel_id', 0, '>') - ->delete(); - } - - /** - * @inheritDoc - */ - protected function setUp(): void - { - parent::setUp(); - overrideableApp::__injectApp([ - 'vendor' => 'codename', - 'app' => 'core-io', - 'namespace' => '\\codename\\core\\io' - ]); - - $app = static::createApp(); - - // Additional overrides to get a more complete app lifecycle - // and allow static global app::getModel() to work correctly - $app->__setApp('helpermodeltest'); - $app->__setVendor('codename'); - $app->__setNamespace('\\codename\\core\\io\\tests\\helper'); - - $app->getAppstack(); - - // avoid re-init - if(static::$initialized) { - return; - } - - static::$initialized = true; - - static::setEnvironmentConfig([ - 'test' => [ - 'database' => [ - // NOTE: by default, we do these tests using - // pure in-memory sqlite. - 'default' => [ - 'driver' => 'sqlite', - 'database_file' => ':memory:', - ], - ], - 'cache' => [ - 'default' => [ - 'driver' => 'memory' - ] - ], - 'filesystem' =>[ - 'local' => [ - 'driver' => 'local', - ] - ], - 'log' => [ - 'default' => [ - 'driver' => 'system', - 'data' => [ - 'name' => 'dummy' - ] - ] - ], - ] - ]); - - static::createModel('helpertest', 'helpermodel', [ - 'field' => [ - 'helpermodel_id', - 'helpermodel_created', - 'helpermodel_modified', - 'helpermodel_text', - ], - 'primary' => [ - 'helpermodel_id' - ], - 'datatype' => [ - 'helpermodel_id' => 'number_natural', - 'helpermodel_created' => 'text_timestamp', - 'helpermodel_modified' => 'text_timestamp', - 'helpermodel_text' => 'text', - ], - 'connection' => 'default' - ], function($schema, $model, $config) { - return new \codename\core\io\tests\helper\model\helpermodel([]); - }); - - static::createModel('helpertest', 'helperjmodel', [ - 'field' => [ - 'helperjmodel_id', - 'helperjmodel_created', - 'helperjmodel_modified', - 'helperjmodel_helpermodel_id', - 'helperjmodel_text', - 'helperjmodel_text_date', - 'helperjmodel_structure', - 'helperjmodel_integer', - 'helperjmodel_number', - 'helperjmodel_boolean', - ], - 'primary' => [ - 'helperjmodel_id' - ], - 'foreign' => [ - 'helperjmodel_helpermodel_id' => [ - 'schema' => 'helpertest', - 'model' => 'helpermodel', - 'key' => 'helpermodel_id' - ], - ], - 'datatype' => [ - 'helperjmodel_id' => 'number_natural', - 'helperjmodel_created' => 'text_timestamp', - 'helperjmodel_modified' => 'text_timestamp', - 'helperjmodel_helpermodel_id' => 'number_natural', - 'helperjmodel_text' => 'text', - 'helperjmodel_text_date' => 'text_date', - 'helperjmodel_structure' => 'structure', - 'helperjmodel_integer' => 'number_natural', - 'helperjmodel_number' => 'number', - 'helperjmodel_boolean' => 'boolean', - ], - 'connection' => 'default' - ], function($schema, $model, $config) { - return new \codename\core\io\tests\helper\model\helperjmodel([]); - }); - - static::architect('helpermodeltest', 'codename', 'test'); - } - - /** - * [testHelperPipelineBufferedFileParquet description] - * @return [type] [description] - */ - public function testHelperPipelineBufferedFileParquet () { - - $model = $this->getModel('helpermodel')->addModel($this->getModel('helperjmodel')); - - $example = pipeline::createModelToModelPipelineConfig($model, 'buffered_file_parquet'); - - $this->assertEquals([ - 'info' => [ - 'name' => 'generated', - 'description' => null, - ], - 'source' => [ - 'type' => 'model', - 'query' => [], - ], - 'transform' => [ - 'helpermodel_created_to_dti' => [ - 'type' => 'convert_datetime', - 'config' => [ - 'source' => 'source', - 'field' => 'helpermodel_created', - 'source_format' => 'Y-m-d H:i:s', - 'target_format' => 'DateTimeImmutable', - ], - ], - 'helpermodel_modified_to_dti' => [ - 'type' => 'convert_datetime', - 'config' => [ - 'source' => 'source', - 'field' => 'helpermodel_modified', - 'source_format' => 'Y-m-d H:i:s', - 'target_format' => 'DateTimeImmutable', - ], - ], - 'helperjmodel_created_to_dti' => [ - 'type' => 'convert_datetime', - 'config' => [ - 'source' => 'source', - 'field' => 'helperjmodel_created', - 'source_format' => 'Y-m-d H:i:s', - 'target_format' => 'DateTimeImmutable', - ], - ], - 'helperjmodel_modified_to_dti' => [ - 'type' => 'convert_datetime', - 'config' => [ - 'source' => 'source', - 'field' => 'helperjmodel_modified', - 'source_format' => 'Y-m-d H:i:s', - 'target_format' => 'DateTimeImmutable', - ], - ], - 'helperjmodel_text_date_to_dti' => [ - 'type' => 'convert_datetime', - 'config' => [ - 'source' => 'source', - 'field' => 'helperjmodel_text_date', - 'source_format' => 'Y-m-d', - 'target_format' => 'DateTimeImmutable', - ], - ], - 'helperjmodel_structure_to_json' => [ - 'type' => 'convert_json', - 'config' => [ - 'source' => 'source', - 'field' => 'helperjmodel_structure', - 'mode' => 'encode', - ], - ], - ], - 'target' => [ - 'generated_target_buffered_file_parquet' => [ - 'type' => 'buffered_file_parquet', - 'buffer' => 1, - 'buffer_size' => 10000, - 'compression' => 'gzip', - 'mapping' => [ - 'helpermodel_id' => [ - 'type' => 'source', - 'field' => 'helpermodel_id', - 'php_type' => 'integer', - 'is_nullable' => false, - ], - 'helpermodel_created' => [ - 'type' => 'transform', - 'field' => 'helpermodel_created_to_dti', - 'php_type' => 'object', - 'php_class' => 'DateTimeImmutable', - 'datetime_format' => 2, - 'is_nullable' => true, - ], - 'helpermodel_modified' => [ - 'type' => 'transform', - 'field' => 'helpermodel_modified_to_dti', - 'php_type' => 'object', - 'php_class' => 'DateTimeImmutable', - 'datetime_format' => 2, - 'is_nullable' => true, - ], - 'helpermodel_text' => [ - 'type' => 'source', - 'field' => 'helpermodel_text', - 'php_type' => 'string', - 'is_nullable' => true, - ], - 'helperjmodel_id' => [ - 'type' => 'source', - 'field' => 'helperjmodel_id', - 'php_type' => 'integer', - 'is_nullable' => true, - ], - 'helperjmodel_created' => [ - 'type' => 'transform', - 'field' => 'helperjmodel_created_to_dti', - 'php_type' => 'object', - 'php_class' => 'DateTimeImmutable', - 'datetime_format' => 2, - 'is_nullable' => true, - ], - 'helperjmodel_modified' => [ - 'type' => 'transform', - 'field' => 'helperjmodel_modified_to_dti', - 'php_type' => 'object', - 'php_class' => 'DateTimeImmutable', - 'datetime_format' => 2, - 'is_nullable' => true, - ], - 'helperjmodel_helpermodel_id' => [ - 'type' => 'source', - 'field' => 'helperjmodel_helpermodel_id', - 'php_type' => 'integer', - 'is_nullable' => true, - ], - 'helperjmodel_text' => [ - 'type' => 'source', - 'field' => 'helperjmodel_text', - 'php_type' => 'string', - 'is_nullable' => true, - ], - 'helperjmodel_text_date' => [ - 'type' => 'transform', - 'field' => 'helperjmodel_text_date_to_dti', - 'php_type' => 'object', - 'php_class' => 'DateTimeImmutable', - 'datetime_format' => 4, - 'is_nullable' => true, - ], - 'helperjmodel_structure' => [ - 'type' => 'transform', - 'field' => 'helperjmodel_structure_to_json', - 'php_type' => 'string', - 'is_nullable' => true, - ], - 'helperjmodel_integer' => [ - 'type' => 'source', - 'field' => 'helperjmodel_integer', - 'php_type' => 'integer', - 'is_nullable' => true, - ], - 'helperjmodel_number' => [ - 'type' => 'source', - 'field' => 'helperjmodel_number', - 'php_type' => 'double', - 'is_nullable' => true, - ], - 'helperjmodel_boolean' => [ - 'type' => 'source', - 'field' => 'helperjmodel_boolean', - 'php_type' => 'boolean', - 'is_nullable' => true, - ], - ], - ], - ], - ], $example->get()); - - } - -} diff --git a/tests/pipeline/abstractPipelineTest.php b/tests/pipeline/abstractPipelineTest.php index dff1bca..35fa275 100644 --- a/tests/pipeline/abstractPipelineTest.php +++ b/tests/pipeline/abstractPipelineTest.php @@ -1,133 +1,145 @@ getModel('pipelinemodel') - ->addFilter('pipelinemodel_id', 0, '>') - ->delete(); - - overrideableApp::__setInstance('response', null); - } - - /** - * @inheritDoc - */ - protected function setUp(): void - { - $app = static::createApp(); - - overrideableApp::__injectApp([ - 'vendor' => 'codename', - 'app' => 'core-io', - 'namespace' => '\\codename\\core\\io' - ]); - - // Additional overrides to get a more complete app lifecycle - // and allow static global app::getModel() to work correctly - $app->__setApp('pipelinetest'); - $app->__setVendor('codename'); - $app->__setNamespace('\\codename\\core\\io\\tests\\pipeline'); - - $app->getAppstack(); - - // fake response instance - $app->__setInstance('response', new \codename\core\response\cli([])); - - // avoid re-init - if(static::$initialized) { - return; + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function tearDown(): void + { + $this->getModel('pipelinemodel') + ->addFilter('pipelinemodel_id', 0, '>') + ->delete(); + + overrideableApp::__setInstance('response', null); } - static::$initialized = true; - - static::setEnvironmentConfig([ - 'test' => [ - 'database' => [ - // NOTE: by default, we do these tests using - // pure in-memory sqlite. - 'default' => [ - 'driver' => 'sqlite', - // 'database_file' => 'pipelinemodel.sqlite', - 'database_file' => ':memory:', + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function setUp(): void + { + $app = static::createApp(); + + overrideableApp::__injectApp([ + 'vendor' => 'codename', + 'app' => 'core-io', + 'namespace' => '\\codename\\core\\io', + ]); + + // Additional overrides to get a more complete app lifecycle + // and allow static global app::getModel() to work correctly + $app::__setApp('pipelinetest'); + $app::__setVendor('codename'); + $app::__setNamespace('\\codename\\core\\io\\tests\\pipeline'); + + $app::getAppstack(); + + // fake response instance + $app::__setInstance('response', new cli()); + + // avoid re-init + if (static::$initialized) { + return; + } + + static::$initialized = true; + + static::setEnvironmentConfig([ + 'test' => [ + 'database' => [ + // NOTE: by default, we do these tests using + // pure in-memory sqlite. + 'default' => [ + 'driver' => 'sqlite', + // 'database_file' => 'pipelinemodel.sqlite', + 'database_file' => ':memory:', + ], + ], + 'cache' => [ + 'default' => [ + 'driver' => 'memory', + ], + ], + 'filesystem' => [ + 'local' => [ + 'driver' => 'local', + ], + ], + 'log' => [ + 'default' => [ + 'driver' => 'system', + 'data' => [ + 'name' => 'dummy', + ], + ], + ], ], - ], - 'cache' => [ - 'default' => [ - 'driver' => 'memory' - ] - ], - 'filesystem' =>[ - 'local' => [ - 'driver' => 'local', - ] - ], - 'log' => [ - 'default' => [ - 'driver' => 'system', - 'data' => [ - 'name' => 'dummy' - ] - ] - ], - ] - ]); - - static::createModel( - 'pipelinetest', 'pipelinemodel', - \codename\core\io\tests\pipeline\model\pipelinemodel::$staticConfig, - function($schema, $model, $config) { - return new \codename\core\io\tests\pipeline\model\pipelinemodel([]); - } - ); - - static::architect('pipelinetest', 'codename', 'test'); - } - - /** - * [createTestData description] - */ - protected function createTestData(): void { - $model = $this->getModel('pipelinemodel'); - - $datasets = [ - [ - 'pipelinemodel_text' => 'first', - ], - [ - 'pipelinemodel_text' => 'second', - ], - [ - 'pipelinemodel_text' => 'third', - ], - ]; - - foreach($datasets as $dataset) { - $model->save($dataset); + ]); + + static::createModel( + 'pipelinetest', + 'pipelinemodel', + pipelinemodel::$staticConfig, + function ($schema, $model, $config) { + return new pipelinemodel([]); + } + ); + + static::architect('pipelinetest', 'codename', 'test'); } - } + /** + * [createTestData description] + * @throws ReflectionException + * @throws exception + */ + protected function createTestData(): void + { + $model = $this->getModel('pipelinemodel'); + + $datasets = [ + [ + 'pipelinemodel_text' => 'first', + ], + [ + 'pipelinemodel_text' => 'second', + ], + [ + 'pipelinemodel_text' => 'third', + ], + ]; + + foreach ($datasets as $dataset) { + $model->save($dataset); + } + } } diff --git a/tests/pipeline/genericPipelineTest.php b/tests/pipeline/genericPipelineTest.php index b9d8de4..97cbcda 100644 --- a/tests/pipeline/genericPipelineTest.php +++ b/tests/pipeline/genericPipelineTest.php @@ -1,251 +1,274 @@ executePipelineWithConfig([ - 'source' => [ - 'type' => 'arraydata' - ], - 'constants' => [ - 'my_constant' => 'Foo', - 'constant_array' => [ - 'key' => 'Bar', - ] - ], - 'transform' => [ - 'padded_simple_text' => [ - 'type' => 'pad_left', - 'config' => [ - 'source' => 'source', - 'field' => 'simple_text', - 'length' => 10, - 'string' => '#', - ] - ], - 'created_array' => [ - 'type' => 'get_valuearray', - 'config' => [ - 'elements' => [ - 'c1' => 'X', - 'c2' => 'Y', - 'c3' => 'Z', - ] - ] - ] - ], - 'target' => [ - 'test' => [ - 'type' => 'dummy', - 'source_filter' => [ - [ - 'field' => 'simple_text', - 'operator' => '!=', - 'value' => 'DEF', - ] - ], - 'target_filter' => [ - [ - 'field' => 'source_array_by_key', - 'operator' => '!=', - 'value' => 'filterme', - ] - ], - 'mapping' => [ - 'simple_text' => [ 'type' => 'source', 'field' => 'simple_text' ], - 'padded_simple_text' => [ 'type' => 'transform', 'field' => 'padded_simple_text' ], - 'padded_simple_text_deep' => [ 'type' => 'transform_deep', 'field' => [ 'padded_simple_text' ] ], - 'source_array_all' => [ 'type' => 'source_deep', 'field' => [ 'array' ] ], - 'source_array_by_index' => [ 'type' => 'source_deep', 'field' => [ 'array', 1 ] ], - 'source_array_by_key' => [ 'type' => 'source_deep', 'field' => [ 'assoc_array', 'k2' ] ], - 'transform_array_by_key' => [ 'type' => 'transform_deep', 'field' => [ 'created_array', 'c2' ] ], - 'raw' => [ 'type' => 'source_deep', 'field' => [] ], - 'constant_value' => [ 'type' => 'constant', 'field' => 'my_constant' ], - 'constant_value_arrayid' => [ 'type' => 'constant', 'field' => ['my_constant'] ], - 'constant_path' => [ 'type' => 'constant', 'field' => ['constant_array', 'key'] ], - - ] - ] - ] - ],[ - [ - // Filtered out by source value - 'simple_text' => 'DEF', - 'array' => [ 'filtered_out' ], - 'assoc_array' => [ ], - ], - [ - // Filtered out by target value - 'simple_text' => 'GHI', - 'array' => [ 'filtered_out' ], - 'assoc_array' => [ 'k2' => 'filterme' ], - ], - $original = [ - 'simple_text' => 'ABC', - 'array' => [ 'A', 'B', 'C' ], - 'assoc_array' => [ 'k1' => 'v1', 'k2' => 'v2', 'k3' => 'v3' ], - ] - ]); - - $target = $pipeline->getTarget('test'); - - $this->assertInstanceOf(\codename\core\io\target\virtualTargetInterface::class, $target); - - if($target instanceof \codename\core\io\target\virtualTargetInterface) { - $data = $target->getVirtualStoreData(); - $this->assertCount(1, $data); - $this->assertEquals( - [ - 'simple_text' => 'ABC', - 'padded_simple_text' => '#######ABC', - 'padded_simple_text_deep' => '#######ABC', - 'source_array_all' => [ 'A', 'B', 'C' ], - 'source_array_by_index' => 'B', - 'source_array_by_key' => 'v2', - 'transform_array_by_key' => 'Y', - 'raw' => $original, - 'constant_value' => 'Foo', - 'constant_value_arrayid' => 'Foo', - 'constant_path' => 'Bar', - ], - $data[0] - ); +class genericPipelineTest extends abstractPipelineTest +{ + /** + * @return void + * @throws ReflectionException + * @throws exception + */ + public function testPipeline(): void + { + $pipeline = $this->executePipelineWithConfig([ + 'source' => [ + 'type' => 'arraydata', + ], + 'constants' => [ + 'my_constant' => 'Foo', + 'constant_array' => [ + 'key' => 'Bar', + ], + ], + 'transform' => [ + 'padded_simple_text' => [ + 'type' => 'pad_left', + 'config' => [ + 'source' => 'source', + 'field' => 'simple_text', + 'length' => 10, + 'string' => '#', + ], + ], + 'created_array' => [ + 'type' => 'get_valuearray', + 'config' => [ + 'elements' => [ + 'c1' => 'X', + 'c2' => 'Y', + 'c3' => 'Z', + ], + ], + ], + ], + 'target' => [ + 'test' => [ + 'type' => 'dummy', + 'source_filter' => [ + [ + 'field' => 'simple_text', + 'operator' => '!=', + 'value' => 'DEF', + ], + ], + 'target_filter' => [ + [ + 'field' => 'source_array_by_key', + 'operator' => '!=', + 'value' => 'filterme', + ], + ], + 'mapping' => [ + 'simple_text' => ['type' => 'source', 'field' => 'simple_text'], + 'padded_simple_text' => ['type' => 'transform', 'field' => 'padded_simple_text'], + 'padded_simple_text_deep' => ['type' => 'transform_deep', 'field' => ['padded_simple_text']], + 'source_array_all' => ['type' => 'source_deep', 'field' => ['array']], + 'source_array_by_index' => ['type' => 'source_deep', 'field' => ['array', 1]], + 'source_array_by_key' => ['type' => 'source_deep', 'field' => ['assoc_array', 'k2']], + 'transform_array_by_key' => ['type' => 'transform_deep', 'field' => ['created_array', 'c2']], + 'raw' => ['type' => 'source_deep', 'field' => []], + 'constant_value' => ['type' => 'constant', 'field' => 'my_constant'], + 'constant_value_arrayid' => ['type' => 'constant', 'field' => ['my_constant']], + 'constant_path' => ['type' => 'constant', 'field' => ['constant_array', 'key']], + + ], + ], + ], + ], [ + [ + // Filtered out by source value + 'simple_text' => 'DEF', + 'array' => ['filtered_out'], + 'assoc_array' => [], + ], + [ + // Filtered out by target value + 'simple_text' => 'GHI', + 'array' => ['filtered_out'], + 'assoc_array' => ['k2' => 'filterme'], + ], + $original = [ + 'simple_text' => 'ABC', + 'array' => ['A', 'B', 'C'], + 'assoc_array' => ['k1' => 'v1', 'k2' => 'v2', 'k3' => 'v3'], + ], + ]); + + $target = $pipeline->getTarget('test'); + + static::assertInstanceOf(virtualTargetInterface::class, $target); + + if ($target instanceof virtualTargetInterface) { + $data = $target->getVirtualStoreData(); + static::assertCount(1, $data); + static::assertEquals( + [ + 'simple_text' => 'ABC', + 'padded_simple_text' => '#######ABC', + 'padded_simple_text_deep' => '#######ABC', + 'source_array_all' => ['A', 'B', 'C'], + 'source_array_by_index' => 'B', + 'source_array_by_key' => 'v2', + 'transform_array_by_key' => 'Y', + 'raw' => $original, + 'constant_value' => 'Foo', + 'constant_value_arrayid' => 'Foo', + 'constant_path' => 'Bar', + ], + $data[0] + ); + } } - } - - - /** - * [testPipelineGetTransformInstanceOfNonexistingFails description] - */ - public function testPipelineGetTransformInstanceOfNonexistingFails(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_NOTFOUND'); - - $pipeline = $this->executePipelineWithConfig([ - 'source' => [ - 'type' => 'arraydata' - ], - 'transform' => [ - ], - 'target' => [ - 'test' => [ - 'type' => 'dummy', - 'mapping' => [ - // 'somefield' => [ 'type' => 'transform', 'field' => 'nonexistant' ] - ] - ] - ] - ]); - - $pipeline->getTransformInstance('nonexisting'); - } - - /** - * [testPipelineFailsWithNonexistantTransform description] - */ - public function testPipelineFailsWithNonexistantTransform(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_CORE_IO_PIPELINE_MISSING_TRANSFORM'); - - $this->executePipelineWithConfig([ - 'source' => [ - 'type' => 'arraydata' - ], - 'transform' => [ - ], - 'target' => [ - 'test' => [ - 'type' => 'dummy', - 'mapping' => [ - 'somefield' => [ 'type' => 'transform', 'field' => 'nonexistant' ] - ] - ] - ] - ]); - } - - /** - * [testPipelineFailsWithNonexistantTransformDeep description] - */ - public function testPipelineFailsWithNonexistantTransformDeep(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_CORE_IO_PIPELINE_MISSING_TRANSFORM'); - - $this->executePipelineWithConfig([ - 'source' => [ - 'type' => 'arraydata' - ], - 'transform' => [ - ], - 'target' => [ - 'test' => [ - 'type' => 'dummy', - 'mapping' => [ - 'somefield' => [ 'type' => 'transform_deep', 'field' => ['nonexistant'] ] - ] - ] - ] - ]); - } - - /** - * [testPipelineFailsWithInvalidTransformType description] - */ - public function testPipelineFailsWithInvalidTransformType(): void { - $this->expectException(\codename\core\exception::class); - - // NOTE: at the moment, this fires a missing class exception - // but I think it really should be EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_MISSING_CLASS - $this->expectExceptionMessage('EXCEPTION_GETINHERITEDCLASS_CLASSFILENOTFOUND'); - - $this->executePipelineWithConfig([ - 'source' => [ - 'type' => 'arraydata' - ], - 'transform' => [ - 'example_invalid_type' => [ - 'type' => 'someinvalidtransformtype', - 'config' => [] - ] - ], - 'target' => [ - 'test' => [ - 'type' => 'dummy', - 'mapping' => [ - 'somefield' => [ 'type' => 'transform', 'field' => 'example_invalid_type' ] - ] - ] - ] - ]); - } - - /** - * [executePipelineWithConfig description] - * @param array $config [description] - * @param array|null $data [data samples for source] - * @return pipeline [description] - */ - protected function executePipelineWithConfig(array $config, ?array $data = null): pipeline { - $pipeline = new \codename\core\io\pipeline(null, $config); - $datasource = new \codename\core\io\datasource\arraydata([]); - if($data === null) { - // example dataset - $data = [ - [ 'value' => 'test' ], - ]; + + /** + * [executePipelineWithConfig description] + * @param array $config [description] + * @param array|null $data [data samples for source] + * @return pipeline [description] + * @throws ReflectionException + * @throws exception + */ + protected function executePipelineWithConfig(array $config, ?array $data = null): pipeline + { + $pipeline = new pipeline(null, $config); + $datasource = new arraydata(); + if ($data === null) { + // example dataset + $data = [ + ['value' => 'test'], + ]; + } + $datasource->setData($data); + + $pipeline->setDatasource($datasource); + $pipeline->run(); + return $pipeline; } - $datasource->setData($data); - $pipeline->setDatasource($datasource); - $pipeline->run(); - return $pipeline; - } + /** + * [testPipelineGetTransformInstanceOfNonexistingFails description] + * @throws ReflectionException + * @throws exception + */ + public function testPipelineGetTransformInstanceOfNonexistingFails(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_NOTFOUND'); + $pipeline = $this->executePipelineWithConfig([ + 'source' => [ + 'type' => 'arraydata', + ], + 'transform' => [ + ], + 'target' => [ + 'test' => [ + 'type' => 'dummy', + 'mapping' => [ + // 'somefield' => [ 'type' => 'transform', 'field' => 'nonexistent' ] + ], + ], + ], + ]); + + $pipeline->getTransformInstance('nonexisting'); + } + /** + * [testPipelineFailsWithNonexistentTransform description] + * @throws ReflectionException + * @throws exception + */ + public function testPipelineFailsWithNonexistentTransform(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('EXCEPTION_CORE_IO_PIPELINE_MISSING_TRANSFORM'); + + $this->executePipelineWithConfig([ + 'source' => [ + 'type' => 'arraydata', + ], + 'transform' => [ + ], + 'target' => [ + 'test' => [ + 'type' => 'dummy', + 'mapping' => [ + 'somefield' => ['type' => 'transform', 'field' => 'nonexistent'], + ], + ], + ], + ]); + } + + /** + * [testPipelineFailsWithNonexistentTransformDeep description] + * @throws ReflectionException + * @throws exception + */ + public function testPipelineFailsWithNonexistentTransformDeep(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('EXCEPTION_CORE_IO_PIPELINE_MISSING_TRANSFORM'); + + $this->executePipelineWithConfig([ + 'source' => [ + 'type' => 'arraydata', + ], + 'transform' => [ + ], + 'target' => [ + 'test' => [ + 'type' => 'dummy', + 'mapping' => [ + 'somefield' => ['type' => 'transform_deep', 'field' => ['nonexistent']], + ], + ], + ], + ]); + } + + /** + * [testPipelineFailsWithInvalidTransformType description] + * @throws ReflectionException + * @throws exception + */ + public function testPipelineFailsWithInvalidTransformType(): void + { + $this->expectException(exception::class); + + // NOTE: at the moment, this fires a missing class exception, + // but I think it really should be EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_MISSING_CLASS + $this->expectExceptionMessage('EXCEPTION_GETINHERITEDCLASS_CLASSFILENOTFOUND'); + + $this->executePipelineWithConfig([ + 'source' => [ + 'type' => 'arraydata', + ], + 'transform' => [ + 'example_invalid_type' => [ + 'type' => 'someinvalidtransformtype', + 'config' => [], + ], + ], + 'target' => [ + 'test' => [ + 'type' => 'dummy', + 'mapping' => [ + 'somefield' => ['type' => 'transform', 'field' => 'example_invalid_type'], + ], + ], + ], + ]); + } } diff --git a/tests/pipeline/model/pipelinemodel.php b/tests/pipeline/model/pipelinemodel.php index 309ca99..f8c50ff 100644 --- a/tests/pipeline/model/pipelinemodel.php +++ b/tests/pipeline/model/pipelinemodel.php @@ -1,40 +1,44 @@ [ + 'pipelinemodel_id', + 'pipelinemodel_created', + 'pipelinemodel_modified', + 'pipelinemodel_text', + ], + 'primary' => [ + 'pipelinemodel_id', + ], + 'datatype' => [ + 'pipelinemodel_id' => 'number_natural', + 'pipelinemodel_created' => 'text_timestamp', + 'pipelinemodel_modified' => 'text_timestamp', + 'pipelinemodel_text' => 'text', + ], + 'connection' => 'default', + ]; - /** - * static configuration - * for usage in unit tests - * @var array - */ - public static $staticConfig = [ - 'field' => [ - 'pipelinemodel_id', - 'pipelinemodel_created', - 'pipelinemodel_modified', - 'pipelinemodel_text', - ], - 'primary' => [ - 'pipelinemodel_id' - ], - 'datatype' => [ - 'pipelinemodel_id' => 'number_natural', - 'pipelinemodel_created' => 'text_timestamp', - 'pipelinemodel_modified' => 'text_timestamp', - 'pipelinemodel_text' => 'text', - ], - 'connection' => 'default' - ]; + /** + * {@inheritDoc} + */ + public function __construct(array $modeldata = []) + { + parent::__construct('pipelinetest', 'pipelinemodel', static::$staticConfig); + } } diff --git a/tests/pipeline/pipelineModelTargetTest.php b/tests/pipeline/pipelineModelTargetTest.php index c3f5538..c5ff428 100644 --- a/tests/pipeline/pipelineModelTargetTest.php +++ b/tests/pipeline/pipelineModelTargetTest.php @@ -1,126 +1,140 @@ getModel('pipelinemodel'); - $this->assertEquals(0, $model->getCount()); - - $pipeline = new \codename\core\io\pipeline(null, [ - 'source' => [ - 'type' => 'arraydata' - ], - 'transform' => [ - - ], - 'target' => [ - 'test_model' => [ - 'type' => 'model', - 'model' => 'pipelinemodel', - 'mapping' => [ - 'pipelinemodel_text' => [ 'type' => 'source', 'field' => 'value' ] - ] - ] - ] - ]); - - $datasource = new \codename\core\io\datasource\arraydata([]); - $datasource->setData([ - [ 'value' => 'one' ], - [ 'value' => 'two' ], - [ 'value' => 'three' ], - ]); - - $pipeline->setDatasource($datasource); - $pipeline->setDryRun(false); - $pipeline->setErrorstackEnabled(true); - $pipeline->run(); - - $this->assertEquals(3, $model->getCount()); - - $errorstack = $pipeline->getErrorstack(); - $this->assertEmpty($errorstack->getErrors()); - $this->assertInstanceOf(\codename\core\errorstack::class, $errorstack); - } - - /** - * [testPipelineAlreadyOpenTransactionWillFail description] - */ - public function testPipelineAlreadyOpenTransactionWillFail(): void { - $model = $this->getModel('pipelinemodel'); - $transaction = new \codename\core\transaction('test', [ $model ]); - $transaction->start(); - - $failed = false; - try { - $this->testPipelineWriteToTargetModel(); - } catch (\codename\core\exception $e) { - $failed = true; - - // still complete/end the transaction - // otherwise other tests might fail - $transaction->end(); - - $this->assertEquals('EXCEPTION_PIPELINE_BEGINTRANSACTIONS_ALREADY_ACTIVE_TRANSACTION', $e->getMessage()); +class pipelineModelTargetTest extends abstractPipelineTest +{ + /** + * [testPipelineAlreadyOpenTransactionWillFail description] + * @throws ReflectionException + * @throws \codename\core\exception + */ + public function testPipelineAlreadyOpenTransactionWillFail(): void + { + $model = $this->getModel('pipelinemodel'); + $transaction = new transaction('test', [$model]); + $transaction->start(); + + $failed = false; + try { + $this->testPipelineWriteToTargetModel(); + } catch (Exception $e) { + $failed = true; + + // still complete/end the transaction + // otherwise other tests might fail + $transaction->end(); + + static::assertEquals('EXCEPTION_PIPELINE_BEGINTRANSACTIONS_ALREADY_ACTIVE_TRANSACTION', $e->getMessage()); + } + + + // We expect this to not complete + if (!$failed) { + static::fail('Expected exception not thrown - must fail!'); + } } - - // We expect this to not complete - if(!$failed) { - $this->fail('Expected exception not thrown - must fail!'); + /** + * [testPipelineWriteToTargetModel description] + * @throws ReflectionException + * @throws \codename\core\exception + */ + public function testPipelineWriteToTargetModel(): void + { + $model = $this->getModel('pipelinemodel'); + static::assertEquals(0, $model->getCount()); + + $pipeline = new pipeline(null, [ + 'source' => [ + 'type' => 'arraydata', + ], + 'transform' => [ + + ], + 'target' => [ + 'test_model' => [ + 'type' => 'model', + 'model' => 'pipelinemodel', + 'mapping' => [ + 'pipelinemodel_text' => ['type' => 'source', 'field' => 'value'], + ], + ], + ], + ]); + + $datasource = new arraydata(); + $datasource->setData([ + ['value' => 'one'], + ['value' => 'two'], + ['value' => 'three'], + ]); + + $pipeline->setDatasource($datasource); + $pipeline->setDryRun(false); + $pipeline->setErrorstackEnabled(); + $pipeline->run(); + + static::assertEquals(3, $model->getCount()); + + $errorstack = $pipeline->getErrorstack(); + static::assertEmpty($errorstack->getErrors()); + static::assertInstanceOf(errorstack::class, $errorstack); } - } - - /** - * [testPipelinePreviewRollback description] - */ - public function testPipelinePreviewRollback(): void { - - $model = $this->getModel('pipelinemodel'); - $this->assertEquals(0, $model->getCount()); - - $pipeline = new \codename\core\io\pipeline(null, [ - 'source' => [ - 'type' => 'arraydata' - ], - 'transform' => [ - - ], - 'target' => [ - 'test_model' => [ - 'type' => 'model', - 'model' => 'pipelinemodel', - 'mapping' => [ - 'pipelinemodel_text' => [ 'type' => 'source', 'field' => 'value' ] - ] - ] - ] - ]); - - $datasource = new \codename\core\io\datasource\arraydata([]); - $datasource->setData([ - [ 'value' => 'one' ], - [ 'value' => 'two' ], - [ 'value' => 'three' ], - ]); - - $pipeline->setDatasource($datasource); - - // Non-dryrun, but preview (rollback at end) - $pipeline->setDryRun(false); - $pipeline->setOptions([ 'preview' => true ]); - - $pipeline->run(); - - $this->assertEquals(0, $model->getCount()); - } + /** + * [testPipelinePreviewRollback description] + * @throws ReflectionException + * @throws \codename\core\exception + */ + public function testPipelinePreviewRollback(): void + { + $model = $this->getModel('pipelinemodel'); + static::assertEquals(0, $model->getCount()); + + $pipeline = new pipeline(null, [ + 'source' => [ + 'type' => 'arraydata', + ], + 'transform' => [ + + ], + 'target' => [ + 'test_model' => [ + 'type' => 'model', + 'model' => 'pipelinemodel', + 'mapping' => [ + 'pipelinemodel_text' => ['type' => 'source', 'field' => 'value'], + ], + ], + ], + ]); + + $datasource = new arraydata(); + $datasource->setData([ + ['value' => 'one'], + ['value' => 'two'], + ['value' => 'three'], + ]); + + $pipeline->setDatasource($datasource); + + // Non-dryrun, but preview (rollback at end) + $pipeline->setDryRun(false); + $pipeline->setOptions(['preview' => true]); + + $pipeline->run(); + + static::assertEquals(0, $model->getCount()); + } } diff --git a/tests/pipelineTest.php b/tests/pipelineTest.php new file mode 100644 index 0000000..71c0a71 --- /dev/null +++ b/tests/pipelineTest.php @@ -0,0 +1,359 @@ + true, + ]); + + // + // check config + // + static::assertEquals(['example' => true], $pipeline->getConfig()->get()); + + // + // check options + // + static::assertNull($pipeline->getOption('example')); + $pipeline->setOptions(['example' => true]); + static::assertTrue($pipeline->getOption('example')); + + // + // check dryrun + // + $pipeline->setDryRun(); + static::assertTrue($pipeline->getDryRun()); + + // + // check erroneous + // + static::assertEmpty($pipeline->getErroneousEntries()); + + // + // set default? + // + $pipeline->setDebug(true); + $pipeline->setLimit(0, 10); + $pipeline->setThrowExceptionOnErroneousData(); + $pipeline->setErrorstackEnabled(); + $pipeline->setSkipErroneous(); + $pipeline->setTrackErroneous(); + } + + /** + * [testPipelineDatasource description] + * @throws ReflectionException + * @throws exception + */ + public function testPipelineDatasource(): void + { + $pipeline = new pipeline(null, []); + + $datasource = new arraydata(); + $datasource->setData([ + [ + 'key1' => 'abc', + 'key2' => 'def', + 'key3' => 'ghi', + ], + [ + 'key1' => 'jkl', + 'key2' => 'mno', + 'key3' => 'pqr', + ], + [ + 'key1' => 'stu', + 'key2' => 'vwx', + 'key3' => 'yz', + ], + ]); + $pipeline->setDatasource($datasource); + static::assertInstanceOf(arraydata::class, $pipeline->getDatasource()); + + static::assertEquals(3, $pipeline->getItemCount()); + static::assertEquals(null, $pipeline->getItemIndex()); + static::assertEquals(null, $pipeline->getStoredItemCount()); + } + + /** + * [testPipelineDatasourcePipelineInstance description] + * @throws ReflectionException + * @throws exception + */ + public function testPipelineDatasourcePipelineInstance(): void + { + $datasource = new model(); + + $pipeline = new pipeline(null, []); + $pipeline->setDatasource($datasource); + static::assertInstanceOf(model::class, $pipeline->getDatasource()); + } + + /** + * [testPipelineCreateDatasourcePipelineInstance description] + * @throws ReflectionException + * @throws exception + */ + public function testPipelineCreateDatasourcePipelineInstance(): void + { + $pipeline = new pipeline(null, [ + 'source' => [ + 'type' => 'model', + 'config' => [], + ], + ]); + $datasource = $pipeline->createDatasource([]); + $pipeline->setDatasource($datasource); + static::assertInstanceOf(model::class, $pipeline->getDatasource()); + } + + /** + * [testPipelineDatasourceBuffered description] + * @throws ReflectionException + * @throws exception + */ + public function testPipelineDatasourceBuffered(): void + { + $pipeline = new pipeline(null, [ + 'config' => [ + 'datasource_buffering' => true, + 'datasource_buffer_size' => 100, + ], + ]); + + $datasource = new arraydata(); + $datasource->setData([ + [ + 'key1' => 'abc', + 'key2' => 'def', + 'key3' => 'ghi', + ], + [ + 'key1' => 'jkl', + 'key2' => 'mno', + 'key3' => 'pqr', + ], + [ + 'key1' => 'stu', + 'key2' => 'vwx', + 'key3' => 'yz', + ], + ]); + $pipeline->setDatasource($datasource); + static::assertInstanceOf(buffered::class, $pipeline->getDatasource()); + } + + /** + * [testPipelineDatasource description] + * @throws ReflectionException + * @throws exception + */ + public function testPipelineDatasourceLoad(): void + { + $pipeline = new pipeline('tests/testPipeline.json', []); + + $datasource = new arraydata(); + $datasource->setData([ + [ + 'key1' => 'abc', + 'key2' => 'def', + 'key3' => 'ghi', + ], + [ + 'key1' => 'jkl', + 'key2' => 'mno', + 'key3' => 'pqr', + ], + [ + 'key1' => 'stu', + 'key2' => 'vwx', + 'key3' => 'yz', + ], + ]); + $pipeline->setDatasource($datasource); + static::assertInstanceOf(arraydata::class, $pipeline->getDatasource()); + + static::assertEquals(3, $pipeline->getItemCount()); + static::assertEquals(null, $pipeline->getItemIndex()); + static::assertEquals(null, $pipeline->getStoredItemCount()); + } + + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $pipeline = new pipeline('tests/testPipeline2.json', []); + + static::assertEquals( + [ + 'target.example.example1' => [ + 'type' => 'target.mapping', + 'source' => ['transform.example1'], + ], + 'target.example.example2' => [ + 'type' => 'target.mapping', + 'source' => ['transform.example2'], + ], + 'target.example.example3' => [ + 'type' => 'target.mapping', + 'source' => ['transform.example3'], + ], + 'target.example' => [ + 'type' => 'target', + 'source' => ['target.example.example1', 'target.example.example2', 'target.example.example3'], + ], + 'transform.example1' => [ + 'type' => 'transform', + 'source' => [], + ], + 'transform.example2' => [ + 'type' => 'transform', + 'source' => ['model.pipelinemodel'], + ], + 'transform.example3' => [ + 'type' => 'transform', + 'source' => ['source.example3'], + ], + 'model.pipelinemodel' => [ + 'type' => 'model', + ], + 'source.example3' => [ + 'type' => 'source', + ], + 'erroneous.erroneous' => [ + 'type' => 'erroneous', + ], + 'erroneous.data' => [ + 'type' => 'erroneous', + ], + ], + $pipeline->getSpecification(), + json_encode($pipeline->getSpecification()) + ); + } + + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function tearDown(): void + { + $this->getModel('pipelinemodel') + ->addFilter('pipelinemodel_id', 0, '>') + ->delete(); + + overrideableApp::__setInstance('response', null); + } + + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function setUp(): void + { + $app = static::createApp(); + + overrideableApp::__injectApp([ + 'vendor' => 'codename', + 'app' => 'core-io', + 'namespace' => '\\codename\\core\\io', + ]); + + // Additional overrides to get a more complete app lifecycle + // and allow static global app::getModel() to work correctly + $app::__setApp('pipelinetest'); + $app::__setVendor('codename'); + $app::__setNamespace('\\codename\\core\\io\\tests\\pipeline'); + + $app::getAppstack(); + + // avoid re-init + if (static::$initialized) { + return; + } + + static::$initialized = true; + + static::setEnvironmentConfig([ + 'test' => [ + 'database' => [ + // NOTE: by default, we do these tests using + // pure in-memory sqlite. + 'default' => [ + 'driver' => 'sqlite', + // 'database_file' => 'pipelinemodel.sqlite', + 'database_file' => ':memory:', + ], + ], + 'cache' => [ + 'default' => [ + 'driver' => 'memory', + ], + ], + 'filesystem' => [ + 'local' => [ + 'driver' => 'local', + ], + ], + 'log' => [ + 'default' => [ + 'driver' => 'system', + 'data' => [ + 'name' => 'dummy', + ], + ], + ], + ], + ]); + + static::createModel( + 'pipelinetest', + 'pipelinemodel', + pipelinemodel::$staticConfig, + function ($schema, $model, $config) { + return new pipelinemodel([]); + } + ); + + static::architect('pipelinetest', 'codename', 'test'); + } +} diff --git a/tests/process/target/model/abstractProcessTargetModelTest.php b/tests/process/target/model/abstractProcessTargetModelTest.php index 7a25e0e..45db849 100644 --- a/tests/process/target/model/abstractProcessTargetModelTest.php +++ b/tests/process/target/model/abstractProcessTargetModelTest.php @@ -1,144 +1,155 @@ getConnection()->inTransaction()) { - // } - overrideableApp::getDb()->getConnection()->rollBack(); - } catch (\PDOException $e) { - if($e->getMessage() != 'There is no active transaction') { - throw $e; - } +use PDOException; +use ReflectionException; + +abstract class abstractProcessTargetModelTest extends base +{ + /** + * [protected description] + * @var bool + */ + protected static bool $initialized = false; + + /** + * {@inheritDoc} + */ + public static function tearDownAfterClass(): void + { + parent::tearDownAfterClass(); + static::$initialized = false; } - $this->getModel('processmodel') - ->addFilter('processmodel_id', 0, '>') - ->delete(); - - overrideableApp::__setInstance('response', null); - } - - /** - * @inheritDoc - */ - protected function setUp(): void - { - $app = static::createApp(); - - overrideableApp::__injectApp([ - 'vendor' => 'codename', - 'app' => 'core-io', - 'namespace' => '\\codename\\core\\io' - ]); - - // Additional overrides to get a more complete app lifecycle - // and allow static global app::getModel() to work correctly - $app->__setApp('processtest'); - $app->__setVendor('codename'); - $app->__setNamespace('\\codename\\core\\io\\tests\\process\\target\\model'); - - $app->getAppstack(); - - // fake response instance - $app->__setInstance('response', new \codename\core\response\cli([])); - - // avoid re-init - if(static::$initialized) { - return; + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function tearDown(): void + { + // try and rollback any existing transaction + try { + overrideableApp::getDb()->getConnection()->rollBack(); + } catch (PDOException $e) { + if ($e->getMessage() != 'There is no active transaction') { + throw $e; + } + } + + $this->getModel('processmodel') + ->addFilter('processmodel_id', 0, '>') + ->delete(); + + overrideableApp::__setInstance('response', null); } - static::$initialized = true; - - static::setEnvironmentConfig([ - 'test' => [ - 'database' => [ - // NOTE: by default, we do these tests using - // pure in-memory sqlite. - 'default' => [ - 'driver' => 'sqlite', - // 'database_file' => 'processmodel.sqlite', - 'database_file' => ':memory:', + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function setUp(): void + { + $app = static::createApp(); + + overrideableApp::__injectApp([ + 'vendor' => 'codename', + 'app' => 'core-io', + 'namespace' => '\\codename\\core\\io', + ]); + + // Additional overrides to get a more complete app lifecycle + // and allow static global app::getModel() to work correctly + $app::__setApp('processtest'); + $app::__setVendor('codename'); + $app::__setNamespace('\\codename\\core\\io\\tests\\process\\target\\model'); + + $app::getAppstack(); + + // fake response instance + $app::__setInstance('response', new cli()); + + // avoid re-init + if (static::$initialized) { + return; + } + + static::$initialized = true; + + static::setEnvironmentConfig([ + 'test' => [ + 'database' => [ + // NOTE: by default, we do these tests using + // pure in-memory sqlite. + 'default' => [ + 'driver' => 'sqlite', + // 'database_file' => 'processmodel.sqlite', + 'database_file' => ':memory:', + ], + ], + 'cache' => [ + 'default' => [ + 'driver' => 'memory', + ], + ], + 'filesystem' => [ + 'local' => [ + 'driver' => 'local', + ], + ], + 'log' => [ + 'default' => [ + 'driver' => 'system', + 'data' => [ + 'name' => 'dummy', + ], + ], + ], ], - ], - 'cache' => [ - 'default' => [ - 'driver' => 'memory' - ] - ], - 'filesystem' =>[ - 'local' => [ - 'driver' => 'local', - ] - ], - 'log' => [ - 'default' => [ - 'driver' => 'system', - 'data' => [ - 'name' => 'dummy' - ] - ] - ], - ] - ]); - - static::createModel( - 'processtest', 'processmodel', - \codename\core\io\tests\process\target\model\model\processmodel::$staticConfig, - function($schema, $model, $config) { - return new \codename\core\io\tests\process\target\model\model\processmodel([]); - } - ); - - static::architect('processtest', 'codename', 'test'); - } - - /** - * [createTestData description] - */ - protected function createTestData(): void { - $model = $this->getModel('processmodel'); - - $datasets = [ - [ - 'processmodel_text' => 'first', - ], - [ - 'processmodel_text' => 'second', - ], - [ - 'processmodel_text' => 'third', - ], - ]; - - foreach($datasets as $dataset) { - $model->save($dataset); + ]); + + static::createModel( + 'processtest', + 'processmodel', + processmodel::$staticConfig, + function ($schema, $model, $config) { + return new processmodel([]); + } + ); + + static::architect('processtest', 'codename', 'test'); } - } + /** + * [createTestData description] + * @throws ReflectionException + * @throws exception + */ + protected function createTestData(): void + { + $model = $this->getModel('processmodel'); + + $datasets = [ + [ + 'processmodel_text' => 'first', + ], + [ + 'processmodel_text' => 'second', + ], + [ + 'processmodel_text' => 'third', + ], + ]; + + foreach ($datasets as $dataset) { + $model->save($dataset); + } + } } diff --git a/tests/process/target/model/deleteTest.php b/tests/process/target/model/deleteTest.php index 5bbb7c5..c43dd0c 100644 --- a/tests/process/target/model/deleteTest.php +++ b/tests/process/target/model/deleteTest.php @@ -1,228 +1,253 @@ getModel('processmodel'); - $this->createTestData(); - - // make sure the data is there - $this->assertEquals(3, $model->getCount()); - - $pipeline = new \codename\core\io\pipeline(null, [ - 'preprocess' => [ - 'delete_with_constant_filter' => [ - 'type' => 'target_model_delete', - 'config' => [ - 'target' => 'test', - 'filter' => [ - [ 'field' => 'processmodel_text', 'operator' => '=', 'value' => 'second' ] // Constant value - ] - ] - ] - ], - 'source' => [ - 'type' => 'arraydata' - ], - 'transform' => [], - 'target' => [ - 'test' => [ - 'type' => 'model', - 'model' => 'processmodel', - ] - ] - ]); - - $datasource = new \codename\core\io\datasource\arraydata(); - $datasource->setData([]); - $pipeline->setDatasource($datasource); - - // this might/should fail? - $pipeline->setDryRun(false); - $pipeline->run(); - - $this->assertEquals(2, $model->getCount()); - } - - /** - * [testProcessDeleteWithTransformValueFilter description] - */ - public function testProcessDeleteWithTransformValueFilter(): void { - $model = $this->getModel('processmodel'); - $this->createTestData(); - - // make sure the data is there - $this->assertEquals(3, $model->getCount()); - - $pipeline = new \codename\core\io\pipeline(null, [ - 'preprocess' => [ - 'delete_with_transform_filter' => [ - 'type' => 'target_model_delete', - 'config' => [ - 'target' => 'test', - 'filter' => [ - [ 'field' => 'processmodel_text', 'operator' => '=', 'value' => [ 'source' => 'transform', 'field' => 'first' ] ] // transform value - ] - ] - ] - ], - 'source' => [ - 'type' => 'arraydata' - ], - 'transform' => [ - 'first' => [ - 'type' => 'value', - 'config' => [ - 'value' => 'first' +class deleteTest extends abstractProcessTargetModelTest +{ + /** + * [testProcessDeleteWithoutFiltersFails description] + * @throws ReflectionException + * @throws exception + */ + public function testProcessDeleteWithConstantValueFilter(): void + { + $model = $this->getModel('processmodel'); + $this->createTestData(); + + // make sure the data is there + static::assertEquals(3, $model->getCount()); + + $pipeline = new pipeline(null, [ + 'preprocess' => [ + 'delete_with_constant_filter' => [ + 'type' => 'target_model_delete', + 'config' => [ + 'target' => 'test', + 'filter' => [ + ['field' => 'processmodel_text', 'operator' => '=', 'value' => 'second'], // Constant value + ], + ], + ], ], - ], - ], - 'target' => [ - 'test' => [ - 'type' => 'model', - 'model' => 'processmodel', - ] - ] - ]); - - $datasource = new \codename\core\io\datasource\arraydata(); - $datasource->setData([]); - $pipeline->setDatasource($datasource); - - // this might/should fail? - $pipeline->setDryRun(false); - $pipeline->run(); - - $this->assertEquals(2, $model->getCount()); - } - - /** - * [testProcessDeleteWithUnsupportedTarget description] - */ - public function testProcessDeleteWithUnsupportedTarget(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_CORE_IO_PROCESS_TARGET_MODEL_UNSUPPORTED'); - - $pipeline = new \codename\core\io\pipeline(null, [ - 'preprocess' => [ - 'delete_with_transform_filter' => [ - 'type' => 'target_model_delete', - 'config' => [ - 'target' => 'test', - 'filter' => [ - [ 'field' => 'processmodel_text', 'operator' => '=', 'value' => [ 'source' => 'transform', 'field' => 'first' ] ] // transform value - ] - ] - ] - ], - 'source' => [ - 'type' => 'arraydata' - ], - 'transform' => [ - 'first' => [ - 'type' => 'value', - 'config' => [ - 'value' => 'first' + 'source' => [ + 'type' => 'arraydata', ], - ], - ], - 'target' => [ - 'test' => [ - 'type' => 'arraydata', - 'mapping' => [] - ] - ] - ]); - - $datasource = new \codename\core\io\datasource\arraydata(); - $datasource->setData([]); - $pipeline->setDatasource($datasource); - - // this might/should fail? - $pipeline->setDryRun(false); - $pipeline->run(); - } - - /** - * Model-Deletion calls without any filters - * must fail due to model mechanics - */ - public function testProcessDeleteWithoutFiltersFails(): void { - $model = $this->getModel('processmodel'); - $this->createTestData(); - - // make sure the data is there - $this->assertEquals(3, $model->getCount()); - - // Must fail, due to model mechanics - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_MODEL_SCHEMATIC_SQL_DELETE_NO_FILTERS_DEFINED'); - - $pipeline = new \codename\core\io\pipeline(null, [ - 'preprocess' => [ - 'delete_unfiltered' => [ - 'type' => 'target_model_delete', - 'config' => [ - 'target' => 'test', - 'filter' => [], // NOTE: TODO: NO filter-key must fail? - ] - ] - ], - 'transform' => [], - 'target' => [ - 'test' => [ - 'type' => 'model', - 'model' => 'processmodel', - ] - ] - ]); - - // this might/should fail? - $pipeline->setDryRun(false); - $pipeline->run(); - } - - /** - * [testErrorsAndDryRun description] - */ - public function testErrorsAndDryRun(): void { - $process = new helper_process_target_model_delete([]); - - $process->resetErrors(); - $this->assertEmpty($process->getErrors()); - - $pipeline = new \codename\core\io\pipeline(null, []); - $pipeline->setDryRun(true); - - $process->setPipelineInstance($pipeline); - $this->assertTrue($process->isDryRun()); - - } - - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $this->expectException(\LogicException::class); - $this->expectExceptionMessage('Not implemented'); - - $process = new \codename\core\io\process\target\model\delete([]); - $specification = $process->getSpecification(); - } - + 'transform' => [], + 'target' => [ + 'test' => [ + 'type' => 'model', + 'model' => 'processmodel', + ], + ], + ]); + + $datasource = new arraydata(); + $datasource->setData([]); + $pipeline->setDatasource($datasource); + + // this might/should fail? + $pipeline->setDryRun(false); + $pipeline->run(); + + static::assertEquals(2, $model->getCount()); + } + + /** + * [testProcessDeleteWithTransformValueFilter description] + * @throws ReflectionException + * @throws exception + */ + public function testProcessDeleteWithTransformValueFilter(): void + { + $model = $this->getModel('processmodel'); + $this->createTestData(); + + // make sure the data is there + static::assertEquals(3, $model->getCount()); + + $pipeline = new pipeline(null, [ + 'preprocess' => [ + 'delete_with_transform_filter' => [ + 'type' => 'target_model_delete', + 'config' => [ + 'target' => 'test', + 'filter' => [ + ['field' => 'processmodel_text', 'operator' => '=', 'value' => ['source' => 'transform', 'field' => 'first']], // transform value + ], + ], + ], + ], + 'source' => [ + 'type' => 'arraydata', + ], + 'transform' => [ + 'first' => [ + 'type' => 'value', + 'config' => [ + 'value' => 'first', + ], + ], + ], + 'target' => [ + 'test' => [ + 'type' => 'model', + 'model' => 'processmodel', + ], + ], + ]); + + $datasource = new arraydata(); + $datasource->setData([]); + $pipeline->setDatasource($datasource); + + // this might/should fail? + $pipeline->setDryRun(false); + $pipeline->run(); + + static::assertEquals(2, $model->getCount()); + } + + /** + * [testProcessDeleteWithUnsupportedTarget description] + * @throws ReflectionException + * @throws exception + */ + public function testProcessDeleteWithUnsupportedTarget(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('EXCEPTION_CORE_IO_PROCESS_TARGET_MODEL_UNSUPPORTED'); + + $pipeline = new pipeline(null, [ + 'preprocess' => [ + 'delete_with_transform_filter' => [ + 'type' => 'target_model_delete', + 'config' => [ + 'target' => 'test', + 'filter' => [ + ['field' => 'processmodel_text', 'operator' => '=', 'value' => ['source' => 'transform', 'field' => 'first']], // transform value + ], + ], + ], + ], + 'source' => [ + 'type' => 'arraydata', + ], + 'transform' => [ + 'first' => [ + 'type' => 'value', + 'config' => [ + 'value' => 'first', + ], + ], + ], + 'target' => [ + 'test' => [ + 'type' => 'arraydata', + 'mapping' => [], + ], + ], + ]); + + $datasource = new arraydata(); + $datasource->setData([]); + $pipeline->setDatasource($datasource); + + // this might/should fail? + $pipeline->setDryRun(false); + $pipeline->run(); + } + + /** + * Model-Deletion calls without any filters + * must fail due to model mechanics + * @throws ReflectionException + * @throws exception + */ + public function testProcessDeleteWithoutFiltersFails(): void + { + $model = $this->getModel('processmodel'); + $this->createTestData(); + + // make sure the data is there + static::assertEquals(3, $model->getCount()); + + // Must fail, due to model mechanics + $this->expectException(exception::class); + $this->expectExceptionMessage('EXCEPTION_MODEL_SCHEMATIC_SQL_DELETE_NO_FILTERS_DEFINED'); + + $pipeline = new pipeline(null, [ + 'preprocess' => [ + 'delete_unfiltered' => [ + 'type' => 'target_model_delete', + 'config' => [ + 'target' => 'test', + 'filter' => [], // NOTE: TODO: NO filter-key must fail? + ], + ], + ], + 'transform' => [], + 'target' => [ + 'test' => [ + 'type' => 'model', + 'model' => 'processmodel', + ], + ], + ]); + + // this might/should fail? + $pipeline->setDryRun(false); + $pipeline->run(); + } + + /** + * [testErrorsAndDryRun description] + * @throws ReflectionException + * @throws exception + */ + public function testErrorsAndDryRun(): void + { + $process = new helper_process_target_model_delete([]); + + $process->resetErrors(); + static::assertEmpty($process->getErrors()); + + $pipeline = new pipeline(null, []); + $pipeline->setDryRun(); + + $process->setPipelineInstance($pipeline); + static::assertTrue($process->isDryRun()); + } + + /** + * Test Spec output (simple case) + */ + public function testSpecification(): void + { + $this->expectException(LogicException::class); + $this->expectExceptionMessage('Not implemented'); + + $process = new delete([]); + $process->getSpecification(); + } } -class helper_process_target_model_delete extends \codename\core\io\process\target\model\delete { - - public function isDryRun() : bool { - return parent::isDryRun(); - } - +class helper_process_target_model_delete extends delete +{ + /** + * @return bool + */ + public function isDryRun(): bool + { + return parent::isDryRun(); + } } diff --git a/tests/process/target/model/model/processmodel.php b/tests/process/target/model/model/processmodel.php index c8b8add..8361403 100644 --- a/tests/process/target/model/model/processmodel.php +++ b/tests/process/target/model/model/processmodel.php @@ -1,40 +1,44 @@ [ + 'processmodel_id', + 'processmodel_created', + 'processmodel_modified', + 'processmodel_text', + ], + 'primary' => [ + 'processmodel_id', + ], + 'datatype' => [ + 'processmodel_id' => 'number_natural', + 'processmodel_created' => 'text_timestamp', + 'processmodel_modified' => 'text_timestamp', + 'processmodel_text' => 'text', + ], + 'connection' => 'default', + ]; - /** - * static configuration - * for usage in unit tests - * @var array - */ - public static $staticConfig = [ - 'field' => [ - 'processmodel_id', - 'processmodel_created', - 'processmodel_modified', - 'processmodel_text', - ], - 'primary' => [ - 'processmodel_id' - ], - 'datatype' => [ - 'processmodel_id' => 'number_natural', - 'processmodel_created' => 'text_timestamp', - 'processmodel_modified' => 'text_timestamp', - 'processmodel_text' => 'text', - ], - 'connection' => 'default' - ]; + /** + * {@inheritDoc} + */ + public function __construct(array $modeldata = []) + { + parent::__construct('processtest', 'processmodel', static::$staticConfig); + } } diff --git a/tests/process/target/model/updateTest.php b/tests/process/target/model/updateTest.php index 67afa7d..e7daee3 100644 --- a/tests/process/target/model/updateTest.php +++ b/tests/process/target/model/updateTest.php @@ -1,307 +1,336 @@ getModel('processmodel'); - $this->createTestData(); - - // make sure the data is there - $this->assertEquals(3, $model->getCount()); - - $pipeline = new \codename\core\io\pipeline(null, [ - 'preprocess' => [ - 'update_with_constant_filter' => [ - 'type' => 'target_model_update', - 'config' => [ - 'target' => 'test', - 'filter' => [ - [ 'field' => 'processmodel_text', 'operator' => '=', 'value' => 'second' ] // Constant value +class updateTest extends abstractProcessTargetModelTest +{ + /** + * [testProcessUpdateWithConstantValueFilterAndConstantData description] + * @throws ReflectionException + * @throws exception + */ + public function testProcessUpdateWithConstantValueFilterAndConstantData(): void + { + $model = $this->getModel('processmodel'); + $this->createTestData(); + + // make sure the data is there + static::assertEquals(3, $model->getCount()); + + $pipeline = new pipeline(null, [ + 'preprocess' => [ + 'update_with_constant_filter' => [ + 'type' => 'target_model_update', + 'config' => [ + 'target' => 'test', + 'filter' => [ + ['field' => 'processmodel_text', 'operator' => '=', 'value' => 'second'], // Constant value + ], + 'data' => [ + 'processmodel_text' => 'updated', + ], + ], ], - 'data' => [ - 'processmodel_text' => 'updated' - ] - ] - ] - ], - 'source' => [ - 'type' => 'arraydata' - ], - 'transform' => [], - 'target' => [ - 'test' => [ - 'type' => 'model', - 'model' => 'processmodel', - ] - ] - ]); - - $datasource = new \codename\core\io\datasource\arraydata(); - $datasource->setData([]); - $pipeline->setDatasource($datasource); - - // this might/should fail? - $pipeline->setDryRun(false); - $pipeline->run(); - - $res = $model->addFilter('processmodel_text', 'updated')->search()->getResult(); - $this->assertCount(1, $res); - } - - /** - * [testProcessUpdateWithConstantValueFilterAndOptionData description] - */ - public function testProcessUpdateWithConstantValueFilterAndOptionData(): void { - $model = $this->getModel('processmodel'); - $this->createTestData(); - - // make sure the data is there - $this->assertEquals(3, $model->getCount()); - - $pipeline = new \codename\core\io\pipeline(null, [ - 'preprocess' => [ - 'update_with_constant_filter' => [ - 'type' => 'target_model_update', - 'config' => [ - 'target' => 'test', - 'filter' => [ - [ 'field' => 'processmodel_text', 'operator' => '=', 'value' => 'second' ] // Constant value + ], + 'source' => [ + 'type' => 'arraydata', + ], + 'transform' => [], + 'target' => [ + 'test' => [ + 'type' => 'model', + 'model' => 'processmodel', ], - 'data' => [ - 'processmodel_text' => [ 'source' => 'option', 'field' => 'updated' ] - ] - ] - ] - ], - 'source' => [ - 'type' => 'arraydata' - ], - 'transform' => [], - 'target' => [ - 'test' => [ - 'type' => 'model', - 'model' => 'processmodel', - ] - ] - ]); - $pipeline->setOptions([ - 'updated' => 'updated' - ]); - - $datasource = new \codename\core\io\datasource\arraydata(); - $datasource->setData([]); - $pipeline->setDatasource($datasource); - - // this might/should fail? - $pipeline->setDryRun(false); - $pipeline->run(); - - $res = $model->addFilter('processmodel_text', 'updated')->search()->getResult(); - $this->assertCount(1, $res); - } - - /** - * [testProcessUpdateWithTransformValueFilterAndTransformData description] - */ - public function testProcessUpdateWithTransformValueFilterAndTransformData(): void { - $model = $this->getModel('processmodel'); - $this->createTestData(); - - // make sure the data is there - $this->assertEquals(3, $model->getCount()); - - $pipeline = new \codename\core\io\pipeline(null, [ - 'preprocess' => [ - 'update_with_transform_filter' => [ - 'type' => 'target_model_update', - 'config' => [ - 'target' => 'test', - 'filter' => [ - [ 'field' => 'processmodel_text', 'operator' => '=', 'value' => [ 'source' => 'transform', 'field' => 'first' ] ] // transform value + ], + ]); + + $datasource = new arraydata(); + $datasource->setData([]); + $pipeline->setDatasource($datasource); + + // this might/should fail? + $pipeline->setDryRun(false); + $pipeline->run(); + + $res = $model->addFilter('processmodel_text', 'updated')->search()->getResult(); + static::assertCount(1, $res); + } + + /** + * [testProcessUpdateWithConstantValueFilterAndOptionData description] + * @throws ReflectionException + * @throws exception + */ + public function testProcessUpdateWithConstantValueFilterAndOptionData(): void + { + $model = $this->getModel('processmodel'); + $this->createTestData(); + + // make sure the data is there + static::assertEquals(3, $model->getCount()); + + $pipeline = new pipeline(null, [ + 'preprocess' => [ + 'update_with_constant_filter' => [ + 'type' => 'target_model_update', + 'config' => [ + 'target' => 'test', + 'filter' => [ + ['field' => 'processmodel_text', 'operator' => '=', 'value' => 'second'], // Constant value + ], + 'data' => [ + 'processmodel_text' => ['source' => 'option', 'field' => 'updated'], + ], + ], ], - 'data' => [ - 'processmodel_text' => [ 'source' => 'transform', 'field' => 'updated' ] - ] - ] - ] - ], - 'source' => [ - 'type' => 'arraydata' - ], - 'transform' => [ - 'first' => [ - 'type' => 'value', - 'config' => [ - 'value' => 'first' ], - ], - 'updated' => [ - 'type' => 'value', - 'config' => [ - 'value' => 'updated' + 'source' => [ + 'type' => 'arraydata', ], - ], - ], - 'target' => [ - 'test' => [ - 'type' => 'model', - 'model' => 'processmodel', - ] - ] - ]); - - $datasource = new \codename\core\io\datasource\arraydata(); - $datasource->setData([]); - $pipeline->setDatasource($datasource); - - // this might/should fail? - $pipeline->setDryRun(false); - $pipeline->run(); - - $res = $model->addFilter('processmodel_text', 'updated')->search()->getResult(); - $this->assertCount(1, $res); - } - - /** - * [testProcessUpdateWithUnsupportedTarget description] - */ - public function testProcessUpdateWithUnsupportedTarget(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_CORE_IO_PROCESS_TARGET_MODEL_UNSUPPORTED'); - - $pipeline = new \codename\core\io\pipeline(null, [ - 'preprocess' => [ - 'update_with_transform_filter' => [ - 'type' => 'target_model_update', - 'config' => [ - 'target' => 'test', - 'filter' => [ - [ 'field' => 'processmodel_text', 'operator' => '=', 'value' => [ 'source' => 'transform', 'field' => 'first' ] ] // transform value + 'transform' => [], + 'target' => [ + 'test' => [ + 'type' => 'model', + 'model' => 'processmodel', ], - 'data' => [ - 'processmodel_text' => [ 'source' => 'transform', 'field' => 'updated' ] - ] - ] - ] - ], - 'source' => [ - 'type' => 'arraydata' - ], - 'transform' => [ - 'first' => [ - 'type' => 'value', - 'config' => [ - 'value' => 'first' ], - ], - 'updated' => [ - 'type' => 'value', - 'config' => [ - 'value' => 'updated' + ]); + $pipeline->setOptions([ + 'updated' => 'updated', + ]); + + $datasource = new arraydata(); + $datasource->setData([]); + $pipeline->setDatasource($datasource); + + // this might/should fail? + $pipeline->setDryRun(false); + $pipeline->run(); + + $res = $model->addFilter('processmodel_text', 'updated')->search()->getResult(); + static::assertCount(1, $res); + } + + /** + * [testProcessUpdateWithTransformValueFilterAndTransformData description] + * @throws ReflectionException + * @throws exception + */ + public function testProcessUpdateWithTransformValueFilterAndTransformData(): void + { + $model = $this->getModel('processmodel'); + $this->createTestData(); + + // make sure the data is there + static::assertEquals(3, $model->getCount()); + + $pipeline = new pipeline(null, [ + 'preprocess' => [ + 'update_with_transform_filter' => [ + 'type' => 'target_model_update', + 'config' => [ + 'target' => 'test', + 'filter' => [ + ['field' => 'processmodel_text', 'operator' => '=', 'value' => ['source' => 'transform', 'field' => 'first']], // transform value + ], + 'data' => [ + 'processmodel_text' => ['source' => 'transform', 'field' => 'updated'], + ], + ], + ], ], - ], - ], - 'target' => [ - 'test' => [ - 'type' => 'arraydata', - 'mapping' => [], - ], - ] - ]); - - $datasource = new \codename\core\io\datasource\arraydata(); - $datasource->setData([]); - $pipeline->setDatasource($datasource); - - // this might/should fail? - $pipeline->setDryRun(false); - $pipeline->run(); - } - - - /** - * Model-Deletion calls without any filters - * must fail due to model mechanics - */ - public function testProcessUpdateWithoutFiltersFails(): void { - $model = $this->getModel('processmodel'); - $this->createTestData(); - - // make sure the data is there - $this->assertEquals(3, $model->getCount()); - - // Must fail, due to model mechanics - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_MODEL_SCHEMATIC_SQL_UPDATE_NO_FILTERS_DEFINED'); - - $pipeline = new \codename\core\io\pipeline(null, [ - 'preprocess' => [ - 'update_unfiltered' => [ - 'type' => 'target_model_update', - 'config' => [ - 'target' => 'test', - 'filter' => [], // NOTE: TODO: NO filter-key must fail? - 'data' => [ - 'processmodel_text' => 'updated' - ] - ] - ] - ], - 'transform' => [], - 'target' => [ - 'test' => [ - 'type' => 'model', - 'model' => 'processmodel', - ] - ] - ]); - - // this might/should fail? - $pipeline->setDryRun(false); - $pipeline->run(); - } - - /** - * [testErrorsAndDryRun description] - */ - public function testErrorsAndDryRun(): void { - $process = new helper_process_target_model_update([]); - - $process->resetErrors(); - $this->assertEmpty($process->getErrors()); - - $pipeline = new \codename\core\io\pipeline(null, []); - $pipeline->setDryRun(true); - - $process->setPipelineInstance($pipeline); - $this->assertTrue($process->isDryRun()); - - } - - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $this->expectException(\LogicException::class); - $this->expectExceptionMessage('Not implemented'); - - $process = new \codename\core\io\process\target\model\update([]); - $specification = $process->getSpecification(); - } - + 'source' => [ + 'type' => 'arraydata', + ], + 'transform' => [ + 'first' => [ + 'type' => 'value', + 'config' => [ + 'value' => 'first', + ], + ], + 'updated' => [ + 'type' => 'value', + 'config' => [ + 'value' => 'updated', + ], + ], + ], + 'target' => [ + 'test' => [ + 'type' => 'model', + 'model' => 'processmodel', + ], + ], + ]); + + $datasource = new arraydata(); + $datasource->setData([]); + $pipeline->setDatasource($datasource); + + // this might/should fail? + $pipeline->setDryRun(false); + $pipeline->run(); + + $res = $model->addFilter('processmodel_text', 'updated')->search()->getResult(); + static::assertCount(1, $res); + } + + /** + * [testProcessUpdateWithUnsupportedTarget description] + * @throws ReflectionException + * @throws exception + */ + public function testProcessUpdateWithUnsupportedTarget(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('EXCEPTION_CORE_IO_PROCESS_TARGET_MODEL_UNSUPPORTED'); + + $pipeline = new pipeline(null, [ + 'preprocess' => [ + 'update_with_transform_filter' => [ + 'type' => 'target_model_update', + 'config' => [ + 'target' => 'test', + 'filter' => [ + ['field' => 'processmodel_text', 'operator' => '=', 'value' => ['source' => 'transform', 'field' => 'first']], // transform value + ], + 'data' => [ + 'processmodel_text' => ['source' => 'transform', 'field' => 'updated'], + ], + ], + ], + ], + 'source' => [ + 'type' => 'arraydata', + ], + 'transform' => [ + 'first' => [ + 'type' => 'value', + 'config' => [ + 'value' => 'first', + ], + ], + 'updated' => [ + 'type' => 'value', + 'config' => [ + 'value' => 'updated', + ], + ], + ], + 'target' => [ + 'test' => [ + 'type' => 'arraydata', + 'mapping' => [], + ], + ], + ]); + + $datasource = new arraydata(); + $datasource->setData([]); + $pipeline->setDatasource($datasource); + + // this might/should fail? + $pipeline->setDryRun(false); + $pipeline->run(); + } + + + /** + * Model-Deletion calls without any filters + * must fail due to model mechanics + * @throws ReflectionException + * @throws exception + */ + public function testProcessUpdateWithoutFiltersFails(): void + { + $model = $this->getModel('processmodel'); + $this->createTestData(); + + // make sure the data is there + static::assertEquals(3, $model->getCount()); + + // Must fail, due to model mechanics + $this->expectException(exception::class); + $this->expectExceptionMessage('EXCEPTION_MODEL_SCHEMATIC_SQL_UPDATE_NO_FILTERS_DEFINED'); + + $pipeline = new pipeline(null, [ + 'preprocess' => [ + 'update_unfiltered' => [ + 'type' => 'target_model_update', + 'config' => [ + 'target' => 'test', + 'filter' => [], // NOTE: TODO: NO filter-key must fail? + 'data' => [ + 'processmodel_text' => 'updated', + ], + ], + ], + ], + 'transform' => [], + 'target' => [ + 'test' => [ + 'type' => 'model', + 'model' => 'processmodel', + ], + ], + ]); + + // this might/should fail? + $pipeline->setDryRun(false); + $pipeline->run(); + } + + /** + * [testErrorsAndDryRun description] + * @throws ReflectionException + * @throws exception + */ + public function testErrorsAndDryRun(): void + { + $process = new helper_process_target_model_update([]); + + $process->resetErrors(); + static::assertEmpty($process->getErrors()); + + $pipeline = new pipeline(null, []); + $pipeline->setDryRun(); + + $process->setPipelineInstance($pipeline); + static::assertTrue($process->isDryRun()); + } + + /** + * Test Spec output (simple case) + */ + public function testSpecification(): void + { + $this->expectException(LogicException::class); + $this->expectExceptionMessage('Not implemented'); + + $process = new update([]); + $process->getSpecification(); + } } -class helper_process_target_model_update extends \codename\core\io\process\target\model\update { - - public function isDryRun() : bool { - return parent::isDryRun(); - } - +class helper_process_target_model_update extends update +{ + /** + * [isDryRun description] + * @return bool [description] + */ + public function isDryRun(): bool + { + return parent::isDryRun(); + } } diff --git a/tests/target/abstractWriteReadTest.php b/tests/target/abstractWriteReadTest.php index a1a9baa..ee172b7 100644 --- a/tests/target/abstractWriteReadTest.php +++ b/tests/target/abstractWriteReadTest.php @@ -1,118 +1,124 @@ 'value1', - 'key2' => 2, - 'key3' => 3.1415, - 'key4' => null, - ], - [ - 'key1' => 'value2', - 'key2' => 3, - 'key3' => 4.23446, - 'key4' => null, - ], - [ - 'key1' => 'value3', - 'key2' => 4, - 'key3' => 5.454545, - 'key4' => null, - ], - ]; - } - - /** - * [getSampleTags description] - * @return array|null - */ - protected function getSampleTags(): ?array { - return null; - } - - /** - * Creates the instance for the generic write-read test - * @param array $configOverride [optional configuration override] - * @return \codename\core\io\target [description] - */ - protected abstract function getWriteReadTargetInstance(array $configOverride = []): \codename\core\io\target; - - /** - * Read the target's written/collected data - * and re-parse it as an array - * @param \codename\core\io\target $target [description] - * @return array [description] - */ - protected abstract function readTargetData(\codename\core\io\target $target): array; - - /** - * [compareData description] - * @param \codename\core\io\target $target [description] - * @param array $samples [description] - */ - protected function compareData(\codename\core\io\target $target, array $samples): void { - $result = $this->readTargetData($target); - $this->assertEquals($samples, $result); - } +abstract class abstractWriteReadTest extends base +{ + /** + * [testWriteReadTarget description] + * @param array $configOverride [description] + * @param array|null $samplesOverride [description] + */ + public function testWriteReadTarget(array $configOverride = [], ?array $samplesOverride = null): void + { + $target = $this->getWriteReadTargetInstance($configOverride); + $samples = $samplesOverride ?? $this->getSampleData(); + $tags = $this->getSampleTags(); + foreach ($samples as $sample) { + $target->store($sample, $tags); + } + $target->finish(); + $this->compareData($target, $samples); + $this->cleanupTarget($target); + } - /** - * [cleanupTarget description] - * @param \codename\core\io\target $target [description] - * @return void - */ - protected abstract function cleanupTarget(\codename\core\io\target $target): void; + /** + * Creates the instance for the generic write-read test + * @param array $configOverride [optional configuration override] + * @return target [description] + */ + abstract protected function getWriteReadTargetInstance(array $configOverride = []): target; - /** - * [testWriteReadTarget description] - * @param array $configOverride [description] - * @param array|null $samplesOverride [description] - */ - public function testWriteReadTarget(array $configOverride = [], ?array $samplesOverride = null): void { - $target = $this->getWriteReadTargetInstance($configOverride); - $samples = $samplesOverride ?? $this->getSampleData(); - $tags = $this->getSampleTags(); - foreach($samples as $sample) { - $target->store($sample, $tags); + /** + * [getSampleData description] + * @return array [description] + */ + protected function getSampleData(): array + { + return [ + [ + 'key1' => 'value1', + 'key2' => 2, + 'key3' => 3.1415, + 'key4' => null, + ], + [ + 'key1' => 'value2', + 'key2' => 3, + 'key3' => 4.23446, + 'key4' => null, + ], + [ + 'key1' => 'value3', + 'key2' => 4, + 'key3' => 5.454545, + 'key4' => null, + ], + ]; } - $target->finish(); - $this->compareData($target, $samples); - $this->cleanupTarget($target); - } - /** - * [testCallingStoreAfterFinishCrashes description] - */ - public function testCallingStoreAfterFinishCrashes(): void { - $target = $this->getWriteReadTargetInstance(); - $samples = $this->getSampleData(); - $tags = $this->getSampleTags(); - foreach($samples as $sample) { - $target->store($sample, $tags); + /** + * [getSampleTags description] + * @return array|null + */ + protected function getSampleTags(): ?array + { + return null; } - $target->finish(); - // In this case, we do not compare, - // but try to call store() again - // which MUST result in an exception - try { - $target->store([]); - $this->fail('Exception EXCEPTION_CORE_IO_TARGET_BUFFERED_ALREADY_FINISHED did not happen!'); - } catch (\codename\core\exception $e) { - $this->assertEquals('EXCEPTION_CORE_IO_TARGET_BUFFERED_ALREADY_FINISHED', $e->getMessage()); + /** + * [compareData description] + * @param target $target [description] + * @param array $samples [description] + */ + protected function compareData(target $target, array $samples): void + { + $result = $this->readTargetData($target); + static::assertEquals($samples, $result); } - $this->cleanupTarget($target); - } + /** + * Read the target's written/collected data + * and reparse it as an array + * @param target $target [description] + * @return array [description] + */ + abstract protected function readTargetData(target $target): array; + + /** + * [cleanupTarget description] + * @param target $target [description] + * @return void + */ + abstract protected function cleanupTarget(target $target): void; + /** + * [testCallingStoreAfterFinishCrashes description] + */ + public function testCallingStoreAfterFinishCrashes(): void + { + $target = $this->getWriteReadTargetInstance(); + $samples = $this->getSampleData(); + $tags = $this->getSampleTags(); + foreach ($samples as $sample) { + $target->store($sample, $tags); + } + $target->finish(); + // In this case, we do not compare, + // but try to call store() again + // which MUST result in an exception + try { + $target->store([]); + static::fail('Exception EXCEPTION_CORE_IO_TARGET_BUFFERED_ALREADY_FINISHED did not happen!'); + } catch (Exception $e) { + static::assertEquals('EXCEPTION_CORE_IO_TARGET_BUFFERED_ALREADY_FINISHED', $e->getMessage()); + } + + $this->cleanupTarget($target); + } } diff --git a/tests/target/arraydata/taggedTest.php b/tests/target/arraydata/taggedTest.php index c749e40..6d58468 100644 --- a/tests/target/arraydata/taggedTest.php +++ b/tests/target/arraydata/taggedTest.php @@ -1,81 +1,100 @@ store([ - 'example' => 'data' - ],[ - 'example' => true, - ]); - $this->assertTrue($result); - - // get data - $result = $target->getVirtualStoreData(); - $this->assertEquals([ - [ 'example' => 'data' ] - ], $result); - - // check finish - $this->assertEmpty($target->finish()); - - // getStructureResultArray - $result = $target->getStructureResultArray(); - - $this->assertCount(1, $result); - $this->assertInstanceOf(\codename\core\io\value\structure\tagged::class, $result[0]); - $this->assertEquals([ - 'example' => 'data' - ], $result[0]->get() ?? []); - $this->assertEquals([ - [ - 'example' => true, - ] - ], $result[0]->getTags()); - - } - - /** - * [testWithoutTags description] - */ - public function testWithoutTags(): void { - - $target = new \codename\core\io\target\arraydata\tagged('general_example', []); - - // set data - $result = $target->store([ - 'example' => 'data' - ]); - $this->assertTrue($result); - - // get data - $result = $target->getVirtualStoreData(); - $this->assertEquals([ - [ 'example' => 'data' ] - ], $result); - - // check finish - $this->assertEmpty($target->finish()); - - // getStructureResultArray - $result = $target->getStructureResultArray(); - - $this->assertCount(1, $result); - $this->assertInstanceOf(\codename\core\value\structure::class, $result[0]); - $this->assertEquals([ - 'example' => 'data' - ], $result[0]->get() ?? []); +namespace codename\core\io\tests\target\arraydata; - } +use codename\core\io\target\arraydata\tagged; +use codename\core\value\structure; +use Exception; +use PHPUnit\Framework\TestCase; +use ReflectionException; +class taggedTest extends TestCase +{ + /** + * [testWithTags description] + * @throws ReflectionException + * @throws \codename\core\exception + */ + public function testWithTags(): void + { + $target = new tagged('general_example', []); + + // set data + $result = $target->store([ + 'example' => 'data', + ], [ + 'example' => true, + ]); + static::assertTrue($result); + + // get data + $result = $target->getVirtualStoreData(); + static::assertEquals([ + ['example' => 'data'], + ], $result); + + // check finish + try { + $target->finish(); + } catch (Exception) { + static::fail(); + } + + // getStructureResultArray + $result = $target->getStructureResultArray(); + + static::assertCount(1, $result); + static::assertInstanceOf(\codename\core\io\value\structure\tagged::class, $result[0]); + static::assertEquals([ + 'example' => 'data', + ], $result[0]->get() ?? []); + + if (!($result[0] instanceof \codename\core\io\value\structure\tagged)) { + static::fail('setup fail'); + } + + static::assertEquals([ + [ + 'example' => true, + ], + ], $result[0]->getTags()); + } + + /** + * [testWithoutTags description] + * @throws ReflectionException + * @throws \codename\core\exception + */ + public function testWithoutTags(): void + { + $target = new tagged('general_example', []); + + // set data + $result = $target->store([ + 'example' => 'data', + ]); + static::assertTrue($result); + + // get data + $result = $target->getVirtualStoreData(); + static::assertEquals([ + ['example' => 'data'], + ], $result); + + // check finish + try { + $target->finish(); + } catch (Exception) { + static::fail(); + } + + // getStructureResultArray + $result = $target->getStructureResultArray(); + + static::assertCount(1, $result); + static::assertInstanceOf(structure::class, $result[0]); + static::assertEquals([ + 'example' => 'data', + ], $result[0]->get() ?? []); + } } diff --git a/tests/target/arraydataTest.php b/tests/target/arraydataTest.php index 16b43e1..6aed471 100644 --- a/tests/target/arraydataTest.php +++ b/tests/target/arraydataTest.php @@ -1,34 +1,42 @@ store([ - 'example' => 'data' - ]); - $this->assertTrue($result); + // set data + $result = $target->store([ + 'example' => 'data', + ]); + static::assertTrue($result); - // get data - $result = $target->getVirtualStoreData(); - $this->assertEquals([ - [ 'example' => 'data' ] - ], $result); + // get data + $result = $target->getVirtualStoreData(); + static::assertEquals([ + ['example' => 'data'], + ], $result); - // check finish - $this->assertEmpty($target->finish()); - - } + // check finish + try { + $target->finish(); + } catch (Exception) { + static::fail(); + } + static::assertTrue(true); + } } diff --git a/tests/target/buffered/file/CsvBufferingAndSplittingWriteReadTest.php b/tests/target/buffered/file/CsvBufferingAndSplittingWriteReadTest.php index 9b93c01..f8ef3b2 100644 --- a/tests/target/buffered/file/CsvBufferingAndSplittingWriteReadTest.php +++ b/tests/target/buffered/file/CsvBufferingAndSplittingWriteReadTest.php @@ -1,205 +1,219 @@ createdOutputFileCount = null; - } - - /** - * Variable that tracks the created output files count - * @var int|null - */ - protected $createdOutputFileCount = null; - - /** - * [testEqualBufferSizeAndSplitCount description] - */ - public function testEqualBufferSizeAndSplitCount(): void { - $this->testWriteReadTarget([ - 'buffer_size' => 2, - 'split_count' => 2, - ]); - $this->assertEquals(2, $this->createdOutputFileCount); - } - - /** - * [testBufferSizeGreaterThanSplitCount description] - */ - public function testBufferSizeGreaterThanSplitCount(): void { - $this->testWriteReadTarget([ - 'buffer_size' => 3, - 'split_count' => 2, - ]); - $this->assertEquals(2, $this->createdOutputFileCount); - } - - /** - * [testBufferSizeLessThanSplitCount description] - */ - public function testBufferSizeLessThanSplitCount(): void { - $this->testWriteReadTarget([ - 'buffer_size' => 1, - 'split_count' => 2, - ]); - $this->assertEquals(2, $this->createdOutputFileCount); - } - - /** - * Tests buffer_size == split_count == sample count - */ - public function testBufferSizeAndSplitCountEqualsSamplesCount(): void { - $samplesCount = count($this->getSampleData()); - $this->testWriteReadTarget([ - 'buffer_size' => $samplesCount, - 'split_count' => $samplesCount, - ]); - $this->assertEquals(1, $this->createdOutputFileCount); - } - - /** - * Tests buffer_size < split_count, split count equaling the original sample count - */ - public function testBufferSizeLessThanSplitCountWithMultipliedSamples(): void { - $originalSamples = $this->getSampleData(); - $multipliedSamples = array_merge($originalSamples, $originalSamples, $originalSamples); - shuffle($multipliedSamples); - $samplesCount = count($multipliedSamples); - $this->testWriteReadTarget([ - 'buffer_size' => 2, - 'split_count' => 3, - ], $multipliedSamples); - $this->assertEquals(3, $this->createdOutputFileCount); - } - - /** - * Tests buffer_size > split_count, buffer size equaling the original sample count - */ - public function testBufferSizeGreaterThanSplitCountWithMultipliedSamples(): void { - $originalSamples = $this->getSampleData(); - $multipliedSamples = array_merge($originalSamples, $originalSamples, $originalSamples); - shuffle($multipliedSamples); - $samplesCount = count($multipliedSamples); - $this->testWriteReadTarget([ - 'buffer_size' => 3, - 'split_count' => 2, - ], $multipliedSamples); - $this->assertEquals(5, $this->createdOutputFileCount); - } - - /** - * Tests small buffer_size and large split_count, not a multiple of sample count - */ - public function testBufferSizeByFarLessThanSplitCountWithMultipliedSamples(): void { - $originalSamples = $this->getSampleData(); - $multipliedSamples = array_merge($originalSamples, $originalSamples, $originalSamples, $originalSamples, $originalSamples, $originalSamples); - shuffle($multipliedSamples); - $samplesCount = count($multipliedSamples); - $this->testWriteReadTarget([ - 'buffer_size' => 4, - 'split_count' => 10, - ], $multipliedSamples); - $this->assertEquals(2, $this->createdOutputFileCount); - } - - /** - * Tests large buffer_size and lower split_count, not a multiple of sample count - */ - public function testBufferSizeByFarGreaterThanSplitCountWithMultipliedSamples(): void { - $originalSamples = $this->getSampleData(); - $multipliedSamples = array_merge($originalSamples, $originalSamples, $originalSamples, $originalSamples, $originalSamples, $originalSamples); - shuffle($multipliedSamples); - $samplesCount = count($multipliedSamples); - $this->testWriteReadTarget([ - 'buffer_size' => 10, - 'split_count' => 4, - ], $multipliedSamples); - $this->assertEquals(5, $this->createdOutputFileCount); - } - - /** - * Tests implicitly disabling splittting by setting split_count = 0 - * and using a buffer size that is not a multiple of sample count - */ - public function testBufferSizeNoSplittingWithMultipliedSamples(): void { - $originalSamples = $this->getSampleData(); - $multipliedSamples = array_merge($originalSamples, $originalSamples, $originalSamples, $originalSamples, $originalSamples, $originalSamples); - shuffle($multipliedSamples); - $samplesCount = count($multipliedSamples); - $this->testWriteReadTarget([ - 'buffer_size' => 4, - 'split_count' => 0, - ], $multipliedSamples); - $this->assertEquals(1, $this->createdOutputFileCount); - } - - - /** - * @inheritDoc - */ - protected function getWriteReadTargetInstance(array $configOverride = []): \codename\core\io\target - { - // - // We're simply writing a CSV split at 2 items/rows each - // and re-read them using multicsv - // - return new \codename\core\io\target\buffered\file\csv('csv_buffer_and_split', array_replace([ - 'delimiter' => ';', - 'buffer_size' => 2, - 'split_count' => 3, - 'mapping' => [ - 'key1' => [ ], - 'key2' => [ ], - 'key3' => [ ], - 'key4' => [ ], - ] - ], $configOverride)); - } - - /** - * @inheritDoc - */ - protected function readTargetData(\codename\core\io\target $target): array { - $files = $target->getFileResultArray(); - - // TODO: we might assert the file count, somehow - // as splitting is one of the features we're testing here... - - $filepaths = []; - foreach($files as $file) { - $filepaths[] = $file->get(); +class CsvBufferingAndSplittingWriteReadTest extends abstractWriteReadTest +{ + /** + * Variable that tracks the created output files count + * @var int|null + */ + protected ?int $createdOutputFileCount = null; + + /** + * [testEqualBufferSizeAndSplitCount description] + */ + public function testEqualBufferSizeAndSplitCount(): void + { + $this->testWriteReadTarget([ + 'buffer_size' => 2, + 'split_count' => 2, + ]); + static::assertEquals(2, $this->createdOutputFileCount); + } + + /** + * [testBufferSizeGreaterThanSplitCount description] + */ + public function testBufferSizeGreaterThanSplitCount(): void + { + $this->testWriteReadTarget([ + 'buffer_size' => 3, + 'split_count' => 2, + ]); + static::assertEquals(2, $this->createdOutputFileCount); + } + + /** + * [testBufferSizeLessThanSplitCount description] + */ + public function testBufferSizeLessThanSplitCount(): void + { + $this->testWriteReadTarget([ + 'buffer_size' => 1, + 'split_count' => 2, + ]); + static::assertEquals(2, $this->createdOutputFileCount); + } + + /** + * Tests buffer_size == split_count == sample count + */ + public function testBufferSizeAndSplitCountEqualsSamplesCount(): void + { + $samplesCount = count($this->getSampleData()); + $this->testWriteReadTarget([ + 'buffer_size' => $samplesCount, + 'split_count' => $samplesCount, + ]); + static::assertEquals(1, $this->createdOutputFileCount); + } + + /** + * Tests buffer_size < split_count, split count equaling the original sample count + */ + public function testBufferSizeLessThanSplitCountWithMultipliedSamples(): void + { + $originalSamples = $this->getSampleData(); + $multipliedSamples = array_merge($originalSamples, $originalSamples, $originalSamples); + shuffle($multipliedSamples); + $this->testWriteReadTarget([ + 'buffer_size' => 2, + 'split_count' => 3, + ], $multipliedSamples); + static::assertEquals(3, $this->createdOutputFileCount); + } + + /** + * Tests buffer_size > split_count, buffer size equaling the original sample count + */ + public function testBufferSizeGreaterThanSplitCountWithMultipliedSamples(): void + { + $originalSamples = $this->getSampleData(); + $multipliedSamples = array_merge($originalSamples, $originalSamples, $originalSamples); + shuffle($multipliedSamples); + $this->testWriteReadTarget([ + 'buffer_size' => 3, + 'split_count' => 2, + ], $multipliedSamples); + static::assertEquals(5, $this->createdOutputFileCount); + } + + /** + * Tests small buffer_size and large split_count, not a multiple of sample count + */ + public function testBufferSizeByFarLessThanSplitCountWithMultipliedSamples(): void + { + $originalSamples = $this->getSampleData(); + $multipliedSamples = array_merge($originalSamples, $originalSamples, $originalSamples, $originalSamples, $originalSamples, $originalSamples); + shuffle($multipliedSamples); + $this->testWriteReadTarget([ + 'buffer_size' => 4, + 'split_count' => 10, + ], $multipliedSamples); + static::assertEquals(2, $this->createdOutputFileCount); + } + + /** + * Tests large buffer_size and lower split_count, not a multiple of sample count + */ + public function testBufferSizeByFarGreaterThanSplitCountWithMultipliedSamples(): void + { + $originalSamples = $this->getSampleData(); + $multipliedSamples = array_merge($originalSamples, $originalSamples, $originalSamples, $originalSamples, $originalSamples, $originalSamples); + shuffle($multipliedSamples); + $this->testWriteReadTarget([ + 'buffer_size' => 10, + 'split_count' => 4, + ], $multipliedSamples); + static::assertEquals(5, $this->createdOutputFileCount); } - // for asserting amount of output files... - $this->createdOutputFileCount = count($files); + /** + * Tests implicitly disabling splitting by setting split_count = 0 + * and using a buffer size that is not a multiple of sample count + */ + public function testBufferSizeNoSplittingWithMultipliedSamples(): void + { + $originalSamples = $this->getSampleData(); + $multipliedSamples = array_merge($originalSamples, $originalSamples, $originalSamples, $originalSamples, $originalSamples, $originalSamples); + shuffle($multipliedSamples); + $this->testWriteReadTarget([ + 'buffer_size' => 4, + 'split_count' => 0, + ], $multipliedSamples); + static::assertEquals(1, $this->createdOutputFileCount); + } - $datasource = new \codename\core\io\datasource\multicsv($filepaths, [ - 'delimiter' => ';', - 'autodetect_utf8_bom' => true, - ]); - $res = []; - foreach($datasource as $r) { - $res[] = $r; + /** + * {@inheritDoc} + */ + protected function setUp(): void + { + parent::setUp(); + $this->createdOutputFileCount = null; } - return $res; - } - - /** - * @inheritDoc - */ - protected function cleanupTarget(\codename\core\io\target $target): void - { - foreach($target->getFileResultArray() as $file) { - unlink($file->get()); + + /** + * {@inheritDoc} + */ + protected function getWriteReadTargetInstance(array $configOverride = []): target + { + // + // We're simply writing a CSV split at 2 items/rows each + // and re-read them using multicsv + // + return new csv( + 'csv_buffer_and_split', + array_replace([ + 'delimiter' => ';', + 'buffer_size' => 2, + 'split_count' => 3, + 'mapping' => [ + 'key1' => [], + 'key2' => [], + 'key3' => [], + 'key4' => [], + ], + ], $configOverride) + ); } - } + /** + * {@inheritDoc} + * @param target $target + * @return array + * @throws exception + */ + protected function readTargetData(target $target): array + { + $files = $target->getFileResultArray(); + + // TODO: we might assert the file count, somehow + // as splitting is one of the features we're testing here... + + $filepaths = []; + foreach ($files as $file) { + $filepaths[] = $file->get(); + } + + // for asserting amount of output files... + $this->createdOutputFileCount = count($files); + + $datasource = new multicsv($filepaths, [ + 'delimiter' => ';', + 'autodetect_utf8_bom' => true, + ]); + $res = []; + foreach ($datasource as $r) { + $res[] = $r; + } + return $res; + } + + /** + * {@inheritDoc} + */ + protected function cleanupTarget(target $target): void + { + foreach ($target->getFileResultArray() as $file) { + unlink($file->get()); + } + } } diff --git a/tests/target/buffered/file/csvArchivedWriteReadTest.php b/tests/target/buffered/file/csvArchivedWriteReadTest.php index f9f6157..25e10ee 100644 --- a/tests/target/buffered/file/csvArchivedWriteReadTest.php +++ b/tests/target/buffered/file/csvArchivedWriteReadTest.php @@ -1,100 +1,107 @@ 'testarchive', - 'archive_encryption' => true, - 'archive_encryption_type' => 'EM_AES_256', - 'archive_encryption_passphrase' => 'abcd1234', - // NOTE: not-specifying file_name may lead to - // absolute paths being added to the zip archive - 'file_name' => 'test', - ]; - } - /** - * @inheritDoc - */ - protected function getWriteReadTargetInstance(array $configOverride = []): \codename\core\io\target - { - return new \codename\core\io\target\buffered\file\csv('csv_test', [ +class csvArchivedWriteReadTest extends abstractWriteReadTest +{ + /** + * {@inheritDoc} + */ + protected function getSampleTags(): ?array + { + return [ + 'archive_name' => 'testarchive', + 'archive_encryption' => true, + 'archive_encryption_type' => 'EM_AES_256', + 'archive_encryption_passphrase' => 'abcd1234', + // NOTE: not-specifying file_name may lead to + // absolute paths being added to the zip archive + 'file_name' => 'test', + ]; + } - 'delimiter' => ';', - 'config' => [ - 'archive' => true, - ], - 'mapping' => [ - 'key1' => [ ], - 'key2' => [ ], - 'key3' => [ ], - 'key4' => [ ], - ] - ]); - } + /** + * {@inheritDoc} + */ + protected function getWriteReadTargetInstance(array $configOverride = []): target + { + return new target\buffered\file\csv('csv_test', [ - /** - * @inheritDoc - */ - protected function readTargetData(\codename\core\io\target $target): array { - $files = $target->getFileResultArray(); - $this->assertCount(1, $files); - foreach($files as $file) { - $filepath = $file->get(); + 'delimiter' => ';', + 'config' => [ + 'archive' => true, + ], + 'mapping' => [ + 'key1' => [], + 'key2' => [], + 'key3' => [], + 'key4' => [], + ], + ]); + } - // ZIP archive working dir... - $dir = sys_get_temp_dir().'/'.uniqid('tempCsvArchived_').'/'; - mkdir($dir, 0777, true); + /** + * {@inheritDoc} + * @param target $target + * @return array + * @throws exception + */ + protected function readTargetData(target $target): array + { + $files = $target->getFileResultArray(); + static::assertCount(1, $files); + $res = []; + foreach ($files as $file) { + $filepath = $file->get(); - // decrypt/unzip - $zip = new \ZipArchive(); - $zip->open($filepath); - $zip->setPassword('abcd1234'); + // ZIP archive working dir... + $dir = sys_get_temp_dir() . '/' . uniqid('tempCsvArchived_') . '/'; + mkdir($dir, 0777, true); - // make sure there's only a single file - $this->assertEquals(1, $zip->numFiles); + // decrypt/unzip + $zip = new ZipArchive(); + $zip->open($filepath); + $zip->setPassword('abcd1234'); - $files = []; - for ($i=0; $i < $zip->numFiles; $i++) { - $files[] = $zip->getNameIndex($i); - } - $zip->extractTo($dir); + // make sure there's only a single file + static::assertEquals(1, $zip->numFiles); - $extractedCsv = $dir . '/' . $files[0]; - $datasource = new \codename\core\io\datasource\csv($extractedCsv, [ - 'delimiter' => ';', - 'autodetect_utf8_bom' => true, - ]); - $res = []; - foreach($datasource as $r) { - $res[] = $r; - } + $files = []; + for ($i = 0; $i < $zip->numFiles; $i++) { + $files[] = $zip->getNameIndex($i); + } + $zip->extractTo($dir); - // remove temp file - $datasource = null; // dispose datasource to free the filehandle - unlink($extractedCsv); - @rmdir($dir); // remove temp working dir, too. + $extractedCsv = $dir . '/' . $files[0]; + $datasource = new csv($extractedCsv, [ + 'delimiter' => ';', + 'autodetect_utf8_bom' => true, + ]); + foreach ($datasource as $r) { + $res[] = $r; + } - return $res; + // remove temp file + $datasource = null; // dispose datasource to free the file handle + unlink($extractedCsv); + @rmdir($dir); // remove temp working dir, too. + } + return $res; } - } - /** - * @inheritDoc - */ - protected function cleanupTarget(\codename\core\io\target $target): void - { - foreach($target->getFileResultArray() as $file) { - unlink($file->get()); + /** + * {@inheritDoc} + */ + protected function cleanupTarget(target $target): void + { + foreach ($target->getFileResultArray() as $file) { + unlink($file->get()); + } } - } - } diff --git a/tests/target/buffered/file/csvTest.php b/tests/target/buffered/file/csvTest.php index 1e1ddbb..03243dc 100644 --- a/tests/target/buffered/file/csvTest.php +++ b/tests/target/buffered/file/csvTest.php @@ -1,330 +1,342 @@ 'value1', - 'key2' => 2, - 'key3' => 3.1415, - 'key4' => null, - ], - [ - 'key1' => 'value2', - 'key2' => 3, - 'key3' => 4.23446, - 'key4' => null, - ], - [ - 'key1' => 'value3', - 'key2' => 4, - 'key3' => 5.454545, - 'key4' => null, - ], - ]; - } - - /** - * [testEnclosure description] - */ - public function testPartialWriteouts(): void { - - $target = new \codename\core\io\target\buffered\file\csv('csv_test_partial_writeouts', [ - 'delimiter' => ';', - 'buffer_size' => 2, - 'config' => [ - ], - 'mapping' => [ - 'key1' => [ ], - 'key2' => [ ], - 'key3' => [ ], - 'key4' => [ ], - ] - ]); - - $samples = $this->getSampleData(); - foreach($samples as $sample) { - $target->store($sample); - } - $target->finish(); - - $files = $target->getFileResultArray(); - $this->assertCount(1, $files); - - $filepath = $files[0]->get(); - $datasource = new \codename\core\io\datasource\csv($filepath, [ - 'delimiter' => ';', - 'autodetect_utf8_bom' => true, - ]); - $res = []; - foreach($datasource as $r) { - $res[] = $r; + /** + * [testEnclosure description] + * @throws ReflectionException + * @throws exception + */ + public function testPartialWriteouts(): void + { + $target = new csv('csv_test_partial_writeouts', [ + 'delimiter' => ';', + 'buffer_size' => 2, + 'config' => [ + ], + 'mapping' => [ + 'key1' => [], + 'key2' => [], + 'key3' => [], + 'key4' => [], + ], + ]); + + $samples = $this->getSampleData(); + foreach ($samples as $sample) { + $target->store($sample); + } + $target->finish(); + + $files = $target->getFileResultArray(); + static::assertCount(1, $files); + + $filepath = $files[0]->get(); + $datasource = new \codename\core\io\datasource\csv($filepath, [ + 'delimiter' => ';', + 'autodetect_utf8_bom' => true, + ]); + $res = []; + foreach ($datasource as $r) { + $res[] = $r; + } + + unlink($filepath); + + static::assertEquals($samples, $res); } - unlink($filepath); - - $this->assertEquals($samples, $res); - } - - /** - * [testPartialWriteoutsWithSplitting description] - */ - public function testPartialWriteoutsWithSplitting(): void { - - $target = new \codename\core\io\target\buffered\file\csv('csv_test_partial_writeouts', [ - 'delimiter' => ';', - 'buffer_size' => 2, - 'split_count' => 3, - 'config' => [ - ], - 'mapping' => [ - 'key1' => [ ], - 'key2' => [ ], - 'key3' => [ ], - 'key4' => [ ], - ] - ]); - - $samples = $this->getSampleData(); - foreach($samples as $sample) { - $target->store($sample); + /** + * [getSampleData description] + * @return array [description] + */ + protected function getSampleData(): array + { + return [ + [ + 'key1' => 'value1', + 'key2' => 2, + 'key3' => 3.1415, + 'key4' => null, + ], + [ + 'key1' => 'value2', + 'key2' => 3, + 'key3' => 4.23446, + 'key4' => null, + ], + [ + 'key1' => 'value3', + 'key2' => 4, + 'key3' => 5.454545, + 'key4' => null, + ], + ]; } - $target->finish(); - $files = $target->getFileResultArray(); - - $this->assertCount(1, $files); - - $filepath = $files[0]->get(); - $datasource = new \codename\core\io\datasource\csv($filepath, [ - 'delimiter' => ';', - 'autodetect_utf8_bom' => true, - ]); - $res = []; - foreach($datasource as $r) { - $res[] = $r; + /** + * [testPartialWriteoutsWithSplitting description] + * @throws ReflectionException + * @throws exception + */ + public function testPartialWriteoutsWithSplitting(): void + { + $target = new csv('csv_test_partial_writeouts', [ + 'delimiter' => ';', + 'buffer_size' => 2, + 'split_count' => 3, + 'config' => [ + ], + 'mapping' => [ + 'key1' => [], + 'key2' => [], + 'key3' => [], + 'key4' => [], + ], + ]); + + $samples = $this->getSampleData(); + foreach ($samples as $sample) { + $target->store($sample); + } + $target->finish(); + + $files = $target->getFileResultArray(); + + static::assertCount(1, $files); + + $filepath = $files[0]->get(); + $datasource = new \codename\core\io\datasource\csv($filepath, [ + 'delimiter' => ';', + 'autodetect_utf8_bom' => true, + ]); + $res = []; + foreach ($datasource as $r) { + $res[] = $r; + } + + unlink($filepath); + + static::assertEquals($samples, $res); } - unlink($filepath); - - $this->assertEquals($samples, $res); - } - - /** - * [testEnclosure description] - */ - public function testEnclosure(): void { - - $target = new \codename\core\io\target\buffered\file\csv('csv_test', [ - 'delimiter' => ';', - 'enclosure' => null, - 'config' => [ - ], - 'mapping' => [ - 'key1' => [ ], - 'key2' => [ ], - 'key3' => [ ], - 'key4' => [ ], - ] - ]); - - $samples = $this->getSampleData(); - foreach($samples as $sample) { - $target->store($sample); - } - $target->finish(); - - $files = $target->getFileResultArray(); - $this->assertCount(1, $files); - - $filepath = $files[0]->get(); - $datasource = new \codename\core\io\datasource\csv($filepath, [ - 'delimiter' => ';', - 'autodetect_utf8_bom' => true, - ]); - $res = []; - foreach($datasource as $r) { - $res[] = $r; + /** + * [testEnclosure description] + * @throws ReflectionException + * @throws exception + */ + public function testEnclosure(): void + { + $target = new csv('csv_test', [ + 'delimiter' => ';', + 'enclosure' => null, + 'config' => [ + ], + 'mapping' => [ + 'key1' => [], + 'key2' => [], + 'key3' => [], + 'key4' => [], + ], + ]); + + $samples = $this->getSampleData(); + foreach ($samples as $sample) { + $target->store($sample); + } + $target->finish(); + + $files = $target->getFileResultArray(); + static::assertCount(1, $files); + + $filepath = $files[0]->get(); + $datasource = new \codename\core\io\datasource\csv($filepath, [ + 'delimiter' => ';', + 'autodetect_utf8_bom' => true, + ]); + $res = []; + foreach ($datasource as $r) { + $res[] = $r; + } + + unlink($filepath); + + static::assertEquals($samples, $res); } - unlink($filepath); - - $this->assertEquals($samples, $res); - - } - - /** - * [testNumericIndexes description] - */ - public function testNumericIndexes(): void { - - $target = new \codename\core\io\target\buffered\file\csv('csv_test', [ - 'delimiter' => ';', - 'numeric_indexes' => true, - 'numeric_index_start' => 1, - 'config' => [ - ], - 'mapping' => [ - '1' => [ 'column' => 'key1' ], - '2' => [ 'column' => 'key2' ], - '3' => [ 'column' => 'key3' ], - '4' => [ 'column' => 'key4' ], - ] - ]); - - $samples = $this->getSampleData(); - foreach($samples as $sample) { - $target->store($sample); - } - $target->finish(); - - $files = $target->getFileResultArray(); - $this->assertCount(1, $files); - - $filepath = $files[0]->get(); - $datasource = new \codename\core\io\datasource\csv($filepath, [ - 'delimiter' => ';', - 'autodetect_utf8_bom' => true, - ]); - $res = []; - foreach($datasource as $r) { - $res[] = $r; + /** + * [testNumericIndexes description] + * @throws ReflectionException + * @throws exception + */ + public function testNumericIndexes(): void + { + $target = new csv('csv_test', [ + 'delimiter' => ';', + 'numeric_indexes' => true, + 'numeric_index_start' => 1, + 'config' => [ + ], + 'mapping' => [ + '1' => ['column' => 'key1'], + '2' => ['column' => 'key2'], + '3' => ['column' => 'key3'], + '4' => ['column' => 'key4'], + ], + ]); + + $samples = $this->getSampleData(); + foreach ($samples as $sample) { + $target->store($sample); + } + $target->finish(); + + $files = $target->getFileResultArray(); + static::assertCount(1, $files); + + $filepath = $files[0]->get(); + $datasource = new \codename\core\io\datasource\csv($filepath, [ + 'delimiter' => ';', + 'autodetect_utf8_bom' => true, + ]); + $res = []; + foreach ($datasource as $r) { + $res[] = $r; + } + + unlink($filepath); + + static::assertEquals($samples, $res); } - unlink($filepath); - - $this->assertEquals($samples, $res); - - } - - /** - * [testNumericIndexes description] - */ - public function testNumericIndexesInvalidIndex(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_CORE_IO_TARGET_NUMERIC_INDEX_INVALID'); - - $target = new \codename\core\io\target\buffered\file\csv('csv_test', [ - 'delimiter' => ';', - 'numeric_indexes' => true, - 'numeric_index_start' => 0, - 'config' => [ - ], - 'mapping' => [ - '1' => [ 'column' => 'key1' ], - '2' => [ 'column' => 'key2' ], - '3' => [ 'column' => 'key3' ], - '4' => [ 'column' => 'key4' ], - ] - ]); - - $samples = $this->getSampleData(); - foreach($samples as $sample) { - $target->store($sample); - } - $target->finish(); - - $files = $target->getFileResultArray(); - $this->assertCount(1, $files); - - $filepath = $files[0]->get(); - $datasource = new \codename\core\io\datasource\csv($filepath, [ - 'delimiter' => ';', - 'autodetect_utf8_bom' => true, - ]); - $res = []; - foreach($datasource as $r) { - $res[] = $r; + /** + * [testNumericIndexes description] + * @throws ReflectionException + * @throws exception + */ + public function testNumericIndexesInvalidIndex(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('EXCEPTION_CORE_IO_TARGET_NUMERIC_INDEX_INVALID'); + + $target = new csv('csv_test', [ + 'delimiter' => ';', + 'numeric_indexes' => true, + 'numeric_index_start' => 0, + 'config' => [ + ], + 'mapping' => [ + '1' => ['column' => 'key1'], + '2' => ['column' => 'key2'], + '3' => ['column' => 'key3'], + '4' => ['column' => 'key4'], + ], + ]); + + $samples = $this->getSampleData(); + foreach ($samples as $sample) { + $target->store($sample); + } + $target->finish(); + + $files = $target->getFileResultArray(); + static::assertCount(1, $files); + + $filepath = $files[0]->get(); + $datasource = new \codename\core\io\datasource\csv($filepath, [ + 'delimiter' => ';', + 'autodetect_utf8_bom' => true, + ]); + $res = []; + foreach ($datasource as $r) { + $res[] = $r; + } + + unlink($filepath); + + static::assertEquals($samples, $res); } - unlink($filepath); - - $this->assertEquals($samples, $res); - - } - - /** - * [testNumericIndexes description] - */ - public function testNumericIndexesWithoutEnclosure(): void { - - $target = new \codename\core\io\target\buffered\file\csv('csv_test', [ - 'delimiter' => ';', - 'enclosure' => null, - 'numeric_indexes' => true, - 'numeric_index_start' => 1, - 'config' => [ - ], - 'mapping' => [ - '1' => [ 'column' => 'key1' ], - '2' => [ 'column' => 'key2' ], - '3' => [ 'column' => 'key3' ], - '4' => [ 'column' => 'key4' ], - ] - ]); - - $samples = $this->getSampleData(); - foreach($samples as $sample) { - $target->store($sample); - } - $target->finish(); - - $files = $target->getFileResultArray(); - $this->assertCount(1, $files); - - $filepath = $files[0]->get(); - $datasource = new \codename\core\io\datasource\csv($filepath, [ - 'delimiter' => ';', - 'autodetect_utf8_bom' => true, - ]); - $res = []; - foreach($datasource as $r) { - $res[] = $r; + /** + * [testNumericIndexes description] + * @throws ReflectionException + * @throws exception + */ + public function testNumericIndexesWithoutEnclosure(): void + { + $target = new csv('csv_test', [ + 'delimiter' => ';', + 'enclosure' => null, + 'numeric_indexes' => true, + 'numeric_index_start' => 1, + 'config' => [ + ], + 'mapping' => [ + '1' => ['column' => 'key1'], + '2' => ['column' => 'key2'], + '3' => ['column' => 'key3'], + '4' => ['column' => 'key4'], + ], + ]); + + $samples = $this->getSampleData(); + foreach ($samples as $sample) { + $target->store($sample); + } + $target->finish(); + + $files = $target->getFileResultArray(); + static::assertCount(1, $files); + + $filepath = $files[0]->get(); + $datasource = new \codename\core\io\datasource\csv($filepath, [ + 'delimiter' => ';', + 'autodetect_utf8_bom' => true, + ]); + $res = []; + foreach ($datasource as $r) { + $res[] = $r; + } + + unlink($filepath); + + static::assertEquals($samples, $res); } - unlink($filepath); - - $this->assertEquals($samples, $res); - - } - - /** - * [testUnsupportedEncoding description] - */ - public function testUnsupportedEncoding(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_TARGET_BUFFERED_FILE_CSV_UNSUPPORTED_REENCODE'); - - $target = new \codename\core\io\target\buffered\file\csv('csv_test', [ - 'delimiter' => ';', - 'enclosure' => null, - 'encoding' => 'error', - 'config' => [ - ], - 'mapping' => [ - 'key1' => [ ], - 'key2' => [ ], - 'key3' => [ ], - 'key4' => [ ], - ] - ]); - $target->store([ - 'key1' => 'value1', - 'key2' => 2, - 'key3' => 3.1415, - 'key4' => null, - ]); - $target->finish(); - - } - + /** + * [testUnsupportedEncoding description] + */ + public function testUnsupportedEncoding(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('EXCEPTION_TARGET_BUFFERED_FILE_CSV_UNSUPPORTED_REENCODE'); + + $target = new csv('csv_test', [ + 'delimiter' => ';', + 'enclosure' => null, + 'encoding' => 'error', + 'config' => [ + ], + 'mapping' => [ + 'key1' => [], + 'key2' => [], + 'key3' => [], + 'key4' => [], + ], + ]); + $target->store([ + 'key1' => 'value1', + 'key2' => 2, + 'key3' => 3.1415, + 'key4' => null, + ]); + $target->finish(); + } } diff --git a/tests/target/buffered/file/csvWriteReadTest.php b/tests/target/buffered/file/csvWriteReadTest.php index 825fe90..8f593d5 100644 --- a/tests/target/buffered/file/csvWriteReadTest.php +++ b/tests/target/buffered/file/csvWriteReadTest.php @@ -1,54 +1,61 @@ ';', - 'mapping' => [ - 'key1' => [ ], - 'key2' => [ ], - 'key3' => [ ], - 'key4' => [ ], - ] - ]); - } - - /** - * @inheritDoc - */ - protected function readTargetData(\codename\core\io\target $target): array { - $files = $target->getFileResultArray(); - $this->assertCount(1, $files); - foreach($files as $file) { - $filepath = $file->get(); - $datasource = new \codename\core\io\datasource\csv($filepath, [ - 'delimiter' => ';', - 'autodetect_utf8_bom' => true, - ]); - $res = []; - foreach($datasource as $r) { - $res[] = $r; - } - return $res; +class csvWriteReadTest extends abstractWriteReadTest +{ + /** + * {@inheritDoc} + */ + protected function getWriteReadTargetInstance(array $configOverride = []): target + { + return new target\buffered\file\csv('csv_test', [ + 'delimiter' => ';', + 'mapping' => [ + 'key1' => [], + 'key2' => [], + 'key3' => [], + 'key4' => [], + ], + ]); } - } - /** - * @inheritDoc - */ - protected function cleanupTarget(\codename\core\io\target $target): void - { - foreach($target->getFileResultArray() as $file) { - unlink($file->get()); + /** + * {@inheritDoc} + * @param target $target + * @return array + * @throws exception + */ + protected function readTargetData(target $target): array + { + $files = $target->getFileResultArray(); + static::assertCount(1, $files); + $res = []; + foreach ($files as $file) { + $filepath = $file->get(); + $datasource = new csv($filepath, [ + 'delimiter' => ';', + 'autodetect_utf8_bom' => true, + ]); + foreach ($datasource as $r) { + $res[] = $r; + } + } + return $res; } - } + /** + * {@inheritDoc} + */ + protected function cleanupTarget(target $target): void + { + foreach ($target->getFileResultArray() as $file) { + unlink($file->get()); + } + } } diff --git a/tests/target/buffered/file/jsonTest.php b/tests/target/buffered/file/jsonTest.php index ced080e..efc2d33 100644 --- a/tests/target/buffered/file/jsonTest.php +++ b/tests/target/buffered/file/jsonTest.php @@ -1,179 +1,188 @@ 'value1', - 'key2' => '2', - 'key3' => '3.1415', - 'key4' => '' - ], - [ - 'key1' => 'value2', - 'key2' => '3', - 'key3' => '4.2344', - 'key4' => '' - ], - [ - 'key1' => 'value3', - 'key2' => '4', - 'key3' => '5.4545', - 'key4' => '' - ], - ]; - } - - /** - * [testJson description] - */ - public function testJson(): void { - $tags = [ - 'file_name' => 'moep', - ]; - - $target = new \codename\core\io\target\buffered\file\json('json_test', [ - 'encoding' => 'UTF-8', - 'encoding_uft8bom' => false, - 'template_elements_path' => [ 'processes' ], - 'mapping' => [ - 'key1' => [ 'path' => [ 'process' ] ], - 'key2' => [ 'path' => [ 'process' ] ], - 'key3' => [ 'path' => [ 'process' ] ], - 'key4' => [ 'path' => [ 'process' ] ], - ], - 'tags' => $tags, - ]); - - $samples = $this->getSampleData(); - foreach($samples as $sample) { - $target->store($sample, $tags); + /** + * [testJson description] + * @throws ReflectionException + * @throws exception + */ + public function testJson(): void + { + $tags = [ + 'file_name' => 'moep', + ]; + + $target = new \codename\core\io\target\buffered\file\json('json_test', [ + 'encoding' => 'UTF-8', + 'encoding_uft8bom' => false, + 'template_elements_path' => ['processes'], + 'mapping' => [ + 'key1' => ['path' => ['process']], + 'key2' => ['path' => ['process']], + 'key3' => ['path' => ['process']], + 'key4' => ['path' => ['process']], + ], + 'tags' => $tags, + ]); + + $samples = $this->getSampleData(); + foreach ($samples as $sample) { + $target->store($sample, $tags); + } + $target->finish(); + + $files = $target->getFileResultArray(); + static::assertCount(1, $files); + + $res = []; + foreach ($files as $file) { + $filepath = $file->get(); + + $data = (new json($filepath))->get(); + + foreach ($data['processes'] as $r) { + $res[] = $r['process'] ?? []; + } + + unlink($filepath); + } + + static::assertEquals($samples, $res); } - $target->finish(); - - $files = $target->getFileResultArray(); - $this->assertCount(1, $files); - - $res = []; - foreach($files as $file) { - $filepath = $file->get(); - $data = (new \codename\core\config\json($filepath))->get(); - - foreach($data['processes'] as $r) { - $res[] = $r['process'] ?? []; - } - - unlink($filepath); + /** + * [getSampleData description] + * @return array [description] + */ + protected function getSampleData(): array + { + return [ + [ + 'key1' => 'value1', + 'key2' => '2', + 'key3' => '3.1415', + 'key4' => '', + ], + [ + 'key1' => 'value2', + 'key2' => '3', + 'key3' => '4.2344', + 'key4' => '', + ], + [ + 'key1' => 'value3', + 'key2' => '4', + 'key3' => '5.4545', + 'key4' => '', + ], + ]; } - $this->assertEquals($samples, $res); - - } - - /** - * [testJson description] - */ - public function testJsonWithSplitCount(): void { - $tags = [ - 'file_name' => 'moep', - ]; - - $target = new \codename\core\io\target\buffered\file\json('json_test', [ - 'encoding' => 'UTF-8', - 'encoding_uft8bom' => false, - 'split_count' => 2, - 'mapping' => [ - 'key1' => [ 'path' => [ 'process' ] ], - 'key2' => [ 'path' => [ 'process' ] ], - 'key3' => [ 'path' => [ 'process' ] ], - 'key4' => [ 'path' => [ 'process' ] ], - ], - 'tags' => $tags, - ]); - - $samples = $this->getSampleData(); - foreach($samples as $sample) { - $target->store($sample, $tags); + /** + * [testJson description] + * @throws ReflectionException + * @throws exception + */ + public function testJsonWithSplitCount(): void + { + $tags = [ + 'file_name' => 'moep', + ]; + + $target = new \codename\core\io\target\buffered\file\json('json_test', [ + 'encoding' => 'UTF-8', + 'encoding_uft8bom' => false, + 'split_count' => 2, + 'mapping' => [ + 'key1' => ['path' => ['process']], + 'key2' => ['path' => ['process']], + 'key3' => ['path' => ['process']], + 'key4' => ['path' => ['process']], + ], + 'tags' => $tags, + ]); + + $samples = $this->getSampleData(); + foreach ($samples as $sample) { + $target->store($sample, $tags); + } + $target->finish(); + + $files = $target->getFileResultArray(); + static::assertCount(2, $files); + + $res = []; + foreach ($files as $file) { + $filepath = $file->get(); + + $data = (new json($filepath))->get(); + + foreach ($data as $r) { + $res[] = $r['process'] ?? $r; + } + + unlink($filepath); + } + + static::assertEquals($samples, $res); } - $target->finish(); - - $files = $target->getFileResultArray(); - $this->assertCount(2, $files); - - $res = []; - foreach($files as $file) { - $filepath = $file->get(); - $data = (new \codename\core\config\json($filepath))->get(); - - foreach($data as $r) { - $res[] = $r['process'] ?? $r; - } - - unlink($filepath); - } - - $this->assertEquals($samples, $res); - - } - - /** - * [testJsonWithTemplate description] - */ - public function testJsonWithTemplate(): void { - $tags = [ - 'file_name' => 'moep', - ]; - - $target = new \codename\core\io\target\buffered\file\json('json_test', [ - 'encoding' => 'UTF-8', - 'encoding_uft8bom' => false, - 'template' => [ - 'process' => [ - - ] - ], - 'split_count' => 1, - 'mapping' => [ - 'process' => [ ], - ], - 'tags' => $tags, - ]); - - $samples = $this->getSampleData(); - $target->store([ - 'process' => $samples[0] - ], $tags); - $target->finish(); - - $files = $target->getFileResultArray(); - $this->assertCount(1, $files); - - $res = []; - foreach($files as $file) { - $filepath = $file->get(); - - $data = (new \codename\core\config\json($filepath))->get(); - - foreach($data as $r) { - $res[] = $r; - } - - unlink($filepath); + /** + * [testJsonWithTemplate description] + * @throws ReflectionException + * @throws exception + */ + public function testJsonWithTemplate(): void + { + $tags = [ + 'file_name' => 'moep', + ]; + + $target = new \codename\core\io\target\buffered\file\json('json_test', [ + 'encoding' => 'UTF-8', + 'encoding_uft8bom' => false, + 'template' => [ + 'process' => [ + + ], + ], + 'split_count' => 1, + 'mapping' => [ + 'process' => [], + ], + 'tags' => $tags, + ]); + + $samples = $this->getSampleData(); + $target->store([ + 'process' => $samples[0], + ], $tags); + $target->finish(); + + $files = $target->getFileResultArray(); + static::assertCount(1, $files); + + $res = []; + foreach ($files as $file) { + $filepath = $file->get(); + + $data = (new json($filepath))->get(); + + foreach ($data as $r) { + $res[] = $r; + } + + unlink($filepath); + } + + static::assertEquals($samples[0], $res[0]); } - - $this->assertEquals($samples[0], $res[0]); - - } - } diff --git a/tests/target/buffered/file/multicsvWriteReadTest.php b/tests/target/buffered/file/multicsvWriteReadTest.php index c60d497..cae27a3 100644 --- a/tests/target/buffered/file/multicsvWriteReadTest.php +++ b/tests/target/buffered/file/multicsvWriteReadTest.php @@ -1,60 +1,68 @@ ';', - 'split_count' => 2, - 'mapping' => [ - 'key1' => [ ], - 'key2' => [ ], - 'key3' => [ ], - 'key4' => [ ], - ] - ]); - } - - /** - * @inheritDoc - */ - protected function readTargetData(\codename\core\io\target $target): array { - $files = $target->getFileResultArray(); - $this->assertCount(2, $files); - $filepaths = []; - foreach($files as $file) { - $filepaths[] = $file->get(); +class multicsvWriteReadTest extends abstractWriteReadTest +{ + /** + * {@inheritDoc} + */ + protected function getWriteReadTargetInstance(array $configOverride = []): target + { + // + // We're simply writing a CSV split at 2 items/rows each + // and re-read them using multicsv + // + return new csv('csv_test', [ + 'delimiter' => ';', + 'split_count' => 2, + 'mapping' => [ + 'key1' => [], + 'key2' => [], + 'key3' => [], + 'key4' => [], + ], + ]); } - $datasource = new \codename\core\io\datasource\multicsv($filepaths, [ - 'delimiter' => ';', - 'autodetect_utf8_bom' => true, - ]); - $res = []; - foreach($datasource as $r) { - $res[] = $r; - } - return $res; - } - /** - * @inheritDoc - */ - protected function cleanupTarget(\codename\core\io\target $target): void - { - foreach($target->getFileResultArray() as $file) { - unlink($file->get()); + /** + * {@inheritDoc} + * @param target $target + * @return array + * @throws exception + */ + protected function readTargetData(target $target): array + { + $files = $target->getFileResultArray(); + static::assertCount(2, $files); + $filepaths = []; + foreach ($files as $file) { + $filepaths[] = $file->get(); + } + $datasource = new multicsv($filepaths, [ + 'delimiter' => ';', + 'autodetect_utf8_bom' => true, + ]); + $res = []; + foreach ($datasource as $r) { + $res[] = $r; + } + return $res; } - } + /** + * {@inheritDoc} + */ + protected function cleanupTarget(target $target): void + { + foreach ($target->getFileResultArray() as $file) { + unlink($file->get()); + } + } } diff --git a/tests/target/buffered/file/parquetBufferedWriteReadTest.php b/tests/target/buffered/file/parquetBufferedWriteReadTest.php index 02f85ff..d1fded9 100644 --- a/tests/target/buffered/file/parquetBufferedWriteReadTest.php +++ b/tests/target/buffered/file/parquetBufferedWriteReadTest.php @@ -1,124 +1,154 @@ testWriteReadTarget([ - 'compression' => 'none', - ]); - } - - /** - * [testAutoGuessTypes description] - */ - public function testAutoGuessTypes(): void { - $this->testWriteReadTarget([ - 'mapping' => [ - 'key1' => [ ], - 'key2' => [ ], - 'key3' => [ ], - 'key4' => [ 'php_type' => 'string', ], // having only null items can't be type-guessed - ] - ]); - } - - /** - * [testCompressionGzip description] - */ - public function testCompressionGzip(): void { - $this->testWriteReadTarget([ - 'compression' => 'gzip', - ]); - } +class parquetBufferedWriteReadTest extends abstractWriteReadTest +{ + /** + * [testCompressionNone description] + */ + public function testCompressionNone(): void + { + $this->testWriteReadTarget([ + 'compression' => 'none', + ]); + } - /** - * Special test with an overridden target class - * to allow empty data pages/RGs to be written in-between - */ - public function testEmptyDataPagesInbetween(): void { - $target = new overriddenParquetTarget('parquet_empty_data_pages_test', [ - 'buffer' => true, - 'buffer_size' => 2, - 'mapping' => [ - 'key1' => [ 'php_type' => 'string' ], - 'key2' => [ 'php_type' => 'integer' ], - 'key3' => [ 'php_type' => 'double' ], - 'key4' => [ 'php_type' => 'string', 'is_nullable' => true ], - ] - ]); - $samples = $this->getSampleData(); - $tags = $this->getSampleTags(); - foreach($samples as $sample) { - $target->publicWriteData([]); - $target->store($sample, $tags); - $target->publicWriteData([]); + /** + * [testAutoGuessTypes description] + */ + public function testAutoGuessTypes(): void + { + $this->testWriteReadTarget([ + 'mapping' => [ + 'key1' => [], + 'key2' => [], + 'key3' => [], + 'key4' => ['php_type' => 'string',], // having only null items can't be type-guessed + ], + ]); } - $target->finish(); - $this->compareData($target, $samples); - $this->cleanupTarget($target); - } - /** - * @inheritDoc - */ - protected function getWriteReadTargetInstance(array $configOverride = []): \codename\core\io\target - { - return new \codename\core\io\target\buffered\file\parquet('parquet_test', array_replace([ - 'buffer' => true, - 'buffer_size' => 2, - 'mapping' => [ - 'key1' => [ 'php_type' => 'string' ], - 'key2' => [ 'php_type' => 'integer' ], - 'key3' => [ 'php_type' => 'double' ], - 'key4' => [ 'php_type' => 'string', 'is_nullable' => true ], - ] - ], $configOverride)); - } + /** + * [testCompressionGzip description] + */ + public function testCompressionGzip(): void + { + $this->testWriteReadTarget([ + 'compression' => 'gzip', + ]); + } - /** - * @inheritDoc - */ - protected function readTargetData(\codename\core\io\target $target): array { - $files = $target->getFileResultArray(); - $this->assertCount(1, $files); - foreach($files as $file) { - $filepath = $file->get(); - $datasource = new \codename\core\io\datasource\parquet($filepath); + /** + * Special test with an overridden target class + * to allow empty data pages/RGs to be written in-between + * @throws ArgumentNullException + * @throws NotSupportedException + * @throws ParquetException + * @throws exception + */ + public function testEmptyDataPagesInbetween(): void + { + $target = new overriddenParquetTarget('parquet_empty_data_pages_test', [ + 'buffer' => true, + 'buffer_size' => 2, + 'mapping' => [ + 'key1' => ['php_type' => 'string'], + 'key2' => ['php_type' => 'integer'], + 'key3' => ['php_type' => 'double'], + 'key4' => ['php_type' => 'string', 'is_nullable' => true], + ], + ]); + $samples = $this->getSampleData(); + $tags = $this->getSampleTags(); + foreach ($samples as $sample) { + $target->publicWriteData([]); + $target->store($sample, $tags); + $target->publicWriteData([]); + } + $target->finish(); + $this->compareData($target, $samples); + $this->cleanupTarget($target); + } - $res = []; - foreach($datasource as $r) { - $res[] = $r; - } - return $res; + /** + * {@inheritDoc} + */ + protected function cleanupTarget(target $target): void + { + foreach ($target->getFileResultArray() as $file) { + unlink($file->get()); + } } - } - /** - * @inheritDoc - */ - protected function cleanupTarget(\codename\core\io\target $target): void - { - foreach($target->getFileResultArray() as $file) { - unlink($file->get()); + /** + * {@inheritDoc} + * @param array $configOverride + * @return target + * @throws \Exception + */ + protected function getWriteReadTargetInstance(array $configOverride = []): target + { + return new parquet( + 'parquet_test', + array_replace([ + 'buffer' => true, + 'buffer_size' => 2, + 'mapping' => [ + 'key1' => ['php_type' => 'string'], + 'key2' => ['php_type' => 'integer'], + 'key3' => ['php_type' => 'double'], + 'key4' => ['php_type' => 'string', 'is_nullable' => true], + ], + ], $configOverride) + ); } - } + /** + * {@inheritDoc} + * @param target $target + * @return array + * @throws exception + */ + protected function readTargetData(target $target): array + { + $files = $target->getFileResultArray(); + static::assertCount(1, $files); + $res = []; + foreach ($files as $file) { + $filepath = $file->get(); + $datasource = new \codename\core\io\datasource\parquet($filepath); + + foreach ($datasource as $r) { + $res[] = $r; + } + } + return $res; + } } -class overriddenParquetTarget extends \codename\core\io\target\buffered\file\parquet { - /** - * public access to ::writeData for simulating special kinds - * of parquet files (e.g. writing empty RGs/data pages) - * @param array $data [description] - * @return void - */ - public function publicWriteData(array $data): void { - $this->writeData($data); - } +class overriddenParquetTarget extends parquet +{ + /** + * public access to ::writeData for simulating special kinds + * of parquet files (e.g. writing empty RGs/data pages) + * @param array $data [description] + * @return void + * @throws ParquetException + * @throws ArgumentNullException + * @throws NotSupportedException + * @throws exception + */ + public function publicWriteData(array $data): void + { + $this->writeData($data); + } } diff --git a/tests/target/buffered/file/parquetTest.php b/tests/target/buffered/file/parquetTest.php index dfea70c..dd657d5 100644 --- a/tests/target/buffered/file/parquetTest.php +++ b/tests/target/buffered/file/parquetTest.php @@ -1,62 +1,73 @@ 'value1', - 'key2' => 2, - 'key3' => 3.1415, - 'key4' => null, - ], - [ - 'key1' => 'value2', - 'key2' => 3, - 'key3' => 4.23446, - 'key4' => null, - ], - [ - 'key1' => 'value3', - 'key2' => 4, - 'key3' => 5.454545, - 'key4' => null, - ], - ]; - - $target = new \codename\core\io\target\buffered\file\parquet('parquet_test', [ - 'mapping' => [ - 'key1' => [ 'php_type' => 'string' ], - 'key2' => [ 'php_type' => 'integer' ], - 'key3' => [ 'php_type' => 'double' ], - 'key4' => [ 'php_type' => 'string', 'is_nullable' => true ], - ] - ]); - - foreach($samples as $sample) { - $target->store($sample); - } +class parquetTest extends base +{ + /** + * [testWriteReadParquet description] + * @throws ReflectionException + * @throws ParquetException + * @throws ArgumentNullException + * @throws NotSupportedException + * @throws exception + */ + public function testWriteReadParquet(): void + { + $samples = [ + [ + 'key1' => 'value1', + 'key2' => 2, + 'key3' => 3.1415, + 'key4' => null, + ], + [ + 'key1' => 'value2', + 'key2' => 3, + 'key3' => 4.23446, + 'key4' => null, + ], + [ + 'key1' => 'value3', + 'key2' => 4, + 'key3' => 5.454545, + 'key4' => null, + ], + ]; - $target->finish(); + $target = new \codename\core\io\target\buffered\file\parquet('parquet_test', [ + 'mapping' => [ + 'key1' => ['php_type' => 'string'], + 'key2' => ['php_type' => 'integer'], + 'key3' => ['php_type' => 'double'], + 'key4' => ['php_type' => 'string', 'is_nullable' => true], + ], + ]); - foreach($target->getFileResultArray() as $file) { - $filepath = $file->get(); - $datasource = new \codename\core\io\datasource\parquet($filepath); + foreach ($samples as $sample) { + $target->store($sample); + } - $res = []; - foreach($datasource as $r) { - $res[] = $r; - } - $this->assertEquals($samples, $res); - unlink($filepath); - } - } + $target->finish(); + foreach ($target->getFileResultArray() as $file) { + $filepath = $file->get(); + $datasource = new parquet($filepath); + + $res = []; + foreach ($datasource as $r) { + $res[] = $r; + } + static::assertEquals($samples, $res); + unlink($filepath); + } + } } diff --git a/tests/target/buffered/file/parquetWriteReadTest.php b/tests/target/buffered/file/parquetWriteReadTest.php index 5ca147a..491423b 100644 --- a/tests/target/buffered/file/parquetWriteReadTest.php +++ b/tests/target/buffered/file/parquetWriteReadTest.php @@ -1,199 +1,216 @@ addWarning('GMP extension required for working with arbitrary precision numbers in Parquet.'); - return; + $this->testWriteReadTarget([ + 'mapping' => [ + 'key_string' => [], + 'key_string_nullable' => [], + 'key_integer' => [], + 'key_integer_nullable' => [], + 'key_bool' => [], + 'key_bool_nullable' => [], + 'key_float' => [], + 'key_double_nullable' => [], + 'key_datetime' => [], + 'key_datetime_nullable' => [], + ], + ], [ + [ + 'key_string' => 'abc', + 'key_string_nullable' => 'abc', + 'key_integer' => 123, + 'key_integer_nullable' => 123, + 'key_bool' => true, + 'key_bool_nullable' => true, + 'key_float' => 1.23, + 'key_double_nullable' => 1.2386768767676, + 'key_datetime' => new DateTimeImmutable('now'), + 'key_datetime_nullable' => new DateTimeImmutable('now'), + ], + [ + 'key_string' => 'def', + 'key_string_nullable' => null, + 'key_integer' => 123, + 'key_integer_nullable' => null, + 'key_bool' => false, + 'key_bool_nullable' => null, + 'key_float' => 2.34, + 'key_double_nullable' => 2.3465656565656, + 'key_datetime' => new DateTimeImmutable('now'), + 'key_datetime_nullable' => null, + ], + [ + 'key_string' => 'ghi', + 'key_string_nullable' => 'ghi', + 'key_integer' => 234, + 'key_integer_nullable' => 2, + 'key_bool' => true, + 'key_bool_nullable' => true, + 'key_float' => 3.45, + 'key_double_nullable' => null, + 'key_datetime' => new DateTimeImmutable('now'), + 'key_datetime_nullable' => new DateTimeImmutable('now'), + ], + ]); } - $this->testWriteReadTarget([ - 'mapping' => [ - 'key_string' => [ ], - 'key_string_nullable' => [ ], - 'key_integer' => [ ], - 'key_integer_nullable' => [ ], - 'key_bool' => [ ], - 'key_bool_nullable' => [ ], - 'key_float' => [ ], - 'key_double_nullable' => [ ], - 'key_datetime' => [ ], - 'key_datetime_nullable' => [ ], - ] - ], [ - [ - 'key_string' => 'abc', - 'key_string_nullable' => 'abc', - 'key_integer' => 123, - 'key_integer_nullable' => 123, - 'key_bool' => true, - 'key_bool_nullable' => true, - 'key_float' => 1.23, - 'key_double_nullable' => 1.2386768767676, - 'key_datetime' => new \DateTimeImmutable('now'), - 'key_datetime_nullable' => new \DateTimeImmutable('now'), - ], - [ - 'key_string' => 'def', - 'key_string_nullable' => null, - 'key_integer' => 123, - 'key_integer_nullable' => null, - 'key_bool' => false, - 'key_bool_nullable' => null, - 'key_float' => 2.34, - 'key_double_nullable' => 2.3465656565656, - 'key_datetime' => new \DateTimeImmutable('now'), - 'key_datetime_nullable' => null, - ], - [ - 'key_string' => 'ghi', - 'key_string_nullable' => 'ghi', - 'key_integer' => 234, - 'key_integer_nullable' => 2, - 'key_bool' => true, - 'key_bool_nullable' => true, - 'key_float' => 3.45, - 'key_double_nullable' => null, - 'key_datetime' => new \DateTimeImmutable('now'), - 'key_datetime_nullable' => new \DateTimeImmutable('now'), - ] - ]); - } - - /** - * [testOtherDatatypesUsingAutoguessFailByNotUniqueTypes description] - */ - public function testOtherDatatypesUsingAutoguessFailByNotUniqueTypes(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('NOT UNIQUE TYPES'); - $this->testWriteReadTarget([ - 'mapping' => [ - 'key_string' => [ ], - 'key_integer_nullable' => [ ], - 'key_datetime' => [ ], - 'key_datetime_nullable' => [ ], - ] - ], [ - [ - 'key_string' => 'abc', - 'key_integer_nullable' => 123, - 'key_datetime' => new \DateTimeImmutable('now'), - ], - [ - 'key_string' => 'def', - 'key_integer_nullable' => null, - 'key_datetime' => new \DateTimeImmutable('now'), - ], - [ - 'key_string' => 333, // NOTE: suddenly provide a non-string, but instead integer value - 'key_integer_nullable' => 123, - 'key_datetime' => new \DateTimeImmutable('now'), - ] - ]); - } - - /** - * [testExtraExplicitDatatypes description] - */ - public function testExtraExplicitDatatypes(): void { - $this->testWriteReadTarget([ - 'mapping' => [ - 'key_datetime' => [ 'php_class' => \DateTimeImmutable::class, 'is_nullable' => true, 'datetime_format' => 'Y-m-d H:i:s', ], - 'key_decimal' => [ 'php_type' => 'decimal', 'is_nullable' => true, 'precision' => 24, 'scale' => 16 ], - ] - ], [ - [ - 'key_decimal' => '0.000000022122', - 'key_datetime' => new \DateTimeImmutable('now'), - ], - [ - 'key_decimal' => '1231234.442424242', - 'key_datetime' => null, - ], - [ - 'key_decimal' => null, - 'key_datetime' => new \DateTimeImmutable('now'), - ] - ]); - } - - /** - * @inheritDoc - */ - protected function compareData( - \codename\core\io\target $target, - array $samples - ): void { - $result = $this->readTargetData($target); - $this->assertCount(count($samples), $result); + /** + * [testOtherDatatypesUsingAutoguessFailByNotUniqueTypes description] + */ + public function testOtherDatatypesUsingAutoguessFailByNotUniqueTypes(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('NOT UNIQUE TYPES'); + $this->testWriteReadTarget([ + 'mapping' => [ + 'key_string' => [], + 'key_integer_nullable' => [], + 'key_datetime' => [], + 'key_datetime_nullable' => [], + ], + ], [ + [ + 'key_string' => 'abc', + 'key_integer_nullable' => 123, + 'key_datetime' => new DateTimeImmutable('now'), + ], + [ + 'key_string' => 'def', + 'key_integer_nullable' => null, + 'key_datetime' => new DateTimeImmutable('now'), + ], + [ + 'key_string' => 333, // NOTE: suddenly provide a non-string, but instead integer value + 'key_integer_nullable' => 123, + 'key_datetime' => new DateTimeImmutable('now'), + ], + ]); + } - // We're overriding the regular comparison method - // to allow hooking into decimal comparisons, - // where we need additional precision parameters - foreach($samples as $index => $sample) { - $resultRow = $result[$index]; + /** + * [testExtraExplicitDatatypes description] + */ + public function testExtraExplicitDatatypes(): void + { + $this->testWriteReadTarget([ + 'mapping' => [ + 'key_datetime' => ['php_class' => DateTimeImmutable::class, 'is_nullable' => true, 'datetime_format' => 'Y-m-d H:i:s',], + 'key_decimal' => ['php_type' => 'decimal', 'is_nullable' => true, 'precision' => 24, 'scale' => 16], + ], + ], [ + [ + 'key_decimal' => '0.000000022122', + 'key_datetime' => new DateTimeImmutable('now'), + ], + [ + 'key_decimal' => '1231234.442424242', + 'key_datetime' => null, + ], + [ + 'key_decimal' => null, + 'key_datetime' => new DateTimeImmutable('now'), + ], + ]); + } - foreach($sample as $key => $value) { - if(is_numeric($value) && is_string($value)) { - // delta comparison of decimals - $this->assertEquals(0, bccomp($value, $resultRow[$key]), 24); - } else { - $this->assertEquals($value, $resultRow[$key]); + /** + * {@inheritDoc} + * @param target $target + * @param array $samples + * @throws exception + */ + protected function compareData( + target $target, + array $samples + ): void { + $result = $this->readTargetData($target); + static::assertCount(count($samples), $result); + + // We're overriding the regular comparison method + // to allow hooking into decimal comparisons, + // where we need additional precision parameters + foreach ($samples as $index => $sample) { + $resultRow = $result[$index]; + + foreach ($sample as $key => $value) { + if (is_numeric($value) && is_string($value)) { + // delta comparison of decimals + static::assertEquals(0, bccomp($value, $resultRow[$key]), 24); + } else { + static::assertEquals($value, $resultRow[$key]); + } + } } - } } - } - - /** - * @inheritDoc - */ - protected function getWriteReadTargetInstance(array $configOverride = []): \codename\core\io\target - { - return new \codename\core\io\target\buffered\file\parquet('parquet_test', array_replace([ - 'mapping' => [ - 'key1' => [ 'php_type' => 'string' ], - 'key2' => [ 'php_type' => 'integer' ], - 'key3' => [ 'php_type' => 'double' ], - 'key4' => [ 'php_type' => 'string', 'is_nullable' => true ], - ] - ], $configOverride)); - } - - /** - * @inheritDoc - */ - protected function readTargetData(\codename\core\io\target $target): array { - $files = $target->getFileResultArray(); - $this->assertCount(1, $files); - foreach($files as $file) { - $filepath = $file->get(); - $datasource = new \codename\core\io\datasource\parquet($filepath); - - $res = []; - foreach($datasource as $r) { - $res[] = $r; - } - return $res; + /** + * {@inheritDoc} + * @param target $target + * @return array + * @throws exception + */ + protected function readTargetData(target $target): array + { + $files = $target->getFileResultArray(); + static::assertCount(1, $files); + $res = []; + foreach ($files as $file) { + $filepath = $file->get(); + $datasource = new \codename\core\io\datasource\parquet($filepath); + + foreach ($datasource as $r) { + $res[] = $r; + } + } + return $res; } - } - /** - * @inheritDoc - */ - protected function cleanupTarget(\codename\core\io\target $target): void - { - foreach($target->getFileResultArray() as $file) { - unlink($file->get()); + /** + * {@inheritDoc} + * @param array $configOverride + * @return target + * @throws \Exception + */ + protected function getWriteReadTargetInstance(array $configOverride = []): target + { + return new parquet( + 'parquet_test', + array_replace([ + 'mapping' => [ + 'key1' => ['php_type' => 'string'], + 'key2' => ['php_type' => 'integer'], + 'key3' => ['php_type' => 'double'], + 'key4' => ['php_type' => 'string', 'is_nullable' => true], + ], + ], $configOverride) + ); } - } + /** + * {@inheritDoc} + */ + protected function cleanupTarget(target $target): void + { + foreach ($target->getFileResultArray() as $file) { + unlink($file->get()); + } + } } diff --git a/tests/target/buffered/file/rawTest.php b/tests/target/buffered/file/rawTest.php index 8123853..542aeb8 100644 --- a/tests/target/buffered/file/rawTest.php +++ b/tests/target/buffered/file/rawTest.php @@ -1,160 +1,167 @@ 'codename', - 'app' => 'core-io', - 'namespace' => '\\codename\\core\\io' - ]); - - $app = static::createApp(); - - $app->__setApp('targetbufferedfiletest'); - $app->__setVendor('codename'); - $app->__setNamespace('\\codename\\core\\io\\target\\buffered\\file'); - - $app->getAppstack(); - } - - /** - * [getSampleData description] - * @return array [description] - */ - protected function getSampleData(): array { - return [ - [ - 'key1' => 'value1', - 'key2' => '2', - 'key3' => '3.1415', - 'key4' => '' - ], - [ - 'key1' => 'value2', - 'key2' => '3', - 'key3' => '4.2344', - 'key4' => '' - ], - [ - 'key1' => 'value3', - 'key2' => '4', - 'key3' => '5.4545', - 'key4' => '' - ], - ]; - } - - /** - * [testWrongPaddingMode description] - */ - public function testWrongPaddingMode(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_TARGET_BUFFERED_FILE_RAW_PADDING_MODE_NOT_SUPPORTED'); - - $target = new \codename\core\io\target\buffered\file\raw('raw_test', [ - 'padding_string' => ' ', - 'padding_mode' => 'wrong', - 'mapping' => [ - 'key1' => [ 'rowIndex' => 0, 'columnIndex' => 0, 'length' => 10 ], - 'key2' => [ 'rowIndex' => 0, 'columnIndex' => 1, 'length' => 10 ], - 'key3' => [ 'rowIndex' => 0, 'columnIndex' => 2, 'length' => 10 ], - 'key4' => [ 'rowIndex' => 0, 'columnIndex' => 3, 'length' => 10 ], - ] - ]); - - } - - /** - * [testValueTooLong description] - */ - public function testValueTooLong(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_TARGET_BUFFERED_FILE_RAW_VALUE_TOO_LONG'); - - $target = new \codename\core\io\target\buffered\file\raw('raw_test', [ - 'padding_string' => ' ', - 'padding_mode' => 'right', - 'mapping' => [ - 'key1' => [ 'rowIndex' => 0, 'columnIndex' => 0, 'length' => 10 ], - 'key2' => [ 'rowIndex' => 0, 'columnIndex' => 1, 'length' => 10 ], - 'key3' => [ 'rowIndex' => 0, 'columnIndex' => 2, 'length' => 10 ], - 'key4' => [ 'rowIndex' => 0, 'columnIndex' => 3, 'length' => 10 ], - ] - ]); - - $samples = $this->getSampleData(); - foreach($samples as $sample) { - $sample['key1'] = 'valuetoolong'; - $target->store($sample); - break; - } - $target->finish(); - - } - - /** - * [testPaddingRight description] - */ - public function testPaddingRight(): void { - - $target = new \codename\core\io\target\buffered\file\raw('raw_test', [ - 'padding_string' => ' ', - 'padding_mode' => 'right', - 'encoding' => 'UTF-8', - 'truncate' => true, - 'split_count' => 2, - 'mapping' => [ - 'key1' => [ 'rowIndex' => 0, 'columnIndex' => 0, 'length' => 10 ], - 'key2' => [ 'rowIndex' => 0, 'columnIndex' => 1, 'length' => 10 ], - 'key3' => [ 'rowIndex' => 0, 'columnIndex' => 2, 'length' => 10 ], - 'key4' => [ 'rowIndex' => 0, 'columnIndex' => 3, 'length' => 10 ], - ] - ]); - - $samples = $this->getSampleData(); - foreach($samples as $sample) { - $target->store($sample); - } - $target->finish(); - - - $files = $target->getFileResultArray(); - $this->assertCount(2, $files); - - $res = []; - foreach($files as $file) { - $filepath = $file->get(); - $datasource = new \codename\core\io\datasource\raw($filepath, [ - 'format' => [ - 'trim' => true, - 'map' => [ - 'key1' => [ 'type' => 'fixed', 'length' => 10 ], - 'key2' => [ 'type' => 'fixed', 'length' => 10 ], - 'key3' => [ 'type' => 'fixed', 'length' => 10 ], - 'key4' => [ 'type' => 'fixed', 'length' => 10 ], + /** + * [testWrongPaddingMode description] + */ + public function testWrongPaddingMode(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('EXCEPTION_TARGET_BUFFERED_FILE_RAW_PADDING_MODE_NOT_SUPPORTED'); + + new \codename\core\io\target\buffered\file\raw('raw_test', [ + 'padding_string' => ' ', + 'padding_mode' => 'wrong', + 'mapping' => [ + 'key1' => ['rowIndex' => 0, 'columnIndex' => 0, 'length' => 10], + 'key2' => ['rowIndex' => 0, 'columnIndex' => 1, 'length' => 10], + 'key3' => ['rowIndex' => 0, 'columnIndex' => 2, 'length' => 10], + 'key4' => ['rowIndex' => 0, 'columnIndex' => 3, 'length' => 10], ], - ], - ]); - - foreach($datasource as $r) { - $res[] = $r; - } + ]); + } - unlink($filepath); + /** + * [testValueTooLong description] + */ + public function testValueTooLong(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('EXCEPTION_TARGET_BUFFERED_FILE_RAW_VALUE_TOO_LONG'); + + $target = new \codename\core\io\target\buffered\file\raw('raw_test', [ + 'padding_string' => ' ', + 'padding_mode' => 'right', + 'mapping' => [ + 'key1' => ['rowIndex' => 0, 'columnIndex' => 0, 'length' => 10], + 'key2' => ['rowIndex' => 0, 'columnIndex' => 1, 'length' => 10], + 'key3' => ['rowIndex' => 0, 'columnIndex' => 2, 'length' => 10], + 'key4' => ['rowIndex' => 0, 'columnIndex' => 3, 'length' => 10], + ], + ]); + + $samples = $this->getSampleData(); + foreach ($samples as $sample) { + $sample['key1'] = 'valuetoolong'; + $target->store($sample); + break; + } + $target->finish(); } - $this->assertEquals($samples, $res); + /** + * [getSampleData description] + * @return array [description] + */ + protected function getSampleData(): array + { + return [ + [ + 'key1' => 'value1', + 'key2' => '2', + 'key3' => '3.1415', + 'key4' => '', + ], + [ + 'key1' => 'value2', + 'key2' => '3', + 'key3' => '4.2344', + 'key4' => '', + ], + [ + 'key1' => 'value3', + 'key2' => '4', + 'key3' => '5.4545', + 'key4' => '', + ], + ]; + } - } + /** + * [testPaddingRight description] + * @throws ReflectionException + * @throws exception + */ + public function testPaddingRight(): void + { + $target = new \codename\core\io\target\buffered\file\raw('raw_test', [ + 'padding_string' => ' ', + 'padding_mode' => 'right', + 'encoding' => 'UTF-8', + 'truncate' => true, + 'split_count' => 2, + 'mapping' => [ + 'key1' => ['rowIndex' => 0, 'columnIndex' => 0, 'length' => 10], + 'key2' => ['rowIndex' => 0, 'columnIndex' => 1, 'length' => 10], + 'key3' => ['rowIndex' => 0, 'columnIndex' => 2, 'length' => 10], + 'key4' => ['rowIndex' => 0, 'columnIndex' => 3, 'length' => 10], + ], + ]); + + $samples = $this->getSampleData(); + foreach ($samples as $sample) { + $target->store($sample); + } + $target->finish(); + + + $files = $target->getFileResultArray(); + static::assertCount(2, $files); + + $res = []; + foreach ($files as $file) { + $filepath = $file->get(); + $datasource = new raw($filepath, [ + 'format' => [ + 'trim' => true, + 'map' => [ + 'key1' => ['type' => 'fixed', 'length' => 10], + 'key2' => ['type' => 'fixed', 'length' => 10], + 'key3' => ['type' => 'fixed', 'length' => 10], + 'key4' => ['type' => 'fixed', 'length' => 10], + ], + ], + ]); + + foreach ($datasource as $r) { + $res[] = $r; + } + + unlink($filepath); + } + + static::assertEquals($samples, $res); + } + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function setUp(): void + { + parent::setUp(); + overrideableApp::__injectApp([ + 'vendor' => 'codename', + 'app' => 'core-io', + 'namespace' => '\\codename\\core\\io', + ]); + + $app = static::createApp(); + + $app::__setApp('targetbufferedfiletest'); + $app::__setVendor('codename'); + $app::__setNamespace('\\codename\\core\\io\\target\\buffered\\file'); + + $app::getAppstack(); + } } diff --git a/tests/target/buffered/file/rawWriteReadTest.php b/tests/target/buffered/file/rawWriteReadTest.php index 0e0f457..db52900 100644 --- a/tests/target/buffered/file/rawWriteReadTest.php +++ b/tests/target/buffered/file/rawWriteReadTest.php @@ -1,63 +1,73 @@ ' ', - 'padding_mode' => 'left', - 'truncate' => true, - 'mapping' => [ - 'key1' => [ 'rowIndex' => 0, 'columnIndex' => 0, 'length' => 10 ], - 'key2' => [ 'rowIndex' => 0, 'columnIndex' => 1, 'length' => 10 ], - 'key3' => [ 'rowIndex' => 0, 'columnIndex' => 2, 'length' => 10 ], - 'key4' => [ 'rowIndex' => 0, 'columnIndex' => 3, 'length' => 10 ], - ] - ]); - } - - /** - * @inheritDoc - */ - protected function readTargetData(\codename\core\io\target $target): array { - $files = $target->getFileResultArray(); - $this->assertCount(1, $files); - foreach($files as $file) { - $filepath = $file->get(); - $datasource = new \codename\core\io\datasource\raw($filepath, [ - 'format' => [ - 'map' => [ - 'key1' => [ 'type' => 'fixed', 'length' => 10 ], - 'key2' => [ 'type' => 'fixed', 'length' => 10 ], - 'key3' => [ 'type' => 'fixed', 'length' => 10 ], - 'key4' => [ 'type' => 'fixed', 'length' => 10 ], +class rawWriteReadTest extends abstractWriteReadTest +{ + /** + * {@inheritDoc} + * @param array $configOverride + * @return target + * @throws exception + */ + protected function getWriteReadTargetInstance(array $configOverride = []): target + { + return new target\buffered\file\raw('raw_test', [ + 'padding_string' => ' ', + 'padding_mode' => 'left', + 'truncate' => true, + 'mapping' => [ + 'key1' => ['rowIndex' => 0, 'columnIndex' => 0, 'length' => 10], + 'key2' => ['rowIndex' => 0, 'columnIndex' => 1, 'length' => 10], + 'key3' => ['rowIndex' => 0, 'columnIndex' => 2, 'length' => 10], + 'key4' => ['rowIndex' => 0, 'columnIndex' => 3, 'length' => 10], ], - 'trim' => true, - ], - ]); - $res = []; - foreach($datasource as $r) { - $res[] = $r; - } - return $res; + ]); } - } - /** - * @inheritDoc - */ - protected function cleanupTarget(\codename\core\io\target $target): void - { - foreach($target->getFileResultArray() as $file) { - unlink($file->get()); + /** + * {@inheritDoc} + * @param target $target + * @return array + * @throws exception + */ + protected function readTargetData(target $target): array + { + $files = $target->getFileResultArray(); + static::assertCount(1, $files); + $res = []; + foreach ($files as $file) { + $filepath = $file->get(); + $datasource = new raw($filepath, [ + 'format' => [ + 'map' => [ + 'key1' => ['type' => 'fixed', 'length' => 10], + 'key2' => ['type' => 'fixed', 'length' => 10], + 'key3' => ['type' => 'fixed', 'length' => 10], + 'key4' => ['type' => 'fixed', 'length' => 10], + ], + 'trim' => true, + ], + ]); + foreach ($datasource as $r) { + $res[] = $r; + } + } + return $res; } - } + /** + * {@inheritDoc} + */ + protected function cleanupTarget(target $target): void + { + foreach ($target->getFileResultArray() as $file) { + unlink($file->get()); + } + } } diff --git a/tests/target/buffered/file/spreadsheetCsvWriteReadTest.php b/tests/target/buffered/file/spreadsheetCsvWriteReadTest.php index c4e6d92..7a4ae99 100644 --- a/tests/target/buffered/file/spreadsheetCsvWriteReadTest.php +++ b/tests/target/buffered/file/spreadsheetCsvWriteReadTest.php @@ -1,71 +1,84 @@ assertTrue(extension_loaded('fileinfo'), 'PhpSpreadsheet needs fileinfo extension - test cannot proceed.'); - $this->assertTrue(function_exists('mime_content_type'), 'PhpSpreadsheet needs mime_content_type() from fileinfo extension - test cannot proceed.'); - } +class spreadsheetCsvWriteReadTest extends abstractWriteReadTest +{ + /** + * {@inheritDoc} + */ + protected function setUp(): void + { + parent::setUp(); - /** - * @inheritDoc - */ - protected function getWriteReadTargetInstance(array $configOverride = []): \codename\core\io\target - { - return new \codename\core\io\target\buffered\file\spreadsheet('spreadsheet_csv_test', [ - 'use_writer' => 'Csv', - 'key_row' => 1, - 'config' => [ - 'encoding_utf8bom' => true, - ], - 'mapping' => [ - 'key1' => [ ], - 'key2' => [ ], - 'key3' => [ ], - 'key4' => [ ], - ] - ]); - } + // PHPSpreadsheet needs fileinfo extension + // which provides mime_content_type + // make sure it's available - early block otherwise. + static::assertTrue(extension_loaded('fileinfo'), 'PhpSpreadsheet needs fileinfo extension - test cannot proceed.'); + static::assertTrue(function_exists('mime_content_type'), 'PhpSpreadsheet needs mime_content_type() from fileinfo extension - test cannot proceed.'); + } - /** - * @inheritDoc - */ - protected function readTargetData(\codename\core\io\target $target): array { - $files = $target->getFileResultArray(); - $this->assertCount(1, $files); - foreach($files as $file) { - $filepath = $file->get(); - $datasource = new \codename\core\io\datasource\spreadsheet($filepath, [ - // default config - ]); - $res = []; - foreach($datasource as $r) { - $res[] = $r; - } - return $res; + /** + * {@inheritDoc} + * @param array $configOverride + * @return target + * @throws ReflectionException + * @throws exception + */ + protected function getWriteReadTargetInstance(array $configOverride = []): target + { + return new target\buffered\file\spreadsheet('spreadsheet_csv_test', [ + 'use_writer' => 'Csv', + 'key_row' => 1, + 'config' => [ + 'encoding_utf8bom' => true, + ], + 'mapping' => [ + 'key1' => [], + 'key2' => [], + 'key3' => [], + 'key4' => [], + ], + ]); } - } - /** - * @inheritDoc - */ - protected function cleanupTarget(\codename\core\io\target $target): void - { - foreach($target->getFileResultArray() as $file) { - unlink($file->get()); + /** + * {@inheritDoc} + * @param target $target + * @return array + * @throws \PhpOffice\PhpSpreadsheet\Exception + * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception + */ + protected function readTargetData(target $target): array + { + $files = $target->getFileResultArray(); + static::assertCount(1, $files); + $res = []; + foreach ($files as $file) { + $filepath = $file->get(); + $datasource = new spreadsheet($filepath, [ + // default config + ]); + foreach ($datasource as $r) { + $res[] = $r; + } + } + return $res; } - } + /** + * {@inheritDoc} + */ + protected function cleanupTarget(target $target): void + { + foreach ($target->getFileResultArray() as $file) { + unlink($file->get()); + } + } } diff --git a/tests/target/buffered/file/spreadsheetTest.php b/tests/target/buffered/file/spreadsheetTest.php index e9c17bf..d1d492a 100644 --- a/tests/target/buffered/file/spreadsheetTest.php +++ b/tests/target/buffered/file/spreadsheetTest.php @@ -1,185 +1,199 @@ 'codename', - 'app' => 'core-io', - 'namespace' => '\\codename\\core\\io' - ]); - - $app = static::createApp(); - - $app->__setApp('targetbufferedfiletest'); - $app->__setVendor('codename'); - $app->__setNamespace('\\codename\\core\\io\\target\\buffered\\file'); - - $app->getAppstack(); - } - - /** - * [getSampleData description] - * @return array [description] - */ - protected function getSampleData(): array { - return [ - [ - 'key1' => 'value1', - 'key2' => '2', - 'key3' => '3.1415', - 'key4' => '' - ], - [ - 'key1' => 'value2', - 'key2' => '3', - 'key3' => '4.2344', - 'key4' => '' - ], - [ - 'key1' => 'value3', - 'key2' => '4', - 'key3' => '5.4545', - 'key4' => '' - ], - ]; - } - - /** - * [testEnclosure description] - */ - public function testWrongWriter(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('INVALID_SPREADSHEET_FILE_FORMAT_SPECIFIED'); - - $target = new \codename\core\io\target\buffered\file\spreadsheet('xlsx_test', [ - 'use_writer' => 'Dompdf', - 'mapping' => [ - 'key1' => [ ], - 'key2' => [ ], - 'key3' => [ ], - 'key4' => [ ], - ], - ]); - - $samples = $this->getSampleData(); - foreach($samples as $sample) { - $target->store($sample); - } - $target->finish(); - - } - - /** - * [testWithTemplate description] - */ - public function testWithTemplate(): void { - - $target = new \codename\core\io\target\buffered\file\spreadsheet('xlsx_test', [ - 'use_writer' => 'Xlsx', - 'use_template_file' => 'tests/target/buffered/file/spreadsheetTest.xlsx', - 'encoding_utf8bom' => true, - 'start_row' => 3, - 'split_count' => 2, - 'freeze' => 'A2', - 'mapping' => [ - 'key1' => [ 'column' => 'A', 'setExplicitString' => true ], - 'key2' => [ 'column' => 'B', 'setExplicitString' => true ], - 'key3' => [ 'column' => 'C', 'formatCode' => '0.0000' ], - 'key4' => [ 'column' => 'D', 'setExplicitString' => true ], - ], - ]); - - $samples = $this->getSampleData(); - foreach($samples as $sample) { - $target->store($sample, [ 'file_password' => '123456' ]); - } - $target->finish(); - - $files = $target->getFileResultArray(); - $this->assertCount(2, $files); - - $res = []; - foreach($files as $file) { - $filepath = $file->get(); - $datasource = new \codename\core\io\datasource\spreadsheet($filepath, [ - 'skip_rows' => 3, - ]); - - foreach($datasource as $r) { - $res[] = $r; - } - - unlink($filepath); + /** + * [testEnclosure description] + * @throws ReflectionException + * @throws exception + */ + public function testWrongWriter(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('INVALID_SPREADSHEET_FILE_FORMAT_SPECIFIED'); + + $target = new \codename\core\io\target\buffered\file\spreadsheet('xlsx_test', [ + 'use_writer' => 'Dompdf', + 'mapping' => [ + 'key1' => [], + 'key2' => [], + 'key3' => [], + 'key4' => [], + ], + ]); + + $samples = $this->getSampleData(); + foreach ($samples as $sample) { + $target->store($sample); + } + $target->finish(); } - foreach($samples as $k => $sample) { - $this->assertEquals(array_values(array_filter($sample)), array_values(array_filter($res[$k] ?? []))); + /** + * [getSampleData description] + * @return array [description] + */ + protected function getSampleData(): array + { + return [ + [ + 'key1' => 'value1', + 'key2' => '2', + 'key3' => '3.1415', + 'key4' => '', + ], + [ + 'key1' => 'value2', + 'key2' => '3', + 'key3' => '4.2344', + 'key4' => '', + ], + [ + 'key1' => 'value3', + 'key2' => '4', + 'key3' => '5.4545', + 'key4' => '', + ], + ]; } - } - - /** - * [testCsvConfig description] - */ - public function testCsvConfig(): void { - - $target = new \codename\core\io\target\buffered\file\spreadsheet('csv_test', [ - 'use_writer' => 'Csv', - 'encoding_utf8bom' => true, - 'start_row' => 3, - 'split_count' => 2, - 'freeze' => 'A2', - 'mapping' => [ - 'key1' => [ ], - 'key2' => [ ], - 'key3' => [ ], - 'key4' => [ ], - ], - 'config' => [ - 'decimal_separator' => ',', - 'thousands_separator' => '.', - 'delimiter' => ';', - 'enclosure' => null, - ], - ]); - - $samples = $this->getSampleData(); - foreach($samples as $sample) { - $target->store($sample); + /** + * [testWithTemplate description] + * @throws ReflectionException + * @throws \PhpOffice\PhpSpreadsheet\Exception + * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception + * @throws exception + */ + public function testWithTemplate(): void + { + $target = new \codename\core\io\target\buffered\file\spreadsheet('xlsx_test', [ + 'use_writer' => 'Xlsx', + 'use_template_file' => 'tests/target/buffered/file/spreadsheetTest.xlsx', + 'encoding_utf8bom' => true, + 'start_row' => 3, + 'split_count' => 2, + 'freeze' => 'A2', + 'mapping' => [ + 'key1' => ['column' => 'A', 'setExplicitString' => true], + 'key2' => ['column' => 'B', 'setExplicitString' => true], + 'key3' => ['column' => 'C', 'formatCode' => '0.0000'], + 'key4' => ['column' => 'D', 'setExplicitString' => true], + ], + ]); + + $samples = $this->getSampleData(); + foreach ($samples as $sample) { + $target->store($sample, ['file_password' => '123456']); + } + $target->finish(); + + $files = $target->getFileResultArray(); + static::assertCount(2, $files); + + $res = []; + foreach ($files as $file) { + $filepath = $file->get(); + $datasource = new spreadsheet($filepath, [ + 'skip_rows' => 3, + ]); + + foreach ($datasource as $r) { + $res[] = $r; + } + + unlink($filepath); + } + + foreach ($samples as $k => $sample) { + static::assertEquals(array_values(array_filter($sample)), array_values(array_filter($res[$k] ?? []))); + } } - $target->finish(); - - $files = $target->getFileResultArray(); - $this->assertCount(2, $files); - - $res = []; - foreach($files as $file) { - $filepath = $file->get(); - $datasource = new \codename\core\io\datasource\spreadsheet($filepath, [ - 'skip_rows' => 3, - ]); - foreach($datasource as $r) { - $res[] = $r; - } - - unlink($filepath); + /** + * [testCsvConfig description] + * @throws ReflectionException + * @throws \PhpOffice\PhpSpreadsheet\Exception + * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception + * @throws exception + */ + public function testCsvConfig(): void + { + $target = new \codename\core\io\target\buffered\file\spreadsheet('csv_test', [ + 'use_writer' => 'Csv', + 'encoding_utf8bom' => true, + 'start_row' => 3, + 'split_count' => 2, + 'freeze' => 'A2', + 'mapping' => [ + 'key1' => [], + 'key2' => [], + 'key3' => [], + 'key4' => [], + ], + 'config' => [ + 'decimal_separator' => ',', + 'thousands_separator' => '.', + 'delimiter' => ';', + 'enclosure' => null, + ], + ]); + + $samples = $this->getSampleData(); + foreach ($samples as $sample) { + $target->store($sample); + } + $target->finish(); + + $files = $target->getFileResultArray(); + static::assertCount(2, $files); + + $res = []; + foreach ($files as $file) { + $filepath = $file->get(); + $datasource = new spreadsheet($filepath, [ + 'skip_rows' => 3, + ]); + + foreach ($datasource as $r) { + $res[] = $r; + } + + unlink($filepath); + } + + foreach ($samples as $k => $sample) { + static::assertEquals(array_values(array_filter($sample)), array_values(array_filter($res[$k] ?? []))); + } } - foreach($samples as $k => $sample) { - $this->assertEquals(array_values(array_filter($sample)), array_values(array_filter($res[$k] ?? []))); + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function setUp(): void + { + parent::setUp(); + overrideableApp::__injectApp([ + 'vendor' => 'codename', + 'app' => 'core-io', + 'namespace' => '\\codename\\core\\io', + ]); + + $app = static::createApp(); + + $app::__setApp('targetbufferedfiletest'); + $app::__setVendor('codename'); + $app::__setNamespace('\\codename\\core\\io\\target\\buffered\\file'); + + $app::getAppstack(); } - - } - } diff --git a/tests/target/buffered/file/spreadsheetXlsWriteReadTest.php b/tests/target/buffered/file/spreadsheetXlsWriteReadTest.php index 30ee634..23f0b34 100644 --- a/tests/target/buffered/file/spreadsheetXlsWriteReadTest.php +++ b/tests/target/buffered/file/spreadsheetXlsWriteReadTest.php @@ -1,54 +1,67 @@ 'Xls', - 'key_row' => 1, - 'mapping' => [ - 'key1' => [ ], - 'key2' => [ ], - 'key3' => [ ], - 'key4' => [ ], - ] - ]); - } - - /** - * @inheritDoc - */ - protected function readTargetData(\codename\core\io\target $target): array { - $files = $target->getFileResultArray(); - $this->assertCount(1, $files); - foreach($files as $file) { - $filepath = $file->get(); - $datasource = new \codename\core\io\datasource\spreadsheet($filepath, [ - // default config - ]); - $res = []; - foreach($datasource as $r) { - $res[] = $r; - } - return $res; +class spreadsheetXlsWriteReadTest extends abstractWriteReadTest +{ + /** + * {@inheritDoc} + * @param array $configOverride + * @return target + * @throws ReflectionException + * @throws exception + */ + protected function getWriteReadTargetInstance(array $configOverride = []): target + { + return new target\buffered\file\spreadsheet('xls_test', [ + 'use_writer' => 'Xls', + 'key_row' => 1, + 'mapping' => [ + 'key1' => [], + 'key2' => [], + 'key3' => [], + 'key4' => [], + ], + ]); } - } - /** - * @inheritDoc - */ - protected function cleanupTarget(\codename\core\io\target $target): void - { - foreach($target->getFileResultArray() as $file) { - unlink($file->get()); + /** + * {@inheritDoc} + * @param target $target + * @return array + * @throws \PhpOffice\PhpSpreadsheet\Exception + * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception + */ + protected function readTargetData(target $target): array + { + $files = $target->getFileResultArray(); + static::assertCount(1, $files); + $res = []; + foreach ($files as $file) { + $filepath = $file->get(); + $datasource = new spreadsheet($filepath, [ + // default config + ]); + foreach ($datasource as $r) { + $res[] = $r; + } + } + return $res; } - } + /** + * {@inheritDoc} + */ + protected function cleanupTarget(target $target): void + { + foreach ($target->getFileResultArray() as $file) { + unlink($file->get()); + } + } } diff --git a/tests/target/buffered/file/spreadsheetXlsxWriteReadTest.php b/tests/target/buffered/file/spreadsheetXlsxWriteReadTest.php index 40b5b35..cae8c8a 100644 --- a/tests/target/buffered/file/spreadsheetXlsxWriteReadTest.php +++ b/tests/target/buffered/file/spreadsheetXlsxWriteReadTest.php @@ -1,54 +1,67 @@ 'Xlsx', - 'key_row' => 1, - 'mapping' => [ - 'key1' => [ ], - 'key2' => [ ], - 'key3' => [ ], - 'key4' => [ ], - ] - ]); - } - - /** - * @inheritDoc - */ - protected function readTargetData(\codename\core\io\target $target): array { - $files = $target->getFileResultArray(); - $this->assertCount(1, $files); - foreach($files as $file) { - $filepath = $file->get(); - $datasource = new \codename\core\io\datasource\spreadsheet($filepath, [ - // default config - ]); - $res = []; - foreach($datasource as $r) { - $res[] = $r; - } - return $res; +class spreadsheetXlsxWriteReadTest extends abstractWriteReadTest +{ + /** + * {@inheritDoc} + * @param array $configOverride + * @return target + * @throws ReflectionException + * @throws \codename\core\exception + */ + protected function getWriteReadTargetInstance(array $configOverride = []): target + { + return new target\buffered\file\spreadsheet('xlsx_test', [ + 'use_writer' => 'Xlsx', + 'key_row' => 1, + 'mapping' => [ + 'key1' => [], + 'key2' => [], + 'key3' => [], + 'key4' => [], + ], + ]); } - } - /** - * @inheritDoc - */ - protected function cleanupTarget(\codename\core\io\target $target): void - { - foreach($target->getFileResultArray() as $file) { - unlink($file->get()); + /** + * {@inheritDoc} + * @param target $target + * @return array + * @throws Exception + * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception + */ + protected function readTargetData(target $target): array + { + $files = $target->getFileResultArray(); + static::assertCount(1, $files); + $res = []; + foreach ($files as $file) { + $filepath = $file->get(); + $datasource = new spreadsheet($filepath, [ + // default config + ]); + foreach ($datasource as $r) { + $res[] = $r; + } + } + return $res; } - } + /** + * {@inheritDoc} + */ + protected function cleanupTarget(target $target): void + { + foreach ($target->getFileResultArray() as $file) { + unlink($file->get()); + } + } } diff --git a/tests/target/buffered/file/xmlTest.php b/tests/target/buffered/file/xmlTest.php index 3cac246..94f0bcb 100644 --- a/tests/target/buffered/file/xmlTest.php +++ b/tests/target/buffered/file/xmlTest.php @@ -1,150 +1,157 @@ 'value1', - 'key2' => '2', - 'key3' => '3.1415', - 'key4' => '' - ], - [ - 'key1' => 'value2', - 'key2' => '3', - 'key3' => '4.2344', - 'key4' => '' - ], - [ - 'key1' => 'value3', - 'key2' => '4', - 'key3' => '5.4545', - 'key4' => '' - ], - ]; - } - - /** - * [testXml description] - */ - public function testXml(): void { - $tags = [ - 'file_name' => 'moep', - ]; - - $target = new \codename\core\io\target\buffered\file\xml('xml_test', [ - 'version' => '1.0', - 'encoding' => 'UTF-8', - 'template_elements_path' => [ 'processes' ], - 'split_count' => 2, - 'mapping' => [ - 'key1' => [ 'path' => [ 'process' ] ], - 'key2' => [ 'path' => [ 'process' ] ], - 'key3' => [ 'path' => [ 'process' ] ], - 'key4' => [ 'path' => [ 'process' ] ], - ], - 'tags' => $tags, - ]); - - $samples = $this->getSampleData(); - foreach($samples as $sample) { - $target->store($sample, $tags); + /** + * [testXml description] + * @throws ReflectionException + * @throws exception + */ + public function testXml(): void + { + $tags = [ + 'file_name' => 'moep', + ]; + + $target = new \codename\core\io\target\buffered\file\xml('xml_test', [ + 'version' => '1.0', + 'encoding' => 'UTF-8', + 'template_elements_path' => ['processes'], + 'split_count' => 2, + 'mapping' => [ + 'key1' => ['path' => ['process']], + 'key2' => ['path' => ['process']], + 'key3' => ['path' => ['process']], + 'key4' => ['path' => ['process']], + ], + 'tags' => $tags, + ]); + + $samples = $this->getSampleData(); + foreach ($samples as $sample) { + $target->store($sample, $tags); + } + $target->finish(); + + + $files = $target->getFileResultArray(); + static::assertCount(2, $files); + + $res = []; + foreach ($files as $file) { + $filepath = $file->get(); + + $datasource = new xml($filepath, [ + 'xpath_query' => '/processes/process', + 'xpath_mapping' => [ + 'key1' => 'key1', + 'key2' => 'key2', + 'key3' => 'key3', + 'key4' => 'key4', + ], + ]); + + foreach ($datasource as $r) { + $res[] = $r; + } + + unlink($filepath); + } + + static::assertEquals($samples, $res); } - $target->finish(); - - - $files = $target->getFileResultArray(); - $this->assertCount(2, $files); - - $res = []; - foreach($files as $file) { - $filepath = $file->get(); - $datasource = new \codename\core\io\datasource\xml($filepath, [ - 'xpath_query' => '/processes/process', - 'xpath_mapping' => [ - 'key1' => 'key1', - 'key2' => 'key2', - 'key3' => 'key3', - 'key4' => 'key4', - ], - ]); - - foreach($datasource as $r) { - $res[] = $r; - } - - unlink($filepath); + /** + * [getSampleData description] + * @return array [description] + */ + protected function getSampleData(): array + { + return [ + [ + 'key1' => 'value1', + 'key2' => '2', + 'key3' => '3.1415', + 'key4' => '', + ], + [ + 'key1' => 'value2', + 'key2' => '3', + 'key3' => '4.2344', + 'key4' => '', + ], + [ + 'key1' => 'value3', + 'key2' => '4', + 'key3' => '5.4545', + 'key4' => '', + ], + ]; } - $this->assertEquals($samples, $res); - - } - - /** - * [testXmlWithTemplate description] - */ - public function testXmlWithTemplate(): void { - $tags = [ - 'file_name' => 'moep', - ]; - - $target = new \codename\core\io\target\buffered\file\xml('xml_test', [ - 'version' => '1.0', - 'encoding' => 'UTF-8', - 'template' => [ - 'process' => [ - - ] - ], - 'split_count' => 2, - 'mapping' => [ - 'process' => [ ], - ], - 'tags' => $tags, - ]); - - $samples = $this->getSampleData(); - $target->store([ - 'process' => $samples[0] - ], $tags); - $target->finish(); - - $files = $target->getFileResultArray(); - $this->assertCount(1, $files); - - $res = []; - foreach($files as $file) { - $filepath = $file->get(); - - $datasource = new \codename\core\io\datasource\xml($filepath, [ - 'xpath_query' => '/process', - 'xpath_mapping' => [ - 'key1' => 'key1', - 'key2' => 'key2', - 'key3' => 'key3', - 'key4' => 'key4', - ], - ]); - - foreach($datasource as $r) { - $res[] = $r; - } - - unlink($filepath); + /** + * [testXmlWithTemplate description] + * @throws ReflectionException + * @throws exception + */ + public function testXmlWithTemplate(): void + { + $tags = [ + 'file_name' => 'moep', + ]; + + $target = new \codename\core\io\target\buffered\file\xml('xml_test', [ + 'version' => '1.0', + 'encoding' => 'UTF-8', + 'template' => [ + 'process' => [ + + ], + ], + 'split_count' => 2, + 'mapping' => [ + 'process' => [], + ], + 'tags' => $tags, + ]); + + $samples = $this->getSampleData(); + $target->store([ + 'process' => $samples[0], + ], $tags); + $target->finish(); + + $files = $target->getFileResultArray(); + static::assertCount(1, $files); + + $res = []; + foreach ($files as $file) { + $filepath = $file->get(); + + $datasource = new xml($filepath, [ + 'xpath_query' => '/process', + 'xpath_mapping' => [ + 'key1' => 'key1', + 'key2' => 'key2', + 'key3' => 'key3', + 'key4' => 'key4', + ], + ]); + + foreach ($datasource as $r) { + $res[] = $r; + } + + unlink($filepath); + } + + static::assertEquals($samples[0], $res[0]); } - - $this->assertEquals($samples[0], $res[0]); - - } - } diff --git a/tests/target/buffered/file/xmlWriteReadTest.php b/tests/target/buffered/file/xmlWriteReadTest.php index 698d5be..508fe27 100644 --- a/tests/target/buffered/file/xmlWriteReadTest.php +++ b/tests/target/buffered/file/xmlWriteReadTest.php @@ -1,61 +1,68 @@ '1.0', - 'encoding' => 'UTF-8', - 'template_elements_path' => ['data'], - 'mapping' => [ - 'key1' => [ 'path' => ['element'] ], - 'key2' => [ 'path' => ['element'] ], - 'key3' => [ 'path' => ['element'] ], - 'key4' => [ 'path' => ['element'] ], - ] - ]); - } - - /** - * @inheritDoc - */ - protected function readTargetData(\codename\core\io\target $target): array { - $files = $target->getFileResultArray(); - $this->assertCount(1, $files); - foreach($files as $file) { - $filepath = $file->get(); - $datasource = new \codename\core\io\datasource\xml($filepath, [ - 'xpath_query' => '/data/element', - 'xpath_mapping' => [ - 'key1' => 'key1', - 'key2' => 'key2', - 'key3' => 'key3', - 'key4' => 'key4', - ] - ]); - $res = []; - foreach($datasource as $r) { - $res[] = $r; - } - return $res; +class xmlWriteReadTest extends abstractWriteReadTest +{ + /** + * {@inheritDoc} + */ + protected function getWriteReadTargetInstance(array $configOverride = []): target + { + return new target\buffered\file\xml('xml_test', [ + 'version' => '1.0', + 'encoding' => 'UTF-8', + 'template_elements_path' => ['data'], + 'mapping' => [ + 'key1' => ['path' => ['element']], + 'key2' => ['path' => ['element']], + 'key3' => ['path' => ['element']], + 'key4' => ['path' => ['element']], + ], + ]); } - } - /** - * @inheritDoc - */ - protected function cleanupTarget(\codename\core\io\target $target): void - { - foreach($target->getFileResultArray() as $file) { - unlink($file->get()); + /** + * {@inheritDoc} + * @param target $target + * @return array + * @throws Exception + */ + protected function readTargetData(target $target): array + { + $files = $target->getFileResultArray(); + static::assertCount(1, $files); + $res = []; + foreach ($files as $file) { + $filepath = $file->get(); + $datasource = new xml($filepath, [ + 'xpath_query' => '/data/element', + 'xpath_mapping' => [ + 'key1' => 'key1', + 'key2' => 'key2', + 'key3' => 'key3', + 'key4' => 'key4', + ], + ]); + foreach ($datasource as $r) { + $res[] = $r; + } + } + return $res; } - } + /** + * {@inheritDoc} + */ + protected function cleanupTarget(target $target): void + { + foreach ($target->getFileResultArray() as $file) { + unlink($file->get()); + } + } } diff --git a/tests/target/buffered/fileTest.php b/tests/target/buffered/fileTest.php index df11bcd..687be79 100644 --- a/tests/target/buffered/fileTest.php +++ b/tests/target/buffered/fileTest.php @@ -1,67 +1,86 @@ getFileHandle(); - $this->assertIsResource($result); - - } - - /** - * [testNewFileHandle description] - */ - public function testWrongNewFileHandle(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('CORE_IO_TARGET_BUFFERED_FILE_HANDLE_ERROR'); - - $target = new dummyFile('file_test', [ - 'append' => true, - ]); - - $result = $target->getNewFileHandle(__DIR__ . "/" . ''); - - } - - /** - * [testNewFileHandle description] - */ - public function testEmptyFileResultArray(): void { - $target = new dummyFile('file_test', []); - - $result = $target->getFileResultArray(); - $this->assertEmpty($result); - - } - + /** + * [testFileHandle description] + * @throws exception + */ + public function testFileHandle(): void + { + $target = new dummyFile('file_test', []); + + $result = $target->getFileHandle(); + static::assertIsResource($result); + } + + /** + * [testNewFileHandle description] + */ + public function testWrongNewFileHandle(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('CORE_IO_TARGET_BUFFERED_FILE_HANDLE_ERROR'); + + $target = new dummyFile('file_test', [ + 'append' => true, + ]); + + $target->getNewFileHandle(__DIR__ . "/"); + } + + /** + * [testNewFileHandle description] + * @throws ReflectionException + * @throws exception + */ + public function testEmptyFileResultArray(): void + { + $target = new dummyFile('file_test', []); + + $result = $target->getFileResultArray(); + static::assertEmpty($result); + } } -class dummyFile extends \codename\core\io\target\buffered\file +class dummyFile extends file { - - public function storeBufferedData() { - return; - } - - public function getFileHandle() { - return parent::getFileHandle(); - } - - public function getNewFileHandle(string $targetFilePath) { - return parent::getNewFileHandle($targetFilePath); - } - - public function getFileResultArray() : array { - return parent::getFileResultArray(); - } - + /** + * perform the real store routine + * -> store the buffered data + * + * @return void + */ + public function storeBufferedData(): void + { + } + + /** + * legacy method returning a new file handle using the currently set targetFilePath + * @return resource + * @throws exception + */ + public function getFileHandle() + { + return parent::getFileHandle(); + } + + /** + * returns a new file handle for the given filepath + * to be opened in write or append mode + * @param string $targetFilePath [description] + * @return resource [a file handle resource] + * @throws exception + */ + public function getNewFileHandle(string $targetFilePath) + { + return parent::getNewFileHandle($targetFilePath); + } } diff --git a/tests/target/dummyTest.php b/tests/target/dummyTest.php index 5554d0c..26113c9 100644 --- a/tests/target/dummyTest.php +++ b/tests/target/dummyTest.php @@ -1,59 +1,74 @@ store([ - 'example' => 'data' - ]); - $this->assertTrue($result); - - // get data - $result = $target->getVirtualStoreData(); - $this->assertEquals([ - [ 'example' => 'data' ] - ], $result); - - // check finish - $this->assertEmpty($target->finish()); + // set data + $result = $target->store([ + 'example' => 'data', + ]); + static::assertTrue($result); - // check set virtual store - $this->assertEmpty($target->setVirtualStoreEnabled(true)); + // get data + $result = $target->getVirtualStoreData(); + static::assertEquals([ + ['example' => 'data'], + ], $result); - // check virtual store state - $this->assertTrue($target->getVirtualStoreEnabled()); - - } + // check finish + try { + $target->finish(); + } catch (\Exception) { + static::fail(); + } - /** - * [testDummyGeneral description] - */ - public function testDummyFinishedError(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_CORE_IO_TARGET_VIRTUAL_ALREADY_FINISHED'); + // check set virtual store + try { + $target->setVirtualStoreEnabled(true); + } catch (\Exception) { + static::fail(); + } - $target = new \codename\core\io\target\dummy('finished_error', []); + // check virtual store state + static::assertTrue($target->getVirtualStoreEnabled()); + } - // set finish - $this->assertEmpty($target->finish()); + /** + * [testDummyGeneral description] + */ + public function testDummyFinishedError(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('EXCEPTION_CORE_IO_TARGET_VIRTUAL_ALREADY_FINISHED'); - // set data - $result = $target->store([ - 'example' => 'data' - ]); + $target = new dummy('finished_error', []); - } + // set finish + try { + $target->finish(); + } catch (\Exception) { + static::fail(); + } + // set data + $target->store([ + 'example' => 'data', + ]); + } } diff --git a/tests/target/filterTest.php b/tests/target/filterTest.php index 5a70e69..0ddcd70 100644 --- a/tests/target/filterTest.php +++ b/tests/target/filterTest.php @@ -1,83 +1,85 @@ true, + 'key1' => 123, + 'key2' => 'willpass', + 'key3' => null, + 'key4' => 'willpass', + ], + [ + 'expectMatch' => false, + 'key1' => 123, + 'key2' => 'abc', + 'key3' => 'wontpass', + 'key4' => null, + ], + [ + 'expectMatch' => false, + 'key1' => 234, + 'key2' => 'abc', + 'key3' => 'wontpass', + 'key4' => null, + ], + ]; - /** - * [testSourceFilters description] - */ - public function testSourceFilters(): void { - - $data = [ - [ - 'expectMatch' => true, - 'key1' => 123, - 'key2' => 'willpass', - 'key3' => null, - 'key4' => 'willpass', - ], - [ - 'expectMatch' => false, - 'key1' => 123, - 'key2' => 'abc', - 'key3' => 'wontpass', - 'key4' => null, - ], - [ - 'expectMatch' => false, - 'key1' => 234, - 'key2' => 'abc', - 'key3' => 'wontpass', - 'key4' => null, - ] - ]; + $filters = [ + [ + 'field' => 'key1', + 'operator' => '=', + 'value' => 123, + ], + [ + 'field' => 'key2', + 'operator' => '!=', + 'value' => 'abc', + ], + [ + 'field' => 'key3', + 'operator' => '=', + 'value' => null, + ], + [ + 'field' => 'key4', + 'operator' => '!=', + 'value' => null, + ], + [ + // should be ignored + 'field' => 'key1', + 'operator' => 'bla', + 'value' => null, + ], + ]; - $filters = [ - [ - 'field' => 'key1', - 'operator' => '=', - 'value' => 123 - ], - [ - 'field' => 'key2', - 'operator' => '!=', - 'value' => 'abc' - ], - [ - 'field' => 'key3', - 'operator' => '=', - 'value' => null - ], - [ - 'field' => 'key4', - 'operator' => '!=', - 'value' => null - ], - [ - // should be ignored - 'field' => 'key1', - 'operator' => 'bla', - 'value' => null - ] - ]; + // + // For this example, we directly test only filters + // and assume source data == target data + // + $target = new arraydata('source_filter_test', [ + 'source_filter' => $filters, + 'target_filter' => $filters, + ]); - // - // For this example, we directly test only filters - // and assume source data == target data - // - $target = new \codename\core\io\target\arraydata('source_filter_test', [ - 'source_filter' => $filters, - 'target_filter' => $filters, - ]); - - foreach($data as $dataset) { - $this->assertEquals($dataset['expectMatch'], $target->matchesSourceFilters($dataset)); - $this->assertEquals($dataset['expectMatch'], $target->matchesTargetFilters($dataset)); + foreach ($data as $dataset) { + static::assertEquals($dataset['expectMatch'], $target->matchesSourceFilters($dataset)); + static::assertEquals($dataset['expectMatch'], $target->matchesTargetFilters($dataset)); + } } - } - } diff --git a/tests/target/model/complexTest.php b/tests/target/model/complexTest.php index fd313b0..e1bf1ba 100644 --- a/tests/target/model/complexTest.php +++ b/tests/target/model/complexTest.php @@ -1,539 +1,579 @@ getModel('testmodel') - ->addFilter('testmodel_id', 0, '>') - ->delete(); - } - - /** - * @inheritDoc - */ - protected function setUp(): void - { - $app = static::createApp(); - - // Additional overrides to get a more complete app lifecycle - // and allow static global app::getModel() to work correctly - $app->__setApp('targettest'); - $app->__setVendor('codename'); - $app->__setNamespace('\\codename\\core\\io\\tests\\target'); - - $app->getAppstack(); - - // avoid re-init - if(static::$initialized) { - return; + /** + * @return void + * @throws ReflectionException + * @throws exception + */ + public function testGeneral(): void + { + $target = new complex('test', [ + 'structure' => [ + 'model' => 'testmodel', + 'join' => [ + [ + 'model' => 'testmodelj', + 'join' => [], + ], + ], + ], + // default method fallback should be: save + ]); + + static::assertInstanceOf(\codename\core\model::class, $target->getModel()); } - static::$initialized = true; + /** + * @return void + * @throws ReflectionException + * @throws exception + */ + public function testTargetStoreSimple(): void + { + $target = new complex('test', [ + 'structure' => [ + 'model' => 'testmodel', + 'join' => [ + [ + 'model' => 'testmodelj', + 'join' => [], + ], + ], + ], + // default method fallback should be: save + ]); + + $target->store([ + 'testmodel_text' => 'simple', + ]); + + $target->finish(); - static::setEnvironmentConfig([ - 'test' => [ - 'database' => [ - // NOTE: by default, we do these tests using - // pure in-memory sqlite. - 'default' => [ - 'driver' => 'sqlite', - 'database_file' => ':memory:', + $model = $this->getModel('testmodel'); + $res = $model + ->addFilter('testmodel_text', 'simple') + ->search()->getResult(); + static::assertCount(1, $res); + } + + /** + * @return void + * @throws ReflectionException + * @throws exception + */ + public function testTargetStoreSimpleVirtual(): void + { + $target = new complex('test', [ + 'structure' => [ + 'model' => 'testmodel', + 'join' => [ + [ + 'model' => 'testmodelj', + 'join' => [], + ], + ], ], - ], - 'cache' => [ - 'default' => [ - 'driver' => 'memory' - ] - ], - 'filesystem' =>[ - 'local' => [ - 'driver' => 'local', - ] - ], - 'log' => [ - 'default' => [ - 'driver' => 'system', - 'data' => [ - 'name' => 'dummy' - ] - ] - ], - ] - ]); - - static::createModel( - 'targettest', 'testmodel', - \codename\core\io\tests\target\model\testmodel::$staticConfig, - function($schema, $model, $config) { - return new \codename\core\io\tests\target\model\testmodel([]); - }); - - static::createModel( - 'targettest', 'testmodelj', - \codename\core\io\tests\target\model\testmodelj::$staticConfig, - function($schema, $model, $config) { - return new \codename\core\io\tests\target\model\testmodelj([]); - }); - - static::architect('targettest', 'codename', 'test'); - } - - /** - * [testGeneral description] - */ - public function testGeneral(): void { - $target = new \codename\core\io\target\model\complex('test', [ - 'structure' => [ - 'model' => 'testmodel', - 'join' => [ - [ - 'model' => 'testmodelj', - 'join' => [], - ] - ], - ], - // default method fallback should be: save - ]); - - $this->assertInstanceOf(\codename\core\model::class, $target->getModel()); - - } - - /** - * [testTargetStoreSimple description] - */ - public function testTargetStoreSimple(): void { - $target = new \codename\core\io\target\model\complex('test', [ - 'structure' => [ - 'model' => 'testmodel', - 'join' => [ - [ - 'model' => 'testmodelj', - 'join' => [], - ] - ], - ], - // default method fallback should be: save - ]); - - $target->store([ - 'testmodel_text' => 'simple' - ]); - - $target->finish(); - - $model = $this->getModel('testmodel'); - $res = $model - ->addFilter('testmodel_text', 'simple') - ->search()->getResult(); - $this->assertCount(1, $res); - } - - /** - * [testTargetStoreSimple description] - */ - public function testTargetStoreSimpleVirtual(): void { - $target = new \codename\core\io\target\model\complex('test', [ - 'structure' => [ - 'model' => 'testmodel', - 'join' => [ - [ - 'model' => 'testmodelj', - 'join' => [], - ] - ], - ], - // default method fallback should be: save - ]); - - $target->setVirtualStoreEnabled(true); - $this->assertTrue($target->getVirtualStoreEnabled()); - - $target->store([ - 'testmodel_text' => 'simple', - 'testmodelj_text' => 'simple', - ]); - - $target->finish(); - - $result = $target->getVirtualStoreData(); - - $this->assertEquals([ - [ - 'testmodel_text' => 'simple', - 'testmodelj_text' => 'simple', - ] - ], $result); - } - - /** - * [testTargetStoreChildrenSimpleVirtual description] - */ - public function testTargetStoreChildrenSimpleVirtual(): void { - $target = new \codename\core\io\target\model\complex('test', [ - 'structure' => [ - 'model' => 'testmodelj', - 'join' => [ - [ - 'model' => 'testmodel', - 'join' => [], - ] - ], - ], - // default method fallback should be: save - ]); - - $target->setVirtualStoreEnabled(true); - $this->assertTrue($target->getVirtualStoreEnabled()); - - $target->store([ - 'testmodelj_text' => 'simple', - 'testmodelj_testmodel' => [ - 'testmodel_text' => 'simple', - ], - ]); - - $target->finish(); - - $result = $target->getVirtualStoreData(); - - $this->assertEquals([ - [ - 'testmodelj_text' => 'simple', - 'testmodelj_testmodel' => [ - 'testmodel_text' => 'simple', - ], - ] - ], $result); - } - - /** - * [testTargetReplaceStoreSimpleVirtual description] - */ - public function testTargetReplaceStoreSimpleVirtual(): void { - $target = new \codename\core\io\target\model\complex('test', [ - 'structure' => [ - 'model' => 'testmodel', - 'join' => [ + // default method fallback should be: save + ]); + + $target->setVirtualStoreEnabled(true); + static::assertTrue($target->getVirtualStoreEnabled()); + + $target->store([ + 'testmodel_text' => 'simple', + 'testmodelj_text' => 'simple', + ]); + + $target->finish(); + + $result = $target->getVirtualStoreData(); + + static::assertEquals([ [ - 'model' => 'testmodelj', - 'join' => [], - ] - ], - ], - 'method' => 'replace', - ]); - - $target->setVirtualStoreEnabled(true); - $this->assertTrue($target->getVirtualStoreEnabled()); - - $target->store([ - 'testmodel_id' => 1, - 'testmodel_text' => 'simple', - 'testmodelj_text' => 'simple', - ]); - - $target->finish(); - - $result = $target->getVirtualStoreData(); - - $this->assertEquals([ - [ - 'testmodel_id' => 1, - 'testmodel_text' => 'simple', - 'testmodelj_text' => 'simple', - ] - ], $result); - } - - /** - * [testTargetReplaceStoreSimpleWithoutUnique description] - */ - public function testTargetReplaceStoreSimpleWithoutUnique(): void { - $target = new \codename\core\io\target\model\complex('test', [ - 'structure' => [ - 'model' => 'testmodelj', - 'join' => [ - ], - ], - 'method' => 'replace', - ]); - - $target->setVirtualStoreEnabled(true); - $this->assertTrue($target->getVirtualStoreEnabled()); - - $target->store([ - 'testmodelj_text' => 'simple', - ]); - - $target->finish(); - - $result = $target->getVirtualStoreData(); - - $this->assertEquals([ - [ - 'testmodelj_text' => 'simple', - ] - ], $result); - } - - /** - * [testTargetStoreByUnique description] - */ - public function testTargetStoreByUniqueVirtual(): void { - - $target = new \codename\core\io\target\model\complex('test', [ - 'structure' => [ - 'model' => 'testmodel', - 'join' => [ + 'testmodel_text' => 'simple', + 'testmodelj_text' => 'simple', + ], + ], $result); + } + + /** + * @return void + * @throws ReflectionException + * @throws exception + */ + public function testTargetStoreChildrenSimpleVirtual(): void + { + $target = new complex('test', [ + 'structure' => [ + 'model' => 'testmodelj', + 'join' => [ + [ + 'model' => 'testmodel', + 'join' => [], + ], + ], + ], + // default method fallback should be: save + ]); + + $target->setVirtualStoreEnabled(true); + static::assertTrue($target->getVirtualStoreEnabled()); + + $target->store([ + 'testmodelj_text' => 'simple', + 'testmodelj_testmodel' => [ + 'testmodel_text' => 'simple', + ], + ]); + + $target->finish(); + + $result = $target->getVirtualStoreData(); + + static::assertEquals([ [ - 'model' => 'testmodelj', - 'join' => [], - ] - ], - ], - 'method' => 'replace' - ]); - - $target->store([ - 'testmodel_text' => 'unique_single1', - 'testmodel_unique_single' => 'UNIQUE1', - ]); - - // - // Get the ID just created - // for usage, further below. - // - $unique1Id = $this->getModel('testmodel') - ->addFilter('testmodel_unique_single', 'UNIQUE1') - ->search()->getResult()[0]['testmodel_id']; - $this->assertNotNull($unique1Id); - - $target->store([ - 'testmodel_text' => 'unique_multi1', - 'testmodel_unique_multi1' => 'UNIQUE_V1', - 'testmodel_unique_multi2' => 'UNIQUE_V2', - ]); - - $target->setVirtualStoreEnabled(true); - $this->assertTrue($target->getVirtualStoreEnabled()); - - $target->store([ - 'testmodel_text' => 'unique_single2', - 'testmodel_unique_single' => 'UNIQUE1', - ]); - - $target->store([ - 'testmodel_text' => 'unique_multi2', - 'testmodel_unique_multi1' => 'UNIQUE_V1_', - 'testmodel_unique_multi2' => 'UNIQUE_V2_', - ]); - - $target->finish(); - - $model = $this->getModel('testmodel'); - - $res = $model->search()->getResult(); - $this->assertCount(2, $res); - - $result = $target->getVirtualStoreData(); - - $this->assertEquals([ - [ - 'testmodel_text' => 'unique_single2', - 'testmodel_unique_single' => 'UNIQUE1', - 'testmodel_id' => $unique1Id, - ], - [ - 'testmodel_text' => 'unique_multi2', - 'testmodel_unique_multi1' => 'UNIQUE_V1_', - 'testmodel_unique_multi2' => 'UNIQUE_V2_', - ], - ], $result); - } - - /** - * [testTargetStoreByUnique description] - */ - public function testTargetStoreByUnique(): void { - - $target = new \codename\core\io\target\model\complex('test', [ - 'structure' => [ - 'model' => 'testmodel', - 'join' => [ + 'testmodelj_text' => 'simple', + 'testmodelj_testmodel' => [ + 'testmodel_text' => 'simple', + ], + ], + ], $result); + } + + /** + * @return void + * @throws ReflectionException + * @throws exception + */ + public function testTargetReplaceStoreSimpleVirtual(): void + { + $target = new complex('test', [ + 'structure' => [ + 'model' => 'testmodel', + 'join' => [ + [ + 'model' => 'testmodelj', + 'join' => [], + ], + ], + ], + 'method' => 'replace', + ]); + + $target->setVirtualStoreEnabled(true); + static::assertTrue($target->getVirtualStoreEnabled()); + + $target->store([ + 'testmodel_id' => 1, + 'testmodel_text' => 'simple', + 'testmodelj_text' => 'simple', + ]); + + $target->finish(); + + $result = $target->getVirtualStoreData(); + + static::assertEquals([ [ - 'model' => 'testmodelj', - 'join' => [], - ] - ], - ], - 'method' => 'replace' - ]); - - $target->store([ - 'testmodel_text' => 'unique_single1', - 'testmodel_unique_single' => 'UNIQUE1', - ]); - - $target->store([ - 'testmodel_text' => 'unique_single2', - 'testmodel_unique_single' => 'UNIQUE1', - ]); - - $target->store([ - 'testmodel_text' => 'unique_multi1', - 'testmodel_unique_multi1' => 'UNIQUE_V1', - 'testmodel_unique_multi2' => 'UNIQUE_V2', - ]); - $target->store([ - 'testmodel_text' => 'unique_multi2', - 'testmodel_unique_multi1' => 'UNIQUE_V1', - 'testmodel_unique_multi2' => 'UNIQUE_V2', - ]); - - $target->finish(); - - $model = $this->getModel('testmodel'); - - $res = $model->search()->getResult(); - $this->assertCount(2, $res); - } - - /** - * [testTargetStoreByUniqueWillFail description] - */ - public function testTargetStoreBySingularUniqueWillFail(): void { - - $this->expectException(\PDOException::class); - - $target = new \codename\core\io\target\model\complex('test', [ - 'structure' => [ - 'model' => 'testmodel', - 'join' => [ + 'testmodel_id' => 1, + 'testmodel_text' => 'simple', + 'testmodelj_text' => 'simple', + ], + ], $result); + } + + /** + * @return void + * @throws ReflectionException + * @throws exception + */ + public function testTargetReplaceStoreSimpleWithoutUnique(): void + { + $target = new complex('test', [ + 'structure' => [ + 'model' => 'testmodelj', + 'join' => [ + ], + ], + 'method' => 'replace', + ]); + + $target->setVirtualStoreEnabled(true); + static::assertTrue($target->getVirtualStoreEnabled()); + + $target->store([ + 'testmodelj_text' => 'simple', + ]); + + $target->finish(); + + $result = $target->getVirtualStoreData(); + + static::assertEquals([ [ - 'model' => 'testmodelj', - 'join' => [], - ] - ], - ], - 'method' => 'save' - ]); - - $target->store([ - 'testmodel_text' => 'unique_single1', - 'testmodel_unique_single' => 'UNIQUE1', - ]); - - $target->store([ - 'testmodel_text' => 'unique_single2', - 'testmodel_unique_single' => 'UNIQUE1', - ]); - } - - /** - * [testTargetStoreByMultipleUniqueWillFail description] - */ - public function testTargetStoreByMultipleUniqueWillFail(): void { - - $this->expectException(\PDOException::class); - - $target = new \codename\core\io\target\model\complex('test', [ - 'structure' => [ - 'model' => 'testmodel', - 'join' => [ + 'testmodelj_text' => 'simple', + ], + ], $result); + } + + /** + * @return void + * @throws ReflectionException + * @throws exception + */ + public function testTargetStoreByUniqueVirtual(): void + { + $target = new complex('test', [ + 'structure' => [ + 'model' => 'testmodel', + 'join' => [ + [ + 'model' => 'testmodelj', + 'join' => [], + ], + ], + ], + 'method' => 'replace', + ]); + + $target->store([ + 'testmodel_text' => 'unique_single1', + 'testmodel_unique_single' => 'UNIQUE1', + ]); + + // + // Get the ID just created + // for usage, further below. + // + $unique1Id = $this->getModel('testmodel') + ->addFilter('testmodel_unique_single', 'UNIQUE1') + ->search()->getResult()[0]['testmodel_id']; + static::assertNotNull($unique1Id); + + $target->store([ + 'testmodel_text' => 'unique_multi1', + 'testmodel_unique_multi1' => 'UNIQUE_V1', + 'testmodel_unique_multi2' => 'UNIQUE_V2', + ]); + + $target->setVirtualStoreEnabled(true); + static::assertTrue($target->getVirtualStoreEnabled()); + + $target->store([ + 'testmodel_text' => 'unique_single2', + 'testmodel_unique_single' => 'UNIQUE1', + ]); + + $target->store([ + 'testmodel_text' => 'unique_multi2', + 'testmodel_unique_multi1' => 'UNIQUE_V1_', + 'testmodel_unique_multi2' => 'UNIQUE_V2_', + ]); + + $target->finish(); + + $model = $this->getModel('testmodel'); + + $res = $model->search()->getResult(); + static::assertCount(2, $res); + + $result = $target->getVirtualStoreData(); + + static::assertEquals([ [ - 'model' => 'testmodelj', - 'join' => [], - ] - ], - ], - 'method' => 'save' - ]); - - $target->store([ - 'testmodel_text' => 'unique_multi1', - 'testmodel_unique_multi1' => 'UNIQUE_V1', - 'testmodel_unique_multi2' => 'UNIQUE_V2', - ]); - $target->store([ - 'testmodel_text' => 'unique_multi2', - 'testmodel_unique_multi1' => 'UNIQUE_V1', - 'testmodel_unique_multi2' => 'UNIQUE_V2', - ]); - } - - /** - * [testTargetStoreReadUsingDatasource description] - */ - public function testTargetStoreReadUsingDatasource(): void { - $target = new \codename\core\io\target\model\complex('test', [ - 'structure' => [ - 'model' => 'testmodel', - 'join' => [ + 'testmodel_text' => 'unique_single2', + 'testmodel_unique_single' => 'UNIQUE1', + 'testmodel_id' => $unique1Id, + ], [ - 'model' => 'testmodelj', - 'join' => [], - ] - ], - ], - 'method' => 'replace' - ]); - - $target->store([ - 'testmodel_text' => 'unique_single1', - 'testmodel_unique_single' => 'UNIQUE1', - ]); - - $target->store([ - 'testmodel_text' => 'unique_single2', - 'testmodel_unique_single' => 'UNIQUE1', - ]); - - $target->store([ - 'testmodel_text' => 'unique_multi1', - 'testmodel_unique_multi1' => 'UNIQUE_V1', - 'testmodel_unique_multi2' => 'UNIQUE_V2', - ]); - $target->store([ - 'testmodel_text' => 'unique_multi2', - 'testmodel_unique_multi1' => 'UNIQUE_V1', - 'testmodel_unique_multi2' => 'UNIQUE_V2', - ]); - - $datasource = new \codename\core\io\datasource\model([ - 'query' => [], - 'model' => 'testmodel', - ]); - - $res = []; - foreach($datasource as $r) { - $res[] = $r; + 'testmodel_text' => 'unique_multi2', + 'testmodel_unique_multi1' => 'UNIQUE_V1_', + 'testmodel_unique_multi2' => 'UNIQUE_V2_', + ], + ], $result); } - $this->assertEquals(['unique_single2', 'unique_multi2'], array_column($res, 'testmodel_text')); - } + /** + * @return void + * @throws ReflectionException + * @throws exception + */ + public function testTargetStoreByUnique(): void + { + $target = new complex('test', [ + 'structure' => [ + 'model' => 'testmodel', + 'join' => [ + [ + 'model' => 'testmodelj', + 'join' => [], + ], + ], + ], + 'method' => 'replace', + ]); + + $target->store([ + 'testmodel_text' => 'unique_single1', + 'testmodel_unique_single' => 'UNIQUE1', + ]); + + $target->store([ + 'testmodel_text' => 'unique_single2', + 'testmodel_unique_single' => 'UNIQUE1', + ]); + + $target->store([ + 'testmodel_text' => 'unique_multi1', + 'testmodel_unique_multi1' => 'UNIQUE_V1', + 'testmodel_unique_multi2' => 'UNIQUE_V2', + ]); + $target->store([ + 'testmodel_text' => 'unique_multi2', + 'testmodel_unique_multi1' => 'UNIQUE_V1', + 'testmodel_unique_multi2' => 'UNIQUE_V2', + ]); + + $target->finish(); + + $model = $this->getModel('testmodel'); + + $res = $model->search()->getResult(); + static::assertCount(2, $res); + } + /** + * @return void + * @throws ReflectionException + * @throws exception + */ + public function testTargetStoreBySingularUniqueWillFail(): void + { + $this->expectException(PDOException::class); + + $target = new complex('test', [ + 'structure' => [ + 'model' => 'testmodel', + 'join' => [ + [ + 'model' => 'testmodelj', + 'join' => [], + ], + ], + ], + 'method' => 'save', + ]); + + $target->store([ + 'testmodel_text' => 'unique_single1', + 'testmodel_unique_single' => 'UNIQUE1', + ]); + + $target->store([ + 'testmodel_text' => 'unique_single2', + 'testmodel_unique_single' => 'UNIQUE1', + ]); + } + /** + * @return void + * @throws ReflectionException + * @throws exception + */ + public function testTargetStoreByMultipleUniqueWillFail(): void + { + $this->expectException(PDOException::class); + + $target = new complex('test', [ + 'structure' => [ + 'model' => 'testmodel', + 'join' => [ + [ + 'model' => 'testmodelj', + 'join' => [], + ], + ], + ], + 'method' => 'save', + ]); + + $target->store([ + 'testmodel_text' => 'unique_multi1', + 'testmodel_unique_multi1' => 'UNIQUE_V1', + 'testmodel_unique_multi2' => 'UNIQUE_V2', + ]); + $target->store([ + 'testmodel_text' => 'unique_multi2', + 'testmodel_unique_multi1' => 'UNIQUE_V1', + 'testmodel_unique_multi2' => 'UNIQUE_V2', + ]); + } + + /** + * @return void + * @throws ReflectionException + * @throws exception + */ + public function testTargetStoreReadUsingDatasource(): void + { + $target = new complex('test', [ + 'structure' => [ + 'model' => 'testmodel', + 'join' => [ + [ + 'model' => 'testmodelj', + 'join' => [], + ], + ], + ], + 'method' => 'replace', + ]); + + $target->store([ + 'testmodel_text' => 'unique_single1', + 'testmodel_unique_single' => 'UNIQUE1', + ]); + + $target->store([ + 'testmodel_text' => 'unique_single2', + 'testmodel_unique_single' => 'UNIQUE1', + ]); + + $target->store([ + 'testmodel_text' => 'unique_multi1', + 'testmodel_unique_multi1' => 'UNIQUE_V1', + 'testmodel_unique_multi2' => 'UNIQUE_V2', + ]); + $target->store([ + 'testmodel_text' => 'unique_multi2', + 'testmodel_unique_multi1' => 'UNIQUE_V1', + 'testmodel_unique_multi2' => 'UNIQUE_V2', + ]); + + $datasource = new model([ + 'query' => [], + 'model' => 'testmodel', + ]); + + $res = []; + foreach ($datasource as $r) { + $res[] = $r; + } + + static::assertEquals(['unique_single2', 'unique_multi2'], array_column($res, 'testmodel_text')); + } + + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function tearDown(): void + { + $this->getModel('testmodel') + ->addFilter('testmodel_id', 0, '>') + ->delete(); + } + + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function setUp(): void + { + $app = static::createApp(); + + // Additional overrides to get a more complete app lifecycle + // and allow static global app::getModel() to work correctly + $app::__setApp('targettest'); + $app::__setVendor('codename'); + $app::__setNamespace('\\codename\\core\\io\\tests\\target'); + + $app::getAppstack(); + + // avoid re-init + if (static::$initialized) { + return; + } + + static::$initialized = true; + + static::setEnvironmentConfig([ + 'test' => [ + 'database' => [ + // NOTE: by default, we do these tests using + // pure in-memory sqlite. + 'default' => [ + 'driver' => 'sqlite', + 'database_file' => ':memory:', + ], + ], + 'cache' => [ + 'default' => [ + 'driver' => 'memory', + ], + ], + 'filesystem' => [ + 'local' => [ + 'driver' => 'local', + ], + ], + 'log' => [ + 'default' => [ + 'driver' => 'system', + 'data' => [ + 'name' => 'dummy', + ], + ], + ], + ], + ]); + + static::createModel( + 'targettest', + 'testmodel', + testmodel::$staticConfig, + function ($schema, $model, $config) { + return new testmodel([]); + } + ); + + static::createModel( + 'targettest', + 'testmodelj', + testmodelj::$staticConfig, + function ($schema, $model, $config) { + return new testmodelj([]); + } + ); + + static::architect('targettest', 'codename', 'test'); + } } diff --git a/tests/target/model/testmodel.php b/tests/target/model/testmodel.php index fdc3db9..7b42d8a 100644 --- a/tests/target/model/testmodel.php +++ b/tests/target/model/testmodel.php @@ -1,61 +1,65 @@ [ - 'testmodel_id', - 'testmodel_created', - 'testmodel_modified', - 'testmodel_text', - 'testmodel_unique_single', - 'testmodel_unique_multi1', - 'testmodel_unique_multi2', - ], - 'primary' => [ - 'testmodel_id' - ], - 'unique' => [ - 'testmodel_unique_single', - [ 'testmodel_unique_multi1', 'testmodel_unique_multi2' ], - ], - 'options' => [ - 'testmodel_unique_single' => [ - 'length' => 16 +class testmodel extends sqlModel +{ + /** + * static configuration + * for usage in unit tests + * @var array + */ + public static array $staticConfig = [ + 'field' => [ + 'testmodel_id', + 'testmodel_created', + 'testmodel_modified', + 'testmodel_text', + 'testmodel_unique_single', + 'testmodel_unique_multi1', + 'testmodel_unique_multi2', ], - 'testmodel_unique_multi1' => [ - 'length' => 16 + 'primary' => [ + 'testmodel_id', ], - 'testmodel_unique_multi2' => [ - 'length' => 16 + 'unique' => [ + 'testmodel_unique_single', + ['testmodel_unique_multi1', 'testmodel_unique_multi2'], ], - ], - 'datatype' => [ - 'testmodel_id' => 'number_natural', - 'testmodel_created' => 'text_timestamp', - 'testmodel_modified' => 'text_timestamp', - 'testmodel_text' => 'text', - 'testmodel_unique_single' => 'text', - 'testmodel_unique_multi1' => 'text', - 'testmodel_unique_multi2' => 'text', - ], - 'connection' => 'default' - ]; + 'options' => [ + 'testmodel_unique_single' => [ + 'length' => 16, + ], + 'testmodel_unique_multi1' => [ + 'length' => 16, + ], + 'testmodel_unique_multi2' => [ + 'length' => 16, + ], + ], + 'datatype' => [ + 'testmodel_id' => 'number_natural', + 'testmodel_created' => 'text_timestamp', + 'testmodel_modified' => 'text_timestamp', + 'testmodel_text' => 'text', + 'testmodel_unique_single' => 'text', + 'testmodel_unique_multi1' => 'text', + 'testmodel_unique_multi2' => 'text', + ], + 'connection' => 'default', + ]; + + /** + * {@inheritDoc} + */ + public function __construct(array $modeldata = []) + { + parent::__construct('targettest', 'testmodel', static::$staticConfig); + } } diff --git a/tests/target/model/testmodelj.php b/tests/target/model/testmodelj.php index 7597e4c..a2a07f9 100644 --- a/tests/target/model/testmodelj.php +++ b/tests/target/model/testmodelj.php @@ -1,57 +1,61 @@ [ - 'testmodelj_id', - 'testmodelj_created', - 'testmodelj_modified', - 'testmodelj_testmodel_id', - 'testmodelj_testmodel', - 'testmodelj_text', - ], - 'primary' => [ - 'testmodelj_id' - ], - 'children' => [ - 'testmodelj_testmodel' => [ - 'type' => 'foreign', - 'field' => 'testmodelj_testmodel_id', - ] - ], - 'foreign' => [ - 'testmodelj_testmodel_id' => [ - 'schema' => 'targettest', - 'model' => 'testmodel', - 'key' => 'testmodel_id' +class testmodelj extends sqlModel +{ + /** + * static configuration + * for usage in unit tests + * @var array + */ + public static array $staticConfig = [ + 'field' => [ + 'testmodelj_id', + 'testmodelj_created', + 'testmodelj_modified', + 'testmodelj_testmodel_id', + 'testmodelj_testmodel', + 'testmodelj_text', + ], + 'primary' => [ + 'testmodelj_id', ], - ], - 'datatype' => [ - 'testmodelj_id' => 'number_natural', - 'testmodelj_created' => 'text_timestamp', - 'testmodelj_modified' => 'text_timestamp', - 'testmodelj_testmodel_id' => 'number_natural', - 'testmodelj_testmodel' => 'virtual', - 'testmodelj_text' => 'text', - ], - 'connection' => 'default' - ]; + 'children' => [ + 'testmodelj_testmodel' => [ + 'type' => 'foreign', + 'field' => 'testmodelj_testmodel_id', + ], + ], + 'foreign' => [ + 'testmodelj_testmodel_id' => [ + 'schema' => 'targettest', + 'model' => 'testmodel', + 'key' => 'testmodel_id', + ], + ], + 'datatype' => [ + 'testmodelj_id' => 'number_natural', + 'testmodelj_created' => 'text_timestamp', + 'testmodelj_modified' => 'text_timestamp', + 'testmodelj_testmodel_id' => 'number_natural', + 'testmodelj_testmodel' => 'virtual', + 'testmodelj_text' => 'text', + ], + 'connection' => 'default', + ]; + + /** + * {@inheritDoc} + */ + public function __construct(array $modeldata = []) + { + parent::__construct('targettest', 'testmodelj', static::$staticConfig); + } } diff --git a/tests/target/modelTest.php b/tests/target/modelTest.php index 0e7271f..70782b7 100644 --- a/tests/target/modelTest.php +++ b/tests/target/modelTest.php @@ -1,249 +1,271 @@ getModel('testmodel') - ->addFilter('testmodel_id', 0, '>') - ->delete(); - } - - /** - * @inheritDoc - */ - protected function setUp(): void - { - $app = static::createApp(); - - // Additional overrides to get a more complete app lifecycle - // and allow static global app::getModel() to work correctly - $app->__setApp('targettest'); - $app->__setVendor('codename'); - $app->__setNamespace('\\codename\\core\\io\\tests\\target'); - - $app->getAppstack(); - - // avoid re-init - if(static::$initialized) { - return; + /** + * @return void + * @throws ReflectionException + * @throws exception + */ + public function testTargetStoreSimple(): void + { + $target = new \codename\core\io\target\model('test', [ + 'model' => 'testmodel', + // default method fallback should be: save + ]); + + $target->store([ + 'testmodel_text' => 'simple', + ]); + + $target->finish(); + + $model = $this->getModel('testmodel'); + $res = $model + ->addFilter('testmodel_text', 'simple') + ->search()->getResult(); + static::assertCount(1, $res); } - static::$initialized = true; - - static::setEnvironmentConfig([ - 'test' => [ - 'database' => [ - // NOTE: by default, we do these tests using - // pure in-memory sqlite. - 'default' => [ - 'driver' => 'sqlite', - // 'database_file' => 'testmodel.sqlite', - 'database_file' => ':memory:', - ], - ], - 'cache' => [ - 'default' => [ - 'driver' => 'memory' - ] - ], - 'filesystem' =>[ - 'local' => [ - 'driver' => 'local', - ] - ], - 'log' => [ - 'default' => [ - 'driver' => 'system', - 'data' => [ - 'name' => 'dummy' - ] - ] - ], - ] - ]); - - static::createModel( - 'targettest', 'testmodel', - \codename\core\io\tests\target\model\testmodel::$staticConfig, - function($schema, $model, $config) { - return new \codename\core\io\tests\target\model\testmodel([]); - }); - - static::architect('targettest', 'codename', 'test'); - } - - /** - * [testTargetStoreSimple description] - */ - public function testTargetStoreSimple(): void { - $target = new \codename\core\io\target\model('test', [ - 'model' => 'testmodel', - // default method fallback should be: save - ]); - - $target->store([ - 'testmodel_text' => 'simple' - ]); - - $target->finish(); - - $model = $this->getModel('testmodel'); - $res = $model - ->addFilter('testmodel_text', 'simple') - ->search()->getResult(); - $this->assertCount(1, $res); - } - - /** - * [testTargetStoreByUnique description] - */ - public function testTargetStoreByUnique(): void { - - $target = new \codename\core\io\target\model('test', [ - 'model' => 'testmodel', - 'method' => 'replace' - ]); - - $target->store([ - 'testmodel_text' => 'unique_single1', - 'testmodel_unique_single' => 'UNIQUE1', - ]); - - $target->store([ - 'testmodel_text' => 'unique_single2', - 'testmodel_unique_single' => 'UNIQUE1', - ]); - - $target->store([ - 'testmodel_text' => 'unique_multi1', - 'testmodel_unique_multi1' => 'UNIQUE_V1', - 'testmodel_unique_multi2' => 'UNIQUE_V2', - ]); - $target->store([ - 'testmodel_text' => 'unique_multi2', - 'testmodel_unique_multi1' => 'UNIQUE_V1', - 'testmodel_unique_multi2' => 'UNIQUE_V2', - ]); - - $target->finish(); - - $model = $this->getModel('testmodel'); - - $res = $model->search()->getResult(); - $this->assertCount(2, $res); - } - - /** - * [testTargetStoreByUniqueWillFail description] - */ - public function testTargetStoreBySingularUniqueWillFail(): void { - - $this->expectException(\PDOException::class); - - $target = new \codename\core\io\target\model('test', [ - 'model' => 'testmodel', - 'method' => 'save' - ]); - - $target->store([ - 'testmodel_text' => 'unique_single1', - 'testmodel_unique_single' => 'UNIQUE1', - ]); - - $target->store([ - 'testmodel_text' => 'unique_single2', - 'testmodel_unique_single' => 'UNIQUE1', - ]); - } - - /** - * [testTargetStoreByMultipleUniqueWillFail description] - */ - public function testTargetStoreByMultipleUniqueWillFail(): void { - - $this->expectException(\PDOException::class); - - $target = new \codename\core\io\target\model('test', [ - 'model' => 'testmodel', - 'method' => 'save' - ]); - - $target->store([ - 'testmodel_text' => 'unique_multi1', - 'testmodel_unique_multi1' => 'UNIQUE_V1', - 'testmodel_unique_multi2' => 'UNIQUE_V2', - ]); - $target->store([ - 'testmodel_text' => 'unique_multi2', - 'testmodel_unique_multi1' => 'UNIQUE_V1', - 'testmodel_unique_multi2' => 'UNIQUE_V2', - ]); - } - - /** - * [testTargetStoreReadUsingDatasource description] - */ - public function testTargetStoreReadUsingDatasource(): void { - $target = new \codename\core\io\target\model('test', [ - 'model' => 'testmodel', - 'method' => 'replace' - ]); - - $target->store([ - 'testmodel_text' => 'unique_single1', - 'testmodel_unique_single' => 'UNIQUE1', - ]); - - $target->store([ - 'testmodel_text' => 'unique_single2', - 'testmodel_unique_single' => 'UNIQUE1', - ]); - - $target->store([ - 'testmodel_text' => 'unique_multi1', - 'testmodel_unique_multi1' => 'UNIQUE_V1', - 'testmodel_unique_multi2' => 'UNIQUE_V2', - ]); - $target->store([ - 'testmodel_text' => 'unique_multi2', - 'testmodel_unique_multi1' => 'UNIQUE_V1', - 'testmodel_unique_multi2' => 'UNIQUE_V2', - ]); - - $datasource = new \codename\core\io\datasource\model([ - 'query' => [], - 'model' => 'testmodel', - ]); - - $res = []; - foreach($datasource as $r) { - $res[] = $r; + /** + * [testTargetStoreByUnique description] + * @throws ReflectionException + * @throws exception + */ + public function testTargetStoreByUnique(): void + { + $target = new \codename\core\io\target\model('test', [ + 'model' => 'testmodel', + 'method' => 'replace', + ]); + + $target->store([ + 'testmodel_text' => 'unique_single1', + 'testmodel_unique_single' => 'UNIQUE1', + ]); + + $target->store([ + 'testmodel_text' => 'unique_single2', + 'testmodel_unique_single' => 'UNIQUE1', + ]); + + $target->store([ + 'testmodel_text' => 'unique_multi1', + 'testmodel_unique_multi1' => 'UNIQUE_V1', + 'testmodel_unique_multi2' => 'UNIQUE_V2', + ]); + $target->store([ + 'testmodel_text' => 'unique_multi2', + 'testmodel_unique_multi1' => 'UNIQUE_V1', + 'testmodel_unique_multi2' => 'UNIQUE_V2', + ]); + + $target->finish(); + + $model = $this->getModel('testmodel'); + + $res = $model->search()->getResult(); + static::assertCount(2, $res); } - $this->assertEquals(['unique_single2', 'unique_multi2'], array_column($res, 'testmodel_text')); - } + /** + * [testTargetStoreByUniqueWillFail description] + * @throws ReflectionException + * @throws exception + */ + public function testTargetStoreBySingularUniqueWillFail(): void + { + $this->expectException(PDOException::class); + + $target = new \codename\core\io\target\model('test', [ + 'model' => 'testmodel', + 'method' => 'save', + ]); + + $target->store([ + 'testmodel_text' => 'unique_single1', + 'testmodel_unique_single' => 'UNIQUE1', + ]); + + $target->store([ + 'testmodel_text' => 'unique_single2', + 'testmodel_unique_single' => 'UNIQUE1', + ]); + } + /** + * [testTargetStoreByMultipleUniqueWillFail description] + * @throws ReflectionException + * @throws exception + */ + public function testTargetStoreByMultipleUniqueWillFail(): void + { + $this->expectException(PDOException::class); + + $target = new \codename\core\io\target\model('test', [ + 'model' => 'testmodel', + 'method' => 'save', + ]); + + $target->store([ + 'testmodel_text' => 'unique_multi1', + 'testmodel_unique_multi1' => 'UNIQUE_V1', + 'testmodel_unique_multi2' => 'UNIQUE_V2', + ]); + $target->store([ + 'testmodel_text' => 'unique_multi2', + 'testmodel_unique_multi1' => 'UNIQUE_V1', + 'testmodel_unique_multi2' => 'UNIQUE_V2', + ]); + } + /** + * [testTargetStoreReadUsingDatasource description] + * @throws ReflectionException + * @throws exception + */ + public function testTargetStoreReadUsingDatasource(): void + { + $target = new \codename\core\io\target\model('test', [ + 'model' => 'testmodel', + 'method' => 'replace', + ]); + + $target->store([ + 'testmodel_text' => 'unique_single1', + 'testmodel_unique_single' => 'UNIQUE1', + ]); + + $target->store([ + 'testmodel_text' => 'unique_single2', + 'testmodel_unique_single' => 'UNIQUE1', + ]); + + $target->store([ + 'testmodel_text' => 'unique_multi1', + 'testmodel_unique_multi1' => 'UNIQUE_V1', + 'testmodel_unique_multi2' => 'UNIQUE_V2', + ]); + $target->store([ + 'testmodel_text' => 'unique_multi2', + 'testmodel_unique_multi1' => 'UNIQUE_V1', + 'testmodel_unique_multi2' => 'UNIQUE_V2', + ]); + + $datasource = new model([ + 'query' => [], + 'model' => 'testmodel', + ]); + + $res = []; + foreach ($datasource as $r) { + $res[] = $r; + } + + static::assertEquals(['unique_single2', 'unique_multi2'], array_column($res, 'testmodel_text')); + } + + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function tearDown(): void + { + $this->getModel('testmodel') + ->addFilter('testmodel_id', 0, '>') + ->delete(); + } + + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function setUp(): void + { + $app = static::createApp(); + + // Additional overrides to get a more complete app lifecycle + // and allow static global app::getModel() to work correctly + $app::__setApp('targettest'); + $app::__setVendor('codename'); + $app::__setNamespace('\\codename\\core\\io\\tests\\target'); + + $app::getAppstack(); + + // avoid re-init + if (static::$initialized) { + return; + } + + static::$initialized = true; + + static::setEnvironmentConfig([ + 'test' => [ + 'database' => [ + // NOTE: by default, we do these tests using + // pure in-memory sqlite. + 'default' => [ + 'driver' => 'sqlite', + // 'database_file' => 'testmodel.sqlite', + 'database_file' => ':memory:', + ], + ], + 'cache' => [ + 'default' => [ + 'driver' => 'memory', + ], + ], + 'filesystem' => [ + 'local' => [ + 'driver' => 'local', + ], + ], + 'log' => [ + 'default' => [ + 'driver' => 'system', + 'data' => [ + 'name' => 'dummy', + ], + ], + ], + ], + ]); + + static::createModel( + 'targettest', + 'testmodel', + testmodel::$staticConfig, + function ($schema, $model, $config) { + return new testmodel([]); + } + ); + + static::architect('targettest', 'codename', 'test'); + } } diff --git a/tests/target/virtualTest.php b/tests/target/virtualTest.php index be135a2..f2646b4 100644 --- a/tests/target/virtualTest.php +++ b/tests/target/virtualTest.php @@ -1,216 +1,242 @@ 'testmodel', + ]); + + // set data + $result = $target->store([ + 'testmodel_text' => 'data', + ]); + static::assertTrue($result); + + // get data + $result = $target->getVirtualStoreData(); + static::assertEquals([ + ['testmodel_text' => 'data'], + ], $result); + + // check finish + try { + $target->finish(); + } catch (\Exception) { + static::fail(); + } + + // check set virtual store + try { + $target->setVirtualStoreEnabled(true); + } catch (\Exception) { + static::fail(); + } + + // check virtual store state + static::assertTrue($target->getVirtualStoreEnabled()); + } + + /** + * [testVirtualModel description] + * @throws ReflectionException + * @throws exception + */ + public function testVirtualModel(): void + { + $target = new virtual('model_example', [ + 'model' => 'testmodel', + ]); + + $model = $target->getModel(); + static::assertInstanceOf(model::class, $model); + } + + /** + * [testVirtualModel description] + * @throws ReflectionException + * @throws exception + */ + public function testVirtualWrongModel(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('EXCEPTION_GETMODEL_MODELNOTFOUND'); + + new virtual('wrong_model_example', [ + 'model' => 'example', + ]); + } - /** - * [protected description] - * @var bool - */ - protected static $initialized = false; - - /** - * @inheritDoc - */ - public static function tearDownAfterClass(): void - { - parent::tearDownAfterClass(); - static::$initialized = false; - } - - /** - * @inheritDoc - */ - protected function tearDown(): void - { - $this->getModel('testmodel') - ->addFilter('testmodel_id', 0, '>') - ->delete(); - } - - /** - * @inheritDoc - */ - protected function setUp(): void - { - $app = static::createApp(); - - // Additional overrides to get a more complete app lifecycle - // and allow static global app::getModel() to work correctly - $app->__setApp('targettest'); - $app->__setVendor('codename'); - $app->__setNamespace('\\codename\\core\\io\\tests\\target'); - - $app->getAppstack(); - - // avoid re-init - if(static::$initialized) { - return; + /** + * [testVirtualFinishedError description] + * @throws ReflectionException + * @throws exception + */ + public function testVirtualFinishedError(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('EXCEPTION_CORE_IO_TARGET_VIRTUAL_ALREADY_FINISHED'); + + $target = new virtual('finished_error', [ + 'model' => 'testmodel', + ]); + + // set finish + try { + $target->finish(); + } catch (\Exception) { + static::fail(); + } + + // set data + $target->store([ + 'testmodel_text' => 'data', + ]); } - static::$initialized = true; - - static::setEnvironmentConfig([ - 'test' => [ - 'database' => [ - // NOTE: by default, we do these tests using - // pure in-memory sqlite. - 'default' => [ - 'driver' => 'sqlite', - // 'database_file' => 'testmodel.sqlite', - 'database_file' => ':memory:', + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function tearDown(): void + { + $this->getModel('testmodel') + ->addFilter('testmodel_id', 0, '>') + ->delete(); + } + + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function setUp(): void + { + $app = static::createApp(); + + // Additional overrides to get a more complete app lifecycle + // and allow static global app::getModel() to work correctly + $app::__setApp('targettest'); + $app::__setVendor('codename'); + $app::__setNamespace('\\codename\\core\\io\\tests\\target'); + + $app::getAppstack(); + + // avoid re-init + if (static::$initialized) { + return; + } + + static::$initialized = true; + + static::setEnvironmentConfig([ + 'test' => [ + 'database' => [ + // NOTE: by default, we do these tests using + // pure in-memory sqlite. + 'default' => [ + 'driver' => 'sqlite', + // 'database_file' => 'testmodel.sqlite', + 'database_file' => ':memory:', + ], + ], + 'cache' => [ + 'default' => [ + 'driver' => 'memory', + ], + ], + 'filesystem' => [ + 'local' => [ + 'driver' => 'local', + ], + ], + 'log' => [ + 'default' => [ + 'driver' => 'system', + 'data' => [ + 'name' => 'dummy', + ], + ], + ], + ], + ]); + + static::createModel('targettest', 'testmodel', [ + 'field' => [ + 'testmodel_id', + 'testmodel_created', + 'testmodel_modified', + 'testmodel_text', + 'testmodel_unique_single', + 'testmodel_unique_multi1', + 'testmodel_unique_multi2', + ], + 'primary' => [ + 'testmodel_id', ], - ], - 'cache' => [ - 'default' => [ - 'driver' => 'memory' - ] - ], - 'filesystem' =>[ - 'local' => [ - 'driver' => 'local', - ] - ], - 'log' => [ - 'default' => [ - 'driver' => 'system', - 'data' => [ - 'name' => 'dummy' - ] - ] - ], - ] - ]); - - static::createModel('targettest', 'testmodel', [ - 'field' => [ - 'testmodel_id', - 'testmodel_created', - 'testmodel_modified', - 'testmodel_text', - 'testmodel_unique_single', - 'testmodel_unique_multi1', - 'testmodel_unique_multi2', - ], - 'primary' => [ - 'testmodel_id' - ], - 'unique' => [ - 'testmodel_unique_single', - [ 'testmodel_unique_multi1', 'testmodel_unique_multi2' ], - ], - 'options' => [ - 'testmodel_unique_single' => [ - 'length' => 16 - ], - 'testmodel_unique_multi1' => [ - 'length' => 16 - ], - 'testmodel_unique_multi2' => [ - 'length' => 16 - ], - ], - 'datatype' => [ - 'testmodel_id' => 'number_natural', - 'testmodel_created' => 'text_timestamp', - 'testmodel_modified' => 'text_timestamp', - 'testmodel_text' => 'text', - 'testmodel_unique_single' => 'text', - 'testmodel_unique_multi1' => 'text', - 'testmodel_unique_multi2' => 'text', - ], - 'connection' => 'default' - ], function($schema, $model, $config) { - return new \codename\core\io\tests\target\model\testmodel([]); - }); - - static::architect('targettest', 'codename', 'test'); - } - - /** - * [testVirtualGeneral description] - */ - public function testVirtualGeneral(): void { - - $target = new \codename\core\io\target\virtual('general_example', [ - 'model' => 'testmodel' - ]); - - // set data - $result = $target->store([ - 'testmodel_text' => 'data' - ]); - $this->assertTrue($result); - - // get data - $result = $target->getVirtualStoreData(); - $this->assertEquals([ - [ 'testmodel_text' => 'data' ] - ], $result); - - // check finish - $this->assertEmpty($target->finish()); - - // check set virtual store - $this->assertEmpty($target->setVirtualStoreEnabled(true)); - - // check virtual store state - $this->assertTrue($target->getVirtualStoreEnabled()); - - } - - /** - * [testVirtualModel description] - */ - public function testVirtualModel(): void { - - $target = new \codename\core\io\target\virtual('model_example', [ - 'model' => 'testmodel' - ]); - - $model = $target->getModel(); - $this->assertInstanceOf(\codename\core\model::class, $model); - - } - - /** - * [testVirtualModel description] - */ - public function testVirtualWrongModel(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_GETMODEL_MODELNOTFOUND'); - - $target = new \codename\core\io\target\virtual('wrong_model_example', [ - 'model' => 'example' - ]); - - } - - /** - * [testVirtualFinishedError description] - */ - public function testVirtualFinishedError(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_CORE_IO_TARGET_VIRTUAL_ALREADY_FINISHED'); - - $target = new \codename\core\io\target\virtual('finished_error', [ - 'model' => 'testmodel' - ]); - - // set finish - $this->assertEmpty($target->finish()); - - // set data - $result = $target->store([ - 'testmodel_text' => 'data' - ]); - - } + 'unique' => [ + 'testmodel_unique_single', + ['testmodel_unique_multi1', 'testmodel_unique_multi2'], + ], + 'options' => [ + 'testmodel_unique_single' => [ + 'length' => 16, + ], + 'testmodel_unique_multi1' => [ + 'length' => 16, + ], + 'testmodel_unique_multi2' => [ + 'length' => 16, + ], + ], + 'datatype' => [ + 'testmodel_id' => 'number_natural', + 'testmodel_created' => 'text_timestamp', + 'testmodel_modified' => 'text_timestamp', + 'testmodel_text' => 'text', + 'testmodel_unique_single' => 'text', + 'testmodel_unique_multi1' => 'text', + 'testmodel_unique_multi2' => 'text', + ], + 'connection' => 'default', + ], function ($schema, $model, $config) { + return new testmodel([]); + }); + static::architect('targettest', 'codename', 'test'); + } } diff --git a/tests/target/xml/textTest.php b/tests/target/xml/textTest.php index d0d40db..f785c2b 100644 --- a/tests/target/xml/textTest.php +++ b/tests/target/xml/textTest.php @@ -1,118 +1,132 @@ 'value1', - 'key2' => '2', - 'key3' => '3.1415', - 'key4' => '' - ], - [ - 'key1' => 'value2', - 'key2' => '3', - 'key3' => '4.2344', - 'key4' => '' - ], - [ - 'key1' => 'value3', - 'key2' => '4', - 'key3' => '5.4545', - 'key4' => '' - ], - ]; - } - - /** - * [testXmlCase1 description] - */ - public function testXmlCase1(): void { - - $target = new \codename\core\io\target\xml\text('xml_test', [ - 'version' => '1.0', - 'encoding' => 'UTF-8', - 'mapping' => [ - 'key1' => [ 'path' => [ 'process' ] ], - 'key2' => [ 'path' => [ 'process' ] ], - 'key3' => [ 'path' => [ 'process' ] ], - 'key4' => [ 'path' => [ 'process' ] ], - ], - ]); - - $samples = $this->getSampleData(); - foreach($samples as $sample) { - $result = $target->store($sample); - $this->assertTrue($result); + /** + * [testXmlCase1 description] + * @throws ReflectionException + * @throws ParseException + * @throws exception + */ + public function testXmlCase1(): void + { + $target = new text('xml_test', [ + 'version' => '1.0', + 'encoding' => 'UTF-8', + 'mapping' => [ + 'key1' => ['path' => ['process']], + 'key2' => ['path' => ['process']], + 'key3' => ['path' => ['process']], + 'key4' => ['path' => ['process']], + ], + ]); + + $samples = $this->getSampleData(); + foreach ($samples as $sample) { + $result = $target->store($sample); + static::assertTrue($result); + } + $target->finish(); + + $results = $target->getTextResultArray(); + + foreach ($results as $k => $v) { + $reader = new Service(); + $xmlResults = $reader->parse($v->get()); + + foreach ($xmlResults as $kXml => $vXml) { + $sampleValues = array_values($samples[$k]); + static::assertEquals( + $sampleValues[$kXml], + $vXml['value'], + print_r([ + $sampleValues[$kXml], + $vXml['value'], + ], true) + ); + } + } } - $target->finish(); - - $results = $target->getTextResultArray(); - - foreach($results as $k => $v) { - $reader = new \Sabre\Xml\Reader(); - $reader->xml($v->get()); - $xmlResults = $reader->parse(); - - foreach($xmlResults['value'] as $kXml => $vXml) { - $sampleValues = array_values($samples[$k]); - $this->assertEquals($sampleValues[$kXml], $vXml['value'], print_r([ - $sampleValues[$kXml], - $vXml['value'] - ], true)); - } + /** + * [getSampleData description] + * @return array [description] + */ + protected function getSampleData(): array + { + return [ + [ + 'key1' => 'value1', + 'key2' => '2', + 'key3' => '3.1415', + 'key4' => '', + ], + [ + 'key1' => 'value2', + 'key2' => '3', + 'key3' => '4.2344', + 'key4' => '', + ], + [ + 'key1' => 'value3', + 'key2' => '4', + 'key3' => '5.4545', + 'key4' => '', + ], + ]; } - } - - /** - * [testXmlCase2 description] - */ - public function testXmlCase2(): void { - - $target = new \codename\core\io\target\xml\text('xml_test', [ - 'version' => '1.0', - 'encoding' => 'UTF-8', - 'mapping' => [ - 'process' => [ ], - ], - ]); - - $samples = $this->getSampleData(); - foreach($samples as $sample) { - $result = $target->store([ - 'process' => $sample - ]); - $this->assertTrue($result); - } - $target->finish(); - - $results = $target->getTextResultArray(); - - foreach($results as $k => $v) { - $reader = new \Sabre\Xml\Reader(); - $reader->xml($v->get()); - $xmlResults = $reader->parse(); - - foreach($xmlResults['value'] as $kXml => $vXml) { - $sampleValues = array_values($samples[$k]); - $this->assertEquals($sampleValues[$kXml], $vXml['value'], print_r([ - $sampleValues[$kXml], - $vXml['value'] - ], true)); - } + /** + * [testXmlCase2 description] + * @throws ParseException + * @throws ReflectionException + * @throws exception + */ + public function testXmlCase2(): void + { + $target = new text('xml_test', [ + 'version' => '1.0', + 'encoding' => 'UTF-8', + 'mapping' => [ + 'process' => [], + ], + ]); + + $samples = $this->getSampleData(); + foreach ($samples as $sample) { + $result = $target->store([ + 'process' => $sample, + ]); + static::assertTrue($result); + } + $target->finish(); + + $results = $target->getTextResultArray(); + + foreach ($results as $k => $v) { + $reader = new Service(); + $xmlResults = $reader->parse($v->get()); + + foreach ($xmlResults as $kXml => $vXml) { + $sampleValues = array_values($samples[$k]); + static::assertEquals( + $sampleValues[$kXml], + $vXml['value'], + print_r([ + $sampleValues[$kXml], + $vXml['value'], + ], true) + ); + } + } } - } - - } diff --git a/tests/testImport.php b/tests/testImport.php deleted file mode 100644 index 558b0ac..0000000 --- a/tests/testImport.php +++ /dev/null @@ -1,17 +0,0 @@ -getModel('pipelinemodel') - ->addFilter('pipelinemodel_id', 0, '>') - ->delete(); - - overrideableApp::__setInstance('response', null); - } - - /** - * @inheritDoc - */ - protected function setUp(): void - { - $app = static::createApp(); - - overrideableApp::__injectApp([ - 'vendor' => 'codename', - 'app' => 'core-io', - 'namespace' => '\\codename\\core\\io' - ]); - - // Additional overrides to get a more complete app lifecycle - // and allow static global app::getModel() to work correctly - $app->__setApp('pipelinetest'); - $app->__setVendor('codename'); - $app->__setNamespace('\\codename\\core\\io\\tests\\pipeline'); - - $app->getAppstack(); - - // avoid re-init - if(static::$initialized) { - return; - } - - static::$initialized = true; - - static::setEnvironmentConfig([ - 'test' => [ - 'database' => [ - // NOTE: by default, we do these tests using - // pure in-memory sqlite. - 'default' => [ - 'driver' => 'sqlite', - // 'database_file' => 'pipelinemodel.sqlite', - 'database_file' => ':memory:', - ], - ], - 'cache' => [ - 'default' => [ - 'driver' => 'memory' - ] - ], - 'filesystem' =>[ - 'local' => [ - 'driver' => 'local', - ] - ], - 'log' => [ - 'default' => [ - 'driver' => 'system', - 'data' => [ - 'name' => 'dummy' - ] - ] - ], - ] - ]); - - static::createModel( - 'pipelinetest', 'pipelinemodel', - \codename\core\io\tests\pipeline\model\pipelinemodel::$staticConfig, - function($schema, $model, $config) { - return new \codename\core\io\tests\pipeline\model\pipelinemodel([]); - } - ); - - static::architect('pipelinetest', 'codename', 'test'); - } - - /** - * [testPipelineGeneral description] - */ - public function testPipelineGeneral(): void { - $pipline = new \codename\core\io\pipeline(null, [ - 'example' => true - ]); - - // - // check config - // - $this->assertEquals([ 'example' => true ], $pipline->getConfig()->get()); - - // - // check options - // - $this->assertNull($pipline->getOption('example')); - $pipline->setOptions([ 'example' => true ]); - $this->assertTrue($pipline->getOption('example')); - - // - // check dryrun - // - $pipline->setDryRun(true); - $this->assertTrue($pipline->getDryRun()); - - // - // check erroneous - // - $this->assertEmpty($pipline->getErroneousEntries()); - - // - // set default? - // - $pipline->setDebug(true); - $pipline->setLimit(0, 10); - $pipline->setThrowExceptionOnErroneousData(true); - $pipline->setErrorstackEnabled(true); - $pipline->setSkipErroneous(true); - $pipline->setTrackErroneous(true); - } - - /** - * [testPipelineDatasource description] - */ - public function testPipelineDatasource(): void { - $pipline = new \codename\core\io\pipeline(null, []); - - $datasource = new \codename\core\io\datasource\arraydata(); - $datasource->setData([ - [ - 'key1' => 'abc', - 'key2' => 'def', - 'key3' => 'ghi', - ], - [ - 'key1' => 'jkl', - 'key2' => 'mno', - 'key3' => 'pqr', - ], - [ - 'key1' => 'stu', - 'key2' => 'vwx', - 'key3' => 'yz', - ] - ]); - $pipline->setDatasource($datasource); - $this->assertInstanceOf(\codename\core\io\datasource\arraydata::class, $pipline->getDatasource()); - - $this->assertEquals(3, $pipline->getItemCount()); - $this->assertEquals(null, $pipline->getItemIndex()); - $this->assertEquals(null, $pipline->getStoredItemCount()); - - } - - /** - * [testPipelineDatasourcePipelineInstance description] - */ - public function testPipelineDatasourcePipelineInstance(): void { - $datasource = new \codename\core\io\datasource\model(); - - $pipline = new \codename\core\io\pipeline(null, []); - $pipline->setDatasource($datasource); - $this->assertInstanceOf(\codename\core\io\datasource\model::class, $pipline->getDatasource()); - - } - - /** - * [testPipelineCreateDatasourcePipelineInstance description] - */ - public function testPipelineCreateDatasourcePipelineInstance(): void { - $pipline = new \codename\core\io\pipeline(null, [ - 'source' => [ - 'type' => 'model', - 'config' => [], - ], - ]); - $datasource = $pipline->createDatasource([]); - $pipline->setDatasource($datasource); - $this->assertInstanceOf(\codename\core\io\datasource\model::class, $pipline->getDatasource()); - - } - - /** - * [testPipelineDatasourceBuffered description] - */ - public function testPipelineDatasourceBuffered(): void { - $pipline = new \codename\core\io\pipeline(null, [ - 'config' => [ - 'datasource_buffering' => true, - 'datasource_buffer_size' => 100, - ], - ]); - - $datasource = new \codename\core\io\datasource\arraydata(); - $datasource->setData([ - [ - 'key1' => 'abc', - 'key2' => 'def', - 'key3' => 'ghi', - ], - [ - 'key1' => 'jkl', - 'key2' => 'mno', - 'key3' => 'pqr', - ], - [ - 'key1' => 'stu', - 'key2' => 'vwx', - 'key3' => 'yz', - ] - ]); - $pipline->setDatasource($datasource); - $this->assertInstanceOf(\codename\core\io\datasource\buffered::class, $pipline->getDatasource()); - - } - - /** - * [testPipelineDatasource description] - */ - public function testPipelineDatasourceLoad(): void { - $pipline = new \codename\core\io\pipeline('tests/testPipeline.json', []); - - $datasource = new \codename\core\io\datasource\arraydata(); - $datasource->setData([ - [ - 'key1' => 'abc', - 'key2' => 'def', - 'key3' => 'ghi', - ], - [ - 'key1' => 'jkl', - 'key2' => 'mno', - 'key3' => 'pqr', - ], - [ - 'key1' => 'stu', - 'key2' => 'vwx', - 'key3' => 'yz', - ] - ]); - $pipline->setDatasource($datasource); - $this->assertInstanceOf(\codename\core\io\datasource\arraydata::class, $pipline->getDatasource()); - - $this->assertEquals(3, $pipline->getItemCount()); - $this->assertEquals(null, $pipline->getItemIndex()); - $this->assertEquals(null, $pipline->getStoredItemCount()); - - } - - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $pipline = new \codename\core\io\pipeline('tests/testPipeline2.json', []); - - $this->assertEquals( - [ - 'target.example.example1' => [ - 'type' => 'target.mapping', - 'source' => [ 'transform.example1' ], - ], - 'target.example.example2' => [ - 'type' => 'target.mapping', - 'source' => [ 'transform.example2' ], - ], - 'target.example.example3' => [ - 'type' => 'target.mapping', - 'source' => [ 'transform.example3' ], - ], - 'target.example' => [ - 'type' => 'target', - 'source' => [ 'target.example.example1', 'target.example.example2', 'target.example.example3' ], - ], - 'transform.example1' => [ - 'type' => 'transform', - 'source' => [ ], - ], - 'transform.example2' => [ - 'type' => 'transform', - 'source' => [ 'model.pipelinemodel' ], - ], - 'transform.example3' => [ - 'type' => 'transform', - 'source' => [ 'source.example3' ], - ], - 'model.pipelinemodel' => [ - 'type' => 'model', - ], - 'source.example3' => [ - 'type' => 'source', - ], - 'erroneous.erroneous' => [ - 'type' => 'erroneous', - ], - 'erroneous.data' => [ - 'type' => 'erroneous', - ], - ], - $pipline->getSpecification(), - json_encode($pipline->getSpecification()) - ); - } - -} diff --git a/tests/testPipeline2.json b/tests/testPipeline2.json index 0d0085a..f54fd80 100644 --- a/tests/testPipeline2.json +++ b/tests/testPipeline2.json @@ -1,42 +1,51 @@ { - "info" : { - "name" : "testing pipeline" + "info": { + "name": "testing pipeline" }, - "source" : { - "type" : "arraydata", - "config" : {} + "source": { + "type": "arraydata", + "config": {} }, - "option" : { + "option": { }, - "transform" : { - "example1" : { - "type" : "value", - "config" : { - "value" : "example1" + "transform": { + "example1": { + "type": "value", + "config": { + "value": "example1" } }, - "example2" : { - "type" : "model_map_single", - "config" : { - "model" : "pipelinemodel", - "map" : "pipelinemodel_id" + "example2": { + "type": "model_map_single", + "config": { + "model": "pipelinemodel", + "map": "pipelinemodel_id" } }, - "example3" : { - "type" : "get_value", - "config" : { - "source" : "source", - "field" : "example3" + "example3": { + "type": "get_value", + "config": { + "source": "source", + "field": "example3" } } }, - "target" : { - "example" : { - "type" : "arraydata", - "mapping" : { - "example1" : { "type" : "transform", "field" : "example1" }, - "example2" : { "type" : "transform", "field" : "example2" }, - "example3" : { "type" : "transform", "field" : "example3" } + "target": { + "example": { + "type": "arraydata", + "mapping": { + "example1": { + "type": "transform", + "field": "example1" + }, + "example2": { + "type": "transform", + "field": "example2" + }, + "example3": { + "type": "transform", + "field": "example3" + } } } } diff --git a/tests/testTransformer.php b/tests/testTransformer.php deleted file mode 100644 index 0b70c51..0000000 --- a/tests/testTransformer.php +++ /dev/null @@ -1,79 +0,0 @@ - 'codename', - 'app' => 'core-io', - 'namespace' => '\\codename\\core\\io' - ]); - $app = static::createApp(); - $app->getAppstack(); - } - - /** - * [testTransformerAvailableTransformNames description] - */ - public function testTransformerAvailableTransformNames(): void { - $config = new \codename\core\config\json\extendable(__DIR__ . "/" . 'testTransformer1.json'); - $transformer = new \codename\core\io\transformer($config->get('transform')); - - $result = $transformer->getAvailableTransformNames(); - $this->assertEquals([ 'static_true' ], $result); - - } - - /** - * [testTransformerAvailableTransformNames description] - */ - public function testTransformerAddTransform(): void { - $transformer = new \codename\core\io\transformer([]); - - $transformer->addTransform('example', [ - 'type' => 'value', - 'config' => [ - 'value' => 'example' - ], - ]); - - $result = $transformer->getTransformInstance('example'); - $this->assertInstanceOf(\codename\core\io\transform::class, $result); - - } - - /** - * [testTransformerTransformInstance description] - */ - public function testTransformerTransformInstance(): void { - $config = new \codename\core\config\json\extendable(__DIR__ . "/" . 'testTransformer1.json'); - $transformer = new \codename\core\io\transformer($config->get('transform')); - - $result = $transformer->getTransformInstance('static_true'); - $this->assertInstanceOf(\codename\core\io\transform::class, $result); - } - - /** - * [testTransformerTransformInstance description] - */ - public function testTransformerWrongTransformInstance(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_NOTFOUND'); - - $config = new \codename\core\config\json\extendable(__DIR__ . "/" . 'testTransformer1.json'); - $transformer = new \codename\core\io\transformer($config->get('transform')); - - $result = $transformer->getTransformInstance('example'); - } - -} diff --git a/tests/testTransformer1.json b/tests/testTransformer1.json index 7d16308..521e888 100644 --- a/tests/testTransformer1.json +++ b/tests/testTransformer1.json @@ -1,19 +1,19 @@ { - "__comment" : "testTransformer", - "mixins" : [ + "__comment": "testTransformer", + "mixins": [ ], - "transform" : { - "static_true" : { - "type" : "value", - "config" : { - "value" : true + "transform": { + "static_true": { + "type": "value", + "config": { + "value": true } }, - "static_false" : { - "type" : "value", - "internal" : true, - "config" : { - "value" : false + "static_false": { + "type": "value", + "internal": true, + "config": { + "value": false } } } diff --git a/tests/transform/abstractTransformTest.php b/tests/transform/abstractTransformTest.php index e3385db..fb53cb3 100644 --- a/tests/transform/abstractTransformTest.php +++ b/tests/transform/abstractTransformTest.php @@ -1,88 +1,95 @@ 'codename', - 'app' => 'core-io', - 'namespace' => '\\codename\\core\\io' - ]); - $app = static::createApp(); - $app->getAppstack(); - } + /** + * [protected description] + * @var array + */ + protected array $transforms = []; - /** - * [protected description] - * @var \codename\core\io\transform[] - */ - protected $transforms = []; - - /** - * @inheritDoc - */ - public function getTransformInstance(string $name): \codename\core\io\transform - { - if(!isset($this->transforms[$name])) { - throw new \Exception('Transform not found: '.$name); + /** + * {@inheritDoc} + * @param string $name + * @return transform + * @throws Exception + */ + public function getTransformInstance(string $name): transform + { + if (!isset($this->transforms[$name])) { + throw new Exception('Transform not found: ' . $name); + } + return $this->transforms[$name]; } - return $this->transforms[$name]; - } - /** - * [addTransform description] - * @param string $name [description] - * @param string $type [description] - * @param array $config [description] - * @return \codename\core\io\transform - */ - protected function addTransform(string $name, string $type, array $config): \codename\core\io\transform { - if($this->transforms[$name] ?? false) { - throw new \Exception("Transform `{$name}` already added."); + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws \codename\core\exception + */ + protected function setUp(): void + { + parent::setUp(); + overrideableApp::__injectApp([ + 'vendor' => 'codename', + 'app' => 'core-io', + 'namespace' => '\\codename\\core\\io', + ]); + $app = static::createApp(); + $app::getAppstack(); } - $this->transforms[$name] = $this->getTransform($type, $config); - return $this->transforms[$name]; - } - /** - * [getTransform description] - * @param string $type [description] - * @param array|null $config [description] - * @return \codename\core\io\transform [description] - */ - protected function getTransform(string $type, ?array $config = null) : \codename\core\io\transform { - $class = app::getInheritedClass('transform_' . $type); - if(class_exists($class)) { - $transform = new $class($config); - if($transform instanceof \codename\core\io\transform) { - // if($transformerInstance instanceof \codename\core\io\pipeline) { - // $transform->setPipelineInstance($transformerInstance); - // } - $transform->setTransformerInstance($this); - } else { - throw new \Exception('Transform has wrong base class: '.$class); - } - return $transform; - } else { - throw new \Exception('Transform class not found: '.$class); + /** + * [addTransform description] + * @param string $name [description] + * @param string $type [description] + * @param array $config [description] + * @return transform + * @throws Exception + */ + protected function addTransform(string $name, string $type, array $config): transform + { + if ($this->transforms[$name] ?? false) { + throw new Exception("Transform `$name` already added."); + } + $this->transforms[$name] = $this->getTransform($type, $config); + return $this->transforms[$name]; } - } - + /** + * [getTransform description] + * @param string $type [description] + * @param array|null $config [description] + * @return transform [description] + * @throws ReflectionException + * @throws \codename\core\exception + */ + protected function getTransform(string $type, ?array $config = null): transform + { + $class = app::getInheritedClass('transform_' . $type); + if (class_exists($class)) { + $transform = new $class($config); + if ($transform instanceof transform) { + $transform->setTransformerInstance($this); + } else { + throw new Exception('Transform has wrong base class: ' . $class); + } + return $transform; + } else { + throw new Exception('Transform class not found: ' . $class); + } + } } diff --git a/tests/transform/calculate/divideTest.php b/tests/transform/calculate/divideTest.php index ac87bac..daab5b3 100644 --- a/tests/transform/calculate/divideTest.php +++ b/tests/transform/calculate/divideTest.php @@ -1,47 +1,56 @@ getTransform('calculate_divide', [ - 'factors' => [ - [ 'source' => 'source', 'field' => 'example_source_field1' ], - [ 'source' => 'source', 'field' => 'example_source_field2' ], - 1.2345, - ], - 'precision' => 2, - ]); - $result = $transform->transform([ - 'example_source_field1' => 5.4321, - 'example_source_field2' => 1.2345, - ]); - // Make sure it stays an array - $this->assertEquals(bcdiv(bcdiv(5.4321, 1.2345, 2), 1.2345, 2), $result); - } +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('calculate_divide', [ - 'factors' => [ - [ 'source' => 'source', 'field' => 'example_source_field1' ], - 'example_source_field2', - ], - 'precision' => 2, - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field1' ] - ], - $transform->getSpecification() - ); - } +class divideTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('calculate_divide', [ + 'factors' => [ + ['source' => 'source', 'field' => 'example_source_field1'], + ['source' => 'source', 'field' => 'example_source_field2'], + 1.2345, + ], + 'precision' => 2, + ]); + $result = $transform->transform([ + 'example_source_field1' => 5.4321, + 'example_source_field2' => 1.2345, + ]); + // Make sure it stays an array + static::assertEquals(bcdiv(bcdiv(5.4321, 1.2345, 2), 1.2345, 2), $result); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('calculate_divide', [ + 'factors' => [ + ['source' => 'source', 'field' => 'example_source_field1'], + 'example_source_field2', + ], + 'precision' => 2, + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field1'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/calculate/multiplyTest.php b/tests/transform/calculate/multiplyTest.php index e53c5f1..57a2fa6 100644 --- a/tests/transform/calculate/multiplyTest.php +++ b/tests/transform/calculate/multiplyTest.php @@ -1,47 +1,56 @@ getTransform('calculate_multiply', [ - 'factors' => [ - [ 'source' => 'source', 'field' => 'example_source_field1' ], - [ 'source' => 'source', 'field' => 'example_source_field2' ], - 1.2345, - ], - 'precision' => 2, - ]); - $result = $transform->transform([ - 'example_source_field1' => 5.4321, - 'example_source_field2' => 1.2345, - ]); - // Make sure it stays an array - $this->assertEquals(bcmul(bcmul(5.4321, 1.2345, 2), 1.2345, 2), $result); - } +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('calculate_multiply', [ - 'factors' => [ - [ 'source' => 'source', 'field' => 'example_source_field1' ], - 'example_source_field2', - ], - 'precision' => 2, - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field1' ] - ], - $transform->getSpecification() - ); - } +class multiplyTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('calculate_multiply', [ + 'factors' => [ + ['source' => 'source', 'field' => 'example_source_field1'], + ['source' => 'source', 'field' => 'example_source_field2'], + 1.2345, + ], + 'precision' => 2, + ]); + $result = $transform->transform([ + 'example_source_field1' => 5.4321, + 'example_source_field2' => 1.2345, + ]); + // Make sure it stays an array + static::assertEquals(bcmul(bcmul(5.4321, 1.2345, 2), 1.2345, 2), $result); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('calculate_multiply', [ + 'factors' => [ + ['source' => 'source', 'field' => 'example_source_field1'], + 'example_source_field2', + ], + 'precision' => 2, + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field1'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/calculate/subtractTest.php b/tests/transform/calculate/subtractTest.php index e827923..8e00402 100644 --- a/tests/transform/calculate/subtractTest.php +++ b/tests/transform/calculate/subtractTest.php @@ -1,47 +1,56 @@ getTransform('calculate_subtract', [ - 'fields' => [ - [ 'source' => 'source', 'field' => 'example_source_field1' ], - [ 'source' => 'source', 'field' => 'example_source_field2' ], - 1.2345, - ], - 'precision' => 2, - ]); - $result = $transform->transform([ - 'example_source_field1' => 5.4321, - 'example_source_field2' => 1.2345, - ]); - // Make sure it stays an array - $this->assertEquals(bcsub(bcsub(5.4321, 1.2345, 2), 1.2345, 2), $result); - } +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('calculate_subtract', [ - 'fields' => [ - [ 'source' => 'source', 'field' => 'example_source_field1' ], - 'example_source_field2', - ], - 'precision' => 2, - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field1' ] - ], - $transform->getSpecification() - ); - } +class subtractTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('calculate_subtract', [ + 'fields' => [ + ['source' => 'source', 'field' => 'example_source_field1'], + ['source' => 'source', 'field' => 'example_source_field2'], + 1.2345, + ], + 'precision' => 2, + ]); + $result = $transform->transform([ + 'example_source_field1' => 5.4321, + 'example_source_field2' => 1.2345, + ]); + // Make sure it stays an array + static::assertEquals(bcsub(bcsub(5.4321, 1.2345, 2), 1.2345, 2), $result); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('calculate_subtract', [ + 'fields' => [ + ['source' => 'source', 'field' => 'example_source_field1'], + 'example_source_field2', + ], + 'precision' => 2, + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field1'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/calculate/sumTest.php b/tests/transform/calculate/sumTest.php index 02f9c60..e3cc60e 100644 --- a/tests/transform/calculate/sumTest.php +++ b/tests/transform/calculate/sumTest.php @@ -1,45 +1,54 @@ getTransform('calculate_sum', [ - 'fields' => [ - [ 'source' => 'source', 'field' => 'example_source_field1' ], - 1.2345, - ], - 'precision' => 2, - ]); - $result = $transform->transform([ - 'example_source_field1' => 1.2345, - ]); - // Make sure it stays an array - $this->assertEquals(bcadd(1.2345, 1.2345, 2), $result); - } +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('calculate_sum', [ - 'fields' => [ - [ 'source' => 'source', 'field' => 'example_source_field1' ], - 'example_source_field2', - ], - 'precision' => 2, - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field1' ] - ], - $transform->getSpecification() - ); - } +class sumTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('calculate_sum', [ + 'fields' => [ + ['source' => 'source', 'field' => 'example_source_field1'], + 1.2345, + ], + 'precision' => 2, + ]); + $result = $transform->transform([ + 'example_source_field1' => 1.2345, + ]); + // Make sure it stays an array + static::assertEquals(bcadd(1.2345, 1.2345, 2), $result); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('calculate_sum', [ + 'fields' => [ + ['source' => 'source', 'field' => 'example_source_field1'], + 'example_source_field2', + ], + 'precision' => 2, + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field1'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/compare/beginswithTest.php b/tests/transform/compare/beginswithTest.php index f365235..83dae7a 100644 --- a/tests/transform/compare/beginswithTest.php +++ b/tests/transform/compare/beginswithTest.php @@ -1,41 +1,50 @@ getTransform('compare_beginswith', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'value' => 'test', - ]); - $result = $transform->transform([ - 'example_source_field' => 'testvalue', - ]); - // Make sure it stays an array - $this->assertTrue($result); - } +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('compare_beginswith', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'value' => 'example_source_field', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } +class beginswithTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('compare_beginswith', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'value' => 'test', + ]); + $result = $transform->transform([ + 'example_source_field' => 'testvalue', + ]); + // Make sure it stays an array + static::assertTrue($result); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('compare_beginswith', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'value' => 'example_source_field', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/compare/datetimeTest.php b/tests/transform/compare/datetimeTest.php index 31e4e0f..15e8f2a 100644 --- a/tests/transform/compare/datetimeTest.php +++ b/tests/transform/compare/datetimeTest.php @@ -1,102 +1,117 @@ getTransform('compare_datetime', [ - 'set_time_to_null' => true, - 'left' => [ - 'source' => 'source', - 'field' => 'example_left_source_field', - 'source_format' => 'Y-m-d', - 'modify' => '+1 day', - ], - 'right' => [ - 'source' => 'source', - 'field' => 'example_right_source_field', - 'source_format' => 'Y-m-d', - 'modify' => '+1 day', - ], - ]); - $result = $transform->transform([ - 'example_left_source_field' => '2021-04-16', - 'example_right_source_field' => '2021-04-16', - ]); - // Make sure it stays an array - $this->assertEquals(0, $result); - } +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - /** - * Testing transforms for Erors - */ - public function testValueValidCase2(): void { - $transform = $this->getTransform('compare_datetime', [ - 'set_time_to_null' => true, - 'left' => [ - 'source' => 'source', - 'field' => 'example_left_source_field', - 'source_format' => 'Y-m-d', - ], - 'right' => [ - 'source' => 'source', - 'field' => 'example_right_source_field', - 'source_format' => 'Y-m-d', - ], - ]); - $result = $transform->transform([ - 'example_left_source_field' => '2021-04-16', - 'example_right_source_field' => '2021-04-17', - ]); - // Make sure it stays an array - $this->assertEquals(-1, $result); - } +class datetimeTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase1(): void + { + $transform = $this->getTransform('compare_datetime', [ + 'set_time_to_null' => true, + 'left' => [ + 'source' => 'source', + 'field' => 'example_left_source_field', + 'source_format' => 'Y-m-d', + 'modify' => '+1 day', + ], + 'right' => [ + 'source' => 'source', + 'field' => 'example_right_source_field', + 'source_format' => 'Y-m-d', + 'modify' => '+1 day', + ], + ]); + $result = $transform->transform([ + 'example_left_source_field' => '2021-04-16', + 'example_right_source_field' => '2021-04-16', + ]); + // Make sure it stays an array + static::assertEquals(0, $result); + } - /** - * Testing transforms for Erors - */ - public function testValueValidCase3(): void { - $transform = $this->getTransform('compare_datetime', [ - 'set_time_to_null' => true, - 'left' => [ - 'source' => 'source', - 'field' => 'example_left_source_field', - 'source_format' => 'Y-m-d', - ], - 'right' => [ - 'source' => 'source', - 'field' => 'example_right_source_field', - 'source_format' => 'Y-m-d', - ], - ]); - $result = $transform->transform([ - 'example_left_source_field' => '2021-04-17', - 'example_right_source_field' => '2021-04-16', - ]); - // Make sure it stays an array - $this->assertEquals(1, $result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase2(): void + { + $transform = $this->getTransform('compare_datetime', [ + 'set_time_to_null' => true, + 'left' => [ + 'source' => 'source', + 'field' => 'example_left_source_field', + 'source_format' => 'Y-m-d', + ], + 'right' => [ + 'source' => 'source', + 'field' => 'example_right_source_field', + 'source_format' => 'Y-m-d', + ], + ]); + $result = $transform->transform([ + 'example_left_source_field' => '2021-04-16', + 'example_right_source_field' => '2021-04-17', + ]); + // Make sure it stays an array + static::assertEquals(-1, $result); + } - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('compare_datetime', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'value' => 'example_source_field', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'TODO_SPEC' ] - ], - $transform->getSpecification() - ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase3(): void + { + $transform = $this->getTransform('compare_datetime', [ + 'set_time_to_null' => true, + 'left' => [ + 'source' => 'source', + 'field' => 'example_left_source_field', + 'source_format' => 'Y-m-d', + ], + 'right' => [ + 'source' => 'source', + 'field' => 'example_right_source_field', + 'source_format' => 'Y-m-d', + ], + ]); + $result = $transform->transform([ + 'example_left_source_field' => '2021-04-17', + 'example_right_source_field' => '2021-04-16', + ]); + // Make sure it stays an array + static::assertEquals(1, $result); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('compare_datetime', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'value' => 'example_source_field', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['TODO_SPEC'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/compare/isdayTest.php b/tests/transform/compare/isdayTest.php index 8941280..0028654 100644 --- a/tests/transform/compare/isdayTest.php +++ b/tests/transform/compare/isdayTest.php @@ -1,57 +1,69 @@ getTransform('compare_isday', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'value' => 'Sunday', - ]); - $result = $transform->transform([ - 'example_source_field' => '2021-04-11', - ]); - // Make sure it stays an array - $this->assertTrue($result); - } +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - /** - * Testing transforms for Erors - */ - public function testValueValidCase2(): void { - $transform = $this->getTransform('compare_isday', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'value' => [ 'Sunday' ], - ]); - $result = $transform->transform([ - 'example_source_field' => '2021-04-11', - ]); - // Make sure it stays an array - $this->assertTrue($result); - } +class isdayTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase1(): void + { + $transform = $this->getTransform('compare_isday', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'value' => 'Sunday', + ]); + $result = $transform->transform([ + 'example_source_field' => '2021-04-11', + ]); + // Make sure it stays an array + static::assertTrue($result); + } - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('compare_isday', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'value' => 1, - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase2(): void + { + $transform = $this->getTransform('compare_isday', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'value' => ['Sunday'], + ]); + $result = $transform->transform([ + 'example_source_field' => '2021-04-11', + ]); + // Make sure it stays an array + static::assertTrue($result); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('compare_isday', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'value' => 1, + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/compare/isequalTest.php b/tests/transform/compare/isequalTest.php index 5a154e7..0464ce6 100644 --- a/tests/transform/compare/isequalTest.php +++ b/tests/transform/compare/isequalTest.php @@ -1,41 +1,50 @@ getTransform('compare_isequal', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'value' => 'hello', - ]); - $result = $transform->transform([ - 'example_source_field' => 'hello', - ]); - // Make sure it stays an array - $this->assertTrue($result); - } +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('compare_isequal', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'value' => 1, - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } +class isequalTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('compare_isequal', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'value' => 'hello', + ]); + $result = $transform->transform([ + 'example_source_field' => 'hello', + ]); + // Make sure it stays an array + static::assertTrue($result); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('compare_isequal', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'value' => 1, + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/compare/isholidayTest.php b/tests/transform/compare/isholidayTest.php index 7ff4f8b..84e0c2c 100644 --- a/tests/transform/compare/isholidayTest.php +++ b/tests/transform/compare/isholidayTest.php @@ -1,211 +1,225 @@ getModel('holidays') - ->addFilter('holidays_id', 0, '>') - ->delete(); - } - - /** - * @inheritDoc - */ - protected function setUp(): void - { - $app = static::createApp(); - - // Don't forget to inject core-io - overrideableApp::__injectApp([ - 'vendor' => 'codename', - 'app' => 'core-io', - 'namespace' => '\\codename\\core\\io' - ]); - - // Additional overrides to get a more complete app lifecycle - // and allow static global app::getModel() to work correctly - $app->__setApp('transformmodeltest'); - $app->__setVendor('codename'); - $app->__setNamespace('\\codename\\core\\io\\tests\\transform\\compare'); - - $app->getAppstack(); - - // avoid re-init - if(static::$initialized) { - return; + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $this->getModel('holidays')->save([ + 'holidays_country' => 'DE', + 'holidays_orderitemcommission_type' => 'energy', + 'holidays_check_date' => '2021-04-19', + 'holidays_can_change' => false, + ]); + + $transform = $this->getTransform('compare_isholiday', [ + 'country' => [ + 'source' => 'source', + 'field' => 'example_country_field', + ], + 'date' => [ + 'source' => 'source', + 'field' => 'example_date_field', + ], + ]); + $result = $transform->transform([ + 'example_country_field' => 'DE', + 'example_date_field' => '2021-04-19', + ]); + // Make sure it stays an array + static::assertTrue($result); } - static::$initialized = true; + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueNotValid(): void + { + $this->getModel('holidays')->save([ + 'holidays_country' => 'DE', + 'holidays_orderitemcommission_type' => 'energy', + 'holidays_check_date' => '2021-04-19', + 'holidays_can_change' => false, + ]); + + $transform = $this->getTransform('compare_isholiday', [ + 'country' => [ + 'source' => 'source', + 'field' => 'example_country_field', + ], + 'date' => [ + 'source' => 'source', + 'field' => 'example_date_field', + ], + ]); + $result = $transform->transform([ + 'example_country_field' => 'DE', + 'example_date_field' => '2021-04-20', + ]); + // Make sure it stays an array + static::assertFalse($result); + } - static::setEnvironmentConfig([ - 'test' => [ - 'database' => [ - // NOTE: by default, we do these tests using - // pure in-memory sqlite. - 'default' => [ - 'driver' => 'sqlite', - 'database_file' => ':memory:', + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('compare_isholiday', [ + 'country' => [ + 'source' => 'source', + 'field' => 'example_country_field', ], - ], - 'cache' => [ - 'default' => [ - 'driver' => 'memory' - ] - ], - 'filesystem' =>[ - 'local' => [ - 'driver' => 'local', - ] - ], - 'log' => [ - 'default' => [ - 'driver' => 'system', - 'data' => [ - 'name' => 'dummy' - ] - ] - ], - ] - ]); - - static::createModel('transformtest', 'holidays', [ - 'field' => [ - 'holidays_id', - 'holidays_created', - 'holidays_modified', - 'holidays_country', - 'holidays_orderitemcommission_type', - 'holidays_check_date', - 'holidays_day_type', - 'holidays_type', - 'holidays_type_name', - 'holidays_can_change', - ], - 'primary' => [ - 'holidays_id' - ], - 'datatype' => [ - 'holidays_id' => 'number_natural', - 'holidays_created' => 'text_timestamp', - 'holidays_modified' => 'text_timestamp', - 'holidays_country' => 'text', - 'holidays_orderitemcommission_type' => 'text', - 'holidays_check_date' => 'text_timestamp', - 'holidays_day_type' => 'number_natural', - 'holidays_type' => 'boolean', - 'holidays_type_name' => 'text', - 'holidays_can_change' => 'boolean', - ], - 'connection' => 'default' - ], function($schema, $model, $config) { - return new \codename\core\io\tests\transform\compare\model\holidays([]); - }); - - static::architect('transformmodeltest', 'codename', 'test'); - } - - /** - * Testing transforms for Erors - */ - public function testValueValid(): void { - $this->getModel('holidays')->save([ - 'holidays_country' => 'DE', - 'holidays_orderitemcommission_type' => 'energy', - 'holidays_check_date' => '2021-04-19', - 'holidays_can_change' => false, - ]); - - $transform = $this->getTransform('compare_isholiday', [ - 'country' => [ - 'source' => 'source', - 'field' => 'example_country_field', - ], - 'date' => [ - 'source' => 'source', - 'field' => 'example_date_field', - ], - ]); - $result = $transform->transform([ - 'example_country_field' => 'DE', - 'example_date_field' => '2021-04-19', - ]); - // Make sure it stays an array - $this->assertTrue($result); - } - - /** - * Testing transforms for Erors - */ - public function testValueNotValid(): void { - $this->getModel('holidays')->save([ - 'holidays_country' => 'DE', - 'holidays_orderitemcommission_type' => 'energy', - 'holidays_check_date' => '2021-04-19', - 'holidays_can_change' => false, - ]); - - $transform = $this->getTransform('compare_isholiday', [ - 'country' => [ - 'source' => 'source', - 'field' => 'example_country_field', - ], - 'date' => [ - 'source' => 'source', - 'field' => 'example_date_field', - ], - ]); - $result = $transform->transform([ - 'example_country_field' => 'DE', - 'example_date_field' => '2021-04-20', - ]); - // Make sure it stays an array - $this->assertFalse($result); - } - - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('compare_isholiday', [ - 'country' => [ - 'source' => 'source', - 'field' => 'example_country_field', - ], - 'date' => [ - 'source' => 'source', - 'field' => 'example_date_field', - ], - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_country_field', 'source.example_date_field' ] - ], - $transform->getSpecification() - ); - } + 'date' => [ + 'source' => 'source', + 'field' => 'example_date_field', + ], + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_country_field', 'source.example_date_field'], + ], + $transform->getSpecification() + ); + } + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function tearDown(): void + { + $this->getModel('holidays') + ->addFilter('holidays_id', 0, '>') + ->delete(); + } + + /** + * {@inheritDoc} + */ + protected function setUp(): void + { + $app = static::createApp(); + + // Don't forget to inject core-io + overrideableApp::__injectApp([ + 'vendor' => 'codename', + 'app' => 'core-io', + 'namespace' => '\\codename\\core\\io', + ]); + + // Additional overrides to get a more complete app lifecycle + // and allow static global app::getModel() to work correctly + $app::__setApp('transformmodeltest'); + $app::__setVendor('codename'); + $app::__setNamespace('\\codename\\core\\io\\tests\\transform\\compare'); + + $app::getAppstack(); + + // avoid re-init + if (static::$initialized) { + return; + } + + static::$initialized = true; + + static::setEnvironmentConfig([ + 'test' => [ + 'database' => [ + // NOTE: by default, we do these tests using + // pure in-memory sqlite. + 'default' => [ + 'driver' => 'sqlite', + 'database_file' => ':memory:', + ], + ], + 'cache' => [ + 'default' => [ + 'driver' => 'memory', + ], + ], + 'filesystem' => [ + 'local' => [ + 'driver' => 'local', + ], + ], + 'log' => [ + 'default' => [ + 'driver' => 'system', + 'data' => [ + 'name' => 'dummy', + ], + ], + ], + ], + ]); + + static::createModel('transformtest', 'holidays', [ + 'field' => [ + 'holidays_id', + 'holidays_created', + 'holidays_modified', + 'holidays_country', + 'holidays_orderitemcommission_type', + 'holidays_check_date', + 'holidays_day_type', + 'holidays_type', + 'holidays_type_name', + 'holidays_can_change', + ], + 'primary' => [ + 'holidays_id', + ], + 'datatype' => [ + 'holidays_id' => 'number_natural', + 'holidays_created' => 'text_timestamp', + 'holidays_modified' => 'text_timestamp', + 'holidays_country' => 'text', + 'holidays_orderitemcommission_type' => 'text', + 'holidays_check_date' => 'text_timestamp', + 'holidays_day_type' => 'number_natural', + 'holidays_type' => 'boolean', + 'holidays_type_name' => 'text', + 'holidays_can_change' => 'boolean', + ], + 'connection' => 'default', + ], function ($schema, $model, $config) { + return new holidays([]); + }); + + static::architect('transformmodeltest', 'codename', 'test'); + } } diff --git a/tests/transform/compare/model/holidays.php b/tests/transform/compare/model/holidays.php index 835051e..cea271a 100644 --- a/tests/transform/compare/model/holidays.php +++ b/tests/transform/compare/model/holidays.php @@ -1,45 +1,49 @@ [ - 'holidays_id', - 'holidays_created', - 'holidays_modified', - 'holidays_country', - 'holidays_orderitemcommission_type', - 'holidays_check_date', - // 'holidays_day_type', - // 'holidays_type', - // 'holidays_type_name', - 'holidays_can_change', - ], - 'primary' => [ - 'holidays_id' - ], - 'datatype' => [ - 'holidays_id' => 'number_natural', - 'holidays_created' => 'text_timestamp', - 'holidays_modified' => 'text_timestamp', - 'holidays_country' => 'text', - 'holidays_orderitemcommission_type' => 'text', - 'holidays_check_date' => 'text_timestamp', - // 'holidays_day_type' => 'number_natural', - // 'holidays_type' => 'boolean', - // 'holidays_type_name' => 'text', - 'holidays_can_change' => 'boolean', - ], - 'connection' => 'default' - ]); - } +class holidays extends sqlModel +{ + /** + * {@inheritDoc} + */ + public function __construct(array $modeldata = []) + { + parent::__construct('transformtest', 'holidays', [ + 'field' => [ + 'holidays_id', + 'holidays_created', + 'holidays_modified', + 'holidays_country', + 'holidays_orderitemcommission_type', + 'holidays_check_date', + // 'holidays_day_type', + // 'holidays_type', + // 'holidays_type_name', + 'holidays_can_change', + ], + 'primary' => [ + 'holidays_id', + ], + 'datatype' => [ + 'holidays_id' => 'number_natural', + 'holidays_created' => 'text_timestamp', + 'holidays_modified' => 'text_timestamp', + 'holidays_country' => 'text', + 'holidays_orderitemcommission_type' => 'text', + 'holidays_check_date' => 'text_timestamp', + // 'holidays_day_type' => 'number_natural', + // 'holidays_type' => 'boolean', + // 'holidays_type_name' => 'text', + 'holidays_can_change' => 'boolean', + ], + 'connection' => 'default', + ]); + } } diff --git a/tests/transform/compare/numberTest.php b/tests/transform/compare/numberTest.php index cde6ce7..f359400 100644 --- a/tests/transform/compare/numberTest.php +++ b/tests/transform/compare/numberTest.php @@ -1,185 +1,212 @@ getTransform('compare_number', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'value' => [ - 'source' => 'source', - 'field' => 'example_value_field', - ], - 'operator' => '=', - 'precision' => 2, - ]); - $result = $transform->transform([ - 'example_source_field' => 1, - 'example_value_field' => 1, - ]); - // Make sure it stays an array - $this->assertTrue($result); - } +class numberTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase1(): void + { + $transform = $this->getTransform('compare_number', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'value' => [ + 'source' => 'source', + 'field' => 'example_value_field', + ], + 'operator' => '=', + 'precision' => 2, + ]); + $result = $transform->transform([ + 'example_source_field' => 1, + 'example_value_field' => 1, + ]); + // Make sure it stays an array + static::assertTrue($result); + } - /** - * Testing transforms for Erors - */ - public function testValueValidCase2(): void { - $transform = $this->getTransform('compare_number', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'value' => [ - 'source' => 'source', - 'field' => 'example_value_field', - ], - 'operator' => '!=', - 'precision' => 2, - ]); - $result = $transform->transform([ - 'example_source_field' => 1, - 'example_value_field' => 2, - ]); - // Make sure it stays an array - $this->assertTrue($result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase2(): void + { + $transform = $this->getTransform('compare_number', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'value' => [ + 'source' => 'source', + 'field' => 'example_value_field', + ], + 'operator' => '!=', + 'precision' => 2, + ]); + $result = $transform->transform([ + 'example_source_field' => 1, + 'example_value_field' => 2, + ]); + // Make sure it stays an array + static::assertTrue($result); + } - /** - * Testing transforms for Erors - */ - public function testValueValidCase3(): void { - $transform = $this->getTransform('compare_number', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'value' => [ - 'source' => 'source', - 'field' => 'example_value_field', - ], - 'operator' => '>', - 'precision' => 2, - ]); - $result = $transform->transform([ - 'example_source_field' => 2, - 'example_value_field' => 1, - ]); - // Make sure it stays an array - $this->assertTrue($result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase3(): void + { + $transform = $this->getTransform('compare_number', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'value' => [ + 'source' => 'source', + 'field' => 'example_value_field', + ], + 'operator' => '>', + 'precision' => 2, + ]); + $result = $transform->transform([ + 'example_source_field' => 2, + 'example_value_field' => 1, + ]); + // Make sure it stays an array + static::assertTrue($result); + } - /** - * Testing transforms for Erors - */ - public function testValueValidCase4(): void { - $transform = $this->getTransform('compare_number', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'value' => [ - 'source' => 'source', - 'field' => 'example_value_field', - ], - 'operator' => '<', - 'precision' => 2, - ]); - $result = $transform->transform([ - 'example_source_field' => 1, - 'example_value_field' => 2, - ]); - // Make sure it stays an array - $this->assertTrue($result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase4(): void + { + $transform = $this->getTransform('compare_number', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'value' => [ + 'source' => 'source', + 'field' => 'example_value_field', + ], + 'operator' => '<', + 'precision' => 2, + ]); + $result = $transform->transform([ + 'example_source_field' => 1, + 'example_value_field' => 2, + ]); + // Make sure it stays an array + static::assertTrue($result); + } - /** - * Testing transforms for Erors - */ - public function testValueValidCase5(): void { - $transform = $this->getTransform('compare_number', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'value' => [ - 'source' => 'source', - 'field' => 'example_value_field', - ], - 'operator' => '>=', - 'precision' => 2, - ]); - $result = $transform->transform([ - 'example_source_field' => 1, - 'example_value_field' => 1, - ]); - // Make sure it stays an array - $this->assertTrue($result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase5(): void + { + $transform = $this->getTransform('compare_number', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'value' => [ + 'source' => 'source', + 'field' => 'example_value_field', + ], + 'operator' => '>=', + 'precision' => 2, + ]); + $result = $transform->transform([ + 'example_source_field' => 1, + 'example_value_field' => 1, + ]); + // Make sure it stays an array + static::assertTrue($result); + } - /** - * Testing transforms for Erors - */ - public function testValueValidCase6(): void { - $transform = $this->getTransform('compare_number', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'value' => [ - 'source' => 'source', - 'field' => 'example_value_field', - ], - 'operator' => '<=', - 'precision' => 2, - ]); - $result = $transform->transform([ - 'example_source_field' => 1, - 'example_value_field' => 1, - ]); - // Make sure it stays an array - $this->assertTrue($result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase6(): void + { + $transform = $this->getTransform('compare_number', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'value' => [ + 'source' => 'source', + 'field' => 'example_value_field', + ], + 'operator' => '<=', + 'precision' => 2, + ]); + $result = $transform->transform([ + 'example_source_field' => 1, + 'example_value_field' => 1, + ]); + // Make sure it stays an array + static::assertTrue($result); + } - /** - * Testing transforms for Erors - */ - public function testValueInvalidOperator(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('INVALID_OPERATOR'); + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueInvalidOperator(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('INVALID_OPERATOR'); - $transform = $this->getTransform('compare_number', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'value' => [ - 'source' => 'source', - 'field' => 'example_value_field', - ], - 'operator' => '!!!', - 'precision' => 2, - ]); - $result = $transform->transform([ - 'example_source_field' => 1, - 'example_value_field' => 1, - ]); - } - - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('compare_number', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'value' => [ - 'source' => 'source', - 'field' => 'example_value_field', - ], - 'operator' => '=', - 'precision' => 2, - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + $transform = $this->getTransform('compare_number', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'value' => [ + 'source' => 'source', + 'field' => 'example_value_field', + ], + 'operator' => '!!!', + 'precision' => 2, + ]); + $transform->transform([ + 'example_source_field' => 1, + 'example_value_field' => 1, + ]); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('compare_number', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'value' => [ + 'source' => 'source', + 'field' => 'example_value_field', + ], + 'operator' => '=', + 'precision' => 2, + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/containsTest.php b/tests/transform/containsTest.php index cd3e3b6..4f43e8a 100644 --- a/tests/transform/containsTest.php +++ b/tests/transform/containsTest.php @@ -1,91 +1,108 @@ getTransform('contains', [ + 'collection' => ['source' => 'source', 'field' => 'example_collection_source_field'], + 'item' => ['source' => 'source', 'field' => 'example_item_source_field'], + ]); + $result = $transform->transform([ + 'example_collection_source_field' => [ + 'test', + 'test1', + 'test2', + ], + 'example_item_source_field' => 'test3', + ]); + // Make sure it stays an array + static::assertFalse($result); + } - /** - * Testing transforms for Erors - */ - public function testValueInvalid(): void { - $transform = $this->getTransform('contains', [ - 'collection' => [ 'source' => 'source', 'field' => 'example_collection_source_field' ], - 'item' => [ 'source' => 'source', 'field' => 'example_item_source_field' ], - ]); - $result = $transform->transform([ - 'example_collection_source_field' => [ - 'test', - 'test1', - 'test2', - ], - 'example_item_source_field' => 'test3' - ]); - // Make sure it stays an array - $this->assertFalse($result); - } - - /** - * Testing transforms for Erors - */ - public function testValueValid(): void { - $transform = $this->getTransform('contains', [ - 'collection' => [ 'source' => 'source', 'field' => 'example_collection_source_field' ], - 'item' => [ 'source' => 'source', 'field' => 'example_item_source_field' ], - ]); - $result = $transform->transform([ - 'example_collection_source_field' => [ - 'test', - 'test1', - 'test2', - ], - 'example_item_source_field' => 'test1' - ]); - // Make sure it stays an array - $this->assertTrue($result); - } - - /** - * Testing transforms for Erors - */ - public function testValueNotSourcFields(): void { - $this->expectException(\codename\core\exception::class); + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('contains', [ + 'collection' => ['source' => 'source', 'field' => 'example_collection_source_field'], + 'item' => ['source' => 'source', 'field' => 'example_item_source_field'], + ]); + $result = $transform->transform([ + 'example_collection_source_field' => [ + 'test', + 'test1', + 'test2', + ], + 'example_item_source_field' => 'test1', + ]); + // Make sure it stays an array + static::assertTrue($result); + } - $transform = $this->getTransform('contains', [ - 'collection' => 'example_collection_source_field', - 'item' => 'example_item_source_field', - ]); - $result = $transform->transform([]); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueNotSourceFields(): void + { + $this->expectException(exception::class); - /** - * Testing transforms for Erors - */ - public function testValueCollectionNotAArray(): void { - $transform = $this->getTransform('contains', [ - 'collection' => [ 'source' => 'source', 'field' => 'example_collection_source_field' ], - 'item' => 'example_item_source_field', - ]); - $result = $transform->transform([ - 'example_collection_source_field' => 'test', - ]); - $this->assertNull($result); - } + $transform = $this->getTransform('contains', [ + 'collection' => 'example_collection_source_field', + 'item' => 'example_item_source_field', + ]); + $transform->transform([]); + } - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('contains', [ - 'collection' => [ 'source' => 'source', 'field' => 'example_collection_source_field' ], - 'item' => [ 'source' => 'source', 'field' => 'example_item_source_field' ], - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_item_source_field', 'source.example_collection_source_field' ] - ], - $transform->getSpecification() - ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueCollectionNotAArray(): void + { + $transform = $this->getTransform('contains', [ + 'collection' => ['source' => 'source', 'field' => 'example_collection_source_field'], + 'item' => 'example_item_source_field', + ]); + $result = $transform->transform([ + 'example_collection_source_field' => 'test', + ]); + static::assertNull($result); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('contains', [ + 'collection' => ['source' => 'source', 'field' => 'example_collection_source_field'], + 'item' => ['source' => 'source', 'field' => 'example_item_source_field'], + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_item_source_field', 'source.example_collection_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/convert/booleanTest.php b/tests/transform/convert/booleanTest.php index 1af32d9..a09ad18 100644 --- a/tests/transform/convert/booleanTest.php +++ b/tests/transform/convert/booleanTest.php @@ -1,187 +1,223 @@ getTransform('convert_boolean', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => true, - ]); - // Make sure it stays an array - $this->assertTrue($result); - } +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - /** - * Testing transforms for Erors - */ - public function testValueTrueCase2(): void { - $transform = $this->getTransform('convert_boolean', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => 1, - ]); - // Make sure it stays an array - $this->assertTrue($result); - } +class booleanTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueTrueCase1(): void + { + $transform = $this->getTransform('convert_boolean', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => true, + ]); + // Make sure it stays an array + static::assertTrue($result); + } - /** - * Testing transforms for Erors - */ - public function testValueTrueCase3(): void { - $transform = $this->getTransform('convert_boolean', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => 'true', - ]); - // Make sure it stays an array - $this->assertTrue($result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueTrueCase2(): void + { + $transform = $this->getTransform('convert_boolean', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => 1, + ]); + // Make sure it stays an array + static::assertTrue($result); + } - /** - * Testing transforms for Erors - */ - public function testValueTrueCase4(): void { - $transform = $this->getTransform('convert_boolean', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => '1', - ]); - // Make sure it stays an array - $this->assertTrue($result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueTrueCase3(): void + { + $transform = $this->getTransform('convert_boolean', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => 'true', + ]); + // Make sure it stays an array + static::assertTrue($result); + } - /** - * Testing transforms for Erors - */ - public function testValueFalseCase1(): void { - $transform = $this->getTransform('convert_boolean', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => false, - ]); - // Make sure it stays an array - $this->assertFalse($result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueTrueCase4(): void + { + $transform = $this->getTransform('convert_boolean', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => '1', + ]); + // Make sure it stays an array + static::assertTrue($result); + } - /** - * Testing transforms for Erors - */ - public function testValueFalseCase2(): void { - $transform = $this->getTransform('convert_boolean', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => 0, - ]); - // Make sure it stays an array - $this->assertFalse($result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueFalseCase1(): void + { + $transform = $this->getTransform('convert_boolean', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => false, + ]); + // Make sure it stays an array + static::assertFalse($result); + } - /** - * Testing transforms for Erors - */ - public function testValueFalseCase3(): void { - $transform = $this->getTransform('convert_boolean', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => 'false', - ]); - // Make sure it stays an array - $this->assertFalse($result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueFalseCase2(): void + { + $transform = $this->getTransform('convert_boolean', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => 0, + ]); + // Make sure it stays an array + static::assertFalse($result); + } - /** - * Testing transforms for Erors - */ - public function testValueFalseCase4(): void { - $transform = $this->getTransform('convert_boolean', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => '0', - ]); - // Make sure it stays an array - $this->assertFalse($result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueFalseCase3(): void + { + $transform = $this->getTransform('convert_boolean', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => 'false', + ]); + // Make sure it stays an array + static::assertFalse($result); + } - /** - * Testing transforms for Erors - */ - public function testValueRequired(): void { - $transform = $this->getTransform('convert_boolean', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'required' => true - ]); - $result = $transform->transform([ - 'example_source_field' => null, - ]); - // Make sure it stays an array - $this->assertNull($result); + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueFalseCase4(): void + { + $transform = $this->getTransform('convert_boolean', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => '0', + ]); + // Make sure it stays an array + static::assertFalse($result); + } - $errors = $transform->getErrors(); - $this->assertNotEmpty($errors); - $this->assertCount(1, $errors); - $this->assertEquals('convert_boolean', $errors[0]['__IDENTIFIER'] ); - $this->assertEquals('TRANSFORM.MISSING_VALUE', $errors[0]['__CODE'] ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueRequired(): void + { + $transform = $this->getTransform('convert_boolean', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'required' => true, + ]); + $result = $transform->transform([ + 'example_source_field' => null, + ]); + // Make sure it stays an array + static::assertNull($result); - /** - * Testing transforms for Erors - */ - public function testValueInvalidValue(): void { - $transform = $this->getTransform('convert_boolean', [ - 'source' => 'source', - 'field' => 'example_source_field' - ]); - $result = $transform->transform([ - 'example_source_field' => 'ABC', - ]); - // Make sure it stays an array - $this->assertNull($result); + $errors = $transform->getErrors(); + static::assertNotEmpty($errors); + static::assertCount(1, $errors); + static::assertEquals('convert_boolean', $errors[0]['__IDENTIFIER']); + static::assertEquals('TRANSFORM.MISSING_VALUE', $errors[0]['__CODE']); + } - $errors = $transform->getErrors(); - $this->assertNotEmpty($errors); - $this->assertCount(1, $errors); - $this->assertEquals('convert_boolean', $errors[0]['__IDENTIFIER'] ); - $this->assertEquals('TRANSFORM.INVALID_VALUE', $errors[0]['__CODE'] ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueInvalidValue(): void + { + $transform = $this->getTransform('convert_boolean', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => 'ABC', + ]); + // Make sure it stays an array + static::assertNull($result); - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('convert_boolean', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + $errors = $transform->getErrors(); + static::assertNotEmpty($errors); + static::assertCount(1, $errors); + static::assertEquals('convert_boolean', $errors[0]['__IDENTIFIER']); + static::assertEquals('TRANSFORM.INVALID_VALUE', $errors[0]['__CODE']); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('convert_boolean', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/convert/datetimeTest.php b/tests/transform/convert/datetimeTest.php index 5a445de..aed2aa0 100644 --- a/tests/transform/convert/datetimeTest.php +++ b/tests/transform/convert/datetimeTest.php @@ -1,201 +1,236 @@ getTransform('convert_datetime', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'source_format' => 'Y-m-d H:i:s', - 'target_format' => 'd.m.Y H:i:s', - ]); - $result = $transform->transform([ - 'example_source_field' => '2021-04-19 10:30:25', - ]); - // Make sure it stays an array - $this->assertEquals('19.04.2021 10:30:25', $result); - } +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use DateTime; +use DateTimeImmutable; +use ReflectionException; - /** - * Testing transforms for Erors - */ - public function testValueValidCase2(): void { - $transform = $this->getTransform('convert_datetime', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'source_format' => [ 'Y-m-d H:i:s', 'Y-m-d' ], - 'target_format' => 'd.m.Y H:i:s', - ]); - $result = $transform->transform([ - 'example_source_field' => '2021-04-19 10:30:25', - ]); - // Make sure it stays an array - $this->assertEquals('19.04.2021 10:30:25', $result); - } +class datetimeTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase1(): void + { + $transform = $this->getTransform('convert_datetime', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'source_format' => 'Y-m-d H:i:s', + 'target_format' => 'd.m.Y H:i:s', + ]); + $result = $transform->transform([ + 'example_source_field' => '2021-04-19 10:30:25', + ]); + // Make sure it stays an array + static::assertEquals('19.04.2021 10:30:25', $result); + } - /** - * Testing transforms for Erors - */ - public function testValueValidCase3(): void { - $transform = $this->getTransform('convert_datetime', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'source_format' => [ 'Y-m-d H:i:s', 'Y-m-d' ], - 'target_format' => 'd.m.Y H:i:s', - 'set_time_to_null' => true, - 'modify' => '+1 day', - ]); - $result = $transform->transform([ - 'example_source_field' => '2021-04-19 10:30:25', - ]); - // Make sure it stays an array - $this->assertEquals('20.04.2021 00:00:00', $result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase2(): void + { + $transform = $this->getTransform('convert_datetime', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'source_format' => ['Y-m-d H:i:s', 'Y-m-d'], + 'target_format' => 'd.m.Y H:i:s', + ]); + $result = $transform->transform([ + 'example_source_field' => '2021-04-19 10:30:25', + ]); + // Make sure it stays an array + static::assertEquals('19.04.2021 10:30:25', $result); + } - /** - * Testing transforms for Erors - */ - public function testValueValidCase4(): void { - $transform = $this->getTransform('convert_datetime', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'source_format' => [ 'Y-m-d H:i:s', 'Y-m-d' ], - 'target_format' => 'd.m.Y H:i:s', - 'set_time_to_null' => true, - 'modify' => [ - 'source' => 'source', - 'field' => 'example_modify_field', - ], - ]); - $result = $transform->transform([ - 'example_source_field' => '2021-04-19 10:30:25', - 'example_modify_field' => '+2 days', - ]); - // Make sure it stays an array - $this->assertEquals('21.04.2021 00:00:00', $result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase3(): void + { + $transform = $this->getTransform('convert_datetime', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'source_format' => ['Y-m-d H:i:s', 'Y-m-d'], + 'target_format' => 'd.m.Y H:i:s', + 'set_time_to_null' => true, + 'modify' => '+1 day', + ]); + $result = $transform->transform([ + 'example_source_field' => '2021-04-19 10:30:25', + ]); + // Make sure it stays an array + static::assertEquals('20.04.2021 00:00:00', $result); + } - /** - * Testing transforms for Erors - */ - public function testValueIsNull(): void { - $transform = $this->getTransform('convert_datetime', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'source_format' => [ 'Y-m-d H:i:s', 'Y-m-d' ], - 'target_format' => 'd.m.Y H:i:s', - ]); - $result = $transform->transform([ - 'example_source_field' => null, - ]); - // Make sure it stays an array - $this->assertNull($result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase4(): void + { + $transform = $this->getTransform('convert_datetime', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'source_format' => ['Y-m-d H:i:s', 'Y-m-d'], + 'target_format' => 'd.m.Y H:i:s', + 'set_time_to_null' => true, + 'modify' => [ + 'source' => 'source', + 'field' => 'example_modify_field', + ], + ]); + $result = $transform->transform([ + 'example_source_field' => '2021-04-19 10:30:25', + 'example_modify_field' => '+2 days', + ]); + // Make sure it stays an array + static::assertEquals('21.04.2021 00:00:00', $result); + } - /** - * Testing transforms for Erors - */ - public function testValueIsNullRequired(): void { - $transform = $this->getTransform('convert_datetime', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'source_format' => [ 'Y-m-d H:i:s', 'Y-m-d' ], - 'target_format' => 'd.m.Y H:i:s', - 'required' => true - ]); - $result = $transform->transform([ - 'example_source_field' => null, - ]); - // Make sure it stays an array - $this->assertNull($result); + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueIsNull(): void + { + $transform = $this->getTransform('convert_datetime', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'source_format' => ['Y-m-d H:i:s', 'Y-m-d'], + 'target_format' => 'd.m.Y H:i:s', + ]); + $result = $transform->transform([ + 'example_source_field' => null, + ]); + // Make sure it stays an array + static::assertNull($result); + } - $errors = $transform->getErrors(); - $this->assertNotEmpty($errors); - $this->assertCount(1, $errors); - $this->assertEquals('VALUE_NULL', $errors[0]['__IDENTIFIER'] ); - $this->assertEquals('TRANSFORM.0', $errors[0]['__CODE'] ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueIsNullRequired(): void + { + $transform = $this->getTransform('convert_datetime', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'source_format' => ['Y-m-d H:i:s', 'Y-m-d'], + 'target_format' => 'd.m.Y H:i:s', + 'required' => true, + ]); + $result = $transform->transform([ + 'example_source_field' => null, + ]); + // Make sure it stays an array + static::assertNull($result); - /** - * Testing transforms for Erors - */ - public function testValueInvalidDatetime(): void { - $transform = $this->getTransform('convert_datetime', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'source_format' => [ 'Y-m-d H:i:s', 'Y-m-d' ], - 'target_format' => 'd.m.Y H:i:s', - 'required' => true - ]); - $result = $transform->transform([ - 'example_source_field' => '19.04.2021 11:22:33', - ]); - // Make sure it stays an array - $this->assertNull($result); + $errors = $transform->getErrors(); + static::assertNotEmpty($errors); + static::assertCount(1, $errors); + static::assertEquals('VALUE_NULL', $errors[0]['__IDENTIFIER']); + static::assertEquals('TRANSFORM.0', $errors[0]['__CODE']); + } - $errors = $transform->getErrors(); - $this->assertNotEmpty($errors); - $this->assertCount(1, $errors); - $this->assertEquals('convert_datetime', $errors[0]['__IDENTIFIER'] ); - $this->assertEquals('TRANSFORM.INVALID_FORMAT', $errors[0]['__CODE'] ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueInvalidDatetime(): void + { + $transform = $this->getTransform('convert_datetime', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'source_format' => ['Y-m-d H:i:s', 'Y-m-d'], + 'target_format' => 'd.m.Y H:i:s', + 'required' => true, + ]); + $result = $transform->transform([ + 'example_source_field' => '19.04.2021 11:22:33', + ]); + // Make sure it stays an array + static::assertNull($result); - /** - * Testing transforms for Erors - */ - public function testValueIsDateTimeObject(): void { - $transform = $this->getTransform('convert_datetime', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'source_format' => [ 'Y-m-d H:i:s', 'Y-m-d' ], - 'target_format' => 'DateTime' - ]); - $result = $transform->transform([ - 'example_source_field' => '2021-04-19 11:22:33', - ]); - // Make sure it stays an array - $this->assertInstanceOf(\DateTime::class, $result); - } + $errors = $transform->getErrors(); + static::assertNotEmpty($errors); + static::assertCount(1, $errors); + static::assertEquals('convert_datetime', $errors[0]['__IDENTIFIER']); + static::assertEquals('TRANSFORM.INVALID_FORMAT', $errors[0]['__CODE']); + } - /** - * Testing transforms for Erors - */ - public function testValueIsDateTimeImmutableObject(): void { - $transform = $this->getTransform('convert_datetime', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'source_format' => [ 'Y-m-d H:i:s', 'Y-m-d' ], - 'target_format' => 'DateTimeImmutable' - ]); - $result = $transform->transform([ - 'example_source_field' => '2021-04-19 11:22:33', - ]); - // Make sure it stays an array - $this->assertInstanceOf(\DateTimeImmutable::class, $result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueIsDateTimeObject(): void + { + $transform = $this->getTransform('convert_datetime', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'source_format' => ['Y-m-d H:i:s', 'Y-m-d'], + 'target_format' => 'DateTime', + ]); + $result = $transform->transform([ + 'example_source_field' => '2021-04-19 11:22:33', + ]); + // Make sure it stays an array + static::assertInstanceOf(DateTime::class, $result); + } - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('convert_datetime', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'source_format' => 'Y-m-d H:i:s', - 'target_format' => 'd.m.Y H:i:s', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueIsDateTimeImmutableObject(): void + { + $transform = $this->getTransform('convert_datetime', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'source_format' => ['Y-m-d H:i:s', 'Y-m-d'], + 'target_format' => 'DateTimeImmutable', + ]); + $result = $transform->transform([ + 'example_source_field' => '2021-04-19 11:22:33', + ]); + // Make sure it stays an array + static::assertInstanceOf(DateTimeImmutable::class, $result); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('convert_datetime', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'source_format' => 'Y-m-d H:i:s', + 'target_format' => 'd.m.Y H:i:s', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/convert/encodingTest.php b/tests/transform/convert/encodingTest.php index 127f557..b705ee9 100644 --- a/tests/transform/convert/encodingTest.php +++ b/tests/transform/convert/encodingTest.php @@ -1,76 +1,92 @@ getTransform('convert_encoding', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'from' => 'UTF-8', - 'to' => 'ASCII', - ]); - $result = $transform->transform([ - 'example_source_field' => 'Täst', - ]); - // Make sure it stays an array - $this->assertEquals(mb_convert_encoding('Täst', 'ASCII', 'UTF-8'), $result); - } +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; +use ValueError; - /** - * Testing transforms for Erors - */ - public function testValueIsNull(): void { - $transform = $this->getTransform('convert_encoding', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'from' => 'UTF-8', - 'to' => 'ASCII', - ]); - $result = $transform->transform([ - 'example_source_field' => null, - ]); - // Make sure it stays an array - $this->assertNull($result); - } +class encodingTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('convert_encoding', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'from' => 'UTF-8', + 'to' => 'ASCII', + ]); + $result = $transform->transform([ + 'example_source_field' => 'Täst', + ]); + // Make sure it stays an array + static::assertEquals(mb_convert_encoding('Täst', 'ASCII', 'UTF-8'), $result); + } - /** - * Testing transforms for Erors - */ - public function testValueInvalid(): void { - $this->expectException(\codename\core\WarningException::class); - // $this->expectExceptionMessage('INVALID_OPERATOR'); + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueIsNull(): void + { + $transform = $this->getTransform('convert_encoding', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'from' => 'UTF-8', + 'to' => 'ASCII', + ]); + $result = $transform->transform([ + 'example_source_field' => null, + ]); + // Make sure it stays an array + static::assertNull($result); + } - $transform = $this->getTransform('convert_encoding', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'from' => 'example', - 'to' => 'example', - ]); - $result = $transform->transform([ - 'example_source_field' => 'Täst', - ]); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueInvalid(): void + { + $this->expectException(ValueError::class); + // $this->expectExceptionMessage('INVALID_OPERATOR'); - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('convert_encoding', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + $transform = $this->getTransform('convert_encoding', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'from' => 'example', + 'to' => 'example', + ]); + $transform->transform([ + 'example_source_field' => 'Täst', + ]); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('convert_encoding', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/convert/jsonTest.php b/tests/transform/convert/jsonTest.php index bfc588c..ff2f71d 100644 --- a/tests/transform/convert/jsonTest.php +++ b/tests/transform/convert/jsonTest.php @@ -1,90 +1,108 @@ getTransform('convert_json', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'mode' => 'encode', - ]); - $result = $transform->transform([ - 'example_source_field' => [ 'example' => true ], - ]); - // Make sure it stays an array - $this->assertEquals(json_encode([ 'example' => true ]), $result); - } +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use LogicException; +use ReflectionException; - /** - * Testing transforms for Erors - */ - public function testValueValidDecode(): void { - $transform = $this->getTransform('convert_json', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'mode' => 'decode', - ]); - $result = $transform->transform([ - 'example_source_field' => json_encode([ 'example' => true ]), - ]); - // Make sure it stays an array - $this->assertEquals([ 'example' => true ], $result); - } +class jsonTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidEncode(): void + { + $transform = $this->getTransform('convert_json', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'mode' => 'encode', + ]); + $result = $transform->transform([ + 'example_source_field' => ['example' => true], + ]); + // Make sure it stays an array + static::assertEquals(json_encode(['example' => true]), $result); + } - /** - * Testing transforms for Erors - */ - public function testValueIsNull(): void { - $transform = $this->getTransform('convert_json', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'mode' => 'encode', - ]); - $result = $transform->transform([ - 'example_source_field' => null, - ]); - // Make sure it stays an array - $this->assertNull($result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidDecode(): void + { + $transform = $this->getTransform('convert_json', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'mode' => 'decode', + ]); + $result = $transform->transform([ + 'example_source_field' => json_encode(['example' => true]), + ]); + // Make sure it stays an array + static::assertEquals(['example' => true], $result); + } - /** - * Testing transforms for Erors - */ - public function testValueInvalid(): void { - $transform = $this->getTransform('convert_json', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'mode' => 'example', - ]); - $result = $transform->transform([ - 'example_source_field' => 'example', - ]); - // Make sure it stays an array - $this->assertEmpty($result); - // $this->markTestSkipped(); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueIsNull(): void + { + $transform = $this->getTransform('convert_json', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'mode' => 'encode', + ]); + $result = $transform->transform([ + 'example_source_field' => null, + ]); + // Make sure it stays an array + static::assertNull($result); + } - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('convert_json', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'mode' => 'encode', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueInvalid(): void + { + $this->expectException(LogicException::class); + // + $transform = $this->getTransform('convert_json', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'mode' => 'example', + ]); + $transform->transform([ + 'example_source_field' => 'example', + ]); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('convert_json', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'mode' => 'encode', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/convert/numberformat/formatTest.php b/tests/transform/convert/numberformat/formatTest.php index 51f55f8..20fbbbc 100644 --- a/tests/transform/convert/numberformat/formatTest.php +++ b/tests/transform/convert/numberformat/formatTest.php @@ -1,117 +1,114 @@ getTransform('convert_numberformat_format', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'style' => 'decimal', - 'locale' => 'en-EN', - 'fraction_digits' => 2, - 'grouping_separator_symbol' => '', - ]); - $result = $transform->transform([ - 'example_source_field' => '1234.5678', - ]); - // Make sure it stays an array - $this->assertEquals('1234.57', $result); - } +namespace codename\core\io\tests\transform\convert\numberformat; - /** - * Tests a case with rounding - * and we exceed the max target digit count - * so we expect less digits in the result - but rounded with an explicit rounding_mode - */ - public function testRoundHalfUpWithMaxFractionDigitsExceeded(): void { - $transform = $this->getTransform('convert_numberformat_format', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'style' => 'decimal', - 'locale' => 'en-EN', - 'rounding_mode' => 'financial', // Alias - 'max_fraction_digits' => 2, - ]); - $result = $transform->transform([ - 'example_source_field' => 1.234, - ]); - $this->assertEquals('1.23', $result); +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - $transform->reset(); - $result = $transform->transform([ - 'example_source_field' => 1.235, - ]); - $this->assertEquals('1.24', $result); - } +class formatTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('convert_numberformat_format', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'style' => 'decimal', + 'locale' => 'en-EN', + 'fraction_digits' => 2, + 'grouping_separator_symbol' => '', + ]); + $result = $transform->transform([ + 'example_source_field' => '1234.5678', + ]); + // Make sure it stays an array + static::assertEquals('1234.57', $result); + } - /** - * Tests a case with rounding - * and we do NOT reach the max target digit count - * so we expect MORE digits (0-padded) in the result - but rounded with an explicit rounding_mode - */ - public function testRoundHalfUpWithMaxFractionDigitsNotReached(): void { - $transform = $this->getTransform('convert_numberformat_format', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'style' => 'decimal', - 'locale' => 'en-EN', - 'rounding_mode' => 'financial', // Alias - 'min_fraction_digits' => 4, - ]); - $result = $transform->transform([ - 'example_source_field' => 1.23, - ]); - $this->assertEquals('1.2300', $result); - } - /** - * Testing transforms for Erors - */ - public function testValueIsNull(): void { - $transform = $this->getTransform('convert_numberformat_format', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'style' => 'decimal', - 'locale' => 'en-EN', - 'fraction_digits' => 2, - 'grouping_separator_symbol' => '', - 'required' => true, - ]); - $result = $transform->transform([ - 'example_source_field' => null, - ]); - // Make sure it stays an array - $this->assertNull($result); + /** + * Tests a case with rounding, + * and we exceed the max target digit count, + * so we expect fewer digits in the result - but rounded with an explicit rounding_mode + * @throws ReflectionException + * @throws exception + */ + public function testRoundHalfUpWithMaxFractionDigitsExceeded(): void + { + $transform = $this->getTransform('convert_numberformat_format', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'style' => 'decimal', + 'locale' => 'en-EN', + 'rounding_mode' => 'financial', // Alias + 'max_fraction_digits' => 2, + ]); + $result = $transform->transform([ + 'example_source_field' => 1.234, + ]); + static::assertEquals('1.23', $result); - $errors = $transform->getErrors(); - $this->assertNotEmpty($errors); - $this->assertCount(1, $errors); - $this->assertEquals('convert_numberformat_format', $errors[0]['__IDENTIFIER'] ); - $this->assertEquals('TRANSFORM.MISSING_VALUE', $errors[0]['__CODE'] ); - } + $transform->reset(); + $result = $transform->transform([ + 'example_source_field' => 1.235, + ]); + static::assertEquals('1.24', $result); + } - /** - * Testing transforms for Erors - */ - public function testValueInvalidParse(): void { - $transform = $this->getTransform('convert_numberformat_format', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'style' => 'decimal', - 'locale' => 'de_DE', - ]); + /** + * Tests a case with rounding, + * and we do NOT reach the max target digit count, + * so we expect MORE digits (0-padded) in the result - but rounded with an explicit rounding_mode + * @throws ReflectionException + * @throws exception + */ + public function testRoundHalfUpWithMaxFractionDigitsNotReached(): void + { + $transform = $this->getTransform('convert_numberformat_format', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'style' => 'decimal', + 'locale' => 'en-EN', + 'rounding_mode' => 'financial', // Alias + 'min_fraction_digits' => 4, + ]); + $result = $transform->transform([ + 'example_source_field' => 1.23, + ]); + static::assertEquals('1.2300', $result); + } - $result = $transform->transform([ - 'example_source_field' => '123###456###', - ]); - // Make sure it stays an array - $this->assertEquals('123', $result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueIsNull(): void + { + $transform = $this->getTransform('convert_numberformat_format', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'style' => 'decimal', + 'locale' => 'en-EN', + 'fraction_digits' => 2, + 'grouping_separator_symbol' => '', + 'required' => true, + ]); + $result = $transform->transform([ + 'example_source_field' => null, + ]); + // Make sure it stays an array + static::assertNull($result); + $errors = $transform->getErrors(); + static::assertNotEmpty($errors); + static::assertCount(1, $errors); + static::assertEquals('convert_numberformat_format', $errors[0]['__IDENTIFIER']); + static::assertEquals('TRANSFORM.MISSING_VALUE', $errors[0]['__CODE']); + } } diff --git a/tests/transform/convert/numberformatTest.php b/tests/transform/convert/numberformatTest.php index 2223fbe..9467633 100644 --- a/tests/transform/convert/numberformatTest.php +++ b/tests/transform/convert/numberformatTest.php @@ -1,190 +1,218 @@ getTransform('convert_numberformat', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'style' => 'decimal', - 'locale' => 'en-EN', - ]); - $result = $transform->transform([ - 'example_source_field' => 1.234, - ]); - // Make sure it stays an array - $this->assertEquals(1.234, $result); - } - - /** - * Testing transforms for Erors - */ - public function testValueValidCase2(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('TRANSFORM_NUMBERFORMAT_CONFIG_LOCALE_INVALID_SOURCE'); - - $transform = $this->getTransform('convert_numberformat', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'style' => [ - 'source' => 'source', - 'field' => 'example_style_field', - ], - 'locale' => [ - 'source' => 'source', - 'field' => 'example_locale_field', - ] - ]); - $result = $transform->transform([ - 'example_source_field' => 1.2345, - 'example_style_field' => 'decimal', - 'example_locale_field' => 'en-EN', - ]); - // Make sure it stays an array - $this->assertEquals('1.2345', $result); - } - - /** - * Testing transforms for Erors - */ - public function testValueValidCase3(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('TRANSFORM_NUMBERFORMAT_CONFIG_STYLE_INVALID_SOURCE'); - - $transform = $this->getTransform('convert_numberformat', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'style' => [ - 'source' => 'source', - 'field' => 'example_style_field', - ], - 'locale' => 'en-EN' - ]); - $result = $transform->transform([ - 'example_source_field' => 1.2345, - ]); - } - - /** - * Testing transforms for Erors - */ - public function testValueValidCase4(): void { - $transform = $this->getTransform('convert_numberformat', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'style' => 'decimal', - 'locale' => [ - 'source' => 'option', - 'field' => 'example_locale_field', - ], - ]); - - $pipline = new \codename\core\io\pipeline(null, []); - $pipline->setOptions([ - 'example_style_field' => 'decimal', - 'example_locale_field' => 'en-EN', - ]); - $transform->setPipelineInstance($pipline); - - $result = $transform->transform([ - 'example_source_field' => 1.2345, - ]); - // Make sure it stays an array - $this->assertEquals('1.2345', $result); - } - - /** - * Testing transforms for Erors - */ - public function testValueValidCase5(): void { - $transform = $this->getTransform('convert_numberformat', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'style' => [ - 'source' => 'option', - 'field' => 'example_style_field', - ], - 'locale' => [ - 'source' => 'option', - 'field' => 'example_locale_field', - ] - ]); - - $pipline = new \codename\core\io\pipeline(null, []); - $pipline->setOptions([ - 'example_style_field' => 'decimal', - 'example_locale_field' => 'en-EN', - ]); - $transform->setPipelineInstance($pipline); - - $result = $transform->transform([ - 'example_source_field' => 1.2345, - ]); - // Make sure it stays an array - $this->assertEquals('1.2345', $result); - } - - /** - * Testing transforms for Erors - */ - public function testValueWrongStyle(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_CORE_IO_TRANSFORM_CONVERT_NUMBERFORMAT_INVALID_TYPE'); - - $transform = $this->getTransform('convert_numberformat', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'style' => 'example', - 'locale' => 'en-EN' - ]); - } - - /** - * Testing transforms for Erors - */ - public function testValueInvalidParse(): void { - $transform = $this->getTransform('convert_numberformat', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'style' => 'decimal', - 'locale' => 'en-EN' - ]); - - $result = $transform->transform([ - 'example_source_field' => '123,2345', - ]); - // Make sure it stays an array - $this->assertFalse($result); - - $errors = $transform->getErrors(); - $this->assertNotEmpty($errors); - $this->assertCount(1, $errors); - $this->assertEquals('convert_numberformat', $errors[0]['__IDENTIFIER'] ); - $this->assertEquals('TRANSFORM.INVALID_PARSE', $errors[0]['__CODE'] ); - } - - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('convert_numberformat', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'style' => 'decimal', - 'locale' => 'de-DE', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } +use codename\core\exception; +use codename\core\io\pipeline; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; +class numberformatTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase1(): void + { + $transform = $this->getTransform('convert_numberformat', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'style' => 'decimal', + 'locale' => 'en-EN', + ]); + $result = $transform->transform([ + 'example_source_field' => 1.234, + ]); + // Make sure it stays an array + static::assertEquals(1.234, $result); + } + + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase2(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('TRANSFORM_NUMBERFORMAT_CONFIG_LOCALE_INVALID_SOURCE'); + + $transform = $this->getTransform('convert_numberformat', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'style' => [ + 'source' => 'source', + 'field' => 'example_style_field', + ], + 'locale' => [ + 'source' => 'source', + 'field' => 'example_locale_field', + ], + ]); + $result = $transform->transform([ + 'example_source_field' => 1.2345, + 'example_style_field' => 'decimal', + 'example_locale_field' => 'en-EN', + ]); + // Make sure it stays an array + static::assertEquals('1.2345', $result); + } + + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase3(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('TRANSFORM_NUMBERFORMAT_CONFIG_STYLE_INVALID_SOURCE'); + + $transform = $this->getTransform('convert_numberformat', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'style' => [ + 'source' => 'source', + 'field' => 'example_style_field', + ], + 'locale' => 'en-EN', + ]); + $transform->transform([ + 'example_source_field' => 1.2345, + ]); + } + + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase4(): void + { + $transform = $this->getTransform('convert_numberformat', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'style' => 'decimal', + 'locale' => [ + 'source' => 'option', + 'field' => 'example_locale_field', + ], + ]); + + $pipeline = new pipeline(null, []); + $pipeline->setOptions([ + 'example_style_field' => 'decimal', + 'example_locale_field' => 'en-EN', + ]); + $transform->setPipelineInstance($pipeline); + + $result = $transform->transform([ + 'example_source_field' => 1.2345, + ]); + // Make sure it stays an array + static::assertEquals('1.2345', $result); + } + + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase5(): void + { + $transform = $this->getTransform('convert_numberformat', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'style' => [ + 'source' => 'option', + 'field' => 'example_style_field', + ], + 'locale' => [ + 'source' => 'option', + 'field' => 'example_locale_field', + ], + ]); + + $pipeline = new pipeline(null, []); + $pipeline->setOptions([ + 'example_style_field' => 'decimal', + 'example_locale_field' => 'en-EN', + ]); + $transform->setPipelineInstance($pipeline); + + $result = $transform->transform([ + 'example_source_field' => 1.2345, + ]); + // Make sure it stays an array + static::assertEquals('1.2345', $result); + } + + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueWrongStyle(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('EXCEPTION_CORE_IO_TRANSFORM_CONVERT_NUMBERFORMAT_INVALID_TYPE'); + + $this->getTransform('convert_numberformat', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'style' => 'example', + 'locale' => 'en-EN', + ]); + } + + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueInvalidParse(): void + { + $transform = $this->getTransform('convert_numberformat', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'style' => 'decimal', + 'locale' => 'en-EN', + ]); + + $result = $transform->transform([ + 'example_source_field' => '123,2345', + ]); + // Make sure it stays an array + static::assertFalse($result); + + $errors = $transform->getErrors(); + static::assertNotEmpty($errors); + static::assertCount(1, $errors); + static::assertEquals('convert_numberformat', $errors[0]['__IDENTIFIER']); + static::assertEquals('TRANSFORM.INVALID_PARSE', $errors[0]['__CODE']); + } + + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('convert_numberformat', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'style' => 'decimal', + 'locale' => 'de-DE', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/countTest.php b/tests/transform/countTest.php index 7647d22..9b868c4 100644 --- a/tests/transform/countTest.php +++ b/tests/transform/countTest.php @@ -1,52 +1,65 @@ getTransform('count', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => null - ]); - // Make sure it stays an array - $this->assertEquals(null, $result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueIsNull(): void + { + $transform = $this->getTransform('count', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => null, + ]); + // Make sure it stays an array + static::assertEquals(null, $result); + } - /** - * Testing transforms for Erors - */ - public function testValueValid(): void { - $transform = $this->getTransform('count', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => [ 'test', 'test2' ] - ]); - // Make sure it stays an array - $this->assertEquals(2, $result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('count', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => ['test', 'test2'], + ]); + // Make sure it stays an array + static::assertEquals(2, $result); + } - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('count', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('count', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/deepaccessTest.php b/tests/transform/deepaccessTest.php index 85738f9..fc0de8c 100644 --- a/tests/transform/deepaccessTest.php +++ b/tests/transform/deepaccessTest.php @@ -1,63 +1,80 @@ getTransform('deepaccess', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'path' => [], + ]); + + static::assertInstanceOf(deepaccess::class, $transform); + } + + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueIsNull(): void + { + $transform = $this->getTransform('deepaccess', [ + 'source' => 'source', + // 'field' => 'example_source_field', + 'required' => true, + ]); + $result = $transform->transform([ + 'example_source_field', + ]); + // Make sure it stays an array + static::assertEquals(null, $result); + } + + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('deepaccess', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => 'test', + ]); + static::assertEmpty($result); + } + + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $this->expectException(LogicException::class); + $this->expectExceptionMessage('Not implemented'); - /** - * Testing transforms for Erors - */ - public function testConstructValid(): void { - $transform = $this->getTransform('deepaccess', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'path' => [], - ]); - - $this->assertInstanceOf(\codename\core\io\transform\deepaccess::class, $transform); - } - - /** - * Testing transforms for Erors - */ - public function testValueIsNull(): void { - $transform = $this->getTransform('deepaccess', [ - 'source' => 'source', - // 'field' => 'example_source_field', - 'required' => true, - ]); - $result = $transform->transform([ - 'example_source_field' - ]); - // Make sure it stays an array - $this->assertEquals(null, $result ); - } - - /** - * Testing transforms for Erors - */ - public function testValueValid(): void { - $transform = $this->getTransform('deepaccess', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => 'test' - ]); - $this->assertEmpty($result); - } - - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $this->expectException(\LogicException::class); - $this->expectExceptionMessage('Not implemented'); - - $transform = $this->getTransform('deepaccess', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $specification = $transform->getSpecification(); - } + $transform = $this->getTransform('deepaccess', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $transform->getSpecification(); + } } diff --git a/tests/transform/dummyTest.php b/tests/transform/dummyTest.php index 2791fb1..fd8e6ae 100644 --- a/tests/transform/dummyTest.php +++ b/tests/transform/dummyTest.php @@ -1,34 +1,44 @@ expectException(LogicException::class); + $this->expectExceptionMessage('Not implemented and shouldn\'t be'); - /** - * [testInternalTransform description] - */ - public function testInternalTransform(): void { - $this->expectException(\LogicException::class); - $this->expectExceptionMessage('Not implemented and shouln\'t be'); - - $transform = $this->getTransform('dummy', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $specification = $transform->internalTransform([]); - } + $transform = $this->getTransform('dummy', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $transform->internalTransform([]); + } - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $this->expectException(\LogicException::class); - $this->expectExceptionMessage('Not implemented and shouln\'t be'); + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $this->expectException(LogicException::class); + $this->expectExceptionMessage('Not implemented and shouldn\'t be'); - $transform = $this->getTransform('dummy', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $specification = $transform->getSpecification(); - } + $transform = $this->getTransform('dummy', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $transform->getSpecification(); + } } diff --git a/tests/transform/explodeTest.php b/tests/transform/explodeTest.php index 983094d..bbeecfb 100644 --- a/tests/transform/explodeTest.php +++ b/tests/transform/explodeTest.php @@ -1,120 +1,145 @@ getTransform('explode', [ - 'source' => 'source', - 'field' => 'example_source_field' - ]); - $result = $transform->transform([ - 'example_source_field' => 'value1,value2' - ]); - $this->assertEquals(['value1','value2'], $result); - } + /** + * Tests for a default delimiter (,) + * @throws ReflectionException + * @throws exception + */ + public function testDefaultDelimiter(): void + { + $transform = $this->getTransform('explode', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => 'value1,value2', + ]); + static::assertEquals(['value1', 'value2'], $result); + } - /** - * Tests a delimiter that is not the default one - */ - public function testCustomDelimiter(): void { - $transform = $this->getTransform('explode', [ - 'delimiter' => ';', - 'source' => 'source', - 'field' => 'example_source_field' - ]); - $result = $transform->transform([ - 'example_source_field' => 'value1;value2' - ]); - $this->assertEquals(['value1','value2'], $result); - } + /** + * Tests a delimiter that is not the default one + * @throws ReflectionException + * @throws exception + */ + public function testCustomDelimiter(): void + { + $transform = $this->getTransform('explode', [ + 'delimiter' => ';', + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => 'value1;value2', + ]); + static::assertEquals(['value1', 'value2'], $result); + } - /** - * Tests explode behaviour, if there is no delimiter match - */ - public function testNonexistingDelimiter(): void { - $transform = $this->getTransform('explode', [ - 'delimiter' => ';', - 'source' => 'source', - 'field' => 'example_source_field' - ]); - $result = $transform->transform([ - 'example_source_field' => 'value1-value2' - ]); - // Make sure it stays an array - $this->assertEquals(['value1-value2'], $result); - } + /** + * Tests explode behaviour, if there is no delimiter match + * @throws ReflectionException + * @throws exception + */ + public function testNonexistingDelimiter(): void + { + $transform = $this->getTransform('explode', [ + 'delimiter' => ';', + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => 'value1-value2', + ]); + // Make sure it stays an array + static::assertEquals(['value1-value2'], $result); + } - /** - * Tests a multichar separator/delimiter - */ - public function testMulticharDelimiter(): void { - $transform = $this->getTransform('explode', [ - 'delimiter' => ';,', - 'source' => 'source', - 'field' => 'example_source_field' - ]); - $result = $transform->transform([ - 'example_source_field' => 'value1;,value2' - ]); - // Make sure it stays an array - $this->assertEquals(['value1','value2'], $result); - } + /** + * Tests a multichar separator/delimiter + * @throws ReflectionException + * @throws exception + */ + public function testMulticharDelimiter(): void + { + $transform = $this->getTransform('explode', [ + 'delimiter' => ';,', + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => 'value1;,value2', + ]); + // Make sure it stays an array + static::assertEquals(['value1', 'value2'], $result); + } - /** - * Tests max. amount of exploded items - */ - public function testLimit(): void { - $transform = $this->getTransform('explode', [ - 'delimiter' => ';', - 'source' => 'source', - 'field' => 'example_source_field', - 'limit' => 3 - ]); - $result = $transform->transform([ - 'example_source_field' => 'value1;value2;value3;value4' - ]); - // Make sure it stays an array - $this->assertEquals(['value1','value2','value3;value4'], $result); - } + /** + * Tests max. amount of exploded items + * @throws ReflectionException + * @throws exception + */ + public function testLimit(): void + { + $transform = $this->getTransform('explode', [ + 'delimiter' => ';', + 'source' => 'source', + 'field' => 'example_source_field', + 'limit' => 3, + ]); + $result = $transform->transform([ + 'example_source_field' => 'value1;value2;value3;value4', + ]); + // Make sure it stays an array + static::assertEquals(['value1', 'value2', 'value3;value4'], $result); + } - /** - * [testDelimiterDynamic description] - */ - public function testDelimiterDynamic(): void { - $transform = $this->getTransform('explode', [ - 'delimiter' => [ - 'source' => 'source', - 'field' => 'example_delimiter', - ], - 'source' => 'source', - 'field' => 'example_source_field' - ]); - $result = $transform->transform([ - 'example_delimiter' => '#', - 'example_source_field' => 'value1#value2' - ]); - // Make sure it stays an array - $this->assertEquals(['value1','value2'], $result); - } + /** + * [testDelimiterDynamic description] + * @throws ReflectionException + * @throws exception + */ + public function testDelimiterDynamic(): void + { + $transform = $this->getTransform('explode', [ + 'delimiter' => [ + 'source' => 'source', + 'field' => 'example_delimiter', + ], + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_delimiter' => '#', + 'example_source_field' => 'value1#value2', + ]); + // Make sure it stays an array + static::assertEquals(['value1', 'value2'], $result); + } - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('explode', [ - 'source' => 'source', - 'field' => 'example_source_field' - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('explode', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/get/arraycolumnTest.php b/tests/transform/get/arraycolumnTest.php index dfbd38e..e290468 100644 --- a/tests/transform/get/arraycolumnTest.php +++ b/tests/transform/get/arraycolumnTest.php @@ -1,102 +1,118 @@ getTransform('get_arraycolumn', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'index' => 'example', - ]); - $result = $transform->transform([ - 'example_source_field' => [ - [ - 'example' => 'test' - ] - ], - ]); - // Make sure it stays an array - // $this->assertTrue($result); - $this->assertEquals([ 'test' ], $result); - } +use codename\core\exception; +use codename\core\io\pipeline; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - /** - * Testing transforms for Erors - */ - public function testValueValidCase2(): void { - $transform = $this->getTransform('get_arraycolumn', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'index' => [ - 'source' => 'source', - 'field' => 'example_index_field', - ] - ]); - $result = $transform->transform([ - 'example_index_field' => 'example', - 'example_source_field' => [ - [ - 'example' => 'test' - ] - ], - ]); - // Make sure it stays an array - // $this->assertTrue($result); - $this->assertEquals([ 'test' ], $result); - } +class arraycolumnTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase1(): void + { + $transform = $this->getTransform('get_arraycolumn', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'index' => 'example', + ]); + $result = $transform->transform([ + 'example_source_field' => [ + [ + 'example' => 'test', + ], + ], + ]); + // Make sure it stays an array + // static::assertTrue($result); + static::assertEquals(['test'], $result); + } - /** - * Testing transforms for Erors - */ - public function testValueValidCase3(): void { - $transform = $this->getTransform('get_arraycolumn', [ - 'source' => 'option', - 'field' => 'example_source_field', - 'index' => [ - 'source' => 'source', - 'field' => 'example_index_field', - ] - ]); + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase2(): void + { + $transform = $this->getTransform('get_arraycolumn', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'index' => [ + 'source' => 'source', + 'field' => 'example_index_field', + ], + ]); + $result = $transform->transform([ + 'example_index_field' => 'example', + 'example_source_field' => [ + [ + 'example' => 'test', + ], + ], + ]); + // Make sure it stays an array + // static::assertTrue($result); + static::assertEquals(['test'], $result); + } - $pipline = new \codename\core\io\pipeline(null, []); - $pipline->setOptions([ - 'example_source_field' => [ - [ - 'example' => 'test' - ] - ], - ]); - $transform->setPipelineInstance($pipline); + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase3(): void + { + $transform = $this->getTransform('get_arraycolumn', [ + 'source' => 'option', + 'field' => 'example_source_field', + 'index' => [ + 'source' => 'source', + 'field' => 'example_index_field', + ], + ]); - $result = $transform->transform([ - 'example_index_field' => 'example', - ]); + $pipeline = new pipeline(null, []); + $pipeline->setOptions([ + 'example_source_field' => [ + [ + 'example' => 'test', + ], + ], + ]); + $transform->setPipelineInstance($pipeline); - // Make sure it stays an array - $this->assertEquals([ 'test' ], $result ); - } + $result = $transform->transform([ + 'example_index_field' => 'example', + ]); - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('get_arraycolumn', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'index' => 'example', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example' ] - ], - $transform->getSpecification() - ); - } + // Make sure it stays an array + static::assertEquals(['test'], $result); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('get_arraycolumn', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'index' => 'example', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/get/arrayvalueTest.php b/tests/transform/get/arrayvalueTest.php index a280af4..acbb629 100644 --- a/tests/transform/get/arrayvalueTest.php +++ b/tests/transform/get/arrayvalueTest.php @@ -1,148 +1,170 @@ getTransform('get_arrayvalue', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'index' => 'example', - ]); - $result = $transform->transform([ - 'example_source_field' => [ - 'example' => true - ], - ]); - // Make sure it stays an array - $this->assertTrue($result); - } +use codename\core\exception; +use codename\core\io\pipeline; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - /** - * Testing transforms for Erors - */ - public function testValueValidCase2(): void { - $transform = $this->getTransform('get_arrayvalue', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'index' => [ - 'source' => 'source', - 'field' => 'example_index_field', - ] - ]); - $result = $transform->transform([ - 'example_index_field' => 'example', - 'example_source_field' => [ - 'example' => true - ], - ]); - // Make sure it stays an array - $this->assertTrue($result); - } +class arrayvalueTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase1(): void + { + $transform = $this->getTransform('get_arrayvalue', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'index' => 'example', + ]); + $result = $transform->transform([ + 'example_source_field' => [ + 'example' => true, + ], + ]); + // Make sure it stays an array + static::assertTrue($result); + } - /** - * Testing transforms for Erors - */ - public function testValueValidCase3(): void { - $transform = $this->getTransform('get_arrayvalue', [ - 'source' => 'option', - 'field' => 'example_source_field', - 'index' => [ - 'source' => 'source', - 'field' => 'example_index_field', - ] - ]); + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase2(): void + { + $transform = $this->getTransform('get_arrayvalue', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'index' => [ + 'source' => 'source', + 'field' => 'example_index_field', + ], + ]); + $result = $transform->transform([ + 'example_index_field' => 'example', + 'example_source_field' => [ + 'example' => true, + ], + ]); + // Make sure it stays an array + static::assertTrue($result); + } - $pipline = new \codename\core\io\pipeline(null, []); - $pipline->setOptions([ - 'example_source_field' => [ - 'example' => true - ], - ]); - $transform->setPipelineInstance($pipline); + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase3(): void + { + $transform = $this->getTransform('get_arrayvalue', [ + 'source' => 'option', + 'field' => 'example_source_field', + 'index' => [ + 'source' => 'source', + 'field' => 'example_index_field', + ], + ]); - $result = $transform->transform([ - 'example_index_field' => 'example', - ]); + $pipeline = new pipeline(null, []); + $pipeline->setOptions([ + 'example_source_field' => [ + 'example' => true, + ], + ]); + $transform->setPipelineInstance($pipeline); - // Make sure it stays an array - $this->assertTrue($result); - } + $result = $transform->transform([ + 'example_index_field' => 'example', + ]); - /** - * Testing transforms for Erors - */ - public function testValueMissingValueCase1(): void { - $transform = $this->getTransform('get_arrayvalue', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'index' => 'example_index', - 'required' => true, - ]); - $result = $transform->transform([ - 'example_source_field' => [ - 'example' => 'test' - ] - ]); - // Make sure it stays an array - $this->assertNull($result, print_r($result, true)); + // Make sure it stays an array + static::assertTrue($result); + } - $errors = $transform->getErrors(); - $this->assertNotEmpty($errors); - $this->assertCount(1, $errors); - $this->assertEquals('GET_ARRAYVALUE_MISSING', $errors[0]['__IDENTIFIER'] ); - $this->assertEquals('TRANSFORM.0', $errors[0]['__CODE'] ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueMissingValueCase1(): void + { + $transform = $this->getTransform('get_arrayvalue', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'index' => 'example_index', + 'required' => true, + ]); + $result = $transform->transform([ + 'example_source_field' => [ + 'example' => 'test', + ], + ]); + // Make sure it stays an array + static::assertNull($result, print_r($result, true)); - /** - * Testing transforms for Erors - */ - public function testValueMissingValueCase2(): void { - $transform = $this->getTransform('get_arrayvalue', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'index' => [ - 'source' => 'source', - 'field' => 'example_index_field', - ], - 'required' => true, - ]); - $result = $transform->transform([ - 'example_index' => 'example_index', - 'example_source_field' => [ - 'example' => 'test' - ] - ]); - // Make sure it stays an array - $this->assertNull($result, print_r($result, true)); + $errors = $transform->getErrors(); + static::assertNotEmpty($errors); + static::assertCount(1, $errors); + static::assertEquals('GET_ARRAYVALUE_MISSING', $errors[0]['__IDENTIFIER']); + static::assertEquals('TRANSFORM.0', $errors[0]['__CODE']); + } - $errors = $transform->getErrors(); - $this->assertNotEmpty($errors); - $this->assertCount(1, $errors); - $this->assertEquals('GET_ARRAYVALUE_MISSING', $errors[0]['__IDENTIFIER'] ); - $this->assertEquals('TRANSFORM.0', $errors[0]['__CODE'] ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueMissingValueCase2(): void + { + $transform = $this->getTransform('get_arrayvalue', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'index' => [ + 'source' => 'source', + 'field' => 'example_index_field', + ], + 'required' => true, + ]); + $result = $transform->transform([ + 'example_index' => 'example_index', + 'example_source_field' => [ + 'example' => 'test', + ], + ]); + // Make sure it stays an array + static::assertNull($result, print_r($result, true)); - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('get_arrayvalue', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'index' => 'example', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example' ] - ], - $transform->getSpecification() - ); - } + $errors = $transform->getErrors(); + static::assertNotEmpty($errors); + static::assertCount(1, $errors); + static::assertEquals('GET_ARRAYVALUE_MISSING', $errors[0]['__IDENTIFIER']); + static::assertEquals('TRANSFORM.0', $errors[0]['__CODE']); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('get_arrayvalue', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'index' => 'example', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/get/conditioned/allTest.php b/tests/transform/get/conditioned/allTest.php index 8661f2f..1df4359 100644 --- a/tests/transform/get/conditioned/allTest.php +++ b/tests/transform/get/conditioned/allTest.php @@ -1,98 +1,110 @@ getTransform('get_conditioned_all', [ - 'return' => true, - 'condition' => [ - [ - 'source' => 'source', - 'field' => 'example_source_field', - 'operator' => '=', - 'value' => 123, - ], - [ - 'source' => 'source', - 'field' => 'example_source_field2', - 'operator' => '!=', - 'value' => 456, - ], - ], - ]); - $result = $transform->transform([ - 'example_source_field' => 123, - 'example_source_field2' => 123, - ]); - $this->assertEquals(true, $result); - } +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - /** - * Testing transforms for Erors - */ - public function testValueValidCase2(): void { - $transform = $this->getTransform('get_conditioned_all', [ - 'required' => true, - 'condition' => [ - [ - 'source' => 'source', - 'field' => 'example_source_field', - 'operator' => '<>', - 'value' => 123, - ], - [ - 'source' => 'source', - 'field' => 'example_source_field2', - 'operator' => '=', - 'value' => 456, - ], - ], - ]); - $result = $transform->transform([ - 'example_source_field' => 123, - 'example_source_field2' => 123, - ]); - $this->assertEquals(null, $result); +class allTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase1(): void + { + $transform = $this->getTransform('get_conditioned_all', [ + 'return' => true, + 'condition' => [ + [ + 'source' => 'source', + 'field' => 'example_source_field', + 'operator' => '=', + 'value' => 123, + ], + [ + 'source' => 'source', + 'field' => 'example_source_field2', + 'operator' => '!=', + 'value' => 456, + ], + ], + ]); + $result = $transform->transform([ + 'example_source_field' => 123, + 'example_source_field2' => 123, + ]); + static::assertTrue($result); + } - $errors = $transform->getErrors(); - $this->assertNotEmpty($errors); - $this->assertCount(1, $errors); - $this->assertEquals('GET_CONDITIONED_ALL_NOMATCH', $errors[0]['__IDENTIFIER'] ); - $this->assertEquals('TRANSFORM.0', $errors[0]['__CODE'] ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase2(): void + { + $transform = $this->getTransform('get_conditioned_all', [ + 'required' => true, + 'condition' => [ + [ + 'source' => 'source', + 'field' => 'example_source_field', + 'operator' => '<>', + 'value' => 123, + ], + [ + 'source' => 'source', + 'field' => 'example_source_field2', + 'operator' => '=', + 'value' => 456, + ], + ], + ]); + $result = $transform->transform([ + 'example_source_field' => 123, + 'example_source_field2' => 123, + ]); + static::assertEquals(null, $result); - /** - * Testing transforms for Erors - */ - public function testValueValidCase3(): void { - $transform = $this->getTransform('get_conditioned_all', [ - 'default' => 'example', - 'return' => true, - 'condition' => [ - [ - 'source' => 'source', - 'field' => 'example_source_field', - 'operator' => '<>', - 'value' => 123, - ], - [ - 'source' => 'source', - 'field' => 'example_source_field2', - 'operator' => '!=', - 'value' => 123, - ], - ], - ]); - $result = $transform->transform([ - 'example_source_field' => 123, - 'example_source_field2' => 123, - ]); - $this->assertEquals('example', $result); - } + $errors = $transform->getErrors(); + static::assertNotEmpty($errors); + static::assertCount(1, $errors); + static::assertEquals('GET_CONDITIONED_ALL_NOMATCH', $errors[0]['__IDENTIFIER']); + static::assertEquals('TRANSFORM.0', $errors[0]['__CODE']); + } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase3(): void + { + $transform = $this->getTransform('get_conditioned_all', [ + 'default' => 'example', + 'return' => true, + 'condition' => [ + [ + 'source' => 'source', + 'field' => 'example_source_field', + 'operator' => '<>', + 'value' => 123, + ], + [ + 'source' => 'source', + 'field' => 'example_source_field2', + 'operator' => '!=', + 'value' => 123, + ], + ], + ]); + $result = $transform->transform([ + 'example_source_field' => 123, + 'example_source_field2' => 123, + ]); + static::assertEquals('example', $result); + } } diff --git a/tests/transform/get/conditionedTest.php b/tests/transform/get/conditionedTest.php index 8664437..9c1836f 100644 --- a/tests/transform/get/conditionedTest.php +++ b/tests/transform/get/conditionedTest.php @@ -1,285 +1,312 @@ getTransform('get_conditioned', [ - 'condition' => [ - [ - 'source' => 'source', - 'field' => 'example_source_field', - 'operator' => '=', - 'value' => 123, - 'return' => true - ] - ], - ]); - $result = $transform->transform([ - 'example_source_field' => 123 - ]); - $this->assertEquals(true, $result); - } + /** + * Tests using a single condition that matches and returns a static value (bool) + * @throws ReflectionException + * @throws exception + */ + public function testSingleConditionTrueReturnConstant(): void + { + $transform = $this->getTransform('get_conditioned', [ + 'condition' => [ + [ + 'source' => 'source', + 'field' => 'example_source_field', + 'operator' => '=', + 'value' => 123, + 'return' => true, + ], + ], + ]); + $result = $transform->transform([ + 'example_source_field' => 123, + ]); + static::assertTrue($result); + } + + /** + * Tests using a single condition that does *NOT* match and returns default value + * which is not being set + * @throws ReflectionException + * @throws exception + */ + public function testSingleConditionFalseReturnNoDefault(): void + { + $transform = $this->getTransform('get_conditioned', [ + 'condition' => [ + [ + 'source' => 'source', + 'field' => 'example_source_field', + 'operator' => '=', + 'value' => 123, + 'return' => true, + ], + ], + ]); + $result = $transform->transform([ + 'example_source_field' => 234, + ]); + static::assertEquals(null, $result); + } - /** - * Tests using a single condition that does *NOT* match and returns default value - * which is not being set - */ - public function testSingleConditionFalseReturnNoDefault(): void { - $transform = $this->getTransform('get_conditioned', [ - 'condition' => [ - [ - 'source' => 'source', - 'field' => 'example_source_field', - 'operator' => '=', - 'value' => 123, - 'return' => true - ] - ], - ]); - $result = $transform->transform([ - 'example_source_field' => 234 - ]); - $this->assertEquals(null, $result); - } + /** + * Tests using a single condition that does *NOT* match and returns default value + * which is not being set + * @throws ReflectionException + * @throws exception + */ + public function testSingleConditionFalseReturnNullRequired(): void + { + $transform = $this->getTransform('get_conditioned', [ + 'required' => true, + 'condition' => [ + [ + 'source' => 'source', + 'field' => 'example_source_field', + 'operator' => '=', + 'value' => 123, + 'return' => true, + ], + ], + ]); + $result = $transform->transform([ + 'example_source_field' => 234, + ]); + static::assertNull($result); - /** - * Tests using a single condition that does *NOT* match and returns default value - * which is not being set - */ - public function testSingleConditionFalseReturnNullRequired(): void { - $transform = $this->getTransform('get_conditioned', [ - 'required' => true, - 'condition' => [ - [ - 'source' => 'source', - 'field' => 'example_source_field', - 'operator' => '=', - 'value' => 123, - 'return' => true - ] - ], - ]); - $result = $transform->transform([ - 'example_source_field' => 234 - ]); - $this->assertNull($result); + $errors = $transform->getErrors(); + static::assertNotEmpty($errors); + static::assertCount(1, $errors); + static::assertEquals('GET_CONDITIONED_MISSING', $errors[0]['__IDENTIFIER']); + static::assertEquals('TRANSFORM.0', $errors[0]['__CODE']); + } - $errors = $transform->getErrors(); - $this->assertNotEmpty($errors); - $this->assertCount(1, $errors); - $this->assertEquals('GET_CONDITIONED_MISSING', $errors[0]['__IDENTIFIER'] ); - $this->assertEquals('TRANSFORM.0', $errors[0]['__CODE'] ); - } + /** + * Tests using a single condition that does *NOT* match and returns default value + * which is not being set + * @throws ReflectionException + * @throws exception + */ + public function testSingleWrongOperator(): void + { + $transform = $this->getTransform('get_conditioned', [ + 'condition' => [ + [ + 'source' => 'source', + 'field' => 'example_source_field', + 'operator' => 'example', + 'value' => 123, + 'return' => true, + ], + ], + ]); + $result = $transform->transform([ + 'example_source_field' => 234, + ]); + static::assertNull($result); + } - /** - * Tests using a single condition that does *NOT* match and returns default value - * which is not being set - */ - public function testSingleWrongOperator(): void { - $transform = $this->getTransform('get_conditioned', [ - 'condition' => [ - [ - 'source' => 'source', - 'field' => 'example_source_field', - 'operator' => 'example', - 'value' => 123, - 'return' => true - ] - ], - ]); - $result = $transform->transform([ - 'example_source_field' => 234 - ]); - $this->assertNull($result); - } + /** + * Tests using a single condition that does *NOT* match and returns default value + * which is not being set + * @throws ReflectionException + * @throws exception + */ + public function testSingleDefault(): void + { + $transform = $this->getTransform('get_conditioned', [ + 'default' => 'example', + 'condition' => [ + [ + 'source' => 'source', + 'field' => 'example_source_field', + 'operator' => 'example', + 'value' => 123, + 'return' => true, + ], + ], + ]); + $result = $transform->transform([ + 'example_source_field' => 234, + ]); + static::assertEquals('example', $result); - /** - * Tests using a single condition that does *NOT* match and returns default value - * which is not being set - */ - public function testSingleDefault(): void { - $transform = $this->getTransform('get_conditioned', [ - 'default' => 'example', - 'condition' => [ - [ - 'source' => 'source', - 'field' => 'example_source_field', - 'operator' => 'example', - 'value' => 123, - 'return' => true - ] - ], - ]); - $result = $transform->transform([ - 'example_source_field' => 234 - ]); - $this->assertEquals('example', $result); + $transform = $this->getTransform('get_conditioned', [ + 'default' => [ + 'source' => 'source', + 'field' => 'example_default_field', + ], + 'condition' => [ + [ + 'source' => 'source', + 'field' => 'example_source_field', + 'operator' => 'example', + 'value' => 123, + 'return' => true, + ], + ], + ]); + $result = $transform->transform([ + 'example_source_field' => 234, + 'example_default_field' => 'example', + ]); + static::assertEquals('example', $result); + } - $transform = $this->getTransform('get_conditioned', [ - 'default' => [ - 'source' => 'source', - 'field' => 'example_default_field', - ], - 'condition' => [ - [ - 'source' => 'source', - 'field' => 'example_source_field', - 'operator' => 'example', - 'value' => 123, - 'return' => true - ] - ], - ]); - $result = $transform->transform([ - 'example_source_field' => 234, - 'example_default_field' => 'example', - ]); - $this->assertEquals('example', $result); - } + /** + * [testSingleConditionTrueReturnDynamic description] + * @throws ReflectionException + * @throws exception + */ + public function testSingleConditionTrueReturnDynamic(): void + { + $transform = $this->getTransform('get_conditioned', [ + 'condition' => [ + [ + 'source' => 'source', + 'field' => 'example_source_field', + 'operator' => '=', + 'value' => 234, + 'return' => [ + 'source' => 'source', + 'field' => 'example_return_me', + ], + ], + ], + ]); + $result = $transform->transform([ + 'example_source_field' => 234, + 'example_return_me' => 'yes', + ]); + static::assertEquals('yes', $result); + } - /** - * [testSingleConditionTrueReturnDynamic description] - */ - public function testSingleConditionTrueReturnDynamic(): void { - $transform = $this->getTransform('get_conditioned', [ - 'condition' => [ - [ - 'source' => 'source', - 'field' => 'example_source_field', - 'operator' => '=', - 'value' => 234, - 'return' => [ - 'source' => 'source', - 'field' => 'example_return_me', - ] - ] - ], - ]); - $result = $transform->transform([ - 'example_source_field' => 234, - 'example_return_me' => 'yes' - ]); - $this->assertEquals('yes', $result); - } + /** + * [testFuzzed description] + * @throws ReflectionException + * @throws exception + */ + public function testFuzzed(): void + { + $testArray = [ - /** - * [testFuzzed description] - */ - public function testFuzzed(): void { + // regular comparisons + ['input' => 123, 'operator' => '=', 'compare' => 123, 'matches' => true], + ['input' => 123, 'operator' => '!=', 'compare' => 123, 'matches' => false], + ['input' => 123, 'operator' => '>', 'compare' => 123, 'matches' => false], + ['input' => 123, 'operator' => '>', 'compare' => 122, 'matches' => true], + ['input' => 123, 'operator' => '<', 'compare' => 123, 'matches' => false], + ['input' => 123, 'operator' => '<', 'compare' => 124, 'matches' => true], + ['input' => null, 'operator' => '=', 'compare' => null, 'matches' => true], + ['input' => null, 'operator' => '!=', 'compare' => null, 'matches' => false], + ['input' => 0, 'operator' => '!=', 'compare' => 0, 'matches' => false], + ['input' => 0, 'operator' => '=', 'compare' => 0, 'matches' => true], + ['input' => '', 'operator' => '=', 'compare' => '', 'matches' => true], - $testArray = [ + // some alphanumeric comparisons + ['input' => 'abc', 'operator' => '=', 'compare' => 'abc', 'matches' => true], + ['input' => 'abc', 'operator' => '!=', 'compare' => 'abc', 'matches' => false], + ['input' => 'abc', 'operator' => '=', 'compare' => 'def', 'matches' => false], + ['input' => 'abc', 'operator' => '!=', 'compare' => 'def', 'matches' => true], + ['input' => 'abc', 'operator' => '>', 'compare' => 'def', 'matches' => false], + ['input' => 'abc', 'operator' => '<', 'compare' => 'def', 'matches' => true], + ['input' => 'abc1', 'operator' => '>', 'compare' => 'def2', 'matches' => false], + ['input' => 'abc2', 'operator' => '<', 'compare' => 'def2', 'matches' => true], + ['input' => '1abc', 'operator' => '>', 'compare' => '2def', 'matches' => false], + ['input' => '1abc', 'operator' => '<', 'compare' => '2def', 'matches' => true], - // regular comparisons - [ 'input' => 123, 'operator' => '=', 'compare' => 123, 'matches' => true ], - [ 'input' => 123, 'operator' => '!=', 'compare' => 123, 'matches' => false ], - [ 'input' => 123, 'operator' => '>', 'compare' => 123, 'matches' => false ], - [ 'input' => 123, 'operator' => '>', 'compare' => 122, 'matches' => true ], - [ 'input' => 123, 'operator' => '<', 'compare' => 123, 'matches' => false ], - [ 'input' => 123, 'operator' => '<', 'compare' => 124, 'matches' => true ], - [ 'input' => null, 'operator' => '=', 'compare' => null, 'matches' => true ], - [ 'input' => null, 'operator' => '!=', 'compare' => null, 'matches' => false ], - [ 'input' => 0, 'operator' => '!=', 'compare' => 0, 'matches' => false ], - [ 'input' => 0, 'operator' => '=', 'compare' => 0, 'matches' => true ], - [ 'input' => '', 'operator' => '=', 'compare' => '', 'matches' => true ], + // String null and empty string comparisons + ['input' => 'abc', 'operator' => '=', 'compare' => null, 'matches' => false], + ['input' => 'abc', 'operator' => '!=', 'compare' => null, 'matches' => true], + ['input' => 'abc', 'operator' => '=', 'compare' => '', 'matches' => false], + ['input' => 'abc', 'operator' => '!=', 'compare' => '', 'matches' => true], - // some alphanumeric comparisons - [ 'input' => 'abc', 'operator' => '=', 'compare' => 'abc', 'matches' => true ], - [ 'input' => 'abc', 'operator' => '!=', 'compare' => 'abc', 'matches' => false ], - [ 'input' => 'abc', 'operator' => '=', 'compare' => 'def', 'matches' => false ], - [ 'input' => 'abc', 'operator' => '!=', 'compare' => 'def', 'matches' => true ], - [ 'input' => 'abc', 'operator' => '>', 'compare' => 'def', 'matches' => false ], - [ 'input' => 'abc', 'operator' => '<', 'compare' => 'def', 'matches' => true ], - [ 'input' => 'abc1', 'operator' => '>', 'compare' => 'def2', 'matches' => false ], - [ 'input' => 'abc2', 'operator' => '<', 'compare' => 'def2', 'matches' => true ], - [ 'input' => '1abc', 'operator' => '>', 'compare' => '2def', 'matches' => false ], - [ 'input' => '1abc', 'operator' => '<', 'compare' => '2def', 'matches' => true ], + // NOTE: Null, 0 and empty string comparisons are special + ['input' => '', 'operator' => '!=', 'compare' => 0, 'matches' => true], // w/ strict type checking: true + ['input' => 0, 'operator' => '!=', 'compare' => '', 'matches' => true], // w/ strict type checking: true + ['input' => '', 'operator' => '=', 'compare' => 0, 'matches' => false], // w/ strict type checking: false + ['input' => 0, 'operator' => '=', 'compare' => '', 'matches' => false], // w/ strict type checking: false + ['input' => null, 'operator' => '!=', 'compare' => 0, 'matches' => false], // w/ strict type checking: true + ['input' => 0, 'operator' => '!=', 'compare' => null, 'matches' => false], // w/ strict type checking: true + ['input' => null, 'operator' => '=', 'compare' => '', 'matches' => true], // w/ strict type checking: false + ['input' => '', 'operator' => '=', 'compare' => null, 'matches' => true], // w/ strict type checking: false - // String null and empty string comparisons - [ 'input' => 'abc', 'operator' => '=', 'compare' => null, 'matches' => false ], - [ 'input' => 'abc', 'operator' => '!=', 'compare' => null, 'matches' => true ], - [ 'input' => 'abc', 'operator' => '=', 'compare' => '', 'matches' => false ], - [ 'input' => 'abc', 'operator' => '!=', 'compare' => '', 'matches' => true ], + // + // TODO: tests with invalid or bad data + // + ]; - // NOTE: Null, 0 and empty string comparisons are special - // as we're not performing strict type checking here. Victim of PHP Type Juggling! - [ 'input' => '', 'operator' => '!=', 'compare' => 0, 'matches' => false ], // w/ strict type checking: true - [ 'input' => 0, 'operator' => '!=', 'compare' => '', 'matches' => false ], // w/ strict type checking: true - [ 'input' => '', 'operator' => '=', 'compare' => 0, 'matches' => true ], // w/ strict type checking: false - [ 'input' => 0, 'operator' => '=', 'compare' => '', 'matches' => true ], // w/ strict type checking: false - [ 'input' => null, 'operator' => '!=', 'compare' => 0, 'matches' => false ], // w/ strict type checking: true - [ 'input' => 0, 'operator' => '!=', 'compare' => null, 'matches' => false ], // w/ strict type checking: true - [ 'input' => null, 'operator' => '=', 'compare' => '', 'matches' => true ], // w/ strict type checking: false - [ 'input' => '', 'operator' => '=', 'compare' => null, 'matches' => true ], // w/ strict type checking: false + foreach ($testArray as $test) { + $transform = $this->getTransform('get_conditioned', [ + 'condition' => [ + [ + 'source' => 'source', + 'field' => 'input_value', + 'operator' => $test['operator'], + 'value' => [ + 'source' => 'source', + 'field' => 'compare_value', + ], + 'return' => [ + 'source' => 'source', + 'field' => 'result_if_match', + ], + ], + ], + 'default' => false, + ]); - // - // TODO: tests with invalid or bad data - // - ]; + $result = $transform->transform([ + 'input_value' => $test['input'], + 'compare_value' => $test['compare'], + 'result_if_match' => true, + ]); - $resultIfMatch = true; - $resultIfNoMatch = false; + static::assertEquals( + $test['matches'], + $result, + 'Comparing ' + . var_export($test['input'], true) + . $test['operator'] + . var_export($test['compare'], true) + . ' to be ' + . var_export((bool)$test['matches'], true) + ); + } + } - foreach($testArray as $test) { - $transform = $this->getTransform('get_conditioned', [ - 'condition' => [ - [ - 'source' => 'source', - 'field' => 'input_value', - 'operator' => $test['operator'], - 'value' => [ + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('get_conditioned', [ + 'condition' => [ + [ 'source' => 'source', - 'field' => 'compare_value' + 'field' => 'example_source_field', + 'operator' => '=', + 'value' => 123, + 'return' => true, ], - 'return' => [ - 'source' => 'source', - 'field' => 'result_if_match', - ] - ] - ], - 'default' => $resultIfNoMatch - ]); - - $result = $transform->transform([ - 'input_value' => $test['input'], - 'compare_value' => $test['compare'], - 'result_if_match' => $resultIfMatch, - ]); - - $this->assertEquals($test['matches'], $result, 'Comparing ' - . var_export($test['input'],true) - . $test['operator'] - . var_export($test['compare'],true) - . ' to be ' - . var_export($test['matches'] ? $resultIfMatch : $resultIfNoMatch,true) - ); + ], + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); } - } - - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('get_conditioned', [ - 'condition' => [ - [ - 'source' => 'source', - 'field' => 'example_source_field', - 'operator' => '=', - 'value' => 123, - 'return' => true - ] - ] - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } } diff --git a/tests/transform/get/currentdatetimeTest.php b/tests/transform/get/currentdatetimeTest.php index c1538b5..b17819d 100644 --- a/tests/transform/get/currentdatetimeTest.php +++ b/tests/transform/get/currentdatetimeTest.php @@ -1,37 +1,47 @@ getTransform('get_currentdatetime', [ - 'modify' => '+1 day', - 'format' => 'Y-m-d', - ]); - $result = $transform->transform([]); - // Make sure it stays an array - $this->assertEquals((new \DateTime('now'))->modify('+1 day')->format('Y-m-d'), $result ); - } +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use DateTime; +use ReflectionException; - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('get_currentdatetime', [ - 'modify' => '+1 day', - 'format' => 'Y-m-d', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ ] - ], - $transform->getSpecification() - ); - } +class currentdatetimeTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('get_currentdatetime', [ + 'modify' => '+1 day', + 'format' => 'Y-m-d', + ]); + $result = $transform->transform([]); + // Make sure it stays an array + static::assertEquals((new DateTime('now'))->modify('+1 day')->format('Y-m-d'), $result); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('get_currentdatetime', [ + 'modify' => '+1 day', + 'format' => 'Y-m-d', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => [], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/get/easterdatetimeTest.php b/tests/transform/get/easterdatetimeTest.php index a69e65d..18ae0d6 100644 --- a/tests/transform/get/easterdatetimeTest.php +++ b/tests/transform/get/easterdatetimeTest.php @@ -1,60 +1,73 @@ addWarning('Calendar extension needed for testing get_easterdatetime transform'); + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('get_easterdatetime', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'format' => 'Y-m-d', + ]); + $result = $transform->transform([ + 'example_source_field' => '2021-04-19', + ]); + + // calculate easter + $days = easter_days('2021'); + $easterDate = (new DateTime('2021-04-19')) + ->setDate('2021', 3, 21) + ->add(new DateInterval("P{$days}D")) + ->format('Y-m-d'); + + // Make sure it stays an array + static::assertEquals($easterDate, $result); + } + + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('get_easterdatetime', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'format' => 'Y-m-d', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => [], + ], + $transform->getSpecification() + ); } - } - - - /** - * Testing transforms for Erors - */ - public function testValueValid(): void { - $transform = $this->getTransform('get_easterdatetime', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'format' => 'Y-m-d', - ]); - $result = $transform->transform([ - 'example_source_field' => '2021-04-19' - ]); - - // calculate easter - $days = \easter_days('2021'); - $easterDate = (new \DateTime('2021-04-19')) - ->setDate('2021', 3, 21) - ->add(new \DateInterval("P{$days}D")) - ->format('Y-m-d'); - - // Make sure it stays an array - $this->assertEquals($easterDate, $result ); - } - - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('get_easterdatetime', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'format' => 'Y-m-d', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ ] - ], - $transform->getSpecification() - ); - } + /** + * {@inheritDoc} + */ + protected function setUp(): void + { + parent::setUp(); + if (!extension_loaded('calendar')) { + static::fail('Calendar extension needed for testing get_easterdatetime transform'); + } + } } diff --git a/tests/transform/get/fallbackTest.php b/tests/transform/get/fallbackTest.php index 27d0a8a..13e6ba0 100644 --- a/tests/transform/get/fallbackTest.php +++ b/tests/transform/get/fallbackTest.php @@ -1,89 +1,101 @@ getTransform('get_fallback', [ - 'fallback' => [ - [ - 'source' => 'source', - 'field' => 'example_source_field', - ], - [ - 'source' => 'source', - 'field' => 'example_source_field2', - ], - ], - ]); - $result = $transform->transform([ - 'example_source_field' => null, - 'example_source_field2' => 'example', - ]); +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - // Make sure it stays an array - $this->assertEquals('example', $result ); - } +class fallbackTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('get_fallback', [ + 'fallback' => [ + [ + 'source' => 'source', + 'field' => 'example_source_field', + ], + [ + 'source' => 'source', + 'field' => 'example_source_field2', + ], + ], + ]); + $result = $transform->transform([ + 'example_source_field' => null, + 'example_source_field2' => 'example', + ]); - /** - * Testing transforms for Erors - */ - public function testValueRequired(): void { - $transform = $this->getTransform('get_fallback', [ - 'required' => true, - 'fallback' => [ - [ - 'source' => 'source', - 'field' => 'example_source_field', - ], - [ - 'source' => 'source', - 'field' => 'example_source_field2', - ], - ], - ]); - $result = $transform->transform([ - 'example_source_field' => null, - 'example_source_field2' => null, - ]); + // Make sure it stays an array + static::assertEquals('example', $result); + } - // Make sure it stays an array - $this->assertNull($result); + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueRequired(): void + { + $transform = $this->getTransform('get_fallback', [ + 'required' => true, + 'fallback' => [ + [ + 'source' => 'source', + 'field' => 'example_source_field', + ], + [ + 'source' => 'source', + 'field' => 'example_source_field2', + ], + ], + ]); + $result = $transform->transform([ + 'example_source_field' => null, + 'example_source_field2' => null, + ]); - $errors = $transform->getErrors(); - $this->assertNotEmpty($errors); - $this->assertCount(1, $errors); - $this->assertEquals('VALUE_NULL', $errors[0]['__IDENTIFIER'] ); - $this->assertEquals('TRANSFORM.0', $errors[0]['__CODE'] ); - } + // Make sure it stays an array + static::assertNull($result); - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('get_fallback', [ - 'fallback' => [ - [ - 'source' => 'source', - 'field' => 'example_source_field', - ], - [ - 'source' => 'source', - 'field' => 'example_source_field2', - ], - ] - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field', 'source.example_source_field2' ] - ], - $transform->getSpecification() - ); - } + $errors = $transform->getErrors(); + static::assertNotEmpty($errors); + static::assertCount(1, $errors); + static::assertEquals('VALUE_NULL', $errors[0]['__IDENTIFIER']); + static::assertEquals('TRANSFORM.0', $errors[0]['__CODE']); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('get_fallback', [ + 'fallback' => [ + [ + 'source' => 'source', + 'field' => 'example_source_field', + ], + [ + 'source' => 'source', + 'field' => 'example_source_field2', + ], + ], + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field', 'source.example_source_field2'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/get/filtered/arrayfilterTest.php b/tests/transform/get/filtered/arrayfilterTest.php index 3c9407b..78d65eb 100644 --- a/tests/transform/get/filtered/arrayfilterTest.php +++ b/tests/transform/get/filtered/arrayfilterTest.php @@ -1,149 +1,164 @@ getTransform('get_filtered_arrayfilter', [ - 'force_array' => true, - 'source' => 'source', - 'field' => 'example_source_field', - 'path' => [ 'example' ], - 'filter' => [ - [ - 'operator' => '=', - 'value' => 1, - ] - ] - ]); - $result = $transform->transform([ - 'example_source_field' => [ - [ - 'example' => 1 - ], - [ - 'example' => 2 - ], - ], - ]); +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - // Make sure it stays an array - $this->assertEquals([ - [ - 'example' => 1 - ] - ], $result ); - } +class arrayfilterTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase1(): void + { + $transform = $this->getTransform('get_filtered_arrayfilter', [ + 'force_array' => true, + 'source' => 'source', + 'field' => 'example_source_field', + 'path' => ['example'], + 'filter' => [ + [ + 'operator' => '=', + 'value' => 1, + ], + ], + ]); + $result = $transform->transform([ + 'example_source_field' => [ + [ + 'example' => 1, + ], + [ + 'example' => 2, + ], + ], + ]); - /** - * Testing transforms for Erors - */ - public function testValueValidCase2(): void { - $transform = $this->getTransform('get_filtered_arrayfilter', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'path' => [ 'example' ], - 'filter' => [ - [ - 'operator' => '=', - 'value' => 1, - ] - ] - ]); - $result = $transform->transform([ - 'example_source_field' => [ - [ - 'example' => 1 - ], - [ - 'example' => 2 - ], - ], - ]); + // Make sure it stays an array + static::assertEquals([ + [ + 'example' => 1, + ], + ], $result); + } - // Make sure it stays an array - $this->assertEquals([ - [ - 'example' => 1 - ] - ], $result ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase2(): void + { + $transform = $this->getTransform('get_filtered_arrayfilter', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'path' => ['example'], + 'filter' => [ + [ + 'operator' => '=', + 'value' => 1, + ], + ], + ]); + $result = $transform->transform([ + 'example_source_field' => [ + [ + 'example' => 1, + ], + [ + 'example' => 2, + ], + ], + ]); - /** - * Testing transforms for Erors - */ - public function testValueWrongOperator(): void { - $transform = $this->getTransform('get_filtered_arrayfilter', [ - 'null_if_empty' => true, - 'source' => 'source', - 'field' => 'example_source_field', - 'path' => [ 'example' ], - 'filter' => [ - [ - 'operator' => '<>', - 'value' => 1, - ], - ] - ]); - $result = $transform->transform([ - 'example_source_field' => [ - [ - 'example' => 1 - ], - [ - 'example' => 2 - ], - ], - ]); + // Make sure it stays an array + static::assertEquals([ + [ + 'example' => 1, + ], + ], $result); + } - // Make sure it stays an array - $this->assertEquals([ - [ - 'example' => 1 - ], - [ - 'example' => 2 - ], - ], $result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueWrongOperator(): void + { + $transform = $this->getTransform('get_filtered_arrayfilter', [ + 'null_if_empty' => true, + 'source' => 'source', + 'field' => 'example_source_field', + 'path' => ['example'], + 'filter' => [ + [ + 'operator' => '<>', + 'value' => 1, + ], + ], + ]); + $result = $transform->transform([ + 'example_source_field' => [ + [ + 'example' => 1, + ], + [ + 'example' => 2, + ], + ], + ]); - /** - * Testing transforms for Erors - */ - public function testValueNoMatch(): void { - $transform = $this->getTransform('get_filtered_arrayfilter', [ - 'null_if_empty' => true, - 'source' => 'source', - 'field' => 'example_source_field', - 'path' => [ 'example' ], - 'filter' => [ - [ - 'operator' => '=', - 'value' => 1, - ], - [ - 'operator' => '!=', - 'value' => 1, - ], - ] - ]); - $result = $transform->transform([ - 'example_source_field' => [ - [ - 'example' => 1 - ], - [ - 'example' => 2 - ], - ], - ]); + // Make sure it stays an array + static::assertEquals([ + [ + 'example' => 1, + ], + [ + 'example' => 2, + ], + ], $result); + } - // Make sure it stays an array - $this->assertNull($result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueNoMatch(): void + { + $transform = $this->getTransform('get_filtered_arrayfilter', [ + 'null_if_empty' => true, + 'source' => 'source', + 'field' => 'example_source_field', + 'path' => ['example'], + 'filter' => [ + [ + 'operator' => '=', + 'value' => 1, + ], + [ + 'operator' => '!=', + 'value' => 1, + ], + ], + ]); + $result = $transform->transform([ + 'example_source_field' => [ + [ + 'example' => 1, + ], + [ + 'example' => 2, + ], + ], + ]); + // Make sure it stays an array + static::assertNull($result); + } } diff --git a/tests/transform/get/filtered/validatedTest.php b/tests/transform/get/filtered/validatedTest.php index 463b482..9cbea8f 100644 --- a/tests/transform/get/filtered/validatedTest.php +++ b/tests/transform/get/filtered/validatedTest.php @@ -1,60 +1,72 @@ getTransform('get_filtered_validated', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'validator' => [ + 'text_bic', + ], + ]); + $result = $transform->transform([ + 'example_source_field' => 'GENODEF1BEB', + ]); + + // Make sure it stays an array + static::assertEquals('GENODEF1BEB', $result); + } + + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueInvalid(): void + { + $transform = $this->getTransform('get_filtered_validated', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'validator' => 'text_bic', + ]); + $result = $transform->transform([ + 'example_source_field' => '12345678901', + ]); + + // Make sure it stays an array + static::assertNull($result); + + $errors = $transform->getErrors(); + static::assertNotEmpty($errors); + static::assertCount(1, $errors); + static::assertEquals('VALIDATION.VALUE_NOT_A_BIC', $errors[0]['__CODE']); + } - /** - * Testing transforms for Erors - */ - public function testValueValid(): void { - $transform = $this->getTransform('get_filtered_validated', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'validator' => [ - 'text_bic' - ], - ]); - $result = $transform->transform([ - 'example_source_field' => 'GENODEF1BEB', - ]); - - // Make sure it stays an array - $this->assertEquals('GENODEF1BEB', $result ); - } - - /** - * Testing transforms for Erors - */ - public function testValueInvalid(): void { - $transform = $this->getTransform('get_filtered_validated', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'validator' => 'text_bic', - ]); - $result = $transform->transform([ - 'example_source_field' => '12345678901', - ]); - - // Make sure it stays an array - $this->assertNull($result ); - - $errors = $transform->getErrors(); - $this->assertNotEmpty($errors); - $this->assertCount(1, $errors); - $this->assertEquals('VALIDATION.VALUE_NOT_A_BIC', $errors[0]['__CODE'] ); - } - - /** - * Testing transforms for Erors - */ - public function testValueMissingValidator(): void { - $this->expectException(\codename\core\exception::class); - - $transform = $this->getTransform('get_filtered_validated', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueMissingValidator(): void + { + $this->expectException(exception::class); + $this->getTransform('get_filtered_validated', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + } } diff --git a/tests/transform/get/filteredTest.php b/tests/transform/get/filteredTest.php index 0b23c84..6e5ba6b 100644 --- a/tests/transform/get/filteredTest.php +++ b/tests/transform/get/filteredTest.php @@ -1,104 +1,119 @@ getTransform('get_filtered', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'filter' => [ - [ - 'operator' => '=', - 'value' => 1, - ] - ] - ]); - $result = $transform->transform([ - 'example_source_field' => 1, - ]); +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - // Make sure it stays an array - $this->assertEquals('1', $result ); - } +class filteredTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('get_filtered', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'filter' => [ + [ + 'operator' => '=', + 'value' => 1, + ], + ], + ]); + $result = $transform->transform([ + 'example_source_field' => 1, + ]); - /** - * Testing transforms for Erors - */ - public function testValueValidCase2(): void { - $transform = $this->getTransform('get_filtered', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'filter' => [ - [ - 'operator' => '!=', - 'value' => 0, - ] - ] - ]); - $result = $transform->transform([ - 'example_source_field' => 1, - ]); + // Make sure it stays an array + static::assertEquals('1', $result); + } - // Make sure it stays an array - $this->assertEquals('1', $result ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase2(): void + { + $transform = $this->getTransform('get_filtered', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'filter' => [ + [ + 'operator' => '!=', + 'value' => 0, + ], + ], + ]); + $result = $transform->transform([ + 'example_source_field' => 1, + ]); - /** - * Testing transforms for Erors - */ - public function testValueNoMatch(): void { - $transform = $this->getTransform('get_filtered', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'filter' => [ - [ - 'operator' => '=', - 'value' => 0, - ], - [ - 'operator' => '!=', - 'value' => 1, - ], - [ - 'operator' => '<>', - 'value' => 1, - ] - ] - ]); - $result = $transform->transform([ - 'example_source_field' => 1, - ]); + // Make sure it stays an array + static::assertEquals('1', $result); + } - // Make sure it stays an array - $this->assertNull($result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueNoMatch(): void + { + $transform = $this->getTransform('get_filtered', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'filter' => [ + [ + 'operator' => '=', + 'value' => 0, + ], + [ + 'operator' => '!=', + 'value' => 1, + ], + [ + 'operator' => '<>', + 'value' => 1, + ], + ], + ]); + $result = $transform->transform([ + 'example_source_field' => 1, + ]); - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('get_filtered', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'filter' => [ - [ - 'operator' => '=', - 'value' => 1, - ] - ] - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + // Make sure it stays an array + static::assertNull($result); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('get_filtered', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'filter' => [ + [ + 'operator' => '=', + 'value' => 1, + ], + ], + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/get/number/fractionTest.php b/tests/transform/get/number/fractionTest.php index d2b8a4a..9a172e6 100644 --- a/tests/transform/get/number/fractionTest.php +++ b/tests/transform/get/number/fractionTest.php @@ -1,90 +1,108 @@ getTransform('get_number_fraction', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => 123.456, - ]); - $this->assertEquals(456, $result); - } +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - /** - * Testing transforms for Erors - */ - public function testValueValidCase2(): void { - $transform = $this->getTransform('get_number_fraction', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'fraction_digits' => 2 - ]); - $result = $transform->transform([ - 'example_source_field' => 123.456, - ]); - $this->assertEquals(45, $result); - } +class fractionTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase1(): void + { + $transform = $this->getTransform('get_number_fraction', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => 123.456, + ]); + static::assertEquals(456, $result); + } - /** - * Testing transforms for Erors - */ - public function testValueIsNull(): void { - $transform = $this->getTransform('get_number_fraction', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'required' => true - ]); - $result = $transform->transform([ - 'example_source_field' => null, - ]); - $this->assertNull($result); + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase2(): void + { + $transform = $this->getTransform('get_number_fraction', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'fraction_digits' => 2, + ]); + $result = $transform->transform([ + 'example_source_field' => 123.456, + ]); + static::assertEquals(46, $result); + } - $errors = $transform->getErrors(); - $this->assertNotEmpty($errors); - $this->assertCount(1, $errors); - $this->assertEquals('GET_NUMBER_REQUIRED', $errors[0]['__IDENTIFIER'] ); - $this->assertEquals('TRANSFORM.0', $errors[0]['__CODE'] ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueIsNull(): void + { + $transform = $this->getTransform('get_number_fraction', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'required' => true, + ]); + $result = $transform->transform([ + 'example_source_field' => null, + ]); + static::assertNull($result); - /** - * Testing transforms for Erors - */ - public function testValueInvalid(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_CORE_IO_TRANSFORM_GET_NUMBER_FRACTION_NOT_NUMERIC'); + $errors = $transform->getErrors(); + static::assertNotEmpty($errors); + static::assertCount(1, $errors); + static::assertEquals('GET_NUMBER_REQUIRED', $errors[0]['__IDENTIFIER']); + static::assertEquals('TRANSFORM.0', $errors[0]['__CODE']); + } - $transform = $this->getTransform('get_number_fraction', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => 'example', - ]); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueInvalid(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('EXCEPTION_CORE_IO_TRANSFORM_GET_NUMBER_FRACTION_NOT_NUMERIC'); - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('get_number_fraction', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + $transform = $this->getTransform('get_number_fraction', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $transform->transform([ + 'example_source_field' => 'example', + ]); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('get_number_fraction', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/get/number/wholeTest.php b/tests/transform/get/number/wholeTest.php index 8ab350a..c741bd8 100644 --- a/tests/transform/get/number/wholeTest.php +++ b/tests/transform/get/number/wholeTest.php @@ -1,75 +1,90 @@ getTransform('get_number_whole', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => 123.456, - ]); - $this->assertEquals(123, $result); - } +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - /** - * Testing transforms for Erors - */ - public function testValueIsNull(): void { - $transform = $this->getTransform('get_number_whole', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'required' => true - ]); - $result = $transform->transform([ - 'example_source_field' => null, - ]); - $this->assertNull($result); +class wholeTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase1(): void + { + $transform = $this->getTransform('get_number_whole', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => 123.456, + ]); + static::assertEquals(123, $result); + } - $errors = $transform->getErrors(); - $this->assertNotEmpty($errors); - $this->assertCount(1, $errors); - $this->assertEquals('GET_NUMBER_REQUIRED', $errors[0]['__IDENTIFIER'] ); - $this->assertEquals('TRANSFORM.0', $errors[0]['__CODE'] ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueIsNull(): void + { + $transform = $this->getTransform('get_number_whole', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'required' => true, + ]); + $result = $transform->transform([ + 'example_source_field' => null, + ]); + static::assertNull($result); - /** - * Testing transforms for Erors - */ - public function testValueInvalid(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_CORE_IO_TRANSFORM_GET_NUMBER_FRACTION_NOT_NUMERIC'); + $errors = $transform->getErrors(); + static::assertNotEmpty($errors); + static::assertCount(1, $errors); + static::assertEquals('GET_NUMBER_REQUIRED', $errors[0]['__IDENTIFIER']); + static::assertEquals('TRANSFORM.0', $errors[0]['__CODE']); + } - $transform = $this->getTransform('get_number_whole', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => 'example', - ]); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueInvalid(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('EXCEPTION_CORE_IO_TRANSFORM_GET_NUMBER_FRACTION_NOT_NUMERIC'); - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('get_number_whole', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + $transform = $this->getTransform('get_number_whole', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $transform->transform([ + 'example_source_field' => 'example', + ]); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('get_number_whole', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/get/onetimeTest.php b/tests/transform/get/onetimeTest.php index c22e27a..581a457 100644 --- a/tests/transform/get/onetimeTest.php +++ b/tests/transform/get/onetimeTest.php @@ -1,68 +1,89 @@ getTransform('get_onetime', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->resetCache(); +use codename\core\io\tests\transform\abstractTransformTest; +use Exception; +use ReflectionException; - // Make sure it stays an array - $this->assertEmpty($result); - } +class onetimeTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws \codename\core\exception + */ + public function testFunctionExistsResetCache(): void + { + $transform = $this->getTransform('get_onetime', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + try { + $transform->resetCache(); + } catch (Exception) { + static::fail(); + } - /** - * Testing transforms for Erors - */ - public function testFunctionExistsResetErrors(): void { - $transform = $this->getTransform('get_onetime', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->resetErrors(); + static::assertTrue(true); + } - // Make sure it stays an array - $this->assertEmpty($result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws \codename\core\exception + */ + public function testFunctionExistsResetErrors(): void + { + $transform = $this->getTransform('get_onetime', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + try { + $transform->resetErrors(); + } catch (Exception) { + static::fail(); + } - /** - * Testing transforms for Erors - */ - public function testValueValid(): void { - $transform = $this->getTransform('get_onetime', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => 'example', - ]); + static::assertTrue(true); + } - // Make sure it stays an array - $this->assertEquals('example', $result ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws \codename\core\exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('get_onetime', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => 'example', + ]); - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('get_onetime', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + // Make sure it stays an array + static::assertEquals('example', $result); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws \codename\core\exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('get_onetime', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/get/optionTest.php b/tests/transform/get/optionTest.php index 6893135..39111a6 100644 --- a/tests/transform/get/optionTest.php +++ b/tests/transform/get/optionTest.php @@ -1,96 +1,121 @@ getTransform('get_option', [ - 'field' => 'example_source_field', - ]); - $result = $transform->resetCache(); - - // Make sure it stays an array - $this->assertEmpty($result); - } - - /** - * Testing transforms for Erors - */ - public function testFunctionExistsResetErrors(): void { - $transform = $this->getTransform('get_option', [ - 'field' => 'example_source_field', - ]); - $result = $transform->resetErrors(); - - // Make sure it stays an array - $this->assertEmpty($result); - } - - /** - * Testing transforms for Erors - */ - public function testValueValid(): void { - $transform = $this->getTransform('get_option', [ - 'field' => 'example_source_field', - ]); - - $pipline = new \codename\core\io\pipeline(null, []); - $pipline->setOptions([ - 'example_source_field' => 'example', - ]); - $transform->setPipelineInstance($pipline); - - $result = $transform->transform([]); - - // Make sure it stays an array - $this->assertEquals('example', $result ); - } - - /** - * Testing transforms for Erors - */ - public function testValueIsNull(): void { - $transform = $this->getTransform('get_option', [ - 'field' => 'example_source_field', - 'required' => true, - ]); - - $pipline = new \codename\core\io\pipeline(null, []); - $pipline->setOptions([ - 'example_source_field' => null, - ]); - $transform->setPipelineInstance($pipline); - - $result = $transform->transform([]); - - // Make sure it stays an array - $this->assertNull($result); - - $errors = $transform->getErrors(); - $this->assertNotEmpty($errors); - $this->assertCount(1, $errors); - $this->assertEquals('OPTION_VALUE_NULL', $errors[0]['__IDENTIFIER'] ); - $this->assertEquals('TRANSFORM.0', $errors[0]['__CODE'] ); - } - - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('get_option', [ - 'field' => 'example_source_field', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'option.example_source_field' ] - ], - $transform->getSpecification() - ); - } +use codename\core\io\pipeline; +use codename\core\io\tests\transform\abstractTransformTest; +use Exception; +use ReflectionException; +class optionTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws \codename\core\exception + */ + public function testFunctionExistsResetCache(): void + { + $transform = $this->getTransform('get_option', [ + 'field' => 'example_source_field', + ]); + try { + $transform->resetCache(); + } catch (Exception) { + static::fail(); + } + + static::assertTrue(true); + } + + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws \codename\core\exception + */ + public function testFunctionExistsResetErrors(): void + { + $transform = $this->getTransform('get_option', [ + 'field' => 'example_source_field', + ]); + try { + $transform->resetErrors(); + } catch (Exception) { + static::fail(); + } + + static::assertTrue(true); + } + + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws \codename\core\exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('get_option', [ + 'field' => 'example_source_field', + ]); + + $pipeline = new pipeline(null, []); + $pipeline->setOptions([ + 'example_source_field' => 'example', + ]); + $transform->setPipelineInstance($pipeline); + + $result = $transform->transform([]); + + // Make sure it stays an array + static::assertEquals('example', $result); + } + + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws \codename\core\exception + */ + public function testValueIsNull(): void + { + $transform = $this->getTransform('get_option', [ + 'field' => 'example_source_field', + 'required' => true, + ]); + + $pipeline = new pipeline(null, []); + $pipeline->setOptions([ + 'example_source_field' => null, + ]); + $transform->setPipelineInstance($pipeline); + + $result = $transform->transform([]); + + // Make sure it stays an array + static::assertNull($result); + + $errors = $transform->getErrors(); + static::assertNotEmpty($errors); + static::assertCount(1, $errors); + static::assertEquals('OPTION_VALUE_NULL', $errors[0]['__IDENTIFIER']); + static::assertEquals('TRANSFORM.0', $errors[0]['__CODE']); + } + + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws \codename\core\exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('get_option', [ + 'field' => 'example_source_field', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['option.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/get/randomstringTest.php b/tests/transform/get/randomstringTest.php index 8ae3e81..b79839c 100644 --- a/tests/transform/get/randomstringTest.php +++ b/tests/transform/get/randomstringTest.php @@ -1,32 +1,41 @@ getTransform('get_randomstring', [ - 'chars' => 'A', - 'length' => 10, - ]); - $result = $transform->transform([]); +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - // Make sure it stays an array - $this->assertEquals('AAAAAAAAAA', $result ); - } +class randomstringTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('get_randomstring', [ + 'chars' => 'A', + 'length' => 10, + ]); + $result = $transform->transform([]); - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('get_randomstring', [ - 'chars' => 'example_source_field', - 'length' => 10, - ]); - $this->assertEmpty($transform->getSpecification()); - } + // Make sure it stays an array + static::assertEquals('AAAAAAAAAA', $result); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('get_randomstring', [ + 'chars' => 'example_source_field', + 'length' => 10, + ]); + static::assertEmpty($transform->getSpecification()); + } } diff --git a/tests/transform/get/strcaseTest.php b/tests/transform/get/strcaseTest.php index 832df6b..71cfccd 100644 --- a/tests/transform/get/strcaseTest.php +++ b/tests/transform/get/strcaseTest.php @@ -1,94 +1,112 @@ expectException(\codename\core\exception::class); - $this->expectExceptionMessage('INVALID_STRCASE_MODE'); +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - $transform = $this->getTransform('get_strcase', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'mode' => 'example', - ]); - $result = $transform->transform([ - 'example_source_field' => 1, - ]); - } +class strcaseTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueInvalidMode(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('INVALID_STRCASE_MODE'); - /** - * Testing transforms for Erors - */ - public function testValueValidCase1(): void { - $transform = $this->getTransform('get_strcase', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'mode' => 'lower', - ]); - $result = $transform->transform([ - 'example_source_field' => 'AbCdEfGhIjKlMnOpQrStUvWxYz', - ]); + $transform = $this->getTransform('get_strcase', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'mode' => 'example', + ]); + $transform->transform([ + 'example_source_field' => 1, + ]); + } - // Make sure it stays an array - $this->assertEquals('abcdefghijklmnopqrstuvwxyz', $result ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase1(): void + { + $transform = $this->getTransform('get_strcase', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'mode' => 'lower', + ]); + $result = $transform->transform([ + 'example_source_field' => 'AbCdEfGhIjKlMnOpQrStUvWxYz', + ]); - /** - * Testing transforms for Erors - */ - public function testValueValidCase2(): void { - $transform = $this->getTransform('get_strcase', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'mode' => 'upper', - ]); - $result = $transform->transform([ - 'example_source_field' => 'AbCdEfGhIjKlMnOpQrStUvWxYz', - ]); + // Make sure it stays an array + static::assertEquals('abcdefghijklmnopqrstuvwxyz', $result); + } - // Make sure it stays an array - $this->assertEquals('ABCDEFGHIJKLMNOPQRSTUVWXYZ', $result ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase2(): void + { + $transform = $this->getTransform('get_strcase', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'mode' => 'upper', + ]); + $result = $transform->transform([ + 'example_source_field' => 'AbCdEfGhIjKlMnOpQrStUvWxYz', + ]); - /** - * Testing transforms for Erors - */ - public function testValueIsNull(): void { - $transform = $this->getTransform('get_strcase', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'mode' => 'upper', - ]); - $result = $transform->transform([ - 'example_source_field' => null, - ]); + // Make sure it stays an array + static::assertEquals('ABCDEFGHIJKLMNOPQRSTUVWXYZ', $result); + } - // Make sure it stays an array - $this->assertNull($result ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueIsNull(): void + { + $transform = $this->getTransform('get_strcase', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'mode' => 'upper', + ]); + $result = $transform->transform([ + 'example_source_field' => null, + ]); + // Make sure it stays an array + static::assertNull($result); + } - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('get_strcase', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'mode' => 'lower', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('get_strcase', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'mode' => 'lower', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/get/strreplaceTest.php b/tests/transform/get/strreplaceTest.php index 88fb569..c6269c0 100644 --- a/tests/transform/get/strreplaceTest.php +++ b/tests/transform/get/strreplaceTest.php @@ -1,71 +1,83 @@ getTransform('get_strreplace', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'search' => [ - 'source' => 'source', - 'field' => 'example_search_field', - ], - 'replace' => [ - 'source' => 'source', - 'field' => 'example_replace_field', - ], - ]); - $result = $transform->transform([ - 'example_source_field' => 'AbCdEfGhIjKlMnOpQrStUvWxYz', - 'example_search_field' => 'KlM', - 'example_replace_field' => 'klm', - ]); +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - // Make sure it stays an array - $this->assertEquals('AbCdEfGhIjklmnOpQrStUvWxYz', $result ); - } +class strreplaceTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase1(): void + { + $transform = $this->getTransform('get_strreplace', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'search' => [ + 'source' => 'source', + 'field' => 'example_search_field', + ], + 'replace' => [ + 'source' => 'source', + 'field' => 'example_replace_field', + ], + ]); + $result = $transform->transform([ + 'example_source_field' => 'AbCdEfGhIjKlMnOpQrStUvWxYz', + 'example_search_field' => 'KlM', + 'example_replace_field' => 'klm', + ]); - /** - * Testing transforms for Erors - */ - public function testValueValidCase2(): void { - $transform = $this->getTransform('get_strreplace', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'search' => 'KlM', - 'replace' => 'klm', - 'case_insensitive' => true, - ]); - $result = $transform->transform([ - 'example_source_field' => 'AbCdEfGhIjKlMnOpQrStUvWxYz', - ]); + // Make sure it stays an array + static::assertEquals('AbCdEfGhIjklmnOpQrStUvWxYz', $result); + } - // Make sure it stays an array - $this->assertEquals('AbCdEfGhIjklmnOpQrStUvWxYz', $result ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase2(): void + { + $transform = $this->getTransform('get_strreplace', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'search' => 'KlM', + 'replace' => 'klm', + 'case_insensitive' => true, + ]); + $result = $transform->transform([ + 'example_source_field' => 'AbCdEfGhIjKlMnOpQrStUvWxYz', + ]); + // Make sure it stays an array + static::assertEquals('AbCdEfGhIjklmnOpQrStUvWxYz', $result); + } - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('get_strreplace', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'mode' => 'lower', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('get_strreplace', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'mode' => 'lower', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/get/substrTest.php b/tests/transform/get/substrTest.php index 8233861..0bf7e4e 100644 --- a/tests/transform/get/substrTest.php +++ b/tests/transform/get/substrTest.php @@ -1,60 +1,72 @@ getTransform('get_substr', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'start' => -3, + ]); + $result = $transform->transform([ + 'example_source_field' => 'AbCdEfGhIjKlMnOpQrStUvWxYz', + ]); + + // Make sure it stays an array + static::assertEquals('xYz', $result); + } + + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidCase2(): void + { + $transform = $this->getTransform('get_substr', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'start' => 3, + 'length' => 3, + ]); + $result = $transform->transform([ + 'example_source_field' => 'AbCdEfGhIjKlMnOpQrStUvWxYz', + ]); + + // Make sure it stays an array + static::assertEquals('dEf', $result); + } - /** - * Testing transforms for Erors - */ - public function testValueValidCase1(): void { - $transform = $this->getTransform('get_substr', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'start' => -3, - ]); - $result = $transform->transform([ - 'example_source_field' => 'AbCdEfGhIjKlMnOpQrStUvWxYz', - ]); - - // Make sure it stays an array - $this->assertEquals('xYz', $result ); - } - - /** - * Testing transforms for Erors - */ - public function testValueValidCase2(): void { - $transform = $this->getTransform('get_substr', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'start' => 3, - 'length' => 3, - ]); - $result = $transform->transform([ - 'example_source_field' => 'AbCdEfGhIjKlMnOpQrStUvWxYz', - ]); - - // Make sure it stays an array - $this->assertEquals('dEf', $result ); - } - - - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('get_substr', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('get_substr', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/get/valueTest.php b/tests/transform/get/valueTest.php index 70ac017..0534d10 100644 --- a/tests/transform/get/valueTest.php +++ b/tests/transform/get/valueTest.php @@ -1,41 +1,50 @@ getTransform('get_value', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => 'AbCdEfGhIjKlMnOpQrStUvWxYz', - ]); +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - // Make sure it stays an array - $this->assertEquals('AbCdEfGhIjKlMnOpQrStUvWxYz', $result ); - } +class valueTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValue(): void + { + $transform = $this->getTransform('get_value', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => 'AbCdEfGhIjKlMnOpQrStUvWxYz', + ]); + // Make sure it stays an array + static::assertEquals('AbCdEfGhIjKlMnOpQrStUvWxYz', $result); + } - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('get_value', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('get_value', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/get/valuearrayTest.php b/tests/transform/get/valuearrayTest.php index 10d015c..0dc9177 100644 --- a/tests/transform/get/valuearrayTest.php +++ b/tests/transform/get/valuearrayTest.php @@ -1,136 +1,151 @@ getTransform('get_valuearray', [ - 'elements' => [ - 'country' => 'DE', - 'zipcode' => [ 'source' => 'source', 'field' => 'example_zipcode_field' ], - 'city' => [ 'source' => 'source', 'field' => 'example_city_field' ], - 'street' => [ 'source' => 'source', 'field' => 'example_street_field' ], - 'houseno' => [ 'source' => 'source', 'field' => 'example_houseno_field' ], - ] - ]); - $result = $transform->transform([ - 'example_zipcode_field' => '01067', - 'example_city_field' => 'Dresden', - 'example_street_field' => 'Adlergasse', - 'example_houseno_field' => '1', - ]); +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - // Make sure it stays an array - $this->assertEquals([ - 'country' => 'DE', - 'zipcode' => '01067', - 'city' => 'Dresden', - 'street' => 'Adlergasse', - 'houseno' => '1', - ], $result ); - } +class valuearrayTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValue(): void + { + $transform = $this->getTransform('get_valuearray', [ + 'elements' => [ + 'country' => 'DE', + 'zipcode' => ['source' => 'source', 'field' => 'example_zipcode_field'], + 'city' => ['source' => 'source', 'field' => 'example_city_field'], + 'street' => ['source' => 'source', 'field' => 'example_street_field'], + 'houseno' => ['source' => 'source', 'field' => 'example_houseno_field'], + ], + ]); + $result = $transform->transform([ + 'example_zipcode_field' => '01067', + 'example_city_field' => 'Dresden', + 'example_street_field' => 'Adlergasse', + 'example_houseno_field' => '1', + ]); - /** - * Testing transforms for Erors - */ - public function testValueRequired(): void { - $transform = $this->getTransform('get_valuearray', [ - 'elements' => [ - 'country' => 'DE', - 'zipcode' => [ 'source' => 'source', 'field' => 'example_zipcode_field' ], - 'city' => [ 'source' => 'source', 'field' => 'example_city_field' ], - 'street' => [ 'source' => 'source', 'field' => 'example_street_field' ], - 'houseno' => [ 'source' => 'source', 'field' => 'example_houseno_field', 'required' => true ], - ] - ]); - $result = $transform->transform([ - 'example_zipcode_field' => '01067', - 'example_city_field' => 'Dresden', - 'example_street_field' => null, - 'example_houseno_field' => null, - ]); + // Make sure it stays an array + static::assertEquals([ + 'country' => 'DE', + 'zipcode' => '01067', + 'city' => 'Dresden', + 'street' => 'Adlergasse', + 'houseno' => '1', + ], $result); + } - // Make sure it stays an array - $this->assertEquals([ - 'country' => 'DE', - 'zipcode' => '01067', - 'city' => 'Dresden', - ], $result ); + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueRequired(): void + { + $transform = $this->getTransform('get_valuearray', [ + 'elements' => [ + 'country' => 'DE', + 'zipcode' => ['source' => 'source', 'field' => 'example_zipcode_field'], + 'city' => ['source' => 'source', 'field' => 'example_city_field'], + 'street' => ['source' => 'source', 'field' => 'example_street_field'], + 'houseno' => ['source' => 'source', 'field' => 'example_houseno_field', 'required' => true], + ], + ]); + $result = $transform->transform([ + 'example_zipcode_field' => '01067', + 'example_city_field' => 'Dresden', + 'example_street_field' => null, + 'example_houseno_field' => null, + ]); - $errors = $transform->getErrors(); - $this->assertNotEmpty($errors); - $this->assertCount(1, $errors); - $this->assertEquals('GET_VALUEARRAY_MISSING_KEY', $errors[0]['__IDENTIFIER'] ); - $this->assertEquals('TRANSFORM.0', $errors[0]['__CODE'] ); - } + // Make sure it stays an array + static::assertEquals([ + 'country' => 'DE', + 'zipcode' => '01067', + 'city' => 'Dresden', + ], $result); - /** - * [testAllowNull description] - */ - public function testAllowNull(): void { - $transform = $this->getTransform('get_valuearray', [ - 'elements' => [ - 'country' => 'DE', - 'zipcode' => [ 'source' => 'source', 'field' => 'example_zipcode_field' ], - 'city' => [ 'source' => 'source', 'field' => 'example_city_field' ], - 'street' => [ 'source' => 'source', 'field' => 'example_street_field', 'allow_null' => true ], - 'houseno' => [ 'source' => 'source', 'field' => 'example_houseno_field', 'required' => true ], - ] - ]); - $result = $transform->transform([ - 'example_zipcode_field' => '01067', - 'example_city_field' => 'Dresden', - 'example_street_field' => null, // allowed, expect passthrough of NULL value. - 'example_houseno_field' => null, // not allowed, key should not be present in result. - ]); + $errors = $transform->getErrors(); + static::assertNotEmpty($errors); + static::assertCount(1, $errors); + static::assertEquals('GET_VALUEARRAY_MISSING_KEY', $errors[0]['__IDENTIFIER']); + static::assertEquals('TRANSFORM.0', $errors[0]['__CODE']); + } - // Make sure it stays an array - $this->assertEquals([ - 'country' => 'DE', - 'zipcode' => '01067', - 'city' => 'Dresden', - 'street' => null - ], $result ); + /** + * [testAllowNull description] + * @throws ReflectionException + * @throws exception + */ + public function testAllowNull(): void + { + $transform = $this->getTransform('get_valuearray', [ + 'elements' => [ + 'country' => 'DE', + 'zipcode' => ['source' => 'source', 'field' => 'example_zipcode_field'], + 'city' => ['source' => 'source', 'field' => 'example_city_field'], + 'street' => ['source' => 'source', 'field' => 'example_street_field', 'allow_null' => true], + 'houseno' => ['source' => 'source', 'field' => 'example_houseno_field', 'required' => true], + ], + ]); + $result = $transform->transform([ + 'example_zipcode_field' => '01067', + 'example_city_field' => 'Dresden', + 'example_street_field' => null, // allowed, expect passthrough of NULL value. + 'example_houseno_field' => null, // not allowed, key should not be present in result. + ]); - // We will still receive one error for one key - $errors = $transform->getErrors(); - $this->assertNotEmpty($errors); - $this->assertCount(1, $errors); - $this->assertEquals('GET_VALUEARRAY_MISSING_KEY', $errors[0]['__IDENTIFIER'] ); - $this->assertEquals('TRANSFORM.0', $errors[0]['__CODE'] ); - } + // Make sure it stays an array + static::assertEquals([ + 'country' => 'DE', + 'zipcode' => '01067', + 'city' => 'Dresden', + 'street' => null, + ], $result); - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('get_valuearray', [ - 'elements' => [ - 'country' => 'DE', - 'zipcode' => [ 'source' => 'source', 'field' => 'example_zipcode_field' ], - 'city' => [ 'source' => 'source', 'field' => 'example_city_field' ], - 'street' => [ 'source' => 'source', 'field' => 'example_street_field' ], - 'houseno' => [ 'source' => 'source', 'field' => 'example_houseno_field' ], - 'example' => [ 'source' => 'source', 'field' => [ 'example', 'example'] ], - ] - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ - 'zipcode' => 'source.example_zipcode_field', - 'city' => 'source.example_city_field', - 'street' => 'source.example_street_field', - 'houseno' => 'source.example_houseno_field', - 'example' => 'source.example.example', - ] - ], - $transform->getSpecification() - ); - } + // We will still receive one error for one key + $errors = $transform->getErrors(); + static::assertNotEmpty($errors); + static::assertCount(1, $errors); + static::assertEquals('GET_VALUEARRAY_MISSING_KEY', $errors[0]['__IDENTIFIER']); + static::assertEquals('TRANSFORM.0', $errors[0]['__CODE']); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('get_valuearray', [ + 'elements' => [ + 'country' => 'DE', + 'zipcode' => ['source' => 'source', 'field' => 'example_zipcode_field'], + 'city' => ['source' => 'source', 'field' => 'example_city_field'], + 'street' => ['source' => 'source', 'field' => 'example_street_field'], + 'houseno' => ['source' => 'source', 'field' => 'example_houseno_field'], + 'example' => ['source' => 'source', 'field' => ['example', 'example']], + ], + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => [ + 'zipcode' => 'source.example_zipcode_field', + 'city' => 'source.example_city_field', + 'street' => 'source.example_street_field', + 'houseno' => 'source.example_houseno_field', + 'example' => 'source.example.example', + ], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/hashTest.php b/tests/transform/hashTest.php index c652d88..d404139 100644 --- a/tests/transform/hashTest.php +++ b/tests/transform/hashTest.php @@ -1,56 +1,68 @@ expectException(exception::class); + $this->expectExceptionMessage('EXCEPTION_TRANSFORM_HASH_NO_ALGORITHM_SPECIFIED'); - /** - * Testing transforms for Erors - */ - public function testConstructInvalid(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_TRANSFORM_HASH_NO_ALGORITHM_SPECIFIED'); - - $transform = $this->getTransform('hash', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => null - ]); - } + $transform = $this->getTransform('hash', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $transform->transform([ + 'example_source_field' => null, + ]); + } - /** - * Testing transforms for Erors - */ - public function testValueValid(): void { - $transform = $this->getTransform('hash', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'algorithm' => 'md5', - ]); - $result = $transform->transform([ - 'example_source_field' => 'test' - ]); - // Make sure it stays an array - $this->assertEquals(hash('md5', 'test'), $result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('hash', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'algorithm' => 'md5', + ]); + $result = $transform->transform([ + 'example_source_field' => 'test', + ]); + // Make sure it stays an array + static::assertEquals(hash('md5', 'test'), $result); + } - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('hash', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'algorithm' => 'md5', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('hash', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'algorithm' => 'md5', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/implode/arrayvalueTest.php b/tests/transform/implode/arrayvalueTest.php index 01b7d00..c11c80f 100644 --- a/tests/transform/implode/arrayvalueTest.php +++ b/tests/transform/implode/arrayvalueTest.php @@ -1,45 +1,54 @@ getTransform('implode_arrayvalue', [ - 'glue' => ',', - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => [ - 'test', - 'test1', - 'test2', - ] - ]); - // Make sure it stays an array - $this->assertEquals('test,test1,test2', $result); - } +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('implode_arrayvalue', [ - 'glue' => ',', - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } +class arrayvalueTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('implode_arrayvalue', [ + 'glue' => ',', + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => [ + 'test', + 'test1', + 'test2', + ], + ]); + // Make sure it stays an array + static::assertEquals('test,test1,test2', $result); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('implode_arrayvalue', [ + 'glue' => ',', + 'source' => 'source', + 'field' => 'example_source_field', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/implodeTest.php b/tests/transform/implodeTest.php index 5753bfd..14e095d 100644 --- a/tests/transform/implodeTest.php +++ b/tests/transform/implodeTest.php @@ -1,161 +1,183 @@ getTransform('implode', [ - 'fields' => [ - [ 'source' => 'source', 'field' => 'example_source_field1' ], - [ 'source' => 'source', 'field' => 'example_source_field2' ], - ] - ]); - $result = $transform->transform([ - 'example_source_field1' => 'value1', - 'example_source_field2' => 'value2', - ]); - $this->assertEquals('value1value2', $result); - } + /** + * Tests for default glue ('') + * @throws ReflectionException + * @throws exception + */ + public function testDefaultGlue(): void + { + $transform = $this->getTransform('implode', [ + 'fields' => [ + ['source' => 'source', 'field' => 'example_source_field1'], + ['source' => 'source', 'field' => 'example_source_field2'], + ], + ]); + $result = $transform->transform([ + 'example_source_field1' => 'value1', + 'example_source_field2' => 'value2', + ]); + static::assertEquals('value1value2', $result); + } - /** - * [testCustomGlue description] - */ - public function testCustomGlue(): void { - $transform = $this->getTransform('implode', [ - 'glue' => ';', - 'fields' => [ - [ 'source' => 'source', 'field' => 'example_source_field1' ], - [ 'source' => 'source', 'field' => 'example_source_field2' ], - ] - ]); - $result = $transform->transform([ - 'example_source_field1' => 'value1', - 'example_source_field2' => 'value2', - ]); - $this->assertEquals('value1;value2', $result); - } + /** + * [testCustomGlue description] + * @throws ReflectionException + * @throws exception + */ + public function testCustomGlue(): void + { + $transform = $this->getTransform('implode', [ + 'glue' => ';', + 'fields' => [ + ['source' => 'source', 'field' => 'example_source_field1'], + ['source' => 'source', 'field' => 'example_source_field2'], + ], + ]); + $result = $transform->transform([ + 'example_source_field1' => 'value1', + 'example_source_field2' => 'value2', + ]); + static::assertEquals('value1;value2', $result); + } - /** - * Tests for providing a constant value in fields - * but with disabled allowConstants config - */ - public function testAllowConstantsDisabled(): void { - $transform = $this->getTransform('implode', [ - 'glue' => ';', - 'fields' => [ - [ 'source' => 'source', 'field' => 'example_source_field1' ], - '-constant-', - [ 'source' => 'source', 'field' => 'example_source_field2' ], - ], - 'fallbackValue' => 'MISSING' - ]); - $result = $transform->transform([ - 'example_source_field1' => 'value1', - 'example_source_field2' => 'value2', - ]); - $this->assertEquals('value1;MISSING;value2', $result); - } + /** + * Tests for providing a constant value in fields + * but with disabled allowConstants config + * @throws ReflectionException + * @throws exception + */ + public function testAllowConstantsDisabled(): void + { + $transform = $this->getTransform('implode', [ + 'glue' => ';', + 'fields' => [ + ['source' => 'source', 'field' => 'example_source_field1'], + '-constant-', + ['source' => 'source', 'field' => 'example_source_field2'], + ], + 'fallbackValue' => 'MISSING', + ]); + $result = $transform->transform([ + 'example_source_field1' => 'value1', + 'example_source_field2' => 'value2', + ]); + static::assertEquals('value1;MISSING;value2', $result); + } - /** - * Tests for source field data retrieval on constant value as field - * but with disabled allowConstants - */ - public function testAllowConstantsDisabledSourceFallback(): void { - $transform = $this->getTransform('implode', [ - 'glue' => ';', - 'fields' => [ - [ 'source' => 'source', 'field' => 'example_source_field1' ], - 'example_source_field1', // existing name in source - [ 'source' => 'source', 'field' => 'example_source_field2' ], - ], - 'fallbackValue' => 'MISSING' - ]); - $result = $transform->transform([ - 'example_source_field1' => 'value1', - 'example_source_field2' => 'value2', - ]); - $this->assertEquals('value1;value1;value2', $result); - } + /** + * Tests for source field data retrieval on constant value as field + * but with disabled allowConstants + * @throws ReflectionException + * @throws exception + */ + public function testAllowConstantsDisabledSourceFallback(): void + { + $transform = $this->getTransform('implode', [ + 'glue' => ';', + 'fields' => [ + ['source' => 'source', 'field' => 'example_source_field1'], + 'example_source_field1', // existing name in source + ['source' => 'source', 'field' => 'example_source_field2'], + ], + 'fallbackValue' => 'MISSING', + ]); + $result = $transform->transform([ + 'example_source_field1' => 'value1', + 'example_source_field2' => 'value2', + ]); + static::assertEquals('value1;value1;value2', $result); + } - /** - * Tests for providing a constant value in fields - * but with enabled allowConstants config - */ - public function testAllowConstantsEnabled(): void { - $transform = $this->getTransform('implode', [ - 'glue' => ';', - 'fields' => [ - [ 'source' => 'source', 'field' => 'example_source_field1' ], - '-constant-', - [ 'source' => 'source', 'field' => 'example_source_field2' ], - ], - 'allowConstants' => true, - 'fallbackValue' => 'MISSING' - ]); - $result = $transform->transform([ - 'example_source_field1' => 'value1', - 'example_source_field2' => 'value2', - ]); - $this->assertEquals('value1;-constant-;value2', $result); - } + /** + * Tests for providing a constant value in fields + * but with enabled allowConstants config + * @throws ReflectionException + * @throws exception + */ + public function testAllowConstantsEnabled(): void + { + $transform = $this->getTransform('implode', [ + 'glue' => ';', + 'fields' => [ + ['source' => 'source', 'field' => 'example_source_field1'], + '-constant-', + ['source' => 'source', 'field' => 'example_source_field2'], + ], + 'allowConstants' => true, + 'fallbackValue' => 'MISSING', + ]); + $result = $transform->transform([ + 'example_source_field1' => 'value1', + 'example_source_field2' => 'value2', + ]); + static::assertEquals('value1;-constant-;value2', $result); + } - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('implode', [ - 'fields' => [ - [ 'source' => 'source', 'field' => 'example_source_field1' ], - [ 'source' => 'source', 'field' => 'example_source_field2' ], - ] - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ - 'source.example_source_field1', - 'source.example_source_field2', - ] - ], - $transform->getSpecification() - ); + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('implode', [ + 'fields' => [ + ['source' => 'source', 'field' => 'example_source_field1'], + ['source' => 'source', 'field' => 'example_source_field2'], + ], + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => [ + 'source.example_source_field1', + 'source.example_source_field2', + ], + ], + $transform->getSpecification() + ); - $transform = $this->getTransform('implode', [ - 'fields' => [ - [ 'source' => 'source', 'field' => 'example_source_field1' ], - 'some_implicit_source_field', - ] - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ - 'source.example_source_field1', - 'source.some_implicit_source_field', - ] - ], - $transform->getSpecification() - ); + $transform = $this->getTransform('implode', [ + 'fields' => [ + ['source' => 'source', 'field' => 'example_source_field1'], + 'some_implicit_source_field', + ], + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => [ + 'source.example_source_field1', + 'source.some_implicit_source_field', + ], + ], + $transform->getSpecification() + ); - $transform = $this->getTransform('implode', [ - 'allowConstants' => true, - 'fields' => [ - [ 'source' => 'source', 'field' => 'example_source_field1' ], - 'some_constant', - ] - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ - 'source.example_source_field1', - 'some_constant', - ] - ], - $transform->getSpecification() - ); - } + $transform = $this->getTransform('implode', [ + 'allowConstants' => true, + 'fields' => [ + ['source' => 'source', 'field' => 'example_source_field1'], + 'some_constant', + ], + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => [ + 'source.example_source_field1', + 'some_constant', + ], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/math/roundTest.php b/tests/transform/math/roundTest.php index 15c6236..c3cfb44 100644 --- a/tests/transform/math/roundTest.php +++ b/tests/transform/math/roundTest.php @@ -1,210 +1,237 @@ getTransform('math_round', [ - 'source' => 'source', - 'field' => 'example_source_field1', - ]); - $result = $transform->transform([ - 'example_source_field1' => 5.4321, - ]); - - $this->assertEquals(5.0, $result); - $this->assertIsFloat($result); // Will stay a float in this case...? - - $transform->reset(); - $result = $transform->transform([ - 'example_source_field1' => 5.5, - ]); - $this->assertEquals(6.0, $result); - } - - /** - * Tests negative rounding, e.g. 5.432 => 10 - */ - public function testNegativeRounding(): void { - $transform = $this->getTransform('math_round', [ - 'source' => 'source', - 'field' => 'example_source_field1', - 'precision' => -1 - ]); - $result = $transform->transform([ - 'example_source_field1' => 5.4321, - ]); - - $this->assertEquals(10, $result); - $this->assertIsFloat($result); // Will stay a float in this case...? - - $transform->reset(); - $result = $transform->transform([ - 'example_source_field1' => 5.0, - ]); - $this->assertEquals(10, $result); - - $transform->reset(); - $result = $transform->transform([ - 'example_source_field1' => 4.0, - ]); - $this->assertEquals(0, $result); - } - - /** - * [testNegativeRoundingDown description] - */ - public function testNegativeRoundingDown(): void { - $transform = $this->getTransform('math_round', [ - 'source' => 'source', - 'field' => 'example_source_field1', - 'precision' => -1, - 'mode' => 'half_down', - ]); - $result = $transform->transform([ - 'example_source_field1' => 5.4321, - ]); - - $this->assertEquals(10.0, $result); - $this->assertIsFloat($result); // Will stay a float in this case...? - - $transform->reset(); - $result = $transform->transform([ - 'example_source_field1' => 5.0, - ]); - $this->assertEquals(0, $result); - - $transform->reset(); - $result = $transform->transform([ - 'example_source_field1' => 4.0, - ]); - $this->assertEquals(0, $result); - } - - /** - * Tests a custom precision value - */ - public function testCustomPrecision(): void { - $transform = $this->getTransform('math_round', [ - 'source' => 'source', - 'field' => 'example_source_field1', - 'precision' => 1 - ]); - $result = $transform->transform([ - 'example_source_field1' => 5.4321, - ]); - - $this->assertEquals(5.4, $result); - $this->assertIsFloat($result); // Will stay a float in this case...? - } - - /** - * Tests half_down rounding - */ - public function testRoundDownBehavior(): void { - $transform = $this->getTransform('math_round', [ - 'source' => 'source', - 'field' => 'example_source_field1', - 'precision' => 1, - 'mode' => 'half_down' - ]); - $result = $transform->transform([ - 'example_source_field1' => 5.45, - ]); - - $this->assertEquals(5.4, $result); - $this->assertIsFloat($result); // Will stay a float in this case...? - - $transform->reset(); - $result = $transform->transform([ - 'example_source_field1' => 5.55, - ]); - - $this->assertEquals(5.5, $result); - $this->assertIsFloat($result); // Will stay a float in this case...? - } - - /** - * Tests default half_up - */ - public function testRoundUpBehavior(): void { - $transform = $this->getTransform('math_round', [ - 'source' => 'source', - 'field' => 'example_source_field1', - 'precision' => 1 - ]); - $result = $transform->transform([ - 'example_source_field1' => 5.45, - ]); - - $this->assertEquals(5.5, $result); - $this->assertIsFloat($result); // Will stay a float in this case...? - } - - /** - * Tests whether half_up and financial modes are the same. - */ - public function testModeAliaseRoundUpFinancial(): void { - $transformA = $this->getTransform('math_round', [ - 'source' => 'source', - 'field' => 'example_source_field1', - 'precision' => 1, - 'mode' => 'financial', - ]); - $resultA = $transformA->transform([ - 'example_source_field1' => 5.45, - ]); - - $transformB = $this->getTransform('math_round', [ - 'source' => 'source', - 'field' => 'example_source_field1', - 'precision' => 1, - 'mode' => 'half_up', - ]); - $resultB = $transformA->transform([ - 'example_source_field1' => 5.45, - ]); - - $this->assertEquals(5.5, $resultA); - $this->assertIsFloat($resultA); // Will stay a float in this case...? - $this->assertEquals($resultA, $resultB); - } - - /** - * Test specifying an invalid mode will throw an exception - */ - public function testInvalidModeWillThrow(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('INVALID_ROUND_MODE'); - $transform = $this->getTransform('math_round', [ - 'source' => 'source', - 'field' => 'example_source_field1', - 'mode' => 'invalid_value', - ]); - } - - // /** - // * Test Spec output (simple case) - // */ - // public function testSpecification(): void { - // $transform = $this->getTransform('calculate_multiply', [ - // 'factors' => [ - // [ 'source' => 'source', 'field' => 'example_source_field1' ], - // 'example_source_field2', - // ], - // 'precision' => 2, - // ]); - // $this->assertEquals( - // [ - // 'type' => 'transform', - // 'source' => [ 'source.example_source_field1' ] - // ], - // $transform->getSpecification() - // ); - // } +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; +class roundTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testDefaultRounding(): void + { + $transform = $this->getTransform('math_round', [ + 'source' => 'source', + 'field' => 'example_source_field1', + ]); + $result = $transform->transform([ + 'example_source_field1' => 5.4321, + ]); + + static::assertEquals(5.0, $result); + static::assertIsFloat($result); // Will stay a float in this case...? + + $transform->reset(); + $result = $transform->transform([ + 'example_source_field1' => 5.5, + ]); + static::assertEquals(6.0, $result); + } + + /** + * Tests negative rounding, e.g. 5.432 => 10 + * @throws ReflectionException + * @throws exception + */ + public function testNegativeRounding(): void + { + $transform = $this->getTransform('math_round', [ + 'source' => 'source', + 'field' => 'example_source_field1', + 'precision' => -1, + ]); + $result = $transform->transform([ + 'example_source_field1' => 5.4321, + ]); + + static::assertEquals(10, $result); + static::assertIsFloat($result); // Will stay a float in this case...? + + $transform->reset(); + $result = $transform->transform([ + 'example_source_field1' => 5.0, + ]); + static::assertEquals(10, $result); + + $transform->reset(); + $result = $transform->transform([ + 'example_source_field1' => 4.0, + ]); + static::assertEquals(0, $result); + } + + /** + * [testNegativeRoundingDown description] + * @throws ReflectionException + * @throws exception + */ + public function testNegativeRoundingDown(): void + { + $transform = $this->getTransform('math_round', [ + 'source' => 'source', + 'field' => 'example_source_field1', + 'precision' => -1, + 'mode' => 'half_down', + ]); + $result = $transform->transform([ + 'example_source_field1' => 5.4321, + ]); + + static::assertEquals(10.0, $result); + static::assertIsFloat($result); // Will stay a float in this case...? + + $transform->reset(); + $result = $transform->transform([ + 'example_source_field1' => 5.0, + ]); + static::assertEquals(0, $result); + + $transform->reset(); + $result = $transform->transform([ + 'example_source_field1' => 4.0, + ]); + static::assertEquals(0, $result); + } + + /** + * Tests a custom precision value + * @throws ReflectionException + * @throws exception + */ + public function testCustomPrecision(): void + { + $transform = $this->getTransform('math_round', [ + 'source' => 'source', + 'field' => 'example_source_field1', + 'precision' => 1, + ]); + $result = $transform->transform([ + 'example_source_field1' => 5.4321, + ]); + + static::assertEquals(5.4, $result); + static::assertIsFloat($result); // Will stay a float in this case...? + } + + /** + * Tests half_down rounding + * @throws ReflectionException + * @throws exception + */ + public function testRoundDownBehavior(): void + { + $transform = $this->getTransform('math_round', [ + 'source' => 'source', + 'field' => 'example_source_field1', + 'precision' => 1, + 'mode' => 'half_down', + ]); + $result = $transform->transform([ + 'example_source_field1' => 5.45, + ]); + + static::assertEquals(5.4, $result); + static::assertIsFloat($result); // Will stay a float in this case...? + + $transform->reset(); + $result = $transform->transform([ + 'example_source_field1' => 5.55, + ]); + + static::assertEquals(5.5, $result); + static::assertIsFloat($result); // Will stay a float in this case...? + } + + /** + * Tests default half_up + * @throws ReflectionException + * @throws exception + */ + public function testRoundUpBehavior(): void + { + $transform = $this->getTransform('math_round', [ + 'source' => 'source', + 'field' => 'example_source_field1', + 'precision' => 1, + ]); + $result = $transform->transform([ + 'example_source_field1' => 5.45, + ]); + + static::assertEquals(5.5, $result); + static::assertIsFloat($result); // Will stay a float in this case...? + } + + /** + * Tests whether half_up and financial modes are the same. + * @throws ReflectionException + * @throws exception + */ + public function testModeAliaseRoundUpFinancial(): void + { + $transformA = $this->getTransform('math_round', [ + 'source' => 'source', + 'field' => 'example_source_field1', + 'precision' => 1, + 'mode' => 'financial', + ]); + $resultA = $transformA->transform([ + 'example_source_field1' => 5.45, + ]); + + $this->getTransform('math_round', [ + 'source' => 'source', + 'field' => 'example_source_field1', + 'precision' => 1, + 'mode' => 'half_up', + ]); + $resultB = $transformA->transform([ + 'example_source_field1' => 5.45, + ]); + + static::assertEquals(5.5, $resultA); + static::assertIsFloat($resultA); // Will stay a float in this case...? + static::assertEquals($resultA, $resultB); + } + + /** + * Test specifying an invalid mode will throw an exception + * @throws ReflectionException + * @throws exception + */ + public function testInvalidModeWillThrow(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('INVALID_ROUND_MODE'); + $this->getTransform('math_round', [ + 'source' => 'source', + 'field' => 'example_source_field1', + 'mode' => 'invalid_value', + ]); + } + + // /** + // * Test Spec output (simple case) + // */ + // public function testSpecification(): void { + // $transform = $this->getTransform('calculate_multiply', [ + // 'factors' => [ + // [ 'source' => 'source', 'field' => 'example_source_field1' ], + // 'example_source_field2', + // ], + // 'precision' => 2, + // ]); + // static::assertEquals( + // [ + // 'type' => 'transform', + // 'source' => [ 'source.example_source_field1' ] + // ], + // $transform->getSpecification() + // ); + // } } diff --git a/tests/transform/model/tjsample.php b/tests/transform/model/tjsample.php index 6ff48d0..1abe22a 100644 --- a/tests/transform/model/tjsample.php +++ b/tests/transform/model/tjsample.php @@ -1,45 +1,49 @@ [ - 'tjsample_id', - 'tjsample_created', - 'tjsample_modified', - 'tjsample_transformmodel_id', - 'tjsample_text', - 'tjsample_integer', - ], - 'primary' => [ - 'tjsample_id' - ], - 'foreign' => [ - 'tjsample_transformmodel_id' => [ - 'schema' => 'transformtest', - 'model' => 'transformmodel', - 'key' => 'transformmodel_id' - ], - ], - 'datatype' => [ - 'tjsample_id' => 'number_natural', - 'tjsample_created' => 'text_timestamp', - 'tjsample_modified' => 'text_timestamp', - 'tjsample_transformmodel_id' => 'number_natural', - 'tjsample_text' => 'text', - 'tjsample_integer' => 'number_natural', - ], - 'connection' => 'default' - ]); - } +class tjsample extends sqlModel +{ + /** + * {@inheritDoc} + */ + public function __construct(array $modeldata = []) + { + parent::__construct('transformtest', 'tjsample', [ + 'field' => [ + 'tjsample_id', + 'tjsample_created', + 'tjsample_modified', + 'tjsample_transformmodel_id', + 'tjsample_text', + 'tjsample_integer', + ], + 'primary' => [ + 'tjsample_id', + ], + 'foreign' => [ + 'tjsample_transformmodel_id' => [ + 'schema' => 'transformtest', + 'model' => 'transformmodel', + 'key' => 'transformmodel_id', + ], + ], + 'datatype' => [ + 'tjsample_id' => 'number_natural', + 'tjsample_created' => 'text_timestamp', + 'tjsample_modified' => 'text_timestamp', + 'tjsample_transformmodel_id' => 'number_natural', + 'tjsample_text' => 'text', + 'tjsample_integer' => 'number_natural', + ], + 'connection' => 'default', + ]); + } } diff --git a/tests/transform/model/transformmodel.php b/tests/transform/model/transformmodel.php index 1306bae..82502cd 100644 --- a/tests/transform/model/transformmodel.php +++ b/tests/transform/model/transformmodel.php @@ -1,35 +1,39 @@ [ - 'transformmodel_id', - 'transformmodel_created', - 'transformmodel_modified', - 'transformmodel_text', - 'transformmodel_integer', - ], - 'primary' => [ - 'transformmodel_id' - ], - 'datatype' => [ - 'transformmodel_id' => 'number_natural', - 'transformmodel_created' => 'text_timestamp', - 'transformmodel_modified' => 'text_timestamp', - 'transformmodel_text' => 'text', - 'transformmodel_integer' => 'number_natural', - ], - 'connection' => 'default' - ]); - } +class transformmodel extends sqlModel +{ + /** + * {@inheritDoc} + */ + public function __construct(array $modeldata = []) + { + parent::__construct('transformtest', 'transformmodel', [ + 'field' => [ + 'transformmodel_id', + 'transformmodel_created', + 'transformmodel_modified', + 'transformmodel_text', + 'transformmodel_integer', + ], + 'primary' => [ + 'transformmodel_id', + ], + 'datatype' => [ + 'transformmodel_id' => 'number_natural', + 'transformmodel_created' => 'text_timestamp', + 'transformmodel_modified' => 'text_timestamp', + 'transformmodel_text' => 'text', + 'transformmodel_integer' => 'number_natural', + ], + 'connection' => 'default', + ]); + } } diff --git a/tests/transform/modelTest.php b/tests/transform/modelTest.php index 1f0eb9b..c196a77 100644 --- a/tests/transform/modelTest.php +++ b/tests/transform/modelTest.php @@ -1,967 +1,1035 @@ getModel('tjsample') - ->addFilter('tjsample_id', 0, '>') - ->delete(); - - $this->getModel('transformmodel') - ->addFilter('transformmodel_id', 0, '>') - ->delete(); - } - - /** - * @inheritDoc - */ - protected function setUp(): void - { - $app = static::createApp(); - - // Don't forget to inject core-io - overrideableApp::__injectApp([ - 'vendor' => 'codename', - 'app' => 'core-io', - 'namespace' => '\\codename\\core\\io' - ]); - - // Additional overrides to get a more complete app lifecycle - // and allow static global app::getModel() to work correctly - $app->__setApp('transformmodeltest'); - $app->__setVendor('codename'); - $app->__setNamespace('\\codename\\core\\io\\tests\\transform'); - - $app->getAppstack(); - - // avoid re-init - if(static::$initialized) { - return; + /** + * [protected description] + * @var bool + */ + protected static bool $initialized = false; + + /** + * {@inheritDoc} + */ + public static function tearDownAfterClass(): void + { + parent::tearDownAfterClass(); + static::$initialized = false; } - static::$initialized = true; - - static::setEnvironmentConfig([ - 'test' => [ - 'database' => [ - // NOTE: by default, we do these tests using - // pure in-memory sqlite. - 'default' => [ - 'driver' => 'sqlite', - // 'database_file' => 'testmodel.sqlite', - 'database_file' => ':memory:', - ], - ], - 'cache' => [ - 'default' => [ - 'driver' => 'memory' - ] - ], - 'filesystem' =>[ - 'local' => [ - 'driver' => 'local', - ] - ], - 'log' => [ - 'default' => [ - 'driver' => 'system', - 'data' => [ - 'name' => 'dummy' - ] - ] - ], - ] - ]); - - static::createModel('transformtest', 'transformmodel', [ - 'field' => [ - 'transformmodel_id', - 'transformmodel_created', - 'transformmodel_modified', - 'transformmodel_text', - 'transformmodel_integer', - ], - 'primary' => [ - 'transformmodel_id' - ], - 'datatype' => [ - 'transformmodel_id' => 'number_natural', - 'transformmodel_created' => 'text_timestamp', - 'transformmodel_modified' => 'text_timestamp', - 'transformmodel_text' => 'text', - 'transformmodel_integer' => 'number_natural', - ], - 'connection' => 'default' - ], function($schema, $model, $config) { - return new \codename\core\io\tests\transform\model\transformmodel([]); - }); - - static::createModel('transformtest', 'tjsample', [ - 'field' => [ - 'tjsample_id', - 'tjsample_created', - 'tjsample_modified', - 'tjsample_transformmodel_id', - 'tjsample_text', - 'tjsample_integer', - ], - 'primary' => [ - 'tjsample_id' - ], - 'foreign' => [ - 'tjsample_transformmodel_id' => [ - 'schema' => 'transformtest', - 'model' => 'transformmodel', - 'key' => 'transformmodel_id' - ], - ], - 'datatype' => [ - 'tjsample_id' => 'number_natural', - 'tjsample_created' => 'text_timestamp', - 'tjsample_modified' => 'text_timestamp', - 'tjsample_transformmodel_id' => 'number_natural', - 'tjsample_text' => 'text', - 'tjsample_integer' => 'number_natural', - ], - 'connection' => 'default' - ], function($schema, $model, $config) { - return new \codename\core\io\tests\transform\model\tjsample([]); - }); - - static::architect('transformmodeltest', 'codename', 'test'); - } - - /** - * Creates sample test data (on need!) - */ - protected function createSampleTestData(): void { - $datasets = [ - [ - 'transformmodel_text' => 'foo', - 'transformmodel_integer' => 111, - ], - [ - 'transformmodel_text' => 'bar', - 'transformmodel_integer' => 222, - ], - [ - 'transformmodel_text' => 'baz', - 'transformmodel_integer' => null, - ], - [ - 'transformmodel_text' => 'qux', - 'transformmodel_integer' => 333, - ], - ]; - $model = $this->getModel('transformmodel'); - foreach ($datasets as $dataset) { - $model->save($dataset); + /** + * Tests model_save in dry-run + * @throws ReflectionException + * @throws exception + */ + public function testModelSaveDryRun(): void + { + $pseudoPipeline = new pipeline(null, []); + $pseudoPipeline->setDryRun(); + + $transform = $this->getTransform('model_save', [ + 'model' => 'transformmodel', + 'data' => [ + 'source' => 'source', + 'field' => 'model_data', + ], + ]); + $transform->setPipelineInstance($pseudoPipeline); + $result = $transform->transform([ + 'model_data' => [ + 'transformmodel_text' => 'abc', + 'transformmodel_integer' => 123, + ], + ]); + static::assertEquals('dry-run', $result); } - } - - /** - * Additionally creates joinable datasets in model tjsample - */ - protected function createJoinableSampleTestData(): void { - // - // create joinable counterparts in tjsample - // - $model = $this->getModel('transformmodel'); - $res = $model->search()->getResult(); - - // make sure there's data to join - $this->assertNotEmpty($res); - - $tjSample = $this->getModel('tjsample'); - foreach($res as $r) { - $tjSample->save([ - 'tjsample_text' => $r['transformmodel_text'].'-join', - 'tjsample_transformmodel_id' => $r[$model->getPrimaryKey()], - ]); + + /** + * Tests model_save in NON-dry-run (writing data) + * @throws ReflectionException + * @throws exception + */ + public function testModelSave(): void + { + $pseudoPipeline = new pipeline(null, []); + $pseudoPipeline->setDryRun(false); + + $transform = $this->getTransform('model_save', [ + 'model' => 'transformmodel', + 'data' => [ + 'source' => 'source', + 'field' => 'model_data', + ], + ]); + $transform->setPipelineInstance($pseudoPipeline); + $result = $transform->transform([ + 'model_data' => [ + 'transformmodel_text' => 'abc', + 'transformmodel_integer' => 123, + ], + ]); + static::assertNotEquals('dry-run', $result); + static::assertGreaterThan(0, $result); + + $model = $this->getModel('transformmodel'); + $dataset = $model->load($result); + static::assertEquals('abc', $dataset['transformmodel_text']); + static::assertEquals(123, $dataset['transformmodel_integer']); } - } - - /** - * Tests model_save in dry-run - */ - public function testModelSaveDryRun(): void { - $pseudoPipeline = new \codename\core\io\pipeline(null, []); - $pseudoPipeline->setDryRun(true); - - $transform = $this->getTransform('model_save', [ - 'model' => 'transformmodel', - 'data' => [ - 'source' => 'source', - 'field' => 'model_data', - ] - ]); - $transform->setPipelineInstance($pseudoPipeline); - $result = $transform->transform([ - 'model_data' => [ - 'transformmodel_text' => 'abc', - 'transformmodel_integer' => 123, - ] - ]); - $this->assertEquals('dry-run', $result); - } - - /** - * Tests model_save in NON-dry-run (writing data) - */ - public function testModelSave(): void { - $pseudoPipeline = new \codename\core\io\pipeline(null, []); - $pseudoPipeline->setDryRun(false); - - $transform = $this->getTransform('model_save', [ - 'model' => 'transformmodel', - 'data' => [ - 'source' => 'source', - 'field' => 'model_data', - ] - ]); - $transform->setPipelineInstance($pseudoPipeline); - $result = $transform->transform([ - 'model_data' => [ - 'transformmodel_text' => 'abc', - 'transformmodel_integer' => 123, - ] - ]); - $this->assertNotEquals('dry-run', $result); - $this->assertGreaterThan(0, $result); - - $model = $this->getModel('transformmodel'); - $dataset = $model->load($result); - $this->assertEquals('abc', $dataset['transformmodel_text']); - $this->assertEquals(123, $dataset['transformmodel_integer']); - } - - /** - * Tests model_save with PKey (editing data) - */ - public function testModelSaveWithPKey(): void { - $this->createSampleTestData(); - - // Pre-define target id to operate on. - $targetId = $this->getModel('transformmodel') - ->addFilter('transformmodel_text', 'bar') - ->search()->getResult()[0]['transformmodel_id']; - $this->assertNotNull($targetId); - - $pseudoPipeline = new \codename\core\io\pipeline(null, []); - $pseudoPipeline->setDryRun(false); - - $transform = $this->getTransform('model_save', [ - 'model' => 'transformmodel', - 'data' => [ - 'source' => 'source', - 'field' => 'model_data', - ] - ]); - $transform->setPipelineInstance($pseudoPipeline); - $result = $transform->transform([ - 'model_data' => [ - 'transformmodel_id' => $targetId, - 'transformmodel_text' => 'abc', - 'transformmodel_integer' => 123, - ] - ]); - - $this->assertEquals($targetId, $result, print_r($result, true)); - - $dataset = $this->getModel('transformmodel') - ->hideAllFields() - ->addField('transformmodel_id') - ->addField('transformmodel_text') - ->addField('transformmodel_integer') - ->load($targetId); - $this->assertEquals([ - 'transformmodel_id' => $targetId, - 'transformmodel_text' => 'abc', - 'transformmodel_integer' => 123, - ], $dataset); - } - - /** - * [testModelSaveOnetime description] - */ - public function testModelSaveOnetime(): void { - $pseudoPipeline = new \codename\core\io\pipeline(null, []); - $pseudoPipeline->setDryRun(false); - - $transform = $this->getTransform('model_save_onetime', [ - 'model' => 'transformmodel', - 'data' => [ - 'source' => 'source', - 'field' => 'model_data', - ] - ]); - $transform->setPipelineInstance($pseudoPipeline); - $result = $transform->transform([ - 'model_data' => [ - 'transformmodel_text' => 'abc', - 'transformmodel_integer' => 123, - ] - ]); - $this->assertNotEquals('dry-run', $result); - $this->assertGreaterThan(0, $result); - - $model = $this->getModel('transformmodel'); - $dataset = $model->load($result); - $this->assertEquals('abc', $dataset['transformmodel_text']); - $this->assertEquals(123, $dataset['transformmodel_integer']); - - // - // Reset the same transform - // and make sure we don't save another entry - // as this is a onetime transform - // - $transform->reset(); - $otherResult = $transform->transform([ - 'model_data' => [ - 'transformmodel_text' => 'new', - 'transformmodel_integer' => 999, - ] - ]); - - $this->assertEquals($result, $otherResult); - } - - /** - * [testModelSaveUniqueInvalidConfig description] - */ - public function testModelSaveUniqueInvalidConfig(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_TRANSFORM_MODEL_SAVE_UNIQUE_INVALID'); - $transform = $this->getTransform('model_save_unique', [ - 'model' => 'transformmodel', - 'unique_by_fields' => [], - 'data' => [ - 'source' => 'source', - 'field' => 'model_data', - ] - ]); - } - - /** - * [testModelSaveUniqueDryRun description] - */ - public function testModelSaveUniqueDryRun(): void { - $this->testModelSaveUnique(true); - } - - /** - * [testModelSaveUnique description] - * @param bool $dryRun [description] - */ - public function testModelSaveUnique($dryRun = false): void { - $pseudoPipeline = new \codename\core\io\pipeline(null, []); - $pseudoPipeline->setDryRun($dryRun); - - $transform = $this->getTransform('model_save_unique', [ - 'model' => 'transformmodel', - 'unique_by_fields' => ['transformmodel_text'], - 'data' => [ - 'source' => 'source', - 'field' => 'model_data', - ] - ]); - $transform->setPipelineInstance($pseudoPipeline); - $result = $transform->transform([ - 'model_data' => [ - 'transformmodel_text' => 'abc', - 'transformmodel_integer' => 123, - ] - ]); - - if(!$dryRun) { - $this->assertNotEquals('dry-run', $result); - $this->assertGreaterThan(0, $result); - - $model = $this->getModel('transformmodel'); - $dataset = $model->load($result); - $this->assertEquals('abc', $dataset['transformmodel_text']); - $this->assertEquals(123, $dataset['transformmodel_integer']); + + /** + * Tests model_save with PKey (editing data) + * @throws ReflectionException + * @throws exception + */ + public function testModelSaveWithPKey(): void + { + $this->createSampleTestData(); + + // Pre-define target id to operate on. + $targetId = $this->getModel('transformmodel') + ->addFilter('transformmodel_text', 'bar') + ->search()->getResult()[0]['transformmodel_id']; + static::assertNotNull($targetId); + + $pseudoPipeline = new pipeline(null, []); + $pseudoPipeline->setDryRun(false); + + $transform = $this->getTransform('model_save', [ + 'model' => 'transformmodel', + 'data' => [ + 'source' => 'source', + 'field' => 'model_data', + ], + ]); + $transform->setPipelineInstance($pseudoPipeline); + $result = $transform->transform([ + 'model_data' => [ + 'transformmodel_id' => $targetId, + 'transformmodel_text' => 'abc', + 'transformmodel_integer' => 123, + ], + ]); + + static::assertEquals($targetId, $result, print_r($result, true)); + + $dataset = $this->getModel('transformmodel') + ->hideAllFields() + ->addField('transformmodel_id') + ->addField('transformmodel_text') + ->addField('transformmodel_integer') + ->load($targetId); + static::assertEquals([ + 'transformmodel_id' => $targetId, + 'transformmodel_text' => 'abc', + 'transformmodel_integer' => 123, + ], $dataset); } - $transform->reset(); - $otherResult = $transform->transform([ - 'model_data' => [ - 'transformmodel_text' => 'abc', - 'transformmodel_integer' => 999, - ] - ]); - $this->assertEquals($result, $otherResult); - - $transform->reset(); - $otherResult = $transform->transform([ - 'model_data' => [ - 'transformmodel_text' => 'def', - 'transformmodel_integer' => 234, - ] - ]); - $this->assertNotEquals($result, $otherResult); - } - - /** - * [testModelMapSingle description] - */ - public function testModelMapSingle(): void { - $this->createSampleTestData(); - - // - // static value / constant - // - $transform = $this->getTransform('model_map_single', [ - 'model' => 'transformmodel', - 'map' => 'transformmodel_integer', - 'filter' => [ - [ 'field' => 'transformmodel_text', 'operator' => '=', 'value' => 'bar' ] - ] - ]); - $result = $transform->transform([]); - $this->assertEquals(222, $result); - - // - // nonexisting, not required - // - $transform = $this->getTransform('model_map_single', [ - 'model' => 'transformmodel', - 'map' => 'transformmodel_integer', - 'filter' => [ - [ 'field' => 'transformmodel_text', 'operator' => '=', 'value' => 'nonexisting' ] - ] - ]); - $result = $transform->transform([]); - $this->assertEquals(null, $result); - $this->assertEmpty($transform->getErrors()); - - // - // nonexisting, required - // - $transform = $this->getTransform('model_map_single', [ - 'model' => 'transformmodel', - 'required'=> true, - 'map' => 'transformmodel_integer', - 'filter' => [ - [ 'field' => 'transformmodel_text', 'operator' => '=', 'value' => 'nonexisting' ] - ] - ]); - $result = $transform->transform([]); - $this->assertEquals(null, $result); - $this->assertNotEmpty($transform->getErrors()); - } - - /** - * [testModelMapSingleOnetime description] - */ - public function testModelMapSingleOnetime(): void { - $this->createSampleTestData(); - - // - // static value / constant - // - $transform = $this->getTransform('model_map_single_onetime', [ - 'model' => 'transformmodel', - 'map' => 'transformmodel_integer', - 'filter' => [ - [ 'field' => 'transformmodel_text', 'operator' => '=', 'value' => 'bar' ] - ] - ]); - $result = $transform->transform([]); - $this->assertEquals(222, $result); - - $transform->reset(); - - $otherResult = $transform->transform([]); - $this->assertEquals($result, $otherResult); - - } - - /** - * [testModelResultAll description] - */ - public function testModelResultAll(): void { - $this->createSampleTestData(); - - // - // static value / constant - // - $transform = $this->getTransform('model_result_all', [ - 'model' => 'transformmodel', - 'filter' => [ - [ 'field' => 'transformmodel_text', 'operator' => '=', 'value' => ['foo', 'qux'] ] - ] - ]); - $result = $transform->transform([]); - $this->assertCount(2, $result); - - // - // static value / constant with grouping - // - $transform = $this->getTransform('model_result_all', [ - 'model' => 'transformmodel', - 'filter' => [ - [ 'field' => 'transformmodel_text', 'operator' => '=', 'value' => ['foo', 'qux'] ] - ], - 'group' => [ - 'transformmodel_id' - ] - ]); - $result = $transform->transform([]); - $this->assertCount(2, $result); - - // - // static value / constant with calculated_fields and aggregate_filter - // - $transform = $this->getTransform('model_result_all', [ - 'model' => 'transformmodel', - 'filter' => [ - [ 'field' => 'transformmodel_integer', 'operator' => '!=', 'value' => null ] - ], - 'filtercollection' => [ - 'example' => [ - 'filters' => [ - [ 'field' => 'transformmodel_integer', 'operator' => '=', 'value' => 111 ], - [ 'field' => 'transformmodel_integer', 'operator' => '=', 'value' => [ 'source' => 'source', 'field' => 'source_key1' ] ] - ], - 'group_operator' => 'AND', - 'conjunction' => 'AND', - ], - ], - 'calculated_fields' => [ - [ 'field' => 'textIntegerOne', 'calculation' => 'SUM(transformmodel_integer)' ], - [ 'field' => 'textIntegerTwo', 'calculation' => 'SUM(transformmodel_integer)' ] - ], - 'aggregate_filter' => [ - [ 'field' => 'textIntegerOne', 'operator' => '=', 'value' => 111 ], - [ 'field' => 'textIntegerTwo', 'operator' => '=', 'value' => [ 'source' => 'source', 'field' => 'source_key1' ] ] - ], - 'group' => [ - 'transformmodel_id' - ] - ]); - $result = $transform->transform([ - 'source_key1' => 111 - ]); - - $this->assertCount(1, $result); - $this->assertEquals(111, $result[0]['textIntegerOne']); - $this->assertEquals(111, $result[0]['textIntegerTwo']); - - // - // static value / constant, no matches - // - $transform = $this->getTransform('model_result_all', [ - 'required' => true, - 'model' => 'transformmodel', - 'filter' => [ - [ 'field' => 'transformmodel_text', 'operator' => '=', 'value' => 'bla' ] - ] - ]); - $result = $transform->transform([]); - $this->assertIsArray($result); - $this->assertCount(0, $result); - - // model_result_all does NOT track any errors - // related to the result and requiredness - $this->assertEmpty($transform->getErrors()); - } - - /** - * [testModelResultAllNull description] - */ - public function testModelResultAllNull(): void { - $this->createSampleTestData(); - - // - // static value / constant with allow_null - // - $transform = $this->getTransform('model_result_all', [ - 'model' => 'transformmodel', - 'filter' => [ - [ 'field' => 'transformmodel_text', 'operator' => '!=', 'value' => [ 'source' => 'source', 'field' => 'source_key1', 'allow_null' => true ] ] - ] - ]); - $result = $transform->transform([]); - $this->assertCount(4, $result, print_r($result, true)); - - // - // static value / constant with null and required - // - $transform = $this->getTransform('model_result_all', [ - 'required' => true, - 'model' => 'transformmodel', - 'filter' => [ - [ 'field' => 'transformmodel_text', 'operator' => '=', 'value' => [ 'source' => 'source', 'field' => 'source_key1' ] ] - ] - ]); - $result = $transform->transform([]); - $this->assertNull($result); - - $errors = $transform->getErrors(); - $this->assertNotEmpty($errors); - $this->assertCount(1, $errors); - $this->assertEquals('VALUE_NULL', $errors[0]['__IDENTIFIER'] ); - $this->assertEquals('TRANSFORM.0', $errors[0]['__CODE'] ); - - // - // static value / constant with null and required - // - $transform = $this->getTransform('model_result_all', [ - 'required' => true, - 'model' => 'transformmodel', - 'calculated_fields' => [ - [ 'field' => 'textIntegerOne', 'calculation' => 'SUM(transformmodel_integer)' ], - ], - 'aggregate_filter' => [ - [ 'field' => 'textIntegerOne', 'operator' => '=', 'value' => [ 'source' => 'source', 'field' => 'source_key1' ] ], - ], - 'group' => [ - 'transformmodel_id' - ] - ]); - $result = $transform->transform([]); - $this->assertNull($result); - - $errors = $transform->getErrors(); - $this->assertNotEmpty($errors); - $this->assertCount(1, $errors); - $this->assertEquals('VALUE_NULL', $errors[0]['__IDENTIFIER'] ); - $this->assertEquals('TRANSFORM.0', $errors[0]['__CODE'] ); - - // - // static value / constant with null and required - // - $transform = $this->getTransform('model_result_all', [ - 'required' => true, - 'model' => 'transformmodel', - 'filtercollection' => [ - 'example' => [ - 'filters' => [ - [ 'field' => 'transformmodel_integer', 'operator' => '=', 'value' => [ 'source' => 'source', 'field' => 'source_key1' ] ] - ], - 'group_operator' => 'AND', - 'conjunction' => 'AND', - ], - ], - ]); - $result = $transform->transform([]); - $this->assertCount(1, $result); - - $errors = $transform->getErrors(); - $this->assertNotEmpty($errors); - $this->assertCount(1, $errors); - $this->assertEquals('VALUE_NULL', $errors[0]['__IDENTIFIER'] ); - $this->assertEquals('TRANSFORM.0', $errors[0]['__CODE'] ); - - } - - /** - * [testModelResultAllOnetime description] - */ - public function testModelResultAllOnetime(): void { - $this->createSampleTestData(); - - $transform = $this->getTransform('model_result_all_onetime', [ - 'model' => 'transformmodel', - 'filter' => [ - [ - 'field' => 'transformmodel_text', - 'operator' => '=', - 'value' => [ + /** + * Creates sample test data (on need!) + * @throws ReflectionException + * @throws exception + */ + protected function createSampleTestData(): void + { + $datasets = [ + [ + 'transformmodel_text' => 'foo', + 'transformmodel_integer' => 111, + ], + [ + 'transformmodel_text' => 'bar', + 'transformmodel_integer' => 222, + ], + [ + 'transformmodel_text' => 'baz', + 'transformmodel_integer' => null, + ], + [ + 'transformmodel_text' => 'qux', + 'transformmodel_integer' => 333, + ], + ]; + $model = $this->getModel('transformmodel'); + foreach ($datasets as $dataset) { + $model->save($dataset); + } + } + + /** + * [testModelSaveOnetime description] + * @throws ReflectionException + * @throws exception + */ + public function testModelSaveOnetime(): void + { + $pseudoPipeline = new pipeline(null, []); + $pseudoPipeline->setDryRun(false); + + $transform = $this->getTransform('model_save_onetime', [ + 'model' => 'transformmodel', + 'data' => [ 'source' => 'source', - 'field' => 'source_key1' - ] - ] - ] - ]); - $result = $transform->transform([ - 'source_key1' => ['foo', 'bar'] - ]); - $this->assertCount(2, $result); - - // reset the transform - // this should not clear its internal cache - // as this is a onetime transform - $transform->reset(); - - $otherResult = $transform->transform([ - 'source_key1' => ['baz', 'qux'] - ]); - $this->assertEquals($result, $otherResult); - } - - /** - * Tests for allow_null to be disabled by default - * in a transform_model_* filter - */ - public function testModelFilterAllowNullDefaultDisabled(): void { - $this->createSampleTestData(); - $transform = $this->getTransform('model_result_all', [ - 'model' => 'transformmodel', - 'filter' => [ - [ - 'field' => 'transformmodel_integer', - 'operator' => '=', - 'value' => [ - 'source' => 'source', - 'field' => 'filter_value', - ] - ] - ] - ]); - $result = $transform->transform([ - 'filter_value' => null - ]); - $this->assertNull($result); - // required is implicitly false, errorstack must be empty - $this->assertEmpty($transform->getErrors()); - } - - /** - * [testModelFilterAllowNullDefaultDisabledRequired description] - */ - public function testModelFilterAllowNullDefaultDisabledRequired(): void { - $this->createSampleTestData(); - $transform = $this->getTransform('model_result_all', [ - 'model' => 'transformmodel', - 'filter' => [ - [ - 'field' => 'transformmodel_integer', - 'operator' => '=', - 'value' => [ - 'source' => 'source', - 'field' => 'filter_value', - ] - ] - ], - 'required' => true - ]); - $result = $transform->transform([ - 'filter_value' => null - ]); - $this->assertNull($result); - // required is implicitly false, errorstack must be empty - $this->assertNotEmpty($transform->getErrors()); - } - - /** - * [testModelFilterAllowNullWorks description] - */ - public function testModelFilterAllowNullWorks(): void { - $this->createSampleTestData(); - $transform = $this->getTransform('model_result_all', [ - 'model' => 'transformmodel', - 'filter' => [ - [ - 'field' => 'transformmodel_integer', - 'operator' => '=', - 'value' => [ - 'source' => 'source', - 'field' => 'filter_value', - 'allow_null' => true - ] - ] - ] - ]); - $result = $transform->transform([ - 'filter_value' => null - ]); - $this->assertCount(1, $result); - $this->assertEmpty($transform->getErrors()); - } - - /** - * Tests basic query using a simple joined model. - */ - public function testModelResultOneJoined(): void { - $this->createSampleTestData(); - $this->createJoinableSampleTestData(); - - // - // static value / constant - // - $transform = $this->getTransform('model_result_one', [ - 'model' => 'transformmodel', - 'join' => [ - [ 'model' => 'tjsample' ] - ], - 'filter' => [ - [ 'field' => 'transformmodel_text', 'operator' => '=', 'value' => 'qux' ] - ] - ]); - $result = $transform->transform([]); - $this->assertEquals(333, $result['transformmodel_integer']); - $this->assertEquals($result['transformmodel_text'].'-join', $result['tjsample_text']); - } - - /** - * [testModelResultOne description] - */ - public function testModelResultOne(): void { - $this->createSampleTestData(); - - // - // static value / constant - // - $transform = $this->getTransform('model_result_one', [ - 'model' => 'transformmodel', - 'filter' => [ - [ 'field' => 'transformmodel_text', 'operator' => '=', 'value' => 'qux' ] - ] - ]); - $result = $transform->transform([]); - $this->assertEquals(333, $result['transformmodel_integer']); - - // - // static value / constant, ambiguous - // - $transform = $this->getTransform('model_result_one', [ - 'model' => 'transformmodel', - 'filter' => [ - [ 'field' => 'transformmodel_text', 'operator' => '=', 'value' => ['qux', 'foo'] ] - ] - ]); - $result = $transform->transform([]); - $this->assertEquals(null, $result, 'Expect null result on ambiguous result'); - - // - // static value / constant, nonexisting - // - $transform = $this->getTransform('model_result_one', [ - 'model' => 'transformmodel', - 'filter' => [ - [ 'field' => 'transformmodel_text', 'operator' => '=', 'value' => 'bla' ] - ] - ]); - $result = $transform->transform([]); - $this->assertEquals(null, $result, 'Expect null result on nonexisting result'); - - // - // Required flag testing - // - $transform = $this->getTransform('model_result_one', [ - 'required' => true, - 'model' => 'transformmodel', - 'filter' => [ - [ 'field' => 'transformmodel_text', 'operator' => '=', 'value' => 'bla' ] - ] - ]); - $result = $transform->transform([]); - $this->assertEquals(null, $result, 'Expect null result on nonexisting result'); - $this->assertNotEmpty($transform->getErrors()); - - // - // dynamic value / constant - // - $transform = $this->getTransform('model_result_one', [ - 'model' => 'transformmodel', - 'filter' => [ - [ - 'field' => 'transformmodel_text', - 'operator' => '=', - 'value' => [ + 'field' => 'model_data', + ], + ]); + $transform->setPipelineInstance($pseudoPipeline); + $result = $transform->transform([ + 'model_data' => [ + 'transformmodel_text' => 'abc', + 'transformmodel_integer' => 123, + ], + ]); + static::assertNotEquals('dry-run', $result); + static::assertGreaterThan(0, $result); + + $model = $this->getModel('transformmodel'); + $dataset = $model->load($result); + static::assertEquals('abc', $dataset['transformmodel_text']); + static::assertEquals(123, $dataset['transformmodel_integer']); + + // + // Reset the same transform + // and make sure we don't save another entry + // as this is a onetime transform + // + $transform->reset(); + $otherResult = $transform->transform([ + 'model_data' => [ + 'transformmodel_text' => 'new', + 'transformmodel_integer' => 999, + ], + ]); + + static::assertEquals($result, $otherResult); + } + + /** + * [testModelSaveUniqueInvalidConfig description] + * @throws ReflectionException + * @throws exception + */ + public function testModelSaveUniqueInvalidConfig(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('EXCEPTION_TRANSFORM_MODEL_SAVE_UNIQUE_INVALID'); + $this->getTransform('model_save_unique', [ + 'model' => 'transformmodel', + 'unique_by_fields' => [], + 'data' => [ 'source' => 'source', - 'field' => 'source_key1' - ] - ] - ] - ]); - $result = $transform->transform([ - 'source_key1' => 'foo' - ]); - $this->assertEquals(111, $result['transformmodel_integer']); - } - - /** - * [testModelResultOneOnetime description] - */ - public function testModelResultOneOnetime(): void { - $this->createSampleTestData(); - - $transform = $this->getTransform('model_result_one_onetime', [ - 'model' => 'transformmodel', - 'filter' => [ - [ - 'field' => 'transformmodel_text', - 'operator' => '=', - 'value' => [ + 'field' => 'model_data', + ], + ]); + } + + /** + * [testModelSaveUniqueDryRun description] + * @throws ReflectionException + * @throws exception + */ + public function testModelSaveUniqueDryRun(): void + { + $this->testModelSaveUnique(true); + } + + /** + * [testModelSaveUnique description] + * @param bool $dryRun [description] + * @throws ReflectionException + * @throws exception + */ + public function testModelSaveUnique(bool $dryRun = false): void + { + $pseudoPipeline = new pipeline(null, []); + $pseudoPipeline->setDryRun($dryRun); + + $transform = $this->getTransform('model_save_unique', [ + 'model' => 'transformmodel', + 'unique_by_fields' => ['transformmodel_text'], + 'data' => [ 'source' => 'source', - 'field' => 'source_key1' - ] - ] - ] - ]); - $result = $transform->transform([ - 'source_key1' => 'foo' - ]); - $this->assertEquals(111, $result['transformmodel_integer']); - - // 'reset' data - must not change - // as this is a onetime transform - $transform->reset(); - - $result = $transform->transform([ - 'source_key1' => 'qux' - ]); - $this->assertEquals(111, $result['transformmodel_integer']); - } - - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('model_result_all', [ - 'model' => 'transformmodel', - 'filter' => [ - [ 'field' => 'transformmodel_integer', 'operator' => '!=', 'value' => null ], - [ 'field' => 'transformmodel_integer', 'operator' => '!=', 'value' => [ 'source' => 'source', 'field' => 'source_key1' ] ] - ], - 'filtercollection' => [ - 'example' => [ - 'filters' => [ - [ 'field' => 'transformmodel_integer', 'operator' => '=', 'value' => 111 ], - [ 'field' => 'transformmodel_integer', 'operator' => '=', 'value' => [ 'source' => 'source', 'field' => 'source_key1' ] ] - ], - 'group_operator' => 'AND', - 'conjunction' => 'AND', - ], - ] - ]); - - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ - 'model.transformmodel', - 'source.source_key1', - 'source.source_key1', - ] - ], - $transform->getSpecification() - ); - } + 'field' => 'model_data', + ], + ]); + $transform->setPipelineInstance($pseudoPipeline); + $result = $transform->transform([ + 'model_data' => [ + 'transformmodel_text' => 'abc', + 'transformmodel_integer' => 123, + ], + ]); + + if (!$dryRun) { + static::assertNotEquals('dry-run', $result); + static::assertGreaterThan(0, $result); + + $model = $this->getModel('transformmodel'); + $dataset = $model->load($result); + static::assertEquals('abc', $dataset['transformmodel_text']); + static::assertEquals(123, $dataset['transformmodel_integer']); + } + + $transform->reset(); + $otherResult = $transform->transform([ + 'model_data' => [ + 'transformmodel_text' => 'abc', + 'transformmodel_integer' => 999, + ], + ]); + static::assertEquals($result, $otherResult); + + $transform->reset(); + $otherResult = $transform->transform([ + 'model_data' => [ + 'transformmodel_text' => 'def', + 'transformmodel_integer' => 234, + ], + ]); + static::assertNotEquals($result, $otherResult); + } + + /** + * [testModelMapSingle description] + * @throws ReflectionException + * @throws exception + */ + public function testModelMapSingle(): void + { + $this->createSampleTestData(); + + // + // static value / constant + // + $transform = $this->getTransform('model_map_single', [ + 'model' => 'transformmodel', + 'map' => 'transformmodel_integer', + 'filter' => [ + ['field' => 'transformmodel_text', 'operator' => '=', 'value' => 'bar'], + ], + ]); + $result = $transform->transform([]); + static::assertEquals(222, $result); + + // + // nonexisting, not required + // + $transform = $this->getTransform('model_map_single', [ + 'model' => 'transformmodel', + 'map' => 'transformmodel_integer', + 'filter' => [ + ['field' => 'transformmodel_text', 'operator' => '=', 'value' => 'nonexisting'], + ], + ]); + $result = $transform->transform([]); + static::assertEquals(null, $result); + static::assertEmpty($transform->getErrors()); + + // + // nonexisting, required + // + $transform = $this->getTransform('model_map_single', [ + 'model' => 'transformmodel', + 'required' => true, + 'map' => 'transformmodel_integer', + 'filter' => [ + ['field' => 'transformmodel_text', 'operator' => '=', 'value' => 'nonexisting'], + ], + ]); + $result = $transform->transform([]); + static::assertEquals(null, $result); + static::assertNotEmpty($transform->getErrors()); + } + + /** + * [testModelMapSingleOnetime description] + * @throws ReflectionException + * @throws exception + */ + public function testModelMapSingleOnetime(): void + { + $this->createSampleTestData(); + + // + // static value / constant + // + $transform = $this->getTransform('model_map_single_onetime', [ + 'model' => 'transformmodel', + 'map' => 'transformmodel_integer', + 'filter' => [ + ['field' => 'transformmodel_text', 'operator' => '=', 'value' => 'bar'], + ], + ]); + $result = $transform->transform([]); + static::assertEquals(222, $result); + $transform->reset(); + + $otherResult = $transform->transform([]); + static::assertEquals($result, $otherResult); + } + + /** + * [testModelResultAll description] + * @throws ReflectionException + * @throws exception + */ + public function testModelResultAll(): void + { + $this->createSampleTestData(); + + // + // static value / constant + // + $transform = $this->getTransform('model_result_all', [ + 'model' => 'transformmodel', + 'filter' => [ + ['field' => 'transformmodel_text', 'operator' => '=', 'value' => ['foo', 'qux']], + ], + ]); + $result = $transform->transform([]); + static::assertCount(2, $result); + + // + // static value / constant with grouping + // + $transform = $this->getTransform('model_result_all', [ + 'model' => 'transformmodel', + 'filter' => [ + ['field' => 'transformmodel_text', 'operator' => '=', 'value' => ['foo', 'qux']], + ], + 'group' => [ + 'transformmodel_id', + ], + ]); + $result = $transform->transform([]); + static::assertCount(2, $result); + + // + // static value / constant with calculated_fields and aggregate_filter + // + $transform = $this->getTransform('model_result_all', [ + 'model' => 'transformmodel', + 'filter' => [ + ['field' => 'transformmodel_integer', 'operator' => '!=', 'value' => null], + ], + 'filtercollection' => [ + 'example' => [ + 'filters' => [ + ['field' => 'transformmodel_integer', 'operator' => '=', 'value' => 111], + ['field' => 'transformmodel_integer', 'operator' => '=', 'value' => ['source' => 'source', 'field' => 'source_key1']], + ], + 'group_operator' => 'AND', + 'conjunction' => 'AND', + ], + ], + 'calculated_fields' => [ + ['field' => 'textIntegerOne', 'calculation' => 'SUM(transformmodel_integer)'], + ['field' => 'textIntegerTwo', 'calculation' => 'SUM(transformmodel_integer)'], + ], + 'aggregate_filter' => [ + ['field' => 'textIntegerOne', 'operator' => '=', 'value' => 111], + ['field' => 'textIntegerTwo', 'operator' => '=', 'value' => ['source' => 'source', 'field' => 'source_key1']], + ], + 'group' => [ + 'transformmodel_id', + ], + ]); + $result = $transform->transform([ + 'source_key1' => 111, + ]); + + static::assertCount(1, $result); + static::assertEquals(111, $result[0]['textIntegerOne']); + static::assertEquals(111, $result[0]['textIntegerTwo']); + + // + // static value / constant, no matches + // + $transform = $this->getTransform('model_result_all', [ + 'required' => true, + 'model' => 'transformmodel', + 'filter' => [ + ['field' => 'transformmodel_text', 'operator' => '=', 'value' => 'bla'], + ], + ]); + $result = $transform->transform([]); + static::assertIsArray($result); + static::assertCount(0, $result); + + // model_result_all does NOT track any errors + // related to the result and requiredness + static::assertEmpty($transform->getErrors()); + } + + /** + * [testModelResultAllNull description] + * @throws ReflectionException + * @throws exception + */ + public function testModelResultAllNull(): void + { + $this->createSampleTestData(); + + // + // static value / constant with allow_null + // + $transform = $this->getTransform('model_result_all', [ + 'model' => 'transformmodel', + 'filter' => [ + ['field' => 'transformmodel_text', 'operator' => '!=', 'value' => ['source' => 'source', 'field' => 'source_key1', 'allow_null' => true]], + ], + ]); + $result = $transform->transform([]); + static::assertCount(4, $result, print_r($result, true)); + + // + // static value / constant with null and required + // + $transform = $this->getTransform('model_result_all', [ + 'required' => true, + 'model' => 'transformmodel', + 'filter' => [ + ['field' => 'transformmodel_text', 'operator' => '=', 'value' => ['source' => 'source', 'field' => 'source_key1']], + ], + ]); + $result = $transform->transform([]); + static::assertNull($result); + + $errors = $transform->getErrors(); + static::assertNotEmpty($errors); + static::assertCount(1, $errors); + static::assertEquals('VALUE_NULL', $errors[0]['__IDENTIFIER']); + static::assertEquals('TRANSFORM.0', $errors[0]['__CODE']); + + // + // static value / constant with null and required + // + $transform = $this->getTransform('model_result_all', [ + 'required' => true, + 'model' => 'transformmodel', + 'calculated_fields' => [ + ['field' => 'textIntegerOne', 'calculation' => 'SUM(transformmodel_integer)'], + ], + 'aggregate_filter' => [ + ['field' => 'textIntegerOne', 'operator' => '=', 'value' => ['source' => 'source', 'field' => 'source_key1']], + ], + 'group' => [ + 'transformmodel_id', + ], + ]); + $result = $transform->transform([]); + static::assertNull($result); + + $errors = $transform->getErrors(); + static::assertNotEmpty($errors); + static::assertCount(1, $errors); + static::assertEquals('VALUE_NULL', $errors[0]['__IDENTIFIER']); + static::assertEquals('TRANSFORM.0', $errors[0]['__CODE']); + + // + // static value / constant with null and required + // + $transform = $this->getTransform('model_result_all', [ + 'required' => true, + 'model' => 'transformmodel', + 'filtercollection' => [ + 'example' => [ + 'filters' => [ + ['field' => 'transformmodel_integer', 'operator' => '=', 'value' => ['source' => 'source', 'field' => 'source_key1']], + ], + 'group_operator' => 'AND', + 'conjunction' => 'AND', + ], + ], + ]); + $result = $transform->transform([]); + static::assertCount(1, $result); + + $errors = $transform->getErrors(); + static::assertNotEmpty($errors); + static::assertCount(1, $errors); + static::assertEquals('VALUE_NULL', $errors[0]['__IDENTIFIER']); + static::assertEquals('TRANSFORM.0', $errors[0]['__CODE']); + } + + /** + * [testModelResultAllOnetime description] + * @throws ReflectionException + * @throws exception + */ + public function testModelResultAllOnetime(): void + { + $this->createSampleTestData(); + + $transform = $this->getTransform('model_result_all_onetime', [ + 'model' => 'transformmodel', + 'filter' => [ + [ + 'field' => 'transformmodel_text', + 'operator' => '=', + 'value' => [ + 'source' => 'source', + 'field' => 'source_key1', + ], + ], + ], + ]); + $result = $transform->transform([ + 'source_key1' => ['foo', 'bar'], + ]); + static::assertCount(2, $result); + + // reset the transform + // this should not clear its internal cache + // as this is a onetime transform + $transform->reset(); + + $otherResult = $transform->transform([ + 'source_key1' => ['baz', 'qux'], + ]); + static::assertEquals($result, $otherResult); + } + + /** + * Tests for allow_null to be disabled by default + * in a transform_model_* filter + * @throws ReflectionException + * @throws exception + */ + public function testModelFilterAllowNullDefaultDisabled(): void + { + $this->createSampleTestData(); + $transform = $this->getTransform('model_result_all', [ + 'model' => 'transformmodel', + 'filter' => [ + [ + 'field' => 'transformmodel_integer', + 'operator' => '=', + 'value' => [ + 'source' => 'source', + 'field' => 'filter_value', + ], + ], + ], + ]); + $result = $transform->transform([ + 'filter_value' => null, + ]); + static::assertNull($result); + // required is implicitly false, errorstack must be empty + static::assertEmpty($transform->getErrors()); + } + + /** + * [testModelFilterAllowNullDefaultDisabledRequired description] + * @throws ReflectionException + * @throws exception + */ + public function testModelFilterAllowNullDefaultDisabledRequired(): void + { + $this->createSampleTestData(); + $transform = $this->getTransform('model_result_all', [ + 'model' => 'transformmodel', + 'filter' => [ + [ + 'field' => 'transformmodel_integer', + 'operator' => '=', + 'value' => [ + 'source' => 'source', + 'field' => 'filter_value', + ], + ], + ], + 'required' => true, + ]); + $result = $transform->transform([ + 'filter_value' => null, + ]); + static::assertNull($result); + // required is implicitly false, errorstack must be empty + static::assertNotEmpty($transform->getErrors()); + } + + /** + * [testModelFilterAllowNullWorks description] + * @throws ReflectionException + * @throws exception + */ + public function testModelFilterAllowNullWorks(): void + { + $this->createSampleTestData(); + $transform = $this->getTransform('model_result_all', [ + 'model' => 'transformmodel', + 'filter' => [ + [ + 'field' => 'transformmodel_integer', + 'operator' => '=', + 'value' => [ + 'source' => 'source', + 'field' => 'filter_value', + 'allow_null' => true, + ], + ], + ], + ]); + $result = $transform->transform([ + 'filter_value' => null, + ]); + static::assertCount(1, $result); + static::assertEmpty($transform->getErrors()); + } + + /** + * Tests basic query using a simple joined model. + * @throws ReflectionException + * @throws exception + */ + public function testModelResultOneJoined(): void + { + $this->createSampleTestData(); + $this->createJoinableSampleTestData(); + + // + // static value / constant + // + $transform = $this->getTransform('model_result_one', [ + 'model' => 'transformmodel', + 'join' => [ + ['model' => 'tjsample'], + ], + 'filter' => [ + ['field' => 'transformmodel_text', 'operator' => '=', 'value' => 'qux'], + ], + ]); + $result = $transform->transform([]); + static::assertEquals(333, $result['transformmodel_integer']); + static::assertEquals($result['transformmodel_text'] . '-join', $result['tjsample_text']); + } + + /** + * Additionally creates joinable datasets in model tjsample + * @throws ReflectionException + * @throws exception + */ + protected function createJoinableSampleTestData(): void + { + // + // create joinable counterparts in tjsample + // + $model = $this->getModel('transformmodel'); + $res = $model->search()->getResult(); + + // make sure there's data to join + static::assertNotEmpty($res); + + $tjSample = $this->getModel('tjsample'); + foreach ($res as $r) { + $tjSample->save([ + 'tjsample_text' => $r['transformmodel_text'] . '-join', + 'tjsample_transformmodel_id' => $r[$model->getPrimaryKey()], + ]); + } + } + + /** + * [testModelResultOne description] + * @throws ReflectionException + * @throws exception + */ + public function testModelResultOne(): void + { + $this->createSampleTestData(); + + // + // static value / constant + // + $transform = $this->getTransform('model_result_one', [ + 'model' => 'transformmodel', + 'filter' => [ + ['field' => 'transformmodel_text', 'operator' => '=', 'value' => 'qux'], + ], + ]); + $result = $transform->transform([]); + static::assertEquals(333, $result['transformmodel_integer']); + + // + // static value / constant, ambiguous + // + $transform = $this->getTransform('model_result_one', [ + 'model' => 'transformmodel', + 'filter' => [ + ['field' => 'transformmodel_text', 'operator' => '=', 'value' => ['qux', 'foo']], + ], + ]); + $result = $transform->transform([]); + static::assertEquals(null, $result, 'Expect null result on ambiguous result'); + + // + // static value / constant, nonexisting + // + $transform = $this->getTransform('model_result_one', [ + 'model' => 'transformmodel', + 'filter' => [ + ['field' => 'transformmodel_text', 'operator' => '=', 'value' => 'bla'], + ], + ]); + $result = $transform->transform([]); + static::assertEquals(null, $result, 'Expect null result on nonexisting result'); + + // + // Required flag testing + // + $transform = $this->getTransform('model_result_one', [ + 'required' => true, + 'model' => 'transformmodel', + 'filter' => [ + ['field' => 'transformmodel_text', 'operator' => '=', 'value' => 'bla'], + ], + ]); + $result = $transform->transform([]); + static::assertEquals(null, $result, 'Expect null result on nonexisting result'); + static::assertNotEmpty($transform->getErrors()); + + // + // dynamic value / constant + // + $transform = $this->getTransform('model_result_one', [ + 'model' => 'transformmodel', + 'filter' => [ + [ + 'field' => 'transformmodel_text', + 'operator' => '=', + 'value' => [ + 'source' => 'source', + 'field' => 'source_key1', + ], + ], + ], + ]); + $result = $transform->transform([ + 'source_key1' => 'foo', + ]); + static::assertEquals(111, $result['transformmodel_integer']); + } + + /** + * [testModelResultOneOnetime description] + * @throws ReflectionException + * @throws exception + */ + public function testModelResultOneOnetime(): void + { + $this->createSampleTestData(); + + $transform = $this->getTransform('model_result_one_onetime', [ + 'model' => 'transformmodel', + 'filter' => [ + [ + 'field' => 'transformmodel_text', + 'operator' => '=', + 'value' => [ + 'source' => 'source', + 'field' => 'source_key1', + ], + ], + ], + ]); + $result = $transform->transform([ + 'source_key1' => 'foo', + ]); + static::assertEquals(111, $result['transformmodel_integer']); + + // 'reset' data - must not change + // as this is a onetime transform + $transform->reset(); + + $result = $transform->transform([ + 'source_key1' => 'qux', + ]); + static::assertEquals(111, $result['transformmodel_integer']); + } + + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('model_result_all', [ + 'model' => 'transformmodel', + 'filter' => [ + ['field' => 'transformmodel_integer', 'operator' => '!=', 'value' => null], + ['field' => 'transformmodel_integer', 'operator' => '!=', 'value' => ['source' => 'source', 'field' => 'source_key1']], + ], + 'filtercollection' => [ + 'example' => [ + 'filters' => [ + ['field' => 'transformmodel_integer', 'operator' => '=', 'value' => 111], + ['field' => 'transformmodel_integer', 'operator' => '=', 'value' => ['source' => 'source', 'field' => 'source_key1']], + ], + 'group_operator' => 'AND', + 'conjunction' => 'AND', + ], + ], + ]); + + static::assertEquals( + [ + 'type' => 'transform', + 'source' => [ + 'model.transformmodel', + 'source.source_key1', + 'source.source_key1', + ], + ], + $transform->getSpecification() + ); + } + + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function tearDown(): void + { + $this->getModel('tjsample') + ->addFilter('tjsample_id', 0, '>') + ->delete(); + + $this->getModel('transformmodel') + ->addFilter('transformmodel_id', 0, '>') + ->delete(); + } + + /** + * {@inheritDoc} + */ + protected function setUp(): void + { + $app = static::createApp(); + + // Don't forget to inject core-io + overrideableApp::__injectApp([ + 'vendor' => 'codename', + 'app' => 'core-io', + 'namespace' => '\\codename\\core\\io', + ]); + + // Additional overrides to get a more complete app lifecycle + // and allow static global app::getModel() to work correctly + $app::__setApp('transformmodeltest'); + $app::__setVendor('codename'); + $app::__setNamespace('\\codename\\core\\io\\tests\\transform'); + + $app::getAppstack(); + + // avoid re-init + if (static::$initialized) { + return; + } + + static::$initialized = true; + + static::setEnvironmentConfig([ + 'test' => [ + 'database' => [ + // NOTE: by default, we do these tests using + // pure in-memory sqlite. + 'default' => [ + 'driver' => 'sqlite', + // 'database_file' => 'testmodel.sqlite', + 'database_file' => ':memory:', + ], + ], + 'cache' => [ + 'default' => [ + 'driver' => 'memory', + ], + ], + 'filesystem' => [ + 'local' => [ + 'driver' => 'local', + ], + ], + 'log' => [ + 'default' => [ + 'driver' => 'system', + 'data' => [ + 'name' => 'dummy', + ], + ], + ], + ], + ]); + + static::createModel('transformtest', 'transformmodel', [ + 'field' => [ + 'transformmodel_id', + 'transformmodel_created', + 'transformmodel_modified', + 'transformmodel_text', + 'transformmodel_integer', + ], + 'primary' => [ + 'transformmodel_id', + ], + 'datatype' => [ + 'transformmodel_id' => 'number_natural', + 'transformmodel_created' => 'text_timestamp', + 'transformmodel_modified' => 'text_timestamp', + 'transformmodel_text' => 'text', + 'transformmodel_integer' => 'number_natural', + ], + 'connection' => 'default', + ], function ($schema, $model, $config) { + return new transformmodel([]); + }); + + static::createModel('transformtest', 'tjsample', [ + 'field' => [ + 'tjsample_id', + 'tjsample_created', + 'tjsample_modified', + 'tjsample_transformmodel_id', + 'tjsample_text', + 'tjsample_integer', + ], + 'primary' => [ + 'tjsample_id', + ], + 'foreign' => [ + 'tjsample_transformmodel_id' => [ + 'schema' => 'transformtest', + 'model' => 'transformmodel', + 'key' => 'transformmodel_id', + ], + ], + 'datatype' => [ + 'tjsample_id' => 'number_natural', + 'tjsample_created' => 'text_timestamp', + 'tjsample_modified' => 'text_timestamp', + 'tjsample_transformmodel_id' => 'number_natural', + 'tjsample_text' => 'text', + 'tjsample_integer' => 'number_natural', + ], + 'connection' => 'default', + ], function ($schema, $model, $config) { + return new tjsample([]); + }); + + static::architect('transformmodeltest', 'codename', 'test'); + } } diff --git a/tests/transform/pad/leftTest.php b/tests/transform/pad/leftTest.php index bf71d61..8627999 100644 --- a/tests/transform/pad/leftTest.php +++ b/tests/transform/pad/leftTest.php @@ -1,94 +1,112 @@ getTransform('pad_left', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'length' => 10, - 'string' => ' ' - ]); - $result = $transform->transform([ - 'example_source_field' => 'example' - ]); - $this->assertEquals(' example', $result); - } +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - /** - * [testNullValuePadding description] - */ - public function testNullValuePadding(): void { - $transform = $this->getTransform('pad_left', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'length' => 10, - 'string' => ' ' - ]); - // - // NOTE: at the moment, str_pad using a NULL input value - // also pads the string, as it was an empty string. - // - $result = $transform->transform([ - 'example_source_field' => null - ]); - $this->assertEquals(' ', $result); - } +class leftTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('pad_left', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'length' => 10, + 'string' => ' ', + ]); + $result = $transform->transform([ + 'example_source_field' => 'example', + ]); + static::assertEquals(' example', $result); + } - /** - * [testEmptyStringPadding description] - */ - public function testEmptyStringPadding(): void { - $transform = $this->getTransform('pad_left', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'length' => 10, - 'string' => ' ' - ]); - $result = $transform->transform([ - 'example_source_field' => '' - ]); - $this->assertEquals(' ', $result); - } + /** + * [testNullValuePadding description] + * @throws ReflectionException + * @throws exception + */ + public function testNullValuePadding(): void + { + $transform = $this->getTransform('pad_left', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'length' => 10, + 'string' => ' ', + ]); + // + // NOTE: at the moment, str_pad using a NULL input value + // also pads the string, as it was an empty string. + // + $result = $transform->transform([ + 'example_source_field' => null, + ]); + static::assertEquals(' ', $result); + } - /** - * [testValueExceedsPadLength description] - */ - public function testValueExceedsPadLength(): void { - $transform = $this->getTransform('pad_left', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'length' => 10, - 'string' => ' ' - ]); - $result = $transform->transform([ - 'example_source_field' => 'exampleexample' - ]); - // Make sure the strings stays the same, - // as we only pad, if there are characters missing - $this->assertEquals('exampleexample', $result); - } + /** + * [testEmptyStringPadding description] + * @throws ReflectionException + * @throws exception + */ + public function testEmptyStringPadding(): void + { + $transform = $this->getTransform('pad_left', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'length' => 10, + 'string' => ' ', + ]); + $result = $transform->transform([ + 'example_source_field' => '', + ]); + static::assertEquals(' ', $result); + } - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('pad_left', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + /** + * [testValueExceedsPadLength description] + * @throws ReflectionException + * @throws exception + */ + public function testValueExceedsPadLength(): void + { + $transform = $this->getTransform('pad_left', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'length' => 10, + 'string' => ' ', + ]); + $result = $transform->transform([ + 'example_source_field' => 'exampleexample', + ]); + // Make sure the strings stays the same, + // as we only pad, if there are characters missing + static::assertEquals('exampleexample', $result); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('pad_left', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/pad/rightTest.php b/tests/transform/pad/rightTest.php index b01d6ce..e53173d 100644 --- a/tests/transform/pad/rightTest.php +++ b/tests/transform/pad/rightTest.php @@ -1,94 +1,112 @@ getTransform('pad_right', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'length' => 10, - 'string' => ' ' - ]); - $result = $transform->transform([ - 'example_source_field' => 'example' - ]); - $this->assertEquals('example ', $result); - } +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - /** - * [testNullValuePadding description] - */ - public function testNullValuePadding(): void { - $transform = $this->getTransform('pad_right', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'length' => 10, - 'string' => ' ' - ]); - // - // NOTE: at the moment, str_pad using a NULL input value - // also pads the string, as it was an empty string. - // - $result = $transform->transform([ - 'example_source_field' => null - ]); - $this->assertEquals(' ', $result); - } +class rightTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('pad_right', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'length' => 10, + 'string' => ' ', + ]); + $result = $transform->transform([ + 'example_source_field' => 'example', + ]); + static::assertEquals('example ', $result); + } - /** - * [testEmptyStringPadding description] - */ - public function testEmptyStringPadding(): void { - $transform = $this->getTransform('pad_right', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'length' => 10, - 'string' => ' ' - ]); - $result = $transform->transform([ - 'example_source_field' => '' - ]); - $this->assertEquals(' ', $result); - } + /** + * [testNullValuePadding description] + * @throws ReflectionException + * @throws exception + */ + public function testNullValuePadding(): void + { + $transform = $this->getTransform('pad_right', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'length' => 10, + 'string' => ' ', + ]); + // + // NOTE: at the moment, str_pad using a NULL input value + // also pads the string, as it was an empty string. + // + $result = $transform->transform([ + 'example_source_field' => null, + ]); + static::assertEquals(' ', $result); + } - /** - * [testValueExceedsPadLength description] - */ - public function testValueExceedsPadLength(): void { - $transform = $this->getTransform('pad_right', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'length' => 10, - 'string' => ' ' - ]); - $result = $transform->transform([ - 'example_source_field' => 'exampleexample' - ]); - // Make sure the strings stays the same, - // as we only pad, if there are characters missing - $this->assertEquals('exampleexample', $result); - } + /** + * [testEmptyStringPadding description] + * @throws ReflectionException + * @throws exception + */ + public function testEmptyStringPadding(): void + { + $transform = $this->getTransform('pad_right', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'length' => 10, + 'string' => ' ', + ]); + $result = $transform->transform([ + 'example_source_field' => '', + ]); + static::assertEquals(' ', $result); + } - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('pad_right', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + /** + * [testValueExceedsPadLength description] + * @throws ReflectionException + * @throws exception + */ + public function testValueExceedsPadLength(): void + { + $transform = $this->getTransform('pad_right', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'length' => 10, + 'string' => ' ', + ]); + $result = $transform->transform([ + 'example_source_field' => 'exampleexample', + ]); + // Make sure the strings stays the same, + // as we only pad, if there are characters missing + static::assertEquals('exampleexample', $result); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('pad_right', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/regexTest.php b/tests/transform/regexTest.php index b4a8197..ea75b2d 100644 --- a/tests/transform/regexTest.php +++ b/tests/transform/regexTest.php @@ -1,155 +1,183 @@ expectException(\codename\core\exception::class); - $this->expectExceptionMessage('TRANSFORM_REGEX_INVALID_CONFIG'); - - $transform = $this->getTransform('regex', [ - 'regex_value' => '/^[0-9]*(\\,[0-9]{3})*(\\.[0-9]*){0,1}$/', - 'mode' => 'match_success_error', - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => null - ]); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testConstructInvalid(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('TRANSFORM_REGEX_INVALID_CONFIG'); - /** - * Testing transforms for Erors - */ - public function testValueValidMatch(): void { - $transform = $this->getTransform('regex', [ - 'regex_value' => '/^[0-9]*(\\,[0-9]{3})*(\\.[0-9]*){0,1}$/', - 'mode' => 'match', - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => '1.23' - ]); - // Make sure it stays an array - $this->assertEquals([ - '1.23', - '', - '.23' - ], $result); - } + $transform = $this->getTransform('regex', [ + 'regex_value' => '/^[0-9]*(\\,[0-9]{3})*(\\.[0-9]*){0,1}$/', + 'mode' => 'match_success_error', + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $transform->transform([ + 'example_source_field' => null, + ]); + } - /** - * Testing transforms for Erors - */ - public function testValueValidMatchSuccess(): void { - $transform = $this->getTransform('regex', [ - 'regex_value' => '/^[0-9]*(\\,[0-9]{3})*(\\.[0-9]*){0,1}$/', - 'mode' => 'match_success', - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => '1.23' - ]); - // Make sure it stays an array - $this->assertTrue($result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidMatch(): void + { + $transform = $this->getTransform('regex', [ + 'regex_value' => '/^[0-9]*(\\,[0-9]{3})*(\\.[0-9]*){0,1}$/', + 'mode' => 'match', + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => '1.23', + ]); + // Make sure it stays an array + static::assertEquals([ + '1.23', + '', + '.23', + ], $result); + } - /** - * Testing transforms for Erors - */ - public function testValueValidReplace(): void { - $transform = $this->getTransform('regex', [ - 'regex_value' => '/^[0-9]*(\\,[0-9]{3})*(\\.[0-9]*){0,1}$/', - 'mode' => 'replace', - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => '1.23' - ]); - // Make sure it stays an array - $this->assertEmpty($result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidMatchSuccess(): void + { + $transform = $this->getTransform('regex', [ + 'regex_value' => '/^[0-9]*(\\,[0-9]{3})*(\\.[0-9]*){0,1}$/', + 'mode' => 'match_success', + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => '1.23', + ]); + // Make sure it stays an array + static::assertTrue($result); + } - /** - * Testing transforms for Erors - */ - public function testValueInvalidMatch(): void { - $transform = $this->getTransform('regex', [ - 'regex_value' => '/^[0-9]*(\\,[0-9]{3})*(\\.[0-9]*){0,1}$/', - 'mode' => 'match', - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => '-1.23' - ]); - // Make sure it stays an array - $this->assertEquals(null, $result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidReplace(): void + { + $transform = $this->getTransform('regex', [ + 'regex_value' => '/[^A-Za-z0-9_\-.]/', + 'replace_value' => '_', + 'mode' => 'replace', + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => 'T#st', + ]); + static::assertEquals('T_st', $result); + } - /** - * Testing transforms for Erors - */ - public function testValueInvalidMatchSuccess(): void { - $transform = $this->getTransform('regex', [ - 'regex_value' => '/^[0-9]*(\\,[0-9]{3})*(\\.[0-9]*){0,1}$/', - 'mode' => 'match_success', - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => '-1.23' - ]); - // Make sure it stays an array - $this->assertFalse($result); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueInvalidMatch(): void + { + $transform = $this->getTransform('regex', [ + 'regex_value' => '/^[0-9]*(\\,[0-9]{3})*(\\.[0-9]*){0,1}$/', + 'mode' => 'match', + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => '-1.23', + ]); + // Make sure it stays an array + static::assertEquals(null, $result); + } - /** - * Testing transforms for Erors - */ - public function testValueError(): void { - $transform = $this->getTransform('regex', [ - 'regex_value' => '/(?:\D+|<\d+>)*[!?]/', - 'mode' => 'match', - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => 'foobar foobar foobar' - ]); - // Make sure it stays an array - $this->assertEquals(null, $result); + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueInvalidMatchSuccess(): void + { + $transform = $this->getTransform('regex', [ + 'regex_value' => '/^[0-9]*(\\,[0-9]{3})*(\\.[0-9]*){0,1}$/', + 'mode' => 'match_success', + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => '-1.23', + ]); + // Make sure it stays an array + static::assertFalse($result); + } - $errors = $transform->getErrors(); - $this->assertNotEmpty($errors); - $this->assertCount(1, $errors); - $this->assertEquals('REGEX_ERROR', $errors[0]['__IDENTIFIER'] ); - $this->assertEquals('TRANSFORM.0', $errors[0]['__CODE'] ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueError(): void + { + $transform = $this->getTransform('regex', [ + 'regex_value' => '/(?:\D+|<\d+>)*[!?]/', + 'mode' => 'match', + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => 'foobar foobar foobar', + ]); + // Make sure it stays an array + static::assertEquals(null, $result); - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('regex', [ - 'regex_value' => '/^[0-9]*(\\,[0-9]{3})*(\\.[0-9]*){0,1}$/', - 'mode' => 'match_success', - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + $errors = $transform->getErrors(); + static::assertNotEmpty($errors); + static::assertCount(1, $errors); + static::assertEquals('REGEX_ERROR', $errors[0]['__IDENTIFIER']); + static::assertEquals('TRANSFORM.0', $errors[0]['__CODE']); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('regex', [ + 'regex_value' => '/^[0-9]*(\\,[0-9]{3})*(\\.[0-9]*){0,1}$/', + 'mode' => 'match_success', + 'source' => 'source', + 'field' => 'example_source_field', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/setTest.php b/tests/transform/setTest.php index 2f925be..b474e02 100644 --- a/tests/transform/setTest.php +++ b/tests/transform/setTest.php @@ -1,32 +1,42 @@ expectException(LogicException::class); + $this->expectExceptionMessage('Not implemented'); - /** - * [testInternalTransform description] - */ - public function testInternalTransform(): void { - $this->expectException(\LogicException::class); - $this->expectExceptionMessage('Not implemented'); - - $transform = $this->getTransform('set', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $specification = $transform->internalTransform([]); - } + $transform = $this->getTransform('set', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $transform->internalTransform([]); + } - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('set', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $specification = $transform->getSpecification(); - $this->assertEquals([], $specification); - } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('set', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $specification = $transform->getSpecification(); + static::assertEquals([], $specification); + } } diff --git a/tests/transform/transformGetValueTest.php b/tests/transform/transformGetValueTest.php index ae52e73..8ba597c 100644 --- a/tests/transform/transformGetValueTest.php +++ b/tests/transform/transformGetValueTest.php @@ -1,192 +1,221 @@ 'abc', + 'source_key2' => '123', + ]; + $transform = $this->getDummyTransform(); + static::assertEquals('abc', $transform->getInternalPipelineValue('source', 'source_key1', $data)); + } - /** - * [getDummyTransform description] - * @return \codename\core\io\transform\dummy [description] - */ - protected function getDummyTransform(): \codename\core\io\transform\dummy { - $dummy = new \codename\core\io\transform\dummy([]); - $dummy->setTransformerInstance($this); - return $dummy; - } - - /** - * [testGetValueSource description] - */ - public function testGetValueSource(): void { - $data = [ - 'source_key1' => 'abc', - 'source_key2' => '123', - ]; - $transform = $this->getDummyTransform(); - $this->assertEquals('abc', $transform->getInternalPipelineValue('source', 'source_key1', $data)); - } - - /** - * [testGetValueSourceDeep description] - */ - public function testGetValueSourceDeep(): void { - $data = [ - 'source_key1' => 'abc', - 'source_key2' => '123', - 'source_key3' => [ - 'subkey1' => 'hä' - ], - ]; - $transform = $this->getDummyTransform(); - $this->assertEquals('abc', $transform->getInternalPipelineValue('source_deep', ['source_key1'], $data)); - $this->assertEquals('hä', $transform->getInternalPipelineValue('source_deep', ['source_key3', 'subkey1'], $data)); - $this->assertEquals($data, $transform->getInternalPipelineValue('source_deep', [], $data)); - } - - /** - * [testGetValueTransform description] - */ - public function testGetValueTransform(): void { - $data = [ - 'source_key1' => 'abc', - 'source_key2' => '123', - ]; - $transform = $this->getDummyTransform(); - $this->addTransform('transformed_key1', 'pad_left', [ - 'source' => 'source', - 'field' => 'source_key1', - 'length' => 10, - 'string' => '#' - ]); - $this->assertEquals('#######abc', $transform->getInternalPipelineValue('transform', 'transformed_key1', $data)); - } - - /** - * [testGetValueTransformDeep description] - */ - public function testGetValueTransformDeep(): void { - $data = [ - 'source_key1' => 'abc', - 'source_key2' => '123', - ]; - $transform = $this->getDummyTransform(); - $this->addTransform('transformed_object1', 'get_valuearray', [ - 'elements' => [ - 'key1' => [ 'source' => 'source', 'field' => 'source_key1' ], - 'key2' => [ 'source' => 'source', 'field' => 'source_key2' ], - ] - ]); - $this->assertEquals([ 'key1' => 'abc', 'key2' => '123' ], $transform->getInternalPipelineValue('transform_deep', ['transformed_object1'], $data)); - $this->assertEquals('abc', $transform->getInternalPipelineValue('transform_deep', ['transformed_object1', 'key1'], $data)); - } + /** + * [getDummyTransform description] + * @return dummy [description] + */ + protected function getDummyTransform(): dummy + { + $dummy = new dummy([]); + $dummy->setTransformerInstance($this); + return $dummy; + } - /** - * [testGetValueInvalidType description] - */ - public function testGetValueInvalidType(): void { - $this->expectException(\codename\core\exception::class); - $this->expectExceptionMessage('EXCEPTION_TRANSFORM_GETVALUE_INVALID_SOURCE_TYPE'); - $transform = $this->getDummyTransform(); - $transform->getInternalPipelineValue('invalid', 'somekey', []); - } + /** + * [testGetValueSourceDeep description] + * @throws \codename\core\exception + */ + public function testGetValueSourceDeep(): void + { + $data = [ + 'source_key1' => 'abc', + 'source_key2' => '123', + 'source_key3' => [ + 'subkey1' => 'hä', + ], + ]; + $transform = $this->getDummyTransform(); + static::assertEquals('abc', $transform->getInternalPipelineValue('source_deep', ['source_key1'], $data)); + static::assertEquals('hä', $transform->getInternalPipelineValue('source_deep', ['source_key3', 'subkey1'], $data)); + static::assertEquals($data, $transform->getInternalPipelineValue('source_deep', [], $data)); + } - /** - * [testGetValueNonexistingSourceKey description] - */ - public function testGetValueNonexistingSourceKey(): void { - $transform = $this->getDummyTransform(); - $this->assertNull($transform->getInternalPipelineValue('source', 'nonexisting', [])); - } + /** + * [testGetValueTransform description] + * @throws \codename\core\exception + */ + public function testGetValueTransform(): void + { + $data = [ + 'source_key1' => 'abc', + 'source_key2' => '123', + ]; + $transform = $this->getDummyTransform(); + $this->addTransform('transformed_key1', 'pad_left', [ + 'source' => 'source', + 'field' => 'source_key1', + 'length' => 10, + 'string' => '#', + ]); + static::assertEquals('#######abc', $transform->getInternalPipelineValue('transform', 'transformed_key1', $data)); + } - /** - * [testGetValueNonexistingSourceDeepKey description] - */ - public function testGetValueNonexistingSourceDeepKey(): void { - $transform = $this->getDummyTransform(); - $this->assertNull($transform->getInternalPipelineValue('source_deep', ['nonexisting'], [])); - } + /** + * [testGetValueTransformDeep description] + * @throws \codename\core\exception + */ + public function testGetValueTransformDeep(): void + { + $data = [ + 'source_key1' => 'abc', + 'source_key2' => '123', + ]; + $transform = $this->getDummyTransform(); + $this->addTransform('transformed_object1', 'get_valuearray', [ + 'elements' => [ + 'key1' => ['source' => 'source', 'field' => 'source_key1'], + 'key2' => ['source' => 'source', 'field' => 'source_key2'], + ], + ]); + static::assertEquals(['key1' => 'abc', 'key2' => '123'], $transform->getInternalPipelineValue('transform_deep', ['transformed_object1'], $data)); + static::assertEquals('abc', $transform->getInternalPipelineValue('transform_deep', ['transformed_object1', 'key1'], $data)); + } - /** - * [testGetValueNonexistingTransformKey description] - */ - public function testGetValueNonexistingTransformKey(): void { - $this->expectException(\Exception::class); - // NOTE: exception test from abstractTransformTest class - $this->expectExceptionMessage('Transform not found: nonexisting'); - $transform = $this->getDummyTransform(); - $transform->getInternalPipelineValue('transform', 'nonexisting', []); - } + /** + * [testGetValueInvalidType description] + */ + public function testGetValueInvalidType(): void + { + $this->expectException(\codename\core\exception::class); + $this->expectExceptionMessage('EXCEPTION_TRANSFORM_GETVALUE_INVALID_SOURCE_TYPE'); + $transform = $this->getDummyTransform(); + $transform->getInternalPipelineValue('invalid', 'somekey', []); + } - /** - * [testGetValueNonexistingTransformDeepKey description] - */ - public function testGetValueNonexistingTransformDeepKey(): void { - $this->expectException(\Exception::class); - // NOTE: exception test from abstractTransformTest class - $this->expectExceptionMessage('Transform not found: nonexisting'); - $transform = $this->getDummyTransform(); - $transform->getInternalPipelineValue('transform_deep', ['nonexisting'], []); - } + /** + * [testGetValueNonexistingSourceKey description] + * @throws \codename\core\exception + */ + public function testGetValueNonexistingSourceKey(): void + { + $transform = $this->getDummyTransform(); + static::assertNull($transform->getInternalPipelineValue('source', 'nonexisting', [])); + } - /** - * [testGetValueErroneous description] - */ - public function testGetValueErroneous(): void { - $this->expectException(\LogicException::class); - $this->expectExceptionMessage('Not implemented'); - $transform = $this->getDummyTransform(); - // - // 'erroneous' type is not implemented to be accessed this way - // Make sure we get an exception if we try to do it anyway. - // - $transform->getInternalPipelineValue('erroneous', 'abc', []); - } + /** + * [testGetValueNonexistingSourceDeepKey description] + * @throws \codename\core\exception + */ + public function testGetValueNonexistingSourceDeepKey(): void + { + $transform = $this->getDummyTransform(); + static::assertNull($transform->getInternalPipelineValue('source_deep', ['nonexisting'], [])); + } - /** - * [testGetValueConstant description] - */ - public function testGetValueConstant(): void { + /** + * [testGetValueNonexistingTransformKey description] + * @throws \codename\core\exception + */ + public function testGetValueNonexistingTransformKey(): void + { + $this->expectException(Exception::class); + // NOTE: exception test from abstractTransformTest class + $this->expectExceptionMessage('Transform not found: nonexisting'); + $transform = $this->getDummyTransform(); + $transform->getInternalPipelineValue('transform', 'nonexisting', []); + } - // Emulate some response-related stuff - // as pipeline may access it in CLI for stdout - $app = static::createApp(); - $app->getAppstack(); - $app->__setInstance('response', new \codename\core\response\cli([])); + /** + * [testGetValueNonexistingTransformDeepKey description] + * @throws \codename\core\exception + */ + public function testGetValueNonexistingTransformDeepKey(): void + { + $this->expectException(Exception::class); + // NOTE: exception test from abstractTransformTest class + $this->expectExceptionMessage('Transform not found: nonexisting'); + $transform = $this->getDummyTransform(); + $transform->getInternalPipelineValue('transform_deep', ['nonexisting'], []); + } - $pipelineConfig = [ - 'constants' => [ - 'primitive' => 123, - 'array' => [ 4, 5, 6 ], - 'object' => [ 'a' => 1, 'b' => 2, 'c' => 3 ] - ], - 'source' => [], - 'transform' => [ - 'dummy' => [ - 'type' => 'dummy', - 'config' => [], - ] - ], - 'target' => [] - ]; - $pipeline = new \codename\core\io\pipeline(null, $pipelineConfig); - $datasource = new \codename\core\io\datasource\arraydata([]); - $datasource->setData([ - [] - ]); - $pipeline->setDatasource($datasource); - $pipeline->run(); - $dummy = $pipeline->getTransformInstance('dummy'); - if($dummy instanceof \codename\core\io\transform\dummy) { - $this->assertEquals(123, $dummy->getInternalPipelineValue('constant', 'primitive', [])); - $this->assertEquals([ 4, 5, 6 ], $dummy->getInternalPipelineValue('constant', 'array', [])); - $this->assertEquals([ 'a' => 1, 'b' => 2, 'c' => 3 ], $dummy->getInternalPipelineValue('constant', 'object', [])); - $this->assertEquals(2, $dummy->getInternalPipelineValue('constant', [ 'object', 'b' ], [])); - } else { - $this->assertInstanceOf(\codename\core\io\transform\dummy::class, $dummy); + /** + * [testGetValueErroneous description] + * @throws \codename\core\exception + */ + public function testGetValueErroneous(): void + { + $this->expectException(LogicException::class); + $this->expectExceptionMessage('Not implemented'); + $transform = $this->getDummyTransform(); + // + // 'erroneous' type is not implemented to be accessed this way + // Make sure we get an exception if we try to do it anyway. + // + $transform->getInternalPipelineValue('erroneous', 'abc', []); } - } + /** + * [testGetValueConstant description] + * @throws ReflectionException + * @throws \codename\core\exception + */ + public function testGetValueConstant(): void + { + // Emulate some response-related stuff + // as pipeline may access it in CLI for stdout + $app = static::createApp(); + $app::getAppstack(); + $app::__setInstance('response', new cli()); + + $pipelineConfig = [ + 'constants' => [ + 'primitive' => 123, + 'array' => [4, 5, 6], + 'object' => ['a' => 1, 'b' => 2, 'c' => 3], + ], + 'source' => [], + 'transform' => [ + 'dummy' => [ + 'type' => 'dummy', + 'config' => [], + ], + ], + 'target' => [], + ]; + $pipeline = new pipeline(null, $pipelineConfig); + $datasource = new arraydata(); + $datasource->setData([ + [], + ]); + $pipeline->setDatasource($datasource); + $pipeline->run(); + $dummy = $pipeline->getTransformInstance('dummy'); + if ($dummy instanceof dummy) { + static::assertEquals(123, $dummy->getInternalPipelineValue('constant', 'primitive', [])); + static::assertEquals([4, 5, 6], $dummy->getInternalPipelineValue('constant', 'array', [])); + static::assertEquals(['a' => 1, 'b' => 2, 'c' => 3], $dummy->getInternalPipelineValue('constant', 'object', [])); + static::assertEquals(2, $dummy->getInternalPipelineValue('constant', ['object', 'b'], [])); + } else { + static::assertInstanceOf(dummy::class, $dummy); + } + } } diff --git a/tests/transform/trim/leftTest.php b/tests/transform/trim/leftTest.php index dfdc787..de5a847 100644 --- a/tests/transform/trim/leftTest.php +++ b/tests/transform/trim/leftTest.php @@ -1,55 +1,67 @@ getTransform('trim_left', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => ' example ' - ]); - // Make sure it stays an array - $this->assertEquals('example ', $result); - } +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - /** - * Testing transforms for Erors - */ - public function testValueValidWithMask(): void { - $transform = $this->getTransform('trim_left', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'character_mask' => '0', - ]); - $result = $transform->transform([ - 'example_source_field' => ' example ' - ]); - // Make sure it stays an array - $this->assertEquals(' example ', $result); - } +class leftTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('trim_left', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => ' example ', + ]); + // Make sure it stays an array + static::assertEquals('example ', $result); + } - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('trim_left', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidWithMask(): void + { + $transform = $this->getTransform('trim_left', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'character_mask' => '0', + ]); + $result = $transform->transform([ + 'example_source_field' => ' example ', + ]); + // Make sure it stays an array + static::assertEquals(' example ', $result); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('trim_left', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/trim/rightTest.php b/tests/transform/trim/rightTest.php index 1198e43..44eca4a 100644 --- a/tests/transform/trim/rightTest.php +++ b/tests/transform/trim/rightTest.php @@ -1,55 +1,67 @@ getTransform('trim_right', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => ' example ' - ]); - // Make sure it stays an array - $this->assertEquals(' example', $result); - } +use codename\core\exception; +use codename\core\io\tests\transform\abstractTransformTest; +use ReflectionException; - /** - * Testing transforms for Erors - */ - public function testValueValidWithMask(): void { - $transform = $this->getTransform('trim_right', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'character_mask' => '0', - ]); - $result = $transform->transform([ - 'example_source_field' => ' example ' - ]); - // Make sure it stays an array - $this->assertEquals(' example ', $result); - } +class rightTest extends abstractTransformTest +{ + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValid(): void + { + $transform = $this->getTransform('trim_right', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => ' example ', + ]); + // Make sure it stays an array + static::assertEquals(' example', $result); + } - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('trim_right', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidWithMask(): void + { + $transform = $this->getTransform('trim_right', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'character_mask' => '0', + ]); + $result = $transform->transform([ + 'example_source_field' => ' example ', + ]); + // Make sure it stays an array + static::assertEquals(' example ', $result); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('trim_right', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/trimTest.php b/tests/transform/trimTest.php index 152d186..1f39b01 100644 --- a/tests/transform/trimTest.php +++ b/tests/transform/trimTest.php @@ -1,55 +1,66 @@ getTransform('trim', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + $result = $transform->transform([ + 'example_source_field' => ' example ', + ]); + // Make sure it stays an array + static::assertEquals('example', $result); + } - /** - * Testing transforms for Erors - */ - public function testValueValid(): void { - $transform = $this->getTransform('trim', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $result = $transform->transform([ - 'example_source_field' => ' example ' - ]); - // Make sure it stays an array - $this->assertEquals('example', $result); - } - - /** - * Testing transforms for Erors - */ - public function testValueValidWithMask(): void { - $transform = $this->getTransform('trim', [ - 'source' => 'source', - 'field' => 'example_source_field', - 'character_mask' => '0', - ]); - $result = $transform->transform([ - 'example_source_field' => ' example ' - ]); - // Make sure it stays an array - $this->assertEquals(' example ', $result); - } - - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('trim', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ 'source.example_source_field' ] - ], - $transform->getSpecification() - ); - } + /** + * Testing transforms for Errors + * @throws ReflectionException + * @throws exception + */ + public function testValueValidWithMask(): void + { + $transform = $this->getTransform('trim', [ + 'source' => 'source', + 'field' => 'example_source_field', + 'character_mask' => '0', + ]); + $result = $transform->transform([ + 'example_source_field' => ' example ', + ]); + // Make sure it stays an array + static::assertEquals(' example ', $result); + } + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('trim', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transform/valueTest.php b/tests/transform/valueTest.php index cc9ed04..cc3514b 100644 --- a/tests/transform/valueTest.php +++ b/tests/transform/valueTest.php @@ -1,38 +1,46 @@ getTransform('value', [ + 'value' => 'example', + ]); + $result = $transform->transform([ + 'example_source_field' => ' example ', + ]); + // Make sure it stays an array + static::assertEquals('example', $result); + } - /** - * Testing transforms for Erors - */ - public function testValueValid(): void { - $transform = $this->getTransform('value', [ - 'value' => 'example', - ]); - $result = $transform->transform([ - 'example_source_field' => ' example ' - ]); - // Make sure it stays an array - $this->assertEquals('example', $result); - } - - /** - * Test Spec output (simple case) - */ - public function testSpecification(): void { - $transform = $this->getTransform('value', [ - 'source' => 'source', - 'field' => 'example_source_field', - ]); - $this->assertEquals( - [ - 'type' => 'transform', - 'source' => [ ] - ], - $transform->getSpecification() - ); - } - + /** + * Test Spec output (simple case) + * @throws ReflectionException + * @throws exception + */ + public function testSpecification(): void + { + $transform = $this->getTransform('value', [ + 'source' => 'source', + 'field' => 'example_source_field', + ]); + static::assertEquals( + [ + 'type' => 'transform', + 'source' => [], + ], + $transform->getSpecification() + ); + } } diff --git a/tests/transformerTest.php b/tests/transformerTest.php new file mode 100644 index 0000000..00c2205 --- /dev/null +++ b/tests/transformerTest.php @@ -0,0 +1,95 @@ +get('transform')); + + $result = $transformer->getAvailableTransformNames(); + static::assertEquals(['static_true'], $result); + } + + /** + * [testTransformerAvailableTransformNames description] + * @throws ReflectionException + * @throws exception + */ + public function testTransformerAddTransform(): void + { + $transformer = new transformer([]); + + $transformer->addTransform('example', [ + 'type' => 'value', + 'config' => [ + 'value' => 'example', + ], + ]); + + $result = $transformer->getTransformInstance('example'); + static::assertInstanceOf(transform::class, $result); + } + + /** + * [testTransformerTransformInstance description] + * @throws ReflectionException + * @throws exception + */ + public function testTransformerTransformInstance(): void + { + $config = new extendable(__DIR__ . "/" . 'testTransformer1.json'); + $transformer = new transformer($config->get('transform')); + + $result = $transformer->getTransformInstance('static_true'); + static::assertInstanceOf(transform::class, $result); + } + + /** + * [testTransformerTransformInstance description] + * @throws ReflectionException + * @throws exception + */ + public function testTransformerWrongTransformInstance(): void + { + $this->expectException(exception::class); + $this->expectExceptionMessage('EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_NOTFOUND'); + + $config = new extendable(__DIR__ . "/" . 'testTransformer1.json'); + $transformer = new transformer($config->get('transform')); + + $transformer->getTransformInstance('example'); + } + + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function setUp(): void + { + parent::setUp(); + overrideableApp::__injectApp([ + 'vendor' => 'codename', + 'app' => 'core-io', + 'namespace' => '\\codename\\core\\io', + ]); + $app = static::createApp(); + $app::getAppstack(); + } +} diff --git a/tests/validator.php b/tests/validator.php index c7db504..30d62b7 100644 --- a/tests/validator.php +++ b/tests/validator.php @@ -1,48 +1,57 @@ 'codename', - 'app' => 'core-io', - 'namespace' => '\\codename\\core\\io' - ]); - $app = static::createApp(); - $app->getAppstack(); - } - - /** - * [getValidator description] - * @return \codename\core\validator [description] - */ - protected function getValidator() : \codename\core\validator { - // load the respective validator via namespace, by instanciated class name - // we have to remove __CLASS__ (THIS exact class here) - - // extract validator name from current class name, stripped by validator base namespace - $validatorClass = str_replace(__CLASS__.'\\', '', (new \ReflectionClass($this))->getName()); - - // replace \ by _ - $validatorName = str_replace('\\', '_', $validatorClass); - - $validator = \codename\core\app::getValidator($validatorName); - $validator->reset(); - return $validator; - } - +abstract class validator extends base +{ + /** + * {@inheritDoc} + * @throws ReflectionException + * @throws exception + */ + protected function setUp(): void + { + parent::setUp(); + overrideableApp::__injectApp([ + 'vendor' => 'codename', + 'app' => 'core-io', + 'namespace' => '\\codename\\core\\io', + ]); + $app = static::createApp(); + $app::getAppstack(); + } + + /** + * [getValidator description] + * @return \codename\core\validator [description] + * @throws ReflectionException + * @throws exception + */ + protected function getValidator(): \codename\core\validator + { + // load the respective validator via namespace, by instantiated class name + // we have to remove __CLASS__ (THIS exact class here) + + // extract validator name from current class name, stripped by validator base namespace + $validatorClass = str_replace(__CLASS__ . '\\', '', (new ReflectionClass($this))->getName()); + + // replace \ by _ + $validatorName = str_replace('\\', '_', $validatorClass); + + $validator = app::getValidator($validatorName); + $validator->reset(); + return $validator; + } } diff --git a/tests/validator/structure.php b/tests/validator/structure.php deleted file mode 100644 index 673482b..0000000 --- a/tests/validator/structure.php +++ /dev/null @@ -1,46 +0,0 @@ -assertEquals('VALIDATION.VALUE_NOT_A_ARRAY', $this->getValidator()->validate('')[0]['__CODE'] ); - } - - /** - * simple non-text value test - * @return void - */ - public function testValueIsNull() { - $this->assertEmpty($this->getValidator()->validate(null)); - } - - /** - * simple non-text value test - * @return void - */ - public function testValueIsNullNotAllowed() { - $validator = new \codename\core\validator\structure(false); - $errors = $validator->validate(null); - - $this->assertNotEmpty($errors); - $this->assertCount(1, $errors); - $this->assertEquals('VALIDATION.VALUE_IS_NULL', $errors[0]['__CODE']); - } - - /** - * simple non-text value test - * @return void - */ - public function testValueIsValid() { - $validator = new \codename\core\validator\structure(); - $this->assertTrue($validator->isValid(null)); - } - -} diff --git a/tests/validator/structure/config/import.php b/tests/validator/structure/config/import.php deleted file mode 100644 index 84869bd..0000000 --- a/tests/validator/structure/config/import.php +++ /dev/null @@ -1,73 +0,0 @@ -getValidator()->validate([]); - - $this->assertNotEmpty($errors); - $this->assertCount(2, $errors); - $this->assertEquals('VALIDATION.ARRAY_MISSING_KEY', $errors[0]['__CODE'] ); - $this->assertEquals('VALIDATION.ARRAY_MISSING_KEY', $errors[1]['__CODE'] ); - } - - /** - * Testing validators for Erors - * @return void - */ - public function testValueInvalidKeySource() { - $config = [ - 'source' => '', - 'target' => [], - ]; - $this->assertNotEmpty($this->getValidator()->validate($config)); - } - - /** - * Testing validators for Erors - * @return void - */ - public function testValueInvalidKeyTarget() { - $config = [ - 'source' => [], - 'target' => '', - ]; - $this->assertNotEmpty($this->getValidator()->validate($config)); - } - - /** - * Testing validators for Erors - * @return void - */ - public function testValueInvalidKeyTransform() { - $config = [ - 'source' => [], - 'target' => [], - 'transform' => 'example', - ]; - $this->assertNotEmpty($this->getValidator()->validate($config)); - } - - /** - * Testing validators for Erors - * @return void - */ - public function testValueValid() { - $config = [ - 'source' => [], - 'target' => [], - ]; - $this->assertEmpty($this->getValidator()->validate($config)); - } - -} diff --git a/tests/validator/structure/config/import/source.php b/tests/validator/structure/config/import/source.php deleted file mode 100644 index 315155b..0000000 --- a/tests/validator/structure/config/import/source.php +++ /dev/null @@ -1,27 +0,0 @@ -assertEquals('VALIDATION.VALUE_NOT_A_ARRAY', $this->getValidator()->validate('')[0]['__CODE'] ); - } - - /** - * Testing validators for Erors - * @return void - */ - public function testValueMissingArrKeys() { - $this->assertEmpty($this->getValidator()->validate([])); - } - -} diff --git a/tests/validator/structure/config/import/sourceTest.php b/tests/validator/structure/config/import/sourceTest.php new file mode 100644 index 0000000..2a72fb2 --- /dev/null +++ b/tests/validator/structure/config/import/sourceTest.php @@ -0,0 +1,38 @@ +validate(''); + + static::assertEquals('VALIDATION.VALUE_NOT_A_ARRAY', $errors[0]['__CODE'] ?? ''); + } + + /** + * Testing validators for Errors + * @return void + */ + public function testValueMissingArrKeys(): void + { + $validator = new source(); + $errors = $validator->validate([]); + + static::assertEmpty($errors); + } +} diff --git a/tests/validator/structure/config/import/target.php b/tests/validator/structure/config/import/target.php deleted file mode 100644 index 7dda2bc..0000000 --- a/tests/validator/structure/config/import/target.php +++ /dev/null @@ -1,27 +0,0 @@ -assertEquals('VALIDATION.VALUE_NOT_A_ARRAY', $this->getValidator()->validate('')[0]['__CODE'] ); - } - - /** - * Testing validators for Erors - * @return void - */ - public function testValueMissingArrKeys() { - $this->assertEmpty($this->getValidator()->validate([])); - } - -} diff --git a/tests/validator/structure/config/import/targetTest.php b/tests/validator/structure/config/import/targetTest.php new file mode 100644 index 0000000..54714a1 --- /dev/null +++ b/tests/validator/structure/config/import/targetTest.php @@ -0,0 +1,38 @@ +validate(''); + + static::assertEquals('VALIDATION.VALUE_NOT_A_ARRAY', $errors[0]['__CODE'] ?? ''); + } + + /** + * Testing validators for Errors + * @return void + */ + public function testValueMissingArrKeys(): void + { + $validator = new target(); + $errors = $validator->validate([]); + + static::assertEmpty($errors); + } +} diff --git a/tests/validator/structure/config/import/transform.php b/tests/validator/structure/config/import/transform.php deleted file mode 100644 index 2259066..0000000 --- a/tests/validator/structure/config/import/transform.php +++ /dev/null @@ -1,27 +0,0 @@ -assertEquals('VALIDATION.VALUE_NOT_A_ARRAY', $this->getValidator()->validate('')[0]['__CODE'] ); - } - - /** - * Testing validators for Erors - * @return void - */ - public function testValueMissingArrKeys() { - $this->assertEmpty($this->getValidator()->validate([])); - } - -} diff --git a/tests/validator/structure/config/import/transformTest.php b/tests/validator/structure/config/import/transformTest.php new file mode 100644 index 0000000..21a6ccd --- /dev/null +++ b/tests/validator/structure/config/import/transformTest.php @@ -0,0 +1,38 @@ +validate(''); + + static::assertEquals('VALIDATION.VALUE_NOT_A_ARRAY', $errors[0]['__CODE'] ?? ''); + } + + /** + * Testing validators for Errors + * @return void + */ + public function testValueMissingArrKeys(): void + { + $validator = new transform(); + $errors = $validator->validate([]); + + static::assertEmpty($errors); + } +} diff --git a/tests/validator/structure/config/importTest.php b/tests/validator/structure/config/importTest.php new file mode 100644 index 0000000..01afc7c --- /dev/null +++ b/tests/validator/structure/config/importTest.php @@ -0,0 +1,90 @@ +validate([]); + + static::assertNotEmpty($errors); + static::assertCount(2, $errors); + static::assertEquals('VALIDATION.ARRAY_MISSING_KEY', $errors[0]['__CODE']); + static::assertEquals('VALIDATION.ARRAY_MISSING_KEY', $errors[1]['__CODE']); + } + + /** + * Testing validators for Errors + * @return void + */ + public function testValueInvalidKeySource(): void + { + $validator = new import(); + $errors = $validator->validate([ + 'source' => '', + 'target' => [], + ]); + + static::assertNotEmpty($errors); + } + + /** + * Testing validators for Errors + * @return void + */ + public function testValueInvalidKeyTarget(): void + { + $validator = new import(); + $errors = $validator->validate([ + 'source' => [], + 'target' => '', + ]); + + static::assertNotEmpty($errors); + } + + /** + * Testing validators for Errors + * @return void + */ + public function testValueInvalidKeyTransform(): void + { + $validator = new import(); + $errors = $validator->validate([ + 'source' => [], + 'target' => [], + 'transform' => 'example', + ]); + + static::assertNotEmpty($errors); + } + + /** + * Testing validators for Errors + * @return void + */ + public function testValueValid(): void + { + $validator = new import(); + $errors = $validator->validate([ + 'source' => [], + 'target' => [], + ]); + + static::assertEmpty($errors); + } +} diff --git a/tests/validator/structureTest.php b/tests/validator/structureTest.php new file mode 100644 index 0000000..eb501ea --- /dev/null +++ b/tests/validator/structureTest.php @@ -0,0 +1,60 @@ +validate(''); + + static::assertEquals('VALIDATION.VALUE_NOT_A_ARRAY', $errors[0]['__CODE'] ?? ''); + } + + /** + * simple non-text value test + * @return void + */ + public function testValueIsNull(): void + { + $validator = new structure(); + $errors = $validator->validate(null); + + static::assertEmpty($errors); + } + + /** + * simple non-text value test + * @return void + */ + public function testValueIsNullNotAllowed(): void + { + $validator = new structure(false); + $errors = $validator->validate(null); + + static::assertNotEmpty($errors); + static::assertCount(1, $errors); + static::assertEquals('VALIDATION.VALUE_IS_NULL', $errors[0]['__CODE']); + } + + /** + * simple non-text value test + * @return void + */ + public function testValueIsValid(): void + { + $validator = new structure(); + static::assertTrue($validator->isValid(null)); + } +} diff --git a/tests/value/structure/taggedTest.php b/tests/value/structure/taggedTest.php new file mode 100644 index 0000000..249104f --- /dev/null +++ b/tests/value/structure/taggedTest.php @@ -0,0 +1,28 @@ + true, + ]); + + static::assertEquals([ + 'example' => true, + ], $tagged->getTags()); + } +} diff --git a/tests/value/structure/testTagged.php b/tests/value/structure/testTagged.php deleted file mode 100644 index e98d5e9..0000000 --- a/tests/value/structure/testTagged.php +++ /dev/null @@ -1,22 +0,0 @@ - true, - ]); - - $this->assertEquals([ - 'example' => true, - ], $tagged->getTags()); - - } - -} diff --git a/tests/value/text/fileabsolute/taggedTest.php b/tests/value/text/fileabsolute/taggedTest.php new file mode 100644 index 0000000..9512dcb --- /dev/null +++ b/tests/value/text/fileabsolute/taggedTest.php @@ -0,0 +1,28 @@ + true, + ]); + + static::assertEquals([ + 'example' => true, + ], $tagged->getTags()); + } +} diff --git a/tests/value/text/fileabsolute/testTagged.php b/tests/value/text/fileabsolute/testTagged.php deleted file mode 100644 index 9058e5d..0000000 --- a/tests/value/text/fileabsolute/testTagged.php +++ /dev/null @@ -1,22 +0,0 @@ - true, - ]); - - $this->assertEquals([ - 'example' => true, - ], $tagged->getTags()); - - } - -} diff --git a/tests/value/text/taggedTest.php b/tests/value/text/taggedTest.php new file mode 100644 index 0000000..118de4a --- /dev/null +++ b/tests/value/text/taggedTest.php @@ -0,0 +1,28 @@ + true, + ]); + + static::assertEquals([ + 'example' => true, + ], $tagged->getTags()); + } +} diff --git a/tests/value/text/testTagged.php b/tests/value/text/testTagged.php deleted file mode 100644 index e1a99d1..0000000 --- a/tests/value/text/testTagged.php +++ /dev/null @@ -1,22 +0,0 @@ - true, - ]); - - $this->assertEquals([ - 'example' => true, - ], $tagged->getTags()); - - } - -} From 8835b538a061a57d4013cb195b79fb17c3192655 Mon Sep 17 00:00:00 2001 From: Ralf Date: Fri, 1 Nov 2024 10:33:39 +0100 Subject: [PATCH 2/2] update php 8.1 > 8.3, dependencies, bugfixing and code cleanup --- backend/class/datasource/buffered.php | 38 +-- backend/class/datasource/csv.php | 4 +- backend/class/datasource/database.php | 2 +- backend/class/datasource/joined.php | 6 +- backend/class/datasource/model.php | 19 +- backend/class/datasource/multicsv.php | 12 +- backend/class/datasource/parquet.php | 8 +- backend/class/datasource/raw.php | 21 +- backend/class/datasource/remap.php | 2 +- backend/class/datasource/spreadsheet.php | 8 +- backend/class/export/pdf.php | 2 +- backend/class/export/pdf/dompdf.php | 2 +- .../class/helper/datasource/bufferedValue.php | 32 ++ backend/class/helper/pipeline.php | 7 +- backend/class/pipeline.php | 80 +++-- backend/class/process/target/model/update.php | 26 ++ backend/class/progressInterface.php | 2 +- .../class/setPipelineInstanceInterface.php | 2 +- backend/class/target.php | 10 +- backend/class/target/buffered.php | 4 +- backend/class/target/buffered/file.php | 2 +- backend/class/target/buffered/file/csv.php | 18 +- backend/class/target/buffered/file/json.php | 2 +- .../class/target/buffered/file/parquet.php | 4 +- .../target/buffered/file/spreadsheet.php | 47 +-- backend/class/target/buffered/file/xml.php | 56 +++- backend/class/target/createArchiveTrait.php | 4 +- backend/class/target/model.php | 2 + backend/class/target/model/complex.php | 8 +- backend/class/target/virtual.php | 6 +- backend/class/target/xml.php | 6 +- backend/class/target/xml/text.php | 2 +- backend/class/transform.php | 6 +- .../class/transform/calculate/subtract.php | 2 +- backend/class/transform/calculate/sum.php | 2 +- backend/class/transform/compare.php | 2 +- backend/class/transform/compare/datetime.php | 2 + backend/class/transform/compare/isday.php | 2 + backend/class/transform/compare/isholiday.php | 2 + backend/class/transform/convert/datetime.php | 2 + .../class/transform/convert/numberformat.php | 4 +- backend/class/transform/get/conditioned.php | 12 + .../class/transform/get/conditioned/all.php | 45 ++- .../class/transform/get/currentdatetime.php | 4 + .../class/transform/get/easterdatetime.php | 2 + .../transform/get/filtered/arrayfilter.php | 2 +- backend/class/transform/get/number/whole.php | 7 +- backend/class/transform/implode.php | 4 +- backend/class/transform/model.php | 45 ++- backend/class/transform/model/map/single.php | 2 + backend/class/transform/model/result/all.php | 2 + backend/class/transform/model/result/one.php | 2 + backend/class/transform/model/save.php | 5 +- .../class/transform/model/save/onetime.php | 4 +- backend/class/transform/regex.php | 2 - backend/class/transformer.php | 12 +- composer.json | 6 +- tests/autoload.php | 10 +- tests/datasource/bufferedTest.php | 14 +- tests/datasource/csvTest.php | 38 +-- tests/datasource/joinedTest.php | 284 +++++++++--------- tests/datasource/model/datasourceentry.php | 2 +- tests/datasource/model/datasourceentryj.php | 2 +- tests/datasource/modelTest.php | 24 +- tests/datasource/rawTest.php | 196 ++++++------ tests/datasource/remapTest.php | 96 +++--- tests/datasource/spreadsheetTest.php | 52 ++-- tests/datasource/xmlTest.php | 58 ++-- tests/helper/model/helperjmodel.php | 2 +- tests/helper/model/helpermodel.php | 2 +- tests/helper/pipelineTest.php | 22 ++ tests/pipeline/abstractPipelineTest.php | 34 ++- tests/pipeline/genericPipelineTest.php | 28 +- tests/pipeline/model/pipelinemodel.php | 2 +- tests/pipeline/pipelineModelTargetTest.php | 2 +- tests/pipelineTest.php | 120 +++++--- .../model/abstractProcessTargetModelTest.php | 34 ++- .../target/model/model/processmodel.php | 2 +- tests/process/target/model/updateTest.php | 4 + .../CsvBufferingAndSplittingWriteReadTest.php | 26 +- .../file/parquetBufferedWriteReadTest.php | 26 +- .../buffered/file/parquetWriteReadTest.php | 22 +- tests/target/buffered/file/rawTest.php | 22 ++ .../target/buffered/file/spreadsheetTest.php | 22 ++ tests/target/buffered/fileTest.php | 2 +- tests/target/filterTest.php | 2 +- tests/target/model/complexTest.php | 57 +++- tests/target/model/testmodel.php | 2 +- tests/target/model/testmodelj.php | 2 +- tests/target/modelTest.php | 40 ++- tests/target/virtualTest.php | 25 ++ tests/target/xml/textTest.php | 20 +- tests/transform/abstractTransformTest.php | 22 ++ tests/transform/calculate/divideTest.php | 10 +- tests/transform/calculate/multiplyTest.php | 10 +- tests/transform/calculate/subtractTest.php | 10 +- tests/transform/calculate/sumTest.php | 10 +- tests/transform/compare/beginswithTest.php | 10 +- tests/transform/compare/datetimeTest.php | 10 +- tests/transform/compare/isdayTest.php | 10 +- tests/transform/compare/isequalTest.php | 10 +- tests/transform/compare/isholidayTest.php | 36 ++- tests/transform/compare/model/holidays.php | 8 +- tests/transform/compare/numberTest.php | 10 +- tests/transform/containsTest.php | 10 +- tests/transform/convert/booleanTest.php | 10 +- tests/transform/convert/datetimeTest.php | 10 +- tests/transform/convert/encodingTest.php | 10 +- tests/transform/convert/jsonTest.php | 10 +- tests/transform/convert/numberformatTest.php | 10 +- tests/transform/countTest.php | 10 +- tests/transform/deepaccessTest.php | 2 +- tests/transform/explodeTest.php | 14 +- tests/transform/get/arraycolumnTest.php | 10 +- tests/transform/get/arrayvalueTest.php | 10 +- tests/transform/get/conditionedTest.php | 26 +- tests/transform/get/currentdatetimeTest.php | 12 +- tests/transform/get/easterdatetimeTest.php | 10 +- tests/transform/get/fallbackTest.php | 10 +- tests/transform/get/filteredTest.php | 10 +- tests/transform/get/number/fractionTest.php | 10 +- tests/transform/get/number/wholeTest.php | 10 +- tests/transform/get/onetimeTest.php | 10 +- tests/transform/get/optionTest.php | 10 +- tests/transform/get/strcaseTest.php | 10 +- tests/transform/get/strreplaceTest.php | 10 +- tests/transform/get/substrTest.php | 10 +- tests/transform/get/valueTest.php | 10 +- tests/transform/get/valuearrayTest.php | 22 +- tests/transform/hashTest.php | 10 +- tests/transform/implode/arrayvalueTest.php | 10 +- tests/transform/implodeTest.php | 46 +-- tests/transform/math/roundTest.php | 2 +- tests/transform/model/tjsample.php | 2 +- tests/transform/model/transformmodel.php | 2 +- tests/transform/modelTest.php | 54 +++- tests/transform/pad/leftTest.php | 12 +- tests/transform/pad/rightTest.php | 12 +- tests/transform/regexTest.php | 11 +- tests/transform/transformGetValueTest.php | 26 +- tests/transform/trim/leftTest.php | 10 +- tests/transform/trim/rightTest.php | 10 +- tests/transform/trimTest.php | 10 +- tests/transform/valueTest.php | 10 +- tests/transformerTest.php | 22 ++ tests/validator.php | 22 ++ 146 files changed, 1616 insertions(+), 1007 deletions(-) create mode 100644 backend/class/helper/datasource/bufferedValue.php diff --git a/backend/class/datasource/buffered.php b/backend/class/datasource/buffered.php index 873c2ea..a8a78ed 100644 --- a/backend/class/datasource/buffered.php +++ b/backend/class/datasource/buffered.php @@ -4,37 +4,9 @@ use codename\core\exception; use codename\core\io\datasource; +use codename\core\io\helper\datasource\bufferedValue; use SplQueue; -/** - * encapsulates a buffered value - */ -class bufferedValue -{ - /** - * [public description] - * @var mixed - */ - public mixed $value; - /** - * [public description] - * @var int [type] - */ - public int $progressPosition; - - /** - * @param mixed $value - * @param int $progressPosition - */ - public function __construct( - mixed $value, - int $progressPosition - ) { - $this->value = $value; - $this->progressPosition = $progressPosition; - } -} - /** * buffered datasource * that encapsulates another datasource @@ -181,10 +153,10 @@ protected function fillBuffer(): void for ($i = 0; $i < $this->bufferSize; $i++) { if ($this->datasource->valid()) { $this->bufferQueue->enqueue( - new bufferedValue( - $this->datasource->current(), - $this->datasource->currentProgressPosition() - ) + new bufferedValue( + $this->datasource->current(), + $this->datasource->currentProgressPosition() + ) ); $this->datasource->next(); } else { diff --git a/backend/class/datasource/csv.php b/backend/class/datasource/csv.php index 4000efc..f7342b9 100644 --- a/backend/class/datasource/csv.php +++ b/backend/class/datasource/csv.php @@ -15,7 +15,7 @@ class csv extends datasource * see https://stackoverflow.com/questions/5601904/encoding-a-string-as-utf-8-with-bom-in-php * @var string */ - public const UTF8_BOM = "\xEF\xBB\xBF"; + public const string UTF8_BOM = "\xEF\xBB\xBF"; /** * [protected description] * @var string [type] @@ -114,7 +114,7 @@ public function setConfig(array $config): void protected function handleUtf8Bom(): void { if (ftell($this->handle) !== 0) { - return; // skip, as we are not on pos 0 (beginning of file) + return; // skip, as we are not on pos 0 (beginning of a file) } if (($header = fread($this->handle, 3)) !== false) { diff --git a/backend/class/datasource/database.php b/backend/class/datasource/database.php index 14e27f9..528cd53 100644 --- a/backend/class/datasource/database.php +++ b/backend/class/datasource/database.php @@ -86,7 +86,7 @@ public function setConfig(array $config): void $dbClass = app::getInheritedClass('database_' . $config['driver']); $this->database = new $dbClass($config); - // use buffered queries when using MYSQL + // use buffered queries; when using MYSQL, // this should reduce memory usage BY A HUGE AMOUNT! if ($this->database->getConnection()->getAttribute(PDO::ATTR_DRIVER_NAME) == 'mysql') { $this->database->getConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true); diff --git a/backend/class/datasource/joined.php b/backend/class/datasource/joined.php index 76a780f..fb42760 100644 --- a/backend/class/datasource/joined.php +++ b/backend/class/datasource/joined.php @@ -62,7 +62,7 @@ class joined extends datasource */ public function __construct(array $datasources, array $config = []) { - // make an array of files, if it's ONE file. + // make an array of files if it's ONE file. if (count($datasources) < 2) { throw new exception('JOINED_DATASOURCE_NEEDS_MULTIPLE_INPUT_DATASOURCES', exception::$ERRORLEVEL_ERROR); } @@ -78,7 +78,7 @@ public function __construct(array $datasources, array $config = []) // datasources may be keyed/named $this->datasources[$key] = $ds; - // first entry represents the main datasource + // the first entry represents the main datasource if ($this->mainDatasourceKey === null) { $this->mainDatasourceKey = $key; } @@ -244,7 +244,7 @@ protected function performJoins(int|string $baseDatasourceIdentifier, array &$cu } } - // we might have had no join matches + // we might have had no join matches, // therefore, pass original datasets if (count($joinedResult) > 0) { $current = $joinedResult; diff --git a/backend/class/datasource/model.php b/backend/class/datasource/model.php index b9b2591..8b12215 100644 --- a/backend/class/datasource/model.php +++ b/backend/class/datasource/model.php @@ -7,6 +7,7 @@ use codename\core\io\datasource; use codename\core\io\pipeline; use codename\core\io\setPipelineInstanceInterface; +use DateMalformedStringException; use ReflectionException; /** @@ -126,10 +127,11 @@ protected function buildModelStructure(array $config): \codename\core\model // // Crazy stuff... - // if you're doing a model=>model import (same model) + // if you're doing a model=>model, import (same model), // you might get into the situation of querying inside a transaction // which leads to STRANGE stuff happening. - // we simply overcome it here by using a separate connection. BAM! + // We simply overcome it here by using a separate connection. + // BAM! // if (($config['connection_separate'] ?? false) || ($this->separateDbConnections[$model->getConfig()->get('connection')] ?? false)) { // get a non-stored db connection @@ -214,6 +216,7 @@ public function key(): mixed /** * {@inheritDoc} + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -232,6 +235,7 @@ public function rewind(): void * @param array $query [description] * @return array [description] * @throws ReflectionException + * @throws DateMalformedStringException * @throws exception */ protected function executeModelQuery(array $query): array @@ -282,11 +286,11 @@ protected function getQuery(): array $offset = ($this->rowId ?? 0); return array_merge( - $this->query, - [ - 'limit' => $limit, - 'offset' => $offset, - ] + $this->query, + [ + 'limit' => $limit, + 'offset' => $offset, + ] ); } else { return $this->query; @@ -304,6 +308,7 @@ public function setQuery(array $data): void /** * {@inheritDoc} + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ diff --git a/backend/class/datasource/multicsv.php b/backend/class/datasource/multicsv.php index a081ebd..42cab18 100644 --- a/backend/class/datasource/multicsv.php +++ b/backend/class/datasource/multicsv.php @@ -50,7 +50,7 @@ class multicsv extends datasource */ protected array $positions = []; /** - * just save the progress limits of the datasources + * save the progress limits of the datasources * to make sure we don't cause IO-intensive operations somehow * @var int|null */ @@ -64,7 +64,7 @@ class multicsv extends datasource */ public function __construct(array|string $files, array $config = []) { - // make an array of files, if it's ONE file. + // make an array of files if it's ONE file. if (!is_array($files)) { $files = [$files]; } @@ -73,7 +73,7 @@ public function __construct(array|string $files, array $config = []) $i = 0; foreach ($files as $file) { - // CHANGED 2021-04-30: we now pass through the full config to nested datasources + // CHANGED 2021-04-30: we now pass through the full config to nest datasources $subconfig = $this->config->get(); $this->datasources[$i] = new csv($file, $subconfig); $i++; @@ -87,14 +87,14 @@ public function __construct(array|string $files, array $config = []) */ public function setConfig(array $config): void { - // CHANGED 2021-04-30: we now pass through the full config to nested datasources + // CHANGED 2021-04-30: we now pass through the full config to nest datasources // and fallback configs to default + store them in a member variable $this->delimiter = $config['delimiter'] = $config['delimiter'] ?? ';'; $this->headed = $config['headed'] = $config['headed'] ?? true; $this->config = new config($config); foreach ($this->datasources as $datasource) { - // CHANGED 2021-04-30: we now pass through the full config to nested datasources + // CHANGED 2021-04-30: we now pass through the full config to nest datasources $subconfig = $this->config->get(); $datasource->setConfig($subconfig); } @@ -108,7 +108,7 @@ public function next(): void $this->datasources[$this->fileindex]->next(); if (!$this->datasources[$this->fileindex]->valid()) { if ($this->fileindex < (count($this->datasources) - 1)) { - // move on to next datasource + // move on to the next datasource $this->fileindex++; } } diff --git a/backend/class/datasource/parquet.php b/backend/class/datasource/parquet.php index 4468e0c..96428ef 100644 --- a/backend/class/datasource/parquet.php +++ b/backend/class/datasource/parquet.php @@ -133,12 +133,12 @@ public function next(): void $this->currentIndex = 0; $this->overallKey = 0; - // NOTE/CHANGED 2021-05-03: we might receive an empty datapage - // right from the start, so we have to execute the code below... + // NOTE/CHANGED 2021-05-03: we might receive an empty datapage + // right from the start, so we have to execute the code below... } else { // // we're still working on the current, already-read rowgroup/page - // move on to next key - it will automatically lead to page change, + // move on to the next key - it will automatically lead to page change, // if required // $this->currentIndex++; @@ -174,7 +174,7 @@ protected function read(): bool // nothing to check, unread data } else { // check current read state - // or simply increment by 1 ? + // or increment by 1? $this->currentRowGroupIndex++; } diff --git a/backend/class/datasource/raw.php b/backend/class/datasource/raw.php index 46eb4ed..ae7faa6 100644 --- a/backend/class/datasource/raw.php +++ b/backend/class/datasource/raw.php @@ -22,11 +22,11 @@ class raw extends datasource */ public ?array $computedMappings = null; /** - * input interpretation format as array + * input interpretation format as an array * [ - * 'map' => [ - * 'output-key-1' => 'partial-sprintf-cmd', - * 'output-key-2' => 'partial-sprintf-cmd' + * 'map' => [ + * 'output-key-1' => 'partial-sprintf-cmd', + * 'output-key-2' => 'partial-sprintf-cmd' * ] * ] * @see http://php.net/manual/de/function.fscanf.php @@ -235,12 +235,12 @@ public function next(): void $formatted = sscanf($readvalue, $mapConfig[$mappedValue]['format']); $value = []; - foreach ($mapConfig[$mappedValue]['map'] as $mapIndex => $mapField) { + foreach ($mapConfig[$mappedValue]['map'] as $mapConfigIndex => $mapField) { // convert encoding, if configured if ($mapConfig[$mappedValue]['convert']) { - $value[$mapField] = mb_convert_encoding($formatted[$mapIndex], $mapConfig[$mappedValue]['convert']['to'], $mapConfig[$mappedValue]['convert']['from'] ?? mb_internal_encoding()); + $value[$mapField] = mb_convert_encoding($formatted[$mapConfigIndex], $mapConfig[$mappedValue]['convert']['to'], $mapConfig[$mappedValue]['convert']['from'] ?? mb_internal_encoding()); } else { - $value[$mapField] = $formatted[$mapIndex]; + $value[$mapField] = $formatted[$mapConfigIndex]; } if ($mapConfig[$mappedValue]['trim']) { @@ -251,8 +251,9 @@ public function next(): void $found = true; break; } else { - // value not found - // mapping invalid. move on to next value? + // value didn't find + // mapping invalid. + // move on to the next value? } } @@ -261,7 +262,7 @@ public function next(): void } } } else { - // end of file? + // end of a file? $this->current = $rawvalue; } diff --git a/backend/class/datasource/remap.php b/backend/class/datasource/remap.php index 2b154f8..658ec4a 100644 --- a/backend/class/datasource/remap.php +++ b/backend/class/datasource/remap.php @@ -31,7 +31,7 @@ class remap extends datasource */ protected bool $sourceDataReplace = false; /** - * key to store original/source data in (null => do not store) + * key to store original/source data in (null => does not store) * @var string|null */ protected ?string $sourceDataKey = null; diff --git a/backend/class/datasource/spreadsheet.php b/backend/class/datasource/spreadsheet.php index 108b9a1..8659fb3 100644 --- a/backend/class/datasource/spreadsheet.php +++ b/backend/class/datasource/spreadsheet.php @@ -87,7 +87,7 @@ class spreadsheet extends datasource */ protected int $skipRows = 0; /** - * number of header row + * number of header rows * @var int */ protected int $headerRow = 1; @@ -146,7 +146,7 @@ public function __construct(string $file = '', array $config = [] /* bool $heade // custom sheet index $this->customSheetIndex = intval($this->customSheetIndex); } else { - // fallback to first sheet + // fallback to the first sheet $this->customSheetIndex = 0; } $this->activeSheet = $this->sheet->getSheet($this->customSheetIndex); @@ -215,7 +215,7 @@ public function next(): void // NOTE: RowIterator starts its index at 1 // Therefore, we are getting the headed data columns at index 2 if ($this->headed && $this->activeSheetRowIterator->valid() && $this->activeSheetRowIterator->key() === ($this->headerRow)) { - // use first row in each sheet for mapping the values + // use the first row in each sheet for mapping the values // get current row. $row = $this->activeSheetRowIterator->current(); @@ -281,7 +281,7 @@ public function next(): void if (!$this->includeEmptyRows && $valueCount === 0) { // if we have no values in this row (valueCount === 0) - // and we want to skip empty rows, simply move on to next row. + // and we want to skip empty rows, simply move on to the next row. $this->next(); } else { $this->globalRowIndex++; diff --git a/backend/class/export/pdf.php b/backend/class/export/pdf.php index 5f96f15..3442280 100644 --- a/backend/class/export/pdf.php +++ b/backend/class/export/pdf.php @@ -6,7 +6,7 @@ use codename\core\value\text\fileabsolute; /** - * converts html to pdf + * converts HTML to PDF * including CSS Stylesheets and other stuff. */ abstract class pdf diff --git a/backend/class/export/pdf/dompdf.php b/backend/class/export/pdf/dompdf.php index 0eb18fd..ec625bf 100644 --- a/backend/class/export/pdf/dompdf.php +++ b/backend/class/export/pdf/dompdf.php @@ -21,7 +21,7 @@ class dompdf extends pdf */ protected ?\Dompdf\Dompdf $dompdf = null; /** - * path to file which was last created by render() + * path to file which render last created() * @var null|fileabsolute */ protected ?fileabsolute $outputFile = null; diff --git a/backend/class/helper/datasource/bufferedValue.php b/backend/class/helper/datasource/bufferedValue.php new file mode 100644 index 0000000..6dc89b7 --- /dev/null +++ b/backend/class/helper/datasource/bufferedValue.php @@ -0,0 +1,32 @@ +value = $value; + $this->progressPosition = $progressPosition; + } +} \ No newline at end of file diff --git a/backend/class/helper/pipeline.php b/backend/class/helper/pipeline.php index ce2e479..6cd7632 100644 --- a/backend/class/helper/pipeline.php +++ b/backend/class/helper/pipeline.php @@ -83,7 +83,7 @@ public static function createModelToModelPipelineConfig(model $model, string $ta $params = static::convertModelfieldToParquetEquivalentParams($currentModel, $field, $mappingEntry, $transforms); // prevent joined models' PKEY - // to be required, if there's NULL ref + // to be required if there's NULL ref if ($index > 0) { if ($field == $currentModel->getPrimaryKey()) { $params['is_nullable'] = true; // ? @@ -142,8 +142,9 @@ protected static function convertModelfieldToParquetEquivalentParams(model $mode switch ($datatype) { case 'structure': - // highly dependent on usage... - // F.e. if FKEY to model, it's the Foreign model's pkey type + // Highly dependent on usage... + // F.e. + // If FKEY to model, it's the Foreign model's pkey type // Otherwise: JSON data // Which might be mapped otherwise. // For now: fallback to string. diff --git a/backend/class/pipeline.php b/backend/class/pipeline.php index bf42d7f..da6d126 100644 --- a/backend/class/pipeline.php +++ b/backend/class/pipeline.php @@ -18,8 +18,22 @@ use PDO; use ReflectionException; +use function array_keys; +use function array_map; +use function array_merge; +use function array_slice; +use function array_sum; +use function bccomp; +use function chr; +use function class_exists; use function count; +use function implode; use function is_array; +use function max; +use function microtime; +use function print_r; +use function round; +use function usort; /** * [pipeline description] @@ -30,32 +44,32 @@ class pipeline implements transformerInterface * [EXCEPTION_CORE_IO_PIPELINE_BEGINTRANSACTIONS_CALLED_TWICE description] * @var string */ - public const EXCEPTION_CORE_IO_PIPELINE_BEGINTRANSACTIONS_CALLED_TWICE = 'EXCEPTION_CORE_IO_PIPELINE_BEGINTRANSACTIONS_CALLED_TWICE'; + public const string EXCEPTION_CORE_IO_PIPELINE_BEGINTRANSACTIONS_CALLED_TWICE = 'EXCEPTION_CORE_IO_PIPELINE_BEGINTRANSACTIONS_CALLED_TWICE'; /** * [EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_INSTANCE_OF_WRONG_BASE_CLASS description] * @var string */ - public const EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_INSTANCE_OF_WRONG_BASE_CLASS = 'EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_INSTANCE_OF_WRONG_BASE_CLASS'; + public const string EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_INSTANCE_OF_WRONG_BASE_CLASS = 'EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_INSTANCE_OF_WRONG_BASE_CLASS'; /** * [EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_NOTFOUND description] * @var string */ - public const EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_NOTFOUND = 'EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_NOTFOUND'; + public const string EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_NOTFOUND = 'EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_NOTFOUND'; /** * [EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_MISSING_CLASS description] * @var string */ - public const EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_MISSING_CLASS = 'EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_MISSING_CLASS'; + public const string EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_MISSING_CLASS = 'EXCEPTION_CORE_IO_PIPELINE_GETTRANSFORM_MISSING_CLASS'; /** * [EXCEPTION_CORE_IO_PIPELINE_GETTARGET_CONFIG_MISSING_TARGET description] * @var string */ - public const EXCEPTION_CORE_IO_PIPELINE_GETTARGET_CONFIG_MISSING_TARGET = 'EXCEPTION_CORE_IO_PIPELINE_GETTARGET_CONFIG_MISSING_TARGET'; + public const string EXCEPTION_CORE_IO_PIPELINE_GETTARGET_CONFIG_MISSING_TARGET = 'EXCEPTION_CORE_IO_PIPELINE_GETTARGET_CONFIG_MISSING_TARGET'; /** * [EXCEPTION_CORE_IO_PIPELINE_GETTARGET_MISSING_CLASS description] * @var string */ - public const EXCEPTION_CORE_IO_PIPELINE_GETTARGET_MISSING_CLASS = 'EXCEPTION_CORE_IO_PIPELINE_GETTARGET_MISSING_CLASS'; + public const string EXCEPTION_CORE_IO_PIPELINE_GETTARGET_MISSING_CLASS = 'EXCEPTION_CORE_IO_PIPELINE_GETTARGET_MISSING_CLASS'; /** * debug flag * @var bool @@ -97,7 +111,7 @@ class pipeline implements transformerInterface */ protected ?config $options = null; /** - * stores the count of items in the current datasource + * stores the count of items in the current datasource * @var null|int */ protected ?int $itemCount = null; @@ -122,12 +136,12 @@ class pipeline implements transformerInterface */ protected array $targetModelInstances = []; /** - * the bottom limit (start, index) of pipeline source + * the bottom limit (start, index) of a pipeline source * @var null|int */ protected ?int $startIndex = null; /** - * the top limit (end, index) of pipeline source + * the top limit (end, index) of a pipeline source * @var null|int */ protected ?int $endIndex = null; @@ -148,8 +162,8 @@ class pipeline implements transformerInterface protected ?errorstack $errorstack = null; /** * whether to skip erroneous processes - * which means: if any of the target fails/runs into erroneous state - * do not handle the whole source entry it originates from + * that mean: if any of the target fails/runs into erroneous state + * do not handle the whole source entry, it originates from * so neither of the targets gets to really STORE data for this entry. * @var bool */ @@ -253,7 +267,7 @@ public function setDatasource(datasource $datasource): void } // - // If datasource buffering is enabled + // If datasource buffering is enabled, // encapsulate the datasource // if ($this->datasourceBuffering) { @@ -518,7 +532,7 @@ public function run(): void // reset all transforms (cache + errorstack) // this is very important // as we're not performing a multi-value, hash-based in-memory caching - // but instead, simply store the last transform result, respectively + // but instead, store the last transform result, respectively // foreach ($this->transforms as $transform) { $transform->reset(); @@ -641,16 +655,22 @@ public function run(): void // foreach ($errorMap as $map => $mapconfig) { if (isset($erroneous[$mapconfig['field']])) { - $mapped[$map] = $erroneous[$mapconfig['field']] ?? null; // set or null + $mapped[$map] = $erroneous[$mapconfig['field']]; // set or null } elseif ($mapconfig['field'] == 'data') { // $mapped[$map] = $data; $dataUtf8 = []; foreach ($data as $k => $v) { if (mb_check_encoding($k, 'UTF-8') === false) { - $k = utf8_encode($k); + $mbDetectEncoding = mb_detect_encoding($k, ['UTF-8', 'ISO-8859-1', 'ASCII', 'Windows-1252']); + if ($mbDetectEncoding !== false) { + $k = mb_convert_encoding($k, 'UTF-8', $mbDetectEncoding); + } } if (!is_array($v) && mb_check_encoding($v, 'UTF-8') === false) { - $v = utf8_encode($v); + $mbDetectEncoding = mb_detect_encoding($v, ['UTF-8', 'ISO-8859-1', 'ASCII', 'Windows-1252']); + if ($mbDetectEncoding !== false) { + $v = mb_convert_encoding($v, 'UTF-8', $mbDetectEncoding); + } } $dataUtf8[$k] = $v; } @@ -685,7 +705,7 @@ public function run(): void // // CHANGED 2019-07-14: - // tags are now generated/transformed AFTER target pipeline process + // tags are now generated/transformed AFTER a target pipeline process // to get erroneous data, optionally. // if ($targetTags[$targetname] ?? false) { @@ -983,6 +1003,16 @@ public function getTarget(string $name): target return $this->target[$name]; } + /** + * [setTarget description] + * @param string $name [description] + * @param target $target [description] + */ + public function setTarget(string $name, target $target): void + { + $this->target[$name] = $target; + } + /** * rollback all open transactions * @return void @@ -1075,7 +1105,7 @@ public function getErrorstack(): errorstack } /** - * whether to skip erroneous processes + * whether to skip erroneous processes, * which means: if any of the target fails/runs into erroneous state * do not handle the whole source entry it originates from, * so neither of the targets gets to really STORE data for this entry. @@ -1087,7 +1117,7 @@ public function setSkipErroneous(bool $state = true): void } /** - * whether to skip erroneous processes + * whether to skip erroneous processes, * which means: if any of the target fails/runs into erroneous state * do not handle the whole source entry it originates from, * so neither of the targets gets to really STORE data for this entry. @@ -1126,16 +1156,6 @@ public function setDryRun(bool $dryRun = true): void $this->dryRun = $dryRun; } - /** - * [setTarget description] - * @param string $name [description] - * @param target $target [description] - */ - public function setTarget(string $name, target $target): void - { - $this->target[$name] = $target; - } - /** * [getOption description] * @param string $key [description] @@ -1218,7 +1238,7 @@ public function getSpecification(): array /** * get a transform instance * by name - * (has to be already initialized during ->run() ) + * (has to be already initialized during ->run()) * * @param string $name [transform name from config] * @return transform [transform instance] diff --git a/backend/class/process/target/model/update.php b/backend/class/process/target/model/update.php index 562f3bb..7b2fd17 100644 --- a/backend/class/process/target/model/update.php +++ b/backend/class/process/target/model/update.php @@ -4,9 +4,15 @@ use codename\core\app; use codename\core\exception; +use codename\core\helper\deepaccess; use codename\core\io\process\target\model; use ReflectionException; +use function array_slice; +use function count; +use function is_array; +use function print_r; + /** * [update description] */ @@ -25,6 +31,16 @@ public function run(): void if ($filter['value'] && isset($filter['value']['source'])) { if ($filter['value']['source'] == 'transform') { $useValue = $this->getPipelineInstance()->getTransformInstance($filter['value']['field'])->transform(null); + } elseif ($filter['value']['source'] == 'transform_deep') { + $transformField = $filter['value']['field'][0]; + $path = array_slice($filter['value']['field'], 1); + $transformed = $this->getPipelineInstance()->getTransformInstance($transformField)->transform(null); + if (count($path) > 0) { + $useValue = deepaccess::get($transformed, $path); + } else { + // only one object path item specified - transform name itself + $useValue = $transformed; + } } else { throw new exception('EXCEPTION_CORE_IO_PROCESS_TARGET_MODEL_UPDATE_UNSUPPORTED_SOURCE', exception::$ERRORLEVEL_FATAL, $filter); } @@ -41,6 +57,16 @@ public function run(): void $data[$field] = $this->getPipelineInstance()->getOption($dataEntry['field']); } elseif ($dataEntry['source'] == 'transform') { $data[$field] = $this->getPipelineInstance()->getTransformInstance($dataEntry['field'])->transform(null); + } elseif ($dataEntry['source'] == 'transform_deep') { + $transformField = $dataEntry['field'][0]; + $path = array_slice($dataEntry['field'], 1); + $transformed = $this->getPipelineInstance()->getTransformInstance($transformField)->transform(null); + if (count($path) > 0) { + $data[$field] = deepaccess::get($transformed, $path); + } else { + // only one object path item specified - transform name itself + $data[$field] = $transformed; + } } else { throw new exception('EXCEPTION_CORE_IO_PROCESS_TARGET_MODEL_UPDATE_UNSUPPORTED_SOURCE', exception::$ERRORLEVEL_FATAL, [$field, $dataEntry]); } diff --git a/backend/class/progressInterface.php b/backend/class/progressInterface.php index 7cca195..b4ecedd 100644 --- a/backend/class/progressInterface.php +++ b/backend/class/progressInterface.php @@ -3,7 +3,7 @@ namespace codename\core\io; /** - * interface to get the current position (of whatever, e.g. an iterator or so) + * interface to get the current position (of whatever, e.g., an iterator or so) */ interface progressInterface { diff --git a/backend/class/setPipelineInstanceInterface.php b/backend/class/setPipelineInstanceInterface.php index 44ae7c1..cd53e08 100644 --- a/backend/class/setPipelineInstanceInterface.php +++ b/backend/class/setPipelineInstanceInterface.php @@ -3,7 +3,7 @@ namespace codename\core\io; /** - * an interface to enable + * an interface to enable * ->setPipelineInstance() on an object */ interface setPipelineInstanceInterface diff --git a/backend/class/target.php b/backend/class/target.php index e92aa15..41d7952 100644 --- a/backend/class/target.php +++ b/backend/class/target.php @@ -103,9 +103,9 @@ protected static function buildFilterFunctions(array $filters): array } else { // // We want the value to be not equal to a specific value. - // This is the more complicated on. + // This is the more complicated. // By definition, 1!=2, at least for integers. We also perform this for strings. - // But it depends on the personal point of view, if we want the value != 123, + // But it depends on the personal point of view if we want the value != 123, // and we provide NULL. For some RDBMS, this might not be defined. // But we interpret it as a "falsy" value. // The !=NULL case is handled above. @@ -114,7 +114,7 @@ protected static function buildFilterFunctions(array $filters): array // - isset() kicks out the NULLs // - and we simply compare via != later on. // - // filter.value != VALUE + // Filter.value != VALUE $filterFunctions[] = function (array $data) use ($filter) { return (isset($data[$filter['field']]) && $data[$filter['field']] != $filter['value']); }; @@ -136,7 +136,7 @@ protected static function buildFilterFunctions(array $filters): array abstract public function store(array $data): bool; /** - * returns true, if the source filters matches the current dataset + * returns true, if the source filters match the current dataset * (before transforming stuff) * @param array $data [description] * @return bool [description] @@ -154,7 +154,7 @@ public function matchesSourceFilters(array $data): bool } /** - * returns true, if the target filters matches the current dataset + * returns true, if the target filters match the current dataset * (after applying transforms and stuff) * @param array $data [description] * @return bool [description] diff --git a/backend/class/target/buffered.php b/backend/class/target/buffered.php index 6635832..0928b45 100644 --- a/backend/class/target/buffered.php +++ b/backend/class/target/buffered.php @@ -13,8 +13,8 @@ abstract class buffered extends target implements targetStoreTagInterface { /** * Whether this target supports partial write-outs - * (buffer flushing) - * This constant must be overridden in order to use it. + * (buffer flushing), + * This constant must be overridden to use it. * @var bool */ public const SupportsPartialWriteout = false; diff --git a/backend/class/target/buffered/file.php b/backend/class/target/buffered/file.php index 4651438..5f4a413 100644 --- a/backend/class/target/buffered/file.php +++ b/backend/class/target/buffered/file.php @@ -95,7 +95,7 @@ protected function getNewFilePath(): bool|string /** * returns a new file handle for the given filepath - * to be opened in write or append mode + * to be opened in written or append mode * @param string $targetFilePath [description] * @return resource [a file handle resource] * @throws exception diff --git a/backend/class/target/buffered/file/csv.php b/backend/class/target/buffered/file/csv.php index 4ed1d66..31333b3 100644 --- a/backend/class/target/buffered/file/csv.php +++ b/backend/class/target/buffered/file/csv.php @@ -18,12 +18,12 @@ class csv extends file * see https://stackoverflow.com/questions/5601904/encoding-a-string-as-utf-8-with-bom-in-php * @var string */ - public const UTF8_BOM = "\xEF\xBB\xBF"; + public const string UTF8_BOM = "\xEF\xBB\xBF"; /** * This target supports Partial Writeouts (buffer flushing) * @var bool */ - public const SupportsPartialWriteout = true; + public const bool SupportsPartialWriteout = true; /** * the delimiter used in the csv * @var string @@ -83,7 +83,7 @@ class csv extends file protected array $filesCreated = []; /** - * Handle of currently opened file, if any. + * Handle of a currently opened file, if any. * @var resource */ protected $currentFileHandle; @@ -136,7 +136,7 @@ protected function storeBufferedData(): void if ($dataChunkCountOffset > 0) { $partialChunkLeftoverSize = 0; - // leftover space in current chunk + // leftover space in the current chunk if ($this->splitCount) { $partialChunkLeftoverSize = $this->splitCount - $dataChunkCountOffset; } @@ -150,8 +150,8 @@ protected function storeBufferedData(): void $moreChunkableData = array_slice($this->bufferArray, $partialChunkLeftoverSize); if (!empty($moreChunkableData)) { $dataChunks = array_merge( - $dataChunks, - array_chunk($moreChunkableData, $this->splitCount) + $dataChunks, + array_chunk($moreChunkableData, $this->splitCount) ); } } elseif ($this->splitCount && (count($this->bufferArray) > $this->splitCount)) { @@ -205,7 +205,7 @@ protected function storeBufferedData(): void // - // Finalize, tag and create result file path array + // Finalize, tag and create a result file path array // if ($this->finished) { // Close the remaining open file handle. @@ -344,7 +344,7 @@ protected function internalStoreBufferedData($handle, array $bufferArray, bool $ } } else { foreach ($bufferArray as $buffered) { - // linearize assoc array for CSV usage + // linearize an assoc array for CSV usage $dataset = []; foreach ($keys as $k) { $dataset[] = $buffered[$k] ?? null; @@ -365,7 +365,7 @@ protected function internalStoreBufferedData($handle, array $bufferArray, bool $ } // - // WARNING: do not close file handle here. + // WARNING: do not close a file handle here. // CHANGED 2021-08-18: moved to storeBufferedData, for appending data. // fclose($handle); } diff --git a/backend/class/target/buffered/file/json.php b/backend/class/target/buffered/file/json.php index 8dfec68..850376c 100644 --- a/backend/class/target/buffered/file/json.php +++ b/backend/class/target/buffered/file/json.php @@ -142,7 +142,7 @@ protected function internalStoreBufferedData($handle, $bufferArray): void if ($this->templateElementsPath ?? false) { $data = deepaccess::set($data, $this->templateElementsPath, $elements); } else { - $data = $elements; // we could replace? + $data = $elements; // we could replace it? } if ($this->splitCount && count($data) === 1) { diff --git a/backend/class/target/buffered/file/parquet.php b/backend/class/target/buffered/file/parquet.php index 0a425ef..f863047 100644 --- a/backend/class/target/buffered/file/parquet.php +++ b/backend/class/target/buffered/file/parquet.php @@ -162,7 +162,7 @@ protected function getParquetWriter(): ParquetWriter $classesFound = []; foreach ($values as $index => $value) { - // only break out > 100 items, if we have already found ANYTHING + // only break out > 100 items if we have already found ANYTHING if (count($typesFound) > 0) { if ($index > 100) { break; @@ -282,7 +282,7 @@ protected function storeBufferedData(): void $this->writeData($this->bufferArray); } - // finish main writer + // finish the main writer $writer = $this->getParquetWriter(); $writer->finish(); diff --git a/backend/class/target/buffered/file/spreadsheet.php b/backend/class/target/buffered/file/spreadsheet.php index 4cdf36b..b24ea4e 100644 --- a/backend/class/target/buffered/file/spreadsheet.php +++ b/backend/class/target/buffered/file/spreadsheet.php @@ -11,6 +11,7 @@ use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\IOFactory; use PhpOffice\PhpSpreadsheet\Shared\StringHelper; +use Random\RandomException; use ReflectionException; /** @@ -23,7 +24,7 @@ class spreadsheet extends file * May occur when you use multiple mail configurators. * @var string */ - public const EXCEPTION_STOREBUFFERDDATA_COLUMNOTFOUND = 'EXCEPTION_STOREBUFFERDDATA_COLUMNOTFOUND'; + public const string EXCEPTION_STOREBUFFERDDATA_COLUMNOTFOUND = 'EXCEPTION_STOREBUFFERDDATA_COLUMNOTFOUND'; /** * [protected description] * @var string|null [type] @@ -93,7 +94,9 @@ public function __construct(string $name, array $config) /** * {@inheritDoc} + * @throws RandomException * @throws ReflectionException + * @throws \PhpOffice\PhpSpreadsheet\Calculation\Exception * @throws \PhpOffice\PhpSpreadsheet\Exception * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception @@ -158,11 +161,13 @@ protected function storeBufferedData(): void /** * @param $path * @param $bufferArray - * @param $tagsChunk + * @param null $tagsChunk * @return void + * @throws \PhpOffice\PhpSpreadsheet\Calculation\Exception * @throws \PhpOffice\PhpSpreadsheet\Exception * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception + * @throws RandomException */ protected function internalStoreBufferedData($path, $bufferArray, $tagsChunk = null): void { @@ -198,14 +203,14 @@ protected function internalStoreBufferedData($path, $bufferArray, $tagsChunk = n $columnIndexMap[$k] = $columnIndex; } - // produce a heading, if key_row is set to a value + // produce a heading if key_row is set to a value if ($this->key_row) { $worksheet->setCellValue( - [ - $columnIndexMap[$k], - $this->key_row, - ], - ($this->numericIndexes ? ($v['columnName'] ?? $k) : $k) + [ + $columnIndexMap[$k], + $this->key_row, + ], + ($this->numericIndexes ? ($v['columnName'] ?? $k) : $k) ); } @@ -220,20 +225,20 @@ protected function internalStoreBufferedData($path, $bufferArray, $tagsChunk = n foreach ($line as $k => $v) { if ($mapping[$k]['setExplicitString'] ?? false) { $worksheet->setCellValueExplicit( - [ - $columnIndexMap[$k] ?? null, - ($mapping[$k]['row'] ?? $currentRow), - ], - $v, - DataType::TYPE_STRING + [ + $columnIndexMap[$k] ?? null, + ($mapping[$k]['row'] ?? $currentRow), + ], + $v, + DataType::TYPE_STRING ); } else { $worksheet->setCellValue( - [ - $columnIndexMap[$k] ?? null, - ($mapping[$k]['row'] ?? $currentRow), - ], - $v + [ + $columnIndexMap[$k] ?? null, + ($mapping[$k]['row'] ?? $currentRow), + ], + $v ); } @@ -258,7 +263,7 @@ protected function internalStoreBufferedData($path, $bufferArray, $tagsChunk = n ->setLockStructure(true) ->setWorkbookPassword($filePassword); - // Protect sheet + // Protect a sheet $sheetNames = $spreadsheet->getSheetNames(); foreach ($sheetNames as $k => $sheetName) { $sheet = $spreadsheet->getSheet($k); @@ -274,7 +279,7 @@ protected function internalStoreBufferedData($path, $bufferArray, $tagsChunk = n } $writer = IOFactory::createWriter($spreadsheet, $this->use_writer); - // save original state of those settings + // save the original state of those settings $prevDecimalSeparator = null; $prevThousandsSeparator = null; diff --git a/backend/class/target/buffered/file/xml.php b/backend/class/target/buffered/file/xml.php index 92baa70..a1f0705 100644 --- a/backend/class/target/buffered/file/xml.php +++ b/backend/class/target/buffered/file/xml.php @@ -13,6 +13,17 @@ use Sabre\Xml\Service; use Sabre\Xml\Writer; +use function array_chunk; +use function array_fill; +use function array_merge; +use function count; +use function fclose; +use function fwrite; +use function implode; +use function is_array; +use function is_int; +use function libxml_get_errors; + class xml extends file { /** @@ -36,6 +47,10 @@ class xml extends file * @var mixed|null */ protected mixed $template; + /** + * @var mixed|null + */ + protected mixed $attribute; /** * @var mixed|null */ @@ -53,6 +68,7 @@ public function __construct(string $name, array $config) $this->version = $this->config['version'] ?? $this->version; $this->encoding = $this->config['encoding'] ?? $this->encoding; $this->template = $this->config['template'] ?? null; + $this->attribute = $this->config['attribute'] ?? null; $this->templateElementsPath = $this->config['template_elements_path'] ?? null; } @@ -136,12 +152,15 @@ protected function internalStoreBufferedData($handle, $bufferArray): void // pre-work some mapping options foreach ($this->config['mapping'] as $mapName => $mapConfig) { + if (!($v['allow_null'] ?? false) && $bufferEntry[$mapName] === null) { + continue; + } if ($mapConfig['path'] ?? false) { // path is relative base for the map name - $objPath = array_merge($mapConfig['path'], [$mapName]); - $resultData = deepaccess::set($resultData, $objPath, $bufferEntry[$mapName]); + $objPath = ($mapConfig['pathOnly'] ?? false) ? $mapConfig['path'] : array_merge($mapConfig['path'], [$mapName]); + $resultData = deepaccess::set($resultData, $objPath, $bufferEntry[$mapName] ?? null); } else { - $resultData[$mapName] = $bufferEntry[$mapName]; + $resultData[$mapName] = $bufferEntry[$mapName] ?? null; } } @@ -156,11 +175,13 @@ protected function internalStoreBufferedData($handle, $bufferArray): void $data = $this->template; } if ($this->templateElementsPath) { - $data = deepaccess::set($data, $this->templateElementsPath, $elements); + $elementsWithData = array_merge(deepaccess::get($data, $this->templateElementsPath), $elements); + $data = deepaccess::set($data, $this->templateElementsPath, $elementsWithData); } else { - $data = $elements; // we could replace? + $data = $elements; // we could replace it? } + $data = $this->createXmlDataStructureWithAttribute([], $data); $writer->write($data); $xmlString = $writer->outputMemory(); @@ -192,4 +213,29 @@ protected function internalStoreBufferedData($handle, $bufferArray): void fwrite($handle, $xmlString); fclose($handle); } + + /** + * @param array $path + * @param mixed $data + * @return array + */ + private function createXmlDataStructureWithAttribute(array $path, mixed $data): array + { + $return = []; + + foreach ($data as $k => $v) { + if (is_int($k)) { + $return[] = $this->createXmlDataStructureWithAttribute($path, $v); + } else { + $currentPath = array_merge($path, [$k]); + $return[] = [ + 'name' => $k, + 'attributes' => $this->attribute[implode('>', $currentPath)] ?? [], + 'value' => is_array($v) ? $this->createXmlDataStructureWithAttribute($currentPath, $v) : $v, + ]; + } + } + + return $return; + } } diff --git a/backend/class/target/createArchiveTrait.php b/backend/class/target/createArchiveTrait.php index 997b38c..70d9795 100644 --- a/backend/class/target/createArchiveTrait.php +++ b/backend/class/target/createArchiveTrait.php @@ -77,7 +77,7 @@ protected function createArchive(): array // NOTE: localName may have been set (inside archive), so we have to use this, if not null $encTypeConstants = [ - // 'EM_NONE' => \ZipArchive::EM_NONE, // this disables passwords + // 'EM_NONE' => \ZipArchive::EM_NONE, // this disables passwords 'EM_AES_128' => ZipArchive::EM_AES_128, 'EM_AES_192' => ZipArchive::EM_AES_192, 'EM_AES_256' => ZipArchive::EM_AES_256, // the safe way. @@ -102,7 +102,7 @@ protected function createArchive(): array } if ($tags) { // - // Just override the first element so transmission module gets it. + // Override the first element so transmission module gets it. // foreach ($tags as &$tagSet) { $tagSet['file_name'] = $archiveTarget; diff --git a/backend/class/target/model.php b/backend/class/target/model.php index 969761c..592b609 100644 --- a/backend/class/target/model.php +++ b/backend/class/target/model.php @@ -6,6 +6,7 @@ use codename\core\exception; use codename\core\io\target; use codename\core\io\targetModelInterface; +use DateMalformedStringException; use ReflectionException; /** @@ -60,6 +61,7 @@ public function getModel(): \codename\core\model * @param array $data * @return bool * @throws ReflectionException + * @throws DateMalformedStringException * @throws exception */ public function store(array $data): bool diff --git a/backend/class/target/model/complex.php b/backend/class/target/model/complex.php index ae17c70..3549e60 100644 --- a/backend/class/target/model/complex.php +++ b/backend/class/target/model/complex.php @@ -8,14 +8,15 @@ use codename\core\io\target\virtualTargetInterface; use codename\core\io\targetModelInterface; use codename\core\model; +use DateMalformedStringException; use ReflectionException; /** * complex model as a target */ class complex extends target implements - targetModelInterface, - virtualTargetInterface + targetModelInterface, + virtualTargetInterface { /** * target model @@ -122,6 +123,7 @@ public function setVirtualStoreEnabled(bool $state): void * @param array $data * @return bool * @throws ReflectionException + * @throws DateMalformedStringException * @throws exception */ public function store(array $data): bool @@ -208,7 +210,7 @@ public function store(array $data): bool protected function handleStore(model $model, array $data): array { foreach ($model->getNestedCollections() as $collection) { - // work through each entry, modify on need + // work through each entry, modify on a need foreach ($data[$collection->field->get()] as &$subData) { $subData = $this->handleStore($collection->collectionModel, $subData); } diff --git a/backend/class/target/virtual.php b/backend/class/target/virtual.php index 70b324c..07da872 100644 --- a/backend/class/target/virtual.php +++ b/backend/class/target/virtual.php @@ -6,14 +6,15 @@ use codename\core\exception; use codename\core\io\target; use codename\core\io\targetModelInterface; +use DateMalformedStringException; use ReflectionException; /** * virtual target (doesn't save anything) */ class virtual extends target implements - targetModelInterface, - virtualTargetInterface + targetModelInterface, + virtualTargetInterface { /** * [protected description] @@ -87,6 +88,7 @@ public function getVirtualStoreEnabled(): bool * {@inheritDoc} * @param array $data * @return bool + * @throws DateMalformedStringException * @throws exception */ public function store(array $data): bool diff --git a/backend/class/target/xml.php b/backend/class/target/xml.php index 4544b3e..e0ddc97 100644 --- a/backend/class/target/xml.php +++ b/backend/class/target/xml.php @@ -11,7 +11,7 @@ use Sabre\Xml\Writer; /** - * xml file as a target + * XML file as a target */ class xml extends target { @@ -110,7 +110,7 @@ public function store(array $data): bool */ public function finish(): void { - // for xml strings, do nothing? - // for xml files, write them? + // for XML strings, do nothing? + // for XML files, write them? } } diff --git a/backend/class/target/xml/text.php b/backend/class/target/xml/text.php index 34c43be..883e7a1 100644 --- a/backend/class/target/xml/text.php +++ b/backend/class/target/xml/text.php @@ -8,7 +8,7 @@ use ReflectionException; /** - * xml text as a target + * XML text as a target * "string" is a reserved keyword. */ class text extends xml implements textResultArrayInterface diff --git a/backend/class/transform.php b/backend/class/transform.php index ac52d78..bd1da14 100644 --- a/backend/class/transform.php +++ b/backend/class/transform.php @@ -230,7 +230,7 @@ protected function getTransformValue(string $name, mixed $value): mixed public function transform(mixed $value): mixed { if ($this->isCached($value)) { - // use cached transform result + // use a cached transform result return $this->cacheValue; } else { $start = null; @@ -268,7 +268,7 @@ protected function isCached(mixed $parameters): bool /** * internal transformation - * override this method to implement + * overrides this method to implement * the 'real' transform * * @param mixed $value [input value] @@ -279,7 +279,7 @@ abstract public function internalTransform(mixed $value): mixed; /** * sets cache from current value * and the instance's config - * @param mixed $parameters [input parameters - e.g. the current value] + * @param mixed $parameters [input parameters - e.g., the current value] * @param mixed $cacheValue [the to-be-cached value] */ protected function setCacheValue(mixed $parameters, mixed $cacheValue): void diff --git a/backend/class/transform/calculate/subtract.php b/backend/class/transform/calculate/subtract.php index b7c3323..84d0f6e 100644 --- a/backend/class/transform/calculate/subtract.php +++ b/backend/class/transform/calculate/subtract.php @@ -55,7 +55,7 @@ public function internalTransform(mixed $value): mixed continue; } if (is_array($field)) { - // different value source (e.g. transform or source/source_deep) + // different value source (e.g., transform or source/source_deep) $sub = bcsub($sub, $this->getValue($field['source'], $field['field'], $value), $this->precision); } else { // constant value diff --git a/backend/class/transform/calculate/sum.php b/backend/class/transform/calculate/sum.php index dac8c46..a3281c1 100644 --- a/backend/class/transform/calculate/sum.php +++ b/backend/class/transform/calculate/sum.php @@ -47,7 +47,7 @@ public function internalTransform(mixed $value): mixed $sum = 0; foreach ($this->fields as $field) { if (is_array($field)) { - // different value source (e.g. transform or source/source_deep) + // different value source (e.g., transform or source/source_deep) $sum = bcadd($sum, $this->getValue($field['source'], $field['field'], $value), $this->precision); } else { // constant value diff --git a/backend/class/transform/compare.php b/backend/class/transform/compare.php index fc92f5a..9185abb 100644 --- a/backend/class/transform/compare.php +++ b/backend/class/transform/compare.php @@ -5,7 +5,7 @@ use codename\core\io\transform; /** - * base class for comparisons ( ==, !=, >=, >, <, <= ) + * base class for comparisons (==, !=, >=, >, <, <=) */ abstract class compare extends transform { diff --git a/backend/class/transform/compare/datetime.php b/backend/class/transform/compare/datetime.php index 49bc253..e9b1cb6 100644 --- a/backend/class/transform/compare/datetime.php +++ b/backend/class/transform/compare/datetime.php @@ -4,6 +4,7 @@ use codename\core\exception; use codename\core\io\transform; +use DateMalformedStringException; /** * datetime comparison @@ -15,6 +16,7 @@ class datetime extends transform * {@inheritDoc} * @param mixed $value * @return mixed + * @throws DateMalformedStringException * @throws exception */ public function internalTransform(mixed $value): mixed diff --git a/backend/class/transform/compare/isday.php b/backend/class/transform/compare/isday.php index 24cc1ae..7a7b2fc 100644 --- a/backend/class/transform/compare/isday.php +++ b/backend/class/transform/compare/isday.php @@ -4,6 +4,7 @@ use codename\core\exception; use codename\core\io\transform\compare; +use DateMalformedStringException; /** * [isequal description] @@ -14,6 +15,7 @@ class isday extends compare * {@inheritDoc} * @param mixed $value * @return mixed + * @throws DateMalformedStringException * @throws exception */ public function internalTransform(mixed $value): mixed diff --git a/backend/class/transform/compare/isholiday.php b/backend/class/transform/compare/isholiday.php index 48b87bb..07af323 100644 --- a/backend/class/transform/compare/isholiday.php +++ b/backend/class/transform/compare/isholiday.php @@ -5,6 +5,7 @@ use codename\core\app; use codename\core\exception; use codename\core\io\transform\compare; +use DateMalformedStringException; use ReflectionException; /** @@ -17,6 +18,7 @@ class isholiday extends compare * @param mixed $value * @return mixed * @throws ReflectionException + * @throws DateMalformedStringException * @throws exception */ public function internalTransform(mixed $value): mixed diff --git a/backend/class/transform/convert/datetime.php b/backend/class/transform/convert/datetime.php index 4b99bd2..d90ae2c 100644 --- a/backend/class/transform/convert/datetime.php +++ b/backend/class/transform/convert/datetime.php @@ -4,6 +4,7 @@ use codename\core\exception; use codename\core\io\transform\convert; +use DateMalformedStringException; use DateTimeImmutable; /** @@ -93,6 +94,7 @@ public function __construct(array $config) * {@inheritDoc} * @param mixed $value * @return mixed + * @throws DateMalformedStringException * @throws exception */ public function internalTransform(mixed $value): mixed diff --git a/backend/class/transform/convert/numberformat.php b/backend/class/transform/convert/numberformat.php index 7141c43..2317b2f 100644 --- a/backend/class/transform/convert/numberformat.php +++ b/backend/class/transform/convert/numberformat.php @@ -15,7 +15,7 @@ class numberformat extends convert * [EXCEPTION_CORE_IO_TRANSFORM_CONVERT_NUMBERFORMAT_INVALID_TYPE description] * @var string */ - public const EXCEPTION_CORE_IO_TRANSFORM_CONVERT_NUMBERFORMAT_INVALID_TYPE = 'EXCEPTION_CORE_IO_TRANSFORM_CONVERT_NUMBERFORMAT_INVALID_TYPE'; + public const string EXCEPTION_CORE_IO_TRANSFORM_CONVERT_NUMBERFORMAT_INVALID_TYPE = 'EXCEPTION_CORE_IO_TRANSFORM_CONVERT_NUMBERFORMAT_INVALID_TYPE'; /** * [protected description] * @var null|NumberFormatter @@ -48,7 +48,7 @@ public function __construct(array $config) $this->locale = $this->config['locale']; $this->style = $this->config['style']; - // initialize numberformatter, only if locale & style are not arrays/objects + // initialize numberformatter, only if locale and style are not arrays/objects // and therefore static if (!is_array($this->locale) && !is_array($this->style)) { $this->numberFormatter = new NumberFormatter($this->locale, self::getNumberFormatterStyle($this->style)); diff --git a/backend/class/transform/get/conditioned.php b/backend/class/transform/get/conditioned.php index db2baef..7bff227 100644 --- a/backend/class/transform/get/conditioned.php +++ b/backend/class/transform/get/conditioned.php @@ -5,6 +5,8 @@ use codename\core\exception; use codename\core\io\transform\get; +use function is_array; + /** * return a value for specific conditions */ @@ -29,11 +31,21 @@ public function internalTransform(mixed $value): mixed return !is_array($condition['return']) ? $condition['return'] : ($this->getValue($condition['return']['source'], $condition['return']['field'], $value)); } break; + case '===': + if ($comparisonValue === $conditionFieldValue) { + return !is_array($condition['return']) ? $condition['return'] : ($this->getValue($condition['return']['source'], $condition['return']['field'], $value)); + } + break; case '!=': if ($comparisonValue != $conditionFieldValue) { return !is_array($condition['return']) ? $condition['return'] : ($this->getValue($condition['return']['source'], $condition['return']['field'], $value)); } break; + case '!==': + if ($comparisonValue !== $conditionFieldValue) { + return !is_array($condition['return']) ? $condition['return'] : ($this->getValue($condition['return']['source'], $condition['return']['field'], $value)); + } + break; case '>': // NOTE: inverted order if ($comparisonValue < $conditionFieldValue) { diff --git a/backend/class/transform/get/conditioned/all.php b/backend/class/transform/get/conditioned/all.php index b996d9c..04ebea2 100644 --- a/backend/class/transform/get/conditioned/all.php +++ b/backend/class/transform/get/conditioned/all.php @@ -5,6 +5,8 @@ use codename\core\exception; use codename\core\io\transform\get\conditioned; +use function is_array; + class all extends conditioned { /** @@ -20,7 +22,6 @@ public function internalTransform(mixed $value): mixed // apply filter foreach ($this->config['condition'] as $condition) { $conditionFieldValue = $this->getValue($condition['source'], $condition['field'], $value); - // $returnFieldValue = !is_array($condition['return']) ? $condition['return'] : ($this->getValue($condition['return']['source'], $condition['return']['field'], $value)); $comparisonValue = !is_array($condition['value']) ? $condition['value'] : ($this->getValue($condition['value']['source'], $condition['value']['field'], $value)); switch ($condition['operator']) { case '=': @@ -29,23 +30,49 @@ public function internalTransform(mixed $value): mixed break 2; } break; + case '===': + $evalResult &= ($comparisonValue === $conditionFieldValue); + if (!$evalResult) { + break 2; + } + break; case '!=': $evalResult &= ($comparisonValue != $conditionFieldValue); if (!$evalResult) { break 2; } break; + case '!==': + $evalResult &= ($comparisonValue !== $conditionFieldValue); + if (!$evalResult) { + break 2; + } + break; + case '>': + // NOTE: inverted order + $evalResult &= ($comparisonValue < $conditionFieldValue); + if (!$evalResult) { + break 2; + } + break; + case '<': + // NOTE: inverted order + $evalResult &= ($comparisonValue > $conditionFieldValue); + if (!$evalResult) { + break 2; + } + break; default: break; } } if ($evalResult) { - return $this->config['return'] ?? true; + return $this->config['return'] ? !is_array($this->config['return']) ? $this->config['return'] : ($this->getValue($this->config['return']['source'], $this->config['return']['field'], $value)) : true; } // - // if we don't 'return' above + // if we don't 'return' above, // we automatically have a falsy result // if (isset($this->config['required']) && $this->config['required']) { @@ -57,6 +84,18 @@ public function internalTransform(mixed $value): mixed } // no filter match + // + // NOTE: $this->config['default'] MAY be FALSE => this should be the value to return in this case (see below) + // + if ($this->config['default'] ?? false) { + return !is_array($this->config['default']) ? $this->config['default'] : ($this->getValue($this->config['default']['source'], $this->config['default']['field'], $value)); + } + // NULL-coalescing using default value, which also may be null or not set. + // + // default == false => false + // default == null => null + // default undefined => null + // return $this->config['default'] ?? null; } } diff --git a/backend/class/transform/get/currentdatetime.php b/backend/class/transform/get/currentdatetime.php index 79fb3e5..1db99b1 100644 --- a/backend/class/transform/get/currentdatetime.php +++ b/backend/class/transform/get/currentdatetime.php @@ -3,6 +3,7 @@ namespace codename\core\io\transform\get; use codename\core\io\transform\get; +use DateMalformedStringException; use DateTime; /** @@ -12,6 +13,9 @@ class currentdatetime extends get { /** * {@inheritDoc} + * @param mixed $value + * @return mixed + * @throws DateMalformedStringException */ public function internalTransform(mixed $value): mixed { diff --git a/backend/class/transform/get/easterdatetime.php b/backend/class/transform/get/easterdatetime.php index 5f8cf9f..82a207d 100644 --- a/backend/class/transform/get/easterdatetime.php +++ b/backend/class/transform/get/easterdatetime.php @@ -5,6 +5,7 @@ use codename\core\exception; use codename\core\io\transform\get; use DateInterval; +use DateMalformedStringException; use DateTime; use function easter_days; @@ -18,6 +19,7 @@ class easterdatetime extends get * {@inheritDoc} * @param mixed $value * @return mixed + * @throws DateMalformedStringException * @throws exception */ public function internalTransform(mixed $value): mixed diff --git a/backend/class/transform/get/filtered/arrayfilter.php b/backend/class/transform/get/filtered/arrayfilter.php index b04de54..6755e46 100644 --- a/backend/class/transform/get/filtered/arrayfilter.php +++ b/backend/class/transform/get/filtered/arrayfilter.php @@ -23,7 +23,7 @@ public function internalTransform(mixed $value): mixed $path = $this->config['path'] ?? null; $filtered = array_filter($v, function ($element) use ($path, $value) { - // we may retrieve an element's sub-key, if path is defined + // we may retrieve an element's subkey if a path is defined $elementValue = $path ? deepaccess::get($element, $path) : $element; $res = true; diff --git a/backend/class/transform/get/number/whole.php b/backend/class/transform/get/number/whole.php index 25661bd..e650165 100644 --- a/backend/class/transform/get/number/whole.php +++ b/backend/class/transform/get/number/whole.php @@ -5,6 +5,8 @@ use codename\core\exception; use codename\core\io\transform\get\number; +use function explode; + /** * getter for the whole component of a number value */ @@ -34,8 +36,9 @@ public function internalTransform(mixed $value): mixed throw new exception('EXCEPTION_CORE_IO_TRANSFORM_GET_NUMBER_FRACTION_NOT_NUMERIC', exception::$ERRORLEVEL_ERROR, $v); } - [$whole, $decimal] = sscanf($v, '%d.%d'); +// [$whole, $decimal] = sscanf($v, '%d.%d'); + $value = explode('.', $v, 2); - return $whole; + return $value[0] ?? null; } } diff --git a/backend/class/transform/implode.php b/backend/class/transform/implode.php index 80928f8..82df2d9 100644 --- a/backend/class/transform/implode.php +++ b/backend/class/transform/implode.php @@ -59,8 +59,8 @@ public function internalTransform(mixed $value): mixed } elseif ($this->allowConstants) { // // CHANGED/ADDED 2019-07-17 - // supply "allowConstants" : true - // in config to enable using the bare values as array elements + // supply "allowConstants": true + // in config to enable using the bare values as an array elements // instead of trying to retrieve them from the source ($value) // $values[] = $field; diff --git a/backend/class/transform/model.php b/backend/class/transform/model.php index ae1523d..0fc5190 100644 --- a/backend/class/transform/model.php +++ b/backend/class/transform/model.php @@ -6,6 +6,7 @@ use codename\core\exception; use codename\core\io\transform; use codename\core\model\plugin\filter\custom; +use DateMalformedStringException; use ReflectionException; /** @@ -124,11 +125,12 @@ public function getSpecification(): array /** * [doQuery description] * @param mixed $value [description] - * @return array|null [description] + * @return int|array|null [description] * @throws ReflectionException + * @throws DateMalformedStringException * @throws exception */ - protected function doQuery(mixed $value): ?array + protected function doQuery(mixed $value): null|int|array { $this->model->reset(); if ($this->config['filter'] ?? false) { @@ -160,6 +162,31 @@ protected function doQuery(mixed $value): ?array } } + if ($this->config['list_filter'] ?? false) { + foreach ($this->config['list_filter'] as $filter) { + // either use the value directly or get it from the current dataset + if ($filter['value'] && isset($filter['value']['source'])) { + $useValue = $this->getValue($filter['value']['source'], $filter['value']['field'], $value); + if ($useValue == null) { + if ($filter['value']['allow_null'] ?? false) { + // Do nothing + } else { + if ($this->config['required'] ?? false) { + $this->errorstack->addError('VALUE_NULL', 0, [ + 'config' => $this->config, + 'value' => $value, + ]); + } + return null; + } + } + } else { + $useValue = $filter['value']; + } + $this->model->addFilterList($filter['field'], $useValue, $filter['operator']); + } + } + if ($this->config['custom_filter'] ?? false) { foreach ($this->config['custom_filter'] as $customFilter) { // either use the value directly or get it from the current dataset @@ -183,11 +210,11 @@ protected function doQuery(mixed $value): ?array } $filterPlugin = new custom( - \codename\core\value\text\modelfield\dummy::getInstance( - $customFilter['field'] - ), - $useValue, - $customFilter['operator'] + \codename\core\value\text\modelfield\dummy::getInstance( + $customFilter['field'] + ), + $useValue, + $customFilter['operator'] ); $this->model->addFilterPlugin($filterPlugin); } @@ -309,6 +336,10 @@ protected function doQuery(mixed $value): ?array // die(); } + if ($this->config['getCount'] ?? false) { + return $this->model->getCount(); + } + return $this->model->search()->getResult(); } } diff --git a/backend/class/transform/model/map/single.php b/backend/class/transform/model/map/single.php index dceaf23..041f1d6 100644 --- a/backend/class/transform/model/map/single.php +++ b/backend/class/transform/model/map/single.php @@ -4,6 +4,7 @@ use codename\core\exception; use codename\core\io\transform\model\map; +use DateMalformedStringException; use ReflectionException; /** @@ -16,6 +17,7 @@ class single extends map * @param mixed $value * @return mixed * @throws ReflectionException + * @throws DateMalformedStringException * @throws exception */ public function internalTransform(mixed $value): mixed diff --git a/backend/class/transform/model/result/all.php b/backend/class/transform/model/result/all.php index 2f8f6fd..3b4e1a7 100644 --- a/backend/class/transform/model/result/all.php +++ b/backend/class/transform/model/result/all.php @@ -4,6 +4,7 @@ use codename\core\exception; use codename\core\io\transform\model\result; +use DateMalformedStringException; use ReflectionException; /** @@ -16,6 +17,7 @@ class all extends result * @param mixed $value * @return mixed * @throws ReflectionException + * @throws DateMalformedStringException * @throws exception */ public function internalTransform(mixed $value): mixed diff --git a/backend/class/transform/model/result/one.php b/backend/class/transform/model/result/one.php index eb40158..da2f2fd 100644 --- a/backend/class/transform/model/result/one.php +++ b/backend/class/transform/model/result/one.php @@ -4,6 +4,7 @@ use codename\core\exception; use codename\core\io\transform\model\result; +use DateMalformedStringException; use ReflectionException; /** @@ -16,6 +17,7 @@ class one extends result * @param mixed $value * @return mixed * @throws ReflectionException + * @throws DateMalformedStringException * @throws exception */ public function internalTransform(mixed $value): mixed diff --git a/backend/class/transform/model/save.php b/backend/class/transform/model/save.php index d0b5331..94ea7a3 100644 --- a/backend/class/transform/model/save.php +++ b/backend/class/transform/model/save.php @@ -4,6 +4,7 @@ use codename\core\exception; use codename\core\io\transform\model; +use DateMalformedStringException; /** * Calls save() on a model using a given dataset @@ -15,6 +16,7 @@ class save extends model * {@inheritDoc} * @param mixed $value * @return mixed + * @throws DateMalformedStringException * @throws exception */ public function internalTransform(mixed $value): mixed @@ -29,6 +31,7 @@ public function internalTransform(mixed $value): mixed * * @param array $data [description] * @return mixed [type] [description] + * @throws DateMalformedStringException * @throws exception */ protected function doSave(array $data): mixed @@ -41,7 +44,7 @@ protected function doSave(array $data): mixed } if ($pkeyValue = $normalizedData[$this->model->getPrimaryKey()] ?? null) { - // simply return pkey value, as we're doing a save using existing PKEY value + // return pkey value, as we're doing a save using existing PKEY value return $pkeyValue; } elseif (!$this->isDryRun()) { // we can only return an insert ID if we're not in a dry run (see above) diff --git a/backend/class/transform/model/save/onetime.php b/backend/class/transform/model/save/onetime.php index 83839bf..328cde0 100644 --- a/backend/class/transform/model/save/onetime.php +++ b/backend/class/transform/model/save/onetime.php @@ -12,10 +12,10 @@ class onetime extends save { /** - * for this class, we just override the cache reset method + * For this class, we just override the cache reset method * to prevent calling internalTransform over and over again. * - * Instead, when we used the save_onetime transform a single time + * Instead, when we use the save_onetime transform a single time, * it won't do its internal job again. * * This may be used for tracking import jobs or so. diff --git a/backend/class/transform/regex.php b/backend/class/transform/regex.php index 0e1086f..1970be7 100644 --- a/backend/class/transform/regex.php +++ b/backend/class/transform/regex.php @@ -64,7 +64,6 @@ public function internalTransform(mixed $value): mixed $v = $this->getValue($this->config['source'], $this->config['field'], $value); if ($this->mode === 'match' || $this->mode === 'match_success') { - if (!is_string($this->regexValue)) { throw new exception('TRANSFORM_REGEX_REGEX_VALUE_MUST_BE_STRING', exception::$ERRORLEVEL_ERROR); } @@ -95,7 +94,6 @@ public function internalTransform(mixed $value): mixed return null; } } elseif ($this->mode === 'replace') { - if ($this->replaceValue === null) { throw new exception('TRANSFORM_REGEX_REPLACE_VALUE_MUST_BE_STRING', exception::$ERRORLEVEL_ERROR); } diff --git a/backend/class/transformer.php b/backend/class/transformer.php index e46cb96..6a253fd 100644 --- a/backend/class/transformer.php +++ b/backend/class/transformer.php @@ -15,12 +15,12 @@ class transformer implements transformerInterface * [EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_NOTFOUND description] * @var string */ - public const EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_NOTFOUND = 'EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_NOTFOUND'; + public const string EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_NOTFOUND = 'EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_NOTFOUND'; /** * [EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_MISSING_CLASS description] * @var string */ - public const EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_MISSING_CLASS = 'EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_MISSING_CLASS'; + public const string EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_MISSING_CLASS = 'EXCEPTION_CORE_IO_TRANSFORMER_GETTRANSFORM_MISSING_CLASS'; /** * configs of the transforms * @var array @@ -95,16 +95,16 @@ public function addTransform(string $name, array $transformConfig): void public function getAvailableTransformNames(): array { return array_keys( - array_filter($this->transformConfigs, function ($item) { - return !isset($item['internal']) || $item['internal'] === false; - }) + array_filter($this->transformConfigs, function ($item) { + return !isset($item['internal']) || $item['internal'] === false; + }) ); } /** * get a transform instance * by name - * (has to be already initialized during ->run() ) + * (has to be already initialized during ->run()) * * @param string $name [transform name from config] * @return transform [transform instance] diff --git a/composer.json b/composer.json index 914dfa5..182c7e8 100644 --- a/composer.json +++ b/composer.json @@ -16,9 +16,9 @@ "require": { "codename/core": "*", "codename/parquet": "*", - "dompdf/dompdf": "^2.0", - "php": "^8.1", - "phpoffice/phpspreadsheet": "^1.27.0", + "dompdf/dompdf": "^3.0", + "php": "^8.3", + "phpoffice/phpspreadsheet": "^2.1", "sabre/xml": "^4.0" }, "require-dev": { diff --git a/tests/autoload.php b/tests/autoload.php index af0dfd4..519685b 100644 --- a/tests/autoload.php +++ b/tests/autoload.php @@ -4,11 +4,11 @@ * This is a per-project autoloading file * For initializing the local project and enabling it for development purposes * - * you need to build up your fullstack autoloading structure + * You need to build up your fullstack autoloading structure * using composer install / composer update - * e.g. for /composer.json + * e.g., for /composer.json * - * and you need to build a local composer classmap + * And you need to build a local composer classmap * that enables the usage of composer's 'autoload-dev' setting * just for this project * @@ -42,7 +42,7 @@ // // This allows having only a local autoloader and no global one -// (e.g. single-project unit testing) +// (e.g., single-project unit testing) // if (!file_exists($globalBootstrap) && !file_exists($localAutoload)) { die("ERROR: No global bootstrap.cli.php or local vendor/autoloader.php found. You might want to initialize your cross-project or single-project autoloader first." . chr(10)); @@ -58,7 +58,7 @@ overrideableApp::reset(); // -// Special quirk for single-project unit testing +// Special quirk for single-project unit testing, // We need to override the homedir for this app // as the framework itself assumes it resides in composer's vendor dir // diff --git a/tests/datasource/bufferedTest.php b/tests/datasource/bufferedTest.php index 4d2b009..b5a6200 100644 --- a/tests/datasource/bufferedTest.php +++ b/tests/datasource/bufferedTest.php @@ -126,13 +126,13 @@ public function testBufferReadingWithMultipleBufferSizesDynamic(): void public function testSetConfigPassthrough(): void { $source = new csv( - __DIR__ . "/" . 'testcsv2.csv', - [ - 'autodetect_utf8_bom' => true, - 'skip_empty_rows' => true, - 'skip_rows' => 11, // wrong setting - 'encoding' => ['from' => 'UTF-8', 'to' => 'UTF-8'], - ] + __DIR__ . "/" . 'testcsv2.csv', + [ + 'autodetect_utf8_bom' => true, + 'skip_empty_rows' => true, + 'skip_rows' => 11, // wrong setting + 'encoding' => ['from' => 'UTF-8', 'to' => 'UTF-8'], + ] ); $buffered = new buffered($source, 999); diff --git a/tests/datasource/csvTest.php b/tests/datasource/csvTest.php index 3be6dcd..3e9829b 100644 --- a/tests/datasource/csvTest.php +++ b/tests/datasource/csvTest.php @@ -63,13 +63,13 @@ public function testDataSourceIsValid(): void public function testDataSourceNext(): void { $datasource = new csv( - __DIR__ . "/" . 'testcsv2.csv', - [ - 'autodetect_utf8_bom' => true, - 'skip_empty_rows' => true, - 'skip_rows' => 1, - 'encoding' => ['from' => 'UTF-8', 'to' => 'UTF-8'], - ] + __DIR__ . "/" . 'testcsv2.csv', + [ + 'autodetect_utf8_bom' => true, + 'skip_empty_rows' => true, + 'skip_rows' => 1, + 'encoding' => ['from' => 'UTF-8', 'to' => 'UTF-8'], + ] ); $i = 0; @@ -97,13 +97,13 @@ public function testDataSourceNext(): void public function testDataSourceWrongOffset(): void { $datasource = new overriddenCsv( - __DIR__ . "/" . 'testcsv2.csv', - [ - 'autodetect_utf8_bom' => true, - 'skip_empty_rows' => true, - 'skip_rows' => 1, - 'encoding' => ['from' => 'UTF-8', 'to' => 'UTF-8'], - ] + __DIR__ . "/" . 'testcsv2.csv', + [ + 'autodetect_utf8_bom' => true, + 'skip_empty_rows' => true, + 'skip_rows' => 1, + 'encoding' => ['from' => 'UTF-8', 'to' => 'UTF-8'], + ] ); $i = 0; @@ -126,11 +126,11 @@ public function testDataSourceWrongOffset(): void public function testDatasourceCsvWindows1252Decoding(): void { $datasource = new csv( - __DIR__ . "/" . 'csv_windows1252_umlauts.csv', - [ - 'delimiter' => ';', - 'encoding' => ['from' => 'Windows-1252', 'to' => 'UTF-8'], - ] + __DIR__ . "/" . 'csv_windows1252_umlauts.csv', + [ + 'delimiter' => ';', + 'encoding' => ['from' => 'Windows-1252', 'to' => 'UTF-8'], + ] ); $rows = []; diff --git a/tests/datasource/joinedTest.php b/tests/datasource/joinedTest.php index d016f72..58783fd 100644 --- a/tests/datasource/joinedTest.php +++ b/tests/datasource/joinedTest.php @@ -19,32 +19,32 @@ class joinedTest extends TestCase public function testSimpleJoinedCsv(bool $indexesEnabled): void { $joinedDatasource = new joined( - [ - new csv( - __DIR__ . '/joined1_base1.csv', - [ - 'delimiter' => ';', - ] - ), - new csv( - __DIR__ . '/joined1_join1.csv', - [ - 'delimiter' => ';', - ] - ), - ], - [ - // CONFIG! - 'join' => [ - [ - 'index' => $indexesEnabled, - 'base_datasource' => 0, // array index-based - 'join_datasource' => 1, // array index-based - 'base_field' => 'col2', - 'join_field' => 'id2', - ], + [ + new csv( + __DIR__ . '/joined1_base1.csv', + [ + 'delimiter' => ';', + ] + ), + new csv( + __DIR__ . '/joined1_join1.csv', + [ + 'delimiter' => ';', + ] + ), + ], + [ + // CONFIG! + 'join' => [ + [ + 'index' => $indexesEnabled, + 'base_datasource' => 0, // array index-based + 'join_datasource' => 1, // array index-based + 'base_field' => 'col2', + 'join_field' => 'id2', ], - ] + ], + ] ); $res = []; @@ -54,7 +54,7 @@ public function testSimpleJoinedCsv(bool $indexesEnabled): void static::assertCount(6, $res); - // At the time of writing, missing values are not applied to join result datasets + // At the time of writing, missing values are not applied to join result datasets; // therefore, array_column will return fewer values in those cases (stipping out unset values) static::assertEquals(['ABC', 'DEF', 'GHI', 'ABC', /*null,*/ 'GHI'], array_column($res, 'name')); } @@ -69,32 +69,32 @@ public function testSimpleJoinedCsv(bool $indexesEnabled): void public function testSimpleJoinedCsvWithNamedDatasources(bool $indexesEnabled): void { $joinedDatasource = new joined( - [ - 'foo' => new csv( - __DIR__ . '/joined1_base1.csv', - [ - 'delimiter' => ';', - ] - ), - 'bar' => new csv( - __DIR__ . '/joined1_join1.csv', - [ - 'delimiter' => ';', - ] - ), - ], - [ - // CONFIG! - 'join' => [ - [ - 'index' => $indexesEnabled, - 'base_datasource' => 'foo', // key-based - 'join_datasource' => 'bar', // key-based - 'base_field' => 'col2', - 'join_field' => 'id2', - ], + [ + 'foo' => new csv( + __DIR__ . '/joined1_base1.csv', + [ + 'delimiter' => ';', + ] + ), + 'bar' => new csv( + __DIR__ . '/joined1_join1.csv', + [ + 'delimiter' => ';', + ] + ), + ], + [ + // CONFIG! + 'join' => [ + [ + 'index' => $indexesEnabled, + 'base_datasource' => 'foo', // key-based + 'join_datasource' => 'bar', // key-based + 'base_field' => 'col2', + 'join_field' => 'id2', ], - ] + ], + ] ); $res = []; @@ -104,7 +104,7 @@ public function testSimpleJoinedCsvWithNamedDatasources(bool $indexesEnabled): v static::assertCount(6, $res); - // At the time of writing, missing values are not applied to join result datasets + // At the time of writing, missing values are not applied to join result datasets; // therefore, array_column will return fewer values in those cases (stipping out unset values) static::assertEquals(['ABC', 'DEF', 'GHI', 'ABC', /*null,*/ 'GHI'], array_column($res, 'name')); } @@ -119,45 +119,45 @@ public function testSimpleJoinedCsvWithNamedDatasources(bool $indexesEnabled): v public function testMultipleJoinedCsvWithNamedDatasources(bool $indexesEnabled): void { $joinedDatasource = new joined( - [ - 'foo' => new csv( - __DIR__ . '/joined1_base1.csv', - [ - 'delimiter' => ';', - ] - ), - 'bar' => new csv( - __DIR__ . '/joined1_join1.csv', - [ - 'delimiter' => ';', - ] - ), - 'baz' => new csv( - __DIR__ . '/joined1_join2.csv', - [ - 'delimiter' => ';', - ] - ), - ], - [ - // CONFIG! - 'join' => [ - [ - 'index' => $indexesEnabled, - 'base_datasource' => 'foo', // key-based - 'join_datasource' => 'bar', // key-based - 'base_field' => 'col2', - 'join_field' => 'id2', - ], - [ - 'index' => $indexesEnabled, - 'base_datasource' => 'bar', // key-based - 'join_datasource' => 'baz', // key-based - 'base_field' => 'other_id', - 'join_field' => 'join2_id', - ], + [ + 'foo' => new csv( + __DIR__ . '/joined1_base1.csv', + [ + 'delimiter' => ';', + ] + ), + 'bar' => new csv( + __DIR__ . '/joined1_join1.csv', + [ + 'delimiter' => ';', + ] + ), + 'baz' => new csv( + __DIR__ . '/joined1_join2.csv', + [ + 'delimiter' => ';', + ] + ), + ], + [ + // CONFIG! + 'join' => [ + [ + 'index' => $indexesEnabled, + 'base_datasource' => 'foo', // key-based + 'join_datasource' => 'bar', // key-based + 'base_field' => 'col2', + 'join_field' => 'id2', + ], + [ + 'index' => $indexesEnabled, + 'base_datasource' => 'bar', // key-based + 'join_datasource' => 'baz', // key-based + 'base_field' => 'other_id', + 'join_field' => 'join2_id', ], - ] + ], + ] ); $res = []; @@ -167,7 +167,7 @@ public function testMultipleJoinedCsvWithNamedDatasources(bool $indexesEnabled): static::assertCount(6, $res); - // At the time of writing, missing values are not applied to join result datasets + // At the time of writing, missing values are not applied to join result datasets; // therefore, array_column will return fewer values in those cases (stipping out unset values) static::assertEquals(['ABC', 'DEF', 'GHI', 'ABC', /*null,*/ 'GHI'], array_column($res, 'name')); static::assertEquals(['BBB', 'BBB', 'CCC', 'BBB', /*null,*/ 'CCC'], array_column($res, 'value')); @@ -182,58 +182,58 @@ public function testMultipleJoinedCsvWithNamedDatasources(bool $indexesEnabled): public function testMultipleJoinedCsvWithNamedDatasourcesAndAmbiguities(bool $indexesEnabled): void { $joinedDatasource = new joined( - [ - 'foo' => new csv( - __DIR__ . '/joined1_base1.csv', - [ - 'delimiter' => ';', - ] - ), - 'bar' => new csv( - __DIR__ . '/joined1_join1.csv', - [ - 'delimiter' => ';', - ] - ), - 'baz' => new csv( - __DIR__ . '/joined1_join2.csv', - [ - 'delimiter' => ';', - ] - ), - 'qux' => new csv( - __DIR__ . '/joined1_join3.csv', - [ - 'delimiter' => ';', - ] - ), - ], - [ - // CONFIG! - 'join' => [ - [ - 'index' => $indexesEnabled, - 'base_datasource' => 'foo', // key-based - 'join_datasource' => 'bar', // key-based - 'base_field' => 'col2', - 'join_field' => 'id2', - ], - [ - 'index' => $indexesEnabled, - 'base_datasource' => 'bar', // key-based - 'join_datasource' => 'baz', // key-based - 'base_field' => 'other_id', - 'join_field' => 'join2_id', - ], - [ - 'index' => $indexesEnabled, - 'base_datasource' => 'foo', // key-based - 'join_datasource' => 'qux', // key-based - 'base_field' => 'col1', - 'join_field' => 'join3_col1', - ], + [ + 'foo' => new csv( + __DIR__ . '/joined1_base1.csv', + [ + 'delimiter' => ';', + ] + ), + 'bar' => new csv( + __DIR__ . '/joined1_join1.csv', + [ + 'delimiter' => ';', + ] + ), + 'baz' => new csv( + __DIR__ . '/joined1_join2.csv', + [ + 'delimiter' => ';', + ] + ), + 'qux' => new csv( + __DIR__ . '/joined1_join3.csv', + [ + 'delimiter' => ';', + ] + ), + ], + [ + // CONFIG! + 'join' => [ + [ + 'index' => $indexesEnabled, + 'base_datasource' => 'foo', // key-based + 'join_datasource' => 'bar', // key-based + 'base_field' => 'col2', + 'join_field' => 'id2', + ], + [ + 'index' => $indexesEnabled, + 'base_datasource' => 'bar', // key-based + 'join_datasource' => 'baz', // key-based + 'base_field' => 'other_id', + 'join_field' => 'join2_id', ], - ] + [ + 'index' => $indexesEnabled, + 'base_datasource' => 'foo', // key-based + 'join_datasource' => 'qux', // key-based + 'base_field' => 'col1', + 'join_field' => 'join3_col1', + ], + ], + ] ); $res = []; diff --git a/tests/datasource/model/datasourceentry.php b/tests/datasource/model/datasourceentry.php index d7317b0..f94f542 100644 --- a/tests/datasource/model/datasourceentry.php +++ b/tests/datasource/model/datasourceentry.php @@ -6,7 +6,7 @@ /** * SQL Base model leveraging the new model servicing modules - * and enables freely defining and loading model configs + * and enabling freely defining and loading model configs */ class datasourceentry extends sqlModel { diff --git a/tests/datasource/model/datasourceentryj.php b/tests/datasource/model/datasourceentryj.php index 661ff87..b8f7ab5 100644 --- a/tests/datasource/model/datasourceentryj.php +++ b/tests/datasource/model/datasourceentryj.php @@ -6,7 +6,7 @@ /** * SQL Base model leveraging the new model servicing modules - * and enables freely defining and loading model configs + * and enabling freely defining and loading model configs */ class datasourceentryj extends sqlModel { diff --git a/tests/datasource/modelTest.php b/tests/datasource/modelTest.php index 3ad1b85..60a811a 100644 --- a/tests/datasource/modelTest.php +++ b/tests/datasource/modelTest.php @@ -3,12 +3,23 @@ namespace codename\core\io\tests\datasource; use codename\core\exception; +use codename\core\exception\compileErrorException; +use codename\core\exception\coreErrorException; +use codename\core\exception\coreWarningException; +use codename\core\exception\parseException; +use codename\core\exception\recoverableErrorException; +use codename\core\exception\strictException; +use codename\core\exception\userErrorException; +use codename\core\exception\userWarningException; +use codename\core\exception\warningException; use codename\core\io\datasource\model; use codename\core\io\pipeline; use codename\core\io\tests\datasource\model\datasourceentry; use codename\core\io\tests\datasource\model\datasourceentryj; use codename\core\test\base; +use ErrorException; use ReflectionException; +use Throwable; class modelTest extends base { @@ -39,7 +50,7 @@ public function testDatasourceDoubleSetModelWillFail(): void $datasource = new model(); $model = $this->getModel('datasourceentry'); $datasource->setModel($model); - $datasource->setModel($model); // second call should fail + $datasource->setModel($model); // the second call should fail } /** @@ -276,6 +287,17 @@ protected function tearDown(): void /** * {@inheritDoc} * @throws ReflectionException + * @throws ErrorException + * @throws Throwable + * @throws compileErrorException + * @throws coreErrorException + * @throws coreWarningException + * @throws parseException + * @throws recoverableErrorException + * @throws strictException + * @throws userErrorException + * @throws userWarningException + * @throws warningException * @throws exception */ protected function setUp(): void diff --git a/tests/datasource/rawTest.php b/tests/datasource/rawTest.php index 355a871..3cc0085 100644 --- a/tests/datasource/rawTest.php +++ b/tests/datasource/rawTest.php @@ -50,22 +50,22 @@ public function testDataSourceInvalidConfig(): void $this->expectExceptionMessage('CORE_IO_DATASOURCE_INVALID_MAP_CONFIG'); new raw( - __DIR__ . "/" . 'testRaw1.txt', - [ - 'format' => [ - 'trim' => true, - 'convert' => [ - 'from' => 'ASCII', - 'to' => 'UTF-8', - ], - 'map' => [ - 'field1' => [ - 'type' => 'wrong', - 'length' => 10, - ], + __DIR__ . "/" . 'testRaw1.txt', + [ + 'format' => [ + 'trim' => true, + 'convert' => [ + 'from' => 'ASCII', + 'to' => 'UTF-8', + ], + 'map' => [ + 'field1' => [ + 'type' => 'wrong', + 'length' => 10, ], ], - ] + ], + ] ); } @@ -77,30 +77,30 @@ public function testDataSourceInvalidConfig(): void public function testDataSourceIsValid(): void { $datasource = new raw( - __DIR__ . "/" . 'testRaw1.txt', - [ - 'format' => [ - 'trim' => true, - 'convert' => [ - 'from' => 'ASCII', - 'to' => 'UTF-8', + __DIR__ . "/" . 'testRaw1.txt', + [ + 'format' => [ + 'trim' => true, + 'convert' => [ + 'from' => 'ASCII', + 'to' => 'UTF-8', + ], + 'map' => [ + 'field1' => [ + 'type' => 'fixed', + 'length' => 10, ], - 'map' => [ - 'field1' => [ - 'type' => 'fixed', - 'length' => 10, - ], - 'field2' => [ - 'type' => 'fixed', - 'length' => 10, - ], - 'field3' => [ - 'type' => 'fixed', - 'length' => 10, - ], + 'field2' => [ + 'type' => 'fixed', + 'length' => 10, + ], + 'field3' => [ + 'type' => 'fixed', + 'length' => 10, ], ], - ] + ], + ] ); $datasource->next(); @@ -120,60 +120,60 @@ public function testDataSourceIsValid(): void public function testDataSourceIsValidWithMappings(): void { $datasource = new raw( - __DIR__ . "/" . 'testRaw1.txt', - [ - 'format' => [ - 'trim' => true, - 'map' => [ - 'key' => [ - 'type' => 'fixed', - 'length' => 5, - ], + __DIR__ . "/" . 'testRaw1.txt', + [ + 'format' => [ + 'trim' => true, + 'map' => [ + 'key' => [ + 'type' => 'fixed', + 'length' => 5, ], ], - 'mappings' => [ - 'key' => [ - 'col11' => [ - 'trim' => true, - 'map' => [ - 'field1' => [ - 'type' => 'fixed', - 'length' => 10, - ], - 'field2' => [ - 'type' => 'fixed', - 'length' => 10, - ], - 'field3' => [ - 'type' => 'fixed', - 'length' => 10, - ], + ], + 'mappings' => [ + 'key' => [ + 'col11' => [ + 'trim' => true, + 'map' => [ + 'field1' => [ + 'type' => 'fixed', + 'length' => 10, + ], + 'field2' => [ + 'type' => 'fixed', + 'length' => 10, + ], + 'field3' => [ + 'type' => 'fixed', + 'length' => 10, ], ], - 'col12' => [ - 'trim' => true, - 'convert' => [ - 'from' => 'ASCII', - 'to' => 'UTF-8', + ], + 'col12' => [ + 'trim' => true, + 'convert' => [ + 'from' => 'ASCII', + 'to' => 'UTF-8', + ], + 'map' => [ + 'field1' => [ + 'type' => 'fixed', + 'length' => 10, + ], + 'field2' => [ + 'type' => 'fixed', + 'length' => 10, ], - 'map' => [ - 'field1' => [ - 'type' => 'fixed', - 'length' => 10, - ], - 'field2' => [ - 'type' => 'fixed', - 'length' => 10, - ], - 'field3' => [ - 'type' => 'fixed', - 'length' => 10, - ], + 'field3' => [ + 'type' => 'fixed', + 'length' => 10, ], ], ], ], - ] + ], + ] ); $datasource->next(); @@ -204,26 +204,26 @@ public function testDataSourceIsValidWithMappings(): void public function testDataSourceNext(): void { $datasource = new raw( - __DIR__ . "/" . 'testRaw1.txt', - [ - 'format' => [ - 'trim' => true, - 'map' => [ - 'field1' => [ - 'type' => 'fixed', - 'length' => 10, - ], - 'field2' => [ - 'type' => 'fixed', - 'length' => 10, - ], - 'field3' => [ - 'type' => 'fixed', - 'length' => 10, - ], + __DIR__ . "/" . 'testRaw1.txt', + [ + 'format' => [ + 'trim' => true, + 'map' => [ + 'field1' => [ + 'type' => 'fixed', + 'length' => 10, + ], + 'field2' => [ + 'type' => 'fixed', + 'length' => 10, + ], + 'field3' => [ + 'type' => 'fixed', + 'length' => 10, ], ], - ] + ], + ] ); $i = 0; diff --git a/tests/datasource/remapTest.php b/tests/datasource/remapTest.php index 7411f2a..6d4e1e1 100644 --- a/tests/datasource/remapTest.php +++ b/tests/datasource/remapTest.php @@ -20,14 +20,14 @@ public function testRemapGeneral(): void $datasource = new arraydata(); $datasource->setData($this->getTestData()); $remappedDatasource = new remap( - $datasource, - [ - 'remap' => [ - 'oldkey1' => 'newkey1', - 'oldkey2' => 'newkey2', - 'oldkey3' => 'newkey3', - ], - ] + $datasource, + [ + 'remap' => [ + 'oldkey1' => 'newkey1', + 'oldkey2' => 'newkey2', + 'oldkey3' => 'newkey3', + ], + ] ); // rewind the datasources @@ -86,15 +86,15 @@ public function testRemapDatasource(): void $datasource = new arraydata(); $datasource->setData($this->getTestData()); $remappedDatasource = new remap( - $datasource, - [ - 'remap' => [ - 'oldkey1' => 'newkey1', - 'oldkey2' => 'newkey2', - 'oldkey3' => 'newkey3', - 'oldkey4' => ['newarraykey1', 'newarraykey2'], - ], - ] + $datasource, + [ + 'remap' => [ + 'oldkey1' => 'newkey1', + 'oldkey2' => 'newkey2', + 'oldkey3' => 'newkey3', + 'oldkey4' => ['newarraykey1', 'newarraykey2'], + ], + ] ); $comparisonDatasource = new arraydata(); @@ -121,8 +121,8 @@ public function testRemapDatasource(): void } /** - * tests outputting a dataset based on the input - * e.g. the remapped values are put ON TOP of the input (or replaced) + * tests outputting a dataset based on the input, + * e.g., the remapped values are put ON TOP of the input (or replaced) * @return void */ public function testRemapReplaceSourceInclusion(): void @@ -131,16 +131,16 @@ public function testRemapReplaceSourceInclusion(): void $datasource->setData($this->getTestData()); $remappedDatasource = new remap( - $datasource, - [ - 'remap' => [ - 'oldkey1' => 'newkey1', - 'oldkey2' => 'newkey2', - 'oldkey3' => 'newkey3', - ], - // the relevant config key - 'replace' => true, - ] + $datasource, + [ + 'remap' => [ + 'oldkey1' => 'newkey1', + 'oldkey2' => 'newkey2', + 'oldkey3' => 'newkey3', + ], + // the relevant config key + 'replace' => true, + ] ); $originalDatasource = new arraydata(); @@ -149,14 +149,14 @@ public function testRemapReplaceSourceInclusion(): void $tempDatasource = new arraydata(); $tempDatasource->setData($this->getTestData()); $normalRemappedDatasource = new remap( - $tempDatasource, - [ - 'remap' => [ - 'oldkey1' => 'newkey1', - 'oldkey2' => 'newkey2', - 'oldkey3' => 'newkey3', - ], - ] + $tempDatasource, + [ + 'remap' => [ + 'oldkey1' => 'newkey1', + 'oldkey2' => 'newkey2', + 'oldkey3' => 'newkey3', + ], + ] ); // rewind the datasources @@ -184,7 +184,7 @@ public function testRemapReplaceSourceInclusion(): void static::assertEquals($value, $remappedDataset[$key]); } - // Don't forget to move the iterator + // Remember to move the iterator $remappedDatasource->next(); $originalDatasource->next(); $normalRemappedDatasource->next(); @@ -205,15 +205,15 @@ public function testRemapSourceDataKey(): void $sourceDataKey = 'original'; $remappedDatasource = new remap( - $datasource, - [ - 'remap' => [ - 'oldkey1' => 'newkey1', - 'oldkey2' => 'newkey2', - 'oldkey3' => 'newkey3', - ], - 'source_data_key' => $sourceDataKey, - ] + $datasource, + [ + 'remap' => [ + 'oldkey1' => 'newkey1', + 'oldkey2' => 'newkey2', + 'oldkey3' => 'newkey3', + ], + 'source_data_key' => $sourceDataKey, + ] ); $comparisonDatasource = new arraydata(); @@ -232,7 +232,7 @@ public function testRemapSourceDataKey(): void $originalDataset = $comparisonDatasource->current(); static::assertEquals($remappedDataset[$sourceDataKey], $originalDataset); - // Don't forget to move the iterator + // Remember to move the iterator $remappedDatasource->next(); $comparisonDatasource->next(); diff --git a/tests/datasource/spreadsheetTest.php b/tests/datasource/spreadsheetTest.php index 1947d73..c384030 100644 --- a/tests/datasource/spreadsheetTest.php +++ b/tests/datasource/spreadsheetTest.php @@ -45,13 +45,13 @@ public function testSpreadsheetGeneral(): void public function testDataSourceIsValid(): void { $datasource = new spreadsheet( - __DIR__ . "/" . 'testSpreadsheet1.xlsx', - [ - 'custom_sheet_index' => 0, - 'multisheet' => 0, - 'skip_rows' => 3, - 'header_row' => 2, - ] + __DIR__ . "/" . 'testSpreadsheet1.xlsx', + [ + 'custom_sheet_index' => 0, + 'multisheet' => 0, + 'skip_rows' => 3, + 'header_row' => 2, + ] ); $datasource->next(); @@ -71,13 +71,13 @@ public function testDataSourceIsValid(): void public function testDataSourceIsValidWithXls(): void { $datasource = new spreadsheet( - __DIR__ . "/" . 'testSpreadsheet1.xls', - [ - 'custom_sheet_index' => 0, - 'multisheet' => 0, - 'skip_rows' => 3, - 'header_row' => 2, - ] + __DIR__ . "/" . 'testSpreadsheet1.xls', + [ + 'custom_sheet_index' => 0, + 'multisheet' => 0, + 'skip_rows' => 3, + 'header_row' => 2, + ] ); $datasource->next(); @@ -97,11 +97,11 @@ public function testDataSourceIsValidWithXls(): void public function testDataSourceNext(): void { $datasource = new spreadsheet( - __DIR__ . "/" . 'testSpreadsheet1.xlsx', - [ - 'skip_rows' => 1, - 'header_row' => 2, - ] + __DIR__ . "/" . 'testSpreadsheet1.xlsx', + [ + 'skip_rows' => 1, + 'header_row' => 2, + ] ); $i = 0; @@ -127,13 +127,13 @@ public function testDataSourceNext(): void public function testDataSourceMulti(): void { $datasource = new spreadsheet( - __DIR__ . "/" . 'testSpreadsheet3.xlsx', - [ - 'multisheet' => true, - 'custom_sheet_index' => 1, - 'skip_rows' => 3, - 'header_row' => 2, - ] + __DIR__ . "/" . 'testSpreadsheet3.xlsx', + [ + 'multisheet' => true, + 'custom_sheet_index' => 1, + 'skip_rows' => 3, + 'header_row' => 2, + ] ); $i = 0; diff --git a/tests/datasource/xmlTest.php b/tests/datasource/xmlTest.php index 38b1128..3483518 100644 --- a/tests/datasource/xmlTest.php +++ b/tests/datasource/xmlTest.php @@ -9,22 +9,22 @@ class xmlTest extends TestCase { /** - * tests general function of the xml datasource + * tests general function of the XML datasource * @return void [type] [description] * @throws Exception */ public function testXmlGeneral(): void { $datasource = new xml( - __DIR__ . "/" . 'testXml1.xml', - [ - 'xpath_query' => '/example/data', - 'xpath_mapping' => [ - 'field1' => 'field1', - 'field2' => 'field2', - 'field3' => 'field3', - ], - ] + __DIR__ . "/" . 'testXml1.xml', + [ + 'xpath_query' => '/example/data', + 'xpath_mapping' => [ + 'field1' => 'field1', + 'field2' => 'field2', + 'field3' => 'field3', + ], + ] ); static::assertEquals('0', $datasource->currentProgressPosition()); @@ -38,22 +38,22 @@ public function testXmlGeneral(): void } /** - * test a simple xml file + * test a simple XML file * @return void [type] [description] * @throws Exception */ public function testDataSourceIsValid(): void { $datasource = new xml( - __DIR__ . "/" . 'testXml1.xml', - [ - 'xpath_query' => '/example/data', - 'xpath_mapping' => [ - 'field1' => 'field1', - 'field2' => 'field2', - 'field3' => 'field3', - ], - ] + __DIR__ . "/" . 'testXml1.xml', + [ + 'xpath_query' => '/example/data', + 'xpath_mapping' => [ + 'field1' => 'field1', + 'field2' => 'field2', + 'field3' => 'field3', + ], + ] ); $datasource->next(); @@ -75,15 +75,15 @@ public function testDataSourceIsValid(): void public function testDataSourceNext(): void { $datasource = new xml( - __DIR__ . "/" . 'testXml1.xml', - [ - 'xpath_query' => '/example/data', - 'xpath_mapping' => [ - 'field1' => 'field1', - 'field2' => 'field2', - 'field3' => 'field3', - ], - ] + __DIR__ . "/" . 'testXml1.xml', + [ + 'xpath_query' => '/example/data', + 'xpath_mapping' => [ + 'field1' => 'field1', + 'field2' => 'field2', + 'field3' => 'field3', + ], + ] ); $i = 0; diff --git a/tests/helper/model/helperjmodel.php b/tests/helper/model/helperjmodel.php index 6f31c63..2f5886b 100644 --- a/tests/helper/model/helperjmodel.php +++ b/tests/helper/model/helperjmodel.php @@ -6,7 +6,7 @@ /** * SQL Base model leveraging the new model servicing modules - * and enables freely defining and loading model configs + * and enabling freely defining and loading model configs * BTW: helperjmodel means "helpermodel join sample" */ class helperjmodel extends sqlModel diff --git a/tests/helper/model/helpermodel.php b/tests/helper/model/helpermodel.php index 705d5b2..0c3c8a9 100644 --- a/tests/helper/model/helpermodel.php +++ b/tests/helper/model/helpermodel.php @@ -6,7 +6,7 @@ /** * SQL Base model leveraging the new model servicing modules - * and enables freely defining and loading model configs + * and enabling freely defining and loading model configs */ class helpermodel extends sqlModel { diff --git a/tests/helper/pipelineTest.php b/tests/helper/pipelineTest.php index 1f8cd45..09fc2ae 100644 --- a/tests/helper/pipelineTest.php +++ b/tests/helper/pipelineTest.php @@ -3,12 +3,23 @@ namespace codename\core\io\tests\helper; use codename\core\exception; +use codename\core\exception\compileErrorException; +use codename\core\exception\coreErrorException; +use codename\core\exception\coreWarningException; +use codename\core\exception\parseException; +use codename\core\exception\recoverableErrorException; +use codename\core\exception\strictException; +use codename\core\exception\userErrorException; +use codename\core\exception\userWarningException; +use codename\core\exception\warningException; use codename\core\io\helper\pipeline; use codename\core\io\tests\helper\model\helperjmodel; use codename\core\io\tests\helper\model\helpermodel; use codename\core\test\base; use codename\core\test\overrideableApp; +use ErrorException; use ReflectionException; +use Throwable; class pipelineTest extends base { @@ -229,6 +240,17 @@ protected function tearDown(): void /** * {@inheritDoc} * @throws ReflectionException + * @throws ErrorException + * @throws Throwable + * @throws compileErrorException + * @throws coreErrorException + * @throws coreWarningException + * @throws parseException + * @throws recoverableErrorException + * @throws strictException + * @throws userErrorException + * @throws userWarningException + * @throws warningException * @throws exception */ protected function setUp(): void diff --git a/tests/pipeline/abstractPipelineTest.php b/tests/pipeline/abstractPipelineTest.php index 35fa275..52feaf3 100644 --- a/tests/pipeline/abstractPipelineTest.php +++ b/tests/pipeline/abstractPipelineTest.php @@ -3,11 +3,22 @@ namespace codename\core\io\tests\pipeline; use codename\core\exception; +use codename\core\exception\compileErrorException; +use codename\core\exception\coreErrorException; +use codename\core\exception\coreWarningException; +use codename\core\exception\parseException; +use codename\core\exception\recoverableErrorException; +use codename\core\exception\strictException; +use codename\core\exception\userErrorException; +use codename\core\exception\userWarningException; +use codename\core\exception\warningException; use codename\core\io\tests\pipeline\model\pipelinemodel; use codename\core\response\cli; use codename\core\test\base; use codename\core\test\overrideableApp; +use ErrorException; use ReflectionException; +use Throwable; abstract class abstractPipelineTest extends base { @@ -43,6 +54,17 @@ protected function tearDown(): void /** * {@inheritDoc} * @throws ReflectionException + * @throws ErrorException + * @throws Throwable + * @throws compileErrorException + * @throws coreErrorException + * @throws coreWarningException + * @throws parseException + * @throws recoverableErrorException + * @throws strictException + * @throws userErrorException + * @throws userWarningException + * @throws warningException * @throws exception */ protected function setUp(): void @@ -106,12 +128,12 @@ protected function setUp(): void ]); static::createModel( - 'pipelinetest', - 'pipelinemodel', - pipelinemodel::$staticConfig, - function ($schema, $model, $config) { - return new pipelinemodel([]); - } + 'pipelinetest', + 'pipelinemodel', + pipelinemodel::$staticConfig, + function ($schema, $model, $config) { + return new pipelinemodel([]); + } ); static::architect('pipelinetest', 'codename', 'test'); diff --git a/tests/pipeline/genericPipelineTest.php b/tests/pipeline/genericPipelineTest.php index 97cbcda..86fa52b 100644 --- a/tests/pipeline/genericPipelineTest.php +++ b/tests/pipeline/genericPipelineTest.php @@ -112,20 +112,20 @@ public function testPipeline(): void $data = $target->getVirtualStoreData(); static::assertCount(1, $data); static::assertEquals( - [ - 'simple_text' => 'ABC', - 'padded_simple_text' => '#######ABC', - 'padded_simple_text_deep' => '#######ABC', - 'source_array_all' => ['A', 'B', 'C'], - 'source_array_by_index' => 'B', - 'source_array_by_key' => 'v2', - 'transform_array_by_key' => 'Y', - 'raw' => $original, - 'constant_value' => 'Foo', - 'constant_value_arrayid' => 'Foo', - 'constant_path' => 'Bar', - ], - $data[0] + [ + 'simple_text' => 'ABC', + 'padded_simple_text' => '#######ABC', + 'padded_simple_text_deep' => '#######ABC', + 'source_array_all' => ['A', 'B', 'C'], + 'source_array_by_index' => 'B', + 'source_array_by_key' => 'v2', + 'transform_array_by_key' => 'Y', + 'raw' => $original, + 'constant_value' => 'Foo', + 'constant_value_arrayid' => 'Foo', + 'constant_path' => 'Bar', + ], + $data[0] ); } } diff --git a/tests/pipeline/model/pipelinemodel.php b/tests/pipeline/model/pipelinemodel.php index f8c50ff..51145b1 100644 --- a/tests/pipeline/model/pipelinemodel.php +++ b/tests/pipeline/model/pipelinemodel.php @@ -6,7 +6,7 @@ /** * SQL Base model leveraging the new model servicing modules - * and enables freely defining and loading model configs + * and enabling freely defining and loading model configs */ class pipelinemodel extends sqlModel { diff --git a/tests/pipeline/pipelineModelTargetTest.php b/tests/pipeline/pipelineModelTargetTest.php index c5ff428..5fe91ed 100644 --- a/tests/pipeline/pipelineModelTargetTest.php +++ b/tests/pipeline/pipelineModelTargetTest.php @@ -129,7 +129,7 @@ public function testPipelinePreviewRollback(): void $pipeline->setDatasource($datasource); - // Non-dryrun, but preview (rollback at end) + // Non-dryrun, but preview (rollback at the end) $pipeline->setDryRun(false); $pipeline->setOptions(['preview' => true]); diff --git a/tests/pipelineTest.php b/tests/pipelineTest.php index 71c0a71..cc08365 100644 --- a/tests/pipelineTest.php +++ b/tests/pipelineTest.php @@ -3,6 +3,15 @@ namespace codename\core\io\tests; use codename\core\exception; +use codename\core\exception\compileErrorException; +use codename\core\exception\coreErrorException; +use codename\core\exception\coreWarningException; +use codename\core\exception\parseException; +use codename\core\exception\recoverableErrorException; +use codename\core\exception\strictException; +use codename\core\exception\userErrorException; +use codename\core\exception\userWarningException; +use codename\core\exception\warningException; use codename\core\io\datasource\arraydata; use codename\core\io\datasource\buffered; use codename\core\io\datasource\model; @@ -10,7 +19,9 @@ use codename\core\io\tests\pipeline\model\pipelinemodel; use codename\core\test\base; use codename\core\test\overrideableApp; +use ErrorException; use ReflectionException; +use Throwable; class pipelineTest extends base { @@ -222,50 +233,50 @@ public function testSpecification(): void $pipeline = new pipeline('tests/testPipeline2.json', []); static::assertEquals( - [ - 'target.example.example1' => [ - 'type' => 'target.mapping', - 'source' => ['transform.example1'], - ], - 'target.example.example2' => [ - 'type' => 'target.mapping', - 'source' => ['transform.example2'], - ], - 'target.example.example3' => [ - 'type' => 'target.mapping', - 'source' => ['transform.example3'], - ], - 'target.example' => [ - 'type' => 'target', - 'source' => ['target.example.example1', 'target.example.example2', 'target.example.example3'], - ], - 'transform.example1' => [ - 'type' => 'transform', - 'source' => [], - ], - 'transform.example2' => [ - 'type' => 'transform', - 'source' => ['model.pipelinemodel'], - ], - 'transform.example3' => [ - 'type' => 'transform', - 'source' => ['source.example3'], - ], - 'model.pipelinemodel' => [ - 'type' => 'model', - ], - 'source.example3' => [ - 'type' => 'source', - ], - 'erroneous.erroneous' => [ - 'type' => 'erroneous', - ], - 'erroneous.data' => [ - 'type' => 'erroneous', - ], + [ + 'target.example.example1' => [ + 'type' => 'target.mapping', + 'source' => ['transform.example1'], ], - $pipeline->getSpecification(), - json_encode($pipeline->getSpecification()) + 'target.example.example2' => [ + 'type' => 'target.mapping', + 'source' => ['transform.example2'], + ], + 'target.example.example3' => [ + 'type' => 'target.mapping', + 'source' => ['transform.example3'], + ], + 'target.example' => [ + 'type' => 'target', + 'source' => ['target.example.example1', 'target.example.example2', 'target.example.example3'], + ], + 'transform.example1' => [ + 'type' => 'transform', + 'source' => [], + ], + 'transform.example2' => [ + 'type' => 'transform', + 'source' => ['model.pipelinemodel'], + ], + 'transform.example3' => [ + 'type' => 'transform', + 'source' => ['source.example3'], + ], + 'model.pipelinemodel' => [ + 'type' => 'model', + ], + 'source.example3' => [ + 'type' => 'source', + ], + 'erroneous.erroneous' => [ + 'type' => 'erroneous', + ], + 'erroneous.data' => [ + 'type' => 'erroneous', + ], + ], + $pipeline->getSpecification(), + json_encode($pipeline->getSpecification()) ); } @@ -286,6 +297,17 @@ protected function tearDown(): void /** * {@inheritDoc} * @throws ReflectionException + * @throws ErrorException + * @throws Throwable + * @throws compileErrorException + * @throws coreErrorException + * @throws coreWarningException + * @throws parseException + * @throws recoverableErrorException + * @throws strictException + * @throws userErrorException + * @throws userWarningException + * @throws warningException * @throws exception */ protected function setUp(): void @@ -346,12 +368,12 @@ protected function setUp(): void ]); static::createModel( - 'pipelinetest', - 'pipelinemodel', - pipelinemodel::$staticConfig, - function ($schema, $model, $config) { - return new pipelinemodel([]); - } + 'pipelinetest', + 'pipelinemodel', + pipelinemodel::$staticConfig, + function ($schema, $model, $config) { + return new pipelinemodel([]); + } ); static::architect('pipelinetest', 'codename', 'test'); diff --git a/tests/process/target/model/abstractProcessTargetModelTest.php b/tests/process/target/model/abstractProcessTargetModelTest.php index 45db849..3c24302 100644 --- a/tests/process/target/model/abstractProcessTargetModelTest.php +++ b/tests/process/target/model/abstractProcessTargetModelTest.php @@ -3,12 +3,23 @@ namespace codename\core\io\tests\process\target\model; use codename\core\exception; +use codename\core\exception\compileErrorException; +use codename\core\exception\coreErrorException; +use codename\core\exception\coreWarningException; +use codename\core\exception\parseException; +use codename\core\exception\recoverableErrorException; +use codename\core\exception\strictException; +use codename\core\exception\userErrorException; +use codename\core\exception\userWarningException; +use codename\core\exception\warningException; use codename\core\io\tests\process\target\model\model\processmodel; use codename\core\response\cli; use codename\core\test\base; use codename\core\test\overrideableApp; +use ErrorException; use PDOException; use ReflectionException; +use Throwable; abstract class abstractProcessTargetModelTest extends base { @@ -53,6 +64,17 @@ protected function tearDown(): void /** * {@inheritDoc} * @throws ReflectionException + * @throws ErrorException + * @throws Throwable + * @throws compileErrorException + * @throws coreErrorException + * @throws coreWarningException + * @throws parseException + * @throws recoverableErrorException + * @throws strictException + * @throws userErrorException + * @throws userWarningException + * @throws warningException * @throws exception */ protected function setUp(): void @@ -116,12 +138,12 @@ protected function setUp(): void ]); static::createModel( - 'processtest', - 'processmodel', - processmodel::$staticConfig, - function ($schema, $model, $config) { - return new processmodel([]); - } + 'processtest', + 'processmodel', + processmodel::$staticConfig, + function ($schema, $model, $config) { + return new processmodel([]); + } ); static::architect('processtest', 'codename', 'test'); diff --git a/tests/process/target/model/model/processmodel.php b/tests/process/target/model/model/processmodel.php index 8361403..510d9af 100644 --- a/tests/process/target/model/model/processmodel.php +++ b/tests/process/target/model/model/processmodel.php @@ -6,7 +6,7 @@ /** * SQL Base model leveraging the new model servicing modules - * and enables freely defining and loading model configs + * and enabling freely defining and loading model configs */ class processmodel extends sqlModel { diff --git a/tests/process/target/model/updateTest.php b/tests/process/target/model/updateTest.php index e7daee3..c4f168e 100644 --- a/tests/process/target/model/updateTest.php +++ b/tests/process/target/model/updateTest.php @@ -6,6 +6,7 @@ use codename\core\io\datasource\arraydata; use codename\core\io\pipeline; use codename\core\io\process\target\model\update; +use DateMalformedStringException; use LogicException; use ReflectionException; @@ -16,6 +17,7 @@ class updateTest extends abstractProcessTargetModelTest { /** * [testProcessUpdateWithConstantValueFilterAndConstantData description] + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -68,6 +70,7 @@ public function testProcessUpdateWithConstantValueFilterAndConstantData(): void /** * [testProcessUpdateWithConstantValueFilterAndOptionData description] + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -124,6 +127,7 @@ public function testProcessUpdateWithConstantValueFilterAndOptionData(): void /** * [testProcessUpdateWithTransformValueFilterAndTransformData description] * @throws ReflectionException + * @throws DateMalformedStringException * @throws exception */ public function testProcessUpdateWithTransformValueFilterAndTransformData(): void diff --git a/tests/target/buffered/file/CsvBufferingAndSplittingWriteReadTest.php b/tests/target/buffered/file/CsvBufferingAndSplittingWriteReadTest.php index f8ef3b2..3248a13 100644 --- a/tests/target/buffered/file/CsvBufferingAndSplittingWriteReadTest.php +++ b/tests/target/buffered/file/CsvBufferingAndSplittingWriteReadTest.php @@ -160,18 +160,18 @@ protected function getWriteReadTargetInstance(array $configOverride = []): targe // and re-read them using multicsv // return new csv( - 'csv_buffer_and_split', - array_replace([ - 'delimiter' => ';', - 'buffer_size' => 2, - 'split_count' => 3, - 'mapping' => [ - 'key1' => [], - 'key2' => [], - 'key3' => [], - 'key4' => [], - ], - ], $configOverride) + 'csv_buffer_and_split', + array_replace([ + 'delimiter' => ';', + 'buffer_size' => 2, + 'split_count' => 3, + 'mapping' => [ + 'key1' => [], + 'key2' => [], + 'key3' => [], + 'key4' => [], + ], + ], $configOverride) ); } @@ -193,7 +193,7 @@ protected function readTargetData(target $target): array $filepaths[] = $file->get(); } - // for asserting amount of output files... + // for asserting number of output files... $this->createdOutputFileCount = count($files); $datasource = new multicsv($filepaths, [ diff --git a/tests/target/buffered/file/parquetBufferedWriteReadTest.php b/tests/target/buffered/file/parquetBufferedWriteReadTest.php index d1fded9..7606e9f 100644 --- a/tests/target/buffered/file/parquetBufferedWriteReadTest.php +++ b/tests/target/buffered/file/parquetBufferedWriteReadTest.php @@ -98,17 +98,17 @@ protected function cleanupTarget(target $target): void protected function getWriteReadTargetInstance(array $configOverride = []): target { return new parquet( - 'parquet_test', - array_replace([ - 'buffer' => true, - 'buffer_size' => 2, - 'mapping' => [ - 'key1' => ['php_type' => 'string'], - 'key2' => ['php_type' => 'integer'], - 'key3' => ['php_type' => 'double'], - 'key4' => ['php_type' => 'string', 'is_nullable' => true], - ], - ], $configOverride) + 'parquet_test', + array_replace([ + 'buffer' => true, + 'buffer_size' => 2, + 'mapping' => [ + 'key1' => ['php_type' => 'string'], + 'key2' => ['php_type' => 'integer'], + 'key3' => ['php_type' => 'double'], + 'key4' => ['php_type' => 'string', 'is_nullable' => true], + ], + ], $configOverride) ); } @@ -138,8 +138,8 @@ protected function readTargetData(target $target): array class overriddenParquetTarget extends parquet { /** - * public access to ::writeData for simulating special kinds - * of parquet files (e.g. writing empty RGs/data pages) + * public access to ":: writeData" for simulating special kinds + * of parquet files (e.g., writing empty RGs/data pages) * @param array $data [description] * @return void * @throws ParquetException diff --git a/tests/target/buffered/file/parquetWriteReadTest.php b/tests/target/buffered/file/parquetWriteReadTest.php index 491423b..86e73d6 100644 --- a/tests/target/buffered/file/parquetWriteReadTest.php +++ b/tests/target/buffered/file/parquetWriteReadTest.php @@ -138,8 +138,8 @@ public function testExtraExplicitDatatypes(): void * @throws exception */ protected function compareData( - target $target, - array $samples + target $target, + array $samples ): void { $result = $this->readTargetData($target); static::assertCount(count($samples), $result); @@ -192,15 +192,15 @@ protected function readTargetData(target $target): array protected function getWriteReadTargetInstance(array $configOverride = []): target { return new parquet( - 'parquet_test', - array_replace([ - 'mapping' => [ - 'key1' => ['php_type' => 'string'], - 'key2' => ['php_type' => 'integer'], - 'key3' => ['php_type' => 'double'], - 'key4' => ['php_type' => 'string', 'is_nullable' => true], - ], - ], $configOverride) + 'parquet_test', + array_replace([ + 'mapping' => [ + 'key1' => ['php_type' => 'string'], + 'key2' => ['php_type' => 'integer'], + 'key3' => ['php_type' => 'double'], + 'key4' => ['php_type' => 'string', 'is_nullable' => true], + ], + ], $configOverride) ); } diff --git a/tests/target/buffered/file/rawTest.php b/tests/target/buffered/file/rawTest.php index 542aeb8..6908724 100644 --- a/tests/target/buffered/file/rawTest.php +++ b/tests/target/buffered/file/rawTest.php @@ -3,10 +3,21 @@ namespace codename\core\io\tests\target\buffered\file; use codename\core\exception; +use codename\core\exception\compileErrorException; +use codename\core\exception\coreErrorException; +use codename\core\exception\coreWarningException; +use codename\core\exception\parseException; +use codename\core\exception\recoverableErrorException; +use codename\core\exception\strictException; +use codename\core\exception\userErrorException; +use codename\core\exception\userWarningException; +use codename\core\exception\warningException; use codename\core\io\datasource\raw; use codename\core\test\base; use codename\core\test\overrideableApp; +use ErrorException; use ReflectionException; +use Throwable; class rawTest extends base { @@ -145,6 +156,17 @@ public function testPaddingRight(): void /** * {@inheritDoc} * @throws ReflectionException + * @throws ErrorException + * @throws Throwable + * @throws compileErrorException + * @throws coreErrorException + * @throws coreWarningException + * @throws parseException + * @throws recoverableErrorException + * @throws strictException + * @throws userErrorException + * @throws userWarningException + * @throws warningException * @throws exception */ protected function setUp(): void diff --git a/tests/target/buffered/file/spreadsheetTest.php b/tests/target/buffered/file/spreadsheetTest.php index d1d492a..a38ea3e 100644 --- a/tests/target/buffered/file/spreadsheetTest.php +++ b/tests/target/buffered/file/spreadsheetTest.php @@ -3,10 +3,21 @@ namespace codename\core\io\tests\target\buffered\file; use codename\core\exception; +use codename\core\exception\compileErrorException; +use codename\core\exception\coreErrorException; +use codename\core\exception\coreWarningException; +use codename\core\exception\parseException; +use codename\core\exception\recoverableErrorException; +use codename\core\exception\strictException; +use codename\core\exception\userErrorException; +use codename\core\exception\userWarningException; +use codename\core\exception\warningException; use codename\core\io\datasource\spreadsheet; use codename\core\test\base; use codename\core\test\overrideableApp; +use ErrorException; use ReflectionException; +use Throwable; class spreadsheetTest extends base { @@ -177,6 +188,17 @@ public function testCsvConfig(): void /** * {@inheritDoc} * @throws ReflectionException + * @throws ErrorException + * @throws Throwable + * @throws compileErrorException + * @throws coreErrorException + * @throws coreWarningException + * @throws parseException + * @throws recoverableErrorException + * @throws strictException + * @throws userErrorException + * @throws userWarningException + * @throws warningException * @throws exception */ protected function setUp(): void diff --git a/tests/target/buffered/fileTest.php b/tests/target/buffered/fileTest.php index 687be79..c01eda2 100644 --- a/tests/target/buffered/fileTest.php +++ b/tests/target/buffered/fileTest.php @@ -74,7 +74,7 @@ public function getFileHandle() /** * returns a new file handle for the given filepath - * to be opened in write or append mode + * to be opened in written or append mode * @param string $targetFilePath [description] * @return resource [a file handle resource] * @throws exception diff --git a/tests/target/filterTest.php b/tests/target/filterTest.php index 0ddcd70..542d668 100644 --- a/tests/target/filterTest.php +++ b/tests/target/filterTest.php @@ -6,7 +6,7 @@ use PHPUnit\Framework\TestCase; /** - * Tests target & source filters + * Tests target and source filters */ class filterTest extends TestCase { diff --git a/tests/target/model/complexTest.php b/tests/target/model/complexTest.php index e1bf1ba..2d65ae4 100644 --- a/tests/target/model/complexTest.php +++ b/tests/target/model/complexTest.php @@ -3,11 +3,23 @@ namespace codename\core\io\tests\target\model; use codename\core\exception; +use codename\core\exception\compileErrorException; +use codename\core\exception\coreErrorException; +use codename\core\exception\coreWarningException; +use codename\core\exception\parseException; +use codename\core\exception\recoverableErrorException; +use codename\core\exception\strictException; +use codename\core\exception\userErrorException; +use codename\core\exception\userWarningException; +use codename\core\exception\warningException; use codename\core\io\datasource\model; use codename\core\io\target\model\complex; use codename\core\test\base; +use DateMalformedStringException; +use ErrorException; use PDOException; use ReflectionException; +use Throwable; class complexTest extends base { @@ -51,6 +63,7 @@ public function testGeneral(): void /** * @return void + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -84,6 +97,7 @@ public function testTargetStoreSimple(): void /** * @return void + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -124,6 +138,7 @@ public function testTargetStoreSimpleVirtual(): void /** * @return void + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -168,6 +183,7 @@ public function testTargetStoreChildrenSimpleVirtual(): void /** * @return void + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -210,6 +226,7 @@ public function testTargetReplaceStoreSimpleVirtual(): void /** * @return void + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -244,6 +261,7 @@ public function testTargetReplaceStoreSimpleWithoutUnique(): void /** * @return void + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -322,6 +340,7 @@ public function testTargetStoreByUniqueVirtual(): void /** * @return void * @throws ReflectionException + * @throws DateMalformedStringException * @throws exception */ public function testTargetStoreByUnique(): void @@ -370,6 +389,7 @@ public function testTargetStoreByUnique(): void /** * @return void + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -403,6 +423,7 @@ public function testTargetStoreBySingularUniqueWillFail(): void /** * @return void + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -437,6 +458,7 @@ public function testTargetStoreByMultipleUniqueWillFail(): void /** * @return void + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -504,6 +526,17 @@ protected function tearDown(): void /** * {@inheritDoc} * @throws ReflectionException + * @throws ErrorException + * @throws Throwable + * @throws compileErrorException + * @throws coreErrorException + * @throws coreWarningException + * @throws parseException + * @throws recoverableErrorException + * @throws strictException + * @throws userErrorException + * @throws userWarningException + * @throws warningException * @throws exception */ protected function setUp(): void @@ -557,21 +590,21 @@ protected function setUp(): void ]); static::createModel( - 'targettest', - 'testmodel', - testmodel::$staticConfig, - function ($schema, $model, $config) { - return new testmodel([]); - } + 'targettest', + 'testmodel', + testmodel::$staticConfig, + function ($schema, $model, $config) { + return new testmodel([]); + } ); static::createModel( - 'targettest', - 'testmodelj', - testmodelj::$staticConfig, - function ($schema, $model, $config) { - return new testmodelj([]); - } + 'targettest', + 'testmodelj', + testmodelj::$staticConfig, + function ($schema, $model, $config) { + return new testmodelj([]); + } ); static::architect('targettest', 'codename', 'test'); diff --git a/tests/target/model/testmodel.php b/tests/target/model/testmodel.php index 7b42d8a..482632f 100644 --- a/tests/target/model/testmodel.php +++ b/tests/target/model/testmodel.php @@ -6,7 +6,7 @@ /** * SQL Base model leveraging the new model servicing modules - * and enables freely defining and loading model configs + * and enabling freely defining and loading model configs */ class testmodel extends sqlModel { diff --git a/tests/target/model/testmodelj.php b/tests/target/model/testmodelj.php index a2a07f9..147d98b 100644 --- a/tests/target/model/testmodelj.php +++ b/tests/target/model/testmodelj.php @@ -6,7 +6,7 @@ /** * SQL Base model leveraging the new model servicing modules - * and enables freely defining and loading model configs + * and enabling freely defining and loading model configs */ class testmodelj extends sqlModel { diff --git a/tests/target/modelTest.php b/tests/target/modelTest.php index 70782b7..d7050b5 100644 --- a/tests/target/modelTest.php +++ b/tests/target/modelTest.php @@ -3,11 +3,23 @@ namespace codename\core\io\tests\target; use codename\core\exception; +use codename\core\exception\compileErrorException; +use codename\core\exception\coreErrorException; +use codename\core\exception\coreWarningException; +use codename\core\exception\parseException; +use codename\core\exception\recoverableErrorException; +use codename\core\exception\strictException; +use codename\core\exception\userErrorException; +use codename\core\exception\userWarningException; +use codename\core\exception\warningException; use codename\core\io\datasource\model; use codename\core\io\tests\target\model\testmodel; use codename\core\test\base; +use DateMalformedStringException; +use ErrorException; use PDOException; use ReflectionException; +use Throwable; class modelTest extends base { @@ -28,6 +40,7 @@ public static function tearDownAfterClass(): void /** * @return void + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -53,6 +66,7 @@ public function testTargetStoreSimple(): void /** * [testTargetStoreByUnique description] + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -94,6 +108,7 @@ public function testTargetStoreByUnique(): void /** * [testTargetStoreByUniqueWillFail description] + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -119,6 +134,7 @@ public function testTargetStoreBySingularUniqueWillFail(): void /** * [testTargetStoreByMultipleUniqueWillFail description] + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -146,6 +162,7 @@ public function testTargetStoreByMultipleUniqueWillFail(): void /** * [testTargetStoreReadUsingDatasource description] * @throws ReflectionException + * @throws DateMalformedStringException * @throws exception */ public function testTargetStoreReadUsingDatasource(): void @@ -204,6 +221,17 @@ protected function tearDown(): void /** * {@inheritDoc} * @throws ReflectionException + * @throws ErrorException + * @throws Throwable + * @throws compileErrorException + * @throws coreErrorException + * @throws coreWarningException + * @throws parseException + * @throws recoverableErrorException + * @throws strictException + * @throws userErrorException + * @throws userWarningException + * @throws warningException * @throws exception */ protected function setUp(): void @@ -258,12 +286,12 @@ protected function setUp(): void ]); static::createModel( - 'targettest', - 'testmodel', - testmodel::$staticConfig, - function ($schema, $model, $config) { - return new testmodel([]); - } + 'targettest', + 'testmodel', + testmodel::$staticConfig, + function ($schema, $model, $config) { + return new testmodel([]); + } ); static::architect('targettest', 'codename', 'test'); diff --git a/tests/target/virtualTest.php b/tests/target/virtualTest.php index f2646b4..1331ed2 100644 --- a/tests/target/virtualTest.php +++ b/tests/target/virtualTest.php @@ -3,11 +3,23 @@ namespace codename\core\io\tests\target; use codename\core\exception; +use codename\core\exception\compileErrorException; +use codename\core\exception\coreErrorException; +use codename\core\exception\coreWarningException; +use codename\core\exception\parseException; +use codename\core\exception\recoverableErrorException; +use codename\core\exception\strictException; +use codename\core\exception\userErrorException; +use codename\core\exception\userWarningException; +use codename\core\exception\warningException; use codename\core\io\target\virtual; use codename\core\io\tests\target\model\testmodel; use codename\core\model; use codename\core\test\base; +use DateMalformedStringException; +use ErrorException; use ReflectionException; +use Throwable; /** * [virtualTest description] @@ -31,6 +43,7 @@ public static function tearDownAfterClass(): void /** * @return void + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -103,6 +116,7 @@ public function testVirtualWrongModel(): void /** * [testVirtualFinishedError description] * @throws ReflectionException + * @throws DateMalformedStringException * @throws exception */ public function testVirtualFinishedError(): void @@ -142,6 +156,17 @@ protected function tearDown(): void /** * {@inheritDoc} * @throws ReflectionException + * @throws ErrorException + * @throws Throwable + * @throws compileErrorException + * @throws coreErrorException + * @throws coreWarningException + * @throws parseException + * @throws recoverableErrorException + * @throws strictException + * @throws userErrorException + * @throws userWarningException + * @throws warningException * @throws exception */ protected function setUp(): void diff --git a/tests/target/xml/textTest.php b/tests/target/xml/textTest.php index f785c2b..a68c6bc 100644 --- a/tests/target/xml/textTest.php +++ b/tests/target/xml/textTest.php @@ -14,7 +14,7 @@ class textTest extends base /** * [testXmlCase1 description] * @throws ReflectionException - * @throws ParseException + * @throws parseException * @throws exception */ public function testXmlCase1(): void @@ -46,12 +46,12 @@ public function testXmlCase1(): void foreach ($xmlResults as $kXml => $vXml) { $sampleValues = array_values($samples[$k]); static::assertEquals( + $sampleValues[$kXml], + $vXml['value'], + print_r([ $sampleValues[$kXml], $vXml['value'], - print_r([ - $sampleValues[$kXml], - $vXml['value'], - ], true) + ], true) ); } } @@ -87,7 +87,7 @@ protected function getSampleData(): array /** * [testXmlCase2 description] - * @throws ParseException + * @throws parseException * @throws ReflectionException * @throws exception */ @@ -119,12 +119,12 @@ public function testXmlCase2(): void foreach ($xmlResults as $kXml => $vXml) { $sampleValues = array_values($samples[$k]); static::assertEquals( + $sampleValues[$kXml], + $vXml['value'], + print_r([ $sampleValues[$kXml], $vXml['value'], - print_r([ - $sampleValues[$kXml], - $vXml['value'], - ], true) + ], true) ); } } diff --git a/tests/transform/abstractTransformTest.php b/tests/transform/abstractTransformTest.php index fb53cb3..317f3ed 100644 --- a/tests/transform/abstractTransformTest.php +++ b/tests/transform/abstractTransformTest.php @@ -3,12 +3,23 @@ namespace codename\core\io\tests\transform; use codename\core\app; +use codename\core\exception\compileErrorException; +use codename\core\exception\coreErrorException; +use codename\core\exception\coreWarningException; +use codename\core\exception\parseException; +use codename\core\exception\recoverableErrorException; +use codename\core\exception\strictException; +use codename\core\exception\userErrorException; +use codename\core\exception\userWarningException; +use codename\core\exception\warningException; use codename\core\io\transform; use codename\core\io\transformerInterface; use codename\core\test\base; use codename\core\test\overrideableApp; +use ErrorException; use Exception; use ReflectionException; +use Throwable; /** * [testRemap description] @@ -38,6 +49,17 @@ public function getTransformInstance(string $name): transform /** * {@inheritDoc} * @throws ReflectionException + * @throws ErrorException + * @throws Throwable + * @throws compileErrorException + * @throws coreErrorException + * @throws coreWarningException + * @throws parseException + * @throws recoverableErrorException + * @throws strictException + * @throws userErrorException + * @throws userWarningException + * @throws warningException * @throws \codename\core\exception */ protected function setUp(): void diff --git a/tests/transform/calculate/divideTest.php b/tests/transform/calculate/divideTest.php index daab5b3..a2c77e7 100644 --- a/tests/transform/calculate/divideTest.php +++ b/tests/transform/calculate/divideTest.php @@ -46,11 +46,11 @@ public function testSpecification(): void 'precision' => 2, ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field1'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field1'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/calculate/multiplyTest.php b/tests/transform/calculate/multiplyTest.php index 57a2fa6..3ac016a 100644 --- a/tests/transform/calculate/multiplyTest.php +++ b/tests/transform/calculate/multiplyTest.php @@ -46,11 +46,11 @@ public function testSpecification(): void 'precision' => 2, ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field1'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field1'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/calculate/subtractTest.php b/tests/transform/calculate/subtractTest.php index 8e00402..91f2439 100644 --- a/tests/transform/calculate/subtractTest.php +++ b/tests/transform/calculate/subtractTest.php @@ -46,11 +46,11 @@ public function testSpecification(): void 'precision' => 2, ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field1'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field1'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/calculate/sumTest.php b/tests/transform/calculate/sumTest.php index e3cc60e..8af71b2 100644 --- a/tests/transform/calculate/sumTest.php +++ b/tests/transform/calculate/sumTest.php @@ -44,11 +44,11 @@ public function testSpecification(): void 'precision' => 2, ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field1'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field1'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/compare/beginswithTest.php b/tests/transform/compare/beginswithTest.php index 83dae7a..929ca90 100644 --- a/tests/transform/compare/beginswithTest.php +++ b/tests/transform/compare/beginswithTest.php @@ -40,11 +40,11 @@ public function testSpecification(): void 'value' => 'example_source_field', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/compare/datetimeTest.php b/tests/transform/compare/datetimeTest.php index 15e8f2a..315c5fd 100644 --- a/tests/transform/compare/datetimeTest.php +++ b/tests/transform/compare/datetimeTest.php @@ -107,11 +107,11 @@ public function testSpecification(): void 'value' => 'example_source_field', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['TODO_SPEC'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['TODO_SPEC'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/compare/isdayTest.php b/tests/transform/compare/isdayTest.php index 0028654..1bb55f9 100644 --- a/tests/transform/compare/isdayTest.php +++ b/tests/transform/compare/isdayTest.php @@ -59,11 +59,11 @@ public function testSpecification(): void 'value' => 1, ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/compare/isequalTest.php b/tests/transform/compare/isequalTest.php index 0464ce6..aa0bbea 100644 --- a/tests/transform/compare/isequalTest.php +++ b/tests/transform/compare/isequalTest.php @@ -40,11 +40,11 @@ public function testSpecification(): void 'value' => 1, ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/compare/isholidayTest.php b/tests/transform/compare/isholidayTest.php index 84e0c2c..b6e5c11 100644 --- a/tests/transform/compare/isholidayTest.php +++ b/tests/transform/compare/isholidayTest.php @@ -3,10 +3,21 @@ namespace codename\core\io\tests\transform\compare; use codename\core\exception; +use codename\core\exception\compileErrorException; +use codename\core\exception\coreErrorException; +use codename\core\exception\coreWarningException; +use codename\core\exception\parseException; +use codename\core\exception\recoverableErrorException; +use codename\core\exception\strictException; +use codename\core\exception\userErrorException; +use codename\core\exception\userWarningException; +use codename\core\exception\warningException; use codename\core\io\tests\transform\abstractTransformTest; use codename\core\io\tests\transform\compare\model\holidays; use codename\core\test\overrideableApp; +use ErrorException; use ReflectionException; +use Throwable; class isholidayTest extends abstractTransformTest { @@ -107,11 +118,11 @@ public function testSpecification(): void ], ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_country_field', 'source.example_date_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_country_field', 'source.example_date_field'], + ], + $transform->getSpecification() ); } @@ -129,12 +140,25 @@ protected function tearDown(): void /** * {@inheritDoc} + * @throws compileErrorException + * @throws coreErrorException + * @throws coreWarningException + * @throws ErrorException + * @throws parseException + * @throws recoverableErrorException + * @throws ReflectionException + * @throws strictException + * @throws Throwable + * @throws userErrorException + * @throws userWarningException + * @throws warningException + * @throws exception */ protected function setUp(): void { $app = static::createApp(); - // Don't forget to inject core-io + // Remember to inject core-io overrideableApp::__injectApp([ 'vendor' => 'codename', 'app' => 'core-io', diff --git a/tests/transform/compare/model/holidays.php b/tests/transform/compare/model/holidays.php index cea271a..65f3b91 100644 --- a/tests/transform/compare/model/holidays.php +++ b/tests/transform/compare/model/holidays.php @@ -6,7 +6,7 @@ /** * SQL Base model leveraging the new model servicing modules - * and enables freely defining and loading model configs + * and enabling freely defining and loading model configs */ class holidays extends sqlModel { @@ -38,9 +38,9 @@ public function __construct(array $modeldata = []) 'holidays_country' => 'text', 'holidays_orderitemcommission_type' => 'text', 'holidays_check_date' => 'text_timestamp', - // 'holidays_day_type' => 'number_natural', - // 'holidays_type' => 'boolean', - // 'holidays_type_name' => 'text', + // 'holidays_day_type' => 'number_natural', + // 'holidays_type' => 'boolean', + // 'holidays_type_name' => 'text', 'holidays_can_change' => 'boolean', ], 'connection' => 'default', diff --git a/tests/transform/compare/numberTest.php b/tests/transform/compare/numberTest.php index f359400..26770e2 100644 --- a/tests/transform/compare/numberTest.php +++ b/tests/transform/compare/numberTest.php @@ -202,11 +202,11 @@ public function testSpecification(): void 'precision' => 2, ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/containsTest.php b/tests/transform/containsTest.php index 4f43e8a..4fba6b9 100644 --- a/tests/transform/containsTest.php +++ b/tests/transform/containsTest.php @@ -98,11 +98,11 @@ public function testSpecification(): void 'item' => ['source' => 'source', 'field' => 'example_item_source_field'], ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_item_source_field', 'source.example_collection_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_item_source_field', 'source.example_collection_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/convert/booleanTest.php b/tests/transform/convert/booleanTest.php index a09ad18..fea94c2 100644 --- a/tests/transform/convert/booleanTest.php +++ b/tests/transform/convert/booleanTest.php @@ -213,11 +213,11 @@ public function testSpecification(): void 'field' => 'example_source_field', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/convert/datetimeTest.php b/tests/transform/convert/datetimeTest.php index aed2aa0..b8f2eff 100644 --- a/tests/transform/convert/datetimeTest.php +++ b/tests/transform/convert/datetimeTest.php @@ -226,11 +226,11 @@ public function testSpecification(): void 'target_format' => 'd.m.Y H:i:s', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/convert/encodingTest.php b/tests/transform/convert/encodingTest.php index b705ee9..55899c7 100644 --- a/tests/transform/convert/encodingTest.php +++ b/tests/transform/convert/encodingTest.php @@ -82,11 +82,11 @@ public function testSpecification(): void 'field' => 'example_source_field', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/convert/jsonTest.php b/tests/transform/convert/jsonTest.php index ff2f71d..9e3c98a 100644 --- a/tests/transform/convert/jsonTest.php +++ b/tests/transform/convert/jsonTest.php @@ -98,11 +98,11 @@ public function testSpecification(): void 'mode' => 'encode', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/convert/numberformatTest.php b/tests/transform/convert/numberformatTest.php index 9467633..b5fb9ab 100644 --- a/tests/transform/convert/numberformatTest.php +++ b/tests/transform/convert/numberformatTest.php @@ -208,11 +208,11 @@ public function testSpecification(): void 'locale' => 'de-DE', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/countTest.php b/tests/transform/countTest.php index 9b868c4..0fced1c 100644 --- a/tests/transform/countTest.php +++ b/tests/transform/countTest.php @@ -55,11 +55,11 @@ public function testSpecification(): void 'field' => 'example_source_field', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/deepaccessTest.php b/tests/transform/deepaccessTest.php index fc0de8c..39bc7bc 100644 --- a/tests/transform/deepaccessTest.php +++ b/tests/transform/deepaccessTest.php @@ -34,7 +34,7 @@ public function testValueIsNull(): void { $transform = $this->getTransform('deepaccess', [ 'source' => 'source', - // 'field' => 'example_source_field', + // 'field' => 'example_source_field', 'required' => true, ]); $result = $transform->transform([ diff --git a/tests/transform/explodeTest.php b/tests/transform/explodeTest.php index bbeecfb..a7365cf 100644 --- a/tests/transform/explodeTest.php +++ b/tests/transform/explodeTest.php @@ -43,7 +43,7 @@ public function testCustomDelimiter(): void } /** - * Tests explode behaviour, if there is no delimiter match + * Tests explode behavior if there is no delimiter match * @throws ReflectionException * @throws exception */ @@ -81,7 +81,7 @@ public function testMulticharDelimiter(): void } /** - * Tests max. amount of exploded items + * Tests max. number of exploded items * @throws ReflectionException * @throws exception */ @@ -135,11 +135,11 @@ public function testSpecification(): void 'field' => 'example_source_field', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/get/arraycolumnTest.php b/tests/transform/get/arraycolumnTest.php index e290468..fa737fc 100644 --- a/tests/transform/get/arraycolumnTest.php +++ b/tests/transform/get/arraycolumnTest.php @@ -108,11 +108,11 @@ public function testSpecification(): void 'index' => 'example', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/get/arrayvalueTest.php b/tests/transform/get/arrayvalueTest.php index acbb629..4efac6d 100644 --- a/tests/transform/get/arrayvalueTest.php +++ b/tests/transform/get/arrayvalueTest.php @@ -160,11 +160,11 @@ public function testSpecification(): void 'index' => 'example', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/get/conditionedTest.php b/tests/transform/get/conditionedTest.php index 9c1836f..222db3f 100644 --- a/tests/transform/get/conditionedTest.php +++ b/tests/transform/get/conditionedTest.php @@ -271,14 +271,14 @@ public function testFuzzed(): void ]); static::assertEquals( - $test['matches'], - $result, - 'Comparing ' - . var_export($test['input'], true) - . $test['operator'] - . var_export($test['compare'], true) - . ' to be ' - . var_export((bool)$test['matches'], true) + $test['matches'], + $result, + 'Comparing ' + . var_export($test['input'], true) + . $test['operator'] + . var_export($test['compare'], true) + . ' to be ' + . var_export((bool)$test['matches'], true) ); } } @@ -302,11 +302,11 @@ public function testSpecification(): void ], ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/get/currentdatetimeTest.php b/tests/transform/get/currentdatetimeTest.php index b17819d..ee916a1 100644 --- a/tests/transform/get/currentdatetimeTest.php +++ b/tests/transform/get/currentdatetimeTest.php @@ -4,6 +4,7 @@ use codename\core\exception; use codename\core\io\tests\transform\abstractTransformTest; +use DateMalformedStringException; use DateTime; use ReflectionException; @@ -12,6 +13,7 @@ class currentdatetimeTest extends abstractTransformTest /** * Testing transforms for Errors * @throws ReflectionException + * @throws DateMalformedStringException * @throws exception */ public function testValueValid(): void @@ -37,11 +39,11 @@ public function testSpecification(): void 'format' => 'Y-m-d', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => [], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => [], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/get/easterdatetimeTest.php b/tests/transform/get/easterdatetimeTest.php index 18ae0d6..c4fe500 100644 --- a/tests/transform/get/easterdatetimeTest.php +++ b/tests/transform/get/easterdatetimeTest.php @@ -52,11 +52,11 @@ public function testSpecification(): void 'format' => 'Y-m-d', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => [], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => [], + ], + $transform->getSpecification() ); } diff --git a/tests/transform/get/fallbackTest.php b/tests/transform/get/fallbackTest.php index 13e6ba0..2d4cff4 100644 --- a/tests/transform/get/fallbackTest.php +++ b/tests/transform/get/fallbackTest.php @@ -91,11 +91,11 @@ public function testSpecification(): void ], ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field', 'source.example_source_field2'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field', 'source.example_source_field2'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/get/filteredTest.php b/tests/transform/get/filteredTest.php index 6e5ba6b..ba65b85 100644 --- a/tests/transform/get/filteredTest.php +++ b/tests/transform/get/filteredTest.php @@ -109,11 +109,11 @@ public function testSpecification(): void ], ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/get/number/fractionTest.php b/tests/transform/get/number/fractionTest.php index 9a172e6..107029b 100644 --- a/tests/transform/get/number/fractionTest.php +++ b/tests/transform/get/number/fractionTest.php @@ -98,11 +98,11 @@ public function testSpecification(): void 'field' => 'example_source_field', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/get/number/wholeTest.php b/tests/transform/get/number/wholeTest.php index c741bd8..b2d3040 100644 --- a/tests/transform/get/number/wholeTest.php +++ b/tests/transform/get/number/wholeTest.php @@ -80,11 +80,11 @@ public function testSpecification(): void 'field' => 'example_source_field', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/get/onetimeTest.php b/tests/transform/get/onetimeTest.php index 581a457..3b12f89 100644 --- a/tests/transform/get/onetimeTest.php +++ b/tests/transform/get/onetimeTest.php @@ -79,11 +79,11 @@ public function testSpecification(): void 'field' => 'example_source_field', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/get/optionTest.php b/tests/transform/get/optionTest.php index 39111a6..386d959 100644 --- a/tests/transform/get/optionTest.php +++ b/tests/transform/get/optionTest.php @@ -111,11 +111,11 @@ public function testSpecification(): void 'field' => 'example_source_field', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['option.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['option.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/get/strcaseTest.php b/tests/transform/get/strcaseTest.php index 71cfccd..d46da54 100644 --- a/tests/transform/get/strcaseTest.php +++ b/tests/transform/get/strcaseTest.php @@ -102,11 +102,11 @@ public function testSpecification(): void 'mode' => 'lower', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/get/strreplaceTest.php b/tests/transform/get/strreplaceTest.php index c6269c0..e75f26c 100644 --- a/tests/transform/get/strreplaceTest.php +++ b/tests/transform/get/strreplaceTest.php @@ -73,11 +73,11 @@ public function testSpecification(): void 'mode' => 'lower', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/get/substrTest.php b/tests/transform/get/substrTest.php index 0bf7e4e..f6d28b1 100644 --- a/tests/transform/get/substrTest.php +++ b/tests/transform/get/substrTest.php @@ -62,11 +62,11 @@ public function testSpecification(): void 'field' => 'example_source_field', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/get/valueTest.php b/tests/transform/get/valueTest.php index 0534d10..5b0b628 100644 --- a/tests/transform/get/valueTest.php +++ b/tests/transform/get/valueTest.php @@ -40,11 +40,11 @@ public function testSpecification(): void 'field' => 'example_source_field', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/get/valuearrayTest.php b/tests/transform/get/valuearrayTest.php index 0dc9177..733335d 100644 --- a/tests/transform/get/valuearrayTest.php +++ b/tests/transform/get/valuearrayTest.php @@ -98,7 +98,7 @@ public function testAllowNull(): void 'example_zipcode_field' => '01067', 'example_city_field' => 'Dresden', 'example_street_field' => null, // allowed, expect passthrough of NULL value. - 'example_houseno_field' => null, // not allowed, key should not be present in result. + 'example_houseno_field' => null, // not allowed, key should not be present in a result. ]); // Make sure it stays an array @@ -135,17 +135,17 @@ public function testSpecification(): void ], ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => [ - 'zipcode' => 'source.example_zipcode_field', - 'city' => 'source.example_city_field', - 'street' => 'source.example_street_field', - 'houseno' => 'source.example_houseno_field', - 'example' => 'source.example.example', - ], + [ + 'type' => 'transform', + 'source' => [ + 'zipcode' => 'source.example_zipcode_field', + 'city' => 'source.example_city_field', + 'street' => 'source.example_street_field', + 'houseno' => 'source.example_houseno_field', + 'example' => 'source.example.example', ], - $transform->getSpecification() + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/hashTest.php b/tests/transform/hashTest.php index d404139..6e53524 100644 --- a/tests/transform/hashTest.php +++ b/tests/transform/hashTest.php @@ -58,11 +58,11 @@ public function testSpecification(): void 'algorithm' => 'md5', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/implode/arrayvalueTest.php b/tests/transform/implode/arrayvalueTest.php index c11c80f..63ba18f 100644 --- a/tests/transform/implode/arrayvalueTest.php +++ b/tests/transform/implode/arrayvalueTest.php @@ -44,11 +44,11 @@ public function testSpecification(): void 'field' => 'example_source_field', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/implodeTest.php b/tests/transform/implodeTest.php index 14e095d..45fff18 100644 --- a/tests/transform/implodeTest.php +++ b/tests/transform/implodeTest.php @@ -84,7 +84,7 @@ public function testAllowConstantsDisabledSourceFallback(): void 'glue' => ';', 'fields' => [ ['source' => 'source', 'field' => 'example_source_field1'], - 'example_source_field1', // existing name in source + 'example_source_field1', // existing name in a source ['source' => 'source', 'field' => 'example_source_field2'], ], 'fallbackValue' => 'MISSING', @@ -97,7 +97,7 @@ public function testAllowConstantsDisabledSourceFallback(): void } /** - * Tests for providing a constant value in fields + * Tests for providing a constant value in fields, * but with enabled allowConstants config * @throws ReflectionException * @throws exception @@ -135,14 +135,14 @@ public function testSpecification(): void ], ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => [ - 'source.example_source_field1', - 'source.example_source_field2', - ], + [ + 'type' => 'transform', + 'source' => [ + 'source.example_source_field1', + 'source.example_source_field2', ], - $transform->getSpecification() + ], + $transform->getSpecification() ); $transform = $this->getTransform('implode', [ @@ -152,14 +152,14 @@ public function testSpecification(): void ], ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => [ - 'source.example_source_field1', - 'source.some_implicit_source_field', - ], + [ + 'type' => 'transform', + 'source' => [ + 'source.example_source_field1', + 'source.some_implicit_source_field', ], - $transform->getSpecification() + ], + $transform->getSpecification() ); $transform = $this->getTransform('implode', [ @@ -170,14 +170,14 @@ public function testSpecification(): void ], ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => [ - 'source.example_source_field1', - 'some_constant', - ], + [ + 'type' => 'transform', + 'source' => [ + 'source.example_source_field1', + 'some_constant', ], - $transform->getSpecification() + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/math/roundTest.php b/tests/transform/math/roundTest.php index c3cfb44..6e0dc5a 100644 --- a/tests/transform/math/roundTest.php +++ b/tests/transform/math/roundTest.php @@ -34,7 +34,7 @@ public function testDefaultRounding(): void } /** - * Tests negative rounding, e.g. 5.432 => 10 + * Tests negative rounding, e.g., 5.432 => 10 * @throws ReflectionException * @throws exception */ diff --git a/tests/transform/model/tjsample.php b/tests/transform/model/tjsample.php index 1abe22a..b3754df 100644 --- a/tests/transform/model/tjsample.php +++ b/tests/transform/model/tjsample.php @@ -6,7 +6,7 @@ /** * SQL Base model leveraging the new model servicing modules - * and enables freely defining and loading model configs + * and enabling freely defining and loading model configs, * BTW: tjsample means "transformmodel join sample" */ class tjsample extends sqlModel diff --git a/tests/transform/model/transformmodel.php b/tests/transform/model/transformmodel.php index 82502cd..60b4d9a 100644 --- a/tests/transform/model/transformmodel.php +++ b/tests/transform/model/transformmodel.php @@ -6,7 +6,7 @@ /** * SQL Base model leveraging the new model servicing modules - * and enables freely defining and loading model configs + * and enabling freely defining and loading model configs */ class transformmodel extends sqlModel { diff --git a/tests/transform/modelTest.php b/tests/transform/modelTest.php index c196a77..5c6b4ad 100644 --- a/tests/transform/modelTest.php +++ b/tests/transform/modelTest.php @@ -3,11 +3,23 @@ namespace codename\core\io\tests\transform; use codename\core\exception; +use codename\core\exception\compileErrorException; +use codename\core\exception\coreErrorException; +use codename\core\exception\coreWarningException; +use codename\core\exception\parseException; +use codename\core\exception\recoverableErrorException; +use codename\core\exception\strictException; +use codename\core\exception\userErrorException; +use codename\core\exception\userWarningException; +use codename\core\exception\warningException; use codename\core\io\pipeline; use codename\core\io\tests\transform\model\tjsample; use codename\core\io\tests\transform\model\transformmodel; use codename\core\test\overrideableApp; +use DateMalformedStringException; +use ErrorException; use ReflectionException; +use Throwable; class modelTest extends abstractTransformTest { @@ -55,6 +67,7 @@ public function testModelSaveDryRun(): void /** * Tests model_save in NON-dry-run (writing data) + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -88,6 +101,7 @@ public function testModelSave(): void /** * Tests model_save with PKey (editing data) + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -136,7 +150,7 @@ public function testModelSaveWithPKey(): void } /** - * Creates sample test data (on need!) + * Creates sample test data (on a need!) * @throws ReflectionException * @throws exception */ @@ -168,6 +182,7 @@ protected function createSampleTestData(): void /** * [testModelSaveOnetime description] + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -235,6 +250,7 @@ public function testModelSaveUniqueInvalidConfig(): void /** * [testModelSaveUniqueDryRun description] + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -246,6 +262,7 @@ public function testModelSaveUniqueDryRun(): void /** * [testModelSaveUnique description] * @param bool $dryRun [description] + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -692,6 +709,7 @@ public function testModelFilterAllowNullWorks(): void /** * Tests basic query using a simple joined model. + * @throws DateMalformedStringException * @throws ReflectionException * @throws exception */ @@ -718,8 +736,9 @@ public function testModelResultOneJoined(): void } /** - * Additionally creates joinable datasets in model tjsample + * Additionally, creates joinable datasets in model tjsample * @throws ReflectionException + * @throws DateMalformedStringException * @throws exception */ protected function createJoinableSampleTestData(): void @@ -886,15 +905,15 @@ public function testSpecification(): void ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => [ - 'model.transformmodel', - 'source.source_key1', - 'source.source_key1', - ], + [ + 'type' => 'transform', + 'source' => [ + 'model.transformmodel', + 'source.source_key1', + 'source.source_key1', ], - $transform->getSpecification() + ], + $transform->getSpecification() ); } @@ -916,12 +935,25 @@ protected function tearDown(): void /** * {@inheritDoc} + * @throws compileErrorException + * @throws coreErrorException + * @throws coreWarningException + * @throws ErrorException + * @throws parseException + * @throws recoverableErrorException + * @throws ReflectionException + * @throws strictException + * @throws Throwable + * @throws userErrorException + * @throws userWarningException + * @throws warningException + * @throws exception */ protected function setUp(): void { $app = static::createApp(); - // Don't forget to inject core-io + // Remember to inject core-io overrideableApp::__injectApp([ 'vendor' => 'codename', 'app' => 'core-io', diff --git a/tests/transform/pad/leftTest.php b/tests/transform/pad/leftTest.php index 8627999..b24259c 100644 --- a/tests/transform/pad/leftTest.php +++ b/tests/transform/pad/leftTest.php @@ -85,7 +85,7 @@ public function testValueExceedsPadLength(): void $result = $transform->transform([ 'example_source_field' => 'exampleexample', ]); - // Make sure the strings stays the same, + // Make sure the strings stay the same, // as we only pad, if there are characters missing static::assertEquals('exampleexample', $result); } @@ -102,11 +102,11 @@ public function testSpecification(): void 'field' => 'example_source_field', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/pad/rightTest.php b/tests/transform/pad/rightTest.php index e53173d..dddfd27 100644 --- a/tests/transform/pad/rightTest.php +++ b/tests/transform/pad/rightTest.php @@ -85,7 +85,7 @@ public function testValueExceedsPadLength(): void $result = $transform->transform([ 'example_source_field' => 'exampleexample', ]); - // Make sure the strings stays the same, + // Make sure the strings stay the same, // as we only pad, if there are characters missing static::assertEquals('exampleexample', $result); } @@ -102,11 +102,11 @@ public function testSpecification(): void 'field' => 'example_source_field', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/regexTest.php b/tests/transform/regexTest.php index ea75b2d..48ba25a 100644 --- a/tests/transform/regexTest.php +++ b/tests/transform/regexTest.php @@ -3,7 +3,6 @@ namespace codename\core\io\tests\transform; use codename\core\exception; -use LogicException; use ReflectionException; class regexTest extends abstractTransformTest @@ -173,11 +172,11 @@ public function testSpecification(): void 'field' => 'example_source_field', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/transformGetValueTest.php b/tests/transform/transformGetValueTest.php index 8ba597c..ed22f0c 100644 --- a/tests/transform/transformGetValueTest.php +++ b/tests/transform/transformGetValueTest.php @@ -2,16 +2,27 @@ namespace codename\core\io\tests\transform; +use codename\core\exception\compileErrorException; +use codename\core\exception\coreErrorException; +use codename\core\exception\coreWarningException; +use codename\core\exception\parseException; +use codename\core\exception\recoverableErrorException; +use codename\core\exception\strictException; +use codename\core\exception\userErrorException; +use codename\core\exception\userWarningException; +use codename\core\exception\warningException; use codename\core\io\datasource\arraydata; use codename\core\io\pipeline; use codename\core\io\transform\dummy; use codename\core\response\cli; +use ErrorException; use Exception; use LogicException; use ReflectionException; +use Throwable; /** - * pseudo-pipeline for testing source, source_deep, transform, transform_deep and stuff. + * pseudo-pipeline for a testing source, source_deep, transform, transform_deep and stuff. */ class transformGetValueTest extends abstractTransformTest { @@ -176,12 +187,23 @@ public function testGetValueErroneous(): void /** * [testGetValueConstant description] * @throws ReflectionException + * @throws ErrorException + * @throws Throwable + * @throws compileErrorException + * @throws coreErrorException + * @throws coreWarningException + * @throws parseException + * @throws recoverableErrorException + * @throws strictException + * @throws userErrorException + * @throws userWarningException + * @throws warningException * @throws \codename\core\exception */ public function testGetValueConstant(): void { // Emulate some response-related stuff - // as pipeline may access it in CLI for stdout + // as a pipeline may access it in CLI for stdout $app = static::createApp(); $app::getAppstack(); $app::__setInstance('response', new cli()); diff --git a/tests/transform/trim/leftTest.php b/tests/transform/trim/leftTest.php index de5a847..b5163e1 100644 --- a/tests/transform/trim/leftTest.php +++ b/tests/transform/trim/leftTest.php @@ -57,11 +57,11 @@ public function testSpecification(): void 'field' => 'example_source_field', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/trim/rightTest.php b/tests/transform/trim/rightTest.php index 44eca4a..71bdfc1 100644 --- a/tests/transform/trim/rightTest.php +++ b/tests/transform/trim/rightTest.php @@ -57,11 +57,11 @@ public function testSpecification(): void 'field' => 'example_source_field', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/trimTest.php b/tests/transform/trimTest.php index 1f39b01..b43c8ce 100644 --- a/tests/transform/trimTest.php +++ b/tests/transform/trimTest.php @@ -56,11 +56,11 @@ public function testSpecification(): void 'field' => 'example_source_field', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => ['source.example_source_field'], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => ['source.example_source_field'], + ], + $transform->getSpecification() ); } } diff --git a/tests/transform/valueTest.php b/tests/transform/valueTest.php index cc3514b..28c223a 100644 --- a/tests/transform/valueTest.php +++ b/tests/transform/valueTest.php @@ -36,11 +36,11 @@ public function testSpecification(): void 'field' => 'example_source_field', ]); static::assertEquals( - [ - 'type' => 'transform', - 'source' => [], - ], - $transform->getSpecification() + [ + 'type' => 'transform', + 'source' => [], + ], + $transform->getSpecification() ); } } diff --git a/tests/transformerTest.php b/tests/transformerTest.php index 00c2205..01a9571 100644 --- a/tests/transformerTest.php +++ b/tests/transformerTest.php @@ -4,11 +4,22 @@ use codename\core\config\json\extendable; use codename\core\exception; +use codename\core\exception\compileErrorException; +use codename\core\exception\coreErrorException; +use codename\core\exception\coreWarningException; +use codename\core\exception\parseException; +use codename\core\exception\recoverableErrorException; +use codename\core\exception\strictException; +use codename\core\exception\userErrorException; +use codename\core\exception\userWarningException; +use codename\core\exception\warningException; use codename\core\io\transform; use codename\core\io\transformer; use codename\core\test\base; use codename\core\test\overrideableApp; +use ErrorException; use ReflectionException; +use Throwable; class transformerTest extends base { @@ -79,6 +90,17 @@ public function testTransformerWrongTransformInstance(): void /** * {@inheritDoc} * @throws ReflectionException + * @throws ErrorException + * @throws Throwable + * @throws compileErrorException + * @throws coreErrorException + * @throws coreWarningException + * @throws parseException + * @throws recoverableErrorException + * @throws strictException + * @throws userErrorException + * @throws userWarningException + * @throws warningException * @throws exception */ protected function setUp(): void diff --git a/tests/validator.php b/tests/validator.php index 30d62b7..76306a8 100644 --- a/tests/validator.php +++ b/tests/validator.php @@ -4,10 +4,21 @@ use codename\core\app; use codename\core\exception; +use codename\core\exception\compileErrorException; +use codename\core\exception\coreErrorException; +use codename\core\exception\coreWarningException; +use codename\core\exception\parseException; +use codename\core\exception\recoverableErrorException; +use codename\core\exception\strictException; +use codename\core\exception\userErrorException; +use codename\core\exception\userWarningException; +use codename\core\exception\warningException; use codename\core\test\base; use codename\core\test\overrideableApp; +use ErrorException; use ReflectionClass; use ReflectionException; +use Throwable; /** * I am just an extender for the unittest class @@ -19,6 +30,17 @@ abstract class validator extends base /** * {@inheritDoc} * @throws ReflectionException + * @throws ErrorException + * @throws Throwable + * @throws compileErrorException + * @throws coreErrorException + * @throws coreWarningException + * @throws parseException + * @throws recoverableErrorException + * @throws strictException + * @throws userErrorException + * @throws userWarningException + * @throws warningException * @throws exception */ protected function setUp(): void