Как стать автором
Обновить

Проблема Eloquent фреймворка Laravel

Работая над очередным проектом на фреймворке Laravel мы обнаружили его уязвимое место. Это модель Eloquent, о которой написано немало, и примеров её использования тоже достаточно. Вот что мы разглядели. Возьмём простую модель (не Eloquent) на рисунке 1.


image


Видим, что джойнятся несколько таблиц, делается какая-то выборка по определённым свойствам из этого join, а потом апдейтится определённое поле определённой таблицы. Случай ординарный и не заслуживает, чтобы его подробно разбирали.


Но что произойдёт если мы применим модель Eloquent вместо предыдущей модели? Как например на рисунке 2.


image


Здесь идёт выборка полей из таблиц ‘prospects’, ‘properties’, ‘leads’. Во всех трёх таблицах есть поле ‘id’.


Что мы ожидали? После join таблиц по определённым признакам мы хотели взять у этих leads поле ‘mailer_address_1’ и отправить его на geocoding и получить для этого поля новое значение, т.е. сделать update.


Что по факту получилось благодаря Eloquent? Поскольку поле ‘id’ встречается в нескольких таблицах, то при update leads у нас финальный sql получился — update leads & id where id от prospects, а не от ‘leads’. Если подробнее, то на выходе join получаем множество столбцов с одинаковыми (повторяющимися) полями. Когда модель Eloquent наполняется, то перебираются столбцы по очереди. В случае ‘id’ каждый следующий перезатирает предыдущий ‘id’, который взят из join. Коварство Eloquent в том, что если даже задать alias, то имена полей после join всё равно будут без префиксов, просто ‘id’.


Решение проблемы Eloquent. Надо указывать конкретные поля. Мы добавили строку → selectRaw (“distinct leads.*”)
как на рисунке 3.


image


Эти ошибки невероятно коварны, так как ваш скрипт работает, а вы получаете ерунду в базе. Узнаёте вы об этом спустя время, когда уже поздно.

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.
Изменить настройки темы