Привет. Итак реализовываю бесконечное дерево категорий, с возможностью чтения его со средины. Столкнулся с трудностями:
есть две таблицы
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 не нашел готовой реализации, увы но застрял.