Rapyd CRUD demo
Three pages, three files each: a Livewire component, a Blade view and a route. Every page shows its own source code underneath, so you can see exactly how little it takes.
No demo data yet. Populate the database
module structure
demo-module/
├─ Livewire/
│ ├─ Home.php
│ ├─ ArticlesTable.php
│ ├─ ArticlesView.php
│ └─ ArticlesEdit.php
├─ Views/
│ ├─ home.blade.php
│ ├─ articles_table.blade.php
│ ├─ articles_view.blade.php
│ ├─ articles_edit.blade.php
│ ├─ menu.blade.php
│ └─ frontend_menu.blade.php
├─ Models/ Article.php, Author.php
├─ Database/ Migrations/, Seeders/
├─ config.php layout, menu entry
├─ routes.php
└─ DemoModuleServiceProvider.php
route
routes.php
Route::get('demo', Home::class)
->middleware(['web'])
->name('demo')
->crumbs(fn ($crumbs) => $crumbs->push('Demo', route('demo')));
component
Livewire/Home.php
<?php
namespace App\Modules\Demo\Livewire;
use App\Modules\Demo\Database\Seeders\DemoSeeder;
use App\Modules\Demo\Models\Article;
use Illuminate\Support\Facades\Artisan;
use Livewire\Component;
class Home extends Component
{
public bool $db_filled = false;
public function mount(): void
{
$this->db_filled = Article::query()->exists();
}
public function populate()
{
// Re-populating an existing dataset can be disabled (config demo.repopulate);
// filling an empty database is always allowed.
if ($this->db_filled && ! config('demo.repopulate', true)) {
abort(403);
}
Artisan::call('db:seed', ['--class' => DemoSeeder::class, '--no-interaction' => true]);
session()->flash('message', 'Demo data (re)populated.');
return redirect()->to(route('demo'));
}
public function render()
{
return view('demo::home')->layout('layout::admin');
}
}
view
Views/home.blade.php
<x-rpd::card title="Rapyd CRUD demo">
@if(session('message'))
<div class="alert alert-success">{{ session('message') }}</div>
@endif
<p>
Three pages, three files each: a Livewire component, a Blade view and a route.
Every page shows its own source code underneath, so you can see exactly how little it takes.
</p>
@if($db_filled)
<p class="mb-3">
<x-rpd::button route="demo.articles" color="primary" label="Open the articles table" />
</p>
@if(config('demo.repopulate', true))
<p class="small text-muted mb-0">
Want a clean slate? <a href="#" wire:click.prevent="populate">Re-populate the demo data</a>
(replaces all authors and articles; on a shared demo disable it with <code>DEMO_REPOPULATE=false</code>).
</p>
@endif
@else
<p class="mb-0">
No demo data yet.
<a href="#" wire:click.prevent="populate" class="btn btn-outline-primary btn-sm">Populate the database</a>
</p>
@endif
</x-rpd::card>