I'm writing a new composer.json file for a project so that it can be available or Packagist or direct reference to its GitHub repo. The project requires either one or both of the HTTP client extensions, pecl_http or curl. If I specify both of the packages under require, Composer will give an error if both are not installed.
How can I tell Composer it's okay to have just one of those two extensions installed?
You cannot define it in a way that you only need one of these extensions, but make Composer fail if none are present.
The usual way for packages is to mention extensions as "suggest". Your code already has to deal with detecting which extension is present and select the correct code path, it's no additional problem to emit an error if all are missing.
Alternatively, have two packages with their dependency exactly on one extension. Or have a main package on top of that which suggests the two implementation packages and makes it clear via it's interface that the developer has to provide at least one implementation.
On the other hand: Dealing with HTTP stuff looks like you should probably rely on PSR-7 interfaces, and let the developer choose the HTTP client implementation to use.
Related
I just got a memory limit error and I solved it in my .ini files. No worries. However, I'd like to put something in my package composer.json to indicated that some minimum memory is required. I know how to specify a php version requirement in composer.json - I'm just wondering if other platform requirements can be added/checked by composer.
Composer can check for software to verify if they are corresponding. But, it doesn't check the system (CPU, memory...). You can specify the requirements in a readme.md file.
You can add in your code the memory limit needed in your script. But, in general, the default memory limit is enough. You may be have loops you can optimize by adding yeld or iterators.
The complete list of properties available in composer.json is very well-documented.
The only one which makes requirements on a user's system is the require section. This can include platform dependencies (also discussed on the "basic usage" page) in the form of virtual packages exposing the version of PHP, its extensions and related libraries, and Composer itself. These are resolved as part of the dependency resolution process, and not when the application runs, although you can enable an additional platform check.
Note that the config section configures the behaviour of Composer itself, not the package, and is marked "root-only" - that is, it will not even be read when another project uses your library. The platform option which you've mentioned is the opposite of a platform requirement: it tells Composer to pretend certain constraints are met even when they are not.
If you want to verify at run-time that a particular configuration is in place, rather than merely documenting it, you can easily write your own using functions such as ini_get. This can either be run as part of initialisation of some relevant object or function, or listed as a file include in the autoload section so that it will always be executed as the application starts up.
UPDATE: Although this is the only working solution provided - please read the comment thread. There are good arguments against this. Also, this requires strong working knowledge of writing and deploying vendor packages. Specifically, you'll want to know how to roll this back when a better solution is posted or the problematic package is fixed.
Add a little php file to your composer project or package.
composer.json
{
...
"autoload": {
...
"files": ["tweak_ini.php"]
}
}
tweak_ini.php
Obviously you'll want to add some logic to make sure you aren't downgrading.
ini_set('memory_limit','1000M');
...
I am updating a prestashop module by including a package that uses guzzle6.0.
Prestashop 1.7 uses an older version of Guzzle 5.
When I install the plugin on Prestashop the included package's version of Guzzle conflicts with the Prestashop one resulting in the following php error.
Uncaught PHP Exception InvalidArgumentException: "Magic request methods require a URI and optional options array" at /var/www/html/modules/package/vendorpackage/guzzlehttp/guzzle/src/Client.php line 81 {"exception":"[object] (InvalidArgumentException(code: 0):Magic request methods require a URI and optional options array at /var/www/html/modules/package/vendorpackage/guzzlehttp/guzzle/src/Client.php:81)"} []
I have found a few other examples of similar issues:
PrestaShop module classes not found (namespaces)
http://forge.prestashop.com/browse/BOOM-2427
Prestashop 1.6, conflict: 2 different modules requiring same class, different versions
https://github.com/Nexmo/nexmo-php/issues/77
Based on these I have a few ideas for how to get around the issue. None of these feel like the right way to do it. Surely there is a cleaner way to handle issues like this with composer?
Remove Guzzle from the included package - this is the simplest one, my problem with this is that if I remove this dependency where does it stop, whats to say any other dependencies wont clash later down the line that cant be removed?
Can check version of Guzzle in package and swap calls dependent on which one loads - similarly to the issue above I can hack a fix in to determine which type of call I should be using for this bug, but I cant tell what other issues this may raise and my code may end up littered with statements for each version.
Manually Change the namespaces of guzzle in the plugin. So I can go into the vendor folder of my package and force a specific namespace for the package, I am guessing this will solve my issue, but I am losing the point of installing a re-usable package.
Fork Guzzle and refer to that version. I could fork guzzle and include it as a VCS package in the plugin. Issue here being that I then have to keep that maintained moving forward.
The easiest way is to choose an alternative package for guzzle, but this might not be best for you.
Pros
You save a lot of time
Cons
You use different package to do the same thing.
The moderate way is to fork guzzle, and then you manually change the namespaces.
Pros
You don't change anything in Prestashop.
If Prestashop upgraded to guzzle 6.0, you could easily switch to it.
Cons
You have to maintain your own customized guzzle.
The hardest way is to patch Prestashop yourself
Pros
You get everything you want.
Send a pull request, you might help a lot of others.
Cons
If Prestashop kept using guzzlehttp 5.0, you end up in a patching nightmare.
Conclusions
I would choose the moderate way if I must use guzzle. If I just wanted to do something special in a few lines of code, I would just use an alternative package. And NO you cannot install different versions of the same package by composer.
Short answer: there's nothing you can do.
Long answer: I sort of found a workaround to your issue, given that I am in the same situation.
If your module depends on a package that depends on Guzzle, and if that package is under your control, you could make your package use HTTPlug. It is an abstraction and it relies on someone else include an actual HTTP client library. That someone could also be you, including a different implementation of php-http/client-implementation.
Over time, as Prestashop might also use this approach (along with other platforms), all of them might end up relying on PSR-7 abstractions of HTTP messages.
It's not really a solution to your current issue, but rather a strategy for the long run, which can also help with where you are right now.
You got two solutions:
Find a version of your package that uses GuzzleHttp 5 (if available).
Find an alternative of your package.
And NOT RECOMMENDED solution:
To change the namespace of Guzzle in your package and installed guzzle 6 too.
(example: use GuzzleHttp\ => 'use GuzzleHttpSix\')
This happens cause there is a conflict in namespace used (witch is the same for guzzle 5 & 6). And Prestashop gives priority to its packages.
The question does not specify what the main goal is. If your main goal is to update Prestashop (and not to solve the specific error), then I suggest that you create a local installation of the Prestashop environment - and use this to update your production environment manually, file-by-file. I can be done in the following way:
Create a fresh Prestashop installation in the intended version (1.7.5?) on your local computer (use a new database). Composer will ensure that the two installations use the same dependencies.
Backup your production database, and restore it on a local database server.
Reconfigure the local Prestashop to talk to local database.
Upgrade the local Prestashop. Check that this updated installation works.
Compare the local installation with the remote installation using a diff tool (for instance, Beyond Compare). Any differences between the two installations needs to be handled case-by-case:
Copy new / updated code from the local installation to the remote installation.
Remove any obsolete files from the remote installation.
Update the production database.
Remember to make a backup of the software and database before you begin.
You can just use "guzzlehttp/guzzle": "~5.0", in your module composer.json file and you the same version which uses prestashop.
I would like to test Intervention Image. It looks like a nice package. The installation instructions say:
The best way to install Intervention Image is quickly and easily with
Composer.
The sentence above implies there's also a inferior, slower and difficult, way to install it. I assume the author is referring to an installation without Composer? That is exactly what I am looking for!
However, I am unable to find a way to do that. I have looked for an autoloader file, or even any autoload call in the code. There's none. No documentation either. It seems that only an installation with Composer is supported in a meaningful way.
Has anybody of you tried to use Intervention Image without resorting to Composer?
The way without composer is simply to fetch the source from github, move it in one off your vendor directories and load all needed files.
As there's no autoload file provided inside the package, you have to extend your own autoload script or register a new autoload handler, as including each required file is a really annyoing task.
If you take a deeper look inside the composer.json file, you may notice inside the require section, that this package also need Guzzle. If you want to install Guzzle, you will again read the sentence "The recommended way to install Guzzle is through Composer". So you have to do the same thing again for Guzzle. This time you need the other two Guzzle dependencies psr7 and promises....
At this point, I hope you build your autoloader robust enough to simply add only a new mapping from namespace prefix to path, as their might be many other required packages.
If you don't want to include composer directly inside your project, for what reasons ever, you could also create a empty composer project, just for managing the dependencies and the autoloader. That might be easier to do everything by hand.
Note: If you are lucky, you could use the Intervention/Image package
without the guzzle dependency.
I'm a bit confused about using Composer.
I have built my own package manager, that uses a config-file and a large SVN-repo that contains all possible libraries (both PHP and Javascript / CSS) I need in several different projects. I download these packages myself from the library websites.
Now I'm trying to use Composer instead, since I like the automatic dependency checking and want to use something that everybody else does. But how do you decide what packages are best?
For example, for CodeMirror, I used to download the latest stable version from https://codemirror.net/ . But when I look in Packagist I see so many different versions that I don't know which to choose. It seems everybody can create new packages for Composer ? I just need the official ones.
So, how do you guys pick the packages you need?
To answer your question directly, for any component you want to import into your project, the way to find the "canonical" source - as opposed to various forks - is to go back to the original source and see what their usage/install instructions suggest. If they support a Packagist-based install, they will usually say so. If not, but there is a composer.json in their (typically) Github repository, then you can add the repository to your composer.json and then require the package as normal.
However, more generally, I think there is some confusion about what Composer really does. As noted in the comments, Composer is a dependency manager for PHP. Packagist is the primary repository for composer-managed packages. The CodeMirror library you cited is fundamentally a javascript library.
Now it's true that if you search for "codemirror" on Packagist, you will see lots of results there, some of which are labeled as Javascript components. But they are primarily:
wrappers that allow consumers to interact with or simply load CodeMirror in PHP-based view-scripts, like conquer/codemirror for the Yii framework, or nitrado/code-mirror-bundle for the Symfony framework; or
shim repositories for the Components project - like components/jquery, for example - which are then installed using the command-line script from their Component Installer for Composer
Bottom line: Composer is primarily used for importing PHP packages. It takes some gymnastics - like the Component Installer for Composer noted above - to make it usable/helpful for non-PHP packages.
I am using the Composer package Omnipay in my project and I want to add a new class to the package (in my case it is support for a new payment gateway). The naming does not conflict with anything and it follows the same naming and structure conventions as sibling folders. However, when I run composer update it deletes my whole folder of changes even though it didn't need to. Is there a way I can tell composer not to delete that directory?
Leave everything under /vendor alone, don't change any files there. You should treat libraries as external dependencies - don't check them into source control or change them in any way. Just reference them in your own code.
If you need to customize a composer library, you can either work around it in your own code (most PHP libraries support dependency injection, which will let you override any of the libraries' classes), or alternatively you can fork the library on github, then reference your own fork in composer.json, or submit the pull request so everyone can benefit from it.
As far as I'm aware, you cannot add to a Composer package as it is external and therefore out of your control. You should treat the packages as libraries only, and add all classes into your own project, ensuring that the packages you need are still set up in your .json file