Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a macro in laravel Macroable

Tags:

php

laravel

please can anyone help me understand what a macro is in Laravel Macroable trait, reading this documentation https://laravel.com/api/5.4/Illuminate/Support/Traits/Macroable.html only tells me how to use but why do I use it, what is it meant for.

like image 615
samezedi Avatar asked Jul 13 '18 01:07

samezedi


2 Answers

It is for adding functionality to a class dynamically at run time.

use Illuminate\Support\Collection;

Collection::macro('someMethod', function ($arg1 = 1, $arg2 = 1) {
    return $this->count() + $arg1 + $arg2;
});

$coll = new Collection([1, 2, 3]);
echo $coll->someMethod(1, 2);
// 6      = 3 + (1 + 2)
echo $coll->someMethod();
// 5      = 3 + (1 + 1)

We have 'macroed' some functionality to the Collection class under the name someMethod. We can now call this method on the Collection class and use its functionality.

We just added a method to the class that didn't exist before without having to touch any source files.

For more detail of what is going on, please check out my article on Macros in Laravel:

asklagbox - blog - Laravel Macros

like image 169
lagbox Avatar answered Nov 19 '22 08:11

lagbox


It allows you to add new functions. One call to ::macro adds one new function. This can be done on those of the internal framework classes which are Macroable.

This action of adding the function to the class is done at run time. Note there was/is an already existing perfectly good name for this action, which isn't the word "macro", which I'll explain at the end of this post.

Q. Why would you do this?

A. If you find yourself juggling with these internal classes, like request & response, adding a function to them might make your code more readable. But as always there is a complexity cost in any abstraction, so only do it if you feel pain.

This article contains a list of the classes you can add functions to using the static call "::macro"

Try not to swallow the word macro though, if you read that article - if you're like me it will give you big indigestion.

So, let's now add one extra function to an internal framework class. Here is the example I have just implemented:

RedirectResponse::macro('withoutQuery', function() {
    return redirect()->to(explode('?', url()->previous())[0]);
});

This enables me in a controller to do this:

redirect()->back()->withoutQuery(); 

(You can just do back() but I added redirect() to make it clear).

This example is to redirect back and where the previous route was something like:

http://myapp.com/home?something=something-else

this function removes the part after '?', to redirect to simply:

http://myapp.com/home

I did not have to code it this way. Indeed another other way to achieve this is for me to put the following function in the base class which all controllers inherit from (App\Http\Controllers\Controller).

public function redirectBackWithoutQuery()
{
    return redirect()->to(explode('?',url()->previous())[0]);
}

That means I can in any controller do this:

return $this->redirectBackWithoutQuery(); 

So in this case the "macro" lets you pretend that your new function is part of an internal framework class, in this case the Illuminate/RedirectResponse class.

Personally I like you found it hard to grasp "laravel macros". I thought that because of the name they were something mysterious.

The first point is you may not need them often. The second point is the choice of the name ::macro to mean "add a function to a class"

What is a real macro?

A true macro is a concept unique to Lisp. A macro is like a function but it builds and returns actual code which is then executed. It is possible to write a function in other languages which returns a string which you then execute as if it was code, and that would be pretty much the same thing. However if you think about it you have all of the syntax to deal with when you do that. Lisp code is actually structured in lists. A comparison might be imagine if javascript was all written as actual json. Then you could write javascript, which was json, which returned json, which the macro would then just execute. But lisp is a lot simpler than json in terms of its syntax so it is a lot easier than what you just imagined. So, a true lisp macro is one of the most beautiful and amazing things you can encounter.

So why are these add-a-function things in laravel called macros? That's unknown to me I'm afraid, you'd have to ask the author, but I asked myself what they really do and is there already a name for that.

Monkey Patches

TL;DR laravel's ::macro could more accurately be described as monkey patch

So if using laravel ::macro calls, I personally decided to create a MonkeyPatchServiceProvider and put them all there, to reduce unnecessary confusion for myself.

I realise the name might sound a bit derogatory, but that's not intended at all. It's simply because there's already a name for this, and we have so much terminology to deal with why not use an existing name.

like image 39
mwal Avatar answered Nov 19 '22 09:11

mwal