Cloned project with dynamic includes in composer.json - php

I have an application server, it is like a blog system (my wordpress killer). It is based in php hosted in github and using composer to manage dependencies. Each installation is hosted in my server (I make the installation for them). When a client requires a new "addon/plugin" I create a new package and host it in a private repository hosting. The problems comes when I need to add new package:
Client 1.
- package for calculate prices
Client 2.
- package for show a welcome message
Client 3.
- package for add a calendar
My application will have every package ready to be used in all instances because I am requiring them via composer:
"require": {
"killer/calculate": "dev-master",
"killer/message": "dev-master",
"killer/calendar": "dev-master"
}
Now image if I have 2K clients and everyone of them are requesting custom packages. How can I provide an application (cloned massively) but just keeping in the each installation just the packages that each client need?
Hypothetical solution
I was searching (if it is possible) for something like the following. For each installation, create a file manually where its content specifies the package to be required. For example, let's say each client's installation has something like this:
//composer.json
"require": {
}
//plugins.json (this file is ignored via .gitignore)
{
"killer/calculate": "dev-master"
}
Then, somehow tells to composer.json to require the data from plugins.json. By this way I am avoiding to create a huge composer.json sharing unnecessary packages for all clients.

There is a feature request for allowing composer.json to extend another file. You should go comment on it to draw some attention to it.
The way you would use that feature is to create a default.json file that contains all your regular composer.json contents, including a require section that lists all the common packages you need.
// default.json
{
"require": {
"php": ">=5.4.0"
}
}
Then have a composer.json file for each project that extends and/or overrides default.json like this:
// composer.json
{
"require": {
"killer/calculate": "dev-master"
},
"extends": "default.json"
}
The final result would be:
{
"require": {
"php": ">=5.4.0",
"killer/calculate": "dev-master"
}
}
If you can't wait on the merge request, then you can go checkout the composer fork from the merge request's author and try it out.

Sounds like you have created your own package ecosystem. So, you could work independently from Packagist and simply host all the packages yourself, probably using Satis.
The main suggestion i have is to introduce your application as a package into this ecosystem.
Your application composer.json contains only the packages relevant for the application itself.
{
"name": "better/application",
"require": {
"another/library": "1.0.0",
"another/framework": "1.2.3",
"another/generator": "2.1.3"
},
"require-dev" : {
"phpunit/phpunit" : "4.*",
}
}
I think, that "cloning" the application for the customer/client is not a good idea, because it ignores that plugins have dependencies on a specific version of your application, which is not always "latest" or "dev-master". Let Composer pull the application by version for each client.
By this way I am avoiding to create a huge composer.json sharing unnecessary packages for all clients.
create one repository per new customer/client
add the application itself and the packages requested by the client inside composer.json
add a client config on top
For instance, the composer.json for Client1:
{
"name": "better/application-for-client1",
"require": {
"better/application": "1.0.0",
"better/app-calculate": "1.2.3"
}
}
For instance, the composer.json for Client2:
{
"name": "better/application-for-client2",
"require": {
"better/application": "1.0.1",
"better/app-calculate": "1.2.4",
"better/app-message": "2.0.0"
}
}
Each customer might have its own setup, requiring different version of your application with different additional application packages/plugins (here indicated by using the prefix "app-").
In the end you have two essential files for a customer: a composer.json and a configuration file.
(How the application detects the available modules is another story. At least, the autoloading will work out of the box, when you register Composers Autoloader during the bootstrap of the application.)
(Sidenote: If your application is a multi-site application, then you might replace "cloning" by "symlinking". With multi-site, i mean an application which runs from one central place using a site id (often customer id). If you have the application folder with all packages for development in one monolithic folder, then build a relase folder by cleaning the development stuff out, so that you get a release version with a blank default config. Then symlink the application, the requested packages to the customer folder and place a configuration on top. This approach might save quite a bit disk space and doesn't involve Composer at all.)

I would also encourage you to use the approach proposed by Jens A. Koch in his answer, having a composer.json file for each customer and requiring the main application and all required plugins. Composer supports this scenario quite well and I want to point you to the starting points:
Composer Types
Composer allows to specify types for packages. You can define your own type to mark plugins for your application as such. Many open-source projects (e.g. Symfony with bundles) have adopted this approach for their plugin eco-system.
Custom Installers
You can register custom installers that can execute for a specific type of composer package (i.e. the type you defined for your plugins). Then you can customize the installation process for your plugins, which means you can:
move your custom plugins to specific locations,
automatically adjust plugin configurations,
and most importantly: provide a mechanism that allows the main application to see which plugins are available.

Hmm.. require all packages ones..
It means one big composer.json for everything is running with your system / is compatible with your system. Maybe you will have to introduce a versioning system too.. So you could end up with v1_composer.json ..
But for each client load only the required packages. For example generate a requires.php for each client with necessary require statements which links to your shared libraries.. This will be the fastest solution and most efficient, because you sharing the code which you can share and you only load it when needed
Conclusion
Share as much code as possible... but don't use it when you don't need it.

Related

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.

Modular design for composer package

I'm working on a framework-like application, for which I would like people to be able to develop modules.
Modules add additional functionality to the core application by providing information to the core about their capabilities. Examples include modules for allowing access to MySql, or the file system or emails.
While modules can provide as much or as little extra functionality as they like, there is a Module class that is used to wrap the functionality provided, and each module should provide at least one of these classes to be included into the application.
Are there any guides or good practices on methods of module registration in PHP in the composer ecosystem. It would be additionally useful if the modules could provide aliases, and describe any configuration they require.
Clarification Edit
I have a core application, we'll call it example-app
Anyone using example-app should be able to introduce new functionality easily using the modular framework of the app.
So, let's say we have two modules example-module-1 and example-module-2. The app needs to know that these modules exist when it is run from the command line.
Everything should be managed from composer, so you will require the core application, and any modules that you wish to use with it. For example
"require" : {
"php": ">=5.5.0",
"example/example-app" : "^1.0",
"example/example-module-1": "^1.0",
"example/example-module-2": "^1.0"
},
What I would like to know is, is there a methodology for the modules to inform the core app at the time of installtion of their existence.
I already have a Module interface that imported modules can sit inside of, I just need a way to make the core app aware of where these classes are defined amongst all the other composer installed dependencies (e.g. I don't want to create a huge class list and step through each one doing instanceof).
The only thing I can think to do at the moment is to provide an additional companion app (something like bin/example-app-config) that each module calls as part of it's composer scripts. It could use cli parameters to tell the core app what the module class is called as well as any other requirements it has. However this doesn't sit right with me as it seems like it wouldn't be OS independent.
(I'm researching this topic and found your question from long ago.)
It looks like composer now supports enumerating installed packages by type that might help you achieve what you would like. Please see: https://getcomposer.org/doc/07-runtime.md#knowing-which-packages-of-a-given-type-are-installed

Code organization with laravel and several git repositories

I am working on several projects but each one connects to a REST web service.
I've developed the first one using Laravel, and developed a few classes really useful to communicate with the web services.
I would like to start the second one, and of course, reuse the classes developed for the REST connection.
My problem is, my company wants me to use several git directories for the projects, and each one should be uploaded to a different springloops project.
Springloops is a bit like github, you can upload your code using git.
How would you proceed to avoid copy/paste and use the same laravel code but in different projects (and I guess, in different locations)?
I'm not sure I'm really clear, but don't hesitate to ask me for more information if you need to.
Thanks.
How about creating your own Composer package and store it in a separate (private) Git repo? As far as Composer is concerned it's just like any other package, you may want to check out this section of the docs:
Using private repositories
Exactly the same solution allows you to work with your private
repositories at GitHub and BitBucket:
{
"require": {
"vendor/my-private-repo": "dev-master"
},
"repositories": [
{
"type": "vcs",
"url": "git#bitbucket.org:vendor/my-private-repo.git"
}
]
}
The only requirement is the installation of SSH keys for a git client.

PHP Composer - How to work with multiple vendors?

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.

Using Composer when multiple components are in the same vcs repo

I have a git repo that contains a few small and related libraries. Since the platform I am working with lacks proper dependency management, dealing with many git repos is a hassle, hence my team decided to put these into one git repo. I'm now working on having our software being installable via Composer. It is however not clear to me how to register each component in this git repo, as I'm not even sure it is possible to have more then one composer.json file per repo. Is this possible? And if so, how?
"is it possible to have more then one composer.json file per repo."
No.
You can't register the components separately, they will be registered as one big dependency and you will have to import them all into other projects, rather than being able to pull them individually.
However you can register where each component lives in the directory structure so that the autoloader is able to load them correctly.
"autoload": {
"psr-0": {
"Intahwebz\\Component1": "src/Component1",
"Intahwebz\\Component2": "src/Intahwebz/Component2",
"Intahwebz": "src/"
}
}
After including the Composer generated autoloader, creating a new class of type Intahwebz\Component1\TestClass will find it in the correct directory.

Categories