Мощь макросов в Laravel велика, так как позволяет расширять класс во время выполнения своими собственными методами. Вы можете добавить полезные методы, которые помогут преобразовать длинный код в выразительный однострочный. Пример из коробки — Валидация Запроса:
public function (Request $request)
{
$request->validate([
'email' => 'required|unique:users',
]); // ...
}
Среди списка классов, реализующих трейт Macroable, обеспечивающий функциональность макросов в классе, есть Query Builder и Eloquent Builder. Оба используются для создания запросов непосредственно к базе данных.
Когда мне нужны ресурсоемкие SQL вычисления, то первое что я делаю — сохраняю результат в Cache, что сильно раздувает код:
$votes = 100;
$users = Cache::remember('users', 60, function () use ($votes) {
return Users::has('comments')
->where('votes', '>', $votes)
->get();
});
Было бы неплохо всё это уместить в одну строку вместо того, чтобы угадывать, что я, черт возьми, здесь понаписал? Разумеется!
План, Класс и Макрос
Я хочу запомнить результаты, используя простой синтаксис — вот как я хочу писать в своем приложении:
$results = User::where('something')->remember(60)->get();
Чтобы это заработало, добавление метода remember() в качестве макроса в Query Builder будет недостаточно. Если мы сделаем только это, то используя другой метод, например get() (или любой другой метод извлечения) — вернется результат запроса в обход любой логики кэширования.
Другими словами: кеш и результат запроса не связаны.
Поэтому я сделал очень простой пакет, согласно схеме ниже. Есть крошечный класс, который, как только вы вызовете remember(), будет промежуточным звеном между Builder и Cache.

Попытаюсь объяснить лучше: когда вы используете метод remember(), экземпляр Eloquent или Query Builder будет инкапсулирован внутри класса, который передаст все ваши методы в Builder… за исключением случаев, когда Builder возвращает результат базы данных — в основном все, что угодно, кроме самого экземпляра Builder.
Это очень хороший способ делать ресурсоемкие вызовы в базу данных, без сложной логики и замыканий. Давайте вернемся к нашему первому примеру:
$votes = 100;
$users = Cache::remember('users', 60, function () use ($votes) {
return Users::has('comments')
->where('votes', '>', $votes)
->get();
});
Ок, мы знаем, что используем кэш. Замыкание находится внутри логики Cache, которая фактически вызывает базу данных, при импорте переменной извне. Теперь сравните это с этой выразительной строкой:
$users = Users::has('comments')->where('votes', '>', $votes)
->remember()
->get();
Работа с ключами кэша выполняется автоматически. По сути, хэшируется SQL-оператор запроса вместе с привязками, делая каждый оператор уникальным. Другими словами, логика может быть такой же, но если вы измените переменную, например количество голосов со 100 до 99, то хеш будет другим, и результат будет выполнен и сохранен в кэше.
Вот и все. Попробуйте и расскажите, что вы об этом думаете.
Пакет: DarkGhostHunter/RememberableQuery
Автор: Italo Baeza
Перевод: Алексей Широков
Наш Телеграм-канал — следите за новостями о Laravel.
