Introduction
I've encountered a potential issue while integrating the data-grid package into a Laravel project, specifically during the development of tests to evaluate the data-grid functionality. It appears that when the withDefaults method is not utilized on the GridFactory, the filters list remains empty, resulting in unfiltered data being returned.
According to the current documentation available at spiral.dev/docs/component-data-grid/current/en, my understanding is that the data-grid
should automatically apply filters as defined within the PostSchema.php
. This assumption is based on the premise that the schema's purpose is to dictate how data should be filtered, sorted, and paginated without necessarily requiring additional methods like withDefaults to enforce these rules explicitly.
Issue Description
Successful condition to filter data
When employing the ->withDefaults
method as shown below, the data is correctly filtered according to the specified conditions:
$factory = $this->app->make(GridFactory::class);
$factory = $factory->withInput(new ArrayInput([
'title' => $post->title(),
]))->withDefaults([
GridFactory::KEY_FILTER => ['title' => $post->title()],
]);
This results in the expected filtered output, demonstrating that the filtering mechanism works as intended when withDefaults
is specified.
array:2 [
"posts" => array:1 [
0 => WayOfDev\App\Entities\Post^ {#11699
-id: "018e7640-fd62-7003-96fb-1822c4360aa4"
-title: "Ea aliquid sit modi neque perspiciatis."
-content: "Est rerum voluptas nesciunt placeat debitis cumque nisi. Cupiditate sequi sapiente libero ut placeat. Et et voluptatibus non atque quod veniam. Et quis ratione qui nulla deleniti et."
-comments: Illuminate\Support\Collection^ {#4622
#items: []
#escapeWhenCastingToString: false
}
}
]
"grid" => array:1 [
"values" => array:4 [
"filters" => array:1 [
"title" => "Ea aliquid sit modi neque perspiciatis."
]
"sorters" => []
"count" => null
"paginator" => array:2 [
"limit" => 10
"page" => 1
]
]
]
] // /app/tests/src/DataGridFactoryTest.php:77
Failing condition to filter data
However, omitting the withDefaults method like this:
$factory = $this->app->make(GridFactory::class);
$factory = $factory->withInput(new ArrayInput([
'title' => $post->title(),
]));
Result:
Leads to an empty filters array, and consequently, all results are returned (10, by the Paginator), indicating that the data is not being filtered.
array:2 [
"posts" => array:10 [
0 => WayOfDev\App\Entities\Post^ {#11699
-id: "018e7642-2833-724d-990f-eddb48fdbc17"
-title: "Et pariatur voluptatum ea dignissimos."
-content: "In explicabo esse quibusdam quidem. Distinctio alias aut rerum est. Cum eveniet mollitia eos velit voluptates sunt. Ea minus rerum incidunt quo."
-comments: Illuminate\Support\Collection^ {#4551
#items: []
#escapeWhenCastingToString: false
}
}
1 => WayOfDev\App\Entities\Post^ {#4438
// Omited for demo
}
2 => WayOfDev\App\Entities\Post^ {#5207
// Omited for demo
}
// Omited for demo
]
"grid" => array:1 [
"values" => array:4 [
"filters" => []
"sorters" => []
"count" => null
"paginator" => array:2 [
"limit" => 10
"page" => 1
]
]
]
] // /app/tests/src/DataGridFactoryTest.php:78
Reproduction Code:
Please find the detailed code for reproduction below, encapsulated within <details>
tags for clarity.
DataGridFactoryTest.php
<?php
declare(strict_types=1);
namespace WayOfDev\Tests;
use Database\Factories\PostFactory;
use Illuminate\Support\Facades\Artisan;
use PHPUnit\Framework\Attributes\Test;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Spiral\DataGrid\GridFactory;
use Spiral\DataGrid\GridInterface;
use Spiral\DataGrid\Input\ArrayInput;
use WayOfDev\App\Entities\Post;
use WayOfDev\App\PostRepository;
use WayOfDev\App\PostSchema;
use function iterator_to_array;
class DataGridFactoryTest extends TestCase
{
public function setUp(): void
{
parent::setUp();
Artisan::call('cycle:migrate:init');
Artisan::call('cycle:orm:render', ['--no-color' => true]);
Artisan::call('cycle:orm:migrate', ['--split' => true, '--run' => true]);
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function getPost(): Post
{
$factory = PostFactory::new()->times(30)->create();
/** @var Post $post */
return $factory->random();
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
#[Test]
public function it_queries_data(): void
{
$post = $this->getPost();
$schema = new PostSchema();
$factory = $this->app->make(GridFactory::class);
$factory = $factory->withInput(new ArrayInput([
'title' => $post->title(),
]));
// ->withDefaults([
// GridFactory::KEY_FILTER => ['title' => $post->title()],
// ]);
$repository = $this->app->make(PostRepository::class);
/** @var GridInterface $result */
$grid = $factory->create($repository->select(), $schema);
$values = [];
foreach ([
GridInterface::FILTERS,
GridInterface::SORTERS,
GridInterface::COUNT,
GridInterface::PAGINATOR,
] as $key) {
$values[$key] = $grid->getOption($key);
}
dd([
'posts' => iterator_to_array($grid),
'grid' => [
'values' => $values,
],
]);
}
}
Post.php
<?php
declare(strict_types=1);
namespace Database\Factories;
use WayOfDev\App\Entities\Post;
use WayOfDev\DatabaseSeeder\Factories\AbstractFactory;
class PostFactory extends AbstractFactory
{
public function makeEntity(array $definition): object
{
return new Post(
title: $definition['title'],
content: $definition['content'],
);
}
public function entity(): string
{
return Post::class;
}
public function definition(): array
{
return [
'title' => $this->faker->sentence,
'content' => $this->faker->paragraph,
];
}
}
PostSchema.php
<?php
declare(strict_types=1);
namespace WayOfDev\App;
use Spiral\DataGrid\GridSchema;
use Spiral\DataGrid\Specification\Filter\Equals;
use Spiral\DataGrid\Specification\Pagination\PagePaginator;
use Spiral\DataGrid\Specification\Sorter\Sorter;
use Spiral\DataGrid\Specification\Value\StringValue;
class PostSchema extends GridSchema
{
public function __construct()
{
// User pagination: limit results to 10 per page
$this->setPaginator(new PagePaginator(10));
// Sorting option: by id
$this->addSorter('id', new Sorter('id'));
// Filter option: find by title matching post input
$this->addFilter('title', new Equals('title', new StringValue()));
}
}