Решил делать свой пет-проект для тренировки разных задач в контексте геймдева. Кратко - браузерная онлайн-игра с ролевой системой. Дошла очередь до боя между двумя игроками на основе их характеристик. СУБД MySQL. Результаты боя храню в таблице fights, где есть таблица fighters (тип json). В этой таблице шаблонно сохраняются значения: { "attacker_id": 1, "defender_id": 3 } Иными словами айди атакующего и айди защищающегося. Далее, пытаюсь получить объект с заранее прописанным отношением модели Fight к Users по attacker_id (по логике чтобы получить данные атакующего). Гуглил. Выяснил, что Laravel не умеет работать с hasOne, если это json-поле. Для решения проблемы на stackoverflow рекомендовали пакет https://github.com/staudenmeir/eloquent-json-relations Установил его в проект, сделал отношение hasOneJson как в документации, но оно не работает. Что нужно сделать? Разобраться, почему не работает отношение hasOneJson из вышеуказанного пакета, и показать как правильно нужно сделать (что и где изменить и на какую строку чтобы заработало); либо решить это средствами самого Laravel (на случай, если я недостаточно глубоко копнул и если фреймворк на самом деле может прогружать связи через json-объект и конкретное поле из него). Приложу скриншот ошибки и код. Если надо, поделюсь архивом проекта (гита нет). Пишите цены за ваше время. P.S. hasOneJson(User::class, 'id', 'attacker_id'); пробовал разные варианты с последним ключом. fights->attacker_id, fights['attacker_id'] и прочие. Не помогает. Ощущение, будто этого пакета нет в проекте, хотя в папке vendor я его вижу. PHP: class Fight extends Model { use HasFactory; use \Staudenmeir\EloquentJsonRelations\HasJsonRelationships; public function attacker(): \Staudenmeir\EloquentJsonRelations\Relations\HasOneJson { return $this->hasOneJson(User::class, 'id', 'attacker_id'); } /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'fighters', 'results', 'rounds' ]; /** * The attributes that should be cast to native types. * * @var array */ protected $casts = [ 'fighters' => 'json', 'results' => 'array', 'rounds' => 'array', ]; } PHP: public function getFightData($id) { $fightData = Fight::with(['attacker'])->find($id); dd($fightData); return view('fightData', compact(['fightData', 'attacker', 'defender'])); } --- Добавлено --- Добавлю интересный момент. Если в методе getFightData($id) сделать так: PHP: public function getFightData($id) { $fightData = Fight::find($id); dd($fightData->fighters['attacker_id']); return view('fightData', compact(['fightData', 'attacker', 'defender'])); } то Laravel выдаст конкретное число (айдишник), как и задумано логикой
1. приведите все же пример? а то не очень понятно таблица в таблице? Если предположить что fighters это поле, а не таблица... то скорее всего нужно Код (Text): return $this->hasOneJson(User::class, 'id', 'fighters->attacker_id');
Прилагаю скриншот. fights это таблица, fighters это участники боя, results это результат боя и rounds это лог боя (удар за ударом между игроками)
Как вы предложили уже пробовал. Не удается, ошибка Call to undefined relationship [attacker] on model [App\Models\Fight]. Исходя из текста ошибки понимаю что отношение некорректное. Но ведь я установил пакет выше. Почему laravel не видит его?
Не стоит так делать. Понятно, что очень хочется, но может всё-таки не надо? Реляционные СУБД предполагают что "большие" пачки данных хранятся в вертикальных узких но очень высоких таблицах (many-to-many связи, справочники а ля wordpress postmeta) - то есть любой "мусор" который может когда-нибудь пригодится, но запрашивается за скрипт 1-2 раза, а часто требующиеся данные, требующие скоростного поиска и поиска по зависимостям - в отдельных столбцах. Отдельные стоблцы в интернет магазинах можно еще ускорить добавив фильтрам товаров и их значениям номера и закодировав их в числа, что позволило бы выбирать без условий вида "если это и это и это", а если "код фильтра по этому товару равен 0123012300123123" - что еще быстрее (аналогия - добавляем товару тег и ищем все товары по одному тегу, что быстрее, чем проверять все условия, чтобы тег определить) То есть совершенно нормально хранить в таблице "дерево постов" колонку "уровень вложенности" и последний из уровней отдельно хранить в таблице "постов" убедившись, что она обновляется ("кэшируется"). Ибо выбирать по этой колонке не осуществляя подключение к другим местам хранения будет быстрее. Важно понимать, что JOIN быстрее не-JOIN, только тогда когда на уровне задумки программы есть соединение между таблицами. Если можно сделать легкий и быстрый JOIN по числу или ID - его стоит и можно сделать. Но если требуется экстра скорость и мгновенность, то надо хитрить и делать задачу без соединений, отталкиваясь от того, что операции, подготовливающие эту экстра-скорость, делаются не каждую секунду, а например, раз в минуту, а вот операции выборки могут и несколько раз в секунду простреливать запросто. В вашем же случае, чтобы подсоединиться по JSON полю - придется всю таблицу делать json_decode() (а там к примеру миллион записей) - чтобы найти из этого миллиона одну строку, где поле равно например 3. JSON в данном случае это формат передачи между системами, и как вариант - хранения какого-то снимка или слепка, лога, дебага, информации которая требуется при работе с данными вручную, истории изменений. Реализовывать связи, опирающиеся на слепок - не очень хороший путь, сильно лучше будет вашу колонку при помещении данных копировать из JSON в обычную колонку, а те что уже есть - прогнать скриптом. Если переживаете, что пока скрипт работает появятся новые - запустите скрипт после того как подключите копирование из JSON в колонку, и добавьте в скрипте проверку "если уже есть - пропустить". Если ваши данные почти всегда имеют разное число столбцов и они настолько сложны, что описать для них фиксированный файл с полями почти невозможно - рассмотрите возможность подключить в проект колоночные БД типа Mongo или кликхауса, но по практике скажу, если вы не можете описать структуру данных вообще никак - то скорее всего вы либо пишите рассадку людей в концертном зале в 10 типах зон, с 10 типами зрителей, за 10ю типами (треугольный, круглый, квадратный, прямоугольный, еще какой-то) столиков - и даже тут посидеть с карандашом можно, чтобы найти общие моменты, либо делаете что-то не так. 90% задач "как делать поиск по JSON" связаны с "мне лень нормально делать", а еще точнее "менеджеру нет желания понимать, а мне стало быть плевать как оно будет работать".