MySQL / PHP - 多层类别结构

时间:2016-04-04 20:22:40

标签: php mysql orm yii2 hierarchical-data

我正在构建一个包含产品数据库的网站。每个产品属于一个类别。类别的结构是多层的,可以包含任意数量的层,例如:

  • Electronics> Games Consoles> Xbox> Xbox One> Games> etc..
  • Fashion> Mens> Shirts> Long Sleeved

我总是将产品分配到层中的“最后”类别。

以下是我的类别表的结构:

id       name            parent_id
================================
1        Fashion         NULL
2        Mens            1
3        Shirts          2
4        Long Sleeved    3
5        Short Sleeved   3

我正在使用Yii2作为我的应用程序框架,但相同的概念应该适用于大多数MVC框架,或者至少应用于实现像ActiveRecord这样的ORM的那些。

我想做的是:

  1. 对于任何类别级别,请获取“主”父级。即对于Shirts,它将是Fashion
  2. 对于任何类别级别,获取层中的所有“最后”级别类别。即对于Mens,它将是Long SleevedShort Sleeved
  3. (更高级)对于任何类别级别,请找出它拥有的子女/父母的数量。
  4. 我的模型中有以下默认关系:

    public function getParent()
    {
        return $this->hasOne(Category::className(), ['id' => 'parent_id']);
    }
    
    public function getParent()
    {
        return $this->hasMany(Category::className(), ['parent_id' => 'id']);
    }
    

    以下是我创建的函数,它输出任何给定类别的“树”:

    public function getParentTree()
    {
        $array = [];
    
        // $this->parent refers to the 'getParent()' relation above
        if(!empty($this->parent))
        {
            $array[] = $this->parent->name;
    
            if(!empty($this->parent->parent))
                $array[] = $this->parent->parent->name;
    
                    if(!empty($this->parent->parent->parent))
                        $array[] = $this->parent->parent->parent->name;
        }
        else
            $array[] = "(none)";
    
        $output = implode(" --> ", array_reverse($array));
    
        return $output;
    }
    

    但这里有很多重复,看起来很难看。但它也让我相信也许我采取了错误的方法并需要重组数据库本身?

1 个答案:

答案 0 :(得分:0)

比尔我想我已经在YII2中解决了这个问题 - >模型。

以下是我的代码。

public static function getSubCategories($parent_id = NULL, $level = 0)
{
    // Get the Category from table
    // Here you can use caching Yii::$app->cache->get to avoid multiple queries
    $categories = Category::find()->select(['id', 'parent_id', 'name'])->where(['parent_id' => $parent_id])->asArray()->all();

    // Logic of Nth level to return
    self::$max_down_level += 1;
    if($level != 0 && self::$max_down_level > $level) return $categories;

    // Now for each sub categories find and return chidren as Array
    foreach($categories as $key => $category)
    {
        $categories[$key]['children'] = self::getSubCategories($category['id'], $level);
    }

    return $categories;
}

另外,不要忘记在模型类中声明public static $max_down_level = 0;变量。现在调用下面的函数。

  1. 获取父类别self::getSubCategories(NULL)
  2. 的所有子女
  3. 让所有孩子达到第二级self::getSubCategories(NULL, 2)
  4. 同样,您可以声明递归函数以获取父类别。

    public static function getParentCategories($parent_id, $level = 0)
    {
        // Get the Category from table
        // Here you can use caching Yii::$app->cache->get to avoid multiple queries
        $categories = Category::find()->select(['id', 'parent_id', 'name'])->where(['id' => $parent_id])->asArray()->all();
    
        // Logic of Nth level to return
        self::$max_up_level += 1;
        if($level != 0 && self::$max_up_level > $level) return $categories;
    
        foreach($categories as $key => $category)
        {
            $categories[$key]['parent'] = self::getParentCategories($category['parent_id'], $level);
        }
    
        return $categories;
    }
    

    另外,不要忘记在模型类中声明public static $max_up_level = 0;变量。现在调用下面的函数。

    1. 获取父类别self :: getParentCategories(16,0)
    2. 的所有子项
    3. 让所有孩子达到2级自我:: getParentCategories(16,2)
    4. 您可以使用自己的班级名称代替self

      希望这有帮助。