Laravel Macros are a clean way to add pieces of functionality to classes you don’t own (core Laravel components) and re-use them in your projects. It was first introduced in the 4.2 version but it was only recently that I discovered the ability to define class-based macros. So, this is what this article is going to be about.
Macros can be defined on any class that makes use of the Macroable trait by simply calling the macro
method providing the required arguments:
Response::macro('macroName', function ($value) {
// code
});
Quick examples
In these two examples, we will be be looking at how we can add two macros at
and toPairs
to Laravel Collection class.
- “at” macro will help us retrieve an item at any given index:
Collection::macro('at', function ($index) {
return $this->slice($index, 1)->first();
});
# Usage
$collection = collect([1, 2, 3]);
$collection->at(0); // 1
- “toPairs” macro is used to transform a collection into an array with pairs:
Collection::macro('toPairs', function () {
return $this->keys()->map(function ($key) {
return [$key, $this->items[$key]];
});
});
# Usage
$collection = collect(['a' => 'b', 'c' => 'd', 'e' => 'f'])->toPairs();
$collection->toArray(); // returns ['a', 'b'], ['c', 'd'], ['e', 'f']
Note: if you are interested in implementing those macros in your app, consider checking this package.
Creating class-based macros
Generally, the default AppServiceProvider
is a perfectly fine place for defining your macros, but it can quickly become bloated. A better way is to put them within their own classes especially if they are related. Let’s take a look at how we can do that.
- Inside your
AppServiceProvider
boot method:
Collection::mixin(new CollectionMacros);
- Create the
CollectionMacros
class:
class CollectionMacros
{
/**
* Retrieve an item at any given index.
*
* @return \Closure
*/
public function at()
{
return function ($index) {
return $this->slice($index, 1)->first();
};
}
/**
* Transform a collection into an array with pairs.
*
* @return \Closure
*/
public function toPairs()
{
return function () {
return $this->keys()->map(function ($key) {
return [$key, $this->items[$key]];
});
};
}
}
Laravel will automatically scan the CollectionMacros
class and makes all the public and protected methods available as macros. Using this technique, our AppServiceProvider
is much cleaner now and our macros are grouped into one single class when they are related.