ローカル開発でSymfony CLIがすごい

[Symfony Advent Calendar 2020](https://qiita.com/advent-calendar/2020/symfony) 12日目の記事です。

[Symfony CLI](https://symfony.com/download)はSymfonyローカルマシンでの開発を支援するコマンドラインツールです。[Laravel Installer](https://laravel.com/docs/8.x/installation)（laravelコマンド）のようにSymfonyプロジェクトの作成にもできますが、それ以外にも優れた機能を備えています。その機能のうち、ぼくがよく使っている便利な機能をいくつかご紹介します。

## Symfonyプロジェクトの作成
Symfonyのプロジェクトを作成するにはlavael Installerと同じ感じです。

```
symfony new [プロジェクト名]
cd [プロジェクト名]
```

プロジェクト名でディレクトリを作成し、ディレクトリ内にSymfonyをインストールします。以降のコマンドはプロジェクトのディレクトリに移動して、実行します。
余談ですが、Symfony CLIはコマンド実行時に、必ずアップデートを確認・ダウンロードし、常に最新のものが利用できるようになっています。

## PHPやSymfony ConsoleなどPHPコマンドを実行する
Symfony CLI経由でPHPなどのコマンドを実行します。これは、後述するバージョン指定、DockerCompose連携で大化けします。

```
# PHP実行
symfony php -v

PHP 7.4.11 (cli) (built: Oct  1 2020 23:30:54) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Xdebug v2.9.6, Copyright (c) 2002-2020, by Derick Rethans
    with Zend OPcache v7.4.11, Copyright (c), by Zend Technologies

# Symfony Console実行（symfony bin/consoleではないので注意）
symfony console -V
Symfony 5.2.0 (env: dev, debug: true)

# composer実行
symfony composer require twig
```

その他、pecl, pear, php-fpm, php-cgi, php-config, phpdbg, phpizeが実行できます。

## ローカルWebサーバ起動
今まではSymfony Console `bin/console` でWebサーバを起動していましたが、それに代わってSymfony CLIで起動するようになりました。

```
# Webサーバ起動
symfony server:start

# バックグラウンドで実行する場合
symfony server:start -d

# Webサーバ終了（バックグラウンド実行時）
symfony server:stop

# ドキュメントルートを変える場合
symfony server:start --document-root=webroot

# ブラウザを開く
symfony open:local

# ログを確認する
symfony server:log
```

ここでポイントはドキュメントルートを指定できる点。当然ながら、LaravelやCakePHPのプロジェクトでも実行できます。
また、PHP-FPMが有効な場合は、自動でPHP-FPMを利用します。


## ローカルをHTTPSにする
`php -S`でビルトインサーバを起動した場合、HTTPでの通信になります。上記のSymfony CLIでのローカルWebサーバ起動も同じくHTTPですが、HTTPSに変えることができます。

```
symfony server:ca:install
```

このコマンドで、ローカルに証明書をインストールします。以降、サーバを起動するとこのローカル証明書を利用したHTTPS通信になります。インストール後にHTTP通信したい場合は、ローカルWebサーバ起動時に、`--allow-http`オプションを指定すると、HTTPとなります。

## PHPのバージョンを指定する
プロジェクトによってPHPのバージョンが異なる場合、[phpenv](https://github.com/phpenv/phpenv)でバージョンを切り替えたりしていましたが、プロジェクトディレクトリのルートに、`.php-version`という名前のファイルを作成しファイル内にPHPのバージョンを記載すると、Homebrewなどでインストールしたローカルの該当バージョンPHPを、切り替えなしで利用できます。
※該当のバージョンのPHPがインストールされている必要があります

```text:.php-version
8.0
```

このファイルがある状態でSymfony CLIを実行すると、指定されたバージョンで実行されます。

```console
# ローカルのデフォルトPHPを実行
php -v

PHP 7.4.11 (cli) (built: Oct  1 2020 23:30:54) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Xdebug v2.9.6, Copyright (c) 2002-2020, by Derick Rethans
    with Zend OPcache v7.4.11, Copyright (c), by Zend Technologies

# Symfony CLI経由で、.php-versionに8.0を指定して実行
symfony php -v

PHP 8.0.0-dev (cli) (built: Oct  5 2020 01:14:40) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.0-dev, Copyright (c) Zend Technologies
    with Zend OPcache v8.0.0-dev, Copyright (c), by Zend Technologies
```

また、composerも指定したPHPのバージョンで実行することができます。

```
# Symfony CLI経由で、バージョンを指定してcomposer実行
symfony composer require twig
```

ローカルWebサーバも、もちろん変わります。ただし、ローカルWebサーバ起動中にバージョンを変えても反映されないので、サーバの再起動が必要です。

```
symfony server:start -d
echo 8.0 > .php-version
symfony server:stop
symfony server:start -d
```

![Screen Shot 2020-12-11 at 11.45.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9882/f96d3a7f-ec6a-f2e4-e186-56e367519306.png)

↓

![Screen Shot 2020-12-11 at 11.42.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9882/f311b546-1728-c20e-af4e-fc7ded0ae029.png)



### インストールされているPHPのバージョンを確認する
ローカルにどのPHPのバージョンがインストールされているか`symfony local:php:list`で確認することができます。

```
symfony local:php:list

┌─────────┬──────────────────────────────────┬─────────┬────────────────────────────────┬───────────────────────────────┬─────────┬─────────┐
│ Version │            Directory             │ PHP CLI │            PHP FPM             │            PHP CGI            │ Server  │ System? │
├─────────┼──────────────────────────────────┼─────────┼────────────────────────────────┼───────────────────────────────┼─────────┼─────────┤
│ 7.2.33  │ /usr/local/Cellar/php@7.2/7.2.33 │ bin/php │ sbin/php-fpm                   │ bin/php-cgi                   │ PHP FPM │         │
│ 7.3.11  │ /usr                             │ bin/php │ sbin/php-fpm                   │                               │ PHP FPM │         │
│ 7.4.11  │ /usr/local                       │ bin/php │ Cellar/php/7.4.11/sbin/php-fpm │ Cellar/php/7.4.11/bin/php-cgi │ PHP FPM │ *       │
│ 8.0.0   │ /usr/local/Cellar/php@8.0/8.0.0  │ bin/php │ sbin/php-fpm                   │ bin/php-cgi                   │ PHP FPM │         │
└─────────┴──────────────────────────────────┴─────────┴────────────────────────────────┴───────────────────────────────┴─────────┴─────────┘

The current PHP version is selected from default version in $PATH

```

## Docker Composeと連携する
プロジェクトルートに`docker-compose.yml`があり、コンテナを起動している場合は、Docker Composeと連携します。前述の状態でSymfony CLIを実行すると、利用しているイメージに合わせて自動的に環境変数が設定されます。
例えば、以下のようなdocker-compose.ymlがある場合、

```yaml:docker-compose.yml
version: '3'
services:
  database:
    image: mariadb
    ports: [3306]
    environment:
      - MYSQL_ROOT_PASSWORD=root
      - MYSQL_DATABASE=database
      - MYSQL_USER=user
      - MYSQL_PASSWORD=password
  mailer:
    image: mailhog/mailhog
    ports: [8025, 1025]

```

Dockerを起動して、Symfony CLIでコマンド実行を行うと、`docker-compose.yml`内の設定（サービス名、イメージ、ポート）を利用して、自動で環境変数を生成します。

```
docker-compose up -d
symfony server:start -d
symfony var:export --multiline

export DATABASE_DATABASE=database
export DATABASE_DRIVER=mysql
export DATABASE_HOST=127.0.0.1
export DATABASE_NAME=database
export DATABASE_PASSWORD=password
export DATABASE_PORT=49195
export DATABASE_SERVER=mysql://127.0.0.1:49195
export DATABASE_URL=mysql://user:password@127.0.0.1:49195/database?sslmode=disable&charset=utf8mb4
export DATABASE_USER=user
export DATABASE_USERNAME=user
export MAILER_AUTH_MODE=
export MAILER_CATCHER=1
export MAILER_DRIVER=smtp
export MAILER_DSN=smtp://127.0.0.1:49197
export MAILER_HOST=127.0.0.1
export MAILER_PASSWORD=
export MAILER_PORT=49197
export MAILER_URL=smtp://127.0.0.1:49197
export MAILER_USERNAME=
export MAILER_WEB_HOST=127.0.0.1
export MAILER_WEB_IP=127.0.0.1
export MAILER_WEB_PORT=49196
export MAILER_WEB_SCHEME=http
export MAILER_WEB_SERVER=http://127.0.0.1:49196
export MAILER_WEB_URL=http://127.0.0.1:49196
[以下省略]
```

イメージにあったポートを指定していれば、上記が自動で生成され、`.env`に記述がなくても上記の環境変数で動作します。また、`.env`に該当の変数が定義されていても、こちらが優先されます。

`docker-compose.yml`のサービス名は、環境変数のプレフィクスになります。サービス名が`database`であれば、`DATABASE_`に、`db`であれば`DB_`となります。現在サポートされているサービスは以下の通りです。

| サービス | ポート | Symfonyで使う場合のデフォルトのプレフィクス |
|----|----|----|
| MySQL |	3306 |	DATABASE_ |
| PostgreSQL |	5432 |	DATABASE_ |
| Redis |	6379 |	REDIS_ |
| Memcached |	11211 |	MEMCACHED_ |
| RabbitMQ |	5672 |	RABBITMQ_ |
| Elasticsearch |	9200 |	ELASTICSEARCH_ |
| MongoDB |	27017 |	MONGODB_  |
| Kafka |	9092 |	KAFKA_ |
| MailCatcher |	1025/1080 or 25/80 |	MAILER_ |
| MailHog |	1025/1080 or 25/80 |	MAILER_ |
| Blackfire |	8707 |	BLACKFIRE_ |

※公式にMailHogは記載されてないけど、動く。

Docker Composeと連携している場合は、追加コマンドが利用できるようになります。

```
# MailHog, MailCatcherを設定している場合は、メールボックスをブラウザで開く
symfony open:local:webmail

# RabbitMQを設定している場合は、マネージャーをブラウザで開く
symfony open:local:rabbitmq

```

1点注意が必要ですが、Docker ComposeでWebサーバやPHPを定義している場合に、Symfony CLIコマンドをローカルで使ってもコンテナ上のWebサーバやPHPは利用しません。 **Symfony CLIは、あくまでローカルでPHPを実行するすることを想定していて、コンテナ上で実行することを想定していません。**


> "Why would you want to use the web server in a Docker container?"
> by Fabien Potencier

※ファビアンも、なんでコンテナなん？って言ってる。

## まとめ
他にも機能はありますが、利用する機会が多いのは上記に挙げたものかなと思います。前述の通り、Symfonyだけではなく、LaravelやCakePHP、頑張ればWordPressなどのCMSも動くので、ぜひ一度試してもらえたらと思います。公式ドキュメントは[こちら](https://symfony.com/doc/current/setup/symfony_server.html)