Page MenuHomePhorge

No OneTemporary

diff --git a/src/infrastructure/edges/query/PhabricatorEdgeQuery.php b/src/infrastructure/edges/query/PhabricatorEdgeQuery.php
index fdeb8fda8b..4676829231 100644
--- a/src/infrastructure/edges/query/PhabricatorEdgeQuery.php
+++ b/src/infrastructure/edges/query/PhabricatorEdgeQuery.php
@@ -1,215 +1,276 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Load object edges created by @{class:PhabricatorEdgeEditor}.
*
* name=Querying Edges
* $src = $earth_phid;
* $type = PhabricatorEdgeConfig::TYPE_BODY_HAS_SATELLITE;
*
* // Load the earth's satellites.
* $satellite_edges = id(new PhabricatorEdgeQuery())
* ->withSourcePHIDs(array($src))
* ->withEdgeTypes(array($type))
* ->execute();
*
* For more information on edges, see @{article:Using Edges}.
*
* @task config Configuring the Query
* @task exec Executing the Query
* @task internal Internal
*/
final class PhabricatorEdgeQuery extends PhabricatorQuery {
private $sourcePHIDs;
private $edgeTypes;
+ private $resultSet;
private $needEdgeData;
/* -( Configuring the Query )---------------------------------------------- */
/**
* Find edges originating at one or more source PHIDs. You MUST provide this
* to execute an edge query.
*
* @param list List of source PHIDs.
* @return this
*
* @task config
*/
public function withSourcePHIDs(array $source_phids) {
$this->sourcePHIDs = $source_phids;
return $this;
}
/**
* Find edges of specific types.
*
* @param list List of PhabricatorEdgeConfig type constants.
* @return this
*
* @task config
*/
public function withEdgeTypes(array $types) {
$this->edgeTypes = $types;
return $this;
}
/**
* When loading edges, also load edge data.
*
* @param bool True to load edge data.
* @return this
*
* @task config
*/
public function needEdgeData($need) {
$this->needEdgeData = $need;
return $this;
}
/* -( Executing the Query )------------------------------------------------ */
/**
* Convenience method for loading destination PHIDs with one source and one
* edge type. Equivalent to building a full query, but simplifies a common
* use case.
*
* @param phid Source PHID.
* @param const Edge type.
* @return list<phid> List of destination PHIDs.
*/
public static function loadDestinationPHIDs($src_phid, $edge_type) {
$edges = id(new PhabricatorEdgeQuery())
->withSourcePHIDs(array($src_phid))
->withEdgeTypes(array($edge_type))
->execute();
return array_keys($edges[$src_phid][$edge_type]);
}
/**
* Load specified edges.
*
* @task exec
*/
public function execute() {
if (!$this->sourcePHIDs) {
throw new Exception(
"You must use withSourcePHIDs() to query edges.");
}
$sources = phid_group_by_type($this->sourcePHIDs);
$result = array();
// When a query specifies types, make sure we return data for all queried
// types. This is mostly to make sure PhabricatorLiskDAO->attachEdges()
// gets some data, so that getEdges() doesn't throw later.
if ($this->edgeTypes) {
foreach ($this->sourcePHIDs as $phid) {
foreach ($this->edgeTypes as $type) {
$result[$phid][$type] = array();
}
}
}
foreach ($sources as $type => $phids) {
$conn_r = PhabricatorEdgeConfig::establishConnection($type, 'r');
$where = $this->buildWhereClause($conn_r);
$order = $this->buildOrderClause($conn_r);
$edges = queryfx_all(
$conn_r,
'SELECT edge.* FROM %T edge %Q %Q',
PhabricatorEdgeConfig::TABLE_NAME_EDGE,
$where,
$order);
if ($this->needEdgeData) {
$data_ids = array_filter(ipull($edges, 'dataID'));
$data_map = array();
if ($data_ids) {
$data_rows = queryfx_all(
$conn_r,
'SELECT edgedata.* FROM %T edgedata WHERE id IN (%Ld)',
PhabricatorEdgeConfig::TABLE_NAME_EDGEDATA,
$data_ids);
foreach ($data_rows as $row) {
$data_map[$row['id']] = idx(
json_decode($row['data'], true),
'data');
}
}
foreach ($edges as $key => $edge) {
$edges[$key]['data'] = idx($data_map, $edge['dataID']);
}
}
foreach ($edges as $edge) {
$result[$edge['src']][$edge['type']][$edge['dst']] = $edge;
}
}
+ $this->resultSet = $result;
return $result;
}
+ /**
+ * Convenience function for selecting edge destination PHIDs after calling
+ * execute().
+ *
+ * Returns a flat list of PHIDs matching the provided source PHID and type
+ * filters. By default, the filters are empty so all PHIDs will be returned.
+ * For example, if you're doing a batch query from several sources, you might
+ * write code like this:
+ *
+ * $query = new PhabricatorEdgeQuery();
+ * $query->withSourcePHIDs(mpull($objects, 'getPHID'));
+ * $query->withEdgeTypes(array($some_type));
+ * $query->execute();
+ *
+ * // Gets all of the destinations.
+ * $all_phids = $query->getDestinationPHIDs();
+ * $handles = id(new PhabricatorObjectHandleData($all_phids))
+ * ->loadHandles();
+ *
+ * foreach ($objects as $object) {
+ * // Get all of the destinations for the given object.
+ * $dst_phids = $query->getDestinationPHIDs(array($object->getPHID()));
+ * $object->attachHandles(array_select_keys($handles, $dst_phids));
+ * }
+ *
+ * @param list? List of PHIDs to select, or empty to select all.
+ * @param list? List of edge types to select, or empty to select all.
+ * @return list<phid> List of matching destination PHIDs.
+ */
+ public function getDestinationPHIDs(
+ array $src_phids = array(),
+ array $types = array()) {
+ if ($this->resultSet === null) {
+ throw new Exception(
+ "You must execute() a query before you you can getDestinationPHIDs().");
+ }
+
+ $src_phids = array_fill_keys($src_phids, true);
+ $types = array_fill_keys($types, true);
+
+ $result_phids = array();
+ foreach ($this->resultSet as $src => $edges_by_type) {
+ if ($src_phids && empty($src_phids[$src])) {
+ continue;
+ }
+ foreach ($edges_by_type as $type => $edges_by_dst) {
+ if ($types && empty($types[$type])) {
+ continue;
+ }
+ foreach ($edges_by_dst as $dst => $edge) {
+ $result_phids[$dst] = true;
+ }
+ }
+ }
+
+ return array_keys($result_phids);
+ }
+
+
/* -( Internals )---------------------------------------------------------- */
/**
* @task internal
*/
private function buildWhereClause($conn_r) {
$where = array();
if ($this->sourcePHIDs) {
$where[] = qsprintf(
$conn_r,
'edge.src IN (%Ls)',
$this->sourcePHIDs);
}
if ($this->edgeTypes) {
$where[] = qsprintf(
$conn_r,
'edge.type IN (%Ls)',
$this->edgeTypes);
}
return $this->formatWhereClause($where);
}
/**
* @task internal
*/
private function buildOrderClause($conn_r) {
return 'ORDER BY edge.dateCreated DESC, edge.seq ASC';
}
}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Jan 19, 13:10 (3 w, 3 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1124928
Default Alt Text
(7 KB)

Event Timeline