[Laravel7] Laradockで開発するための準備

# 目的
新しい環境を構築する際に、手順が確立していないと面倒なことが多かったので、
Laradockで作る簡単な手順をココに記載しておこうと思う。
※なお、docker for macでのdocker環境があること前提で記載している。

## 1.Laradock設定
### 1-1.Laradockの準備

[laradock](https://github.com/laradock/laradock.git)はこちらから入手する。

コマンドは、
`git clone https://github.com/laradock/laradock.git`

### 1-2.Laradockの設定
・ mysqlのversionの指定があれば、

```:.env
MYSQL_VERSION=5.7.12
```
として指定する。

・管理画面にVoyagerを使うため

```:.env
PHP_FPM_INSTALL_EXIF=true
```
としておく。


```:.phpfpm/Dockerfile
ARG INSTALL_EXIF=true
```
こちらも設定すること。


### 1-3.nginx conf設定

・[XXX]はhost名にしておくこと

```:nginx/sites/[XXX].conf
server {

    listen 80;
    listen [::]:80;

    server_name [XXX].local;
    root /var/www/[XXX]/public;
    index index.php index.html index.htm;

    location / {
         try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
        try_files $uri /index.php =404;
        fastcgi_pass php-upstream;
        fastcgi_index index.php;
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        #fixes timeouts
        fastcgi_read_timeout 600;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }

    error_log /var/log/nginx/app_error.log;
    access_log /var/log/nginx/app_access.log;
}
```

### 1-4.hosts設定

・macの場合
`sudo vi /etc/hosts`

```:/etc/hosts
127.0.0.1 [XXX].local
```

これで、`http://[XXX].local/`としてアクセスできるようになる。

### 1-5.laradock立ち上げ

`docker-compose up -d nginx mysql workspace redis`

このように立ち上がれば成功。
![スクリーンショット 2020-07-11 2.09.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232174/e7e7c969-e94c-167e-fc05-7cfb1158cc44.png)

### 1-6.mysql database作成
.mysqlコンテナに入る
`docker-compose exec mysql bash`

・mysql起動
`mysql -uroot -proot`

・database作成&権限付与
`CREATE DATABASE IF NOT EXISTS `[XXX]_db` COLLATE 'utf8_general_ci' ;`
`GRANT ALL ON `[XXX]_db`.* TO 'default'@'%' ;`


## 2.Laravel設定
### 2-1.Laravel 準備

このようにLaradockと同じ場所にLaravel projectを設置する。
![スクリーンショット 2020-07-11 2.16.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232174/7df309bf-8a0d-fd3d-af03-ccfea49c02da.png)

`composer create-project --prefer-dist laravel/laravel [XXX]`

### 2-2. .env作成
workspaceに入って、[XXX]に遷移。
`docker-compose exec workspace sh`
`cd [XXX]`

.envを作成する。
`cd [XXX]`
`cp .env.example .env`

そして、key:generateしておく。
`php artisan key:generate`

### 2-3. .env Mｙｓｑｌ設定

Laravel [XXX]直下の.env

```:.env
DB_CONNECTION=mysql
DB_HOST=mysql
DB_HOST_READ=mysql
DB_PORT=3306
DB_DATABASE=[XXX]_db
DB_USERNAME=default
DB_PASSWORD=secret
```

※マスター/スレーブ構成の準備として`DB_HOST_READ=mysql`を追記している

### 2-4. .env redis設定

Laravel [XXX]直下の.env

```:.env
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379
```

### 2-5. .env Voyager設定

Laravel [XXX]直下の.env

```:.env
SESSION_COOKIE=auth
SESSION_COOKIE_ADMIN=auth-admin
```

### 2-6. laravel/ui設定(ログイン機能)

`composer require laravel/ui`
`npm install && npm run dev`
`php artisan ui vue --auth`
`php artisan migrate`

【参考】[https://qiita.com/kapibarasensei/items/c6b40366505f94103c35](https://qiita.com/kapibarasensei/items/c6b40366505f94103c35)

### 2-7. voyager設定

`composer require tcg/voyager`
`php artisan voyager:install`

・管理者作成
`php artisan voyager:admin admin@admin.com --create`

```:/config/session.php
$uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
if (strpos($uri, '/admin/') === 0 || $uri === '/admin') {
    $conf['cookie'] = env(
        'SESSION_COOKIE_ADMIN',
        str_slug(env('APP_NAME', 'laravel'), '_').'_admin_session'
    );
}
```

```:/config/auth.php
$uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
if (strpos($uri, '/admin/') === 0 || $uri === '/admin') {
    $conf['defaults'] = [
        'guard' => 'web',
        'passwords' => 'users',
    ];
}
```

【参考】[https://qiita.com/daisu_yamazaki/items/0e27a62990ef32998a2d](https://qiita.com/daisu_yamazaki/items/0e27a62990ef32998a2d)

### 2-8. redis準備
`composer require predis/predis`

【参考】[https://qiita.com/ma7ma7pipipi/items/e3f7007d38ee5cedcd48](https://qiita.com/ma7ma7pipipi/items/e3f7007d38ee5cedcd48)

### 2-9. doctrine/dbal準備
`composer require doctrine/dbal`

### 2-10. マスター/スレーブ設定

```:config/database.php
        'mysql' => [
            'driver' => 'mysql',
            'url' => env('DATABASE_URL'),
            'read' => [
                'host' => env('DB_HOST_READ', '127.0.0.1'),
                'port' => env('DB_PORT', '3306'),
            ],
            'write' => [
                'host' => env('DB_HOST', '127.0.0.1'),
                'port' => env('DB_PORT', '3306'),
            ],
```

【参考】[https://qiita.com/ngyuki/items/a3ab2ea615e8ba73a491](https://qiita.com/ngyuki/items/a3ab2ea615e8ba73a491)

### 2-11. Laravel-enum

`composer require bensampo/laravel-enum`

【参考】[https://qiita.com/10mi8o/items/dcab6fbf0e71389304f1](https://qiita.com/10mi8o/items/dcab6fbf0e71389304f1)


### 2-12. キャッシュクリア等実行
`php artisan migrate`
`composer dump-autoload`
`php artisan cache:clear`
`php artisan config:clear`
`php artisan route:clear`
`php artisan view:clear `


---

これで一通りの準備が出来たかと思います。
ここからは、Voyagerからアップする画像の保存先をS3にする場合の設定を記述しておきます。
※本家のドキュメント、動画にはありましたが、日本語化されていなかったので忘備録として。

---

## 3.S3等設定
### 3-1.パッケージのインストール
`composer require league/flysystem-aws-s3-v3`

### 3-2. .env記述

```:.env
AWS_ACCESS_KEY_ID=ユーザーを作成した際に表示されたAccess key ID
AWS_SECRET_ACCESS_KEY=ユーザーを作成した際に表示されたSecret access key
AWS_DEFAULT_REGION=ap-northeast-1 （東京リージョンの場合）
AWS_BUCKET=bucket名
AWS_URL=buketのURL
AWS_ENDPOINT=https://s3-ap-northeast-1.amazonaws.com（東京リージョンの場合）
```

【参考】[https://qiita.com/tiwu_dev/items/ecb115a92ebfebf6a92f](https://qiita.com/tiwu_dev/items/ecb115a92ebfebf6a92f)


※ENDPOINTはVoyagerのアップ時に利用している?
https://s3-[リージョン名].amazonaws.com
【参考】[AWSサービスエンドポイント](https://docs.aws.amazon.com/ja_jp/general/latest/gr/rande.html)

### 3-3.Voyager用設定
Voyagerの画像ファイルの保存先をS3にしたいが、設定手順が見つからなかったので記載。

```:config/voyager.php
    'storage' => [
        'disk' => 's3',
    ],
```

※S3の権限設定も必要。
(Voyagerからの画像アップをするので公開設定にしておく)
【参考】[https://qiita.com/masch/items/fedd4894087b7447827f](https://qiita.com/masch/items/fedd4894087b7447827f)


## 4.その他
### 4-1.Helper
[Laravel 5へ自作のヘルパー関数を追加するベストプラクティス](https://s8a.jp/laravel-custom-helper)
※ヘルパー関数を読み込むサービスプロバイダを定義する方法 を利用しています

### 4-2.Api設定
apiでもsessionを使えるようにしておく。

```:app/Http/Kernel.php
        'api' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            // 'throttle:60,1',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
```

### 4-3. 管理画面のみBasic認証

`php artisan make:middleware BasicAuthMiddleware`

```:app/Http/Middleware/BasicAuthMiddleware.php
<?php

namespace App\Http\Middleware;

use Closure;

class BasicAuthMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $url = config('app.url');
        $urlAddress = [
            'http://[XXX].test',
        ];

        // localの場合は外す
        if(!in_array($url, $urlAddress)) {
            // PHPによるBasic認証
            switch (true) {
                case !isset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']):
                case $_SERVER['PHP_AUTH_USER'] !== 'user':
                case $_SERVER['PHP_AUTH_PW'] !== 'password':
                    header('WWW-Authenticate: Basic realm="Enter username and password."');
                    header('Content-Type: text/plain; charset=utf-8');
                    die('このページを見るにはログインが必要です');
            }
        }

        header('Content-Type: text/html; charset=utf-8');
        return $next($request);
    }
}
```

※localではbasic認証を付けないようにしている。
※ここでuserとパスワードを管理するよりも、.envで設定して環境毎に変えるとかも良いかもしれません。

```:app/Http/Kernel.php
protected $routeMiddleware = [

        'basicauth' => \App\Http\Middleware\BasicAuthMiddleware::class, //追加
    ];
```

```:routes/web.php
// Basic認証
Route::group(['middleware' => 'basicauth'], function() {
    Route::group(['prefix' => 'admin'], function () {
        Voyager::routes();
    });
});
```