mardi 1 août 2017

extend composer packages without extending each class

I am at the point of creating my first composer package. This package, which would offer the same functionality as an existing package, with mostly some additional functionality specific to my package. Next to my own classes, all of the classes from the Vendor package still need to be accessible, but from my package's namespace. Some Vendor classes will need some adjustments, but nothing major.

Let's look at a simple example. The vendor package has a few classes, Foo and Bar, that live in the namespace Vendor\Package.

<?php

namespace Vendor\Package;

class Foo // class needs adjustments/addition
{
   private $vendorVar;

   public function fooFunction() // function is fine as it is
   {
      return 'Vendor Foo output';
   }

   public function anotherFooFunction() // function should do some additional things
   {
      $this->vendorVar = 'Vendor!';
   }
}

and

<?php

namespace Vendor\Package;

class Bar // class is fine as it is
{
   public function barFunction() // function is fine as it is
   {
      return 'Vendor Bar output';
   }
}

Since I would like to add some additional functionality and change existing once for class Foo, I inherit the vendor one as such:

<?php

namespace Me\MyPackage;

use Vendor\Package\Foo as vendorFoo;

class Foo extends vendorFoo 
{
   private $myVar;

   public function myFooFunction() // additional function to the Foo class
      {
      return 'My Foo output';
   }

   public function anotherFooFunction() // change the functionality for this function
   {
      $this->myVar = 'Me!';
      parent::anotherFooFunction();
   }
}

Now I can do the following:

<?php

use Me\MyPackage\Foo;

$foo = new Foo();

echo $foo->myFooFunction(); // output: 'My Foo output'
echo $foo->fooFunction(); // output: 'Vendor Foo output'
$foo->anotherFooFunction; // will set $vendorVar and $myVar

Since I don't want that the users need to know about the Vendor package, I want them to have access to all other functionality of the Vendor package, but via my own namespace. Basically they need to be able to do something like

<?php

use Me\MyPackage\Bar;

$bar = new Bar();

echo $bar->barFunction(); // output: 'Vendor Bar output'

I assume that I can simply add the following code in my package.

<?php

namespace Me\MyPackage;

use Vendor\Package\Bar as vendorBar;

class Bar extends vendorBar {} // Do I have to add this for each class I want to use from my namespace?

When the Vendor package has many classes and I only want to touch one, this seems overkill to me. Is this the only/best way to go on about this, or are there other/better ways?

Additional information:

  • I am using the Laravel framework, but I guess this shouldn't matter much.
  • Forking doesn't seem like a good idea. When for example small changes in the Vendor package have been made, e.g. a security fix, I would have to rewrite my code. I am going to assume that the class structure of the Vendor package is not going to change very quickly.
  • This would be an extension of the original Vendor package, and therefor it would not be appropriate to add a pull request.
  • I tried to work with a simple example, but for those interested, I would like to extend the laravel\passport package. This question is a followup of the following one: Add or adjust functionality of installed packages
  • Additional question, how do major packages go around this? For example, how does Laravel use the Symphony functionality throughout its framework?


via Chebli Mohamed

Aucun commentaire:

Enregistrer un commentaire