Refactor attachment cropping functionality to support multiple variants

- Introduced AttachmentCrop model to manage crop variants for attachments.
- Updated Attachment model to remove direct crop fields and establish relationships with AttachmentCrop.
- Modified AttachmentService to handle storing and updating multiple crop variants (desktop and mobile).
- Adjusted validation rules to accommodate new crop structure.
- Updated database migration to create attachment_crops table and migrate existing crop data.
- Refactored tests to ensure compatibility with the new cropping structure and validate multiple crop variants.
- Enhanced documentation to reflect changes in attachment handling and cropping capabilities.
This commit is contained in:
2026-08-18 14:40:22 -03:00
parent c00b3d609c
commit e619c51ac9
14 changed files with 526 additions and 150 deletions

View File

@@ -0,0 +1,91 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
if (! Schema::hasTable('attachment_crops')) {
Schema::create('attachment_crops', function (Blueprint $table): void {
$table->id();
$table->foreignId('attachment_id')->constrained('attachments')->cascadeOnDelete();
$table->string('variant', 20);
$table->json('crop_horizontal');
$table->json('crop_vertical');
$table->foreignId('cropped_attachment_id')
->unique()
->constrained('attachments')
->cascadeOnDelete();
$table->timestamps();
$table->unique(['attachment_id', 'variant']);
});
}
if (Schema::hasColumn('attachments', 'cropped_attachment_id')) {
DB::table('attachments')
->whereNotNull('cropped_attachment_id')
->orderBy('id')
->chunkById(100, function ($attachments): void {
foreach ($attachments as $attachment) {
DB::table('attachment_crops')->updateOrInsert(
['attachment_id' => $attachment->id, 'variant' => 'desktop'],
[
'crop_horizontal' => $attachment->crop_horizontal
?? json_encode(['start_percentage' => 0, 'end_percentage' => 100]),
'crop_vertical' => $attachment->crop_vertical
?? json_encode(['start_percentage' => 0, 'end_percentage' => 100]),
'cropped_attachment_id' => $attachment->cropped_attachment_id,
'created_at' => now(),
'updated_at' => now(),
]
);
}
});
Schema::table('attachments', function (Blueprint $table): void {
$table->dropForeign(['cropped_attachment_id']);
$table->dropColumn([
'crop_horizontal',
'crop_vertical',
'cropped_attachment_id',
]);
});
}
}
public function down(): void
{
Schema::table('attachments', function (Blueprint $table): void {
$table->json('crop_horizontal')->nullable()->after('size');
$table->json('crop_vertical')->nullable()->after('crop_horizontal');
$table->foreignId('cropped_attachment_id')
->nullable()
->unique()
->after('crop_vertical')
->constrained('attachments')
->nullOnDelete();
});
DB::table('attachment_crops')
->where('variant', 'desktop')
->orderBy('id')
->chunkById(100, function ($crops): void {
foreach ($crops as $crop) {
DB::table('attachments')
->where('id', $crop->attachment_id)
->update([
'crop_horizontal' => $crop->crop_horizontal,
'crop_vertical' => $crop->crop_vertical,
'cropped_attachment_id' => $crop->cropped_attachment_id,
]);
}
});
Schema::dropIfExists('attachment_crops');
}
};