Skip to content

Table Builder ​

Introduction ​

The Table Builder is a powerful feature in Thesky9 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 Thesky9 CMS extend the Botble\Table\Abstracts\TableAbstract class. To create a table, you need to:

  1. Create a new class that extends TableAbstract
  2. Implement the setup() method to configure your table

Here's a basic example:

php
<?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:

php
$this->model(YourModel::class)

Default Sorting ​

You can set the default sorting column and direction:

php
$this->defaultSortColumnName = 'created_at';
$this->defaultSortDirection = 'desc';

Columns ​

Columns are the core components of your table. Thesky9 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:

php
$this->addColumns([
    IdColumn::make(),
    NameColumn::make()->route('your-model.edit'),
    CreatedAtColumn::make(),
    StatusColumn::make(),
]);

Available Column Types ​

Thesky9 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 customized
  • FormattedColumn: A customizable column that can display formatted data

Identification Columns ​

  • IdColumn: Displays the ID of the record
  • NameColumn: Displays the name of the record (usually linked to the edit page)

Date and Time Columns ​

  • CreatedAtColumn: Displays the creation date
  • UpdatedAtColumn: Displays the last update date
  • DateColumn: Displays a date with formatting options
  • DateTimeColumn: 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 styling
  • EnumColumn: Displays enum values with proper formatting
  • YesNoColumn: Displays boolean values as Yes/No
  • LinkableColumn: A column that can be linked to a route
  • EmailColumn: Displays an email address with optional mailto link
  • PhoneColumn: Displays a phone number with optional tel link

Action Columns ​

  • RowActionsColumn: Displays action buttons for each row
  • CheckboxColumn: Displays a checkbox for row selection

Column Usage Examples ​

Here are examples of how to use some of the most common column types:

IdColumn ​

php
IdColumn::make()
    ->title('Custom ID') // Optional: override default title
    ->width(50) // Optional: set column width

NameColumn ​

php
NameColumn::make()
    ->route('your-model.edit') // Link to edit page
    ->limit(30) // Limit text length

ImageColumn ​

php
ImageColumn::make()
    ->with(80) // Set image width
    ->mediaSize('thumb') // Set media size (thumb, medium, etc.)
    ->fullMediaSize() // Use full size image

DateColumn ​

php
DateColumn::make('created_at')
    ->dateFormat('Y-m-d') // Custom date format
    ->diffForHumans() // Show as "2 days ago"

StatusColumn ​

php
StatusColumn::make()
    ->title('Status')

EmailColumn ​

php
EmailColumn::make()
    ->title('Email Address')
    ->linkable() // Make email clickable as mailto link

PhoneColumn ​

php
PhoneColumn::make()
    ->title('Phone Number')
    ->linkable() // Make phone clickable as tel link

LinkableColumn ​

php
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 ​

php
FormattedColumn::make('categories_name')
    ->title('Categories')
    ->getValueUsing(function (FormattedColumn $column) {
        return $column->getItem()->categories->pluck('name')->implode(', ');
    })
    ->withEmptyState() // Show placeholder when empty

EnumColumn ​

php
EnumColumn::make('type')
    ->title('Type')

YesNoColumn ​

php
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 ​

php
$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 ​

php
$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 ​

php
$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 ​

php
$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:

php
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>';
    })

Column Traits and Features ​

Columns can be enhanced with additional traits that provide special functionality:

Copyable Trait ​

Makes column content copyable to clipboard with a single click.

php
FormattedColumn::make('api_key')
    ->title('API Key')
    ->copyable() // Enable copy functionality

Maskable Trait ​

Apply a mask/pattern to column content to hide sensitive information.

php
EmailColumn::make()
    ->title('Email')
    ->mask('***-**-####') // Mask pattern

Blurrable Trait ​

Blur sensitive content with a toggle to show/hide.

php
FormattedColumn::make('phone')
    ->title('Phone Number')
    ->blur() // Content will be blurred by default

These traits can be combined for enhanced column functionality:

php
FormattedColumn::make('sensitive_field')
    ->title('Sensitive Data')
    ->copyable()
    ->blur()
    ->withEmptyState('N/A')

Actions ​

Actions allow users to interact with the data in your table. There are three types of actions:

  1. Row Actions: Actions that apply to a single row (e.g., Edit, Delete)
  2. Bulk Actions: Actions that apply to multiple selected rows
  3. Header Actions: Actions that appear in the table header (e.g., Create New)

Row Actions ​

Add row actions using the addActions() method:

php
$this->addActions([
    EditAction::make()->route('your-model.edit'),
    DeleteAction::make()->route('your-model.destroy'),
]);

Bulk Actions ​

Add bulk actions using the addBulkActions() method:

php
$this->addBulkActions([
    DeleteBulkAction::make()->permission('your-model.destroy'),
]);

Header Actions ​

Add header actions using the addHeaderAction() method:

php
$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:

php
$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 ​

Thesky9 CMS provides several built-in bulk change types:

  • NameBulkChange: For changing name/title fields
  • StatusBulkChange: For changing status fields
  • CreatedAtBulkChange: For changing creation dates
  • DateBulkChange: For changing any date fields
  • SelectBulkChange: For changing fields with predefined options
  • TextBulkChange: For changing text fields
  • NumberBulkChange: For changing numeric fields
  • EmailBulkChange: For changing email fields
  • PhoneBulkChange: For changing phone number fields
  • IsFeaturedBulkChange: For toggling featured/highlighted status

Bulk Change Examples ​

php
// Name change
NameBulkChange::make()
    ->title(trans('core/base::tables.name'))

// Status change
StatusBulkChange::make()
    ->title(trans('core/base::tables.status'))

// Custom select change
SelectBulkChange::make()
    ->name('category')
    ->title(trans('plugins/blog::posts.category'))
    ->searchable()
    ->choices(fn () => Category::query()->pluck('name', 'id')->all())

// Date change
DateBulkChange::make()
    ->name('published_date')
    ->title(trans('plugins/blog::posts.published_date'))

// Featured toggle
IsFeaturedBulkChange::make()
    ->title(trans('core/base::tables.is_featured'))

Custom Bulk Change Handling ​

You can customize how bulk changes are processed using the onSavingBulkChangeItem method:

php
$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:

php
$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:

php
$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:

php
$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:

php
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 Thesky9 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.