Extracting folder move operations to a FolderMover class.

This improves maintainability as well as doesn't update the db row until the folder was actually successfully moved on disk. This keeps db / filesystem in sync.
parent c7581754
...@@ -85,7 +85,6 @@ class MediaServiceProvider extends ServiceProvider ...@@ -85,7 +85,6 @@ class MediaServiceProvider extends ServiceProvider
$events->listen(FolderIsDeleting::class, DeleteFolderOnDisk::class); $events->listen(FolderIsDeleting::class, DeleteFolderOnDisk::class);
$events->listen(FolderIsDeleting::class, DeleteAllChildrenOfFolder::class); $events->listen(FolderIsDeleting::class, DeleteAllChildrenOfFolder::class);
$events->listen(FileStartedMoving::class, MoveFileOnDisk::class); $events->listen(FileStartedMoving::class, MoveFileOnDisk::class);
$events->listen(FolderStartedMoving::class, MoveFolderOnDisk::class);
$this->app[TagManager::class]->registerNamespace(new File()); $this->app[TagManager::class]->registerNamespace(new File());
$this->registerThumbnails(); $this->registerThumbnails();
......
<?php <?php
namespace Modules\Media\Events\Handlers; namespace Modules\Media\Services;
use Illuminate\Contracts\Filesystem\Factory; use Illuminate\Contracts\Filesystem\Factory;
use Modules\Media\Events\FolderStartedMoving; use League\Flysystem\FileExistsException;
use Modules\Media\Entities\File;
use Modules\Media\Repositories\FileRepository; use Modules\Media\Repositories\FileRepository;
use Modules\Media\Repositories\FolderRepository;
class MoveFolderOnDisk final class FolderMover implements Mover
{ {
/** /**
* @var Factory * @var Factory
...@@ -16,31 +18,50 @@ class MoveFolderOnDisk ...@@ -16,31 +18,50 @@ class MoveFolderOnDisk
* @var FileRepository * @var FileRepository
*/ */
private $file; private $file;
/**
* @var FolderRepository
*/
private $folder;
private $fromPath;
private $toPath;
public function __construct(Factory $filesystem, FileRepository $file) public function __construct(Factory $filesystem, FileRepository $file, FolderRepository $folder)
{ {
$this->filesystem = $filesystem; $this->filesystem = $filesystem;
$this->file = $file; $this->file = $file;
$this->folder = $folder;
} }
public function handle(FolderStartedMoving $event) public function move(File $folder, File $destination) : bool
{ {
$this->moveOriginal($event); $movedOnDisk = $this->moveOriginalOnDisk($folder, $destination);
if ($movedOnDisk === false) {
return false;
}
$folder = $this->moveDatabase($folder, $destination);
$this->renameDatabaseReferences($event); $this->renameDatabaseReferences($folder);
return true;
} }
private function moveOriginal(FolderStartedMoving $event) private function moveOriginalOnDisk(File $folder, File $destination) : bool
{ {
$this->move($event->previousData['path']->getRelativeUrl(), $event->folder->path->getRelativeUrl()); $this->fromPath = $folder->path->getRelativeUrl();
$this->toPath = $this->getNewPathFor($folder->filename, $destination);
return $this->moveDirectory($this->fromPath, $this->toPath);
} }
private function renameDatabaseReferences(FolderStartedMoving $event) private function moveDatabase(File $folder, File $destination) : File
{ {
$previousPath = $event->previousData['path']->getRelativeUrl(); return $this->folder->move($folder, $destination);
$newPath = $event->folder->path->getRelativeUrl(); }
$this->replacePathReferences($event->folder->id, $previousPath, $newPath); private function renameDatabaseReferences(File $folder)
{
$this->replacePathReferences($folder->id, $this->fromPath, $this->toPath);
} }
private function replacePathReferences($folderId, $previousPath, $newPath) private function replacePathReferences($folderId, $previousPath, $newPath)
...@@ -59,13 +80,18 @@ class MoveFolderOnDisk ...@@ -59,13 +80,18 @@ class MoveFolderOnDisk
} }
} }
private function move($fromPath, $toPath) private function moveDirectory($fromPath, $toPath) : bool
{ {
$this->filesystem->disk($this->getConfiguredFilesystem()) try {
->move( $this->filesystem->disk($this->getConfiguredFilesystem())
$this->getDestinationPath($fromPath), ->move(
$this->getDestinationPath($toPath) $this->getDestinationPath($fromPath),
); $this->getDestinationPath($toPath)
);
} catch (FileExistsException $e) {
return false;
}
return true;
} }
private function getDestinationPath($path) : string private function getDestinationPath($path) : string
...@@ -77,14 +103,16 @@ class MoveFolderOnDisk ...@@ -77,14 +103,16 @@ class MoveFolderOnDisk
return $path; return $path;
} }
/**
* @return string
*/
private function getConfiguredFilesystem() : string private function getConfiguredFilesystem() : string
{ {
return config('asgard.media.config.filesystem'); return config('asgard.media.config.filesystem');
} }
private function getNewPathFor(string $filename, File $folder) : string
{
return $this->removeDoubleSlashes($folder->path->getRelativeUrl() . '/' . str_slug($filename));
}
private function removeDoubleSlashes(string $string) : string private function removeDoubleSlashes(string $string) : string
{ {
return str_replace('//', '/', $string); return str_replace('//', '/', $string);
......
<?php
namespace Modules\Media\Services;
use Modules\Media\Entities\File;
interface Mover
{
public function move(File $file, File $destination) : bool;
}
...@@ -330,101 +330,6 @@ final class EloquentFolderRepositoryTest extends MediaTestCase ...@@ -330,101 +330,6 @@ final class EloquentFolderRepositoryTest extends MediaTestCase
$this->assertCount(2, File::all()); $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_back_to_root_folder()
{
$parentFolder = $this->folder->create(['name' => 'My Folder', 'parent_id' => 0]);
$folder = $this->folder->create(['name' => 'Child Folder', 'parent_id' => $parentFolder->id]);
$file = app(FileService::class)->store(\Illuminate\Http\UploadedFile::fake()->image('my-file.jpg'), $folder->id);
$this->assertEquals('/assets/media/my-folder/child-folder', $folder->path->getRelativeUrl());
$this->assertEquals('/assets/media/my-folder/child-folder/my-file.jpg', $file->path->getRelativeUrl());
$this->assertTrue($this->app['files']->isDirectory(public_path('/assets/media/my-folder/child-folder')));
$this->assertTrue($this->app['files']->exists(public_path('/assets/media/my-folder/child-folder/my-file.jpg')));
$this->folder->move($folder, $this->makeRootFolder());
$this->assertTrue($this->app['files']->isDirectory(public_path('/assets/media/child-folder')));
$this->assertTrue($this->app['files']->exists(public_path('/assets/media/child-folder/my-file.jpg')));
$this->assertEquals('/assets/media/child-folder', $folder->path->getRelativeUrl());
$file->refresh();
$this->assertEquals('/assets/media/child-folder/my-file.jpg', $file->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') private function createFile($fileName = 'random/name.jpg')
{ {
return File::create([ return File::create([
...@@ -436,13 +341,4 @@ final class EloquentFolderRepositoryTest extends MediaTestCase ...@@ -436,13 +341,4 @@ final class EloquentFolderRepositoryTest extends MediaTestCase
'folder_id' => 0, 'folder_id' => 0,
]); ]);
} }
private function makeRootFolder() : File
{
return new File([
'id' => 0,
'folder_id' => 0,
'path' => config('asgard.media.config.files-path'),
]);
}
} }
<?php
namespace Modules\Media\Tests;
use Modules\Media\Entities\File;
use Modules\Media\Repositories\FolderRepository;
use Modules\Media\Services\FileService;
use Modules\Media\Services\FolderMover;
final class FolderMoverTest extends MediaTestCase
{
/**
* @var FolderMover
*/
private $mover;
/**
* @var FolderRepository
*/
private $folder;
protected function setUp()
{
parent::setUp();
$this->resetDatabase();
$this->mover = app(FolderMover::class);
$this->folder = app(FolderRepository::class);
$this->app['config']->set('asgard.media.config.files-path', '/assets/media/');
}
public function tearDown()
{
if ($this->app['files']->isDirectory(public_path('assets')) === true) {
$this->app['files']->deleteDirectory(public_path('assets'));
}
}
/** @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->mover->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_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->mover->move($folderTwo, $folder);
$this->assertEquals('/assets/media/my-folder/future-child-folder', $folderTwo->path->getRelativeUrl());
}
/** @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->mover->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_back_to_root_folder()
{
$parentFolder = $this->folder->create(['name' => 'My Folder', 'parent_id' => 0]);
$folder = $this->folder->create(['name' => 'Child Folder', 'parent_id' => $parentFolder->id]);
$file = app(FileService::class)->store(\Illuminate\Http\UploadedFile::fake()->image('my-file.jpg'), $folder->id);
$this->assertEquals('/assets/media/my-folder/child-folder', $folder->path->getRelativeUrl());
$this->assertEquals('/assets/media/my-folder/child-folder/my-file.jpg', $file->path->getRelativeUrl());
$this->assertTrue($this->app['files']->isDirectory(public_path('/assets/media/my-folder/child-folder')));
$this->assertTrue($this->app['files']->exists(public_path('/assets/media/my-folder/child-folder/my-file.jpg')));
$this->mover->move($folder, $this->makeRootFolder());
$this->assertTrue($this->app['files']->isDirectory(public_path('/assets/media/child-folder')));
$this->assertTrue($this->app['files']->exists(public_path('/assets/media/child-folder/my-file.jpg')));
$this->assertEquals('/assets/media/child-folder', $folder->path->getRelativeUrl());
$file->refresh();
$this->assertEquals('/assets/media/child-folder/my-file.jpg', $file->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->mover->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')));
}
/** @test */
public function it_does_not_move_folder_if_folder_name_exists_at_location()
{
$mainFolder = $this->folder->create(['name' => 'My Folder']);
$folderTwo = $this->folder->create(['name' => 'Child Folder']);
$folderThird = $this->folder->create(['name' => 'Child Folder', 'parent_id' => $mainFolder->id]);
$this->assertTrue($this->app['files']->isDirectory(public_path('/assets/media/my-folder/child-folder')));
$this->mover->move($folderTwo, $mainFolder);
$this->assertTrue($this->app['files']->isDirectory(public_path('/assets/media/child-folder')));
$this->assertEquals('/assets/media/child-folder', $folderTwo->path->getRelativeUrl());
}
private function makeRootFolder() : File
{
return new File([
'id' => 0,
'folder_id' => 0,
'path' => config('asgard.media.config.files-path'),
]);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment