@Gregpopov
Full stack web developer

Как создать бесконечное дерево каталогов с возможностью чтения со средины?

Привет. Итак реализовываю бесконечное дерево категорий, с возможностью чтения его со средины. Столкнулся с трудностями:

есть две таблицы

catalog:

______________________
|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 |

С первыми двумя «коленами» все получается естественно без проблем, но вот дальше все сыпется.
Фрагменты из кода:
Контроллер:
/**
     * 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,
            ]);
        }
    }

Модель:
/**
     * 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;
            }
        }
    }


На Yii не нашел готовой реализации, увы но застрял.
  • Вопрос задан
  • 218 просмотров
Решения вопроса 1
Пригласить эксперта
Ответы на вопрос 1
@novrm
Извините, если не в тему, но как в бесконечности найти средину?

Еще - так может короче:
(isset($id) ? $model->parent_id = $id : $model->parent_id = NULL);
$model->parent_id = (isset($id) ? $id : null);
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы