true,
'show_filter' => true,
'show_actions' => true,
'show_quick_edit_button' => false,
'show_edit_button' => true,
'show_view_button' => true,
'show_delete_button' => true,
'show_row_selector' => true,
'show_create_btn' => true,
'show_quick_create_btn' => false,
'show_bordered' => false,
'show_toolbar' => true,
'row_selector_style' => 'primary',
'row_selector_circle' => true,
'row_selector_clicktr' => false,
'row_selector_label_key' => null,
'row_selector_bg' => 'var(--20)',
'show_exporter' => false,
'show_export_all' => true,
'show_export_current_page' => true,
'show_export_selected_rows' => true,
'export_limit' => 50000,
'dialog_form_area' => ['700px', '670px'],
'table_header_style' => 'table-header-gray',
];
/**
* Create a new grid instance.
*
* Grid constructor.
* @param Repository|null $repository
* @param null $builder
*/
public function __construct(?Repository $repository = null, ?\Closure $builder = null)
{
if ($repository) {
$this->keyName = $repository->getKeyName();
}
$this->model = new Model($repository);
$this->columns = new Collection();
$this->rows = new Collection();
$this->builder = $builder;
$this->tableId = 'grid-'.Str::random(8);
$this->model()->setGrid($this);
$this->setupTools();
$this->setupFilter();
$this->callResolving();
}
/**
* Get table ID.
*
* @return string
*/
public function getTableId()
{
return $this->tableId;
}
/**
* Get primary key name of model.
*
* @return string
*/
public function getKeyName()
{
return $this->keyName ?: 'id';
}
/**
* Set primary key name.
*
* @param string $name
*/
public function setKeyName(string $name)
{
$this->keyName = $name;
}
/**
* Add column to Grid.
*
* @param string $name
* @param string $label
*
* @return Column|Collection
*/
public function column($name, $label = '')
{
if (strpos($name, '.') !== false) {
list($relationName, $relationColumn) = explode('.', $name);
$label = empty($label) ? admin_trans_field($relationColumn) : $label;
$name = Str::snake($relationName).'.'.$relationColumn;
}
$column = $this->addColumn($name, $label);
return $column;
}
/**
* Add number column.
*
* @param null|string $label
* @return Column
*/
public function number(?string $label = null)
{
return $this->addColumn('#', $label ?: '#')->bold();
}
/**
* Batch add column to grid.
*
* @example
* 1.$grid->columns(['name' => 'Name', 'email' => 'Email' ...]);
* 2.$grid->columns('name', 'email' ...)
*
* @param array $columns
*
* @return null
*/
public function columns($columns = [])
{
if (func_num_args() == 0) {
return $this->columns;
}
if (func_num_args() == 1 && is_array($columns)) {
foreach ($columns as $column => $label) {
$this->column($column, $label);
}
return;
}
foreach (func_get_args() as $column) {
$this->column($column);
}
}
/**
* @return Collection
*/
public function getColumns()
{
return $this->columns;
}
/**
* Add column to grid.
*
* @param string $field
* @param string $label
*
* @return Column
*/
protected function addColumn($field = '', $label = '')
{
$column = new Column($field, $label);
$column->setGrid($this);
$this->columns->put($field, $column);
return $column;
}
/**
* Get Grid model.
*
* @return Model
*/
public function model()
{
return $this->model;
}
/**
* @return array
*/
public function getColumnNames()
{
return $this->columnNames;
}
/**
* @param array $options
* @return $this
*/
public function setRowSelectorOptions(array $options = [])
{
if (isset($options['style'])) {
$this->options['row_selector_style'] = $options['style'];
}
if (isset($options['circle'])) {
$this->options['row_selector_circle'] = $options['circle'];
}
if (isset($options['clicktr'])) {
$this->options['row_selector_clicktr'] = $options['clicktr'];
}
if (isset($options['label'])) {
$this->options['row_selector_label_key'] = $options['label_name'];
}
if (isset($options['bg'])) {
$this->options['row_selector_bg'] = $options['bg'];
}
return $this;
}
/**
* Prepend checkbox column for grid.
*
* @return void
*/
protected function prependRowSelectorColumn()
{
if (!$this->options['show_row_selector']) {
return;
}
$circle = $this->options['row_selector_circle'] ? 'checkbox-circle' : '';
$column = new Column(
Column::SELECT_COLUMN_NAME,
<<
HTML
);
$column->setGrid($this);
$column->displayUsing(Displayers\RowSelector::class);
$this->columns->prepend($column, Column::SELECT_COLUMN_NAME);
}
/**
* Apply column filter to grid query.
*/
protected function applyColumnFilter()
{
$this->columns->each->bindFilterQuery($this->model());
}
/**
* Build the grid.
*
* @return void
*/
public function build()
{
if ($this->built) {
return;
}
$collection = $this->processFilter(false);
$data = $collection->toArray();
$this->prependRowSelectorColumn();
$this->appendActionsColumn();
Column::setOriginalGridModels($collection);
$this->columns->map(function (Column $column) use (&$data) {
$column->fill($data);
$this->columnNames[] = $column->getName();
});
$this->buildRows($data);
$this->built = true;
if ($data && $this->responsive) {
$this->responsive->build();
}
$this->sortHeaders();
}
/**
* Build the grid rows.
*
* @param array $data
*
* @return void
*/
protected function buildRows(array $data)
{
$this->rows = collect($data)->map(function ($model) {
return new Row($this, $model);
});
if ($this->rowsCallback) {
foreach ($this->rowsCallback as $value) {
$this->rows->map($value);
}
}
}
/**
* Set grid row callback function.
*
* @param Closure $callable
*
* @return Collection|null
*/
public function rows(Closure $callable = null)
{
if (is_null($callable)) {
return $this->rows;
}
$this->rowsCallback[] = $callable;
}
/**
* Get create url.
*
* @return string
*/
public function getCreateUrl()
{
$queryString = '';
if ($constraints = $this->model()->getConstraints()) {
$queryString = http_build_query($constraints);
}
return sprintf('%s/create%s',
$this->getResource(),
$queryString ? ('?'.$queryString) : ''
);
}
/**
* @param string $width
* @param string $height
* @return $this
*/
public function setModalFormDimensions(string $width, string $height)
{
$this->options['dialog_form_area'] = [$width, $height];
return $this;
}
/**
* Render create button for grid.
*
* @return string
*/
public function renderCreateButton()
{
if (!$this->options['show_create_btn'] && !$this->options['show_quick_create_btn']) {
return '';
}
return (new Tools\CreateButton($this))->render();
}
/**
* @return $this
*/
public function withBorder()
{
$this->options['show_bordered'] = true;
return $this;
}
/**
* Set grid header.
*
* @param Closure|string|Renderable $content
*
* @return $this|Closure
*/
public function header($content = null)
{
if (!$content) {
return $this->header;
}
$this->header = $content;
return $this;
}
/**
* Render grid header.
*
* @return string
*/
public function renderHeader()
{
if (!$this->header) {
return '';
}
$content = Helper::render($this->header, [$this->processFilter(false)]);
if (empty($content)) {
return '';
}
if ($content instanceof Renderable) {
$content = $content->render();
}
if ($content instanceof Htmlable) {
$content = $content->toHtml();
}
return <<{$content}
HTML;
}
/**
* Set grid footer.
*
* @param Closure|string|Renderable $content
*
* @return $this|Closure
*/
public function footer($content = null)
{
if (!$content) {
return $this->footer;
}
$this->footer = $content;
return $this;
}
/**
* Render grid footer.
*
* @return string
*/
public function renderFooter()
{
if (!$this->footer) {
return '';
}
$content = Helper::render($this->footer, [$this->processFilter(false)]);
if (empty($content)) {
return '';
}
if ($content instanceof Renderable) {
$content = $content->render();
}
if ($content instanceof Htmlable) {
$content = $content->toHtml();
}
return <<{$content}
HTML;
}
/**
* Get or set option for grid.
*
* @param string $key
* @param mixed $value
*
* @return $this|mixed
*/
public function option($key, $value = null)
{
if (is_null($value)) {
return $this->options[$key];
}
$this->options[$key] = $value;
return $this;
}
/**
* Disable row selector.
*
* @return $this
*/
public function disableRowSelector(bool $disable = true)
{
$this->tools->disableBatchActions($disable);
return $this->option('show_row_selector', !$disable);
}
/**
* Show row selector.
*
* @return $this
*/
public function showRowSelector(bool $val = true)
{
return $this->disableRowSelector(!$val);
}
/**
* Remove create button on grid.
*
* @return $this
*/
public function disableCreateButton(bool $disable = true)
{
return $this->option('show_create_btn', !$disable);
}
/**
* Show create button.
*
* @return $this
*/
public function showCreateButton(bool $val = true)
{
return $this->disableCreateButton(!$val);
}
/**
* @param bool $disable
* @return $this
*/
public function disableQuickCreateButton(bool $disable = true)
{
return $this->option('show_quick_create_btn', !$disable);
}
/**
* @param bool $val
* @return $this
*/
public function showQuickCreateButton(bool $val = true)
{
return $this->disableQuickCreateButton(!$val);
}
/**
* If allow creation.
*
* @return bool
*/
public function allowCreateBtn()
{
return $this->options['show_create_btn'];
}
/**
* If grid show quick create button.
*
* @return bool
*/
public function allowQuickCreateBtn()
{
return $this->options['show_quick_create_btn'];
}
/**
* Set resource path.
*
* @param string $path
* @return $this
*/
public function resource(string $path)
{
if (!empty($path)) {
$this->resourcePath = admin_url($path);
}
return $this;
}
/**
* Get resource path.
*
* @return string
*/
public function getResource()
{
return $this->resourcePath ?: (
$this->resourcePath = url(app('request')->getPathInfo())
);
}
/**
* Create a grid instance.
*
* @param mixed ...$params
* @return $this
*/
public static function make(...$params)
{
return new static(...$params);
}
/**
* Enable responsive tables.
* @see https://github.com/nadangergeo/RWD-Table-Patterns
*
* @return Responsive
*/
public function responsive()
{
if (!$this->responsive) {
$this->responsive = new Responsive($this);
}
return $this->responsive;
}
/**
* @return bool
*/
public function allowResponsive()
{
return $this->responsive ? true : false;
}
/**
* @param Closure $closure
* @return $this;
*/
public function wrap(\Closure $closure)
{
$this->wrapper = $closure;
return $this;
}
/**
* @return bool
*/
public function hasWrapper()
{
return $this->wrapper ? true : false;
}
/**
* Add variables to grid view.
*
* @param array $variables
*
* @return $this
*/
public function with($variables = [])
{
$this->variables = $variables;
return $this;
}
/**
* Get all variables will used in grid view.
*
* @return array
*/
protected function variables()
{
$this->variables['grid'] = $this;
$this->variables['tableId'] = $this->tableId;
return $this->variables;
}
/**
* Set a view to render.
*
* @param string $view
* @param array $variables
*/
public function setView($view, $variables = [])
{
if (!empty($variables)) {
$this->with($variables);
}
$this->view = $view;
}
/**
* Set grid title.
*
* @param string $title
*
* @return $this
*/
public function setTitle($title)
{
$this->variables['title'] = $title;
return $this;
}
/**
* Set grid description.
*
* @param string $description
*
* @return $this
*/
public function setDescription($description)
{
$this->variables['description'] = $description;
return $this;
}
/**
* Set resource path for grid.
*
* @param string $path
*
* @return $this
*/
public function setResource($path)
{
$this->resourcePath = $path;
return $this;
}
/**
* Get the string contents of the grid view.
*
* @return string
*/
public function render()
{
$this->handleExportRequest(true);
try {
$this->callComposing();
$this->build();
} catch (\Throwable $e) {
return Admin::makeExceptionHandler()->renderException($e);
}
return $this->doWrap();
}
/**
* @return string
*/
protected function doWrap()
{
$view = view($this->view, $this->variables());
if (!$wrapper = $this->wrapper) {
return $view->render();
}
return $wrapper($view);
}
/**
* Add column to grid.
*
* @param string $name
* @return Column|Collection
*/
public function __get($name)
{
return $this->addColumn($name);
}
/**
* Dynamically add columns to the grid view.
*
* @param $method
* @param $arguments
*
* @return Column
*/
public function __call($method, $arguments)
{
if (static::hasMacro($method)) {
return $this->macroCall($method, $arguments);
}
return $this->addColumn($method, $arguments[0] ?? null);
}
}