PHP code example of toolbelt / inertia-table
1. Go to this page and download the library: Download toolbelt/inertia-table library . Choose the download type require .
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
toolbelt / inertia-table example snippets
// config/inertia-table.php
return [
'per_page' => 25,
'per_page_options' => [10, 25, 50, 100],
'debounce' => 300,
'action_path' => '_inertia-table/actions',
'export_path' => '_inertia-table/exports',
'relationship_sorter' => \Musing\InertiaTable\Sorters\PowerJoinsRelationshipSorter::class,
'queue' => [
'connection' => null,
'queue' => null,
'delay' => 0,
'disk' => 'local',
'path' => 'table-exports',
'expires_after' => 604800,
],
'view_path' => '_inertia-table/views',
'views' => ['table' => 'table_views'],
];
namespace App\Tables;
use App\Models\Topic;
use Illuminate\Database\Eloquent\Builder;
use Musing\InertiaTable\Actions\Action;
use Musing\InertiaTable\Columns\BadgeColumn;
use Musing\InertiaTable\Columns\NumberColumn;
use Musing\InertiaTable\Columns\TextColumn;
use Musing\InertiaTable\Filters\SetFilter;
use Musing\InertiaTable\Table;
use Musing\InertiaTable\Variant;
final class TopicsTable extends Table
{
protected ?string $defaultSort = 'name';
// Optional: override the global per_page / per_page_options config for this table only.
protected ?int $perPage = 50;
protected ?array $perPageOptions = [25, 50, 100];
public function query(): Builder
{
return Topic::query()->withCount('quotes');
}
public function columns(): array
{
return [
TextColumn::make('name', 'Name')->searchable()->sortable(),
NumberColumn::make('quotes_count', 'Quotes')->sortable(),
BadgeColumn::make('is_featured', 'Featured')
->mapAs(fn (bool $value) => $value ? 'Featured' : 'Normal')
->variant(fn (bool $value) => $value ? Variant::Success : Variant::Default),
];
}
public function filters(): array
{
return [
SetFilter::make('status', 'Status')->options([
'published' => 'Published',
'draft' => 'Draft',
]),
];
}
public function actions(): array
{
return [
Action::make('edit', 'Edit')
->row()
->icon('Pencil')
->hideLabel()
->tooltip('Edit topic')
->endpoint('get', fn (Topic $topic) => route('topics.edit', $topic)),
];
}
}
return inertia('Admin/Topics/Index', [
'topics' => TopicsTable::make()
->reloadProps(['featuredCount']),
]);
use App\Models\Topic;
use Musing\InertiaTable\Columns\TextColumn;
use Musing\InertiaTable\Filters\BooleanFilter;
use Musing\InertiaTable\Table;
return inertia('Admin/Topics/Index', [
'topics' => Table::build(
resource: Topic::query()->where('archived', false),
columns: [
TextColumn::make('name')->searchable()->sortable(),
],
filters: [
BooleanFilter::make('is_featured', 'Featured'),
],
name: 'topics',
defaultSort: 'name',
perPageOptions: [25, 50, 100],
defaultPerPage: 25,
transformModelUsing: fn (Topic $topic) => [
...$topic->toArray(),
'display_name' => str($topic->name)->headline()->toString(),
],
),
]);
TextColumn::make('status')
->sortable()
->mapAs(['pending' => 'Pending', 'approved' => 'Approved'])
->sortUsingMap();
TextColumn::make('priority')
->sortable()
->sortUsingPriority(['urgent', 'normal', 'low']);
TextColumn::make('description')
->wrap()
->truncate(2)
->cellClass('max-w-md');
DateTimeColumn::make('published_at', 'Published')
->format('d/m/Y H:i')
->centerAligned();
ActionColumn::new()->asDropdown();
final class TopicsTable extends Table
{
protected ?bool $stickyHeader = true;
}
TopicsTable::make()->stickyHeader();
public function columns(): array
{
return [
NumberColumn::make('id')->sticky(),
TextColumn::make('name')->stickable(),
TextColumn::make('email')->stickable(),
ActionColumn::new()->sticky(),
];
}
TextColumn::make('score')->sortable()->sortUsing(
fn (Builder $query, SortDirection $direction) =>
$query->orderBy('score', $direction->value),
);
BadgeColumn::make('status')
->mapAs(['active' => 'Active', 'blocked' => 'Blocked'])
->variant(['active' => Variant::Success, 'blocked' => Variant::Danger])
->icon(['active' => 'CheckCircle', 'blocked' => 'XCircle']);
TextColumn::make('name')->image('avatar_url', fn (Image $image) => $image
->rounded()
->large()
->alt('User avatar'));
TextColumn::make('name')->url(
fn (Topic $topic, Url $url) => $url
->route('topics.edit', $topic)
->openInNewTab(),
);
use Musing\InertiaTable\EmptyState;
use Musing\InertiaTable\Url;
use Musing\InertiaTable\Variant;
public function emptyState(): ?EmptyState
{
return EmptyState::make('No topics yet', 'Create the first topic.')
->dataAttributes(['kind' => 'topics'])
->action(
label: 'Create topic',
url: fn (Url $url) => $url->route('topics.create'),
variant: Variant::Info,
icon: 'Plus',
);
}
public function dataAttributesForModel(Model $model, array $data): array
{
return [
'record-id' => $model->getKey(),
'status' => $data['status_label'],
];
}
protected array|string|null $search = ['name', 'email'];
// Explicitly disable global search, even if a column is searchable.
protected array|string|null $search = [];
TextFilter::make('name', 'Name')->clauses([
'contains', 'starts_with', 'equals', 'not_equals',
]);
SetFilter::make('category_id', 'Category')->options(
Category::query()->orderBy('name')->pluck('name', 'id')->all(),
);
DateFilter::make('created_at', 'Created at');
SetFilter::make('status')->options([
'empty' => 'Without quotes',
'featured' => 'Featured',
])->applyUsing(function (Builder $query, string|array $value, string $clause) {
$values = (array) $value;
if ($clause === 'equals' && $values[0] === 'empty') {
$query->doesntHave('quotes');
}
});
public function columns(): array
{
return [
TextColumn::make('author.name', 'Author')->searchable()->sortable(),
TextColumn::make('author.company.name', 'Company')->searchable(),
NumberColumn::make('comments.score', 'Comment score')->sortable(),
];
}
public function filters(): array
{
return [
TextFilter::make('author.company.name', 'Company'),
NumericFilter::make('comments.score', 'Comment score'),
];
}
use Spatie\QueryBuilder\QueryBuilder;
protected function withQueryBuilder(QueryBuilder $query): QueryBuilder
{
$query->where('topics.tenant_id', tenant()->id);
return $query;
}
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Musing\InertiaTable\Selection;
Action::make('delete', 'Delete')
->row()
->destructive()
->icon('Trash2')
->hideLabel()
->tooltip('Delete topic')
->authorized(fn (Topic $topic) => auth()->user()->can('delete', $topic))
->handle(fn (Topic $topic) => $topic->delete())
->confirm('Delete topic?', 'This cannot be undone.', 'Delete', 'Cancel');
Action::make('archive', 'Archive')
->bulk()
->authorize(fn (Request $request) => $request->user()->can('update', Topic::class))
->before(fn (Selection $selection) => Log::info('Archiving topics', [
'count' => $selection->count(),
]))
->handleSelection(fn (Selection $selection) => $selection
->query()
->update(['archived_at' => now()]))
->after(fn () => session()->flash('success', 'Topics archived'));
public function selectableQuery(Builder $query): Builder
{
return $query->whereNull('locked_at');
}
public function isSelectable(Model $model): bool
{
return $model->locked_at === null;
}
Action::make('edit')
->row()
->endpoint('get', fn (Topic $topic) => route('topics.edit', $topic));
Action::make('delete', 'Delete')
->bulk()
->destructive()
->confirm(
'Delete :count selected topics?',
'You selected :count matching topics to move to trash.',
'Delete :count',
);
->confirm(
[
'Delete :count topic?',
'Delete :count topics?',
'Delete all :count matching topics?',
],
[
'This topic will be deleted.',
':count topics will be deleted.',
'All :count matching topics will be deleted.',
],
'Delete :count',
);
use Illuminate\Http\Request;
use Musing\InertiaTable\Exports\Export;
public function exports(): array
{
return [
Export::make('all', 'All topics'),
Export::make('filtered', 'Filtered topics')->filtered(),
Export::make('selected', 'Selected topics')->selected(),
Export::make('excel', 'Excel', type: 'xlsx')
->filtered()
->authorize(fn (Request $request) => $request->user()->can('export')),
];
}
TextColumn::make('reference')
->exportAs(fn (string $value, Topic $topic) => "#{$value}");
TextColumn::make('internal_notes')->dontExport();
NumberColumn::make('amount')
->exportFormat('#,##0.00')
->exportMeta(['style' => ['font' => ['bold' => true]]]);
use Illuminate\Support\Facades\Storage;
use Musing\InertiaTable\Exports\QueuedExportSnapshot;
Export::make('archive', 'Export archive')
->filtered()
->queue(
connection: 'redis',
queue: 'exports',
delay: 5,
disk: 's3',
expiresAfter: 86_400,
)
->redirectAfterDispatch('/exports')
->deliveryUrlUsing(
fn (QueuedExportSnapshot $snapshot) => Storage::disk($snapshot->disk)
->temporaryUrl($snapshot->path, now()->addHour()),
)
->onReady(fn (QueuedExportSnapshot $snapshot, ?string $url) => /* notify */ null)
->onFailure(fn (QueuedExportSnapshot $snapshot, \Throwable $exception) => /* report */ null);
NumericFilter::make('source_id', 'Source')->withoutClause();
use Musing\InertiaTable\Views;
public function views(): ?Views
{
return Views::make();
}
public function views(): ?Views
{
return Views::make()
->' => tenant()->id]);
}
bash
php artisan vendor:publish --tag=inertia-table-config
bash
php artisan vendor:publish --tag=inertia-table-migrations
php artisan migrate
bash
php artisan vendor:publish --tag=inertia-table-translations