I have a Zend Framework 2 application. It contains some library code containing business logic and some other utilities that will be common to other applications that will be created later.
My intention is to share it across projects using Composer. The question is, how do I do this properly and streamline the development? I will almost certainly need to make changes and additions to the library, from within the other project.
I tried setting up vendor/stuff
as a git submodule containing the package needed, and referencing it in the primary composer.json
like this (ref):
"repositories": [ { "type": "git", "url": "vendor/stuff" } ], "require": { "stuff/library": "master" },
Composer isn't able to load it in this way. It complains that the package could not be found, presumably because it's ignoring the fact that the URL is both local and relative. Technically, it doesn't need to; the vendor/stuff folder was initialised separately through git submodule commands.
In order to add a Git submodule, use the “git submodule add” command and specify the URL of the Git remote repository to be included as a submodule. When adding a Git submodule, your submodule will be staged. As a consequence, you will need to commit your submodule by using the “git commit” command.
A git submodule is a record within a host git repository that points to a specific commit in another external repository. Submodules are very static and only track specific commits. Submodules do not track git refs or branches and are not automatically updated when the host repository is updated.
In most cases, Git submodules are used when your project becomes more complex, and while your project depends on the main Git repository, you might want to keep their change history separate. Using the above as an example, the Room repository depends on the House repository, but they operate separately.
Unfortunately* Composer doesn't support Git submodules, as the main aim of Composer is to provide a similar inter-project dependency functionality and it would be pointless to try to replicate submodules in Composer.
I have the same problem that you are trying to solve, of developing a library while simultaneously developing the application that uses that library. There are a couple of ways to solve that problem just using composer.
This is the quickest and dirtiest way of doing it. Just do a composer update to create the appropriate directory for the library in your vendors directory, then replace it with symbolic link from your the directory that contains your library.
Obviously this is not great as you can accidentally overwrite code that you may have edited by running composer update.
Composer has the option to download the source via a Git clone (--prefer-src
) rather than downloading a zipball (--prefer-dist
) which is the default. This allows you to edit the source code inside the vendors directory and then commit it through Git.
e.g. Say you have project that requires amongst other libraries symfony/yaml
which you want to fix a bug in. What you could do is:
composer update
- This will download all of dependencies of the project.
composer update symfony/yaml --prefer-source
- This will now update just the symfony/yaml
directory in the vendors directory.
Fix the bug and then commit it through git.
The way I ---actually--- used to work when I'm developing a project and it's requirement in tandem, is to use Composers ability to set explicitly set a repository to use to resolve dependencies. e.g. if your code is in:
/projects/library/ /projects/project/
In the composer file for your project add the repository entry:
"repositories": [ { "type": "vcs", "url": "/projects/library/" } ]
Running composer update
will now look at the Git entries in /projects/library/ to resolve any dependencies on the library in preference to those listed in Packagist or other repository.
This does mean that when you want to test a change in the library code you need to:
Commit it, so that it has a Git entry.
Run Composer update in the project directory to get the latest version.
But you avoid having to push the commit to an external repository, which is good as it means you aren't pushing code that may not work, and it means you can work offline as Git commits don't require an internet connection.
Although that is apparently the best way of working, it's still kind of dangerous as it is too easy to accidentally check in a version of your composer.json that has references to local directories, which obviously will break the project for everyone else.
To avoid this I made a couple of small scripts that i) backup my real composer.json file, ii) Add in some local repositories, iii) run composer update
iv) Restore the real composer.json file.
cp -f composer.json composer.json.bak php composerLocal.php composer update cp -f composer.json.bak composer.json
<?php $srcFile = file_get_contents("composer.json"); $hackFile = file_get_contents("composer.local"); $finalString = str_replace('"LOCALHACK",', $hackFile, $srcFile); file_put_contents("composer.json", $finalString); ?>
"LOCALHACK", "repositories": [ { "type": "vcs", "url": "/projects/library1" }, { "type": "vcs", "url": "/projects/library2" } ],
And then place "//": "LOCALHACK",
somewhere in your projects composer.json
file. Running localupdate.sh
now safely does a composer update against local repositories without any chance of committing a bad version of composer.json.
This is how I tend to work now:
i) Composer update in the project ii) Go into the vendors directory and delete the library that I want to be developing at the same time. iii) Git clone from whichever repo you are developing the library in, into the appropriate vendors directory.
Composer understands git repos, so won't overwrite a git cloned directory(, though it does seem to get a little confused about editing the composer.json of the library).
Doing the git clone yourself, gives you complete control over what gets installed, and allows you to install from a repo that composer doesn't know about, or an untagged version, without having to edit the composer.json in the project.
That's the key feature of doing the git clone yourself; by not touching the composer.json of the project, it's completely safe, with no possibility of checking in a composer.json that has been modified to use local/custom repos.
The validation for composer.json files has been tightened and it is no longer possible to have a "//": "LOCALHACK"
entry in the file. Which is another reason why the Composer guys not having versioning for the Composer project is nuts.
* I actually think Git Submodules are a dumb, dumb, dumb implementation to 'solve' a difficult problem in a way that only causes more problems down the road, and so Composer not supporting them is way more 'fortunate' than 'unfortunate'. Obviously other people do use them, and are happy with them, so that is just my opinion, man, but if you're using Composer you shouldn't have a need for submodules.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With