Search code examples
phpgitcomposer-phpgitlabsemantic-versioning

Editing multiple PHP Packages which are managed in composer


I use composer to manage my dependencies. Those dependencies are located on packagist (public) and my companies local composer repository which itself gets its packages from the companies gitlab instance where only the tags pushed to the package server.

Now to my Problem.

I have a package which I will call A. Package A has a dependency to B. I am editing code in B which I put in a git branch which is by the nature of the setup only on the gitlab and not on the package server. B has a dependency to C.

I also have to edit a private library D. D is a dependency of C.

So I am editing code in B and D. I have to change the psr-4 autoload path of classes in D and add a new namespace to D.

I.e. Before:

"autoload": {
  "psr-4": {
     "hello\\hi": "src/"
  }
}

After:

"autoload": {
  "psr-4": {
     "hello\\hi\\": "src/abc",
     "foor\\bar\\": "src/def",
  }
}

How am I getting the autoloader to pick up the new classes when the Version of D is set to a tag (e.g. ^2.0) in C.

Normally I would require the dev Version of D in A. But composer argues that package C required Package D in Version ^2.0.

My current workaround seems clumsy: I changed the version of D in C to dev-<branch in gitlab of D> I pushed a new branch to gitlab of C. In B, I have changed the version of C to dev-<branch in gitlab of C>. I pushed a new branch to gitlab of B. And in a I define the version of B to be the dev-<branch in gitlab of B>.

But the gitlab branches would not be discovered, thus I had to add the gitlab Repositories in the repositories section of A.

This has to be simpler, for example, to force install the package regardless of the other dependencies. This is only for development and testing purposes not for production.


Solution

  • First, the fact you are doing this suggests a problem with your architecture. A shared library should have a well-defined purpose, and a well-defined, independently testable API. So the changes to package D should be defined as changes to that API, and tested against that definition. You might want to integration test it with its immediate dependents, but working with a chain of 4 libraries is a bad sign.

    However, this is the real world, so this is probably not something you can fix over night.

    Version aliasing in composer.json allows you to specify which version constraints a version (such as a dev branch) fulfils. This can be specified in either of two different ways (you don't need both):

    • In the dev branch of repo D, you can specify {"extra":{"branch-alias":{"dev-foo": "2.0.x-dev"}}}.
    • In the dev branch of repo A, you can specify {"require":{"package/D": "dev-foo as 2.0.x-dev"}}

    Alternatively, if you're actively developing both branches, rather than just integration-testing the library, you could by-pass Composer altogether. If you set the preferred-install option to source then composer install, each library will be a full git clone, and you can switch branch and edit directly. You can use composer status to keep track of what you've manually edited. If you end up doing this, it's definitely a good idea to think about how to avoid needing it in future.