Рассмотрим таблицу вложенных расположений, в которой есть столбцы для location_id
, его name
и parent_id
. Это родительское поле позволяет вам знать, что вы находитесь во вложенном месте.
Пример настройки:
Locations
-----------------------------------
location_id | name | parent_id
-----------------------------------
1 | Isle A | NULL
2 | Column 23 | 1
3 | Shelf 2 | 2
4 | Box C | 3
Допустим, у нас есть элемент, расположенный в location_id=4
. Теперь мы хотим легко показать полное местоположение элемента в формате через запятую. Мы ожидаем увидеть:
Остров А, Столбец 23, Полка 2, Ящик C
Для этого у меня есть следующая Laravel Модель с функцией full_name()
, которая заботится о форматировании и рекурсивных вызовах:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Location extends Model
{
protected $table = 'locations';
protected $primaryKey = 'location_id';
protected $with = [
'location'
];
public function location()
{
return $this->hasMany('App\Location', 'parent_id', 'location_id');
}
public function full_name()
{
return ($this->location ? $this->location->full_name() . ', ' : '') . $this->name;
}
}
Пока ничего сложного, работает правильно и выдает то, что мне нужно. Теперь представьте, что другой фрагмент кода допускает ошибку, и происходит следующее:
Locations
-----------------------------------
location_id | name | parent_id
-----------------------------------
1 | Isle A | NULL
2 | Column 23 | 3
3 | Shelf 2 | 2
4 | Box C | 3
Обратите внимание, что расположение # 2 * parent_id
изменилось на 3
. Это создает бесконечное число l oop объединений между 2 и 3. Laravel не обнаружит это повторение (после всего, что мы говорим, чтобы оно продолжало присоединяться), и выполнение в конечном итоге будет d ie. Это моя проблема .
Возможное решение, о котором я подумал, - сохранить текущий список "посещенных" location_id, и, если мы наткнемся на повтор, мы прекращаем выполнение. Если бы это была «нормальная» функция, я бы решил, что что-то вроде этого будет работать:
public function location($recurrence_guard = [])
{
if(in_array($this->location_id, $recurrence_guard)) {
return collect([]); // or null?
}
array_push($recurrence_guard, $this->location_id);
return $this->hasOne('\App\Location(<somehow pass $recurrence_guard_in_here>)', 'location_id', 'parent_id');
}
Очевидно, что это чепуха, и это не то, как работают отношения Laravel. Я ищу идеи о том, как передать дополнительные параметры в отношения или какие-то лучшие идеи о том, как спроектировать это.
Спасибо!