| Total Complexity | 60 |
| Total Lines | 585 |
| Duplicated Lines | 0 % |
| Changes | 0 | ||
Complex classes like AbstractFile often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use AbstractFile, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 24 | abstract class AbstractFile implements FileInterface |
||
| 25 | { |
||
| 26 | /** |
||
| 27 | * Various file properties |
||
| 28 | * |
||
| 29 | * Note that all properties, which only the persisted (indexed) files have are stored in this |
||
| 30 | * overall properties array only. The only properties which really exist as object properties of |
||
| 31 | * the file object are the storage, the identifier, the fileName and the indexing status. |
||
| 32 | * |
||
| 33 | * @var array |
||
| 34 | */ |
||
| 35 | protected $properties; |
||
| 36 | |||
| 37 | /** |
||
| 38 | * The storage this file is located in |
||
| 39 | * |
||
| 40 | * @var ResourceStorage |
||
| 41 | */ |
||
| 42 | protected $storage; |
||
| 43 | |||
| 44 | /** |
||
| 45 | * The identifier of this file to identify it on the storage. |
||
| 46 | * On some drivers, this is the path to the file, but drivers could also just |
||
| 47 | * provide any other unique identifier for this file on the specific storage. |
||
| 48 | * |
||
| 49 | * @var string |
||
| 50 | */ |
||
| 51 | protected $identifier; |
||
| 52 | |||
| 53 | /** |
||
| 54 | * The file name of this file |
||
| 55 | * |
||
| 56 | * @var string |
||
| 57 | */ |
||
| 58 | protected $name; |
||
| 59 | |||
| 60 | /** |
||
| 61 | * If set to true, this file is regarded as being deleted. |
||
| 62 | * |
||
| 63 | * @var bool |
||
| 64 | */ |
||
| 65 | protected $deleted = false; |
||
| 66 | |||
| 67 | /** |
||
| 68 | * any other file |
||
| 69 | */ |
||
| 70 | const FILETYPE_UNKNOWN = 0; |
||
| 71 | |||
| 72 | /** |
||
| 73 | * Any kind of text |
||
| 74 | * @see http://www.iana.org/assignments/media-types/text |
||
| 75 | */ |
||
| 76 | const FILETYPE_TEXT = 1; |
||
| 77 | |||
| 78 | /** |
||
| 79 | * Any kind of image |
||
| 80 | * @see http://www.iana.org/assignments/media-types/image |
||
| 81 | */ |
||
| 82 | const FILETYPE_IMAGE = 2; |
||
| 83 | |||
| 84 | /** |
||
| 85 | * Any kind of audio file |
||
| 86 | * @see http://www.iana.org/assignments/media-types/audio |
||
| 87 | */ |
||
| 88 | const FILETYPE_AUDIO = 3; |
||
| 89 | |||
| 90 | /** |
||
| 91 | * Any kind of video |
||
| 92 | * @see http://www.iana.org/assignments/media-types/video |
||
| 93 | */ |
||
| 94 | const FILETYPE_VIDEO = 4; |
||
| 95 | |||
| 96 | /** |
||
| 97 | * Any kind of application |
||
| 98 | * @see http://www.iana.org/assignments/media-types/application |
||
| 99 | */ |
||
| 100 | const FILETYPE_APPLICATION = 5; |
||
| 101 | |||
| 102 | /****************** |
||
| 103 | * VARIOUS FILE PROPERTY GETTERS |
||
| 104 | ******************/ |
||
| 105 | /** |
||
| 106 | * Returns true if the given property key exists for this file. |
||
| 107 | * |
||
| 108 | * @param string $key |
||
| 109 | * @return bool |
||
| 110 | */ |
||
| 111 | public function hasProperty($key) |
||
| 112 | { |
||
| 113 | return array_key_exists($key, $this->properties); |
||
| 114 | } |
||
| 115 | |||
| 116 | /** |
||
| 117 | * Returns a property value |
||
| 118 | * |
||
| 119 | * @param string $key |
||
| 120 | * @return mixed Property value |
||
| 121 | */ |
||
| 122 | public function getProperty($key) |
||
| 123 | { |
||
| 124 | if ($this->hasProperty($key)) { |
||
| 125 | return $this->properties[$key]; |
||
| 126 | } |
||
| 127 | return null; |
||
| 128 | } |
||
| 129 | |||
| 130 | /** |
||
| 131 | * Returns the properties of this object. |
||
| 132 | * |
||
| 133 | * @return array |
||
| 134 | */ |
||
| 135 | public function getProperties() |
||
| 136 | { |
||
| 137 | return $this->properties; |
||
| 138 | } |
||
| 139 | |||
| 140 | /** |
||
| 141 | * Returns the identifier of this file |
||
| 142 | * |
||
| 143 | * @return string |
||
| 144 | */ |
||
| 145 | public function getIdentifier() |
||
| 146 | { |
||
| 147 | return $this->identifier; |
||
| 148 | } |
||
| 149 | |||
| 150 | /** |
||
| 151 | * Get hashed identifier |
||
| 152 | * |
||
| 153 | * @return string |
||
| 154 | */ |
||
| 155 | public function getHashedIdentifier() |
||
| 156 | { |
||
| 157 | return $this->properties['identifier_hash']; |
||
| 158 | } |
||
| 159 | |||
| 160 | /** |
||
| 161 | * Returns the name of this file |
||
| 162 | * |
||
| 163 | * @return string |
||
| 164 | */ |
||
| 165 | public function getName() |
||
| 166 | { |
||
| 167 | // Do not check if file has been deleted because we might need the |
||
| 168 | // name for undeleting it. |
||
| 169 | return $this->name; |
||
| 170 | } |
||
| 171 | |||
| 172 | /** |
||
| 173 | * Returns the basename (the name without extension) of this file. |
||
| 174 | * |
||
| 175 | * @return string |
||
| 176 | */ |
||
| 177 | public function getNameWithoutExtension() |
||
| 178 | { |
||
| 179 | return PathUtility::pathinfo($this->getName(), PATHINFO_FILENAME); |
||
|
|
|||
| 180 | } |
||
| 181 | |||
| 182 | /** |
||
| 183 | * Returns the size of this file |
||
| 184 | * |
||
| 185 | * @throws \RuntimeException |
||
| 186 | * @return int|null Returns null if size is not available for the file |
||
| 187 | */ |
||
| 188 | public function getSize() |
||
| 189 | { |
||
| 190 | if ($this->deleted) { |
||
| 191 | throw new \RuntimeException('File has been deleted.', 1329821480); |
||
| 192 | } |
||
| 193 | if (empty($this->properties['size'])) { |
||
| 194 | $size = array_pop($this->getStorage()->getFileInfoByIdentifier($this->getIdentifier(), ['size'])); |
||
| 195 | } else { |
||
| 196 | $size = $this->properties['size']; |
||
| 197 | } |
||
| 198 | return $size ? (int)$size : null; |
||
| 199 | } |
||
| 200 | |||
| 201 | /** |
||
| 202 | * Returns the uid of this file |
||
| 203 | * |
||
| 204 | * @return int |
||
| 205 | */ |
||
| 206 | public function getUid() |
||
| 207 | { |
||
| 208 | return (int)$this->getProperty('uid'); |
||
| 209 | } |
||
| 210 | |||
| 211 | /** |
||
| 212 | * Returns the Sha1 of this file |
||
| 213 | * |
||
| 214 | * @throws \RuntimeException |
||
| 215 | * @return string |
||
| 216 | */ |
||
| 217 | public function getSha1() |
||
| 218 | { |
||
| 219 | if ($this->deleted) { |
||
| 220 | throw new \RuntimeException('File has been deleted.', 1329821481); |
||
| 221 | } |
||
| 222 | return $this->getStorage()->hashFile($this, 'sha1'); |
||
| 223 | } |
||
| 224 | |||
| 225 | /** |
||
| 226 | * Returns the creation time of the file as Unix timestamp |
||
| 227 | * |
||
| 228 | * @throws \RuntimeException |
||
| 229 | * @return int |
||
| 230 | */ |
||
| 231 | public function getCreationTime() |
||
| 232 | { |
||
| 233 | if ($this->deleted) { |
||
| 234 | throw new \RuntimeException('File has been deleted.', 1329821487); |
||
| 235 | } |
||
| 236 | return (int)$this->getProperty('creation_date'); |
||
| 237 | } |
||
| 238 | |||
| 239 | /** |
||
| 240 | * Returns the date (as UNIX timestamp) the file was last modified. |
||
| 241 | * |
||
| 242 | * @throws \RuntimeException |
||
| 243 | * @return int |
||
| 244 | */ |
||
| 245 | public function getModificationTime() |
||
| 246 | { |
||
| 247 | if ($this->deleted) { |
||
| 248 | throw new \RuntimeException('File has been deleted.', 1329821488); |
||
| 249 | } |
||
| 250 | return (int)$this->getProperty('modification_date'); |
||
| 251 | } |
||
| 252 | |||
| 253 | /** |
||
| 254 | * Get the extension of this file in a lower-case variant |
||
| 255 | * |
||
| 256 | * @return string The file extension |
||
| 257 | */ |
||
| 258 | public function getExtension() |
||
| 259 | { |
||
| 260 | $pathinfo = PathUtility::pathinfo($this->getName()); |
||
| 261 | |||
| 262 | $extension = strtolower($pathinfo['extension'] ?? ''); |
||
| 263 | |||
| 264 | return $extension; |
||
| 265 | } |
||
| 266 | |||
| 267 | /** |
||
| 268 | * Get the MIME type of this file |
||
| 269 | * |
||
| 270 | * @return string mime type |
||
| 271 | */ |
||
| 272 | public function getMimeType() |
||
| 273 | { |
||
| 274 | return $this->properties['mime_type'] ?: array_pop($this->getStorage()->getFileInfoByIdentifier($this->getIdentifier(), ['mimetype'])); |
||
| 275 | } |
||
| 276 | |||
| 277 | /** |
||
| 278 | * Returns the fileType of this file |
||
| 279 | * basically there are only five main "file types" |
||
| 280 | * "audio" |
||
| 281 | * "image" |
||
| 282 | * "software" |
||
| 283 | * "text" |
||
| 284 | * "video" |
||
| 285 | * "other" |
||
| 286 | * see the constants in this class |
||
| 287 | * |
||
| 288 | * @return int $fileType |
||
| 289 | */ |
||
| 290 | public function getType() |
||
| 291 | { |
||
| 292 | // this basically extracts the mimetype and guess the filetype based |
||
| 293 | // on the first part of the mimetype works for 99% of all cases, and |
||
| 294 | // we don't need to make an SQL statement like EXT:media does currently |
||
| 295 | if (!$this->properties['type']) { |
||
| 296 | $mimeType = $this->getMimeType(); |
||
| 297 | [$fileType] = explode('/', $mimeType); |
||
| 298 | switch (strtolower($fileType)) { |
||
| 299 | case 'text': |
||
| 300 | $this->properties['type'] = self::FILETYPE_TEXT; |
||
| 301 | break; |
||
| 302 | case 'image': |
||
| 303 | $this->properties['type'] = self::FILETYPE_IMAGE; |
||
| 304 | break; |
||
| 305 | case 'audio': |
||
| 306 | $this->properties['type'] = self::FILETYPE_AUDIO; |
||
| 307 | break; |
||
| 308 | case 'video': |
||
| 309 | $this->properties['type'] = self::FILETYPE_VIDEO; |
||
| 310 | break; |
||
| 311 | case 'application': |
||
| 312 | |||
| 313 | case 'software': |
||
| 314 | $this->properties['type'] = self::FILETYPE_APPLICATION; |
||
| 315 | break; |
||
| 316 | default: |
||
| 317 | $this->properties['type'] = self::FILETYPE_UNKNOWN; |
||
| 318 | } |
||
| 319 | } |
||
| 320 | return (int)$this->properties['type']; |
||
| 321 | } |
||
| 322 | |||
| 323 | /** |
||
| 324 | * Useful to find out if this file can be previewed or resized as image. |
||
| 325 | * @return bool true if File has an image-extension according to $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] |
||
| 326 | */ |
||
| 327 | public function isImage(): bool |
||
| 330 | } |
||
| 331 | |||
| 332 | /** |
||
| 333 | * Useful to find out if this file has a file extension based on any of the registered media extensions |
||
| 334 | * @return bool true if File is a media-extension according to $GLOBALS['TYPO3_CONF_VARS']['SYS']['mediafile_ext'] |
||
| 335 | */ |
||
| 336 | public function isMediaFile(): bool |
||
| 337 | { |
||
| 338 | return GeneralUtility::inList(strtolower($GLOBALS['TYPO3_CONF_VARS']['SYS']['mediafile_ext'] ?? ''), $this->getExtension()); |
||
| 339 | } |
||
| 340 | |||
| 341 | /** |
||
| 342 | * Useful to find out if this file can be edited. |
||
| 343 | * |
||
| 344 | * @return bool true if File is a text-based file extension according to $GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'] |
||
| 345 | */ |
||
| 346 | public function isTextFile(): bool |
||
| 347 | { |
||
| 348 | return GeneralUtility::inList(strtolower($GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'] ?? ''), $this->getExtension()); |
||
| 349 | } |
||
| 350 | /****************** |
||
| 351 | * CONTENTS RELATED |
||
| 352 | ******************/ |
||
| 353 | /** |
||
| 354 | * Get the contents of this file |
||
| 355 | * |
||
| 356 | * @throws \RuntimeException |
||
| 357 | * @return string File contents |
||
| 358 | */ |
||
| 359 | public function getContents() |
||
| 360 | { |
||
| 361 | if ($this->deleted) { |
||
| 362 | throw new \RuntimeException('File has been deleted.', 1329821479); |
||
| 363 | } |
||
| 364 | return $this->getStorage()->getFileContents($this); |
||
| 365 | } |
||
| 366 | |||
| 367 | /** |
||
| 368 | * Replace the current file contents with the given string |
||
| 369 | * |
||
| 370 | * @param string $contents The contents to write to the file. |
||
| 371 | * |
||
| 372 | * @throws \RuntimeException |
||
| 373 | * @return File The file object (allows chaining). |
||
| 374 | */ |
||
| 375 | public function setContents($contents) |
||
| 376 | { |
||
| 377 | if ($this->deleted) { |
||
| 378 | throw new \RuntimeException('File has been deleted.', 1329821478); |
||
| 379 | } |
||
| 380 | $this->getStorage()->setFileContents($this, $contents); |
||
| 381 | return $this; |
||
| 382 | } |
||
| 383 | |||
| 384 | /**************************************** |
||
| 385 | * STORAGE AND MANAGEMENT RELATED METHODS |
||
| 386 | ****************************************/ |
||
| 387 | |||
| 388 | /** |
||
| 389 | * Get the storage this file is located in |
||
| 390 | * |
||
| 391 | * @return ResourceStorage |
||
| 392 | * @throws \RuntimeException |
||
| 393 | */ |
||
| 394 | public function getStorage() |
||
| 395 | { |
||
| 396 | if ($this->storage === null) { |
||
| 397 | throw new \RuntimeException('You\'re using fileObjects without a storage.', 1381570091); |
||
| 398 | } |
||
| 399 | return $this->storage; |
||
| 400 | } |
||
| 401 | |||
| 402 | /** |
||
| 403 | * Checks if this file exists. This should normally always return TRUE; |
||
| 404 | * it might only return FALSE when this object has been created from an |
||
| 405 | * index record without checking for. |
||
| 406 | * |
||
| 407 | * @return bool TRUE if this file physically exists |
||
| 408 | */ |
||
| 409 | public function exists() |
||
| 410 | { |
||
| 411 | if ($this->deleted) { |
||
| 412 | return false; |
||
| 413 | } |
||
| 414 | return $this->storage->hasFile($this->getIdentifier()); |
||
| 415 | } |
||
| 416 | |||
| 417 | /** |
||
| 418 | * Sets the storage this file is located in. This is only meant for |
||
| 419 | * \TYPO3\CMS\Core\Resource-internal usage; don't use it to move files. |
||
| 420 | * |
||
| 421 | * @internal Should only be used by other parts of the File API (e.g. drivers after moving a file) |
||
| 422 | * @param ResourceStorage $storage |
||
| 423 | * @return File |
||
| 424 | */ |
||
| 425 | public function setStorage(ResourceStorage $storage) |
||
| 426 | { |
||
| 427 | $this->storage = $storage; |
||
| 428 | $this->properties['storage'] = $storage->getUid(); |
||
| 429 | return $this; |
||
| 430 | } |
||
| 431 | |||
| 432 | /** |
||
| 433 | * Set the identifier of this file |
||
| 434 | * |
||
| 435 | * @internal Should only be used by other parts of the File API (e.g. drivers after moving a file) |
||
| 436 | * @param string $identifier |
||
| 437 | * @return File |
||
| 438 | */ |
||
| 439 | public function setIdentifier($identifier) |
||
| 440 | { |
||
| 441 | $this->identifier = $identifier; |
||
| 442 | return $this; |
||
| 443 | } |
||
| 444 | |||
| 445 | /** |
||
| 446 | * Returns a combined identifier of this file, i.e. the storage UID and the |
||
| 447 | * folder identifier separated by a colon ":". |
||
| 448 | * |
||
| 449 | * @return string Combined storage and file identifier, e.g. StorageUID:path/and/fileName.png |
||
| 450 | */ |
||
| 451 | public function getCombinedIdentifier() |
||
| 452 | { |
||
| 453 | if (!empty($this->properties['storage']) && MathUtility::canBeInterpretedAsInteger($this->properties['storage'])) { |
||
| 454 | $combinedIdentifier = $this->properties['storage'] . ':' . $this->getIdentifier(); |
||
| 455 | } else { |
||
| 456 | $combinedIdentifier = $this->getStorage()->getUid() . ':' . $this->getIdentifier(); |
||
| 457 | } |
||
| 458 | return $combinedIdentifier; |
||
| 459 | } |
||
| 460 | |||
| 461 | /** |
||
| 462 | * Deletes this file from its storage. This also means that this object becomes useless. |
||
| 463 | * |
||
| 464 | * @return bool TRUE if deletion succeeded |
||
| 465 | */ |
||
| 466 | public function delete() |
||
| 467 | { |
||
| 468 | // The storage will mark this file as deleted |
||
| 469 | $wasDeleted = $this->getStorage()->deleteFile($this); |
||
| 470 | |||
| 471 | // Unset all properties when deleting the file, as they will be stale anyway |
||
| 472 | // This needs to happen AFTER the storage deleted the file, because the storage |
||
| 473 | // emits a signal, which passes the file object to the slots, which may need |
||
| 474 | // all file properties of the deleted file. |
||
| 475 | $this->properties = []; |
||
| 476 | |||
| 477 | return $wasDeleted; |
||
| 478 | } |
||
| 479 | |||
| 480 | /** |
||
| 481 | * Marks this file as deleted. This should only be used inside the |
||
| 482 | * File Abstraction Layer, as it is a low-level API method. |
||
| 483 | */ |
||
| 484 | public function setDeleted() |
||
| 485 | { |
||
| 486 | $this->deleted = true; |
||
| 487 | } |
||
| 488 | |||
| 489 | /** |
||
| 490 | * Returns TRUE if this file has been deleted |
||
| 491 | * |
||
| 492 | * @return bool |
||
| 493 | */ |
||
| 494 | public function isDeleted() |
||
| 495 | { |
||
| 496 | return $this->deleted; |
||
| 497 | } |
||
| 498 | |||
| 499 | /** |
||
| 500 | * Renames this file. |
||
| 501 | * |
||
| 502 | * @param string $newName The new file name |
||
| 503 | * |
||
| 504 | * @param string $conflictMode |
||
| 505 | * @return FileInterface |
||
| 506 | */ |
||
| 507 | public function rename($newName, $conflictMode = DuplicationBehavior::RENAME) |
||
| 508 | { |
||
| 509 | if ($this->deleted) { |
||
| 510 | throw new \RuntimeException('File has been deleted.', 1329821482); |
||
| 511 | } |
||
| 512 | return $this->getStorage()->renameFile($this, $newName, $conflictMode); |
||
| 513 | } |
||
| 514 | |||
| 515 | /** |
||
| 516 | * Copies this file into a target folder |
||
| 517 | * |
||
| 518 | * @param Folder $targetFolder Folder to copy file into. |
||
| 519 | * @param string $targetFileName an optional destination fileName |
||
| 520 | * @param string $conflictMode a value of the \TYPO3\CMS\Core\Resource\DuplicationBehavior enumeration |
||
| 521 | * |
||
| 522 | * @throws \RuntimeException |
||
| 523 | * @return File The new (copied) file. |
||
| 524 | */ |
||
| 525 | public function copyTo(Folder $targetFolder, $targetFileName = null, $conflictMode = DuplicationBehavior::RENAME) |
||
| 526 | { |
||
| 527 | if ($this->deleted) { |
||
| 528 | throw new \RuntimeException('File has been deleted.', 1329821483); |
||
| 529 | } |
||
| 530 | return $targetFolder->getStorage()->copyFile($this, $targetFolder, $targetFileName, $conflictMode); |
||
| 531 | } |
||
| 532 | |||
| 533 | /** |
||
| 534 | * Moves the file into the target folder |
||
| 535 | * |
||
| 536 | * @param Folder $targetFolder Folder to move file into. |
||
| 537 | * @param string $targetFileName an optional destination fileName |
||
| 538 | * @param string $conflictMode a value of the \TYPO3\CMS\Core\Resource\DuplicationBehavior enumeration |
||
| 539 | * |
||
| 540 | * @throws \RuntimeException |
||
| 541 | * @return File This file object, with updated properties. |
||
| 542 | */ |
||
| 543 | public function moveTo(Folder $targetFolder, $targetFileName = null, $conflictMode = DuplicationBehavior::RENAME) |
||
| 544 | { |
||
| 545 | if ($this->deleted) { |
||
| 546 | throw new \RuntimeException('File has been deleted.', 1329821484); |
||
| 547 | } |
||
| 548 | return $targetFolder->getStorage()->moveFile($this, $targetFolder, $targetFileName, $conflictMode); |
||
| 549 | } |
||
| 550 | |||
| 551 | /***************** |
||
| 552 | * SPECIAL METHODS |
||
| 553 | *****************/ |
||
| 554 | /** |
||
| 555 | * Returns a publicly accessible URL for this file |
||
| 556 | * |
||
| 557 | * WARNING: Access to the file may be restricted by further means, e.g. some |
||
| 558 | * web-based authentication. You have to take care of this yourself. |
||
| 559 | * |
||
| 560 | * @param bool $relativeToCurrentScript Determines whether the URL returned should be relative to the current script, in case it is relative at all (only for the LocalDriver) |
||
| 561 | * @return string|null NULL if file is deleted, the generated URL otherwise |
||
| 562 | */ |
||
| 563 | public function getPublicUrl($relativeToCurrentScript = false) |
||
| 564 | { |
||
| 565 | if ($this->deleted) { |
||
| 566 | return null; |
||
| 567 | } |
||
| 568 | return $this->getStorage()->getPublicUrl($this, $relativeToCurrentScript); |
||
| 569 | } |
||
| 570 | |||
| 571 | /** |
||
| 572 | * Returns a path to a local version of this file to process it locally (e.g. with some system tool). |
||
| 573 | * If the file is normally located on a remote storages, this creates a local copy. |
||
| 574 | * If the file is already on the local system, this only makes a new copy if $writable is set to TRUE. |
||
| 575 | * |
||
| 576 | * @param bool $writable Set this to FALSE if you only want to do read operations on the file. |
||
| 577 | * |
||
| 578 | * @throws \RuntimeException |
||
| 579 | * @return string |
||
| 580 | */ |
||
| 581 | public function getForLocalProcessing($writable = true) |
||
| 582 | { |
||
| 583 | if ($this->deleted) { |
||
| 584 | throw new \RuntimeException('File has been deleted.', 1329821486); |
||
| 585 | } |
||
| 586 | return $this->getStorage()->getFileForLocalProcessing($this, $writable); |
||
| 587 | } |
||
| 588 | |||
| 589 | /*********************** |
||
| 590 | * INDEX RELATED METHODS |
||
| 591 | ***********************/ |
||
| 592 | /** |
||
| 593 | * Updates properties of this object. |
||
| 594 | * This method is used to reconstitute settings from the |
||
| 595 | * database into this object after being instantiated. |
||
| 596 | * |
||
| 597 | * @param array $properties |
||
| 598 | */ |
||
| 599 | abstract public function updateProperties(array $properties); |
||
| 600 | |||
| 601 | /** |
||
| 602 | * Returns the parent folder. |
||
| 603 | * |
||
| 604 | * @return FolderInterface |
||
| 605 | */ |
||
| 606 | public function getParentFolder() |
||
| 609 | } |
||
| 610 | } |
||
| 611 |