Documentation | Framework Bundle
MIT License (MIT). Please see LICENSE
for more information. Maintained by Spiral Scout.
Data Grid and specification builder. Subtree split of the Spiral Data Grid component (see spiral/framework)
Home Page: https://spiral.dev/docs/component-data-grid
License: MIT License
Documentation | Framework Bundle
MIT License (MIT). Please see LICENSE
for more information. Maintained by Spiral Scout.
For convenience, we can add several most common filters as ILike
for PostgreSQL (and many others). This will also require a new query writer
Right now, DateTimeValue
converts ''
to 'now'
(PHP \Datetime
class specific). As a BC-break need to be implemented in v2.0
http://prntscr.com/q3795o We do not need empty IN statements.
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.
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
However, omitting the withDefaults method like this:
$factory = $this->app->make(GridFactory::class);
$factory = $factory->withInput(new ArrayInput([
'title' => $post->title(),
]));
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
Please find the detailed code for reproduction below, encapsulated within <details>
tags for clarity.
<?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,
],
]);
}
}
<?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,
];
}
}
<?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()));
}
}
It will be useful to validate any value if it is allowed to be empty (using !empty(...)
check). Example:
new NotEmpty();
new NotEmpty(new IntValue());
It will check if the passed value is not empty without any conversion. Additionally, if a sub-value passed, will perform it's accepts
and converts
operations.
Concerns: will not work with StringValue
and ScalarValue
because right now they do not allow empty values by default, except using such a construction
new NotEmpty(new StringValue(true));
which is equivalent to
new StringValue();
It would be nice to be able to reuse Cycle data grid configurations for full-text search in ElasticSearch or Bleve indexes
Sometimes we need to change some grid handling during creation and it can be reached by DataGrid attribute and its great.
And you can define your own factory in this attribute and its great too.
BUT
I would like to change some small part of your basic \Spiral\DataGrid\GridFactory
and I would like to extend it and override only create
method
BUT AGAIN
In you GridFactory you work in methods only with private properties and I should duplicate whole class for my factory
AND IT IS BAD APPROACH
If your class is not finalized and it can works as parent class why did you use private access?
Could you change it to protected?
It can be actual for any not-finalized classes by OOP...
instead of
{
"filter": {
"reviewed": true,
"status": "active"
},
"sort": {
"newest": 1,
"countReviews": -1
},
"paginate": {
"page": 3
}
}
read from
{
"reviewed": true,
"status": "active",
"sortByNewest": 1,
"sortByCountReviews": -1,
"page": 3
}
In case when you need sorting in DataGrid by nullable field I've detected that Sorter uses INNER JOIN on building Select Query.
If values are nullable this moment reduces amount of records.
Sorting mustn't reduce records amount
Make any simple table with nullable field. For example it can be updatedBy
. This field will be changed only after update.
Insert some records with different values in this field.
Prepare grid and add sorting by updatedBy
field
Q | A |
---|---|
Framework Version | 2.7.8 |
PHP version | 7.4.16 |
Need value which support only uuid.
In case when you need using default search
filter in DataGrid by nullable field I've detected that Filter uses INNER JOIN on building Select Query.
If values are nullable this moment reduces amount of records and it is not fully suitable in cases when I want to make search by some optional fields.
It will be great if Filter was more flexible and allows to define used JOIN type.
Make any simple table with nullable field. For example it can be updatedBy
. This field will be changed only after update.
Insert some records with different values in this field.
Configure your Grid with using filter search
by updatedBy.email
like this:
$this->addFilter(
'search',
new Filter\Any(
new Filter\Like('name'),
new Filter\Like('updatedBy.email')
)
);
Prepare grid and use search by default grid search.
Check prepared sql by logs
Q | A |
---|---|
Framework Version | 2.7.8 |
PHP version | 7.4.16 |
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.