How do we rename composer package namespaces?

77 Views Asked by At

I have two modules (myModuleA and myModuleB) on a PrestaShop website that are using different version of the library phpoffice\phpspreadsheet. The problem is that when I call a method from phpoffice\phpspreadsheet in myModuleA, it's start using myModuleB phpoffice\phpspreadsheet method.

Example:

Call to a member function setActiveSheetIndex() on null

in modules/mymoduleb/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Worksheet.php (line 1439)

in modules/mymodulea/test.php (line 33).

Is it possible to rename namespace from phpoffice\phpspreadsheet ?

I want to use phpoffice\phpspreadsheet like so :

use MyModuleA\PhpOffice\PhpSpreadsheet\Spreadsheet; 

and

use MyModuleB\PhpOffice\PhpSpreadsheet\Spreadhsset; 
2

There are 2 best solutions below

1
Samuel Cook On

You wouldn't need to rename the namespaces, just use an alias:

use MyModuleA\PhpOffice\PhpSpreadsheet\Spreadsheet as module_a_spreadsheet;

use MyModuleB\PhpOffice\PhpSpreadsheet\Spreadsheet as module_b_spreadsheet;

Then you can use them independently:

module_a_spreadsheet::foo();

module_b_spreadsheet::foo();

More about aliasing: https://www.php.net/manual/en/language.namespaces.importing.php


Update - Based on your comment, it IS possible to create an alias for an entire namespace, but you would need to register the same new namespace alias for all additional classes that were called within the original class. You could use a combination spl_autoload_register and class_alias, but this seem like a huge waste in resource and a bit of overkill in my opinion. I haven't tested the code below, but I think it would be a good place to start:

spl_autoload_register(
    function( $class_name ){
        
        $original_namespace = 'PhpOffice';

        if( substr($class_name,  0, strlen($original_namespace) ) != $original_namespace ) {
            return;
        }

        $module_a_class = 'MyModuleA\\'.$class_name;
        $module_b_class = 'MyModuleB\\'.$class_name;

        class_alias($module_a_class, $class_name);
        class_alias($module_b_class, $class_name);

        $module_a_exists = class_exists($module_a_class );
        $module_b_exists = class_exists($module_b_class );
    },
    $throw = true,
    $prepend = false
);

I think the simplest solution is to just create a couple of variables and use those:

$module_a_spreadsheet = new PhpOffice\PhpSpreadsheet\Spreadsheet();
$module_b_spreadsheet = new PhpOffice\PhpSpreadsheet\Spreadsheet();
0
Krystian Podemski On

This is a common issue with the PrestaShop modules, where we don't have one composer.json, but all modules load their dependencies.

The solution could be to prefix all your vendors, there are some tools to help you do that:

https://github.com/humbug/php-scoper or PHP-Prefixer: https://github.com/PHP-Prefixer/hello-prestashop-world