get('per_page', 9); $query = Noticia::query(); // filtros opcionales if ($request->filled('publicado')) { $query->where('publicado', $request->boolean('publicado')); } if ($request->filled('categoria')) { $query->where('categoria', $request->string('categoria')); } if ($request->filled('q')) { $q = trim((string) $request->get('q')); $query->where(function ($sub) use ($q) { $sub->where('titulo', 'like', "%{$q}%") ->orWhere('descripcion_corta', 'like', "%{$q}%"); }); } $data = $query ->orderByDesc('destacado') ->orderByDesc('fecha_publicacion') ->orderByDesc('orden') ->orderByDesc('id') ->paginate($perPage); return response()->json([ 'success' => true, 'data' => $data->items(), 'meta' => [ 'current_page' => $data->currentPage(), 'last_page' => $data->lastPage(), 'per_page' => $data->perPage(), 'total' => $data->total(), ], ]); } // GET /api/noticias/{noticia} public function show(Noticia $noticia) { return response()->json([ 'success' => true, 'data' => $noticia, ]); } // GET /api/noticias/{noticia} public function showPublic(Noticia $noticia) { abort_unless($noticia->publicado, 404); return response()->json([ 'success' => true, 'data' => $noticia, ]); } // POST /api/noticias (multipart/form-data si viene imagen) public function store(Request $request) { $data = $request->validate([ 'titulo' => ['required', 'string', 'max:220'], 'slug' => ['nullable', 'string', 'max:260', 'unique:noticias,slug'], 'descripcion_corta' => ['nullable', 'string', 'max:500'], 'contenido' => ['nullable', 'string'], 'categoria' => ['nullable', 'string', 'max:80'], 'tag_color' => ['nullable', 'string', 'max:30'], 'imagen' => ['nullable', 'file', 'mimes:jpg,jpeg,png,webp', 'max:4096'], 'imagen_path' => ['nullable', 'string', 'max:255'], 'link_url' => ['nullable', 'string', 'max:600'], 'link_texto' => ['nullable', 'string', 'max:120'], 'fecha_publicacion' => ['nullable', 'date'], 'publicado' => ['nullable', 'boolean'], 'destacado' => ['nullable', 'boolean'], 'orden' => ['nullable', 'integer'], ]); // slug por defecto if (empty($data['slug'])) { $data['slug'] = Str::slug($data['titulo']); } // subir imagen si viene if ($request->hasFile('imagen')) { $path = $request->file('imagen')->store('noticias', 'public'); $data['imagen_path'] = $path; } // si publican sin fecha, poner ahora if (!empty($data['publicado']) && empty($data['fecha_publicacion'])) { $data['fecha_publicacion'] = now(); } $noticia = Noticia::create($data); return response()->json([ 'success' => true, 'data' => $noticia, ], 201); } // PUT/PATCH /api/noticias/{noticia} public function update(Request $request, Noticia $noticia) { $data = $request->validate([ 'titulo' => ['sometimes', 'required', 'string', 'max:220'], 'slug' => ['sometimes', 'nullable', 'string', 'max:260', 'unique:noticias,slug,' . $noticia->id], 'descripcion_corta' => ['sometimes', 'nullable', 'string', 'max:500'], 'contenido' => ['sometimes', 'nullable', 'string'], 'categoria' => ['sometimes', 'nullable', 'string', 'max:80'], 'tag_color' => ['sometimes', 'nullable', 'string', 'max:30'], 'imagen' => ['sometimes', 'nullable', 'file', 'mimes:jpg,jpeg,png,webp', 'max:4096'], 'imagen_path' => ['sometimes', 'nullable', 'string', 'max:255'], 'link_url' => ['sometimes', 'nullable', 'string', 'max:600'], 'link_texto' => ['sometimes', 'nullable', 'string', 'max:120'], 'fecha_publicacion' => ['sometimes', 'nullable', 'date'], 'publicado' => ['sometimes', 'boolean'], 'destacado' => ['sometimes', 'boolean'], 'orden' => ['sometimes', 'integer'], ]); // si llega imagen, reemplazar if ($request->hasFile('imagen')) { if ($noticia->imagen_path && Storage::disk('public')->exists($noticia->imagen_path)) { Storage::disk('public')->delete($noticia->imagen_path); } $path = $request->file('imagen')->store('noticias', 'public'); $data['imagen_path'] = $path; } // si se marca publicado y no hay fecha, set now if (array_key_exists('publicado', $data) && $data['publicado'] && empty($noticia->fecha_publicacion) && empty($data['fecha_publicacion'])) { $data['fecha_publicacion'] = now(); } // si cambian titulo y slug no vino, regenerar slug (opcional) if (array_key_exists('titulo', $data) && !array_key_exists('slug', $data)) { $data['slug'] = Str::slug($data['titulo']); } $noticia->update($data); return response()->json([ 'success' => true, 'data' => $noticia->fresh(), ]); } // DELETE /api/noticias/{noticia} public function destroy(Noticia $noticia) { // opcional: borrar imagen al eliminar if ($noticia->imagen_path && Storage::disk('public')->exists($noticia->imagen_path)) { Storage::disk('public')->delete($noticia->imagen_path); } $noticia->delete(); return response()->json([ 'success' => true, 'message' => 'Noticia eliminada correctamente', ]); } }