Scriptify.ru

Источник: https://scotch.io/@Lily-Rae/laravel-macros-for-collections-and-eloquent

Одним из больших преимуществ в Laravel является использование моделей Eloquent и коллекций. Коллекции имеют множество удобных методов, которые помогают легко работать с данными и писать читаемый код:

$squareRoots = collect([1, 4, 9, 16])->map(function($number)  {
    return sqrt($number);
});

Время от времени вы можете писать один и тот же код для разных коллекций. В этом случае будет полезно расширить класс Illuminate\Support\Collection, используя макросы:

use Illuminate\Support\Collection;

Collection::macro('squareRoot', function() {
    return $this->map(function($number) {
        return sqrt($number);
    });
});

Большим преимуществом здесь, помимо повторного использования кода, является то, что мы можем дальше использовать цепочки методов, и наш новый метод будет выглядеть так, как будто принадлежит фреймворку:

collect([1, 2, 3, 4])->squareRoot();
collect([2, 4, 6, 8])->squareRoot()->doSomethingElse();

Хорошим местом для макросов может служить сервис-провайдер, так они будут доступны в любом месте приложения.

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Collection;

class MacrosServiceProvider extends ServiceProvider
{

    public function boot()
    {
        Collection::macro('squareRoot', function() {
            return $this->map(function($number) {
                return sqrt($number);
            });
        });
    }

    public function register()
    {
        //
    }
}

Макросы также могут быть использованы в отношениях Eloquent. Для примера, конвертируем отношение Один-ко-многим в Один-к-одному

use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;

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

Теперь внутри модели возможно будет использовать наш макрос. Это значит, что теперь нет необходимости получать первое значение из коллекции

public function posts() {
    return $this->hasMany(Post::class);
}

public function latestPost() {
    return $this->posts()->latest()->toHasOne();
}

Содержание статьи