Prestashop Guzzle Conflict - php

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.

Related

Same composer package in 2 different WordPress plugins

We have developed 2 WordPress plugins which are using same composer package.
Depending on plugin versions the package included in plugin may be changed, we constantly add new functionality to our package.
The problem is that for example plugin A have version 1.0.0 of package, and plugin B have version 1.0.1, WordPress loads only one package , from plugin which loaded first, so if plugin A loaded first then plugin B will use version 1.0.0 package.
We are including autoload.php on both plugins.
Is it possible to do some configuration in WordPress or from composer side to make every plugin load and work with package included on his vendor folder ?
Is it possible to do some configuration in WordPress or from composer side to make every plugin load and work with package included on his vendor folder ?
In general no. The option about namespace rewriting has already been given by Chris Haas, so if you need to rely on different code behind the same global static names, you have to provide a different name for each version.
Another option is you align both plugins to rely on the same dependency version-stability. The example you give with 1.0.0 and 1.0.1 versions, the API should be compatible and it should not be an issue (if the package follows semantic versioning).
From the context of your question, it seems the dependency has not yet matured enough that this is an option practically.
Instead it should be possible to have the plugin which is currently based on 1.0.0 to use 1.0.1 as well. Then the version conflict is solved, as now it is the same version and can use the same names. This may not be an ideal solution, but could get you back to a working version fast and gives you more room to consider a better way in the future (e.g. having a build for those plugins that use scoping).
Additionally you could/should wrap all access to third-party libraries once in your own code so that such problems aren't that deep reaching (dependency issues tend to be harder to resolve). This methodology is independent to Wordpress or Composer, just a recommendation on how to interface to third-party dependencies (or even Wordpress itself[1], which you may know better).
If however what you ask here is already such a wrapper you build your own (e.g. in form of a composer package), consider to adhere to semantic versioning and stabilize its API first.
PHP has no built-in utility to create archives apart from PHAR, e.g. that you can have imports via names but to different code. This is likely also the reason why Composer does not support it and instead provides PSR-0/PSR-4, classmap and file inclusion autoload configuration.
As you have the scenario to share the same namespaces across the plugins - there is no other option actually as it runs in the same PHP process - the first one wins. You may however make your own plugins interoperable so that they can establish a loading order in their own hierarchy, e.g. to prefix the one autoloader before the other conditionally if it exists.
I'd probably go with scoping in the first place and only share build utilities between the plugins nowadays and have a nice package for each plugin afterwards. Yes, scoping can be PITA, but if you have this early on, you don't have to solve this later which is much harder.
Compare for the level of WordPress plugins WordPress Plugin: How do I avoid "tight coupling"? and Multiple Custom Metabox Help - both well dated so it is easier to not take code verbatim but to develop own conclusions.

Prestashop 1.6, conflict: 2 different modules requiring same class, different versions

In my Prestashop project, I have several modules. In one of them (let's call it "AWS") I installed AWS SDK using composer (in PHPStorm), as explained here. Composer has "required", among other libraries, "guzzlehttp", updated to its final version.
On the other hand, there is another module (let's call it "orangeConnect") with composer too, that has an earlier version of "guzzlehttp".
The problem lies when I am using AWS SDK in php, inside a php script in the first module. What happens is that it tries to call the URI Composer class and it crashes. Actually, because of the inexistence of one class "UriResolver". The thing is that if I remove "orangeConnect" then AWS SDK connect correctly, which means that the class Uri, in "AWS" is not taken correctly because of "orangeConnect" module. However, I need imperatively to support "orangeConnect" in the project.
How can I, in summary, solve this conflict between classes in PHP inside Prestashop and allow each module to include the corresponding valid version of guzzleHttp without conflicts of any kind?
Thank you.
If the official maintainer of orangeConnect module doesn't upgrade the code, there are only 3 methods you can take:
Method 1: You can maintain a copy of your own orangeConnect code, and upgrade to latest Guzzle. Usually it won't be to difficult because Guzzle's interface are well designed.
Method 2: Get the old Guzzle's code and put it into a new namespace (eg: OldGuzzle) and make orangeConnect use OldGuzzle namespace. You can achieve this by do a global regex replace simply.
Method 3: (Only for big systems) Divide your PHP application to micro-service modules, and isolate orangeConnect and AWS SDK and make them use different Guzzle.

WordPress plugin + Composer?

I'm making WordPress plugin that is using a few third party libraries. Is it common practice to use Composer for WordPress plugin?
If it's okay to use it, then I assume that I should provide all Composer files along with my plugin, because I don't want to make people manually run composer install.
Another question is, is it safe to use Composer's autoloading? I configured it to autoload my own classes and the libraries are of course autoloaded as well. That's convenient.
Is using Composer with WordPress plugin an overhead? Or does it have any additional issues?
This is old question, but nothing has changed since 3 years. Using Composer for requiring dependencies in WordPress plugin/themes is usually a bad idea. PHP does not allow to load more than one class with the same FQN. So if two different plugins will install the same library independently, classes from random installation of library will be loaded which may result really weird bugs (especially if these are different versions of the same library). To avoid such problems you should have only one composer.json instance per project, so in this case Composer should be run at WordPress level.
In general if you have the same package installed multiple times, you probably will get some troubles (and this will happen if every plugin maintainer will use Composer on its own). Note that this is not directly related to Composer - if you copy libraries manually you will get exactly the same problem (maybe even worse).
If you really want to use Composer in your plugin you may try tools like humbug/php-scoper which will modify namespaces of used dependencies and make them unique.

Using Composer, can dependencies be shared between multiple projects?

First of all, I'm a complete newbie to Composer. I've been trying it out since it's a sounds awesome and mainly because Zend Framework 2 uses it.
Zend Framework 2 is actually also the reason for this thread.
It get the basics of Composer. But with my current server setup I have a request, which I can't seem to figure out if possible.
Let me explain.
I have multiple Zend Framework 2 projects:
/home/morten/sites/Project-1/
/home/morten/sites/Project-2/
/home/morten/sites/Project-3/
All of these projects should be running ZF2. When running composer in each project - each of them get their own separate download of the ZF2 Library files. Which is a bit redundant with my setup.
I have a complete and up-to-date download of ZF2 Library located at:
/var/www/shared/Zend/
And my php.ini has that path added to PHP's include_path, so the whole ZF2 library is available for all the three projects.
IS IT POSSIBLE to make Composer use in it's setup. Because if I try to change stuff and try things out in the composer files, then it just re-downloads Zend because it's a required component for other modules.
Can this be done? And if yes, how can I do it?
Hope I have explained myself good enough for you guys to understand what I'm trying to do and want :)
Thanks a lot in advance!
Regards,
Morten
You might be able to have one composer.json file stored in /var/www/shared/Zend, where you would put your dependencies and use Composer do manage them. Then all projects could include the same autoloader.
However, I wouldn't recommend that approach:
Your project's dependencies (composer.json) should be stored with your project. If you want to install your project somewhere else (for instance if you want to move one project to another server), you are missing the composer.json to install the required dependencies.
It will not be possible to update the dependencies of one project, without updating the dependencies of all other projects. If you want to introduce a new feature in Project 1, which requires a new version of a certain dependency, all other projects will get this new version as well - which might introduce backward compatibility breaks if an older feature that Project 2 relies on, is no longer supported. Since you can only have one version of each dependency, it is not possible for two projects to have different versions of the same dependency.
This approach might be useful if all projects will have the exact same functionality and code, but in that case you should probably merge them into one project.
In all other cases, I would suggest to use Composer the way it's supposed to be used: give all projects their own composer.json file and let Composer download the dependencies per project, in each project's vendor directory. The downside is that it'll cost you a little more disk space, but you'll get a lot of flexibility for it in return.

What's the best way to develop a library using composer?

We're starting a new project, and we're managing dependencies with Composer. We'll probably build our app on top of Laravel 4. But we'll also create our own library, which we will use for all our next projects, not just this one.
So, we have this terrible doubt: what's the best way to develop a library using composer?
If we list that new library as a dependency, every time we modify it we will have to commit the change to the repository and then call composer update.
That seems terrible!
Is there a better way to do that?
I think there are two ways to handle this, which I use depending on the case:
The library is a pure library, which is standalone, fully tested, and develop it using TDD to ensure that it all works. That way it can be used with the "commit, update" cycle you described just fine I think.
You are developing a plugin or something that must be integrated in something else (application/framework) and testing it standalone is more difficult, or you are developing it very tightly with your application. In this case require the dev-master version of the library so Composer installs it with a git clone (if it was already installed as a tag you will have to rm -rf vendor/your/library to force a reinstall as opposed to an update). You can also force this for tagged releases using the --prefer-source flag. Then once you have a clone in the vendor dir you can very easily work directly in there. If you do work in a team though you will still need to do this commit and then update to make sure the others get the latest version.
The third alternative is to just develop the code in the src/ directory of your application until it is mostly stabilized and then you can extract it as a new package and add it back as a dependency, then fall back on the first two ways I described because it will then be a lot more viable.
If you set the dependency to the repository master branch instead of a packaged distribution file, Composer will check out a working copy into the vendors folder. You can modify this working copy right in the vendors folder, as if it's part of the main project, but then commit it into its own repository. You'll indeed have to make sure to composer update after that to keep the composer.lock file in sync with the development of that library though.
It's still the more convenient way to develop a project in tandem with a dependency.
If you aim to develop a truly awesome library, then you should try to develop it independently of any other software you create.
It should fulfill one exact task only. And this probably is done after some commits, so the initial creation of the library should take only a week or two to come to a stable first version. And this version can be tagged and then used elsewhere.
When tagging, strictly try to follow semantic versioning - that way you can use the library with a version restriction like "~1.0", meaning at least version 1.0, but anything up to 1.9999 is acceptable, as long as it is not 2.0 (which would mean incompatible changes).
And then you really do not need to update any other software when you release a new version of the library. You only need to update if you want to include fixed bugs. Without bugfixes, you can update, but there is no need to do so immediately after the library's new version release.
Composer will take care of all the dependencies you need. The most important thing if you start a new library is to include the composer.json right from the start into the repository.
What if you really want to always include the newest release of the library in every other software you write? I'm not sure you realize the implications this has. It means that you are strictly binding your other software to the most recent library version. Break that version, or introduce a nasty bug, and all your software breaks. So being able to update or not actually is a feature. You will find that all foreign libraries you might use will follow the same release mechanism: They tag a new version if an important bug was fixed, or if a reasonable amount of new features was implemented. They do not wait for you to approve a new version - you have to approve THEIR new version in your software by explicitly updating to the most recent one. And the same should apply to an internal library.
Try to avoid fiddling with "dev-master" solutions mentioned here. They might work, but Composer works best if used with tagged versions. If you have a reasonably stable state of your library, tag it with "0.0.0" and include that version everywhere else instead of "dev-master". And then tag according to semantic version rules.

Categories