【问题标题】:Laravel get all parents of categoryLaravel 获取类别的所有父母
【发布时间】:2017-09-01 09:58:02
【问题描述】:

我在 laravel 中有分类和子分类

namespace App;

use Illuminate\Database\Eloquent\Model;

class Category extends Model
{
    protected $table = 'categories';

    public function parent()
    {
        return $this->belongsTo('App\Category', 'parent_id');
    }

    public function children()
    {
        return $this->hasMany('App\Category', 'parent_id');
    }
}

我可以添加一个属于已创建类别的新类别。像“测试->测试子类别”之类的东西,然后假设我将创建属于测试子类别的“测试子子类别”,如下所示:“测试->测试子类别->测试子类别" 在视图中,我想打印该类别的父母(如果有的话)。 我是这样做的:

@if($category->parent)
   <td>{{ $category->parent->name }} <strong>-></strong> {{ $category->name }}</td>
@else
   <td>{{ $category->name }}</td>    
@endif

但这仅显示一个父类别(“测试的子类别 -> 测试的子子类别”)。我想向所有看起来像这样的父母展示:“测试->测试的子类别->测试的子子类别” 我该怎么做?

【问题讨论】:

标签: php laravel


【解决方案1】:

您可以在 Cateory 模型上定义一个模型访问器,它检索所有父级并将它们放入一个集合中。因此,在您的 Category 模型中添加以下方法:

public function getParentsAttribute()
{
    $parents = collect([]);

    $parent = $this->parent;

    while(!is_null($parent)) {
        $parents->push($parent);
        $parent = $parent->parent;
    }

    return $parents;
}

然后在您的刀片模板中,您可以获取一个类别的所有父项

@if(count($category->parents))
    <td>{{ $category->parents->implode('-') }} <strong>-></strong> {{ $category->name }}</td>
@else
    <td>{{ $category->name }}</td>
@endif

我认为没有其他解决方案不同于递归检索所有父母和 @Ross Wilson 在 cmets 中建议的包。考虑到查询的数量将等于父类别的数量。

您可以做的另一件事是将父树设置到categories 表中的数据库中,以节省大量查询。在您的categories 表中添加一个字符串字段,如parents_tree,并在保存/更新时将此值设置为已连接的父名称。这有点脏,因为如果其中一个父母更改其名称,您必须相应地更新所有孩子。取决于您要屈服于哪种权衡。

【讨论】:

  • 谢谢,我试过了,但在视图中它抛出错误“关系方法必须返回 Illuminate\Database\Eloquent\Relations\Relation 类型的对象”知道为什么吗?
  • 你想用()括号来做$category-&gt;parents()吗?
  • 我正在尝试不使用括号,现在我添加了它们,它工作得很好,谢谢!
  • 哦,我明白了,您没有将方法定义为模型访问器,而是定义为普通模型方法。那也没关系。很高兴它有帮助
【解决方案2】:

我知道这是旧的,但这是未来任何人的正确答案。这将为您提供无限的类别

在类别模型中

    public function parent()
{
    return $this->belongsTo('App\Category', 'parent_id');
}

public function getParentsNames() {

    $parents = collect([]);

    if($this->parent) { 
        $parent = $this->parent;
        while(!is_null($parent)) {
            $parents->push($parent);
            $parent = $parent->parent;
        }
        return $parents;
    } else {
        return $this->name;
    }

}

在 Blade 中(我相信您也可以在模型级别执行此操作,但这是我的快速方法)

 @if ($category->getParentsNames() !== $category->name)
                                @foreach ($category->getParentsNames()->reverse() as $item)
                                    @if ($item->parent_id == 0)
                                        <li class="breadcrumb-item"><a href="/{{ $item->slug }}">{{ $item->name }}</a></li>
                                             @else
                                        <li class="breadcrumb-item"><a href="../{{ $item->slug }}">{{ $item->name }}</a></li>
                                    @endif
                                @endforeach  
                            @endif

结果首页/客厅/沙发/沙发

【讨论】:

    【解决方案3】:

    您可以附加父变量:

    class Category extends Model
    {
        protected $table = 'categories';
    
        protected $appends = [
            'parent'
        ];
    
        public function parent()
        {
            return $this->belongsTo('App\Category', 'parent_id');
        }
    }
    

    这是最短的解决方案,但这不是最好的方法,因为每次加载父对象时。最好这样做:

    类类别扩展模型 { 受保护的 $table = '类别';

    public function parent()
    {
        return $this->belongsTo('App\Category', 'parent_id');
    }
    
    public function getParentsNames() {
        if($this->parent) {
            return $this->parent->getParentsNames(). " > " . $this->name;
        } else {
            return $this->name;
        }
    }
    

    在你的刀片中你调用:{{ $category-&gt;getParentsNames() }}

    【讨论】:

    • 通过使用这个 .. 我在我的选择框中有选项 Electronics Buldings Electronics > Laptop Cars Electronics > Computer 所以它不是最好的分类!你明白了吗?
    【解决方案4】:

    我的唯一笔记是为了进入主要类别,也许它会对某人有用。

     static function  getDepth($parent_id) {
    
           $categories= Categories::find($parent_id);
    
           if ($categories) {
               if ($categories->parent_id == 0) {
                   return $categories->category_name;
               } else {
                   return self::getDepth($categories->parent_id);
               }
           }
    
        }
    

    blade.php

       <td>{{ \App\Models\Admin\Category::getDepth($category->parent_id)}}</td>
    

    【讨论】:

      【解决方案5】:

      到目前为止,我发现的最佳解决方案是使用嵌套集模型
      详细的解释/实现已经很长时间了,并且已经有很多关于它的主题。所以我会缩短主题。

      这个想法是用介于父值之间的值对类别进行分组,依此类推。 例如:

      Clothes : 1-10
          - T-shirts: 2-3
          - Pants: 4-9
              - Shorts 5-6
              - Joggers 7-8
      
      

      使用这些值,只需一个查询就可以很容易地查询所有的祖先或后代类别,因为它们总是包含在两个值之间。

      一个主要缺点是;当类别发生变化(创建/删除/移动)时,需要重新评估和更新节点。


      这是(IMO)我找到的最佳解释:http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

      我还发现这个库似乎可以很好地退出 https://github.com/lazychaser/laravel-nestedset

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-21
        • 1970-01-01
        • 1970-01-01
        • 2011-07-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多