Цикл «шаги», затем «подэтапы», затем «подэтапы» в PHP / CodeIgniter - PullRequest
1 голос
/ 28 декабря 2010

Полагаю, мой первый вопрос: поскольку я - одинокий разработчик, я скучаю по тому, как другие отбрасывают идеи или получают идеи, когда я застрял в проблеме.Есть ли сайт, специально предназначенный для решения этой проблемы?Как виртуальный сайт совместного программиста?Или StackOverflow может работать таким образом?

Мой главный вопрос: я работаю над чем-то вроде списка дел, но каждый элемент может иметь подэтапы ... или даже подэтапы... а может и дальше.У меня есть таблица с полями "id, item, parent_id", со всеми элементами верхнего уровня, имеющими parent_id = 0. Используя Datamapper ORM в CodeIgniter, я использую это:

$i = new Item();
$i->where('parent_id',0)->get();
foreach($i as $item) {
   echo $item->item;
   $si = new Item();
   $si->where('parent_id',$item->id)->get();
   foreach($si as $subItem) {
      echo $subItem->item;
      // and so on
   }
}

Это работает, но есть ли более разумный способ сделать это?Может быть, какая-то рекурсивная функция?

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

Ответы [ 3 ]

3 голосов
/ 28 декабря 2010

Если вы пишете свой собственный SQL, вы могли бы сделать это за 3 запроса.

"SELECT * FROM items WHERE parent_id = 0;"
"SELECT * FROM items WHERE parent_id IN (SELECT id FROM items WHERE parent_id = 0;"

Тем не менее, вы выглядите так, как будто хотите иметь многопустотную древовидную структуру :

| item |
  | sub-item |
    | sub-sub-item |

Если вы используете CI, есть (на мой взгляд) лучший ORM под названием Doctrine , который будет обрабатывать древовидные структуры данных, ссылающиеся на себя (используя рекурсию, как вы предлагали). К счастью, есть хорошая статья для включения его в CodeIgniter!

http://www.phpandstuff.com/articles/codeigniter-doctrine-from-scratch-day-1-install-and-setup

Doctrine создаст запрос для вас - он также поддерживает отношения и множество других полезных функций, таких как кэширование, которых нет в CodeIgniter:)

3 голосов
/ 28 декабря 2010

На вашем месте я бы посмотрел на реализацию древовидной структуры. По сути, у вас есть база, настроенная для списка смежности (с точки зрения БД - код php, который вам все равно придется писать и тестировать). Если вы добавите столбец level, чтобы определить, на каком уровне иерархии находятся заданные задачи, вы можете извлекать все данные с помощью 1-2 запросов, самостоятельно объединяясь, хотя это будет медленным, если уровень вложенности довольно глубокий.

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

Взгляните на Управление иерархическими данными в MySQL , которое подробно объясняет оба аспекта со стороны БД ... Это специфично для MySQL, но вы должны быть в состоянии применять те же принципы независимо от БД или для другая конкретная БД.

Конечно, в любом случае вам нужно реализовать сопоставление для этого на стороне PHP, что является более трудоемким делом, чем вы делаете сейчас ... но оно также позволяет вам обращаться к БД меньшее количество раз.

Я бы также рекомендовал использовать Doctrine (как рекомендовал Сет) вместо CI Datamapper ... В нем все это уже реализовано ... вам просто нужно изучить основы Doctrine и подключить его к CI, который я я уверен, что есть тонны учебников.

0 голосов
/ 28 декабря 2010

Что-то вроде этого, не проверено: count ($ ss) может не возвращать правильное значение, чтобы увидеть, есть ли какие-либо результаты, возвращаемые по запросу, поэтому обновите его как необходимый (в Zend я могу рассчитывать на Zend_Db_Table_Rowset, но не shure какой объект CI возвращает и если вы можете сосчитать количество результатов) обновите статистику if, чтобы она вызывала функцию, только если есть результаты, возвращаемые по вашему запросу)

    function recursive( $i )
    {
        foreach ( $i as $item )
        {
            echo $item->item;
            $si = new Item();
            $ss = $si->where('parent_id', $item->id)->get();
            if ( count($ss) > 0 ) 
                recursive($ss);
        }
    }
    $i = new Item();
    recursive($i->where('parent_id', 0)->get());
...