PHP Composer - How to work with multiple vendors? - php

The project I'm working on requires using the PHP SDK's from multiple 3rd parties. Two of these are Amazon Web Services and the Google API Client (for Google+), and both of them use Composer to manage their files / dependencies. I'm not sure how to best set it up code / structure wise, though, because I don't need both AWS and Google loaded together. I might need AWS in one area and Google in another, so I don't want to just autoload everything every time and have the additional overhead from libraries I don't need right then. Right now I have the structure set up like this:
awscode.php
googlecode.php
libs
composer.json
composer.lock
vendor
autoload.php
aws
google
So, everything Composer related is in a shared composer.json file, and all vendor files in the single vendor directory. But, I can't seem to find a way to just load up say AWS. It wants me to use the autoload.php from what I can tell, which seems to want to load up everything.
Do I need to set it up more like this if I want control over each library?
awscode.php
googlecode.php
libs
aws
composer.json
composer.lock
vendor
autoload.php
aws
google
composer.json
composer.lock
vendor
autoload.php
google
I'm obviously new to Composer and how to best utilize it, and want to make sure that I am setting it up the best way for both my situation, and for future management.

When using Composer, it only loads the classes when they are actually called in your code. To my knowledge this uses the PHP spl_autoload_register.
So in answer to your question, there won't be a significant extra overhead (if any).

Autoloading means that the file which defines a class gets read when you first use that class.
You should include all your project dependencies in one composer.json, they won't be loaded in files you don't use them in.

Related

Merge composer vendor folders from various integrations in subfolders into one root folder

I create tools/bridges between my app/project and 3rd party integrations (like Mailchimp, Calendly a.o.) many of which have their own vendor folder with files.
A typical integration looks like this:
/tool1/index.php composer.json ...
/tool1/vendor/
/tool1/mycode/
/tool2/index.php composer.json ...
/tool2/vendor/
/tool2/mycode/
Same structure for 20+ other tools, many of which have their own vendor folders. Most downloaded or installed from GitHub.
I'm trying to do some maintenance and centralize the vendor folder into the root of the project, instead of calling a vendor folder from each tool. The reason for this is that most use the same packages, such as PSR, Guzzle, league, composer a.o.
It should then look like this:
/vendor/*
/tool1/index.php composer.json ...
/tool1/mycode/
/tool2/index.php composer.json ...
/tool2/mycode/
My issue is (due to lack of knowledge on the subject) that I'm not sure what to do with the autoload files for each of my tools. Obviously, there's an autoload.php in each vendor folder, specifically for that 1 tool (I presume).
Is this asking for trouble and am I better of keeping each tool separated, including the vendor files, or is it good practise to indeed move it to the root folder and spend some time getting my structure in order. If the latter, please advise how to keep things working properly.
It these are really completely independent tools, keep them separated, with their own discrete dependencies.
Trying to merge multiple composer.json files will take you down into dependency-hell, with different tools requiring incompatible dependencies and not being able to install/update.
And trying to have a single vendor for multiple projects will be a fool's errand, since many tools will use slightly different versions of the same dependencies.
The only reason to move everything to the same composer.json file is that if everything was actually one single project, and you need to guarantee a set of version constraints to keep the application working correctly

Managing Multiple Websites with a Single Laravel Codebase

My team has recently put together a Laravel codebase that works great for multiple websites. Currently we are running them as an app that installs on a centOS7 profile.
Whenever a new site is required, we fire up a profile, and the code gets cloned in. The codebase depends heavily on packages (custom laravel packages). Currently every site pulls in all of the packages that we have developed. Currently the differences are 1) The .env file. and 2) The theme config files (which come from a package and I'll touch on later).
I want to be able to pull packages based on need, I don't want to pull in every package we've developed. My question is, is there a way around pulling in every package? I was thinking of removing the composer.json file from git and treating it like a config file? I also thought about generating the composer.json file.
Eventually we want to add CI/CD to the process and really automate this thing. I am really fighting to keep the codebase in one repository. Am I wrong? Should we split the codebase up, one repository per project that comes in? But then you have to consider that updates become a nightmare.
Currently, themes are pulled in as packages. Every site has all of the themes in the composer file. The app has admin users that can login and set a theme to active. Still, I'd like if it only pulled in the necessary themes resources.
Sorry if I rambled a bit, but I am wondering how to scale the application properly.
Thanks a bunch!
tldr; How can I run multiple websites using one codebase, while being able to specify different required custom packages?
I haven't actually tested this but you might be able to accomplish what you want by defining multiple composer.json files. Read more on defining other composer.json files
Then, in each composer.json file define a different vendor directory. Example:
{
"config": {
"vendor-dir": "plugins"
}
}
Next, on each install specify which composer.json file to install, From the docs:
By setting the COMPOSER env variable it is possible to set the filename of composer.json to something else.
Example from docs:
COMPOSER=composer-other.json php composer.phar install
Read more on specifying the environment.
Last but not least, you will have to bootstrap your website or application for the specific vendor directory:
require __DIR__.'/../custom-vendor-directory/autoload.php';
This can be customized in your application's index.php file. The original source.

Can we use Composer with sparse SVN checkout to share dependencies?

Our current development setup uses a single Subversion repository containing multiple projects, each with branches, tags, and trunk. We then use a "sparse checkout" to select the projects, and branches of those projects, to work with.
The result is that the directory structure of a working copy matches that of the repository, including branch information, and we never use svn switch. (This style of working will probably be familiar to anyone who uses SVN, but may be surprising to those who don't.)
We are thinking of using Composer to manage both external and internal dependencies, but I'm not sure how this can work with the sparse checkout style of working.
I would like some way of using a directory within the existing checkout to satisfy a dependency, rather than each "root project" needing a separate copy.
For example:
sites/Foo/trunk
depends on lib Aaa, so references lib/Aaa/trunk
depends on lib Bbb 1.5.*, so references lib/Bbb/branches/release-1.5
sites/Bar/trunk
depends on lib Aaa 1.0.*, so references lib/Aaa/branches/release-1.0
depends on lib Bbb 1.5.*, so references lib/Bbb/branches/release-1.5
At present, if I edit the code in lib/Bbb/branches/release-1.5, I can test those changes on both sites, without needing to commit one and update the other.
Is there any way of using Composer to manage these dependencies?
(PS: Please don't answer with "give up on SVN, use Git, it is teh awesomez"; that is an answer to a different question.)
No - I do not believe that you can do this with Composer as standard: it expects to copy the files from whichever source (Packagist/VCS/Zips) to the local vendor folder, which is not what you want.
That said, I believe there are two potential ways you could get this working (at least in part):
Autoloader
You could try using the autoload field in the composer.json file to include the correct files into the project. You would still need to manage the checkouts of the relevant branches/versions manually (like I assume you do now), but you would be able to manage the inclusion of the internal libraries through Composer. This will probably require that your libraries are properly namespaced. The paths to the files for each namespace are relative to the root of the project, but can go below the root (via the /../ path) if required.
To be honest though, if you already have an autoloader for these files, there may not be much advantage to this solution. Relevant Docs
Composer Plugin
You could also write a composer plugin/"custom installer" that could probably manage this. This would have the advantage that you could have it manage checking out the correct parts of the sparse repository to have the correct version available, as well as doing correct wildstar version checking, but would be a much more difficult and riskier venture.
The basic process would be that you would define a new package type (e.g. 'internal-svn-package'). You would create the plugin as an external library that gets installed normally via Composer, which declares (via it's composer.json) that it handles this new type of package. Your custom logic would then be used for any packages that are listed with this custom type. I'm not sure how much of the internal composer logic for SVN checkouts you would be able to reuse however. Relevant Docs

Working on dependent, unpublished libraries with Composer

Let me first describe what I'm doing:
I'm working on two libraries, call them A and B - neither of these are public anywhere, and I don't want to publish them until they're stable.
Library A depends on Library B.
These two libraries are in separate, local Git repositories, and have individual composer.json files.
My problem is this: during development, I need a way to specify the dependency on Library B in Library A - which is simple enough, it's just an entry in the "require" section of Library A, and since nothing is versioned or committed yet, I'm specifying "dev-master" as the version requirement.
The issue is, library B of course does not really "exist" anywhere yet, as this is all local development on local Git repositories.
What I don't want, is I don't want to have to commit changes to Library B and having to do a composer install for Library A for every incremental change.
In fact, I don't want to "install" library B at all, as long as I'm just working on the repositories locally - that is, I don't want copies of Library B in Library A's vendor folder, I just want the generated auto-loader for Library A to point directly to my local Library B folder.
Surely there must be a way to do this? I have spent half a day searching and reading the documentation, blog posts, third-party guides, stack overflow questions, etc. - and found nothing.
Isn't this a totally common scenario and requirement for pretty much any developer?
Ideally, I also would like to be able to do this with a local file somehow - that is, I would rather not have to pollute my composer.json file with settings that are only relevant to me while I'm developing. But this is secondary - I can live with having to "hack" my local composer.json and avoid checking in the changes during development, but I cannot live with having to commit and install/update/copy files with every incremental change.
Any ideas?
It's not that common I think that people work on two brand new libs at once, but I agree we should support this better somehow.
I think the easiest/only way to do this is to install libB in libA using a local VCS repository definition (file:///path/to/foo/.git works), and then replace vendor/lib/A by a symlink to libA's folder. Just be careful if you run update because I'm not quite sure what happens in that case.
The other less pretty but perhaps easier way is to just develop libB in the vendor dir of libA, you can run install in libB's folder to get any dev dependencies. It's a bit ugly but not so dramatic IMO.

How can I safely add to a composer package?

I am using the Composer package Omnipay in my project and I want to add a new class to the package (in my case it is support for a new payment gateway). The naming does not conflict with anything and it follows the same naming and structure conventions as sibling folders. However, when I run composer update it deletes my whole folder of changes even though it didn't need to. Is there a way I can tell composer not to delete that directory?
Leave everything under /vendor alone, don't change any files there. You should treat libraries as external dependencies - don't check them into source control or change them in any way. Just reference them in your own code.
If you need to customize a composer library, you can either work around it in your own code (most PHP libraries support dependency injection, which will let you override any of the libraries' classes), or alternatively you can fork the library on github, then reference your own fork in composer.json, or submit the pull request so everyone can benefit from it.
As far as I'm aware, you cannot add to a Composer package as it is external and therefore out of your control. You should treat the packages as libraries only, and add all classes into your own project, ensuring that the packages you need are still set up in your .json file

Categories