From 7abce876532d468843cdfa40a5dc8c56601e2c56 Mon Sep 17 00:00:00 2001 From: Clemens Schwaighofer Date: Tue, 4 Jul 2023 12:56:05 +0900 Subject: [PATCH] composer test update --- www/admin/class_test.datetime.php | 20 + www/admin/class_test.html_build.block.php | 83 +++ www/admin/class_test.html_build.element.php | 142 +++++ www/admin/class_test.html_build.replace.php | 83 +++ www/admin/class_test.php | 3 + www/composer.lock | 2 +- www/vendor/composer/installed.json | 2 +- www/vendor/composer/installed.php | 2 +- .../publish/last.published | 2 +- .../src/Combined/DateTime.php | 25 + .../src/Template/HtmlBuilder/Block.php | 264 +++++++++ .../src/Template/HtmlBuilder/Element.php | 559 ++++++++++++++++++ .../Template/HtmlBuilder/General/Error.php | 127 ++++ .../General/HtmlBuilderExcpetion.php | 21 + .../Template/HtmlBuilder/General/Settings.php | 69 +++ .../Template/HtmlBuilder/StringReplace.php | 194 ++++++ .../Combined/CoreLibsCombinedDateTimeTest.php | 64 ++ ...reLibsSecuritySymmetricEncryptionTest.php} | 2 +- .../CoreLibsTemplateHtmlBuilderBlockTest.php | 34 ++ ...CoreLibsTemplateHtmlBuilderElementTest.php | 546 +++++++++++++++++ ...bsTemplateHtmlBuilderStringReplaceTest.php | 65 ++ 21 files changed, 2304 insertions(+), 5 deletions(-) create mode 100644 www/admin/class_test.html_build.block.php create mode 100644 www/admin/class_test.html_build.element.php create mode 100644 www/admin/class_test.html_build.replace.php create mode 100644 www/vendor/egrajp/corelibs-composer-all/src/Template/HtmlBuilder/Block.php create mode 100644 www/vendor/egrajp/corelibs-composer-all/src/Template/HtmlBuilder/Element.php create mode 100644 www/vendor/egrajp/corelibs-composer-all/src/Template/HtmlBuilder/General/Error.php create mode 100644 www/vendor/egrajp/corelibs-composer-all/src/Template/HtmlBuilder/General/HtmlBuilderExcpetion.php create mode 100644 www/vendor/egrajp/corelibs-composer-all/src/Template/HtmlBuilder/General/Settings.php create mode 100644 www/vendor/egrajp/corelibs-composer-all/src/Template/HtmlBuilder/StringReplace.php rename www/vendor/egrajp/corelibs-composer-all/test/phpunit/Security/{CoreLibsSecuritySymmetricEncryption.php => CoreLibsSecuritySymmetricEncryptionTest.php} (98%) create mode 100644 www/vendor/egrajp/corelibs-composer-all/test/phpunit/Template/CoreLibsTemplateHtmlBuilderBlockTest.php create mode 100644 www/vendor/egrajp/corelibs-composer-all/test/phpunit/Template/CoreLibsTemplateHtmlBuilderElementTest.php create mode 100644 www/vendor/egrajp/corelibs-composer-all/test/phpunit/Template/CoreLibsTemplateHtmlBuilderStringReplaceTest.php diff --git a/www/admin/class_test.datetime.php b/www/admin/class_test.datetime.php index 56c8854d..a20fb41c 100644 --- a/www/admin/class_test.datetime.php +++ b/www/admin/class_test.datetime.php @@ -143,6 +143,26 @@ print "DATE-dow[$date];invalid: " . DateTime::setWeekdayNameFromDate($date) . "< print "DATE-dow[$date],long;invalid: " . DateTime::setWeekdayNameFromDate($date, true) . "
"; print "DOW-date[$date];invalid: " . DateTime::setWeekdayNumberFromDate($date) . "
"; +// check date range includes a weekend +// does not: +$start_date = '2023-07-03'; +$end_date = '2023-07-05'; +print "Has Weekend: " . $start_date . " ~ " . $end_date . ": " + . Dgs::prBl(DateTime::dateRangeHasWeekend($start_date, $end_date)) . "
"; +$start_date = '2023-07-03'; +$end_date = '2023-07-10'; +print "Has Weekend: " . $start_date . " ~ " . $end_date . ": " + . Dgs::prBl(DateTime::dateRangeHasWeekend($start_date, $end_date)) . "
"; +$start_date = '2023-07-03'; +$end_date = '2023-07-31'; +print "Has Weekend: " . $start_date . " ~ " . $end_date . ": " + . Dgs::prBl(DateTime::dateRangeHasWeekend($start_date, $end_date)) . "
"; +$start_date = '2023-07-01'; +$end_date = '2023-07-03'; +print "Has Weekend: " . $start_date . " ~ " . $end_date . ": " + . Dgs::prBl(DateTime::dateRangeHasWeekend($start_date, $end_date)) . "
"; + + print ""; // __END__ diff --git a/www/admin/class_test.html_build.block.php b/www/admin/class_test.html_build.block.php new file mode 100644 index 00000000..c3c8899c --- /dev/null +++ b/www/admin/class_test.html_build.block.php @@ -0,0 +1,83 @@ + BASE . LOG, + 'log_file_id' => $LOG_FILE_ID, + 'log_per_date' => true, +]); + +// define a list of from to color sets for conversion test + +$PAGE_NAME = 'TEST CLASS: HTML BUILD: BLOCK'; +print ""; +print "" . $PAGE_NAME . ""; +print ""; +print '
Class Test Master
'; +print '

' . $PAGE_NAME . '

'; + +$el = Block::cel('div', 'el-1', 'Content', ['red'], ['onClick' => 'javascript:alert(\'JS alert\');']); + +print "
" . htmlentities(Block::buildHtml($el)) . "
"; + +$el_a = Block::cel('div', 'u-id', '', ['base', 'cool']); +$el_a_1 = Block::cel('span', 's-id-1', 'Span A', ['bold']); +$el_a_2 = Block::cel('span', 's-id-2', 'Span B'); +$el_a_3 = Block::cel('a', 'link-a', 'Title', ['l-highlight'], ['OnClick' => 'Foo();']); +$el_a_2 = Block::aelx($el_a_2, $el_a_3); +// css changes before added to array +$el_a_1 = Block::acssel($el_a_1, 'italic', 'green', 'italic', 'font-large'); +$el_a_1 = Block::rcssel($el_a_1, 'green'); +// switch +$el_a_1 = Block::scssel($el_a_1, ['one', 'two', 'three'], ['three']); +// this will add el_a_2 to the el_a block +$el_a_1 = Block::aelx($el_a_1, $el_a_2); +$el_a = Block::aelx($el_a, $el_a_1, $el_a_2); + +// this will not update el_a +// $el_a_1 = Block::aelx($el_a_1, $el_a_2); + +$el_a_list = []; +$el_a_list[] = Block::cel('foo', 'foo-A'); +$el_a_list[] = Block::cel('bar', 'foo-B'); +$el_a_list[] = Block::cel('baz', 'foo-C'); +$el_a_list[] = Block::cel('br'); +$el_a_list[] = Block::cel('input'); + +echo "
"; +print "EL_A:
" . print_r($el_a, true) . "
"; + +echo "
"; +print "phfo(\$el_o):
" . htmlentities(Block::buildHtml($el_a, true)) . "
"; +echo "
"; +print "phfa(\$el_list):
" . htmlentities(Block::buildHtmlFromList($el_a_list, true)) . "
"; + +echo "
"; +// self loop test (will not trigger, are arrays) +$el_s = Block::cel('div', 'id-s', 'Self', []); +$el_s = Block::aelx($el_s, $el_s); + +print "phfo(\$el_):
" . htmlentities(Block::buildHtml($el_s, true)) . "
"; + +print ""; + +// __END__ diff --git a/www/admin/class_test.html_build.element.php b/www/admin/class_test.html_build.element.php new file mode 100644 index 00000000..68bb56f6 --- /dev/null +++ b/www/admin/class_test.html_build.element.php @@ -0,0 +1,142 @@ + BASE . LOG, + 'log_file_id' => $LOG_FILE_ID, + 'log_per_date' => true, +]); + +// define a list of from to color sets for conversion test + +$PAGE_NAME = 'TEST CLASS: HTML BUILD'; +print ""; +print "" . $PAGE_NAME . ""; +print ""; +print '
Class Test Master
'; +print '

' . $PAGE_NAME . '

'; + +$el = new Element('div', 'el-1', 'Content', ['red'], ['onClick' => 'javascript:alert(\'JS alert\');']); + +print "
" . htmlentities($el->buildHtml()) . "
"; + +$el_o = new Element('div', 'u-id', '', ['base', 'cool']); +$el_o_1 = new Element('span', 's-id-1', 'Span A', ['bold']); +$el_o_2 = new Element('span', 's-id-2', 'Span B'); +$el_o_3 = new Element('a', 'link-a', 'Title', ['l-highlight'], ['OnClick' => 'Foo();']); +$el_o_2->addSub($el_o_3); +$el_o->addSub($el_o_1, $el_o_2); + +$el_o_1->addCss('italic', 'green', 'italic', 'font-large') + ->removeCss('green'); + +$el_o_2->addCss('wrong-css') + ->removeCss('wrong-css', 'correct-css'); +$el_o_2->addCss('a', 'b')->removeCss('correct-css'); + +$el_o_1->addSub($el_o_2); + +// var_dump($el2); + +$el_o_list = []; +$el_o_list[] = new Element('foo', 'foo-A'); +$el_o_list[] = new Element('bar', 'foo-B'); +$el_o_list[] = new Element('baz', 'foo-C'); +$el_o_list[] = new Element('br'); +$el_o_list[] = new Element('input', 'tag', '', [], ['name' => 'foo', 'value' => 'ABC']); + +// $el2->resetSub(); +// var_dump($el2); +echo "
"; +print "EL_O:
" . print_r($el_o, true) . "
"; + +echo "
"; +print "buildHtml():
" . htmlentities($el_o->buildHtml()) . "
"; +echo "
"; +print "phfo(\$el_o):
" . htmlentities($el_o::printHtmlFromObject($el_o, true)) . "
"; +echo "
"; +print "phfa(\$el_list):
" . htmlentities($el_o::buildHtmlFromList($el_o_list, true)) . "
"; + +echo "
"; + +// self loop + +$el_s = new Element('div', 'id-s', 'Self'); +try { + $el_s->addSub($el_s, new Element('span', '', 'Span')); +} catch (HtmlBuilderExcpetion $e) { + print "E: " . $e->getMessage() . " | " . $e->getTraceAsString() . "
"; +} + +// var_dump($el_s); +print "el_s, buildHtml():
" . htmlentities($el_s->buildHtml()) . "
"; + +$el_s_2 = new Element('div', 'id-s', 'Self', []); +$el_s_2->addSub( + new Element('span', 's-1', 's 1'), + new Element('span', 's-2', 's 2'), +); + +$el_s_3 = new Element('div', 'id-3', 'ID 3'); +try { + $el_s_3->addSub($el_s_2); + $el_s_2->addSub($el_s_2); +} catch (HtmlBuilderExcpetion $e) { + print "E: " . $e->getMessage() . " | " . $e->getTraceAsString() . "
"; +} + +// print "
" . var_export($el_s_3, true) . "
"; + +print "el_s_3, buildHtml():
" . htmlentities($el_s_3->buildHtml()) . "
"; + +echo "
"; +Error::resetMessages(); +try { + $el_er = new Element(''); +} catch (HtmlBuilderExcpetion $e) { + print "E: " . $e->getMessage() . " | " . $e->getTraceAsString() . "
"; + if ($e->getPrevious() !== null) { + print "E: " . $e->getPrevious()->getMessage() . " | " . $e->getPrevious()->getTraceAsString() . "
"; + } +} +print "Errors:
" . print_r(Error::getMessages(), true) . "
"; +print "Warning: " . Support::printToString(Error::hasWarning()) . "
"; +print "Error: " . Support::printToString(Error::hasError()) . "
"; +Error::resetMessages(); +try { + $el_er = new Element('123123'); +} catch (HtmlBuilderExcpetion $e) { + print "E: " . $e->getMessage() . " | " . $e->getTraceAsString() . "
"; + if ($e->getPrevious() !== null) { + print "E: " . $e->getPrevious()->getMessage() . " | " . $e->getPrevious()->getTraceAsString() . "
"; + } +} +print "Errors:
" . print_r(Error::getMessages(), true) . "
"; +print "Warning: " . Support::printToString(Error::hasWarning()) . "
"; +print "Error: " . Support::printToString(Error::hasError()) . "
"; + +print ""; + +// __END__ diff --git a/www/admin/class_test.html_build.replace.php b/www/admin/class_test.html_build.replace.php new file mode 100644 index 00000000..99cca158 --- /dev/null +++ b/www/admin/class_test.html_build.replace.php @@ -0,0 +1,83 @@ + BASE . LOG, + 'log_file_id' => $LOG_FILE_ID, + 'log_per_date' => true, +]); + +// define a list of from to color sets for conversion test + +$PAGE_NAME = 'TEST CLASS: HTML BUILD: STRING REPLACE'; +print ""; +print "" . $PAGE_NAME . ""; +print ""; +print '
Class Test Master
'; +print '

' . $PAGE_NAME . '

'; + +$html_block = << + {CONTENT} + +HTML; + +print "
" . htmlentities(StringReplace::replaceData(
+	$html_block,
+	[
+		'ID' => 'block-id',
+		'CSS' => join(',', ['blue', 'red']),
+		'{CONTENT}' => 'Some content here
with bla bla inside' + ] +)) . "
"; + +StringReplace::loadElements( + ['foo', $html_block], + ['bar', <<{CONTENT} +HTML] +); + +print "Get:
" . htmlentities(StringReplace::getElement('bar') ?: '') . '
'; + +print "Build element:
" . htmlentities(StringReplace::buildElement(
+	'bar',
+	[
+		'ID}' => 'new-id',
+		'{CONTENT' => 'Test cow 日本語'
+	]
+)) . '
' ; + +print "Build element as replace:
" . htmlentities(StringReplace::buildElement(
+	'bar',
+	['
+		ID}' => 'diff-id',
+		'{CONTENT' => 'Test cow 日本語. More text plus'
+	],
+	'rpl-1'
+)) . '
' ; + +print "Get replacement:
" . htmlentities(StringReplace::getReplaceBlock('rpl-1')) . "
"; + +print ""; + +// __END__ diff --git a/www/admin/class_test.php b/www/admin/class_test.php index 91e61713..c0f15b72 100644 --- a/www/admin/class_test.php +++ b/www/admin/class_test.php @@ -81,6 +81,9 @@ $test_files = [ 'class_test.encryption.php' => 'Class Test: ENCRYPTION', 'class_test.math.php' => 'Class Test: MATH', 'class_test.html.php' => 'Class Test: HTML/ELEMENTS', + 'class_test.html_build.element.php' => 'Class Test: HTML BUILDER: ELEMENT', + 'class_test.html_build.block.php' => 'Class Test: HTML BUILDER: BLOCK', + 'class_test.html_build.replace.php' => 'Class Test: HTML BUILDER: STRING REPLACE', 'class_test.email.php' => 'Class Test: EMAIL', 'class_test.create_email.php' => 'Class Test: CREATE EMAIL', 'class_test.uids.php' => 'Class Test: UIDS', diff --git a/www/composer.lock b/www/composer.lock index d9009567..c66c2c3c 100644 --- a/www/composer.lock +++ b/www/composer.lock @@ -12,7 +12,7 @@ "dist": { "type": "path", "url": "/storage/var/www/html/developers/clemens/core_data/composer-packages/CoreLibs-Composer-All", - "reference": "e0f8bad2d97bb7f3a5332528f799bae2942354c8" + "reference": "5f223fb50dd242310afed09d516a2c30426515fd" }, "require": { "php": ">=8.1", diff --git a/www/vendor/composer/installed.json b/www/vendor/composer/installed.json index 0fed1d96..3b4f67f4 100644 --- a/www/vendor/composer/installed.json +++ b/www/vendor/composer/installed.json @@ -7,7 +7,7 @@ "dist": { "type": "path", "url": "/storage/var/www/html/developers/clemens/core_data/composer-packages/CoreLibs-Composer-All", - "reference": "e0f8bad2d97bb7f3a5332528f799bae2942354c8" + "reference": "5f223fb50dd242310afed09d516a2c30426515fd" }, "require": { "php": ">=8.1", diff --git a/www/vendor/composer/installed.php b/www/vendor/composer/installed.php index 0b9c39fa..e15a3572 100644 --- a/www/vendor/composer/installed.php +++ b/www/vendor/composer/installed.php @@ -13,7 +13,7 @@ 'egrajp/corelibs-composer-all' => array( 'pretty_version' => 'dev-development', 'version' => 'dev-development', - 'reference' => 'e0f8bad2d97bb7f3a5332528f799bae2942354c8', + 'reference' => '5f223fb50dd242310afed09d516a2c30426515fd', 'type' => 'library', 'install_path' => __DIR__ . '/../egrajp/corelibs-composer-all', 'aliases' => array(), diff --git a/www/vendor/egrajp/corelibs-composer-all/publish/last.published b/www/vendor/egrajp/corelibs-composer-all/publish/last.published index 47da986f..3b740421 100644 --- a/www/vendor/egrajp/corelibs-composer-all/publish/last.published +++ b/www/vendor/egrajp/corelibs-composer-all/publish/last.published @@ -1 +1 @@ -9.1.0 +9.3.1 diff --git a/www/vendor/egrajp/corelibs-composer-all/src/Combined/DateTime.php b/www/vendor/egrajp/corelibs-composer-all/src/Combined/DateTime.php index c1f16147..27917886 100644 --- a/www/vendor/egrajp/corelibs-composer-all/src/Combined/DateTime.php +++ b/www/vendor/egrajp/corelibs-composer-all/src/Combined/DateTime.php @@ -452,6 +452,31 @@ class DateTime return $days; } } + + /** + * check if a weekend day (sat/sun) is in the given date range + * Can have time too, but is not needed + * + * @param string $start_date Y-m-d + * @param string $end_date Y-m-d + * @return bool True for has weekend, False for has not + */ + public static function dateRangeHasWeekend( + string $start_date, + string $end_date, + ): bool { + $dd_start = new \DateTime($start_date); + $dd_end = new \DateTime($end_date); + if ( + // starts with a weekend + $dd_start->format('N') >= 6 || + // start day plus diff will be 6 and so fall into a weekend + ((int)$dd_start->format('w') + $dd_start->diff($dd_end)->days) >= 6 + ) { + return true; + } + return false; + } } // __END__ diff --git a/www/vendor/egrajp/corelibs-composer-all/src/Template/HtmlBuilder/Block.php b/www/vendor/egrajp/corelibs-composer-all/src/Template/HtmlBuilder/Block.php new file mode 100644 index 00000000..2015280e --- /dev/null +++ b/www/vendor/egrajp/corelibs-composer-all/src/Template/HtmlBuilder/Block.php @@ -0,0 +1,264 @@ + $css, + * @param array $options + * @return array{tag:string,id:string,name:string,content:string,css:array,options:array,sub:array} + * @throws HtmlBuilderExcpetion + */ + public static function cel( + string $tag, + string $id = '', + string $content = '', + array $css = [], + array $options = [] + ): array { + if (!preg_match("/^[A-Za-z]+$/", $tag)) { + Error::setError( + '201', + 'invalid or empty tag', + ['tag' => $tag] + ); + throw new HtmlBuilderExcpetion('Invalid or empty tag'); + } + return [ + 'tag' => $tag, + 'id' => $id, + 'name' => $options['name'] ?? '', + 'content' => $content, + 'css' => $css, + 'options' => $options, + 'sub' => [], + ]; + } + + /** + * Search element tree for id and add + * if id is empty add at current + * + * @param array{tag:string,id:string,name:string,content:string,css:array,options:array,sub:array} $base + * @param array{tag:string,id:string,name:string,content:string,css:array,options:array,sub:array} $attach + * @param string $id + * @return array{tag:string,id:string,name:string,content:string,css:array,options:array,sub:array} + */ + public static function ael( + array $base, + array $attach, + string $id = '' + ): array { + // no id or matching id + if ( + empty($id) || + $base['id'] == $id + ) { + self::addSub($base, $attach); + return $base; + } + // find id in 'id' in all 'sub' + foreach ($base['sub'] as $el) { + $el = self::ael($el, $attach, $id); + } + + return $base; + } + + /** + * Undocumented function + * + * @param array{tag:string,id:string,name:string,content:string,css:array,options:array,sub:array} $base + * @param array{tag:string,id:string,name:string,content:string,css:array,options:array,sub:array} ...$attach + * @return array{tag:string,id:string,name:string,content:string,css:array,options:array,sub:array} + */ + public static function aelx( + array $base, + array ...$attach + ): array { + $base = self::addSub($base, ...$attach); + return $base; + } + + /** + * Undocumented function + * + * @param array{tag:string,id:string,name:string,content:string,css:array,options:array,sub:array} $element + * @param array{tag:string,id:string,name:string,content:string,css:array,options:array,sub:array} $sub + * @return array{tag:string,id:string,name:string,content:string,css:array,options:array,sub:array} + */ + public static function addSub(array $element, array ...$sub): array + { + if (!isset($element['sub'])) { + $element['sub'] = []; + } + array_push($element['sub'], ...$sub); + return $element; + } + + /** + * Undocumented function + * + * @param array{tag:string,id:string,name:string,content:string,css:array,options:array,sub:array} $element + * @return array{tag:string,id:string,name:string,content:string,css:array,options:array,sub:array} + */ + public static function resetSub(array $element): array + { + $element['sub'] = []; + return $element; + } + + // CSS Elements + + /** + * Undocumented function + * + * @param array{tag:string,id:string,name:string,content:string,css:array,options:array,sub:array} $element + * @param string ...$css + * @return array{tag:string,id:string,name:string,content:string,css:array,options:array,sub:array} + */ + public static function acssel(array $element, string ...$css): array + { + $element['css'] = array_unique(array_merge($element['css'] ?? [], $css)); + return $element; + } + + /** + * Undocumented function + * + * @param array{tag:string,id:string,name:string,content:string,css:array,options:array,sub:array} $element + * @param string ...$css + * @return array{tag:string,id:string,name:string,content:string,css:array,options:array,sub:array} + */ + public static function rcssel(array $element, string ...$css): array + { + $element['css'] = array_diff($element['css'] ?? [], $css); + return $element; + } + + /** + * Undocumented function + * scssel (switch) is not supported + * use rcssel -> acssel + * + * @param array{tag:string,id:string,name:string,content:string,css:array,options:array,sub:array} $element + * @param array $rcss + * @param array $acss + * @return array{tag:string,id:string,name:string,content:string,css:array,options:array,sub:array} + */ + public static function scssel(array $element, array $rcss, array $acss): array + { + return self::acssel( + self::rcssel($element, ...$rcss), + ...$acss + ); + } + + /** + * Undocumented function + * alias phfo + * + * @param array{tag:string,id:string,name:string,content:string,css:array,options:array,sub:array} $tree + * @param bool $add_nl [default=false] + * @return string + */ + public static function buildHtml(array $tree, bool $add_nl = false): string + { + if (empty($tree['tag'])) { + return ''; + } + // print "D01: " . microtime(true) . "
"; + $line = '<' . $tree['tag']; + + if (!empty($tree['id'])) { + $line .= ' id="' . $tree['id'] . '"'; + if (in_array($tree['tag'], Settings::NAME_ELEMENTS)) { + $line .= ' name="' + . (!empty($tree['name']) ? $tree['name'] : $tree['id']) + . '"'; + } + } + if (count($tree['css'])) { + $line .= ' class="' . join(' ', $tree['css']) . '"'; + } + foreach ($tree['options'] ?? [] as $key => $item) { + if (in_array($key, Settings::SKIP_OPTIONS)) { + continue; + } + $line .= ' ' . $key . '="' . $item . '"'; + } + $line .= '>'; + if (!empty($tree['content'])) { + $line .= $tree['content']; + } + // sub nodes + foreach ($tree['sub'] ?? [] as $sub) { + if ($add_nl === true) { + $line .= "\n"; + } + $line .= self::buildHtml($sub, $add_nl); + if ($add_nl === true) { + $line .= "\n"; + } + } + + // close line if needed + if (!in_array($tree['tag'], Settings::NO_CLOSE)) { + $line .= ''; + } + + return $line; + } + + /** + * Undocumented function + * alias phfa + * + * @param array,options:array,sub:array}> $list + * @param bool $add_nl [default=false] + * @return string + */ + public static function buildHtmlFromList(array $list, bool $add_nl = false): string + { + $output = ''; + foreach ($list as $el) { + $output .= self::buildHtml($el, $add_nl); + } + return $output; + } + + /** + * Undocumented function + * wrapper for buildHtmlFromList + * + * @param array,options:array,sub:array}> $list array of Elements to build string from + * @param bool $add_nl [default=false] Optional output string line break + * @return string build html as string + */ + public static function printHtmlFromArray(array $list, bool $add_nl = false): string + { + return self::buildHtmlFromList($list, $add_nl); + } +} + +// __END__ diff --git a/www/vendor/egrajp/corelibs-composer-all/src/Template/HtmlBuilder/Element.php b/www/vendor/egrajp/corelibs-composer-all/src/Template/HtmlBuilder/Element.php new file mode 100644 index 00000000..85d58745 --- /dev/null +++ b/www/vendor/egrajp/corelibs-composer-all/src/Template/HtmlBuilder/Element.php @@ -0,0 +1,559 @@ + */ + private array $css = []; + /** @var array */ + private array $options = []; + /** @var array list of elements */ + private array $sub = []; + + /** + * create new html element + * + * @param string $tag html tag (eg div, button, etc) + * @param string $id html tag id, used also for name if name + * not set in $options + * @param string $content content text inside, eg
Content
+ * if sub elements exist, they are added after content + * @param array $css array of css names, put style in $options + * @param array $options Additional element options in + * key = value format + * eg: onClick => 'something();' + * id, css are skipped + * name only set on input/button + * @throws HtmlBuilderExcpetion + */ + public function __construct( + string $tag, + string $id = '', + string $content = '', + array $css = [], + array $options = [] + ) { + // exit if not valid tag + try { + $this->setTag($tag); + } catch (HtmlBuilderExcpetion $e) { + throw new HtmlBuilderExcpetion('Could not create Element', 0, $e); + } + $this->setId($id); + $this->setName($options['name'] ?? ''); + $this->setContent($content); + $this->addCss(...$css); + $this->setOptions($options); + } + + /** + * set tag + * + * @param string $tag + * @return void + * @throws HtmlBuilderExcpetion + */ + public function setTag(string $tag): void + { + // tag must be letters only + if (!preg_match("/^[A-Za-z]+$/", $tag)) { + Error::setError( + '201', + 'invalid or empty tag', + ['tag' => $tag] + ); + throw new HtmlBuilderExcpetion('Invalid or empty tag: ' . $tag); + } + $this->tag = $tag; + } + + /** + * get the tag name + * + * @return string HTML element tag + */ + public function getTag(): string + { + return $this->tag; + } + + /** + * set the element id + * + * @param string $id + * @return void + */ + public function setId(string $id): void + { + // invalid id and name check too + // be strict: [a-zA-Z0-9], -, _ + // cannot start with digit, two hyphens or a hyphen with a digit: + // 0abc + // __abc + // _0abc + if ( + !empty($id) && + !preg_match("/^[A-Za-z][\w-]*$/", $id) + ) { + Error::setWarning( + '202', + 'possible invalid id', + ['id' => $id, 'tag' => $this->getTag()] + ); + // TODO: shoud throw error + } + $this->id = $id; + } + + /** + * get the html tag id + * + * @return string HTML element id + */ + public function getId(): string + { + return $this->id; + } + + /** + * Set name for elements + * only for elements that need it (input/button/form) + * + * @param string $name + * @return void + */ + public function setName(string $name): void + { + if ( + !empty($name) && + !preg_match("/^[A-Za-z][\w-]*$/", $name) + ) { + Error::setWarning( + '203', + 'possible invalid name', + ['name' => $name, 'id' => $this->getId(), 'tag' => $this->getTag()] + ); + // TODO: shoud throw error + } + $this->name = $name; + } + + /** + * get the name if set + * + * @return string Optional HTML name (eg for input) + */ + public function getName(): string + { + return $this->name; + } + + /** + * Set new content for element + * + * @param string $content + * @return void + */ + public function setContent(string $content): void + { + $this->content = $content; + } + + /** + * get the elment text content (not sub elements) + * + * @return string HTML content text as is + */ + public function getContent(): string + { + return $this->content; + } + + /** + * set or update options + * + * @param array $options + * @return void + */ + public function setOptions(array $options): void + { + foreach ($options as $key => $value) { + if (empty($key)) { + Error::setError( + '110', + 'Cannot set option with empty key', + ['id' => $this->getId(), 'tag' => $this->getTag()] + ); + // TODO: shoud throw error + continue; + } + // if data is null + if ($value === null) { + if (isset($this->options[$key])) { + unset($this->options[$key]); + } else { + Error::setError( + '210', + 'Cannot set option with null value', + ['id' => $this->getId(), 'tag' => $this->getTag()] + ); + } + // TODO: shoud throw error + continue; + } + $this->options[$key] = $value; + } + } + + /** + * get the options array + * also holds "name" option + * anything like: style, javascript, value or any other html tag option + * right side can be empty but not null + * + * @return array get options as list html option name and value + */ + public function getOptions(): array + { + return $this->options; + } + + // Sub Elements + + /** + * get the sub elements (array of Elements) + * + * @return array Array of Elements (that can have sub elements) + */ + public function getSub(): array + { + return $this->sub; + } + + /** + * add one or many sub elements (add at the end) + * + * @param Element $sub One or many elements to add + * @return void + * @throws HtmlBuilderExcpetion + */ + public function addSub(Element ...$sub): void + { + foreach ($sub as $_sub) { + // if one of the elements is the same as this class, ignore it + // with this we avoid self reference loop + if ($_sub == $this) { + Error::setError( + '100', + 'Cannot assign Element to itself, this would create an infinite loop', + ['id' => $this->getId(), 'tag' => $this->getTag()] + ); + throw new HtmlBuilderExcpetion('Cannot assign Element to itself, this would create an infinite loop'); + } + array_push($this->sub, $_sub); + } + } + + /** + * Remove an element from the sub array + * By pos in array or id set on first level + * + * @param int|string $id String id name or int pos number in array + * @return void + */ + public function removeSub(int|string $id): void + { + // find element with id and remove it + // or when number find pos in sub and remove it + if (is_int($id)) { + if (!isset($this->sub[$id])) { + return; + } + unset($this->sub[$id]); + return; + } + // only on first level + foreach ($this->sub as $pos => $el) { + if ( + $el->getId() === $id + ) { + unset($this->sub[$pos]); + return; + } + } + } + + /** + * remove all sub elements + * + * @return void + */ + public function resetSub(): void + { + $this->sub = []; + } + + // CSS Elements + + /** + * get the current set css elements + * + * @return array list of css element entries + */ + public function getCss(): array + { + return $this->css; + } + + /** + * add one or many new css elements + * Note that we can chain: add/remove/reset + * + * @param string ...$css one or more css strings to add + * @return Element Current element for chaining + */ + public function addCss(string ...$css): Element + { + // should do check for empty/invalid css + $_set_css = []; + foreach ($css as $_css) { + if (empty($_css)) { + Error::setError( + '204', + 'cannot have empty css string', + ); + // TODO: shoud throw error + continue; + } + // -?[_A-Za-z][_A-Za-z0-9-]* + if (!preg_match("/^-?[_A-Za-z][_A-Za-z0-9-]*$/", $_css)) { + Error::setWarning( + '205', + 'possible invalid css string', + ['css' => $_css, 'id' => $this->id, 'tag' => $this->tag] + ); + // TODO: shoud throw error + } + $_set_css[] = $_css; + } + $this->css = array_unique(array_merge($this->css, $_set_css)); + return $this; + } + + /** + * remove one or more css elements + * Note that we can chain: add/remove/reset + * + * @param string ...$css one or more css strings to remove + * @return Element Current element for chaining + */ + public function removeCss(string ...$css): Element + { + $this->css = array_diff($this->css, $css); + return $this; + } + + /** + * unset all css elements + * Note that we can chain: add/remove/reset + * + * @return Element + */ + public function resetCss(): Element + { + $this->css = []; + return $this; + } + + // build output from tree + + /** + * build html string from the current element tree (self) + * or from the Element tree given as parameter + * if $add_nl is set then new lines are added before each sub element added + * no indet is done (tab or other) + * + * @param Element|null $tree Different Element tree to build + * if not set (null), self is used + * @param bool $add_nl [default=false] Optional output string line breaks + * @return string HTML as string + */ + public function buildHtml(Element $tree = null, bool $add_nl = false): string + { + // print "D01: " . microtime(true) . "
"; + if ($tree === null) { + $tree = $this; + } + $line = '<' . $tree->getTag(); + + if ($tree->getId()) { + $line .= ' id="' . $tree->getId() . '"'; + if (in_array($tree->getTag(), Settings::NAME_ELEMENTS)) { + $line .= ' name="' + . (!empty($tree->getName()) ? $tree->getName() : $tree->getId()) + . '"'; + } + } + if (count($tree->getCss())) { + $line .= ' class="' . join(' ', $tree->getCss()) . '"'; + } + foreach ($tree->getOptions() as $key => $item) { + // skip + if (in_array($key, Settings::SKIP_OPTIONS)) { + continue; + } + $line .= ' ' . $key . '="' . $item . '"'; + } + $line .= '>'; + if (strlen($tree->getContent()) > 0) { + $line .= $tree->getContent(); + } + // sub nodes + foreach ($tree->getSub() as $sub) { + if ($add_nl === true) { + $line .= "\n"; + } + $line .= $tree->buildHtml($sub, $add_nl); + if ($add_nl === true) { + $line .= "\n"; + } + } + + // close line if needed + if (!in_array($tree->getTag(), Settings::NO_CLOSE)) { + $line .= 'getTag() . '>'; + } + + return $line; + } + + // this is static + + /** + * Builds a single string from an array of elements + * a new line can be added before each new element if $add_nl is set to true + * + * @param array $list array of Elements, uses buildHtml internal + * @param bool $add_nl [default=false] Optional output string line breaks + * @return string HTML as string + */ + public static function buildHtmlFromList(array $list, bool $add_nl = false): string + { + $output = ''; + foreach ($list as $el) { + if (!empty($output) && $add_nl === true) { + $output .= "\n"; + } + $output .= $el->buildHtml(); + } + return $output; + } + + // so we can call builder statically + + /** + * Search element tree for id and add + * if id is empty add at element given in parameter $base + * + * @param Element $base Element to attach to + * @param Element $attach Element to attach (single) + * @param string $id Optional id, if empty then attached at the end + * If set will loop through ALL sub elements until + * matching id found. if not found, not added + * @return Element Element with attached sub element + */ + public static function addElementWithId( + Element $base, + Element $attach, + string $id = '' + ): Element { + // no id or matching id + if ( + empty($id) || + $base->getId() == $id + ) { + $base->addSub($attach); + return $base; + } + // find id in 'id' in all 'sub' + foreach ($base->getSub() as $el) { + self::addElementWithId($el, $attach, $id); + } + + return $base; + } + + /** + * add one or more elemens to $base + * + * @param Element $base Element to attach to + * @param Element ...$attach Element or Elements to attach + * @return Element Element with attached sub elements + */ + public static function addElement( + Element $base, + Element ...$attach + ): Element { + // we must make sure we do not self attach + $base->addSub(...$attach); + return $base; + } + + /** + * Static call version for building + * not recommended to be used, rather use "Element->buildHtml()" + * wrapper for buildHtml + * + * @param ?Element $tree Element tree to build + * if not set returns empty string + * @param bool $add_nl [default=false] Optional output string line break + * @return string build html as string + * @deprecated Do not use, use Element->buildHtml() instead + */ + public static function printHtmlFromObject(Element $tree = null, bool $add_nl = false): string + { + // nothing ->bad + if ($tree === null) { + return ''; + } + return $tree->buildHtml(add_nl: $add_nl); + } + + /** + * Undocumented function + * wrapper for buildHtmlFromList + * + * @param array $list array of Elements to build string from + * @param bool $add_nl [default=false] Optional output string line break + * @return string build html as string + */ + public static function printHtmlFromArray(array $list, bool $add_nl = false): string + { + return self::buildHtmlFromList($list, $add_nl); + } +} + +// __END__ diff --git a/www/vendor/egrajp/corelibs-composer-all/src/Template/HtmlBuilder/General/Error.php b/www/vendor/egrajp/corelibs-composer-all/src/Template/HtmlBuilder/General/Error.php new file mode 100644 index 00000000..be025f03 --- /dev/null +++ b/www/vendor/egrajp/corelibs-composer-all/src/Template/HtmlBuilder/General/Error.php @@ -0,0 +1,127 @@ +}> */ + private static array $messages = []; + + /** + * internal writer for messages + * + * @param string $level + * @param string $id + * @param string $message + * @param array $context + * @return void + */ + private static function writeContent( + string $level, + string $id, + string $message, + array $context + ): void { + self::$messages[] = [ + 'level' => $level, + 'id' => $id, + 'message' => $message, + 'context' => $context, + ]; + } + + /** + * warning collector for all internal string errors + * builds an warning with warning id, message text and array with optional content + * + * @param string $id + * @param string $message + * @param array $context + * @return void + */ + public static function setWarning(string $id, string $message, array $context = []): void + { + self::writeContent('Warning', $id, $message, $context); + } + + /** + * error collector for all internal string errors + * builds an error with error id, message text and array with optional content + * + * @param string $id + * @param string $message + * @param array $context + * @return void + */ + public static function setError(string $id, string $message, array $context = []): void + { + self::writeContent('Error', $id, $message, $context); + } + + /** + * Return all set errors + * + * @return array + */ + public static function getMessages(): array + { + return self::$messages; + } + + /** + * Reset all errors + * + * @return void + */ + public static function resetMessages(): void + { + self::$messages = []; + } + + /** + * internal level in message array exists check + * + * @param string $level + * @return bool + */ + private static function hasLevel(string $level): bool + { + return array_filter( + self::$messages, + function ($var) use ($level) { + return $var['level'] == $level ? true : false; + } + ) === [] ? false : true; + } + + /** + * Check if any error is set + * + * @return bool + */ + public static function hasError(): bool + { + return self::hasLevel('Error'); + } + + /** + * Check if any warning is set + * + * @return bool + */ + public static function hasWarning(): bool + { + return self::hasLevel('Warning'); + } +} + +// __END__ diff --git a/www/vendor/egrajp/corelibs-composer-all/src/Template/HtmlBuilder/General/HtmlBuilderExcpetion.php b/www/vendor/egrajp/corelibs-composer-all/src/Template/HtmlBuilder/General/HtmlBuilderExcpetion.php new file mode 100644 index 00000000..8fe8a3fc --- /dev/null +++ b/www/vendor/egrajp/corelibs-composer-all/src/Template/HtmlBuilder/General/HtmlBuilderExcpetion.php @@ -0,0 +1,21 @@ + list of html elements that can have the name tag */ + public const NAME_ELEMENTS = [ + 'button', + 'fieldset', + 'form', + 'iframe', + 'input', + 'map', + 'meta', + 'object', + 'output', + 'param', + 'select', + 'textarea', + ]; + + /** @var array options key entries to be skipped in build */ + public const SKIP_OPTIONS = [ + 'id', + 'name', + 'class', + ]; + + /** @var array html elements that don't need to be closed */ + public const NO_CLOSE = [ + 'input', + 'br', + 'img', + 'hr', + 'area', + 'col', + 'keygen', + 'wbr', + 'track', + 'source', + 'param', + 'command', + // only in header + 'base', + 'meta', + 'link', + 'embed', + ]; + + /** @var array invalid tags, not allowed in body */ + public const NOT_IN_BODY_ALLOWED = [ + 'base', + 'meta', + 'link', + 'embed', // not sure + ]; +} + +// __END__ diff --git a/www/vendor/egrajp/corelibs-composer-all/src/Template/HtmlBuilder/StringReplace.php b/www/vendor/egrajp/corelibs-composer-all/src/Template/HtmlBuilder/StringReplace.php new file mode 100644 index 00000000..7a259d5d --- /dev/null +++ b/www/vendor/egrajp/corelibs-composer-all/src/Template/HtmlBuilder/StringReplace.php @@ -0,0 +1,194 @@ + */ + private static array $elements = []; + /** @var array */ + private static array $replace = []; + + /** + * load html blocks into array for repeated usage + * each array group parameter has 0: index, 1: content + * There is no content check done. + * index must be non empty (but has no fixed format) + * if same index is tried twice it will set an error and skip + * + * @param array{0:string,1:string} ...$element Elements to load + * @return void + * @throws HtmlBuilderExcpetion + */ + public static function loadElements(array ...$element): void + { + foreach ($element as $el) { + $index = $el[0] ?? ''; + if (empty($index)) { + Error::setError( + '310', + 'Index cannot be an empty string', + [ + 'element' => $index + ] + ); + throw new HtmlBuilderExcpetion('Index cannot be an empty string'); + } + if (isset(self::$elements[$index])) { + Error::setError( + '311', + 'Index already exists', + [ + 'element' => $index + ] + ); + throw new HtmlBuilderExcpetion('Index already exists: ' . $index); + } + // content check? + self::$elements[$index] = $el[1]; + } + } + + /** + * update an element at index + * can also be used to reset (empty string) + * + * @param string $index + * @param string $element + * @return void + */ + public static function updateElement(string $index, string $element): void + { + if (!isset(self::$elements[$index])) { + Error::setError( + '312', + 'Index does not exists', + [ + 'element' => $index + ] + ); + throw new HtmlBuilderExcpetion('Index does not exists: ' . $index); + } + // allow empty reset + self::$elements[$index] = $element; + } + + /** + * get an element block at index + * if not found will return false + * + * @param string $index + * @return string + * @throws HtmlBuilderExcpetion + */ + public static function getElement(string $index): string + { + if (!isset(self::$elements[$index])) { + Error::setError('321', 'Index not found in elements', ['element' => $index]); + throw new HtmlBuilderExcpetion('Index not found in elements array: ' . $index); + } + return self::$elements[$index]; + } + + /** + * set a replacement block at index + * can be used for setting one block and using it agai + * + * @param string $index + * @param string $content + * @return void + */ + public static function setReplaceBlock(string $index, string $content): void + { + self::$replace[$index] = $content; + } + + /** + * get replacement block at index, if not found return empty and set error + * + * @param string $index + * @return string + * @throws HtmlBuilderExcpetion + */ + public static function getReplaceBlock(string $index): string + { + if (!isset(self::$replace[$index])) { + Error::setError('331', 'Index not found in replace block', ['replace' => $index]); + throw new HtmlBuilderExcpetion('Index not found in replace block array: ' . $index); + } + return self::$replace[$index]; + } + + /** + * build and element on an index and either returns it or also sets it + * into the replace block array + * if index not found in relement list will return false + * + * @param string $index index of set element + * @param array $replace array of text to search (key) and replace (value) for + * @return string + * @throws HtmlBuilderExcpetion + */ + public static function buildElement( + string $index, + array $replace, + string $replace_index = '' + ): string { + try { + self::getElement($index); + } catch (HtmlBuilderExcpetion $e) { + throw new HtmlBuilderExcpetion('Cannot fetch element with index: ' . $index, 0, $e); + } + if ($replace_index) { + self::setReplaceBlock( + $replace_index, + self::replaceData(self::$elements[$index], $replace) + ); + return self::getReplaceBlock($replace_index); + } else { + return self::replaceData(self::$elements[$index], $replace); + } + } + + /** + * main replace entries in text string + * elements to be replaced are in {} brackets. if they are missing in the + * replace array they will be added. + * if the replace and content count is not the same then an error will be thrown + * + * @param string $data + * @param array $replace + * @return string + * @throws HtmlBuilderExcpetion + */ + public static function replaceData(string $data, array $replace): string + { + $to_replace = array_keys($replace); + // all replace data must have {} around + array_walk($to_replace, function (&$entry) { + if (!str_starts_with($entry, '{')) { + $entry = '{' . $entry; + } + if (!str_ends_with($entry, '}')) { + $entry .= '}'; + } + // do some validation? + }); + // replace content + return str_replace($to_replace, array_values($replace), $data); + } +} + +// __END__ diff --git a/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Combined/CoreLibsCombinedDateTimeTest.php b/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Combined/CoreLibsCombinedDateTimeTest.php index 2dd24809..ddc03cad 100644 --- a/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Combined/CoreLibsCombinedDateTimeTest.php +++ b/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Combined/CoreLibsCombinedDateTimeTest.php @@ -458,6 +458,47 @@ final class CoreLibsCombinedDateTimeTest extends TestCase ]; } + /** + * Undocumented function + * + * @return array + */ + public function dateRangeHasWeekendProvider(): array + { + return [ + 'no weekend' => [ + '2023-07-03', + '2023-07-04', + false + ], + 'start weekend sat' => [ + '2023-07-01', + '2023-07-04', + true + ], + 'start weekend sun' => [ + '2023-07-02', + '2023-07-04', + true + ], + 'end weekend sat' => [ + '2023-07-03', + '2023-07-08', + true + ], + 'end weekend sun' => [ + '2023-07-03', + '2023-07-09', + true + ], + 'long period > 6 days' => [ + '2023-07-03', + '2023-07-27', + true + ] + ]; + } + /** * date string convert test * @@ -780,6 +821,29 @@ final class CoreLibsCombinedDateTimeTest extends TestCase $output ); } + + /** + * Undocumented function + * + * @covers ::dateRangeHasWeekend + * @dataProvider dateRangeHasWeekendProvider + * @testdox dateRangeHasWeekend $start_date and $end_date are expected weekend $expected [$_dataName] + * + * @param string $start_date + * @param string $end_date + * @param bool $expected + * @return void + */ + public function testDateRangeHasWeekend( + string $start_date, + string $end_date, + bool $expected + ): void { + $this->assertEquals( + $expected, + \CoreLibs\Combined\DateTime::dateRangeHasWeekend($start_date, $end_date) + ); + } } // __END__ diff --git a/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Security/CoreLibsSecuritySymmetricEncryption.php b/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Security/CoreLibsSecuritySymmetricEncryptionTest.php similarity index 98% rename from www/vendor/egrajp/corelibs-composer-all/test/phpunit/Security/CoreLibsSecuritySymmetricEncryption.php rename to www/vendor/egrajp/corelibs-composer-all/test/phpunit/Security/CoreLibsSecuritySymmetricEncryptionTest.php index 9e2773da..33a2f458 100644 --- a/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Security/CoreLibsSecuritySymmetricEncryption.php +++ b/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Security/CoreLibsSecuritySymmetricEncryptionTest.php @@ -13,7 +13,7 @@ use CoreLibs\Security\SymmetricEncryption; * @coversDefaultClass \CoreLibs\Security\SymmetricEncryption * @testdox \CoreLibs\Security\SymmetricEncryption method tests */ -final class CoreLibsSecuritySymmetricEncryption extends TestCase +final class CoreLibsSecuritySymmetricEncryptionTest extends TestCase { /** * Undocumented function diff --git a/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Template/CoreLibsTemplateHtmlBuilderBlockTest.php b/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Template/CoreLibsTemplateHtmlBuilderBlockTest.php new file mode 100644 index 00000000..0350af92 --- /dev/null +++ b/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Template/CoreLibsTemplateHtmlBuilderBlockTest.php @@ -0,0 +1,34 @@ + 'foo();']); + $this->assertEquals( + '
content
', + Block::buildHtml($el) + ); + } + + // ael + // aelx|addSub + // resetSub + // acssel/rcssel/scssel + // buildHtml + // buildHtmlFromList|printHtmlFromArray +} + +// __END__ diff --git a/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Template/CoreLibsTemplateHtmlBuilderElementTest.php b/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Template/CoreLibsTemplateHtmlBuilderElementTest.php new file mode 100644 index 00000000..7c96e32f --- /dev/null +++ b/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Template/CoreLibsTemplateHtmlBuilderElementTest.php @@ -0,0 +1,546 @@ + [ + 'tag' => 'div', + 'id' => 'id', + 'content' => 'content', + 'css' => ['css'], + 'options' => ['onclick' => 'foo();'], + 'expected' => '
content
' + ], + 'simple input' => [ + 'tag' => 'input', + 'id' => 'id', + 'content' => null, + 'css' => ['css'], + 'options' => ['name' => 'name', 'onclick' => 'foo();'], + 'expected' => '' + ] + ]; + } + + + /** + * Undocumented function + * + * @covers ::Element + * @covers ::buildHtml + * @covers ::getTag + * @covers ::getId + * @covers ::getContent + * @covers ::getOptions + * @covers ::getCss + * @dataProvider providerCreateElements + * @testdox create single new Element test [$_dataName] + * + * @param string $tag + * @param string|null $id + * @param string|null $content + * @param array|null $css + * @param array|null $options + * @param string $expected + * @return void + */ + public function testCreateElement( + string $tag, + ?string $id, + ?string $content, + ?array $css, + ?array $options, + string $expected + ): void { + $el = new Element($tag, $id ?? '', $content ?? '', $css ?? [], $options ?? []); + $this->assertEquals( + $expected, + $el->buildHtml(), + 'element creation failed' + ); + + $this->assertEquals( + $tag, + $el->getTag(), + 'get tag failed' + ); + + if ($id !== null) { + $this->assertEquals( + $id, + $el->getId(), + 'get id failed' + ); + } + if ($content !== null) { + $this->assertEquals( + $content, + $el->getContent(), + 'get content failed' + ); + } + if ($css !== null) { + $this->assertEquals( + $css, + $el->getCss(), + 'get css failed' + ); + } + if ($options !== null) { + $this->assertEquals( + $options, + $el->getOptions(), + 'get options failed' + ); + } + if (!empty($options['name'])) { + $this->assertEquals( + $options['name'], + $el->getName(), + 'get name failed' + ); + } + } + + /** + * css add/remove + * + * @cover ::getCss + * @cover ::addCss + * @cover ::removeCss + * @testdox test handling of adding and removing css classes + * + * @return void + */ + public function testCssHandling(): void + { + $el = new Element('div', 'css-test', 'CSS content'); + $this->assertEqualsCanonicalizing( + [], + $el->getCss(), + 'check empty css' + ); + $el->addCss('foo'); + $this->assertEqualsCanonicalizing( + ['foo'], + $el->getCss(), + 'check added one css' + ); + $el->removeCss('foo'); + $this->assertEqualsCanonicalizing( + [], + $el->getCss(), + 'check remove added css' + ); + // add serveral + // remove some of them + $el->addCss('a', 'b', 'c'); + $this->assertEqualsCanonicalizing( + ['a', 'b', 'c'], + $el->getCss(), + 'check added some css' + ); + $el->removeCss('a', 'c'); + // $this->assertArray + $this->assertEqualsCanonicalizing( + ['b'], + $el->getCss(), + 'check remove some css' + ); + // chained add and remove + $el->addCss('a', 'b', 'c', 'd')->removeCss('b', 'd'); + $this->assertEqualsCanonicalizing( + ['a', 'c'], + $el->getCss(), + 'check chain add remove some css' + ); + $el->resetCss(); + $this->assertEqualsCanonicalizing( + [], + $el->getCss(), + 'check reset css' + ); + // remove something that does not eixst + $el->addCss('exists'); + $el->removeCss('not'); + $this->assertEqualsCanonicalizing( + ['exists'], + $el->getCss(), + 'check remove not exitsing' + ); + } + + /** + * nested test + * + * @testdox nested test and loop assign detection + * + * @return void + */ + public function testBuildNested(): void + { + Error::resetMessages(); + $el = new Element('div', 'build-test'); + $el_sub = new Element('div', 'sub-1'); + $el->addSub($el_sub); + $this->assertEquals( + '
', + $el->buildHtml(), + 'nested build failed' + ); + // this would create a loop, throws error + $this->expectException(HtmlBuilderExcpetion::class); + $this->expectExceptionMessage("Cannot assign Element to itself, this would create an infinite loop"); + $el_sub->addSub($el_sub); + $this->assertEquals( + '
', + $el_sub->buildHtml(), + 'loop detection failed' + ); + $this->assertTrue( + Error::hasError(), + 'failed to throw error post loop detection' + ); + $this->assertEquals( + [[ + 'level' => 'Error', + 'id' => '100', + 'message' => 'Cannot assign Element to itself, this would create an infinite loop', + 'context' => ['tag' => 'div', 'id' => 'sub-1'] + ]], + Error::getMessages(), + 'check error is 100 failed' + ); + // get sub + $this->assertEquals( + [$el_sub], + $el->getSub(), + 'get sub failed' + ); + // reset sub + $el->resetSub(); + $this->assertEquals( + [], + $el->getSub(), + 'reset sub failed' + ); + } + + /** + * Undocumented function + * + * @testdox updated nested connection + * + * @return void + */ + public function testNestedChangeContent(): void + { + $el = new Element('div', 'build-test'); + $el_s_1 = new Element('div', 'sub-1'); + $el_s_2 = new Element('div', 'sub-2'); + $el_s_3 = new Element('div', 'sub-3'); + $el_s_4 = new Element('div', 'sub-4'); + + $el->addSub($el_s_1, $el_s_2); + // only sub -1, -2 + $this->assertEquals( + '
', + $el->buildHtml(), + 'check basic nested' + ); + + // now add -3, -4 to both -1 and -2 + $el_s_1->addSub($el_s_3, $el_s_4); + $el_s_2->addSub($el_s_3, $el_s_4); + $this->assertEquals( + '
' + . '
' + . '
', + $el->buildHtml(), + 'check nested added' + ); + + // now add some css to el_s_3, will update in both sets + $el_s_3->addCss('red'); + $this->assertEquals( + '
' + . '
' + . '
', + $el->buildHtml(), + 'check nested u@dated' + ); + } + + /** + * Undocumented function + * + * @testdox test change tag/id/content + * + * @return void + */ + public function testChangeElementData(): void + { + $el = new Element('div', 'id', 'Content'); + // content change + $this->assertEquals( + 'Content', + $el->getContent(), + 'set content' + ); + $el->setContent('New Content'); + $this->assertEquals( + 'New Content', + $el->getContent(), + 'changed content' + ); + + $this->assertEquals( + 'div', + $el->getTag(), + 'set tag' + ); + $el->setTag('span'); + $this->assertEquals( + 'span', + $el->getTag(), + 'changed tag' + ); + + $this->assertEquals( + 'id', + $el->getId(), + 'set id' + ); + $el->setId('id-2'); + $this->assertEquals( + 'id-2', + $el->getId(), + 'changed id' + ); + } + + /** + * Undocumented function + * + * @testdox test change options + * + * @return void + */ + public function testChangeOptions(): void + { + $el = new Element('button', 'id', 'Action', ['css'], ['value' => '3']); + $this->assertEquals( + ['value' => '3'], + $el->getOptions(), + 'set option' + ); + $el->setOptions([ + 'value' => '2' + ]); + $this->assertEquals( + ['value' => '2'], + $el->getOptions(), + 'changed option' + ); + // add a new one + $el->setOptions([ + 'Foo' => 'bar', + 'Moo' => 'cow' + ]); + $this->assertEquals( + [ + 'value' => '2', + 'Foo' => 'bar', + 'Moo' => 'cow' + ], + $el->getOptions(), + 'changed option' + ); + } + + // build output + // build from array list + + /** + * Undocumented function + * + * @testdox build element tree from object + * + * @return void + */ + public function testBuildHtmlObject(): void + { + // build a simple block + // div -> div -> button + // -> div -> span + // -> div -> input + $el = new Element('div', 'master', '', ['master']); + $el->addSub( + Element::addElement( + new Element('div', 'div-button', '', ['dv-bt']), + new Element('button', 'button-id', 'Click me', ['bt-red'], [ + 'OnClick' => 'action();', + 'value' => 'click', + 'type' => 'button' + ]), + ), + Element::addElement( + new Element('div', 'div-span', '', ['dv-sp']), + new Element('span', 'span-id', 'Big important message
other', ['red']), + ), + Element::addElement( + new Element('div', 'div-input', '', ['dv-in']), + new Element('input', 'input-id', '', ['in-blue'], [ + 'OnClick' => 'otherAction();', + 'value' => 'Touch', + 'type' => 'button' + ]), + ), + ); + $this->assertEquals( + '
' + . '
' + . '' + . '
' + . '
' + . 'Big important message
other
' + . '
' + . '
' + . '' + . '
' + . '
', + $el->buildHtml() + ); + } + + /** + * Undocumented function + * + * @testdox build elements from array list + * + * @return void + */ + public function testbuildHtmlArray(): void + { + $this->assertEquals( + '
A
' + . '
B
' + . '
C
', + Element::buildHtmlFromList([ + new Element('div', 'id-1', 'A'), + new Element('div', 'id-2', 'B'), + new Element('div', 'id-3', 'C'), + ]) + ); + } + + /** + * Undocumented function + * + * @testdox check for invalid tag detection, possible invalid id, possible invalid css + * + * @return void + */ + public function testInvalidElement(): void + { + Error::resetMessages(); + $this->expectException(HtmlBuilderExcpetion::class); + $this->expectExceptionMessage("Could not create Element"); + $el = new Element(''); + $this->assertTrue( + Error::hasError(), + 'failed to set error invalid tag detection' + ); + $this->assertEquals( + [[ + 'level' => 'Error', + 'id' => '201', + 'message' => 'invalid or empty tag', + 'context' => ['tag' => ''] + ]], + Error::getMessages(), + 'check error message failed' + ); + + // if we set invalid tag + $el = new Element('div'); + $this->expectException(HtmlBuilderExcpetion::class); + $this->expectExceptionMessageMatches("/^Invalid or empty tag: /"); + $this->expectExceptionMessage("Invalid or empty tag: 123123"); + $el->setTag('123123'); + $this->assertTrue( + Error::hasError(), + 'failed to set error invalid tag detection' + ); + $this->assertEquals( + [[ + 'level' => 'Error', + 'id' => '201', + 'message' => 'invalid or empty tag', + 'context' => ['tag' => ''] + ]], + Error::getMessages(), + 'check error message failed' + ); + + + // invalid id (warning) + Error::resetMessages(); + $el = new Element('div', '-$a15'); + $this->assertTrue( + Error::hasWarning(), + 'failed to set warning invalid id detection' + ); + $this->assertEquals( + [[ + 'level' => 'Warning', + 'id' => '202', + 'message' => 'possible invalid id', + 'context' => ['id' => '-$a15', 'tag' => 'div'] + ]], + Error::getMessages(), + 'check error message failed' + ); + + // invalid name + Error::resetMessages(); + $el = new Element('div', 'valid', '', [], ['name' => '-$asdf&']); + $this->assertTrue( + Error::hasWarning(), + 'failed to set warning invalid name detection' + ); + $this->assertEquals( + [[ + 'level' => 'Warning', + 'id' => '203', + 'message' => 'possible invalid name', + 'context' => ['name' => '-$asdf&', 'id' => 'valid', 'tag' => 'div'] + ]], + Error::getMessages(), + 'check error message failed' + ); + } + + // static add element + // print object/array +} + +// __END__ diff --git a/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Template/CoreLibsTemplateHtmlBuilderStringReplaceTest.php b/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Template/CoreLibsTemplateHtmlBuilderStringReplaceTest.php new file mode 100644 index 00000000..491d8892 --- /dev/null +++ b/www/vendor/egrajp/corelibs-composer-all/test/phpunit/Template/CoreLibsTemplateHtmlBuilderStringReplaceTest.php @@ -0,0 +1,65 @@ + + {CONTENT} + +HTML; + + $this->assertEquals( + << + Some content here
with bla bla inside + +HTML, + StringReplace::replaceData( + $html_block, + [ + 'ID' => 'block-id', + 'CSS' => join(',', ['blue', 'red']), + '{CONTENT}' => 'Some content here
with bla bla inside', + ] + ) + ); + } + + /** + * Undocumented function + * + * @testdox replaceData error + * + * @return void + */ + /* public function testReplaceDataErrors(): void + { + $this->expectException(HtmlBuilderExcpetion::class); + $this->expectExceptionMessage("Replace and content array count differ"); + StringReplace::replaceData('{FOO}', ['{FOO}', '{BAR}'], ['foo']); + } */ +} + +// __END__