Поэтому у меня есть данные, структурированные следующим образом:
id|parent_id|name 1 |null |foo 2 |1 |bar 3 |2 |baz
Так что в основном foo->bar->baz
. Я не понимаю, как использовать конструктор запросов laravel для получения строк для дочерней строки, а затем ее предков (до parent_id == null
). Можно ли это сделать с помощью laravel? Я провел небольшое исследование, и Postgres имеет RECURSIVE
то время как MySQL не выполняет ( рекурсивный запрос Postgres для обновления значений поля при перемещении parent_id ).
Я считаю, что MySQL имеет нечто похожее: как выполнить рекурсивный запрос SELECT в MySQL?
Но как бы реализовать это в Laravel?
Мой начальный код в основном использует область запроса, но я просто не понимаю:
Model::select('name')->getParent(3); //get baz and the ancestors of baz protected function scopeGetParent($id) { $parent = Model::where('id', '=', $id); return $query->getParent($parent->parent_id); }
Желаемый результат:
name baz bar foo
Есть идеи?
Итак, после использования метода merge()
для класса Collections
:
public static function ancestors($id) { $ancestors = Model::where('id', '=', $id)->get(); while ($ancestors->last()->parent_id !== null) { $parent = Model::where('id', '=', $ancestors->last()->parent_id)->get(); $ancestors = $ancestors->merge($parent); } return $ancestors; }
Это даст то, что мне нужно, но я считаю, что он может быть более чистым, поэтому, пожалуйста, не стесняйтесь его редактировать!
Я изменил решение tiffanyhwang и превратил его в нестатический метод и включил атрибут accessor, чтобы упростить получение результатов.
public function ancestors() { $ancestors = $this->where('id', '=', $this->parent_id)->get(); while ($ancestors->last() && $ancestors->last()->parent_id !== null) { $parent = $this->where('id', '=', $ancestors->last()->parent_id)->get(); $ancestors = $ancestors->merge($parent); } return $ancestors; }
и аксессуар для извлечения коллекции предков из атрибута модели
public function getAncestorsAttribute() { return $this->ancestors(); // or like this, if you want it the other way around // return $this->ancestors()->reverse(); }
так что теперь вы можете получить таких предков:
$ancestors = $model->ancestors;
и с момента его создания вы можете теперь легко сделать это:
echo $model->ancestors->implode('title',', ');
Другим способом может быть использование пакета etrepat / baum , это реализация Laravel модели вложенного набора . Он использует упорядоченное дерево, которое работает быстрее и использует нерекурсивные запросы. Хотя ваши данные структурированы следующим образом:
root |_ Child 1 |_ Child 1.1 |_ Child 1.2 |_ Child 2 |_ Child 2.1 |_ Child 2.2
Структурированные таким образом в модели с вложенными наборами:
___________________________________________________________________ | Root | | ____________________________ ____________________________ | | | Child 1 | | Child 2 | | | | __________ _________ | | __________ _________ | | | | | C 1.1 | | C 1.2 | | | | C 2.1 | | C 2.2 | | | 1 2 3_________4 5________6 7 8 9_________10 11_______12 13 14 | |___________________________| |___________________________| | |___________________________________________________________________|
Вставка узлов проста:
$child1 = $root->children()->create(['name' => 'Child 1']);