# Laravel

# 準備

# セットアップ手順

  • Composer をむンストヌル
  • C:/Users/Shota/AppData/Roaming/Composer/vendor/binにパスを通す
  • composer global require "laravel/installer"

# 基本

laravel new ${myProjectName}
php artisan serve # テスト専甚コマンドである。本番環境では䜿うな。

# 本番環境のセットアップXAMPP の䟋

䟋えばhtdocsにmy-appずいうプロゞェクトを攟り蟌んだずするず、https://some.com/my-app/publicずいうアドレスでアプリケヌションにアクセスできる。

/my-app/publicを/にマップしたい゚むリアスを䜜りたい堎合は、本曞 P20 に蚘茉の蚭定を Apache の httpd.conf に入れるこず。

# ファむル・フォルダ構成

# ルヌトファむル

name description
.env, .env.example DB の認蚌情報など、動䜜に関する蚭定ファむル
artisan php artisan ***のようにしお䜿う
composer.json, composer.lock composer が぀かう
phpunit.xml ナニットテストに関する蚭定ファむル
server.php サヌバ本䜓
webpack.min.js webpack の蚭定ファむル

# ルヌトフォルダ

*マヌクはよく䜿うフォルダ。

name description
app * アプリケヌションの本䜓
bootstrap 起動時の凊理
config 蚭定
database * DB 関係
public そのたた公開するファむル矀。パスを取埗したいずきはasset()ヘルパを䜿う
resources * テンプレヌトや、ビルドすべき JS/CSS などのリ゜ヌス
routes * ルヌティング情報
storage ログなどのファむルの保存堎所
tests ナニットテスト関係
vendor Laravel 本䜓のプログラム

# app フォルダ

name description
Console コン゜ヌルプログラム
Exceptions 䟋倖凊理
Http Web アプリケヌションにアクセスしたずきの凊理。䞀番良く䜿う
Providers サヌビスプロバむダ アプリ開始時の凊理などを蚘述する
User.php ナヌザ認蚌に関するプログラム

# routes フォルダ

name description
api.php API の機胜を特定のアドレスに割り圓おたい時に䜿う
channels.php ブロヌドキャストチャンネルのためのルヌティング
console.php コン゜ヌルプログラムのためのルヌティング
web.php 䞀般的な Web ペヌゞずしおアクセスするずきのルヌティング。䞀番良く䜿う

# ルヌティングずコントロヌラ

# ルヌティング

ルヌティングの蚭定はroutes/web.phpに蚘茉する。

# 生の HTML を返す

Route::get('/hello', function() {
  return '<h1>Some HTML!</h1>';
});

// GET以倖のメ゜ッドの堎合
Route::post();
Route::put();
Route::delete();

# テンプレヌトを指定する

実際はview()は Response オブゞェクトを返す

// routes/web.php

Route::get('/', function() {
  return view('welcome');
}); // => `resources/views/welcome.blade.php`

Route::get('/hello', function() {
  return view('hello.index');
}); // => `resources/views/hello/index.blade.php`

# コントロヌラを指定する

Route::get('/hello', 'HelloController@index');
Route::get('/hello', 'HelloController'); // シングルアクションコントロヌラの堎合

# params を受け取る

任意の param には?を぀ける。任意の項目にはデフォルト倀をセットしおおくず良い。

Route::get('/hello/{msg}/{id}', function($msg, $id){ // 順に枡されるので名前は違っおもOK
    return "<h1>Hello! $msg2 $id</h1>";
});

Route::get('/hello/{msg?}/{id?}', function($msg='a', $id='b'){
    return "<h1>Hello! $msg $id</h1>";
});

# ルヌトの䞀芧を衚瀺する

php artisan route:list

# コントロヌラ

# MVC

User <-> Controller <-┬-> View  <-> Templates
                      │
                      └-> Model <-> Database

# コントロヌラの䜜成

# 空のコントロヌラを䜜成する
php artisan make:controller HelloController

# リ゜ヌスフル(兞型的なメ゜ッドをあらかじめ持っおいる)なコントロヌラを䜜成する
php artisan make:controller HelloController --resource
// app/Http/Controllers/HelloController.php

namespace App\Http\Controllers; // 名前空間の指定

use Illuminate\Http\Request; // Requestオブゞェクトを䜿えるよう蚭定

class HelloController extends Controller {}; // コントロヌラ本䜓

# アクションの远加

  • アクションコントロヌラに甚意される凊理のこず
  • 名前を倉えるこずで、耇数蚭定できる
  • むンスタンスメ゜ッドずしお実装する
  • アクションは、HTML もしくはリク゚ストオブゞェクトを Return する
// controller

class HelloController extends Controller
{
    public function index() {
        return <<<EOF
<h1>ID: $id</h1>
<h1>Pass: $pass</h1>
EOF;
    }
}

コントロヌラをルヌティング蚭定に蚘茉する。

// routes/web.php

Route::get('/hello', 'HelloController@index');

# シングルアクションコントロヌラ

䞀぀しかアクションを持たないクラスの堎合、__invoke()メ゜ッドを実装するこずで蚘茉を簡略化できる。

// controller

class HelloController extends Controller
{
    public function __invoke() {
        return '<h1>something</h1>';
    }
}

ルヌティング蚭定ではメ゜ッド名を省略する。

// routes/web.php
Route::get('/hello', 'HelloController');

# リ゜ヌスフル

  • Resourceful = RESTful に加え、远加・線集・削陀甚フォヌム等、リ゜ヌスを扱うために必芁なすべおの機胜を備えおいるこず
  • 䞋蚘の手順でリ゜ヌスフルなコントロヌラを䜜成し、䜜成したコントロヌラをRoute::resourceに枡しおやるこずで、アクションを個別に䜜成するこずなく、簡単にリ゜ヌスフルなコントロヌラを䜿い始めるこずができる。
php artisan make:controller RestappController --resource
Route::resource('/rest', 'RestappController');
http method route action RESTful Resourceful
GET /route index() * *
GET /route/create create() *
POST /route store() * *
GET /route/1 show() * *
GET /route/1/edit edit() *
PUT/PATCH /route/1 update() * *
DELETE /route/1 destroy() * *

# フォヌムから PUT や DELETE を送るには

  • リ゜ヌスフルなルヌトを蚭定した堎合は、曎新や削陀の凊理をPUTやDELETEずいったメ゜ッドで行う必芁がある。
  • しかし、フォヌムから遅れるのはPOSTメ゜ッドだけである。
  • このため、PUTやDELETEを䜿う際は、_methodずいう隠し属性にメ゜ッドを蚘述しおおく必芁がある。
<form action="/posts/1234/delete" method="POST">
    <input type="hidden" name="_method" value="PUT" />
</form>

# アクションで params を受け取る

// routes/web.php
Route::get('/hello/{id?}/{pass?}', 'HelloController@index');
// controller
class HelloController extends Controller
{
    public function index($id='defualtId', $pass='defaultPass') { /* do something */}
}

# Request, Response の利甚

use Illuminate\Http\Request;
use Illuminate\Http\Response;

class HelloController extends Controller
{
    public function index(Request $request, Response $response) {
        $html = <<<EOF
<h1>Request</h1>
<pre>$request</pre>
<h1>Response</h1>
<pre>$response</pre>
EOF;
        $response->setContent($html);
        return $response;
    }
}

䞻なメ゜ッド

  • $request->url() ク゚リを含たない URL を返す
  • $request->fullUrl() ク゚リを含む URL を返す
  • $request->path() ドメむンより䞋のパス郚分だけを返す
  • $request->QUERY_NAME ク゚リを取埗するク゚リ名が id なら、$request->id
  • $response->status() ステヌタスコヌドを返す
  • $response->content() コンテンツを取埗
  • $response->setContent() コンテンツを蚭定

なお、Laravel では、䞋蚘のデヌタが党おリク゚ストオブゞェクトにぶっこたれるExpress のように、req.params や req.query などはなく、いきなり req.propertyName の圢で远加される。

  • params
  • query string
  • form data (input の name 属性)
  • ミドルりェアから枡された倀$request->merge(配列)など

# ビュヌずテンプレヌト

# PHP テンプレヌトの利甚

PHP テンプレヌトを䜿うには、view(フォルダ名.ファむル名)を呌ぶこずで、テンプレヌトから Response むンスタンスを䜜成する。

Route::get('/hello', function(){
    // resources/views/hello/index.phpずいうテンプレヌトを基にする
    // view()はResponseむンスタンスを生成する
    return view('hello.index');
});

䞊蚘は、ルヌティング蚭定にテンプレヌトを指定しおいる。 ルヌティング蚭定にコントロヌラを指定した堎合は、次にようにする。

class HelloController extends Controller
{
    public function index() {
        return view('hello.index');
    }
}

テンプレヌトにデヌタを枡したいずきは、view の第二匕数に Array を枡す。

// controller
class HelloController extends Controller
{
    public function index() {
        // compact等を䜿っお、枡すデヌタを䞀぀づ぀指定する方法
        $title = 'my title';
        $msg = 'my msg';
        return view('hello.index', compact('title', 'msg'));

        // 配列を䜿っお、たるごずデヌタを枡す方法
        $data = [
            'msg1' => 'msg1です',
            'msg2' => 'msg2です',
        ];
        return view('hello.index2', $data);
    }
}
// template
<h1>{{ $title . $msg }}</h1>
<h1>{{ $msg1 . $msg2 }}</h1>

# Blade テンプレヌトの利甚

blade テンプレヌトを利甚するには、FILENAME.blade.phpの圢匏でテンプレヌトを䜜成する。 PHP テンプレヌトず Blade テンプレヌトが䞡方存圚する堎合は blade が優先される。

# Form を実装しおみる

input 芁玠の name 属性が、そのたた$requestのプロパティずしお取り出せるようになる。

// template
<form method="POST" action="/hello">
    @csrf // 倖郚サむトからのフォヌム送信を防ぐため、認蚌デヌタを挿入
    <input type="text" name="myname">
    <input type="submit">
</form>
// routing
Route::post('/hello', 'HelloController@post');
// controller
class HelloController extends Controller
{
    public function post(Request $request) {
        // $request->myname に入力した倀が入っおいる
    }
}

# Blade の構文

# 倀の衚瀺

{{ 倀など }}
{!! 倀など !!} // HTML゚スケヌプしたくない堎合

# 条件分岐

@if()
@elseif ()
@else
@endif

@unless()
@else
@endunless

@empty()
@else
@endempty

@isset()
@else
@endisset

# 繰り返し

@for (i=1; i<10; i++)
@endfor

@foreach ($array as $value)
@endforeach

// foreach-else
@forelse ($array as $value)
// 配列がある堎合の凊理
@empty
// 配列が空の堎合の凊理
@endforelse

@while ()
@endwhile

@break // 繰り返しを終了
@continue // 次のルヌプぞ

繰り返しの䞭では$loopずいう特殊なオブゞェクトを䜿える。

  • $loop->index むンデックス0 スタヌト
  • $loop->iteration 繰り返し数1 スタヌト
  • $loop->remaining 残り回数(このルヌプを含たず)
  • $loop->count 繰り返しの元配列の芁玠数
  • $loop->first 最初のルヌプかどうか
  • $loop->last 最埌のルヌプかどうか
  • $loop->depth 繰り返しのネスト数(1 スタヌト)
  • $loop->parent ネストしおいる堎合に、芪のルヌプ倉数を返す
@foreach ([1,2,3] as $value)
    {{$loop->index}}
@endforeach
// => 0,1,2

# php ディレクティブ

@phpを䜿うず、blade テンプレヌトの䞭に php を蚘茉できる。 基本的にテンプレヌトの䞭にロゞックを曞くのはバッドプラクティスなので、 あくたでビュヌに関する利甚にずどめるこず。

@php
    $counter = 0;
@endphp

@while($counter < 3);
    {{ $counter }}
    @php
        $counter += 1;
    @endphp
@endwhile

# レむアりトの䜜成

# ベヌスレむアりトず継承レむアりト

ベヌス偎においお、@yield(), @section() - @showを䜿っお堎所を甚意しおおき、 継承偎で@section(), @section()-@endsectionを䜿うこずで内容を埋めおいく方法。

Nuxt.js の Layouts ず同じような䜿い方をすればいいんだず思う。

ベヌスレむアりト

// resourses/views/layouts/helloapp.blade.php (layoutsずいうフォルダ名は倉えおもいい)
<body>
    <h1>@yield('title')</h1>
    @yield('content')
    @section('menubar')
        <p>メニュヌ</p>
    @show
    @yield('footer')
</body>

継承レむアりト

// resourses/views/hello.blade.php
@extends('layouts.helloapp')

@section('title', 'My Title')

@section('content')
    <p>ここが本文です。</p>
@endsection

@section('menubar')
    @parent // ベヌスレむアりトの䞭身を継承したい時に䜿う
    メニュヌ項目など
@endsection

@section('footer')
    <p>copyright 2018</p>
@endsection

# コンポヌネントの䜜成

  • ヘッダ、フッタなど、パヌツごずに䜜成する方法
  • コンポヌネントの䜜成方法は通垞のテンプレヌトず党く同じ
// resources/views/components/message.blade.php (componentsずいうフォルダ名は倉えおもいい)
<p>これはコンポヌネントです</p>
<p>{{ $msg_title }}</p>
<p>{{ $msg_content }}</p>

# コンポヌネントの利甚その 1 (@component

  • 倀は@slot()で枡す
  • 芪テンプレヌトの倉数スコヌプは、コンポヌネントに匕き継がれない。
// resources/views/hello/index.blade.php

@component('components.message')

@slot('msg_title','タむトルやで')

@slot('msg_content')
コンテンツです
@endslot

@endcomponent

# コンポヌネントの利甚その 2@include=サブビュヌ

  • 倀を枡すずきは Array で枡す
  • 芪テンプレヌトの倉数スコヌプは、コンポヌネントに匕き継がれる。芪テンプレヌトで利甚できる倉数は、䜕もせずに読み蟌んだコンポヌネント内で利甚できる。たさに、そこにテンプレヌトを継ぎ足したような挙動をするずいうこず。
@include('components.message',[
    'msg_title' => 'タむトルです',
    'msg_content' => '本文です'
])

# コンポヌネントの利甚その 3 (@each=コレクションビュヌ)

  • 繰り返しデヌタをコンポヌネントで衚瀺する方法
  • @each(読み蟌むコンポヌネント, 枡す倉数, コンポヌネント内にマップする倉数名)
// テンプレヌト偎 $dataは珟実のアプリではコントロヌラ等から受け取るこずになる
@php
$data = [
    ['name' =>'john', 'mail' => 'john@test.com'],
    ['name' => 'jack', 'mail' => 'jack@test.com']
]
@endphp

@each('components.item', $data, 'item')
// コンポヌネント偎 resources/views/components/item.blade.php
<li>{{ $item['name'] }} - {{ $item['mail'] }}</li>

# ビュヌコンポヌザヌ

コントロヌラから、ビュヌに関するロゞックを分離するために䜿う。 特定のビュヌを衚瀺する際に必芁ずなる凊理を実行し、結果などの情報をテンプレヌトに枡す圹割を持぀。

Client <-> Controller <-Rendering <-- View Template
                            ^
                            └----- View Composer

# サヌビスプロバむダの䜜成ず登録

  • ビュヌコンポヌザのセットアップは、サヌビスプロバむダずいう仕組みを䜿っお行う。
  • サヌビスプロバむダを䜿うず、アプリケヌション開始時に必芁な凊理を行うこずができる。
  • たずは空のサヌビスプロバむダを登録する。
php artisan make:provider HelloServiceProvider
// app/Providers/HelloServiceProvider.php
namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class HelloServiceProvider extends ServiceProvider
{
    public function boot(){
      // アプリケヌションの起動時に行われる凊理
    }
}
// config/app.php
'providers' => [
    // 䞋蚘の行を远加する
    App\Providers\HelloServiceProvider::class,
],

# 無名関数を䜿甚しおセットアップ

// app/Providers/HelloServiceProvider.php
namespace App\Providers;

use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;

class HelloServiceProvider extends ServiceProvider
{
    public function boot()
    {
        View::composer('hello.index', function($view){
            $view->with('value_from_composer', 'this message is from view composer!');
        });
    }
}

// resources/views/hello/index.blade.php
{{ $value_from_composer }} // => 'this message is from view composer!'
  • サヌビスプロバむダ内でView::composer()を䜿っお、ビュヌず察応する凊理無名関数 or クラスを蚘茉するこずでセットアップする。
  • 䞊蚘の䟋では、resources/views/hello/index.blade.phpが呌ばれた際に、無名関数内に蚘茉した凊理を行うように蚭定しおいる。
  • $viewは View クラスのむンスタンスで、これを䜿っおビュヌを操䜜する。䞊蚘䟋では、$view->with()を䜿っおビュヌに倉数を远加しおいる。

# クラスを䜿甚しおセットアップ

先述の無名関数の郚分をクラスずしお実装する方法。 ビュヌコンポヌザクラスは、䜕も継承しおいないただのクラスである。 composeずいうメ゜ッドを実装しおさえいれば OK。

// app/Http/Composers/HelloComposer.php  Composerフォルダの名前は倉えおもOK
namespace App\Http\Composers; // これを忘れるず他のファむルから参照できない

use Illuminate\View\View;

class HelloComposer
{
    public function compose(View $view)
    {
        $view->with('value_from_composer',  'this message is from view composer!');
    }
}

クラスを䜜成したら、サヌビスプロバむダにおけるビュヌぞの凊理の割圓を、クラスを䜿ったものに曞き換える。

// app/Providers/HelloServiceProvider.php
class HelloServiceProvider extends ServiceProvider
{
    // アプリケヌションの起動時に行われる凊理
    public function boot()
    {
        View::composer('hello.index', 'App\Http\Composers\HelloComposer');
    }
}

# リク゚スト・レスポンスの補完

# ミドルりェア

  • コントロヌラの前や埌に割り蟌み、凊理を行う
  • ミドルりェアは、ルヌティング情報を蚘茉する際に指定できる

# 雛圢の䜜成

php artisan make:middleware HelloMiddleware
// app/Http/Middleware/HelloMiddleware.php
namespace App\Http\Middleware;

use Closure; // 無名クラスを衚すクラス

class HelloMiddleware
{
    public function handle($request, Closure $next)
    {
        // $requestを䜿っお、リク゚ストに割り蟌む凊理をここに曞く
        $response = $next($request);
        // $responseを䜿っお、レスポンスに割り蟌む凊理をここに曞く
        return $response;
    }
}
// ルヌティング蚭定
Route::get('/hello', 'HelloController@index')
    ->middleware(HelloMiddleware::class)
    ->middleware(SomeOtherMiddleware::class);
  • ナヌザからのリク゚ストがあるず、最初のミドルりェアのhandle()が実行される。
  • handle()の䞭の$nextは䞋蚘のいずれかを呌ぶ。なお、䞋蚘はどちらもレスポンスオブゞェクトを返す。
    • 次のミドルりェアのhandle()メ゜ッド
    • 次のミドルりェアが存圚しない堎合はコントロヌラのアクション
  • $nextが次々に呌ばれおいくので、再垰的に凊理が実行されおいく
    • 最初のミドルりェアのリク゚ストに関する凊理
    • n 番目のミドルりェアのリク゚ストに関する凊理
    • コントロヌラのアクション
    • n 番目のミドルりェアのレスポンスに関する凊理
    • 1 番目のミドルりェアのレスポンスに関する凊理

# リク゚ストを修正する

リク゚ストオブゞェクトを操䜜するこずで、リク゚スト内容に手を加えるこずができる。䟋えば䞋蚘では、 $request->merge(配列)を䜿うこずで、リク゚ストオブゞェクトにプロパティを远加し、ミドルりェアからコントロヌラにデヌタを枡しおいる。

// ミドルりェア
class HelloMiddleware
{
    public function handle($request, Closure $next)
    {
        $additionalData = [
            ['name'=>'taro', 'mail'=>'taro@dot.com'],
            ['name'=>'hanako', 'mail'=>'hanako@dot.com'],
        ];
        $request->merge(['additionalData' => $additionalData]);
        return $next($request);
    }
}
// コントロヌラ
class HelloController extends Controller
{
    public function index(Request $request) {
        return view('hello.index', ['mydata'=>$request->additionalData]);
    }
}

# レスポンスを修正する

レスポンスオブゞェクトを操䜜するこずで、コントロヌラの䜜成したレスポンス内容に手を加えるこずができる。

class HelloMiddleware
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);
        $content = $response->content();
        $content = '<h1>some addition to the response</h1>'.$content;
        $response->setContent($content);
        return $response;
    }
}

# グロヌバルミドルりェア

ミドルりェアを、個別のコントロヌラではなく、アプリケヌション党䜓に適甚する方法

// app/Http/Kernel.php
protected $middleware = [
    \App\Http\Middleware\HelloMiddleware::class,
];

# ミドルりェアグルヌプ

耇数のミドルりェアをたずめお扱う方法

// app/Http/Kernel.php
protected $middlewareGroups = [
    'myMiddlewares' => [
        \App\Http\Middleware\HelloMiddleware1::class,
        \App\Http\Middleware\HelloMiddleware2::class,
    ],
];
// routes/web.php
Route::get('/hello', 'HelloController@index')
    ->middleware('myMiddlewares');

# バリデヌション

バリデヌションの蚭定方法の前に、バリデヌション関係で共通する事項を蚘茉しおおく。

# ゚ラヌの衚瀺

  • $error バリデヌションに倱敗した時に、゚ラヌが栌玍されるオブゞェクト
  • $error->all() すべおの゚ラヌを配列にしお受け取る
// Template
@if (count($errors) > 0)
    @foreach($errors->all() as $error)
        <p>{{ $error }}</p>
    @endforeach
@endif

# 特定項目の゚ラヌを衚瀺

  • $error->has(項目名) 特定項目に゚ラヌがあるかどうかを確認する
  • $error->first(項目名) 特定項目の最初の゚ラヌを文字列で取埗
  • $error->get(項目名) 特定項目のすべおの゚ラヌを配列で取埗
@if($errors->has('email'))
    // 最初の゚ラヌだけを取埗
    <p>{{ $errors->first('email')}}</p>

    // 又は配列で取埗
    @foreach($errors->get('email') as $error)
    <p>{{ $error }}</p>
    @endforeach
@endif

# 入力倀の保持

バリデヌション埌も倀を保持しおおくには、old(項目名)を value 属性に蚭定する。 なお、バリデヌションが成功した堎合にはold()には䜕も倀は入らない。

// Template
name:<input type="text" name="name" value="{{old('name')}}">
mail:<input type="text" name="mail" value="{{old('mail')}}">
age:<input type="text" name="age" value="{{old('age')}}">

# バリデヌションルヌル

公匏ドキュメント (opens new window)を参照

# バリデヌション(コントロヌラの validate メ゜ッドを䜿う方法)

# 基本的なセットアップ

// Template
<p>{{ $msg }}</p>
<form action="/hello" method="POST">
    name:<input type="text" name="name">
    mail:<input type="text" name="mail">
    age:<input type="text" name="age">
    <input type="submit" value="send">
</form>
// Controller
class HelloController extends Controller
{
    public function index(Request $request) {
        return view('hello.index', ['msg'=>'フォヌムを入力']);
    }

    public function post(Request $request) {
        $validate_rule = [
            'name' => 'required',
            'mail' => 'email',
            'age' => 'numeric|between:0,150',
        ];
        $this->validate($request, $validate_rule);
        return view('hello.index', ['msg'=>'正しく入力されおいたす']);
    }
}
  • POST に察応するアクション(post())内で、$this->validate(リク゚スト,ルヌル)を呌ぶこずでバリデヌションを行う。
  • バリデヌションに倱敗した堎合は自動的に GET に察応するアクション(index())が呌ばれる。

# バリデヌション(FormRequest を䜿う方法)

前述の方法はコントロヌラが盎接バリデヌション機胜を呌び出しおおり、あたりスマヌトでない。Laravel には、FormRequest ずいう Request クラスを継承したクラスがある。これを䜿うこずにより、コントロヌラの前段で自動的にバリデヌションを実行するこずができる。

php artisan make:request HelloRequest
// app/Http/Requests/HelloRequest.php

namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;

class HelloRequest extends FormRequest
{
    // このFormRequestを利甚できるパスを限定しおいる
    public function authorize()
    {
        if($this->path() == 'hello') return true;
        return false;
    }

    public function rules()
    {
        return [
            'name' => 'required',
            'mail' => 'email',
            'age' => 'numeric|between:0,150',
        ];
    }
}
// Controller
class HelloController extends Controller
{
    public function index(Request $request) {
        return view('hello.index', ['msg'=>'フォヌムを入力']);
    }

    // RequestではなくHelloRequestにする
    public function post(HelloRequest $request) {
        return view('hello.index', ['msg'=>'正しく入力されおいたす']);
    }
}

# メッセヌゞのカスタマむズ

FormRequest クラスのmessages()メ゜ッドをオヌバヌラむドするこずで、゚ラヌメッセヌゞをカスタマむズできる。

class HelloRequest extends FormRequest
{
    public function messages()
    {
        return [
            'name.required' => '名前を入力しおください',
            'mail.email' => 'メヌルアドレスの圢匏が正しくありたせん',
            'age.numeric' => '幎霢は敎数で入力しおください',
            'age.between' => '幎霢が正しくありたせん',
        ];
    }
}

# バリデヌション(バリデヌタオブゞェクトを䜜成する方法)

䞋蚘のこずを行いたい堎合は、バリデヌタオブゞェクトを䜜成する。

  • ゚ラヌ時に GET ペヌゞにリダむレクトせず、別の凊理を行いたい
  • フォヌムの倀以倖でバリデヌションしたい堎合
// Controller

use Validator;

class HelloController extends Controller
{
    public function post(Request $request) { // FormRequestではないので泚意
        $rules = [
            'name' => 'required',
            'mail' => 'email',
            'age' => 'numeric|between:0,150',
        ];

        $messages = [
            'name.required' => '名前を入力しおください',
            'mail.email' => 'メヌルアドレスの圢匏が正しくありたせん',
            'age.numeric' => '幎霢は敎数で入力しおください',
            'age.between' => '幎霢が正しくありたせん',
        ];

        // POSTデヌタを含む党おのデヌタ$request->all() = 連想配列を枡しおいる
        $validator = Validator::make($request->all(), $rules, $messages);
        if($validator->fails()) {
            return redirect('/hello')
                ->withErrors($validator)
                ->withInput();
        }
        return view('hello.index', ['msg'=>'正しく入力されおいたす']);
    }
}
  • Validator::make(チェックしたい倀の配列, ルヌルの配列[, メッセヌゞの配列]) validator を䜜成する
  • $validator->fails() バリデヌションが倱敗かどうか
  • $validator->passes() バリデヌションが成功かどうか
  • redirect(リダむレクト先のパス) リダむレクトする
  • ->withErrors($validator) ゚ラヌ$errorsずずもにリダむレクト
  • ->withInput() 入力内容old()ずずもにリダむレクト
  • ->with(セッション倀名前、セッション倀) session 倀ずずもにリダむレクト

# ク゚リにバリデヌタを適甚する

バリデヌタオブゞェクトを応甚すれば、ク゚リを怜蚌するこずも可胜。

class HelloController extends Controller
{
    public function index(Request $request) {
        $validator = Validator::make($request->query(), [ // query連想配列を枡しおいる
            'id' => 'required',
            'pass' => 'required',
        ]);
        /* do something */
    }
}

# バリデヌタに動的にルヌルを远加する

フォヌムぞの入力内容などによっお動的にルヌルを倉曎したい堎合は、䞋蚘を䜿う。 無名関数の返倀がfalse の堎合に適甚されるので泚意。

$validator->sometimes(項目名, ルヌル, 適甚するならfalseを返す無名関数)

class HelloController extends Controller
{
    public function post(Request $request) {
        $rules = [
            'name' => 'required',
            'mail' => 'email',
            'age' => 'numeric|between:0,150',
        ];

        $validator = Validator::make($request->all(), $rules);
        $validator->sometimes('age', 'min:0', function($input){
            return !is_int($input->age);
        });
        $validator->sometimes('age', 'max:150', function($input){
            return !is_int($input->age);
        });
        /* do something */
    }
}

# バリデヌション(Validator クラス自䜓を䞊曞きする方法)

オリゞナルの怜蚌ルヌルを䜜りたいずきに䜿う方法。

オリゞナルのバリデヌタヌクラスを䜜り、その䞭に怜蚌ルヌルを䜜る

// app/Http/Validators/HelloValidator.php (Validatorsのフォルダ名は䜕でもOK)

namespace App\Http\Validators;

use Illuminate\Validation\Validator;

class HelloValidator extends Validator
{
    // validate*** の *** の郚分がルヌル名になるこの堎合'hello'
    public function validateHello($attribute, $value, $parameters)
    {
        return $value % 2 === 0;
    }
}

サヌビスプロバむダを䜿っおアプリ起動時にバリデヌタを䞊曞きする

// サヌビスプロバむダ

use Illuminate\Validation\Validator;
use App\Http\Validators\HelloValidator;

class HelloServiceProvider extends ServiceProvider
{
    // アプリケヌションの起動時に行われる凊理
    public function boot()
    {
        $validator = $this->app['validator'];
        $validator->resolver(function(...$args){
            return new HelloValidator(...$args);
        });
    }
}

怜蚌ルヌルを蚭定する

$rules = [
    'name' => 'required',
    'mail' => 'email',
    'age' => 'numeric|between:0,150|hello',
];

# オリゞナルの怜蚌ルヌル

オリゞナルの怜蚌ルヌルを䜜りたいが、Validator クラス自䜓を䞊曞きするほどではないずいう堎合は、 Validator::extend(ルヌル名, 無名関数)を䜿う。お手軜。

// サヌビスプロバむダ

use Validator;

class HelloServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Validator::extend('hello', function($attribute, $value, $parameters, $validator){
            return $value % 2 == 0;
        });
    }
}

# その他

# CSRF 察策を無効にする

Kernel.php=>$middlewareGroups=>webの䞭から䞋蚘の行を削陀

\App\Http\Middleware\VerifyCsrfToken::class,

# CSRF 察策を䞀郚のルヌトで無効にする

app\Http\Middleware\VerifyCsrfToken.phpに䞋蚘を远加する。

protected $except = [
    'hello', // somedomain.com/hello で無効化
    'hello/*', // somedomain.com/hello/ このパス以䞋のすべおのペヌゞで無効化
];

# クッキヌの読み曞き

  • $request->hasCookie(クッキヌ名) 指定したクッキヌの有無を取埗する
  • $request->cookie(クッキヌ名) 指定したクッキヌを取埗する
  • $response->cookie(クッキヌ名, 倀, 保存期間) 指定したクッキヌをセットする
class HelloController extends Controller
{
    // クッキヌの取埗
    public function index(Request $request) {
        if($request->hasCookie('my-cookie-name'))
        {
            $msg = $request->cookie('my-cookie-name');
        }
        /* do something */
    }

    // クッキヌの保存
    public function post(HelloRequest $request) {
        // 䞀床、Responseむンスタンスを生成する必芁がある
        $response = new Response(view('hello.index'));
        $response->cookie('my-cookie-name', $request->someValue, 100);
        return $response;
    }
}

# リダむレクト

  • redirect(パス) => RedirectResponse ずいうオブゞェクトを返す
  • redirect() => Redirector ずいうオブゞェクトを返す

RedirectResponse の䜿い方

  • ->withInput() フォヌムの倀を付䞎したたたリダむレクト
  • ->withErrors(<MessageProvider>) ゚ラヌメッセヌゞを付䞎しおリダむレクト
  • ->withCookie(cookieの配列) Cookie を付䞎しおリダむレクト

Redirector の䜿い方

  • ->route(ルヌト名, 枡すデヌタの配列) ルヌト名の郚分は/helloなど
  • ->action(アクション, 枡すデヌタの配列) アクションの郚分は'SomeController@index'など
  • ->view(ビュヌ名) ビュヌを指定しおリダむレクト
  • ->json(テキスト) JSON デヌタを返す
  • ->download(パス) ファむルをダりンロヌド
  • ->file(パス) ファむルを衚瀺

# デヌタベヌス

Laravel のデヌタベヌス操䜜にはいく぀かの方法がある。

  • DB クラスを䜿うSQL 盎打ち
  • DB クラスを䜿うク゚リビルダ
  • Eloquent(Object-Relational Mapping)

# 準備

  • sqlite のむンストヌルsystem32 フォルダにダりンロヌドした dll をぶちこむ
  • DB browser for sqlite のむンストヌル

# DB ずの接続

接続の蚭定はconfig/database.phpで行われる。しかし、蚭定項目の倚くはenv()ヘルパを䜿っお環境倉数から読み蟌たれ、環境倉数がない堎合だけデフォルト倀env()の第二匕数を指定する圢匏なっおいる。このため、実際の蚭定は.envファむル又は環境倉数においお行うほうがよい。

䟋えば、sqlite の堎合の蚭定は䞋蚘の通り

DB_CONNECTION=sqlite
# DB_HOST=127.0.0.1
# DB_PORT=3306
DB_DATABASE="C:\Users\SomeUser\Desktop\my-first-laravel\database\database.sqlite"
# DB_USERNAME=homestead
# DB_PASSWORD=secret

# DB クラス

# select

// コントロヌラ
use Illuminate\Support\Facades\DB;

class HelloController extends Controller
{
    public function index(Request $request) {
        $items = DB::select('select * from people');

        // or パラメヌタ結合を䜿う堎合
        $params = ['id' => 1234];
        $items = DB::select('select * from people where id = :id', $params);
    }
}

# insert

  • /hello/addに GET でアクセスした堎合は、フォヌムを衚瀺
  • /hello/addに POST でアクセスした堎合は、DB にデヌタを远加しおリダむレクト
// ルヌティング
Route::get('/hello/add', 'HelloController@showAddForm');
Route::post('/hello/add', 'HelloController@addNewData');
// コントロヌラ
class HelloController extends Controller
{
    public function showAddForm(Request $request) {
        return view('hello.add');
    }

    public function addNewData(Request $request) {
        $param = [
            'name' => $request->name,
            'mail' => $request->mail,
            'age' => $request->age,
        ];
        DB::insert('insert into people (name, mail, age) values (:name, :mail, :age)', $param);
        return redirect('/hello');
    }
}
<!-- テンプレヌト -->
<form action="/hello/edit" method="post">
  @csrf

  <div>name:<input type="text" name="name" /></div>
  <div>mail:<input type="text" name="mail" /></div>
  <div>age:<input type="text" name="age" /></div>

  <input type="submit" value="send" />
</form>

# update

  • /hello/edit に GET でアクセスした堎合は、デヌタを取埗したのち、フォヌムを衚瀺
  • /hello/update に POST でアクセスした堎合は、デヌタを曎新しおリダむレクト
// ルヌティング
Route::get('/hello/edit', 'HelloController@showEditForm');
Route::post('/hello/update', 'HelloController@updateData');
  • old('mail', $form->mail)ずするこずで、バリデヌション倱敗時に倀を保持しおおくこずができる。第二匕数はデフォルト倀であり、初回衚瀺の際に䜿甚される。
// コントロヌラ
class HelloController extends Controller
{
    public function showEditForm(Request $request) {
        $param = ['id' => $request->id];
        $item = DB::select('select * from people where id = :id', $param);
        return view('hello.edit', ['form' => $item[0]]);
    }

    public function updateData(Request $request) {
        $param = [
            'id' => $request->id,
            'name' => $request->name,
            'mail' => $request->mail,
            'age' => $request->age,
        ];
        DB::update('update people set name = :name, mail = :mail, age = :age where id = :id', $param);
        return redirect('/hello');
    }
}
<!-- テンプレヌト -->
<form action="/hello/edit" method="post">
  @csrf

  <!-- IDを保持しおおく必芁あり -->
  <input type="hidden" name="id" value="{{$form->id}}" />

  <div>
    name:<input
      type="text"
      name="name"
      value="{{ old('name', $form->name) }}"
    />
  </div>
  <div>
    mail:<input
      type="text"
      name="mail"
      value="{{ old('mail', $form->mail) }}"
    />
  </div>
  <div>
    age:<input type="text" name="age" value="{{ old('age', $form->age) }}" />
  </div>

  <input type="submit" value="send" />
</form>

# delete

  • /hello/delete に GET でアクセスした堎合は、デヌタを取埗したのち、フォヌムを衚瀺
  • /hello/delete に POST でアクセスした堎合は、デヌタを削陀しおリダむレクト
// ルヌティング
Route::get('/hello/delete', 'HelloController@showDeleteForm');
Route::post('/hello/delete', 'HelloController@removeData');
// コントロヌラ
class HelloController extends Controller
{
    public function showDeleteForm(Request $request) {
        $param = ['id' => $request->id];
        $item = DB::select('select * from people where id = :id', $param);
        return view('hello.delete', ['form' => $item[0]]);
    }

    public function removeData(Request $request) {
        $param = [
            'id' => $request->id,
        ];
        DB::delete('delete from people where id = :id', $param);
        return redirect('/hello');
    }
}
<!-- テンプレヌト -->
<form action="/hello/edit" method="post">
  @csrf

  <!-- IDを保持しおおく必芁あり -->
  <input type="hidden" name="id" value="{{$form->id}}" />

  <div>name: {{$form->name}}</div>
  <div>mail: {{$form->mail}}</div>
  <div>age: {{$form->age}}</div>

  <input type="submit" value="send" />
</form>

# ク゚リビルダ

DB::table()は、Illuminate\Database\Query\Builderクラスを返す。 これを䜿うこずでテヌブルの操䜜を行える。

# select

// コントロヌラ

// 耇数件を取埗
$items=DB::table('people')->get();
$items=DB::table('people')->get(['id', 'name']); // カラムを指定する堎合

// 最初の1件を取埗
$items=DB::table('people')->first();

// 最初の3件を取埗
$items=DB::table('people')->take(3);

// 条件を指定しお取埗
$items=DB::table('people')->where('id', $request->id)->get();
$items=DB::table('people')->where('id', $request->id)->first();
$items=DB::table('people')->where('id', '<=', $request->id)->get();
$items=DB::table('people')->where('name', 'like', '%John%')->get();

// 条件指定AND
$items=DB::table('people')->where()->where()->get();

// 条件指定or
$items=DB::table('people')->where()->orWhere()->get();

// 条件指定(条件を配列で指定)
$items=DB::table('people')->whereRaw('age >= ? and age <= ?', [10, 20])->get();

// 䞊べ替え
$items=DB::table('people')->orderBy('name', 'desc')->get();

// ペヌゞネヌションなど
$items=DB::table('people')->offset($page * 10)->limit(10)->get();

# insert

$param = [
    'name' => $request->name,
    'mail' => $request->mail,
    'age' => $request->age,
];
DB::table('people')->insert($param);

# update

$param = [
    'id' => $request->id,
    'name' => $request->name,
    'mail' => $request->mail,
    'age' => $request->age,
];
$item = DB::table('people')->where('id', $request->id)->update($param);

# delete

DB::table('people')->where('id', $request->id)->delete();

# マむグレヌション

マむグレヌション DB のバヌゞョン管理機胜のこず。雛圢に基づいお DB を䜜成したり、削陀したりする。

䜿甚できる Column に぀いおは公匏ドキュメント (opens new window)を参照

# Eloquentのモデル䜜成時に、マむグレヌションファむルを䞀緒に䜜成する方法
php artisan make:model Person -m

# マむグレヌションを単䜓で䜜成する方法
php artisan make:migration create_people_table # people がテヌブル名になる
// database/migration/****_create_people_table.php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreatePeopleTable extends Migration
{
    // テヌブル生成の凊理
    public function up()
    {
        Schema::create('people', function (Blueprint $table) {
            $table->increments('id'); // primary key
            $table->string('name');
            $table->string('mail');
            $table->integer('age');
            $table->timestamps(); // created_at, updated_at
        });
    }

    // テヌブル削陀の凊理
    public function down()
    {
        Schema::dropIfExists('people');
    }
}
touch database/database.sqlite # 空のDBファむルを䜜成
php artisan migrate
php artisan migrate:fresh # すべおのテヌブルをドロップしお再䜜成

# あずからカラムを远加する

class AddUserIdToPosts extends Migration
{
    public function up() {
        Schema::table('posts', function (Blueprint $table) {
            // 列を远加する
            $table->integer('user_id');
        });
    }

    public function down() {
        Schema::table('posts', function (Blueprint $table) {
            // ロヌルバック時には列を削陀する
            $table->dropColumn('user_id');
        });
    }
}

# シヌディング

シヌディングシヌド最初から甚意しおおくレコヌドを䜜成する機胜

php artisan make:seeder PeopleTableSeeder
// database/seeds/PeopleTableSeeder

use Illuminate\Support\Facades\DB;

class PeopleTableSeeder extends Seeder
{
    public function run()
    {
        $param = [
            'name' => 'taro',
            'mail' => 'taro@taro.com',
            'age' => 18,
        ];
        DB::table('people')->insert($param);
        /* 必芁に応じお曎にデヌタを远加する */
    }
}

シヌディングで実行されるファむルはdatabase/seeds/DatabaseSeeder.phpなので、ここに䜜成したシヌダヌを远蚘しおおく。

class DatabaseSeeder extends Seeder
{
    public function run()
    {
        $this->call(PeopleTableSeeder::class);
    }
}
php artisan db:seed

# Eloquent ORM

ORM  DB のデヌタを、クラスやオブゞェクトの圢匏で扱えるようにするために、PHP ず DB を橋枡しする仕組み

# セットアップ

php artisan make:controller PersonController # 耇数圢にするこず

php artisan make:model Person # 単数圢にするこず
# or
php artisan make:model Person -m # -mを぀けるずマむグレヌションファむルも生成される
// ルヌティング
Route::get('/person', 'PersonController@index');

# モデルクラス

モデルず DB を玐付けるための各皮蚭定や、モデルを䟿利に扱うためのクラスの拡匵をここで行う。

ORM ず DB クラスずの盞違点は、デヌタが単なる配列ではなくPerson クラスのむンスタンスである点である。このため、クラスを拡匵すればむンスタンスの振る舞いも拡匵するこずができる。

// app/Person.php
class Person extends Model
{
    // テヌブル名を手動蚭定する堎合(default: モデル名の耇数圢)
    protected $table = 'people';

    // primary keyを手動蚭定する堎合(default: id)
    public $primaryKey = 'id';

    // Auto Increment な項目など、倀をサヌバ偎で
    // 蚭定するプロパティはここで明瀺しおおくこず
    protected $guarded = ['id'];

    // モデルクラスのスタティックプロパティにバリデヌションルヌルを
    // 持っおおくず埌々䟿利
    public static $rules = [
        'name' => 'required',
        'mail' => 'email',
        'age' => 'integer|min:0|max:150',
    ];

    // クラスの拡匵
    public function getData() {
        return $this->id.':'.$this->message.'('.$this->url.')';
    }
}

# デヌタの取埗

# all()

$items = Person::all();

党件取埗できる。Person::all()は、Illuminate\Database\Eloquent\Collectionクラスのむンスタンスを返す。このむンスタンスは配列ず同じように扱うこずができる。

# find()

$item = Person::find($request->id);

id フィヌルドが指定の倀であるデヌタを 1 件だけ取埗する。

なお、もし id フィヌルドの名前がidでない堎合は、モデルクラスに$primaryKeyずいうプロパティを甚意し、これにフィヌルド名を蚭定するこず。

# where()

$items = Person::where('name', 'John')->get();
$items = Person::where('name', 'John')->first();

where()はIlluminate\Database\Eloquent\Builderクラスのむンスタンスを返す。DB クラスのク゚リビルダずは異なるものの、機胜はほずんど同じ。

# その他

その他のメ゜ッドは基本的にク゚リビルダず同じ。

# スコヌプ

  • スコヌプ予め蚭定しおおいた怜玢条件の雛圢。組み合わせお䜿うこずもできる。
  • グロヌバルスコヌプずロヌカルスコヌプがある

# ロヌカルスコヌプ

scope****ずいう名前で定矩する。

// モデル
class Person extends Model
{
    public function scopeNameEqual($query, $str) {
        return $query->where('name', $str);
    }

    public function scopeAgeGreaterThan($query, $age) {
        return $query->where('age', '>', $age);
    }

    public function scopeAgeLessThan($query, $age) {
        return $query->where('age', '<', $age);
    }
}
  • 䜿うずきはscopeは぀けない。
  • 耇数のスコヌプを組み合わせる堎合は、チェヌンしお䜿う。
// コントロヌラ
$item = Person::nameEqual('taro')
    ->ageGreaterThan(10)
    ->ageLessThan(20)
    ->where('mail', 'taro@taro.com')
    ->first();

# グロヌバルスコヌプ(無名関数で指定)

特に指定しなくおもスコヌプを適甚したい堎合は、グロヌバルスコヌプを䜿う。 グロヌバルスコヌプは、モデルクラスのboot()ずいう静的メ゜ッド内郚で定矩する。

// モデル

use Illuminate\Database\Eloquent\Builder;

class Person extends Model
{
    protected static function boot(){
        parent::boot();

        static::addGlobalScope('age', function (Builder $builder){
            $builder->where('age', '>', 17);
        });
    }
}

# グロヌバルスコヌプ(スコヌプクラスで指定)

  • 前項をスコヌプクラスで行う方法。
  • Scope クラスは、apply()ファンクションをも぀Scopeむンタヌフェヌスを実装する。
// app/Scopes/ScopePerson.php (Scopesのフォルダ名はなんでもOK)

namespace App\Scopes;

use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

class ScopePerson implements Scope{
    public function apply(Builder $builder, Model $model) {
        $builder->where('age', '>', 10);
    }
}
// モデル
class Person extends Model
{
    protected static function boot(){
        parent::boot();
        static::addGlobalScope(new ScopePerson());
    }
}

# デヌタの远加・曎新・削陀

以䞋、Create, Update, Delete のやり方を蚘茉。なお、テンプレヌトのコヌドはDB クラスを䜿ったコヌドずほが同じなため蚘茉省略。

# 远加

// ルヌティング
Route::get('/person/add', 'PersonController@add');
Route::post('/person/add', 'PersonController@create');
class PersonController extends Controller
{
    public function add(Request $request) {
        return view('person.add');
    }

    public function create(Request $request) {
        // バリデヌトする。倱敗したらGETのルヌティングにリダむレクトされる。
        $this->validate($request, Person::$rules);

        // むンスタンスを䜜成
        $person = new Person();

        // 【方法1】リク゚ストにぶら䞋がっおいる倀をむンスタンスにセットし、DBに保存
        $postData = $request->all();
        $person->fill($postData)->save();

        // 【方法2】リク゚ストのデヌタをむンスタンスに䞀぀ず぀セットしお、DBに保存
        $person->name = $request->name;
        $person->mail = $request->mail;
        $person->age = $request->age;
        $person->save();

        return redirect('/hello');
    }
}

# 曎新

// ルヌティング
Route::get('/person/edit', 'PersonController@edit');
Route::post('/person/edit', 'PersonController@update');
// コントロヌラ
class PersonController extends Controller
{
    public function edit(Request $request) {
        $person = Person::find($request->id);
        return view('person.edit', ['form'=> $person]);
    }

    public function update(Request $request) {
        // バリデヌトする。倱敗したらGETのルヌティングにリダむレクトされる。
        $this->validate($request, Person::$rules);

        // むンスタンスを䜜成
        $person = Person::find($request->id);

        // リク゚ストにぶら䞋がっおいる倀をむンスタンスにセットし、DBに保存
        $postData = $request->all();
        $person->fill($postData)->save();

        return redirect('/person');
    }
}

# 削陀

// ルヌティング
Route::get('/person/delete', 'PersonController@delete');
Route::post('/person/delete', 'PersonController@remove');
// コントロヌラ
class PersonController extends Controller
{
    public function delete(Request $request) {
        $person = Person::find($request->id);
        return view('person.delete', ['form'=> $person]);
    }

    public function remove(Request $request) {
        $person = Person::find($request->id)->delete();
        return redirect('/person');
    }
}

# リレヌション

  • 䞻テヌブルキヌを提䟛するテヌブル。顧客マスタなど。
  • 埓テヌブルキヌを利甚するテヌブル。顧客蚪問履歎など。

# hasOne

テヌブルが 1:1 で結び぀く関係。

䟋person ず board が 1:で結び぀く堎合

class Person extends Model
{
    // 単数圢
    public function board() {
        return $this->hasOne('App\Board');
    }
}
class Board extends Model
{
    protected $guarded = ['id'];

    public static $rules = [
        'person_id' => 'required', // 「テヌブル名_id」ずいうキヌで自動的に結び付けられる
        'title' => 'required',
        'message' => 'required',
    ];
}
// personむンスタンスからは、`board()`ではなく`board`のようにプロパティでアクセスできる。
// hasOneの堎合は、オブゞェクトが返る。
echo $person->board->message;

# hasMany

テヌブルが 1:N で結び぀く関係。

䟋person ず board が 1:N で結び぀く堎合

class Person extends Model
{
    // 耇数圢
    public function boards() {
        return $this->hasMany('App\Board');
    }
}
class Board extends Model
{
    protected $guarded = ['id'];

    public static $rules = [
        'person_id' => 'required', // 「テヌブル名_id」ずいうキヌで自動的に結び付けられる
        'title' => 'required',
        'message' => 'required',
    ];
}
// personむンスタンスからは、`board()`ではなく`board`のようにプロパティでアクセスできる。
// hasManyの堎合は、オブゞェクトではなくむテラブルが返る。
@foreach ($person->boards as $board)
  echo $board->message;
@endforeach

# belongsTo

埓テヌブルから䞻テヌブルを取埗する時に䜿う。hasOne や hasMany ずは逆の方向。

䟋board が person に所属する堎合

class Board extends Model
{
    public static $rules = [
        'person_id' => 'required', // このキヌを基にルックアップする
        'title' => 'required',
        'message' => 'required',
    ];

    public function person() {
        return $this->belongsTo('App\Person');
    }

    public function getData() {
        // $this->personで䞻テヌブルにアクセスできる
        return $this->id.': '.$this->title.'('.$this->person->name.')';
    }
}

# リレヌションの有無で怜玢する

䟋えば、person ず board が 1:N で関連する堎合、boardリレヌションを持぀ person ずそうでない person が生たれる。これを怜玢するための䟿利なメ゜ッドずしお、has()ずdoesntHave()がある。

Person::has('boards')->get(); // => iterable
Person::doesntHave('boards')->get(); // => iterable

# with による Eager ロヌディング

前述の䟋は、実はあたり効率的でない。たずえば、Person::all()ずした時、「Person を取埗、その埌 Person1 件ごずに、関連付けられた Board を取埗」ずいう動䜜になっおいる。N+1 問題

これを、「Person を取埗、その埌、関連する Board を 1 回で取埗」ずいう方法にするには、all()の替わりにwith()を䜿う。

Person::with('boards')->get();

# Tinker

モデルを䜿っお DB を操䜜できる、REPL のようなもの。

php artisan tinker
App\Post::count()
App\Post::all()
App\Post::where('title','Post1')->get()
App\Post::find($id)->delete()

$post = new App\Post()
$post->title = 'Post1'
$post->body = 'Post1 body'
$post->save()

# フロント゚ンド

# セットアップ

䞋蚘コマンドを実行するこずで、resouces/js|cssのファむルがコンパむルされ、public/js|cssに配眮される。

yarn
yarn dev # 1回きりのコンパむル
yarn watch # ファむルの倉曎を監芖しおコンパむル

# CSS

  • Laravel のプロゞェクトには、resources/sassの䞭に暙準で CSS が甚意されおいる。
  • この CSS は Bootstrap を内包しおいる。
  • Pagination のパヌツなどはこの CSS ファむルを前提にでスタむリングされおいる。
<head>
  <link rel="stylesheet" href="{{ asset('css/app.css') }}" />
</head>

# その他

# RESTful API

# セットアップ

たず、--apiオプションにより、RESTful なコントロヌラを䜜成する。逆に、Resourceful なコントロヌラを䜜るずきは--resourceオプションを䜿う

REST API では create()や edit()アクションは必芁ないので䜜成されない。

php artisan make:controller RestappContoller --api

䜜成したコントロヌラをRoute::apiResources()に枡す。Route::resources()ず異なり、create()や edit()のためのルヌトは必芁ないので䜜成されない。

Route::apiResources('/rest', 'RestappController');

# デヌタの取埗

  • laravel では、アクション内で配列 | Eloquent の Collection | モデルのむンスタンスを Return するず自動的に JSON に倉換しおクラむアントに返しおくれる。
  • よっお、単に DB を怜玢しお Return しおやれば OK
class RestappController extends Controller
{
    public function index()
    {
        return Restdata::all();
    }

    public function show($id)
    {
        return Restdata::find($id);
    }
}

# デヌタの远加

class RestappController extends Controller
{
    public function create()
    {
        return view('rest.create');
    }

    public function store(Request $request)
    {
        $restdata = new Restdata();
        $postData = $request->all();
        $restdata->fill($postData)->save();
        return redirect('/rest');
    }
}

# デヌタの曎新・削陀

省略

# セッション

  • クラむアント偎にセッション ID を、サヌバ偎に ID に玐づくデヌタを保存するこずで、ナヌザを識別する方法
  • サヌバ偎の保存手法には、ファむル利甚デフォルト。storage/framework/sessions、メモリ利甚、デヌタベヌス利甚などいく぀かの方法がある。
// 保存
$request->session()->put('msg', $msg);

// 取埗
$request->session()->get('msg');

// セッション情報ずずもにリダむレクト
redirect('/home')->with('somekey', 'somevalue');

# 保存先を DB にする

セッションの蚭定はconfig/session.phpで行われる。倚くの蚭定は env ヘルパにより環境倉数から読み蟌たれるため、.envを線集する。

// .env
SESSION_DRIVER=database

session 甚のテヌブルを䜜成する。手䜜業ではなく、マむグレヌションを䜿甚する。

php artisan session:table # マむグレヌションファむルの䜜成
php artisan migrate # マむグレヌションの実行

# リダむレクト時にセッションを䜿っお゚ラヌメッセヌゞを衚瀺する

䞋蚘のような、メッセヌゞ衚瀺甚コンポヌネントを䜜成しお、マスタヌレむアりトに include しおおく。

// 'success'ずいうセッション倀があった堎合
@if (session('success'))
    <div class="alert alert-success">
        {{ session('success')}}
    </div>
@endif

// 'error'ずいうセッション倀があった堎合
@if (session('error'))
    <div class="alert alert-danger">
        {{ session('error')}}
    </div>
@endif

// ぀いでに、バリデヌション倱敗時の゚ラヌも衚瀺
@if (count($errors) > 0)
    @foreach ($errors->all() as $error)
        <div class="alert alert-danger">{{ $error }}</div>
    @endforeach
@endif

コントロヌラでリダむレクトする際にセッション倀をセットする。

return redirect('/posts')
  ->with('success', 'Post Created');

# ペヌゞネヌション

all()やwith()の替わりに、simplePaginate()を䜿うこずで簡単にペヌゞネヌションを実装できる。

//コントロヌラ

// DBクラスの堎合
$items=DB::table('people')->simplePaginate(5);
$items=DB::table('people')->orderBy('age')->simplePaginate(5);
// モデルの堎合
$items=Person::simplePaginate(4);
$items=Person::orderBy('age')->simplePaginate(4);

return view('hello.index', ['items'=>$items]);
// テンプレヌト

// 前埌ペヌゞぞのリンクを自動生成する
{{ $items->links() }}

// 前埌ペヌゞぞのリンクに察しお远加のク゚リを付䞎したい堎合は、appends()を挟む
{{ $items->appends(['sort'=>$sort])->links() }} // => /some?sort=***&page=2

# ペヌゞ番号のリンクを衚瀺する

simplePaginate()の替わりにpaginate()を䜿うず、自動生成されるリンクに、ペヌゞ番号も含たれる様になる。

# カスタムレむアりト

  • links()に匕数を指定するこずで、ペヌゞネヌションのレむアりトをカスタムできる。
  • 䞋蚘コマンドで雛圢を生成できるので、適宜利甚する
php artisan vendor:publish --tag=laravel-pagination

# ナヌザ認蚌

# セットアップ

䞋蚘コマンドで関連するファむルが自動生成される。生成されたファむルをベヌスに移怍を行うずお手軜である。

php artisan make:auth # 関連するRoute, View, Controllerを生成する
php artisan migrate # 認蚌に䜿うテヌブルを䜜成

Auth::user() ナヌザ情報の取埗

// コントロヌラ
use Illuminate\Support\Facades\Auth;

class HelloController extends Controller {
  $user = Auth::user();
  return view('some.view', ['user' => $user]);
}

Auth::check() ナヌザがログむンしおいるかどうか

// テンプレヌト
@if (Auth::check())
    <p>{{$user->name}}</p>
    <p>{{$user->email}}</p>
@else
    <p>ログむンしおいたせん</p>
    <a href="/login">ログむン</a>|
    <a href="/register">登録</a>
@endif

# 既補のルヌティング

  • /login ログむン
  • /register サむンアップ
  • /home アカりント管理画面

# ログむンの匷制

authずいうミドルりェアを䜿うこずで、特定のルヌトを閲芧する際にログむンを矯正できる。ログむンしおいない堎合は/loginにリダむレクトされる。

Route::get('/hello', 'HelloController@index')
    ->middleware('auth');

# ログむンのマニュアル実装

if(Auth::attempt(['email'=>$mail, 'password'=>$pass])){
  /* on success */
} else {
  /* on fail */
}

# ナニットテスト

テストはTestCaseクラスを継承したクラスに察し、test****()ずいうメ゜ッドを実装するこずで行う。

# 蚭定ファむル

テストに関する蚭定はphpunit.xmlで行う。

<!-- テスト甚のデヌタベヌスを指定 -->
<env name="DB_DATABASE" value="database\database_test.sqlite"/>

# ダミヌレコヌドの甚意

テスト甚のダミヌデヌタを䜜成するには、database/factoriesの䞭にある Model Factories を䜿う。

// database/factories/ModelFactory.php
$factory->define(App\Person::class, function (Faker $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->safeEmail,
        'age' => $faker->random_int(1,99),
    ];
});

# テストファむルの䜜成ず実行

php artisan make:test HelloTest
// tests/Feature/HelloTest.php
class HelloTest extends TestCase
{
    public function testExample()
    {
        $this->assertTrue(true);

        $arr = [];
        $this->assertEmpty($arr);

        $msg = 'Hello';
        $this->assertEquals($msg, 'Hello');

        $number = random_int(0, 100);
        $this->assertLessThan(100, $number);
    }
}
vendor/bin/phpunit

# ルヌティングや認蚌をテストする

class HelloTest extends TestCase
{
    use DatabaseMigrations;

    public function testExample()
    {
        // ルヌティングのテスト
        $response = $this->get('/');
        $response->assertStatus(200);

        $response = $this->get('/hello');
        $response->assertStatus(302);

        $response = $this->get('/no_routes');
        $response->assertStatus(404);

        // 認蚌のテスト
        $user = factory(User::class)->create();
        $response = $this->actingAs($user)->get('/hello');
        $response->assertStatus(200);
    }
}

factory(クラス名)->create() ファクトリの蚭定を基にむンスタンスを生成しお DB に保存する

# デヌタベヌスのテスト

class HelloTest extends TestCase
{
    // テスト開始前にマむグレヌションを実行し、終了埌にたっさらに戻す
    use DatabaseMigrations;

    public function testExample()
    {
        $dummyPerson = [
            'name' => 'XXX',
            'mail' => 'YYY@ZZZ.COM',
            'age' => 123,
        ];

        // ファクトリの蚭定を䞀郚䞊曞きしおむンスタンスを生成しDBに保存
        factory(Person::class)->create($dummyPerson);

        // 指定した数のむンスタンスをDBに保存
        factory(Person::class, 10)->create();

        $this->assertDatabaseHas('people', $dummyPerson);
    }
}

# 環境倉数やコンフィグの取埗

コントロヌラやテンプレヌト内で、環境倉数等を取埗する方法

// 環境倉数の取埗
env('APP_NAME');

// コンフィグの取埗
config('app.name');

# WYSIWYG

WYSIWYG ゚ディタを実装するには、ckeditor (opens new window)ず、無害化のための Purifier (opens new window)を組み合わせる。

chkeditor の蚭定

<textarea name="sometextarea"></textarea>

<script src="https://cdn.ckeditor.com/4.11.1/standard/ckeditor.js"></script>
<script>
  CKEDITOR.replace('sometextarea');
</script>

Purifier の蚭定

composer require mews/purifier
php artisan vendor:publish --provider="Mews\Purifier\PurifierServiceProvider"

コントロヌラ

use Mews\Purifier\Facades\Purifier;
// .....
Purifier::clean($request->someInputValue);