vorst.ru - Статьи о задачах возникающих при создании сайта и их решении
Статьи помеченные tree

Nested Set

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

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

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

Наши задачи проще и сводятся к следующему:

  1. Управление рубрикатором - добавление и удаление рубрик, редактирование, отображение списка рубрик для визуального контроля.
  2. Закрепление статьи за рубрикой.
  3. Вывод списка рубрик для выбора нужной рубрики.

Для их решения, как обычно, нужна модель, контроллер, представления и еще виджет.


Рубрикатор

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

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

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

У нас есть рубрики записанные в правой колонке:

id lft rgt level name
1 1 12 1 Root
2 2 5 2 --- Data structures
3 3 4 3 ------ Nested Set
4 6 9 2 --- Searching
5 7 8 3 ------ Posts chains
6 10 11 2 --- About sites

И нужна структура данных, которая помогла бы нам:

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


Поиск



Nested Set

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

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

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

Наши задачи проще и сводятся к следующему:

  1. Управление рубрикатором - добавление и удаление рубрик, редактирование, отображение списка рубрик для визуального контроля.
  2. Закрепление статьи за рубрикой.
  3. Вывод списка рубрик для выбора нужной рубрики.

Для их решения, как обычно, нужна модель, контроллер, представления и еще виджет.


    Поделиться

Cоздадим таблицу, которая будет хранить дерево рубрик и введем обязательную корневую рубрику.

CREATE TABLE tbl_rubric (
  id INT(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
  lft INT(11) NOT NULL,
  rgt INT(11) NOT NULL,
  level INT(11) NOT NULL,
  name VARCHAR(50) NOT NULL,
  KEY lft (lft),
  KEY rgt (rgt),
  KEY level (level)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO tbl_rubric (id, lft, rgt, level, name) values(1, 1, 2, 1, 'Без рубрики')

Установим расширение Nested Set.

Создадим модель common\models\Rubric.php, подключив расширение и определив два служебных поля значение которых будет объяснено позже.

namespace common\models;
use creocoder\nestedsets\NestedSetsBehavior;
use yii\db\ActiveRecord;
class Rubric extends ActiveRecord
{
  public $parent_node; // the parent node for just added
  public $post_count; // posts count in a rubric
  ...
  public function behaviors()
  {
    return [
      'tree' => [
        'class' => NestedSetsBehavior::className(),
          'depthAttribute' => 'level',
      ],
    ];
  }
  ...

И напишем пару методов.

Первый из которых будем использовать для вывода названий рубрик. Для отражения уровня вложенности будем делать отступы. Формирование отступов зависит от вывода. Метод формирования будет разным для выпадающего списка и просто вывода в блоке.

  public function getPrettyName($dropdown = false)
  {
    return $dropdown 
      ? str_repeat('-', ($this->level - 1) * 2) . ' ' . $this->name
      : '<span style="margin-left:' . (($this->level - 2) * 20) . 'px;">' . 
        $this->name . '</span>';
  }

Второй метод нужен для формирования выпадающего списка, который будет использоваться во-первых при выборе рубрики, за которой будет закреплена статья и во-вторых для выбора рубрики, которая является родительской рубрикой для вновь добавляемой рубрики.

Цели добавления новой рубрики и служит одно из дополнительных полей модели - $parent_node. Добавляя новую рубрику мы должны определить ее предка. Именно за ним и будет вставлен "новичок".

Итак, метод items()

  public function items($rootTitle = null)
  {
    if(!$rootTitle) 
      $rootTitle = \Yii::t('app', 'Root');
    $a = [];
    $a[1] = $rootTitle;
    foreach(Rubric::find()->where('id>1')->orderBy('lft ASC')->all() as $node)
      $a[$node->id] = $node->getPrettyName(true);
    return $a;
}

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

Заключение

Для создания рубрикатора не обязательно вникать в детали работы программы-расширения, которая выполняет всю основную работу.

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

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