Page MenuHomePhabricator

D14772.id35727.diff
No OneTemporary

D14772.id35727.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -3004,6 +3004,7 @@
'PhabricatorSearchEditController' => 'applications/search/controller/PhabricatorSearchEditController.php',
'PhabricatorSearchEngine' => 'applications/search/engine/PhabricatorSearchEngine.php',
'PhabricatorSearchEngineAPIMethod' => 'applications/search/engine/PhabricatorSearchEngineAPIMethod.php',
+ 'PhabricatorSearchEngineAttachment' => 'applications/search/engineextension/PhabricatorSearchEngineAttachment.php',
'PhabricatorSearchEngineExtension' => 'applications/search/engineextension/PhabricatorSearchEngineExtension.php',
'PhabricatorSearchEngineExtensionModule' => 'applications/search/engineextension/PhabricatorSearchEngineExtensionModule.php',
'PhabricatorSearchEngineTestCase' => 'applications/search/engine/__tests__/PhabricatorSearchEngineTestCase.php',
@@ -3149,6 +3150,7 @@
'PhabricatorSubscriptionsListController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsListController.php',
'PhabricatorSubscriptionsRemoveSelfHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsRemoveSelfHeraldAction.php',
'PhabricatorSubscriptionsRemoveSubscribersHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsRemoveSubscribersHeraldAction.php',
+ 'PhabricatorSubscriptionsSearchEngineAttachment' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsSearchEngineAttachment.php',
'PhabricatorSubscriptionsSearchEngineExtension' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsSearchEngineExtension.php',
'PhabricatorSubscriptionsSubscribeEmailCommand' => 'applications/subscriptions/command/PhabricatorSubscriptionsSubscribeEmailCommand.php',
'PhabricatorSubscriptionsSubscribersPolicyRule' => 'applications/subscriptions/policyrule/PhabricatorSubscriptionsSubscribersPolicyRule.php',
@@ -7321,6 +7323,7 @@
'PhabricatorSearchEditController' => 'PhabricatorSearchBaseController',
'PhabricatorSearchEngine' => 'Phobject',
'PhabricatorSearchEngineAPIMethod' => 'ConduitAPIMethod',
+ 'PhabricatorSearchEngineAttachment' => 'Phobject',
'PhabricatorSearchEngineExtension' => 'Phobject',
'PhabricatorSearchEngineExtensionModule' => 'PhabricatorConfigModule',
'PhabricatorSearchEngineTestCase' => 'PhabricatorTestCase',
@@ -7482,6 +7485,7 @@
'PhabricatorSubscriptionsListController' => 'PhabricatorController',
'PhabricatorSubscriptionsRemoveSelfHeraldAction' => 'PhabricatorSubscriptionsHeraldAction',
'PhabricatorSubscriptionsRemoveSubscribersHeraldAction' => 'PhabricatorSubscriptionsHeraldAction',
+ 'PhabricatorSubscriptionsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
'PhabricatorSubscriptionsSearchEngineExtension' => 'PhabricatorSearchEngineExtension',
'PhabricatorSubscriptionsSubscribeEmailCommand' => 'MetaMTAEmailTransactionCommand',
'PhabricatorSubscriptionsSubscribersPolicyRule' => 'PhabricatorPolicyRule',
diff --git a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php
--- a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php
+++ b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php
@@ -1123,10 +1123,25 @@
$this->saveQuery($saved_query);
-
$query = $this->buildQueryFromSavedQuery($saved_query);
$pager = $this->newPagerForSavedQuery($saved_query);
+ $attachments = $this->getConduitSearchAttachments();
+
+ // TODO: Validate this better.
+ $attachment_specs = $request->getValue('attachments');
+ $attachments = array_select_keys(
+ $attachments,
+ array_keys($attachment_specs));
+
+ foreach ($attachments as $key => $attachment) {
+ $attachment->setViewer($viewer);
+ }
+
+ foreach ($attachments as $key => $attachment) {
+ $attachment->willLoadAttachmentData($query, $attachment_specs[$key]);
+ }
+
$this->setQueryOrderForConduit($query, $request);
$this->setPagerLimitForConduit($pager, $request);
$this->setPagerOffsetsForConduit($pager, $request);
@@ -1137,10 +1152,36 @@
if ($objects) {
$field_extensions = $this->getConduitFieldExtensions();
+ $attachment_data = array();
+ foreach ($attachments as $key => $attachment) {
+ $attachment_data[$key] = $attachment->loadAttachmentData(
+ $objects,
+ $attachment_specs[$key]);
+ }
+
foreach ($objects as $object) {
- $data[] = $this->getObjectWireFormatForConduit(
+ $field_map = $this->getObjectWireFieldsForConduit(
$object,
$field_extensions);
+
+ $attachment_map = array();
+ foreach ($attachments as $key => $attachment) {
+ $attachment_map[$key] = $attachment->getAttachmentForObject(
+ $object,
+ $attachment_data[$key],
+ $attachment_specs[$key]);
+ }
+
+ $id = (int)$object->getID();
+ $phid = $object->getPHID();
+
+ $data[] = array(
+ 'id' => $id,
+ 'type' => phid_get_type($phid),
+ 'phid' => $phid,
+ 'fields' => $field_map,
+ 'attachments' => $attachment_map,
+ );
}
}
@@ -1264,21 +1305,6 @@
}
}
- protected function getObjectWireFormatForConduit(
- $object,
- array $field_extensions) {
- $phid = $object->getPHID();
-
- return array(
- 'id' => (int)$object->getID(),
- 'type' => phid_get_type($phid),
- 'phid' => $phid,
- 'fields' => $this->getObjectWireFieldsForConduit(
- $object,
- $field_extensions),
- );
- }
-
protected function getObjectWireFieldsForConduit(
$object,
array $field_extensions) {
@@ -1291,4 +1317,29 @@
return $fields;
}
+ public function getConduitSearchAttachments() {
+ $extensions = $this->getEngineExtensions();
+
+ $attachments = array();
+ foreach ($extensions as $extension) {
+ $extension_attachments = $extension->getSearchAttachments();
+ foreach ($extension_attachments as $attachment) {
+ $attachment_key = $attachment->getAttachmentKey();
+ if (isset($attachments[$attachment_key])) {
+ $other = $attachments[$attachment_key];
+ throw new Exception(
+ pht(
+ 'Two search engine attachments (of classes "%s" and "%s") '.
+ 'specify the same attachment key ("%s"); keys must be unique.',
+ get_class($attachment),
+ get_class($other),
+ $attachment_key));
+ }
+ $attachments[$attachment_key] = $attachment;
+ }
+ }
+
+ return $attachments;
+ }
+
}
diff --git a/src/applications/search/engine/PhabricatorSearchEngineAPIMethod.php b/src/applications/search/engine/PhabricatorSearchEngineAPIMethod.php
--- a/src/applications/search/engine/PhabricatorSearchEngineAPIMethod.php
+++ b/src/applications/search/engine/PhabricatorSearchEngineAPIMethod.php
@@ -23,6 +23,7 @@
return array(
'queryKey' => 'optional string',
'constraints' => 'optional map<string, wild>',
+ 'attachments' => 'optional map<string, bool>',
'order' => 'optional order',
) + $this->getPagerParamTypes();
}
@@ -58,6 +59,7 @@
$out[] = $this->buildConstraintsBox($engine);
$out[] = $this->buildOrderBox($engine, $query);
$out[] = $this->buildFieldsBox($engine);
+ $out[] = $this->buildAttachmentsBox($engine);
$out[] = $this->buildPagingBox($engine);
return $out;
@@ -401,6 +403,94 @@
->appendChild($table);
}
+ private function buildAttachmentsBox(
+ PhabricatorApplicationSearchEngine $engine) {
+
+ $info = pht(<<<EOTEXT
+By default, only basic information about objects is returned. If you want
+more extensive information, you can use available `attachments` to get more
+information in the results (like subscribers and projects).
+
+Generally, requesting more information means the query executes more slowly
+and returns more data (in some cases, much more data). You should normally
+request only the data you need.
+
+To request extra data, specify which attachments you want in the `attachments`
+parameter:
+
+```lang=json, name="Example Attachments Request"
+{
+ ...
+ "attachments": {
+ "subscribers": true
+ },
+ ...
+}
+```
+
+This example specifies that results should include information about
+subscribers. In the return value, each object will now have this information
+filled out in the corresponding `attachments` value:
+
+```lang=json, name="Example Attachments Result"
+{
+ ...
+ "data": [
+ {
+ ...
+ "attachments": {
+ "subscribers": {
+ "subscriberPHIDs": [
+ "PHID-WXYZ-2222",
+ ],
+ "subscriberCount": 1,
+ "viewerIsSubscribed": false
+ }
+ },
+ ...
+ },
+ ...
+ ],
+ ...
+}
+```
+
+These attachments are available:
+EOTEXT
+ );
+
+ $attachments = $engine->getConduitSearchAttachments();
+
+ $rows = array();
+ foreach ($attachments as $key => $attachment) {
+ $rows[] = array(
+ $key,
+ $attachment->getAttachmentName(),
+ $attachment->getAttachmentDescription(),
+ );
+ }
+
+ $table = id(new AphrontTableView($rows))
+ ->setHeaders(
+ array(
+ pht('Key'),
+ pht('Name'),
+ pht('Description'),
+ ))
+ ->setColumnClasses(
+ array(
+ 'prewrap',
+ 'pri',
+ 'wide',
+ ));
+
+ return id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('Attachments'))
+ ->setCollapsed(true)
+ ->appendChild($this->buildRemarkup($info))
+ ->appendChild($table);
+ }
+
private function buildPagingBox(
PhabricatorApplicationSearchEngine $engine) {
diff --git a/src/applications/search/engineextension/PhabricatorSearchEngineAttachment.php b/src/applications/search/engineextension/PhabricatorSearchEngineAttachment.php
new file mode 100644
--- /dev/null
+++ b/src/applications/search/engineextension/PhabricatorSearchEngineAttachment.php
@@ -0,0 +1,50 @@
+<?php
+
+abstract class PhabricatorSearchEngineAttachment extends Phobject {
+
+ private $attachmentKey;
+ private $viewer;
+ private $searchEngine;
+
+ final public function setViewer($viewer) {
+ $this->viewer = $viewer;
+ return $this;
+ }
+
+ final public function getViewer() {
+ return $this->viewer;
+ }
+
+ final public function setSearchEngine(
+ PhabricatorApplicationSearchEngine $engine) {
+ $this->searchEngine = $engine;
+ return $this;
+ }
+
+ final public function getSearchEngine() {
+ return $this->searchEngine;
+ }
+
+ public function setAttachmentKey($attachment_key) {
+ $this->attachmentKey = $attachment_key;
+ return $this;
+ }
+
+ public function getAttachmentKey() {
+ return $this->attachmentKey;
+ }
+
+ abstract public function getAttachmentName();
+ abstract public function getAttachmentDescription();
+
+ public function willLoadAttachmentData($query, $spec) {
+ return;
+ }
+
+ public function loadAttachmentData(array $objects, $spec) {
+ return null;
+ }
+
+ abstract public function getAttachmentForObject($object, $data, $spec);
+
+}
diff --git a/src/applications/search/engineextension/PhabricatorSearchEngineExtension.php b/src/applications/search/engineextension/PhabricatorSearchEngineExtension.php
--- a/src/applications/search/engineextension/PhabricatorSearchEngineExtension.php
+++ b/src/applications/search/engineextension/PhabricatorSearchEngineExtension.php
@@ -40,6 +40,10 @@
return array();
}
+ public function getSearchAttachments() {
+ return array();
+ }
+
public function applyConstraintsToQuery(
$object,
$query,
diff --git a/src/applications/subscriptions/engineextension/PhabricatorSubscriptionsSearchEngineAttachment.php b/src/applications/subscriptions/engineextension/PhabricatorSubscriptionsSearchEngineAttachment.php
new file mode 100644
--- /dev/null
+++ b/src/applications/subscriptions/engineextension/PhabricatorSubscriptionsSearchEngineAttachment.php
@@ -0,0 +1,84 @@
+<?php
+
+final class PhabricatorSubscriptionsSearchEngineAttachment
+ extends PhabricatorSearchEngineAttachment {
+
+ public function getAttachmentName() {
+ return pht('Subscribers');
+ }
+
+ public function getAttachmentDescription() {
+ return pht('Get information about subscribers.');
+ }
+
+ public function loadAttachmentData(array $objects, $spec) {
+ $object_phids = mpull($objects, 'getPHID');
+ $edge_type = PhabricatorObjectHasSubscriberEdgeType::EDGECONST;
+
+
+ $subscribers_query = id(new PhabricatorEdgeQuery())
+ ->withSourcePHIDs($object_phids)
+ ->withEdgeTypes(array($edge_type));
+ $subscribers_query->execute();
+
+ $viewer = $this->getViewer();
+ $viewer_phid = $viewer->getPHID();
+ if ($viewer) {
+ $edges = id(new PhabricatorEdgeQuery())
+ ->withSourcePHIDs($object_phids)
+ ->withEdgeTypes(array($edge_type))
+ ->withDestinationPHIDs(array($viewer_phid))
+ ->execute();
+
+ $viewer_map = array();
+ foreach ($edges as $object_phid => $types) {
+ if ($types[$edge_type]) {
+ $viewer_map[$object_phid] = true;
+ }
+ }
+ } else {
+ $viewer_map = array();
+ }
+
+ return array(
+ 'subscribers.query' => $subscribers_query,
+ 'viewer.map' => $viewer_map,
+ );
+ }
+
+ public function getAttachmentForObject($object, $data, $spec) {
+ $subscribers_query = idx($data, 'subscribers.query');
+ $viewer_map = idx($data, 'viewer.map');
+ $object_phid = $object->getPHID();
+
+ $subscribed_phids = $subscribers_query->getDestinationPHIDs(
+ array($object_phid),
+ array(PhabricatorObjectHasSubscriberEdgeType::EDGECONST));
+ $subscribed_count = count($subscribed_phids);
+ if ($subscribed_count > 10) {
+ $subscribed_phids = array_slice($subscribed_phids, 0, 10);
+ }
+
+ $subscribed_phids = array_values($subscribed_phids);
+
+ $viewer = $this->getViewer();
+ $viewer_phid = $viewer->getPHID();
+
+ if (!$viewer_phid) {
+ $self_subscribed = false;
+ } else if (isset($viewer_map[$object_phid])) {
+ $self_subscribed = true;
+ } else if ($object->isAutomaticallySubscribed($viewer_phid)) {
+ $self_subscribed = true;
+ } else {
+ $self_subscribed = false;
+ }
+
+ return array(
+ 'subscriberPHIDs' => $subscribed_phids,
+ 'subscriberCount' => $subscribed_count,
+ 'viewerIsSubscribed' => $self_subscribed,
+ );
+ }
+
+}
diff --git a/src/applications/subscriptions/engineextension/PhabricatorSubscriptionsSearchEngineExtension.php b/src/applications/subscriptions/engineextension/PhabricatorSubscriptionsSearchEngineExtension.php
--- a/src/applications/subscriptions/engineextension/PhabricatorSubscriptionsSearchEngineExtension.php
+++ b/src/applications/subscriptions/engineextension/PhabricatorSubscriptionsSearchEngineExtension.php
@@ -50,5 +50,11 @@
return $fields;
}
+ public function getSearchAttachments() {
+ return array(
+ id(new PhabricatorSubscriptionsSearchEngineAttachment())
+ ->setAttachmentKey('subscribers'),
+ );
+ }
}
diff --git a/src/applications/transactions/editfield/PhabricatorEditField.php b/src/applications/transactions/editfield/PhabricatorEditField.php
--- a/src/applications/transactions/editfield/PhabricatorEditField.php
+++ b/src/applications/transactions/editfield/PhabricatorEditField.php
@@ -516,7 +516,7 @@
$edit_type = $this->getEditType();
if ($edit_type === null) {
- return null;
+ return array();
}
return array($edit_type);
@@ -526,7 +526,7 @@
$edit_type = $this->getEditType();
if ($edit_type === null) {
- return null;
+ return array();
}
return array($edit_type);

File Metadata

Mime Type
text/plain
Expires
Sat, Oct 19, 4:13 AM (3 w, 5 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6727819
Default Alt Text
D14772.id35727.diff (15 KB)

Event Timeline