diff --git a/phpstan.neon b/phpstan.neon index 9b905ada0..9780a37a2 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -30,11 +30,11 @@ parameters: count: 1 path: src/DataSource/DibiFluentMssqlDataSource.php - - message: "#^Cannot call method filterData\\(\\) on Contributte\\\\Datagrid\\\\DataModel\\|null\\.$#" + message: "#^Cannot call method filterData\\(\\) on Contributte\\\\Datagrid\\\\AbstractDataModel\\|null\\.$#" count: 1 path: src/Datagrid.php - - message: "#^Cannot call method filterRow\\(\\) on Contributte\\\\Datagrid\\\\DataModel\\|null\\.$#" + message: "#^Cannot call method filterRow\\(\\) on Contributte\\\\Datagrid\\\\AbstractDataModel\\|null\\.$#" count: 1 path: src/Datagrid.php - # In PHP 8+, the Stringable typehint should be used, and this can be removed. diff --git a/src/AbstractDataModel.php b/src/AbstractDataModel.php new file mode 100644 index 000000000..92ef56d9c --- /dev/null +++ b/src/AbstractDataModel.php @@ -0,0 +1,32 @@ +dataModel instanceof DataModel) { + if (!$this->dataModel instanceof AbstractDataModel) { throw new DatagridException('You have to set a data source first.'); } diff --git a/src/DataModel.php b/src/DataModel.php index db72f7c47..7a375ec74 100644 --- a/src/DataModel.php +++ b/src/DataModel.php @@ -29,25 +29,11 @@ use Nette\SmartObject; use Nextras\Orm\Collection\ICollection; -/** - * @method onBeforeFilter(IDataSource $dataSource) - * @method onAfterFilter(IDataSource $dataSource) - * @method onAfterPaginated(IDataSource $dataSource) - */ -final class DataModel +final class DataModel extends AbstractDataModel { use SmartObject; - /** @var array|callable[] */ - public array $onBeforeFilter = []; - - /** @var array|callable[] */ - public array $onAfterFilter = []; - - /** @var array|callable[] */ - public array $onAfterPaginated = []; - private IDataSource $dataSource; public function __construct(mixed $source, string $primaryKey) @@ -133,7 +119,7 @@ public function filterData( return $this->dataSource->sort($sorting)->getData(); } - public function filterRow(array $condition): mixed + public function filterRow(array $condition): array { $this->onBeforeFilter($this->dataSource); $this->onAfterFilter($this->dataSource); diff --git a/src/DataSource/IDataSource.php b/src/DataSource/IDataSource.php index 2137dadea..e297c27f8 100644 --- a/src/DataSource/IDataSource.php +++ b/src/DataSource/IDataSource.php @@ -16,7 +16,7 @@ public function getCount(): int; /** * Get the data */ - public function getData(): iterable; + public function getData(): array; /** * Filter data diff --git a/src/Datagrid.php b/src/Datagrid.php index 2bfc007a9..d77da88d5 100644 --- a/src/Datagrid.php +++ b/src/Datagrid.php @@ -183,7 +183,7 @@ class Datagrid extends Control /** @var array */ protected array $toolbarButtons = []; - protected ?DataModel $dataModel = null; + protected ?AbstractDataModel $dataModel = null; protected string $primaryKey = 'id'; @@ -344,7 +344,7 @@ public function render(): void /** * Check whether datagrid has set some columns, initiated data source, etc */ - if (!($this->dataModel instanceof DataModel)) { + if (!($this->dataModel instanceof AbstractDataModel)) { throw new DatagridException('You have to set a data source first.'); } @@ -469,7 +469,7 @@ public function setRowCallback(callable $callback): self */ public function setPrimaryKey(string $primaryKey): self { - if ($this->dataModel instanceof DataModel) { + if ($this->dataModel instanceof AbstractDataModel) { throw new DatagridException('Please set datagrid primary key before setting datasource.'); } @@ -481,10 +481,18 @@ public function setPrimaryKey(string $primaryKey): self /** * @return static * @throws InvalidArgumentException + * @throws DatagridException */ public function setDataSource(mixed $source): self { - $this->dataModel = new DataModel($source, $this->primaryKey); + $this->setDataModel(new DataModel($source, $this->primaryKey)); + + return $this; + } + + public function setDataModel(AbstractDataModel $dataModel): self + { + $this->dataModel = $dataModel; $this->dataModel->onBeforeFilter[] = [$this, 'beforeDataModelFilter']; $this->dataModel->onAfterFilter[] = [$this, 'afterDataModelFilter']; diff --git a/src/RestDataModel.php b/src/RestDataModel.php new file mode 100644 index 000000000..e28cfb39a --- /dev/null +++ b/src/RestDataModel.php @@ -0,0 +1,62 @@ +dataSource = $source; + } + + public function getDataSource(): IDataSource + { + return $this->dataSource; + } + + public function filterData(?DatagridPaginator $paginatorComponent, Sorting $sorting, array $filters): iterable + { + $this->onBeforeFilter($this->dataSource); + + $this->dataSource->filter($filters); + + $this->onAfterFilter($this->dataSource); + + /** + * Paginator is optional + */ + if ($paginatorComponent !== null) { + $paginator = $paginatorComponent->getPaginator(); + + $this->dataSource->sort($sorting)->limit( + $paginator->getOffset(), + $paginator->getItemsPerPage() + ); + + $this->onAfterPaginated($this->dataSource); + + $data = $this->dataSource->getData(); + $paginator->setItemCount($this->dataSource->getCount()); + + return $data; + } + + return $this->dataSource->sort($sorting)->getData(); + } + + public function filterRow(array $condition): array + { + $this->onBeforeFilter($this->dataSource); + $this->onAfterFilter($this->dataSource); + + return $this->dataSource->filterOne($condition)->getData(); + } + +}