Студия разработки сайтов и приложений

Netspark.ru

Платформа для ботов в Telegram

Ботопотамы

Laravel и тайна потерянного global scope

Если у вас к модельке в Ларавеле был прикручен global scope и работал как часы, как вдруг в новой функции потерялся, или сломался — посмотрите, не используете ли вы raw-методы. Например, whereRaw(), или orderByRaw() в этой новой функции.

Global Scope — это класс, в котором можно один раз определить условия и затем применять их автоматически ко всем eloquent-запросам той или иной модели (то есть к запросам через Model::). Например, можно написать global scope для ограничения моделей по автору, чтобы к любому запросу типа Order::all() автоматически добавлялось ->where('user_id', '=', Auth::user()->id).

Так вот, оказывается, global scope чувствителен к наличию «сырых» запросов. Но это не значит, что их нельзя использовать вместе, можно. Всё дело в том, что билдер запроса не изолирует «сырые» условия от «нормальных». И если у вас есть например вот такое условие в whereRaw():

(DAYOFYEAR(date_of_birth) - DAYOFYEAR(?) BETWEEN 0 AND 30) OR (DAYOFYEAR(date_of_birth) - DAYOFYEAR(?) BETWEEN -365 AND -335)

то билдер не добавит за вас никаких скобочек и пристыкует условие из скоупа как есть:

(DAYOFYEAR(date_of_birth) - DAYOFYEAR(?) BETWEEN 0 AND 30) OR (DAYOFYEAR(date_of_birth) - DAYOFYEAR(?) BETWEEN -365 AND -335) AND (user_id = 3)

и как нетрудно заметить, приоритет выполнения условий тут будет совсем не такой, как мы задумывали.

Решение, как теперь очевидно, простое: всегда, когда требуется использовать whereRaw() нужно всё условие целиком оборачивать в скобочки.

А ещё можно пойти дальше, переписать класс билдера, добавив скобочки в whereRaw() автоматически, и в своих моделях указать использовать этот новый билдер. Как вот здесь сделали.

P.S. Собственно, это же может произойти и просто если использовать одновременно whereRaw() и where(). Так что, следите за скобочками.

Обсуждение

Чтобы обсудить заметку, написать комментарий, или просто связаться, заходите в Телеграм-канал. У нас весело и всем рады!

Также меня можно найти в Хвиттере, VC.ru, Дзене, или Тенчате. А если вы на парковке, присоединяйтесь к каналу в Max!