@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
at upstream/main 182 lines 4.5 kB view raw
1<?php 2 3/** 4 * This is a more formal version of @{class:PhabricatorEdgeQuery} that is used 5 * to expose edges to Conduit. 6 */ 7final class PhabricatorEdgeObjectQuery 8 extends PhabricatorCursorPagedPolicyAwareQuery { 9 10 private $sourcePHIDs; 11 private $sourcePHIDType; 12 private $edgeTypes; 13 private $destinationPHIDs; 14 15 public function withSourcePHIDs(array $source_phids) { 16 $this->sourcePHIDs = $source_phids; 17 return $this; 18 } 19 20 public function withEdgeTypes(array $types) { 21 $this->edgeTypes = $types; 22 return $this; 23 } 24 25 public function withDestinationPHIDs(array $destination_phids) { 26 $this->destinationPHIDs = $destination_phids; 27 return $this; 28 } 29 30 protected function willExecute() { 31 $source_phids = $this->sourcePHIDs; 32 33 if (!$source_phids) { 34 throw new Exception( 35 pht( 36 'Edge object query must be executed with a nonempty list of '. 37 'source PHIDs.')); 38 } 39 40 $phid_item = null; 41 $phid_type = null; 42 foreach ($source_phids as $phid) { 43 $this_type = phid_get_type($phid); 44 if ($this_type == PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN) { 45 throw new Exception( 46 pht( 47 'Source PHID "%s" in edge object query has unknown PHID type.', 48 $phid)); 49 } 50 51 if ($phid_type === null) { 52 $phid_type = $this_type; 53 $phid_item = $phid; 54 continue; 55 } 56 57 if ($phid_type !== $this_type) { 58 throw new Exception( 59 pht( 60 'Two source PHIDs ("%s" and "%s") have different PHID types '. 61 '("%s" and "%s"). All PHIDs must be of the same type to execute '. 62 'an edge object query.', 63 $phid_item, 64 $phid, 65 $phid_type, 66 $this_type)); 67 } 68 } 69 70 $this->sourcePHIDType = $phid_type; 71 } 72 73 protected function loadPage() { 74 $type = $this->sourcePHIDType; 75 $conn = PhabricatorEdgeConfig::establishConnection($type, 'r'); 76 $table = PhabricatorEdgeConfig::TABLE_NAME_EDGE; 77 $rows = $this->loadStandardPageRowsWithConnection($conn, $table); 78 79 $result = array(); 80 foreach ($rows as $row) { 81 $result[] = PhabricatorEdgeObject::newFromRow($row); 82 } 83 84 return $result; 85 } 86 87 protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { 88 $parts = parent::buildWhereClauseParts($conn); 89 90 $parts[] = qsprintf( 91 $conn, 92 'src IN (%Ls)', 93 $this->sourcePHIDs); 94 95 $parts[] = qsprintf( 96 $conn, 97 'type IN (%Ls)', 98 $this->edgeTypes); 99 100 if ($this->destinationPHIDs !== null) { 101 $parts[] = qsprintf( 102 $conn, 103 'dst IN (%Ls)', 104 $this->destinationPHIDs); 105 } 106 107 return $parts; 108 } 109 110 public function getQueryApplicationClass() { 111 return null; 112 } 113 114 protected function getPrimaryTableAlias() { 115 return 'edge'; 116 } 117 118 public function getOrderableColumns() { 119 return array( 120 'dateCreated' => array( 121 'table' => 'edge', 122 'column' => 'dateCreated', 123 'type' => 'int', 124 ), 125 'sequence' => array( 126 'table' => 'edge', 127 'column' => 'seq', 128 'type' => 'int', 129 130 // TODO: This is not actually unique, but we're just doing our best 131 // here. 132 'unique' => true, 133 ), 134 ); 135 } 136 137 protected function getDefaultOrderVector() { 138 return array('dateCreated', 'sequence'); 139 } 140 141 protected function newInternalCursorFromExternalCursor($cursor) { 142 list($epoch, $sequence) = $this->parseCursor($cursor); 143 144 // Instead of actually loading an edge, we're just making a fake edge 145 // with the properties the cursor describes. 146 147 $edge_object = PhabricatorEdgeObject::newFromRow( 148 array( 149 'dateCreated' => $epoch, 150 'seq' => $sequence, 151 )); 152 153 return id(new PhabricatorQueryCursor()) 154 ->setObject($edge_object); 155 } 156 157 protected function newPagingMapFromPartialObject($object) { 158 return array( 159 'dateCreated' => $object->getDateCreated(), 160 'sequence' => $object->getSequence(), 161 ); 162 } 163 164 protected function newExternalCursorStringForResult($object) { 165 return sprintf( 166 '%d_%d', 167 $object->getDateCreated(), 168 $object->getSequence()); 169 } 170 171 private function parseCursor($cursor) { 172 if (!preg_match('/^\d+_\d+\z/', $cursor)) { 173 $this->throwCursorException( 174 pht( 175 'Expected edge cursor in the form "0123_6789", got "%s".', 176 $cursor)); 177 } 178 179 return explode('_', $cursor); 180 } 181 182}