Ejemplo n.º 1
0
 private function loadDocuments(AphrontPagerView $pager)
 {
     // TODO: Do we want/need a query object for this?
     $document_dao = new PhrictionDocument();
     $content_dao = new PhrictionContent();
     $conn = $document_dao->establishConnection('r');
     switch ($this->view) {
         case 'all':
             $data = queryfx_all($conn, 'SELECT * FROM %T ORDER BY id DESC LIMIT %d, %d', $document_dao->getTableName(), $pager->getOffset(), $pager->getPageSize() + 1);
             break;
         case 'updates':
             // TODO: This query is a little suspicious, verify we don't need to key
             // or change it once we get more data.
             $data = queryfx_all($conn, 'SELECT d.* FROM %T d JOIN %T c ON c.documentID = d.id
         GROUP BY c.documentID
         ORDER BY MAX(c.id) DESC LIMIT %d, %d', $document_dao->getTableName(), $content_dao->getTableName(), $pager->getOffset(), $pager->getPageSize() + 1);
             break;
         default:
             throw new Exception("Unknown view '{$this->view}'!");
     }
     $data = $pager->sliceResults($data);
     $documents = $document_dao->loadAllFromArray($data);
     if ($documents) {
         $content = $content_dao->loadAllWhere('documentID IN (%Ld)', mpull($documents, 'getID'));
         $content = mpull($content, null, 'getDocumentID');
         foreach ($documents as $document) {
             $document->attachContent($content[$document->getID()]);
         }
     }
     return $documents;
 }
Ejemplo n.º 2
0
 protected function loadPage()
 {
     $table = new PhrictionDocument();
     $conn_r = $table->establishConnection('r');
     $rows = queryfx_all($conn_r, 'SELECT * FROM %T %Q %Q %Q', $table->getTableName(), $this->buildWhereClause($conn_r), $this->buildOrderClause($conn_r), $this->buildLimitClause($conn_r));
     $documents = $table->loadAllFromArray($rows);
     if ($documents) {
         $ancestor_slugs = array();
         foreach ($documents as $key => $document) {
             $document_slug = $document->getSlug();
             foreach (PhabricatorSlug::getAncestry($document_slug) as $ancestor) {
                 $ancestor_slugs[$ancestor][] = $key;
             }
         }
         if ($ancestor_slugs) {
             $ancestors = queryfx_all($conn_r, 'SELECT * FROM %T WHERE slug IN (%Ls)', $document->getTableName(), array_keys($ancestor_slugs));
             $ancestors = $table->loadAllFromArray($ancestors);
             $ancestors = mpull($ancestors, null, 'getSlug');
             foreach ($ancestor_slugs as $ancestor_slug => $document_keys) {
                 $ancestor = idx($ancestors, $ancestor_slug);
                 foreach ($document_keys as $document_key) {
                     $documents[$document_key]->attachAncestor($ancestor_slug, $ancestor);
                 }
             }
         }
     }
     return $documents;
 }
 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>';
 }
<?php

$table = new PhrictionDocument();
$conn_w = $table->establishConnection('w');
echo pht('Populating Phriction policies.') . "\n";
$default_view_policy = PhabricatorPolicies::POLICY_USER;
$default_edit_policy = PhabricatorPolicies::POLICY_USER;
foreach (new LiskMigrationIterator($table) as $doc) {
    $id = $doc->getID();
    if ($doc->getViewPolicy() && $doc->getEditPolicy()) {
        echo pht('Skipping document %d; already has policy set.', $id) . "\n";
        continue;
    }
    // If this was previously a magical project wiki page (under projects/, but
    // not projects/ itself) we need to apply the project policies. Otherwise,
    // apply the default policies.
    $slug = $doc->getSlug();
    $slug = PhabricatorSlug::normalize($slug);
    $prefix = 'projects/';
    if ($slug != $prefix && strncmp($slug, $prefix, strlen($prefix)) === 0) {
        $parts = explode('/', $slug);
        $project_slug = $parts[1];
        $project_slug = PhabricatorSlug::normalizeProjectSlug($project_slug);
        $project_slugs = array($project_slug);
        $project = id(new PhabricatorProjectQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withSlugs($project_slugs)->executeOne();
        if ($project) {
            $view_policy = nonempty($project->getViewPolicy(), $default_view_policy);
            $edit_policy = nonempty($project->getEditPolicy(), $default_edit_policy);
            $project_name = $project->getName();
            echo pht("Migrating document %d to project policy %s...\n", $id, $project_name);
            $doc->setViewPolicy($view_policy);
 public function loadHandles()
 {
     $types = phid_group_by_type($this->phids);
     $handles = array();
     $external_loaders = PhabricatorEnv::getEnvConfig('phid.external-loaders');
     foreach ($types as $type => $phids) {
         switch ($type) {
             case PhabricatorPHIDConstants::PHID_TYPE_MAGIC:
                 // Black magic!
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     switch ($phid) {
                         case ManiphestTaskOwner::OWNER_UP_FOR_GRABS:
                             $handle->setName('Up For Grabs');
                             $handle->setFullName('upforgrabs (Up For Grabs)');
                             $handle->setComplete(true);
                             break;
                         case ManiphestTaskOwner::PROJECT_NO_PROJECT:
                             $handle->setName('No Project');
                             $handle->setFullName('noproject (No Project)');
                             $handle->setComplete(true);
                             break;
                         default:
                             $handle->setName('Foul Magicks');
                             break;
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_USER:
                 $object = new PhabricatorUser();
                 $users = $object->loadAllWhere('phid IN (%Ls)', $phids);
                 $users = mpull($users, null, 'getPHID');
                 $image_phids = mpull($users, 'getProfileImagePHID');
                 $image_phids = array_unique(array_filter($image_phids));
                 $images = array();
                 if ($image_phids) {
                     $images = id(new PhabricatorFile())->loadAllWhere('phid IN (%Ls)', $image_phids);
                     $images = mpull($images, 'getBestURI', 'getPHID');
                 }
                 $statuses = id(new PhabricatorUserStatus())->loadCurrentStatuses($phids);
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($users[$phid])) {
                         $handle->setName('Unknown User');
                     } else {
                         $user = $users[$phid];
                         $handle->setName($user->getUsername());
                         $handle->setURI('/p/' . $user->getUsername() . '/');
                         $handle->setFullName($user->getUsername() . ' (' . $user->getRealName() . ')');
                         $handle->setAlternateID($user->getID());
                         $handle->setComplete(true);
                         if (isset($statuses[$phid])) {
                             $handle->setStatus($statuses[$phid]->getTextStatus());
                         }
                         $handle->setDisabled($user->getIsDisabled());
                         $img_uri = idx($images, $user->getProfileImagePHID());
                         if ($img_uri) {
                             $handle->setImageURI($img_uri);
                         } else {
                             $handle->setImageURI(PhabricatorUser::getDefaultProfileImageURI());
                         }
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_MLST:
                 $object = new PhabricatorMetaMTAMailingList();
                 $lists = $object->loadAllWhere('phid IN (%Ls)', $phids);
                 $lists = mpull($lists, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($lists[$phid])) {
                         $handle->setName('Unknown Mailing List');
                     } else {
                         $list = $lists[$phid];
                         $handle->setName($list->getName());
                         $handle->setURI($list->getURI());
                         $handle->setFullName($list->getName());
                         $handle->setComplete(true);
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_DREV:
                 $object = new DifferentialRevision();
                 $revs = $object->loadAllWhere('phid in (%Ls)', $phids);
                 $revs = mpull($revs, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($revs[$phid])) {
                         $handle->setName('Unknown Revision');
                     } else {
                         $rev = $revs[$phid];
                         $handle->setName($rev->getTitle());
                         $handle->setURI('/D' . $rev->getID());
                         $handle->setFullName('D' . $rev->getID() . ': ' . $rev->getTitle());
                         $handle->setComplete(true);
                         $status = $rev->getStatus();
                         if ($status == ArcanistDifferentialRevisionStatus::CLOSED || $status == ArcanistDifferentialRevisionStatus::ABANDONED) {
                             $closed = PhabricatorObjectHandleStatus::STATUS_CLOSED;
                             $handle->setStatus($closed);
                         }
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_CMIT:
                 $object = new PhabricatorRepositoryCommit();
                 $commits = $object->loadAllWhere('phid in (%Ls)', $phids);
                 $commits = mpull($commits, null, 'getPHID');
                 $repository_ids = array();
                 $callsigns = array();
                 if ($commits) {
                     $repository_ids = mpull($commits, 'getRepositoryID');
                     $repositories = id(new PhabricatorRepository())->loadAllWhere('id in (%Ld)', array_unique($repository_ids));
                     $callsigns = mpull($repositories, 'getCallsign');
                 }
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($commits[$phid]) || !isset($callsigns[$repository_ids[$phid]])) {
                         $handle->setName('Unknown Commit');
                     } else {
                         $commit = $commits[$phid];
                         $callsign = $callsigns[$repository_ids[$phid]];
                         $repository = $repositories[$repository_ids[$phid]];
                         $commit_identifier = $commit->getCommitIdentifier();
                         // In case where the repository for the commit was deleted,
                         // we don't have have info about the repository anymore.
                         if ($repository) {
                             $name = $repository->formatCommitName($commit_identifier);
                             $handle->setName($name);
                         } else {
                             $handle->setName('Commit ' . 'r' . $callsign . $commit_identifier);
                         }
                         $handle->setURI('/r' . $callsign . $commit_identifier);
                         $handle->setFullName('r' . $callsign . $commit_identifier);
                         $handle->setTimestamp($commit->getEpoch());
                         $handle->setComplete(true);
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_TASK:
                 $object = new ManiphestTask();
                 $tasks = $object->loadAllWhere('phid in (%Ls)', $phids);
                 $tasks = mpull($tasks, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($tasks[$phid])) {
                         $handle->setName('Unknown Revision');
                     } else {
                         $task = $tasks[$phid];
                         $handle->setName($task->getTitle());
                         $handle->setURI('/T' . $task->getID());
                         $handle->setFullName('T' . $task->getID() . ': ' . $task->getTitle());
                         $handle->setComplete(true);
                         $handle->setAlternateID($task->getID());
                         if ($task->getStatus() != ManiphestTaskStatus::STATUS_OPEN) {
                             $closed = PhabricatorObjectHandleStatus::STATUS_CLOSED;
                             $handle->setStatus($closed);
                         }
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_FILE:
                 $object = new PhabricatorFile();
                 $files = $object->loadAllWhere('phid IN (%Ls)', $phids);
                 $files = mpull($files, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($files[$phid])) {
                         $handle->setName('Unknown File');
                     } else {
                         $file = $files[$phid];
                         $handle->setName($file->getName());
                         $handle->setURI($file->getBestURI());
                         $handle->setComplete(true);
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_PROJ:
                 $object = new PhabricatorProject();
                 $projects = $object->loadAllWhere('phid IN (%Ls)', $phids);
                 $projects = mpull($projects, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($projects[$phid])) {
                         $handle->setName('Unknown Project');
                     } else {
                         $project = $projects[$phid];
                         $handle->setName($project->getName());
                         $handle->setURI('/project/view/' . $project->getID() . '/');
                         $handle->setComplete(true);
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_REPO:
                 $object = new PhabricatorRepository();
                 $repositories = $object->loadAllWhere('phid in (%Ls)', $phids);
                 $repositories = mpull($repositories, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($repositories[$phid])) {
                         $handle->setName('Unknown Repository');
                     } else {
                         $repository = $repositories[$phid];
                         $handle->setName($repository->getCallsign());
                         $handle->setURI('/diffusion/' . $repository->getCallsign() . '/');
                         $handle->setComplete(true);
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_OPKG:
                 $object = new PhabricatorOwnersPackage();
                 $packages = $object->loadAllWhere('phid in (%Ls)', $phids);
                 $packages = mpull($packages, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($packages[$phid])) {
                         $handle->setName('Unknown Package');
                     } else {
                         $package = $packages[$phid];
                         $handle->setName($package->getName());
                         $handle->setURI('/owners/package/' . $package->getID() . '/');
                         $handle->setComplete(true);
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_APRJ:
                 $project_dao = new PhabricatorRepositoryArcanistProject();
                 $projects = $project_dao->loadAllWhere('phid IN (%Ls)', $phids);
                 $projects = mpull($projects, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($projects[$phid])) {
                         $handle->setName('Unknown Arcanist Project');
                     } else {
                         $project = $projects[$phid];
                         $handle->setName($project->getName());
                         $handle->setComplete(true);
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_WIKI:
                 $document_dao = new PhrictionDocument();
                 $content_dao = new PhrictionContent();
                 $conn = $document_dao->establishConnection('r');
                 $documents = queryfx_all($conn, 'SELECT * FROM %T document JOIN %T content
           ON document.contentID = content.id
           WHERE document.phid IN (%Ls)', $document_dao->getTableName(), $content_dao->getTableName(), $phids);
                 $documents = ipull($documents, null, 'phid');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($documents[$phid])) {
                         $handle->setName('Unknown Document');
                     } else {
                         $info = $documents[$phid];
                         $handle->setName($info['title']);
                         $handle->setURI(PhrictionDocument::getSlugURI($info['slug']));
                         $handle->setComplete(true);
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             default:
                 $loader = null;
                 if (isset($external_loaders[$type])) {
                     $loader = $external_loaders[$type];
                 } else {
                     if (isset($external_loaders['*'])) {
                         $loader = $external_loaders['*'];
                     }
                 }
                 if ($loader) {
                     $object = newv($loader, array());
                     $handles += $object->loadHandles($phids);
                     break;
                 }
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setType($type);
                     $handle->setPHID($phid);
                     $handle->setName('Unknown Object');
                     $handle->setFullName('An Unknown Object');
                     $handles[$phid] = $handle;
                 }
                 break;
         }
     }
     return $handles;
 }
 private function renderDocumentChildren($slug)
 {
     $document_dao = new PhrictionDocument();
     $content_dao = new PhrictionContent();
     $conn = $document_dao->establishConnection('r');
     $limit = 250;
     $d_child = PhabricatorSlug::getDepth($slug) + 1;
     $d_grandchild = PhabricatorSlug::getDepth($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 IN (%Ld)
     ORDER BY d.depth, c.title LIMIT %d', $document_dao->getTableName(), $content_dao->getTableName(), $slug == '/' ? '' : $slug, $d_child, $d_grandchild, array(PhrictionDocumentStatus::STATUS_EXISTS, PhrictionDocumentStatus::STATUS_STUB), $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 = PhabricatorSlug::getAncestry($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' => PhabricatorSlug::getDefaultTitle($slug), 'empty' => true);
         }
     }
     $children = isort($children, 'title');
     $list = array();
     foreach ($children as $child) {
         $list[] = hsprintf('<li>');
         $list[] = $this->renderChildDocumentLink($child);
         $grand = idx($grandchildren, $child['slug'], array());
         if ($grand) {
             $list[] = hsprintf('<ul>');
             foreach ($grand as $grandchild) {
                 $list[] = hsprintf('<li>');
                 $list[] = $this->renderChildDocumentLink($grandchild);
                 $list[] = hsprintf('</li>');
             }
             $list[] = hsprintf('</ul>');
         }
         $list[] = hsprintf('</li>');
     }
     if ($more_children) {
         $list[] = phutil_tag('li', array(), pht('More...'));
     }
     $content = array(phutil_tag('div', array('class' => 'phriction-children-header ' . 'sprite-gradient gradient-lightblue-header'), pht('Document Hierarchy')), phutil_tag('div', array('class' => 'phriction-children'), phutil_tag('ul', array(), $list)));
     return id(new PHUIDocumentView())->setOffset(true)->appendChild($content);
 }
 protected function willFilterPage(array $documents)
 {
     if ($documents) {
         $ancestor_slugs = array();
         foreach ($documents as $key => $document) {
             $document_slug = $document->getSlug();
             foreach (PhabricatorSlug::getAncestry($document_slug) as $ancestor) {
                 $ancestor_slugs[$ancestor][] = $key;
             }
         }
         if ($ancestor_slugs) {
             $table = new PhrictionDocument();
             $conn_r = $table->establishConnection('r');
             $ancestors = queryfx_all($conn_r, 'SELECT * FROM %T WHERE slug IN (%Ls)', $document->getTableName(), array_keys($ancestor_slugs));
             $ancestors = $table->loadAllFromArray($ancestors);
             $ancestors = mpull($ancestors, null, 'getSlug');
             foreach ($ancestor_slugs as $ancestor_slug => $document_keys) {
                 $ancestor = idx($ancestors, $ancestor_slug);
                 foreach ($document_keys as $document_key) {
                     $documents[$document_key]->attachAncestor($ancestor_slug, $ancestor);
                 }
             }
         }
     }
     // To view a Phriction document, you must also be able to view all of the
     // ancestor documents. Filter out documents which have ancestors that are
     // not visible.
     $document_map = array();
     foreach ($documents as $document) {
         $document_map[$document->getSlug()] = $document;
         foreach ($document->getAncestors() as $key => $ancestor) {
             if ($ancestor) {
                 $document_map[$key] = $ancestor;
             }
         }
     }
     $filtered_map = $this->applyPolicyFilter($document_map, array(PhabricatorPolicyCapability::CAN_VIEW));
     // Filter all of the documents where a parent is not visible.
     foreach ($documents as $document_key => $document) {
         // If the document itself is not visible, filter it.
         if (!isset($filtered_map[$document->getSlug()])) {
             $this->didRejectResult($documents[$document_key]);
             unset($documents[$document_key]);
             continue;
         }
         // If an ancestor exists but is not visible, filter the document.
         foreach ($document->getAncestors() as $ancestor_key => $ancestor) {
             if (!$ancestor) {
                 continue;
             }
             if (!isset($filtered_map[$ancestor_key])) {
                 $this->didRejectResult($documents[$document_key]);
                 unset($documents[$document_key]);
                 break;
             }
         }
     }
     if (!$documents) {
         return $documents;
     }
     if ($this->needContent) {
         $contents = id(new PhrictionContent())->loadAllWhere('id IN (%Ld)', mpull($documents, 'getContentID'));
         foreach ($documents as $key => $document) {
             $content_id = $document->getContentID();
             if (empty($contents[$content_id])) {
                 unset($documents[$key]);
                 continue;
             }
             $document->attachContent($contents[$content_id]);
         }
     }
     return $documents;
 }