diff --git a/composer.json b/composer.json index c062dcda0..0371b2d93 100644 --- a/composer.json +++ b/composer.json @@ -26,6 +26,7 @@ "php": "^8.0", "ext-json": "*", "ext-mbstring": "*", + "psr/container": "^1.0|^2.0", "yiisoft/arrays": "^2.0|^3.0", "yiisoft/data": "dev-master", "yiisoft/factory": "^1.0", diff --git a/src/BaseListView.php b/src/BaseListView.php index 9c0f328cc..976f517d8 100644 --- a/src/BaseListView.php +++ b/src/BaseListView.php @@ -46,7 +46,7 @@ abstract class BaseListView extends Widget private string $layoutGridTable = "{items}\n{summary}\n{pager}"; private string $pagination = ''; protected ?ReadableDataInterface $dataReader = null; - private array $sortLinkAttributes = []; + protected array $sortLinkAttributes = []; private ?string $summary = null; private array $summaryAttributes = []; private string $toolbar = ''; diff --git a/src/Column/AbstractColumn.php b/src/Column/AbstractColumn.php deleted file mode 100644 index abf382086..000000000 --- a/src/Column/AbstractColumn.php +++ /dev/null @@ -1,354 +0,0 @@ -attributes = $values; - - return $new; - } - - /** - * Return new instance with the column content. - * - * @param Closure $value This is a callable that will be used to generate the content. - * - * The signature of the function should be the following: `function ($data, $key, $index, $column)`. - * - * Where `$data`, `$key`, and `$index` refer to the data, key and index of the row currently being rendered - * and `$column` is a reference to the {@see Column} object. - */ - public function content(Closure $value): static - { - $new = clone $this; - $new->content = $value; - - return $new; - } - - /** - * Return new instance with the HTML attributes for the column content. - * - * @param array $values Attribute values indexed by attribute names. - */ - public function contentAttributes(array $values): static - { - $new = clone $this; - $new->contentAttributes = $values; - - return $new; - } - - /** - * Return new instance with the data label for the column content. - * - * @param string $value The data label for the column content. - */ - public function dataLabel(string $value): static - { - $new = clone $this; - $new->contentAttributes['data-label'] = $value; - - return $new; - } - - /** - * Return new instance with the HTML display when the content is empty. - * - * @param string $value The HTML display when the content of a cell is empty. This property is used to render cells - * that have no defined content, e.g. empty footer or filter cells. - */ - public function emptyCell(string $value): static - { - $new = clone $this; - $new->emptyCell = $value; - - return $new; - } - - /** - * Return new instance with the HTML attributes for the filter cell. - * - * @param array $values Attribute values indexed by attribute names. - */ - public function filterAttributes(array $values): static - { - $new = clone $this; - $new->filterAttributes = $values; - - return $new; - } - - /** - * Return new instance with the footer content. - * - * @param string $value The footer content. - */ - public function footer(string $value): static - { - $new = clone $this; - $new->footer = $value; - - return $new; - } - - /** - * Return new instance with the HTML attributes for the footer cell. - * - * @param array $value Attribute values indexed by attribute names. - */ - public function footerAttributes(array $value): static - { - $new = clone $this; - $new->footerAttributes = $value; - - return $new; - } - - public function getAttributes(): array - { - return $this->attributes; - } - - public function isVisible(): bool - { - return $this->visible; - } - - /** - * Return new instance with the label for the column. - * - * @param string $value The label to be displayed in the {@see header|header cell} and also to be used as the - * sorting link label when sorting is enabled for this column. - * - * If it is not set and the active record classes provided by the GridViews data provider are instances of the - * object data, the label will be determined using Otherwise {@see Inflector::toHumanReadable()} will be used to - * get a label. - */ - public function label(string $value): static - { - $new = clone $this; - $new->label = $value; - - return $new; - } - - /** - * Return new instance with the HTML attributes for the header cell. - * - * @param array $value Attribute values indexed by attribute names. - */ - public function labelAttributes(array $value): static - { - $new = clone $this; - $new->labelAttributes = $value; - - return $new; - } - - /** - * Return new instance with the name of the column. - * - * @param string $value The name of the column. - */ - public function name(string $value): static - { - $new = clone $this; - $new->contentAttributes['name'] = $value; - - return $new; - } - - /** - * Renders a data cell. - * - * @param array|object $data The data. - * @param mixed $key The key associated with the data. - * @param int $index The zero-based index of the data in the data provider. - */ - public function renderDataCell(array|object $data, mixed $key, int $index): string - { - $contentAttributes = $this->contentAttributes; - - /** - * @var string $name - * @var mixed $value - */ - foreach ($contentAttributes as $name => $value) { - if ($value instanceof Closure) { - /** @var mixed */ - $contentAttributes[$name] = $value($data, $key, $index, $this); - } - } - - if (!array_key_exists('data-label', $contentAttributes) && $this->getLabel() !== '') { - $contentAttributes['data-label'] = mb_strtolower($this->getLabel(), 'UTF-8'); - } - - return Td::tag() - ->attributes($contentAttributes) - ->content($this->renderDataCellContent($data, $key, $index)) - ->encode(false) - ->render(); - } - - /** - * Renders the filter cell. - */ - public function renderFilterCell(): string - { - return Th::tag() - ->attributes($this->filterAttributes) - ->content($this->renderFilterCellContent()) - ->encode(false) - ->render(); - } - - /** - * Renders the footer cell. - */ - public function renderFooterCell(): string - { - return Td::tag() - ->attributes($this->footerAttributes) - ->content($this->renderFooterCellContent()) - ->encode(false) - ->render(); - } - - /** - * Renders the header cell. - */ - public function renderHeaderCell(): string - { - return Th::tag() - ->attributes($this->labelAttributes) - ->content($this->renderHeaderCellContent()) - ->encode(false) - ->render(); - } - - /** - * Return new instance specifying whether the column is visible or not. - * - * @param bool $value Whether the column is visible or not. - */ - public function visible(bool $value): static - { - $new = clone $this; - $new->visible = $value; - - return $new; - } - - public static function create(): static - { - return new static(); - } - - protected function getContent(): Closure|null - { - return $this->content; - } - - protected function getContentAttributes(): array - { - return $this->contentAttributes; - } - - protected function getEmptyCell(): string - { - return $this->emptyCell; - } - - protected function getLabel(): string - { - return $this->label; - } - - /** - * Renders the data cell content. - * - * @param array|object $data The data. - * @param mixed $key The key associated with the data. - * @param int $index The zero-based index of the data in the data provider. - */ - protected function renderDataCellContent(array|object $data, mixed $key, int $index): string - { - $html = $this->emptyCell; - - if ($this->content !== null) { - $html = (string) call_user_func($this->content, $data, $key, $index, $this); - } - - return $html; - } - - /** - * Renders the filter cell content. - * - * The default implementation simply renders a space. - * This method may be overridden to customize the rendering of the filter cell (if any). - */ - protected function renderFilterCellContent(): string - { - return $this->emptyCell; - } - - /** - * Renders the header cell content. - * - * The default implementation simply renders {@see header}. - * This method may be overridden to customize the rendering of the header cell. - */ - protected function renderHeaderCellContent(): string - { - return $this->getLabel() !== '' ? $this->getLabel() : $this->emptyCell; - } - - /** - * Renders the footer cell content. - * - * The default implementation simply renders {@see footer}. - * This method may be overridden to customize the rendering of the footer cell. - */ - private function renderFooterCellContent(): string - { - return $this->footer !== '' ? $this->footer : $this->emptyCell; - } -} diff --git a/src/Column/ActionColumn.php b/src/Column/ActionColumn.php index a2ab5d5a4..a6d920e90 100644 --- a/src/Column/ActionColumn.php +++ b/src/Column/ActionColumn.php @@ -5,428 +5,137 @@ namespace Yiisoft\Yii\DataView\Column; use Closure; -use InvalidArgumentException; -use Yiisoft\Html\Tag\A; -use Yiisoft\Html\Tag\Span; -use Yiisoft\Router\CurrentRoute; -use Yiisoft\Router\UrlGeneratorInterface; - -use function is_array; /** - * ActionColumn is a column for the {@see GridView} widget that displays buttons for viewing and manipulating the items. + * `ActionColumn` is a column for the {@see GridView} widget that displays buttons for viewing and manipulating + * the items. */ -final class ActionColumn extends AbstractColumn +final class ActionColumn implements ColumnInterface { - private array $buttons = []; - private string $primaryKey = 'id'; - private string $template = '{view}{update}{delete}'; - private array|null $urlArguments = null; - private Closure|null $urlCreator = null; - private CurrentRoute $currentRoute; - private UrlGeneratorInterface|null $urlGenerator = null; - private array $urlParamsConfig = []; - private string $urlName = ''; - private array $urlQueryParameters = []; - private array $visibleButtons = []; - /** - * Return new instance with the buttons array. - * - * @param array $value button rendering callbacks. The array keys are the button names (without curly brackets), - * and the values are the corresponding button rendering callbacks. The callbacks should use the following - * signature: - * - * ```php - * [ - * buttons => [ - * 'action' => function (string $url, $data, int $key) { - * // return the button HTML code - * } - * ], - * ] - * ``` - * - * where `$url` is the URL that the column creates for the button, `$data` is the data object being rendered - * for the current row, and `$key` is the key of the data in the data provider array. - * - * You can add further conditions to the button, for example only display it, when the data is editable (here - * assuming you have a status field that indicates that): - * - * ```php - * [ - * buttons = [ - * 'update' => function (string $url, $data, $key) { - * return $data->status === 'editable' ? Html::a('Update', $url) : ''; - * }, - * ], - * ], - * ``` + * @var callable|null */ - public function buttons(array $value): self - { - $new = clone $this; - $new->buttons = $value; - - return $new; - } + private $urlCreator; /** - * Initializes the default button rendering callback for single button. + * @psalm-param array $buttons + * @psalm-param array $visibleButtons */ - public function createDefaultButtons(): self - { - /** @psalm-var array */ - $defaultButtons = [ - 'view' => static fn (string $url): string => A::tag() - ->attributes( - [ - 'name' => 'view', - 'role' => 'button', - 'style' => 'text-decoration: none!important;', - 'title' => 'View', - ], - ) - ->content(Span::tag()->content('🔎')) - ->href($url) - ->render(), - 'update' => static fn (string $url): string => A::tag() - ->attributes( - [ - 'name' => 'update', - 'role' => 'button', - 'style' => 'text-decoration: none!important;', - 'title' => 'Update', - ], - ) - ->content(Span::tag()->content('✎')) - ->href($url) - ->render(), - 'delete' => static fn (string $url): string => A::tag() - ->attributes( - [ - 'name' => 'delete', - 'role' => 'button', - 'style' => 'text-decoration: none!important;', - 'title' => 'Delete', - ], - ) - ->content(Span::tag()->content('❌')) - ->href($url) - ->render(), - ]; - - $new = clone $this; - - foreach ($defaultButtons as $name => $button) { - $new->buttons[$name] = $button; - } - - return $new; + public function __construct( + private string $primaryKey = 'id', + private string $template = "{view}\n{update}\n{delete}", + private ?string $routeName = null, + private array $urlParamsConfig = [], + private ?array $urlArguments = null, + private array $urlQueryParameters = [], + ?callable $urlCreator = null, + private ?string $header = null, + private ?string $footer = null, + private mixed $content = null, + private array $buttons = [], + private array $visibleButtons = [], + private array $columnAttributes = [], + private array $headerAttributes = [], + private array $bodyAttributes = [], + private array $footerAttributes = [], + private bool $visible = true, + ) { + $this->urlCreator = $urlCreator; } - public function currentRoute(CurrentRoute $value): self + public function getPrimaryKey(): string { - $new = clone $this; - $new->currentRoute = $value; - - return $new; + return $this->primaryKey; } - public function getLabel(): string + public function getTemplate(): string { - $label = parent::getLabel(); - - return $label !== '' ? $label : 'Actions'; + return $this->template; } - public function getUrlGenerator(): UrlGeneratorInterface + public function getRouteName(): ?string { - if ($this->urlGenerator === null) { - throw new InvalidArgumentException('Url generator is not set.'); - } - - return $this->urlGenerator; + return $this->routeName; } - /** - * Return new instance specifying which is the primaryKey of the data to be used to generate the url automatically. - * - * @param string $value the primaryKey of the data to be used to generate the url automatically. - */ - public function primaryKey(string $value): self + public function getUrlParamsConfig(): array { - $new = clone $this; - $new->primaryKey = $value; - - return $new; + return $this->urlParamsConfig; } - /** - * Return new instance with the template set. - * - * @param string $value The template used for composing each cell in the action column. Tokens enclosed within curly - * brackets are treated as controller action IDs (also called *button names* in the context of action column). - * - * They will be replaced by the corresponding button rendering callbacks specified in {@see buttons}. For example, - * the token `{view}` will be replaced by the result of the callback `buttons['view']`. If a callback cannot be - * found, the token will be replaced with an empty string. - * - * As an example, to only have the view, and update button you can add the ActionColumn to your GridView columns as - * follows: - * - * ```php - * [ - * 'class' => ActionColumn::class, - * 'template()' => ['{view} {update} {delete}'], - * ], - * ``` - * - * {@see buttons} - */ - public function template(string $value): self + public function getUrlArguments(): ?array { - $new = clone $this; - - $result = preg_match_all('/{([\w\-\/]+)}/', $value, $matches); - - if ($result > 0 && !empty($matches[1])) { - $new->buttons = array_intersect_key($new->buttons, array_flip($matches[1])); - } - - $new->template = $value; - - return $new; + return $this->urlArguments; } - /** - * Return a new instance with arguments of the route. - * - * @param array $value Arguments of the route. - */ - public function urlArguments(array $value): self + public function getUrlQueryParameters(): array { - $new = clone $this; - $new->urlArguments = $value; - - return $new; + return $this->urlQueryParameters; } - /** - * Return a new instance with the url creator. - * - * @param Closure $value The url creator. - * - * The signature of the callback should be the same as that of {@see createUrl()}. It can accept additional - * parameter, which refers to the column instance itself: - * ```php - * function (string $action, array|object $data, mixed $key, int $index) { - * //return string; - * } - * ``` - * - * If this property is not set, button URLs will be created using {@see createUrl()}. - */ - public function urlCreator(Closure $value): self + public function getUrlCreator(): ?callable { - $new = clone $this; - $new->urlCreator = $value; - - return $new; + return $this->urlCreator; } - /** - * Return a new instance with URL generator interface for pagination. - * - * @param UrlGeneratorInterface $value The URL generator interface for pagination. - */ - public function urlGenerator(UrlGeneratorInterface $value): self + public function getHeader(): ?string { - $new = clone $this; - $new->urlGenerator = $value; - - return $new; + return $this->header; } - /** - * Returns a new instance with the name of the route. - * - * @param string $value The name of the route. - */ - public function urlName(string $value): self + public function getFooter(): ?string { - $new = clone $this; - $new->urlName = $value; - - return $new; + return $this->footer; } - /** - * Return a new instance with query parameters of the route. - * - * @param array $value The query parameters of the route. - */ - public function urlQueryParameters(array $value): self + public function getContent(): mixed { - $new = clone $this; - $new->urlQueryParameters = $value; - - return $new; + return $this->content; } /** - * Return a new instance with config url parameters of the route. - * - * @param array $value The config url parameters of the route. + * @psalm-return array */ - public function urlParamsConfig(array $value): self + public function getButtons(): array { - $new = clone $this; - $new->urlParamsConfig = $value; - - return $new; + return $this->buttons; } /** - * Return new instance whether button is visible or not. - * - * @param array $value The visibility conditions for each button. The array keys are the button names (without curly - * brackets), and the values are the boolean true/false or the anonymous function. When the button name is not - * specified in this array it will be shown by default. - * - * The callbacks must use the following signature: - * - * ```php - * [ - * visibleButtons => [ - * update => [ - * function ($data, $key, int $index) { - * return $data->status === 'editable'; - * } - * ], - * ], - * ] - * ``` - * - * Or you can pass a boolean value: - * - * ```php - * [ - * visibleButtons => [ - * 'update' => true, - * ], - * ], - * ``` + * @psalm-return array */ - public function visibleButtons(array $value): self + public function getVisibleButtons(): array { - $new = clone $this; - $new->visibleButtons = $value; - - return $new; + return $this->visibleButtons; } - /** - * Renders the data cell content. - * - * @param array|object $data The data. - * @param mixed $key The key associated with the data. - * @param int $index The zero-based index of the data in the data provider. - * {@see GridView::dataProvider}. - */ - protected function renderDataCellContent(array|object $data, mixed $key, int $index): string + public function getColumnAttributes(): array { - if ($this->getContent() !== null) { - return parent::renderDataCellContent($data, $key, $index); - } - - if (empty($this->buttons)) { - $this->buttons = $this->createDefaultButtons()->buttons; - } - - return PHP_EOL . preg_replace_callback( - '/{([\w\-\/]+)}/', - function (array $matches) use ($data, $key, $index): string { - $content = ''; - $name = $matches[1]; - - if ( - $this->isVisibleButton($name, $data, $key, $index) && - isset($this->buttons[$name]) && - $this->buttons[$name] instanceof Closure - ) { - $url = $this->createUrl($name, $data, $key, $index); - $content = (string) $this->buttons[$name]($url, $data, $key); - } - - return $content !== '' ? $content . PHP_EOL : ''; - }, - $this->template - ); + return $this->columnAttributes; } - /** - * Creates a URL for the given action and object. This method is called for each button and each row. - * - * @param string $action The button name (or action id). - * @param array|object $data The data object. - * @param mixed $key The key associated with the data. - * @param int $index The current row index. - */ - private function createUrl(string $action, array|object $data, mixed $key, int $index): string + public function getHeaderAttributes(): array { - if (is_callable($this->urlCreator)) { - return (string) call_user_func($this->urlCreator, $action, $data, $key, $index, $this); - } - - if ($this->primaryKey !== '') { - /** @var mixed */ - $key = $data[$this->primaryKey] ?? $key; - } - - $currentRouteName = $this->currentRoute->getName() ?? ''; - - $route = match ($this->urlName) { - '' => $currentRouteName . '/' . $action, - default => $this->urlName . '/' . $action, - }; - - $urlQueryParameters = []; - $urlParamsConfig = is_array($key) ? $key : [$this->primaryKey => $key]; - - $urlParamsConfig = match ($this->urlParamsConfig) { - [] => $urlParamsConfig, - default => array_merge($this->urlParamsConfig, $urlParamsConfig), - }; - - if ($this->urlArguments !== null) { - /** @psalm-var array */ - $urlArguments = array_merge($this->urlArguments, $urlParamsConfig); - } else { - $urlArguments = []; - $urlQueryParameters = array_merge($this->urlQueryParameters, $urlParamsConfig); - } - - return $this->getUrlGenerator()->generate($route, $urlArguments, $urlQueryParameters); + return $this->headerAttributes; } - private function isVisibleButton(string $name, array|object $data, mixed $key, int $index): bool + public function getBodyAttributes(): array { - $visible = false; - - if ($this->visibleButtons === []) { - $visible = true; - } + return $this->bodyAttributes; + } - if (isset($this->visibleButtons[$name]) && is_bool($this->visibleButtons[$name])) { - $visible = $this->visibleButtons[$name]; - } + public function getFooterAttributes(): array + { + return $this->footerAttributes; + } - if (isset($this->visibleButtons[$name]) && $this->visibleButtons[$name] instanceof Closure) { - /** @var bool */ - $visible = $this->visibleButtons[$name]($data, $key, $index); - } + public function isVisible(): bool + { + return $this->visible; + } - return $visible; + public function getRenderer(): string + { + return ActionColumnRenderer::class; } } diff --git a/src/Column/ActionColumnRenderer.php b/src/Column/ActionColumnRenderer.php new file mode 100644 index 000000000..9a236b5ee --- /dev/null +++ b/src/Column/ActionColumnRenderer.php @@ -0,0 +1,210 @@ +checkColumn($column); + return $cell->addAttributes($column->getColumnAttributes()); + } + + public function renderHeader(ColumnInterface $column, Cell $cell, GlobalContext $context): Cell + { + $this->checkColumn($column); + return $cell + ->content($column->getHeader() ?? 'Actions') + ->addAttributes($column->getHeaderAttributes()); + } + + public function renderFilter(ColumnInterface $column, Cell $cell, GlobalContext $context): ?Cell + { + return null; + } + + public function renderBody(ColumnInterface $column, Cell $cell, DataContext $context): Cell + { + $this->checkColumn($column); + + $contentSource = $column->getContent(); + + if ($contentSource !== null) { + $content = (string)(is_callable($contentSource) ? $contentSource($context) : $contentSource); + } else { + $buttons = empty($column->getButtons()) ? $this->getDefaultButtons() : $column->getButtons(); + $content = preg_replace_callback( + '/{([\w\-\/]+)}/', + function (array $matches) use ($column, $buttons, $context): string { + $name = $matches[1]; + + if ( + $this->isVisibleButton( + $column, + $name, + $context->getData(), + $context->getKey(), + $context->getIndex() + ) && + isset($buttons[$name]) + ) { + $url = $this->createUrl($column, $name, $context->getData(), $context->getKey()); + return (string)$buttons[$name]($url); + } + + return ''; + }, + $column->getTemplate() + ); + $content = trim($content); + } + + return $cell + ->addAttributes($column->getBodyAttributes()) + ->content(PHP_EOL . $content . PHP_EOL) + ->encode(false); + } + + public function renderFooter(ColumnInterface $column, Cell $cell, GlobalContext $context): Cell + { + $this->checkColumn($column); + + if ($column->getFooter() !== null) { + $cell = $cell->content($column->getFooter()); + } + + return $cell->addAttributes($column->getFooterAttributes()); + } + + private function createUrl(ActionColumn $column, string $action, array|object $data, mixed $key): string + { + if ($column->getUrlCreator() !== null) { + return (string) ($column->getUrlCreator())($action, $data, $key); + } + + $primaryKey = $column->getPrimaryKey(); + $routeName = $column->getRouteName(); + + if ($primaryKey !== '') { + $key = $data[$primaryKey] ?? $key; + } + + $currentRouteName = $this->currentRoute->getName() ?? ''; + + $route = $routeName === null + ? $currentRouteName . '/' . $action + : $routeName . '/' . $action; + + + $urlParamsConfig = array_merge( + $column->getUrlParamsConfig(), + is_array($key) ? $key : [$primaryKey => $key] + ); + + if ($column->getUrlArguments() !== null) { + /** @psalm-var array */ + $urlArguments = array_merge($column->getUrlArguments(), $urlParamsConfig); + $urlQueryParameters = []; + } else { + $urlArguments = []; + $urlQueryParameters = array_merge($column->getUrlQueryParameters(), $urlParamsConfig); + } + + return $this->urlGenerator->generate($route, $urlArguments, $urlQueryParameters); + } + + private function isVisibleButton( + ActionColumn $column, + string $name, + array|object $data, + mixed $key, + int $index + ): bool { + $visibleButtons = $column->getVisibleButtons(); + + if (empty($visibleButtons)) { + return true; + } + + $visibleValue = $visibleButtons[$name] ?? false; + if (is_bool($visibleValue)) { + return $visibleValue; + } + + /** @var bool */ + return $visibleValue($data, $key, $index); + } + + /** + * Initializes the default button rendering callback for single button. + * @psalm-return array + */ + private function getDefaultButtons(): array + { + return [ + 'view' => static fn(string $url): string => Html::a( + Html::span('🔎'), + $url, + [ + 'name' => 'view', + 'role' => 'button', + 'style' => 'text-decoration: none!important;', + 'title' => 'View', + ], + )->render(), + 'update' => static fn(string $url): string => Html::a( + Html::span('✎'), + $url, + [ + 'name' => 'update', + 'role' => 'button', + 'style' => 'text-decoration: none!important;', + 'title' => 'Update', + ], + )->render(), + 'delete' => static fn(string $url): string => Html::a( + Html::span('❌'), + $url, + [ + 'name' => 'delete', + 'role' => 'button', + 'style' => 'text-decoration: none!important;', + 'title' => 'Delete', + ], + )->render(), + ]; + } + + /** + * @psalm-assert ActionColumn $column + */ + private function checkColumn(ColumnInterface $column): void + { + if (!$column instanceof ActionColumn) { + throw new InvalidArgumentException( + sprintf( + 'Expected "%s", but "%s" given.', + self::class, + $column::class + ) + ); + } + } +} diff --git a/src/Column/Base/Cell.php b/src/Column/Base/Cell.php new file mode 100644 index 000000000..97fd4c08b --- /dev/null +++ b/src/Column/Base/Cell.php @@ -0,0 +1,117 @@ +encode = $encode; + return $new; + } + + /** + * @param bool $doubleEncode Whether already encoded HTML entities in tag content should be encoded. + * Defaults to `true`. + */ + public function doubleEncode(bool $doubleEncode): self + { + $new = clone $this; + $new->doubleEncode = $doubleEncode; + return $new; + } + + /** + * @param callable|string|Stringable $content Tag content. + */ + public function content(string|Stringable|callable $content): self + { + $new = clone $this; + $new->content = $content; + return $new; + } + + /** + * Add a set of attributes to existing cell attributes. + * Same named attributes are replaced. + * + * @param array $attributes Name-value set of attributes. + */ + public function addAttributes(array $attributes): self + { + $new = clone $this; + $new->attributes = array_merge($new->attributes, $attributes); + return $new; + } + + /** + * Replace attributes with a new set. + * + * @param array $attributes Name-value set of attributes. + */ + public function attributes(array $attributes): self + { + $new = clone $this; + $new->attributes = $attributes; + return $new; + } + + /** + * Set attribute value. + * + * @param string $name Name of the attribute. + * @param mixed $value Value of the attribute. + */ + public function attribute(string $name, mixed $value): self + { + $new = clone $this; + $new->attributes[$name] = $value; + return $new; + } + + public function getAttributes(): array + { + return $this->attributes; + } + + public function isEncode(): ?bool + { + return $this->encode; + } + + public function isDoubleEncode(): bool + { + return $this->doubleEncode; + } + + public function getContent(): string|Stringable|callable + { + return $this->content; + } +} diff --git a/src/Column/Base/DataContext.php b/src/Column/Base/DataContext.php new file mode 100644 index 000000000..e4b99ca82 --- /dev/null +++ b/src/Column/Base/DataContext.php @@ -0,0 +1,38 @@ +column; + } + + public function getData(): array|object + { + return $this->data; + } + + public function getKey(): mixed + { + return $this->key; + } + + public function getIndex(): int + { + return $this->index; + } +} diff --git a/src/Column/Base/GlobalContext.php b/src/Column/Base/GlobalContext.php new file mode 100644 index 000000000..656c36f76 --- /dev/null +++ b/src/Column/Base/GlobalContext.php @@ -0,0 +1,44 @@ +dataReader; + } + + public function getSortLinkAttributes(): array + { + return $this->sortLinkAttributes; + } + + public function getUrlArguments(): array + { + return $this->urlArguments; + } + + public function getUrlQueryParameters(): array + { + return $this->urlQueryParameters; + } + + public function getFilterModelName(): ?string + { + return $this->filterModelName; + } +} diff --git a/src/Column/CheckboxColumn.php b/src/Column/CheckboxColumn.php index 91bad7980..9b9daabfa 100644 --- a/src/Column/CheckboxColumn.php +++ b/src/Column/CheckboxColumn.php @@ -4,73 +4,81 @@ namespace Yiisoft\Yii\DataView\Column; -use Yiisoft\Html\Tag\Input; - /** - * CheckboxColumn displays a column of checkboxes in a grid view. + * `CheckboxColumn` displays a column of checkboxes in a grid view. */ -final class CheckboxColumn extends AbstractColumn +final class CheckboxColumn implements ColumnInterface { - private bool $multiple = true; - /** - * Return new instance with the multiple flag, for default is `true`. - * - * @param bool $value The multiple flag value. + * @var callable|null */ - public function multiple(bool $value): self + private $content; + + public function __construct( + private ?string $header = null, + private ?string $footer = null, + private array $columnAttributes = [], + private array $headerAttributes = [], + private array $bodyAttributes = [], + private array $inputAttributes = [], + ?string $name = null, + private bool $multiple = true, + ?callable $content = null, + private bool $visible = true, + ) { + $this->content = $content; + if ($name !== null) { + $this->inputAttributes['name'] = $name; + } + } + + public function getHeader(): ?string { - $new = clone $this; - $new->multiple = $value; + return $this->header; + } - return $new; + public function getFooter(): ?string + { + return $this->footer; } - /** - * Renders the data cell content. - * - * @param array|object $data The data. - * @param mixed $key The key associated with the data. - * @param int $index The zero-based index of the data in the data provider. - */ - protected function renderDataCellContent(array|object $data, mixed $key, int $index): string + public function getColumnAttributes(): array { - if ($this->getContent() !== null) { - return parent::renderDataCellContent($data, $key, $index); - } + return $this->columnAttributes; + } - $contentAttributes = $this->getContentAttributes(); - $name = null; - $value = null; + public function getHeaderAttributes(): array + { + return $this->headerAttributes; + } - if (!array_key_exists('value', $contentAttributes)) { - $value = is_array($key) - ? json_encode($key, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) : (string) $key; - } + public function getBodyAttributes(): array + { + return $this->bodyAttributes; + } - if (!array_key_exists('name', $contentAttributes)) { - $name = 'checkbox-selection'; - } + public function getInputAttributes(): array + { + return $this->inputAttributes; + } - return Input::checkbox($name, $value)->addAttributes($contentAttributes)->render(); + public function isMultiple(): bool + { + return $this->multiple; } - /** - * Renders the header cell content. - * - * The default implementation simply renders {@see header}. - * This method may be overridden to customize the rendering of the header cell. - */ - protected function renderHeaderCellContent(): string + public function getContent(): ?callable { - if ($this->getLabel() !== '' || $this->multiple === false) { - return parent::renderHeaderCellContent(); - } + return $this->content; + } - return Input::checkbox() - ->addAttributes(['class' => 'select-on-check-all']) - ->name('checkbox-selection-all') - ->value(1) - ->render(); + public function getRenderer(): string + { + return CheckboxColumnRenderer::class; + } + + public function isVisible(): bool + { + return $this->visible; } } diff --git a/src/Column/CheckboxColumnRenderer.php b/src/Column/CheckboxColumnRenderer.php new file mode 100644 index 000000000..635a41855 --- /dev/null +++ b/src/Column/CheckboxColumnRenderer.php @@ -0,0 +1,101 @@ +checkColumn($column); + return $cell->addAttributes($column->getColumnAttributes()); + } + + public function renderHeader(ColumnInterface $column, Cell $cell, GlobalContext $context): ?Cell + { + $this->checkColumn($column); + + $header = $column->getHeader(); + if ($header === null) { + if (!$column->isMultiple()) { + return null; + } + $header = Html::checkbox('checkbox-selection-all', 1); + } + + return $cell + ->addAttributes($column->getHeaderAttributes()) + ->content($header); + } + + public function renderFilter(ColumnInterface $column, Cell $cell, GlobalContext $context): ?Cell + { + return null; + } + + public function renderBody(ColumnInterface $column, Cell $cell, DataContext $context): Cell + { + $this->checkColumn($column); + + $inputAttributes = $column->getInputAttributes(); + $name = null; + $value = null; + + if (!array_key_exists('name', $inputAttributes)) { + $name = 'checkbox-selection'; + } + + if (!array_key_exists('value', $inputAttributes)) { + $key = $context->getKey(); + $value = is_array($key) + ? json_encode($key, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) + : (string)$key; + } + + $input = Html::checkbox($name, $value, $inputAttributes); + + $contentClosure = $column->getContent(); + /** @var string|Stringable $content */ + $content = $contentClosure === null ? $input : $contentClosure($input, $context); + + return $cell + ->addAttributes($column->getBodyAttributes()) + ->content($content) + ->encode(false); + } + + public function renderFooter(ColumnInterface $column, Cell $cell, GlobalContext $context): Cell + { + $this->checkColumn($column); + + if ($column->getFooter() !== null) { + $cell = $cell->content($column->getFooter()); + } + + return $cell; + } + + /** + * @psalm-assert CheckboxColumn $column + */ + private function checkColumn(ColumnInterface $column): void + { + if (!$column instanceof CheckboxColumn) { + throw new InvalidArgumentException( + sprintf( + 'Expected "%s", but "%s" given.', + CheckboxColumn::class, + $column::class + ) + ); + } + } +} diff --git a/src/Column/ColumnInterface.php b/src/Column/ColumnInterface.php new file mode 100644 index 000000000..294e94aac --- /dev/null +++ b/src/Column/ColumnInterface.php @@ -0,0 +1,20 @@ + 'date', @@ -58,348 +45,130 @@ final class DataColumn extends AbstractColumn 'url' => 'url', 'week' => 'week', ]; - private Stringable|null|string|int|bool|float $filterValueDefault = null; - private string $linkSorter = ''; - private mixed $value = null; - private bool $withSorting = true; /** - * Return new instance with the attribute name. - * - * @param string $value The attribute name associated with this column. When neither {@see content} nor {@see value} - * is specified, the value of the specified attribute will be retrieved from each data and displayed. - * - * Also, if {@see label} is not specified, the label associated with the attribute will be displayed. + * @psalm-param array> $filterInputSelectItems */ - public function attribute(string $value): self - { - $new = clone $this; - $new->attribute = $value; - - return $new; + public function __construct( + private ?string $property = null, + private ?string $header = null, + private ?string $footer = null, + private array $columnAttributes = [], + private array $headerAttributes = [], + private array $filterAttributes = [], + private array $bodyAttributes = [], + private bool $withSorting = true, + private mixed $content = null, + private ?string $filter = null, + private ?string $filterProperty = null, + private string $filterType = 'text', + private array $filterInputAttributes = [], + private ?string $filterModelName = null, + private Stringable|null|string|int|bool|float $filterValueDefault = null, + private array $filterInputSelectItems = [], + private string $filterInputSelectPrompt = '', + private bool $visible = true, + ) { + if (!isset($this->filterTypes[$filterType])) { + throw new InvalidArgumentException(sprintf('Invalid filter type "%s".', $filterType)); + } } - /** - * Return new instance with the filter input. - * - * @param string $value The HTML code representing a filter input (e.g. a text field, a dropdown list) that is - * used for this data column. This property is effective only when {@see filterModel} is set. - * - * - If this property is not set, a text field will be generated as the filter input with attributes defined - * with {@see filterInputAttributes}. - * - If this property is an array, a dropdown list will be generated that uses this property value as the list - * options. - * - If you don't want a filter for this data column, set this value to be false. - */ - public function filter(string $value): self + public function getProperty(): ?string { - $new = clone $this; - $new->filter = $value; - - return $new; + return $this->property; } - /** - * Return new instance with the filter attribute. - * - * @param string $value The attribute name of the {@see filterModel} associated with this column. If not set, will - * have the same value as {@see attribute}. - */ - public function filterAttribute(string $value): self + public function getHeader(): ?string { - $new = clone $this; - $new->filterAttribute = $value; - - return $new; + return $this->header; } - /** - * Return new instance with the HTML attributes for the filter input. - * - * @param array $values Attribute values indexed by attribute names. - * - * This property is used in combination with the {@see filter} property. When {@see filter} is not set or is an - * array, this property will be used to render the HTML attributes for the generated filter input fields. - * - * Empty `id` in the default value ensures that id would not be obtained from the data attribute thus - * providing better performance. - */ - public function filterInputAttributes(array $values): self + public function getFooter(): ?string { - $new = clone $this; - $new->filterInputAttributes = $values; - - return $new; + return $this->footer; } - /** - * Return new instance with the filter input select items. - * - * @param array $values The select items for the filter input. - * - * This property is used in combination with the {@see filter} property. When {@see filter} is not set or is an - * array, this property will be used to render the HTML attributes for the generated filter input fields. - * - * @psalm-param string[] $values - */ - public function filterInputSelectItems(array $values): self + public function getColumnAttributes(): array { - $new = clone $this; - $new->filterInputSelectItems = $values; - - return $new; + return $this->columnAttributes; } - /** - * Return new instance with the filter input select prompt. - * - * @param string $prompt The prompt text for the filter input select. - * @param bool|float|int|string|Stringable|null $value The value for the prompt. - * - * This property is used in combination with the {@see filter} property. When {@see filter} is not set or is an - * array, this property will be used to render the HTML attributes for the generated filter input fields. - */ - public function filterInputSelectPrompt(string $prompt, Stringable|null|string|int|bool|float $value = null): self + public function getHeaderAttributes(): array { - $new = clone $this; - $new->filterInputSelectPrompt = $prompt; - $new->filterValueDefault = $value; - - return $new; + return $this->headerAttributes; } - /** - * Return new instance with the filter model name. - * - * @param string $value The form model name that keeps the user-entered filter data. When this property is set, the - * grid view will enable column-based filtering. Each data column by default will display a text field at the top - * that users can fill in to filter the data. - * - * Note that in order to show an input field for filtering, a column must have its {@see DetailColumn::attribute} - * property set and the attribute should be active in the current scenario of $filterModelName or have - * {@see DataColumn::filter} set as the HTML code for the input field. - */ - public function filterModelName(string $value): self + public function getFilterAttributes(): array { - $new = clone $this; - $new->filterModelName = $value; - - return $new; + return $this->filterAttributes; } - /** - * Return new instance with the filter type. - * - * @param string $value The filter type. - */ - public function filterType(string $value): self + public function getBodyAttributes(): array { - if (!isset($this->filterTypes[$value])) { - throw new InvalidArgumentException(sprintf('Invalid filter type "%s".', $value)); - } - - $new = clone $this; - $new->filterType = $value; - - return $new; + return $this->bodyAttributes; } - /** - * Return new instance with set filter value default text input field. - * - * @param bool|float|int|string|Stringable|null $value The default value for the filter input field. - */ - public function filterValueDefault(Stringable|null|string|int|bool|float $value): self + public function isWithSorting(): bool { - $new = clone $this; - $new->filterValueDefault = $value; - - return $new; + return $this->withSorting; } - public function getAttribute(): string + public function getContent(): mixed { - return $this->attribute; + return $this->content; } - public function getFilter(): string + public function getFilter(): ?string { return $this->filter; } - public function getFilterAttribute(): string + public function getFilterProperty(): ?string { - return $this->filterAttribute; + return $this->filterProperty; } - public function getLabel(): string + public function getFilterType(): string { - return parent::getLabel() !== '' ? parent::getLabel() : ucfirst($this->attribute); + return $this->filterTypes[$this->filterType]; } - /** - * Return new instance with the link sorter. - * - * @param string $value The URL that will be used to sort the data in this column. - */ - public function linkSorter(string $value): self + public function getFilterInputAttributes(): array { - $new = clone $this; - $new->linkSorter = $value; - - return $new; + return $this->filterInputAttributes; } - /** - * Return new instance with the value of column. - * - * @param mixed $value An anonymous function or a string that is used to determine the value to - * display in the current column. - * - * If this is an anonymous function, it will be called for each row and the return value will be used as the value - * to display for every data. The signature of this function should be: - * - * `function ($data, $key, $index, $column)`. - * - * Where `$data`, `$key`, and `$index` refer to the data, key and index of the row currently being rendered - * and `$column` is a reference to the {@see DetailColumn} object. - * - * You may also set this property to a string representing the attribute name to be displayed in this column. - * - * This can be used when the attribute to be displayed is different from the {@see attribute} that is used for - * sorting and filtering. - * - * If this is not set, `$data[$attribute]` will be used to obtain the value, where `$attribute` is the value of - * {@see attribute}. - */ - public function value(mixed $value): self + public function getFilterModelName(): ?string { - $new = clone $this; - $new->value = $value; - - return $new; + return $this->filterModelName; } - /** - * Return new instance whether the column is sortable or not. - * - * @param bool $value Whether the column is sortable or not. - */ - public function withSorting(bool $value): self + public function getFilterValueDefault(): float|Stringable|bool|int|string|null { - $new = clone $this; - $new->withSorting = $value; - - return $new; + return $this->filterValueDefault; } /** - * Renders the data cell content. - * - * @param array|object $data The data. - * @param mixed $key The key associated with the data. - * @param int $index The zero-based index of the data in the data provider. + * @psalm-return array> */ - protected function renderDataCellContent(object|array $data, mixed $key, int $index): string - { - if ($this->getContent() !== null) { - return parent::renderDataCellContent($data, $key, $index); - } - - return $this->getDataCellValue($data, $key, $index); - } - - protected function renderFilterCellContent(): string - { - $filter = $this->filter !== '' ? $this->filter : parent::renderFilterCellContent(); - - if ($this->filterAttribute !== '') { - $filter = match ($this->filterType) { - 'select' => $this->renderFilterSelect(), - default => $this->renderFilterInput(), - }; - } - - return $filter; - } - - protected function renderHeaderCellContent(): string + public function getFilterInputSelectItems(): array { - $label = Html::encode($this->getLabel()); - - if ($this->attribute !== '' && $this->withSorting && $this->linkSorter !== '') { - $label = $this->linkSorter; - } - - return $label; + return $this->filterInputSelectItems; } - /** - * Returns the data cell value. - * - * @param array|object $data The data. - * @param mixed $key The key associated with the data. - * @param int $index The zero-based index of the data in the data provider. - */ - private function getDataCellValue(array|object $data, mixed $key, int $index): string + public function getFilterInputSelectPrompt(): string { - $value = ''; - - if ($this->value !== null && !($this->value instanceof Closure)) { - $value = (string) $this->value; - } - - if ($this->value instanceof Closure) { - $value = (string) call_user_func($this->value, $data, $key, $index, $this); - } - - if ($this->attribute !== '' && $this->value === null) { - $value = (string) ArrayHelper::getValue($data, $this->attribute); - } - - return $value === '' ? $this->getEmptyCell() : $value; + return $this->filterInputSelectPrompt; } - private function renderFilterInput(): string + public function isVisible(): bool { - $filterInputAttributes = $this->filterInputAttributes; - $filterInputTag = Input::tag(); - - if (!array_key_exists('name', $filterInputAttributes)) { - $filterInputTag = $filterInputTag->name( - Attribute::getInputName($this->filterModelName, $this->filterAttribute), - ); - } - - if (!array_key_exists('value', $filterInputAttributes) && $this->filterValueDefault !== '') { - $filterInputTag = $filterInputTag->value($this->filterValueDefault); - } - - return $filterInputTag - ->addAttributes($filterInputAttributes) - ->type($this->filterTypes[$this->filterType]) - ->render(); + return $this->visible; } - private function renderFilterSelect(): string + public function getRenderer(): string { - $filterInputAttributes = $this->filterInputAttributes; - $filterSelectTag = Select::tag(); - - if (!array_key_exists('name', $filterInputAttributes)) { - $filterSelectTag = $filterSelectTag->name( - Attribute::getInputName($this->filterModelName, $this->filterAttribute), - ); - } - - if ($this->filterValueDefault !== null) { - $filterSelectTag = $filterSelectTag->value($this->filterValueDefault); - } - - return $filterSelectTag - ->addAttributes($filterInputAttributes) - ->optionsData($this->filterInputSelectItems) - ->prompt($this->filterInputSelectPrompt) - ->render(); + return DataColumnRenderer::class; } } diff --git a/src/Column/DataColumnRenderer.php b/src/Column/DataColumnRenderer.php new file mode 100644 index 000000000..bde50e763 --- /dev/null +++ b/src/Column/DataColumnRenderer.php @@ -0,0 +1,190 @@ +checkColumn($column); + return $cell->addAttributes($column->getColumnAttributes()); + } + + public function renderHeader(ColumnInterface $column, Cell $cell, GlobalContext $context): Cell + { + $this->checkColumn($column); + + $label = $column->getHeader() ?? ($column->getProperty() === null ? '' : ucfirst($column->getProperty())); + + if ($column->getProperty() !== null && $column->isWithSorting()) { + $linkSorter = $this->renderLinkSorter($context, $column->getProperty(), $label); + if (!empty($linkSorter)) { + return $cell->content($linkSorter)->encode(false); + } + } + + return $cell + ->addAttributes($column->getHeaderAttributes()) + ->content($label); + } + + public function renderFilter(ColumnInterface $column, Cell $cell, GlobalContext $context): ?Cell + { + $this->checkColumn($column); + + if ($column->getFilter() !== null) { + $content = $column->getFilter(); + } elseif ($column->getFilterProperty() !== null) { + $content = match ($column->getFilterType()) { + 'select' => $this->renderFilterSelect($column, $context), + default => $this->renderFilterInput($column, $context), + }; + } else { + return null; + } + + return $cell + ->content($content) + ->addAttributes($column->getFilterAttributes()) + ->encode(false); + } + + public function renderBody(ColumnInterface $column, Cell $cell, DataContext $context): Cell + { + $this->checkColumn($column); + + $contentSource = $column->getContent(); + + if ($contentSource !== null) { + $content = (string)(is_callable($contentSource) ? $contentSource($context) : $contentSource); + } elseif ($column->getProperty() !== null) { + $content = (string)ArrayHelper::getValue($context->getData(), $column->getProperty()); + } else { + $content = ''; + } + + return $cell + ->addAttributes($column->getBodyAttributes()) + ->content($content); + } + + public function renderFooter(ColumnInterface $column, Cell $cell, GlobalContext $context): Cell + { + $this->checkColumn($column); + + if ($column->getFooter() !== null) { + $cell = $cell->content($column->getFooter()); + } + + return $cell; + } + + private function renderLinkSorter(GlobalContext $context, string $property, string $label): string + { + $dataReader = $context->getDataReader(); + if (!$dataReader instanceof PaginatorInterface) { + return ''; + } + + $sort = $dataReader->getSort(); + if ($sort === null) { + return ''; + } + + $linkSorter = $dataReader instanceof OffsetPaginator + ? LinkSorter::widget()->currentPage($dataReader->getCurrentPage()) + : LinkSorter::widget(); + + return $linkSorter + ->attribute($property) + ->attributes($sort->getCriteria()) + ->directions($sort->getOrder()) + ->iconAscClass('bi bi-sort-alpha-up') + ->iconDescClass('bi bi-sort-alpha-down') + ->label($label) + ->linkAttributes($context->getSortLinkAttributes()) + ->pageSize($dataReader->getPageSize()) + ->urlArguments($context->getUrlArguments()) + ->urlQueryParameters($context->getUrlQueryParameters()) + ->render(); + } + + private function renderFilterInput(DataColumn $column, GlobalContext $context): string + { + $filterInputAttributes = $column->getFilterInputAttributes(); + $filterInputTag = Input::tag(); + + if (!array_key_exists('name', $filterInputAttributes)) { + $filterInputTag = $filterInputTag->name( + Attribute::getInputName( + (string)($column->getFilterModelName() ?? $context->getFilterModelName()), + $column->getFilterProperty() ?? '' + ), + ); + } + + if (!array_key_exists('value', $filterInputAttributes) && $column->getFilterValueDefault() !== '') { + $filterInputTag = $filterInputTag->value($column->getFilterValueDefault()); + } + + return $filterInputTag + ->addAttributes($filterInputAttributes) + ->type($column->getFilterType()) + ->render(); + } + + private function renderFilterSelect(DataColumn $column, GlobalContext $context): string + { + $filterInputAttributes = $column->getFilterInputAttributes(); + $filterSelectTag = Select::tag(); + + if (!array_key_exists('name', $filterInputAttributes)) { + $filterSelectTag = $filterSelectTag->name( + Attribute::getInputName( + (string)($column->getFilterModelName() ?? $context->getFilterModelName()), + $column->getFilterProperty() ?? '' + ), + ); + } + + if ($column->getFilterValueDefault() !== null) { + $filterSelectTag = $filterSelectTag->value($column->getFilterValueDefault()); + } + + return $filterSelectTag + ->addAttributes($filterInputAttributes) + ->optionsData($column->getFilterInputSelectItems()) + ->prompt($column->getFilterInputSelectPrompt()) + ->render(); + } + + /** + * @psalm-assert DataColumn $column + */ + private function checkColumn(ColumnInterface $column): void + { + if (!$column instanceof DataColumn) { + throw new InvalidArgumentException( + sprintf( + 'Expected "%s", but "%s" given.', + DataColumn::class, + $column::class + ) + ); + } + } +} diff --git a/src/Column/RadioColumn.php b/src/Column/RadioColumn.php index d2db0afee..9a089c24f 100644 --- a/src/Column/RadioColumn.php +++ b/src/Column/RadioColumn.php @@ -4,41 +4,75 @@ namespace Yiisoft\Yii\DataView\Column; -use Yiisoft\Html\Tag\Input; - -use function json_encode; - /** - * RadioButtonColumn displays a column of radio buttons in a grid view. + * `RadioColumn` displays a column of radio buttons in a grid view. */ -final class RadioColumn extends AbstractColumn +final class RadioColumn implements ColumnInterface { /** - * Renders the data cell content. - * - * @param array|object $data The data. - * @param mixed $key The key associated with the data. - * @param int $index The zero-based index of the data in the data provider. + * @var callable|null */ - protected function renderDataCellContent(array|object $data, mixed $key, int $index): string - { - if ($this->getContent() !== null) { - return parent::renderDataCellContent($data, $key, $index); + private $content; + + public function __construct( + private ?string $header = null, + private ?string $footer = null, + private array $columnAttributes = [], + private array $headerAttributes = [], + private array $bodyAttributes = [], + private array $inputAttributes = [], + ?string $name = null, + ?callable $content = null, + private bool $visible = true, + ) { + $this->content = $content; + if ($name !== null) { + $this->inputAttributes['name'] = $name; } + } - $contentAttributes = $this->getContentAttributes(); - $name = null; - $value = null; + public function getHeader(): ?string + { + return $this->header; + } - if (!array_key_exists('name', $contentAttributes)) { - $name = 'radio-selection'; - } + public function getFooter(): ?string + { + return $this->footer; + } - if (!array_key_exists('value', $contentAttributes)) { - $value = is_array($key) - ? json_encode($key, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) : (string) $key; - } + public function getColumnAttributes(): array + { + return $this->columnAttributes; + } - return Input::radio($name, $value)->addAttributes($contentAttributes)->render(); + public function getHeaderAttributes(): array + { + return $this->headerAttributes; + } + + public function getBodyAttributes(): array + { + return $this->bodyAttributes; + } + + public function getInputAttributes(): array + { + return $this->inputAttributes; + } + + public function getContent(): ?callable + { + return $this->content; + } + + public function isVisible(): bool + { + return $this->visible; + } + + public function getRenderer(): string + { + return RadioColumnRenderer::class; } } diff --git a/src/Column/RadioColumnRenderer.php b/src/Column/RadioColumnRenderer.php new file mode 100644 index 000000000..c7afb4943 --- /dev/null +++ b/src/Column/RadioColumnRenderer.php @@ -0,0 +1,98 @@ +checkColumn($column); + return $cell->addAttributes($column->getColumnAttributes()); + } + + public function renderHeader(ColumnInterface $column, Cell $cell, GlobalContext $context): ?Cell + { + $this->checkColumn($column); + + $header = $column->getHeader(); + if ($header === null) { + return null; + } + + return $cell + ->addAttributes($column->getHeaderAttributes()) + ->content($header); + } + + public function renderFilter(ColumnInterface $column, Cell $cell, GlobalContext $context): ?Cell + { + return null; + } + + public function renderBody(ColumnInterface $column, Cell $cell, DataContext $context): Cell + { + $this->checkColumn($column); + + $inputAttributes = $column->getInputAttributes(); + $name = null; + $value = null; + + if (!array_key_exists('name', $inputAttributes)) { + $name = 'radio-selection'; + } + + if (!array_key_exists('value', $inputAttributes)) { + $key = $context->getKey(); + $value = is_array($key) + ? json_encode($key, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) + : (string)$key; + } + + $input = Html::radio($name, $value, $inputAttributes); + + $contentClosure = $column->getContent(); + /** @var string|Stringable $content */ + $content = $contentClosure === null ? $input : $contentClosure($input, $context); + + return $cell + ->addAttributes($column->getBodyAttributes()) + ->content($content) + ->encode(false); + } + + public function renderFooter(ColumnInterface $column, Cell $cell, GlobalContext $context): Cell + { + $this->checkColumn($column); + + if ($column->getFooter() !== null) { + $cell = $cell->content($column->getFooter()); + } + + return $cell; + } + + /** + * @psalm-assert RadioColumn $column + */ + private function checkColumn(ColumnInterface $column): void + { + if (!$column instanceof RadioColumn) { + throw new InvalidArgumentException( + sprintf( + 'Expected "%s", but "%s" given.', + RadioColumn::class, + $column::class + ) + ); + } + } +} diff --git a/src/Column/SerialColumn.php b/src/Column/SerialColumn.php index a8be90e7c..382b6337b 100644 --- a/src/Column/SerialColumn.php +++ b/src/Column/SerialColumn.php @@ -5,24 +5,46 @@ namespace Yiisoft\Yii\DataView\Column; /** - * SerialColumn displays a column of row numbers (1-based). + * `SerialColumn` displays a column of row numbers (1-based). */ -final class SerialColumn extends AbstractColumn +final class SerialColumn implements ColumnInterface { - protected function getLabel(): string + public function __construct( + private ?string $header = null, + private ?string $footer = null, + private array $columnAttributes = [], + private array $bodyAttributes = [], + private bool $visible = true, + ) { + } + + public function getHeader(): ?string + { + return $this->header; + } + + public function getFooter(): ?string + { + return $this->footer; + } + + public function getColumnAttributes(): array + { + return $this->columnAttributes; + } + + public function getBodyAttributes(): array + { + return $this->bodyAttributes; + } + + public function isVisible(): bool { - return parent::getLabel() !== '' ? parent::getLabel() : '#'; + return $this->visible; } - /** - * Renders the data cell content. - * - * @param array|object $data The data. - * @param mixed $key The key associated with the data. - * @param int $index The zero-based index of the data in the data provider. {@see GridView::dataProvider}. - */ - protected function renderDataCellContent(array|object $data, mixed $key, int $index): string + public function getRenderer(): string { - return (string) ($index + 1); + return SerialColumnRenderer::class; } } diff --git a/src/Column/SerialColumnRenderer.php b/src/Column/SerialColumnRenderer.php new file mode 100644 index 000000000..00e4bc17a --- /dev/null +++ b/src/Column/SerialColumnRenderer.php @@ -0,0 +1,61 @@ +checkColumn($column); + return $cell->addAttributes($column->getColumnAttributes()); + } + + public function renderHeader(ColumnInterface $column, Cell $cell, GlobalContext $context): Cell + { + $this->checkColumn($column); + return $cell->content($column->getHeader() ?? '#'); + } + + public function renderFilter(ColumnInterface $column, Cell $cell, GlobalContext $context): ?Cell + { + return null; + } + + public function renderBody(ColumnInterface $column, Cell $cell, DataContext $context): Cell + { + $this->checkColumn($column); + + return $cell + ->addAttributes($column->getBodyAttributes()) + ->content((string)($context->getIndex() + 1)); + } + + public function renderFooter(ColumnInterface $column, Cell $cell, GlobalContext $context): Cell + { + $this->checkColumn($column); + return $cell->content($column->getFooter() ?? ''); + } + + /** + * @psalm-assert SerialColumn $column + */ + private function checkColumn(ColumnInterface $column): void + { + if (!$column instanceof SerialColumn) { + throw new InvalidArgumentException( + sprintf( + 'Expected "%s", but "%s" given.', + SerialColumn::class, + $column::class + ) + ); + } + } +} diff --git a/src/GridView.php b/src/GridView.php index 905d1f39b..da495ca37 100644 --- a/src/GridView.php +++ b/src/GridView.php @@ -5,20 +5,22 @@ namespace Yiisoft\Yii\DataView; use Closure; +use Psr\Container\ContainerInterface; +use Stringable; use Yiisoft\Definitions\Exception\CircularReferenceException; use Yiisoft\Definitions\Exception\InvalidConfigException; use Yiisoft\Definitions\Exception\NotInstantiableException; use Yiisoft\Factory\NotFoundException; use Yiisoft\Html\Html; -use Yiisoft\Html\Tag\Col; -use Yiisoft\Html\Tag\Colgroup; -use Yiisoft\Html\Tag\Td; use Yiisoft\Html\Tag\Tr; -use Yiisoft\Router\CurrentRoute; use Yiisoft\Router\UrlGeneratorInterface; use Yiisoft\Translator\TranslatorInterface; -use Yiisoft\Yii\DataView\Column\AbstractColumn; use Yiisoft\Yii\DataView\Column\ActionColumn; +use Yiisoft\Yii\DataView\Column\Base\Cell; +use Yiisoft\Yii\DataView\Column\Base\GlobalContext; +use Yiisoft\Yii\DataView\Column\Base\DataContext; +use Yiisoft\Yii\DataView\Column\ColumnInterface; +use Yiisoft\Yii\DataView\Column\ColumnRendererInterface; use Yiisoft\Yii\DataView\Column\DataColumn; /** @@ -36,13 +38,18 @@ final class GridView extends BaseListView public const FILTER_POS_HEADER = 'header'; public const FILTER_POS_FOOTER = 'footer'; public const FILTER_POS_BODY = 'body'; + private Closure|null $afterRow = null; private Closure|null $beforeRow = null; - /** @psalm-var array */ + + /** + * @var ColumnInterface[] + */ private array $columns = []; + private bool $columnsGroupEnabled = false; private string $emptyCell = ' '; - private string $filterModelName = ''; + private ?string $filterModelName = null; private string $filterPosition = self::FILTER_POS_BODY; private array $filterRowAttributes = []; private bool $footerEnabled = false; @@ -52,9 +59,11 @@ final class GridView extends BaseListView private array $rowAttributes = []; private array $tableAttributes = []; private array $tbodyAttributes = []; + private array $headerCellAttributes = []; + private array $bodyCellAttributes = []; public function __construct( - private CurrentRoute $currentRoute, + private ContainerInterface $columnRenderersContainer, TranslatorInterface|null $translator = null, UrlGeneratorInterface|null $urlGenerator = null ) { @@ -90,7 +99,7 @@ public function beforeRow(Closure|null $value): self /** * Return a new instance the specified columns. * - * @param AbstractColumn ...$values The grid column configuration. Each array element represents the configuration + * @param ColumnInterface ...$values The grid column configuration. Each array element represents the configuration * for one particular grid column. For example, * * ```php @@ -105,11 +114,10 @@ public function beforeRow(Closure|null $value): self * ] * ``` */ - public function columns(AbstractColumn ...$values): self + public function columns(ColumnInterface ...$values): self { $new = clone $this; $new->columns = $values; - return $new; } @@ -143,7 +151,7 @@ public function emptyCell(string $value): self /** * Return new instance with the filter model name. * - * @param string $value The form model name that keeps the user-entered filter data. When this property is set, the + * @param string|null $value The form model name that keeps the user-entered filter data. When this property is set, the * grid view will enable column-based filtering. Each data column by default will display a text field at the top * that users can fill in to filter the data. * @@ -151,7 +159,7 @@ public function emptyCell(string $value): self * property set and the attribute should be active in the current scenario of $filterModelName or have * {@see DataColumn::filter} set as the HTML code for the input field. */ - public function filterModelName(string $value): self + public function filterModelName(?string $value): self { $new = clone $this; $new->filterModelName = $value; @@ -329,190 +337,181 @@ public function tbodyClass(?string ...$class): static } /** - * Renders the data active record classes for the grid view. + * Return new instance with the HTML attributes for the `th` tag. * - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException + * @param array $attributes The tag attributes in terms of name-value pairs. */ - protected function renderItems(): string + public function headerCellAttributes(array $attributes): self { - $columns = $this->renderColumns(); - - $content = array_filter([ - $this->columnsGroupEnabled ? $this->renderColumnGroup($columns) : false, - $this->headerTableEnabled ? $this->renderTableHeader($columns) : false, - $this->footerEnabled ? $this->renderTableFooter($columns) : false, - $this->renderTableBody($columns), - ]); - - return Html::tag('table', PHP_EOL . implode(PHP_EOL, $content) . PHP_EOL, $this->tableAttributes) - ->encode(false) - ->render(); + $new = clone $this; + $new->headerCellAttributes = $attributes; + return $new; } /** - * This function tries to guess the columns to show from the given data if {@see columns} are not explicitly - * specified. + * Return new instance with the HTML attributes for the `td` tag. * - * @psalm-return list|list + * @param array $attributes The tag attributes in terms of name-value pairs. */ - private function guessColumns(): array + public function bodyCellAttributes(array $attributes): self { - $items = $this->getItems(); - - $columns = []; - foreach ($items as $item) { - /** - * @var string $name - * @var mixed $value - */ - foreach ($item as $name => $value) { - if ($value === null || is_scalar($value) || is_callable([$value, '__toString'])) { - $columns[] = DataColumn::create()->attribute($name); - } - } - break; - } - - if (!empty($items)) { - $columns[] = ActionColumn::create(); - } - - return $columns; + $new = clone $this; + $new->bodyCellAttributes = $attributes; + return $new; } /** - * Creates column objects and initializes them. + * Renders the data active record classes for the grid view. * * @throws InvalidConfigException * @throws NotFoundException * @throws NotInstantiableException * @throws CircularReferenceException - * - * @psalm-return array|array */ - private function renderColumns(): array + protected function renderItems(): string { - $columns = $this->columns; - - if ($columns === []) { - $columns = $this->guessColumns(); - } + $columns = empty($this->columns) ? $this->guessColumns() : $this->columns; + $columns = array_filter( + $columns, + static fn(ColumnInterface $column) => $column->isVisible() + ); + $renderers = []; foreach ($columns as $i => $column) { - if ($column instanceof AbstractColumn && $column->isVisible()) { - $column = $column->emptyCell($this->emptyCell); - - if ($column instanceof ActionColumn) { - $column = $column - ->currentRoute($this->currentRoute) - ->urlGenerator($this->getUrlGenerator()); - } - - if ($column instanceof DataColumn) { - $linkSorter = $this->renderLinkSorter($column->getAttribute(), $column->getLabel()); - $column = $column->filterModelName($this->filterModelName); - - if ($linkSorter !== '') { - $column = $column->linkSorter($linkSorter); - } - } + $renderers[$i] = $this->getColumnRenderer($column); + } - $columns[$i] = $column; - } else { - unset($columns[$i]); + $blocks = []; + + $globalContext = new GlobalContext( + $this->getDataReader(), + $this->sortLinkAttributes, + $this->urlArguments, + $this->urlQueryParameters, + $this->filterModelName, + ); + + if ($this->columnsGroupEnabled) { + $tags = []; + foreach ($columns as $i => $column) { + $cell = $renderers[$i]->renderColumn($column, new Cell(), $globalContext); + $tags[] = Html::col($cell->getAttributes()); } + $blocks[] = Html::colgroup()->columns(...$tags)->render(); } - return $columns; - } - - /** - * Renders the column group. - * - * @param array $columns The columns of gridview. - * - * @psalm-param array|array $columns - */ - private function renderColumnGroup(array $columns): string - { - $cols = []; - - foreach ($columns as $column) { - if ($column instanceof AbstractColumn) { - $cols[] = Col::tag()->attributes($column->getAttributes()); + if ($this->filterPosition === self::FILTER_POS_BODY + || $this->filterPosition === self::FILTER_POS_HEADER + || $this->filterPosition === self::FILTER_POS_FOOTER + ) { + $tags = []; + $hasFilters = false; + foreach ($columns as $i => $column) { + $baseCell = new Cell(encode: false, content: ' '); + $cell = $renderers[$i]->renderFilter($column, $baseCell, $globalContext); + if ($cell === null) { + $cell = $baseCell; + } else { + $hasFilters = true; + } + /** @var string|Stringable $content */ + $content = $cell->getContent(); + $tags[] = Html::td(attributes: $cell->getAttributes()) + ->content($content) + ->encode($cell->isEncode()) + ->doubleEncode($cell->isDoubleEncode()); } + $filterRow = $hasFilters ? Html::tr($this->filterRowAttributes)->cells(...$tags) : null; + } else { + $filterRow = null; } - return Colgroup::tag()->columns(...$cols)->render(); - } + if ($this->headerTableEnabled) { + $tags = []; + foreach ($columns as $i => $column) { + $cell = $renderers[$i]->renderHeader($column, new Cell($this->headerCellAttributes), $globalContext); + /** @var string|Stringable $content */ + $content = $cell?->getContent(); + $tags[] = $cell === null + ? Html::th(' ')->encode(false) + : Html::th(attributes: $cell->getAttributes()) + ->content($content) + ->encode($cell->isEncode()) + ->doubleEncode($cell->isDoubleEncode()); + } + $headerRow = Html::tr($this->headerRowAttributes)->cells(...$tags); + + if ($filterRow === null) { + $rows = [$headerRow]; + } elseif ($this->filterPosition === self::FILTER_POS_HEADER) { + $rows = [$filterRow, $headerRow]; + } elseif ($this->filterPosition === self::FILTER_POS_BODY) { + $rows = [$headerRow, $filterRow]; + } else { + $rows = [$headerRow]; + } - /** - * Renders the filter. - * - * @param array $columns The columns of gridview. - * - * @return string The rendering result. - * - * @psalm-param array|array $columns - */ - private function renderFilters(array $columns): string - { - $cells = []; - $countFilter = 0; - $filterRowAttributes = $this->filterRowAttributes; + $blocks[] = Html::thead()->rows(...$rows)->render(); + } - Html::addCssClass($filterRowAttributes, 'filters'); + if ($this->footerEnabled) { + $tags = []; + foreach ($columns as $i => $column) { + $cell = $renderers[$i]->renderFooter( + $column, + (new Cell())->content(' ')->encode(false), + $globalContext + ); + /** @var string|Stringable $content */ + $content = $cell->getContent(); + $tags[] = Html::td(attributes: $cell->getAttributes()) + ->content($content) + ->encode($cell->isEncode()) + ->doubleEncode($cell->isDoubleEncode()); + } + $footerRow = Html::tr($this->footerRowAttributes)->cells(...$tags); - foreach ($columns as $column) { - if ($column instanceof DataColumn && ($column->getFilter() !== '' || $column->getFilterAttribute() !== '')) { - $cells[] = $column->renderFilterCell(); - $countFilter++; - } else { - $cells[] = Td::tag()->content(' ')->encode(false)->render(); + $rows = [$footerRow]; + if ($this->filterPosition === self::FILTER_POS_FOOTER) { + /** @var Tr */ + $rows[] = $filterRow; } - } - return match ($countFilter > 0) { - false => '', - default => Html::tag('tr', PHP_EOL . implode(PHP_EOL, $cells) . PHP_EOL, $filterRowAttributes) - ->encode(false) - ->render(), - }; - } + $blocks[] = Html::tfoot()->rows(...$rows)->render(); + } - /** - * Renders the table body. - * - * @param array $columns The columns of gridview. - * - * @psalm-param array|array $columns - * - * @throws InvalidConfigException - */ - private function renderTableBody(array $columns): string - { $rows = []; - $index = 0; foreach ($this->getItems() as $key => $value) { if ($this->beforeRow !== null) { - /** @var string */ + /** @var Tr|null $row */ $row = call_user_func($this->beforeRow, $value, $key, $index, $this); - if (!empty($row)) { $rows[] = $row; } } - $rows[] = $this->renderTableRow($columns, $value, $key, $index); + $tags = []; + foreach ($columns as $i => $column) { + $context = new DataContext($column, $value, $key, $index); + $cell = $renderers[$i]->renderBody($column, new Cell(), $context); + $contentSource = $cell->getContent(); + /** @var string|Stringable $content */ + $content = $contentSource instanceof Closure + ? $contentSource($context) + : $contentSource; + $tags[] = empty($content) + ? Html::td()->content($this->emptyCell)->encode(false) + : Html::td(attributes: $this->prepareBodyAttributes($cell->getAttributes(), $context)) + ->content($content) + ->encode($cell->isEncode()) + ->doubleEncode($cell->isDoubleEncode()); + } + $rows[] = Html::tr($this->rowAttributes)->cells(...$tags); if ($this->afterRow !== null) { - /** @var string */ + /** @var Tr|null $row */ $row = call_user_func($this->afterRow, $value, $key, $index, $this); - if (!empty($row)) { $rows[] = $row; } @@ -520,107 +519,64 @@ private function renderTableBody(array $columns): string $index++; } - - if ($rows === [] && $this->emptyText !== '') { - $colspan = count($columns); - - return Html::tbody($this->tbodyAttributes) - ->rows(Tr::tag()->cells($this->renderEmpty($colspan))) - ->render(); - } - - $tbody = Html::tbody($this->tbodyAttributes); - return $tbody->open() . PHP_EOL . implode(PHP_EOL, $rows) . PHP_EOL . $tbody->close(); + $blocks[] = empty($rows) + ? Html::tbody($this->tbodyAttributes) + ->rows(Html::tr()->cells($this->renderEmpty(count($columns)))) + ->render() + : Html::tbody($this->tbodyAttributes)->rows(...$rows)->render(); + + return Html::tag('table', attributes: $this->tableAttributes)->open() + . PHP_EOL + . implode(PHP_EOL, $blocks) + . PHP_EOL + . ''; } /** - * Renders the table footer. - * - * @param array $columns The columns of gridview. + * This function tries to guess the columns to show from the given data if {@see columns} are not explicitly + * specified. * - * @psalm-param array|array $columns + * @psalm-return list */ - private function renderTableFooter(array $columns): string + private function guessColumns(): array { - $cells = []; - $footerRowAttributes = $this->footerRowAttributes; + $items = $this->getItems(); - foreach ($columns as $column) { - if ($column instanceof AbstractColumn) { - $cells[] = $column->renderFooterCell(); + $columns = []; + foreach ($items as $item) { + /** + * @var string $name + * @var mixed $value + */ + foreach ($item as $name => $value) { + if ($value === null || is_scalar($value) || is_callable([$value, '__toString'])) { + $columns[] = new DataColumn(property: $name); + } } + break; } - $content = Html::tag('tr', PHP_EOL . implode('', $cells) . PHP_EOL, $footerRowAttributes) - ->encode(false) - ->render(); - - if ($this->filterPosition === self::FILTER_POS_FOOTER) { - $content .= PHP_EOL . $this->renderFilters($columns); + if (!empty($items)) { + $columns[] = new ActionColumn(); } - return Html::tag('tfoot', PHP_EOL . $content . PHP_EOL)->encode(false)->render(); + return $columns; } - /** - * Renders the table header. - * - * @param array $columns The columns of gridview. - * - * @psalm-param array|array $columns - */ - private function renderTableHeader(array $columns): string + private function prepareBodyAttributes(array $attributes, DataContext $context): array { - $cell = []; - $cells = ''; - - foreach ($columns as $column) { - if ($column instanceof AbstractColumn) { - $cell[] = $column->renderHeaderCell(); + foreach ($attributes as $i => $attribute) { + if (is_callable($attribute)) { + $attributes[$i] = $attribute($context); } } - if ($cell !== []) { - $cells = PHP_EOL . implode(PHP_EOL, $cell) . PHP_EOL; - } - - $content = Html::tag('tr', $cells, $this->headerRowAttributes)->encode(false)->render(); - $renderFilters = PHP_EOL . $this->renderFilters($columns); - - if ($this->filterPosition === self::FILTER_POS_HEADER) { - $content = $renderFilters . PHP_EOL . $content; - } elseif (self::FILTER_POS_BODY === $this->filterPosition) { - $content .= $renderFilters; - } - - return Html::tag('thead', PHP_EOL . trim($content) . PHP_EOL)->encode(false)->render(); + return $attributes; } - /** - * Renders a table row with the given data and key. - * - * @param array $columns The columns of gridview. - * @param array|object $data The data. - * @param mixed $key The key associated with the data. - * @param int $index The zero-based index of the data in the data provider. - * - * @psalm-param array|array $columns - */ - private function renderTableRow(array $columns, array|object $data, mixed $key, int $index): string + private function getColumnRenderer(ColumnInterface $column): ColumnRendererInterface { - $cells = []; - $content = ''; - - foreach ($columns as $column) { - if ($column instanceof AbstractColumn) { - $cells[] = $column->renderDataCell($data, $key, $index); - } - } - - if ($cells !== []) { - $content = PHP_EOL . implode(PHP_EOL, $cells) . PHP_EOL; - } - - return Html::tag('tr', $content, $this->rowAttributes)->encode(false)->render(); + /** @var ColumnRendererInterface */ + return $this->columnRenderersContainer->get($column->getRenderer()); } } diff --git a/tests/Column/ActionColumnTest.php b/tests/Column/ActionColumnTest.php index ff14772b1..4bbe47740 100644 --- a/tests/Column/ActionColumnTest.php +++ b/tests/Column/ActionColumnTest.php @@ -9,8 +9,9 @@ use Yiisoft\Definitions\Exception\InvalidConfigException; use Yiisoft\Definitions\Exception\NotInstantiableException; use Yiisoft\Factory\NotFoundException; -use Yiisoft\Html\Tag\A; +use Yiisoft\Html\Html; use Yiisoft\Yii\DataView\Column\ActionColumn; +use Yiisoft\Yii\DataView\Column\Base\DataContext; use Yiisoft\Yii\DataView\Column\DataColumn; use Yiisoft\Yii\DataView\GridView; use Yiisoft\Yii\DataView\Tests\Support\Assert; @@ -44,10 +45,14 @@ public function testContent(): void - 🔎 + + 🔎 + - 🔎 + + 🔎 + @@ -56,16 +61,14 @@ public function testContent(): void HTML, GridView::widget() ->columns( - ActionColumn::create() - ->content( - /** @psalm-param string[] $data */ - static fn (array $data): string => A::tag() - ->addAttributes(['class' => 'text-decoration-none', 'title' => 'View']) - ->content('🔎') - ->encode(false) - ->href('/admin/view?id=' . $data['id']) - ->render(), - ), + new ActionColumn( + content: static fn(DataContext $context): string => Html::a() + ->addAttributes(['class' => 'text-decoration-none', 'title' => 'View']) + ->content('🔎') + ->encode(false) + ->href('/admin/view?id=' . $context->getData()['id']) + ->render(), + ) ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -92,10 +95,14 @@ public function testContentAttributes(): void - 🔎 + + 🔎 + - 🔎 + + 🔎 + @@ -104,17 +111,15 @@ public function testContentAttributes(): void HTML, GridView::widget() ->columns( - ActionColumn::create() - ->content( - /** @psalm-param string[] $data */ - static fn (array $data): string => A::tag() - ->addAttributes(['title' => 'View']) - ->content('🔎') - ->encode(false) - ->href('/admin/view?id=' . $data['id']) - ->render(), - ) - ->contentAttributes(['class' => 'text-decoration-none test.class']), + new ActionColumn( + content: static fn(DataContext $context): string => Html::a() + ->addAttributes(['title' => 'View']) + ->content('🔎') + ->encode(false) + ->href('/admin/view?id=' . $context->getData()['id']) + ->render(), + bodyAttributes: ['class' => 'text-decoration-none test.class'] + ), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -141,12 +146,12 @@ public function testCustomButton(): void - + 🔒 - + 🔒 @@ -157,19 +162,18 @@ public function testCustomButton(): void HTML, GridView::widget() ->columns( - ActionColumn::create() - ->buttons( - [ - 'resend-password' => static fn (string $url): string => A::tag() - ->addAttributes(['class' => 'text-decoration-none', 'title' => 'Resend password']) - ->content('🔒') - ->encode(false) - ->href($url) - ->render(), - ], - ) - ->template('{resend-password}') - ->visibleButtons(['resend-password' => true]), + new ActionColumn( + buttons: [ + 'resend-password' => static fn(string $url): string => Html::a() + ->addAttributes(['class' => 'text-decoration-none', 'title' => 'Resend password']) + ->content('🔒') + ->encode(false) + ->href($url) + ->render(), + ], + template: '{resend-password}', + visibleButtons: ['resend-password' => true] + ), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -177,57 +181,6 @@ public function testCustomButton(): void ); } - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ - public function testDataLabel(): void - { - Assert::equalsWithoutLE( - << - - - - - - - - - - - - - - -
Actions
- 🔎 - - -
- 🔎 - - -
-
Page 1 of 1
- - HTML, - GridView::widget() - ->columns(ActionColumn::create()->dataLabel('test.label')) - ->id('w1-grid') - ->dataReader($this->createOffsetPaginator($this->data, 10)) - ->render() - ); - } - - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ public function testFooterAttributes(): void { Assert::equalsWithoutLE( @@ -246,14 +199,14 @@ public function testFooterAttributes(): void - + 🔎 - + 🔎 @@ -266,7 +219,10 @@ public function testFooterAttributes(): void HTML, GridView::widget() ->columns( - ActionColumn::create()->footer('test.footer')->footerAttributes(['class' => 'test.class']), + new ActionColumn( + footer: 'test.footer', + footerAttributes: ['class' => 'test.class'], + ), ) ->footerEnabled(true) ->id('w1-grid') @@ -275,12 +231,6 @@ public function testFooterAttributes(): void ); } - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ public function testLabel(): void { Assert::equalsWithoutLE( @@ -294,14 +244,14 @@ public function testLabel(): void - + 🔎 - + 🔎 @@ -313,7 +263,7 @@ public function testLabel(): void HTML, GridView::widget() - ->columns(ActionColumn::create()->label('test.label')) + ->columns(new ActionColumn(header: 'test.label')) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) ->render() @@ -339,14 +289,14 @@ public function testLabelWithMbString(): void - + 🔎 - + 🔎 @@ -358,7 +308,7 @@ public function testLabelWithMbString(): void HTML, GridView::widget() - ->columns(ActionColumn::create()->label('Ενέργειες')) + ->columns(new ActionColumn(header: 'Ενέργειες')) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) ->render() @@ -384,14 +334,14 @@ public function testLabelAttributes(): void - + 🔎 - + 🔎 @@ -403,64 +353,18 @@ public function testLabelAttributes(): void HTML, GridView::widget() - ->columns(ActionColumn::create()->label('test.label')->labelAttributes(['class' => 'test.class'])) - ->id('w1-grid') - ->dataReader($this->createOffsetPaginator($this->data, 10)) - ->render() - ); - } - - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ - public function testName(): void - { - Assert::equalsWithoutLE( - << - - - - - - - - - - - - - - -
Actions
- 🔎 - - -
- 🔎 - - -
-
Page 1 of 1
- - HTML, - GridView::widget() - ->columns(ActionColumn::create()->name('test.name')) + ->columns( + new ActionColumn( + header: 'test.label', + headerAttributes: ['class' => 'test.class'], + ), + ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) ->render() ); } - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ public function testNotVisible(): void { Assert::equalsWithoutLE( @@ -479,7 +383,7 @@ public function testNotVisible(): void HTML, GridView::widget() - ->columns(ActionColumn::create()->visible(false)) + ->columns(new ActionColumn(visible: false)) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) ->render() @@ -505,14 +409,14 @@ public function testPrimaryKey(): void - + 🔎 - + 🔎 @@ -524,7 +428,7 @@ public function testPrimaryKey(): void HTML, GridView::widget() - ->columns(ActionColumn::create()->primaryKey('identity_id')) + ->columns(new ActionColumn(primaryKey: 'identity_id')) ->id('w1-grid') ->dataReader( $this->createOffsetPaginator( @@ -560,18 +464,18 @@ public function testRender(): void - 1 - John - + 1 + John + 🔎 - 2 - Mary - + 2 + Mary + 🔎 @@ -584,9 +488,9 @@ public function testRender(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - ActionColumn::create(), + new DataColumn('id'), + new DataColumn('name'), + new ActionColumn(), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -613,14 +517,14 @@ public function testUrlArguments(): void - + 🔎 - + 🔎 @@ -632,7 +536,7 @@ public function testUrlArguments(): void HTML, GridView::widget() - ->columns(ActionColumn::create()->urlArguments(['test-arguments' => 'test.arguments'])) + ->columns(new ActionColumn(urlArguments: ['test-arguments' => 'test.arguments'])) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) ->render() @@ -658,14 +562,14 @@ public function testUrlCreator(): void - + 🔎 - + 🔎 @@ -678,11 +582,12 @@ public function testUrlCreator(): void HTML, GridView::widget() ->columns( - ActionColumn::create() - ->urlCreator( - /** @psalm-param string[] $data */ - static fn (string $action, array $data): string => 'https://test.com/' . $action . '?id=' . $data['id'], - ), + new ActionColumn( + urlCreator: static fn( + string $action, + array $data + ): string => 'https://test.com/' . $action . '?id=' . $data['id'], + ) ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -690,12 +595,6 @@ public function testUrlCreator(): void ); } - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ public function testUrlQueryParameters(): void { Assert::equalsWithoutLE( @@ -709,14 +608,14 @@ public function testUrlQueryParameters(): void - + 🔎 - + 🔎 @@ -728,19 +627,13 @@ public function testUrlQueryParameters(): void HTML, GridView::widget() - ->columns(ActionColumn::create()->urlQueryParameters(['test-param' => 'test.param'])) + ->columns(new ActionColumn(urlQueryParameters: ['test-param' => 'test.param'])) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) ->render() ); } - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ public function testUrlParamsConfig(): void { Assert::equalsWithoutLE( @@ -754,14 +647,14 @@ public function testUrlParamsConfig(): void - + 🔎 - + 🔎 @@ -773,19 +666,13 @@ public function testUrlParamsConfig(): void HTML, GridView::widget() - ->columns(ActionColumn::create()->urlParamsConfig(['test-param' => 'test.param'])) + ->columns(new ActionColumn(urlParamsConfig: ['test-param' => 'test.param'])) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) ->render() ); } - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ public function testVisibleButtonsClosure(): void { Assert::equalsWithoutLE( @@ -799,12 +686,12 @@ public function testVisibleButtonsClosure(): void - + 🔎 - + @@ -815,8 +702,8 @@ public function testVisibleButtonsClosure(): void HTML, GridView::widget() ->columns( - ActionColumn::create()->visibleButtons( - [ + new ActionColumn( + visibleButtons: [ 'view' => static fn (array $data): bool => $data['id'] === 1, 'update' => static fn (array $data): bool => $data['id'] !== 1, ], diff --git a/tests/Column/CheckboxColumnTest.php b/tests/Column/CheckboxColumnTest.php index f9c11fa86..b099e4d16 100644 --- a/tests/Column/CheckboxColumnTest.php +++ b/tests/Column/CheckboxColumnTest.php @@ -9,6 +9,8 @@ use Yiisoft\Definitions\Exception\InvalidConfigException; use Yiisoft\Definitions\Exception\NotInstantiableException; use Yiisoft\Factory\NotFoundException; +use Yiisoft\Html\Tag\Input\Checkbox; +use Yiisoft\Yii\DataView\Column\Base\DataContext; use Yiisoft\Yii\DataView\Column\CheckboxColumn; use Yiisoft\Yii\DataView\Column\DataColumn; use Yiisoft\Yii\DataView\GridView; @@ -40,18 +42,18 @@ public function testContent(): void Id Name - + - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -61,11 +63,9 @@ public function testContent(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - CheckboxColumn::create()->content( - static fn (array|object $data, mixed $key, int $index): string => '' - ), + new DataColumn('id'), + new DataColumn('name'), + new CheckboxColumn(content: static fn(Checkbox $input, DataContext $context): string => ''), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -89,18 +89,18 @@ public function testContentAttributes(): void Id Name - + - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -110,60 +110,13 @@ public function testContentAttributes(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - CheckboxColumn::create() - ->content( - static fn (array|object $data, mixed $key, int $index): string => '' - ) - ->contentAttributes(['class' => 'test.class']), - ) - ->id('w1-grid') - ->dataReader($this->createOffsetPaginator($this->data, 10)) - ->render() - ); - } - - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ - public function testDataLabel(): void - { - Assert::equalsWithoutLE( - << - - - - - - - - - - - - - - - - - - - - -
IdName
1John
2Mary
-
Page 1 of 1
- - HTML, - GridView::widget() - ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - CheckboxColumn::create()->dataLabel('test.label'), + new DataColumn('id'), + new DataColumn('name'), + new CheckboxColumn( + content: static fn(Checkbox $input, DataContext $context): string => '', + bodyAttributes: ['class' => 'test.class'], + ), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -192,14 +145,14 @@ public function testLabel(): void - 1 - John - + 1 + John + - 2 - Mary - + 2 + Mary + @@ -208,9 +161,9 @@ public function testLabel(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - CheckboxColumn::create()->label('test.label'), + new DataColumn('id'), + new DataColumn('name'), + new CheckboxColumn(header: 'test.label'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -239,14 +192,14 @@ public function testLabelMbString(): void - 1 - John - + 1 + John + - 2 - Mary - + 2 + Mary + @@ -255,9 +208,9 @@ public function testLabelMbString(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - CheckboxColumn::create()->label('Πλαίσιο ελέγχου'), + new DataColumn('id'), + new DataColumn('name'), + new CheckboxColumn(header: 'Πλαίσιο ελέγχου'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -286,14 +239,14 @@ public function testLabelAttributes(): void - 1 - John - + 1 + John + - 2 - Mary - + 2 + Mary + @@ -302,9 +255,9 @@ public function testLabelAttributes(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - CheckboxColumn::create()->label('test.label')->labelAttributes(['class' => 'test.class']), + new DataColumn('id'), + new DataColumn('name'), + new CheckboxColumn(header: 'test.label', headerAttributes: ['class' => 'test.class']), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -328,19 +281,19 @@ public function testName(): void Id Name - + - 1 - John - + 1 + John + - 2 - Mary - + 2 + Mary + @@ -349,9 +302,9 @@ public function testName(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - CheckboxColumn::create()->name('test.checkbox'), + new DataColumn('id'), + new DataColumn('name'), + new CheckboxColumn(name: 'test.checkbox'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -380,13 +333,13 @@ public function testNotMultiple(): void - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -396,9 +349,9 @@ public function testNotMultiple(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - CheckboxColumn::create()->multiple(false), + new DataColumn('id'), + new DataColumn('name'), + new CheckboxColumn(multiple: false), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -426,12 +379,12 @@ public function testNotVisible(): void - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -440,9 +393,9 @@ public function testNotVisible(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - CheckboxColumn::create()->visible(false), + new DataColumn('id'), + new DataColumn('name'), + new CheckboxColumn(visible: false), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -466,18 +419,18 @@ public function testRender(): void Id Name - + - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -487,9 +440,9 @@ public function testRender(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - CheckboxColumn::create(), + new DataColumn('id'), + new DataColumn('name'), + new CheckboxColumn(), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) diff --git a/tests/Column/DataColumnFilterTest.php b/tests/Column/DataColumnFilterTest.php index 5dd4f4cf0..9526ac067 100644 --- a/tests/Column/DataColumnFilterTest.php +++ b/tests/Column/DataColumnFilterTest.php @@ -80,19 +80,19 @@ public function testFilter(): void Id Name - -   - + +   + - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -101,8 +101,8 @@ public function testFilter(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id')->filter(' '), - DataColumn::create()->attribute('name')->filter(''), + new DataColumn('id', filter: ' '), + new DataColumn('name', filter: ''), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -128,22 +128,22 @@ public function testFilterDate(): void Name Birthday - +     - + - 1 - John - 2000-01-01 + 1 + John + 2000-01-01 - 2 - Mary - 2000-01-02 + 2 + Mary + 2000-01-02 @@ -152,9 +152,9 @@ public function testFilterDate(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('birthday')->filterAttribute('birthday')->filterType('date'), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('birthday', filterProperty: 'birthday', filterType: 'date'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->dataWithDate, 10)) @@ -180,22 +180,22 @@ public function testFilterDateTime(): void Name Birthday - +     - + - 1 - John - 2000-01-01 00:00:00 + 1 + John + 2000-01-01 00:00:00 - 2 - Mary - 2000-01-02 00:00:00 + 2 + Mary + 2000-01-02 00:00:00 @@ -204,9 +204,9 @@ public function testFilterDateTime(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('birthday')->filterAttribute('birthday')->filterType('datetime'), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('birthday', filterProperty: 'birthday', filterType: 'datetime'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->dataWithDateTime, 10)) @@ -232,22 +232,22 @@ public function testFilterEmail(): void Name Email - +     - + - 1 - John - test1@example.com + 1 + John + test1@example.com - 2 - Mary - test2@example.com + 2 + Mary + test2@example.com @@ -256,9 +256,9 @@ public function testFilterEmail(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('email')->filterAttribute('email')->filterType('email'), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('email', filterProperty: 'email', filterType: 'email'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->dataWithEmail, 10)) @@ -283,19 +283,19 @@ public function testFilterInputAttributes(): void Id Name - - - + + + - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -304,16 +304,18 @@ public function testFilterInputAttributes(): void HTML, GridView::widget() ->columns( - DataColumn::create() - ->attribute('id') - ->filterAttribute('id') - ->filterInputAttributes(['class' => 'test.class']) - ->filterValueDefault(0), - DataColumn::create() - ->attribute('name') - ->filterAttribute('name') - ->filterInputAttributes(['class' => 'test.class']) - ->filterValueDefault(''), + new DataColumn( + property: 'id', + filterProperty: 'id', + filterInputAttributes: ['class' => 'test.class'], + filterValueDefault: 0, + ), + new DataColumn( + property: 'name', + filterProperty: 'name', + filterInputAttributes: ['class' => 'test.class'], + filterValueDefault: '', + ), ) ->filterModelName('searchModel') ->id('w1-grid') @@ -340,22 +342,22 @@ public function testFilterMonth(): void Name Month - +     - + - 1 - John - 2000-01 + 1 + John + 2000-01 - 2 - Mary - 2000-02 + 2 + Mary + 2000-02 @@ -364,9 +366,9 @@ public function testFilterMonth(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('month')->filterAttribute('month')->filterType('month'), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('month', filterProperty: 'month', filterType: 'month'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->dataWithMonth, 10)) @@ -391,19 +393,19 @@ public function testFilterNumber(): void Id Name - - + +   - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -412,8 +414,8 @@ public function testFilterNumber(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id')->filterAttribute('id')->filterType('number'), - DataColumn::create()->attribute('name'), + new DataColumn('id', filterProperty: 'id', filterType: 'number'), + new DataColumn('name'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -441,21 +443,22 @@ public function testFilterPositionFooter(): void -    +   +   - - - + + + - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -464,18 +467,20 @@ public function testFilterPositionFooter(): void HTML, GridView::widget() ->columns( - DataColumn::create() - ->attribute('id') - ->filterAttribute('id') - ->filterValueDefault(0) - ->filterAttributes(['class' => 'text-center', 'style' => 'width:60px']) - ->filterInputAttributes(['maxlength' => '5']), - DataColumn::create() - ->attribute('name') - ->filterAttribute('name') - ->filterValueDefault('') - ->filterAttributes(['class' => 'text-center', 'style' => 'width:60px']) - ->filterInputAttributes(['maxlength' => '5']), + new DataColumn( + property: 'id', + filterProperty: 'id', + filterValueDefault: 0, + filterAttributes: ['class' => 'text-center', 'style' => 'width:60px'], + filterInputAttributes: ['maxlength' => '5'], + ), + new DataColumn( + property: 'name', + filterProperty: 'name', + filterValueDefault: '', + filterAttributes: ['class' => 'text-center', 'style' => 'width:60px'], + filterInputAttributes: ['maxlength' => '5'], + ), ) ->filterModelName('searchModel') ->filterPosition(GridView::FILTER_POS_FOOTER) @@ -499,9 +504,9 @@ public function testFilterPositionHeader(): void
- - - + + + @@ -510,12 +515,12 @@ public function testFilterPositionHeader(): void - - + + - - + +
Id
1John1John
2Mary2Mary
@@ -524,18 +529,20 @@ public function testFilterPositionHeader(): void HTML, GridView::widget() ->columns( - DataColumn::create() - ->attribute('id') - ->filterAttribute('id') - ->filterValueDefault(0) - ->filterAttributes(['class' => 'text-center', 'style' => 'width:60px']) - ->filterInputAttributes(['maxlength' => '5']), - DataColumn::create() - ->attribute('name') - ->filterAttribute('name') - ->filterValueDefault('') - ->filterAttributes(['class' => 'text-center', 'style' => 'width:60px']) - ->filterInputAttributes(['maxlength' => '5']), + new DataColumn( + property: 'id', + filterProperty: 'id', + filterValueDefault: 0, + filterAttributes: ['class' => 'text-center', 'style' => 'width:60px'], + filterInputAttributes: ['maxlength' => '5'], + ), + new DataColumn( + property: 'name', + filterProperty: 'name', + filterValueDefault: '', + filterAttributes: ['class' => 'text-center', 'style' => 'width:60px'], + filterInputAttributes: ['maxlength' => '5'], + ), ) ->filterModelName('searchModel') ->filterPosition(GridView::FILTER_POS_HEADER) @@ -562,19 +569,19 @@ public function testFilterRange(): void Id Name - - + +   - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -583,12 +590,13 @@ public function testFilterRange(): void HTML, GridView::widget() ->columns( - DataColumn::create() - ->attribute('id') - ->filterAttribute('id') - ->filterType('range') - ->filterValueDefault(0), - DataColumn::create()->attribute('name'), + new DataColumn( + property: 'id', + filterProperty: 'id', + filterType: 'range', + filterValueDefault: 0, + ), + new DataColumn('name'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -613,19 +621,19 @@ public function testFilterRowAttributes(): void Id Name - - - + + + - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -634,18 +642,20 @@ public function testFilterRowAttributes(): void HTML, GridView::widget() ->columns( - DataColumn::create() - ->attribute('id') - ->filterAttribute('id') - ->filterValueDefault(0) - ->filterAttributes(['class' => 'text-center', 'style' => 'width:60px']) - ->filterInputAttributes(['maxlength' => '5']), - DataColumn::create() - ->attribute('name') - ->filterAttribute('name') - ->filterValueDefault('') - ->filterAttributes(['class' => 'text-center', 'style' => 'width:60px']) - ->filterInputAttributes(['maxlength' => '5']), + new DataColumn( + property: 'id', + filterProperty: 'id', + filterValueDefault: 0, + filterAttributes: ['class' => 'text-center', 'style' => 'width:60px'], + filterInputAttributes: ['maxlength' => '5'], + ), + new DataColumn( + property: 'name', + filterProperty: 'name', + filterValueDefault: '', + filterAttributes: ['class' => 'text-center', 'style' => 'width:60px'], + filterInputAttributes: ['maxlength' => '5'], + ), ) ->filterModelName('searchModel') ->filterRowAttributes(['class' => 'text-center']) @@ -672,19 +682,19 @@ public function testFilterSearch(): void Id Name - +   - + - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -693,8 +703,8 @@ public function testFilterSearch(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name')->filterAttribute('name')->filterType('search'), + new DataColumn('id'), + new DataColumn('name', filterProperty: 'name', filterType: 'search'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -719,23 +729,23 @@ public function testFilterSelect(): void Id Name - - - +   - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -744,13 +754,15 @@ public function testFilterSelect(): void HTML, GridView::widget() ->columns( - DataColumn::create() - ->attribute('id') - ->filterAttribute('id') - ->filterInputSelectItems(['1' => 'Jhon', '2' => 'Mary']) - ->filterInputSelectPrompt('Select...', 0) - ->filterType('select'), - DataColumn::create()->attribute('name'), + new DataColumn( + property: 'id', + filterProperty: 'id', + filterInputSelectItems: ['1' => 'Jhon', '2' => 'Mary'], + filterInputSelectPrompt: 'Select...', + filterValueDefault: 0, + filterType: 'select', + ), + new DataColumn('name'), ) ->filterModelName('searchModel') ->filterRowAttributes(['class' => 'text-center']) @@ -778,22 +790,22 @@ public function testFilterTelephone(): void Name Telephone - +     - + - 1 - John - 1 (555) 123-4567 + 1 + John + 1 (555) 123-4567 - 2 - Mary - 1 (555) 123-4568 + 2 + Mary + 1 (555) 123-4568 @@ -802,9 +814,9 @@ public function testFilterTelephone(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('telephone')->filterAttribute('telephone')->filterType('tel'), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('telephone', filterProperty: 'telephone', filterType: 'tel'), ) ->filterModelName('searchModel') ->filterRowAttributes(['class' => 'text-center']) @@ -832,22 +844,22 @@ public function testFilterTime(): void Name Time - +     - + - 1 - John - 12:00:00 + 1 + John + 12:00:00 - 2 - Mary - 12:00:01 + 2 + Mary + 12:00:01 @@ -856,9 +868,9 @@ public function testFilterTime(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('time')->filterAttribute('time')->filterType('time'), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('time', filterProperty: 'time', filterType: 'time'), ) ->filterModelName('searchModel') ->filterRowAttributes(['class' => 'text-center']) @@ -886,22 +898,22 @@ public function testFilterUrl(): void Name Url - +     - + - 1 - John -   + 1 + John +   - 2 - Mary -   + 2 + Mary +   @@ -910,9 +922,9 @@ public function testFilterUrl(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('url')->filterAttribute('url')->filterType('url'), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('url', filterProperty: 'url', filterType: 'url'), ) ->filterModelName('searchModel') ->filterRowAttributes(['class' => 'text-center']) @@ -940,22 +952,22 @@ public function testFilterWeek(): void Name Week - +     - + - 1 - John - 2000-W01 + 1 + John + 2000-W01 - 2 - Mary - 2000-W02 + 2 + Mary + 2000-W02 @@ -964,9 +976,9 @@ public function testFilterWeek(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('week')->filterAttribute('week')->filterType('week'), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('week', filterProperty: 'week', filterType: 'week'), ) ->filterModelName('searchModel') ->filterRowAttributes(['class' => 'text-center']) @@ -993,19 +1005,19 @@ public function testFilters(): void Id Name - - - + + + - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -1014,18 +1026,20 @@ public function testFilters(): void HTML, GridView::widget() ->columns( - DataColumn::create() - ->attribute('id') - ->filterAttribute('id') - ->filterValueDefault(0) - ->filterAttributes(['class' => 'text-center', 'style' => 'width:60px']) - ->filterInputAttributes(['maxlength' => '5']), - DataColumn::create() - ->attribute('name') - ->filterAttribute('name') - ->filterValueDefault('') - ->filterAttributes(['class' => 'text-center', 'style' => 'width:60px']) - ->filterInputAttributes(['maxlength' => '5']), + new DataColumn( + property: 'id', + filterProperty: 'id', + filterValueDefault: 0, + filterAttributes: ['class' => 'text-center', 'style' => 'width:60px'], + filterInputAttributes: ['maxlength' => '5'], + ), + new DataColumn( + property: 'name', + filterProperty: 'name', + filterValueDefault: '', + filterAttributes: ['class' => 'text-center', 'style' => 'width:60px'], + filterInputAttributes: ['maxlength' => '5'], + ), ) ->filterModelName('searchModel') ->id('w1-grid') diff --git a/tests/Column/DataColumnTest.php b/tests/Column/DataColumnTest.php index 33e5f7af2..9d866e16b 100644 --- a/tests/Column/DataColumnTest.php +++ b/tests/Column/DataColumnTest.php @@ -9,6 +9,7 @@ use Yiisoft\Definitions\Exception\InvalidConfigException; use Yiisoft\Definitions\Exception\NotInstantiableException; use Yiisoft\Factory\NotFoundException; +use Yiisoft\Yii\DataView\Column\Base\DataContext; use Yiisoft\Yii\DataView\Column\DataColumn; use Yiisoft\Yii\DataView\GridView; use Yiisoft\Yii\DataView\Tests\Support\Assert; @@ -43,12 +44,12 @@ public function testContent(): void - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -57,12 +58,14 @@ public function testContent(): void HTML, GridView::widget() ->columns( - DataColumn::create() - ->attribute('id') - ->content(static fn (array $data): int => (int) $data['id']), - DataColumn::create() - ->attribute('name') - ->content(static fn (array $data): string => (string) $data['name']), + new DataColumn( + 'id', + content: static fn(DataContext $context): int => (int)$context->getData()['id'], + ), + new DataColumn( + 'name', + content: static fn(DataContext $context): string => (string)$context->getData()['name'], + ), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -90,12 +93,12 @@ public function testContentAttributes(): void - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -104,14 +107,16 @@ public function testContentAttributes(): void HTML, GridView::widget() ->columns( - DataColumn::create() - ->attribute('id') - ->content(static fn (array $data): int => (int) $data['id']) - ->contentAttributes(['class' => 'test.class']), - DataColumn::create() - ->attribute('name') - ->content(static fn (array $data): string => (string) $data['name']) - ->contentAttributes(['class' => 'test.class']), + new DataColumn( + 'id', + content: static fn(DataContext $context): int => (int)$context->getData()['id'], + bodyAttributes: ['class' => 'test.class'], + ), + new DataColumn( + 'name', + content: static fn(DataContext $context): string => (string)$context->getData()['name'], + bodyAttributes: ['class' => 'test.class'], + ), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -139,12 +144,12 @@ public function testContentAttributesClosure(): void - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -153,12 +158,8 @@ public function testContentAttributesClosure(): void HTML, GridView::widget() ->columns( - DataColumn::create() - ->attribute('id') - ->contentAttributes(['class' => static fn (): string => 'test.class']), - DataColumn::create() - ->attribute('name') - ->contentAttributes(['class' => static fn (): string => 'test.class']), + new DataColumn('id', bodyAttributes: ['class' => static fn(): string => 'test.class']), + new DataColumn('name', bodyAttributes: ['class' => static fn(): string => 'test.class']), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -166,55 +167,6 @@ public function testContentAttributesClosure(): void ); } - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ - public function testDataLabel(): void - { - Assert::equalsWithoutLE( - << - - - - - - - - - - - - - - - - - -
IdName
1John
2Mary
-
Page 1 of 1
-
- HTML, - GridView::widget() - ->columns( - DataColumn::create()->attribute('id')->dataLabel('test.id'), - DataColumn::create()->attribute('name')->dataLabel('test.name'), - ) - ->id('w1-grid') - ->dataReader($this->createOffsetPaginator($this->data, 10)) - ->render() - ); - } - - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ public function testLabel(): void { Assert::equalsWithoutLE( @@ -229,12 +181,12 @@ public function testLabel(): void - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -243,8 +195,8 @@ public function testLabel(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id')->label('test.id'), - DataColumn::create()->attribute('name')->label('test.username'), + new DataColumn('id', header: 'test.id'), + new DataColumn('name', header: 'test.username'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -272,12 +224,12 @@ public function testLabelMbString(): void - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -286,8 +238,8 @@ public function testLabelMbString(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name')->label('Όνομα χρήστη'), + new DataColumn('id'), + new DataColumn('name', header: 'Όνομα χρήστη'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -315,61 +267,12 @@ public function testLabelAttributes(): void - 1 - John - - - 2 - Mary - - - -
Page 1 of 1
- - HTML, - GridView::widget() - ->columns( - DataColumn::create() - ->attribute('id') - ->label('test.id') - ->labelAttributes(['class' => 'test.class']), - DataColumn::create() - ->attribute('name') - ->label('test.username') - ->labelAttributes(['class' => 'test.class']), - ) - ->id('w1-grid') - ->dataReader($this->createOffsetPaginator($this->data, 10)) - ->render() - ); - } - - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ - public function testLinkSorter(): void - { - Assert::equalsWithoutLE( - << - - - - - - - - - - - + + - - + +
idname
1John1John
2Mary2Mary
@@ -378,12 +281,8 @@ public function testLinkSorter(): void HTML, GridView::widget() ->columns( - DataColumn::create() - ->attribute('id') - ->linkSorter('id'), - DataColumn::create() - ->attribute('name') - ->linkSorter('name'), + new DataColumn('id', header: 'test.id', headerAttributes: ['class' => 'test.class']), + new DataColumn('name', header: 'test.username', headerAttributes: ['class' => 'test.class']), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -391,55 +290,6 @@ public function testLinkSorter(): void ); } - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ - public function testName(): void - { - Assert::equalsWithoutLE( - << - - - - - - - - - - - - - - - - - -
Id Name
1John
2Mary
-
Page 1 of 1
- - HTML, - GridView::widget() - ->columns( - DataColumn::create()->attribute('id')->name('test.id'), - DataColumn::create()->attribute('name')->name('test.username'), - ) - ->id('w1-grid') - ->dataReader($this->createOffsetPaginator($this->data, 10, 1, true)) - ->render() - ); - } - - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ public function testNotSorting(): void { Assert::equalsWithoutLE( @@ -454,12 +304,12 @@ public function testNotSorting(): void - 1 - test + 1 + test - 2 - test + 2 + test @@ -468,8 +318,8 @@ public function testNotSorting(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id')->withSorting(false), - DataColumn::create()->attribute('name')->value('test'), + new DataColumn('id', withSorting: false), + new DataColumn('name', content: 'test'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10, 1, true)) @@ -496,10 +346,10 @@ public function testNotVisible(): void - 1 + 1 - 2 + 2 @@ -508,8 +358,8 @@ public function testNotVisible(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name')->visible(false), + new DataColumn('id'), + new DataColumn('name', visible: false), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -537,12 +387,12 @@ public function testSort(): void - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -551,8 +401,8 @@ public function testSort(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), + new DataColumn('id'), + new DataColumn('name'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10, 1, true)) @@ -580,12 +430,12 @@ public function testValue(): void - 1 - test + 1 + test - 1 - test + 1 + test @@ -594,8 +444,8 @@ public function testValue(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id')->value(1), - DataColumn::create()->attribute('name')->value('test'), + new DataColumn('id', content: 1), + new DataColumn('name', content: 'test'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -623,12 +473,12 @@ public function testValueClosure(): void - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -637,12 +487,14 @@ public function testValueClosure(): void HTML, GridView::widget() ->columns( - DataColumn::create() - ->attribute('id') - ->value(static fn (array $data): int => (int) $data['id']), - DataColumn::create() - ->attribute('name') - ->value(static fn (array $data): string => (string) $data['name']), + new DataColumn( + 'id', + content: static fn(DataContext $context): string => (string)$context->getData()['id'] + ), + new DataColumn( + 'name', + content: static fn(DataContext $context): string => (string)$context->getData()['name'] + ), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) diff --git a/tests/Column/ExceptionTest.php b/tests/Column/ExceptionTest.php index 8dbd18c64..f5b218bb2 100644 --- a/tests/Column/ExceptionTest.php +++ b/tests/Column/ExceptionTest.php @@ -17,13 +17,6 @@ public function testFilterType(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid filter type "unknown".'); - Column\DataColumn::create()->filterType('unknown'); - } - - public function testGetUrlGenerator(): void - { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Url generator is not set'); - Column\ActionColumn::create()->getUrlGenerator(); + new Column\DataColumn(filterType: 'unknown'); } } diff --git a/tests/Column/ImmutableTest.php b/tests/Column/ImmutableTest.php deleted file mode 100644 index 414ae0c9a..000000000 --- a/tests/Column/ImmutableTest.php +++ /dev/null @@ -1,77 +0,0 @@ -assertNotSame($actionColumn, $actionColumn->buttons([])); - $this->assertNotSame($actionColumn, $actionColumn->createDefaultButtons()); - $this->assertNotSame($actionColumn, $actionColumn->primaryKey('')); - $this->assertNotSame($actionColumn, $actionColumn->template('{view}')); - $this->assertNotSame($actionColumn, $actionColumn->urlArguments([])); - $this->assertNotSame($actionColumn, $actionColumn->urlCreator(static fn () => '')); - $this->assertNotSame($actionColumn, $actionColumn->urlGenerator(Mock::urlGenerator())); - $this->assertNotSame($actionColumn, $actionColumn->urlName('')); - $this->assertNotSame($actionColumn, $actionColumn->urlQueryParameters([])); - $this->assertNotSame($actionColumn, $actionColumn->urlParamsConfig([])); - $this->assertNotSame($actionColumn, $actionColumn->visibleButtons([])); - } - - public function testCheckboxColumn(): void - { - $checkboxColumn = Column\CheckboxColumn::create(); - $this->assertNotSame($checkboxColumn, $checkboxColumn->multiple(false)); - } - - public function testColumn(): void - { - $column = $this->createColumn(); - $this->assertNotSame($column, $column->attributes([])); - $this->assertNotSame($column, $column->content(static fn () => '')); - $this->assertNotSame($column, $column->contentAttributes([])); - $this->assertNotSame($column, $column->dataLabel('')); - $this->assertNotSame($column, $column->emptyCell('')); - $this->assertNotSame($column, $column->filterAttributes([])); - $this->assertNotSame($column, $column->footer('')); - $this->assertNotSame($column, $column->footerAttributes([])); - $this->assertNotSame($column, $column->label('')); - $this->assertNotSame($column, $column->labelAttributes([])); - $this->assertNotSame($column, $column->name('')); - $this->assertNotSame($column, $column->visible(false)); - } - - public function testDataColumn(): void - { - $column = Column\DataColumn::create(); - $this->assertNotSame($column, $column->attribute('')); - $this->assertNotSame($column, $column->filter('')); - $this->assertNotSame($column, $column->filterAttribute('')); - $this->assertNotSame($column, $column->filterInputAttributes([])); - $this->assertNotSame($column, $column->filterInputSelectItems([])); - $this->assertNotSame($column, $column->filterInputSelectPrompt('')); - $this->assertNotSame($column, $column->filterModelName('')); - $this->assertNotSame($column, $column->filterType('text')); - $this->assertNotSame($column, $column->filterValueDefault(null)); - $this->assertNotSame($column, $column->linkSorter('')); - $this->assertNotSame($column, $column->value(null)); - $this->assertNotSame($column, $column->withSorting(false)); - } - - private function createColumn(): Column\AbstractColumn - { - return new class () extends Column\AbstractColumn { - }; - } -} diff --git a/tests/Column/RadioColumnTest.php b/tests/Column/RadioColumnTest.php index 75847ef75..bcc31c212 100644 --- a/tests/Column/RadioColumnTest.php +++ b/tests/Column/RadioColumnTest.php @@ -9,6 +9,8 @@ use Yiisoft\Definitions\Exception\InvalidConfigException; use Yiisoft\Definitions\Exception\NotInstantiableException; use Yiisoft\Factory\NotFoundException; +use Yiisoft\Html\Tag\Input\Radio; +use Yiisoft\Yii\DataView\Column\Base\DataContext; use Yiisoft\Yii\DataView\Column\DataColumn; use Yiisoft\Yii\DataView\Column\RadioColumn; use Yiisoft\Yii\DataView\GridView; @@ -45,13 +47,13 @@ public function testContent(): void - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -61,12 +63,14 @@ public function testContent(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - RadioColumn::create() - ->content( - static fn (array $data, mixed $key, int $index): string => '' - ), + new DataColumn('id'), + new DataColumn('name'), + new RadioColumn( + content: static fn( + Radio $input, + DataContext $context + ): string => '' + ), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -95,13 +99,13 @@ public function testContentAttributes(): void - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -111,60 +115,15 @@ public function testContentAttributes(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - RadioColumn::create() - ->content( - static fn (array $data, mixed $key, int $index): string => '' - ) - ->contentAttributes(['class' => 'test-class']), - ) - ->id('w1-grid') - ->dataReader($this->createOffsetPaginator($this->data, 10)) - ->render() - ); - } - - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ - public function testDataLabel(): void - { - Assert::equalsWithoutLE( - << - - - - - - - - - - - - - - - - - - - - -
IdName 
1John
2Mary
-
Page 1 of 1
- - HTML, - GridView::widget() - ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - RadioColumn::create()->dataLabel('test.label'), + new DataColumn('id'), + new DataColumn('name'), + new RadioColumn( + content: static fn( + Radio $input, + DataContext $context + ): string => '', + bodyAttributes: ['class' => 'test-class'] + ), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -193,14 +152,14 @@ public function testLabel(): void - 1 - John - + 1 + John + - 2 - Mary - + 2 + Mary + @@ -209,9 +168,9 @@ public function testLabel(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - RadioColumn::create()->label('test.label'), + new DataColumn('id'), + new DataColumn('name'), + new RadioColumn(header: 'test.label'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -219,12 +178,6 @@ public function testLabel(): void ); } - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ public function testLabelMbString(): void { Assert::equalsWithoutLE( @@ -240,14 +193,14 @@ public function testLabelMbString(): void - 1 - John - + 1 + John + - 2 - Mary - + 2 + Mary + @@ -256,9 +209,9 @@ public function testLabelMbString(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - RadioColumn::create()->label('Ραδιόφωνο'), + new DataColumn('id'), + new DataColumn('name'), + new RadioColumn(header: 'Ραδιόφωνο'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -266,12 +219,6 @@ public function testLabelMbString(): void ); } - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ public function testLabelAttributes(): void { Assert::equalsWithoutLE( @@ -287,14 +234,14 @@ public function testLabelAttributes(): void - 1 - John - + 1 + John + - 2 - Mary - + 2 + Mary + @@ -303,9 +250,9 @@ public function testLabelAttributes(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - RadioColumn::create()->label('test.label')->labelAttributes(['class' => 'test-class']), + new DataColumn('id'), + new DataColumn('name'), + new RadioColumn(header: 'test.label', headerAttributes: ['class' => 'test-class']), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -334,14 +281,14 @@ public function testName(): void - 1 - John - + 1 + John + - 2 - Mary - + 2 + Mary + @@ -350,9 +297,9 @@ public function testName(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - RadioColumn::create()->name('test.radio'), + new DataColumn('id'), + new DataColumn('name'), + new RadioColumn(name: 'test.radio'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -380,12 +327,12 @@ public function testNotVisible(): void - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -394,9 +341,9 @@ public function testNotVisible(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - RadioColumn::create()->visible(false), + new DataColumn('id'), + new DataColumn('name'), + new RadioColumn(visible: false), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -410,7 +357,7 @@ public function testNotVisible(): void * @throws NotInstantiableException * @throws CircularReferenceException */ - public function testRender(): void + public function testRender1(): void { Assert::equalsWithoutLE( << - 1 - John + 1 + John - 2 - Mary + 2 + Mary @@ -441,9 +388,9 @@ public function testRender(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - RadioColumn::create(), + new DataColumn('id'), + new DataColumn('name'), + new RadioColumn(), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) diff --git a/tests/GridView/BaseTest.php b/tests/GridView/BaseTest.php index 4e6df2ec5..f257a2151 100644 --- a/tests/GridView/BaseTest.php +++ b/tests/GridView/BaseTest.php @@ -9,6 +9,7 @@ use Yiisoft\Definitions\Exception\InvalidConfigException; use Yiisoft\Definitions\Exception\NotInstantiableException; use Yiisoft\Factory\NotFoundException; +use Yiisoft\Html\Html; use Yiisoft\Yii\DataView\Column\DataColumn; use Yiisoft\Yii\DataView\Column\SerialColumn; use Yiisoft\Yii\DataView\GridView; @@ -24,12 +25,6 @@ final class BaseTest extends TestCase ['id' => 2, 'name' => 'Mary', 'age' => 21], ]; - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ public function testAfterItemBeforeItem(): void { Assert::equalsWithoutLE( @@ -45,35 +40,35 @@ public function testAfterItemBeforeItem(): void -
+ - 1 - 1 - John - 20 + 1 + 1 + John + 20 -
-
+ + - 2 - 2 - Mary - 21 + 2 + 2 + Mary + 21 -
+
Page 1 of 1
HTML, GridView::widget() - ->afterRow(static fn () => '') - ->beforeRow(static fn () => '
') + ->afterRow(static fn() => Html::tr(['class' => 'after'])) + ->beforeRow(static fn() => Html::tr(['class' => 'before'])) ->columns( - SerialColumn::create(), - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('age'), + new SerialColumn(), + new DataColumn(property: 'id'), + new DataColumn(property: 'name'), + new DataColumn(property: 'age'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -81,12 +76,6 @@ public function testAfterItemBeforeItem(): void ); } - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ public function testColumnGroupEnabled(): void { Assert::equalsWithoutLE( @@ -107,14 +96,14 @@ public function testColumnGroupEnabled(): void - 1 - 1 - John + 1 + 1 + John - 2 - 2 - Mary + 2 + 2 + Mary @@ -123,9 +112,9 @@ public function testColumnGroupEnabled(): void HTML, GridView::widget() ->columns( - SerialColumn::create()->attributes(['class' => 'text-primary']), - DataColumn::create()->attribute('id')->attributes(['class' => 'bg-primary']), - DataColumn::create()->attribute('name')->attributes(['class' => 'bg-success']), + new SerialColumn(columnAttributes: ['class' => 'text-primary']), + new DataColumn(property: 'id', columnAttributes: ['class' => 'bg-primary']), + new DataColumn(property: 'name', columnAttributes: ['class' => 'bg-success']), ) ->columnsGroupEnabled(true) ->id('w1-grid') @@ -134,12 +123,6 @@ public function testColumnGroupEnabled(): void ); } - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ public function testColumnGroupEnabledEmpty(): void { Assert::equalsWithoutLE( @@ -162,16 +145,16 @@ public function testColumnGroupEnabledEmpty(): void - 1 - 1 - John - 20 + 1 + 1 + John + 20 - 2 - 2 - Mary - 21 + 2 + 2 + Mary + 21 @@ -180,10 +163,10 @@ public function testColumnGroupEnabledEmpty(): void HTML, GridView::widget() ->columns( - SerialColumn::create(), - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('age'), + new SerialColumn(), + new DataColumn(property: 'id'), + new DataColumn(property: 'name'), + new DataColumn(property: 'age'), ) ->columnsGroupEnabled(true) ->id('w1-grid') @@ -192,12 +175,6 @@ public function testColumnGroupEnabledEmpty(): void ); } - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ public function testColumnGuess(): void { Assert::equalsWithoutLE( @@ -214,20 +191,20 @@ public function testColumnGuess(): void - 1 - John - 20 - + 1 + John + 20 + 🔎 - 2 - Mary - 21 - + 2 + Mary + 21 + 🔎 @@ -245,12 +222,6 @@ public function testColumnGuess(): void ); } - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ public function testEmptyCell(): void { Assert::equalsWithoutLE( @@ -264,7 +235,7 @@ public function testEmptyCell(): void - Empty cell + Empty cell @@ -272,7 +243,7 @@ public function testEmptyCell(): void
HTML, GridView::widget() - ->columns(DataColumn::create()->attribute('id')) + ->columns(new DataColumn('id')) ->emptyCell('Empty cell') ->id('w1-grid') ->dataReader($this->createOffsetPaginator([['id' => '']], 10)) @@ -280,12 +251,6 @@ public function testEmptyCell(): void ); } - /** - * @throws InvalidConfigException - * @throws NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ public function testEmptyText(): void { Assert::equalsWithoutLE( @@ -310,10 +275,10 @@ public function testEmptyText(): void HTML, GridView::widget() ->columns( - SerialColumn::create(), - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('age'), + new SerialColumn(), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('age'), ) ->emptyText('Not found.') ->id('w1-grid') @@ -343,19 +308,21 @@ public function testFooterRowAttributes(): void - Total:22 + Total: + 2 + 2 - 1 - 1 - John + 1 + 1 + John - 2 - 2 - Mary + 2 + 2 + Mary @@ -364,9 +331,9 @@ public function testFooterRowAttributes(): void HTML, GridView::widget() ->columns( - SerialColumn::create()->footer('Total:'), - DataColumn::create()->attribute('id')->footer('2'), - DataColumn::create()->attribute('name')->footer('2'), + new SerialColumn(footer: 'Total:'), + new DataColumn('id', footer: '2'), + new DataColumn('name', footer: '2'), ) ->footerEnabled(true) ->footerRowAttributes(['class' => 'text-primary']) @@ -399,16 +366,16 @@ public function testHeader(): void - 1 - 1 - John - 20 + 1 + 1 + John + 20 - 2 - 2 - Mary - 21 + 2 + 2 + Mary + 21 @@ -417,10 +384,10 @@ public function testHeader(): void HTML, GridView::widget() ->columns( - SerialColumn::create(), - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('age'), + new SerialColumn(), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('age'), ) ->header('List of users') ->id('w1-grid') @@ -452,16 +419,16 @@ public function testHeaderIntoGrid(): void - 1 - 1 - John - 20 + 1 + 1 + John + 20 - 2 - 2 - Mary - 21 + 2 + 2 + Mary + 21 @@ -470,10 +437,10 @@ public function testHeaderIntoGrid(): void HTML, GridView::widget() ->columns( - SerialColumn::create(), - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('age'), + new SerialColumn(), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('age'), ) ->header('List of users') ->id('w1-grid') @@ -506,16 +473,16 @@ public function testHeaderRowAttributes(): void - 1 - 1 - John - 20 + 1 + 1 + John + 20 - 2 - 2 - Mary - 21 + 2 + 2 + Mary + 21 @@ -524,10 +491,10 @@ public function testHeaderRowAttributes(): void HTML, GridView::widget() ->columns( - SerialColumn::create(), - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('age'), + new SerialColumn(), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('age'), ) ->headerRowAttributes(['class' => 'text-primary']) ->id('w1-grid') @@ -550,16 +517,16 @@ public function testHeaderTableEnabledFalse(): void - - - - + + + + - - - - + + + +
11John2011John20
22Mary2122Mary21
@@ -568,10 +535,10 @@ public function testHeaderTableEnabledFalse(): void HTML, GridView::widget() ->columns( - SerialColumn::create(), - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('age'), + new SerialColumn(), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('age'), ) ->headerTableEnabled(false) ->id('w1-grid') @@ -610,10 +577,10 @@ public function testRenderEmptyData(): void HTML, GridView::widget() ->columns( - SerialColumn::create(), - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('age'), + new SerialColumn(), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('age'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator([], 10)) @@ -643,16 +610,16 @@ public function testRowAttributes(): void - 1 - 1 - John - 20 + 1 + 1 + John + 20 - 2 - 2 - Mary - 21 + 2 + 2 + Mary + 21 @@ -661,10 +628,10 @@ public function testRowAttributes(): void HTML, GridView::widget() ->columns( - SerialColumn::create(), - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('age'), + new SerialColumn(), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('age'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -686,16 +653,16 @@ public function testRowAttributes(): void - 1 - 1 - John - 20 + 1 + 1 + John + 20 - 2 - 2 - Mary - 21 + 2 + 2 + Mary + 21 @@ -704,10 +671,10 @@ public function testRowAttributes(): void HTML, GridView::widget() ->columns( - SerialColumn::create(), - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('age'), + new SerialColumn(), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('age'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -738,16 +705,16 @@ public function testTableAttributes(): void - 1 - 1 - John - 20 + 1 + 1 + John + 20 - 2 - 2 - Mary - 21 + 2 + 2 + Mary + 21 @@ -756,10 +723,10 @@ public function testTableAttributes(): void HTML, GridView::widget() ->columns( - SerialColumn::create(), - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('age'), + new SerialColumn(), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('age'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) diff --git a/tests/GridView/ImmutableTest.php b/tests/GridView/ImmutableTest.php index d321e7749..e63543d7a 100644 --- a/tests/GridView/ImmutableTest.php +++ b/tests/GridView/ImmutableTest.php @@ -55,7 +55,7 @@ public function testGridView(): void $gridView = DataView\GridView::widget(); $this->assertNotSame($gridView, $gridView->afterRow(null)); $this->assertNotSame($gridView, $gridView->beforeRow(null)); - $this->assertNotSame($gridView, $gridView->columns(DataColumn::create())); + $this->assertNotSame($gridView, $gridView->columns(new DataColumn())); $this->assertNotSame($gridView, $gridView->columnsGroupEnabled(false)); $this->assertNotSame($gridView, $gridView->emptyCell('')); $this->assertNotSame($gridView, $gridView->filterModelName('')); diff --git a/tests/GridView/TranslatorTest.php b/tests/GridView/TranslatorTest.php index 20d42494a..94f1f6c16 100644 --- a/tests/GridView/TranslatorTest.php +++ b/tests/GridView/TranslatorTest.php @@ -47,12 +47,6 @@ protected function setUp(): void WidgetFactory::initialize($container, []); } - /** - * @throws InvalidConfigException - * @throws \Yiisoft\Factory\NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ public function testEmptyTextTranslatorWithLocaleDefault(): void { Assert::equalsWithoutLE( @@ -77,10 +71,10 @@ public function testEmptyTextTranslatorWithLocaleDefault(): void HTML, GridView::widget() ->columns( - SerialColumn::create(), - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('age'), + new SerialColumn(), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('age'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator([], 10)) @@ -88,12 +82,6 @@ public function testEmptyTextTranslatorWithLocaleDefault(): void ); } - /** - * @throws InvalidConfigException - * @throws \Yiisoft\Factory\NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ public function testEmptyTextTranslatorWithLocaleSpanish(): void { $this->translator->setLocale('es'); @@ -120,10 +108,10 @@ public function testEmptyTextTranslatorWithLocaleSpanish(): void HTML, GridView::widget() ->columns( - SerialColumn::create(), - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('age'), + new SerialColumn(), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('age'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator([], 10)) @@ -131,12 +119,6 @@ public function testEmptyTextTranslatorWithLocaleSpanish(): void ); } - /** - * @throws InvalidConfigException - * @throws \Yiisoft\Factory\NotFoundException - * @throws NotInstantiableException - * @throws CircularReferenceException - */ public function testEmptyTextTranslatorWithLocaleRussian(): void { $this->translator->setLocale('ru'); @@ -163,10 +145,10 @@ public function testEmptyTextTranslatorWithLocaleRussian(): void HTML, GridView::widget() ->columns( - SerialColumn::create(), - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('age'), + new SerialColumn(), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('age'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator([], 10)) @@ -196,16 +178,16 @@ public function testSummaryTranslatorWithLocaleDefault(): void - 1 - 1 - John - 20 + 1 + 1 + John + 20 - 2 - 2 - Mary - 21 + 2 + 2 + Mary + 21 @@ -214,10 +196,10 @@ public function testSummaryTranslatorWithLocaleDefault(): void HTML, GridView::widget() ->columns( - SerialColumn::create(), - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('age'), + new SerialColumn(), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('age'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -249,16 +231,16 @@ public function testSummaryTranslatorWithLocaleSpanish(): void - 1 - 1 - John - 20 + 1 + 1 + John + 20 - 2 - 2 - Mary - 21 + 2 + 2 + Mary + 21 @@ -267,10 +249,10 @@ public function testSummaryTranslatorWithLocaleSpanish(): void HTML, GridView::widget() ->columns( - SerialColumn::create(), - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('age'), + new SerialColumn(), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('age'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) @@ -302,16 +284,16 @@ public function testSummaryTranslatorWithLocaleRussian(): void - 1 - 1 - John - 20 + 1 + 1 + John + 20 - 2 - 2 - Mary - 21 + 2 + 2 + Mary + 21 @@ -320,10 +302,10 @@ public function testSummaryTranslatorWithLocaleRussian(): void HTML, GridView::widget() ->columns( - SerialColumn::create(), - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('age'), + new SerialColumn(), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('age'), ) ->id('w1-grid') ->dataReader($this->createOffsetPaginator($this->data, 10)) diff --git a/tests/Pagination/KeysetPaginationBaseTest.php b/tests/Pagination/KeysetPaginationBaseTest.php index a5275a8c6..35bc856cd 100644 --- a/tests/Pagination/KeysetPaginationBaseTest.php +++ b/tests/Pagination/KeysetPaginationBaseTest.php @@ -90,29 +90,29 @@ public function testRenderPaginationLinks(): void - 1 - name1 - description1 + 1 + name1 + description1 - 2 - name2 - description2 + 2 + name2 + description2 - 3 - name3 - description3 + 3 + name3 + description3 - 4 - name4 - description4 + 4 + name4 + description4 - 5 - name5 - description5 + 5 + name5 + description5 @@ -126,9 +126,9 @@ public function testRenderPaginationLinks(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('description'), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('description'), ) ->id('w1-grid') ->dataReader($keysetPaginator) @@ -152,29 +152,29 @@ public function testRenderPaginationLinks(): void - 6 - name6 - description6 + 6 + name6 + description6 - 7 - name7 - description7 + 7 + name7 + description7 - 8 - name8 - description8 + 8 + name8 + description8 - 9 - name9 - description9 + 9 + name9 + description9 - 10 - name10 - description10 + 10 + name10 + description10 @@ -188,9 +188,9 @@ public function testRenderPaginationLinks(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('description'), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('description'), ) ->id('w1-grid') ->dataReader($keysetPaginator) @@ -214,14 +214,14 @@ public function testRenderPaginationLinks(): void - 11 - name11 - description11 + 11 + name11 + description11 - 12 - name12 - description12 + 12 + name12 + description12 @@ -235,9 +235,9 @@ public function testRenderPaginationLinks(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('description'), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('description'), ) ->id('w1-grid') ->dataReader($keysetPaginator) @@ -261,29 +261,29 @@ public function testRenderPaginationLinks(): void - 6 - name6 - description6 + 6 + name6 + description6 - 7 - name7 - description7 + 7 + name7 + description7 - 8 - name8 - description8 + 8 + name8 + description8 - 9 - name9 - description9 + 9 + name9 + description9 - 10 - name10 - description10 + 10 + name10 + description10 @@ -297,9 +297,9 @@ public function testRenderPaginationLinks(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('description'), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('description'), ) ->id('w1-grid') ->dataReader($keysetPaginator) @@ -323,29 +323,29 @@ public function testRenderPaginationLinks(): void - 1 - name1 - description1 + 1 + name1 + description1 - 2 - name2 - description2 + 2 + name2 + description2 - 3 - name3 - description3 + 3 + name3 + description3 - 4 - name4 - description4 + 4 + name4 + description4 - 5 - name5 - description5 + 5 + name5 + description5 @@ -359,9 +359,9 @@ public function testRenderPaginationLinks(): void HTML, GridView::widget() ->columns( - DataColumn::create()->attribute('id'), - DataColumn::create()->attribute('name'), - DataColumn::create()->attribute('description'), + new DataColumn('id'), + new DataColumn('name'), + new DataColumn('description'), ) ->id('w1-grid') ->dataReader($keysetPaginator)