From a26f9c1c1fd5e3798fa5514bac9b1bc074805eaa Mon Sep 17 00:00:00 2001 From: Andy Heathershaw Date: Mon, 17 Apr 2017 21:31:45 +0100 Subject: [PATCH] #4: Added a framework for manipulating data during system updates. Full URL path to an album is now saved in the database. Fall-back routes are now mapped by the first segment - a = album, p = photo, i = image --- app/Album.php | 54 ++++++++++++++----- app/AlbumSources/LocalFilesystemSource.php | 2 +- app/DataMigration.php | 8 +++ app/Helpers/DbHelper.php | 4 +- app/Helpers/MiscHelper.php | 15 ++++++ .../Controllers/Gallery/AlbumController.php | 2 +- .../Controllers/Gallery/DefaultController.php | 2 +- .../Controllers/Gallery/PhotoController.php | 4 +- app/Http/Middleware/AppInstallation.php | 9 ++++ app/ModelObservers/AlbumObserver.php | 22 ++++++++ app/Photo.php | 2 +- app/Providers/AppServiceProvider.php | 5 ++ .../DataMigrationV2_0_0_alpha_1.php | 27 ++++++++++ ...7_04_17_154654_add_parent_album_column.php | 2 + .../base/gallery/album_default.blade.php | 2 +- .../themes/base/gallery/album_empty.blade.php | 16 ++++-- .../base/gallery/album_slideshow.blade.php | 10 +--- .../base/partials/album_breadcrumb.blade.php | 7 +++ routes/web.php | 12 +++-- 19 files changed, 168 insertions(+), 37 deletions(-) create mode 100644 app/DataMigration.php create mode 100644 app/ModelObservers/AlbumObserver.php create mode 100644 database/data_migrations/DataMigrationV2_0_0_alpha_1.php create mode 100644 resources/views/themes/base/partials/album_breadcrumb.blade.php diff --git a/app/Album.php b/app/Album.php index 8c15d14..d8dd6a6 100644 --- a/app/Album.php +++ b/app/Album.php @@ -4,6 +4,7 @@ namespace App; use App\AlbumSources\IAlbumSource; use App\AlbumSources\LocalFilesystemSource; +use App\Helpers\MiscHelper; use Illuminate\Database\Eloquent\Model; use Illuminate\Http\Request; use Illuminate\Notifications\Notifiable; @@ -19,7 +20,7 @@ class Album extends Model * @var array */ protected $fillable = [ - 'name', 'description', 'url_alias', 'is_private', 'user_id', 'storage_id', 'default_view', 'parent_album_id' + 'name', 'description', 'url_alias', 'is_private', 'user_id', 'storage_id', 'default_view', 'parent_album_id', 'url_path' ]; /** @@ -30,6 +31,26 @@ class Album extends Model protected $hidden = [ ]; + /** + * Gets an array of parent items + * @return array + */ + public function albumParentTree() + { + $albums = []; + $current = $this; + + while (!is_null($current)) + { + $albums[] = $current; + + $current = $current->parent; + } + + $albums = array_reverse($albums); + return $albums; + } + public function anonymousPermissions() { return $this->belongsToMany(Permission::class, 'album_anonymous_permissions'); @@ -66,7 +87,23 @@ class Album extends Model public function generateAlias() { - $this->url_alias = ucfirst(preg_replace('/[^a-z0-9\-]/', '-', strtolower($this->name))); + $this->url_alias = MiscHelper::capitaliseWord(preg_replace('/[^a-z0-9\-]/', '-', strtolower($this->name))); + } + + public function generateUrlPath() + { + $parts = []; + $current = $this; + + while (!is_null($current)) + { + $parts[] = $current->url_alias; + + $current = $current->parent; + } + + $parts = array_reverse($parts); + $this->url_path = join('/', $parts); } /** @@ -146,19 +183,12 @@ class Album extends Model public function url() { - $parts = []; - $current = $this; - - while (!is_null($current)) + if (is_null($this->url_path)) { - $parts[] = $current->url_alias; - - $current = $current->parent; + $this->generateUrlPath(); } - $parts = array_reverse($parts); - - return route('viewAlbum', join('/', $parts)); + return route('viewAlbum', $this->url_path); } public function userPermissions() diff --git a/app/AlbumSources/LocalFilesystemSource.php b/app/AlbumSources/LocalFilesystemSource.php index b2df40f..d2640bc 100644 --- a/app/AlbumSources/LocalFilesystemSource.php +++ b/app/AlbumSources/LocalFilesystemSource.php @@ -62,7 +62,7 @@ class LocalFilesystemSource extends AlbumSourceBase implements IAlbumSource public function getUrlToPhoto(Photo $photo, $thumbnail = null) { $photoUrl = route('downloadPhoto', [ - 'albumUrlAlias' => $this->album->url_alias, + 'albumUrlAlias' => $this->album->url_path, 'photoFilename' => $photo->storage_file_name ]); diff --git a/app/DataMigration.php b/app/DataMigration.php new file mode 100644 index 0000000..07178c1 --- /dev/null +++ b/app/DataMigration.php @@ -0,0 +1,8 @@ +withCount('photos'); } - public static function getAlbumByAlias($urlAlias) + public static function getAlbumByPath($urlPath) { - return Album::where('url_alias', $urlAlias)->first(); + return Album::where('url_path', $urlPath)->first(); } } \ No newline at end of file diff --git a/app/Helpers/MiscHelper.php b/app/Helpers/MiscHelper.php index 967fa87..f74af77 100644 --- a/app/Helpers/MiscHelper.php +++ b/app/Helpers/MiscHelper.php @@ -4,6 +4,21 @@ namespace App\Helpers; class MiscHelper { + public static function capitaliseWord($word) + { + $word = strtolower($word); + + $wordLetters = []; + preg_match_all('/\b[a-z]/i', $word, $wordLetters, PREG_OFFSET_CAPTURE); + + foreach ($wordLetters[0] as $wordLetter) + { + $word = substr_replace($word, strtoupper($wordLetter[0]), $wordLetter[1], 1); + } + + return $word; + } + public static function convertToBytes($val) { if(empty($val))return 0; diff --git a/app/Http/Controllers/Gallery/AlbumController.php b/app/Http/Controllers/Gallery/AlbumController.php index 1d2ea51..68e6b01 100644 --- a/app/Http/Controllers/Gallery/AlbumController.php +++ b/app/Http/Controllers/Gallery/AlbumController.php @@ -18,7 +18,7 @@ class AlbumController extends Controller { public function index(Request $request, $albumUrlAlias) { - $album = DbHelper::getAlbumByAlias($albumUrlAlias); + $album = DbHelper::getAlbumByPath($albumUrlAlias); if (is_null($album)) { App::abort(404); diff --git a/app/Http/Controllers/Gallery/DefaultController.php b/app/Http/Controllers/Gallery/DefaultController.php index 9ae139c..93de77b 100644 --- a/app/Http/Controllers/Gallery/DefaultController.php +++ b/app/Http/Controllers/Gallery/DefaultController.php @@ -16,7 +16,7 @@ class DefaultController extends Controller { public function index(Request $request) { - $albums = DbHelper::getAlbumsForCurrentUser(); + $albums = DbHelper::getAlbumsForCurrentUser(0); $resetStatus = $request->session()->get('status'); // Record the visit to the index (no album or photo to record a hit against though) diff --git a/app/Http/Controllers/Gallery/PhotoController.php b/app/Http/Controllers/Gallery/PhotoController.php index d735bf4..b69ad54 100644 --- a/app/Http/Controllers/Gallery/PhotoController.php +++ b/app/Http/Controllers/Gallery/PhotoController.php @@ -22,7 +22,7 @@ class PhotoController extends Controller { public function download(Request $request, $albumUrlAlias, $photoFilename) { - $album = DbHelper::getAlbumByAlias($albumUrlAlias); + $album = DbHelper::getAlbumByPath($albumUrlAlias); if (is_null($album)) { App::abort(404); @@ -89,7 +89,7 @@ class PhotoController extends Controller public function show(Request $request, $albumUrlAlias, $photoFilename) { - $album = DbHelper::getAlbumByAlias($albumUrlAlias); + $album = DbHelper::getAlbumByPath($albumUrlAlias); if (is_null($album)) { App::abort(404); diff --git a/app/Http/Middleware/AppInstallation.php b/app/Http/Middleware/AppInstallation.php index 90df54f..7f3da93 100644 --- a/app/Http/Middleware/AppInstallation.php +++ b/app/Http/Middleware/AppInstallation.php @@ -3,6 +3,7 @@ namespace App\Http\Middleware; use App\Configuration; +use App\DataMigration; use App\Facade\UserConfig; use App\Helpers\MiscHelper; use Closure; @@ -96,6 +97,14 @@ class AppInstallation Artisan::call('cache:clear'); Artisan::call('migrate', ['--force' => true]); + + $className = sprintf('DataMigrationV%s', str_replace(['.', '-'], '_', $appVersionNumber)); + if (class_exists($className)) + { + /** @var DataMigration $upgradeClass */ + $upgradeClass = new $className; + $upgradeClass->run($versionNumber); + } } $versionNumber->value = $appVersionNumber; diff --git a/app/ModelObservers/AlbumObserver.php b/app/ModelObservers/AlbumObserver.php new file mode 100644 index 0000000..4511f78 --- /dev/null +++ b/app/ModelObservers/AlbumObserver.php @@ -0,0 +1,22 @@ +generateAlias(); + $album->generateUrlPath(); + } + + public function updating(Album $album) + { + // Re-generate the alias and path + $album->generateAlias(); + $album->generateUrlPath(); + } +} \ No newline at end of file diff --git a/app/Photo.php b/app/Photo.php index a36e04a..6dfb60c 100644 --- a/app/Photo.php +++ b/app/Photo.php @@ -65,7 +65,7 @@ class Photo extends Model public function url() { return route('viewPhoto', [ - 'albumUrlAlias' => $this->album->url_alias, + 'albumUrlAlias' => $this->album->url_path, 'photoFilename' => $this->storage_file_name ]); } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 2a30aba..50d4234 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,10 +2,12 @@ namespace App\Providers; +use App\Album; use App\Helpers\ConfigHelper; use App\Helpers\ImageHelper; use App\Helpers\ThemeHelper; use App\Helpers\ValidationHelper; +use App\ModelObservers\AlbumObserver; use Illuminate\Database\QueryException; use Illuminate\Mail\Mailer; use Illuminate\Support\Facades\DB; @@ -38,6 +40,9 @@ class AppServiceProvider extends ServiceProvider Validator::extend('is_dir', (ValidationHelper::class . '@directoryExists')); Validator::extend('dir_empty', (ValidationHelper::class . '@isDirectoryEmpty')); Validator::extend('is_writeable', (ValidationHelper::class . '@isPathWriteable')); + + // Model observers + Album::observe(AlbumObserver::class); } /** diff --git a/database/data_migrations/DataMigrationV2_0_0_alpha_1.php b/database/data_migrations/DataMigrationV2_0_0_alpha_1.php new file mode 100644 index 0000000..b8ab079 --- /dev/null +++ b/database/data_migrations/DataMigrationV2_0_0_alpha_1.php @@ -0,0 +1,27 @@ +storeAlbumUrlPaths(); + } + + /** + * Ensures all albums have a full URL path stored. + * @return void + */ + private function storeAlbumUrlPaths() + { + $albumsWithNoPath = Album::where('url_path', null)->get(); + + /** @var Album $album */ + foreach ($albumsWithNoPath as $album) + { + $album->touch(); + } + } +} \ No newline at end of file diff --git a/database/migrations/2017_04_17_154654_add_parent_album_column.php b/database/migrations/2017_04_17_154654_add_parent_album_column.php index cb4125d..26d40c1 100644 --- a/database/migrations/2017_04_17_154654_add_parent_album_column.php +++ b/database/migrations/2017_04_17_154654_add_parent_album_column.php @@ -16,6 +16,7 @@ class AddParentAlbumColumn extends Migration Schema::table('albums', function (Blueprint $table) { $table->unsignedInteger('parent_album_id')->nullable(); + $table->string('url_path')->nullable(); $table->foreign('parent_album_id') ->references('id')->on('albums') @@ -34,6 +35,7 @@ class AddParentAlbumColumn extends Migration { $table->dropForeign('albums_parent_album_id_foreign'); $table->dropColumn('parent_album_id'); + $table->dropColumn('url_path'); }); } } diff --git a/resources/views/themes/base/gallery/album_default.blade.php b/resources/views/themes/base/gallery/album_default.blade.php index c639f49..d34e6ef 100644 --- a/resources/views/themes/base/gallery/album_default.blade.php +++ b/resources/views/themes/base/gallery/album_default.blade.php @@ -7,7 +7,7 @@
diff --git a/resources/views/themes/base/gallery/album_empty.blade.php b/resources/views/themes/base/gallery/album_empty.blade.php index 146449a..82fd590 100644 --- a/resources/views/themes/base/gallery/album_empty.blade.php +++ b/resources/views/themes/base/gallery/album_empty.blade.php @@ -1,12 +1,18 @@ @extends('themes.base.layout') @section('title', $album->name) -@section('breadcrumb') - - -@endsection - @section('content') +
+
+
+ +
+
+
+
diff --git a/resources/views/themes/base/gallery/album_slideshow.blade.php b/resources/views/themes/base/gallery/album_slideshow.blade.php index 439f3b6..06499c1 100644 --- a/resources/views/themes/base/gallery/album_slideshow.blade.php +++ b/resources/views/themes/base/gallery/album_slideshow.blade.php @@ -2,14 +2,8 @@ @section('title', $album->name) @section('breadcrumb') - + + @include(Theme::viewName('partials.album_breadcrumb')) @endsection @section('content') diff --git a/resources/views/themes/base/partials/album_breadcrumb.blade.php b/resources/views/themes/base/partials/album_breadcrumb.blade.php new file mode 100644 index 0000000..4fe7e14 --- /dev/null +++ b/resources/views/themes/base/partials/album_breadcrumb.blade.php @@ -0,0 +1,7 @@ +@foreach ($album->albumParentTree() as $parentAlbum) + @if ($parentAlbum->id == $album->id) + + @else + + @endif +@endforeach \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index e4251ff..90f4983 100644 --- a/routes/web.php +++ b/routes/web.php @@ -66,6 +66,12 @@ Route::get('/', 'Gallery\DefaultController@index')->name('home'); Route::get('/activate/{token}', 'Auth\ActivateController@activate')->name('auth.activate'); Route::get('/password/change', 'Auth\ChangePasswordController@showChangePasswordForm')->name('auth.changePassword'); Route::post('/password/change', 'Auth\ChangePasswordController@processChangePassword')->name('auth.processChangePassword'); -Route::get('{albumUrlAlias}', 'Gallery\AlbumController@index')->name('viewAlbum'); -Route::get('{albumUrlAlias}/{photoFilename}', 'Gallery\PhotoController@show')->name('viewPhoto'); -Route::get('photo/{albumUrlAlias}/{photoFilename}', 'Gallery\PhotoController@download')->name('downloadPhoto'); \ No newline at end of file +Route::get('a/{albumUrlAlias}', 'Gallery\AlbumController@index') + ->name('viewAlbum') + ->where('albumUrlAlias', '.*'); +Route::get('p/{albumUrlAlias}/{photoFilename}', 'Gallery\PhotoController@show') + ->name('viewPhoto') + ->where('albumUrlAlias', '.*'); +Route::get('i/{albumUrlAlias}/{photoFilename}', 'Gallery\PhotoController@download') + ->name('downloadPhoto') + ->where('albumUrlAlias', '.*'); \ No newline at end of file