既存のアプリケーションのバージョンアップを行うにあたって、composerの扱いにかなり悩んだ為記録しました。
状況
PHPやフレームワークのバージョンをかなり一気に上げなければならない
もし少しずつバージョンアップでも良いなら、下記で良いはずで、もしエラーが出たら個別に対処すれば良いのだが
composer require <パッケージ名>:<バージョン>
一気にバージョンを上げる場合、収集つかないくらいのエラーが表示される
依存関係や、パッケージがgitからダウンロードできないやら、色々、、個別に対処するのは不可能と判断。
解決策
####オプションをつける
下記のオプションをつけることにした
--update-with-dependencies
依存関係にあるパッケージをアップデートする
--prefer-dist
githubからではなくdistからダウンロードする
ただ、これでもまだ依存関係に関するエラーが表示される
(依存関係にあるものはオプションで解決できるはずなのではないの、、?)
####1つのコマンドに引数としてパッケージを渡す
だったら一度のrequireコマンドにエラーの元となる依存関係のあるパッケージを一気に渡せば依存パッケージの更新(追加)を解決しながらエラーなく進むかも、とやってみることにした。
composer require --update-with-dependencies --prefer-dist <パッケージ名>:<バージョン>
これを実行して
Problem 1
- <パッケージ名>:<バージョン>[3.0.0, ..., 3.x-dev] require <依存パッケージ名>:<バージョン> ^3.0.0 -> found <依存パッケージ名>:<バージョン>[dev-master, 3.0.0a1, ..., 3.x-dev (alias of dev-master)] but the package is fixed to 2.3.4 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.
Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.
こういうのが出たら、<依存パッケージ名>:<バージョン>を実行コマンドに追記していく。
composer require --update-with-dependencies --prefer-dist <パッケージ名>:<バージョン> <依存パッケージ名>:<バージョン>
これをひたすら繰り返す事で最終的にエラーなく処理が終了するところまで辿り着き、composer.jsonも.lockも想定のバージョンになり、アップデートしたものと依存関係にないパッケージについてはバージョン据え置きという、想定どおりの動作ができた。
####requireとrequire-devを分けたい時は
ひとつのコマンドでrequireとrequire-devのセクションを分けながらパッケージの追加はできない為、一気にパッケージ追加を行う中でどうしても開発用と分けてコマンド実行できない時は、一旦requireセクションにパッケージが追加された後に下記を実行すれば良い。
composer require --no-update --dev <パッケージ名>:<バージョン> <依存パッケージ名>:<バージョン>
一旦まとめ
という方法でできたけどcomposer歴が短すぎてこの方法がこういう場合の正攻法なのかわからない。
もっと良い方法がある、やこの方法に落とし穴がある等もしあれば、ご指摘頂けると助かります。
さらに気になったので
上記までで最低限の依存パッケージのバージョンアップデートはできたが、本当に最低限なのが気になった。
具体的には、新バージョンと諸々同じ環境で新規にフレームワークによるプロジェクトを作成した際のデフォルトのcomposer.jsonに記載されているパッケージのバージョンは、確かにフレームワーク自体のバージョンは上記までの作業で一致しているが、パッケージ名からは完全に関係しているとしか思えない(でもフレームワークをrequireした時には依存関係には出てこなかった)パッケージのバージョンが一致していない。
(PHP自体のバージョンとか、フレームワークのマイグレーションやデバッグ用のパッケージのバージョンはかなり古いまま、フレームワークのバージョンだけ新しくなっている状態)
依存関係にないのが不思議なくらいだが、そうなってないなら仕方ないので自分でなんとかすることにした。
####具体的には
①同じバージョンの新規プロジェクトを作成
②できあがったcomposer.jsonに記載のバージョンを元にrequireコマンドを作成
③コマンドを実行してエラーになったら上記「オプションをつける」「1つのコマンドに引数としてパッケージを渡す」を参考に対応(まぁこちらもエラー出ますよね)
これやるのとやらないのとでは、やった方が良さそうだけど、これも掘り下げれば良い解決方法があるのかもしれない。
おまけ1
最初はrequireコマンドじゃなくてremoveコマンドでやろうと思っていました。依存関係とバージョンアップが多すぎて収集つかない為。
バージョンアップするものと関係ありそうなパッケージをremoveでjsonから削除し、その後update --dry-runでlockファイルから削除されるパッケージ名を確認、パッケージ名指定で
updateを行う事で関係ないパッケージのアップデートは行われずにremoveで削除したパッケージ関連のものがlockファイルから消える為、一度古いバージョン関連のものを全部消して、改めて新しいバージョンのものを追加する、的な。
composer remove --no-update <パッケージ名> <パッケージ名> <パッケージ名>
####下記のような問題点がありこの方法はやめました
・removeするパッケージを自分で決めるしかない、名前を元にしてだいたいでやるか、packagist等で依存関係を調べるか、、後者は終わりが見えない
・--no-updateオプションを付ける事でremove時にupdateは走らない(はず)と思って実行したけど走った(これはmacOSの自動変換が走った事でオプションが有効にならなかった疑惑あり)
・updateコマンドの引数(パッケージ数)が大変なことになった
採用した方の方法でrequireに付けた引数もかなり多かったけど、updateの引数よりはマシ、、
おまけ2
悩み始めた初期の頃、そもそもcomposerのバージョンが開発時と違うという点も気になりcomposerも開発時のバージョン(1.)に戻して色々試してみたけど、処理がすごく遅いですね!
ただ古いバージョンのパッケージのインストールが途中でエラーにならなかったり(gitからではなくdistが優先だったりするのかな?オプションつけなくても)等のメリットもありましたが、最新バージョン(2.)と互換性もありdistからダウンロードするようオプションつけさえすれば良いので、管理するパッケージがかなり古いバージョンの環境だとしても、composer(1.*)を使う必要は全くありませんでしたが、一応コマンドを。
composer self-update --1 //1つ古いバージョンへ
composer self-update --2 //新しいバージョンへ