Неочевидный нюанс при изменении пространства имён моделей в Laravel

от автора

На работе поступила очередная задача: разобраться и устранить странную проблему в работе давно и надёжно работающего сервиса. Проблема заключалась в том, что часть объектов двух видов перестала работать. Причём именно часть объектов.

Сам сервис написан на PHP с использованием фреймворка Laravel и служит для общения с внешней системой.

Поскольку есть внешняя система, то в первую очередь проверил её. Но с ней всё было в порядке. Данные уходили и приходили. И в БД сервиса всё заносилось как надо.

Но при обращении к ресурсам определённых объектов по API не возвращалась часть полей, которые хранятся в связанной таблице, связь типа полиморфное отношение «один-к-одному» («MorphOne»).

class FirstModel extends Model {     ...      public function childModel(): MorphOne     {         return $this->morphOne(ChildModel::class, 'entity');     }     ... }
class SecondModel extends Model {     ...      public function childModel(): MorphOne     {         return $this->morphOne(ChildModel::class, 'entity');     }     ... }
class ChildModel extends Model {     ...      public function entity(): MorphTo     {         return $this->morphTo();     }     ... }

Анализ проблемных объектов показал, что неполные данные возвращались по тем из них, которые были созданы до определенного момента времени вчера. Значит, дело возможно в изменениях в коде. Посмотрел логи git’а.

И в них увидел, что как раз вчера, добавляя новые модели, коллега изменил пространство имён у ряда уже существующих. Именно у тех, в которых и появились проблемы. Само изменение было правомерным и давно напрашивалось. И сделано правильно: пространство имён было изменено во всех нужных местах кода. PHPStorm за этим проследил.

Было:

namespace App\Models\Name1; ... class FirstModel extends Model {     ... }
namespace App\Models\Name1; ... class SecondModel extends Model {     ... }

Стало:

namespace App\Models\Name2; ... class FirstModel extends Model {     ... }
namespace App\Models\Name2; ... class SecondModel extends Model {     ... }

Значит, предположил я, где-то закэшировалось старое namespace. Были очищены все кэши Laravel. Но проблема осталась.

Снова внимательно изучил записи в БД. В них всё было записано правильно.

Обратился за помощью к коллегам. Созвонились, описал проблему, показал сделанные шаги. Бурное обсуждение и дискуссия не дали результата. В конце концов, один из нас спросил у DeepSeek. И в ответе ИИ, глаз выхватил строку про то, что в таблице, связанной связью типа “MorphOne”, хранится полное квалифицированное имя объекта.

Снова глянул в таблицу БД. Ну, конечно. Для объектов, созданных до переноса классов в новое пространство, в таблице было записано старое. Я же смотрел на эти записи и не заметил очевидного. Вот что значит «глаз замылился».

Написал и залил простенькую миграцию.

    public function up()     {         ChildModel::where('entity_type', 'App\Models\Name1\FirstModel')             ->update(['entity_type' => 'App\Models\Name2\FirstModel']);         ChildModel::where('entity_type', 'App\Models\Name1\SecondModel')             ->update(['entity_type' => 'App\Models\Name2\SecondModel']);     }

Дождался окончания тестирования и развёртывания. И вуаля, всё заработало правильно.

Вывод простой: в Laravel при любых изменения в полном квалифицированном имени класса модели, имеющей полиморфные отношения, не забывать изменять эти имена в соответствующих связанных таблицах в БД.

И остаётся проблема: как не забыть про этот нюанс в следующий раз.


ссылка на оригинал статьи https://habr.com/ru/articles/929078/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *