Laraveの知識をアウトプットして、資産化してます

# 新規プロジェクト
まずはプロジェクトの作成をしていきます。

```:よく使うコマンド
$ composer create-project laravel/laravel sampleproject --prefer-dist "6.0.*"
```
個人的に上記のコマンドでバージョンを指定してプロジェクトを作成します。
`sampleproject`の箇所がプロジェクト名となります。
書き方は他にもいろいろあります。

```:ターミナル
# バージョン指定なし (最新版をインストール, 初期値でmysqlを利用する）
$ composer create-project --prefer-dist laravel/laravel プロジェクト名

# バージョン指定あり (初期値でmysqlを利用する）
$ composer create-project --prefer-dist "laravel/laravel=5.5.*" sampleproject

#書き方はいろいろ
$ composer create-project laravel/laravel sampleproject --prefer-dist "6.0.*"
```
#初期設定

続いては初期設定をしていきます。
時間や地域、言語などを日本にしていきましょう。

## 暗号化

```:コマンド
php artisan key:generate
```

[[Laravel5.5] APP_KEY の行方を追う](https://qiita.com/yk2220s/items/dcbf54c6d1f33a0cb06f)

## タイムゾーンを日本に変更

タイムゾーンの変更

```php:config/app.php

'timezone' => 'UTC',
#UTCをAsia/Tokyoに変更
'timezone' => 'Asia/Tokyo',
```

## 言語を日本に変更

```php:config/app.php

'locale' => 'en',
#enをjaに変更
'locale' => 'ja',

```

## フェイカーもを日本語に設定



```php:config/app.php

#before
'faker_locale' => 'en_US',

#after
'faker_locale' => 'ja_JP',

```



## DBの文字設定
これに関しては変更しなくても大丈夫です。

```php:config/database.php
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',

#mb4を消す(顔文字を不要)
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',

```

##デバックバーのインストール

```:ターミナル
$ composer require barryvdh/laravel-debugbar
```
画面上に非表示にするために、.envファイルを変更する

```php:.env
APP_DEBUG=true
#falseに変更する
APP_DEBUG=false
```

これでも画面に残っている場合は、キャッシュを消す


```:ターミナル

php artisan cache:clear
php artisan config:clear
php artisan route:clear
php artisan view:clear
```
何かと反映しないときは、上記コマンドでキャッシュを削除して反映させるので、よく使います。

##tinkerのインストール
[tinkerの使い方](https://qiita.com/juve_534/items/96dc6e7e0652dced1428)
[公式ドキュメント](https://laravel.com/docs/8.x/artisan#tinker)

tinkerは処理を確認する際に使います。デバックの一つの方法です。

```:tinkerの導入
$ composer require laravel/tinker
```


```:tnker起動コマンド
$ php artisan tinker
```

```:Taskの一覧を取得する
$ php artisan tinker


>>> Task::all();
```

[他にもあります](https://qiita.com/Ping/items/10ada8d069e13d729701)


## DBの設定変更

.envファイルの下記のDB設定における、DATABASE名、USERNAM名、PWを設定していく

```php:.env
//アプリ名の変更
APP_NAME=Laravel


//DB情報を変更する
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=laravel
DB_PASSWORD=
```
### MAMPでDBの作成

[![Image from Gyazo](https://i.gyazo.com/c6140917bcd57e00e09e9b7c6328bd4c.gif)](https://gyazo.com/c6140917bcd57e00e09e9b7c6328bd4c)


### MAMPでUSERを作成
[![Image from Gyazo](https://i.gyazo.com/b9693d32bcdbff3e535cc0681a9be76a.gif)](https://gyazo.com/b9693d32bcdbff3e535cc0681a9be76a)

### 作成した情報を記述する

```php:.env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306 #MAMP上で設定されたlocalhostになる
DB_DATABASE=laravel_task
DB_USERNAME=laravel_user
DB_PASSWORD=password
```

[MAMPのローカルホストを変更する場合](https://pc-karuma.net/mamp-settings-mac/)


### 接続できるか確認

```:ターミナル
$php artisan migrate
```
成功した場合は、無事にDBに接続できている。

### MAMPのDBをSeaquel Proで確認する場合

ユーザー名:root
パスワード:root
データベース:
ソケット:/Applications/MAMP/tmp/mysql/mysql.sock
![スクリーンショット 2020-05-14 12.31.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455403/cc73304d-9e55-0555-122b-f20a06c780c0.png)

これで接続すれば、確認ができる

## Laravel-ui認証

[マニュアルページを開く](https://readouble.com/laravel/6.x/ja/frontend.html)

```:laravel/uiパッケージをインストール（laravel6)

//laravel6の場合
$ composer require laravel/ui:^1.0 --dev
$ composer require laravel/ui "1.*"

//laravel7の場合
$ composer require laravel/ui:^2.4 --dev
$ composer require laravel/ui "2.*"
```

```:フロントエンドのスカフォールドをインストール
// 基本的なスカフォールドを生成
php artisan ui bootstrap
php artisan ui vue
php artisan ui react

// ログイン／ユーザー登録スカフォールドを生成
php artisan ui bootstrap --auth
php artisan ui vue --auth
php artisan ui react --auth
```

```:vue.js+bootstrapの場合
$ composer require laravel/ui
$ php artisan ui vue --auth
$ npm install bootstrap-vue bootstrap

import BootstrapVue from 'bootstrap-vue';
Vue.use(BootstrapVue);
```
[参考ページはこちら](https://qiita.com/take-FIRST_PLAN/items/e77f9f148d808e7f3f7a)

```:依存パッケージのインストール
$ npm install && npm run dev
```

```:補足
$ npm run dev ・・開発用にビルド
$ npm run watch ・・常時ビルド
$ npm run prod ・・本番用にビルド
```

### 新規登録後の移行先を変更

```php:RegisterControll.php
#before homeを消す
protected $redirectTo = '/home';

#after
protected $redirectTo = '/';

```
### ログイン後の移行先を変更

#### laravel6の場合

```php:loginControll.php
#before homeを消す
protected $redirectTo = '/home';

#after
protected $redirectTo = '/';

```
#### larvel6.8以降の場合
laravel6.8以降は、よりDRYになっている。

```php/RouteServiceProvider.php
<?php
// 略
class RouteServiceProvider extends ServiceProvider
{
    // 略　
    public const HOME = '/home';
```
ここでHOMEを定義することで、複数のAuth系のコントローラーで反映される。

```php:app/Http/Controllers/auth/LoginController.php
<?php
// 略　
class LoginController extends Controller
{
    // 略
    protected $redirectTo = RouteServiceProvider::HOME;
    // 略
}
```


###エラーメッセージを日本語化

コマンドでやる場合

```
$ php -r "copy('https://readouble.com/laravel/6.0/ja/install-ja-lang-files.php', 'install-ja-lang.php');"
$ php -f install-ja-lang.php
$ php -r "unlink('install-ja-lang.php');"
```

下記リンクを開く
https://github.com/minoryorg/laravel-resources-lang-ja


ファイルをダウンロード
[![Image from Gyazo](https://i.gyazo.com/10254e7b8bd08ddf945a1452e788a86a.gif)](https://gyazo.com/10254e7b8bd08ddf945a1452e788a86a)

ダウンロードしたフォルダを開くと、jaというフォルダが存在する
![スクリーンショット 2020-05-15 11.05.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455403/bb523146-ea0f-f07b-50d8-8b1fd4014a0e.png)

resources/langフォルダに、ダウンロードしたjaフォルダを追加
![スクリーンショット 2020-05-15 11.10.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455403/c13db1d3-b0c5-e585-8c1c-e5102a46da0a.png)

これで日本語されています
passwordなど英語表記のものを日本語にするには、

```php:validation.php
'attributes' => [],
//最下部のattributesにパスワードの項目を追加する

'attributes' => [
        'password'=>'パスワード'
    ],
```

# ターミナルで開いておきたい

```:ターミナル(タブ１）:CSSなどを監視
$ npm run development -- --watch
```

```:ターミナル（タブ2)：ローカルサーバー
$ php artisan serve
```

```:ターミナル(タブ3)：コマンド実行用
$ 何かターミナルコマンド入力する際に利用する
```
 特定の環境のwebpackでは、ファイル変更時に更新されないことがあります。自分のシステムでこれが起きた場合は、watch-pollコマンドを使用してください。

```
$ npm run watch-poll
```


### font-awesomeをインストール

```:コマンド
$ npm install --save-dev @fortawesome/fontawesome-free
```



# MVCの操作
ここからMVCコントローラーの操作を進めていく
##モデル
###モデルの作成

```:一番便利なコマンド
# Post関連など全て作成する場合は、下記が一番便利（all）
$ php artisan make:model Models/Post -a
```
上記コマンドを実施すると、コンとローラー、マイグレーションファイル、seeder、factory、テストが生成される。どちらにせよこれらは利用するので、基本このコマンドを使うと良い。


補足として、他のコマンドを紹介しておきます。

```:ターミナル

#モデル単体を作成
$php artisan make:model Models/Test

# モデル、マイグレーションファイル、コントローラーを同時に作成
$ php artisan make:model Models/Test -mc

#コントローラーの作成（基本的なアクション含む）
php artisan make:controller PhotoController --resource

```
Models/Test Modelsフォルダの中で、Test.phpを作成
-mcはマイグレーションファイルとコントローラーを同時に作成するオプション

###マイグレーション
#### マイグレーションファイルの作成

```:ターミナル
$php artisan make:migration create_tests_table

#追加で作成
php artisan make:migration add_user_id_to_posts_table --table=posts
```

#### マイグレーションの記述
マニュアル
https://readouble.com/laravel/6.x/ja/migrations.html
マニュアルを参考に、カラム型、制限をかけて、カラム修飾子で詳細に設定する

[MySQLの外部キー制約RESTRICT,CASCADE,SET NULL,NO ACTIONの違いは？](https://qiita.com/suin/items/21fe6c5a78c1505b19cb)

カラム

```php:_create_tweet_table.php
Schema::create('tweets', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('title', 200);　#200文字制限
            $table->unsignedBigInteger('user_id');
            $table->foreign('user_id')->references('id')->on('users');
            $table->text('text');
            $table->timestamps();
        });
```

#### マイグレーションを実行

```:マイグレーションを実行
$ php artisan migrate
```

```:マイグレーションの履歴を確認
$php artisan migrate:status
```

```:マイグレーションをロールバックする
$php artisan migrate:rollback --step=5
```

### $fillable(ホワイトリスト）
カラム情報をcreateや更新などしてよいか許可する。これをしないとエラーが発生する。


```php:Post.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class post extends Model
{
    protected $fillable = [
        'title', 'body', 'user_id'
    ];

}

```

### カラムの変更
[参考になるページ1](https://qiita.com/mdrq/items/f10e488caa4497eec79b)
[参考になるページ2](https://yshrfmru.hatenablog.com/entry/2019/01/04/203957#%E3%82%AB%E3%83%A9%E3%83%A0%E5%A4%89%E6%9B%B4)

「up」の中にはテーブル作成時の記述、「down」の中にはテーブル削除時の記述を書きます。

`Schema::create`ではなく、`Schema::table`を記述して変更する
#### 準備


#####インストール

```:コマンド
$ composer require doctrine/dbal
```

上記コマンドをしない場合は下記のエラーが表示される

```:エラー
[RuntimeException]                                                                   
  Changing columns for table "books" requires Doctrine DBAL; install "doctrine/dbal".
```

#####変更用のマイグレーションファイルを作成
変更用のmigrationファイルを作成する。

```:コマンドの例
$ php artisan make:migration change_books_table --table books
```

```:コマンド例
$ php artisan make:migration modify_users_table --table=users
```



####カラム名の変更

`renameColumn`を利用する

```php:変更用のファイル
public function up()
{
    Schema::table('users', function (Blueprint $table) {
        $table->renameColumn('from', 'to');
    });
}
```


####カラム属性の変更
DBを削除して、再度マイグレーションするのも一つではあるが、この例ではあくまで既存のDBのカラム名を変更するやり方とする。


作成したファイルに変更内容を記述する。
`->change();`で変更する


```php:change_books_table
public function up()
{
    Schema::table('books', function (Blueprint $table) {
        $table->datetime('published')->change();
    });
}
```

```php:公式の例
Schema::table('users', function (Blueprint $table) {
    $table->string('name', 50)->change();
});
```

#### カラムを削除

`dropColumn`を利用する

```php:カラム削除時の記述
Schema::table('users', function (Blueprint $table) {
    $table->dropColumn('votes');
});
```


####再度に更新させる

```:コマンド
$ php artisan migrate
```

#### すべてのmigrationをリセットする

`migrate:reset`コマンドはアプリケーション全部のマイグレーションをロールバックします。

```
$ php artisan migrate:reset
```
これを実施後に既存のmigrationファイルを書き換えれば良い。



###リレーション
[マニュアル](https://readouble.com/laravel/6.x/ja/eloquent-relationships.html#one-to-many-polymorphic-relations)
[User.phpのパスを変更する場合](https://qiita.com/vrvr/items/4755e758f5d4b2e07579)


#### 1対多
##### 外部キーがデフォルトの<テーブル名_id>の場合

`namespace <ファイルのパス>`

```php:tweet.php
<?php

namespace App\Model;  //フォルダの階層

use Illuminate\Database\Eloquent\Model;

class Tweet extends Model
{
    public function user() #userとのリレーションを定義。belongs = 単数
    {
        return $this->belongsTo('App\User');
    }
    public function comments() #commentとのリレーションを定義。hasMany = 複数
    {
        return $this->hasMany('App\Model\Comment');
    }
}

```
上記では`Model`を利用するために、`namespace App\Model;`と`use Illuminate\Database\Eloquent\Model;`でモデルクラスを呼び出している。だから、`class Tweet extends Model`とextendsで継承できる

```php:user.php
<?php

namespace App;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    public function tweets()
    {
        return $this->hasMany('App\Model\Tweet');
    }
    public function comments()
    {
        return $this->hasMany('App\Model\Comment');
    }
    
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    
}

```


#####外部キーの名前がデフォルトの<テーブル名_id>でない場合

[foreign_keyは<テーブル名_id>でない場合（カスタムしている場合）](https://qiita.com/saya1001kirinn/items/69e2146691101f92d57b)

ポイントは、外部キーのカラム名を指定してあげること。

`hasMany('モデルの場所', '<テーブル名_id>でない場合は、外部キーの指定', '参照先テーブルのカラムがidでない場合、カラムを指定')

デフォルトだと、
- `user_id`や`tweet_id`などの`<テーブル名_id>`を外部キーとして参照する。
- `参照先テーブルのid`を取得する


だから、デフォルトの外部キーとカラムが違う場合は、それぞれ指定する必要がある。

######所得先が"id"の場合は、local_idを省略

```php:公式情報
return $this->hasMany('App\Comment', 'foreign_key');
```
公式情報の`foreign_key`の箇所に指定の外部キーを記述する。

```php:例
return $this->hasMany('App\User', 'buyer_id');
```

```php:例
return $this->hasMany('App\User', 'seller_id');
```
上記の例のように、指定の外部キーを記述する。

具体的に見てみましょう

```php:Product.php
<?php

namespace App\Model;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    public function seller()
    {
        return $this->belongsTo('App\User', 'seller_id'); //seller_idと一致するUserを取得する
    }
}

```

```php:User.php
class User extends Authenticatable
{
    public function sell_products()
    {
        return $this->hasMany('App\Model\Product', 'seller_id'); //productの中でseller_idがこのUserのidと一致するものを取得する
    }
}
```
#####所得先が"id"でない場合は、local_idを指定

ようするに、デフォルトの"id"を参照しないので、どのカラムを指定するのかオプションで指定する。

```php:公式情報
return $this->hasMany('App\Comment', '外部キーのカラム名', 'カラム名');
```
上記を指定すればよい。
あまり使うことはないと思うが、簡単に例を出す。


```php:デフォルトだとid
return $this->hasMany('App\Product', 'seller_id', 'id');
```


デフォルトだと`id`を参照する。しかし`id`ではなく、`product_number`を取得するとしたら、

```php:公式情報
return $this->hasMany('App\Product', 'seller_id', 'product_number');
```
上記のように記述する。


####多対多
[公式ページ](https://readouble.com/laravel/6.x/ja/eloquent-relationships.html#many-to-many)

`belongsToMany`を利用して、多対多を定義する。

#####基本

```php:belongsToManyの引数
return $this->belongsToMany('紐付けるモデル', '中間テーブル', '中間テーブルのこのモデル_id', '中間テーブルの紐付け先モデル_id');

```
第 1 引数では最終的な接続先モデル名を名前空間含めて指定する
第 2 引数では中間テーブル名を指定する
第 3 引数では接続元モデル ID を示す中間テーブル内のカラム名を指定する
第 4 引数では最終的な接続先モデル ID を示す中間テーブル内のカラム名を指定する
第 5 引数では接続元モデル ID のカラム名を指定する
第 6 引数では最終的な接続先モデル ID のカラム名を指定する


```php:公式ページ
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * userに所属する役目を取得
     */
    public function roles()
    {
        return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id');
    }
}
```



######マイグレーション

****他の例*****

- productモデル（リレーションの定義：必須）
- product_tagモデル（中間テーブル、リレーションの定義：不要）
- tagモデル（リレーションの定義；必須）

上記のモデルがあるとする。

それぞれのマイグレーションファイルを記述する


多となる`Product`のマイグレーションファイル


```php:_create_product_table.php
<?php

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

class CreateProductsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('products', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('title');
            $table->text('text');
            $table->unsignedBigInteger('user_id');
            $table->foreign('user_id')->references('id')->on('users');
            $table->timestamps();
        });
    }


```

もう一方の多となる`Tag`

```php:_create_Tab_table.php
<?php

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

class CreateTabsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('Tabs', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->timestamps();
        });
    }
```

ProductとTagを紐づける、中間テーブル`product_tag`
これに関しては外部キーで紐付けてあげればよい。

```_create_product_tag_table.php
<?php

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

class CreateProductsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('products', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->unsignedBigInteger('product_id');
            $table->foreign('product_id')->references('id')->on('products');
            $table->unsignedBigInteger('tag_id');
            $table->foreign('tag_id')->references('id')->on('tags');
            $table->timestamps();
        });
    }
```


###### エラー

#######SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint

*結論: 外部キーをもつモデルを先に削除しなさい*

下記の例は、postの外部キーをもつcommentのmigrationファイルです。
この場合、postより先にcommentモデルを削除する必要がある。
なので、そのように設定する。

```php:_create_post_tags_table.php
<?php

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

class CreatePostTagsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('post_tags', function (Blueprint $table) {
            $table->increments('id');
            $table->unsignedInteger('tag_id');
            $table->unsignedInteger('post_id');
            $table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
            $table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('post_tags'); 
        Schema::dropIfExists('posts'); //下に親モデル
        Schema::dropIfExists('tags');  //下に親モデル
    }
}


```

焦点をあててみると、

```php:ここ
    public function down()
    {
        Schema::dropIfExists('post_tags'); 
        Schema::dropIfExists('posts'); //下に親モデル ここ
        Schema::dropIfExists('tags');  //下に親モデル ここ
    }
```
外部キーの親モデルを下に書けばよい。

同様に親モデル側のmigrationにも書いていきます。

```php:_create_post_table.php
<?php

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

class CreatePostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title', 50);
            $table->text('body');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('post_tags');
        Schema::dropIfExists('posts');
    }
}

```

```php:create_tags_table.php
<?php

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

class CreateTagsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('tags', function (Blueprint $table) {
            $table->increments('id');
            $table->timestamps();
            $table->string('name');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('post_tags');
        Schema::dropIfExists('tags');
    }
}

```


#######SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'posts' already exists

このエラーが発生した場合は、一度リセットしなおせば良い。

```
$php artisan migrate:refresh
```
これで改善します。


あとは、リレーションを記述する。


#####リレーションの記述

productとtagのリレーションだけ記述すればいいので、難しくない。

```php:Product.php
<?php

namespace App\Model;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    public function tags()
    {
        return $this->belongsToMany('App\Models\Tag', 'product_tag'); 
    }
}
```



```php:Tag.php
<?php

namespace App\Model;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    public function products()
    {
        return $this->belongsToMany('App\Models\Product', 'product_tag'); 
    }
}
```

```php:product_tag

// 得に記述不要

```

これで多対多の完成です。



####save,create
[参考ページ](https://readouble.com/laravel/5.8/ja/eloquent-relationships.html#many-to-many-polymorphic-relations)
[参考](https://nextat.co.jp/staff/archives/200)

#####create
saveとsaveManyメソッドに加え、createメソッドも使用できます。属性の配列を引数に受け付け、モデルを作成しデータベースへ挿入します。saveとcreateの違いはsaveが完全なEloquentモデルを受け付けるのに対し、createは普通のPHPの「配列」を受け付ける点です。


```php:create
$post = App\Post::find(1);

$comment = $post->comments()->create([
    'message' => 'A new comment.',
]);

```

外部キーを紐付けるとき

```php:attach()で紐付ける
$post = Post::create($params);
$tag = Tag::firstOrCreate(['name' => $request->tags]);
$post->tags()->attach($tag);
```

#####createMany

```php:createMany
$post = App\Post::find(1);

$post->comments()->createMany([
    [
        'message' => 'A new comment.',
    ],
    [
        'message' => 'Another new comment.',
    ],
]);
```


#####save

```php:save
$post = App\Post::find(1);
$post->comments()->save($comment);
```

#####saveMany
複数の関連したモデルを保存する必要があるなら、`saveMany`メソッドを使用できます。

```php:saveMany
$post = App\Post::find(1);

//書き方1
$post->comments()->saveMany([
    new App\Comment(['message' => 'A new comment.']),
    new App\Comment(['message' => 'Another comment.']),
]);

//書き方2
$post->comments->saveMany([ $item1 , $item2 ]);

//書き方3
$post->comments()->saveMany($comments);
```






## ルーティング

### ファイルの場所
- web.php: 基本はここ
- api.php: APIのルーティングはこちら

###書き方
[チートシート](https://qiita.com/fagai/items/a1bf55b6249aee03a624)
[参考になる資料](https://blog.capilano-fw.com/?p=556#i-5)


#### GET

```php:web.php

Route::get('url', 'コントローラー＠アクション')->name('パスの名前');

Route::get('/posts/{post}', 'PostController@show')->name('posts.show');
```

#### POST

```php:web.php
Route::post('/',   'HomeController@post');

```

#### resource

#####通常
```php:web.php
Route::resource('photos', 'PhotoCommentController');
// [GET](/photos)           ->index
// [GET](/photos/{id})      ->show($id)
// [GET](/photos/create)    ->create
// [POST](/photos)          ->store
// [GET](/photos/{id})      ->edit($id)
// [PUT/PATCH](/photos/{id})->update($id)
// [DELETE](/photos/{id})   ->destroy($id)

Route::resource('photos', 'PhotoController');

```

##### only

```php:web.php

Route::resource('photos', 'PhotoController', [
  'only' => ['index', 'show']
]);
Route::resource('posts', 'PostsController', ['only' => ['create', 'store']]);

```

##### except

```php:web.php

Route::resource('photos', 'PhotoController', [
  'except' => ['index', 'show']
]);

Route::resource('tweets', 'TweetController', [ 'except' => ['index', 'show']]);

```

##### ネスト

```php:web.php

Route::resource('photos.comments', 'PhotoCommentController');
//photos/{photoId}/comments/{commentId}

```

##### middleware（ミドルウェア）

```php:->middleware()

#ログイン認証
Route::get('profile', function() {
    // 認証済みのユーザーのみが入れる
})->middleware('auth');

Route::get('/settings/security', function () {
    // ユーザーは続けるためにパスワードの入力が必要
})->middleware(['auth', 'password.confirm']);
```

```php:Route：：group()
#ユーザー認証あり
Route::group(['middleware' => 'auth'], function()
{
    Route::resource('tweets', 'TweetController', [ 'except' => ['index', 'show']]);
});
```

```php:Route：：middleware

Route::middleware(['first', 'second'])->group(function () {
    Route::get('/', function () {
        // firstとsecondミドルウェアを使用
    });

    Route::get('user/profile', function () {
        // firstとsecondミドルウェアを使用
    });
});

```

マニュアル：
https://readouble.com/laravel/6.x/ja/controllers.html


```php:ログイン認証の書き方
Route::get('/', function () {
    //
})->middleware('auth');

// １つのルートに対して複数のミドルウェアを指定する場合
Route::get('/', function () {
    //
})->middleware('auth', 'auth2');

// 複数のルートに対して１つのミドルウェアを指定する場合
Route::group(['middleware' => 'auth'], function () {
    //
});

// 複数のルートに対して複数のミドルウェアを指定する場合
Route::group(['middleware' => ['auth', 'auth2'], function () {
    //
});
```

[ログイン認証のマニュアルはこちら](https://readouble.com/laravel/6.x/ja/authentication.html)



TestController@indexでコントローラーを紐づけている。

###ルーティング一覧の確認方法

```:routingの一覧を確認
//ターミナルで確認
$ php artisan route:list

//ファイルで確認
$ php artisan route:list > route.text
```


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

```:ターミナル
$ php artisan make:controller TestController
```

### コントローラーの記述
```php:TestController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Test; #モデルとコントローラーを紐づける
use Illuminate\Support\Facades\DB; #この記述がないとクエリビルダはエラーになります

class TestController extends Controller
{
    //
    public function index() #railsの場合はdef indexだが、 laravelの場合はpublic function index() 
    {
        $values = Test::all(); #モデルを介して、DBから情報を取得
        dd($values); #railsのbinding.pryのように取得した内容を確認できる。
        return view('tests.index', compact('values')); #ここでどのviewなのか指定して紐づける
        #つまり、最後にどのviewにどの値を持っていくか指定する。

        #user認証をコントローラーで作成する場合
        if (Auth::check()) {
            return view('test/menu');
        } else {
            // ログインしていなかったら、Login画面を表示
            return view('auth/login');
        }
    }
}
```

#### エラー
##### [Notice: Undefined index](https://qiita.com/wakahara3/items/bb7c8d7a1673b161abe7)
nullの値が混じっているとエラーになるので、対策をとる必要がある。

#### index

#### create



#### store

```php:
    public function store(Request $request)
    {
        
        //newでsaveする方法
        $tweet = new Tweet;
        $tweet->title = $request->input('title');
        $tweet->text = $request->input('text');
        $tweet->user_id = $user->id;
        $tweet->save();

        //::createでいきなり保存する方法
        $task = Task::create($request->all());

        //validateしたあとに保存する方法
        $params = $request->validate([
                'title' => 'required|max:255',
                'body' => 'required|string',
            ]);

        $post = Post::create($params);
        

    }
```


##### エラー
[$fillableでホワイトリスト指定する](https://qiita.com/toro_ponz/items/b33c757cb7ba5bb48ed4)
これをしておかないとエラーが発生する。

```:エラー
Add [name] to fillable property to allow mass assignment on
```


```php:post.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    protected $fillable = [
        'title',
        'body',
    ];

    public function comments()
    {
        return $this->hasMany('App\Models\Comment');
    }
}

```


#### show

#### edit

#### update

```php:更新する
    public function update(Request $request, post $post)
    {
    $params = $request->validate([
        'title' => 'required|max:255',
        'body' => 'required|string',
    ]);
    $post->fill($params)->save();

    $task->update($request->all());

    }
```

```php:update()を使用
App\Flight::where('id', 1)
          ->update(['name' => $request->name]);
```

```php:save()を使用
$flight = App\Flight::find(1)
$flight->name = $request->name;
$flight->save();
```

#### destroy


### クエリビルダ

[マニュアルはこちら](https://readouble.com/laravel/6.x/ja/queries.html)

```php:
# use Illuminate\Support\Facades\DB;の記述がないとエラーになります

public function index()
    {
        $users = DB::table('users')
                ->where('votes', '>=', 100)
                ->get();

        $users = DB::table('users')
                ->where('votes', '<>', 100)
                ->get();

        $users = DB::table('users')
                ->where('name', 'like', 'T%')
                ->get();
        $users = DB::table('users')->where([
                    ['status', '=', '1'],
                    ['subscribed', '<>', '1'],
                 ])->get();

        return view('user.index', compact('users');

    }
```

### N+1問題

`::with(['comments']`のようにして、リレーションを引っ張る

[参考リンク](https://qiita.com/tmf16/items/b9dd262c7738472c86d9)
[公式ドキュメント](https://readouble.com/laravel/6.x/ja/eloquent-relationships.html)


```php:リレーションを引っ張る

//一つの場合
public function index()
{
    $users = User::with('posts')->limit(5)->get();
    return view('user.index')->with('users', $users);
}

//複数の場合は[]でまとめる
public function index()
    {
        $posts = Post::with(['comments'])->orderBy('created_at', 'desc')->paginate(20);

        return view('posts.index', ['posts' => $posts]);
    }

```

```php:リレーションをさらに引っ張る
public function index()
{
    $users = User::with('posts.comments')->limit(5)->get();
    return view('user.index')->with('users', $users);
}
````

```sql:結果
select * from users limit 5
select * from posts where posts.user_id in (1, 2, 3, 4, 5)
select * from comments where comments.post_id in (10, 20, 30, 40, 50)
```


```php:Authの場合

User::with('departmento')->find(Auth::id());
```
[参考リンク](https://stackoverflow.com/questions/49645879/laravel-authuser-relationship)

### where

```php:where（複数）
    public function index(Request $request)
    {
        //
        $last_comment_id = $request->id;
        $comment = Comment::find($last_comment_id);
        // $comments = Comment::Where([
        //                             ['tweet_id', '=', $comment->tweet->id],
        //                             ['created_at', '>', $comment->created_at],
        //                         ])->orderBy('created_at', 'asc')->get();
        $comments = Comment::With(['user'])->where([
                                                    ['tweet_id', '=', $comment->tweet->id],
                                                    ['created_at', '>', $comment->created_at],
                                                    ])->orderBy('created_at', 'asc')->get()->toJson();
        return $comments;
    }
```



##バリデーション
[マニュアルはこちら](https://readouble.com/laravel/6.x/ja/validation.html)
- 方法①:コントローラー上にリクエストをvalidationする 
- 方法②:`FormRequest`にvalidationを追加して、それをリクエストして利用する。

###方法1:コントローラー上でバリデーションする
`$request->validate()`を使ってvalidationする。

```php:controller
public function store(Request $request)
{
    $validatedData = $request->validate([
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ]);

    // ブログポストは有効
}
```


### 方法2:バリデーションを記述するファイルを作成
```:コマンド
#モデル名だけだと、コントローラーでモデルファイルとバリデーションファイルで競合になるので注意
php artisan make:request StoreTweet
```

```php:HTTP/Requests/StoreTweet.php

public function authorize()
    {
        #before
        return false;

        #after
        return true;
    }

public function rules()
    {
        return [
            // #バリデーションのルールを記述する
            'カラム名' => 'ルール１|ルール2|ルール3',
            'title' => 'required|string|max:45',
            'text' => 'required|string|max:400',
        ];
    }

```

```php:StoreTweet.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreTweet extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            //
            'title' => 'required|string|max:45',
            'text' => 'required|string|max:400',
        ];
    }
}

```
### 作成したバリデーションをコントローラーで読み込みさせる

```php:TweetController
use App\HTTP\Requests\StoreTweet; #バリデーションのファイルを読み込みさせる

class TweetController extends Controller
{
    #before: Request
    public function store(Request $request)

    #before: RequestをStoreTweetに変更 > バリデーションルールが適用
    public function store(StoreTweet $request)
    {
        //
        $user = Auth::user();
        $tweet = new Tweet;
        $tweet->title = $request->input('title');
        $tweet->text = $request->input('text');
        $tweet->user_id = $user->id;
        $tweet->save();
        return redirect(route('tweets.index'));

    }
```

### エラーメッセージをviewに表示

```php:１箇所にすべてのエラーを表示
@if ($errors->any())
    <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif
```

```php:inputの周辺でエラーを表示
@error('title')
    <div class="alert alert-danger">{{ $message }}</div>
@enderror
```

### エラーメッセージの編集

```php:validation.php

#型
'ルール'             => ':カラム名は〜です。',

#before
'required'             => ':attributeは必須です。',

#after
'required'             => ':attributeを入力してください。',

```

## ダミーデータ(seeder)
[マニュアルはこちら]（https://readouble.com/laravel/6.x/ja/seeding.html)

```:seederの作成
$ php artisan make:seeder PhotoTableSeeder
```

シーダクラスを書き上げたら、Composerのオートローダを再生成するために、dump-autoloadコマンドを実行する必要があります。

**流れ**
まず、seederのファイルを作成して記述します（後述）。
その後に、次のコマンドを実行します。

```:実行前コマンド
$ composer dump-autoload
```
これで準備ができたので、seederを実行します

```:全seederを実行
$php artisan db:seed
```
特定のseederのみを実行させたい場合

```:特定のseederクラスのみ実行
$ php artisan db:seed --class=UsersTableSeeder
```

## FactoryとSeederの作成

### 1対多


#### UserのFactory

```php:UserFactory.php
<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */
use App\User;
use Faker\Generator as Faker;
use Illuminate\Support\Str;

/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| This directory should contain each of the model factory definitions for
| your application. Factories provide a convenient way to generate new
| model instances for testing / seeding your application's database.
|
*/

$factory->define(User::class, function (Faker $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'email_verified_at' => now(),
        'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
        'remember_token' => Str::random(10),
    ];
});

```

#### 1対多の子要素のFactory

```php:PostFactory.php
<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\Models\Post;
use App\Models\Tag;
use Faker\Generator as Faker;

$factory->define(Post::class, function (Faker $faker) {
    //親要素のUserを取得
    $userIDs  = App\User::pluck('id')->all();
    return [
        'title'     => $faker->realText(30),
        'body'      => $faker->realText(),
        //外部キーに親要素のUserをセット（ランダム）
        'user_id'   => $faker->randomElement($userIDs),
    ];
});

```

```php:LikeFactory.php
<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\Models\like;
use Faker\Generator as Faker;

$factory->define(like::class, function (Faker $faker) {
    $postIDs  = App\Models\Post::pluck('id')->all();
    $userIDs  = App\User::pluck('id')->all();
    return [
        'post_id' => $faker->randomElement($postIDs),
        'user_id' => $faker->randomElement($userIDs),
    ];
});

```



## Seederの記述

```php:UserSeeder.php
<?php

use Illuminate\Database\Seeder;
use App\User;

class UserSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        App\User::create([
            'name' => "test",
            'email' => "test@test",
            'email_verified_at' => now(),
            'password' => bcrypt("test1234"),
            'remember_token' => "test12345"
        ]);
        factory(User::class, 100)->create();
    }
}

```

### １つのダミーデータを作成する

```:seedの作成
php artisan make:seeder UsersTableSeeder
```

seederのファイルを記述
1つのデータのみ作成する場合

```php:database/seeds/UserTableSeeder.php
<?php

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;

class DatabaseSeeder extends Seeder
{
    /**
     * データベース初期値設定の実行
     *
     * @return void
     */
    public function run()
    {
        DB::table('users')->insert([
            'name' => Str::random(10),
            'email' => Str::random(10).'@gmail.com',
            'password' => Hash::make('password'),
        ]);
    }
}
```

```php:繰り返し処理でやる場合
<?php

use Illuminate\Database\Seeder;

class TaskSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        for ($i = 1; $i <= 10; $i++) {
            Task::create([
                'title' => 'title' . $i,
                'content' => 'content' . $i,
                'person_in_charge' => 'person_in_charge' . $i,
            ]);
        }
    }
}
```

#### seeder実行時に作成されるモデルを追加

```php:DatabaseSeeder.php
<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call(UsersTableSeeder::class);
        $this->call(TweetSeeder::class); #追加
    }
}

```


```:実行前コマンド
composer dump-autoload
```

```:seedの実行
#すべてのseedを実行する場合
php artisan db:seed

#特定のファイルのみ実行する場合
php artisan db:seed --class=UsersTableSeeder

#一度DBをリセットする場合
php artisan migrate:fresh --seed
```


### ファクトリーで多数のダミーデータを作成する

[マニュアル](https://readouble.com/laravel/6.x/ja/database-testing.html)


[参考になる資料:
[PHP] Fakerでランダムなフェイクデータを作成する](https://qiita.com/Sa2Knight/items/fb82be7551cc84764267)

#### ファクトリの生成

```:コマンド

#モデル指定(モデル作成時にオプション-aを利用している場合、すでに作成されます)
php artisan make:factory TweetFactory --model=Tweet


#モデル指定なし
php artisan make:factory TweetFactory
```



#### フェイカーもを日本語に設定

```php:config/app.php

#before
'faker_locale' => 'en_US',

#after
'faker_locale' => 'ja_US',

```

#### 作成したファクトリーを記述

```php:database/factories/TweetFactory.php
use Faker\Generator as Faker;
use Illuminate\Support\Str;

$factory->define(App\User::class, function (Faker $faker) {
    #外部キーが必要な場合、user->idをpluckで取得する
    $userIDs  = App\User::pluck('id')->all();

    return [
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'email_verified_at' => now(),
        'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
        'remember_token' => Str::random(10),
        'title' => $faker->realText(30),
        #日本語の文章はrealText
        'text' => $faker->realText(200),
        #外部キーを挿入
        'user_id' => $faker->randomElement($userIDs),
    ];
});
```
Fakerの例

| country | 国名 |
|:--|:--|
| prefecture | 都道府県 |
| city | 市 |
| ward | 区 |
| streetAddress | 町以下 |
| postcode | 郵便番号 |
| secondaryAddress | マンション名 |
| company | 会社名 |
| userName | ユーザ名 |
| domainName | ドメイン名 |
| email | メールアドレス |
| name | 名前（姓 + 名） |
| lastName | 姓 |
| firstName | 名 |
| firstNameMale | 名（男性） |
| firstNameFeMale | 名（女性） |
| kanaName | 名前カナ |
| lastKanaName | 姓カナ |
| firstKanaName | 名カナ |
| firstKanaNameMale | 名カナ（男性） |
| firstKanaNameFemale | 名カナ（女性） |
| phoneNumber | 電話番号 |
| realText | 日本語文章 |

[pluckメソッド](https://qiita.com/k-o-u/items/31e4a2f9f5d2a3c7867f)
[外部キー制約の書き方](https://kengotakimoto.com/post-2794/)


#### ファクトリーの記述をseedファイルに使用する

```php:
<?php

use Illuminate\Database\Seeder;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\DB;
use App\Model\Tweet;

class TweetSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
  
#before
    public function run()
    {
        //

        DB::table('tweets')->insert([
            'title' => Str::random(10),
            'text' => Str::random(20),
            'user_id' => 1
        ]);
    }
#after
    public function run()
    {
        //
        #ファクトリーでTweetモデルを200個作成する
        factory(Tweet::class, 200)->create();
       
    }
}
```

#### seeder実行時に作成されるモデルを追加

```php:DatabaseSeeder.php
<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call(UsersTableSeeder::class);
        $this->call(TweetSeeder::class); #追加することでseederが実行される
    }
}

```
####実行する

```:実行前コマンド
composer dump-autoload
```

```:seedの実行
#すべてのseedを実行する場合
php artisan db:seed

#特定のファイルのみ実行する場合
php artisan db:seed --class=UsersTableSeeder

#一度DBをリセットする場合
php artisan migrate:fresh --seed
```


##View

基本的な考え方


1. app.blade.phpなどの土台となるhtmlを用意する。
2. その中に、コンテンツを入れたい場所に@yieldを記述する。
3. 他のbladeファイルは、@extendsで土台となるapp.blade.phpを呼び出す。
4. 呼び出したら、`@yield`の部分を`@section`で記述する
5. 部分テンプレートが必要な場合は、`@include`で呼び出す。


基本的な考え方2

viewファイルの指定は、
`layouts.app`のように`.`で指定する。
`.`で指定するのは、viewであったり、web.phpのnameなどです。


基本的な考え方3（変数）

コントローラーで変数を定義

```php:コントローラー

$test_1 = 1;
$test_2 = 2;

return view('posts.index', compact('test','test_2');
```
コントローラーから渡された変数は{{}}で使用する。

```php:変数をviewで使用する
<div>
  {{ $test_1 }}
</div>
```

#### @yield
指定した@sectionの内容を表示する。
つまり、@sectionの内容を埋め込みたい場所

```php:app.blade.php
@yield('content')
```

```php:index.blade.php
@section('content','これが表示されます'）
@section('content')
 こんな書き方もあります
@endsection()
```




#### @sectionの使い方

**基本**
1. `@yield`の場所に`@section`~`@endsection`で記述を追加する
2. `@yield`をなしでも、`@section`〜`@show`で表示可能。また,`@section`で上書きをしたり、`@section`~`@parent`~`@endsection`で`@show`の内容を残しつつ、さらに記述を追加できる。



```php:@sectionの書き方

//1 @endsection使わない場合
@section('title', 'アプリ名')

//1で変数を渡す場合
@section('title', $post->title)

//2 @endsectionを使う場合
@section('content')
<a></a>
@endsection

```

つまり、
yieldを指定して、endsectionを使って書くか、そうでないかのやり方が基本となる。

#### @includeは部分テンプレート

[わかりやすいサイト](http://recipes.laravel.jp/recipe/106)

```php:まとめ
//呼び出すだけ
@include('layouts.header')

//変数を渡して呼び出す
@include('layouts.header', ['テンプレート内の変数' => 渡す値])

```

headerを別ファイルにまとめて、土台となるapp.blade.phpに読み込ませる

```php:layouts/app.blade.php
    <body>
        <div class="flex-center position-ref full-height">
          @include('layouts.header') # views/layouts.header.blade.phpを読み込む
        </div>
    </body>
```

変数を渡す場合

```php:app.blade.php
<body>
  <h1>All the items:</h1>
  @foreach ($items as $foo)
    @include('partials.item-display', ['item' => $foo])
  @endforeach
</body>
```

```php:item-dispay.blade.php
<div>
    Name: {{ $item->name }}<br>
    Description: {{{ $item->description }}}
</div>
```

extendsしたテンプレートへ挿入したいsectionはどこに書いても良い
extends宣言の前でも後でも良い
includeしたテンプレートへ挿入したいsectionは、includeするよりも先にsectionを書かないといけない
sectionの記述後にincludeしないといけない

エラーが起こるケース

```php:複数行に改行している場合、エラーが発生
@include('my-partial-name', [
    'value1' => 'abc',
    'value2' => $some_var,
    'value3' => date('Y-m-d'),
])
```



[参考リンク](https://qiita.com/awesam86/items/0bc8c3f70222220259b0)

```php:views/layouts/app.blade.php
<html>
    <head>
        <title>アプリ名 - @yield('title')</title>
    </head>
    <body>
        @section('sidebar')
            ここがメインのサイドバー
        @show

        <div class="container">
            @yield('content')
        </div>
    </body>
</html>
```

layoutsを土台にして、index.blade.phpを作成する

```php:views/tweets/index.blade.php
<!-- resources/views/child.blade.phpとして保存 -->

@extends('layouts.app') # layoutsフォルダの中にある、app.blade.phpを読み込む

@section('title', 'Page Title') # @yield('title')の中身をPage Titleにする

@section('sidebar')
    @parent

    <p>ここはメインのサイドバーに追加される</p>
@endsection

@section('content')
    <p>ここが本文のコンテンツ</p>
@endsection
```

実際に表示されるのは下記になる

ここがメインのサイドバー
ここはメインのサイドバーに追加される

ここが本文のコンテンツ




### 土台となるapp.blade.phpを作成
[マニュアルはこちら]
(https://readouble.com/laravel/6.x/ja/blade.html)

viewsの中にlayoutsフォルダを作成し、その中にapp.blade.phpを作成する



```php:views/layouts/app.blade.php
```

### {{}}XSS攻撃を防ぐ





### メソッド
#### ループ処理
[公式ドキュメント](https://readouble.com/laravel/6.x/ja/blade.html?header=%25E7%25B9%25B0%25E3%2582%258A%25E8%25BF%2594%25E3%2581%2597)

@foreachは全部に適応 => エラーが出たりする
@forelseは空欄の時も設定できる => エラーが出ないようにカスタムしやすい

```php:公式ドキュメント
@for ($i = 0; $i < 10; $i++)
    現在の値は： {{ $i }}
@endfor

@foreach ($users as $user)
    <p>これは {{ $user->id }} ユーザーです。</p>
@endforeach

@forelse ($users as $user)
    <li>{{ $user->name }}</li>
@empty
    <p>ユーザーなし</p>
@endforelse

@while (true)
    <p>無限ループ中</p>
@endwhile
```

#####brake処理

`@continue`で続行、`@break`で終了


```php:brakeで途中で終了させる
@foreach ($users as $user)
    @if ($user->type == 1)
        @continue
    @endif

    <li>{{ $user->name }}</li>

    @if ($user->number == 5)
        @break
    @endif
@endforeach
```

くは、ディレクティブに条件を記述して、一行で済ますこともできます。

```php:ifをblakeに変更


@foreach ($users as $user)
    @continue($user->type == 1)

    <li>{{ $user->name }}</li>

    @break($user->number == 5)
@endforeach
```






#### ログイン判定
マニュアル
https://readouble.com/laravel/6.x/ja/blade.html


```php:認証によって表示切り替え
@auth
    // ユーザーは認証済み
@else 
    // 
@endauth

@guest
    // ユーザーは認証されていない
@endguest
```

### aタグにrouteのリンクを埋め込む
routeのnameを記述することで、リンク先のURLを簡単に指定できる

```
<a href={{ route('contacts.index') }}
```

### フラッシュメッセージ
[参考](https://qiita.com/usaginooheso/items/6a99e565f16de2f9ddf7)
# 補足情報


### ページネーション

[マニュアル](https://readouble.com/laravel/6.x/ja/pagination.html)

`->paginate(表示件数)`をつけるだけ

```php:コントローラー
public function index()
    {
        #before
        $users = DB::table('users')->get();

        #after(getをpaginateに変更）
        $users = DB::table('users')->paginate(15);

        return view('user.index', ['users' => $users]);
    }
```

#### viewにページネーションを表示

```php:viewに付与
{{ $users->links() }}
```


### -> と =>の違い

->…オブジェクトのプロパティやメソッドを参照する場合に使う
=>…連想配列のキーと値を区切る場合に使う


=> ダブルアロー演算子
定義する際に利用する
配列のキーととバリューを定義する際に利用する。

``キー => バリュー``



```ruby:rubyの場合
#シンボル型
[name: '田中', age: 19]

#ロケットハッシュ
[name => '田中', age => 19]

#laravelはシンボル型がない。
```

-> アロー演算子
表示する際に利用する
モデルのカラムを取り出したりする際に利用する。
``左から右に取り出す``

```php:laravel
$user->name #名前を表示
$user->age #年齢を表示
```

## テスト

[わかりやすいサイト](https://qiita.com/nozaki-sankosc/items/4f20a4a30e6b730ec211)
[参考にしようと思う記事](https://qiita.com/yotahada-nus3/items/46f6bdb1dbdcf093fdfc)
[ログインのテスト](https://engineer-lady.com/program_info/create-login-phpunit-laravel7/)
[noteで参考になる記事](https://note.com/kodokuna_dancer/n/n52f7387ecb00)
[Laravelでテストコードを書くためのチュートリアル](https://qiita.com/niisan-tokyo/items/264d4e8584ed58536bf4)

### テストファイルの作成

Featureテスト
実際の通信を伴う機能テスト

```:コマンド
php artisan make:test [テストケースクラス名]

php artisan make:test PostTest
```

Unitテスト
PHPクラス単位の単体テスト

```:コマンド
php artisan make:test [テストケースクラス名] --unit

php artisan make:test PostTest --unit
```

### テストファイルの編集

注意：　`public function test~`のように`test`が先頭にないと実行されない。

```php:ExampleTest
<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class ExampleTest extends TestCase
{
    /**
     * @return void
     */
    public function testBasicTest()
    {
        $response = $this->get('/');
        $response->assertStatus(200);
    }
}
```

#### 実例

```php:TaskTestphp

<?php

namespace Tests\Unit;

// use PHPUnit\Framework\TestCase;
use Tests\TestCase;
use App\Models\Task;

class TaskTest extends TestCase
{
    /**
     * A basic unit test example.
     *
     * @return void
     * @test
     */
    public function testExample()
    {
        // $this->assertTrue(true);
        $response = $this->get('/tasks');
        $response->assertStatus(200);
    }

    public function testHttpIndex()
    {
        $response = $this->get('/tasks');
        $response->assertStatus(200);
    }

    public function testHttpCreate()
    {
        $response = $this->get('/tasks/create');
        $response->assertStatus(200);
    }

    public function testHttpShow()
    {
        $response = $this->get('/tasks/1');
        $response->assertStatus(200);
    }

    public function testHttpEdit()
    {
        $response = $this->get('/tasks/1/edit');
        $response->assertStatus(200);
    }

    public function testInsert_success()
    {
        $tasks = factory(Task::class, 3)->create();
        $count = count($tasks);
        $this->assertEquals(3, $count);
    }
}

```

実行すると
![スクリーンショット 2020-11-29 18.29.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455403/c5db3efe-e145-ef5f-9eb9-36cfe766906b.png)



### 実行方法

```:実行コマンド1(laravel7)
$ php artisan test
```
または

```:実行コマンド2
$ vendor/bin/phpunit
```




# デバック

## eval(\Psy\sh());

## dd()


#js

## jsを使えるようにする
[参考リンク](https://qiita.com/ntm718/items/fed0e1060557a4e28ef3)

###jsファイルを作成

```javascript:resource/js/sample.js

#ここに記述をする

```

###jsファイルを読み込みさせる

```javascript:resource/js/app.js

require('./bootstrap');
require('./flashmessage');
require('./sample'); //requireで読み込みさせる
```

```javascript:webpack.mix.js
const mix = require('laravel-mix');


mix.js([
        'resources/js/app.js',
        'resources/js/scroll.js',
        'resources/js/sample.js',
        'resources/js/comments.js',
    ], 'public/js')
    .sass('resources/sass/app.scss', 'public/css');

```

```:コマンド
npm run dev
```

個別に読み込ませるなど

```php:css
<link href="{{ mix('css/app.css') }}" rel="stylesheet" type="text/css">
````
app.cssはscssなどをコンパイルしたもので、scssも問題なく利用できます。

```php:js
@section('js')
<script src="{{ mix('js/app.js') }}"></script>
@show
```




## 非同期通信(AJAX)
[非同期通信でデバックする方法](https://qiita.com/hubtakaya/items/8a2028e3c4da97253e48)

[参考](https://atuweb.net/201609_laravel-get-ajax-request/)$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});


```php:アクションを作成
public function getData()
{
    $comments = Comment::orderBy('created_at', 'desc')->get();
    $json = ["comments" => $comments];
    return response()->json($json);
}
```

```php:json型でレスポンス
return response()->json($json);
```

[json型について](https://qiita.com/qiita-kurara/items/089db7349e33b9402b42)

### ajaxを使って、jsonを取得する
ajaxを使えるようにするために、app.blade.phpのheadの部分でスクリプトを読み込む。

```php:ajaxを使うスクリプト
<script src="{{ asset('js/app.js') }}" defer></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
```


```javascript:ajaxのjsを作成
$.ajax({
    url: "result/ajax/",
    dataType: "json",
    success: data => {
      // 成功時の処理
    },
    error: () => {
      // エラー時の処理
    }
})
```



[マニュアル](https://readouble.com/laravel/6.x/ja/validation.html?header=AJAX%25E3%2583%25AA%25E3%2582%25AF%25E3%2582%25A8%25E3%2582%25B9%25E3%2583%2588%25E3%2581%25A8%25E3%2583%2590%25E3%2583%25AA%25E3%2583%2587%25E3%2583%25BC%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%25B3)
>AJAXリクエストとバリデーション
この例ではアプリケーションにデータを送るために伝統的なフォームを使いました。しかし、多くのアプリケーションでAJAXリクエストが使用されています。AJAXリクエストにvalidateメソッドを使う場合、Laravelはリダイレクトレスポンスを生成しません。代わりにバリデーションエラーを全部含んだJSONレスポンスを生成します。このJSONレスポンスは422 HTTPステータスコードで送られます。

[マニュアル](https://readouble.com/laravel/6.x/ja/csrf.html?header=X-CSRF-TOKEN)
>さらに追加でPOSTパラメーターとしてCSRFトークンを確認したい場合は、LaravelのVerifyCsrfTokenミドルウェアがX-CSRF-TOKENリクエストヘッダもチェックします。たとえば、HTML中のmetaタグにトークンを保存します。

```php
<meta name="csrf-token" content="{{ csrf_token() }}">
```

metaタグを作成したら、jQueryのようなライブラリーで、全リクエストヘッダにトークンを追加できます。この手法によりAJAXベースのアプリケーションにシンプルで便利なCSRF保護を提供できます。

```php


$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});
```


[参考](https://qiita.com/Alesion30/items/dddb3f162e60b16fdc6d#%E9%9D%9E%E5%90%8C%E6%9C%9F%E9%80%9A%E4%BF%A1%E3%81%A8%E3%81%AF)

## jsonにリレーションのモデルを付与する
[マニュアル](https://readouble.com/laravel/6.x/ja/eloquent-serialization.html)
[参考](https://qiita.com/hiyoko3/items/eb4ee9c04b296c9e7241)

#パッケージ（ライブラリ）を入れる
[参考になるサイト](https://laraweb.net/surrounding/3973/)
[参考になるサイト](https://qiita.com/shinkuFencer/items/8e109d45861ee56df42a)



### 追加方法

パッケージを後追いで追加する場合、

`composer require {パッケージ名}` で行います。

パッケージ名が `hoge/huga` の場合


```
$ ~/composer/composer.phar require hoge/huge
```

この場合は当該パッケージのみを入れ込み、またcomposer.jsonにも追記してくれます。

なお、`hoge/huge`にあたるパッケージ名の一覧は
[Packagist](https://packagist.org/)から探す。

### バージョン指定してパッケージを後追いで追加したい

古いバージョンのモジュールを使う必要がある、というような場合にはバージョン指定で入れる。
`composer require {パッケージ名}:{バージョン番号}` で行います。
下記は`hoge/huga`の2.6.30のバージョンを入れたい場合の例。

```
$ ~/composer/composer.phar require hoge/huge:2.6.30
```



バージョン番号もPackageistにあるのでそこを参考に。

```
# パッケージを追加
$ composer require [vendor/package]
# 実例
$ composer require goodby/csv
# バージョン指定してパッケージを追加
$ composer require goodby/csv:1.2.0

# 削除
$ composer remove [vendor/package]

# 「開発」で必要なものを追加
$ composer require --dev [vendor/package]

# 「開発」で必要なものを削除
$ composr remove --dev [vendor/package]
```

### 参考

* [composerで利用できるコマンド一覧 \| WEBサービス創造記](http://linuxserver.jp/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0/php/composer-list#require)