From 515581504312df9d3f082db43160d74e700a0972 Mon Sep 17 00:00:00 2001 From: "Fabian @ Blax Software" Date: Tue, 19 May 2026 14:20:20 +0200 Subject: [PATCH] BF migration issues, R hybrid --- config/files.php | 17 ++++++ ...6_04_14_000001_create_blax_files_table.php | 51 ++++++++++++++++ ...4_14_000002_create_blax_filables_table.php | 53 +++++++++++++++++ .../create_blax_filables_table.php.stub | 33 ----------- .../create_blax_files_table.php.stub | 30 ---------- src/FilesServiceProvider.php | 58 ++++++++++++++----- 6 files changed, 165 insertions(+), 77 deletions(-) create mode 100644 database/migrations/2026_04_14_000001_create_blax_files_table.php create mode 100644 database/migrations/2026_04_14_000002_create_blax_filables_table.php delete mode 100644 database/migrations/create_blax_filables_table.php.stub delete mode 100644 database/migrations/create_blax_files_table.php.stub diff --git a/config/files.php b/config/files.php index d05e64b..3a28df1 100644 --- a/config/files.php +++ b/config/files.php @@ -2,6 +2,23 @@ return [ + /* + |-------------------------------------------------------------------------- + | Auto-load migrations + |-------------------------------------------------------------------------- + | + | When true (the default) the package auto-loads its migrations from + | `vendor/blax-software/laravel-files/database/migrations` so a fresh + | `composer require` + `php artisan migrate` Just Works™. Set to false + | if you publish the migrations and want to manage them yourself — the + | package will then defer entirely to your published copies. + | + | See: laravel-workkit/PRINCIPLES/laravel-composer-packages.md + | + */ + + 'run_migrations' => true, + /* |-------------------------------------------------------------------------- | Models diff --git a/database/migrations/2026_04_14_000001_create_blax_files_table.php b/database/migrations/2026_04_14_000001_create_blax_files_table.php new file mode 100644 index 0000000..9d78439 --- /dev/null +++ b/database/migrations/2026_04_14_000001_create_blax_files_table.php @@ -0,0 +1,51 @@ +uuid('id')->primary(); + // UUID rather than `unsignedBigInteger` so the package works + // out-of-the-box with the UUID-PK conventions used across the + // Blax fleet (see PRINCIPLES section "UUIDs or ULIDs for + // everything"). Hosts on bigint user IDs can publish the + // migration and swap this column type before running it. + $table->uuid('user_id')->nullable()->index(); + $table->string('name')->nullable(); + $table->string('type')->nullable(); + $table->string('extension')->nullable(); + $table->unsignedBigInteger('size')->nullable(); + $table->string('disk')->default(config('files.disk', 'local')); + $table->string('relativepath')->nullable(); + $table->json('meta')->nullable(); + $table->timestamp('last_accessed_at')->nullable(); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists(config('files.table_names.files', 'files')); + } +}; diff --git a/database/migrations/2026_04_14_000002_create_blax_filables_table.php b/database/migrations/2026_04_14_000002_create_blax_filables_table.php new file mode 100644 index 0000000..18f3cdc --- /dev/null +++ b/database/migrations/2026_04_14_000002_create_blax_filables_table.php @@ -0,0 +1,53 @@ +uuid('id')->primary(); + $table->uuid('file_id'); + // uuidMorphs for the same reason `user_id` is a UUID on the + // files table: Blax host apps are UUID-PK by convention, so a + // bigint morph FK wouldn't fit. Hosts that need bigint can + // publish + edit. + $table->uuidMorphs('filable'); + $table->string('as')->nullable()->index(); + $table->smallInteger('order')->nullable()->default(null); + $table->json('meta')->nullable(); + $table->timestamps(); + + $table->foreign('file_id') + ->references('id') + ->on(config('files.table_names.files', 'files')) + ->cascadeOnDelete(); + + $table->unique(['file_id', 'filable_type', 'filable_id', 'as'], 'filables_unique'); + }); + } + + public function down(): void + { + Schema::dropIfExists(config('files.table_names.filables', 'filables')); + } +}; diff --git a/database/migrations/create_blax_filables_table.php.stub b/database/migrations/create_blax_filables_table.php.stub deleted file mode 100644 index aa80c6e..0000000 --- a/database/migrations/create_blax_filables_table.php.stub +++ /dev/null @@ -1,33 +0,0 @@ -id(); - $table->uuid('file_id'); - $table->morphs('filable'); - $table->string('as')->nullable()->index(); - $table->smallInteger('order')->nullable()->default(null); - $table->json('meta')->nullable(); - $table->timestamps(); - - $table->foreign('file_id') - ->references('id') - ->on(config('files.table_names.files', 'files')) - ->cascadeOnDelete(); - - $table->unique(['file_id', 'filable_type', 'filable_id', 'as'], 'filables_unique'); - }); - } - - public function down(): void - { - Schema::dropIfExists(config('files.table_names.filables', 'filables')); - } -}; diff --git a/database/migrations/create_blax_files_table.php.stub b/database/migrations/create_blax_files_table.php.stub deleted file mode 100644 index 8c51246..0000000 --- a/database/migrations/create_blax_files_table.php.stub +++ /dev/null @@ -1,30 +0,0 @@ -uuid('id')->primary(); - $table->unsignedBigInteger('user_id')->nullable()->index(); - $table->string('name')->nullable(); - $table->string('type')->nullable(); - $table->string('extension')->nullable(); - $table->unsignedBigInteger('size')->nullable(); - $table->string('disk')->default(config('files.disk', 'local')); - $table->string('relativepath')->nullable(); - $table->json('meta')->nullable(); - $table->timestamp('last_accessed_at')->nullable(); - $table->timestamps(); - }); - } - - public function down(): void - { - Schema::dropIfExists(config('files.table_names.files', 'files')); - } -}; diff --git a/src/FilesServiceProvider.php b/src/FilesServiceProvider.php index 6b84b44..f7871fb 100644 --- a/src/FilesServiceProvider.php +++ b/src/FilesServiceProvider.php @@ -15,11 +15,40 @@ class FilesServiceProvider extends \Illuminate\Support\ServiceProvider public function boot() { $this->offerPublishing(); + $this->registerMigrations(); $this->registerModelBindings(); $this->registerRoutes(); $this->registerCommands(); } + /** + * Auto-load the package's migrations so fresh installs work without + * publishing. Disabled via `files.run_migrations = false` for projects + * that prefer to publish + manage migrations themselves. + * + * Follows the hybrid auto-load + publishable pattern documented in + * `laravel-workkit/PRINCIPLES/laravel-composer-packages.md`. + */ + protected function registerMigrations(): void + { + if (! config('files.run_migrations', true)) { + return; + } + + $this->loadMigrationsFrom(__DIR__ . '/../database/migrations'); + } + + /** + * Set up publishing of config and migrations for `php artisan vendor:publish`. + * + * Migrations are published preserving the SOURCE filename — the + * migrations table records filenames, so keeping them identical means + * any migration already executed via auto-load is recognised as run + * for the published copy too. Slap a fresh `date('Y_m_d_His')` on the + * publish destination and Laravel sees a brand-new migration and runs + * it again, causing the "table already exists" failures consumers used + * to hit before this rewrite. + */ protected function offerPublishing() { if (! $this->app->runningInConsole()) { @@ -28,23 +57,24 @@ class FilesServiceProvider extends \Illuminate\Support\ServiceProvider $this->publishes([ __DIR__ . '/../config/files.php' => $this->app->configPath('files.php'), - ], 'files-config'); + ], ['files-config', 'config']); - $this->publishes([ - __DIR__ . '/../database/migrations/create_blax_files_table.php.stub' => $this->getMigrationFileName('create_blax_files_table.php'), - __DIR__ . '/../database/migrations/create_blax_filables_table.php.stub' => $this->getMigrationFileName('create_blax_filables_table.php'), - ], 'files-migrations'); - } + $migrationsPath = __DIR__ . '/../database/migrations'; + $publishMap = []; + foreach (glob($migrationsPath . '/*.php') as $sourcePath) { + $publishMap[$sourcePath] = $this->app->databasePath('migrations/' . basename($sourcePath)); + } - protected function getMigrationFileName(string $migrationFileName): string - { - $timestamp = date('Y_m_d_His'); - $filesystem = $this->app->make(\Illuminate\Filesystem\Filesystem::class); + $this->publishes($publishMap, ['files-migrations', 'migrations']); - return \Illuminate\Support\Collection::make([$this->app->databasePath() . DIRECTORY_SEPARATOR . 'migrations' . DIRECTORY_SEPARATOR]) - ->flatMap(fn($path) => $filesystem->glob($path . '*_' . $migrationFileName)) - ->push($this->app->databasePath() . "/migrations/{$timestamp}_{$migrationFileName}") - ->first(); + // Convenience tag: publish everything the package owns in one go. + $this->publishes( + array_merge( + [__DIR__ . '/../config/files.php' => $this->app->configPath('files.php')], + $publishMap, + ), + 'files', + ); } protected function registerModelBindings(): void