public function testSlugAncestry()
 {
     $slugs = array('/' => array(), 'pokemon/' => array('/'), 'pokemon/squirtle/' => array('/', 'pokemon/'));
     foreach ($slugs as $slug => $ancestry) {
         $this->assertEqual($ancestry, PhrictionDocument::getSlugAncestry($slug), "Ancestry of '{$slug}'");
     }
 }
 private function renderChildren($slug)
 {
     $document_dao = new PhrictionDocument();
     $content_dao = new PhrictionContent();
     $conn = $document_dao->establishConnection('r');
     $limit = 50;
     $d_child = PhrictionDocument::getSlugDepth($slug) + 1;
     $d_grandchild = PhrictionDocument::getSlugDepth($slug) + 2;
     // Select children and grandchildren.
     $children = queryfx_all($conn, 'SELECT d.slug, d.depth, c.title FROM %T d JOIN %T c
     ON d.contentID = c.id
     WHERE d.slug LIKE %> AND d.depth IN (%d, %d)
       AND d.status = %d
     ORDER BY d.depth, c.title LIMIT %d', $document_dao->getTableName(), $content_dao->getTableName(), $slug == '/' ? '' : $slug, $d_child, $d_grandchild, PhrictionDocumentStatus::STATUS_EXISTS, $limit);
     if (!$children) {
         return;
     }
     // We're going to render in one of three modes to try to accommodate
     // different information scales:
     //
     //  - If we found fewer than $limit rows, we know we have all the children
     //    and grandchildren and there aren't all that many. We can just render
     //    everything.
     //  - If we found $limit rows but the results included some grandchildren,
     //    we just throw them out and render only the children, as we know we
     //    have them all.
     //  - If we found $limit rows and the results have no grandchildren, we
     //    have a ton of children. Render them and then let the user know that
     //    this is not an exhaustive list.
     if (count($children) == $limit) {
         $more_children = true;
         foreach ($children as $child) {
             if ($child['depth'] == $d_grandchild) {
                 $more_children = false;
             }
         }
         $show_grandchildren = false;
     } else {
         $show_grandchildren = true;
         $more_children = false;
     }
     $grandchildren = array();
     foreach ($children as $key => $child) {
         if ($child['depth'] == $d_child) {
             continue;
         } else {
             unset($children[$key]);
             if ($show_grandchildren) {
                 $ancestors = PhrictionDocument::getSlugAncestry($child['slug']);
                 $grandchildren[end($ancestors)][] = $child;
             }
         }
     }
     // Fill in any missing children.
     $known_slugs = ipull($children, null, 'slug');
     foreach ($grandchildren as $slug => $ignored) {
         if (empty($known_slugs[$slug])) {
             $children[] = array('slug' => $slug, 'depth' => $d_child, 'title' => PhrictionDocument::getDefaultSlugTitle($slug), 'empty' => true);
         }
     }
     $list = array();
     $list[] = '<ul>';
     foreach ($children as $child) {
         $list[] = $this->renderChildDocumentLink($child);
         $grand = idx($grandchildren, $child['slug'], array());
         if ($grand) {
             $list[] = '<ul>';
             foreach ($grand as $grandchild) {
                 $list[] = $this->renderChildDocumentLink($grandchild);
             }
             $list[] = '</ul>';
         }
     }
     if ($more_children) {
         $list[] = '<li>More...</li>';
     }
     $list[] = '</ul>';
     $list = implode("\n", $list);
     return '<div class="phriction-children">' . '<div class="phriction-children-header">Document Hierarchy</div>' . $list . '</div>';
 }