evgeniy-silantev/laravel-table

Generate tables with Laravel.

Downloads

12

Stars

0

Version

1.2.9

Generate tables with Laravel

Source Code Latest Version Total Downloads License: MIT Build Status Coverage Status Quality Score

Laravel Table allows you to easily render tables in your views, directly built from PHP code.
This package is shipped with a pre-configuration for Bootstrap 4.* and FontAwesome 5.
However, the templates customization makes it very simple to use with another UI framework.

Compatibility

Laravel version PHP version Package version
^5.5 ^7.1 ^1.0

Usage

Prepare the table configuration somewhere in your code and pass it to the view :

$table = (new \Okipa\LaravelTable\Table)->model(\App\News::class)->routes([
    'index'   => ['name' => 'users.index'],
    'create'  => ['name' => 'user.create'],
    'edit'    => ['name' => 'user.edit'],
    'destroy' => ['name' => 'user.destroy'],
])->destroyConfirmationHtmlAttributes(function (User $user) {
    return [
        'data-confirm' => 'Are you sure you want to delete the user ' . $user->name . ' ?',
    ];
});
$table->column('first_name')->sortable(true)->searchable();
$table->column('last_name')->sortable()->searchable();
$table->column('email')->sortable()->searchable();

In your view, simply render your table like this :

{{ $table }}

Table of contents

Installation

  • Install the package with composer :
composer require "evgeniy-silantev/laravel-table:^1.0"

Configuration

Publish the package configuration and override the available config values :

php artisan vendor:publish --tag=laravel-table:config

Customize translations

To customize the existing translations, publish the packages translations files to make the wanted changes :

php artisan vendor:publish --tag=laravel-table:translations

Customize templates

Customize the used templates to make this package fit to your needs.
Publish the views with the command :

php artisan vendor:publish --tag=laravel-table:views

Table API

:warning: All the following methods are chainable with \Okipa\LaravelTable\Table object except the ->column() and the ->result() methods (returning respectively \Okipa\LaravelTable\Column and \Okipa\LaravelTable\Result objects).

->model()

Set the model used during the table generation.

Notes:

  • Signature : model(string $tableModel): \Okipa\LaravelTable\Table
  • Required

Use case example :

(new \Okipa\LaravelTable\Table)->model(\App\News::class);

->identifier()

Set the table identifier, in order to automatically generate its id and to customize all the interaction fields in case of multiple tables used on a single view : the interactions with the table like sorting, searching an more will only have an impact on the identified table.

Notes:

  • Signature : identifier(string $identifier): \Okipa\LaravelTable\Table
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->identifier('Your identifier');

->request()

Set the request used for the table generation.

Notes:

  • Signature : request(Request $request): \Okipa\LaravelTable\Table
  • Optional

Use case example :

// example in a controller
public function index(Request $request) {
    app(\Okipa\LaravelTable\\Okipa\LaravelTable\Table::class)->request($request);
    // ...
}

->routes()

Set the routes used during the table generation.
The routes declarations will be used for the following features :

  • index (required) : used for the rows number definition, sort and search features.
  • create (optional) : the create button is displayed if this route is declared. The button used this route to redirect to the model creation page.
  • edit (optional) : the edit button is displayed on each row if this route is declared. The route is used to redirect to the model edition page.
  • destroy (optional) : the destroy button is displayed on each row if this route is declared. The route is used to trigger the model destroy action.
  • show (optional) : the show button is displayed on each row if this route is declared. The route is used to redirect to the model show page.

Note :

  • Signature : routes(array $routes): \Okipa\LaravelTable\Table
  • Required
  • Each route have to be defined with the following structure :
// example
[
    'index' => [
        // required
        'name' => 'news.index',
        // optional
        'params' => [
            // set route params
            // or do not declare it
        ]
    ]
];
  • :warning: As the current model is always provided as a param to the edit, destroy and show routes, you do not have to define it in the ->routes() call. You also should declare your routes carefully to avoid errors. See the examples bellow :
    // assuming your declared your route with implicit binding :
    Route::get('parent/{$parent}/user/edit/{$user}/child/{$child}', 'UsersController@edit')->name('user.edit');
    // you'll have to declare your params with keys as following :
    (new Table)->model(User::class)->routes([
        // ...
        'edit'    => ['name'=> 'user.edit', 'params' => ['parent' => $parent, 'child' => $child]],
        // ...
    ])
    // because the route will be generated with the table related model as first param (the params order differs from the declaration) :
    route('user.edit, [$user, 'parent' => $parent, 'child' => $child]);
    // now imagine your route is declared with the table related model as first param like this :
    Route::get('/user/edit/{$user}/child/{$child}/{otherParam}', 'UsersController@edit')->name('user.edit');
    // in this case only, you will be able to declare your routes without keys :
    (new Table)->model(User::class)->routes([
        // ...
        'edit'    => ['name'=> 'user.edit', 'params' => [$child, 'otherValue']],
        // ...
    ])
    // because the route params are given in the same order as the route declaration :
    route('user.edit, [$user, $child, 'otherValue']);

Use case example :

(new \Okipa\LaravelTable\Table)->routes([
    'index' => ['name' => 'news.index'],
    'create' => ['name' => 'news.create', 'params' => ['param1' => 'value1']],
    'edit' => ['name' => 'news.edit', 'params' => ['param2' => 'value2']],
    'destroy' => ['name' => 'news.destroy'],
    'show' => ['name' => 'news.show'],
]);

->rowsNumber

Override the config default number of rows displayed on the table.
The default number of displayed rows is defined in the config('laravel-table.value.rowsNumber') config value.
Set false to display all the models contained in database.

Note :

  • Signature : rowsNumber(?int $rows): \Okipa\LaravelTable\Table
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->rowsNumber(50);
// or
(new \Okipa\LaravelTable\Table)->rowsNumber(null);

->rowsNumberSelectionActivation()

Override the default rows number selection activation status.
Calling this method displays a rows number input that enable the user to choose how much rows to show.
The default rows number selection activation status is managed by the config('laravel-table.value.rowsNumberSelectionActivation') value.

Note :`

  • Signature : rowsNumberSelectionActivation($activate = true): \Okipa\LaravelTable\Table
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->rowsNumberSelectionActivation(false);

->query()

Set the query closure that will be executed during the table generation.
For example, you can define your joined tables here.
The closure let you manipulate the following attribute : $query.

Note :

  • Signature : query(Closure $queryClosure): \Okipa\LaravelTable\Table
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->query(function($query){
    $query->select('users.*');
    $query->addSelect('companies.name as company');
    $query->join('users', 'users.id', '=', 'companies.owner_id');
});

->appends()

Add an array of arguments to append to the paginator and to the following table actions :

  • row number selection
  • searching
  • search canceling
  • sorting.

Note :

  • Signature : appends(array $appendedValues): \Okipa\LaravelTable\Table
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->appends(request()->only('status'));

->containerClasses()

Override default table container classes.
The default container classes are defined in the config('laravel-table.classes.container') config value.

Note :

  • Signature : containerClasses(array $containerClasses): \Okipa\LaravelTable\Table
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->containerClasses(['set', 'your', 'classes']);

->tableClasses()

Override default table classes.
The default table classes are defined in the config('laravel-table.classes.table') config value.

Note :

  • Signature : tableClasses(array $tableClasses): \Okipa\LaravelTable\Table
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->tableClasses(['set', 'your', 'classes']);

->trClasses()

Override default table tr classes.
The default tr classes are defined in the config('laravel-table.classes.tr') config value.

Note :

  • Signature : trClasses(array $trClasses): \Okipa\LaravelTable\Table
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->trClasses(['set', 'your', 'classes']);

->thClasses()

Override default table tr classes.
The default th classes are defined in the config('laravel-table.classes.th') config value.

Note :

  • Signature : thClasses(array $thClasses): \Okipa\LaravelTable\Table
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->thClasses(['set', 'your', 'classes']);

->tdClasses()

Override default table td classes.
The default td classes are defined in the config('laravel-table.classes.td') config value.

Note :

  • Signature : tdClasses(array $tdClasses): \Okipa\LaravelTable\Table
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->tdClasses(['set', 'your', 'classes']);

->rowsConditionalClasses()

Set rows classes when the given conditions are respected.
The closure let you manipulate the following attribute : $model. ` Note :

  • Signature : rowsConditionalClasses(Closure $rowClassesClosure, array $rowClasses): \Okipa\LaravelTable\Table
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->rowsConditionalClasses(function($model){
    return $model->hasParticularAttribute;
}, ['set', 'your', 'classes']);

->destroyConfirmationHtmlAttributes()

Define html attributes on the destroy buttons to handle dynamic javascript destroy confirmations.
The closure let you manipulate the following attribute : $model.
Beware : the management of the destroy confirmation is on you, if you do not setup a javascript treatment to ask a confirmation, the destroy action will be directly executed.

Note :

  • Signature : destroyConfirmationHtmlAttributes(Closure $destroyConfirmationClosure): \Okipa\LaravelTable\Table
  • Optional (but strongly recommended !)

Use case example :

(new \Okipa\LaravelTable\Table)->destroyHtmlAttributes(function($model){
    return ['data-confirm' => __('Are you sure you want to delete the user :name ?', [
        'name' => $model->name
    ])];
});

Javascript snippet example :

// example of javascript snippet to ask a confirmation before executing the action
// this example assume that a bootstrap modal component has been included in your view
// https://getbootstrap.com/docs/4.3/components/modal/#modal-components
const destroyButton = $('form.destroy button[type="submit"]');
destroyButton.click((e) => {
  e.preventDefault();
  const $this = $(e.target);
  const message = $this.data("confirm");
  const confirmationModal = $("#confirmationModal");
  confirmationModal.find(".modal-body").text(message);
  confirmationModal.modal("show");
});

->disableRows()

Set the disable lines closure that will be executed during the table generation.
The optional second param let you override the classes that will be applied for the disabled lines.
By default, the « config('laravel-table.classes.disabled') » config value is applied.
For example, you can disable the current logged user to prevent him being edited or deleted from the table.
The closure let you manipulate the following attribute : $model.

Note :

  • Signature : disableRows(Closure $rowDisableClosure, array $classes = []): \Okipa\LaravelTable\Table
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->disableRows(function($user){
    return $user->id = auth()->id;
}, ['bg-danger', 'text-primary']);

->tableTemplate()

Set a custom template path for the table component.
The default table template path is defined in the config('laravel-table.template.table') config value.

Note :

  • Signature : tableTemplate(string $tableComponentPath): \Okipa\LaravelTable\Table
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->tableTemplate('tailwindCss.table');

->theadTemplate()

Set a custom template path for the thead component.
The default thead template path is defined in the config('laravel-table.template.thead') config value.

Note :

  • Signature : theadTemplate(string $theadComponentPath): \Okipa\LaravelTable\Table
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->theadTemplate('tailwindCss.thead');

->tbodyTemplate()

Set a custom template path for the tbody component.
The default tbody template path is defined in the config('laravel-table.template.tbody') config value.

Note :

  • Signature : tbodyTemplate(string $tbodyComponentPath): \Okipa\LaravelTable\Table
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->tbodyTemplate('tailwindCss.tbody');

->resultsTemplate()

Set a custom template path for the results component.
The default results template path is defined in the config('laravel-table.template.results') config value.

Note :

  • Signature : resultsTemplate(string $resultsComponentPath): \Okipa\LaravelTable\Table
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->resultsComponentPath('tailwindCss.results');

->tfootTemplate()

Set a custom template path for the tfoot component.
The default tfoot template path is defined in the config('laravel-table.template.tfoot') config value.

Note :

  • Signature : tfootTemplate(string $tfootComponentPath): \Okipa\LaravelTable\Table
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->tfootTemplate('tailwindCss.tfoot');

->column()

Add a column that will be displayed in the table.
The column key is optional if the column is not declared as sortable or searchable.

Note :

  • Signature : column(string $databaseColumn = null): \Okipa\LaravelTable\Column
  • Required
  • **Warning : ** this method should not be chained with the other \Okipa\LaravelTable\Table methods because it returns a \Okipa\LaravelTable\Column object. See the use case examples to check how to use this method.

Use case example :

(new \Okipa\LaravelTable\Table)->column('email');

->result()

Add a result row that will be displayed at the bottom of the table.

Note :

  • Signature : result(): Result
  • Optional
  • **Warning : ** this method should not be chained with the other \Okipa\LaravelTable\Table methods because it returns a \Okipa\LaravelTable\Result object. See the use case examples to check how to use this method.

Use case example :

(new \Okipa\LaravelTable\Table)->result();

Column API

:warning: All the column methods are chainable with \Okipa\LaravelTable\Column object.

->classes()

Set the custom classes that will be applied on this column only.

Note :

  • Signature : classes(array $classes): \Okipa\LaravelTable\Column
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->column()->classes(['font-weight-bold']);

->title()

Set the column title or override the default (__('validation.attributes.[column key])) title generated from the column name.

Note :

  • Signature : title(string $title = null): \Okipa\LaravelTable\Column
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->column()->title('E-mail');

->sortable()

Make the column sortable.
You also can choose to set the column sorted by default.
If no column is sorted by default, the first one will be automatically sorted.

Note :

  • Signature : sortable(bool $sortByDefault = false, $sortDirection = 'asc'): \Okipa\LaravelTable\Column
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->column('email')->sortable();
// alternative
(new \Okipa\LaravelTable\Table)->column('email')->sortable(true, 'desc');

->searchable()

Make the column searchable.
The first param allows you to precise the searched database table (can references a database table alias).
The second param allows you to precise the searched database attributes (if not precised, the table database column is searched).

Note :

  • Signature : public function searchable(string $databaseSearchedTable = null, array $databaseSearchedColumns = []): \Okipa\LaravelTable\Column
  • Optional

Use case example :

// example 1
(new \Okipa\LaravelTable\Table)->column('email')->searchable();
// example 2
$table = (new \Okipa\LaravelTable\Table)->model(\App\User::class)->query(function($query) {
    $query->select('users.*');
    $query->addSelect('companies.name as company');
    $query->join('companies', 'companies.owner_id', '=', 'users.id');
});
$table->column('company')->searchable('companies', ['name']);
// example 3
$table = (new \Okipa\LaravelTable\Table)->model(\App\User::class)->query(function($query) {
    $query->select('users.*');
    $query->addSelect(\DB::raw('CONCAT(companies.name, " ", companies.activity) as company'));
    $query->join('companies as companiesAliasedTable', 'companies.owner_id', '=', 'users.id');
});
$table->column('company')->searchable('companiesAliasedTable', ['name', 'activity']);

->dateTimeFormat()

Set the format for a datetime, date or time database column (optional).
(Carbon::parse($value)->format($format) method is used under the hood).

Note :

  • Signature : dateTimeFormat(string $dateTimeFormat): \Okipa\LaravelTable\Column
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->column('created_at')->dateTimeFormat('d/m/Y H:i');

->button()

Display the column as a button with the given classes.

Note :

  • Signature : button(array $buttonClasses = []): \Okipa\LaravelTable\Column
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->column('email')->button(['btn', 'btn-sm', 'btn-primary']);

Wrap the column value into a <a></a> component.
You can declare the link as a string or as a closure which will let you manipulate the following attributes : $model, $column.
If no url is declared, it will be set with the column value.

Note :

  • Signature : link($url = null): \Okipa\LaravelTable\Column
  • Optional

Use case example :

// example 1
(new \Okipa\LaravelTable\Table)->column('url')->link();
// example 2
(new \Okipa\LaravelTable\Table)->column()->link(route('news.index'));
// example 3
(new \Okipa\LaravelTable\Table)->column()->link(function($news) {
    return route('news.show', $news);
});

->icon()

Add an icon before the displayed value.
Set the second param as true if you want the icon to be displayed even if the column has no value.

Note :

  • Signature : icon(string $icon, bool $displaydisplayIconWhenNoValue = false): \Okipa\LaravelTable\Column
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->column('email')->icon('<i class="fas fa-envelope"></i>', true);

->stringLimit()

Set the string value display limitation.
Shows "..." when the limit is reached.

Note :

  • Signature : stringLimit(int $stringLimit): \Okipa\LaravelTable\Column
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->column('email')->stringLimit(30);

->value()

Display a custom value for the column.
The closure let you manipulate the following attributes : $model, $column.

Note :

  • Signature : value(Closure $valueClosure): \Okipa\LaravelTable\Column
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->column()->value(function($user) {
    return config('users.type.' . $user->type_id);
});

->html()

Display a custom HTML for the column.
The closure let you manipulate the following attributes : $model, $column.

Note :

  • Signature : html(Closure $htmlClosure): \Okipa\LaravelTable\Column
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->column()->html(function($user) {
    return '<div>' . $user->first_name . '</div>';
});

Result API

:warning: All the result methods are chainable with \Okipa\LaravelTable\Result object.

->title()

Set the result row title.

Note :

  • Signature : title(string $title): \Okipa\LaravelTable\Result
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->result()->title('Turnover total');

->html()

Display a HTML output for the result row.
The closure let you manipulate the following attributes : $displayedList.

Note :

  • Signature : html(Closure $htmlClosure): \Okipa\LaravelTable\Result
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->result()->html(function($displayedList) {
    return $displayedList->sum('turnover');
});

->classes()

Override the default results classes and apply the given classes only on this result row.
The default result classes are managed by the config('laravel-table.classes.results') value.

Note :

  • Signature : classes(array $classes): \Okipa\LaravelTable\Result
  • Optional

Use case example :

(new \Okipa\LaravelTable\Table)->result()->classes(['bg-dark', 'text-white', 'font-weight-bold']);

Tips

  • Request : No need to transmit the request to the table : it systematically uses the current request given by the request() helper to get the number of lines to show and the searching, sorting or pagination data. However, if you need to pass a particular request to the table, you can do it with the ->request() method.
  • Column titles : By default, the table columns titles take the following value : __('validation.attributes.[databaseColumn]). You can set a custom title using the title() method.
  • Columns displaying combination : The following table column methods can be combined to display a result as wished. If you can't get the wanted result, you should use the ->html() method to build a custom display.
    • ->button()
    • ->link()
    • ->icon()
    • ->stringLimit()
    • ->value()

Usage examples

Basic

In your controller, simply call the package like the following example to generate your table :

$table = (new \Okipa\LaravelTable\Table)->model(\App\News::class)->routes(['index' => ['name' => 'news.index']]);
$table->column('title')->sortable()->searchable();

Then, send your $table object in your view and render your table like this :

{{ $table }}

That's it !

Advanced

If you need your table for a more advanced usage, with a multilingual project for example, here is an example of what you can do in your controller :

$table = (new \Okipa\LaravelTable\Table)->model(\App\News::class)
    ->request($request)
    ->routes([
        'index'      => ['name' => 'news.index'],
        'create'     => ['name' => 'news.create'],
        'edit'       => ['name' => 'news.edit'],
        'destroy'    => ['name' => 'news.destroy'],
        'show'    => ['name' => 'news.show'],
    ])
    ->rowsNumber(50) // or set `false` to get all the items contained in database
    ->rowsNumberSelectionActivation(false)
    ->query(function ($query) use ($category_id) {
        // some examples of what you can do
        $query->select('news.*');
        // add a constraint
        $query->where('category_id', $category_id);
        // get value stored in a json field
        $query->addSelect('news.json_field->>json_attribute as json_attribute');
        // get a formatted value form a pivot table
        $query->selectRaw('count(comments.id) as comments_count');
        $query->leftJoin('news_commment', 'news_commment.news_id', '=', 'news.id');
        $query->leftJoin('comments', 'comments.id', '=', 'news_commment.comment_id');
        $query->groupBy('comments.id');
        // alias a value to make it available from the column model
        $query->addSelect('users.name as author');
        $query->join('users', 'users.id', '=', 'news.author_id');
    })
    ->disableRows(function($model){
        return $model->id === 1 || $model->id === 2;
    }, ['disabled', 'bg-secondary'])
    ->rowsConditionalClasses(function($model){
        return $model->id === 3;
    }, ['highlighted', 'bg-success']);
$table->column('image')->html(function ($model, $column) {
    return $model->{$column->databaseDefaultColumn}
        ? '<img src="' . $model->{$column->databaseDefaultColumn} . '" alt="' .  $model->title . '">'
        : null;
});
$table->column('title')->sortable()->searchable();
$table->column('content')->stringLimit(30);
$table->column('author')->sortable()->searchable('user', ['name']);
$table->column('category_id')
    ->title('Category custom name')
    ->icon('your-icon')
    ->button(['btn', 'btn-sm', 'btn-outline-primary'])
    ->value(function ($model, $column) {
        return config('news.category.' . $model->{$column->databaseDefaultColumn});
    });
$table->column()->link(function($model){
    return route('news.show', $model);
})->button(['btn', 'btn-sm', 'btn-primary']);
$table->column('released_at')->sortable()->dateTimeFormat('d/m/Y H:i:s');
$table->result()->title('Total of comments')->html(function($displayedList){
    return $displayedList->sum('comments_count');
});

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Credits

License

The MIT License (MIT). Please see License File for more information.

EvgeniySilantev

Author

EvgeniySilantev