Skip to content
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

add method getSortParam(). #16

Merged
merged 5 commits into from
May 16, 2023
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
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"require-dev": {
"maglnet/composer-require-checker": "^4.3",
"phpunit/phpunit": "^10.0",
"roave/infection-static-analysis-plugin": "^1.29",
"roave/infection-static-analysis-plugin": "^1.31",
"vimeo/psalm": "^5.8",
"yiisoft/cache": "^3.0",
"yiisoft/db-sqlite": "^1.0"
Expand Down
5 changes: 4 additions & 1 deletion src/AbstractIteratorDataDataProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@

use function ceil;

/**
* The basic implementation of the {@see teratorDataProviderInterface} and can be used as a base class for data
* providers that retrieve data from an array or an iterator object.
*/
abstract class AbstractIteratorDataDataProvider implements IteratorDataProviderInterface
{
protected int $limit = self::DEFAULT_LIMIT;
Expand Down Expand Up @@ -39,7 +43,6 @@ public function getTotalPages(): int

public function withLimit(int $value): static
{
// validate limit
if ($value < 0) {
$value = self::DEFAULT_LIMIT;
}
Expand Down
2 changes: 1 addition & 1 deletion src/ActiveIteratorDataProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Yiisoft\ActiveRecord\ActiveQueryInterface;

/**
* Provides a way to iterate over the results of an Active Query with support for pagination.
* Provides a way to iterate over the results of an active query with support for pagination.
*/
final class ActiveIteratorDataProvider extends AbstractIteratorDataDataProvider
{
Expand Down
3 changes: 3 additions & 0 deletions src/QueryIteratorDataProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

use Yiisoft\Db\Query\QueryInterface;

/**
* Provides a way to iterate over the results of {@see \Yiisoft\Db\Query\QueryInterface} in terms of data items.
*/
final class QueryIteratorDataProvider extends AbstractIteratorDataDataProvider
{
public function __construct(private QueryInterface $query)
Expand Down
94 changes: 63 additions & 31 deletions src/Sort.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
use function substr;

/**
* Sort represents information relevant to sorting.
* Represents information relevant to sorting.
*
* When data needs to be sorted according to one or several columns, we can use Sort to represent the sorting
* information and generate appropriate hyperlinks that can lead to sort actions.
Expand All @@ -32,7 +32,7 @@
* 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC],
* ],
* ],
* )->params(['sort' => 'age,-name'])->multisort();
* )->params(['sort' => 'age,-name'])->multiSort();
* ```
*
* In the above, we declare two {@see columns} that support sorting: `name` and `age`.
Expand All @@ -46,7 +46,7 @@ final class Sort
private array $params = [];
/** @psalm-var non-empty-string */
private string $separator = ',';
private string $sortParam = 'sort';
private string $sortParamName = 'sort';

/**
* @param array $values List of columns that are allowed to be sorted.
Expand All @@ -59,8 +59,6 @@ final class Sort
* 'name' => [
* 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC],
* 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC],
* 'default' => SORT_DESC,
* 'label' => 'Name',
* ],
* ]
* ```
Expand All @@ -74,8 +72,6 @@ final class Sort
* 'asc' => ['age' => SORT_ASC],
* 'desc' => ['age' => SORT_DESC],
* ],
* 'default' => SORT_ASC,
* 'label' => 'age',
* ]
* ```
*
Expand All @@ -92,12 +88,6 @@ final class Sort
* - The `asc` and `desc` elements specify how to sort by the column in ascending and descending orders,
* respectively. Their values represent the actual columns and the directions by which the data should be sorted
* by.
* - The `default` element specifies by which direction the column should be sorted if it is not currently sorted
* (the default value is ascending order).
* - The `label` element specifies what label should be used to create a sort link.
*
* Note that if the Sort object is already created, you can only use the full format to configure every column.
* Each column must include these elements: `asc` and `desc`.
*/
public function columns(array $values = []): self
{
Expand Down Expand Up @@ -170,8 +160,6 @@ public function defaultColumnOrder(array $values): self
}

/**
* Returns the sort direction of the specified column in the current request.
*
* @param string $vale The column name.
*
* @return int|null Sort direction of the column.
Expand All @@ -187,8 +175,6 @@ public function getColumnOrder(string $value): int|null
}

/**
* Returns the currently requested sort information.
*
* @param bool $value Whether to recalculate the sort directions.
*
* @return array Sort directions indexed by column names.
Expand All @@ -200,13 +186,13 @@ public function getColumnOrders(bool $value = false): array
return $this->columnOrders;
}

if (isset($this->params[$this->sortParam])) {
if (isset($this->params[$this->sortParamName])) {
$this->columnOrders = [];

$sortParam = $this->parseSortParam((string) $this->params[$this->sortParam]);
$sortParamName = $this->parseSortParam((string) $this->params[$this->sortParamName]);

/** @var array<array-key,string> $sortParam */
foreach ($sortParam as $column) {
/** @var array<array-key,string> $sortParamName */
foreach ($sortParamName as $column) {
$descending = strncmp($column, '-', 1) === 0;
$column = $descending ? substr($column, 1) : $column;

Expand All @@ -226,8 +212,6 @@ public function getColumnOrders(bool $value = false): array
}

/**
* Returns the columns and their corresponding sort directions.
*
* @param bool $value whether to recalculate the sort directions. Defaults to `false`.
*
* @return array The columns (`keys`) and their corresponding sort directions (`values`).
Expand Down Expand Up @@ -257,7 +241,14 @@ public function getOrders(): array
return $columns;
}

public function getSortParams(string $column): array
/**
* @param string $column The name of the column.
*
* @throws InvalidArgumentException if the specified column is unknown.
*
* @return array The sort parameter value for the specified column.
*/
public function getSortParam(string $column): array
{
if ($this->hasColumn($column) === false) {
throw new InvalidArgumentException("Unknown attribute: $column");
Expand All @@ -280,7 +271,48 @@ public function getSortParams(string $column): array
$sorts[] = $direction === SORT_DESC ? '-' . $attribute : $attribute;
}

return [$this->sortParam => implode($this->separator, $sorts)];
return [$this->sortParamName => implode($this->separator, $sorts)];
}

/**
* Returns an array of sort parameter values for all columns.
*
* @return array An array of sort parameter values for all columns.
*/
public function getSortParams(): array
{
$sortParams = [];
$columnOrders = $this->getColumnOrders(true);

/** @psalm-var array<string,int> $columnOrders */
foreach ($columnOrders as $column => $direction) {
$directions = $columnOrders;
$direction = $direction === SORT_DESC ? SORT_ASC : SORT_DESC;
unset($directions[$column]);

$directions = match ($this->multiSort) {
true => array_merge([$column => $direction], $directions),
default => [$column => $direction],
};

$sorts = [];

foreach ($directions as $attribute => $direction) {
$sorts[] = $direction === SORT_DESC ? '-' . $attribute : $attribute;
}

$sortParams[$column][$this->sortParamName] = implode($this->separator, $sorts);
}

return $sortParams;
}

/**
* @return string The parameter name for specifying sort information in a URL.
*/
public function getSortParamName(): string
{
return $this->sortParamName;
}

/**
Expand All @@ -301,10 +333,10 @@ public function multiSort(bool $value = true): self
*
* In order to add hash to all links use `\array_merge($_GET, ['#' => 'my-hash'])`.
*
* The array element indexed by {@see sortParam} is considered to be the current sort directions.
* The array element indexed by {@see sortParamName} is considered to be the current sort directions.
* If the element does not exist, the {@see defaultColumnOrder} will be used.
*
* @see sortParam
* @see sortParamName
* @see defaultColumnOrder
*/
public function params(array $value): self
Expand All @@ -330,9 +362,9 @@ public function separator(string $value): self
*
* @see params
*/
public function sortParam(string $value): self
public function sortParamName(string $value): self
{
$this->sortParam = $value;
$this->sortParamName = $value;

return $this;
}
Expand All @@ -350,7 +382,7 @@ private function hasColumn(string $value): bool
}

/**
* Parses the value of {@see sortParam} into an array of sort column.
* Parses the value of {@see sortParamName} into an array of sort column.
*
* The format must be the column name only for ascending or the column name prefixed with `-` for descending.
*
Expand All @@ -364,7 +396,7 @@ private function hasColumn(string $value): bool
* ]
* ```
*
* @param string $param the value of the {@see sortParam}.
* @param string $param the value of the {@see sortParamName}.
*
* @return array The valid sort attributes.
*/
Expand Down
69 changes: 51 additions & 18 deletions tests/DataProvider/SortTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public function testGetOrders(): void
$this->assertSame(SORT_DESC, $orders['age']);
}

public function testGetSortParams(): void
public function testGetSortParam(): void
{
$this->sort
->columns(
Expand All @@ -180,22 +180,22 @@ public function testGetSortParams(): void
->multiSort()
->params(['sort' => 'age,-name']);

$this->assertSame(['sort' => '-age,-name'], $this->sort->getSortParams('age'));
$this->assertSame(['sort' => 'name,age'], $this->sort->getSortParams('name'));
$this->assertSame(['sort' => '-age,-name'], $this->sort->getSortParam('age'));
$this->assertSame(['sort' => 'name,age'], $this->sort->getSortParam('name'));

$this->sort->multiSort(false);

$this->assertSame(['sort' => '-age'], $this->sort->getSortParams('age'));
$this->assertSame(['sort' => '-age'], $this->sort->getSortParam('age'));

$this->sort
->defaultColumnOrder(['age' => SORT_DESC, 'name' => SORT_ASC])
->multiSort()
->params(['sort' => 'age,name']);

$this->assertSame(['sort' => '-age,name'], $this->sort->getSortParams('age'));
$this->assertSame(['sort' => '-age,name'], $this->sort->getSortParam('age'));
}

public function testGetSortParamsWithException(): void
public function testGetSortParamWithException(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Unknown attribute: unexistingAttribute');
Expand All @@ -206,7 +206,48 @@ public function testGetSortParamsWithException(): void
]
)->params(['sort' => 'age,-name'])->multiSort();

$this->sort->getSortParams('unexistingAttribute');
$this->sort->getSortParam('unexistingAttribute');
}

public function testGetSortParams(): void
{
$this->sort
->columns(
[
'age',
'name' => [
'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC],
'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC],
],
],
)
->multiSort()
->params(['sort' => 'age,-name']);

$this->assertSame(
[
'age' => ['sort' => '-age,-name'],
'name' => ['sort' => 'name,age'],
],
$this->sort->getSortParams(),
);

$this->sort->multiSort(false);

$this->assertSame(['age' => ['sort' => '-age']], $this->sort->getSortParams());

$this->sort
->defaultColumnOrder(['age' => SORT_DESC, 'name' => SORT_ASC])
->multiSort()
->params(['sort' => 'age,name']);

$this->assertSame(
[
'age' => ['sort' => '-age,name'],
'name' => ['sort' => '-name,age'],
],
$this->sort->getSortParams(),
);
}

public function testSeparator(): void
Expand All @@ -229,18 +270,10 @@ public function testSeparator(): void
$this->assertSame(['age' => SORT_ASC, 'name' => SORT_ASC], $this->sort->getColumnOrders(true));
}

public function testSortParam(): void
public function testSortParamNamme(): void
{
$this->sort->columns(
[
'age',
'name' => [
'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC],
'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC],
],
]
)->params(['order' => 'age,-name'])->sortParam('order')->multiSort(true);
$this->sort->sortParamName('order');

$this->assertSame(['age' => SORT_ASC, 'name' => SORT_DESC], $this->sort->getColumnOrders());
$this->assertSame('order', $this->sort->getSortParamName());
}
}