LoginSignup
1
2

More than 3 years have passed since last update.

【Laravel】プロジェクトの作成からブラウザ経由のDB操作までを実際にやってみる(アプリ作成の手順詳細)

Posted at

Laravel学習のため、プロジェクト作成しブラウザからのDB操作(新規追加、編集、削除)を自分でやってみる。

目次

  1. composerのインストール
  2. laravelのインストール
  3. laravelサーバーの起動
  4. DBにsqliteを設定
  5. モデルとマイグレーションの作成
  6. マイグレーションでDBのテーブルにカラムを追加
  7. コントローラの作成
  8. ルーティングの設定
  9. seederを使ってテストデータをDBに設定
  10. 一覧画面の作成(ブラウザにDBの全データを表示)
  11. 詳細ページの作成
  12. 編集機能の作成
  13. 削除機能の作成


1. composerのインストール

composerのインストール方法を参照。


2. laravelのインストール

$ composer create-project laravel/laravel [プロジェクト名] --prefer-dist

指定したプロジェクト名でフォルダが作成される。

--prefer-distオプション
高速ダウンロード用。

このオプションをつけると圧縮されていないファイルを優先してダウンロードする。また、すべてのVSC(バージョン管理ソフト)を取得しないので軽量となる。


3. laravelサーバーの起動

php artisan serve

$ php artisan serve
Starting Laravel development server: http://127.0.0.1:8000

表示されたURLにアクセス
http://127.0.0.1:8000

image.png

上記画面が表示されればOK。
サーバーの停止はctrl + c


DBにsqliteを設定

使用が簡単かつmacにデフォルトでインストールされているsqliteをDBに使用する。

laravelインストール時のデフォルトのDBはMySQLのため、環境ファイルの設定を一部変更する。

.envファイルの変更

ルートディレクトリ直下にある.envファイルを開き、以下コードを変更する。

.env(変更前)
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

↓ 以下に変更

.env(変更後)
DB_CONNECTION=sqlite

DB用のファイルを作成する

database/database.sqliteを作成する。

プロジェクトのルートディレクトリで以下を実行。

$ touch database/database.sqlite

image.png

モデルとマイグレーションの作成

DBのテーブルに対応するモデルと、テーブルにカラムを追加したり型指定するマイグレーションファイルを作成する。

(参考)モデルとは?マイグレーションとの違い

$ php artisan make:model [モデル名] -m
  • artisanコマンドのmake:modelでモデルを作成する。
  • -mオプションでマイグレーションファイルも同時生成。(--migrateの省略形)
  • モデル名は冒頭大文字の単数形。単語をつなげる場合はキャメルケースにする(例:MakerCode)



▼モデルの命名規則
DBのテーブル名は複数形とし、Model名はその単数形とする。

・DBのテーブル名: 複数形のスネークケース
・対応するModel名: 冒頭大文字のキャメルケース

<例1>
・DBのテーブル名: articles
・対応するModel名: Article

<例2>
・DBのテーブル名: maker_codes
・対応するModel名: MakerCode



▼(例)Productモデルを作成

$ php artisan make:model Product -m

Model created successfully.
Created Migration: 2021_01_15_022833_create_products_table

2つのファイルが生成される。

・モデル
app > Models > モデル名.php
image.png

・マイグレーション
database > migrations > タイムスタンプcreateテーブル名_table.php
image.png

(補足)モデルとマイグレーションファイルを別々に作る場合

マイグレーションファイルは作成用のartisanコードがあるので、それを使って生成できる。

$ php artisan make:model Product
$ php artisan make:migration create_products_table


マイグレーションでDBのテーブルにカラムを追加する

マイグレーションファイルの編集

作成したいカラムを追記する。デフォルトでidとtimestampsのカラムがある。

up関数の中に追記する。

$table->型('カラム名')

2021_01_15_022833_create_products_table.php
    public function up()
    {
        Schema::create('products', function (Blueprint $table) {
            $table->id();
            $table->string('product_name')->unique(); //追加
            $table->integer('price'); //追加
            $table->boolean('is_stocked')->nullable(); //追加
            $table->timestamps();
        });
    }

必要に応じて、unique()nullable()などの修飾子をつけることができる。


カラムタイプと修飾子

他にもたくさんのカラムタイプが用意されている。
image.png
続きは以下リンク参照。

Laravel公式 使用できるカラムタイプ一覧

▼インデックス修飾子
image.png

▼カラム修飾子
image.png


マイグレーションの実行

作成したマイグレーションファイルの内容をテーブルに反映する。

php artisan migrate



▼migrationの実行例

$ php artisan migrate

Migration table created successfully.
Migrating: 2021_01_15_022833_create_products_table
Migrated:  2021_01_15_022833_create_products_table (0.90ms)

テーブルの作成に成功。

エラー発生時
Illuminate\Database\QueryException
Database (/laravel/test-pj/database/database.sqlite) does not exist. (SQL: PRAGMA foreign_keys = ON;)

対策:$ touch database/database.sqlite を実行


コントローラの作成

DBにデータを追加・読み込み・編集・削除(CRUD操作)するためにコントローラを作成する。

作成時にオプションで-rをつけると、CRUD操作のためのアクションが記載されたコントローラを作成することができる。

$ php artisan make:controller [コントローラ名] -r
  • -r--resourceの省略形
  • コントローラ名は冒頭大文字で、後ろにControllerをつける(例:ProductController)
  • app > Http > Controllerの中にファイルが生成される

--resourceオプションで作成したコントローラを特別にリソースコントローラと呼ぶ。



▼ProcuctControllerの作成例
create, show, editなどCRUD操作に必要なアクションの外枠を既に記述してくれている。
あとは実際の処理を各アクションの中に記述するだけの状態。

$ php artisan make:controller ProductController -r
Controller created successfully.

image.png

▼ファイルの中身

ProductController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ProductController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        //
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        //
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        //
    }
}


ルーティングの設定

先ほど作成したコントローラの各アクションをルートに登録する。

ルーティングは、app > routes > web.php に記述する。

image.png

リソースコントローラのルート登録は、Routeファサードのresourceメソッドで簡単にできる。

web.php
Route::resource('$URI', 'コントローラ名');
  • $URIは複数形のパスを指定する。



▼実例

web.php
Route::resource('products', 'ProductController');

▼ルートの登録状況を確認

$ php artisan route:list

$ php artisan route:list
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+
| Domain | Method    | URI                     | Name             | Action                                         | Middleware |
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+
|        | GET|HEAD  | api/user                |                  | Closure                                        | api        |
|        | GET|HEAD  | products                | products.index   | App\Http\Controllers\ProductController@index   | web        |
|        | POST      | products                | products.store   | App\Http\Controllers\ProductController@store   | web        |
|        | GET|HEAD  | products/create         | products.create  | App\Http\Controllers\ProductController@create  | web        |
|        | GET|HEAD  | products/{product}      | products.show    | App\Http\Controllers\ProductController@show    | web        |
|        | PUT|PATCH | products/{product}      | products.update  | App\Http\Controllers\ProductController@update  | web        |
|        | DELETE    | products/{product}      | products.destroy | App\Http\Controllers\ProductController@destroy | web        |
|        | GET|HEAD  | products/{product}/edit | products.edit    | App\Http\Controllers\ProductController@edit    | web        |
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+

リソースコントローラの各アクションがルート登録されている。

Laravel8.xでエラーが出た場合は、RouteServiceProvider.phpのコメントアウトを解除する

(補足)sqliteにテーブルが作成されているか確認する

sqliteにアクセスするためには、sqlite3コマンドで、database.sqliteを開く。

ルートディレクトリで以下を実行。
$ sqlite3 database/database.sqlite

$ sqlite3 database/database.sqlite
SQLite version 3.28.0 2019-04-15 14:49:49
Enter ".help" for usage hints.

#テーブル一覧を表示
sqlite> .table
failed_jobs      password_resets  users          
migrations       products  

#productsテーブルの構造(schema)を表示
sqlite> .schema products
CREATE TABLE IF NOT EXISTS "products" (
  "id" integer not null primary key autoincrement,
  "product_name" varchar not null,
  "price" integer not null,
  "is_stocked" tinyint(1) not null,
  "created_at" datetime null,
  "updated_at" datetime null
);

productsテーブルがあり、指定したカラムを持っていることがわかる。

▼sqlite3の主なコマンド

コマンド 内容
.tables テーブル一覧を表示
.schema [テーブル名] 指定したテーブルのスキーマ定義を表示
.exit sqliteを終了
.help ヘルプを表示


seederを使ってテストデータをDBに設定する

seeder(シーダ)とは、DBを手軽にテストするために、テストデータをDBに設定する機能。

$ php artisan make:seeder シーダ名
  • シーダ名は、[テーブル名]TableSeeder とするのが一般的
  • 保存先: app > database > seeders

なかなか便利な機能で、deleteやedit機能などでデータをあれこれ変更した後に、seederをDBに送ればまた初期のデータを復活させることができる。



▼実例

$ php artisan make:seeder ProductTableSeeder
Seeder created successfully.

image.png

ProductTableSeeder.php
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class ProductTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        //
    }
}

run関数を持ったクラスが生成される。

seederの編集

seederファイルのrun関数の中に処理を記述する。
今回はクエリビルダで記述する。冒頭でDBファサードのuse宣言をが必要。

ProductTableSeeder.php
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB; //追加

class ProductTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        //以下追加
        DB::table('products')->insert([
            [
                'product_name' => 'iPhone6s',
                'price' => 62000,
                'is_stocked' => false
            ],
            [
                'product_name' => 'iPhone8',
                'price' => 84000, 
                'is_stocked' => true        
            ],
            [
                'product_name' => 'iPhone12',
                'price' => 120000,
                'is_stocked' => true               
            ]           
        ]);
    }
}

今回はクエリビルダで記述しているが、Eroquentでも問題ない。

(参考)Eroquetとクエリビルダとは?


seederをDBに反映する

seederをDBに反映する際は、基本的にDatabaseSeeder.phpを使う。
そのため、作成したクラスをDatabaseSeeder.phpの中で呼び出す。

DatabaseSeeder.php
public function run()
    {
        $this->call(ProductTableSeeder::class);
    }

DatabaseSeeder.phpをメインとして使うとseederファイルを複数に分割している場合も容易にDBに反映できる。

#Composerのオートローダを再生成する
$ composer dump-autoload

#DatabaseSeeder.phpを実行する
$ php artisan db:seed



▼実際の処理例

$ composer dump-autoload
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
Discovered Package: facade/ignition
Discovered Package: fideloper/proxy
Discovered Package: fruitcake/laravel-cors
Discovered Package: laravel/sail
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.
Generated optimized autoload files containing 4618 classes

$ php artisan db:seed
Seeding: Database\Seeders\ProductTableSeeder
Seeded:  Database\Seeders\ProductTableSeeder (9.16ms)
Database seeding completed successfully.

以上でseederで作成したデータをDBに反映完了。



▼(補足)別のseederファイルを直接DBに反映する
DatabaseSeeder.phpではなく、別途作成したseederファイルのみ読み込ませたい場合は、--classオプションでseederを指定する。

php artisan db:seed --class=ProductTableSeeder


DBのデータを確認する

・DBのデータを抽出してみる

artisanコマンドのtinkerを使って、Laravelの対話モードに入り、Eloquentのallメソッドで指定したモデルのすべてのデータを取得する。

$ php artisan tinker
>>>[モデルの完全な名前空間]::all();

対話モードはexitで抜ける。

tinkerの元の意味は小さな改善をすること。phpの対話モードでコマンドを一つづつ実施することが由来している?



▼実例

ターミナル
$ php artisan tinker
Psy Shell v0.10.5 (PHP 7.3.11  cli) by Justin Hileman
>>>
>>> App\Models\Product::all();
=> Illuminate\Database\Eloquent\Collection {#4309
     all: [
       App\Models\Product {#4308
         id: "1",
         product_name: "iPhone6s",
         price: "62000",
         is_stocked: "0",
         created_at: null,
         updated_at: null,
       },
       App\Models\Product {#4307
         id: "2",
         product_name: "iPhone8",
         price: "84000",
         is_stocked: "1",
         created_at: null,
         updated_at: null,
       },
       App\Models\Product {#4298
         id: "3",
         product_name: "iPhone12",
         price: "120000",
         is_stocked: "1",
         created_at: null,
         updated_at: null,
       },
     ],
   }
>>>
>>> exit
Exit:  Goodbye

指定したデータが取得できている。


・sqliteで確認する

ルートディレクトリで以下を実行。
$ sqlite3 database/database.sqlite

テーブルの中のデータをすべて表示(SQL)
select * form [テーブル名]

$ sqlite3 database/database.sqlite

sqlite> select * from products;
1|iPhone6s|62000|0||
2|iPhone8|84000|1||
3|iPhone12|120000|1||

sqlite> .exit


一覧画面の作成(ブラウザにDBの全データを表示)

取得した全データを表示する一覧画面を作成する。

コントローラのindexアクションを編集する

以前に作成したコントローラのindexアクションの戻り値にDBのすべてのデータを指定する。

Eloquentを使うため冒頭に使用するモデルのクラスをuse宣言する。

ProductController.php
<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Product;  //追記

class ProductController extends Controller
{
    public function index()
    {
        $productsInfo = Product::all(); //追記
        return $productsInfo; //追記
    }

//以下略

(参考)Eroquetとは?

サーバーを起動する

$ php artisan serveを実行する。

$ php artisan serve

Starting Laravel development server: http://127.0.0.1:8000


ブラウザで表示する

URIにindexに対応するルートを入力する。(ここでは /products)

ルートは、$php artisan route:listコマンドで確認できる。

image.png

取得したデータの表示に成功。取得データをそのまま返しているのでデータはJSON形式で表示される。


ビューの作成

取得データを見やすく表示するためにビューを作成する。
ビューは resources > views 配下に、拡張子.blade.php
で保存する。

今回は、productsディレクトリを作成し、外側となるbase.blade.phpとメイン部分となるindex.phpを用意する。

▼ディレクトリ構造
image.png

レイアウトの作成

layoutsディレクトリの中にbase.blade.phpを作成する。

base.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>@yield('title')</title>
</head>
<body>
  <h1>@yield('title')</h1>

  @yield('content')
</body>
</html>

メインビューの作成

index.blade.phpを作成する。

index.blade.php
@extends('.products.layouts.base')

@section('title', '製品一覧')

@section('newLink')
  <a href="/products/create">新規作成</a>
  <hr>
@stop

@section('content')
  @foreach ($products as $product)
    <div>
      <h2>{{$product->product_name}}</h2>
      <p>製品価格{{number_format($product->price)}}</p>
      <p>在庫
        @if ($product->is_stocked) あり 
        @else なし
        @endif
      </p>
      <a href="/products/{{$product->id}}/edit">編集する</a> | 
      <a href="/products/{{$product->id}}">商品詳細</a>
      <hr>
    </div>
  @endforeach
@stop

後々作成する、新規作成、編集、商品詳細ページへのリンクも設置してある。

(参考)section, yield, extendsについて


コントローラでビューを指定

ProductControllerのindexアクションで、作成したビュー(index.blade.php)を開くように処理を変更する。

ProductController.php
<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Product;  //追記

class ProductController extends Controller
{
    public function index()
    {
        $productsInfo = Product::all();
        return view('products.index', ['products' => $productsInfo]);   //変更
    }

//以下略
  • viewをviewヘルパーと呼び、指定したビューを開く。その際、第2引数でデータを渡せる。
  • resource > products > index.blade.phpは、products.indexとして指定。
  • 第2引数の書き方: ['変数名' => 渡すデータ]



▼ブラウザの表示
保存して、サーバー起動php artisan serve
し、URIを入力する。

image.png

DBから取得したデータが成形して表示されている。


詳細ページの作成

商品詳細ページを作成する。

コントローラの編集

ProductControllerのshowアクションを編集する。

ProductController.php
    public function show($id)
    {
        //受け取ったidの製品情報を格納
        $product = Product::find($id);
        return view('products.show', ['product' => $product]);
    }

URLのproductsの後ろのデータが$idとして渡される。
findメソッドを使って、指定したidのデータを変数$productに格納する。


ビューの編集(show.blade.php)

resources > products 配下にshow.blade.phpを作成する。

show.blade.php
@extends('.products.layouts.base')

@section('title', '製品詳細')

@section('content')
  <div>
    <h2>{{$product->product_name}}</h2>
    <p>製品価格{{number_format($product->price)}}</p>
    <p>在庫
      @if ($product->is_stocked) あり 
      @else なし
      @endif
    </p>
    <a href="/products/{{$product->id}}/edit">編集する</a> |  
    <a href="/products">製品一覧に戻る</a> |
    @component('components.delete-txt', ['product'=>$product])
    @endcomponent
    <hr>
  </div>
@stop

あとは、http://127.0.0.1:8000/products/1 のように、末尾でidを指定すると製品詳細ページが開く。

image.png

編集と削除リンク先は後ほど作成。



▼(補足)削除機能のボタン
削除機能はcomponentとして読み込んでいる。詳細の機能は最後の削除機能で作成する。

    @component('components.delete-txt', ['product'=>$product])
    @endcomponent


新規追加機能の作成

ルーティングの確認

DBに保存するには、createアクションを実行し、storeアクションを行う。

ルートを確認すると、/products/createでcreateアクションを実行、/productsにPOSTでアクセスするとstoreアクション実行となる。

$ php artisan route:list
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+
| Domain | Method    | URI                     | Name             | Action                                         | Middleware |
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+
|        | POST      | products                | products.store   | App\Http\Controllers\ProductController@store   | web        |
|        | GET|HEAD  | products/create         | products.create  | App\Http\Controllers\ProductController@create  | web        |
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+


createビューの作成

新規作成ページとして、create.blade.phpを作成する。

create.blade.php
@extends('.products.layouts.base')

@section('title', '製品の新規追加')

@section('content')
  <form action="/products" method="post">
    @csrf
    <div>
      <label for="product_name">製品名</label>
      <input type="text" name="product_name" required autoforcous>
    </div>
    <div>
      <label for="price">製品価格
      </label>
      <input type="text" name="price" required>
    </div>
    <div>
      <label for="stock">在庫有無</label>
      <select name="stock">
        <option value="1">あり</option>
        <option value="0">なし</option>
      </select>
    </div>
    <div>
    <div>
      <input type="submit" value="送信">
    </div>
  </form>
@stop

@csrf
クロスサイトリクエストフォージェリ対策として必須

(参考)Laravel公式 CSRF保護

@csrfの記述がないと、submit後に419のエラーページに飛ばされる。(419はLaravel独自のエラーページ)

image.png


コントローラの編集

新規追加のためには、createアクションとstoreアクションの2つに処理を追加する。

createアクション

createアクションでは、上記で作成したビューを表示させるのみ。

ProductController.php
    public function create()
    {
        return view('products.create');
    }

storeアクション

storeアクションでは、submitで送られてきたデータを受け取り、DBに保存する処理を記述する。

ProductController.php
    public function store(Request $request)
    {
        $product = new Product;

        $product->product_name = $request->product_name;
        $product->price = $request->price;
        $product->is_stocked = $request->stock;

        $product->save();

        return redirect('products/'.$product->id);
    }

$product = new Product;
Productモデルからインスタンスを作成し、変数に代入。
この変数に各データを保存していく。

$request->[name属性]
submitで送られてきたデータは$requestに保存されている。
name属性を指定してデータを取得する。

$product->save();
すべてのデータを格納したら、saveメソッドでDBに保存する。

return redirect('products/'.$product->id);
新たに作成した製品詳細ページにリダイレクトする。


ブラウザで開く

ブラウザでcreateページを開く。
http://127.0.0.1:8000/products/create

image.png

↓ 送信

image.png

新規保存し、新しい製品詳細ページの表示に成功。


編集機能の作成

ルーティングの確認

既存商品の情報を編集するには、editアクションとupdateアクションを使う。

$ php artisan route:list
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+
| Domain | Method    | URI                     | Name             | Action                                         | Middleware |
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+
|        | PUT|PATCH | products/{product}      | products.update  | App\Http\Controllers\ProductController@update  | web        |
|        | GET|HEAD  | products/{product}/edit | products.edit    | App\Http\Controllers\ProductController@edit    | web        |
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+

products/{product}/editにアクセスして、商品の編集を行い、products/{product}にPUT|PATCHでアクセスすればDBの情報を更新できる。


編集ページの作成

編集用のビュー、edit.blade.phpを作成する。
基本的にはcreate.blade.phpと同じ。PUTでアクセスするために擬似メソッドを設置する。

▼create.blade.phpとの違い

  • formタグのactionでパスが変わる。
  • 擬似フォームメソッドの@method('PUT')を設置。
  • inputタグにvalue属性で既存の設定データを表示。
  • 在庫の有無に合わせてselectタグの初期値を設定。
  • submitボタンのvalueを更新に変更。
edit.blade.php
@extends('.products.layouts.base')

@section('title', '製品の編集')

@section('content')
<form action="/products/{{$product->id}}" method="post">
    @csrf
    @method('PUT')
    <div>
      <label for="product_name">製品名</label>
      <input type="text" name="product_name" value="{{$product->product_name}}" required autoforcous>
    </div>
    <div>
      <label for="price">製品価格
      </label>
      <input type="text" name="price" value="{{$product->price}}" required>
    </div>
    <div>
      <label for="stock">在庫有無</label>
      <select name="stock">
        @php 
          $selected = "selected";
          if ($product->is_stocked)
            $selected = ""
        @endphp
        <option value="1">あり</option>
        <option value="0" {{$selected}}>なし</option>
      </select>
    </div>
    <div>
      <input type="submit" value="更新">
    </div>
  </form>
@stop



・擬似フォームメソッド
HTMLフォームはPUT, PATCH, DELETEリクエストを作成できないため(対応していない)、_methodを偽装する必要がある。

<input type="hidden" name="_method" value="リクエストメソッド名">

type="hidden"をつけると画面上に表示していないデータを送信することができる。_methodというキー名で、指定したリクエストメソッドを値として送信している。

▼putを使う方法
送信ボタンの上に以下タグを設置する。

edit.blade.php
<input type="hidden" name="_method" value="put">
<input type="submit" value="更新">

これを、laravelの擬似フォームメソッドを使うととても簡単にかける。

@method('PUT')

・(参考)Laravel公式 擬似フォームメソッド


(補足)PUTとPATCHの違い
PUTはすべてのデータをまるごと変更する場合に使い、PATCHは一部のデータを変更する場合に使うらしい。
ここでは、PUTとPATCHどちらを使っても同じ結果になる。


コントローラの編集

editアクションとupdateアクションを編集する。

editアクション

Productモデルの指定したidのデータを取得してビューに渡す。

ProductController.php
    public function edit($id)
    {
        $product = Product::find($id);
        return view('products.edit', ['product'=>$product]);
    }

updateアクション

記述はstoreアクションとほぼ同じ。
最初にProductモデルの新規インスタンスではなく、指定したidのデータを取得する。

受け取ったデータ$requestを代入し、saveでDBに保存する。

ProductController.php
    public function update(Request $request, $id)
    {
        $product = Product::find($id);

        $product->product_name = $request->product_name;
        $product->price = $request->price;
        $product->is_stocked = $request->stock;

        $product->save();

        return redirect('products/'.$product->id); 
    }


削除機能の作成

ルーティングの確認

$ php artisan route:list
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+
| Domain | Method    | URI                     | Name             | Action                                         | Middleware |
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+
|        | DELETE    | products/{product}      | products.destroy | App\Http\Controllers\ProductController@destroy | web        |
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+

products/{product}にDELETEでアクセスすればデータを削除できる。

削除コンポーネントを作成する

削除ボタンは編集と詳細ページに設置する。laravelの機能であるコンポーネント化し簡単に呼び出しを行う。

コンポーネントはボタンとテキストの2種類を用意する。

▼編集
image.png

▼詳細
image.png

ファイルの作成

resources > views > componentsの配下に、ファイルを2つ作成する。

image.png

▼削除ボタンコンポーネント

delete-btn.blade.php
<form action="/products/{{$product->id}}" method="post" id="delete-btn">
      @csrf
      @method('DELETE')
      <input type="submit" name="" value="削除">
</form>

・acrtion属性の値に"/products/{{$product->id}}"を設定。

formはDELETEメソッドをサポートしていないため、ここではpostを指定。

@csrf
クロスサイトリクエストフォージェリ防止機能を追加(必須!)

@method('DELETE')
擬似フォームメソッドでDELETEを指定。これでdeleteメソッドで通信できるようになる。

▼削除テキストコンポーネント

delete-txt.blade.php
<form action='/products/{{$product->id}}' method='POST' id='dlt-txt'>
  @csrf
  @method('DELETE')
  <a onclick='document.getElementById("dlt-txt").submit()'>削除する</a>
</form>

inputタグをテキストに変更するため、JavaScriptのsubmitメソッドを使用。

formタグにid="dlt-btn"を指定し、sbumitの対象をdocument.getElementById(dlt-btn)とする。

以上でコンポーネントが完成。


componentの仕組み

前述のコードで既にcomponentの呼び出し処理は記述してあるが、componentの仕組みについて。

Laravelではblade.phpファイルをコンポーネントとして呼び出すことができる。

extends, yield, sectionの簡易的な機能のようなもの。

コンポーネントの呼び出しはとても簡単で、呼び出したいところに以下のコードを記述する。

  @component('ビューのパス', ['変数名'=>渡したいデータ])
  @endcomponent

ビューのパスは相対ではなく、viewsフォルダからの絶対パスとなる。

image.png

このため、products > edit.blade.php から components >
delete-text.blade.phpを呼び出したい場合は、components.delete-txtとする。

第2引数はデータを渡したいときに使う。読み込むのみでデータを渡す必要がない場合は不要。


ブラウザの表示(削除機能の確認)

image.png

↓ 商品詳細(iPhone8)

image.png

↓ 削除

image.png

削除成功。



バリデーション、CSSの調整はないが、LaravelのCRUD操作の基本はおさえられた。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2