Răsfoiți Sursa

✨ feat(media): adicionar módulo de gerenciamento de mídia

Fase: dev | Origin: melhoria-interna
Gustavo Zanatta 1 săptămână în urmă
părinte
comite
4148d0fd95

+ 44 - 0
app/Http/Controllers/MediaController.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Http\Requests\MediaRequest;
+use App\Http\Resources\MediaResource;
+use App\Services\MediaService;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+
+class MediaController extends Controller
+{
+    public function __construct(protected MediaService $service) {}
+
+    public function indexBySource(Request $request): JsonResponse
+    {
+        $source   = $request->query('source');
+        $sourceId = (int) $request->query('source_id');
+        $items    = $this->service->getAllBySource($source, $sourceId);
+        return $this->successResponse(payload: MediaResource::collection($items));
+    }
+
+    public function store(MediaRequest $request): JsonResponse
+    {
+        $item = $this->service->create($request->validated());
+        return $this->successResponse(
+            payload: new MediaResource($item),
+            message: __('messages.created'),
+            code: 201,
+        );
+    }
+
+    public function show(int $id): JsonResponse
+    {
+        $item = $this->service->findById($id);
+        return $this->successResponse(payload: new MediaResource($item));
+    }
+
+    public function destroy(int $id): JsonResponse
+    {
+        $this->service->delete($id);
+        return $this->successResponse(message: __('messages.deleted'), code: 204);
+    }
+}

+ 31 - 0
app/Http/Requests/MediaRequest.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace App\Http\Requests;
+
+use App\Enums\MediaTypeEnum;
+use Illuminate\Foundation\Http\FormRequest;
+use Illuminate\Validation\Rule;
+
+class MediaRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        $rules = [
+            'type'      => ['sometimes', Rule::enum(MediaTypeEnum::class)],
+            'source'    => 'sometimes|nullable|string|max:100',
+            'source_id' => 'sometimes|nullable|integer',
+            'path'      => 'sometimes|string|max:500',
+            'name'      => 'sometimes|string|max:255',
+            'url'       => 'sometimes|string|max:500',
+        ];
+
+        if ($this->isMethod('post')) {
+            $rules['type']      = ['required', Rule::enum(MediaTypeEnum::class)];
+            $rules['path']      = 'required|string|max:500';
+            $rules['name']      = 'required|string|max:255';
+            $rules['url']       = 'required|string|max:500';
+        }
+
+        return $rules;
+    }
+}

+ 26 - 0
app/Http/Resources/MediaResource.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Carbon\Carbon;
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+
+class MediaResource extends JsonResource
+{
+    public function toArray(Request $request): array
+    {
+        return [
+            'id'         => $this->id,
+            'type'       => $this->type,
+            'source'     => $this->source,
+            'source_id'  => $this->source_id,
+            'path'       => $this->path,
+            'name'       => $this->name,
+            'url'        => $this->url ? url($this->url) : null,
+            'user_id'    => $this->user_id,
+            'created_at' => Carbon::parse($this->created_at)->format('Y-m-d H:i:s'),
+            'updated_at' => Carbon::parse($this->updated_at)->format('Y-m-d H:i:s'),
+        ];
+    }
+}

+ 27 - 0
app/Models/Media.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace App\Models;
+
+use App\Enums\MediaTypeEnum;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use Illuminate\Database\Eloquent\SoftDeletes;
+
+class Media extends Model
+{
+    use SoftDeletes;
+
+    protected $guarded = ['id'];
+
+    protected function casts(): array
+    {
+        return [
+            'type' => MediaTypeEnum::class,
+        ];
+    }
+
+    public function user(): BelongsTo
+    {
+        return $this->belongsTo(User::class);
+    }
+}

+ 70 - 0
app/Services/MediaService.php

@@ -0,0 +1,70 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\Media;
+use Illuminate\Database\Eloquent\Collection;
+use Illuminate\Http\UploadedFile;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\Storage;
+
+class MediaService
+{
+    public function getAllBySource(string $source, int $sourceId): Collection
+    {
+        return Media::where('source', $source)
+            ->where('source_id', $sourceId)
+            ->orderBy('created_at', 'desc')
+            ->get();
+    }
+
+    public function findById(int $id): ?Media
+    {
+        return Media::find($id);
+    }
+
+    public function create(array $data): Media
+    {
+        $data['user_id'] = Auth::id();
+        return Media::create($data);
+    }
+
+    public function upload(UploadedFile $file, string $source, int $sourceId, string $mediaType = 'imagem'): Media
+    {
+        $path = $file->store("media/{$source}/{$sourceId}", 'public');
+
+        return $this->create([
+            'type'      => $mediaType,
+            'source'    => $source,
+            'source_id' => $sourceId,
+            'path'      => $path,
+            'name'      => $file->getClientOriginalName(),
+            'url'       => Storage::url($path),
+        ]);
+    }
+
+    public function uploadLogo(UploadedFile $file, int $sourceId): Media
+    {
+        Media::where('source', 'partner_agreement_logo')
+            ->where('source_id', $sourceId)
+            ->get()
+            ->each(function (Media $m) {
+                Storage::disk('public')->delete($m->path);
+                $m->forceDelete();
+            });
+
+        return $this->upload($file, 'partner_agreement_logo', $sourceId, 'imagem');
+    }
+
+    public function delete(int $id): bool
+    {
+        $model = $this->findById($id);
+
+        if (!$model) {
+            return false;
+        }
+
+        Storage::disk('public')->delete($model->path);
+        return $model->delete();
+    }
+}

+ 32 - 0
database/migrations/2025_01_01_000013_create_media_table.php

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    public function up(): void
+    {
+        Schema::create('media', function (Blueprint $table) {
+            $table->id();
+            $table->string('type');
+            $table->string('source')->nullable();
+            $table->unsignedBigInteger('source_id')->nullable();
+            $table->string('path');
+            $table->string('name');
+            $table->string('url');
+            $table->foreignId('user_id')->nullable()->constrained('users')->nullOnDelete();
+            $table->timestamps();
+            $table->softDeletes();
+
+            $table->index(['source', 'source_id']);
+            $table->index('user_id');
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::dropIfExists('media');
+    }
+};

+ 14 - 0
routes/authRoutes/media.php

@@ -0,0 +1,14 @@
+<?php
+
+use App\Http\Controllers\MediaController;
+use Illuminate\Support\Facades\Route;
+
+Route::controller(MediaController::class)->prefix('media')->group(function () {
+    Route::get('/', 'indexBySource');
+
+    Route::post('/', 'store');
+
+    Route::get('/{id}', 'show');
+
+    Route::delete('/{id}', 'destroy');
+});