Laravel 入門

# 前置
Laravelのドキュメントがよくわからないので、自分用のメモとして作成。
網羅はできていません。追記もしていきます。

5.4のドキュメントを参考にしています。

# 開発環境
※ホストはWindows
(だけど、GitBASHつかうからコマンド的にはLinux)

## 前準備
- XAMP(ホストでphpコマンド叩きたい)
- GitBASH(CUI叩きやすければ別に何でもいい)
- Composer(インストールした場所のvendor/binをパスに指定しておく)
- VirtualBox
- Vagrant

## プロジェクト作成
**laravelコマンド**

```bash
composer global require "laravel/installer"
```

**プロジェクト(ディレクトリ)作成**

```bash
laravel new 名前
```

## Homestead
laravel公式のbox。

**プロジェクトにHomesteadを含める**

```bash
cd プロジェクト
composer require laravel/homestead --dev
sh vendor/bin/homestead make
```

**※デフォルトでデータベースを増やす**

```vim:Homestead.yaml
databases:
    - homestead
    - new_database # 追加すると、デフォルトでこのデータベースが増えてる
```
ちなみにDBのユーザ名/パスワードは「homestead/secret」で用意されている。

->[DBの初期構成も加えたいなら](http://qiita.com/tsuuuuu_san/items/8107b276efc4e07c43d6#%E3%83%9E%E3%82%A4%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3)
->[テーブルの初期値も加えたいなら](http://qiita.com/tsuuuuu_san/items/8107b276efc4e07c43d6#%E3%82%B7%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0)

**Homestead起動**

```bash
vagrant up
```

**サーバ起動**

```bash
php artisan serve
```
http://127.0.0.1:8000/
にアクセスできれば成功

**※表示がうまくいかなかったら**

```.env.exampleがあるけど、.envがない
cp -p .env.example .env
```

```Homestead内に共有用のディレクトリがない
vagrant ssh 
ls /home/vagrant/ | grep Code
mkdir -p /home/vagrant/Code
```

# ディレクトリ構成
|階層1|階層2|説明|
|:--:|:--:|:--:|
|app||主要なファイルは全部ここに入る|
|L|Console|コマンドクラスが格納される|
|L|Exceptions|例外ハンドラ|
|L|Http|コントローラ、ミドルウェア、フォームリクエスト|
|L|Providers|サービスプロバイダ|
|bootstrap||初期起動、オートローディング|
|config||設定ファイル置き場|
|database||DBのマイグレや初期値設定のファイル郡|
|public||index.php|
|resources||ビューやアセットの元ファイル郡|
|routes||ルート定義を持つファイル郡|
|strage||フレームワークが作るキャッシュとか|
|tests||テスト用|
|vendor||Composer用|
|.env||環境設定ファイル|

# 用語集
|用語|説明|
|:--|:--|
|契約|インターフェースのこと|

# 設定ファイル
「config」配下に格納されており、.envファイルで環境毎のデフォルトを設定する。
.envの値は、

```php
env('key', 'デフォルト値')
```

で取得できる。

|ファイル|設定|説明|.env|備考|
|:--|:--|:--|:--|:--|
|app.php|name|アプリケーション名|APP_NAME||
||env|環境名|APP_ENV||
||debug|デバッグモード|APP_DEBUG||
||url|コンソールで使用するURL?|APP_URL||
||timezone|date系の関数で使用されるタイムゾーン|-|デフォルトUTCです。日本なら「Asia/Tokyo」に直す。|
||locale|ロケール|-|日本なら「ja」にした方が良い|
||fallback_locale|指定ロケールが存在しない時に使用|||
||key|要設定の暗号化キー|APP_KEY|「php artisan key:generate」で設定|
||cipher|暗号化キーに何か|-||
||log|ログファイルの出力方法|APP_LOG|"single", "daily", "syslog", "errorlog"|
||log_max_files|log=>"daily"の場合の保存日数|-||
||log_level|指定値以上をログに出力|APP_LOG_LEVEL||
||providers|自動読込サービスプロバイダ|-||
||aliases|クラスのエイリアス|-|デフォルトでは大半がファサードのよう|
|auth.php|||||
|bloadcasting.php|||||
|cache.php|||||
|database.php|default|デフォルトで使用するDB|DB_CONNECTION||
||connections|DBの接続設定|DB_HOST<br />DB_PORT<br />DB_DATABASE<br />DB_USERNAME<br />DB_PASSWORD|細かい設定は実際に見た方が良い<br /><br />localの場合MySQLポートは33060|
||migrations||||
||redis|||redis用設定|
|filesystemes.php|||||
|mail.php|||||
|queue.php|||||
|services.php|||||
|session.php|driver|セッションドライバ|SESSION_DRIVER|"file", "cookie", "database", "apc","memcached", "redis", "array"|
|view.php|||||

# ライフサイクル
**[1]index.php**
入り口。
オートローダの読み込み。
使用するカーネルの分岐とそのhandleメソッドの呼び出し。

**[2]カーネル (app/Http|console/Kernel.php)**
アプリケーションがリクエストを処理する前の処理定義
ファサードやサービスプロバイダのロード。(registerメソッドの実行)
ミドルウェアの実行。
コントローラ等に処理を委譲。

**[3]コントローラ**
**[4]ビュー**

# コントローラ
## コントローラの作成
```bash
php artisan make:controller コントローラ名
```
⇒「app/Http/Controller/コントローラ名.php」が作成される

## 関数とルーティング
```php:app/Http/Controller/コントローラ名.php
public function 関数名() {
  return view('user');
}
```

```php:routes/web.php
Route::get('URI', 'コントローラ名@関数名');
//Route::post('URI', 'コントローラ名@関数名');
//Route::put('URI', 'コントローラ名@関数名');
//Route::patch('URI', 'コントローラ名@関数名');
//Route::delete('URI', 'コントローラ名@関数名');
//Route::options('URI', 'コントローラ名@関数名');
//Route::match(['get', 'post'], 'URI', 'コントローラ名@関数名');
//Route::any('URI', 'コントローラ名@関数名');
```
※コントローラ名の指定にて、名前空間の「App\Http\Controllers」は指定が不要

## routeキャッシュ
コントローラベースのルート定義だけを使用しているなら、
下記のコマンドを打つだけで、全ルート登録が早くなるらしい。
開発後の最後にコマンド打てばいい。

```
php artisan route:cache
```

## ビューの表示とレスポンスパラメータ
viewヘルパを使う。

```php:例
view('ビュー名', ['name' => 'hoge']);
```

第1引数：「resources/views/ビュー名.blade.php」と対応
第2引数：ビューに渡すデータ。例ではname変数で参照できる。

## リクエストパラメータの受け取り方
「Illuminate\Http\Request」クラスをタイプヒントで指定すると、
DIされて使えるようになる。

**Request->input('パラメータ名'[, 'デフォルト値'])**
で、値が取得できる。
※配列の入力はドット記法でアクセスできる。

```php:app/Http/Controller/コントローラ名.php
public function show(Request $req)
{
  return view('user', ['name' => $req->input('name')]);
}
```

※リクエストは、デフォルトのミドルウェアにより、「トリム」「空文字⇒null」の処理が行われる

## URIのパラメータを受け取る
### パラメータが必須
```php:app/Http/Controller/コントローラ名.php
public function show(Request $req, $id)
{
  return view('user', ['name' => $req->input('name')]);
}
```

```php:routes/web.php
Route::get('URI/{id}', 'コントローラ名@関数名');
```

### パラメータが任意
```php:app/Http/Controller/コントローラ名.php
// 引数にはデフォルト値が必要
public function show(Request $req, $id = '')
{
  return view('user', [
    'id' => $id,
    'name' => $req->input('name'),
  ]);
}
```

```php:routes/web.php
// パラメータには「?」を付ける
Route::get('URI/{id?}', 'コントローラ名@関数名');
```

## バリデーション
### コントローラに埋め込む方法
「App\Http\Controllers\Controller」に
「ValidatesRequests」トレイトが使われているため、
特に意識せずコントローラに埋め込める。

バリデーションに引っかかった場合、自動的に以前のページにリダイレクトされる。
エラーメッセージはViewにて、「$errors」に格納される。

```php:バリデーション例
$this->validate($request, [
  'title' => 'required|unique:posts|max:255',
  'body' => 'required',
]);
```

```html:ビューでエラーメッセージを表示
@if ($errors->any())
  <ul>
    @foreach ($errors->all() as $error)
      <li>{{ $error }}</li>
    @endforeach
  </ul>
@endif
```

### FormRequestを使う方法(外部ファイルにする)
FormRequestはカスタムRequestクラスで、バリデーションロジックを含んでいる。

```bash:FormRequest作成
php artisan make:request フォームリクエスト名
```
⇒「app/Http/Requests/フォームリクエスト名.php」が作成される。

```php:フォームリクエスト名.php
namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class フォームリクエスト名 extends FormRequest
{
  public function authorize()
  {
    //認証用、特に考えてなければtrueにしておく
    return true;
  }

  public function rules()
  {
    //ここにバリデーションかく
    return [
      'name' => 'required',
    ];
  }

  public function messages()
  {
    // カスタムエラーメッセージ
    return [
      'name.required' => '名前がねーよ',
    ];
  }
}
```

```php:コントローラでタイプヒント
public function show(フォームリクエスト名 $req)
{
}
```

### よく使いそうなルール
|ルール|説明|
|:--|:--|
|bail|ひとつでもバリデーションに引っかかったら判定停止|
|required|必須|
|present|フィールドが存在しているか|
|nullable|nullを許容する|
|string|文字列か|
|integer|整数値か|
|numeric|数値か|
|digits:値|数値の桁数|
|digits_between:最小値,最大値|数値の桁範囲|
|between:min,max|サイズの範囲内か|
|date_format:フォーマット|日付形式|
|regex:正規表現|正規表現にマッチするか|

# ビュー
## どこに作る
resources/views/ビュー名.blade.php

## CSRF保護
LaravelはPOST、PUT、DELETEにCSRF保護のチェックが入る。

ので、ビューに隠しCSRFトークンフィールドを含める必要がある。

```php:トークン埋め込み例
<form method="POST" action="/profile">
  {{csrf_field()}}
</form>
```

### そもそもチェックはずしたい
「app/Http/Kernel.php」のミドルウェアの設定から、
「\App\Http\Middleware\VerifyCsrfToken::class,」の記載を削除する。

### 一部のURIだけはずしたい
```php:app/Http/Middleware/VerifyCsfToken.php
protected $except = [
  // 除外したいルートを指定
  'user',
];
```

## Blade
テンプレートエンジン。

### データ表示
```php:一般的な使い方
{{ $hoge }}
```

```php:HTMLエスケープしない
{!! $hoge !!}
```

### 構文
```php:if
@if (count($records) === 1)
@elseif (count($records) > 1)
@else
@endif
```

```php:phpの便利な関数
@isset($hoge)
@endisset

@empty($hoge)
@endempty
```

```php:for
@for ($i = 0; $i < 10; $i++)
@endfor
```

```php:foreach
@foreach ($users as $user)
@endforeach
```

```php:while
@while (true)
  //@continue,@breakもつかえる
@endwhile
```

### コメント
```php
{{-- コメント --}}
```

### phpブロック
```php
@php
@endphp
```

### サービス注入
```php
@inject('サービス名', '解決クラス名')
```

# HTTPリクエスト
## 入力値チェック
```
if ($request->has('name')) {
}
```

# レスポンス
## レスポンスオブジェクト
「Illuminate\Http\Response」クラスを用いる。

```php:例
response('Hello World', 200)
  ->withHeaders([
    'Content-Type' => $type,
    'X-Header-One' => 'Header Value',
    'X-Header-Two' => 'Header Value',
  ]);
```

## JSONレスポンス
```php:例
response()->json([
  'name' => 'Abigail',
  'state' => 'CA'
])
```

# セッション
## セッションドライバ
Laravelはセッションをどこに保存するか、最初からいくつか選べる。

デフォルトは、fileセッションドライバ。
(strage/framework/sessionに保存)

## Requestインスタンスを使用する方法
```php:取得
public function show(Request $request)
{
  //第2引数にデフォルト値を設定可能
  $value = $request->session()->get('key');
}
```

```php:保存
$request->session()->put('key', 'value');
```

### セット

## Sessionグローバルヘルパを使用する方法
```php:取得
$value = session('key');
```

```php:保存
session(['key' => 'value']);
```

# ログ
LaravelではMonologを使用しており、
デフォルトでエラーと例外はログするように設定されている。

## ログに書き込み
```php
Log::emergency($message);
Log::alert($message);
Log::critical($message);
Log::error($message);
Log::warning($message);
Log::notice($message);
Log::info($message);
Log::debug($message);
```

# ミドルウェア
リクエストを処理する前や後に行う処理のこと。
フィルタリングするーみたいな言い方をする。

## ミドルウェアの作成
```bash:artisanコマンド
php artisan make:middleware ミドルウェア名
```
⇒app/Http/Middleware/ミドルウェア名.phpが作成される

```php:作成されるクラス
<?php

namespace App\Http\Middleware;

use Closure;

class ミドルウェア名
{
    public function handle($request, Closure $next)
    {
        return $next($request);
    }
}
```

## ミドルウェアの登録
### 全リクエストに適用
「app/Http/Kernel.php」のプロパティ「$middleware」に含める。

### 特定のルートに適用
ルートファイル(routes/web.phpとか)のルートに、
完全なクラス名、ミドルウェアの短縮名、ミドルウェアグループ名
を指定。

```php
// 複数登録したいときは第2引数、第3引数・・に書いていく
Route::get('URI', 'コントローラ名@関数名')
->middleware('sample');
```

**※短縮名**
「app/Http/Kernel.php」に
短縮名をキー、値を完全なクラス名で登録。

```php
protected $routeMiddleware = [
  'sample' => \App\Http\Middleware\SampleMiddleware::class,
];
```

**※ミドルウェアグループ**
複数のミドルウェアをひとつのキーでまとめ、
「app/Http/Kernel.php」に登録。

```php
protected $middlewareGroups = [
  'sample' => [
    \App\Http\Middleware\SampleMiddleware::class,
    \App\Http\Middleware\TestMiddleware::class,
  ],
];
```

## アクションのタイミング
「\$next($request)」は、アプリケーションに処理を委譲し、
レスポンスを取得する。

ので、

```php
public function handle($request, Closure $next)
{
  //前処理をここにかく

  return $next($request);
}
```

↑こうかけば、ミドルウェアのアクションはリクエストより前に行われ、

```php
public function handle($request, Closure $next)
{
  $response = $next($request);

  //後処理をここにかく

  return $response;
}
```

↑こうかけば、ミドルウェアのアクションはリクエストより後に行われる。

## パラメータのとり方
```php
public function handle($request, Closure $next)
{
  echo $request->name;

  return $next($request);
}
```

## ミドルウェアパラメータ
ミドルウェアとルートの結合の際に、パラメータを指定することができ、
それをミドルウェアで受け取ることができる。

```php:routes/web.php
// ミドルウェアの指定で、「:」の後にパラメータをつける
Route::get('URI', 'コントローラ名@関数名')
->middleware('sample:hoge');
```

```php:ミドルウェア
// $nextの後にリクエストパラメータを受け取る引数を指定できる
 public function handle($request, Closure $next, $midle_param)
{
　　if ($request->param == $midle_param) {
            return redirect('/');
　　}

　　return $next($request);
 }
```

# サービスプロバイダとは
初期起動時にロードされるもので、
サービスコンテナの結合、イベントリスナ、フィルター、ルートなどを登録しておく場所。

プロバイダはregisterメソッドとbootメソッドを主としており、

**[1]全プロバイダのregisterメソッドが呼ばれる
[2]次に全プロバイダのbootメソッドが呼ばれる**

という動作を行う。


## プロバイダの作成
```bash:artisanコマンド
php artisan make:provider プロバイダ名
```
⇒app/Providers/プロバイダ名.phpが作成される

```php:作成されるプロバイダ例
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class SampleProvider extends ServiceProvider
{
  public function boot()
  {
  }

  public function register()
  {
  }
}
```

### registerメソッド
**サービスコンテナへの登録(結合)のみ**を行うところ。

詳しくは「サービスコンテナとは」にて記載。

#### コンテナの結合を遅らせる
プロバイダの役目が**コンテナの結合のみ**なら、
リクエストするまでロードをさせなくできる。

パフォーマンスあっぷ。

```php
class SampleProvider extends ServiceProvider
{
  // [1] $defer = trueを設定
  protected $defer = true;

  public function register()
  {
    $this->app->singleton(Hoge::class, function ($app) {
      return new Hoge();
    });
  }

  // [2] providersメソッド内にて、プロバイダで登録するコンテナ結合名を返す
  public function provides()
  {
    return [Hoge::class];
  }
}
```

### bootメソッド
他の全サービスプロバイダが登録し終えてから呼び出される。

詳しくは、他機能の登録にて記載。

## プロバイダの登録
「config/app.php」に登録。

```php
'providers' => [
  App\Providers\SampleProvider::class,
],
```

# サービスコンテナとは
DIコンテナのこと。

```lang:ちゃんと調べ切れてないところ
・「Illuminate\Contracts\Container\Container」クラスがその基本機能を担っている

・Containerクラスを継承した「Illuminate\Foundation\Application」がみんながサービスコンテナと考えるもの（だと思う）

・artisanコマンドで作成できるクラスの大半は上記クラスを継承した$this-appオブジェクトをもっている

・基本的には$this->appに対して、操作すればDIできるはず
```

## DI基礎
**※DI(オブジェクト注入)**
・・・オブジェクトが依存しないように、外部から入れ込むこと
**※DIコンテナ**
・・・入れ込むオブジェクトのめんどうな生成を解決するもの

```php:DI例
class Hoge {
  function hoge() {
    $hoge = new Obj();  //DIじゃない
  }
}

class Fuga {
  function fuga(Obj $obj) {  //外部から注入しているので、DI
    $fuga = $obj;
  }
}
```

**※ちなみに**
上記で外部から注入しているObjがクラスであるならば、
依存性は解決されていない。
　⇒クラスに限定してしまうと、そのクラスに依存してしまうことになる。

Objはインターフェースである必要がある。
　⇒インターフェースを実装すれば、Fugaクラスはどんなクラスでも許容してくれる！

## サービスコンテナを使う
### 手順1：サービスコンテナに登録
DIのためのインターフェース、またその実装は**サービスプロバイダ**の中でわれる。

※サービスプロバイダについてや、その作成方法は別項目を参照

```php:例)サービスプロバイダに登録
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Lib\ImplementSample;

class SampleProvider extends ServiceProvider
{
  public function register()
  {
　  // [1]抽象クラスを「App\Lib\ImplementSample」という名前で登録
    $this->app->bind('App\Lib\ImplementSample', function(){
      return new ImplementSample();
    });

    // [2]抽象クラスが呼ばれたら、「App\Lib\ImplementSample」クラスで実装
    $this->app->bind(
      'App\Lib\InterfaceSample',
      'App\Lib\ImplementSample'
    );
  }
}
```

#### 登録方法1：シンプルに
bind関数を使う。

登録と呼び出しで使用するキーとなる文字列、
呼び出した際に返すオブジェクトをコールバックで指定。

```php
$this->app->bind('App\Lib\ImplementSample', function(){
  return new ImplementSample();
});
```

**※キーについて**
コンテナから呼び出すための名前に過ぎないので、どんな値でも入れられる。

オブジェクトの注入の際に指定されたキーが存在しない場合、
コンテナはそのキーをクラス名と判断する。

後述する、タイプヒントによる自動注入はこの仕組みによるもののようだ。

#### 登録方法2：シングルトンで
オブジェクトが常に同一のものを返すように、コンテナに登録。

```php
$this->app->singleton('App\Lib\ImplementSample', function(){
  return new ImplementSample();
});
```

下記記事をみるかぎり、アプリケーションで唯一のオブジェクトを保障するわけではないらしい。

[LaravelのDIの挙動を勘違いしていてドハマリした件](http://qiita.com/ak-ymst/items/00e7d3cee16ba6d3e7109)

#### 登録方法3：インスタンス化したものを
インスタンス化したものを登録する。

```php
$hoge = new Hoge();

$this->app->instance('Hoge', $hoge);
```

#### 登録方法3：プリミティブなものを
注入方法がわからないので保留

#### テクニック：インターフェースと実装の紐付け
キーでコンテナが依存を解決できるのであれば、
以下のように記載することで、インターフェースの依存解決で実装が自動で行われる。

```php
$this->app->bind(
  'App\Lib\InterfaceSample',  // インターフェースを指定
  'App\Lib\ImplementSample'   // 実装を指定
);
```

### 手順2：オブジェクト注入
#### 注入方法1：自動で注入
コントローラ、イベントリスナ、キュージョブ、ミドルウェアなどで利用できる方法。

コンストラクタやメソッドで「タイプヒント」するだけ。

```php:例)コントローラに注入
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Lib\InterfaceSample;

class UserController extends Controller
{
  // タイプヒントで自動注入
  public function __construct(InterfaceSample $is) {
  }
}
```

#### 注入方法2：明示的に注入
##### 2-1：$this-appを使う
DIしたい箇所で、既にコンテナ用オブジェクトが使えるなら、
その子を使って注入する。

```php
$obj = $this->app('App\Lib\InterfaceSample');
```

#### 2-2：resolveヘルパを使う
$this->appが無かったとき用。

```php
$obj = $this->resolve('App\Lib\InterfaceSample');
```

# ファサード
ファサードは、サービスコンテナを用いてオブジェクトへアクセスする方法のひとつ。

使うだけなら、
エイリアスされたクラス名をuseで指定すれば、
その大元のクラスをstaticオブジェクトとして使えるもの。
というイメージ。

```php
use App;  // Appファサードを使う

public functio hoge() {
  // Appファサードでサービスコンテナから依存解決
  $obj = App::make('App\Lib\Hoge');
}
```

## Laravelが用意するファサード
使いそうなものを抜粋。

|ファサード|クラス|サービスコンテナ結合|使用目的|
|:--|:--|:--|:--|
|App|Illuminate\Foundation\Application|app|サービスコンテナ|
|Route|Illuminate\Routing\Router|router|ルーティング|
|Request|Illuminate\Http\Request|request|リクパラ|
|Validator|Illuminate\Validation\Factory|validator|バリデーション|
|View|Illuminate\View\Factory|view|ビュー|
|DB|Illuminate\Database\DatabaseManager|db|データベース操作|

## カスタムファサード

# DB
## 生のクエリを書く
### メソッド
```php
DB::select('クエリ');  //SELECT結果が返る(StdClassオブジェクト)
DB::insert('クエリ');  //件数が返る
DB::update('クエリ');  //件数が返る
DB::delete('クエリ');  //件数が返る
DB::statement('クエリ');  //結果がいらないクエリで用いる
```

### プリペアドステートメント
メソッドの第1引数のクエリで、置換したい箇所を「?」ないし名前を指定。
メソッドの第2引数で、置換する値を保持した配列を指定。

```php
DB::select('SELECT * FROM table WHERE id = ?', [1]);
DB::select('SELECT * FROM table WHERE id = :id', ['id' => 1]);
```

### トランザクション
#### DB::transaction
第2引数で、デッドロック時の試行回数が指定できる。

```php
DB::transaction(function () {
  // この中で実行したクエリがトランザクション対象となる
});
```

#### 手動
```php
DB::beginTransaction();
DB::rollBack();
DB::commit();
```

## クエリビルダ

## Eloquent ORM

## マイグレーション
データベーススキーマの作成を手助けしてくれる。
操作はSchemaビルダで行う。

### マイグレーションの作成
```bash:artisanコマンド
php artisan make:migration マイグレーション名
```
⇒database/migrations/タイムスタンプ_マイグレーション名.phpが作成される

```php:タイムスタンプ_マイグレーション名.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class マイグレーション名 extends Migration
{
    // 通常のマイグレーション操作はupが実行される
    public function up()
    {
    }

    // 巻き戻し系のマイグレーション操作ではdownが実行される
    public function down()
    {
        // upで行った操作を戻す処理を書く
    }
}
```

### マイグレーションの主な操作
```bash:マイグレーションの実行
# database/migrations配下の全マイグレーションをタイムスタンプ順に全実行
# 実行後に対象DBのmigrationsテーブルが作成 and 更新される
php artisan migrate

# 全マイグレーションを最初にロールバック、再度マイグレーションを実行
php artisan migrate:refresh

# refreshに加え、シーダクラスの実行
php artisan migrate:refresh --seed

# 最後のnマイグレーションのみをロールバック&再マイグレーション
php artisan migrate:refresh --step=1
```

```bash:マイグレーション状況の確認
php artisan migrate:status

+------+------------------------------------------------+
| Ran? | Migration                                      |
+------+------------------------------------------------+
| Y    | 2014_10_12_000000_create_users_table           |
| Y    | 2014_10_12_100000_create_password_resets_table |
+------+------------------------------------------------+
```

```bash:マイグレーション操作のロールバック
# 直近の「一度に」実行したマイグレーション操作をまとめて戻す
php artisan migrate:rollback

# 最後からnマイグレーションの操作を戻す
php artisan migrate:rollback --step=1

# 全マイグレーション操作を戻す
php artisan migrate:reset
```

### DB操作
#### テーブル作成
```php
Schema::create('テーブル名', function (Blueprint $table) {
  $table->engine = 'InnoDB';  # ストレージエンジンの指定
  $table->string('name')->first();     # カラム追加(メソッド名が型を表す)
});
```

**※カラム追加で使用するメソッド(主要なものを抜粋)**

|メソッド|型|
|:--|:--|
|$table->boolean('')|BOOLEAN|
|$table->date('')|DATE|
|$table->datetime('')|DATETIME|
|$table->timestamps()|NULLを許容するcreated_at、updated_at|
|$table->softDeletes()|NULLを許容するdeleted_at|
|$table->integer('')|INTEGER|
|$table->double('')|DOUBLE|
|$table->increment('')|インクリメントする主キー|
|$table->string('')|VARCHAR|
|$table->text('')|TEXT|

**※カラム追加時の修飾子メソッド(主要なものを抜粋)**

|メソッド|説明|
|:--|:--|
|default(デフォ値)|カラムのデフォルト値設定|
|comment('コメント')|カラムコメント|
|nullable()|NULLの許容|
|after('カラム名')|指定カラム名の次にカラムを設置|

**※その他**

|メソッド|説明|
|:--|:--|
|$table->primary('カラム名')|主キー|
|$table->primary(['カラム名１','カラム名２'])|複合キー|
|$table->unique('カラム名')|ユニークキー|
|$table->unique(['カラム名１','カラム名２'])|複合ユニークキー|
|$table->index('カラム名')|インデックス|

**※便利なメソッド**

|メソッド|説明|
|:--|:--|
|Schema::hasTable('テーブル名')|テーブルの存在チェック|
|Schema::hasColumn('テーブル名','カラム名')|テーブル.カラムの存在チェック|

#### テーブル削除
```php
Schema::dropIfExists('テーブル名');
```

## シーディング
データベースの初期値設定に使用する。

### シーダの作成
```bash:artisanコマンド
php artisan make:seeder シーダ名
```
⇒database/seeds/シーダ名.phpが作成される

```php:シーダ名.php
<?php
use Illuminate\Database\Seeder;

class シーダ名 extends Seeder
{
    public function run()
    {
      //ここにDBファサード等を用いて、INSERTのクエリを書けば良い
    }
}
```

### テクニック
#### 追加のシーダを呼ぶ
```php
$this->call(HogeSeeder::class);
```

### シーダの実行
```bash
# DatabaseSeederクラスの実行
php artisan db:seed

# 特定のクラスの実行
php artisan db:seed --class=クラス名
```

# テスト
## テスト用DotEnv
「.env.testing」を用意しておくと、phpunit実行時はこのDotEnvファイルが読み込まれる。
PHPUnit以外でもartisanコマンドに「--env=testing」オプションを付与した場合も
読み込まれる模様。

## ディレクトリ
|ディレクトリ|使用目的|
|:--|:--|
|tests/Unit|単体テスト用(主にメソッド単位)|
|tests/Feature|機能テスト用(幅広いテスト行う)|

## PHPUnit実行
プロジェクトルート下で以下を実行。

```bash:実行
vendor/bin/phpunit
```

Laravelのプロジェクトルートに、
既にデフォルトのphpunit.xmlが用意されているため、その子が読み込まれる。
オートローダが読み込まれるほか、APP_ENVが「testing」に設定される。

## テストファイルの作成
```bash
php artisan make:test テストクラス名
```
⇒「tests/Feature/テストクラス名.php」が作成される

```bash
php artisan make:test テストクラス名　--unit
```
⇒「tests/Unit/テストクラス名.php」が作成される

## モック
### ファサードのモック
```php
Cache::shouldReceive('get')  // Cacheファサードのget関数を
                    ->once() // 一度だけ
                    ->with('key') // get関数の引数は'key'
                    ->andReturn('value'); // 戻り値は'value'にする
```

# LaravelMix
wepbackのAPIラッパー。
アセットのコンパイル環境を整える手間を省ける。

## 準備
①npmのインストール
②Laravel Mixのインストール
Laravelのプロジェクトには最初からpackage.jsonが含まれているため、
以下のみで完了。

```bash
cd プロジェクト

# Windows以外
npm install

# Windows
npm install --no-bin-links
```

```json:参考)package.json
{
    "private": true,
    "scripts": {
        "dev": "npm run development",
        "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch-poll": "npm run watch -- --watch-poll",
        "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
        "prod": "npm run production",
        "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
    },
    "devDependencies": {
        "axios": "^0.16.2",
        "bootstrap-sass": "^3.3.7",
        "cross-env": "^5.0.1",
        "jquery": "^3.1.1",
        "laravel-mix": "^1.0",
        "lodash": "^4.17.4",
        "vue": "^2.1.10"
    }
}
```

## エントリポイントの設定
依存関係の解析をどこから始めるかは「webpack.min.js」にて
以下のような記載で行われる。

```js:webpack.min.js
let mix = require('laravel-mix');

// メソッド例）mix.アセット('エントリポイント', 'コンパイル先')
// ※メソッドチェーンで繋げる
mix.js('resources/assets/js/app.js', 'public/js')
  .sass('resources/assets/sass/app.scss', 'public/css');
```

### キャッシュ対策
```js:webpack.min.js
mix.js('resources/assets/js/app.js', 'public/js')
  .version();
```

```php:ハッシュ付きファイルの読み込み
{{ mix('/js/app.js') }}
```

↑これで読み込むファイルに「?=バージョンハッシュ」がついて、キャッシュ対策になる。


## Mixの実行(コンパイル)
実行後、コンパイル済みの「public/js/app.js」と「public/css/app.css」が出力される。

```bash
npm run dev

# 圧縮ver(なんかこっち失敗した)
npm run dev production
```

### 再コンパイル
以下のコマンドで、変更があるたびに再コンパイルが行われるようになる。

```bash
npm run watch

# 一部環境では再コンパイルが失敗するため、以下のコマンドで行う
npm run watch-poll
```

## JavaScript関連
### 設定
```js:webpack.min.js
mix.js('resources/assets/js/app.js', 'public/js');
```

上記で
・ES2015記法
・モジュール
・.vueファイルのコンパイル
・開発環境向けの圧縮
が可能となる。