diff --git a/src/App.php b/src/App.php index 6ad3f5072b..a3cf4b8fae 100644 --- a/src/App.php +++ b/src/App.php @@ -888,12 +888,12 @@ public function isVoidTag(string $tag): bool * ]) * --> welcome' * - * @param array<0|string, string|bool> $attr - * @param string|array, 2?: string|array|null}|string>|null $value + * @param array<0|string, string|bool> $attr + * @param string|array, 2?: string|array|null}|string>|null $value */ - public function getTag(string $tag = null, array $attr = [], $value = null): string + public function getTag(string $tag, array $attr = [], $value = null): string { - $tag = strtolower($tag === null ? 'div' : $tag); + $tag = strtolower($tag); $tagOrig = $tag; $isOpening = true; diff --git a/src/Form/Control/Dropdown.php b/src/Form/Control/Dropdown.php index 67bacdf07c..b306299bfa 100644 --- a/src/Form/Control/Dropdown.php +++ b/src/Form/Control/Dropdown.php @@ -111,8 +111,6 @@ protected function init(): void * Returns presentable value to be inserted into input tag. * * Dropdown input tag accepts only CSV formatted list of IDs. - * - * @return mixed */ public function getValue() { diff --git a/src/Form/Control/Input.php b/src/Form/Control/Input.php index fd905b64f1..d8fbee3a83 100644 --- a/src/Form/Control/Input.php +++ b/src/Form/Control/Input.php @@ -88,7 +88,7 @@ public function setInputAttr($name, $value = null) /** * Returns presentable value to be inserted into input tag. * - * @return mixed + * @return string|null */ public function getValue() { diff --git a/src/Form/Control/ScopeBuilder.php b/src/Form/Control/ScopeBuilder.php index e0228bfae2..15ed73f619 100644 --- a/src/Form/Control/ScopeBuilder.php +++ b/src/Form/Control/ScopeBuilder.php @@ -502,24 +502,23 @@ protected function renderView(): void */ public function queryToScope(array $query): Scope\AbstractScope { - $type = $query['type'] ?? 'query-builder-group'; - $query = $query['query'] ?? $query; + if (!isset($query['type'])) { + $query = ['type' => 'query-builder-group', 'query' => $query]; + } - switch ($type) { - case 'query-builder-group': - $components = array_map(fn ($v) => $this->queryToScope($v), $query['children']); - $scope = new Scope($components, $query['logicalOperator']); + switch ($query['type']) { + case 'query-builder-rule': + $scope = $this->queryToCondition($query['query']); break; - case 'query-builder-rule': - $scope = $this->queryToCondition($query); + case 'query-builder-group': + $components = array_map(fn ($v) => $this->queryToScope($v), $query['query']['children']); + $scope = new Scope($components, $query['query']['logicalOperator']); break; - default: - $scope = Scope::createAnd(); } - return $scope; + return $scope; // @phpstan-ignore-line } /** diff --git a/src/Table/Column.php b/src/Table/Column.php index e9e24b78b7..808a2e45c9 100644 --- a/src/Table/Column.php +++ b/src/Table/Column.php @@ -246,9 +246,9 @@ public function getTagAttributes(string $position, array $attr = []): array * Returns a suitable cell tag with the supplied value. Applies modifiers * added through addClass and setAttr. * - * @param string $position 'head', 'body' or 'tail' - * @param string|array $value either HTML or array defining HTML structure, see App::getTag help - * @param array $attr extra attributes to apply on the tag + * @param string $position 'head', 'body' or 'tail' + * @param string|array, 2?: string|array|null}|string>|null $value either HTML or array defining HTML structure, see App::getTag help + * @param array $attr extra attributes to apply on the tag */ public function getTag(string $position, $value, array $attr = []): string { @@ -291,7 +291,7 @@ public function getHeaderCellHtml(Field $field = null, $value = null): string $attr['id'] = $this->name . '_th'; // add the action tag to the caption - $caption = [$this->headerActionTag, $caption]; + $caption = [$this->headerActionTag, $this->getApp()->encodeHtml($caption)]; } if ($this->table->sortable) { diff --git a/src/Table/Column/ActionButtons.php b/src/Table/Column/ActionButtons.php index ed1e7fdc8c..13c372ddc2 100644 --- a/src/Table/Column/ActionButtons.php +++ b/src/Table/Column/ActionButtons.php @@ -118,12 +118,12 @@ public function getDataCellTemplate(Field $field = null): string } // render our buttons - $output = ''; + $outputHtml = ''; foreach ($this->buttons as $button) { - $output .= $button->getHtml(); + $outputHtml .= $button->getHtml(); } - return $this->getApp()->getTag('div', ['class' => 'ui buttons'], [$output]); + return $this->getApp()->getTag('div', ['class' => 'ui buttons'], [$outputHtml]); } public function getHtmlTags(Model $row, ?Field $field): array diff --git a/src/Table/Column/ActionMenu.php b/src/Table/Column/ActionMenu.php index 09850af4a0..9e6c256fbd 100644 --- a/src/Table/Column/ActionMenu.php +++ b/src/Table/Column/ActionMenu.php @@ -120,15 +120,15 @@ public function getDataCellTemplate(Field $field = null): string } // render our menus - $output = ''; + $outputHtml = ''; foreach ($this->items as $item) { - $output .= $item->getHtml(); + $outputHtml .= $item->getHtml(); } $res = $this->getApp()->getTag('div', ['class' => 'ui ' . $this->ui . ' atk-action-menu'], [ ['div', ['class' => 'text'], $this->label], $this->icon ? $this->getApp()->getTag('i', ['class' => $this->icon . ' icon'], '') : '', - ['div', ['class' => 'menu'], [$output]], + ['div', ['class' => 'menu'], [$outputHtml]], ]); return $res; diff --git a/src/Table/Column/Labels.php b/src/Table/Column/Labels.php index a019f49bf1..07170a278a 100644 --- a/src/Table/Column/Labels.php +++ b/src/Table/Column/Labels.php @@ -16,7 +16,7 @@ */ class Labels extends Table\Column { - /** @var array|null Allowed values, prioritized over Field::$values */ + /** @var array|null Allowed values, prioritized over Field::$values */ public ?array $values = null; public function getHtmlTags(Model $row, ?Field $field): array @@ -29,10 +29,10 @@ public function getHtmlTags(Model $row, ?Field $field): array $labelsHtml = []; foreach ($v as $id) { // if field values is set, then use titles instead of IDs - $id = $values[$id] ?? $id; + $label = $values[$id] ?? $id; - if ($id !== '') { - $labelsHtml[] = $this->getApp()->getTag('div', ['class' => 'ui label'], $id); + if ($label !== '') { + $labelsHtml[] = $this->getApp()->getTag('div', ['class' => 'ui label'], $label); } } diff --git a/src/Table/Column/Link.php b/src/Table/Column/Link.php index 058149d421..4f7ee68b0a 100644 --- a/src/Table/Column/Link.php +++ b/src/Table/Column/Link.php @@ -121,21 +121,21 @@ public function getDataCellTemplate(Field $field = null): string $attr['target'] = $this->target; } - $icon = ''; + $iconHtml = ''; if ($this->icon) { - $icon = $this->getApp()->getTag('i', ['class' => $this->icon . ' icon'], ''); + $iconHtml = $this->getApp()->getTag('i', ['class' => $this->icon . ' icon'], ''); } - $label = ''; + $labelHtml = ''; if ($this->useLabel) { - $label = $field ? ('{$' . $field->shortName . '}') : '[Link]'; + $labelHtml = $field ? ('{$' . $field->shortName . '}') : '[Link]'; } if ($this->class) { $attr['class'] = $this->class; } - return $this->getApp()->getTag('a', $attr, [$icon, $label]); // TODO $label is not HTML encoded + return $this->getApp()->getTag('a', $attr, [$iconHtml, $labelHtml]); } public function getHtmlTags(Model $row, ?Field $field): array diff --git a/src/Table/Column/Status.php b/src/Table/Column/Status.php index 8e531ea3a0..ae466775fb 100644 --- a/src/Table/Column/Status.php +++ b/src/Table/Column/Status.php @@ -46,7 +46,8 @@ public function getDataCellHtml(Field $field = null, array $attr = []): string } return $this->getApp()->getTag('td', $attr, [ - $this->getApp()->getTag('i', ['class' => 'icon {$_' . $field->shortName . '_icon}'], '') . ' {$' . $field->shortName . '}', + ['i', ['class' => 'icon {$_' . $field->shortName . '_icon}'], ''], + ' {$' . $field->shortName . '}', ]); } diff --git a/src/Table/Column/Tooltip.php b/src/Table/Column/Tooltip.php index f9a75f37c5..e3cf5d56e1 100644 --- a/src/Table/Column/Tooltip.php +++ b/src/Table/Column/Tooltip.php @@ -47,13 +47,13 @@ public function getDataCellHtml(Field $field = null, array $attr = []): string } return $this->getApp()->getTag('td', $attr, [ - ' {$' . $field->shortName . '}' - . $this->getApp()->getTag('span', [ - 'class' => 'ui icon link {$_' . $field->shortName . '_data_visible_class}', - 'data-tooltip' => '{$_' . $field->shortName . '_data_tooltip}', - ], [ - ['i', ['class' => 'ui icon {$_' . $field->shortName . '_icon}']], - ]), + ' {$' . $field->shortName . '}', + ['span', [ + 'class' => 'ui icon link {$_' . $field->shortName . '_data_visible_class}', + 'data-tooltip' => '{$_' . $field->shortName . '_data_tooltip}', + ], [ + ['i', ['class' => 'ui icon {$_' . $field->shortName . '_icon}']], + ]], ]); } diff --git a/tests/TagTest.php b/tests/TagTest.php index 4caa2308ee..07ff4194d2 100644 --- a/tests/TagTest.php +++ b/tests/TagTest.php @@ -10,6 +10,9 @@ class TagTest extends TestCase { + /** + * @param array{0: string, 1?: array<0|string, string|bool>, 2?: string|array|null} $args + */ public static function assertTagRender(string $expectedHtml, array $args): void { $app = (new \ReflectionClass(App::class))->newInstanceWithoutConstructor(); @@ -21,12 +24,11 @@ public function testBasic(): void { self::assertTagRender('', ['b']); self::assertTagRender('hello world', ['b', [], 'hello world']); - self::assertTagRender('
', []); } public function testEscaping(): void { - self::assertTagRender('
', [null, ['foo' => 'he"llo']]); + self::assertTagRender('
', ['div', ['foo' => 'he"llo']]); self::assertTagRender('bold text >>', ['b', [], 'bold text >>']); }