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.
That's duplication I don't want...can you explain why it's a problem for you? Duplication is not, per se, a problem on its own...so what are the consequences of duplication which you are trying to avoid here? As Markus said, having all your plugins depend on a single copy of the dependencies potentially introduces extra overhead of testing whenever you want to update a library, and might prevent an upgrade from happening across the whole suite if it causes a test to fail in just one of them. You might be happy with that risk, but you haven't articulated the benefits you want in return.mklink /Jfor that.that's an additional 24MB of needless space...agreed it's probably unnecessary, but then again in modern terms that's a completely trivial amount of storage. You wouldn't even notice - that's half a dozen photos from your phone, or a handful of documents. If this was 1995 I might take that complaint more seriously. It's annoying but I wouldn't say it's worth re-engineering your whole setup for. However that's just my opinion, obviously.