با معجزه ماکروها در لاراول آشنا شوید

ابتدا به قطعه کد زیر نگاهی بندازیم که برای uppercase کردن  محتویات یک کالکشن به کار می رود:

$uppercaseWords = collect(['code', 'ferengi'])->map(function($word)  {
   return strtoupper($word);
});

خب این کد مشکلی نداره ولی تصور کنید که بخواهیم  تعداد زیادی کالکشن رو uppercase کنیم!  تایپ کردن و تکرار  این  قطعه کد خیلی خسته کننده خواهد شد، اینطور نیست ؟
خب پس بیاید به کمک ماکروها که جزء ویژگی های جدید لاراول  هستند کدمون رو بهبود بدهیم.

use Illuminate\Support\Collection;

Collection::macro('uppercase', function() {

    return collect($this->items)->map(function($word) {
        return strtoupper($word);
    });

});

 حالا که ماکروی خودمون رو تعریف کردیم، پس بیاید ازش استفاده کنیم:

$uppercaseWords = collect(['code', 'daily'])->uppercase();
$moreUppercaseWords = collect(['code', 'every', 'day'])->uppercase();
$evenMoreUppercaseWords = collect(['laravel', 'facade'])->uppercase();

خب شاید شما بگویید که " من می تونستم این کار رو یا  یک فانکشن ساده هم انجام بدهم" حتما به این صورت:

function uppercase($collection) {
...
}

$uppercaseWords = uppercase(collect(['hello','Iran']));

بله  می شود این  کار رو کرد ولی توجه داشته باشید که شما   با استفاده از ماکروها همچنان میتونید از فانکشن هاتون رو chain کنید و کد شما خوانایی بهتری خواهد داشت.

//lots of functions
function4(function3(function2(function1(collect(['Ali','Iran'])))));

//lots of macros
collect(['i', 'want', 'to', 'live', 'in','peace'])
  ->function1()
  ->function2()
  ->function3()
  ->function4();

یه مثال کاربردی تر دیگه روی کامپوننت Request لاراول بگیم، مثلا اگه بخواهیم، دامین اصلی  رکوئست رو تشخیص بدهیم  با استفاده از ماکرو ها به این صورت می تونیم:

Request::macro('isTld', function ($tld) {
    return Str::is('*.' . $tld, $this->root());
});

اون نامگذاری متغیر tld$ برای مخفف کلمات Top Level Domainهست، مثل com. یا net.

حالا به راحتی می تونیم در رکوئست ها دامنه اصلی رو چک کنیم

Request::isTld('com') // returns true for app.com
Request::isTld('dev') // returns false for app.dev

یه ماکرو پیشرفته تر که  بر اساس TLD یک where به مدل اضافه میکنه

Builder::macro('whenTldMatches', function($tld, $callback) {
    if (Request::isTld($tld)) {
        call_user_func($callback->bindTo($this));
    }
    return $this;
});

SomeModel::whenTldMatches('org', function () {
    $this->where('id', '>', 5);
})->get();

// applies ->where() on app.org but not app.com

حالا شاید بپرسید کجا ماکروها رو تعریف کنم ؟

‌ء Service providers ها  جای خوبی برای تعریف ماکرو ها هستند. مثلا App\Providers\AppServiceProvider

ولی پیشنهاد میکنم برای ماکروها یه سرویس پرووایدر ایجاد کنید مثلا App\Providers\MacrosServiceProvider

برای کدوم کامپوننت ها می تونیم ماکرو بنویسیم ؟

تقریبا برای همشون مثل  فسادهایی مانند: 

  • Cache
  • File
  • Lang
  • Request
  • Response
  • Route
  • URL

یا کلاس هایی مثل:

  • Illuminate\Database\Eloquent\Relation
  • Illuminate\Support\Collection
  • Illuminate\Routing\ResponseFactory

جالبه نه ؟ به relationship ها می تونید ماکرو اضافه کنید، مثلا :

HasMany::macro('toHasOne', function() {
     return new HasOne(
     $this->getQuery,
     $this->getParent,
     $this->foreignKey,
     $this->localKey
     );
});

که میاد و آخرین عنصر یک رابطه  مشخص رو میگیره.