CakePHP3のCMSチュートリアルを速攻試せる環境をDockerで立ち上げる

# Overview
CakePHPのドキュメントにある[コンテンツ管理チュートリアル - 3.8](https://book.cakephp.org/3/ja/tutorials-and-examples/cms/installation.html)を
極力単純にDocker上で動かしつつ実行できる環境を作った。

別記事を書くためにCakeが動作するプロジェクトのベースが欲しかったので
自分が作成したCakeプロジェクトで利用しているファイルをシュリンクして作成した。

リポジトリ：https://github.com/stlwolf/cake3_cms_in_docker

## この記事&リポジトリが役に立ちそうなケース
CakeをDocker上で実行するための環境作りについての情報はチラホラあるけど、
とりあえずNginxとか考えずにチュートリアルを写経しながら動作確認してみたいんじゃ〜
って人がいれば使えるんじゃないかと。

注：上記のユースケースから、開発環境や本番環境での利用に耐える実行環境ではありません。
　　チュートリアルの記事通り、PHPのビルトインサーバーを利用します。

# Environment
- ホスト
  - macOS Catalina 10.15.4
  - CakePHP 3.7
- コンテナ
  - PHP 7.3.18
  - mysqld Ver 5.7.27

# Usage
- composerライブラリのセットアップ  
  - `./operation.sh setup`

- コンテナ＆cakeサーバー起動  
  - `./operation.sh`  
   （`operation.sh`はフォアグラウンドで実行されるので、  コンテナを停止する時は`Ctrl+C`で行ってください）

- 無事起動したらブラウザで `http://localhost:8765/` にアクセスすれば下記のページが表示されるはず
<img width="1120" alt="Screen Shot 2020-06-13 at 4.01.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59057/e52b6d10-6700-80bd-3187-10f87d3b1ae2.png">

- ここまででCMSチュートリアルの「データベース設定」の項目まで完了しているので、
あとは[「最初のモデルの作成」](https://book.cakephp.org/3/ja/quickstart.html#id5)以降のチュートリアルを試すことができます。
チュートリアルを写経したり、コードを追加して色々いじってみましょう。

# 軽い内容解説
- スケルトンはcakephp/appの3.*系を利用  
  - [GitHub - cakephp/app at 3.8.0](https://github.com/cakephp/app/tree/3.8.0)
  - [コンテンツ管理チュートリアル - 3.8](https://book.cakephp.org/3/ja/tutorials-and-examples/cms/installation.html)

- Dockerで動作させるために追加したファイル

```
├── docker
│   └── containers                  # コンテナ毎のDockerfileなどを配置
│       ├── common.env              # コンテナ共通の設定
│       ├── mysql                   # MySQLコンテナ 
│       │   ├── conf
│       │   │   └── my.cnf
│       │   └── init
│       │       └── 1_init_ddl.sql  # 「CMS チュートリアル - データベース作成¶」に記述があるSQL
│       └── php-fpm                 # bin/cake server を実行するPHPコンテナ
│           └── Dockerfile         
├── docker-compose.yml
├── operation.sh                    # 利用するコマンドをまとめた簡易スクリプト
```

### docker/containers
各コンテナに関するファイルを配置してある。

#### common.env
phpコンテナとmysqlコンテナで共通で使う設定を抜き出してある。
タイムゾーンがJSTになってるのはベースにしたアーキテクチャがJSTで決め打ってた為。

### mysql
MySQLを動作させる為の設定ファイルを配置。

#### init/1_init_ddl.sql
コンテナ作成時に実行されるSQLファイルを配置。
mysqlコンテナでは`docker-entrypoint-initdb.d`にマウントされる。
下記のSQLと、チュートリアルの[この箇所](https://book.cakephp.org/3/ja/quickstart.html#cms)のSQLを記述してある。

```
`GRANT ALL ON *.* TO 'cakephp'@'%';` # cakeからアクセスするユーザを作成
`CREATE DATABASE cake_cms;`          # DB作成
```

`docker-entrypoint-initdb.d`については、[Docker Hub](https://hub.docker.com/_/mysql)を参照。

### php-fpm
PHPを実行してcakeサーバーを実行するためのコンテナ。
特にwebサーバーと連携させてないので`php-fpm`タグである必要はないけど、
ベースにしたアーキテクチャが`php-fpm`、`nginx`連携のものだったため、そのまま流用。

#### Dockerfile
CakePHPを動作させるのに必要なライブラリをインストールしてある。
必要なライブラリは[インストール - 3.8](https://book.cakephp.org/3/ja/installation.html)を参照のこと。
コンテナ起動時に以下を実行して、ビルトインサーバーを起動させる。
`CMD ["bin/cake", "server", "-H", "0.0.0.0"]`

### docker-compose.yml
特別にテクニカルなことはしていない。（と思う）
ローカルにcomposerをインストールしないで、コンテナ上で実行したかったので
下記の部分でコンテナイメージの作成だけ行っている。

```
  composer:
    image: composer
    volumes:
      - ./:/app:cached
    working_dir: /app
```

### operation.sh
よく実行するDockerコマンドをスクリプトにした。
`composer`コマンドをcomposerコンテナ上で実行するために、以下のコマンドを利用する。

```
docker-compose run composer install --ignore-platform-reqs --no-interaction

[オプション説明]
--ignore-platform-req　PHPで依存関係の解消時にホスト側の設定をみてエラーになるのを防ぐ    
```

`composer`コマンドのオプションについては [Command-line interface / Commands - Composer](https://getcomposer.org/doc/03-cli.md#install-i) を参照のこと。


### config/app.php
- ほぼチュートリアル[「データベースの設定」](https://book.cakephp.org/3/ja/quickstart.html#id4)にある内容通りに設定してあるけど  
  `'host'`の設定値だけはコンテナで稼働している`mysqld`に接続するために、`mysql`に変更してある。（ドキュメントでは`localhost`）

```
     'Datasources' => [
         'default' => [
             'className' => 'Cake\Database\Connection',
             'driver' => 'Cake\Database\Driver\Mysql',
             'persistent' => false,
             'host' => 'mysql', # この値はphpfpmコンテナのdepends_onの値に対応させている
             'username' => 'cakephp',
             'password' => 'AngelF00dC4k3~',
             'database' => 'cake_cms',
             'encoding' => 'utf8mb4',
             'timezone' => 'UTC',
             'cacheMetadata' => true,
         ], 
```