CRUD
Create
- 商品モデルを作成
カラム名 | 説明 | Laravel関数 | MySQLのデータ型 |
---|---|---|---|
name 商品名 | string | varchar(255) | |
description | 商品の説明文 | text | text |
price | 価格 | integer | int(11) |
sail artisan make:model Product -m
database\migrations\XXXX_XX_XX_XXXXXX_create_products_table.php
<?php 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('description'); + $table->integer('price')->unsigned(); /** * マイナスの値が保存できないようにしている。 */ $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('products'); } };
商品のコントローラーを作成
CRUDをまとめて作成するので「--resource」オプション
sail artisan make:controller ProductController --resource --model=Product
カテゴリと商品とを紐づけ
app\Models\Product.php
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Product extends Model { use HasFactory; + + public function category() + { + return $this->belongsTo(Category::class); + } }
app\Models\Category.php
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Category extends Model { use HasFactory; + + public function products() + { + return $this->hasMany(Product::class); + } }
マイグレーションファイルdatabase\migrations\XXXX_XX_XX_XXXXXX_create_products_table.php
に1行追加
新しいカラムとして、カテゴリのIDを追加
カラム名 | 説明 | Laravel関数 | MySQLのデータ型 |
---|---|---|---|
category_id | カテゴリID | integer | int(11) |
<?php 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('description'); $table->integer('price')->unsigned(); + $table->integer('category_id')->unsigned(); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('products'); } };
Eloquentは外部キーカラムを自動的に決定します。規約により、親モデルの小文字クラス名に「_id」という接尾辞を付けます。
この場合では、Categoryモデルに対する外部キーカラムはcategory_idとなり、商品とカテゴリが紐づきます。
カテゴリーIDにはマイナスの値はあり得ないので、unsignedを指定しています。
<?php use Illuminate\Support\Facades\Route; +use App\Http\Controllers\ProductController; /* |-------------------------------------------------------------------------- | 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('/', function () { return view('welcome'); }); + +Route::resource('products', ProductController::class);
- コントローラー
app\Http\Controllers\ProductController.php
- indexアクション
public function index() { - // + $products = Product::all(); + + return view('products.index', compact('products')); }
indexで呼び出すviewファイル
resources\views\products\index.blade.php
+<a href="{{ route('products.create') }}"> Create New Product</a> + +<table> + <tr> + <th>Name</th> + <th>Description</th> + <th>Price</th> + <th>Category ID</th> + <th >Action</th> + </tr> + @foreach ($products as $product) + <tr> + <td>{{ $product->name }}</td> + <td>{{ $product->description }}</td> + <td>{{ $product->price }}</td> + <td>{{ $product->category_id }}</td> + <td> + <a href="{{ route('products.show',$product->id) }}">Show</a> + <a href="{{ route('products.edit',$product->id) }}">Edit</a> + </td> + </tr> + @endforeach +</table>
- createアクション
public function create() { - // + return view('products.create'); }
データ入力フォーム
resources\views\products\create.blade.php
+<div> + <h2>Add New Product</h2> +</div> +<div> + <a href="{{ route('products.index') }}"> Back</a> +</div> + +<form action="{{ route('products.store') }}" method="POST"> + @csrf + + <div> + <strong>Name:</strong> + <input type="text" name="name" placeholder="Name"> + </div> + <div> + <strong>Description:</strong> + <textarea style="height:150px" name="description" placeholder="Description"></textarea> + </div> + <div> + <strong>Price:</strong> + <input type="number" name="price" placeholder="Price"> + </div> + <div> + <button type="submit">Submit</button> + </div> + +</form>
- storeアクション
app\Http\Controllers\ProductController.php
public function store(Request $request) { - // + $product = new Product(); + $product->name = $request->input('name'); + $product->description = $request->input('description'); + $product->price = $request->input('price'); + $product->save(); + + return to_route('products.index'); }
- showアクション
app\Http\Controllers\ProductController.php
public function show(Product $product) { - // + return view('products.show', compact('product')); }
viewファイル作成
resources\views\products\show.blade.php
+<div> + <h2> Show Product</h2> +</div> +<div> + <a href="{{ route('products.index') }}"> Back</a> +</div> + +<div> + <strong>Name:</strong> + {{$product->name}} +</div> + +<div> + <strong>Description:</strong> + {{$product->description}} +</div> + +<div> + <strong>Price:</strong> + {{$product->price}} +</div>
- editアクション
public function edit(Product $product) { - // + return view('products.edit', compact('product')); }
resources\views\products\edit.blade.php
+<div> + <h2>Edit Product</h2> +</div> +<div> + <a href="{{ route('products.index') }}"> Back</a> +</div> + +<form action="{{ route('products.update',$product->id) }}" method="POST"> + @csrf + @method('PUT') + + <div> + <strong>Name:</strong> + <input type="text" name="name" value="{{ $product->name }}" placeholder="Name"> + </div> + <div> + <strong>Description:</strong> + <textarea style="height:150px" name="description" placeholder="description">{{ $product->description }}</textarea> + </div> + <div> + <strong>Price:</strong> + <input type="number" name="price" value="{{ $product->price }}"> + </div> + <div> + <button type="submit">Submit</button> + </div> + +</form>
- updateアクション
public function update(Request $request, Product $product) { - // + $product->name = $request->input('name'); + $product->description = $request->input('description'); + $product->price = $request->input('price'); + $product->update(); + + return to_route('products.index'); }
- destroyアクション
public function destroy(Product $product) { - // + $product->delete(); + + return to_route('products.index'); }
resources\views\products\index.blade.php
を変更
<a href="{{ route('products.create') }}"> Create New Product</a> <table> <tr> <th>Name</th> <th>Description</th> <th>Price</th> <th>Category ID</th> <th >Action</th> </tr> @foreach ($products as $product) <tr> <td>{{ $product->name }}</td> <td>{{ $product->description }}</td> <td>{{ $product->price }}</td> <td>{{ $product->category_id }}</td> <td> + <form action="{{ route('products.destroy',$product->id) }}" method="POST"> <a href="{{ route('products.show',$product->id) }}">Show</a> <a href="{{ route('products.edit',$product->id) }}">Edit</a> + @csrf + @method('DELETE') + <button type="submit">Delete</button> + </form> </td> </tr> @endforeach </table>
商品登録時にカテゴリを選択できるようにしよう
app\Http\Controllers\ProductController.php
にモデルを追加
<?php namespace App\Http\Controllers; use App\Models\Product; +use App\Models\Category; use Illuminate\Http\Request; class ProductController extends Controller /* === 後略 === */
app\Http\Controllers\ProductController.php
のcreateアクションを修正
public function create() { - return view('products.create'); + $categories = Category::all(); + + return view('products.create', compact('categories')); }
resources\views\products\create.blade.php
を修正
<div> <h2>Add New Product</h2> </div> <div> <a href="{{ route('products.index') }}"> Back</a> </div> <form action="{{ route('products.store') }}" method="POST"> @csrf <div> <strong>Name:</strong> <input type="text" name="name" placeholder="Name"> </div> <div> <strong>Description:</strong> <textarea style="height:150px" name="description" placeholder="Description"></textarea> </div> <div> <strong>Price:</strong> <input type="number" name="price" placeholder="Price"> </div> + <div> + <strong>Category:</strong> + <select name="category_id"> + @foreach ($categories as $category) + <option value="{{ $category->id }}">{{ $category->name }}</option> + @endforeach + </select> + </div> <div> <button type="submit">Submit</button> </div> </form>
app\Http\Controllers\ProductController.php
のstoreアクションでcategory_idをデータベースに保存できるように修正
public function store(Request $request) { $product = new Product(); $product->name = $request->input('name'); $product->description = $request->input('description'); $product->price = $request->input('price'); + $product->category_id = $request->input('category_id'); $product->save(); return to_route('products.index'); }
app\Http\Controllers\ProductController.php
のedhitアクションを変更
public function edit(Product $product) { - return view('products.edit', compact('product')); + $categories = Category::all(); + + return view('products.edit', compact('product', 'categories')); }
resources\views\products\edit.blade.php
を修正
<div> <h2>Edit Product</h2> </div> <div> <a href="{{ route('products.index') }}"> Back</a> </div> <form action="{{ route('products.update',$product->id) }}" method="POST"> @csrf @method('PUT') <div> <strong>Name:</strong> <input type="text" name="name" value="{{ $product->name }}" placeholder="Name"> </div> <div> <strong>Description:</strong> <textarea style="height:150px" name="description" placeholder="description">{{ $product->description }}</textarea> </div> <div> <strong>Price:</strong> <input type="number" name="price" value="{{ $product->price }}"> </div> + <div> + <strong>Category:</strong> + <select name="category_id"> + @foreach ($categories as $category) + @if ($category->id == $product->category_id) + <option value="{{ $category->id }}" selected>{{ $category->name }}</option> + @else + <option value="{{ $category->id }}">{{ $category->name }}</option> + @endif + @endforeach + </select> + </div> <div> <button type="submit">Submit</button> </div> </form>
app\Http\Controllers\ProductController.php
のupdadeアクションを修正
public function update(Request $request, Product $product) { $product->name = $request->input('name'); $product->description = $request->input('description'); $product->price = $request->input('price'); + $product->category_id = $request->input('category_id'); $product->update(); return to_route('products.index'); }
ダミーデータの追加
Fakerのランダム値の日本語化。設定ファイルを編集
config/app.php
'faker_locale' => 'ja_JP',
- ファクトリ
コマンドsail artisan make:factory ProductFactory
database/factories/ProductFactory.php
<?php namespace Database\Factories; use Illuminate\Database\Eloquent\Factories\Factory; /** * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Product> */ class ProductFactory extends Factory { /** * Define the model's default state. * * @return array<string, mixed> */ public function definition() { return [ 'name' => fake()->name(), 'description' => fake()->realText(50, 5), 'price' => fake()->numberBetween(100, 200000), 'category_id' => 1, ]; } }
- シーダー
コマンドsail artisan make:seeder ProductSeeder
database/seeders/ProductSeecer.php
<?php namespace Database\Seeders; use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; use App\Models\Product; class ProductSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { // ProductFactoryクラスで定義した内容にもとづいてダミーデータを20件生成 し、productsテーブルに追加する Product::factory()->count(20)->create(); } }
- ファクトリとシーダークラスの作成後にコマンド実行でダミーデータを追加
コマンドsail artisan db:seed --class=ProductSeeder