LivewireでJetStream認証のCRUD

livewire-JetStreamプロジェクト作成
composer create-project laravel/laravel livewire-jetstream
Jetstreamのインストール
composer require laravel/jetstream
livewireのインストール
php artisan jetstream:install livewire
node js packageのインストールと起動
npm install && npm run dev
Migrationの作成
php artisan make:migration create_products_table
edit: database/migrations
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('products', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->text('detail');
            $table->timestamps();
        });
    }
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('products');
    }
};
データベースの作成
php artisan migrate
Product Modelの作成
php artisan make:model Product
edit: App/Models/Product.php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
    use HasFactory;
    /**
     * Write code on Method
     *
     * @return response()
     */
    protected $fillable = [
        'name', 'detail'
    ];
}
Product Componentの作成
php artisan make:livewire products
コンポーネントとブレードの2種作成される
app/Http/Livewire/Products.php
resources/views/livewire/products.blade.php
edit: app/Http/Livewire/Products.php
namespace App\Http\Livewire;
use Livewire\Component;
use App\Models\Product;
class Products extends Component
{
    public $products, $name, $detail, $product_id;
    public $isOpen = 0;
    /**
     * The attributes that are mass assignable.
     *
     * @var array
    */
    public function render()
    {
        $this->products = Product::all();
        return view('livewire.products');
    }
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    public function create()
    {
        $this->resetInputFields();
        $this->openModal();
    }
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    public function openModal()
    {
        $this->isOpen = true;
    }
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    public function closeModal()
    {
        $this->isOpen = false;
    }
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    private function resetInputFields(){
        $this->name = '';
        $this->detail = '';
        $this->product_id = '';
    }
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    public function store()
    {
        $this->validate([
            'name' => 'required',
            'detail' => 'required',
        ]);
   
        Product::updateOrCreate(['id' => $this->product_id], [
            'name' => $this->name,
            'detail' => $this->detail
        ]);
  
        session()->flash('message', 
            $this->product_id ? 'Product Updated Successfully.' : 'Product Created Successfully.');
  
        $this->closeModal();
        $this->resetInputFields();
    }
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    public function edit($id)
    {
        $product = Product::findOrFail($id);
        $this->product_id = $id;
        $this->name = $product->name;
        $this->detail = $product->detail;
    
        $this->openModal();
    }
     /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    public function delete($id)
    {
        Product::find($id)->delete();
        session()->flash('message', 'Product Deleted Successfully.');
    }
}
edit: resources/views/livewire/products.blade.php
<x-slot name="header">
 <h2 class="font-semibold text-xl text-gray-800 leading-tight text-center">
  Laravel 9 JetStream Livewire CRUD Operations Tutorial - LaravelTuts.com
 </h2>
</x-slot>
<div class="py-12">
 <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
  <div class="bg-white overflow-hidden shadow-xl sm:rounded-lg px-4 py-4">
   @if (session()->has('message'))
    <div class="bg-teal-100 border-t-4 border-teal-500 rounded-b text-teal-900 px-4 py-3 shadow-md my-3" role="alert">
     <div class="flex">
      <div>
       <p class="text-sm">{{ session('message') }}</p>
      </div>
     </div>
    </div>
   @endif
   <button wire:click="create()" class="bg-blue-500 hover:bg-blue-700 text-white py-1 mb-6 px-3 rounded my-3 mt-1">Create New Product</button>
   @if($isOpen)
    @include('livewire.create')
   @endif
   <table class="table-fixed w-full">
    <thead>
     <tr class="bg-gray-100">
      <th class="px-4 py-2 w-20">No.</th>
      <th class="px-4 py-2">Title</th>
      <th class="px-4 py-2">Body</th>
      <th class="px-4 py-2 w-60">Action</th>
     </tr>
    </thead>
    <tbody>
     @foreach($products as $product)
     <tr>
      <td class="border px-4 py-2">{{ $product->id }}</td>
      <td class="border px-4 py-2">{{ $product->name }}</td>
      <td class="border px-4 py-2">{{ $product->detail }}</td>
      <td class="border px-4 py-2 text-center">
      <button wire:click="edit({{ $product->id }})" class="bg-blue-500 hover:bg-blue-700 text-white py-1 px-3 rounded">Edit</button>
      <button wire:click="delete({{ $product->id }})" class="bg-red-500 hover:bg-red-700 text-white py-1 px-3 rounded">Delete</button>
      </td>
     </tr>
     @endforeach
    </tbody>
   </table>
  </div>
 </div>
</div>
edit: resources/views/livewire/create.blade.php
<div class="fixed z-10 inset-0 overflow-y-auto ease-out duration-400">
 <div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
  <div class="fixed inset-0 transition-opacity">
   <div class="absolute inset-0 bg-gray-500 opacity-75"></div>
  </div>
  <!-- This element is to trick the browser into centering the modal contents. -->
  <span class="hidden sm:inline-block sm:align-middle sm:h-screen"></span>
  <div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" role="dialog" aria-modal="true" aria-labelledby="modal-headline">
   <form>
    <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
     <div class="">
      <div class="mb-4">
       <label for="exampleFormControlInput1" class="block text-gray-700 text-sm font-bold mb-2">Name:</label>
       <input type="text" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" id="exampleFormControlInput1" placeholder="Enter Name" wire:model="name">
       @error('name') <span class="text-red-500">{{ $message }}</span>@enderror
      </div>
      <div class="mb-4">
       <label for="exampleFormControlInput2" class="block text-gray-700 text-sm font-bold mb-2">Detail:</label>
       <textarea class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" id="exampleFormControlInput2" wire:model="detail" placeholder="Enter Detail"></textarea>
       @error('detail') <span class="text-red-500">{{ $message }}</span>@enderror
      </div>
     </div>
    </div>
    <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
     <span class="flex w-full rounded-md shadow-sm sm:ml-3 sm:w-auto">
     <button wire:click.prevent="store()" type="button" class="inline-flex justify-center w-full rounded-md border border-transparent px-4 py-2 bg-green-600 text-base leading-6 font-medium text-white shadow-sm hover:bg-green-500 focus:outline-none focus:border-green-700 focus:shadow-outline-green transition ease-in-out duration-150 sm:text-sm sm:leading-5">
     Save
     </button>
     </span>
     <span class="mt-3 flex w-full rounded-md shadow-sm sm:mt-0 sm:w-auto">
     <button wire:click="closeModal()" type="button" class="inline-flex justify-center w-full rounded-md border border-gray-300 px-4 py-2 bg-white text-base leading-6 font-medium text-gray-700 shadow-sm hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue transition ease-in-out duration-150 sm:text-sm sm:leading-5">
     Cancel
     </button>
     </span>
    </form>
   </div>
  </div>
 </div>
</div>
edit: resources/views/layouts/app.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <meta name="csrf-token" content="{{ csrf_token() }}">
 <title>{{ config('app.name', 'Laravel') }}</title>
 <!-- Fonts -->
 <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap">
 <!-- Styles -->
 <script src="https://cdn.tailwindcss.com/?plugins=forms"></script>
 @livewireStyles
 <!-- Scripts -->
  @vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body class="font-sans antialiased">
 <x-jet-banner />
 <div class="min-h-screen bg-gray-100">
  @livewire('navigation-menu')
  <!-- Page Heading -->
  @if (isset($header))
  <header class="bg-white shadow">
   <div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
    {{ $header }}
   </div>
  </header>
  @endif
  <!-- Page Content -->
  <main>
   {{ $slot }}
  </main>
 </div>
 @stack('modals')
 @livewireScripts
</body>
</html>
edit: routes/web.php
<?php
 use Illuminate\Support\Facades\Route;
 use App\Http\Livewire\Products;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('products', Products::class)->middleware('auth');



 

Previous article

LivewireでBreeze認証のCRUD

Next article

Bootstrap5-Auth With Vite