skip to Main Content

I am new to composer in the PHP world.

I am trying to create a package Foo that has the package Bar as a dependency. Bar is available via packagist. Foo doesn’t need any of the PHP code of Bar though, just some of the assets. These assets can change with every new release of Bar, so it’s not really feasible to ship them with Foo.

Foo is not supposed to run on its own (although it could), but it’s supposed to be used as a dependency by other packages – for instance Yada. That is where my trouble begins.

So, let’s say, we have

  1. Bar with some assets.
  2. Foo using Bar as a dependency, e.g. with a composer.json where the relevant pieces look like
{
  "name": "foo/foo",
  "require": {
    "bar/bar": "<some-version>"
  }
}
  1. Yada using Foo as a dependency, e.g. with a composer.json where the relevant pieces look like
{
  "name": "yada/yada",
  "require": {
    "foo/foo": "<some-version>"
  }
}

I tried installing Foo on its own (in theory one could create a tool from that which could be useful standalone) and as a dependency of Bar. I expected vendor folder to always be created in the same spot (relative to my Foo files).

But:

  1. If I run composer install on Foo directly, then vendor/Bar will be put into Foo‘s directory.
  2. If I run composer install on Yada, then Foo and Bar will both be installed, but vendor/Foo and vendor/Bar will be put into Yada‘s folder, so Bar‘s files will be in a different spot compared to 1).
    Please note that 1) does not mean I have run composer install on Yada, changed into the vendor/Foo and there ran composer install again.

That means, that I cannot know where the assets that I want to used will be placed in relation to the files of Foo, can I? In other words: How would a PHP class of Foo know where too look for the vendor files of Bar that contain the assets if Foo was installed as a dependency (or sub-depencency or sub-sub-…) of some other package?

I learned about the post-install-cmd script that you can add to the composer.json file. That would allow me to copy the assets to a pre-determined folder in relation to the files of Foo, so they could be referenced. Alas, "Only scripts defined in the root package’s composer.json are executed. If a dependency of the root package specifies its own scripts, Composer does not execute those additional scripts.". In other words, when you install Foo as a dependency of Yada, then the post-install-cmd script will not run.

Is there a recommended solution to this kind of problem in the "composer world"? Or would it mean that when you want to use Foo in your package, you will not only have to add it using require in your composer.json, but to also add a tiny post-install-cmd script to copy/move the asset files as required? Would this be considered acceptable for PHP projects?

2

Answers


  1. Chosen as BEST ANSWER

    I don't know whether this is recommended, but I was able to find a solution to my problem:

    Given that I don't think I can determine where in the dependency chain Foo will be in relation to Bar - given that it could be used as a dependency or potentially standalone at some point - I created a simple function to traverse the file tree upwards starting at __DIR__ looking for vendor.


  2. Bar will always be under ./vendor/bar, relative to the composer.json that required it. The only thing you need to determine is the project root, which you could require the caller to inject, or ask Composer to provide.

    For example, in Foo, you can use Composer itself to determine Bar’s install directory:

    composer require composer/composer
    

    And then:

    $barPath = (new ComposerInstalledVersions())->getInstallPath('bar/bar');
    

    This will give you the correct directory regardless of whether Bar is running from Foo or from Yada. (Which you’ll then presumably have to manipulate further to get to the assets.)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search