G
G
Greg Popov2016-05-27 20:27:40
MySQL
Greg Popov, 2016-05-27 20:27:40

How to create an infinite directory tree with the ability to read from the middle?

Hello. So I am implementing an infinite tree of categories, with the ability to read it from the middle. Faced difficulties:
there are two
catalog tables:
______________________
|id | title | parent_id |
| 1 | test1 | NULL |
| 2 | test2 | 1 |
| 3 | test3 | 2 |
| 4 | test4 | 3 |
catalog_to_catalog:
______________________
id | master_id | slave_id |
| 1 | 1 | NULL |
| 2 | 2 | 1 |
| 3 | 3 | 2 |
| 4 | 3 | 1 |
| 5 | 4 | 3 |
| 6 | 4 | 2 |
| 7 | 4 | 1 |
With the first two "knees" everything turns out naturally without problems, but then everything fizzles.
Code snippets:
Controller:

/**
     * Creates a new Category model.
     * If creation is successful, the browser will be redirected to the 'view' page.
     * @param int $id id of the parent category
     * @return mixed
     */
    public function actionCreate($id = null)
    {

        $categories = Category::getList();
        $model = new Category();

        (isset($id) ? $model->parent_id = $id : $model->parent_id = NULL);

        if ($model->load(Yii::$app->request->post()) && $model->validate()) {
            
            $transaction = $model->getDb()->beginTransaction();
            $model->save(false); // saving main model
            
            $relatedCategories = (array) $model->checkParent($model->parent_id);

            if(!empty($relatedCategories)){
                array_push($relatedCategories, [
                    'parent' => (integer) $model->parent_id,
                    'child'  => (integer) $model->id
                ]);
                var_dump($relatedCategories); die();
                $toBindData = array_slice($relatedCategories, 1, count($relatedCategories));

                foreach ($toBindData as $key => $value){

                    $binderModel = new CategoryToCategory(); // creating binder
                    $binderModel->category_parent_id = $toBindData[$key]['parent'];
                    $binderModel->category_child_id = $toBindData[$key]['child'];

                    if(!$binderModel->save()){

                        $transaction->rollBack();

                        return $this->render('create', [
                            'model' => $model,
                            'categories' => $categories,
                        ]);
                    }

                }

            }else{
                $binderModel = new CategoryToCategory(); // creating binder
                $binderModel->category_parent_id = $model->id;
                $binderModel->category_child_id = (integer)(!empty($model->parent_id)) ? $model->parent_id : null;
                $binderModel->save();
            }


            $transaction->commit();
            return $this->redirect(['view', 'id' => $model->id]);
            
        } else {
            return $this->render('create', [
                'model' => $model,
                'categories' => $categories,
            ]);
        }
    }

Model:
/**
     * Generates catalog items list based on parent_category_id
     * @param  null|integer $notInclude
     * @return array
     */
    public static function getList($notInclude = null)
    {
        $catalog = (object) CategoryToCategory::find()
            ->innerJoinWith('category')
            ->indexBy('id')
            ->orderBy('id')
            ->all();

        $list = (array) [];


        foreach ($catalog as $key => $item){



            if(isset($notInclude) && $item->category->id != $notInclude && $item->category->parent_id != $notInclude ){

                $list[$item->category->id] = [
                    'id' => $item->category->id,
                    'title' =>
                        isset($list[$item->category->parent_id]) && $item->category->parent_id != null ?
                        $list[$item->category->parent_id]['title'].' - '.$item->category->title :
                        $item->category->title,
                ];

            }else if(!isset($notInclude) && $notInclude == null){
                
                $list[$item->category->id] = [
                    'id' => $item->category->id,
                    'title' =>
                        $item->category->parent_id != null ?
                        $list[$item->category->parent_id]['title'].' - '.$item->category->title :
                        $item->category->title,
                ];
                
            }


        }

        return (array) $list;

    }
    
    public function checkParent($id){
        
        $list = [];
        
        $parent = CategoryToCategory::find()->orderBy('category_parent_id')->where([
            'category_parent_id' => $id
        ])->all();
        //var_dump($parent); die();

        foreach ($parent as $key => $item){
            $list[$key]['parent'] = $item->category_parent_id;
            $list[$key]['child'] = $item->category_child_id;

            if(isset($item->category_child_id)){
                $this->checkParent($item->category_child_id);
                return $list;
            }
        }
    }

On Yii, I did not find a ready-made implementation, alas, but I got stuck.

Answer the question

In order to leave comments, you need to log in

2 answer(s)
S
shagguboy, 2016-05-28
@Gregpopov

NESTED SET

N
novrm, 2016-05-27
@novrm

Sorry, if not in the topic, but how to find the middle in infinity?
Also, maybe shorter:

(isset($id) ? $model->parent_id = $id : $model->parent_id = NULL);
$model->parent_id = (isset($id) ? $id : null);

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question