Skip to content

Commit

Permalink
Merge branch '5.2' into 6.0
Browse files Browse the repository at this point in the history
  • Loading branch information
lcharette committed Oct 12, 2024
2 parents 2cde2c3 + d43817e commit e62f217
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 26 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- [Bakery] The default sub commands in `AssetsBuildCommand` are now in `AssetsBuildCommandListener`
- [Bakery] Added the server option to `assets:webpack` to run HMR server (`npm run webpack:server`) plus use new npm command syntax.
- [Bakery] `AbstractAggregateCommandEvent` construction is now optional. Added `addCommands` and `prependCommands`. All setters methods return `$this`.
- [Sprunje] The sprunje toArray now returns the `sortable` and `filterable` keys. These will can be used by the frontend to dynamically display which columns is filterable/sortable.

## [5.1.2](https://github.com/userfrosting/sprinkle-core/compare/5.1.1...5.1.2)
- Replace `LocaleMiddleware` with `ServerRequestMiddleware`. A new class, `RequestContainer`, can be injected or retrieved from the container to get the server request. It will be `null` if the request is not defined (called before it is injected into the container by Middleware or if there's no request, e.g., a Bakery command).
Expand Down
86 changes: 60 additions & 26 deletions app/src/Sprunje/Sprunje.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,16 @@ abstract class Sprunje
*/
protected $listableKey = 'listable';

/**
* @var string Array key for the list of sortable columns.
*/
protected $sortableKey = 'sortable';

/**
* @var string Array key for the list of filterable columns.
*/
protected $filterableKey = 'filterable';

/**
* @var int CSV export split the request into multiple chunk to avoid memory overflow.
* Lower this value if you encounter memory issues when exporting large data sets.
Expand Down Expand Up @@ -208,6 +218,7 @@ public function toResponse(ResponseInterface $response): ResponseInterface
{
$format = $this->options['format'];

// TODO : This should be split into two methods, one for JSON and one for CSV. This would allow to add more format later.
if ($format == 'csv') {
// Prepare response
$response = $response->withHeader('Content-Disposition', "attachment;filename={$this->name}.csv");
Expand Down Expand Up @@ -242,6 +253,8 @@ public function getArray(): array
$this->countFilteredKey => $countFiltered,
$this->rowsKey => $rows->values()->toArray(),
$this->listableKey => $this->getListable(),
$this->sortableKey => $this->getSortable(),
$this->filterableKey => $this->getFilterable(),
];
}

Expand Down Expand Up @@ -347,29 +360,6 @@ public function getModels(): array
return [$count, $countFiltered, $collection];
}

/**
* Get lists of values for specified fields in 'listable' option, calling a custom lister callback when appropriate.
*
* @return array<string,mixed>
*/
public function getListable(): array
{
$result = [];
foreach ($this->listable as $name) {
// Determine if a custom filter method has been defined
$methodName = 'list' . Str::studly($name);

if (method_exists($this, $methodName)) {
// @phpstan-ignore-next-line Allow variable method call, since we know it exists
$result[$name] = $this->$methodName();
} else {
$result[$name] = $this->getColumnValues($name);
}
}

return $result;
}

/**
* Get the underlying queryable object in its current state.
*
Expand Down Expand Up @@ -405,7 +395,7 @@ public function applyFilters(EloquentBuilderContract|QueryBuilderContract $query
{
foreach ($this->options['filters'] as $name => $value) {
// Check that this filter is allowed
if (($name != '_all') && !in_array($name, $this->filterable, true)) {
if (($name != '_all') && !in_array($name, $this->getFilterable(), true)) {
$e = new SprunjeException("Bad filter: $name");
$message = new UserMessage('VALIDATE.SPRUNJE.BAD_FILTER', ['name' => $name]);
$e->setDescription($message);
Expand All @@ -432,7 +422,7 @@ public function applySorts(EloquentBuilderContract|QueryBuilderContract $query):
{
foreach ($this->options['sorts'] as $name => $direction) {
// Check that this sort is allowed
if (!in_array($name, $this->sortable, true)) {
if (!in_array($name, $this->getSortable(), true)) {
$e = new SprunjeException("Bad sort: $name");
$message = new UserMessage('VALIDATE.SPRUNJE.BAD_SORT', ['name' => $name]);
$e->setDescription($message);
Expand Down Expand Up @@ -488,6 +478,16 @@ public function setFilterable(array $filterable): static
return $this;
}

/**
* Returns fields to allow filtering upon.
*
* @return string[]
*/
public function getFilterable(): array
{
return $this->filterable;
}

/**
* Set fields to allow listing (enumeration) upon.
*
Expand All @@ -502,6 +502,30 @@ public function setListable(array $listable): static
return $this;
}

/**
* Get lists of values for specified fields in 'listable' option, calling a
* custom lister callback when appropriate.
*
* @return array<string,mixed>
*/
public function getListable(): array
{
$result = [];
foreach ($this->listable as $name) {
// Determine if a custom filter method has been defined
$methodName = 'list' . Str::studly($name);

if (method_exists($this, $methodName)) {
// @phpstan-ignore-next-line Allow variable method call, since we know it exists
$result[$name] = $this->$methodName();
} else {
$result[$name] = $this->getColumnValues($name);
}
}

return $result;
}

/**
* Set fields to allow sorting upon.
*
Expand All @@ -516,6 +540,16 @@ public function setSortable(array $sortable): static
return $this;
}

/**
* Returns fields to allow sorting upon.
*
* @return string[]
*/
public function getSortable(): array
{
return $this->sortable;
}

/**
* Set fields to show in output.
*
Expand Down Expand Up @@ -554,7 +588,7 @@ public function setCsvChunk(int $csvChunk): static
*/
protected function filterAll(EloquentBuilderContract|QueryBuilderContract $query, mixed $value): static
{
foreach ($this->filterable as $name) {
foreach ($this->getFilterable() as $name) {
if (Str::studly($name) != 'all' && !in_array($name, $this->excludeForAll, true)) {
// Since we want to match _any_ of the fields, we wrap the field callback in a 'orWhere' callback
$query->orWhere(function ($fieldQuery) use ($name, $value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ public function testBaseSprunje(): void
],
],
'listable' => [],
'sortable' => [],
'filterable' => [],
], $data);
}
}
Expand Down
50 changes: 50 additions & 0 deletions app/tests/Integration/Sprunje/SprunjeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,26 @@ class SprunjeTest extends CoreTestCase
]
];

/**
* @var string[]
*/
protected array $filterable = [
'name',
'description',
'type',
'active',
];

/**
* @var string[]
*/
protected array $sortable = [
'id',
'name',
'description',
'type',
];

public function setUp(): void
{
parent::setUp();
Expand Down Expand Up @@ -122,6 +142,8 @@ public function testBaseSprunje(): void
['id' => 3, 'name' => 'The foobar', 'description' => 'Le Foo et le Bar', 'type' => 1, 'active' => true],
],
'listable' => $this->listable,
'sortable' => $this->sortable,
'filterable' => $this->filterable,
], $sprunje->getArray());
}

Expand All @@ -139,6 +161,8 @@ public function testWithPagination(): void
['id' => 2, 'name' => 'The bar', 'description' => 'Le Bar', 'type' => 2, 'active' => false],
],
'listable' => $this->listable,
'sortable' => $this->sortable,
'filterable' => $this->filterable,
], $sprunje->getArray());
}

Expand All @@ -161,6 +185,8 @@ public function testWithPaginationOnStringOptions(): void
['id' => 2, 'name' => 'The bar', 'description' => 'Le Bar', 'type' => 2, 'active' => false],
],
'listable' => $this->listable,
'sortable' => $this->sortable,
'filterable' => $this->filterable,
], $sprunje->getArray());
}

Expand All @@ -180,6 +206,8 @@ public function testWithSort(): void
['id' => 1, 'name' => 'The foo', 'description' => 'Le Foo', 'type' => 1, 'active' => true],
],
'listable' => $this->listable,
'sortable' => $this->sortable,
'filterable' => $this->filterable,
], $sprunje->getArray());
}

Expand All @@ -201,6 +229,8 @@ public function testWithCustomSort(): void
['id' => 3, 'name' => 'The foobar', 'description' => 'Le Foo et le Bar', 'type' => 1, 'active' => true],
],
'listable' => $this->listable,
'sortable' => $this->sortable,
'filterable' => $this->filterable,
], $sprunje->getArray());
}

Expand Down Expand Up @@ -229,6 +259,8 @@ public function testWithFilter(): void
['id' => 3, 'name' => 'The foobar', 'description' => 'Le Foo et le Bar', 'type' => 1, 'active' => true],
],
'listable' => $this->listable,
'sortable' => $this->sortable,
'filterable' => $this->filterable,
], $sprunje->getArray());
}

Expand All @@ -243,6 +275,8 @@ public function testWithEmptyFilter(): void
'count_filtered' => 0,
'rows' => [],
'listable' => $this->listable,
'sortable' => $this->sortable,
'filterable' => $this->filterable,
], $sprunje->getArray());
}

Expand All @@ -264,6 +298,8 @@ public function testWithCustomFilter(): void
['id' => 3, 'name' => 'The foobar', 'description' => 'Le Foo et le Bar', 'type' => 1, 'active' => true],
],
'listable' => $this->listable,
'sortable' => $this->sortable,
'filterable' => $this->filterable,
], $sprunje->getArray());
}

Expand All @@ -285,6 +321,8 @@ public function testWithAllFilter(): void
['id' => 3, 'name' => 'The foobar', 'description' => 'Le Foo et le Bar', 'type' => 1, 'active' => true],
],
'listable' => $this->listable,
'sortable' => $this->sortable,
'filterable' => $this->filterable,
], $sprunje->getArray());
}

Expand All @@ -304,6 +342,8 @@ public function testWithTrueBooleanFilter(): void
['id' => 3, 'name' => 'The foobar', 'description' => 'Le Foo et le Bar', 'type' => 1, 'active' => true],
],
'listable' => $this->listable,
'sortable' => $this->sortable,
'filterable' => $this->filterable,
], $sprunje->getArray());
}

Expand All @@ -323,6 +363,8 @@ public function testWithFalseBooleanFilter(): void
// ['id' => 3, 'name' => 'The foobar', 'description' => 'Le Foo et le Bar', 'type' => 1, 'active' => true],
],
'listable' => $this->listable,
'sortable' => $this->sortable,
'filterable' => $this->filterable,
], $sprunje->getArray());
}

Expand Down Expand Up @@ -359,6 +401,8 @@ public function testWithColumns(): void
['id' => 3, 'name' => 'The foobar'],
],
'listable' => $this->listable,
'sortable' => $this->sortable,
'filterable' => $this->filterable,
], $sprunje->getArray());
}

Expand All @@ -381,6 +425,8 @@ public function testForSetters(): void
['id' => 1, 'description' => 'Le Foo'],
],
'listable' => [],
'sortable' => ['description'],
'filterable' => ['description'],
], $sprunje->getArray());
}

Expand Down Expand Up @@ -463,6 +509,8 @@ public function testToResponseWithJson(): void
['id' => 3, 'name' => 'The foobar', 'description' => 'Le Foo et le Bar', 'type' => 1, 'active' => true],
],
'listable' => $this->listable,
'sortable' => $this->sortable,
'filterable' => $this->filterable,
], $response);
$this->assertSame('application/json', $response->getHeaderLine('Content-Type'));
}
Expand All @@ -479,6 +527,8 @@ public function testRelationSprunje(): void
['id' => 2, 'name' => 'bar', 'description' => 'Le Bar', 'type' => 2, 'active' => false],
],
'listable' => [],
'sortable' => [],
'filterable' => [],
], $sprunje->getArray());
}
}
Expand Down

0 comments on commit e62f217

Please sign in to comment.