Paulund
2020-07-05 #laravel

Extending Laravel With Macros

Laravel makes development easier with a load of helpful functionality you can use in your applications. But has there ever been a situation where it doesn't quite do what you want?

There's a trait in the Laravel code base called Macroable. There's not much documentation on this trait but it allows you extend any class that's using this trait.

The macroable trait allows you to add a new method into the class at runtime to use throughout your application.

For example the \Illuminate\Support\Collection class is macroable and will allow you to add a new method into the class.

Collection::macro('hello', function($name) {
   echo 'Hello ' . $name;
});

Collection::hello('John'); // Outputs "Hello John"

These macros should be defined in the boot method of the AppServiceProvider.

class AppServiceProvider
{
    public function boot()
    {
        Collection::macro('hello', function () {
            echo 'Hello ' . $name;
        }
    }

You could even create your own MacroServiceProvider and add this to the config/app.php file to have a new service provider just for your macros.

What Objects Are Macroable

  • Illuminate\Auth\RequestGuard
  • Illuminate\Auth\SessionGuard
  • Illuminate\Cache\Repository
  • Illuminate\Console\Command
  • Illuminate\Console\Scheduling\Event
  • Illuminate\Console\Scheduling\Schedule
  • Illuminate\Cookie\CookieJar
  • Illuminate\Database\Grammar
  • Illuminate\Database\Eloquent\FactoryBuilder
  • Illuminate\Database\Eloquent\Relations\Relation
  • \Illuminate\Database\Query\Builder
  • \Illuminate\Database\Schema\Blueprint
  • \Illuminate\Events\Dispatcher
  • \Illuminate\Filesystem\Filesystem
  • \Illuminate\Http\Request
  • \Illuminate\Http\Response
  • \Illuminate\Http\Client\Factory
  • \Illuminate\Http\Client\Response
  • \Illuminate\Mail\Mailer
  • \Illuminate\Redis\Connections\Connection
  • \Illuminate\Routing\Redirector
  • \Illuminate\Routing\Route
  • \Illuminate\Routing\Router
  • \Illuminate\Routing\UrlGenerator
  • \Illuminate\Support\Arr
  • \Illuminate\Support\Collection
  • \Illuminate\Support\LazyCollection
  • \Illuminate\Support\Optional
  • \Illuminate\Support\Str
  • \Illuminate\Support\Stringable
  • \Illuminate\Support\Testing\Fakes\NotificationFake
  • \Illuminate\Testing\TestResponse
  • \Illuminate\Translation\Translator
  • \Illuminate\Validation\Rule
  • \Illuminate\View\Factory
  • \Illuminate\View\View

As you can see the marcoable trait is used throughout the framework making it easy to extend Laravel functionality in many different places.

If you find yourself creating duplicate logic through your codebase when using these classes maybe consider using a macro to extend the class instead.

Mixin Classes

There's another way of defining macro methods in Laravel and it's called Mixin classes. These are classes that can be merged into a class that has the macroable trait.

class CarbonMixin
{
   // extra helper functions for carbon
}

Then you can merge these into Carbon by using the following the the boot method of your application.

Carbon::mixin(new CarbonMixin());

This way allows you to keep all class specific methods in their own file.

Laravel macros are a great feature you should try to help clean up your codebase.