[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
1 <?php 2 3 final class PhabricatorFileQuery 4 extends PhabricatorCursorPagedPolicyAwareQuery { 5 6 private $ids; 7 private $phids; 8 private $authorPHIDs; 9 private $explicitUploads; 10 private $transforms; 11 private $dateCreatedAfter; 12 private $dateCreatedBefore; 13 private $contentHashes; 14 15 public function withIDs(array $ids) { 16 $this->ids = $ids; 17 return $this; 18 } 19 20 public function withPHIDs(array $phids) { 21 $this->phids = $phids; 22 return $this; 23 } 24 25 public function withAuthorPHIDs(array $phids) { 26 $this->authorPHIDs = $phids; 27 return $this; 28 } 29 30 public function withDateCreatedBefore($date_created_before) { 31 $this->dateCreatedBefore = $date_created_before; 32 return $this; 33 } 34 35 public function withDateCreatedAfter($date_created_after) { 36 $this->dateCreatedAfter = $date_created_after; 37 return $this; 38 } 39 40 public function withContentHashes(array $content_hashes) { 41 $this->contentHashes = $content_hashes; 42 return $this; 43 } 44 45 /** 46 * Select files which are transformations of some other file. For example, 47 * you can use this query to find previously generated thumbnails of an image 48 * file. 49 * 50 * As a parameter, provide a list of transformation specifications. Each 51 * specification is a dictionary with the keys `originalPHID` and `transform`. 52 * The `originalPHID` is the PHID of the original file (the file which was 53 * transformed) and the `transform` is the name of the transform to query 54 * for. If you pass `true` as the `transform`, all transformations of the 55 * file will be selected. 56 * 57 * For example: 58 * 59 * array( 60 * array( 61 * 'originalPHID' => 'PHID-FILE-aaaa', 62 * 'transform' => 'sepia', 63 * ), 64 * array( 65 * 'originalPHID' => 'PHID-FILE-bbbb', 66 * 'transform' => true, 67 * ), 68 * ) 69 * 70 * This selects the `"sepia"` transformation of the file with PHID 71 * `PHID-FILE-aaaa` and all transformations of the file with PHID 72 * `PHID-FILE-bbbb`. 73 * 74 * @param list<dict> List of transform specifications, described above. 75 * @return this 76 */ 77 public function withTransforms(array $specs) { 78 foreach ($specs as $spec) { 79 if (!is_array($spec) || 80 empty($spec['originalPHID']) || 81 empty($spec['transform'])) { 82 throw new Exception( 83 "Transform specification must be a dictionary with keys ". 84 "'originalPHID' and 'transform'!"); 85 } 86 } 87 88 $this->transforms = $specs; 89 return $this; 90 } 91 92 public function showOnlyExplicitUploads($explicit_uploads) { 93 $this->explicitUploads = $explicit_uploads; 94 return $this; 95 } 96 97 protected function loadPage() { 98 $table = new PhabricatorFile(); 99 $conn_r = $table->establishConnection('r'); 100 101 $data = queryfx_all( 102 $conn_r, 103 'SELECT f.* FROM %T f %Q %Q %Q %Q', 104 $table->getTableName(), 105 $this->buildJoinClause($conn_r), 106 $this->buildWhereClause($conn_r), 107 $this->buildOrderClause($conn_r), 108 $this->buildLimitClause($conn_r)); 109 110 $files = $table->loadAllFromArray($data); 111 112 if (!$files) { 113 return $files; 114 } 115 116 // We need to load attached objects to perform policy checks for files. 117 // First, load the edges. 118 119 $edge_type = PhabricatorEdgeConfig::TYPE_FILE_HAS_OBJECT; 120 $file_phids = mpull($files, 'getPHID'); 121 $edges = id(new PhabricatorEdgeQuery()) 122 ->withSourcePHIDs($file_phids) 123 ->withEdgeTypes(array($edge_type)) 124 ->execute(); 125 126 $object_phids = array(); 127 foreach ($files as $file) { 128 $phids = array_keys($edges[$file->getPHID()][$edge_type]); 129 $file->attachObjectPHIDs($phids); 130 foreach ($phids as $phid) { 131 $object_phids[$phid] = true; 132 } 133 } 134 135 // If this file is a transform of another file, load that file too. If you 136 // can see the original file, you can see the thumbnail. 137 138 // TODO: It might be nice to put this directly on PhabricatorFile and remove 139 // the PhabricatorTransformedFile table, which would be a little simpler. 140 141 $xforms = id(new PhabricatorTransformedFile())->loadAllWhere( 142 'transformedPHID IN (%Ls)', 143 $file_phids); 144 $xform_phids = mpull($xforms, 'getOriginalPHID', 'getTransformedPHID'); 145 foreach ($xform_phids as $derived_phid => $original_phid) { 146 $object_phids[$original_phid] = true; 147 } 148 149 $object_phids = array_keys($object_phids); 150 151 // Now, load the objects. 152 153 $objects = array(); 154 if ($object_phids) { 155 // NOTE: We're explicitly turning policy exceptions off, since the rule 156 // here is "you can see the file if you can see ANY associated object". 157 // Without this explicit flag, we'll incorrectly throw unless you can 158 // see ALL associated objects. 159 160 $objects = id(new PhabricatorObjectQuery()) 161 ->setParentQuery($this) 162 ->setViewer($this->getViewer()) 163 ->withPHIDs($object_phids) 164 ->setRaisePolicyExceptions(false) 165 ->execute(); 166 $objects = mpull($objects, null, 'getPHID'); 167 } 168 169 foreach ($files as $file) { 170 $file_objects = array_select_keys($objects, $file->getObjectPHIDs()); 171 $file->attachObjects($file_objects); 172 } 173 174 foreach ($files as $key => $file) { 175 $original_phid = idx($xform_phids, $file->getPHID()); 176 if ($original_phid == PhabricatorPHIDConstants::PHID_VOID) { 177 // This is a special case for builtin files, which are handled 178 // oddly. 179 $original = null; 180 } else if ($original_phid) { 181 $original = idx($objects, $original_phid); 182 if (!$original) { 183 // If the viewer can't see the original file, also prevent them from 184 // seeing the transformed file. 185 $this->didRejectResult($file); 186 unset($files[$key]); 187 continue; 188 } 189 } else { 190 $original = null; 191 } 192 $file->attachOriginalFile($original); 193 } 194 195 return $files; 196 } 197 198 private function buildJoinClause(AphrontDatabaseConnection $conn_r) { 199 $joins = array(); 200 201 if ($this->transforms) { 202 $joins[] = qsprintf( 203 $conn_r, 204 'JOIN %T t ON t.transformedPHID = f.phid', 205 id(new PhabricatorTransformedFile())->getTableName()); 206 } 207 208 return implode(' ', $joins); 209 } 210 211 private function buildWhereClause(AphrontDatabaseConnection $conn_r) { 212 $where = array(); 213 214 $where[] = $this->buildPagingClause($conn_r); 215 216 if ($this->ids) { 217 $where[] = qsprintf( 218 $conn_r, 219 'f.id IN (%Ld)', 220 $this->ids); 221 } 222 223 if ($this->phids) { 224 $where[] = qsprintf( 225 $conn_r, 226 'f.phid IN (%Ls)', 227 $this->phids); 228 } 229 230 if ($this->authorPHIDs) { 231 $where[] = qsprintf( 232 $conn_r, 233 'f.authorPHID IN (%Ls)', 234 $this->authorPHIDs); 235 } 236 237 if ($this->explicitUploads) { 238 $where[] = qsprintf( 239 $conn_r, 240 'f.isExplicitUpload = true'); 241 } 242 243 if ($this->transforms) { 244 $clauses = array(); 245 foreach ($this->transforms as $transform) { 246 if ($transform['transform'] === true) { 247 $clauses[] = qsprintf( 248 $conn_r, 249 '(t.originalPHID = %s)', 250 $transform['originalPHID']); 251 } else { 252 $clauses[] = qsprintf( 253 $conn_r, 254 '(t.originalPHID = %s AND t.transform = %s)', 255 $transform['originalPHID'], 256 $transform['transform']); 257 } 258 } 259 $where[] = qsprintf($conn_r, '(%Q)', implode(') OR (', $clauses)); 260 } 261 262 if ($this->dateCreatedAfter) { 263 $where[] = qsprintf( 264 $conn_r, 265 'f.dateCreated >= %d', 266 $this->dateCreatedAfter); 267 } 268 269 if ($this->dateCreatedBefore) { 270 $where[] = qsprintf( 271 $conn_r, 272 'f.dateCreated <= %d', 273 $this->dateCreatedBefore); 274 } 275 276 if ($this->contentHashes) { 277 $where[] = qsprintf( 278 $conn_r, 279 'f.contentHash IN (%Ls)', 280 $this->contentHashes); 281 } 282 283 return $this->formatWhereClause($where); 284 } 285 286 protected function getPagingColumn() { 287 return 'f.id'; 288 } 289 290 public function getQueryApplicationClass() { 291 return 'PhabricatorFilesApplication'; 292 } 293 294 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Nov 30 09:20:46 2014 | Cross-referenced by PHPXref 0.7.1 |