foldershare-8.x-1.2/src/Entity/FolderShareTraits/OperationRenameTrait.php
src/Entity/FolderShareTraits/OperationRenameTrait.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | <?php namespace Drupal\foldershare\Entity\FolderShareTraits; use Drupal\foldershare\ManageFileSystem; use Drupal\foldershare\ManageLog; use Drupal\foldershare\Utilities\FileUtilities; use Drupal\foldershare\Entity\Exception\LockException; use Drupal\foldershare\Entity\Exception\ValidationException; /** * Rename FolderShare entities. * * This trait includes methods to rename FolderShare entities and * wrapped File entities. * * <B>Internal trait</B> * This trait is internal to the FolderShare module and used to define * features of the FolderShare entity class. It is a mechanism to group * functionality to improve code management. * * @ingroup foldershare */ trait OperationRenameTrait { /*--------------------------------------------------------------------- * * Rename FolderShare entity. * *---------------------------------------------------------------------*/ /** * {@inheritdoc} */ public function rename(string $newName ) { // // Validate // -------- // The new name must be different and legal. $oldName = $this ->getName(); if ( $oldName === $newName ) { // No change. return ; } // The checkName() function throws an exception if the name is too // long or uses illegal characters. $this ->checkName( $newName ); // // Lock root folder tree. // ---------------------- // Lock the item's root's folder tree to insure no other operation can // modify the folder tree while this item is being updated. // // LOCK ROOT FOLDER TREE. $rootId = $this ->getRootItemId(); if (self::acquireRootOperationLock( $rootId ) === FALSE) { throw new LockException( self::getStandardLockExceptionMessage(t( 'renamed' ), $this ->getName())); } // // Lock owner's root list, if needed. // ---------------------------------- // If this item is a root item, then lock the root list of the item's // owner (which is normally this user). This is needed in order to keep // the root list unchanged while we check for name collisions. // // LOCK OWNER'S ROOT LIST. if ( $this ->isRootItem() === TRUE) { if (self::acquireUserRootListLock( $this ->getOwnerId()) === FALSE) { // UNLOCK ROOT FOLDER TREE. self::releaseRootOperationLock( $rootId ); throw new LockException( self::getStandardLockExceptionMessage(t( 'renamed' ), $this ->getName())); } } // // Check name. // ----------- // Check that the new name is unique within either the parent folder // (if any) or the owner's root list (if there is no parent). if ( $this ->isRootItem() === TRUE) { $uid = (int) $this ->getOwnerId(); if (self::isRootNameUnique( $newName , (int) $this ->id(), $uid ) === FALSE) { // UNLOCK OWNER'S ROOT LIST. self::releaseUserRootListLock( $uid ); // UNLOCK ROOT FOLDER TREE. self::releaseRootOperationLock( $rootId ); throw new ValidationException( self::getStandardNameInUseExceptionMessage( $newName )); } } else { $parentFolder = $this ->getParentFolder(); if ( $parentFolder ->isNameUnique( $newName , (int) $this ->id()) === FALSE) { // UNLOCK ROOT FOLDER TREE. self::releaseRootOperationLock( $rootId ); throw new ValidationException( self::getStandardNameInUseExceptionMessage( $newName )); } } // // Change the name. // ---------------- // Set the name and save. // // If the item is a file, image, or media object change the underlying // item's name too. $this ->setName( $newName ); $this ->save(); $this ->renameWrappedFile( $newName ); // // Unlock everything. // ------------------ // Unlock the owner's root list, if it was locked, and unlock the // root folder tree containing the item. // if ( $this ->isRootItem() === TRUE) { // UNLOCK OWNER'S ROOT LIST. self::releaseUserRootListLock( $this ->getOwnerId()); } // UNLOCK ROOT FOLDER TREE. self::releaseRootOperationLock( $rootId ); // // Hook & log. // ----------- // Note the change. $requestingUid = self::getCurrentUserId()[0]; self::postOperationHook( 'rename' , [ $this , $oldName , $newName , $requestingUid , ]); ManageLog::activity( "Renamed @kind '@oldName' (# @id) to '@newName'." , [ '@id' => $this ->id(), '@kind' => $this ->getKind(), '@oldName' => $oldName , '@newName' => $newName , 'entity' => $this , 'uid' => $requestingUid , ]); } /*--------------------------------------------------------------------- * * Rename wrapped File entity. * *---------------------------------------------------------------------*/ /** * Renames an entity's underlying file, image, and media entity. * * After a FolderShare entity has been renamed, this method updates any * underlying entities to share the same name. This includes File objects * underneath 'file' and 'image' kinds, and Media objects underneath * 'media' kinds. * * This method has no effect if the current entity is not a file, image, * or media wrapper. * * @param string $newName * The new name for the underlying entities. */ private function renameWrappedFile(string $newName ) { if ( $this ->isFolder() === TRUE) { // Folders do not wrap files. return ; } // Change the underlying File or Media entity's name. This public // name appears in the file and image URI as well so that field // formatters can see a name and extension, if they need it. if ( $this ->isFile() === TRUE || $this ->isImage() === TRUE) { if ( $this ->isFile() === TRUE) { $file = $this ->getFile(); } else { $file = $this ->getImage(); } if ( $file === NULL) { // There is no wrapped file? The entity is corrupted! return ; } // Get the file's MIME type based upon the new name, which may // have changed the file name extension. $mimeType = \Drupal::service( 'file.mime_type.guesser' )->guess( $newName ); // Set the name first. This is used by the FileUtilities call below // to compute a new URI based upon the name (really, just the // extension) and the file's entity ID. $file ->setFilename( $newName ); $file ->save(); $oldUri = $file ->getFileUri(); $newUri = ManageFileSystem::getFileUri( $file ); // If the URIs differ, then something about the new name has caused // the underlying saved file to change its name. This is probably the // filename extension. Move the file. if ( $oldUri !== $newUri ) { // It should not be possible for the following move to fail. The // old and new URIs differ and both are based upon the file // entity's ID, which is unique. This prevents name collisions. // Only the filename extensions can differ. // // The only errors that can occur are problems with the underlying // server file system. And there's nothing we can do about them. // The above function will report those to the server log. FileUtilities::rename( $oldUri , $newUri ); // Update the URI to point to the moved file. $file ->setFileUri( $newUri ); // If the file name has changed, the extension may have changed, // and thus the MIME type may have changed. Save the new MIME type. $file ->setMimeType( $mimeType ); $file ->save(); $this ->setMimeType( $mimeType ); } // If the newly renamed file now has a top-level MIME type that // indicates a change from a generic file to an image, or the // reverse, then we need to swap use of the 'file' and 'image' // fields in the FolderShare entity. Both fields still reference // a File entity. $isForImage = self::isMimeTypeImage( $mimeType ); if ( $this ->isFile() === TRUE && $isForImage === TRUE) { // The file was a generic file, and now it is an image. $this ->clearFileId(); $this ->setImageId( $file ->id()); $this ->setKind(self::IMAGE_KIND); } elseif ( $this ->isImage() === TRUE && $isForImage === FALSE) { // The file was an image, and now it is a generic file. $this ->setFileId( $file ->id()); $this ->clearImageId(); $this ->setKind(self::FILE_KIND); } $this ->save(); unset( $file ); } elseif ( $this ->isMedia() === TRUE) { $media = $this ->getMedia(); if ( $media !== NULL) { $media ->setName( $newName ); $media ->save(); unset( $media ); } } } } |