Using Composer when multiple components are in the same vcs repo - php

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.

Related

How Symfony container collects vendor classes?

I am working on very old legacy code, mostly procedural. Trying to improve it. Rewriting applications is impossible right now. The plan is to add a few libraries which would help organize things and improve that way.
I added a Symfony dependency-injection component in order to do that. It would provide the possibility to fetch needed services with its dependency easy.
I watched symfonycast tutorial on how to play with container. And with that knowledge, I managed to write a simple loader to start the container and to use services made by me. It is simple, it guesses FQCN based on file path, and then uses reflection to get dependencies. But I can not figure out how to load vendor classes, because here you can not guess namespace that way. :)
The question is: What exactly Symfony uses to load classes from the vendor folder, does it reads composer.json files to see namespaces, does it uses some composer feature, or something else?
Loading classes is different than instancing services.
The first can in fact use regular composer facilities to discover vendored classes in a legacy project like yours, even if they weren't installed with composer. This uses the standard php autoload mechanism with some added magic.
To include the, let's say lib/ legacy directory in the discoverable files you would add the following to composer.json:
"autoload": {
"classmap": ["lib/"]
}
And then run composer dump-autoload. Note that by including vendor/autoload.php in your legacy files you could even forego the require directives for your dependencies and rely on composer as well. This can be a path for migrating them to composer-managed dependencies, too.
Service instancing requires not only being able to locate the classes themselves, but also their respective dependencies so the container can create the object tree automatically. This usually involves hand-writing service definition files: classes in the vendor/ folder are not automatically registered as services. A bundle (or your own definitions) enables support for an specific library.
Take for instance the Mailer component: you can use it as a standalone library, but for framework integration (which includes service definitions and depen) you'd need to install Mailer bundle as well.
The exception where automatic service registration applies (when using symfony framework, not the standalone dependency injection component) is for files under src/. During container compilation, services.yaml is loaded and the ContainerConfigurator with help from FileLoader, looks for *.php files the directories configured as a resource, creating service definitions for them.
I guess you could do a similar thing for your legacy dependencies in a CompilerPass by using a similar technique or by trying to leverage the composer classmap but, specially if your legacy dependencies do not follow a PSR loading standard, I'd advise against it, since it can pull in tests, example files, etc.

composer inside other composer project

I have a composer project for which I need to create a custom plugin that will also use composer. Both the main project and the plugin use the same dependencies but in different versions. How should I resolve these dependencies between each other? So that the plugin uses a dependency from its composer vendor and not from the vendor of the main project?
I found for example this solution: https://github.com/TypistTech/imposter-plugin but it doesn't seem very elegant to me.
Compare as well with another recent Q&A Dependency Conflict between Plugin and Theme which should add more general clarification.
As you normally use Composer to resolve dependencies you could also use it here. However there seems to be a little misconception or at least some lack of clarity in your question:
So that the plugin uses a dependency from its composer vendor and not from the vendor of the main project?
In a compoer project, there is only one vendor folder, the one of the root project, the one you likely meant by "main project".
This paired with the description of only a "Project" and a "Plugin" there might be a slight chance that it is either one project which has its dependencies managed by Composer ("Project") of which one dependency is the "Plugin".
Or you have just two independent projects ("Project" and "Plugin") that can work independent to each other (normally not the case for "Plugin" material).
At the end of the day it is less a question of Composer, but just whether your software projects dependencies can resolve or not in a compatible manner.
As PHP has a global namespace and it is static, if you really have incompatible dependencies across the same software packages, you need to fork these and rename the namespace so that you can have one dependency for your module A and one for module B. So next to your a "Project" and a "Plugin" you also have projects you manage the dependency packages in, e.g. rewriting Namespaces and then offering to composer via a repository.

Getting composer package from git submodule

I am trying to implement a repository for my libraries which are repositories, and added as sub-modules of the main repository, so the development of each library can be separated from each other and the composer require have to look at only the main repository
My Repository structure is something like this
Main repositoey
----Submodule 1
----Submodule 2
----Submodule 3
----...
This structure is needed because if, i want to share the library to anyone, then they only have to add the main repository to their composer.json and not every single repository for the library.
I have tried similar thing using the branches and tags but, that is not feasible when more than one libraries with same version, we can not create duplicate tags for different branches, which is possible for the submodules.
What i want to implement is
Create modules
Push on the bitbucket repository
Share the module internally with colleagues
They should be able to get the module by running composer require vensor/module
And they do not need to add another repository
I do not know this is the correct direction i am heading in.
Please guide me or suggest a better way to implement the same mechanism.
Personally I don't like git submodules. It is better to create separate git repository and add composer package with packagist(public code) or satis(internal usage).
You can create package and publish it then you can add it to require in your composer.json then if you modify package you don't need create a new 2 commits in main repository and in submodule.

Cloned project with dynamic includes in composer.json

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.

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.

Categories