composer: [with patch] requiring a platform package that is provided by another required package fails
First, this issue is not entirely trivial to reproduce, because everyone has different PHP versions and extensions installed. To reproduce the steps and behaviors below, please ensure that you run php -n $(which composer)
instead of plainly composer
, or that with composer show --platform | grep mongo
, nothing shows up š
If youāre on Ubuntu or something, php -n
will also prevent loading ext-phar
, so nothing will work. In that case, just make sure you have no ext-mongo
, and run composer
directly instead of php -n $(which composer)
.
Letās say your code needs ext-mongo
(via Doctrine ODM, for instance), but thatās not available on PHP 7, so you want to use https://github.com/alcaeus/mongo-php-adapter, which in its composer.json
says "provide": { "ext-mongo": "1.6.12" }
, and which is a wrapper around ext-mongodb
to provide an interface thatās compatible with the old ext-mongo
.
Start with a basic composer.json
, to mock the existence of ext-mongodb
(again, you do not want ext-mongo
installed when following along, so always run with php -n
later):
$ composer init -n
$ composer config platform.php "7.0.4"
$ composer config platform.ext-mhash "7.0.4"
$ composer config platform.ext-mongodb "1.1.3"
I will use the composer-provide
branch of https://github.com/alcaeus/mongo-php-adapter explicitly because the master branch has changed between using provide
and replace
a few times recently. There is also a composer-replace
branch that uses replace
instead of provide
for ext-mongo
.
Remember, php -n
will prevent ini loads, so if you have ext-mongo locally, it should not get loaded:
$ php -n $(which composer) require alcaeus/mongo-php-adapter:dev-composer-provide
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
- Installing mongodb/mongodb (1.0.1)
Loading from cache
- Installing alcaeus/mongo-php-adapter (dev-composer-provide 698d301)
Cloning 698d3012c306af299491aa166dc9aa29a4bce5b8
Writing lock file
Generating autoload files
Now there is a package that provides āext-mongoā installed, and that info is in the lock file. Which works as expected if you now require that extension:
$ php -n $(which composer) require ext-mongo:*
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Nothing to install or update
Writing lock file
Generating autoload files
A subsequent composer update
also works. Great, so letās try a case that fails - having the requirements already in place, but no lock file:
$ rm -rf composer.lock vendor
$ php -n $(which composer) update
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.
Problem 1
- The requested PHP extension ext-mongo * is missing from your system. Install or enable PHP's mongo extension.
Weird, right? The same happens if you require both in one go obviously:
$ php -n $(which composer) remove ext-mongo
$ php -n $(which composer) remove alcaeus/mongo-php-adapter
$ php -n $(which composer) require alcaeus/mongo-php-adapter:dev-composer-provide ext-mongo:*
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.
Problem 1
- The requested PHP extension ext-mongo * is missing from your system. Install or enable PHP's mongo extension.
Installation failed, reverting ./composer.json to its original content.
You could of course also manually put both packages into composer.json
and run composer update
, same effect (thatās actually what happened when we removed lock file and vendor dir earlier and ran an update).
For the steps above, instead of requiring ext-mongo
, you can also use doctrine/mongodb
, which in turn requires ext-mongo
. Same behavior.
There is a workaround: if you put the āalcaeus/mongo-php-adapterā package into a āpackageā repo inside composer.json, things work. Take this composer.json
:
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/alcaeus/mongo-php-adapter"
}
],
"require": {
"alcaeus/mongo-php-adapter": "dev-composer-provide",
"doctrine/mongodb": "^1.2"
},
"config": {
"platform": {
"php": "7.0.4",
"ext-mhash": "7.0.4",
"ext-mongodb": "1.1.3"
}
}
}
That works:
$ rm -rf composer.lock vendor
$ php -n $(which composer) update
Loading composer repositories with package information
Updating dependencies (including require-dev)
ā¦
This pointed to a problem with information from Packagist, and indeed, itās due to behavior in (and data available to) ComposerRepository
.
There is no information from Packagist on provided platform packages such as ext-mongo
, so without a lock file, the info that one of the other required packages provides ext-mongo
is apparently not there, and thatās why things fail.
Here is the fix:
diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php
index 5bd4e8a..91d6d58 100644
--- a/src/Composer/Repository/ComposerRepository.php
+++ b/src/Composer/Repository/ComposerRepository.php
@@ -371,7 +371,9 @@ public function whatProvides(Pool $pool, $name)
// override provider with its alias so it can be expanded in the if block above
$this->providersByUid[$version['uid']] = $package;
} else {
- $this->providers[$name][$version['uid']] = $package;
+ foreach($package->getNames() as $nameName) {
+ $this->providers[$nameName][$version['uid']] = $package;
+ }
$this->providersByUid[$version['uid']] = $package;
}
However, that feels like a band-aid treating a symptom of the real underlying issue, which is that Packagist does not have a list of provider packages for platform packages:
$ ls ~/.composer/cache/repo/https---packagist.org/provider-ext*
ls: .composer/cache/repo/https---packagist.org/provider-ext*: No such file or directory
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Reactions: 8
- Comments: 24 (17 by maintainers)
Commits related to this issue
- Add release blog post for ODM 1.1.0 and 1.0.6 — committed to doctrine/doctrine-website-sphinx by alcaeus 8 years ago
Any progress on this? š¢
Itās an issue for me, since I have to run around telling people that they need to add
provide: { "ext-mongo": "..." }
in their composer.json at root level in order to get this to work. Even if itās a workaround, Iād appreciate a fix here.What is the status of this? Trying to use any library that polyfills extension behavior is impossibly difficult and complex to get right. It shouldnāt be. Correct me if I am wrong, but it looks like this issue is continually being pushed to the next releaseā¦but this should be a āblockerā as it quite literally describes a broken implementation for a feature that is documented involving the most important aspect of Composer: dependency resolution.
Iāll be dead before then.
This should work in 2.0 so closing