Making Composer consider other directories for packages, to avoid duplication

10 hours ago 1
ARTICLE AD BOX

I'm trying to fold league/omnipay into a plugin suite in such a way that it's modular. So the core project module has this composer.json:

{ "require": { "league/omnipay": "^3.2" }, "config": { "allow-plugins": { "php-http/discovery": true } } }

All good. When I do composer require or composer update it grabs all the dependencies and dumps them in plugins/core_module/vendor/.

Next I want to bundle up a bunch of companion plugins that offer various specific gateways: PayPal, Stripe, WorldPay. etc so users can choose which ones they want for their site.

PayPal, for example, requires the following composer.json:

{ "require": { "league/omnipay": "^3.2", "omnipay/paypal": "^3.0" } }

The annoying thing is that it downloads a bunch of dependencies into its own vendor directory that also include the ones already downloaded in the core module. That's duplication I don't want.

What I would like is to somehow instruct Composer (and, by inference, my PHP application when it needs to load the classes) that "the league/omnipay library is over there, mate --->" so it only downloads/updates the extra stuff it needs specifically for the PayPal integration. Likewise for Square, Stripe, etc modules.

I've tried messing around with things like this:

... "repositories": [ { "type": "path", "url": "../core_module/vendor/omnipay" } ], ...

but it still downloads the entire dependency tree into the gateway's own vendordirectory, so I'm probably not using the feature correctly.

Once installed, the various plugins all sit alongside one another:

plugins/core_module plugins/gateway_paypal plugins/gateway_stripe plugins/...

so relative paths will work.

How can I instruct Composer to only download/maintain one copy of each dependency and not duplicate the ones in core_module?

Or, if that's not possible, what other options are available? (symlinks might work, but I need to consider Windows users too).

One thing I have not yet tried, which might work according to other SO topics, is adding this to each gateway plugin's composer.json:

{ "config": { "vendor-dir": "../core_module/vendor/" } }

In theory, I suspect that will then install the dependencies to the sibling directory's vendor folder which may then "see" that there are already some dependencies there and just fill in the gaps.

My only reservation is this approach doesn't keep things compartmentalised, so if someone decides to ditch PayPal and go with Stripe in future, unpicking it is more complicated and potentially leaves behind disk cruft. If the PayPal gateway code and dependencies could be confined to its own gateway_paypal folder, deletion is simply a case of removing the entire directory. I'd much prefer that than polluting the core_module vendor dir, if possible.

Read Entire Article