Laravel6 チートシート

# はじめに
Laravel触り始めたばかりの初心者です。
いちいち調べるのもめんどくさくなってきたので基本的な部分をまとめてみました。
自分用のチートシートにはなりますが、Laravel6で開発中の初心者の方も参考にしてください。
開発環境に関しては、MAMPで構築しています。
（2021年4月13日 Dockerパターンも追加）

## 【MAMP】Laravelのインストールから初期設定
### Laravelのインストール
Laravelのインストールはcomposerコマンドで行います。

```terminal:ターミナル
composer create-project laravel/laravel （フォルダ名） --prefer-dist "6.0.*"
```

`composer create-project`には2つのオプションがあります。
1. --prefer-dist
2. –prefer-source 

`--prefer-dist`は、zipファイルでダウンロードします、こっちのほうが高速なのでこちらを採用。
`--prefer-source`は、git cloneでソースを落とします。

### Laravelの動作確認
Laravelのインストールが正常に行われたかを確認するために開発サーバーを起動します。

```terminal:ターミナル
php artisan serve
```

### 初期設定
Laravelでやっておくべき初期設定は以下の8つです。

1. タイムゾーン
2. 言語設定
3. DBの文字コード
4. デバッグバー
5. DB設定
6. エラーメッセージの日本語訳
7. HTMLにCSRFトークンの設置
8. Models/User.phpの設置

#### タイムゾーン
タイムゾーンを日本時間に変更します。

```php:config/app.php(70行目あたり)
'timezone' => 'Asia/Tokyo'
```

#### 言語設定
言語設定を日本語に変更します。

```php:config/app.php(83行目あたり)
'locale' => 'ja'
```

#### DBの文字コード
文字コードをUTF-8に変更します。

```php:config/database.php(55行目~56行目あたり)
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci'
```

#### デバッグバー
デバッグ用にデバッグバーを表示させます。

```terminal:ターミナル
composer require barryvdh/laravel-debugbar
```

現時点での設定では本番環境でもデバッグバーが表示されます。
DBなどの値がユーザーに見えてしまうため本番環境ではデバッグバーを非表示にする必要があります。

```env:.env
APP_DEBUG=false
```

#### DB設定
.envファイルのDBに関する記載の部分を修正していきます。

```env:.env
DB_CONNECTION=mysql //DB種類
DB_HOST=127.0.0.1 //ホスト
DB_PORT=3306 //ポート
DB_DATABASE=laravel //データベース名
DB_USERNAME=root //ユーザー名
DB_PASSWORD= //パスワード
```

##### 接続確認

```terminal:ターミナル
php artisan migrate
```

###### エラー発生
修正すべきポイントは3つです。

①.envのDB_HOSTを修正

```env:.env
DB_HOST=localhost
```

②config/database.phpのunix_socketを修正

```php:config/database.php(54行目あたり)
'unix_socket' =>  '/Applications/MAMP/tmp/mysql/mysql.sock'
```

③ターミナルでキャッシュクリア

```terminal:ターミナル
php artisan cache:clear
php artisan config:cache
```

#### エラーメッセージの日本語訳
`resources/lang/en`内にエラーメッセージのファイルがあるがこれらすべて英語となっています。
そのため、日本語訳するために以下のサイトからダウンロードします。

https://github.com/minoryorg/laravel-resources-lang-ja


ダウンロードしたファイルを`resources/lang/ja`内に格納します。

##### 任意修正箇所

エラーメッセージが一部英語で表示されます。

![スクリーンショット 2021-03-29 12.46.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/838372/bd6e1cff-e9db-6279-1032-f1d7f10bc3f7.png)

エラーメッセージの変更は以下のように行います。

```php:resources/lang/ja/validation.php
"attributes" => [
  "password" => "パスワード"
]
```

![スクリーンショット 2021-03-29 12.48.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/838372/ad7f5562-cc7b-8eab-6ca1-650af8e4e5f0.png)


#### HTMLにCSRFトークンの設置
こちらを入れておかないとフォームが必ずエラーとなります。
HTMLのheadタグ内の共通レイアウトbladeファイルを作り、そこに記載します。

```php:resources/views/layout.blade.php(レイアウトファイル)
<meta name="csrf-token" content="{{ csrf_token() }}">
```

#### Models/User.phpの設置
**ディレクトリを作成し、User.phpを移動する**

```terminal:ターミナル
$ mkdir Models
$ mv User.php Models
```

**ファイルの修正**

```php:App/Models/User.php(3行目)
namespace App\Models;
```

```php:App/Http/Controllers/Auth/RegisterController.php(7行目)
use App\Models\User;
```

```php:App/Http/Controllers/Auth/RegisterController.php(7行目)
use App\Models\User;
```

```php:config/auth.php(68行目)
'providers' => [
    'users' => [
      'driver' => 'eloquent',
      'model' => App\Models\User::class,
    ],
],
```

```php:database/factories/UserFactory.php(5行目)
use App\Models\User;
```

## 【Docker】Laravelのインストールから初期設定
### インストール
以下のURLを参考に設定します。
コマンド3つで以下の環境を作れます。
**php:7.4-fpm-buster**
**Laravel6.0.***
**Node14.***
**composer:1.10**
**nginx:1.18-alpine**
**mysql:5.7**

https://github.com/ssk9597/Docker-php-node-nginx-mysql

### Laravelの動作確認
Laravelのインストールが正常に行われたかを確認するために開発サーバーを起動します。
MAMPとの違いはdocker環境に入ってからサーバーを起動する必要があります。

```terminal:ターミナル
docker-compose exec app bash
php artisan serve
```

### 初期設定
Laravelでやっておくべき初期設定は以下の5つです。

1. タイムゾーン
2. 言語設定
3. DBの文字コード
4. エラーメッセージの日本語訳
5. Models/User.phpの設置

#### タイムゾーン
タイムゾーンを日本時間に変更します。

```php:config/app.php(70行目あたり)
'timezone' => 'Asia/Tokyo'
```

#### 言語設定
言語設定を日本語に変更します。

```php:config/app.php(83行目あたり)
'locale' => 'ja'
```

#### DBの文字コード
文字コードをUTF-8に変更します。

```php:config/database.php(55行目~56行目あたり)
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci'
```

#### エラーメッセージの日本語訳
`resources/lang/en`内にエラーメッセージのファイルがあるがこれらすべて英語となっています。
そのため、日本語訳するために以下のサイトからダウンロードします。

https://github.com/minoryorg/laravel-resources-lang-ja


ダウンロードしたファイルを`resources/lang/ja`内に格納します。

##### 任意修正箇所

エラーメッセージが一部英語で表示されます。

![スクリーンショット 2021-03-29 12.46.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/838372/bd6e1cff-e9db-6279-1032-f1d7f10bc3f7.png)

エラーメッセージの変更は以下のように行います。

```php:resources/lang/ja/validation.php
"attributes" => [
  "password" => "パスワード"
]
```

![スクリーンショット 2021-03-29 12.48.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/838372/ad7f5562-cc7b-8eab-6ca1-650af8e4e5f0.png)

#### Models/User.phpの設置
**ディレクトリを作成し、User.phpを移動する**

```terminal:ターミナル
$ mkdir Models
$ mv User.php Models
```

**ファイルの修正**

```php:App/Models/User.php(3行目)
namespace App\Models;
```

```php:App/Http/Controllers/Auth/RegisterController.php(7行目)
use App\Models\User;
```

```php:App/Http/Controllers/Auth/RegisterController.php(7行目)
use App\Models\User;
```

```php:config/auth.php(68行目)
'providers' => [
    'users' => [
      'driver' => 'eloquent',
      'model' => App\Models\User::class,
    ],
],
```

```php:database/factories/UserFactory.php(5行目)
use App\Models\User;
```


## フロントエンドでVue.jsを使うとき
Laravel6ではインストールが必要となりました。

```terminal:ターミナル
// laravel/uiをインストール
composer require laravel/ui:^1.0 --dev

//　どちらかを選択
// ①auth機能あり
php artisan ui vue --auth
// ②auth機能なし
php artisan ui vue

// コンパイルとインストール
npm install && npm run dev
```

### npm run devでエラーが発生した場合
エラーメッセージは以下の通りです。

```
ERROR  Failed to compile with 2 errors                                                             

 error  in ./resources/sass/app.scss
```

#### 【原因】
sass-loaderのバージョンの互換性がない。

#### 【対応】
バージョンの変更を行う

```terminal:ターミナル
// sass-loaderをアンインストール
npm uninstall --save-dev sass-loader

// sass-loaderをインストール
npm install --save-dev sass-loader@7.1.0

// 実行
npm run dev
```

## MVCアーキテクチャ
大きく分けて2つの動きが考えられます。

**①DBの情報を必要としないとき**
クライアント → ルーティング → コントローラー → ビュー

**②DBの情報を必要とするとき**
クライアント → ルーティング → (コントローラー ⇄ モデル ⇄ DB) → ビュー

### ルーティング
<details>
<summary>フォルダ</summary>
routes/web.php
`api`の場合は、routes/api.php
</details>

```php:routes/web.php
// ①直接Viewに移動
// Viewのwelcome
Route::get("/", function() {
  return view("welcome");
}

// ②Controllerに移動
// ControllerのUserControllerのindexメソッドに移動
Route::get("/user", "UserController@index");
```

### コントローラー
<details>
<summary>フォルダ</summary>
app/Http/Controllers
</details>

#### コントローラーの作成方法

```terminal:ターミナル
php artisan make:controller UserController
```

#### リソースコントローラー（RESTful）
1行のコードで典型的なCRUDルートをコントローラーで作成できます。

```terminal:ターミナル
php artisan make:controller PhotoController --resource
```

| 動詞　　　　 | URI                 | アクション     | ルート名          |
|:-----------|:--------------------|:------------|:----------------|
| GET        | /tests              | index       | Tests.index     |
| GET        | /tests/create       | create      | Tests.create    |
| POST       | /tests              | store       | Tests.store     |
| GET        | /tests/{test}       | show        | Tests.show      |
| GET        | /tests/{test}/edit  | edit        | Tests.edit      |
| PUT/PATCH  | /tests/{test}       | update      | Tests.update    |
| PUT/PATCH  | /tests/{test}       | destroy     | Tests.destroy   |

updateの場合は、
＠csrfの下に、
**@method("PUT")**が必要です。

destroyの場合は、
@csrfの下に、
**@method("DELETE")**が必要です。

##### ルーティングを制限する
Route::resouceはCRUDのルーティングを一度に行えるのですごく便利ですが、これらのメソッドを全て使うケースは多くないと思います。
削除するだけでは例外のエラーが発生するためルーティングを制限する必要があります。

```php:routes/web.php
// index, createのみ使うとき
Route::resource('photos', 'PhotoController', ['only' => ['index', 'create']]);

// show, update以外すべて使うとき
Route::resource('photos', 'PhotoController', ['only' => ['index', 'create', 'store', 'edit', 'destroy']]);
```

##### RestFulでよく使われる書き方
**認証がされているときに表示する**

```php:routes/web.php
Route::group(["prefix" => "photos", "middleware" => "auth"], function() {
   Route::get("index", "PhotosController@index")->name(Photos.index);
   Route::get("create", "PhotosConroller@create")->name(Photos.create);
   Route::posts("store", "PhotosController@store")->name(Photos.store);
   Route::get("show/{id}", "PhotosController@show")->name(Photos.show);
   Route::get("edit/{id}", "PhotosController@edit")->name(Photos.edit);
   Route::post("update/{id}", "PhotosController@update")->name(Photos.update);
   Route::post("destroy/{id}", "PhotosController@destroy")->name(Photos.destroy);
})
```

**`id`の値をどのようにして取ればいいのか？**

```php:resources/views/show.blade.php
<form action="{{ route('tests.edit', $test->id) }}" method="GET">
</form>
```

#### 値の取り出し方
値の取り出し方は2通りあります。
①Viewのフォーム経由から値を受け取る
②ModelでDBから値を受け取る

##### View経由
```php:resources/views/index.blade.php
<form action="{{ route('tests.store') }}" method="POST">
    // nameで渡す
    <label for="email">メールアドレス</label>
    <input type="email" id="email" name="email">
    <label for="password">パスワード</label>
    <input type="password" id="password" name="password">

    // hidden(valueに値を入れてnameで渡す)
    // Auth::id()はログインユーザーのIDを取得できます。
    <input type="hidden" name="id" value="{{ Auth::id() }}">
    // Auth::user()はログイン中のユーザー情報を取得できます。
    <input type="hidden" name="login_user" value="{{ Auth::user() }}">
    <input type="submit" value="送信する">
</form>
```

```php:app/Http/Controllers/UserController
use App\Models\User;

public function store(Request $request) {
    // 値を取得する
    // $email = $request->input("email");
    // $password = $request->input("password");

    // 正しく取得できているか確認
    // dd($email);

    // Modelを呼び出すだけでOK
    $user = new User;
    
    // インスタンス化したものに保存
    $user->email = $request->input("email");
    $user->password = $request->input("password");
    
    // DBに保存
    $user->save();

    // リダイレクト
    return redirect("user/index");
}
```

**`POST`がうまくいかないとき**
一旦キャッシュをすべてクリアしてみましょう。

```terminal:ターミナル
php artisan optimize:clear
```

##### Model経由

```php:app/Http/Controller/UserController.php
// ModelsのUserを読み込み
use App\Models\User

// クエリビルダーを使うためのおまじない
use Illuminate\Support\Facades\DB

// ①Eloquent
// all() = すべてのデータを取得する
$values = User::all();

// find() = 引数の値のidのデータを取得する
$value = User::find($id);

// where() = 条件指定(categoryカラムがPHPのデータを取得する)
$value = User::where("category", "PHP")->get();

// ②クエリビルダー
// get() = 条件にあったデータのすべてを取得する
$values = DB::table("users")->get();

// first() = 最初の１件を取得する
$value = DB::table("users")->first();

// SELECT = 取得するカラムを指定する
$values = DB::table("users")->select("name", "email")->get();

// user.indexのViewに移動し、$valuesの値を渡す
return view("user.index", compact("values"));
```

https://www.ritolab.com/entry/120

https://www.ritolab.com/entry/93

#### CRUD

```php:app/Http/Controller/UserController.php
// ModelsのUserを読み込み
use App\Models\User

// クエリビルダーを使うためのおまじない
use Illuminate\Support\Facades\DB

// ①Create
// 1つずつ記載するのもいいけどやっぱりfillを使う方がスマートだよね！
$user->name = $request->name;
$user->email = $request->email;
// ...etc
$user->birthday = $request->birthday;
$user->save();

$user->fill($request->all())->save();

// ②Read
// 上記でやったため省略

// ③Update
// こちらもfillを使う方がスマート！$fillableをチェックしてくれるのがやっぱりいいよね
$user->fill(['name' => 'Sho'])->save();

// ④Delete
// モデルを取得して削除してもいいけど、PKで削除するのもありだよね
User::find($id)->delete();

User::destroy($id);
User::destroy([1, 2]);
```

### モデル
<details>
<summary>フォルダ</summary>
app/Models
</details>

#### モデルの作成方法
同時にマイグレーションファイルを作成すると便利

```terminal:ターミナル
php artisan make:model Models/Post --migration
```

##### マイグレーションとは？
マイグレーションとは、DBテーブルの履歴を管理する仕組みです。
<details>
<summary>フォルダ</summary>
database/migrations
</details>

###### マイグレーションの頻出カラムタイプ

```php:database/migrations/XXXX_XX_XXXXXX_create_users_table.php
public function up()
    {
        Schema::create('registers', function (Blueprint $table) {
            // 符号なしBIGINTを使用した自動増分ID
            $table->bigIncrements('id')->comment('id');
            // 20文字以内の文字列
            $table->string('name', 20)->comment('名前');
            // 255文字以内で独自の文字列
            $table->string('email', 255)->unique('email')->comment('メールアドレス');
            // 日付
            $table->date('birthday')->comment('生年月日');
            // 0~255までの整数値で符号なし
            $table->tinyInteger('gender')->unsigned()->comment('1:男性 2:女性');
            // 最大65535文字で未記入可
            $table->text('memo', 65535)->nullable()->comment('メッセージ');
            $table->timestamps();
        });
    }
```

**テーブルにカラムを作成する**

```terminal:ターミナル
php artisan migrate
```

###### マイグレーションを修正する

**①migrationファイルを新規に作成する**
`--table`オプションでテーブル名を指定します。
ファイル名は何をするかをわかりやすくするのがおすすめです。
下記の場合、「usersテーブルにemailを追加する」です。

```terminal:ターミナル
php artisan make:migration add_email_users_table --table=users
```

**②migrationファイルを修正**

```php:database/migrations/XXXX_XX_XXXXXX_add_email_users_table.php
public function up()
    {
        Schema::table('users', function (Blueprint $table) {
             $table->string('email');  //カラム追加
        });
    }

public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('email');  //カラムの削除
        });
    }
```

**③migration**

```terminal:ターミナル
php artisan migrate
```

### ビュー
<details>
<summary>フォルダ</summary>
resources/views
</details>

#### assetsヘルパー
Bladeファイル内にCSSやJSを記述すると可読性が著しく落ちるので別ファイルに保存します。

```
public 
  |__ css
  |__ js
  |__ img
```

```php:resources/views/index.blade.php
<!-- css -->
<link rel="stylesheet" href="{{ asset('/css/style.css') }}">

<!-- js -->
<script src="{{ asset('/js/index.js') }}"></script>

<!-- img -->
<img alt="ロゴ" src="{{ asset('/img/logo.jpg') }}">
```

## ダミーデータ
### Factory & Faker
<details>
<summary>フォルダ</summary>
database/factories
</details>

```terminal:ターミナル
php artisan make:factory PostFactory
```

**ここで修正が必要です**

```php:database/factories/PostFactory.php
// これは誤り
// use App\Model

// こちらが正しい
use App\Models\Post

// ModelではなくPostのためこちらも誤り
/* $factory->difine(Model::class, function (Faker $faker) {
    return [
    
    ];
} */

//こちらが正しい
$factory->define(Post::class, function (Faker $faker) {
    return [
        "name" => $faker->name,
        "title" => $faker->realText(50),
        "email" => $faker->unique()->email,
        "tel" => $faker->phoneNumber,
        "password" => $faker->password,
        "url" => $faker->url,
        "gender" => $faker->randomElement(["0", "1"]),
        "age" => $faker->numberBetween($min = 1, $max = 6),
        "contact" => $faker->realText(200)
    ];
});
```

その他のFakerに関しては以下を確認してください。

https://shingo-sasaki-0529.hatenablog.com/entry/how_to_use_php_faker


#### 作成手順
##### ①config/app.phpの修正

```php:config/app.php(109行目あたり)
"faker_locale" => "ja_JP"
```

##### ②シーダの作成

```terminal:ターミナル
php artisan make:seeder PostSeeder
```

```php:PostSeeder.php
use App\Models\Post

public function run() {
    // 200個作成
    factory(Post::class, 200)->create();
}
```

##### ③データベースシーダーに追記
```php:database/seeds/DatabaseSeeder.php
public function run()
{
    $this->call([
        // ここに付け足していく
        UsersTableSeeder::class,
        PostsSeeder::class,
    ]);
}
```

###### ④ターミナル

```terminal:ターミナル
// Composerのオートローダーを再生成する
composer dump-autoload

// データベースに入っている値を初期化し入力する場合
php artisan migrate:fresh --seed
```

## バリデーション
<details>
<summary>フォルダ</summary>
app/Http/Requests
</details>

```terminal:ターミナル
php artisan make:request StoreBlogPost
```


```php:app/Http/Requests/StoreBlogPost.php
// ①trueに変更（これをしないとうまく作用しない）
public function authorize() {
    return true;
}

public function rules() {
    return [
        // 【必須】最大20文字
        "name" => "required|string|max:20",
        // 【必須】最大255文字のメールアドレスであり被りがあってはならない
        "email" => "required|email|unique:users|max:255",
        // 【必須】8文字以上で確認用と同じパスワード
        "password" => "required|confirmed|min:8",
        // 【任意】
        "hobby" => "nullable",
    ]
}
```

```php:app/Http/Controllers/StoreBlogPostController
// ファイルを読み込む
use App\Http\Requests\StoreBlogPost;

// これで自動的にバリデーションができるようになる
public function store(StoreBlogPost $request) {
}
```

```php:resources/views/blogpost.blade.php
// ①それぞれ書く
@error("email")
    <span>
        <strong>{{ $message }}</strong>
    </span>
@enderror

// ②まとめて書く
@if ($errors->any())
    <div>
        <ul>
            @foreach($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif
```