PHPackages                             rudiwer/rwtable-laravel - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Admin Panels](/categories/admin)
4. /
5. rudiwer/rwtable-laravel

ActiveLibrary[Admin Panels](/categories/admin)

rudiwer/rwtable-laravel
=======================

Reusable RWTable backend package for Laravel applications.

v0.9.5(3mo ago)03MITPHPPHP ^8.3CI passing

Since Mar 21Pushed 4w agoCompare

[ Source](https://github.com/RUDIWER/rwtable-laravel)[ Packagist](https://packagist.org/packages/rudiwer/rwtable-laravel)[ Docs](https://github.com/RUDIWER/rwtable-laravel)[ RSS](/packages/rudiwer-rwtable-laravel/feed)WikiDiscussions main Synced 3w ago

READMEChangelogDependencies (12)Versions (7)Used By (0)

rudiwer/rwtable-laravel
=======================

[](#rudiwerrwtable-laravel)

Reusable Laravel / Inertia backend package for the RWTable Vue 3 component

RWTable is a combined package consisting of a Vue 3 table component and a server-side Laravel / Inertia action class.

The table is specifically designed for use with Vue 3 / Inertia / Laravel. The styling is based on Tailwind CSS, and a Vuetify-styled version will be available soon.
The table itself can also be used independently of Inertia and Laravel, but Excel export and chart export currently still rely fully on Inertia.

The following features are available:

- Client- or server-side data handling
- Pagination (with configurable row counts) or endless scroll
- General search field
- Column sorting
- Config menu with adjustable table height and toggleable horizontal/vertical scrolling
- Column selection and reordering for table visibility
- Resizable column widths and column reordering
- Sticky (fixed) columns
- Per-column filtering with logical expressions
- Excel export
- Chart export (based on ECharts.js)
- Custom actions menu to add your own functionality
- Multi-language support according to Laravel standards
- Inline editing
- Column layouts with chips, icons, custom date formatting, select and autocomplete fields
- Client-side and/or server-side validation during editing
- Custom actions on column / cell click and more...

This package provides:

- table data processing action (`RwTableAction`) for Inertia pages,
- persisted chart configurations,
- persisted excel export configurations,
- route registration,
- translation namespace loading and publish support.

Monorepo split/release blueprint:

- `docs/rwtable-monorepo-release-blueprint.md`

Demo video
----------

[](#demo-video)

Table of Contents
-----------------

[](#table-of-contents)

1. [Requirements](#requirements)
2. [Installation](#installation)
3. [Configuration](#configuration)
4. [Routes](#routes)
5. [Request Contracts](#request-contracts)
6. [Controller Responses](#controller-responses)
7. [RwTableAction API](#rwtableaction-api)
8. [Server Mode Recipes (Managed vs Manual)](#server-mode-recipes-managed-vs-manual)
9. [Database Schema](#database-schema)
10. [Internationalization](#internationalization)
11. [Security Notes](#security-notes)
12. [Integration Example](#integration-example)
13. [Troubleshooting](#troubleshooting)

---

Requirements
------------

[](#requirements)

### Minimum supported versions (current package constraints)

[](#minimum-supported-versions-current-package-constraints)

LayerMinimumPHP`8.3`Laravel`13.0``inertiajs/inertia-laravel``2.0 (stable) or 3.0 beta`Notes:

- Laravel 10 is **not** supported by the current package constraints.
- Not yet tested in a project with laravel 11 / 12
- If your frontend uses RWTable Vue components, pair this package with Vue `3.4+`, `@inertiajs/vue3 2+`, and Tailwind CSS `3.2+` for intended styling.

From `composer.json`:

| Package | Version | | --------------------------- | ------- | --- | ---------- | | `php` | `^8.3` | | `illuminate/database` | `^13.0` | | `illuminate/http` | `^13.0` | | `illuminate/support` | `^13.0` | | `inertiajs/inertia-laravel` | `^2.0   |     | ^3.0@beta` |

---

Installation
------------

[](#installation)

### Quick Start (production install)

[](#quick-start-production-install)

```
composer require rudiwer/rwtable-laravel:^x.y
npm install @rudiwer/rwtable-vue@^x.y
php artisan vendor:publish --tag=rwtable-config --tag=rwtable-migrations --tag=rwtable-lang
php artisan migrate
```

Use matching major/minor versions for both packages (`x.y`).

Frontend-specific features such as the top-right toolbar 3-dot menu payload and date/datetime display formatting are documented in:

- `packages/rwtable-vue/README.md`

### Optional: local path install (maintainers)

[](#optional-local-path-install-maintainers)

Add a path repository in your app `composer.json`:

```
{
  "repositories": [
    {
      "type": "path",
      "url": "../packages/rwtable-laravel",
      "options": { "symlink": true }
    }
  ]
}
```

Then require the package from that local path:

```
composer require rudiwer/rwtable-laravel:*
```

Publish resources
-----------------

[](#publish-resources)

```
php artisan vendor:publish --tag=rwtable-config
php artisan vendor:publish --tag=rwtable-migrations
php artisan vendor:publish --tag=rwtable-lang
```

Run migrations:

```
php artisan migrate
```

---

Configuration
-------------

[](#configuration)

Published file: `config/rwtable.php`

```
return [
    'routes' => [
        'enabled' => true,
        'prefix' => 'admin',
        'name_prefix' => 'admin.',
        'middleware' => ['web', 'auth'],
    ],

    'field_aliases' => [
        // optional alias map for filter/sort safety
        // 'status_description' => 'statuses.description',
    ],

    'security' => [
        'allowed_field_pattern' => '/^[A-Za-z0-9_\.]+$/',
    ],
];
```

### Config keys

[](#config-keys)

KeyDescription`routes.enabled`Enables/disables package route loading`routes.prefix`URI prefix for package routes`routes.name_prefix`Route name prefix`routes.middleware`Middleware stack for package routes`field_aliases`Safe alias map used by `RwTableAction::resolveColumn()``security.allowed_field_pattern`Regex whitelist for user-supplied field namesPractical full config example:

```
return [
    'routes' => [
        'enabled' => true,
        'prefix' => 'admin',
        'name_prefix' => 'admin.',
        'middleware' => ['web', 'auth', 'verified'],
    ],
    'field_aliases' => [
        'status_label' => 'statuses.description',
        'priority_label' => 'priorities.description',
        'owner_name' => 'users.name',
    ],
    'security' => [
        'allowed_field_pattern' => '/^[A-Za-z0-9_\.]+$/',
    ],
];
```

---

Routes
------

[](#routes)

Routes are loaded from `routes/web.php` when `routes.enabled=true`.

MethodURINameController`GET``/rw-table-charts/{tableIdentifier}``rw-table-charts.index``RwTableChartController@index``POST``/rw-table-charts/{tableIdentifier}``rw-table-charts.store``RwTableChartController@store``DELETE``/rw-table-charts/{id}``rw-table-charts.destroy``RwTableChartController@destroy``GET``/rw-table-exports/{tableIdentifier}``rw-table-exports.index``RwTableExportController@index``POST``/rw-table-exports/{tableIdentifier}``rw-table-exports.store``RwTableExportController@store``DELETE``/rw-table-exports/{id}``rw-table-exports.delete``RwTableExportController@destroy``DELETE``/rw-table-exports/{id}/destroy``rw-table-exports.destroy``RwTableExportController@destroy`All routes are user-scoped (authenticated user only).

---

Request Contracts
-----------------

[](#request-contracts)

`StoreRwTableExportRequest`
---------------------------

[](#storerwtableexportrequest)

```
{
  "id": "nullable|integer|exists:rw_table_exports,id",
  "description": "required|string|max:255",
  "config": "required|array"
}
```

`StoreRwTableChartRequest`
--------------------------

[](#storerwtablechartrequest)

Core fields:

```
{
  "id": "nullable|integer|exists:rw_table_charts,id",
  "description": "required|string|max:255",
  "config": "required|array"
}
```

The chart request accepts both:

- builder-oriented keys (`config.builder.dataset.*`, `config.builder.chart.*`, `config.builder.presentation.*`),
- legacy keys (`config.xAxis`, `config.yAxis`, `config.seriesField`, `config.type`, etc.).

Allowed chart types:

- `bar`, `line`, `pie`, `doughnut`,
- `bar3d`, `line3d`,
- `bar3d_webgl`, `line3d_webgl`.

Practical chart payload (all common fields):

```
{
  "id": 12,
  "description": "Registrations by school year",
  "config": {
    "builder": {
      "dataset": {
        "x_field": "school_year",
        "metric_field": "amount",
        "aggregate": "sum",
        "series_field": "status",
        "limit": 25,
        "sort_direction": "desc"
      },
      "chart": {
        "type": "bar",
        "orientation": "vertical",
        "stacked": false,
        "show_legend": true
      },
      "presentation": {
        "allow_chart_type_change": true
      }
    },
    "xAxis": "school_year",
    "yAxis": "amount",
    "operation": "sum",
    "seriesField": "status",
    "series": ["todo", "in_progress", "done"],
    "type": "bar",
    "orientation": "vertical",
    "stacked": false,
    "showLegend": true,
    "allowViewerChartTypeChange": true,
    "limit": 25,
    "sortDirection": "desc"
  }
}
```

Practical export payload (all common fields):

```
{
  "id": 9,
  "description": "Active registrations export",
  "config": {
    "columns": [
      {
        "key": "id",
        "label": "ID",
        "selected": true,
        "width": 80
      },
      {
        "key": "name",
        "label": "Name",
        "selected": true,
        "width": 220
      },
      {
        "key": "status",
        "label": "Status",
        "selected": true,
        "width": 140
      },
      {
        "key": "created_at",
        "label": "Created at",
        "selected": false,
        "width": 180
      }
    ],
    "includeHeader": true,
    "fileName": "registrations-active"
  }
}
```

---

Controller Responses
--------------------

[](#controller-responses)

Charts
------

[](#charts)

```
// index
{ "charts": [ { "id": 1, "description": "...", "config": {...} } ] }

// store
{ "message": "...", "chart": { "id": 1, "description": "...", "config": {...} } }

// destroy
{ "message": "..." }
```

Exports
-------

[](#exports)

```
// index
{ "exports": [ { "id": 1, "description": "...", "config": [...] } ] }

// store
{ "message": "...", "export": { "id": 1, "description": "...", "config": [...] } }

// destroy
{ "message": "..." }
```

Validation failures return HTTP `422` with Laravel validation payload.

---

RwTableAction API
-----------------

[](#rwtableaction-api)

`RwTableAction` is the central reusable backend helper.

`handle(Request $request, string $modelClass, string $viewComponent, array $globalFields = ['id'], int $perPageDefault = 25, array $extraProps = [], ?callable $queryCallback = null): Inertia\Response`
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

[](#handlerequest-request-string-modelclass-string-viewcomponent-array-globalfields--id-int-perpagedefault--25-array-extraprops---callable-querycallback--null-inertiaresponse)

Supports:

- global search,
- typed filtering (`text`, `number`, `date`, `datetime`),
- filter modes (`=`, `!=`, `bevat`, `bevat niet`, `>`, ` $this->statusOptions()],
        function ($query): void {
            $query->where('school_id', auth()->user()->school_id);
        }
    );
}
```

Client side usually uses:

- `managed=true`
- `dataSource` (`axios` or `inertia`)
- optional infinite mode without extra parent merge logic.

### Recipe B: Manual mode backend (`serverSide=true`)

[](#recipe-b-manual-mode-backend-serversidetrue)

In this setup, parent frontend handles `@change` and calls your endpoint. Backend returns normalized pagination payload.

```
use App\Models\Task;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

public function data(Request $request): JsonResponse
{
    $query = Task::query();

    $global = trim((string) $request->input('global', ''));

    if ($global !== '') {
        $query->where(function ($builder) use ($global): void {
            $builder
                ->orWhere('title', 'like', "%{$global}%")
                ->orWhere('owner', 'like', "%{$global}%")
                ->orWhere('status', 'like', "%{$global}%");
        });
    }

    $sortField = (string) $request->input('sortField', 'id');
    $sortOrder = strtolower((string) $request->input('sortOrder', 'asc')) === 'desc' ? 'desc' : 'asc';
    $perPage = max(1, min(100, (int) $request->input('rowsPerPage', 25)));
    $page = max(1, (int) $request->input('page', 1));

    $paginated = $query
        ->orderBy($sortField, $sortOrder)
        ->paginate($perPage, ['*'], 'page', $page);

    return response()->json([
        'data' => $paginated->items(),
        'total' => $paginated->total(),
        'current_page' => $paginated->currentPage(),
        'last_page' => $paginated->lastPage(),
    ]);
}
```

Manual mode best-practice notes:

- Keep payload keys compatible with RWTable `paramMap`.
- For infinite scroll, frontend parent must append/merge rows when page increases.
- Backend should still return full pagination metadata (`total`, `current_page`, `last_page`).

---

Database Schema
---------------

[](#database-schema)

`rw_table_charts`
-----------------

[](#rw_table_charts)

- `id`
- `user_id` (nullable FK, `nullOnDelete`)
- `table_identifier` (indexed)
- `description`
- `config` (json, nullable)
- timestamps
- unique: `(user_id, table_identifier, description)`

`rw_table_exports`
------------------

[](#rw_table_exports)

- `id`
- `user_id` (nullable FK, `nullOnDelete`)
- `table_identifier` (indexed)
- `description`
- `config` (json)
- timestamps
- unique: `(user_id, table_identifier, description)`

---

Internationalization
--------------------

[](#internationalization)

Translations are loaded under namespace `rwtable`.

In service provider:

- `loadTranslationsFrom(__DIR__.'/../lang', 'rwtable')`

Published override path:

```
lang/vendor/rwtable/{locale}/rwtable.php

```

Shipped locales:

- `en`
- `nl`
- `fr`
- `de`

---

Security Notes
--------------

[](#security-notes)

Key protections built into the package:

- route-level auth middleware by default,
- user scoping for chart/export persistence,
- field-name regex whitelist via `allowed_field_pattern`,
- optional server alias map for safe resolved columns,
- validation type and rules enforcement in update/create actions,
- `firstOrFail` ownership checks on mutable resources.

Recommended:

- keep route middleware strict,
- always provide `editableFields` in `update/create` wrappers,
- avoid exposing unrestricted model attributes.

---

Integration Example
-------------------

[](#integration-example)

```
use App\Http\Controllers\Controller;
use App\Models\Task;
use Illuminate\Http\Request;
use Rwsoft\RwTableLaravel\Actions\RwTableAction;

class TaskController extends Controller
{
    public function index(Request $request)
    {
        return RwTableAction::handle(
            $request,
            Task::class,
            'Admin/Task/Index',
            ['id', 'title', 'status'],
            25,
            ['statuses' => []]
        );
    }

    public function inlineUpdate(Request $request, int $id)
    {
        return RwTableAction::update(
            $request,
            Task::class,
            $id,
            ['title', 'status', 'priority', 'tags']
        );
    }

    public function inlineCreate(Request $request)
    {
        return RwTableAction::create(
            $request,
            Task::class,
            ['title', 'status', 'priority', 'tags', 'index']
        );
    }

    public function inlineDelete(Request $request, int $id)
    {
        return RwTableAction::destroy($request, Task::class, $id);
    }
}
```

---

Troubleshooting
---------------

[](#troubleshooting)

Routes not available
--------------------

[](#routes-not-available)

- check `config/rwtable.php` -&gt; `routes.enabled`
- clear caches: `php artisan optimize:clear`

403 from chart/export endpoints
-------------------------------

[](#403-from-chartexport-endpoints)

- ensure user is authenticated
- confirm route middleware includes `auth`

422 during inline update/create
-------------------------------

[](#422-during-inline-updatecreate)

- check `validationType`
- ensure `validationRules` are passed for client validation
- ensure model has `rules($id)` for model validation path

SQL/column errors in filtering/sorting
--------------------------------------

[](#sqlcolumn-errors-in-filteringsorting)

- use `field_aliases` for derived/related fields
- ensure incoming fields satisfy `allowed_field_pattern`

###  Health Score

37

—

LowBetter than 81% of packages

Maintenance89

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

6

Last Release

90d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/f68354a2827853890902782bb7a502614e7082747a85acb6409ab6a7cad916fb?d=identicon)[rudiwer](/maintainers/rudiwer)

---

Top Contributors

[![RUDIWER](https://avatars.githubusercontent.com/u/10944491?v=4)](https://github.com/RUDIWER "RUDIWER (7 commits)")

---

Tags

laravelinertiadatatablerwtable

### Embed Badge

![Health badge](/badges/rudiwer-rwtable-laravel/health.svg)

```
[![Health](https://phpackages.com/badges/rudiwer-rwtable-laravel/health.svg)](https://phpackages.com/packages/rudiwer-rwtable-laravel)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.1M337](/packages/psalm-plugin-laravel)[larastan/larastan

Larastan - Discover bugs in your code without running it. A phpstan/phpstan extension for Laravel

6.4k51.0M7.6k](/packages/larastan-larastan)[api-platform/laravel

API Platform support for Laravel

59156.3k11](/packages/api-platform-laravel)[erag/laravel-lang-sync-inertia

A powerful Laravel package for syncing and managing language translations across backend and Inertia.js (Vue/React) frontends, offering effortless localization, auto-sync features, and smooth multi-language support for modern Laravel applications.

4821.5k](/packages/erag-laravel-lang-sync-inertia)[simplestats-io/laravel-client

Analytics for Laravel. Track visitors, registrations, and payments. Discover which channels actually drive revenue, not just traffic. Server-side, GDPR compliant, ad-blocker proof.

5019.3k](/packages/simplestats-io-laravel-client)[calebdw/larastan

Larastan - Discover bugs in your code without running it. A phpstan/phpstan extension for Laravel

15104.9k4](/packages/calebdw-larastan)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
