Laravel5.5をGoogle App Engineで動かす

これを執筆している時点ではまだベータ版ですが、ようやくGoogle App Engineのスタンダード環境でPHP7.2が使えるようになり、Laravelの最新LTSであるところの5.5も使えるようになりました。
しかし、実際に使おうとすると数々のハマりどころがありましたので、その辺りをまとめようと思います。ついでにLaradockあたりもチョロっと。

*この記事はまだ不安定な環境に関するものであるため、すぐに内容が不正確になる可能性があります。ご了承ください。*

## 開発環境構築

Laradockで開発環境を構築します。
Laradockの導入方法・使い方等は[公式ドキュメント](https://laradock.io/getting-started/)でご確認ください。
`docker-compose up -d nginx mysql`する前に以下の設定を追記します。

### MySQL

`docker-compose exec mysql mysql -u homestead -psecret`からテーブルの中身を確認した時に文字化けしないよう、laradock/mysql/my.cnfに以下の設定を追記します。

```
 [mysql]
default-character-set=utf8mb4 #これを追記
```

### Google Cloud SDK

Laradock内でgcloudコマンドを使ったり、GAEへデプロイを行うため、Google Cloud SDKをインストールします。
workspaceに入って自分でコマンドを叩くなんてナンセンスです。workspace/Dockerfileに以下を追記しましょう。

```
# ここから
###########################################################################
# Google Cloud SDK:
###########################################################################

RUN export CLOUD_SDK_REPO="cloud-sdk-$(lsb_release -c -s)" && \
    echo "deb http://packages.cloud.google.com/apt $CLOUD_SDK_REPO main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list && \
    curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \
    apt-get update -y && apt-get install google-cloud-sdk -y
# ここまで追記

###########################################################################
# Check PHP version:
###########################################################################
```

ちなみに、デプロイに関する詳細は[ComposerでGoogle App Engineへのデプロイ等を楽にする](https://qiita.com/fullkawa/items/1b435c9ce41472509e14)にまとめています。


## 設定など

### Google Cloud SDKの認証

`docker-compose up -d nginx mysql`を実行し、無事コンテナが起動したら、以下の手順で忘れずに認証を行なってください。

```
$ docker-compose exec --user=laradock workspace bash
laradock@4372800326ab:/var/www$ gcloud auth login
```

### GaeSupportLaravelの導入

GAEでLaravelを使えるようにするため、[a1comms/GaeSupportLaravel](https://github.com/a1comms/GaeSupportLaravel)を利用します。
READMEでは

```
"require": {
    "a1comms/gae-support-laravel": "~5.4"
}
```

composer.jsonに上記を追記せよと書いてありますが、[Packagist](https://packagist.org/packages/a1comms/gae-support-laravel)の方を見ると5.4はなさそう...？(2018/11/11現在)　また、5.1系はLaravel5.1用のようです。
5.5を利用する場合は以下のように追記します。

```
"require": {
    "a1comms/gae-support-laravel": "dev-php72-laravel55"
}
```

`bootstrap/app.php`, `config/app.php`, `composer.json`の修正はREADME通りやって大丈夫です。

### 環境変数

.envファイルでSESSION_DRIVERの値を"gae"に変更しないとセッションが利用できません。どうしてこんな重要なことがREADMEに書いていないの...

```
#SESSION_DRIVER=file
SESSION_DRIVER=gae
```

セッションはMemcacheではなく、CloudDatastoreに"sessions"という種類で保存されます。
通常は見えない？ので、こんな感じのGQLで確認しました。

```
SELECT * FROM sessions
```

あと、[ソース](https://github.com/a1comms/GaeSupportLaravel/blob/php72-laravel55/src/A1comms/GaeSupportLaravel/GaeSupportServiceProvider.php)を読む限り、これも追加しないといけないんじゃないかなあ...

```
FILESYSTEM_DRIVER=gae
```

こちらはまだ利用の機会がないので検証できしだい書き換えます。(経験者の編集リクエスト歓迎)

### app.yaml

app.yamlはほぼ[GCPのドキュメント](https://cloud.google.com/appengine/docs/standard/php7/config/appref#example)ままです。

```
runtime: php72

handlers:
# Serve a directory as a static resource.
- url: /css
  static_dir: public/css
- url: /image
  static_dir: public/image
- url: /js
  static_dir: public/js

# Serve images as static resources.
- url: /(.+\.(gif|png|jpg))$
  static_files: \1
  upload: .+\.(gif|png|jpg)$

# Serve your app through a front controller at index.php or public/index.php.
- url: .*
  script: auto
```

注意点は、**skip_filesディレクティブがなくなったので、アップロードしたくないファイルは`.gcloudignore`に記述すること**でしょうか。これをしないとvendorのファイルで軽くファイル数上限の10000を超えるでしょう。

また、[GAE/PHPで.gcloudignoreにcomposer.lockを入れてはいけない](https://qiita.com/hnw/items/3adb8b3450152d5cf143)で記述されている以下の点も要注意です。(大変参考になりました。ありがとうございます！)

> どうやらPHP 7.2環境では/vendor/ディレクトリは特別扱いされているようで、自分の手元の/vendor/をアップロードしても無視されます。代わりに、アップロードされたcomposer.lockを元にcomposer installした結果が反映されます。

つまり、"laralib/l5scaffold"のように**vendor以下のファイルを直接修正しないと動かない場合は詰みます。**
参考: [Laravel5.6でscaffoldが動かなかった件](https://qiita.com/masahirok_jp/items/43205bb62cdc4240bb83)

```
$ gcloud app deploy --project=MY_PROJECT_ID
(中略)
Script gcloud app deploy --project=MY_PROJECT_ID handling the deploy event returned with error code 1
```

ビルドの詳細に以下のようなログが出力されます。

```
...
Step #1 - "builder": Generating optimized autoload files
Step #1 - "builder": > Illuminate\Foundation\ComposerScripts::postAutoloadDump
Step #1 - "builder": > @php artisan package:discover
Step #1 - "builder": [2018-11-11 09:43:06] staging.ERROR: Trait 'Illuminate\Console\AppNamespaceDetectorTrait' not found {"exception":"[object] (Symfony\\Component\\Debug\\Exception\\FatalErrorException(code: 1): Trait 'Illuminate\\Console\\AppNamespaceDetectorTrait' not found at /workspace/vendor/laralib/l5scaffold/src/Commands/ScaffoldMakeCommand.php:21)"} []
Step #1 - "builder": Script @php artisan package:discover handling the post-autoload-dump event returned with error code 255
Step #1 - "builder": 
Step #1 - "builder": error: `composer_update_lock` returned code: 255
Finished Step #1 - "builder"
ERROR
ERROR: build step 1 "gcr.io/gae-runtimes/php72_app_builder:php72_7_2_8_20181026_RC00" failed: exit status 1
```

幸い"laralib/l5scaffold"は運用時には不要なので、私は`config/app.php`の`Laralib\L5scaffold\GeneratorsServiceProvider::class,`をコメントアウトすることで逃げました。もっと賢い対処方法を知っている方がいたら、ぜひご教授ください。