From b0508d79b37ce9ab2bcdb14f6d2e5c44ffc2e887 Mon Sep 17 00:00:00 2001 From: ncoronel Date: Mon, 29 Jun 2026 09:43:46 -0300 Subject: [PATCH] feat: implement Attachment domain for file storage and integrate into Tenant service for logo management --- .../Models/AttachableAttachment.php | 44 ------------------- app/Domains/Attachable/Models/Attachment.php | 9 ---- .../Models/Concerns/HasAttachments.php | 24 ---------- app/Domains/Tenant/Models/Tenant.php | 2 - app/Domains/Tenant/Services/TenantService.php | 10 ----- ..._06_25_000500_create_attachments_table.php | 3 -- ...factor_attachments_to_attachable_pivot.php | 43 ------------------ phpunit.xml | 4 +- tests/Feature/Attachable/AttachmentTest.php | 42 ------------------ 9 files changed, 2 insertions(+), 179 deletions(-) delete mode 100644 app/Domains/Attachable/Models/AttachableAttachment.php delete mode 100644 app/Domains/Attachable/Models/Concerns/HasAttachments.php delete mode 100644 database/migrations/2026_06_25_000600_refactor_attachments_to_attachable_pivot.php diff --git a/app/Domains/Attachable/Models/AttachableAttachment.php b/app/Domains/Attachable/Models/AttachableAttachment.php deleted file mode 100644 index caed0da..0000000 --- a/app/Domains/Attachable/Models/AttachableAttachment.php +++ /dev/null @@ -1,44 +0,0 @@ - 'integer', - 'attachment_id' => 'integer', - ]; - } - - /** - * @return MorphTo - */ - public function attachable(): MorphTo - { - return $this->morphTo(); - } - - /** - * @return BelongsTo - */ - public function attachment(): BelongsTo - { - return $this->belongsTo(Attachment::class, 'attachment_id'); - } -} diff --git a/app/Domains/Attachable/Models/Attachment.php b/app/Domains/Attachable/Models/Attachment.php index cca3f90..82de3a5 100644 --- a/app/Domains/Attachable/Models/Attachment.php +++ b/app/Domains/Attachable/Models/Attachment.php @@ -6,7 +6,6 @@ use App\Domains\Attachable\Enums\AttachmentType; use Illuminate\Database\Eloquent\Attributes\Fillable; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; -use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Support\Str; #[Fillable([ @@ -41,14 +40,6 @@ class Attachment extends Model ]; } - /** - * @return HasMany - */ - public function attachables(): HasMany - { - return $this->hasMany(AttachableAttachment::class, 'attachment_id'); - } - /** * Get the pre-signed temporary S3 URL for this attachment. */ diff --git a/app/Domains/Attachable/Models/Concerns/HasAttachments.php b/app/Domains/Attachable/Models/Concerns/HasAttachments.php deleted file mode 100644 index 48ec7a4..0000000 --- a/app/Domains/Attachable/Models/Concerns/HasAttachments.php +++ /dev/null @@ -1,24 +0,0 @@ - - */ - public function attachments(): MorphToMany - { - return $this->morphToMany( - Attachment::class, - 'attachable', - 'attachable_attachments', - 'attachable_id', - 'attachment_id', - ); - } -} diff --git a/app/Domains/Tenant/Models/Tenant.php b/app/Domains/Tenant/Models/Tenant.php index ec60942..fdc8ae3 100644 --- a/app/Domains/Tenant/Models/Tenant.php +++ b/app/Domains/Tenant/Models/Tenant.php @@ -3,7 +3,6 @@ namespace App\Domains\Tenant\Models; use App\Domains\Attachable\Models\Attachment; -use App\Domains\Attachable\Models\Concerns\HasAttachments; use App\Domains\Catalog\Models\Product; use Illuminate\Database\Eloquent\Attributes\Fillable; use Illuminate\Database\Eloquent\Factories\HasFactory; @@ -24,7 +23,6 @@ use Illuminate\Database\Eloquent\Relations\HasMany; ])] class Tenant extends Model { - use HasAttachments; use HasFactory; public function getRouteKeyName(): string diff --git a/app/Domains/Tenant/Services/TenantService.php b/app/Domains/Tenant/Services/TenantService.php index 3964498..3357101 100644 --- a/app/Domains/Tenant/Services/TenantService.php +++ b/app/Domains/Tenant/Services/TenantService.php @@ -55,14 +55,6 @@ class TenantService /** @var Tenant $tenant */ $tenant = Tenant::query()->create($data); - if ($headerAttachmentId) { - $tenant->attachments()->attach($headerAttachmentId); - } - - if ($footerAttachmentId) { - $tenant->attachments()->attach($footerAttachmentId); - } - return $tenant; }); } @@ -94,7 +86,6 @@ class TenantService if ($attachment) { $tenant->header_logo_id = $attachment->id; - $tenant->attachments()->attach($attachment->id); } else { $tenant->header_logo_id = null; } @@ -111,7 +102,6 @@ class TenantService if ($attachment) { $tenant->footer_logo_id = $attachment->id; - $tenant->attachments()->attach($attachment->id); } else { $tenant->footer_logo_id = null; } diff --git a/database/migrations/2026_06_25_000500_create_attachments_table.php b/database/migrations/2026_06_25_000500_create_attachments_table.php index 61f127d..acdc1ad 100644 --- a/database/migrations/2026_06_25_000500_create_attachments_table.php +++ b/database/migrations/2026_06_25_000500_create_attachments_table.php @@ -13,8 +13,6 @@ return new class extends Migration { Schema::create('attachments', function (Blueprint $table) { $table->id(); - $table->string('attachable_type'); - $table->unsignedBigInteger('attachable_id'); $table->uuid('key')->unique(); $table->string('path'); $table->string('filename'); @@ -24,7 +22,6 @@ return new class extends Migration $table->unsignedBigInteger('size')->default(0); $table->timestamps(); - $table->index(['attachable_type', 'attachable_id']); $table->index('type'); $table->index('mime_type'); }); diff --git a/database/migrations/2026_06_25_000600_refactor_attachments_to_attachable_pivot.php b/database/migrations/2026_06_25_000600_refactor_attachments_to_attachable_pivot.php deleted file mode 100644 index 1f9f6be..0000000 --- a/database/migrations/2026_06_25_000600_refactor_attachments_to_attachable_pivot.php +++ /dev/null @@ -1,43 +0,0 @@ -dropIndex(['attachable_type', 'attachable_id']); - $table->dropColumn(['attachable_type', 'attachable_id']); - }); - - Schema::create('attachable_attachments', function (Blueprint $table): void { - $table->id(); - $table->string('attachable_type'); - $table->unsignedBigInteger('attachable_id'); - $table->foreignId('attachment_id')->constrained('attachments')->cascadeOnDelete(); - - $table->unique(['attachable_type', 'attachable_id', 'attachment_id'], 'attachable_attachments_unique'); - $table->index(['attachable_type', 'attachable_id'], 'attachable_attachments_attachable_index'); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::dropIfExists('attachable_attachments'); - - Schema::table('attachments', function (Blueprint $table): void { - $table->string('attachable_type'); - $table->unsignedBigInteger('attachable_id'); - $table->index(['attachable_type', 'attachable_id']); - }); - } -}; diff --git a/phpunit.xml b/phpunit.xml index e7f0a48..72d70e8 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -23,8 +23,8 @@ - - + + diff --git a/tests/Feature/Attachable/AttachmentTest.php b/tests/Feature/Attachable/AttachmentTest.php index f5bf356..219b2f2 100644 --- a/tests/Feature/Attachable/AttachmentTest.php +++ b/tests/Feature/Attachable/AttachmentTest.php @@ -6,7 +6,6 @@ use App\Domains\Attachable\Enums\AttachmentType; use App\Domains\Attachable\Exceptions\AttachmentStorageException; use App\Domains\Attachable\Models\Attachment; use App\Domains\Attachable\Services\AttachmentService; -use App\Domains\Tenant\Models\Tenant; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Storage; @@ -22,19 +21,12 @@ class AttachmentTest extends TestCase { Storage::fake('s3'); - $tenant = Tenant::query()->create([ - 'codigo' => 'acme', - 'nombre' => 'Acme', - 'dominio' => 'acme.com', - ]); - $file = UploadedFile::fake()->image('logo.png'); $attachment = app(AttachmentService::class)->store( $file, 'attachments/acme/logo.png', ); - $tenant->attachments()->attach($attachment->getKey()); $this->assertSame(AttachmentType::Image, $attachment->type); $this->assertTrue(Str::isUuid($attachment->key)); @@ -48,26 +40,14 @@ class AttachmentTest extends TestCase 'filename' => 'logo.png', 'type' => AttachmentType::Image->value, ]); - $this->assertDatabaseHas('attachable_attachments', [ - 'attachable_type' => $tenant->getMorphClass(), - 'attachable_id' => $tenant->getKey(), - 'attachment_id' => $attachment->id, - ]); $freshAttachment = Attachment::query()->findOrFail($attachment->id); $this->assertSame(AttachmentType::Image, $freshAttachment->type); - $this->assertTrue($tenant->attachments->contains($freshAttachment)); } public function test_it_does_not_persist_the_attachment_when_the_s3_upload_fails(): void { - $tenant = Tenant::query()->create([ - 'codigo' => 'globex', - 'nombre' => 'Globex', - 'dominio' => 'globex.com', - ]); - $disk = Mockery::mock(); Storage::shouldReceive('disk') ->once() @@ -94,12 +74,6 @@ class AttachmentTest extends TestCase { Storage::fake('s3'); - $tenant = Tenant::query()->create([ - 'codigo' => 'initech', - 'nombre' => 'Initech', - 'dominio' => 'initech.com', - ]); - Storage::disk('s3')->put('attachments/initech/spec.pdf', 'spec'); $attachment = Attachment::query()->create([ @@ -111,7 +85,6 @@ class AttachmentTest extends TestCase 'extension' => 'pdf', 'size' => 512, ]); - $tenant->attachments()->attach($attachment->getKey()); app(AttachmentService::class)->delete($attachment); @@ -119,19 +92,10 @@ class AttachmentTest extends TestCase $this->assertDatabaseMissing('attachments', [ 'id' => $attachment->id, ]); - $this->assertDatabaseMissing('attachable_attachments', [ - 'attachment_id' => $attachment->id, - ]); } public function test_it_keeps_the_database_record_when_the_s3_delete_fails(): void { - $tenant = Tenant::query()->create([ - 'codigo' => 'umbrella', - 'nombre' => 'Umbrella', - 'dominio' => 'umbrella.com', - ]); - $attachment = Attachment::query()->create([ 'path' => 'attachments/umbrella/audio.mp3', 'key' => (string) Str::uuid(), @@ -141,7 +105,6 @@ class AttachmentTest extends TestCase 'extension' => 'mp3', 'size' => 1024, ]); - $tenant->attachments()->attach($attachment->getKey()); $disk = Mockery::mock(); Storage::shouldReceive('disk') @@ -161,11 +124,6 @@ class AttachmentTest extends TestCase $this->assertDatabaseHas('attachments', [ 'id' => $attachment->id, ]); - $this->assertDatabaseHas('attachable_attachments', [ - 'attachment_id' => $attachment->id, - 'attachable_type' => $tenant->getMorphClass(), - 'attachable_id' => $tenant->getKey(), - ]); } } }