vorst.ru - Как написать действия контроллера для работы с Nested Set
Статьи из рубрики nested-set

Виджет для вывода списка рубрик Nested Set

Выбор всех статей по рубрике

В конце предыдущей статьи были указаны две вещи, которых не хватает для начала использования рубрикатора.

Первая из них - необходимо добавить поле rubric в таблицу post. С этой операцией связано и изменения в модели common/models/Post, которые очевидно касаются методов rules() и attributeLabels().

Кроме этого нужно добавить обработку выбранной пользователем рубрики в actionIndex() контроллера frontend/controllers/PostController.


Простые действия над деревом Nested Set

Что нужно учесть для CRUD

Все необходимые методы, для управления деревом Nested Set уже определены в расширении.

Поэтому изменения в стандартном контроллере совсем небольшие. Нужно, например, вместо стандартного метода save() модели использовать метод prependTo() расширения, а вместо delete(), deleteWithChildren().


Представления для операций с Nested Set

Что нужно учесть в представлениях при редактировании Nested Set

Мы, в общих чертах, разобрались с деревьями Nested Set и создали модель для хранения дерева. В модели определили пару простых методов.

Теперь нужно разобраться с тем, как добавлять новые рубрики. Начнем с представлений.


Подключение расширения Nested Set

Определение данных и необходимых методов в модели

Мы получили общее представление о древовидной структуре данных называемой Nested Set. Теперь пришло время подключить к блогу соответствующее расширение.

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


Как устроена структура данных Nested Set

Как сделать рубрикатор

Рубрикатор, как средство поиска интересных статей, имеет свои недостатки - трудно придумать иерархию, названия рубрик, трудно потом решить к какой конкретно рубрике относится статья. "Но, так принято" - скажите вы и будете правы.

Поэтому, давайте делать рубрикатор.



Поиск



Простые действия над деревом Nested Set

Что нужно учесть для CRUD

Все необходимые методы, для управления деревом Nested Set уже определены в расширении.

Поэтому изменения в стандартном контроллере совсем небольшие. Нужно, например, вместо стандартного метода save() модели использовать метод prependTo() расширения, а вместо delete(), deleteWithChildren().


    Поделиться

Связано это, конечно же, с необходимостью заполнять или изменять значения в полях lft, rgt, смысл которых рассматривался в первой статье, посвященной организации рубрикатора.

Но, по порядку.

Controller

Начнем с добавления новой рубрики. Из формы ввода поступают всего два поля данных - $parent_node и $name. Именно значение поля $parent_node позволяет правильно заполнить поля lft, rgt новой записи и делается это с помощью метода prependTo() расширения.

А все действие выглядит следующим образом:

public function actionCreate()
{
  $model = new Rubric();
  if ($model->load(Yii::$app->request->post())) {
    if($model->prependTo($this->findModel($model->parent_node)))
      return $this->redirect(['index']);
  } else {
    return $this->render('create', [
      'model' => $model,
    ]);
  }
}

При редактировании важно учесть возможность изменения родителя.

public function actionUpdate($id)
{
  $model = $this->findModel($id);
  // $parent_node is empty, so it must be set
  if($one = $model->parents(1)->one())
  {
    $model->parent_node = $one->id;
    if ($model->load(Yii::$app->request->post()) && $model->save()) {
      return $this->redirect(['index']);
...

При удалении рубрики необходимо заменить в статьях соответствующие ссылки на рубрику "Root". Эту же операцию нужно выполнить для всех потомков, так как и они будут удалены при вызове метода deleteWithChildren().

      $node = $this->findModel($id);
      // find all node childrens
      $childrens = $node->children()->all();
      $node->deleteWithChildren();
      // update deleted rubrics to 1 in all posts with rubrics are $id or $childrens ID
      $ids = $id;
      foreach($childrens as $node)
        $ids .= ',' . $node->id;
      Post::updateAll(['rubric' => 1], 'rubric IN (' . $ids . ')');

Действие index это стандартный GridView.

Для начала работы с рубрикатором нам не хватает еще пары вещей. Во-первых нужно определить поле rubric в модели Post и во-вторых нужен виджет, который позволит выбирать нужную рубрику для просмотра всех, относящихся к рубрике статей. Но об этом, как обычно, в следующей статье.

Заключение

В контроллере рубрикатора обязательно использовать методы, предусмотренные расширением Nested Sets для модификации дерева.

Оставить комментарий

Только авторизованные пользователи могут оставлять комментарии. Пожалуйста авторизуйтесь или пройдите регистрацию.