Change and update requirements for a composer vendor package - composer-php

I have a PHP project using composer. Among others there is this requirement:
/composer.json:
"require": {
.
.
"mypackage/backend": "^5.0",
.
.
}
mypackage/backend requires a third package:
/vendor/mypackage/backend/composer.json:
"require": {
.
.
"mypackage/pdf": "branch/name",
.
.
}
finaly mypackage/pdf requires a additional packages:
/vendor/mypackage/pdf/composer.json:
"require": {
"tecnickcom/tcpdf": "6.2.*",
"setasign/fpdi": "1.5.*",
"setasign/fpdi-tcpdf": "1.5.4"
}
I want mypackage/pdf to require the latest versions respectively, like this:
"require": {
"tecnickcom/tcpdf": "6.4.*",
"setasign/fpdi": "*",
"setasign/fpdi-tcpdf": "2.*"
}
So I want to do somethings like this:
composer require tecnickcom/tcpdf:6.4.4 setasign/fpdi-tcpdf:^2.3 setasign/fpdi:^2.3
but for the vendor package mypackage/pdf whithout to create another vendor folder in mypackage/pdf.
What is the composer way to do this?

Composer won't/You can't. Composer is a dependency manager (not a package manager), that means, for your main (the root) project, it will resolve all dependencies for a matching version.
That means it either can or there are conflicts and it can't.
Composer however will never install dependencies deeper inside the vendor folder than the first vendor/package-name hierarchy.
You have such a conflict in your example: "tecnickcom/tcpdf": "6.2.*" prevents "tecnickcom/tcpdf": "6.4.*" and vice-versa.
When you try to "install" this, the dependency will result in version conflict errors as there is no version of that package that will full-fil all of the two constraints: 6.2.* and 6.4.*.

Related

Composer error when trying to include multi level public personal repositories

I'm splitting up some of my personal code to modularize and reuse it on different projects.
I've started using composer recently and have been using it for referencing these modules on my projects.
The following has worked for me so far:
First project composer.json
{
"name": "mpf/apimodule",
"version":"dev-main",
"autoload": {
"psr-4": {
"APIModule\\":"classes/"
}
}
}
Second project composer.json
{
"name": "mpf/crawler",
"version":"dev-main",
"autoload": {
"psr-4": {
"API\\": "classes/"
}
},
"repositories": [
{
"type": "vcs",
"url": "git#github.com:{User}/{Repo}.git"
}
],
"require": {
"fabpot/goutte": "^3.2",
"mpf/apimodule": "dev-main"
}
}
Both composers are compiled and the project works as intended.
But when I try to add a third layer
Third project composer.json
{
"autoload": {
"psr-4": {
"API\\": "classes/"
}
},
"repositories": [
{
"type": "vcs",
"url": "git#github.com:{User}/{Repo}.git"
}
],
"require": {
"mpf/crawler": "dev-main"
}
}
I get the following error when running the composer update command
Your requirements could not be resolved to an installable set of packages.
Problem 1
- Root composer.json requires mpf/crawler dev-main -> satisfiable by mpf/crawler[dev-main].
- mpf/crawler dev-main requires mpf/apimodule dev-main -> could not be found in any
version, there may be a typo in the package name.
I've found a similar issue, but my repositories are all public and that was the problem for them.
I've tried running composer -vvv / composer diagnose, but couldn't find any useful information with the results.
From the description given in your question, you add repositories into root composer.json files. This works fine as long as you're using the root composer.json file. That is the project having this file.
Now while this works on each per-project basis, when you put the third (or fourth, fifth etc. ) composer.json file into the mix, or as you word it "add a third layer", it stops working.
Technically it does not stop working, however Composer can not resolve that inherited repository any longer to resolve the root dependency:
- Root composer.json requires mpf/crawler dev-main \
-> satisfiable by mpf/crawler[dev-main].
- mpf/crawler dev-main requires mpf/apimodule dev-main \
-> could not be found in any version, there may be a typo in the package name.
As honest as Composer is here, it may be puzzling in your situation. You've certainly already double-checked there is no typo and still though, Composer can not find any version.
That is because Composer uses the composer.json#/repositories configuration only from the root composer.json - that is the file itself. Let's visualize this a bit:
composer.json
vendor/mpf/crawler/composer.json
My educated guess is that, albeit you've added the repository for mpf/crawler to composer.json the repository for mpf/apimodule has not been added to it but only to vendor/mpf/crawler/composer.json.
The fix is easy, add all repositories your root project requires to resolve all dependencies to that projects configuration file (composer.json in the project you install the dependencies in).
If you think this through, it might become more clear why that is so:
The moment you install from composer.json, all repositories should be defined already as otherwise the outcome of the install will be a pure game of luck. Packages would be able to overwrite your repositories configuration and you would not be in control any longer.
My recommendations to continue your journey:
Add repositories inside your root composer.json file, to ensure your projects' configuration is complete. (Goal: understanding root configuration, the project level)
When working with this, consider if you want to have a global configuration of repositories. That is you can on the level of your computer user configure a list of repositories shared across projects (on that host). (Goal: understanding global configuration, the level of your host, working with projects)
Take a Safari-Tour on the different types of repositories Composer offers (compare with the documentation) as you may find even more in there (e.g. path repositories, another central .json file you can share etc. - there are quite some options). (Goal: understanding of the different repository configuration types)
kuba points to an entry in the Composer FAQ for this topic (via):
Why can't Composer load repositories recursively? (Composer FAQ)

Composer - what difference makes using alias in dependency

In my composer.json file, I have defined a dependency with an alias:
"require": {
"xxx/yyy" : "dev-branch as 1.2.3",
...
}
This dependency coresponds to a dependeny in another dependent package, which requires as well "xxx/yyy": "dev-branch as 1.2.3"
composer update rushes through and does not complain.
However, when I change the dependency in my project to
"require": {
"xxx/yyy" : ">=1.2.3",
...
}
composer complains and refuses to dissolve. I do not understand. To my comprehension, composer should load the latest version of dev-branch and treat it as if it would be version "1.2.3". It doesn't. Why?

Can't replace a package with Composer

I made an improvement (PR not merged yet) to an upstream library, guzzlehttp/psr-7, that's a dependency of another package that I depend on, spatie/crawler.
To force Composer to use my package instead of the upstream package, I tried the following:
I branched my fork of the library (branch name: cache-to-string) and updated its composer.json:
"name": "benmorel/guzzle-psr7",
"replace": {
"guzzlehttp/psr7": "1.6.*"
}
I updated my project's composer.json to use my fork instead:
"repositories": [
{
"type": "vcs",
"url": "https://github.com/BenMorel/psr7"
}
],
"require": {
"benmorel/guzzle-psr7": "dev-cache-to-string"
}
And ran composer update, which fails with the following error:
Your requirements could not be resolved to an installable set of packages.
Problem 1
The requested package benmorel/guzzle-psr7 could not be found in any version, there may be a typo in the package name.
How to fix this?
You don't need to change package name in your fork. You don't need to change composer.json of your fork at all. All you need is to add your fork to repositories section and change constraint of required package to use your dev branch:
"repositories": [
{
"type": "vcs",
"url": "https://github.com/BenMorel/psr7"
}
],
"require": {
"guzzlehttp/psr7": "dev-cache-to-string as 1.6.1"
}
Composer will override original guzzlehttp/psr7 package by version from your repository.
Using alias for branch may be required if some other package require guzzlehttp/psr7 - dev-cache-to-string will not match ^1.4. If you use dev-cache-to-string as 1.6.1 as a constraint, your branch will be detected as 1.6.1 release.

Can a composer "master" package pull in dev-master packages without modifying minimum-stability

I want to achieve the following setup (I've omitted other dependencies and stuff for clarity):
Project's composer.json
{
"require": {
"vendor/masterpackage": "*"
}
}
Master package's composer.json
{
"require": {
"vendor/package-1": "dev-master",
"vendor/package-2": "dev-master"
}
}
The master package is versioned with releases, child packages are not, hence the dev-master requirement.
Since minimum-stability can only be set in the root composer.json and is applied to all dependencies (which is undesired in my case), is it possible to set a dev-stability flag for only the master package AND its own dependencies so that its child packages get installed properly? I've already tried "vendor/masterpackage": "*#dev" but to no avail...
The way you experiment with it, it will not work.
The dependencies of depended packages cannot be influenced directly. So if your project prohibits development packages, you are out of luck.
You'd can add these indirect packages into your projects composer.json, adding them with the necessary #dev or dev-X surroundings. That way the will be required directly, allowing for development stability, and the master package requirement will also be fulfilled.
However, be warned that depending on branches is a very very bad habit and makes your dependencies very brittle. The commit id that has been used is recorded, but once you update and it goes wrong, you'll have a hard time juggling all the moving parts, i.e. all repositories that are only providing a branch.
I've found a way to get this working and thought it would be beneficial to post it as an answer for future reference.
Project's composer.json
{
"require": {
"wikimedia/composer-merge-plugin": "dev-master",
"vendorname/masterpackage": "*"
},
"merge-plugin": {
"require": [
"vendor/vendorname/masterpackage/dev-composer.json"
]
}
}
Master package's dev-composer.json
{
"require": {
"vendorname/package-1": "dev-master#dev",
"vendorname/package-2": "dev-master#dev"
}
}
The merge plugin makes this working since it treats dependencies of specified JSON files as if they are in the root composer.json

Can I use Composer to clone git repo of a package unavailable in Packagist?

I would like to use jquery DataTables within my project. Since the package is not available in Packagist, I am trying to use composer to clone the git repo of DataTables but it fails. Please advise how to proceed:
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/DataTables/DataTables"
}
],
"require": {
"DataTables/DataTables": "master"
}
}
Then composer update returns:
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 package datatables could not be found in any version, there
may be a typo in the package name.
Potential causes:
- A typo in the package name
- The package is not available in a stable-enough version according to your min
imum-stability setting
see <https://groups.google.com/d/topic/composer-dev/_g3ASeIFlrc/discussion> f
or more details.
Read <http://getcomposer.org/doc/articles/troubleshooting.md> for further common
problems.
I would further like to clone/download a specific version of the repo.
Old question and answer, however:
The error is not in the name of the package (that is indeed DataTables/DataTables) but in the indication of the stability. If you want the 'master' branch, you need to write 'dev-master' in composer and the stability level is dev. Otherwise require a specific tag.
In your case:
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/DataTables/DataTables"
}
],
"require": {
"DataTables/DataTables": "dev-master"
}
}
will work as expected:
root#erme:/usr/local/munk_php/jquerydatatables# composer install
Loading composer repositorInstalling dependencies (including require-dev)
- Installing datatables/datatables (dev-master 96b7ef9)
Cloning 96b7ef9176543bbf1f1488c0f9538ad9dcc9bc01
Writing lock file
Generating autoload files
The package name in https://github.com/DataTables/DataTables/blob/master/component.json isn't DataTables/DataTables
Try
"require": {
"DataTables": "dev-master"
}

Resources