Table Builder
Introduction
The Table Builder is a powerful feature in Botble CMS that allows you to create and customize data tables with minimal effort. It provides a fluent API for defining columns, actions, filters, and more. Tables are used throughout the admin panel to display and manage data.
The table system is built on top of DataTables and provides a clean, consistent interface for displaying and interacting with your data.
Basic Usage
All tables in Botble CMS extend the Botble\Table\Abstracts\TableAbstract
class. To create a table, you need to:
- Create a new class that extends
TableAbstract
- Implement the
setup()
method to configure your table
Here's a basic example:
<?php
namespace YourPlugin\Tables;
use Botble\Table\Abstracts\TableAbstract;
use Botble\Table\Columns\IdColumn;
use Botble\Table\Columns\NameColumn;
use Botble\Table\Columns\CreatedAtColumn;
use Botble\Table\Columns\StatusColumn;
use Botble\Table\Actions\EditAction;
use Botble\Table\Actions\DeleteAction;
use Botble\Table\BulkActions\DeleteBulkAction;
use Botble\Table\HeaderActions\CreateHeaderAction;
use YourPlugin\Models\YourModel;
use Illuminate\Database\Eloquent\Builder;
class YourModelTable extends TableAbstract
{
public function setup(): void
{
$this
->model(YourModel::class)
->addColumns([
IdColumn::make(),
NameColumn::make()->route('your-model.edit'),
CreatedAtColumn::make(),
StatusColumn::make(),
])
->addHeaderAction(CreateHeaderAction::make()->route('your-model.create'))
->addActions([
EditAction::make()->route('your-model.edit'),
DeleteAction::make()->route('your-model.destroy'),
])
->addBulkAction(DeleteBulkAction::make()->permission('your-model.destroy'))
->addBulkChanges([
NameBulkChange::make(),
StatusBulkChange::make(),
CreatedAtBulkChange::make(),
])
->queryUsing(function (Builder $query) {
return $query
->select([
'id',
'name',
'created_at',
'status',
]);
});
}
}
Table Configuration
Setting the Model
Use the model()
method to specify which model the table should use:
$this->model(YourModel::class)
Default Sorting
You can set the default sorting column and direction:
$this->defaultSortColumnName = 'created_at';
$this->defaultSortDirection = 'desc';
Columns
Columns are the core components of your table. Botble CMS provides several pre-built column types to make it easy to display different types of data.
Adding Columns
Use the addColumns()
method to add columns to your table:
$this->addColumns([
IdColumn::make(),
NameColumn::make()->route('your-model.edit'),
CreatedAtColumn::make(),
StatusColumn::make(),
]);
Available Column Types
Botble CMS provides many built-in column types that make it easy to display different types of data. Here's a comprehensive list of available column types:
Basic Columns
Column
: A basic column that can be customizedFormattedColumn
: A customizable column that can display formatted data
Identification Columns
IdColumn
: Displays the ID of the recordNameColumn
: Displays the name of the record (usually linked to the edit page)
Date and Time Columns
CreatedAtColumn
: Displays the creation dateUpdatedAtColumn
: Displays the last update dateDateColumn
: Displays a date with formatting optionsDateTimeColumn
: Displays a date and time with formatting options
Media Columns
ImageColumn
: Displays an image with customizable size
Status and State Columns
StatusColumn
: Displays the status with appropriate stylingEnumColumn
: Displays enum values with proper formattingYesNoColumn
: Displays boolean values as Yes/No
Link and Contact Columns
LinkableColumn
: A column that can be linked to a routeEmailColumn
: Displays an email address with optional mailto linkPhoneColumn
: Displays a phone number with optional tel link
Action Columns
RowActionsColumn
: Displays action buttons for each rowCheckboxColumn
: Displays a checkbox for row selection
Column Usage Examples
Here are examples of how to use some of the most common column types:
IdColumn
IdColumn::make()
->title('Custom ID') // Optional: override default title
->width(50) // Optional: set column width
NameColumn
NameColumn::make()
->route('your-model.edit') // Link to edit page
->limit(30) // Limit text length
ImageColumn
ImageColumn::make()
->with(80) // Set image width
->mediaSize('thumb') // Set media size (thumb, medium, etc.)
->fullMediaSize() // Use full size image
DateColumn
DateColumn::make('created_at')
->dateFormat('Y-m-d') // Custom date format
->diffForHumans() // Show as "2 days ago"
StatusColumn
StatusColumn::make()
->title('Status')
EmailColumn
EmailColumn::make()
->linkable() // Make email clickable
LinkableColumn
LinkableColumn::make('website')
->title('Website')
->route('your-model.show') // Link to a route
// OR
->urlUsing(fn (LinkableColumn $column) => $column->getItem()->external_url) // Custom URL
->externalLink() // Open in new tab
FormattedColumn
FormattedColumn::make('categories_name')
->title('Categories')
->getValueUsing(function (FormattedColumn $column) {
return $column->getItem()->categories->pluck('name')->implode(', ');
})
->withEmptyState() // Show placeholder when empty
EnumColumn
EnumColumn::make('type')
->title('Type')
YesNoColumn
YesNoColumn::make('is_featured')
->title('Featured')
Common Column Customization Methods
All column types inherit from the base Column
class and share common customization methods. Here are the most frequently used methods:
Basic Customization
$column
->title('Column Title') // Set column title
->name('column_name') // Set column name (database field)
->content('Static Content') // Set static content
->width(150) // Set column width in pixels
->addClass('custom-class') // Add CSS class
->visible(false) // Hide column initially (can be shown via column visibility)
->hidden() // Hide column completely
Data Handling
$column
->orderable(false) // Disable ordering
->searchable(false) // Disable searching
->exportable(false) // Exclude from exports
->printable(false) // Exclude from print view
->getValueUsing(function (FormattedColumn $column) {
// Custom logic to get the value
return $column->getItem()->some_relation->name;
})
->renderUsing(function (FormattedColumn $column, $value) {
// Custom rendering logic
return '<span class="badge bg-success">' . $value . '</span>';
})
Alignment and Styling
$column
->alignStart() // Align content to start (left in LTR)
->alignCenter() // Align content to center
->alignEnd() // Align content to end (right in LTR)
->withColor('success') // Apply color (success, danger, warning, info, etc.)
->withIcon('ti ti-check') // Add an icon
Special Features
$column
->withEmptyState('N/A') // Show placeholder when empty
->limit(50) // Limit text length
->copyable() // Make content copyable
->mask('***-**-####') // Apply a mask pattern
->blur() // Blur sensitive content
FormattedColumn Specific Methods
The FormattedColumn
class provides additional methods for advanced customization:
FormattedColumn::make('categories_name')
->title(trans('plugins/blog::posts.categories'))
->getValueUsing(function (FormattedColumn $column) {
// Access the current row item
$item = $column->getItem();
// Get related data
$categories = $item->categories->sortBy('name')
->map(function ($category) {
return $category->name;
})
->all();
return implode(', ', $categories);
})
->append(function ($column) {
// Add content after the column value
return '<span class="ms-1 badge bg-info">New</span>';
})
->prepend(function ($column) {
// Add content before the column value
return '<i class="ti ti-tag me-1"></i>';
})
Actions
Actions allow users to interact with the data in your table. There are three types of actions:
- Row Actions: Actions that apply to a single row (e.g., Edit, Delete)
- Bulk Actions: Actions that apply to multiple selected rows
- Header Actions: Actions that appear in the table header (e.g., Create New)
Row Actions
Add row actions using the addActions()
method:
$this->addActions([
EditAction::make()->route('your-model.edit'),
DeleteAction::make()->route('your-model.destroy'),
]);
Bulk Actions
Add bulk actions using the addBulkActions()
method:
$this->addBulkActions([
DeleteBulkAction::make()->permission('your-model.destroy'),
]);
Header Actions
Add header actions using the addHeaderAction()
method:
$this->addHeaderAction(CreateHeaderAction::make()->route('your-model.create'));
Bulk Changes
Bulk changes allow users to update multiple records at once. Add bulk changes using the addBulkChanges()
method:
$this->addBulkChanges([
NameBulkChange::make(),
StatusBulkChange::make(),
CreatedAtBulkChange::make(),
SelectBulkChange::make()
->name('category')
->title(trans('plugins/blog::posts.category'))
->searchable()
->choices(fn () => Category::query()->pluck('name', 'id')->all()),
]);
Available Bulk Change Types
Botble CMS provides several built-in bulk change types:
NameBulkChange
: For changing name fieldsStatusBulkChange
: For changing status fieldsCreatedAtBulkChange
: For changing creation datesUpdatedAtBulkChange
: For changing update datesSelectBulkChange
: For changing fields with predefined optionsTextBulkChange
: For changing text fieldsNumberBulkChange
: For changing numeric fieldsDateBulkChange
: For changing date fieldsEmailBulkChange
: For changing email fieldsIsFeaturedBulkChange
: For toggling featured status
Custom Bulk Change Handling
You can customize how bulk changes are processed using the onSavingBulkChangeItem
method:
$this->onSavingBulkChangeItem(function (Model $item, string $inputKey, ?string $inputValue) {
if ($inputKey === 'category') {
// Custom handling for category changes
$item->categories()->sync([$inputValue]);
return $item;
}
return null; // Let the default handler process other fields
});
Query Customization
Basic Query Customization
Use the queryUsing()
method to customize the query that fetches data for your table:
$this->queryUsing(function (Builder $query) {
return $query
->with(['relation1', 'relation2']) // Eager load relations
->select([
'id',
'name',
'created_at',
'status',
]);
});
Advanced Query Customization
For more advanced query customization, you can use the onAjax()
method:
$this->onAjax(function (self $table) {
return $table->toJson(
$table
->table
->eloquent($table->query())
->filter(function ($query) {
if ($keyword = $this->request->input('search.value')) {
$keyword = '%' . $keyword . '%';
return $query
->where('name', 'LIKE', $keyword)
->orWhereHas('relation', function ($subQuery) use ($keyword) {
return $subQuery->where('name', 'LIKE', $keyword);
});
}
return $query;
})
);
});
Custom Filtering
Use the onFilterQuery()
method to handle custom filtering:
$this->onFilterQuery(
function (
EloquentBuilder|QueryBuilder|EloquentRelation $query,
string $key,
string $operator,
?string $value
) {
if (!$value || $key !== 'custom_filter') {
return false;
}
return $query->whereHas(
'relation',
fn (BaseQueryBuilder $query) => $query->where('relation.field', $value)
);
}
);
Real-World Example
Here's a real-world example from the Blog plugin's PostTable:
class PostTable extends TableAbstract
{
public function setup(): void
{
$this->defaultSortColumnName = 'created_at';
$this
->model(Post::class)
->addHeaderAction(CreateHeaderAction::make()->route('posts.create'))
->addActions([
EditAction::make()->route('posts.edit'),
DeleteAction::make()->route('posts.destroy'),
])
->addColumns([
IdColumn::make(),
ImageColumn::make(),
NameColumn::make()->route('posts.edit'),
FormattedColumn::make('categories_name')
->title(trans('plugins/blog::posts.categories'))
->width(150)
->orderable(false)
->searchable(false)
->getValueUsing(function (FormattedColumn $column) {
$categories = $column
->getItem()
->categories
->sortBy('name')
->map(function (Category $category) {
return Html::link(route('categories.edit', $category->getKey()), $category->name, ['target' => '_blank']);
})
->all();
return implode(', ', $categories);
})
->withEmptyState(),
FormattedColumn::make('author_id')
->title(trans('plugins/blog::posts.author'))
->width(150)
->orderable(false)
->searchable(false)
->getValueUsing(function (FormattedColumn $column) {
return $column->getItem()->author_name;
})
->renderUsing(function (FormattedColumn $column) {
$url = $column->getItem()->author_url;
if (! $url) {
return null;
}
return Html::link($url, $column->getItem()->author_name, ['target' => '_blank']);
})
->withEmptyState(),
CreatedAtColumn::make(),
StatusColumn::make(),
])
->addBulkActions([
DeleteBulkAction::make()->permission('posts.destroy'),
])
->addBulkChanges([
NameBulkChange::make(),
StatusBulkChange::make(),
CreatedAtBulkChange::make(),
SelectBulkChange::make()
->name('category')
->title(trans('plugins/blog::posts.category'))
->searchable()
->choices(fn () => Category::query()->pluck('name', 'id')->all()),
IsFeaturedBulkChange::make(),
])
->queryUsing(function (Builder $query) {
return $query
->with([
'categories' => function (BelongsToMany $query): void {
$query->select(['categories.id', 'categories.name']);
},
'author',
])
->select([
'id',
'name',
'image',
'created_at',
'status',
'updated_at',
'author_id',
'author_type',
]);
});
}
}
Conclusion
The Table Builder in Botble CMS provides a powerful and flexible way to create and customize data tables. By leveraging the provided column types, actions, and query customization methods, you can create rich, interactive tables with minimal effort.
For more examples, look at the table implementations in the core plugins, such as the Blog, Page, and User plugins.