Предотвратить рекурсию в личных отношениях Laravel Eloquent - PullRequest
1 голос
/ 28 февраля 2020

Рассмотрим таблицу вложенных расположений, в которой есть столбцы для 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. Я ищу идеи о том, как передать дополнительные параметры в отношения или какие-то лучшие идеи о том, как спроектировать это.

Спасибо!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...