CakePHPの開発環境構築

本記事は[こちら](https://zenn.dev/isana/articles/cakephp-docker-enviroment)からの転載です。
当時、内定を頂いた転職先の業務のキャッチアップのために学習していた内容を書いたという背景があったのでした。

## モチベーション
CakePHPのキャッチアップの為に簡単に環境構築を行いましたのでその記録です。

## 環境
- ホストOS: ubuntu20.04(wsl)
- PHP: 7.3
- CakePHP: 4.*

アプリとDBだけの簡単な構成でdocker-compose.ymlを作成します。
ハマりポイントとしてはmysqlのバージョンです。
はじめは8.0で構築したのですが以下のエラーでmyappとdbの疎通が出来ませんでした。
> Error: [InvalidArgumentException] There was a problem connecting to the database: SQLSTATE[HY000] [2054] The server requested authentication method unknown to the client in /var/www/html/mycakeapp/vendor/robmorgan/phinx/src/Phinx/Db/Adapter/PdoAdapter.php

調べたところ[これ](https://dev.mysql.com/doc/refman/8.0/en/upgrading-from-previous-series.html#upgrade-caching-sha2-password-compatible-connectors)でした。今回の本題ではないのでmysqlを5.7に下げて回避しました。
`docker-compose.yml`

```yml
version: "3.7"
services:
  myapp:
    build:
      context: ./docker
      dockerfile: Dockerfile
    ports:
      - "8888:80"
      - "8765:8765"
    tty: true
    stdin_open: true
    volumes:
      - ./html:/var/www/html

  db:
    image: mysql:5.7
    volumes:
      - "./db:/docker-entrypoint-initdb.d"
    environment:
      MYSQL_DATABASE: sampledb
      MYSQL_USER: sample-user
      MYSQL_PASSWORD: 12345678
      MYSQL_ROOT_PASSWORD: 12345678
```

`Dockerfile`にはCakeが依存しているPHP拡張を入れます。

```Dockerfile
FROM php:7.3-apache

RUN apt-get update \
    && apt-get install -y unzip libicu-dev \
    && docker-php-ext-install intl \
    && docker-php-ext-install pdo_mysql \
    && a2enmod rewrite \
    && apt-get clean \
    && rm -fr /var/lib/apt/lists/*

```

mysqlの初期化クエリ`articles.sql`はcakeのチュートリアルから持ってきた物を置いておきます。

```sql
USE sampledb;

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    email VARCHAR(255) NOT NULL,
    password VARCHAR(255) NOT NULL,
    created DATETIME,
    modified DATETIME
);

CREATE TABLE articles (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    title VARCHAR(255) NOT NULL,
    slug VARCHAR(191) NOT NULL,
    body TEXT,
    published BOOLEAN DEFAULT FALSE,
    created DATETIME,
    modified DATETIME,
    UNIQUE KEY (slug),
    FOREIGN KEY user_key (user_id) REFERENCES users(id)
) CHARSET=utf8mb4;

CREATE TABLE tags (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(191),
    created DATETIME,
    modified DATETIME,
    UNIQUE KEY (title)
) CHARSET=utf8mb4;

CREATE TABLE articles_tags (
    article_id INT NOT NULL,
    tag_id INT NOT NULL,
    PRIMARY KEY (article_id, tag_id),
    FOREIGN KEY tag_key(tag_id) REFERENCES tags(id),
    FOREIGN KEY article_key(article_id) REFERENCES articles(id)
);

INSERT INTO users (email, password, created, modified)
VALUES
('cakephp@example.com', 'secret', NOW(), NOW());

INSERT INTO articles (user_id, title, slug, body, published, created, modified)
VALUES
(1, 'First Post', 'first-post', 'This is the first post.', 1, now(), now());
```

最終的な`フォルダ構成`は以下の通り

```bash
.
├── /docker
│   ├── Dockerfile
│   └── /initdb
│       └── articles.sql
├── /html // cakeのアプリケーションが入る
└── docker-compose.yml
```
`docker compose up -d`で起動します。

### projectを作成
起動中のコンテナにアタッチしてcakeのプロジェクトを作成していきます。

> $ docker compose exec myapp bash
> $ cd ..
> $ php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
>php -r "if (hash_file('sha384', 'composer-setup.php') === '756890a4488ce9024fc62c56153228907f1545c228516cbf63f885e036d37e9a59d27d63f46af1d4d07ee0f76181c7d3') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
>php composer-setup.php
>php -r "unlink('composer-setup.php');"
> $ php composer.phar create-project --prefer-dist cakephp/app:4.* html

普段はcomposer公式dockerイメージを使っているのですが、`create-project`で依存関係が無いと怒られ、上手く回避できなかったのでcomposer.pharを入れて使いました。

### 閑話休題
全然本題と関係ない話なのですが、composerの選択肢は以下3つだと思うんですがみなさんはどうしているのか気になります。

- composerをグローバルインストールして使う
- composer公式dockerイメージを使う
- composer.pharをプロジェクトローカルに入れる

### Permission denied
話を戻します。
`docker compose up -d`した状態でとりあえず`http://localhost:8888/`にアクセスすると以下のエラーが出ます。
> [**Warning** (512)](javascript:void(0);): SplFileInfo::openFile(/var/www/html/tmp/cache/models/myapp_cake_model_debug_kit_requests): failed to open stream: Permission denied [**CORE/src/Cache/Engine/FileEngine.php**, line **387**]

/tmpがroot権限になっているので権限を変更すれば解決します。

> sudo chown -R www-data:www-data tmp

### database接続設定
あとはDBに接続できるようにしてやります。余談ですが`config`配下の設定ファイルが多くてややこしいのでここで無駄にハマりました。
`config/app_local.php`

```php
'Datasources' => [
	'default' => [
		'className' => 'Cake\Database\Connection',
		'driver' => 'Cake\Database\Driver\Mysql',
		'persistent' => false,
		// 以下の設定項目をdocker-compose.ymlに合せる
		'host' => 'db', // servicesの名称
		'username' => 'sample-user', // MYSQL_USER
		'password' => '12345678', // MYSQL_PASSWORD
		'database' => 'sampledb', // MYSQL_DATABASE
		// ここまで
		'encoding' => 'utf8mb4',
		'timezone' => 'UTC',
		'cacheMetadata' => true,
	],

```
`CakePHP is able to connect to the database.`と表示されコック帽が緑色になったらDBとの導通OK
[![Image from Gyazo](https://i.gyazo.com/bf60690c199b72300ec4af44b0712e5b.png)](https://gyazo.com/bf60690c199b72300ec4af44b0712e5b)

ここからは[チュートリアル](https://book.cakephp.org/4/ja/tutorials-and-examples/cms/installation.html)をやったり、簡単なアプリを作ってみたりしながら勉強していきましょう。