Мощь макросов в 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.