2016-04-04 17 views
2

私は製品データベースを含むウェブサイトを構築しています。各製品はカテゴリに属します。カテゴリの構造は、多層であり、例えば階層の任意の数を含むことができる:>Long Sleeved MySQL/PHP - マルチティアカテゴリ構造

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

    私は常に、製品をティアの「最後の」カテゴリに割り当てます。ここで

    は私のカテゴリテーブルの構造である:

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

    私は自分のアプリケーションフレームワークとしてYii2を使用していますが、同じ概念は、ほとんどのMVCフレームワークに適用されなければならない、などのORMを実装する少なくともこれらActiveRecord。私が何をしたいか

    は次のとおりです。すべてのカテゴリレベルの場合

    1. 、「マスター」の親を取得します。私。 Shirtsの場合Fashion
    2. いずれのカテゴリレベルでも、階層内のすべての「最後の」レベルカテゴリを取得します。私。 Mensの場合、Long SleevedShort Sleevedとなります。
    3. (さらに高度な)どのカテゴリレベルでも、それが持つ子/親の数を調べることができます。

    I持って私のモデルでは、次のデフォルトの関係:

    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; 
    } 
    

    しかし、ここにはたくさんの繰り返しがあり、それは醜く見えます。しかし、おそらく私は間違ったアプローチをとっており、データベース自体を再構築する必要があると私は信じています。

+0

あなたは 'parent_id'で正しい軌道に乗っています。オンラインのツリービルダーを見つけたり、関数を再帰的にすることができます。つまり、現在の要素に親があるかどうかをチェックし、親を配列に追加し、親に対して同じ関数を実行します(これはツリー全体を反復処理します)。 – JimL

+0

http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/ – Barmar

+0

parent_idは、カテゴリテーブルにデータを格納する理想的な方法ですが、カテゴリパスをインデックスに登録して、何をやっているのか再帰を避ける必要がある場合。この情報をYiiのキャッシュに保存したり、SQLクエリで利用できるパスインデックスが必要な場合は、カテゴリ構造を変更しながらこのテーブルを更新してカテゴリパスを格納するテーブルを作成できます。 – lucas

答えて

0

Bill私はこの問題をYII2 - > Modelsで解決したと思います。

以下は私のコードです。

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)

同じように、上記第二レベルまですべての子を取得するには親カテゴリself::getSubCategories(NULL)

  • のすべての子を取得します。

    さらに、public static $max_up_level = 0;変数をモデルクラスに宣言することを忘れないでください。以下のような関数を呼び出します。親カテゴリの自己のすべての子を取得するには

    1. :: getParentCategories(16、0)
    2. 第二レベルの自己までのすべての子供たちを取得するには:: getParentCategories(16、2)

    selfの代わりに独自のクラス名を使用することができます

    これは役に立ちます。