Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strategy to override a class in a library installed with Composer

I am using Codeigniter and Composer. One of the requirements is PHPExcel. Now I need to change a function in one of the classes. What should be the best strategy to do it? Should I change the code in the vendor folder? If so, how to maintain the change across all the instances? If not how do I override that particular class. Though I mention PHPExcel I would like a generic solution.

I am not sure if this is the right forum for this question. If not i will remove this. Please let me know if any more details are needed.

Thank You.

like image 833
SNAG Avatar asked Jan 23 '15 06:01

SNAG


People also ask

What is Classmap in composer json?

This map is built by scanning for classes in all . php and . inc files in the given directories/files. You can use the classmap generation support to define autoloading for all libraries that do not follow PSR-0/4. To configure this you specify all directories or files to search for classes.

What is PSR 4 in laravel?

This PSR describes a specification for autoloading classes from file paths. It is fully interoperable, and can be used in addition to any other autoloading specification, including PSR-0. This PSR also describes where to place files that will be autoloaded according to the specification.

How do I update a composer package?

To update your packagesNavigate to the root of your git repo, where your composer. json file is. Run composer update (on your local machine) to update the required packages and re-generate a composer.


3 Answers

In composer.json, under ["autoload"]["psr-4"], add an entry with namespace as the key and path as the value:

{
     "autoload": {

         "psr-4": {

             "BuggyVendor\\Namespace\\": "myfixes/BuggyVendor/Namespace"
         }
     }
}

Copy files you want to override under that path (keeping sub-namespace directory structure) and edit them there. They will be picked in preference to the library package's original "classpath". It would seem that namespace->path mappings added to composer.json in this manner are considered before those added by required packages. Note: I just tried it and it worked, though I don't know if it is an intended feature or what possible gotchas are.

EDIT: found a gotcha. Sometimes when you subsequently require another package with composer require vendor/package, you will "lose" the override. If this happens, you must issue composer dump-autoload manually. This will restore the correct autoload order honoring your override.

like image 105
Szczepan Hołyszewski Avatar answered Nov 06 '22 07:11

Szczepan Hołyszewski


Adding these last 2 lines to the autoload section of my composer.json is what worked for me when I wanted to override just one file within the vendors directory:

"autoload": {        
    "classmap": [
        "database"
    ],
    "psr-4": {
        "App\\": "app/"
    },
    "exclude-from-classmap": ["vendor/somepackagehere/blah/Something.php"],
    "files": ["app/Overrides/Something.php"]
},

Remember that the namespace within app/Overrides/Something.php needs to match whatever the original was in vendor/somepackagehere/blah/Something.php.

Remember to run composer dump-autoload after editing the composer.json.

Docs: https://getcomposer.org/doc/04-schema.md#files

like image 25
Ryan Avatar answered Nov 06 '22 07:11

Ryan


There is one more option. In case you need to rewrite the only class you can use files in composer.json like this

 "autoload": {
     "files": ["path/to/rewritten/Class.php"]
  }

So if you want to rewrite class Some\Namespace\MyClass put it like this

#path/to/rewritten/Class.php

namespace Some\Namespace;

class MyClass {
  #do whatever you want here
}

Upon each request composer will load that file into memory, so when it comes to use Some\Namespace\MyClass - implementation from path/to/rewritten/Class.php will be used.

like image 33
Albert Tobac Avatar answered Nov 06 '22 07:11

Albert Tobac