typisttech / imposter-plugin

Composer plugin that wraps all composer vendor packages inside your own namespace. Intended for WordPress plugins.
https://www.typist.tech/projects/imposter-plugin
MIT License
146 stars 11 forks source link

Issues with Guzzle (PSR4 transforming) #39

Closed Wouter0100 closed 6 years ago

Wouter0100 commented 6 years ago

Detailed description

I'm maintining a wide variaty of WHMCS modules. Recently WHMCS seems to started using Composer in their own, closed source, software - which conflicts with my modules. Since them I'm looking for such a plugin as Imposter to fix my dependency issues.

Most things seems to work just fine, expect with Guzzle and loading PSR-4 classes.

For example a trace I gathered. Here the core WHMCS software requests Guzzle, and the autoloader seems to respond with my transformed Guzzle instance:

1  Composer\Autoload\includeFile(/var/www/*/app/modules/addons/mollierecurring/vendor/composer/../guzzlehttp/guzzle/src/ClientInterface.php) called at [/var/www/*/app/vendor/composer/ClassLoader.php:322]
--
  | #2  Composer\Autoload\ClassLoader->loadClass(DevApp\WHMCS\MollieRecurring\Vendor\GuzzleHttp\ClientInterface)
  | #3  spl_autoload_call(DevApp\WHMCS\MollieRecurring\Vendor\GuzzleHttp\ClientInterface) called at [/var/www/*/app/modules/addons/mollierecurring/vendor/guzzlehttp/guzzle/src/Client.php:25]
  | #4  include(/var/www/*/app/modules/addons/mollierecurring/vendor/guzzlehttp/guzzle/src/Client.php) called at [/var/www/*/app/vendor/composer/ClassLoader.php:444]
  | #5  Composer\Autoload\includeFile(/var/www/*/app/modules/addons/mollierecurring/vendor/composer/../guzzlehttp/guzzle/src/Client.php) called at [/var/www/*/app/vendor/composer/ClassLoader.php:322]
  | #6  Composer\Autoload\ClassLoader->loadClass(GuzzleHttp\Client)
  | #7  spl_autoload_call(GuzzleHttp\Client) called at [/var/www/*/app/vendor/whmcs/whmcs-foundation/lib/Admin/Setup/General/UriManagement/ConfigurationController.php:0]
  | #8  WHMCS\Admin\Setup\General\UriManagement\ConfigurationController->queryEnvironmentMode() called at [/var/www/*/app/vendor/whmcs/whmcs-foundation/lib/Admin/Setup/General/UriManagement/ConfigurationController.php:0]
  | #9  WHMCS\Admin\Setup\General\UriManagement\ConfigurationController->remoteDetectEnvironmentMode(WHMCS\Http\Message\ServerRequest Object ([*queryBag] => Symfony\Component\HttpFoundation\ParameterBag Object ([*parameters] => Array ()),[*requestBag] => Symfony\Component\HttpFoundation\ParameterBag Object ([*parameters] => Array ()),[*attributesBag] => Symfony\Component\HttpFoundation\ParameterBag Object ([*parameters] => Array ()),[Zend\Diactoros\ServerRequestattributes] => Array (),[Zend\Diactoros\ServerRequestcookieParams] => Array (),[Zend\Diactoros\ServerRequestparsedBody] => ,[Zend\Diactoros\ServerRequestqueryParams] => Array (),[Zend\Diactoros\ServerRequestserverParams] => Array (),[Zend\Diactoros\ServerRequestuploadedFiles] => Array (),[*headers] => Array (),[*headerNames] => Array (),[Zend\Diactoros\ServerRequestprotocol] => 1.1,[Zend\Diactoros\ServerRequeststream] => Zend\Diactoros\PhpInputStream Object ([Zend\Diactoros\PhpInputStreamcache] => ,[Zend\Diactoros\PhpInputStreamreachedEof] => ,[*resource] => Resource id #361,[*stream] => php://input),[Zend\Diactoros\ServerRequestmethod] => ,[Zend\Diactoros\ServerRequestrequestTarget] => ,[Zend\Diactoros\ServerRequesturi] => Zend\Diactoros\Uri Object ([*allowedSchemes] => Array ([http] => 80,[https] => 443),[Zend\Diactoros\Urischeme] => ,[Zend\Diactoros\UriuserInfo] => ,[Zend\Diactoros\Urihost] => ,[Zend\Diactoros\Uriport] => ,[Zend\Diactoros\Uripath] => ,[Zend\Diactoros\Uriquery] => ,[Zend\Diactoros\Urifragment] => ,[Zend\Diactoros\UriuriString] => ))) called at [/var/www/*/app/vendor/whmcs/whmcs-foundation/lib/Admin/Setup/General/UriManagement/View/Helper/SimpleSetting.php:0]
  | #10 WHMCS\Admin\Setup\General\UriManagement\View\Helper\SimpleSetting->getSimpleSettingHtmlPartial() called at [/var/www/*/app/admin/configgeneral.php:0]

This results in either incompatbility or Cannot declare class DevApp\WHMCS\MollieRecurring\Vendor\GuzzleHttp\Client, because the name is already in use in /var/www/*/app/modules/addons/mollierecurring/vendor/guzzlehttp/guzzle/src/Client.php on line 25-errors.

Also - the autoloading files for Guzzle does not work. This because Guzzle includes this file, which checks if GuzzleHttp\uri_template is loaded - but most of the time it is (because of the core software, which already has Guzzle loaded) and so my namespace's Guzzle functions won't get loaded.

WHMCS loads Composer itself and I'm not sure how their composer.json looks like. Mine is, for example:

{
    "require": {
        "mollie/mollie-api-php": "2.0.*",
        "typisttech/imposter-plugin": "^0.3.0"
    },
    "config": {
        "vendor-dir": "src/addons/mollierecurring/vendor"
    },
    "extra": {
        "imposter": {
            "namespace": "DevApp\\WHMCS\\MollieRecurring\\Vendor\\"
        }
    }
}

Context

It is important to me to keep using my current packages (I don't use guzzle directly, but most of my packages do). This could also benefit other people, as Guzzle is a widely used package to handle HTTP requests.

Possible implementation

Unsure. Maybe manually update the PSR-4 mapping?

Your environment

tangrufus commented 6 years ago

WHMCS loads Composer itself and I'm not sure how their composer.json looks like.

If 2 composer.json files in place, imposter won't and should not affects the other one, i.e: the WHMCS' composer.json.


Besides, the way Guzzle includes src/functions.php is not supported:

if (!function_exists('GuzzleHttp\uri_template')) {
    require __DIR__ . '/functions.php';
}

This if/else condition is kind of custom autoloader. So far, imposter supports composer autoloaders only. Pull requests are welcomed.


Both the above issues stop you from using imposter. Perhaps, using WHMCS's Guzzle is the simplest solution.

Wouter0100 commented 6 years ago

Darn - thanks for the fast reply. Unfortunately, I hoped Imposter was a solution for having multiple composer autoloaders and multiple composer.json files. WHMCS does not allow me to edit or manage theirs (and is not even shipped in the source).

So my modules manage their own composer.json where I added Imposter. Unfortunately using WHMCS's Guzzle isn't really possible - as my own dependencies use Guzzle, and as far as I know I can't "flag" Guzzle in my composer.json manually as installed.

tangrufus commented 6 years ago

After a second thought, the first issue is incorrect. You usage is similar to the project goal - make 2 WordPress plugins bundle their composer packages without conflicts.

However, imposter can't be used on custom autoloaders(issue 2).

I can't "flag" Guzzle in my composer.json manually as installed.

One thing you could try is to use branch aliases - alias a "fake", "empty" package as guzzle.

See: https://getcomposer.org/doc/articles/aliases.md

Wouter0100 commented 6 years ago

Hmm - thanks for your response. After my reply I further continued searching and eventually found PHP Scoper, which does the same - but on a more aggressive level.

With some custom code and an additional script to change package ID's in autoload_files.php, I got things working and isolated.