diff --git a/assets/datagrid.js b/assets/datagrid.js index d3c97db7a..97178323e 100644 --- a/assets/datagrid.js +++ b/assets/datagrid.js @@ -775,7 +775,7 @@ dataGridRegisterExtension('datagrid.after_inline_edit', { var grid = $('.datagrid-' + payload._datagrid_name); if (payload._datagrid_inline_edited) { - grid.find('tr[data-id=' + payload._datagrid_inline_edited + '] > td').addClass('edited'); + grid.find('tr[data-id="' + payload._datagrid_inline_edited + '"] > td').addClass('edited'); return grid.find('.datagrid-inline-edit-trigger').removeClass('hidden'); } else if (payload._datagrid_inline_edit_cancel) { return grid.find('.datagrid-inline-edit-trigger').removeClass('hidden'); @@ -884,7 +884,7 @@ dataGridRegisterExtension('datagrid.redraw-item', { success: function(payload) { var row; if (payload._datagrid_redraw_item_class) { - row = $('tr[data-id=' + payload._datagrid_redraw_item_id + ']'); + row = $('tr[data-id="' + payload._datagrid_redraw_item_id + '"]'); return row.attr('class', payload._datagrid_redraw_item_class); } } @@ -902,7 +902,7 @@ dataGridRegisterExtension('datagrid.reset-filter-by-column', { ref = payload.non_empty_filters; for (i = 0, len = ref.length; i < len; i++) { key = ref[i]; - grid.find('[data-datagrid-reset-filter-by-column=' + key + ']').removeClass('hidden'); + grid.find('[data-datagrid-reset-filter-by-column="' + key + '"]').removeClass('hidden'); } href = grid.find('.reset-filter').attr('href'); return grid.find('[data-datagrid-reset-filter-by-column]').each(function() { diff --git a/src/DataGrid.php b/src/DataGrid.php index 81e328da2..d9801d885 100644 --- a/src/DataGrid.php +++ b/src/DataGrid.php @@ -36,10 +36,12 @@ use Ublaboo\DataGrid\Column\MultiAction; use Ublaboo\DataGrid\Components\DataGridPaginator\DataGridPaginator; use Ublaboo\DataGrid\DataSource\IDataSource; +use Ublaboo\DataGrid\Exception\CannotChangeDataModelException; use Ublaboo\DataGrid\Exception\DataGridColumnNotFoundException; use Ublaboo\DataGrid\Exception\DataGridException; use Ublaboo\DataGrid\Exception\DataGridFilterNotFoundException; use Ublaboo\DataGrid\Exception\DataGridHasToBeAttachedToPresenterComponentException; +use Ublaboo\DataGrid\Exception\InitializingDataModelCallbacksException; use Ublaboo\DataGrid\Export\Export; use Ublaboo\DataGrid\Export\ExportCsv; use Ublaboo\DataGrid\Filter\Filter; @@ -237,7 +239,7 @@ class DataGrid extends Control protected $toolbarButtons = []; /** - * @var DataModel|null + * @var DataModelInterface|null */ protected $dataModel; @@ -494,7 +496,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 DataModelInterface)) { throw new DataGridException('You have to set a data source first.'); } @@ -623,7 +625,7 @@ public function setRowCallback(callable $callback): self */ public function setPrimaryKey(string $primaryKey): self { - if ($this->dataModel instanceof DataModel) { + if ($this->dataModel instanceof DataModelInterface) { throw new DataGridException('Please set datagrid primary key before setting datasource.'); } @@ -637,14 +639,26 @@ public function setPrimaryKey(string $primaryKey): self * @param mixed $source * @return static * @throws InvalidArgumentException + * @throws InitializingDataModelCallbacksException */ public function setDataSource($source): self { $this->dataModel = new DataModel($source, $this->primaryKey); - $this->dataModel->onBeforeFilter[] = [$this, 'beforeDataModelFilter']; - $this->dataModel->onAfterFilter[] = [$this, 'afterDataModelFilter']; - $this->dataModel->onAfterPaginated[] = [$this, 'afterDataModelPaginated']; + $this->initializeCallbacks(); + + return $this; + } + + + /** + * @throws InitializingDataModelCallbacksException + */ + public function setDataModel(DataModelInterface $dataModel): self + { + $this->dataModel = $dataModel; + + $this->initializeCallbacks(); return $this; } @@ -3324,4 +3338,16 @@ private function getPresenterInstance(): Presenter return $this->getPresenter(); } + + private function initializeCallbacks(): void + { + if ($this->dataModel === null) { + throw new InitializingDataModelCallbacksException(); + } + + $this->dataModel->onBeforeFilter[] = [$this, 'beforeDataModelFilter']; + $this->dataModel->onAfterFilter[] = [$this, 'afterDataModelFilter']; + $this->dataModel->onAfterPaginated[] = [$this, 'afterDataModelPaginated']; + } + } diff --git a/src/DataModel.php b/src/DataModel.php index d6a4394f0..20fd2c707 100644 --- a/src/DataModel.php +++ b/src/DataModel.php @@ -31,7 +31,7 @@ * @method onAfterFilter(IDataSource $dataSource) * @method onAfterPaginated(IDataSource $dataSource) */ -final class DataModel +final class DataModel implements DataModelInterface { use SmartObject; diff --git a/src/DataModelInterface.php b/src/DataModelInterface.php new file mode 100644 index 000000000..ca398bb04 --- /dev/null +++ b/src/DataModelInterface.php @@ -0,0 +1,27 @@ +getControl()->getAttribute('class') === null) { + if ($control->getControlPrototype()->getAttribute('class') === null) { $control->setAttribute('class', 'form-control input-sm form-control-sm'); } diff --git a/src/RestBasedDataModel.php b/src/RestBasedDataModel.php new file mode 100644 index 000000000..628974a79 --- /dev/null +++ b/src/RestBasedDataModel.php @@ -0,0 +1,100 @@ +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(); + } + + + /** + * @return mixed + */ + public function filterRow(array $condition) + { + $this->onBeforeFilter($this->dataSource); + $this->onAfterFilter($this->dataSource); + + return $this->dataSource->filterOne($condition)->getData(); + } +} diff --git a/src/templates/datagrid.latte b/src/templates/datagrid.latte index 3a70f59bb..61f86891d 100644 --- a/src/templates/datagrid.latte +++ b/src/templates/datagrid.latte @@ -270,8 +270,10 @@ {/foreach} - {input $filter['inline_edit']['cancel'], class => 'btn btn-xs btn-danger'} - {input $filter['inline_edit']['submit'], class => 'btn btn-xs btn-primary'} + {block inline-edit-buttons} + {input $filter['inline_edit']['cancel'], class => 'btn btn-xs btn-danger'} + {input $filter['inline_edit']['submit'], class => 'btn btn-xs btn-primary'} + {/block} {input $filter['inline_edit']['_id']} {input $filter['inline_edit']['_primary_where_column']} @@ -292,24 +294,26 @@ {$td->endTag()|noescape} {/foreach} - {foreach $actions as $key => $action} - {if $row->hasAction($key)} - {if $action->hasTemplate()} - {include $action->getTemplate(), item => $item, (expand) $action->getTemplateVariables(), row => $row} - {else} - {$action->render($row)|noescape} + {block col-actions} + {foreach $actions as $key => $action} + {if $row->hasAction($key)} + {if $action->hasTemplate()} + {include $action->getTemplate(), item => $item, (expand) $action->getTemplateVariables(), row => $row} + {else} + {$action->render($row)|noescape} + {/if} {/if} + {/foreach} + + + + {if $inlineEdit && $row->hasInlineEdit()} + {$inlineEdit->renderButton($row)|noescape} {/if} - {/foreach} - - - - {if $inlineEdit && $row->hasInlineEdit()} - {$inlineEdit->renderButton($row)|noescape} - {/if} - {if $itemsDetail && $itemsDetail->shouldBeRendered($row)} - {$itemsDetail->renderButton($row)|noescape} - {/if} + {if $itemsDetail && $itemsDetail->shouldBeRendered($row)} + {$itemsDetail->renderButton($row)|noescape} + {/if} + {/block} {/if} @@ -437,8 +441,10 @@ {/foreach} - {input $filter['inline_add']['cancel']} - {input $filter['inline_add']['submit']} + {block inline-add-buttons} + {input $filter['inline_add']['cancel']} + {input $filter['inline_add']['submit']} + {/block} {/if}