WSL上にPHP7.3＋CakePHP2の開発環境を作成する(Ubuntu20.04)

## はじめに

WSLで環境を作成すると便利な点が多い(大分よくなりましたが、ハマることも多いです)ため、手順をまとめました。
諸々の都合により、最新環境ではありません。

* 起動が早い、バックアップ、復元が簡単にできる
* Windows側とUbuntu側でファイルを共有できる
* UbuntuのGUIアプリをWindows側で表示できる
* sysmtedが使えない点も、[genie](https://github.com/arkane-systems/genie)や、[Distrod](https://github.com/nullpo-head/wsl-distrod)を利用することで回避できるようになった
* VSCodeの拡張機能`Remote Development`を利用するとデバッグの設定が容易になる(Linux側に導入した拡張機能でデバッグを行うため、パスのマッピングが不要)

### インストール概要
* WSL上にUbuntu20.4＋PHP7.3＋CakePHP2の環境を作成する
* Xdebugを追加してVSCodeからデバッグできるようにする
* WSL上のLinuxはSYSVinitで起動するためsystemctlが利用できない。諸々不便なため[Distrod](https://github.com/nullpo-head/wsl-distrod)を導入する。
* [genie](https://github.com/arkane-systems/genie)を導入してもsystemctlを利用できるようにはなるが下記の欠点がある

  * Windows相互運用(LinuxのコンソールからWindows側のexeを起動する)が正しく動かないようです(VSCodeが起動しない)
  * そのため、を利用(+PHP7.3環境を作成する)


## 前提
* Windows11Pro
* Windows Termialインストール済み(Ubuntuインストール後、Ubuntuが選択できるようになる)
* VSCodeインストール済み、拡張機能`Remote Development`インストール済み

## Ubuntuのインストールとsystemdの有効化(Distrod)

1. wlsのインストール(Windows側コンソール)
```bash
> wsl --install -d Ubuntu
```
2. wsl更新(Windows側コンソール,要管理者権限)
```bash
> wsl --update
```

3. Ubuntuのターミナルを起動して、パッケージの最新版を取得、更新
``` bash
$ sudo apt update;
$ sudo apt upgrade;
```

4. VSCodeのRemote-WSLから接続して動作確認

- 画面左端の「リモートエクスプローラー」アイコン⇒ターゲットを「WSLターゲット」にして、Ubuntuに接続する
![image](https://user-images.githubusercontent.com/42880820/184065402-d9fe722b-1dbc-4492-bf57-58500d1113cd.png)

- ホームディレクトリが開けることを確認する

- VSCodeのターミナル(Ctrl＋@)から下記コマンドを実行して、(VSCodeで)ファイルが開くことを確認する

```bash
$ code .bashrc
```


5. Distrodをインストール
```bash
$ curl -L -O "https://raw.githubusercontent.com/nullpo-head/wsl-distrod/main/install.sh"
$ chmod +x install.sh
$ sudo ./install.sh install

# enable distrod
$ sudo /opt/distrod/bin/distrod enable
```

6. WSLを再起動(Windowsホスト側コンソール)
```
wsl --shutdown
```


7. 再起動後、systemdが起動していることを確認するため`systemctl status`を実行する
```bash
$ systemctl status
● DESKTOP-0IMGJGP
    State: degraded
     Jobs: 0 queued
   Failed: 1 units
    Since: Thu 2022-08-11 17:57:38 JST; 6min ago
   CGroup: /
           ├─init.scope
           │ └─1 /sbin/init systemd.setenv=WSL_INTEROP=/run/WSL/8_interop systemd.setenv=WSL_DISTRO_NAME=Ubuntu systemd>
           └─system.slice
             ├─apache2.service
             │ ├─615 /usr/sbin/apache2 -k start
             │ ├─652 /usr/sbin/apache2 -k start
             │ ├─653 /usr/sbin/apache2 -k start
             │ ├─654 /usr/sbin/apache2 -k start
             │ ├─655 /usr/sbin/apache2 -k start
             │ ├─656 /usr/sbin/apache2 -k start
             │ └─880 /usr/sbin/apache2 -k start
             ├─systemd-udevd.service
             │ └─225 /lib/systemd/systemd-udevd
```

## PHP環境のインストール

apacheをインストールする

```bash
$ sudo apt install apache2
$ apache2 -v
Server version: Apache/2.4.41 (Ubuntu)
```

インストール後、サービスの状態を確認。'active'になっていれば起動している

```bash
$ systemctl status apache2.service
● apache2.service - The Apache HTTP Server
     Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
     Active: active (running) since Thu 2022-08-11 18:27:26 JST; 5min ago
       Docs: https://httpd.apache.org/docs/2.4/
   Main PID: 2833 (apache2)
      Tasks: 55 (limit: 9155)
     Memory: 21.2M
     CGroup: /system.slice/apache2.service
             ├─2833 /usr/sbin/apache2 -k start
             ├─2834 /usr/sbin/apache2 -k start
             └─2835 /usr/sbin/apache2 -k start
```

* Windows側から'localhost'でアクセスすると、トップページが見える
(localhostでUbuntu側へつないでくれる)
  * IISが動いていると80番ポートがバッティングしてエラーとなるため、先に止めておくこと)
![image](https://user-images.githubusercontent.com/42880820/184104527-ab0c49c0-52c3-4810-b8a5-18854e13bf6b.png)



* PHP7.3をインストール

`ppa:ondrej/php`リポジトリの追加はタイムアウトが発生し失敗する場合、時間をおいて繰り返す。
```
$ sudo add-apt-repository ppa:ondrej/php

$ sudo apt update

$ install php7.3 php7.3-common php7.3-cli php7.3-fpm php7.3-mysql php7.3-dev php7.3-mbstring php7.3-zip php7.3-curl php7.3-gd php7.3-xml
```

インストール後、バージョンを確認する
```bash
$ php -v
PHP 7.3.33-5+ubuntu20.04.1+deb.sury.org+1 (cli) (built: Aug  1 2022 08:06:52) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.33, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.3.33-5+ubuntu20.04.1+deb.sury.org+1, Copyright (c) 1999-2018, by Zend Technologies
```

ブラウザからPHPが動作しているか確認する。`localhost/phpinfo.php`で表示することができる。

```bash
$ echo '<?php echo phpinfo();' > /var/www/html/phpinfo.php
```

![image](https://user-images.githubusercontent.com/42880820/184111015-7ac8c337-604f-477a-af17-2bb4d2cfae8b.png)


## CakePHP2.10のインストール

* composerのインストール
```bash
$ curl https://getcomposer.org/installer > composer-setup.php
$ php composer-setup.php
$ sudo mv -i composer.phar /usr/local/bin/composer
$ composer --version
Composer version 2.3.10 2022-07-13 15:48:23
```

* cakephp2, phpunit3.7のインストール

  * /var/www/html/に`cake2`ディレクトリ(プロジェクトルート)を作成ししてそこにCakePHP2.10をインストールする
  * phpunitは3.7以降もサポートしているようですが、長らく3.7までのサポートだったので3.7にしています

```bash
$ sudo mkdir /var/www/html/cake2
$ cd /var/www/html/cake2
$ sudo vi composer.json
```


composer.json に下記を記載
```json
{
    "name": "cake2/hello-cake",
    "require": {
       "cakephp/cakephp": "2.10.*"
    },
    "require-dev": {
        "phpunit/phpunit": "3.7.*",
        "cakephp/debug_kit": ">=2.2.4,<3.0.0"
    },
    "config": {
        "vendor-dir": "vendors/",
        "allow-plugins": {
            "composer/installers": true
        }
    },
    "extra": {
        "installer-paths": {
            "./plugins/{$name}/": [
                "cakephp/debug_kit"
            ]
        }
    }
}
```

* インストール
⇒エラーになる場合は、ディレクトリの権限を確認
```bash
$ composer install
```

* ディレクトリ構造
```
$ tree -L 1 -a
.
├── composer.json
├── composer.lock
├── plugins
└── vendors
```
* bake でappを展開する
```bash
$ ./vendors/bin/cake bake project app

$ tree -L 1 -a
.
├── app
├── composer.json
├── composer.lock
├── plugins
└── vendors
```

* index.php ファイルを作成する(プロジェクトルート)

```php
<?php
define('APP_DIR', 'app');
define('DS', DIRECTORY_SEPARATOR);
define('ROOT', dirname(__FILE__));
define('WEBROOT_DIR', 'webroot');
define('WWW_ROOT', ROOT . DS . APP_DIR . DS . WEBROOT_DIR . DS);

/**
 * This only needs to be changed if the "cake" directory is located
 * outside of the distributed structure.
 * Full path to the directory containing "cake". Do not add trailing directory separator
 */

require APP_DIR . DS . WEBROOT_DIR . DS . 'index.php';
```

これで一応トップページ(index.php)は表示される(警告はこのすぐあとで対応)。
![image](https://user-images.githubusercontent.com/42880820/184264490-f96091ae-d013-4efc-9e21-202ca675891f.png)

* apacheのmod rewwriteを有効にする

  * `rewrite_module`の読み込みを有効化するため、シンボリックリンクを作成
```bash
cd /etc/apache2/mods-enabled
sudo ln -s ../mods-available/rewrite.load rewrite.load
```
  
  
* `/var/www/`配下で`.htaccess`を使った設定の書き換えを有効化するため`apache2.conf`を書き換え

/var/www ディレクトリの`AllowOverride`を`None`⇒`All`に変更

`/etc/apache2/apache2.conf`
```conf
<Directory /var/www/>
        Options Indexes FollowSymLinks
#       AllowOverride None
        AllowOverride All
        Require all granted
</Directory>
```

* プロジェクトルートに'.htaccess'ファイルを作成。mod rewriteを有効にする
```
<IfModule mod_rewrite.c>
  RewriteEngine on
  RewriteRule ^$ app/webroot/ [L]
  RewriteRule (.*) app/webroot/$1 [L]
</IfModule>
```


![image](https://user-images.githubusercontent.com/42880820/184264407-e50f5272-4469-474c-ab4d-6c3187213682.png)


### MySQLのインストール
* MySQLをインストールする

```bash
$ sudo apt install -y mysql-server 
$ mysql -V
mysql  Ver 8.0.30-0ubuntu0.20.04.2 for Linux on x86_64 ((Ubuntu))
```

* ユーザを作成＋認証用プラグインを変更

適当なユーザを作成(パスワードは適宜書き換え)
```sql
mysql> create user 'username'@'%' identified by 'password'
mysql> grant all on *.* to username;
 ```

cakephp2の場合、MySQL8のパスワード暗号化形式を変更する必要がある	
MySQL8デフォルトの認証方式`caching_sha2_password`は利用できない(PDOの制限)ため、`mysql_native_password`へ変更する

```sql
mysql> select user, host, plugin from mysql.user;
+------------------+-----------+-----------------------+
| user             | host      | plugin                |
+------------------+-----------+-----------------------+
| username         | %         | caching_sha2_password |
| debian-sys-maint | localhost | caching_sha2_password |
| mysql.infoschema | localhost | caching_sha2_password |
| mysql.session    | localhost | caching_sha2_password |
| mysql.sys        | localhost | caching_sha2_password |
| root             | localhost | auth_socket           |
+------------------+-----------+-----------------------+

mysql> ALTER USER 'username' IDENTIFIED WITH mysql_native_password BY 'password';
flush privileges;
```


変更結果

```sql
mysql> select user, host, plugin from mysql.user;
+------------------+-----------+-----------------------+
| user             | host      | plugin                |
+------------------+-----------+-----------------------+
| tkykn            | %         | mysql_native_password |
+------------------+-----------+-----------------------+
```

* 接続用に空のデータベースを作成しておく
```sql
mysql> create database cake2;
```

* CakePHPのデータベース接続設定を修正する

DB接続テンプレートファイルをコピーして編集
```bash
$ cd /var/www/html/cake2/app/Config
$ cp database.php.default database.php
```

* login、password, databaseを適宜修正する
```php
	public $default = array(
		'datasource' => 'Database/Mysql',
		'persistent' => false,
		'host' => 'localhost',
		'login' => 'user',
		'password' => 'password',
		'database' => 'database_name',
		'prefix' => '',
		//'encoding' => 'utf8',
	);
 ```
データベースに接続できたためエラーが解消

![image](https://user-images.githubusercontent.com/42880820/184277160-572f9893-2e78-475b-958e-f960a3783390.png)

### DebugKitのインストール

app/Config/bootstrap.php に、プラグインのロードの記述を追加

```php
CakePlugin::load('DebugKit');
```

全てのエラーが解消しました

![image](https://user-images.githubusercontent.com/42880820/184277749-f6c34087-c7a6-417f-92d5-974060461b0c.png)


### XDebugのインストール

PHP7.3用のxdebugをインストール

```bash
$ sudo apt install php7.3-xdebug
```

php.ini の最後にデバッグ用の設定を追記

```ini
[xdebug]
xdebug.mode=debug,coverage
xdebug.start_with_request=yes
```
apache再起動
```bash
$ sudo systemctl restart apache2
```

* `Step Debugger`と`Coverage`が有効になっていることを確認
  * `Coverage`はユニットテストでソースカバレッジを表示するために必要なため有効にする
![image](https://user-images.githubusercontent.com/42880820/184542672-3b283e4b-a514-4a80-b7b5-3474aecf8f55.png)


### その他必要な設定

#### 絶対パスを相対パスに変更

Composerでインストールすると、絶対パスが埋め込まれていしまう
フォルダを移動したりコピーした場合に動かなくなるため修正する


* `app/webroot/index.php`の`CAKE_CORE_INCLUDE_PATH`
* `app/webroot/test.php`の`CAKE_CORE_INCLUDE_PATH`

```php
// define('CAKE_CORE_INCLUDE_PATH',  DS . 'var' . DS . 'www' . DS . 'html' . DS . 'cake2' . DS . 'vendors' . DS . 'cakephp' . DS . 'cakephp' . DS . 'lib');
define('CAKE_CORE_INCLUDE_PATH',  ROOT . DS . 'vendors' . DS . 'cakephp' . DS . 'cakephp' . DS . 'lib');
```

* `app/Console/cake.php`

```php
// $install = $root . PATH_SEPARATOR .  DS . 'var' . DS . 'www' . DS . 'html' . DS . 'cake2' . DS . 'vendors' . DS . 'cakephp' . DS . 'cakephp' . DS . 'lib'; 
$install = $root . DS . 'vendors' . DS . 'cakephp' . DS . 'cakephp' . DS . 'lib';
```

#### PHPUnitのエラー対応

* ①CakePHP2のユニットテスト(`http://localhost/cake2/test.php`)で下記のようなエラーが発生する(PHPUnitのバグっぽい)
![image](https://user-images.githubusercontent.com/42880820/184478539-65936a54-d6a4-4ec9-a8d5-b5dce1ef502f.png)

そのため`PHPUnit_Framework_Comparator_DOMDocument::assertEquals()`の引数定義を書き換える（オーバーライドしたメソッドの引数の数が異なるため、親に合わせる)

/approot/vendors/phpunit/phpunit/PHPUnit/Framework/Comparator/DOMDocument.php
```php
    // public function assertEquals($expected, $actual, $delta = 0, $canonicalize = FALSE, $ignoreCase = FALSE)  // 修正前
    public function assertEquals($expected, $actual, $delta = 0, $canonicalize = FALSE, $ignoreCase = FALSE, array &$processed = array())  // 修正後
```

* ②`PHP.ini`のxdebugの設定に`coverage`を追加する

CakePHP2のテストをブラウザから実行後、カバレッジを`Analyze Code Coverage`から見ることができる。その際下記のようなエラーが出た場合、カバレッジを有効にする必要がある。

![image](https://user-images.githubusercontent.com/42880820/184478707-8080ef59-cea8-421f-a5df-c9ff7fee853b.png)

php.ini に`coverage`が入っていることを確認

```ini
[xdebug]
xdebug.mode=debug,coverage
xdebug.start_with_request=yes
```