Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/phriction/query/PhrictionDocumentQuery.php b/src/applications/phriction/query/PhrictionDocumentQuery.php
index de3064fd42..0c6a2c23bc 100644
--- a/src/applications/phriction/query/PhrictionDocumentQuery.php
+++ b/src/applications/phriction/query/PhrictionDocumentQuery.php
@@ -1,289 +1,390 @@
<?php
final class PhrictionDocumentQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
private $ids;
private $phids;
private $slugs;
private $depths;
private $slugPrefix;
private $statuses;
+ private $parentPaths;
+ private $ancestorPaths;
+
private $needContent;
const ORDER_HIERARCHY = 'hierarchy';
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
}
public function withPHIDs(array $phids) {
$this->phids = $phids;
return $this;
}
public function withSlugs(array $slugs) {
$this->slugs = $slugs;
return $this;
}
public function withDepths(array $depths) {
$this->depths = $depths;
return $this;
}
- public function withSlugPrefix($slug_prefix) {
+ public function withSlugPrefix($slug_prefix) {
$this->slugPrefix = $slug_prefix;
return $this;
}
public function withStatuses(array $statuses) {
$this->statuses = $statuses;
return $this;
}
+ public function withParentPaths(array $paths) {
+ $this->parentPaths = $paths;
+ return $this;
+ }
+
+ public function withAncestorPaths(array $paths) {
+ $this->ancestorPaths = $paths;
+ return $this;
+ }
+
public function needContent($need_content) {
$this->needContent = $need_content;
return $this;
}
protected function loadPage() {
return $this->loadStandardPage($this->newResultObject());
}
public function newResultObject() {
return new PhrictionDocument();
}
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 PhrictionContentQuery())
->setViewer($this->getViewer())
->setParentQuery($this)
->withIDs(mpull($documents, 'getContentID'))
->execute();
$contents = mpull($contents, null, 'getID');
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;
}
protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
$joins = parent::buildJoinClauseParts($conn);
if ($this->getOrderVector()->containsKey('updated')) {
$content_dao = new PhrictionContent();
$joins[] = qsprintf(
$conn,
'JOIN %T c ON d.contentID = c.id',
$content_dao->getTableName());
}
return $joins;
}
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
$where = parent::buildWhereClauseParts($conn);
if ($this->ids !== null) {
$where[] = qsprintf(
$conn,
'd.id IN (%Ld)',
$this->ids);
}
if ($this->phids !== null) {
$where[] = qsprintf(
$conn,
'd.phid IN (%Ls)',
$this->phids);
}
if ($this->slugs !== null) {
$where[] = qsprintf(
$conn,
'd.slug IN (%Ls)',
$this->slugs);
}
if ($this->statuses !== null) {
$where[] = qsprintf(
$conn,
'd.status IN (%Ls)',
$this->statuses);
}
if ($this->slugPrefix !== null) {
$where[] = qsprintf(
$conn,
'd.slug LIKE %>',
$this->slugPrefix);
}
if ($this->depths !== null) {
$where[] = qsprintf(
$conn,
'd.depth IN (%Ld)',
$this->depths);
}
+ if ($this->parentPaths !== null || $this->ancestorPaths !== null) {
+ $sets = array(
+ array(
+ 'paths' => $this->parentPaths,
+ 'parents' => true,
+ ),
+ array(
+ 'paths' => $this->ancestorPaths,
+ 'parents' => false,
+ ),
+ );
+
+ $paths = array();
+ foreach ($sets as $set) {
+ $set_paths = $set['paths'];
+ if ($set_paths === null) {
+ continue;
+ }
+
+ if (!$set_paths) {
+ throw new PhabricatorEmptyQueryException(
+ pht('No parent/ancestor paths specified.'));
+ }
+
+ $is_parents = $set['parents'];
+ foreach ($set_paths as $path) {
+ $path_normal = PhabricatorSlug::normalize($path);
+ if ($path !== $path_normal) {
+ throw new Exception(
+ pht(
+ 'Document path "%s" is not a valid path. The normalized '.
+ 'form of this path is "%s".',
+ $path,
+ $path_normal));
+ }
+
+ $depth = PhabricatorSlug::getDepth($path_normal);
+ if ($is_parents) {
+ $min_depth = $depth + 1;
+ $max_depth = $depth + 1;
+ } else {
+ $min_depth = $depth + 1;
+ $max_depth = null;
+ }
+
+ $paths[] = array(
+ $path_normal,
+ $min_depth,
+ $max_depth,
+ );
+ }
+ }
+
+ $path_clauses = array();
+ foreach ($paths as $path) {
+ $parts = array();
+ list($prefix, $min, $max) = $path;
+
+ // If we're getting children or ancestors of the root document, they
+ // aren't actually stored with the leading "/" in the database, so
+ // just skip this part of the clause.
+ if ($prefix !== '/') {
+ $parts[] = qsprintf(
+ $conn,
+ 'd.slug LIKE %>',
+ $prefix);
+ }
+
+ if ($min !== null) {
+ $parts[] = qsprintf(
+ $conn,
+ 'd.depth >= %d',
+ $min);
+ }
+
+ if ($max !== null) {
+ $parts[] = qsprintf(
+ $conn,
+ 'd.depth <= %d',
+ $max);
+ }
+
+ $path_clauses[] = '('.implode(') AND (', $parts).')';
+ }
+
+ $where[] = '('.implode(') OR (', $path_clauses).')';
+ }
+
return $where;
}
public function getBuiltinOrders() {
return parent::getBuiltinOrders() + array(
self::ORDER_HIERARCHY => array(
'vector' => array('depth', 'title', 'updated'),
'name' => pht('Hierarchy'),
),
);
}
public function getOrderableColumns() {
return parent::getOrderableColumns() + array(
'depth' => array(
'table' => 'd',
'column' => 'depth',
'reverse' => true,
'type' => 'int',
),
'title' => array(
'table' => 'c',
'column' => 'title',
'reverse' => true,
'type' => 'string',
),
'updated' => array(
'table' => 'd',
'column' => 'contentID',
'type' => 'int',
'unique' => true,
),
);
}
protected function getPagingValueMap($cursor, array $keys) {
$document = $this->loadCursorObject($cursor);
$map = array(
'id' => $document->getID(),
'depth' => $document->getDepth(),
'updated' => $document->getContentID(),
);
foreach ($keys as $key) {
switch ($key) {
case 'title':
$map[$key] = $document->getContent()->getTitle();
break;
}
}
return $map;
}
protected function willExecuteCursorQuery(
PhabricatorCursorPagedPolicyAwareQuery $query) {
$vector = $this->getOrderVector();
if ($vector->containsKey('title')) {
$query->needContent(true);
}
}
protected function getPrimaryTableAlias() {
return 'd';
}
public function getQueryApplicationClass() {
return 'PhabricatorPhrictionApplication';
}
}
diff --git a/src/applications/phriction/query/PhrictionDocumentSearchEngine.php b/src/applications/phriction/query/PhrictionDocumentSearchEngine.php
index e0781ec81f..e3d962146a 100644
--- a/src/applications/phriction/query/PhrictionDocumentSearchEngine.php
+++ b/src/applications/phriction/query/PhrictionDocumentSearchEngine.php
@@ -1,144 +1,160 @@
<?php
final class PhrictionDocumentSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Wiki Documents');
}
public function getApplicationClassName() {
return 'PhabricatorPhrictionApplication';
}
public function newQuery() {
return id(new PhrictionDocumentQuery())
->needContent(true);
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['statuses']) {
$query->withStatuses($map['statuses']);
}
if ($map['paths']) {
$query->withSlugs($map['paths']);
}
+ if ($map['parentPaths']) {
+ $query->withParentPaths($map['parentPaths']);
+ }
+
+ if ($map['ancestorPaths']) {
+ $query->withAncestorPaths($map['ancestorPaths']);
+ }
+
return $query;
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorSearchCheckboxesField())
->setKey('statuses')
->setLabel(pht('Status'))
->setOptions(PhrictionDocumentStatus::getStatusMap()),
id(new PhabricatorSearchStringListField())
->setKey('paths')
->setIsHidden(true)
->setLabel(pht('Paths')),
+ id(new PhabricatorSearchStringListField())
+ ->setKey('parentPaths')
+ ->setIsHidden(true)
+ ->setLabel(pht('Parent Paths')),
+ id(new PhabricatorSearchStringListField())
+ ->setKey('ancestorPaths')
+ ->setIsHidden(true)
+ ->setLabel(pht('Ancestor Paths')),
);
}
protected function getURI($path) {
return '/phriction/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array(
'active' => pht('Active'),
'all' => pht('All'),
);
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'all':
return $query;
case 'active':
return $query->setParameter(
'statuses',
array(
PhrictionDocumentStatus::STATUS_EXISTS,
));
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function getRequiredHandlePHIDsForResultList(
array $documents,
PhabricatorSavedQuery $query) {
$phids = array();
foreach ($documents as $document) {
$content = $document->getContent();
$phids[] = $content->getAuthorPHID();
}
return $phids;
}
protected function renderResultList(
array $documents,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($documents, 'PhrictionDocument');
$viewer = $this->requireViewer();
$list = new PHUIObjectItemListView();
$list->setUser($viewer);
foreach ($documents as $document) {
$content = $document->getContent();
$slug = $document->getSlug();
$author_phid = $content->getAuthorPHID();
$slug_uri = PhrictionDocument::getSlugURI($slug);
$byline = pht(
'Edited by %s',
$handles[$author_phid]->renderLink());
$updated = phabricator_datetime(
$content->getDateCreated(),
$viewer);
$item = id(new PHUIObjectItemView())
->setHeader($content->getTitle())
->setHref($slug_uri)
->addByline($byline)
->addIcon('none', $updated);
$item->addAttribute($slug_uri);
$icon = $document->getStatusIcon();
$color = $document->getStatusColor();
$label = $document->getStatusDisplayName();
$item->setStatusIcon("{$icon} {$color}", $label);
if (!$document->isActive()) {
$item->setDisabled(true);
}
$list->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setObjectList($list);
$result->setNoDataString(pht('No documents found.'));
return $result;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Fri, Mar 14, 4:37 PM (1 d, 10 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
72040
Default Alt Text
(14 KB)

Event Timeline