вторник, 1 сентября 2009 г.

Проблемы с sfDoctrineTreePlugin

Здесь было описание проблемы. Описание съели опера и WYSIWYG-редактор =\
В общем, дело обстояло так. В нынешнем проекте необходимо иметь список вложенных категорий. Symfony с ORM Doctrine позволяют это сделать практически без напрягов. Структура каталога категорий - вложенные множества (nested sets), о них и о других иерархических структурах данных можно почитать, например, здесь. В Доктрине есть встроенные средства для доступа и хранения таких структур. Для отображения данных нашел плагин к Symfony - sfDoctrineTreePlugin. С точки зрения интерфейса - красивый, кроссбраузерный (работает даже в Opera), но немного не доделанный.
Объясню. В исходной таблице с данными порядка 70 записей. При попытке отображения дерева данным плагином имеем большие тормоза. Открываем лог и видим ~300 запросов к базе. Непорядок. Пришлось лезть в код плагина и ковыряться. После небольших правок итог - 4 запроса. Если кому интересно или я вдруг забуду, опишу решение:
Необходима правка кода шаблона sfDoctrineTreePlugin/modules/sfDoctrineTree/templates/_nested_set_list.php:


<?php use_helper('Javascript', 'DoctrineTree'); ?>

<?php if( isset($records) && is_object($records) && $records->count() > 0 ): ?>

  <ul  id="dhtmlgoodies_tree2" class="dhtmlgoodies_tree">

    <?php

      $prevLevel = 0;

      $noRootAttr =  " noDrag='true' noSiblings='true' noDelete='true'";

      if ($no_root_rename) {

        $noRootAttr .= " noRename='true'";

      }

      if (isset($options['noAdd']) && $options['noAdd']) {

        $noRootAttr .= " noAdd='true'";

      }

      $nodeNoAttr = $options->count() > 0 ? _tag_options($options) : null;

      foreach($records AS $record):

        $currentLevel = $record->getLevel();

        $noAttr = $currentLevel == 0 ?  $noRootAttr : $nodeNoAttr;

        $recordIdentifier = $record->identifier();

        foreach ($recordIdentifier as $obj) {

          $identifier[] = $obj;

        }

        if($prevLevel > 0 && $currentLevel == $prevLevel) {

          echo '</li>';

        }

        if($currentLevel > $prevLevel) {

          echo '<ul>';

        }

        elseif ($currentLevel < $prevLevel) {

          echo str_repeat('</ul></li>', $prevLevel - $currentLevel);

        }

    ?>

      <li id ="node<?php echo $identifier[0] ?>" <?php echo $noAttr ?>>

    <?php

        $partial = $link_partial ? $link_partial : 'sfDoctrineTree/link';

        include_partial($partial, array('record' => $record, 'model' => $model, 'field' => $field, 'root' => $root, 'identifier' => $identifier[0]));

        if ($currentLevel == 0) {

          echo image_tag('/sfDoctrineTreePlugin/images/indicator.gif', array('style' => 'padding:0pt 5px;display:none;vertical-align:middle;', 'id' => 'doctrine_tree_indicator'));

        }

        $prevLevel = $currentLevel;

      endforeach;

    ?>

    </li>

  </ul>

<?php endif; ?>



Код здесь. Проблема была в вызовах в цикле вида $record->getNode()->getLevel(), которые я заменил на $record->getLevel().

Комментариев нет: