-3

I'm developing an app that will consist of multiple Composer packages.

First I have the "main" app (it will be a "project" in Composer) that will contain all the necessary files and folders:

app/ public/ index.php logs/ config.php ..etc.. 

This is not an issue. I just set the type as "project" in the composer file so it can be install with composer create-project foo/bar.

I will also build a few optional extensions for the main app. They will be their own Composer packages. This isn't either an issue. I just make them into type "library" and install them with composer install foo/the-extension.

The issue

The extensions will have their own namespaces and some of them will have their own dependencies. A couple of them will even have the same dependencies.
This is needed since all of them will are optional. You can install one or the other or all.

Currently, I've created a new folder called "/dev" in the main app where I have all my extensions while developing. Then, in the main app, I'm loading all the extensions auto loaders:

# Main apps autoloader require_once __DIR__ . '/vendor/autoload.php'; # Extensions require_once __DIR__ . '/dev/foo/vendor/autoload.php'; require_once __DIR__ . '/dev/bar/vendor/autoload.php'; ...etc... 

This works, but it comes with a few drawbacks:

  1. I need to change the code in the main app every time I'm going to make a commit to the main apps repo. This is a hassle and it's easy to miss something
  2. Potential versioning clashes. If two packages depends on the same package that gets a new update. If I miss to update both, there might be a version clash. (This have happened)

It's never good to have more than one auto loader since that can mess things up royally.

So, does anyone know of a proper way of handling this, or is it one of those "well, if it works for you, do it like that"-type of situations?

Been searching for a good solution for this a while now but haven't found any. If I missed some answer here on SO, please mark it as a duplicate and I'll remove this post.

Edit

As @sammitch points out in the answer below, I could add the extensions using Composers "repositories" key. This would remove the multiple auto loader problem. However, that will make the development flow pretty awkward:

  1. You make a change to an extension
  2. You commit and push that change to a git repo
  3. You do a composer update in the main app (to get the new commit)
  4. Now you can test if your changes work

I rather not need to go through all that every single time I make a change the extensions code just to see if the change worked or not.

0

1 Answer 1

10

Whoa whoa whoa, you should only ever have one composer autoloader, and it's a bad idea to just cram in external dependencies like that as it will complicate your dev and/or deployment pipelines later.

What you want to do is have the main project include the subpackages as actual packages. You can do this either by:

1. Pushing them to a git host

https://getcomposer.org/doc/05-repositories.md#loading-a-package-from-a-vcs-repository

{ "repositories": [{ "type": "vcs", "url": "https://github.com/youruser/yourrepo"}], "require": { "youruser/yourpackage": "^1.0.0" } } 

2. Specifying a local repo

Composer require local package

{ "repositories": [{ "type": "vcs", "url": "/home/youruser/src/yourrepo" }], "require": { "youruser/yourpackage": "^1.0.0" } } 

Now you can simply run composer install or composer update youruser/yourpackage and composer will pull in all the necessaries and build the relevant autoloader.

Note: Repository specifications are only effective in the root composer.json, so if your dependencies have specific repo config you'll need to either put that config into the root composer.json, or into your global composer config.

Sign up to request clarification or add additional context in comments.

7 Comments

Yes, I know it's bad to have multiple auto loaders, that's why I stated "It's never good to have more than one autoloader." :-) The problem with both these approaches are that it will make the development flow awkward. I will need to do a git push every single time I make a change, just to be able to test if it worked. It also requires me to remove those composer lines every time I make a commit to the main app. It is a better approach than what I'm doing, but still sub optimal.
What I rather would like, even though I realize it's probably not possible, is to have composer check if the /dev folder exists and if it does, load any packages inside it. Or something similar.
I get that it's extra steps, but you need to follow a consistent workflow that matches how your code will be deployed, otherwise you're going to have unanticipated problems when you try to deploy the finished product via composer. Eg: missing and/or mismatched dependencies, changes made manually in a dependent library that were never actually pushed, or were tagged as a different version, etc.
I totally agree, that's the main reason I don't like the way I have it now. I have done it like that previously but working on multiple extensions and, specially in the beginning, making a lot of small changes was a major pain. I also don't like the idea of committing untested code to the repo, since it makes the commit history anything but clean. I could squash the commits after, but that would be yet an extra step.
Maybe there simply isn't any better/more stream-lined approach of doing it. That could explain why I haven't found any better answers while searching :-)
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.