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.
Related
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
In Prestashop I can write my modules. But I have some code that is framework independent and I want to reuse in other Prestamodules AND in other frameworks I use.
So far so good. My solution was to put an Vendor folder and a composer.json to my Prestamodules to get those libaries I needed.
Now comes the problem that (offcourse) duplicated namespaces get into conflict. Is there a way around for this or should I do a global vendor folder in the root of Presta (what I want to avoid at any cost, I want to decide when I upgrade a single module or not. So the vendors should be per-module)
Vendors can't be per module if they are executed in the same request. You have to use a central vendor folder for all your dependencies - or you avoid using Composer and try to manage individual dependencies yourself - with the same problem as before: You cannot have two versions of the same class in your code.
Which one gets used? The first that the code encounters, depending on how autoloading is configured. Assume "random" order - it will break your code at the most inconvenient time.
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
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.
Issue: Nest a git repo in a git repo WITHOUT storing the second repo in the hosts master repo. The repos need to be two separate entity's. This way I can easily update a client sites base code (used on multiple sites).
Reason for two repos: I have a base php framework that my projects use. Each client gets their own repo that has the files required for that site. Due to the way git/submodules work I have to keep the "framework" as the master repo with the "clients code" as the submodule. The reason is I MUST have the index.php & .htaccess (part of the framework) in the root. That's fine since my framework is designed to extend as needed. I can just put any client files I need in the "site" folder and store that as a separate repo. The obvious downside is in order to setup the site you have to first install the "framework repo" then install the "client repo". Since these are private this setup is fine. I also liked the benefit of being able to update my framework from another project. Trouble is now any push's I do from that clone include the "client code". Also since I need the same setup for my local test of the framework that submodule gets added back to the main framework repo. I thought well why not just clone the "site" folder that holds the "client code" and add that folder to the ignore list. I have to update each by hand but again thats fine. However torisegit seems to think that its now a subproject (limited support) and I cant even add that folder to the ignore list. So i'm assuming nesting git clones is bad but I could be doing it wrong.
Goal: I need to be able to deploy two repos. My "framework" im sure has to be the base/root repo. Then I need to embed somehow a second "client" repo in a folder inside the base repo. The "client" repo never stores the framework code, just its own code. I want to be able to update and push changes to the "framework code" (its alpha so lots of bug fixes) without it storing anything about the "client code" so I can easly just clone it into a new folder for a new site. Again client code is stored in a single folder one level up from the frameworks root. (See example below). Doing this as a git clone breaks TortoiseGit and possibly git when I try to copy paste a folder and even add it by hand to the ignore file. Adding it as a submodules adds it to the master repo so when I clone it trys to add it.
Final Thoughts: Perhaps subprojects would work but there does not seem to be much support for it and I dont understand how to use it. Im trying to keep it to major tools so that my two main tools TortoiseGit and NetBeans support everything. Perhaps there is a way to not store a submodule in the master repo but I cant find it. Maybe subfolders would work but again there does not seem to be much support for it. Seems like the simplest would be it just ignore the folder but at least TortoiseGit seems to break when I try this but I could be doing it wrong.
Example Folder Layout:
-.git (framework repo)
- system *framework folder
-- foo *framework folder
-- bar *framework folder
- site (root for second repo aka client)
-- .git (client repo)
-- config.php *client file
- index.php *framework file
- .htaccess *framework file
The "system" folder, index.php and .htaccess are part of the PHP framework and are generic to all my sites. The "site" folder holds the second repo that contains the files for that site. The second option is to rewrite my framework so that its stored in its own folder and gets called by a new index.php. However this is a major rewrite with a pathing nightmare do to the way its written. Plus the issue of dealing with the .htaccess file since that has to be in the root. Sure I could copy it but then any changes to that file would not get updated in a pull. But at this point i think its the only way.
Hope this makes sense. I'm out of ideas but really want to get this to work.
You can always just clone the second repository where ever inside the first you like, then add the second's folder to your .gitignore file.
In your example above, you'd just add:
site/
to your .gitignore.
Git Submodules is the best thing I can think of. Check it out here. It's very handy for splitting up code into reusable repos too.