Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401]
1 <?php 2 /* 3 * Copyright 2016-2017 MongoDB, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 namespace MongoDB\GridFS; 19 20 use MongoDB\Collection; 21 use MongoDB\Driver\Cursor; 22 use MongoDB\Driver\Manager; 23 use MongoDB\Driver\ReadPreference; 24 use MongoDB\Exception\InvalidArgumentException; 25 use MongoDB\UpdateResult; 26 use stdClass; 27 use function abs; 28 use function sprintf; 29 30 /** 31 * CollectionWrapper abstracts the GridFS files and chunks collections. 32 * 33 * @internal 34 */ 35 class CollectionWrapper 36 { 37 /** @var string */ 38 private $bucketName; 39 40 /** @var Collection */ 41 private $chunksCollection; 42 43 /** @var string */ 44 private $databaseName; 45 46 /** @var boolean */ 47 private $checkedIndexes = false; 48 49 /** @var Collection */ 50 private $filesCollection; 51 52 /** 53 * Constructs a GridFS collection wrapper. 54 * 55 * @see Collection::__construct() for supported options 56 * @param Manager $manager Manager instance from the driver 57 * @param string $databaseName Database name 58 * @param string $bucketName Bucket name 59 * @param array $collectionOptions Collection options 60 * @throws InvalidArgumentException 61 */ 62 public function __construct(Manager $manager, $databaseName, $bucketName, array $collectionOptions = []) 63 { 64 $this->databaseName = (string) $databaseName; 65 $this->bucketName = (string) $bucketName; 66 67 $this->filesCollection = new Collection($manager, $databaseName, sprintf('%s.files', $bucketName), $collectionOptions); 68 $this->chunksCollection = new Collection($manager, $databaseName, sprintf('%s.chunks', $bucketName), $collectionOptions); 69 } 70 71 /** 72 * Deletes all GridFS chunks for a given file ID. 73 * 74 * @param mixed $id 75 */ 76 public function deleteChunksByFilesId($id) 77 { 78 $this->chunksCollection->deleteMany(['files_id' => $id]); 79 } 80 81 /** 82 * Deletes a GridFS file and related chunks by ID. 83 * 84 * @param mixed $id 85 */ 86 public function deleteFileAndChunksById($id) 87 { 88 $this->filesCollection->deleteOne(['_id' => $id]); 89 $this->chunksCollection->deleteMany(['files_id' => $id]); 90 } 91 92 /** 93 * Drops the GridFS files and chunks collections. 94 */ 95 public function dropCollections() 96 { 97 $this->filesCollection->drop(['typeMap' => []]); 98 $this->chunksCollection->drop(['typeMap' => []]); 99 } 100 101 /** 102 * Finds GridFS chunk documents for a given file ID and optional offset. 103 * 104 * @param mixed $id File ID 105 * @param integer $fromChunk Starting chunk (inclusive) 106 * @return Cursor 107 */ 108 public function findChunksByFileId($id, $fromChunk = 0) 109 { 110 return $this->chunksCollection->find( 111 [ 112 'files_id' => $id, 113 'n' => ['$gte' => $fromChunk], 114 ], 115 [ 116 'sort' => ['n' => 1], 117 'typeMap' => ['root' => 'stdClass'], 118 ] 119 ); 120 } 121 122 /** 123 * Finds a GridFS file document for a given filename and revision. 124 * 125 * Revision numbers are defined as follows: 126 * 127 * * 0 = the original stored file 128 * * 1 = the first revision 129 * * 2 = the second revision 130 * * etc… 131 * * -2 = the second most recent revision 132 * * -1 = the most recent revision 133 * 134 * @see Bucket::downloadToStreamByName() 135 * @see Bucket::openDownloadStreamByName() 136 * @param string $filename 137 * @param integer $revision 138 * @return stdClass|null 139 */ 140 public function findFileByFilenameAndRevision($filename, $revision) 141 { 142 $filename = (string) $filename; 143 $revision = (integer) $revision; 144 145 if ($revision < 0) { 146 $skip = abs($revision) - 1; 147 $sortOrder = -1; 148 } else { 149 $skip = $revision; 150 $sortOrder = 1; 151 } 152 153 return $this->filesCollection->findOne( 154 ['filename' => $filename], 155 [ 156 'skip' => $skip, 157 'sort' => ['uploadDate' => $sortOrder], 158 'typeMap' => ['root' => 'stdClass'], 159 ] 160 ); 161 } 162 163 /** 164 * Finds a GridFS file document for a given ID. 165 * 166 * @param mixed $id 167 * @return stdClass|null 168 */ 169 public function findFileById($id) 170 { 171 return $this->filesCollection->findOne( 172 ['_id' => $id], 173 ['typeMap' => ['root' => 'stdClass']] 174 ); 175 } 176 177 /** 178 * Finds documents from the GridFS bucket's files collection. 179 * 180 * @see Find::__construct() for supported options 181 * @param array|object $filter Query by which to filter documents 182 * @param array $options Additional options 183 * @return Cursor 184 */ 185 public function findFiles($filter, array $options = []) 186 { 187 return $this->filesCollection->find($filter, $options); 188 } 189 190 /** 191 * Finds a single document from the GridFS bucket's files collection. 192 * 193 * @param array|object $filter Query by which to filter documents 194 * @param array $options Additional options 195 * @return array|object|null 196 */ 197 public function findOneFile($filter, array $options = []) 198 { 199 return $this->filesCollection->findOne($filter, $options); 200 } 201 202 /** 203 * Return the bucket name. 204 * 205 * @return string 206 */ 207 public function getBucketName() 208 { 209 return $this->bucketName; 210 } 211 212 /** 213 * Return the chunks collection. 214 * 215 * @return Collection 216 */ 217 public function getChunksCollection() 218 { 219 return $this->chunksCollection; 220 } 221 222 /** 223 * Return the database name. 224 * 225 * @return string 226 */ 227 public function getDatabaseName() 228 { 229 return $this->databaseName; 230 } 231 232 /** 233 * Return the files collection. 234 * 235 * @return Collection 236 */ 237 public function getFilesCollection() 238 { 239 return $this->filesCollection; 240 } 241 242 /** 243 * Inserts a document into the chunks collection. 244 * 245 * @param array|object $chunk Chunk document 246 */ 247 public function insertChunk($chunk) 248 { 249 if (! $this->checkedIndexes) { 250 $this->ensureIndexes(); 251 } 252 253 $this->chunksCollection->insertOne($chunk); 254 } 255 256 /** 257 * Inserts a document into the files collection. 258 * 259 * The file document should be inserted after all chunks have been inserted. 260 * 261 * @param array|object $file File document 262 */ 263 public function insertFile($file) 264 { 265 if (! $this->checkedIndexes) { 266 $this->ensureIndexes(); 267 } 268 269 $this->filesCollection->insertOne($file); 270 } 271 272 /** 273 * Updates the filename field in the file document for a given ID. 274 * 275 * @param mixed $id 276 * @param string $filename 277 * @return UpdateResult 278 */ 279 public function updateFilenameForId($id, $filename) 280 { 281 return $this->filesCollection->updateOne( 282 ['_id' => $id], 283 ['$set' => ['filename' => (string) $filename]] 284 ); 285 } 286 287 /** 288 * Create an index on the chunks collection if it does not already exist. 289 */ 290 private function ensureChunksIndex() 291 { 292 foreach ($this->chunksCollection->listIndexes() as $index) { 293 if ($index->isUnique() && $index->getKey() === ['files_id' => 1, 'n' => 1]) { 294 return; 295 } 296 } 297 298 $this->chunksCollection->createIndex(['files_id' => 1, 'n' => 1], ['unique' => true]); 299 } 300 301 /** 302 * Create an index on the files collection if it does not already exist. 303 */ 304 private function ensureFilesIndex() 305 { 306 foreach ($this->filesCollection->listIndexes() as $index) { 307 if ($index->getKey() === ['filename' => 1, 'uploadDate' => 1]) { 308 return; 309 } 310 } 311 312 $this->filesCollection->createIndex(['filename' => 1, 'uploadDate' => 1]); 313 } 314 315 /** 316 * Ensure indexes on the files and chunks collections exist. 317 * 318 * This method is called once before the first write operation on a GridFS 319 * bucket. Indexes are only be created if the files collection is empty. 320 */ 321 private function ensureIndexes() 322 { 323 if ($this->checkedIndexes) { 324 return; 325 } 326 327 $this->checkedIndexes = true; 328 329 if (! $this->isFilesCollectionEmpty()) { 330 return; 331 } 332 333 $this->ensureFilesIndex(); 334 $this->ensureChunksIndex(); 335 } 336 337 /** 338 * Returns whether the files collection is empty. 339 * 340 * @return boolean 341 */ 342 private function isFilesCollectionEmpty() 343 { 344 return null === $this->filesCollection->findOne([], [ 345 'readPreference' => new ReadPreference(ReadPreference::RP_PRIMARY), 346 'projection' => ['_id' => 1], 347 'typeMap' => [], 348 ]); 349 } 350 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body