見出し画像

Laravel10(PHP8.2)+LaravelSail+MySQL8+phpMyAminで簡易的なECサイトを作るチュートリアル③

お疲れ様です。
このLaravelでのECサイト作成記事も3記事目となってしまいました。

最初の記事

https://note.com/mukae9/n/n48cbf8f2fd9f

2番目の記事

https://note.com/mukae9/n/n78bed0cbe47c

当初は3記事くらいで終わるでしょと思ってましたが、
目論見が外れすぎてこの有様です。

それでは前回まででデータベース周りは完成していますので、
そのデータベースの情報をペジネーションを使って一覧表示させるところまでやってしまいましょう!

1、そもそもLaravelで画面表示の流れはどうなっているのか?

前までの記事とは変わってここからはフロント(UI)の話になってきます。
そこ意識してくださいね。

htmlファイルや生のPHPなどですと基本的にファイル名そのものがURLの一部となって、
例えばdemo.htmlとかですと
http://localhost/demo.htmlとかになるかと思います。

Laravelの場合はそんな単純な動きではないため、
詳しく説明しすぎると僕もあなたも闇落ちしてしまうと思いますので、
かなりシンプルに流れを追ってみます。

https://localhost/

とアクセスされたとすると、
まずappフォルダ(Laravelフォルダ)直下のroutesフォルダの中の
web.phpが反応します。

ちなみに現在のweb.phpは

<?php

/*
|--------------------------------------------------------------------------
| 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::get('/dashboard', function () {
    return view('dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');

Route::middleware('auth')->group(function () {
    Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
    Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
    Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
});

require __DIR__.'/auth.php';

​となっているかと思います。
このファイルの

Route::get('/', function () {
    return view('welcome');
});

が「get送信」で / (つまりはメインとなるhttp://localhost/)にアクセスされた際に、viewのwelcomeファイルを表示しなさい。

という意味になります。

view('welcome');

は何のことかというと、
appフォルダ(Laravelフォルダ)直下の
resouses/views/welcome.blade.phpのことをさしています。

http://localhost/にアクセスした時に、
「Laravel」と表示されていたのはこの流れが処理されていたからということになります。

ただ、この動きはLaravelなど多くのフレームワークの基本となるMVCモデルのCが抜けてしまっている処理の流れになりますので、
次の章でMVCの動きを追いつつ、一覧表示をさせて行きたいと思います



1、ルーティングをしよう(routes/web.php)


まずはとにかくルーティングをしたいと思います。

今回は
http://localhost/とアクセスされた場合に
一覧(stocks.blade.php)を表示させる事にします。

すると、
web.phpは前回のままですと、

<?php

/*
|--------------------------------------------------------------------------
| 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('stocks');
});


となります。
が、上述の通りこれではMVCのCであるControllerを利用していない事になるのでルーティングを一旦消して

use App\Http\Controllers\StockController;//追加


~
~

 
Route::get('/', [StockController::class, 'index'])->name('stock.index');

に置き換えてみましょう。

これでルーティングは完了しました!

http://localhost/

にアクセスするとStockController@indexなんて無いわ!ってエラーが出るかと思います。今から作りましょう。


2、コントローラーの作成


それではMVCのCに当たるコントローラーを作っていきましょう。

コントローラーは
demoフォルダ(Laravelフォルダ)直下の
app/Http/Controllersの中にあります。
demo/app/Http/Controllersとなります。

コントローラーもartisanコマンド作ると楽です。
demo上で

php artisan make:controller StockController

と打ち込むとControllersフォルダ内にStockControllerが作成されます。
中身を見てみましょう。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class StockController extends Controller
{
   //
}


Controllerクラスを引き継いだクラスですね。

今は意味が良くわからないかもしれませんが、
この中にメソッドを作りルーティングで指定してあげると、該当するメソッドの中身の処理が行われるっと認識しておくだけでOKです。


先ほどルーティングで

 Route::get('/', [StockController::class, 'index'])->name('stock.index');

としていますので、つまりはindexメソッドを作ってあげる必要があります。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class StockController extends Controller
{
   public function index() //追加
   {
       return view('stocks');
   }
}

これで
http://localhost/
にアクセスすると、今度はview('stock')って何ですか?
と聞かれてしまいますが、

http://localhost/にアクセス

web.phpでルーティング

StockControllerのindexメソッドを発動

上記の通りreturnでstocks.blade.phpを返す処理

と言う一連の流れが出来上がりました。

それでは実際に表示させるstocks.blade.phpを作っていきましょう。



3、Viewのファイルを作る



bladeファイルを作るartisanコマンドはデフォルトでは無いので純粋に
resouses/views/フォルダに新規ファイルで
stocks.blade.phpを作成します。

ファイルの中身は

<x-app-layout>
    <div class="container-fluid">
        <div class="mx-auto" style="max-width:1200px">
            <h1 style="color:#555555; text-align:center; font-size:1.2em; padding:24px 0px; font-weight:bold;">商品一覧</h1>
            <div class="">
                <div class="grid grid-cols-4 gap-4 flex-wrap">
                    商品一覧を出したい
                </div>
            </div>
        </div>
    </div>
</x-app-layout>

こちらをコピーして頂ければ十分かと思います。
bladeファイルの書き方やHTML/CSSについては今回の記事では詳細な説明は省きますので、
https://readouble.com/laravel/10.x/ja/blade.html
などのドキュメントをご参考下さい。

ここでようやく
http://localhost/
にアクセスすると、エラーになってしまいますね。
Userネームなどログインしてないのに、ログインしないと見れない情報にアクセスしているためです。

まずはとりあえず画面を表示させたいので、

http://localhost/register
※画面崩れてる人、、、npm run devしてる?

でユーザー登録した後にもう一度、

http://localhost/

にアクセスしてみてください!


まっさら。

なんか切ない画面が完成しましたね。
商品一覧出したいですね。

さて、これでMVCモデルでいうVとCが出来ました。
あとはMのデータベースから情報を取得するModel側の処理を作っていきたいと思います。



4、Modelを作る



データベースから情報を取得するには、
modelクラスとそれを利用するControllerへの処理の記述が必要になってきます。

まずはmodelクラスを作ってみます。

php artisan make:model Stock

するとapp(Laravel自体フォルダ)の直下に
Modelsフォルダとその中にStock.phpファイルが作成されます。

Stocks.phpファイルの中身を見てみると

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Stock extends Model
{
   //
}

となっています。
このままでもいいのですが、
これだと何でもかんでもデータベースへの変更を受け付けてしまいますんで
カラムに対してガードをかけます。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Stock extends Model
{
   protected $guarded = [
     'id'
   ];
}

これだけで、Stocksテーブルのidカラムは外部からの変更を許可しない状態になりました。
(逆にガードではなく、許可を出すprotected $fillableもあります。カラム数などから判断してみてください。「自分は変更を許さないカラムがどれなのか」をはっきりさせたいのでガード派です。特にこだわりはないです。)

さあこれだけでモデルの作成は完了しました!
「気持ち悪!」って感じてしまう自分がいるのですが、
このStock.phpはどこにも実際のデータベースのStocksテーブルと結び付ける記述がどこにもありません。

けどLaravelの命名規則で
Modelのクラス名を単数形で指定して、
テーブル名を複数形にするというのがあるので、
それを満たしておけば
勝手にLaravelが判断して結びつけてくれます。
今回だと「Stock」モデルと「Stocks」テーブル。
他にも「Person」モデルと「Peaple」テーブル。

(…過保護すぎない?)

もちろん
protected $table = 'test_table';
などを追記すればそのモデル名とは関係ないテーブルと紐付けも可能です。

これでmodelのファイル作成は完了です。
すかすかのファイルに見えますがModelクラスを継承しているので必要な処理はそちらにズラリと書いてあります。
(気になる方はVenderフォルダへダイブ!)

5、Controllerにモデル操作の記述をする


いよいよあとはコントローラー上でmodelを使ってデータベースから情報を取得するだけです!
一覧画面を表示させるためにルーティングしたコントーラーメソッドは
StockController@indexでしたね。

今だと、stocks.blade.phpを返す記述しかありません。
return view('stocks');

そのため、
(  i  )DBから情報を取得する記述
(  ii )その情報をviewに受け渡す記述
( iii )viewで受け取って表示する記述
が必要となります。


( i )DBから情報を取得する記述
からやっていきます。

DBから情報を取得する手段は、
DBファサードを使うか、
Eloquantを使うかなどとなってきますが、

DBファサード、、、どっかで聞きましたね。
そうです、シーダー情報をDBにINSERTするときに使ったのを覚えてますでしょうか。

ちなみに色々ありますが
Eloquant…SQLの書き方知らなくても簡単にDBを扱える/モデルが必要
DBファサード…SQLライクに記述できるしEloquantより処理速度が早い

といったところでしょうか。
チームの事情に合わせて利用するかと思うのでどちらも慣れておくといいと思います。

それでは今回は
モデルも作ったしStockControllerでEloquantで商品情報を取得したいと思います。

<?php

namespace App\Http\Controllers;

use App\Models\Stock; //追加

use Illuminate\Http\Request;

class StockController extends Controller
{
   public function index()
   {
       $stocks = Stock::SimplePaginate(6); //Eloquantで検索
       return view('stocks');
   }
}

まずはいつものように
use App\Models\Stock;
でStockモデルを利用しやすくします。

そして、
$stocks = Stock::SimplePaginate(6);
でstockテーブルから情報を取得しています。

いきなり変則的なSimplePaginate(6);
を使っての抽出となりますが、
ここの数字が1ページで表示する情報量になります。
今回は1ページに6つの情報を表示ということになります。

Laravelが頑張りすぎてて「これだけ???」ってなるかと思いますが、
これだけです。
これだけでペジネーション機能が使えます。

なお、Eloquantでできることは多彩です。


$stocks = Stock::all();
で全件取得

$stocks = Stock::where(条件)->get();
で条件にあった情報を全件取得

などなどありますので、
一度記事を見ておくといいかもしれません。

https://readouble.com/laravel/10.x/ja/eloquent.html


( ii )DB情報をviewに受け渡す記述

さて、このままではDBから情報は抽出できていますがそれをどこに渡すのかが記述されていません。

<?php

namespace App\Http\Controllers;

use App\Models\Stock;

use Illuminate\Http\Request;

class StockController extends Controller
{
   public function index()
   {
       $stocks = Stock::Paginate(6);
       return view('stocks',compact('stocks')); //追記変更
   }
}

return view('stocks');
から
return view('stocks',compact('stocks')); 
に追記変更されています。

view(ここではstocks.blade.phpのこと)を返すけど
$stocksという変数も連れて行って。

という意味になります。
->with()という関数で変数を受け渡すことも出来ます。
第二引数に渡すだけでも連れて行くことが出来ます。

一番自分が馴染むスタイルのどれでも良いかと思います。
ちなみに生PHPばっかりやってる自分はcompact派。

( iii )viewで受け取って表示する記述

ここまででDBの情報を抽出し、
その情報をstocks.blade.phpに持たせて表示させることは完成しました。

あとはview側(stocks.blade.php)で値を表示させる記述が必要です。

6、View側で値を受け取る

stocks.blade.phpに追記していきます。
そういえばvscodeでbladeファイルの編集やりにくい方はこういう拡張入れておくと見やすいですよ。

自分はphpstorm派だけど・・
<x-app-layout>
    <div class="container-fluid">
        <div class="mx-auto" style="max-width:1200px">
            <h1 style="color:#555555; text-align:center; font-size:1.2em; padding:24px 0px; font-weight:bold;">商品一覧</h1>
            <div class="">
                <div class="grid grid-cols-4 gap-4 flex-wrap">
                {{-- 追加 --}}
                    @foreach($stocks as $stock)
                        <div class="mycart_box text-center rounded shadow-lg bg-white p-6">
                            {{$stock->name}} <br>
                            {{$stock->fee}}円<br>
                            <img src="/image/{{$stock->imagePath}}" alt="" class="incart" >
                            <br>
                            {{$stock->explain}} <br>
                        </div>
    
                    @endforeach
                {{-- ここまで --}}  
                </div>
                {{-- 追加 --}}
                <div class="text-center" style="width: 200px;margin: 20px auto;">
                    {{  $stocks->links()}} 
                </div>
                {{-- ここまで --}}  
            </div>
        </div>
    </div>
</x-app-layout>

ここでとりあえず
http://localhost/
にアクセスしてみましょう!

さあどうでしょうか?
画像はまだですがそれっぽいやつがデータベース情報が6つ表示されているかと思います。

でも確かにデータベースから情報を取得できています!
ECサイトの風味が出始めましたね!




加えてページ下部にある
ナビゲーションメニューでNextを押してみると、、、
表示が変わって新たな6つの情報が表示されました!
(これ本当に生PHPでやるのめんどくさいから。もしふ〜んって反応してた人がいたら、Laravel開発者たちに懺悔を。)

さらにNextを表示すると、
16個の商品が登録されていますので、残り4個の商品が表示されていますね!

7、foreachを理解する


説明を加えて行くと
@foreach($stocks as $stock)

@endforeach


コントローラーの
return view('stocks',compact('stocks'))
で受け渡された
 $stocksを展開させています。

ちなみに$stocksにはデータベースの情報がレコード×各情報の二次元配列(正確にはobjectだけど説明しやすいので)で格納されています。

$stocks['レコード自体の番号0~15']['そのレコードの情報nameとか']

こういうイメージですね。

なのでまず、
@foreach($stocks as $stock)で
二次元配列から配列$stock[]の状態(つまりはフィルムカメラ1つのレコード情報とか)まで展開して、
あとは
{{$stock->name}}などで情報を表示させています。
print $stock['name'];と一緒です。

もう少しイメージがつきやすいように言うと
foreach1周目は$stocks[0]の情報を展開するので、
DB上の最初のレコードであるフィルムカメラの情報を$stockに格納します。

$stock=
[
  'name' => 'フィルムカメラ',
  'detail' => '1960年式のカメラです',
  'fee' => 200000,
  'last' => 1,
  'imgpath' => 'フィルムカメラ.jpg',
];


こう言うことになります。

だから1周目は{{$stock->name}}でフィルムカメラの名前が表示されますね。

foreach2周目は


$stock=
[
  'name' => 'イヤホン',
  'detail' => 'ノイズキャンセリングがついてます',
  'fee' => 20000,
  'last' => 1,
  'imgpath' => 'イヤホン.jpg',
];


と言うことになるので
イヤホンの情報が取得されます。

これが繰り返されています。
(もしこれでも分からなかったらforeachとかをもう一度学ぼう!)

8、ペジネーションのこと



今回は
EloquantのPaginateを使って6つの情報を表示するように制御しているので
情報を6つ展開したら最初のページは完了します。

そして
{{$stocks->links()}}
この記述をするだけでLaravelが自動で残りのレコード数から
あと何ページあるのかを判断してペジネートさせてくれています。
(URLをよく見たらページの遷移情報がくっついています。)

破壊力抜群ですね。

生PHPでペジネーションを実装しようとして地獄を見た初心者時代が今でも蘇ります。

これで商品一覧を表示させるページの機能が大分出来上がりました!

次回でレイアウトを少し整えて
カート機能を作っていきたいと思います!

9、次の記事に行く前の課題


次の記事で使うカート画面の構築をしておきましょう!
この記事の総復習になるので頑張ってみてください!

■routes/web.phpで/myCartにアクセスされた場合でStockController@myCartメソッドが発動するようにルーティング
■myCart.blade.phpを作成(stocks.blade.phpと同じ構成でbody内は下記参考)
■UserStockモデルとcreate_users_stocks_tableを作成(記事①で作ってる方は作らないでOK)
users_stocksテーブルの構成は
・id(bigIncrements)
・stockId(int)
・userId(int)
・timestamps()

UserStockモデルで
・stockId(int)
・userId(int)
への変更許可と、
作成後にマイグレーションしておく。

■users_stocksテーブルにphpMyadminからでいいので、
id=1,
stockId=1,
userId=1

id=2,
stockId=2,
userId=2


の2つのダミー情報を入れておく。
こういうこと⇩


■StocksController@myCartに
UserStockモデルを使ってEloquantで全データを取得
その値を引き渡してmyCart.blade.php表示させる処理を記述。

■myCart.blade.phpに<h1>カートの中身</h1>とControllerから渡されたuserIdとstockIdをforeachを使って表示
(1122と味気なく表示されたらOK、追加位置はstocks.blade.phpと同じく
<div class="d-flex flex-row flex-wrap">以下でOK)


それではまた次回の記事で!
お疲れ様でした!

次回の記事

https://note.com/mukae9/n/n07d05ad60908


この記事が気に入ったらサポートをしてみませんか?