Php Laravel获取祖先(URL)
在Laravel中,我有一个包含id、父id、slug(自引用)的表 当我有一个ID时,我需要以如下格式获取它的所有祖先(用“/”分隔) 但在没有像“laravel nestedset”这样的包的情况下,这是一种有效的方式 “ 我是这样实现的Php Laravel获取祖先(URL),php,laravel,laravel-5,eloquent,Php,Laravel,Laravel 5,Eloquent,在Laravel中,我有一个包含id、父id、slug(自引用)的表 当我有一个ID时,我需要以如下格式获取它的所有祖先(用“/”分隔) 但在没有像“laravel nestedset”这样的包的情况下,这是一种有效的方式 “ 我是这样实现的 public function parent() { return $this->belongsTo('Collection', 'parent_id'); } public function getParentsAttribute() {
public function parent()
{
return $this->belongsTo('Collection', 'parent_id');
}
public function getParentsAttribute()
{
$parents = collect([]);
$parent = $this->parent;
while(!is_null($parent)) {
$parents->push($parent);
$parent = $parent->parent;
}
return $parents;
}
任何其他有效的方法都可以通过“/”分隔,如果您知道可以嵌套多少个最大级别,那么您可以使用即时加载。假设最大深度为3级,则可以执行以下操作:
$model->with('parent.parent.parent');
您还可以使用递归而不是循环
public function getParentsAttribute()
{
if (!$this->parent) {
return collect([]);
}
return collect($this->parent->parents)->push($this->parent);
}
如果要添加第一个对象(self),则完整调用将是:
$model->parents->push($model)->reverse->implode('attr_name', '/');
您还可以将其包装到属性中
public function getPathAttribute() {
return $model->parents->push($model)->reverse->implode('attr_name', '/');
}
并像
$model->path那样调用代码>在评论中进行了一点对话后,我认为这是一个很好的解决方案:
// YourModel.php
// Add this line of you want the "parents" property to be populated all the time.
protected $appends = ['parents'];
public function getParentsAttribute()
{
$collection = collect([]);
$parent = $this->parent;
while($parent) {
$collection->push($parent);
$parent = $parent->parent;
}
return $collection;
}
然后,您可以使用以下方法检索您的父母:
YourModel::find(123)->parents
(集合实例)
YourModel::find(123)->parents->introde('yourprop','/')
(introde为string,请参阅)
YourModel::find(123)->parents->reverse()->内爆('yourprop','/')
(顺序相反)
正如Nikolai Kiselev所指出的,您也可以将其与此相结合,以节省一些查询:
protected $with = ['parent.parent.parent'];
// or inline:
YourModel::find(123)->with(['parent.parent.parent']);
这将在对象加载时预加载父对象。如果您决定不使用此选项,则只要您调用$yourModel->parent
,就会加载父级(惰性)。另外,parents
属性返回一个集合(不过可能是一个普通数组)。然后只需调用$collection->内爆('/')
就可以将它变成一个字符串。在数据库中是否有一个名为level的列,其中包含level?如果你这样做了,你可以动态构建一个查询来获取所有的父对象,然后使用类似于GROUP_CONCAT
的方法,让数据库做腿部工作-PS我不使用Laravel,但我使用嵌套集来实现这一点,简单的父子关系会有点困难,因为你需要为每个级别进行连接。有没有办法使用Elount“with()”来实现这一点-渴望加载?@Flame你的意思是像returncollection::find(33)->parents->introde('/')代码>?哦,很抱歉,当然父对象
是一个对象,您应该像->内爆('yourproperty','/')
那样调用它,其中yourproperty
是父对象的属性。仅当集合只有简单的标量值时,单参数调用才起作用。但这会使调用变得非常困难,因为您的父对象也会嵌套在对象中。您必须使用$mainObject->parent->parent->parent->parent
访问它们,因此如果您想要一个parents@Flame,没错,但至少不那么重要queries@NikolaiKiselev为什么您认为这个解决方案执行的查询更少?为了检索邻接列表模型中的完整树,我们需要根据树的深度进行连接。(在本例3中)我不确定这是否真的解决了1个查询,即使它解决了,速度的提高是有争议的,因为您正在交易一个PHP循环来从这个嵌套属性创建一个父数组,而原始解决方案是执行3个小查询并在PHP中推送它们array@hoseinz3,每次在中调用$parent->parent
,而getParentsAttribute()
的循环将触发一个新的DB查询,除非这些嵌套关系之前已预加载对不起,请再问一个与此相关的问题。有没有办法找到注释者和自我level1/level2/level3/WITH-THIS
。我想您可以将$THIS
推送到getParentsAttribute()
中的$collection中,您可能还需要将reverse()
方法放在那里。
protected $with = ['parent.parent.parent'];
// or inline:
YourModel::find(123)->with(['parent.parent.parent']);