スクリーンショット_2020-01-18_16

Laravel6.0(PHP7.3)+MySQL+Laradockで簡易的なECサイトを作る③

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

最初の記事

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

2番目の記事

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

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

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

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

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');
});
Auth::routes();​

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

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/とアクセスされた場合に
一覧(shop.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('shop');
});

Auth::routes();


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

Route::get('/', 'ShopController@index');

としてみましょう。

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

http://localhost/

にアクセスするとShopController@indexなんて無いわ!ってエラーが出るかと思います。


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


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

コントローラーは
appフォルダ(Laravelフォルダ)直下の
app/Http/Controllersの中にあります。
※僕の記事を参考に環境構築した方はapp連打で分かりにくい方すいません。
app(Laravelフォルダ)/app/Http/Controllersとなります。
(シンプルにフォルダ名ミスりました)

コントローラーもartisanコマンド作ると楽です。
app(Laravelフォルダ)上で

php artisan make:controller ShopController

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

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ShopController extends Controller
{
   //
}


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

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


先ほどルーティングで
Route::get('/', 'ShopController@index');
としていますので、つまりはindexメソッドを作ってあげる必要があります。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

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

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

http://localhost/にアクセス

web.phpでルーティング

ShopControllerのindexメソッドを発動

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

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

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



3、Viewのファイルを作る



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

ファイルの中身は

@extends('layouts.app')

@section('content')
<div class="container-fluid">
   <div class="">
       <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="d-flex flex-row flex-wrap">
                   商品一覧を出したい
               </div>
           </div>
       </div>
   </div>
</div>
@endsection

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

と言いつつ簡単な部分は説明しますと、
@extends('layouts.app')でデザインのテンプレートとなる
resouses/views/layoutsフォルダのapp.blade.phpファイルを継承しています。

そして
shop.blade.phpの
@section('content')

@endsection

の中身をapp.blade.phpファイルの@yield('content')に埋め込むような形になっています。

ここでようやく
http://localhost/
にアクセスすると、エラーなく画面が表示されるかと思います。

スクリーンショット 2020-01-18 17.07.28

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

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



4、Modelを作る



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

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

php artisan make:model Models/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を使ってデータベースから情報を取得するだけです!
一覧画面を表示させるためにルーティングしたコントーラーメソッドは
ShopController@indexでしたね。

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

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


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

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

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

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

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

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

<?php

namespace App\Http\Controllers;

use App\Models\Stock; //追加

use Illuminate\Http\Request;

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

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

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

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

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

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

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

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

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

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


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

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

<?php

namespace App\Http\Controllers;

use App\Models\Stock;

use Illuminate\Http\Request;

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

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

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

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

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

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

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

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

6、View側で値を受け取る

shop.blade.phpに追記していきます。

@extends('layouts.app')

@section('content')
<div class="container-fluid">
   <div class="">
       <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="d-flex flex-row flex-wrap">
                 商品一覧を出したい

                {{-- 追加 --}}

                 @foreach($stocks as $stock)
                      {{$stock->name}} <br>
                      {{$stock->fee}}円<br>
                      <img src="/image/{{$stock->imgpath}}" alt="" class="incart" >
                      <br>
                      {{$stock->detail}} <br>
                 @endforeach
                 {{$stocks->links()}} 

                {{-- ここまで --}}
               </div>
           </div>
       </div>
   </div>
</div>
@endsection

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

さあどうでしょうか?
デザイン性のかけらもないけどデータベース情報が6つ表示されているかと思います。

スクリーンショット 2020-01-18 17.14.29

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

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

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

7、foreachを理解する



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

@endforeach


コントローラーの
return view('shop',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にアクセスされた場合でShopController@myCartメソッドが発動するようにルーティング
■mycart.blade.phpを作成(shop.blade.phpと同じ構成でbody内は下記参考)
■Cartモデルとcreate_carts_tableを作成(cartsテーブルは記事①で作ってる方は作らないでOK)
cartsテーブルの構成は
・id(bigIncrements)
・stock_id(int)
・user_id(int)
・timestamps()

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

■cartsテーブルにphpMyadminからでいいので、
id=1,
stock_id=1,
user_id=1

id=2,
stock_id=2,
user_id=2


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

スクリーンショット 2020-01-19 14.59.22


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

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

実践課題
■/mycartはログインしている人だけに表示させたい!対策をしてみよう!
ヒント:middleware('auth')を使う!

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

次回の記事

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


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