К основному контенту

Используем TreeBehavior в CakePHP 1.2

Это вовсе не полное руководство, а пара замечаний к практическому использованию.

TreeBehavior – весьма полезный компонент CakePHP, реализующий паттерн Nested Sets для указанной модели. Если что-то непонятно, то вот ссылки:

  1. Про паттерны древовидных структур
  2. Что такое Behavior в CakePHP 1.2
  3. TreeBehavior

TreeBehavior позволяет хранить несколько корневых элементов, у которых родительский id равен NULL. Не поддавайтесь искушению – для себя сделайте отдельный корневой элемент. Большинство функций, например Model::children не работают с идентификатором записи равной NULL. Поэтому, если возникнет необходимость получить всех потомков корня, придется сначала выбрать самостоятельно все элементы с parent_id=NULL, а потом для каждого из них вызвать Model::children().

То есть, если создается, скажем, структурированный каталог сайтов, не надо поддаваться искушению добавить основные разделы, как корневые – создайте сначала “совсем-совсем” корневой элемент с именем, скажем, ROOT, а к нему уже добавлять реальные разделы, которые будут использоваться. Должна получиться такая структура:

ROOT (id=1, parent_id=0)
   |
   +-- Сайты о программировании (id=2, parent_id=1)
   |
   +-- Блоги (id=3, parent_id=1)
   |
   +-- CakePHP (id=4, parent_id=1)
       |
       +----- Форумы о Cake
       |
       +----- Компоненты Cake

Зато, при таком подходе можно использовать одну модель для хранения разных деревьев.

И еще. Я либо плохо искал, либо это действительно так. В TreeBehavior я не нашел метода, чтобы получить массив потомков узла в виде дерева. Метод children возвращает “плоский” массив. Пришлось написать небольшой метод для моей модели, который вызывает children, а потом каждому элементу массива добваляет элемент ‘children’ который содежит массив потомков, у которых тоже добвляет элемент ‘children’ и т.д.

Если главные элементы у модели, все-таки все с parent_id=NULL, функция тоже будет работать. Но лучше все-таки использовать схему, описанную мной выше.


function childrenAsTree($options=null) {

  // Если TreeBehavior неактивен, то можно и не
  // напрягаться
  if ($this->Behaviors->enabled('Tree')) {

    if (is_array($options)) {
      if (array_key_exists('id', $options)) {
        $_id = $options['id'];
      } else {
        $_id = null;
      }
    } else {
      $_id = $options;
    }

    // все потомки NULL --
    // это все записи
    if (is_null($_id)) {
      $res = $this->find('all', array('recursive'=>-1));
    } else {
      $res = $this->children($_id);
    }

    $retArr = $this->_toTree($res, $_id);
    return $retArr;
  }

}
 
private function &_toTree(&$arr, $parentId ) {
  $parentFieldName = $this->Behaviors->Tree->settings[$this->alias]['parent'];
  
  $retArr = array();
  
  if (!empty($arr)) {
  
  // Set::extract fix :-(
    if (is_null($parentId)) {
      foreach($arr as $item) {
        if (empty($item[$this->alias][$parentFieldName])) {
          $retArr[] = $item;
        }
      }
    } else {
      $retArr = Set::extract($arr,
        "/{$this->alias}[$parentFieldName=$parentId]");
    }

    for ($i=0; $i<count($retArr); $i++) {
      $retArr[$i]['children'] = $this->_toTree(&$arr,
        $retArr[$i][$this->alias][$this->primaryKey]);
    }
  }
  
  return $retArr;
}

Популярные сообщения из этого блога

Sitemap для Shop-Script

С недавних пор наш национальный поисковик присоединился к славной компании поисковиков, умеющих обрабатывать файлы sitemap . Наверное, это связано с какими-то общеланетарными амбициями. Как бы то ни было, теперь есть возможность скормить Яндексу файл(ы) sitemap . Я решил, что обрабатывать сайт какой-нибудь сторонней приблудой много дольше, чем просто сгенерировать файлы sitemap с помощью скрипта. Тем более, что у shop-script в общем-то довольно простая структура. Новая версия Shop-Script с ЧПУ пока недоступна, получу — модифицирую скрипт. :-) Скрипт простенький, делает sitemap для aux-страниц — это у shop-script так называются обычные статические html страницы; страниц с категориями. Без разбивки на страницы 1, 2 и т.д. на мой взгляд эти страницы не слишком важны страниц с товарами и обсуждениями товаров Можно запускать из браузера, можно по cron’у. Корневую страницу сайта, страницу с новостями, страницу с формой обратной связи и т.п. надо записать в отдельный файл sitemap ...

Набережные

На бывшей доске почета, а ныне просто небольшой фотовыставке достижений Московского Судостроительного и Судоремонтного Завода (МССЗ) увидел пару интересных фотографий продукции этого завода на фоне набережных Москвы. Вот только сами набережные и годы съемки определить не смог. :) Знатоки подсказывают: первая фотография: Гончарная набережная у м.Таганская ; вторая: Фрунзенская набережная дом 34-32-26 .

Зеленые облака

Сегодня часов около 12 дня бежал по делам рядом со станцией метро Юго-Западная и обратил внимание на странный цвет неба. Поскольку прямо по курсу, километрах в трех-четырех находится железнодорожная станция "Очаково", решил, что там авария какая-нибудь. "Хлор или иприт" - внезапно промелькнула мысль. Странно, уроки НВП я, большей частью, прогуливал... Позже в Интернете прочел, что это сильный ветер поднял в воздух большое количество пыльцы. Сделал фотографию на планшет, убедился, что получилось плохо - цвета почти видно, и, так как торопился, не стал дальше заморачиваться. Вот сейчас еду в метро домой, попробовал немного задрать контраст и насыщенность. Может, получится чего.