Safely edit a third party composer (vendor) package in Laravel & prevent losing customized changes on release of a new version of the package

13,218

Solution 1

It actually isn't safe to edit composer packages, for the very reason you point out.

What I do is extends the classes that I want/need to change.

I have done it here with the Filesystem class. It doesn't ensure that it won't break, but it does let you update without overwriting your changes.

config/app.php

<?php

return [

    'providers' => [

//        'Illuminate\Filesystem\FilesystemServiceProvider',
        'MyApp\Filesystem\FilesystemServiceProvider',
    ],

    'aliases' => [
        ...
    ],

];

MyApp\Filesystem\FilesystemServiceProvider.php

<?php namespace MyApp\Filesystem;

use Config;
use Storage;
use League\Flysystem\Filesystem;
use Dropbox\Client as DropboxClient;
use League\Flysystem\Dropbox\DropboxAdapter;
use Illuminate\Filesystem\FilesystemManager as LaravelFilesystemManager;

class FilesystemManager extends LaravelFilesystemManager{

    public function createDropboxDriver(array $config)
    {
        $client = new DropboxClient($config['token'], $config['app']);

        return $this->adapt(
            new Filesystem(new DropboxAdapter($client))
        );
    }
}

Solution 2

The simple, fast and safe method:

  1. Create a directory in the Laravel's root directory and name it packages or whatever you like.
  2. Move the modified package from vendor directory to your packages directory.
  3. Update composer.json to load the package from your packages directory instead of vendor directory.

first remove it from require

"require": {
    "php": ">=5.6.4",
    "laravel/framework": "5.3.*",
    "laravelcollective/html": "^5.3.0", <==== remove this line                           
    "barryvdh/laravel-debugbar": "^2.3",
    "doctrine/dbal": "^2.5"
},

and then add it to autoload

"autoload": {
    "psr-4": {
        "App\\": "app/",
        "Collective\\Html\\": "packages/laravelcollective/html/src", <==== add this line
    },
}

Please do not forget to run

composer dumpauto

Alternative for step 3.

There is also a new alternative if you're using latest version of composer.

Add this to you composer.json

"repositories": [
    {
        "type": "path",
        "url": "./packages/laravelcollective"
    }
]

And then modify the version of package to dev-master

"require": {
    "php": ">=5.6.4",
    "laravel/framework": "5.3.*",
    "laravelcollective/html": "dev-master", <==== this line                           
    "barryvdh/laravel-debugbar": "^2.3",
    "doctrine/dbal": "^2.5"
},

Finally

composer update

Solution 3

if you want to keep your changes AND update the package from the original repo at the same time, you can fork this package and point composer to pull from your fork, not the original repo.

All you have to do is add your fork as a repository and update the version constraint to point to your custom branch. Your custom branch name must be prefixed with dev-.

update your composer.json file as follows:

{
    "repositories": [
        {
            "type": "vcs",
            "url": "https://github.com/MyGithub/html"
        }
    ],
    "require": {
        "laravelcollective/html": "dev-bugfix"
    }
}

Note that you don't change the require statement except to specify your bugfix branch. You still reference the upstream package (laravelcollective/html), not your personal fork (MyGithub/html).

also, note that dev- is automatically added so branch name is bugfix not dev-bugfix. if you named your branch as dev-bugfix you will require it as dev-dev-bugfix.

Solution 4

If you want to make changes to a class of a package you have to

  1. Create a class that extends the package class and make your changes

  2. Create a service provider that extends the service provider of the class and change the registerBinding class to bind your extended class

  3. Put that new service provider in providersarray in config\app

  4. Disable package discovery for this package, you may list the package name in the extra section of your application's composer.json file:

    "extra": {
        "laravel": {
            "dont-discover": [
                "barryvdh/laravel-debugbar"
            ]
        }
    }, 
    
Share:
13,218

Related videos on Youtube

TimothyBuktu
Author by

TimothyBuktu

PHP, Javascript, HTML, CSS

Updated on September 15, 2022

Comments

  • TimothyBuktu
    TimothyBuktu over 1 year

    I want to edit a package I pulled from composer in my Laravel 5 project, however i believe that if I ran composer update and a new version of this package has been released, I will lose all of my changes. How should I go about editing the package? Is there a way to copy package out of the vendor directory so I can use it somewhere else in my project?

  • TimothyBuktu
    TimothyBuktu almost 9 years
    Thanks for the answer. In this method would I have to change the namespace in each class to "MyApp" or would it be better to remove the the original package from my composer.json after I've copied it?
  • whoacowboy
    whoacowboy almost 9 years
    It depends on how much of the package you need to alter. For what I did, I only needed to update 2 classes, so I just pulled those two classes into my namespace, and made the adjustments. I left the original classes intact, and refer to the updated classes in my app. If it is extensive, you could always fork the repo on github and make your updates there. That way when there is a change it would give you time to update your code.
  • Matthew Brown
    Matthew Brown almost 9 years
    I usually fork the repo and reference my forked repository in my composer.json file under repositories section. Downside being you won't get updates when said package gets updated.
  • sinaza
    sinaza almost 4 years
    When you're addressing the package e.g., Collective\\Html\\ make sure you check the package's composer.json and match your address with it. There might be more than one namespace that has to be addressed.
  • Sjaak Wish
    Sjaak Wish almost 4 years
    Also take not that you are not using the composer file of the package. There might be auto loading for laravel in the package like this: code "extra": { "laravel": { "providers": [ "Company\\Package" ] } } Make sure to add the package in /config/app.php => 'providers' array
  • Kevin Chavez
    Kevin Chavez over 2 years
    just wondering this is still valid for Laravel 8.x right?
  • whoacowboy
    whoacowboy over 2 years
    @KevinChavez It is still working for me on 8.32.1