Pada chapter version constraints
kita sudah melihat bagaimana satu kendala seperti ^3.0 dipetakan menjadi rentang versi. Proyek nyata jarang sesederhana itu: sebuah aplikasi bisa memuat puluhan paket, dan setiap paket membawa daftar require-nya sendiri. Dependency resolution adalah proses Composer memilih tepat satu versi untuk setiap paket sehingga semua kendala dari semua pihak terpenuhi sekaligus. Pada chapter ini kita membedah cara kerja proses tersebut, memicu konflik yang sesungguhnya di terminal, lalu belajar membaca pesan galat resolusi dan memperbaikinya.
Satu Versi untuk Semua Kendala #
Bayangkan setiap kendala sebagai himpunan versi yang diizinkan. Kendala ^3.0 pada psr/log mengizinkan 3.0.0 sampai sebelum 4.0.0, sedangkan kendala ~1.0 dari paket lain mengizinkan 1.0.0 sampai sebelum 2.0.0. Composer kemudian mencari satu titik potong yang memuaskan seluruh himpunan, dan bila beberapa versi lolos, versi tertinggi yang dipilih. Perhitungan ini bukan dilakukan berurutan per paket, melainkan dengan solver berbasis logika proposisional (SAT solver) yang menguji kombinasi kandidat sampai menemukan solusi yang konsisten — atau membuktikan tidak ada solusi.
Dua istilah penting di sini: monolog/monolog yang kita tulis di composer.json adalah dependensi langsung (direct dependency), sedangkan psr/log yang dibutuhkan oleh monolog adalah dependensi transitif (transitive dependency). Kendala kedua jenis itu diperlakukan sama kuat: satu saja yang dilanggar, resolusi gagal. Kita bisa memeriksa siapa-menybut-siapa dengan perintah composer why:
cd demo-konflik
composer why psr/logOutput yang Dihasilkan:
monolog/monolog 1.27.1 requires psr/log (~1.0)Baris tersebut memberi tahu bahwa satu-satunya alasan psr/log hadir di proyek adalah karena monolog/monolog versi 1.27.1 memintanya dengan kendala ~1.0. Informasi seperti ini adalah titik awal setiap kali kita menghadapi konflik.
Konflik Kendala di Praktik #
Konflik paling mudah dipahami lewat percobaan. Kita mulai dengan proyek kosong bernama demo-konflik, lalu memasang monolog/monolog dengan kendala versi 1.x:
composer require monolog/monolog:"^1.25"Output yang Dihasilkan:
./composer.json has been created
Running composer update monolog/monolog
Loading composer repositories with package information
Updating dependencies
Lock file operations: 2 installs, 0 updates, 0 removals
- Locking monolog/monolog (1.27.1)
- Locking psr/log (1.1.4)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 2 installs, 0 updates, 0 removals
- Installing psr/log (1.1.4): Extracting archive
- Installing monolog/monolog (1.27.1): Extracting archive
11 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files
1 package you are using is looking for funding.
Use the `composer fund` command to find out more!
No security vulnerability advisories found.Resolusi berhasil: monolog 1.27.1 dipilih, dan karena paket tersebut mensyaratkan psr/log ~1.0, versi 1.1.4 dipasang sebagai dependensi transitif. Sekarang kita tantang solver-nya — misalnya kita ingin memakai psr/log 3.x secara langsung:
composer require psr/log:"^3.0"Output yang Dihasilkan:
./composer.json has been updated
Running composer update psr/log
Loading composer repositories with package information
Updating dependencies
Your requirements could not be resolved to an installable set of packages.
Problem 1
- Root composer.json requires psr/log ^3.0, found psr/log[3.0.0, 3.0.1, 3.0.2] but these were not loaded, likely because it conflicts with another require.
Problem 2
- monolog/monolog is locked to version 1.27.1 and an update of this package was not requested.
- monolog/monolog 1.27.1 requires psr/log ~1.0 -> found psr/log[1.0.0, ..., 1.1.4] but it conflicts with your root composer.json require (^3.0).
Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.
Installation failed, reverting ./composer.json and ./composer.lock to their original content.Mari kita baca pesan galat itu bagian demi bagian:
Your requirements could not be resolved...— solver sudah mencoba semua kombinasi dan menyimpulkan tidak ada satu pun set versi yang memenuhi semua kendala.- Problem 1 — kendala baru kita (
psr/log ^3.0) sebenarnya punya kandidat (3.0.0, 3.0.1, 3.0.2), tetapi kandidat itu bentrok dengan kendala lain. - Problem 2 — sumber bentroknya diungkap terang-terangan: monolog 1.27.1 hanya menerima
psr/log ~1.0(rentang 1.0.0 sampai 1.1.4), yang tidak beririsan dengan^3.0. Installation failed, reverting...— Composer membatalkan seluruh perubahan;composer.jsondancomposer.lockdikembalikan ke isi semula, sehingga proyek tetap konsisten.
Perhatikan juga saran -W di akhir pesan. Perintah composer require secara bawaan hanya menyelesaikan ulang paket yang disebut; monolog dibiarkan terkunci di 1.27.1, sehingga solver tidak leluasa menaikkan psr/log.
Memperbaiki Konflik #
Solusi konflik selalu berupa penyelarasan kendala: longgarkan salah satu, atau naikkan paket yang menahan. Karena kita memang ingin psr/log 3.x, jalannya adalah menaikkan monolog ke versi 3.x yang mendukung psr/log ^2.0 || ^3.0. Kedua kendala kita tulis dalam satu perintah agar keduanya diselesaikan bersamaan:
composer require monolog/monolog:"^3.0" psr/log:"^3.0"Output yang Dihasilkan:
./composer.json has been updated
Running composer update monolog/monolog psr/log
Loading composer repositories with package information
Updating dependencies
Lock file operations: 0 installs, 2 updates, 0 removals
- Upgrading monolog/monolog (1.27.1 => 3.12.1)
- Upgrading psr/log (1.1.4 => 3.0.2)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 0 installs, 2 updates, 0 removals
- Upgrading psr/log (1.1.4 => 3.0.2): Extracting archive
- Upgrading monolog/monolog (1.27.1 => 3.12.1): Extracting archive
Generating autoload files
1 package you are using is looking for funding.
Use the `composer fund` command to find out more!
No security vulnerability advisories found.Kini composer why psr/log menampilkan dua baris — root project dan monolog sama-sama mensyaratkannya, dan keduanya sehat:
__root__ - requires psr/log (^3.0)
monolog/monolog 3.12.1 requires psr/log (^2.0 || ^3.0)Tidak semua konflik selesai dengan menaikkan versi. Kadang kendala kita sendiri yang terlalu ketat (misalnya ^3.0.2 yang menutup pintu bagi paket lain yang masih butuh 3.0.0), dan kadang dua paket memang belum punya versi yang cocok — pada kasus itu, salah satu paket harus ditunda atau diganti alternatifnya.
update Menyelesaikan Ulang, install Membekukan #
Hubungan composer.json, composer.lock, dan resolusi bisa diringkas begini: composer update menjalankan resolusi penuh lalu membekukan hasilnya ke lock file, sedangkan composer install memasang persis apa yang sudah ada di lock file tanpa berpikir ulang. Kita buktikan keduanya. Pada proyek demo-konflik sebelumnya, coba ubah kendala monolog di composer.json menjadi ^3.0 tanpa menjalankan update, lalu jalankan composer install:
composer installOutput yang Dihasilkan:
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Warning: The lock file is not up to date with the latest changes in composer.json. You may be getting outdated dependencies. It is recommended that you run `composer update` or `composer update <package name>`.
- Required package "monolog/monolog" is in the lock file as "1.27.1" but that does not satisfy your constraint "^3.0".
This usually happens when composer files are incorrectly merged or the composer.json file is manually edited.
Read more about correctly resolving merge conflicts https://getcomposer.org/doc/articles/resolving-merge-conflicts.md
and prefer using the "require" command over editing the composer.json file directly https://getcomposer.org/doc/03-cli.md#require-rcomposer install tetap memasang monolog 1.27.1 dari lock file dan hanya mencetak peringatan — inilah jaminan reproducibility: rekan tim dan server CI mendapat versi yang sama persis selama lock file yang dibagikan. Untuk menyelesaikan ulang, kita jalankan composer update monolog/monolog:
composer update monolog/monologOutput yang Dihasilkan:
Loading composer repositories with package information
Updating dependencies
Your requirements could not be resolved to an installable set of packages.
Problem 1
- Root composer.json requires monolog/monolog ^3.0 -> satisfiable by monolog/monolog[3.0.0, ..., 3.12.1].
- monolog/monolog[3.0.0, ..., 3.12.1] require psr/log ^2.0 || ^3.0 -> found psr/log[2.0.0, 3.0.0, 3.0.1, 3.0.2] but the package is fixed to 1.1.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.Gagal lagi — dan kali ini penyebabnya menarik: ini adalah partial update. Selama psr/log tidak kita sebut sebagai argumen, solver menganggap psr/log terkunci di 1.1.4, padahal monolog 3.x membutuhkan minimal 2.0.0. Pesan galat bahkan memberi dua jalan keluar: sebut psr/log sebagai argumen, atau gunakan -W agar dependensi transitif ikut diselesaikan ulang:
composer update monolog/monolog --with-all-dependenciesOutput yang Dihasilkan:
Loading composer repositories with package information
Updating dependencies
Lock file operations: 0 installs, 2 updates, 0 removals
- Upgrading monolog/monolog (1.27.1 => 3.12.1)
- Upgrading psr/log (1.1.4 => 3.0.2)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 0 installs, 2 updates, 0 removals
- Upgrading psr/log (1.1.4 => 3.0.2): Extracting archive
- Upgrading monolog/monolog (1.27.1 => 3.12.1): Extracting archive
Generating autoload files
1 package you are using is looking for funding.
Use the `composer fund` command to find out more!
No security vulnerability advisories found.Paket Platform Ikut Diresolusi #
Ada satu kelompok “paket” yang tidak diunduh dari Packagist: platform package. PHP itu sendiri (php), ekstensi (ext-json, ext-pdo), bahkan Composer sendiri (composer) dilacak sebagai paket dengan nomor versi, dan kendala terhadapnya ikut dihitung saat resolusi. Daftar lengkapnya bisa dilihat dengan composer show --platform — berikut beberapa baris pertamanya:
composer 2.10.3 Composer package
composer-plugin-api 2.9.0 The Composer Plugin API
composer-runtime-api 2.2.2 The Composer Runtime API
ext-bcmath 8.4.23 The bcmath PHP extension
ext-bz2 8.4.23 The bz2 PHP extension
ext-calendar 8.4.23 The calendar PHP extensionKita bisa mendaftarkan syarat platform seperti dependensi biasa, dan resolusinya pun sama — berhasil bila terpenuhi, gagal bila tidak:
composer require php:"^8.1" ext-json:"*"Output yang Dihasilkan:
./composer.json has been updated
Running composer update php ext-json
Loading composer repositories with package information
Pattern "php" listed for update matches platform packages, but these cannot be updated by Composer.
Pattern "ext-json" listed for update matches platform packages, but these cannot be updated by Composer.
Updating dependencies
Nothing to modify in lock file
Writing lock file
Installing dependencies from lock file (including require-dev)
Nothing to install, update or remove
Generating autoload files
1 package you are using is looking for funding.
Use the `composer fund` command to find out more!
No security vulnerability advisories found.PHP 8.4.23 memenuhi ^8.1 dan ekstensi json ada, jadi kendala lolos. Sebaliknya, meminta versi PHP yang lebih tua dari yang berjalan langsung ditolak — Composer memang tidak bisa “menurunkan” PHP kita:
composer require php:"^5.6"Output yang Dihasilkan:
./composer.json has been updated
Running composer update php
Loading composer repositories with package information
Pattern "php" listed for update matches platform packages, but these cannot be updated by Composer.
Updating dependencies
Your requirements could not be resolved to an installable set of packages.
Problem 1
- Root composer.json requires php ^5.6 but your php version (8.4.23) does not satisfy that requirement.
Installation failed, reverting ./composer.json and ./composer.lock to their original content.Perilaku platform package ini punya sisi manajerial yang penting: bagaimana menjamin paket yang kita pilih cocok dengan PHP di server produksi yang versinya mungkin lebih tua dari mesin pengembang. Topik pinning platform dengan config.platform dan perintah composer check-platform-reqs kita bahas tuntas pada chapter platform requirements
. Sebelum ke sana, kita pelajari dulu hasil samping terpenting dari resolusi: vendor/autoload.php, pintu masuk semua kelas dependensi ke kode PHP kita, pada chapter autoloading
.