diff --git a/Modules/Media/Events/FolderStartedMoving.php b/Modules/Media/Events/FolderStartedMoving.php new file mode 100644 index 000000000..1931c0986 --- /dev/null +++ b/Modules/Media/Events/FolderStartedMoving.php @@ -0,0 +1,23 @@ +folder = $folder; + $this->previousData = $previousData; + } +} diff --git a/Modules/Media/Events/Handlers/MoveFolderOnDisk.php b/Modules/Media/Events/Handlers/MoveFolderOnDisk.php new file mode 100644 index 000000000..c8e010354 --- /dev/null +++ b/Modules/Media/Events/Handlers/MoveFolderOnDisk.php @@ -0,0 +1,87 @@ +filesystem = $filesystem; + $this->file = $file; + } + + public function handle(FolderStartedMoving $event) + { + $this->moveOriginal($event); + + $this->renameDatabaseReferences($event); + } + + private function moveOriginal(FolderStartedMoving $event) + { + $this->move($event->previousData['path']->getRelativeUrl(), $event->folder->path->getRelativeUrl()); + } + + private function renameDatabaseReferences(FolderStartedMoving $event) + { + $previousPath = $event->previousData['path']->getRelativeUrl(); + $newPath = $event->folder->path->getRelativeUrl(); + + $this->replacePathReferences($event->folder->id, $previousPath, $newPath); + } + + private function replacePathReferences($folderId, $previousPath, $newPath) + { + $medias = $this->file->allChildrenOf($folderId); + + foreach ($medias as $media) { + $oldPath = $media->path->getRelativeUrl(); + + $media->update([ + 'path' => str_replace($previousPath, $newPath, $oldPath), + ]); + if ($media->isFolder() === true) { + $this->replacePathReferences($media->id, $previousPath, $newPath); + } + } + } + + private function move($fromPath, $toPath) + { + $this->filesystem->disk($this->getConfiguredFilesystem()) + ->move( + $this->getDestinationPath($fromPath), + $this->getDestinationPath($toPath) + ); + } + + private function getDestinationPath($path) : string + { + if ($this->getConfiguredFilesystem() === 'local') { + return basename(public_path()) . $path; + } + + return $path; + } + + /** + * @return string + */ + private function getConfiguredFilesystem() : string + { + return config('asgard.media.config.filesystem'); + } +} diff --git a/Modules/Media/Providers/MediaServiceProvider.php b/Modules/Media/Providers/MediaServiceProvider.php index 3643e1d0b..f78da7acd 100644 --- a/Modules/Media/Providers/MediaServiceProvider.php +++ b/Modules/Media/Providers/MediaServiceProvider.php @@ -16,6 +16,7 @@ use Modules\Media\Entities\File; use Modules\Media\Events\FileStartedMoving; use Modules\Media\Events\FolderIsDeleting; +use Modules\Media\Events\FolderStartedMoving; use Modules\Media\Events\FolderWasCreated; use Modules\Media\Events\FolderWasUpdated; use Modules\Media\Events\Handlers\CreateFolderOnDisk; @@ -23,6 +24,7 @@ use Modules\Media\Events\Handlers\DeleteFolderOnDisk; use Modules\Media\Events\Handlers\HandleMediaStorage; use Modules\Media\Events\Handlers\MoveFileOnDisk; +use Modules\Media\Events\Handlers\MoveFolderOnDisk; use Modules\Media\Events\Handlers\RegisterMediaSidebar; use Modules\Media\Events\Handlers\RemovePolymorphicLink; use Modules\Media\Events\Handlers\RenameFolderOnDisk; @@ -83,6 +85,7 @@ public function boot(DispatcherContract $events) $events->listen(FolderIsDeleting::class, DeleteFolderOnDisk::class); $events->listen(FolderIsDeleting::class, DeleteAllChildrenOfFolder::class); $events->listen(FileStartedMoving::class, MoveFileOnDisk::class); + $events->listen(FolderStartedMoving::class, MoveFolderOnDisk::class); $this->app[TagManager::class]->registerNamespace(new File()); $this->registerThumbnails(); diff --git a/Modules/Media/Repositories/Eloquent/EloquentFolderRepository.php b/Modules/Media/Repositories/Eloquent/EloquentFolderRepository.php index 905b167e2..407b01883 100644 --- a/Modules/Media/Repositories/Eloquent/EloquentFolderRepository.php +++ b/Modules/Media/Repositories/Eloquent/EloquentFolderRepository.php @@ -8,6 +8,7 @@ use Modules\Media\Events\FolderIsCreating; use Modules\Media\Events\FolderIsDeleting; use Modules\Media\Events\FolderIsUpdating; +use Modules\Media\Events\FolderStartedMoving; use Modules\Media\Events\FolderWasCreated; use Modules\Media\Events\FolderWasUpdated; use Modules\Media\Repositories\FolderRepository; @@ -89,6 +90,28 @@ public function allNested(): NestedFoldersCollection return new NestedFoldersCollection($this->all()); } + public function move(File $folder, File $destination): File + { + $previousData = [ + 'filename' => $folder->filename, + 'path' => $folder->path, + ]; + + $folder->update([ + 'path' => $this->getNewPathFor($folder->filename, $destination), + 'folder_id' => $destination->id, + ]); + + event(new FolderStartedMoving($folder, $previousData)); + + return $folder; + } + + private function getNewPathFor(string $filename, File $folder) + { + return $folder->path->getRelativeUrl() . '/' . str_slug($filename); + } + /** * @param array $data * @return string diff --git a/Modules/Media/Repositories/FolderRepository.php b/Modules/Media/Repositories/FolderRepository.php index 5bcbc405a..cc73a9d6c 100644 --- a/Modules/Media/Repositories/FolderRepository.php +++ b/Modules/Media/Repositories/FolderRepository.php @@ -23,4 +23,6 @@ public function findFolder(int $folderId); public function allChildrenOf(File $folder); public function allNested() : NestedFoldersCollection; + + public function move(File $folder, File $destination) : File; } diff --git a/Modules/Media/Tests/EloquentFolderRepositoryTest.php b/Modules/Media/Tests/EloquentFolderRepositoryTest.php index 8a8e3e549..2a28e37c1 100644 --- a/Modules/Media/Tests/EloquentFolderRepositoryTest.php +++ b/Modules/Media/Tests/EloquentFolderRepositoryTest.php @@ -330,6 +330,79 @@ public function it_removes_folder_and_files_from_database() $this->assertCount(2, File::all()); } + /** @test */ + public function it_can_move_folder_in_database() + { + $folder = $this->folder->create(['name' => 'My Folder']); + $folderTwo = $this->folder->create(['name' => 'Future Child folder']); + + $this->assertEquals('/assets/media/future-child-folder', $folderTwo->path->getRelativeUrl()); + $this->folder->move($folderTwo, $folder); + $this->assertEquals('/assets/media/my-folder/future-child-folder', $folderTwo->path->getRelativeUrl()); + } + + /** @test */ + public function it_can_move_folder_on_disk() + { + $folder = $this->folder->create(['name' => 'My Folder']); + $folderTwo = $this->folder->create(['name' => 'Future Child folder']); + + $this->assertTrue($this->app['files']->isDirectory(public_path('/assets/media/future-child-folder'))); + $this->folder->move($folderTwo, $folder); + $this->assertTrue( + $this->app['files']->isDirectory(public_path('/assets/media/my-folder/future-child-folder')), + 'Folder was not moved' + ); + } + + /** @test */ + public function it_can_move_folder_with_folders_and_files_in_it_database() + { + $mainFolder = $this->folder->create(['name' => 'My Folder']); + $folderTwo = $this->folder->create(['name' => 'Second folder']); + $folderThird = $this->folder->create(['name' => 'Third folder', 'parent_id' => $folderTwo->id]); + $file = app(FileService::class)->store(\Illuminate\Http\UploadedFile::fake()->image('my-file.jpg'), $folderTwo->id); + $fileTwo = app(FileService::class)->store(\Illuminate\Http\UploadedFile::fake()->image('my-other-file.jpg'), $folderThird->id); + + $this->assertEquals('/assets/media/second-folder', $folderTwo->path->getRelativeUrl()); + $this->assertEquals('/assets/media/second-folder/third-folder', $folderThird->path->getRelativeUrl()); + $this->assertEquals('/assets/media/second-folder/my-file.jpg', $file->path->getRelativeUrl()); + $this->assertEquals('/assets/media/second-folder/third-folder/my-other-file.jpg', $fileTwo->path->getRelativeUrl()); + + $this->folder->move($folderTwo, $mainFolder); + + $folderTwo->refresh(); + $folderThird->refresh(); + $file->refresh(); + $fileTwo->refresh(); + $this->assertEquals('/assets/media/my-folder/second-folder', $folderTwo->path->getRelativeUrl()); + $this->assertEquals('/assets/media/my-folder/second-folder/third-folder', $folderThird->path->getRelativeUrl()); + $this->assertEquals('/assets/media/my-folder/second-folder/my-file.jpg', $file->path->getRelativeUrl()); + $this->assertEquals('/assets/media/my-folder/second-folder/third-folder/my-other-file.jpg', $fileTwo->path->getRelativeUrl()); + } + + /** @test */ + public function it_can_move_folder_with_folders_and_files_in_it_disk() + { + $mainFolder = $this->folder->create(['name' => 'My Folder']); + $folderTwo = $this->folder->create(['name' => 'Second folder']); + $folderThird = $this->folder->create(['name' => 'Third folder', 'parent_id' => $folderTwo->id]); + $file = app(FileService::class)->store(\Illuminate\Http\UploadedFile::fake()->image('my-file.jpg'), $folderTwo->id); + $fileTwo = app(FileService::class)->store(\Illuminate\Http\UploadedFile::fake()->image('my-other-file.jpg'), $folderThird->id); + + $this->assertTrue($this->app['files']->isDirectory(public_path('/assets/media/second-folder'))); + $this->assertTrue($this->app['files']->isDirectory(public_path('/assets/media/second-folder/third-folder'))); + $this->assertTrue($this->app['files']->exists(public_path('/assets/media/second-folder/my-file.jpg'))); + $this->assertTrue($this->app['files']->exists(public_path('/assets/media/second-folder/third-folder/my-other-file.jpg'))); + + $this->folder->move($folderTwo, $mainFolder); + + $this->assertTrue($this->app['files']->isDirectory(public_path('/assets/media/my-folder/second-folder'))); + $this->assertTrue($this->app['files']->isDirectory(public_path('/assets/media/my-folder/second-folder/third-folder'))); + $this->assertTrue($this->app['files']->exists(public_path('/assets/media/my-folder/second-folder/my-file.jpg'))); + $this->assertTrue($this->app['files']->exists(public_path('/assets/media/my-folder/second-folder/third-folder/my-other-file.jpg'))); + } + private function createFile($fileName = 'random/name.jpg') { return File::create([