mehradsadeghi / laravel-decorator
Decorate and extend functionalities of methods without causing any break to the existing codebase.
Requires
- php: ^7.1
- laravel/framework: 5.*|6.*|7.*
Requires (Dev)
- orchestra/testbench: ^4.0
README
Decorate and extend functionalities of methods without causing any break to the existing codebase.
Installation
$ composer require mehradsadeghi/laravel-decorator
Usage
Assuming you have a class named Person
with a method named getFullName
which its inputs and output should get decorated:
class Person { public function makeFullName($firstName, $lastName) { return "$firstName $lastName"; } } $person = new Person(); $person->makeFullName('mehrad', 'sadeghi'); // mehrad sadeghi
When using decorator
without setting any decoration, The default behavior of makeFullName
method will remain the same:
decorate([Person::class, 'makeFullName'], ['mehrad', 'sadeghi']); // mehrad sadeghi
In order to decorate makeFullName
method:
$decorator = function ($callable) { return function (...$params) use ($callable) { // decorating the inputs foreach($params as $key => $param) { $params[$key] = trim($param); } // real call to makeFullName method $output = app()->call($callable, $params); // decorating the output $output = strtoupper($output); return $output; }; }; decorator([Person::class, 'makeFullName'])->set($decorator);
Note that the decorator
should be a valid PHP callable. So it can be a Closure
or an array callable, Which can be defined as follows:
class PersonDecorator { public function decorateFullName($callable) { return function (...$params) use ($callable) { // decorating the inputs foreach($params as $key => $param) { $params[$key] = trim($param); } // real call to makeFullName method $output = app()->call($callable, $params); // decorating the output $output = strtoupper($output); return $output; }; } } decorator([Person::class, 'makeFullName'])->set([PersonDecorator::class, 'decorateFullName']);
Now we've assigned our decorator to the makeFullName
method. Calling makeFullName
with decorate
helper function will apply its decoration:
decorate([Person::class, 'makeFullName'], [' mehrad ', ' sadeghi ']); // MEHRAD SADEGHI
Multiple Decorators
You can easily set multiple decorators on a method:
decorator([Person::class, 'makeFullName']) ->set(function($callable) { // decoration }) ->set(function($callable) { // decoration });
or
decorator([Person::class, 'makeFullName']) ->set([PersonDecorator::class, 'secondDecorator']) ->set([PersonDecorator::class, 'firstDecorator']);
Forgetting (Removing) Decorator(s)
You can easily remove one or all decorators assigned to a callable. From example above, Assume we have two decorators:
class PersonDecorator { public function decorateInput($callable) { return function (...$params) use ($callable) { // decorating the inputs foreach($params as $key => $param) { $params[$key] = trim($param); } // real call to makeFullName method $output = app()->call($callable, $params); return $output; }; } public function decorateOutput($callable) { return function (...$params) use ($callable) { // real call to makeFullName method $output = app()->call($callable, $params); // decorating the output $output = strtoupper($output); return $output; }; } } decorator([Person::class, 'makeFullName']) ->set([PersonDecorator::class, 'decorateInput']) ->set([PersonDecorator::class, 'decorateOutput']);
The output of calling decorate
would be:
decorate([Person::class, 'makeFullName'], [' mehrad ', ' sadeghi ']); // MEHRAD SADEGHI
Then for removing decorateOutput
:
decorator([Person::class, 'makeFullName']) ->forget([PersonDecorator::class, 'decorateOutput']);
And the output of calling decorate
would be:
decorate([Person::class, 'makeFullName'], [' mehrad ', ' sadeghi ']); // mehrad sadeghi
Note that for removing all decorations of a callable, just leave the forget
parameter empty:
decorator([Person::class, 'makeFullName'])->forget();