I've read several questions in SO about how to install 3rd party libraries in another "project". Inevitably, the answer is to use composer and they all say we need a composer.json file in the project root.
I'm confused. I am working on a project, whose "source" build has the following structure
web/
src/
The web folder includes several PHP files that are implemented by the project. This project so far doesn't use composer at all.
The src directory contains c/c++ files for some core engine files.
I now need to add, let's say, php-jwt to this "project" (which is a hybrid PHP+C++ project) in a way that I can include the jwt library in some file inside web/views/myfile.php
I also have the following additional requirements:
The project is quite a large one, and its packaging rules are quite complex. At the end, basically RPM or DEB files are created that users install on their systems. I want to make sure users installing the project, of which jwt-php is a part don't need to install composer.
Given that, where exactly do I download the jwt library using composer? Inside web/ ?
Maybe, we just add a composer.json right next to these two directories:
- web/
- src/
- vendor/---------
composer.json -
composer.lock -
------ autoload.php
------ composer
------ jwt-php
------ other-php-cpp-package-1
------ other-php-cpp-package-2
------ other-php-cpp-package-3
------ other-php-cpp-package-4
-------
Then, our composer.json might look like:
{
"name": "project/cphp",
"type": "library",
"description": "PHP C++ Project X",
"keywords": ["php","c++"],
"copyright": "",
"license": "",
"version": "1.0.0",
"authors": [{
"name": "user1361529",
"role": "Developer"
}],
"require": {
"jwt-php": "*",
},
"require-dev": {},
"autoload": {
"classmap": [],
"psr-0": {},
"psr-4": {}
},
"config": {}
}
If we are using a MacOS for example, we would install the composer:
cd path/to/main/dir
sudo composer install
We can always change the directory later. It might not be so important initially.
As you said, your project is a multi-language hybrid application.
I do not recommend that you install the vendor's vendor directory in the root directory of your project. If your php mainly exists in the web directory, then you can install the vendor in the web directory. The directory structure is as follows:
web/
---vendor/
------autoload.php
------...
---composer.json
---composer.lock
---...
src/
For references to installed libraries, you can use the include '../vendor/autoload.php' in web/views/myfile.php to load the composer auto-registration script (or you might be able to introduce autoload in a unified main entry script). Then call the third-party library through the namespace: new Firebase\JWT\JWT();
Then, submit the vendor to your VCS and package it into RPM or DEB so your customers don't need to install composer.
Answer by Google Translate
Edit:
It is dangerous to place the vendor directory in the directory with open permissions to the web server. Please adjust the specific directory structure according to the actual situation. By the way, the directory named web does not necessarily have the open permission of the web server.
If you do not want to use composer then you can simply download the library and call it in your code.
<?php
require _DIR.'path-to-librayr';
use class;
Related
I've got a local PHP project (a website), and I want to use another project I've made (a tiny web framework) as a Composer package for the website project. I'm developing them in tandem, but want to keep them as separate projects; when I deploy the website, I want to use Composer to install the framework project as a package, just like I would with Guzzle or any other common Composer package.
The website project has the following composer.json:
{
"repositories": [
{
"type": "path",
"url": "/local/path/to/framework/package"
"options": {
"symlink": true
}
}
],
"require": {
"my/framework": "dev-master",
"guzzlehttp/guzzle": "6.3.3"
}
}
In /local/path/to/framework/package/composer.json I have:
{
"name": "my/framework",
"description": "A tiny framework.",
"autoload": {
"psr-4": {
"MyFramework\\": "src"
}
}
}
I run php composer.phar update and it sets up a symlink to the framework package in my website project. If I update code in the framework, it's immediately available to the website code. This is great.
However, later on I want to deploy the website project to my web server. For a clean deployment, I have a deploy script that exports an archive copy of the appropriate branch of the website git repo, and then runs php composer.phar install to make sure all the proper packages are installed. With the above config, the deploy script creates a symlink to the framework package, which is obviously no good when the deployment artifact is zipped up and scp'd out to the web server.
If I remove the symlink option above, then I have to run php composer.phar update every time I make any changes in the framework package, which is irritating since I'm developing the packages in tandem. But then on deploy, the package is copied in, rather than being symlinked in; this is good for deploy, except it always copies in the master branch (because I specified dev-master in composer.json).
Is there a way to set up Composer so that I can have the convenience of a local symlinked package for development, but to let the deployment script get a clean copy of the framework package, without having to change composer.json every time I want to deploy?
I also tried changing the repository type to vcs instead of path, but then Composer clones the framework package repository, and I really don't need a clone of the repo in my local vendor/ tree, either during development or deployment. I just want to be able to have a symlinked tree (which gets me instant updates) during development, and have a clean package installed for deplotment.
I may have to resign myself to developing the framework project "properly," that is, as a Composer package that I tag with actual release version numbers, and then update my website project to use a specific version of when it comes time for a deployment. I still haven't figured out the easiest way to do that, though.
You can use Composer Studio plugin.
It uses a separate file for configuration and allows you to have symlinks in development and a regular Composer install for prod deploy, without touching composer.json.
With it, your website composer.json will look like a regular file:
{
"require": {
"my/framework": "dev-master",
"guzzlehttp/guzzle": "6.3.3"
}
}
And with studio.json in the root of the project, with the following content:
{
"version": 2,
"paths": [
"/local/path/to/framework/package"
]
}
you can tell the plugin where to locate my/framework. Studio will then symlink the packages from the provided paths.
To have a regular install, just remove or rename studio.json, remove the vendor folder and composer.lock file and run the install again when deploying.
I made a composer plugin to make it more easy to test packages.
It doesn't require a configuration file, changing your composer.json and doesn't change the upgrade behavior of composer update
https://github.com/SanderSander/composer-link
It works as simple as calling composer link ../path-to-package to link the local package into your project.
for educational proposes I write my own PHP application and add a little plugin system. The application itself uses composer to manage required dependencies.
It is possible that a plugin have his own dependencies (Guzzle etc.) and that two plugins have some overlapping dependencies. To reduce storage and avoid any interference I will use composer with composer installers for the plugins:
/src
/plugins
/DemoPlugin
composer.json
/src
/config
...
/vendor
composer.phar
composer.json
...
So it is possible to install a plugin easy over the "main" application and composer handles all dependencies automatically (incl. autoloading).
But this workflow creates a problem that I cant solve at the moment: It requires that the user uses composer require app/plugin-name and download the plugin from the network. But I cant guarantee that every plugin can be installed this way. For example: Paid plugins, company internal plugins or simple dev plugins which only exists as "zip file".
With composer installers the plugins are stored in a different directory, in place of the "classic" vendor directory. But from my understanding it is not possible to copy a zip based plugin into this plugin folder. I cant find any method to start the installation of the plugin (downloading vendor, maybe setup scripts etc.).
This concludes into my question: It is possible to tell the composer instance from the "main application" that a plugin should be installed (downloading vendor, maybe setup scripts etc.) but dont start a download because the plugin is already placed correctly?
If I run composer install in the plugin directory, composer will download the vendor directly into the plugin directory - with all the problems (duplicate dependencies, no integration into the autoload etc.).
I appreciate any help!
What you are looking for is a path repository.
To follow your example you can use the following composer.json
{
"name": "test/test",
"type": "test",
"repositories": [{
"type": "path",
"url": "./plugins/**/"
}],
"require": {
"guzzlehttp/guzzle": "^6.3"
}
}
Where you have the following structure:
├── composer.json
├── composer.lock
└── plugins
└── DemoPlugin
└── composer.json
You can eventually require your plugin as you would do usually:
composer require "test/demo:#dev"
And you will see the dependencies are not duplicated (you do not need to install the DemoPlugin package).
I am a Composer beginner and I am trying to make one project dependent of another one, while both project only exist on my local machine.
The composer.json in my library project (ProjectA) is:
{
"name" : "project/util",
"type" : "library"
}
I initialized git in the base folder of this project.
My composer.json in the project depending on the first one (ProjectB):
{
"repositories": [
{
"name" : "util",
"type" : "git",
"url" : "/d/workspaces/util"
}
],
"require": {
"project/util" : "*"
},
}
When I run composer install from ProjectB, I get the following error:
[RuntimeException]
Failed to clone , could not read packages from it
fatal: repository '' does not exist
I asume something is wrong with the url of the repository, but I am not sure what else to write there.
Autoload local package using composer (without going to packagist every time you change).
There are many ways to do so, I will be covering 2 of them:
In all cases we have 2 main parties:
- the local package (the code that we do not want to publish on packagist to be able to autoload it in our project composer).
- the main project (the code base that needs to use the local package code, can be another package and or any project).
Method 1: (direct namespace)
Open the main project composer.json file and autoload the local package namespaces using any method (PSR-4, PSR-0, ...).
example:
if in the composer.json of the local package we have:
"autoload": {
"psr-4": {
“Local\\Pack\\": "library"
}
},
"autoload-dev": {
"psr-4": {
"Local\\Pack\\Tests\\": "tests"
}
},
then in the composer.json of the main project we should have:
"autoload": {
"psr-4": {
"Mahmoudz\\Project\\": "src",
"Local\\Pack\\": "../path/to/local/pack/library” << referencing the other local package
}
},
"autoload-dev": {
"psr-4": {
"Mahmoudz\\Project\\Tests\\": "tests"
}
},
Advantages:
- you don’t touche the vendor directory (running composer update by mistake will not override your local changes)
- you don’t need your package to be on packagist to use it
- you work in one place (the local package) and the changes are automatically loaded in the main project
Disadvantages:
- you cannot publish the composer.json on production (needs editing before publishing to require the real package)
Method 2: (local repository)
Download the local package from a local repository.
local package:
1. initialize git in the package (even if you don’t want to use it - no need to commit anything)
2. add composer.json file. In the file make sure you have the following:
"name": "vendor-name/package-name",
"autoload": { … // use whichever method you prefer, but make sure it’s being loaded correctly
"minimum-stability": "dev"
composer dump-autoload
main project:
1. edit your composer.json to contain the following:
"repositories": [
{
"type": "vcs",
"url": "/full/path/to/the/local/package/package-name"
}
],
"require": {
"vendor-name/package-name": "dev-master"
},
composer update vendor-name/package-name
now check your vendor directory you should see the vendor-name/package- name
NOTE: whenever you make change in the local package (not the vendor) you need to git commit then you can composer update the main project, it will get the latest copy of the repo to the main project vendor directory.
Advantage:
- you don’t touch the vendor directory (running composer update by mistake will not override your local changes) - you don’t need your package to be on packagist to use it
Disadvantage:
- you have to keep committing your changes (in the local package) and then running composer update in the main project
- you cannot publish the composer.json on production (needs editing before publishing to require the real package)
I think you've just got the syntax wrong. The type should just be VCS, and then composer figures out what type of VCS it is.
So in your project B, the entry for repositories should be:
"repositories": [
{
"type": "vcs",
"url" : "/d/workspaces/util"
}
],
You don't need to name what library is available in /d/workspaces/util. Composer will scan the composer.json file in that directory and know what project name is available there, and use the project from that directory in preference to a version listed on packagist or other repository.
The easiest way is to use type=path https://getcomposer.org/doc/05-repositories.md#path
{
"repositories": [
{
"type" : "path",
"url" : "/d/workspaces/util"
}
],
"require": {
"project/util" : "*"
},
}
I found this tutorial really useful: https://johannespichler.com/developing-composer-packages-locally/ when I was facing issues with local package production
Note the symlink condition allowing the vendor folder to be a symlink which then means you no longer need to composer update each time you want to see change
"options": {
"symlink": true
}
In addition to Danack's solution: Changing the path from /d/ to d:/ worked for me.
Like this:
"repositories": [
{
"type": "vcs",
"url" : "d:/workspaces/util"
}
],
NOTE: This answer assumes that you have something like a Package Registry or GIT repository where you
can retrieve the releases of your package. If you do not yet have this. https://getcomposer.org/doc/05-repositories.md
Composer enables us to autoload a local development package without contaminating the composer.lock file.
When Composer finds a conflict between two or more packages it wil autoload only one of these packages.
You can use the autoload-dev to autoload a specific folder for development. (https://getcomposer.org/doc/04-schema.md#autoload-dev)
The autoload-dev (and autoload) settings do not touch the composer.lock file
In your projects composer.json file:
"repositories": {
"99999999": {
"type": "composer",
"url": "https://gitlab.com/api/v4/group/99999999/-/packages/composer/packages.json"
}
}
"require": {
"a-vendor-name/test-package": "1.0.*"
},
"autoload-dev": {
"classmap": [
"./../../packages/a-vendor-name/test-package"
],
"exclude-from-classmap": [
"vendor/a-vendor-name/test-package"
]
}
In this example the packages directory lives outside the project root and contains its own package GIT repositories.
autoload-dev because we only want this folder to load when we are developing. (https://getcomposer.org/doc/04-schema.md#autoload-dev)
classmap to load the packages from a local directory. (https://getcomposer.org/doc/04-schema.md#classmap)
exclude-from-classmap to disable loading the package within the vendor directory.
Will also suppress the warning about multiple classes with the same namespace. (https://getcomposer.org/doc/04-schema.md#exclude-files-from-classmaps)
Running DEVELOPMENT (default behaviour):
composer update a-vendor-name/test-package // or any other composer command
Your package will still be downloaded from your Package Registry. This downloaded package is not only ignored in you applications code, its also possible to update it according to the project composer.json file. Which in turn will update the composer.lock file, the right way.
Running DTAP / PRODUCTION by using the --no-dev flag:
composer update a-vendor-name/test-package --no-dev // or any other composer command
In addition to #Glen Solsberry's solutions, if you're running in a docker container like me, you can add a volume to your docker-compose.yml file like:
services:
theservicename:
...
volumes:
- ../:/var/www
- /path/to/src/package:/var/www/vendor/path/to/src/package
...
When you make changes locally they will reflect in the container.
I have a project with the following structure:
- src
----/ /* Relevant files */
- tests
----/ /* Irrelevant files */
- composer.json
- phpunit.xml
The project is sent to packagist on every commit already. But, it is sending the test files.
I'd like to ignore tests folder, so composer wont download unecessary files when someone calls composer require my/package
Here is whats the content of my composer.json looks like:
{
"name": "my/package",
"description": "...",
"type": "library",
"license": "MIT",
"require": {
"php": ">=7"
},
"require-dev": {
"phpunit/phpunit": ">=5.4"
},
"autoload": {
"psr-4": {
"MyProject\\": "./src"
}
}
}
Ignore tests folder when send to packagist
Let's first clear up some confusion.
When you enable Packagist for your repository, Packagist will load the composer.json to get metadata about your project and fetch the version informations from the tags/branches.
But you are not sending your PHP code or any tests to Packagist.
I'd like to ignore tests folder, so composer wont download unecessary files when someone calls composer require my/package
This question pops up quite often. I'm referencing a detailed answer, which i've written some time ago, which explains a lot of the background: https://stackoverflow.com/a/32476500/1163786
Usage of a .gitattributes file with export-ignore directive
Technically, you could add a .gitattributes file to your repository, which declares a export-ignore rule for the test folder.
This means that any git export will no longer have the tests folder, including the Github zip file.
Ok, exclude done..
But, when someone composer require's your project, it will now depend on the --prefer-dist setting to install the package from the dist (zip). (You would get the tests with --prefer-source).
If it is a small library, stop to worry. Be happy.. :)
If it is a bigger application, then a better solution is to package your application properly, instead of relying on the git exported zip distribution.
Most developers don't use a build.xml or any build script anymore, but that's the correct way to do it in my opinion.
That means once you are ready to tag a new release.
You trigger your build script, which fetches all the dependencies, runs the tests once more and when everything is ok, drop all the tests and packages the files for deployment.
Small hint: don't forget to add a autoload-dev section for your tests to composer.json.
If your Packagist package is linked to a GitHub repo, just create a "Release" in GitHub that does not contain the development files.
This works out-of-the-box for your end users, because Composer install/update uses --prefer-dist by default, which serves the package zip that is in the "Release".
The easiest way to do this (And it's how some Symfony packages does it, for instance), is to create a .gitattributes (as Jens suggested) with the following content:
/tests export-ignore
Now, when you create a tag/release in GitHub, the release zip won't contain the tests folder.
The only scenario where tests folder would be included in this case is if the user installed your package with --prefer-source, but if they do that, they should know what they're doing.
I have two packages that was pulled to my project with composer.
I don't want to have composer pull updates on these packages from anywhere and don't want composer to try and override my files with any repository.
If I remove the packages from my composer.json file it deletes the packages an removes the autoloaders.
How do I get composer to leave the packages alone and allow me to work on the code without losing the files or autoloaders on update.
I figured out how to do this.
What you want to do is create an artifact directory.
Thus in your main composer.json file you need to do something like this:
"repositories": [
{
"type": "artifact",
"url": "custom/artifact/"
},
..........
the url var should be the file path to the zip files relative to composer.json file.
Now you only need to add a composer.json file with a name and version to a zip file.
If the package already contains a composer.json file you only need to add a version.
example:
vendor-package-1.0.zip needs a composer.json file with:
{
"version": "1.0",
"name": "vendor/package",
"type": "library",
........... etc
}
It is important to define the version in the composer.json file or it will not find it.
Now you call this package by version from your projects composer file:
"require": {
"vendor/package": "1.0",
Now you can create and update files in your package without the worry that some online change or offline server will cause any problems.
As long as the version stays the same it should leave your files alone.
The good thing is that files added or removed will still update the autoloaders as specified in the zip package's composer.json file.
Give a specific version for that package, so it will not be updated when new versions come up
If you don't have too many packages, you can use
composer update package1 package2