Add photo management features, update database configuration, and enhance park model seeding

This commit is contained in:
pacnpal
2025-02-25 15:44:21 -05:00
parent 15b2d4ebcf
commit b4462ba89e
31 changed files with 2700 additions and 71 deletions

View File

@@ -0,0 +1,212 @@
<?php
namespace App\Http\Controllers;
use App\Models\Park;
use App\Models\Photo;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Intervention\Image\ImageManager;
use Intervention\Image\Drivers\Gd\Driver;
use Intervention\Image\Encoders\JpegEncoder;
use Illuminate\Support\Str;
class PhotoController extends Controller
{
/**
* Display a listing of the photos for a park.
*/
public function index(Park $park)
{
$photos = $park->photos()->ordered()->get();
return response()->json([
'photos' => $photos,
'featured_photo' => $park->featuredPhoto(),
]);
}
/**
* Store a newly uploaded photo.
*/
public function store(Request $request, Park $park)
{
$request->validate([
'photo' => 'required|image|max:10240', // 10MB max
'title' => 'nullable|string|max:255',
'description' => 'nullable|string',
'alt_text' => 'nullable|string|max:255',
'credit' => 'nullable|string|max:255',
'source_url' => 'nullable|url|max:255',
'is_featured' => 'nullable|boolean',
]);
// Handle file upload
if ($request->hasFile('photo')) {
$file = $request->file('photo');
$originalFilename = $file->getClientOriginalName();
$extension = $file->getClientOriginalExtension();
// Generate a unique filename
$filename = time() . '_' . Str::slug(pathinfo($originalFilename, PATHINFO_FILENAME)) . '.' . $extension;
// Define the storage path
$storagePath = 'photos/parks/' . $park->id;
$fullPath = $storagePath . '/' . $filename;
// Store the original file
$file->storeAs('public/' . $storagePath, $filename);
// Create image manager instance
$manager = new ImageManager(new Driver());
// Get image dimensions
$image = $manager->read($file);
$width = $image->width();
$height = $image->height();
// Generate thumbnail
$thumbnailFilename = pathinfo($filename, PATHINFO_FILENAME) . '_thumb.' . $extension;
$thumbnail = $manager->read($file)->scaleDown(width: 300, height: 300);
// Save thumbnail
$encodedThumbnail = $thumbnail->encode(
new JpegEncoder(80)
);
Storage::put(
'public/' . $storagePath . '/' . $thumbnailFilename,
$encodedThumbnail->toString()
);
// Create photo record
$photo = $park->addPhoto([
'title' => $request->input('title'),
'description' => $request->input('description'),
'file_path' => $fullPath,
'file_name' => $originalFilename,
'file_size' => $file->getSize(),
'mime_type' => $file->getMimeType(),
'width' => $width,
'height' => $height,
'alt_text' => $request->input('alt_text'),
'credit' => $request->input('credit'),
'source_url' => $request->input('source_url'),
'is_featured' => $request->input('is_featured', false),
]);
return response()->json([
'message' => 'Photo uploaded successfully',
'photo' => $photo,
], 201);
}
return response()->json([
'message' => 'No photo file provided',
], 400);
}
/**
* Display the specified photo.
*/
public function show(Photo $photo)
{
return response()->json($photo);
}
/**
* Update the specified photo.
*/
public function update(Request $request, Photo $photo)
{
$request->validate([
'title' => 'nullable|string|max:255',
'description' => 'nullable|string',
'alt_text' => 'nullable|string|max:255',
'credit' => 'nullable|string|max:255',
'source_url' => 'nullable|url|max:255',
'is_featured' => 'nullable|boolean',
]);
$photo->update($request->only([
'title', 'description', 'alt_text', 'credit', 'source_url'
]));
// Handle featured status
if ($request->has('is_featured') && $request->input('is_featured')) {
$photo->setAsFeatured();
}
return response()->json([
'message' => 'Photo updated successfully',
'photo' => $photo,
]);
}
/**
* Remove the specified photo.
*/
public function destroy(Photo $photo)
{
// Get the file paths
$filePath = 'public/' . $photo->file_path;
$pathInfo = pathinfo($photo->file_path);
$thumbnailPath = 'public/' . $pathInfo['dirname'] . '/' . $pathInfo['filename'] . '_thumb.' . $pathInfo['extension'];
// Delete the files
Storage::delete([$filePath, $thumbnailPath]);
// Delete the record
$photo->delete();
return response()->json([
'message' => 'Photo deleted successfully',
]);
}
/**
* Reorder photos for a park.
*/
public function reorder(Request $request, Park $park)
{
$request->validate([
'photo_ids' => 'required|array',
'photo_ids.*' => 'required|integer|exists:photos,id',
]);
$success = $park->reorderPhotos($request->input('photo_ids'));
if ($success) {
return response()->json([
'message' => 'Photos reordered successfully',
]);
}
return response()->json([
'message' => 'Failed to reorder photos',
], 500);
}
/**
* Set a photo as featured.
*/
public function setFeatured(Request $request, Park $park, Photo $photo)
{
if ($photo->photoable_id !== $park->id || $photo->photoable_type !== Park::class) {
return response()->json([
'message' => 'Photo does not belong to this park',
], 400);
}
$success = $park->setFeaturedPhoto($photo);
if ($success) {
return response()->json([
'message' => 'Featured photo set successfully',
]);
}
return response()->json([
'message' => 'Failed to set featured photo',
], 500);
}
}