[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/src/applications/phriction/query/ -> PhrictionDocumentQuery.php (source)

   1  <?php
   2  
   3  final class PhrictionDocumentQuery
   4    extends PhabricatorCursorPagedPolicyAwareQuery {
   5  
   6    private $ids;
   7    private $phids;
   8    private $slugs;
   9    private $depths;
  10    private $slugPrefix;
  11    private $statuses;
  12  
  13    private $needContent;
  14  
  15    private $status       = 'status-any';
  16    const STATUS_ANY      = 'status-any';
  17    const STATUS_OPEN     = 'status-open';
  18    const STATUS_NONSTUB  = 'status-nonstub';
  19  
  20    private $order        = 'order-created';
  21    const ORDER_CREATED   = 'order-created';
  22    const ORDER_UPDATED   = 'order-updated';
  23    const ORDER_HIERARCHY = 'order-hierarchy';
  24  
  25    public function withIDs(array $ids) {
  26      $this->ids = $ids;
  27      return $this;
  28    }
  29  
  30    public function withPHIDs(array $phids) {
  31      $this->phids = $phids;
  32      return $this;
  33    }
  34  
  35    public function withSlugs(array $slugs) {
  36      $this->slugs = $slugs;
  37      return $this;
  38    }
  39  
  40    public function withDepths(array $depths) {
  41      $this->depths = $depths;
  42      return $this;
  43    }
  44  
  45    public function  withSlugPrefix($slug_prefix) {
  46      $this->slugPrefix = $slug_prefix;
  47      return $this;
  48    }
  49  
  50    public function withStatuses(array $statuses) {
  51      $this->statuses = $statuses;
  52      return $this;
  53    }
  54  
  55    public function withStatus($status) {
  56      $this->status = $status;
  57      return $this;
  58    }
  59  
  60    public function needContent($need_content) {
  61      $this->needContent = $need_content;
  62      return $this;
  63    }
  64  
  65    public function setOrder($order) {
  66      $this->order = $order;
  67      return $this;
  68    }
  69  
  70    protected function loadPage() {
  71      $table = new PhrictionDocument();
  72      $conn_r = $table->establishConnection('r');
  73  
  74      if ($this->order == self::ORDER_HIERARCHY) {
  75        $order_clause = $this->buildHierarchicalOrderClause($conn_r);
  76      } else {
  77        $order_clause = $this->buildOrderClause($conn_r);
  78      }
  79  
  80      $rows = queryfx_all(
  81        $conn_r,
  82        'SELECT d.* FROM %T d %Q %Q %Q %Q',
  83        $table->getTableName(),
  84        $this->buildJoinClause($conn_r),
  85        $this->buildWhereClause($conn_r),
  86        $order_clause,
  87        $this->buildLimitClause($conn_r));
  88  
  89      $documents = $table->loadAllFromArray($rows);
  90  
  91      if ($documents) {
  92        $ancestor_slugs = array();
  93        foreach ($documents as $key => $document) {
  94          $document_slug = $document->getSlug();
  95          foreach (PhabricatorSlug::getAncestry($document_slug) as $ancestor) {
  96            $ancestor_slugs[$ancestor][] = $key;
  97          }
  98        }
  99  
 100        if ($ancestor_slugs) {
 101          $ancestors = queryfx_all(
 102            $conn_r,
 103            'SELECT * FROM %T WHERE slug IN (%Ls)',
 104            $document->getTableName(),
 105            array_keys($ancestor_slugs));
 106          $ancestors = $table->loadAllFromArray($ancestors);
 107          $ancestors = mpull($ancestors, null, 'getSlug');
 108  
 109          foreach ($ancestor_slugs as $ancestor_slug => $document_keys) {
 110            $ancestor = idx($ancestors, $ancestor_slug);
 111            foreach ($document_keys as $document_key) {
 112              $documents[$document_key]->attachAncestor(
 113                $ancestor_slug,
 114                $ancestor);
 115            }
 116          }
 117        }
 118      }
 119  
 120      return $documents;
 121    }
 122  
 123    protected function willFilterPage(array $documents) {
 124      // To view a Phriction document, you must also be able to view all of the
 125      // ancestor documents. Filter out documents which have ancestors that are
 126      // not visible.
 127  
 128      $document_map = array();
 129      foreach ($documents as $document) {
 130        $document_map[$document->getSlug()] = $document;
 131        foreach ($document->getAncestors() as $key => $ancestor) {
 132          if ($ancestor) {
 133            $document_map[$key] = $ancestor;
 134          }
 135        }
 136      }
 137  
 138      $filtered_map = $this->applyPolicyFilter(
 139        $document_map,
 140        array(PhabricatorPolicyCapability::CAN_VIEW));
 141  
 142      // Filter all of the documents where a parent is not visible.
 143      foreach ($documents as $document_key => $document) {
 144        // If the document itself is not visible, filter it.
 145        if (!isset($filtered_map[$document->getSlug()])) {
 146          $this->didRejectResult($documents[$document_key]);
 147          unset($documents[$document_key]);
 148          continue;
 149        }
 150  
 151        // If an ancestor exists but is not visible, filter the document.
 152        foreach ($document->getAncestors() as $ancestor_key => $ancestor) {
 153          if (!$ancestor) {
 154            continue;
 155          }
 156  
 157          if (!isset($filtered_map[$ancestor_key])) {
 158            $this->didRejectResult($documents[$document_key]);
 159            unset($documents[$document_key]);
 160            break;
 161          }
 162        }
 163      }
 164  
 165      if (!$documents) {
 166        return $documents;
 167      }
 168  
 169      if ($this->needContent) {
 170        $contents = id(new PhrictionContent())->loadAllWhere(
 171          'id IN (%Ld)',
 172          mpull($documents, 'getContentID'));
 173  
 174        foreach ($documents as $key => $document) {
 175          $content_id = $document->getContentID();
 176          if (empty($contents[$content_id])) {
 177            unset($documents[$key]);
 178            continue;
 179          }
 180          $document->attachContent($contents[$content_id]);
 181        }
 182      }
 183  
 184      return $documents;
 185    }
 186  
 187    private function buildJoinClause(AphrontDatabaseConnection $conn) {
 188      $join = '';
 189      if ($this->order == self::ORDER_HIERARCHY) {
 190        $content_dao = new PhrictionContent();
 191        $join = qsprintf(
 192          $conn,
 193          'JOIN %T c ON d.contentID = c.id',
 194          $content_dao->getTableName());
 195      }
 196      return $join;
 197    }
 198    protected function buildWhereClause(AphrontDatabaseConnection $conn) {
 199      $where = array();
 200  
 201      if ($this->ids) {
 202        $where[] = qsprintf(
 203          $conn,
 204          'd.id IN (%Ld)',
 205          $this->ids);
 206      }
 207  
 208      if ($this->phids) {
 209        $where[] = qsprintf(
 210          $conn,
 211          'd.phid IN (%Ls)',
 212          $this->phids);
 213      }
 214  
 215      if ($this->slugs) {
 216        $where[] = qsprintf(
 217          $conn,
 218          'd.slug IN (%Ls)',
 219          $this->slugs);
 220      }
 221  
 222      if ($this->statuses) {
 223        $where[] = qsprintf(
 224          $conn,
 225          'd.status IN (%Ld)',
 226          $this->statuses);
 227      }
 228  
 229      if ($this->slugPrefix) {
 230        $where[] = qsprintf(
 231          $conn,
 232          'd.slug LIKE %>',
 233          $this->slugPrefix);
 234      }
 235  
 236      if ($this->depths) {
 237        $where[] = qsprintf(
 238          $conn,
 239          'd.depth IN (%Ld)',
 240          $this->depths);
 241      }
 242  
 243      switch ($this->status) {
 244        case self::STATUS_OPEN:
 245          $where[] = qsprintf(
 246            $conn,
 247            'd.status NOT IN (%Ld)',
 248            array(
 249              PhrictionDocumentStatus::STATUS_DELETED,
 250              PhrictionDocumentStatus::STATUS_MOVED,
 251              PhrictionDocumentStatus::STATUS_STUB,
 252            ));
 253          break;
 254        case self::STATUS_NONSTUB:
 255          $where[] = qsprintf(
 256            $conn,
 257            'd.status NOT IN (%Ld)',
 258            array(
 259              PhrictionDocumentStatus::STATUS_MOVED,
 260              PhrictionDocumentStatus::STATUS_STUB,
 261            ));
 262          break;
 263        case self::STATUS_ANY:
 264          break;
 265        default:
 266          throw new Exception("Unknown status '{$this->status}'!");
 267      }
 268  
 269      $where[] = $this->buildPagingClause($conn);
 270  
 271      return $this->formatWhereClause($where);
 272    }
 273  
 274    private function buildHierarchicalOrderClause(
 275      AphrontDatabaseConnection $conn_r) {
 276  
 277      if ($this->getBeforeID()) {
 278        return qsprintf(
 279          $conn_r,
 280          'ORDER BY d.depth, c.title, %Q %Q',
 281          $this->getPagingColumn(),
 282          $this->getReversePaging() ? 'DESC' : 'ASC');
 283      } else {
 284        return qsprintf(
 285          $conn_r,
 286          'ORDER BY d.depth, c.title, %Q %Q',
 287          $this->getPagingColumn(),
 288          $this->getReversePaging() ? 'ASC' : 'DESC');
 289      }
 290    }
 291  
 292    protected function getPagingColumn() {
 293      switch ($this->order) {
 294        case self::ORDER_CREATED:
 295        case self::ORDER_HIERARCHY:
 296          return 'd.id';
 297        case self::ORDER_UPDATED:
 298          return 'd.contentID';
 299        default:
 300          throw new Exception("Unknown order '{$this->order}'!");
 301      }
 302    }
 303  
 304    protected function getPagingValue($result) {
 305      switch ($this->order) {
 306        case self::ORDER_CREATED:
 307        case self::ORDER_HIERARCHY:
 308          return $result->getID();
 309        case self::ORDER_UPDATED:
 310          return $result->getContentID();
 311        default:
 312          throw new Exception("Unknown order '{$this->order}'!");
 313      }
 314    }
 315  
 316    public function getQueryApplicationClass() {
 317      return 'PhabricatorPhrictionApplication';
 318    }
 319  
 320  }


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1