Search code examples
phppackagecomposer-phppackage-managerspackagist

Composer: Require a specific version of a non-required package


When using the package manager Composer, is it possible to specify the required version for a non-required package?

For example: Say I have a blog module, and a widget module. Both modules work fine by themseleves, and do not 'require' the other module.

However, the latest version of the blog module will only work with with version 2.x of the widget module. So if the widget module is added to the project's composer.json, Composer should only let it install version 2.x, as installing a lower version will break the blog module.

I'm aware of the 'suggest' feature of Composer, but it doesn't appear to enforce versions.

Is this possible? If so, how?


Solution

  • If the blog and the widget have no direct dependencies, then the blog shouldn't break if the widget is present in the wrong version. Fix the blog module to accept any version of the widget. Use whatever is necessary to detect if the widget is present, check it's version, and apply the necessary fix to accept any version.

    If you cannot fix it this way, another way is to add the widget as a direct dependency to the blog. Obviously there is some detection already, because the blog can work with or without the widget. What is wrong with always installing the widget?

    There might be a solution by using conflict - here you can state packages that must not be present if the package in that version wants to be installed (like blog 4.2.7 conflicts with widget 1.*). Note that your current released blog versions which don't work together with the older widget will never get that conflict info, so if you already released the blog without, users will still fall into that trap. Even more so, if the newest blog release introduces that conflict, all installations which have the old widget will never get that blog release, but stay at the last blog release that does not state that conflicting widget version.

    There is some hope to get out of this mess.

    Assuming that blog version 4.1.* is still compatible with widget 1.x, and blog version 4.2.0 now is incompatible. You should do the following:

    1. Issue a patch update of the current blog module that fixes the incompatibility by rolling the changes back, but tagging a new release. The incompatibility should have been mentioned somewhere, so without it this should be considered a bug that needs to be fixed. If the last compatible blog version was 4.1.12, and after that 4.2.0 became incompatible, you could add a new tag 4.2.1 that points to the same commit as 4.1.12. This will fix the bug, but unfortunately remove the new features that lead to the 4.2 release. So be it.
    2. Add the conflict information to the blog. This incompatibility with older widgets should be treated as an incompatible software update itself, so after adding the conflict info to composer.json you can again release the 4.2.0 software branch as the new version 5.0.0.
    3. Any installation that includes your blog in any version 4 will always try to get the newest version when updating. So a version requirement of either ~4.1 or 4.2.* will update to the newest matching version 4.2.1. This version does not have the compatibility issue.
    4. Any installation wishing to update to the newest blog version will know that a new major release means possible incompatibility. So an update with an existing widget 1.x won't work, and Composer will tell this.
    5. Any installation that fetched that incompatible version 4.2.0 will be repaired with an update to 4.2.1 no matter what widget version is installed.

    The same workflow will apply if the incompatibility was introduced with a newer patch version, i.e. blog 4.2.6 is compatible, 4.2.7 is incompatible. Issue a new 4.2.8 with the change removed (i.e. re-issue 4.2.6 as 4.2.8), add the conflict entry to the 4.2.7 code and release that as 5.0.0.