PHPのComposerでコマンドを定義したら開発がすごく便利でした

# はじめに
チーム開発を行う際に、よく使うコマンドをComposerにまとめました。
こうすることでフレームワークで使う「あのコマンドってどうだっけ？」というのを共有しやすくなりました。

# 書き方
基本的な書き方としては、`scripts[command]`でアクセスできる箇所に配列で列挙していきます。
例えば`composer test`で`composer test-phpcs`というコマンドを発行したい場合には下記のように書きます。

```json:composer.json
{
  "scripts": {
    "test": [
      "composer test-phpcs",
    ]
  }
}
```

この配列には複数のコマンドを書くことが出来ます。

```json:composer.json
{
  "scripts": {
    "test": [
      "composer test-phpcs",
      "composer test-behat",
    ]
  }
}
```

またComposerから他のComposerのサブコマンドを呼び出す場合、コマンド名に`@`をつけることで省略可できます。
（@mosa7さん指摘ありがとうございます！）

```json:composer.json
{
  "scripts": {
    "test": [
      "@test-phpcs",
      "@test-behat",
    ]
  }
}
```

ちなみにこのケースではComposerでComposerのコマンドを呼んでいるので、無限ループにならないように気をつける必要があります。

# 予約キーワード
Composerでは特定のscriptsが定義されています。
これらのScriptsをcomposer.jsonで定義することで、特定のタイミングで呼ばれるコマンドになります。

| コマンド名 | 呼び出される条件 |
|---------------------------|----------------------------------------------------------|
| pre-install-cmd           | installの前。                                            |
| post-install-cmd          | installの後。                                            |
| pre-update-cmd            | updateの前。                                             |
| post-update-cmd           | updateの後。                                             |
| post-status-cmd           | statusの後。                                             |
| pre-archive-cmd           | archiveの前。                                            |
| post-archive-cmd          | archiveの後。                                            |
| pre-autoload-dump         | install / update中のdump-autoloadの前。                  |
| post-autoload-dump        | install / update中のdump-autoloadの後。                  |
| post-root-package-install | create-project中にあるルートパッケージのインストール後。 |
| post-create-project-cmd   | create-projectの後。                                     |
| pre-dependencies-solving  | 依存が解決される前。                                     |
| post-dependencies-solving | 依存が解決された後。                                     |
| pre-package-install       | パッケージのインストール前                               |
| post-package-install      | パッケージのインストール後                               |
| pre-package-update        | パッケージのアップデート前                               |
| post-package-update       | パッケージのアップデート後                               |
| pre-package-uninstall     | パッケージのアンインストール前                           |
| post-package-uninstall    | パッケージのアンインストール後                           |
| init                      | composerインスタンスが初期化された後                     |
| command                   | composerコマンドが実行される前。                         |
| pre-file-download         | ファイルダウンロードの前。                               |

正しいマニュアルについてはこちらを参考にしてください。

https://getcomposer.org/doc/articles/scripts.md#command-events


例えば`composer update`の後に独自で定義した初期化系のコマンドを実行したい場合いにはこのように書きます。

```json:composer.json
{
  "scripts": {
    "post-update-cmd": [
      "@set-wp-content",
      "@init-phpcs"
    ]
  }
}
```

https://getcomposer.org/doc/articles/scripts.md#command-events

# パスについて
Composerが実行される場合のパスは、vendors配下のバイナリが含まれるようになっています。
（ @mosa7さんご指摘ありがとうございます！）

```composer.json
{
  "scripts": {
    "env": "env"
  }
}
```

例えばこんな感じです。

```bash
$ composer env

PATH=/Users/yousan/repository/vendor/bin:/Users/yousan/.nvm/versions/node/v6.9.1/bin:/usr/local/opt/php70/bin:/Users/yousan/bin:/Users/yousan/sh:/usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/yousan/.composer/vendor/bin:/Users/yousan/.composer/vendor/bin
```

PHPUnitがBrewなどのローカルでインストールされていて、でもリポジトリにあるComposerでバージョン指定を行いたい場合があります。
その場合のcomposer.jsonでは、Composerでインストールされるパッケージの方が優先的に呼び出されるので、相対パスの前置詞（./vendor/phpunit/phpunitなど）は不要です。


# 実例

実際に案件で使ったcomposer.jsonのサブコマンド集です。


```json:composer.json
{
  "scripts": {
    "test": [
      "composer test-phpcs",
      "composer test-behat"
    ],
    "_test-behat": "behatへのパスは相対パスで書かなくても良い",
    "test-behat": [
      "./vendor/bin/behat --config ./tests/behat.yml"
    ],
    "test-phpcs": [
      "./vendor/bin/phpcs --standard=phpcs.ruleset.xml"
    ],
    "init-phpcs": [
      "rm -rf ./vendor/squizlabs/php_codesniffer/CodeSniffer/Standards/WordPress",
      "git clone git@github.com:WordPress-Coding-Standards/WordPress-Coding-Standards.git ./vendor/squizlabs/php_codesniffer/CodeSniffer/Standards/WordPress",
      "./vendor/bin/phpcs --config-set installed_paths `pwd -P`/vendor/squizlabs/php_codesniffer/CodeSniffer/Standards/WordPress"
    ],
    "set-wp-content": [
      "rm -rf public/wp/wp-content/themes",
      "ln -s ../../../themes public/wp/wp-content/",
      "rm -rf public/wp/wp-content/plugins",
      "ln -s ../../../plugins public/wp/wp-content/",
      "cp etc/wp-config.php public/wp/",
      "cp etc/wp.gitignore public/wp/.gitignore",
      "cp etc/wp.htaccess public/wp/.htaccess",
      "cp -R etc/languages public/wp/wp-content/"
    ],
    "db-export": [
      "wp db export - | gzip > etc/dump_`whoami`.sql.gz",
      "wp db export - | gzip > etc/dump.sql.gz"
    ],
    "db-import": [
      "wp db export - | gzip > etc/dump_`whoami`.sql.gz",
      "gunzip -c -f etc/dump.sql.gz > etc/dump.sql",
      "wp db import etc/dump.sql",
      "rm  etc/dump.sql"
    ],
    "db-staging": [
      "composer db-export",
      "wp search-replace --url=ex.dev/wp ex.dev/wp example.com",
      "wp db export - | sed -e 's/utf8mb4/utf8/g' | gzip - > etc/for_example.com.gz",
      "composer db-import"
    ],
    "post-install-cmd": [
      "composer set-wp-content",
      "composer init-phpcs"
    ],
    "post-update-cmd": [
      "composer set-wp-content",
      "composer init-phpcs"
    ]
  }
}
```

良いComposerライフをお送りください！