orderByRaw("CASE WHEN zone = 'left' THEN 0 ELSE 1 END") ->ordered() ->get() ->groupBy('zone'); return view('admin.home-slides.index', [ 'slides' => $slides, 'zoneLabels' => $this->zoneLabels(), ]); } public function create(Request $request): View { $zone = in_array($request->query('zone'), self::ZONES, true) ? $request->query('zone') : 'left'; return view('admin.home-slides.create', [ 'slide' => new HomeSlide([ 'zone' => $zone, 'show_title' => true, 'show_subtitle' => true, 'show_button' => true, 'sort_order' => 100, 'is_active' => true, ]), 'zoneLabels' => $this->zoneLabels(), ]); } public function store(Request $request): RedirectResponse { $data = $this->validateSlide($request, true); $data['image_path'] = $this->storeImage($request); HomeSlide::create($data); return redirect()->route('admin.home-slides.index')->with('status', 'Слайд добавлен.'); } public function edit(HomeSlide $homeSlide): View { return view('admin.home-slides.edit', [ 'slide' => $homeSlide, 'zoneLabels' => $this->zoneLabels(), ]); } public function update(Request $request, HomeSlide $homeSlide): RedirectResponse { $data = $this->validateSlide($request); if ($request->hasFile('image')) { $newPath = $this->storeImage($request); $oldPath = $homeSlide->image_path; $data['image_path'] = $newPath; $homeSlide->update($data); if ($oldPath && $oldPath !== $newPath) { $this->deleteImage($oldPath); } return redirect()->route('admin.home-slides.index')->with('status', 'Слайд обновлен.'); } $homeSlide->update($data); return redirect()->route('admin.home-slides.index')->with('status', 'Слайд обновлен.'); } public function destroy(HomeSlide $homeSlide): RedirectResponse { $this->deleteImage($homeSlide->image_path); $homeSlide->delete(); return redirect()->route('admin.home-slides.index')->with('status', 'Слайд удален.'); } private function validateSlide(Request $request, bool $requireImage = false): array { return $request->validate([ 'zone' => ['required', Rule::in(self::ZONES)], 'title' => ['nullable', 'string', 'max:160'], 'show_title' => ['nullable', 'boolean'], 'subtitle' => ['nullable', 'string', 'max:1500'], 'show_subtitle' => ['nullable', 'boolean'], 'button_text' => ['nullable', 'string', 'max:60'], 'button_url' => ['nullable', 'string', 'max:255', 'regex:/^(\\/|https?:\\/\\/).+/i'], 'show_button' => ['nullable', 'boolean'], 'sort_order' => ['required', 'integer', 'min:0', 'max:9999'], 'is_active' => ['nullable', 'boolean'], 'image' => [ $requireImage ? 'required' : 'nullable', 'image', 'mimes:jpg,jpeg,png,webp', 'max:5120', ], ]) + [ 'show_title' => $request->boolean('show_title'), 'show_subtitle' => $request->boolean('show_subtitle'), 'show_button' => $request->boolean('show_button'), 'is_active' => $request->boolean('is_active'), ]; } private function storeImage(Request $request): string { $file = $request->file('image'); if (!$file) { return ''; } $extension = strtolower((string) $file->getClientOriginalExtension()); if ($extension === '') { $extension = 'jpg'; } $name = now()->format('YmdHis') . '-' . Str::uuid() . '.' . $extension; return (string) $file->storeAs('home-slides', $name, 'public'); } private function deleteImage(?string $path): void { if (!$path) { return; } if (str_starts_with($path, 'uploads/')) { $filePath = public_path(ltrim($path, '/')); if (File::exists($filePath)) { File::delete($filePath); } return; } Storage::disk('public')->delete($path); } private function zoneLabels(): array { return [ 'left' => 'Большой слайдер (2/3)', 'right' => 'Малый слайдер (1/3)', ]; } }