Skip to content

Replace GlobalContext by HeaderContext #269

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/Column/ActionColumnRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
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\Base\HeaderContext;

use function is_bool;
use function is_callable;
Expand Down Expand Up @@ -73,7 +72,7 @@ public function renderColumn(ColumnInterface $column, Cell $cell, GlobalContext
return $cell->addAttributes($column->columnAttributes);
}

public function renderHeader(ColumnInterface $column, Cell $cell, HeaderContext $context): Cell
public function renderHeader(ColumnInterface $column, Cell $cell, GlobalContext $context): Cell
{
return $cell
->content($column->header ?? $context->translate('Actions'))
Expand Down
215 changes: 201 additions & 14 deletions src/Column/Base/GlobalContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,79 @@
namespace Yiisoft\Yii\DataView\Column\Base;

use Stringable;
use Yiisoft\Data\Reader\ReadableDataInterface;
use Yiisoft\Arrays\ArrayHelper;
use Yiisoft\Data\Paginator\PageToken;
use Yiisoft\Data\Reader\Sort;
use Yiisoft\Html\Html;
use Yiisoft\Html\Tag\A;
use Yiisoft\Translator\TranslatorInterface;
use Yiisoft\Yii\DataView\BaseListView;
use Yiisoft\Data\Reader\OrderHelper;
use Yiisoft\Yii\DataView\UrlConfig;
use Yiisoft\Yii\DataView\UrlParametersFactory;

use function call_user_func_array;
use function count;

/**
* `GlobalContext` provides shared context for all columns in a grid.
* `GlobalContext` provides context for rendering and handling grid column headers, footers and container cells.
*
* @psalm-import-type UrlCreator from BaseListView
*/
final class GlobalContext
{
/**
* Creates a new global context instance.
*
* @param ReadableDataInterface $dataReader Data reader for accessing grid data.
* @param array $pathArguments URL path arguments for link generation.
* @psalm-param array<string,scalar|Stringable|null> $pathArguments
* @param array $queryParameters URL query parameters for link generation.
* @param TranslatorInterface $translator Translator service for internationalizing grid content.
* @param string $translationCategory Category used for translations within the grid.
* Creates a new context instance.
*
* @param Sort|null $originalSort Original sort configuration before any modifications.
* @param Sort|null $sort Current sort configuration that reflects the active sort state.
* @param array $orderProperties Map of field names to their sort properties.
* @param string|null $sortableHeaderClass CSS class for sortable headers.
* @param string|Stringable $sortableHeaderPrepend Content to prepend to sortable headers.
* @param string|Stringable $sortableHeaderAppend Content to append to sortable headers.
* @param string|null $sortableHeaderAscClass CSS class for ascending sort headers.
* @param string|Stringable $sortableHeaderAscPrepend Content to prepend to ascending sort headers.
* @param string|Stringable $sortableHeaderAscAppend Content to append to ascending sort headers.
* @param string|null $sortableHeaderDescClass CSS class for descending sort headers.
* @param string|Stringable $sortableHeaderDescPrepend Content to prepend to descending sort headers.
* @param string|Stringable $sortableHeaderDescAppend Content to append to descending sort headers.
* @param array $sortableLinkAttributes HTML attributes for sort links.
* @param string|null $sortableLinkAscClass CSS class for ascending sort links.
* @param string|null $sortableLinkDescClass CSS class for descending sort links.
* @param PageToken|null $pageToken Current page token for pagination.
* @param int|null $pageSize Number of items per page.
* @param bool $multiSort Whether multiple column sorting is enabled.
* @param UrlConfig $urlConfig URL configuration settings.
* @param UrlCreator|null $urlCreator Callback for creating sort URLs.
* @param TranslatorInterface $translator Translator service for header content.
* @param string $translationCategory Category for header translations.
*
* @internal
*
* @psalm-param array<string, string> $orderProperties
* @psalm-param UrlCreator|null $urlCreator
*/
public function __construct(
public readonly ReadableDataInterface $dataReader,
public readonly array $pathArguments,
public readonly array $queryParameters,
private readonly ?Sort $originalSort,
private readonly ?Sort $sort,
private readonly array $orderProperties,
private readonly ?string $sortableHeaderClass,
private readonly string|Stringable $sortableHeaderPrepend,
private readonly string|Stringable $sortableHeaderAppend,
private readonly ?string $sortableHeaderAscClass,
private readonly string|Stringable $sortableHeaderAscPrepend,
private readonly string|Stringable $sortableHeaderAscAppend,
private readonly ?string $sortableHeaderDescClass,
private readonly string|Stringable $sortableHeaderDescPrepend,
private readonly string|Stringable $sortableHeaderDescAppend,
public readonly array $sortableLinkAttributes,
public readonly ?string $sortableLinkAscClass,
public readonly ?string $sortableLinkDescClass,
private readonly ?PageToken $pageToken,
private readonly int|null $pageSize,
private readonly bool $multiSort,
private readonly UrlConfig $urlConfig,
private $urlCreator,
private readonly TranslatorInterface $translator,
private readonly string $translationCategory,
) {
Expand All @@ -37,10 +88,146 @@
*
* @param string|Stringable $id Message ID to translate.
*
* @return string Translated message in the current language.
* @return string Translated message.
*/
public function translate(string|Stringable $id): string
{
return $this->translator->translate($id, category: $this->translationCategory);
}

/**
* Prepare a sortable header cell with appropriate styling and links.
*
* @param Cell $cell The header cell to prepare.
* @param string $property The property name for sorting.
*
* @psalm-return list{Cell,?A,string,string}
*
* @return array Array containing:
* - Modified cell
* - Sort link (or null)
* - Content to prepend
* - Content to append
*/
public function prepareSortable(Cell $cell, string $property): array
{
$originalProperty = $property;
$property = $this->orderProperties[$property] ?? '';
if (
$property === ''
|| $this->sort === null
|| $this->originalSort === null
|| !$this->sort->hasFieldInConfig($property)
) {
return [$cell, null, '', ''];
}

$linkAttributes = [];
$propertyOrder = $this->sort->getOrder()[$property] ?? null;
if ($propertyOrder === null) {
$cell = $cell->addClass($this->sortableHeaderClass);
$prepend = $this->sortableHeaderPrepend;
$append = $this->sortableHeaderAppend;
} else {
$cell = $cell->addClass(
$propertyOrder === 'asc' ? $this->sortableHeaderAscClass : $this->sortableHeaderDescClass
);
$prepend = $propertyOrder === 'asc' ? $this->sortableHeaderAscPrepend : $this->sortableHeaderDescPrepend;
$append = $propertyOrder === 'asc' ? $this->sortableHeaderAscAppend : $this->sortableHeaderDescAppend;
Html::addCssClass(
$linkAttributes,
$propertyOrder === 'asc' ? $this->sortableLinkAscClass : $this->sortableLinkDescClass,
);
}
$url = $this->urlCreator === null ? '#' : call_user_func_array(
$this->urlCreator,
UrlParametersFactory::create(
$this->pageToken,
$this->pageSize,
$this->getLinkSortValue($this->originalSort, $this->sort, $property, $originalProperty),
$this->urlConfig,
)
);

return [
$cell,
A::tag()->attributes($linkAttributes)->url($url),
(string) $prepend,
(string) $append,
];
}

/**
* Get the sort value for a link based on the current sort state.
*
* @param Sort $originalSort Original sort configuration.
* @param Sort $sort Current sort configuration.
* @param string $property Property name for sorting.
* @param string $originalProperty Original property name before an override.
*
* @return string|null Sort value for the link or `null` if unchanged.
*/
private function getLinkSortValue(
Sort $originalSort,
Sort $sort,
string $property,
string $originalProperty
): ?string {
$originalOrder = $originalSort->getOrder();
$order = $sort->getOrder();

if (isset($order[$property])) {
if ($this->multiSort) {
if ($order[$property] === 'asc') {
$order[$property] = 'desc';
} elseif (!empty($originalOrder) && count($order) === 1) {
$order[$property] = 'asc';

Check warning on line 184 in src/Column/Base/GlobalContext.php

View check run for this annotation

Codecov / codecov/patch

src/Column/Base/GlobalContext.php#L181-L184

Added lines #L181 - L184 were not covered by tests
} else {
unset($order[$property]);

Check warning on line 186 in src/Column/Base/GlobalContext.php

View check run for this annotation

Codecov / codecov/patch

src/Column/Base/GlobalContext.php#L186

Added line #L186 was not covered by tests
}
} elseif (isset($originalOrder[$property])) {
if ($order[$property] === $originalOrder[$property]) {
$order = [$property => $originalOrder[$property] === 'asc' ? 'desc' : 'asc'];
} else {
unset($order[$property]);
}
} elseif ($order[$property] === 'asc') {
$order = [$property => 'desc'];

Check warning on line 195 in src/Column/Base/GlobalContext.php

View check run for this annotation

Codecov / codecov/patch

src/Column/Base/GlobalContext.php#L194-L195

Added lines #L194 - L195 were not covered by tests
} else {
unset($order[$property]);
}
} elseif ($this->multiSort) {
$order[$property] = 'asc';

Check warning on line 200 in src/Column/Base/GlobalContext.php

View check run for this annotation

Codecov / codecov/patch

src/Column/Base/GlobalContext.php#L200

Added line #L200 was not covered by tests
} else {
$order = [$property => 'asc'];
}

if ($this->isEqualOrders($order, $originalOrder)) {
return null;

Check warning on line 206 in src/Column/Base/GlobalContext.php

View check run for this annotation

Codecov / codecov/patch

src/Column/Base/GlobalContext.php#L206

Added line #L206 was not covered by tests
}

$resultOrder = $sort->withOrder($order)->getOrder();
if (empty($resultOrder)) {
return null;

Check warning on line 211 in src/Column/Base/GlobalContext.php

View check run for this annotation

Codecov / codecov/patch

src/Column/Base/GlobalContext.php#L211

Added line #L211 was not covered by tests
}

return OrderHelper::arrayToString(
ArrayHelper::renameKey($resultOrder, $property, $originalProperty)
);
}

/**
* Compare two sort orders for equality.
*
* @param array $a First sort order.
* @param array $b Second sort order.
*
* @return bool Whether the sort orders are equal.
*/
private function isEqualOrders(array $a, array $b): bool
{
ksort($a);
ksort($b);
return $a === $b;
}
}
Loading
Loading