Skip to content

Commit

Permalink
Extracting folder move operations to a FolderMover class.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nWidart committed Oct 10, 2017
1 parent c758175 commit e0b1499
Show file tree
Hide file tree
Showing 6 changed files with 287 additions and 197 deletions.
92 changes: 0 additions & 92 deletions Modules/Media/Events/Handlers/MoveFolderOnDisk.php

This file was deleted.

1 change: 0 additions & 1 deletion Modules/Media/Providers/MediaServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ 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();
Expand Down
120 changes: 120 additions & 0 deletions Modules/Media/Services/FolderMover.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?php

namespace Modules\Media\Services;

use Illuminate\Contracts\Filesystem\Factory;
use League\Flysystem\FileExistsException;
use Modules\Media\Entities\File;
use Modules\Media\Repositories\FileRepository;
use Modules\Media\Repositories\FolderRepository;

final class FolderMover implements Mover
{
/**
* @var Factory
*/
private $filesystem;
/**
* @var FileRepository
*/
private $file;
/**
* @var FolderRepository
*/
private $folder;
private $fromPath;
private $toPath;

public function __construct(Factory $filesystem, FileRepository $file, FolderRepository $folder)
{
$this->filesystem = $filesystem;
$this->file = $file;
$this->folder = $folder;
}

public function move(File $folder, File $destination) : bool
{
$movedOnDisk = $this->moveOriginalOnDisk($folder, $destination);

if ($movedOnDisk === false) {
return false;
}
$folder = $this->moveDatabase($folder, $destination);

$this->renameDatabaseReferences($folder);

return true;
}

private function moveOriginalOnDisk(File $folder, File $destination) : bool
{
$this->fromPath = $folder->path->getRelativeUrl();
$this->toPath = $this->getNewPathFor($folder->filename, $destination);

return $this->moveDirectory($this->fromPath, $this->toPath);
}

private function moveDatabase(File $folder, File $destination) : File
{
return $this->folder->move($folder, $destination);
}

private function renameDatabaseReferences(File $folder)
{
$this->replacePathReferences($folder->id, $this->fromPath, $this->toPath);
}

private function replacePathReferences($folderId, $previousPath, $newPath)
{
$medias = $this->file->allChildrenOf($folderId);

foreach ($medias as $media) {
$oldPath = $media->path->getRelativeUrl();

$media->update([
'path' => $this->removeDoubleSlashes(str_replace($previousPath, $newPath, $oldPath)),
]);
if ($media->isFolder() === true) {
$this->replacePathReferences($media->id, $previousPath, $newPath);
}
}
}

private function moveDirectory($fromPath, $toPath) : bool
{
try {
$this->filesystem->disk($this->getConfiguredFilesystem())
->move(
$this->getDestinationPath($fromPath),
$this->getDestinationPath($toPath)
);
} catch (FileExistsException $e) {
return false;
}
return true;
}

private function getDestinationPath($path) : string
{
if ($this->getConfiguredFilesystem() === 'local') {
return basename(public_path()) . $path;
}

return $path;
}

private function getConfiguredFilesystem() : string
{
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
{
return str_replace('//', '/', $string);
}
}
10 changes: 10 additions & 0 deletions Modules/Media/Services/Mover.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Modules\Media\Services;

use Modules\Media\Entities\File;

interface Mover
{
public function move(File $file, File $destination) : bool;
}
104 changes: 0 additions & 104 deletions Modules/Media/Tests/EloquentFolderRepositoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -330,101 +330,6 @@ 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_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')
{
return File::create([
Expand All @@ -436,13 +341,4 @@ private function createFile($fileName = 'random/name.jpg')
'folder_id' => 0,
]);
}

private function makeRootFolder() : File
{
return new File([
'id' => 0,
'folder_id' => 0,
'path' => config('asgard.media.config.files-path'),
]);
}
}
Loading

0 comments on commit e0b1499

Please sign in to comment.