I am trying to create a PHP library which includes other libraries, and I bet I'm missing something fundamental.
Using the AWS PHP SDK as a guide, I'd like to create a library which, after installing with Composer, requires other libraries, yet the entire scope of classes (both from the current library, and required libraries) all become available simply by using require 'vendor/autoload.php;'.
What are the basic requirements to set this up? Is it a matter of configuring composer.json, namespacing in a particular way, or both?
What you're describing is exactly Composer's main purpose - the definition of a package of code that may require and implement other packages.
Using the AWS SDK as a guide, if you look at the composer.json file, which provides all of the Composer configuration information, you'll see two require blocks, one labeled require and one labeled require-dev:
"require": {
"php": ">=5.5",
"guzzlehttp/guzzle": "^5.3.1|^6.2.1",
"guzzlehttp/psr7": "^1.4.1",
"guzzlehttp/promises": "~1.0",
"mtdowling/jmespath.php": "~2.2"
},
"require-dev": {
"ext-openssl": "*",
"ext-pcre": "*",
"ext-spl": "*",
"ext-json": "*",
"ext-dom": "*",
"ext-simplexml": "*",
"phpunit/phpunit": "^4.8.35|^5.4.0",
"behat/behat": "~3.0",
"doctrine/cache": "~1.4",
"aws/aws-php-sns-message-validator": "~1.0",
"nette/neon": "^2.3",
"andrewsville/php-token-reflection": "^1.4",
"psr/cache": "^1.0"
},
This is how you define what other packages/libraries your library depends upon. The require section lists all other libraries that must be installed when your library is installed. The require-dev section lists libraries that may only be necessary when you are working in a development environment, and are not needed in your production environment.
When you specify other libraries that are required, Composer will install your library, and then go out and also require the libraries your library requires (and then the libraries those libraries require, and so on and so on).
Also included with the libraries to include, you'll notice that the version numbers are also included, to ensure compatibility.
The easiest way to add new dependencies I find is on the command line, with the composer require command, documented here: https://getcomposer.org/doc/03-cli.md#require. The command helps you search for the package you want if you don't know it exactly, and can resolve the latest version for you automatically (which you can override if you need/want to).
If you wish to require a development-only dependency, add the --dev flag when running the command.
Using this command, Composer will automatically update your composer.json file, pull down the dependency onto the local machine, and update your autoloader.
You should never need to do anything more than require_once vendor/autoload.php to ensure dependencies can be autoloaded - Composer will do all the legwork of setting up the autoloader so you don't have to, and keep everything up to date as new dependencies are added.
Here's the complete documentation on the composer.json schema: https://getcomposer.org/doc/04-schema.md. You will want to have a composer.json config file in the root of project, so you can configure composer for your project (and any others that require your library later). If you don't have one, you can use the composer init command to interactively create one. Documentation on that command is available here: https://getcomposer.org/doc/03-cli.md#init
And here's their basic usage guide, in case you haven't gone through it already: https://getcomposer.org/doc/01-basic-usage.md
Related
I found the composer.json & composer.lock(php) has conflict section (not to be confused with merge conflict ). The other similar files like package.json/yarn.json (nodejs) or Pipfile (python) and the corresponding lock files package-lock.json/yarn.lock or Pipfile.lock, do not have such format even though all these lock files serve the same purpose (lock the dependence to the exact version) and implement in the similar way (at least looking from the surface)
So what is usage of it and what should I do with it ? I read the composer document https://getcomposer.org/doc/04-schema.md#conflict but I still feel confused, e.g.
Map of packages that conflict with this version of this package. They will not be allowed to be installed together with your package.
For example after running composer install I have a composer.lock saying
{
"name": "symfony/http-kernel",
"version": "v4.4.20",
...
"conflict": {
"symfony/browser-kit": "<4.3",
"symfony/config": "<3.4",
"symfony/console": ">=5",
"symfony/dependency-injection": "<4.3",
"symfony/translation": "<4.2",
"twig/twig": "<1.43|<2.13,>=2"
},
...
It is easy to guess "symfony/console" 5.0 is conflicted with "symfony/http-kernel" 4.4.20 so symfony/console 5.0 will not be installed.
Do I need to do anything with the conflict ? So far I feel like that as a package user (not the package developer) those info is just a FYI and I don't need to do anything. But then why bother to list them for me ? After all package.json and Pipefile don't have such information and I don't find the problem without it.
--- update ---
From the answer I got I realize I need to emphasize this: I understand composer.lock is for composer so I don't need to worry about it.
What I don't understand is the purpose putting it in composer.json, this file is for human users. So if it has a conflict section what should I do about it?
I want to know a practical use case of "conflict" section in my composer.json if I am not a package developer but a package user.
When building an application, you are free to choose your dependencies way better than when you are building a reusable library like symfony/http-kernel which you've mentioned in your question.
Putting any other package constraint in the conflict section of such a package means: if you want to install the package in the current version, no other package version must be installed that is listed in the conflict section. From your example: symfony/http-kernel in v4.4.20 must not be installed if symfony/browser-kit is installed in any version <4.3.
In your own application, you have more freedom to use stricter constraints for the packages you use. You could require all packages with pretty strict version numbers, but this makes updates less comfortable. For example, this is a part of the require section in one of my current projects:
"doctrine/annotations": "^1.0",
"doctrine/doctrine-bundle": "^2.2",
"doctrine/doctrine-migrations-bundle": "^3.0",
"doctrine/orm": "^2.7",
"easycorp/easyadmin-bundle": "^3.1",
"exercise/htmlpurifier-bundle": "^3.1",
"knplabs/knp-snappy-bundle": "^1.8",
"league/csv": "^9.6",
"lexik/jwt-authentication-bundle": "^2.10",
"nelmio/cors-bundle": "^2.1",
All these packages might install tons of other dependencies which I cannot control. But if I know that any version of the other dependencies causes trouble, I can list them in the conflict section of my application such that this version is not installed.
For example, in the past I've needed that for an update of doctrine/migrations where the configuration has changed. I wanted to be able to update all packages except this one, because I didn't want to bother with the configuration changes I had to apply to my application for a while.
"conflict": {
"symfony/console": ">=5",
this means that for some reason your package can't work with symfony/console version 5 and higher, so it will keep it below 5.
E.g. you can exclude some package faulty version:
"conflict": {
"foo/bar": "1.420.69",
}
I know this is an old post, but thought I'd add a point to what's already been said:
You may still benefit from a conflict section in composer.json if you know any of your code conflicts with any packages. It could be any reason from both your code and the package trying to do similar jobs and stepping on each other's toes or simply that a package is badly written and breaks your code.
In that case, you can add a conflict section in your composer.json to tell composer to never download that package (or some releases of it).
This would be useful if you work with other developers and someone else might try to require that package, or if you worry that composer may try to install it as a dependency of yet another package e.g. X is the package you don't want, but another package Y depends on X and you don't know. Without the conflict section, composer would download package X without you even knowing/noticing.
I am using Symfony for an application. This application needs particulars PHP extensions to work, such as PHP GD, which are not listed in the base Symfony requirements.
I would like to know if it's possible to kind of edit the base list of requirements to add those extensions for my application to have them listed under the symfony check:requirements console output.
This requirements will NOT be tested when you launch symfony check:requirements, because this command doesn't depend of your application, it only checks the capacity to use symfony on the server.
This command will always return the same result, even if you launch it in a directory where there is no composer.yaml file.
But, you can add the needed extension by updating the composer.json file:
...
"require": {
"php": "^7.2",
...
"ext-gd": "*",
"ext-json": "*",
...
"foo/bar-bundle": "^1.3",
...
}
So, if the GD extension isn't installed on your server, installation of your application will not start.
I'm trying to integrate processout but they only seem to support composer integration.
https://github.com/ProcessOut/processout-php
How would I integrate this just by uploading the /src/ folder into my project?
<?php
// Load dependencies
require 'vendor/autoload.php';
// Instantiate ProcessOut
$processout = new \ProcessOut\ProcessOut();
$processout->setProjectId('<project-id>');
$processout->setProjectSecret('<project-key>');
// Set this project as the default one for the current request
\ProcessOut\ProcessOut::setDefault($processout);
?>
You are ignoring that Composer is not an autoloader generator, but first and foremost a dependency manager. If you look at the composer.json file of the ProcessOut package you see:
"require": {
"php": ">=5.4",
"ext-curl": "*",
"ext-mbstring": "*",
"anlutro/curl": "1.4"
},
The last line is a package it depends on itself, and that you'll be missing out when not using Composer. You could theoretically load and include all dependencies recursively yourself, but in the end - just get composer and let it do its work.
They have a php release where you only have to load autoload.php:
https://github.com/ProcessOut/processout-php/releases
My project is based on the Zend Skeleton App, and I'm using Composer to add vendor packages. However, when I add the zendservice-amazon package, it is not getting autoloaded.
Here is part of my composer.json file:
"require": {
"php": ">=5.3.3",
"zendframework/zendframework": "2.3.*",
"zendframework/zendservice-amazon": "2.0.*",
"doctrine/doctrine-orm-module": "0.7.*",
"zf-commons/zfc-user-doctrine-orm": "dev-master"
}
I have looked at the autoload files in the vendor directory, and they include the ZendService\Amazon namespace. I've tried several different things, but it's not working.
I've double checked that composer's autoloader is being used, so this is really puzzling. Any ideas? Thanks in advance.
The documentation and examples are wrong in the Zend Framework documentation. Instead of:
$s3 = new \ZendService\Amazon\S3();
You need to add an extra "S3":
$s3 = new \ZendService\Amazon\S3\S3();
I am trying to install PHPUnit/Runner/Version.php using PHP composer and I get the following error.
The requested package phpunit/phpunit-runner could not be found in any version, there may be a typo in the package name.
I am not sure if I am install the wrong package or what. The following is what I have in my composer.json file.
{
"require-dev": {
"phpunit/phpunit": "4.1.*",
"phpunit/php-invoker": "*",
"phpunit/dbunit": ">=1.2",
"phpunit/phpunit-selenium": ">=1.2",
"phpunit/phpunit-story": "*",
"phpunit/phpunit-runner": "*" - with this removed that file is unavailable
}
}
Any help would be great.
The class PHPUnit_Runner_Version is part of the core PHPUnit package phpunit/phpunit in any version.
So there is no need to require it seperately because the package name you invented does not exist.
You probably have a different problem you didn't ask in this question about some software not being able to require this class, but this likely isn't being solved this way.