296 lines
9.5 KiB
PHP
296 lines
9.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
trait AnimalPhotoActions
|
|
{
|
|
public static function uploadPhoto(): void
|
|
{
|
|
if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
|
|
http_response_code(405);
|
|
echo h(t('error.method_not_allowed'));
|
|
return;
|
|
}
|
|
|
|
$id = (int) ($_POST['animal_id'] ?? 0);
|
|
if ($id <= 0) {
|
|
http_response_code(400);
|
|
echo h(t('error.bad_request'));
|
|
return;
|
|
}
|
|
|
|
if (!isset($_FILES['photo']) || $_FILES['photo']['error'] !== UPLOAD_ERR_OK) {
|
|
http_response_code(400);
|
|
echo h(t('error.upload_failed'));
|
|
return;
|
|
}
|
|
|
|
$db = DB::pdo();
|
|
|
|
$tmp = $_FILES['photo']['tmp_name'];
|
|
$orig = (string) ($_FILES['photo']['name'] ?? 'photo');
|
|
$size = (int) ($_FILES['photo']['size'] ?? 0);
|
|
$mime = (string) ($_FILES['photo']['type'] ?? '');
|
|
|
|
$base = preg_replace('/[^a-zA-Z0-9._-]+/', '_', pathinfo($orig, PATHINFO_FILENAME));
|
|
$base = $base ?: 'photo';
|
|
$dir = __DIR__ . '/../../public/media/animals/' . $id;
|
|
try {
|
|
$stored = ImageService::storeUploaded($tmp, $dir, $base, 'photo');
|
|
$filename = $stored['filename'];
|
|
$mime = $stored['mime'];
|
|
$size = $stored['size'];
|
|
} catch (Throwable $e) {
|
|
http_response_code(400);
|
|
echo h($e->getMessage());
|
|
return;
|
|
}
|
|
|
|
// si aucune photo primaire, celle-ci devient primaire
|
|
$stmt = $db->prepare('SELECT COUNT(*) FROM animal_photos WHERE animal_id=:id AND is_primary=1');
|
|
$stmt->execute([':id' => $id]);
|
|
$hasPrimary = (int) $stmt->fetchColumn() > 0;
|
|
|
|
$stmt = $db->prepare('
|
|
INSERT INTO animal_photos(animal_id, filename, original_name, mime, size_bytes, is_primary)
|
|
VALUES(:aid,:fn,:orig,:mime,:sz,:prim)
|
|
');
|
|
$stmt->execute([
|
|
':aid' => $id,
|
|
':fn' => $filename,
|
|
':orig' => $orig,
|
|
':mime' => $mime,
|
|
':sz' => $size,
|
|
':prim' => $hasPrimary ? 0 : 1,
|
|
]);
|
|
|
|
header('Location: /animal?id=' . $id);
|
|
exit();
|
|
}
|
|
|
|
public static function uploadPhotos(): void
|
|
{
|
|
if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
|
|
http_response_code(405);
|
|
return;
|
|
}
|
|
|
|
$animalId = (int) ($_POST['animal_id'] ?? 0);
|
|
if ($animalId <= 0) {
|
|
http_response_code(400);
|
|
echo h(t('error.bad_request'));
|
|
return;
|
|
}
|
|
|
|
if (empty($_FILES['photos'])) {
|
|
http_response_code(400);
|
|
echo h(t('error.no_files'));
|
|
return;
|
|
}
|
|
|
|
$isPublic = (int) ($_POST['is_public'] ?? 1 ? 1 : 0);
|
|
$redirectHash = trim((string) ($_POST['redirect_hash'] ?? ''));
|
|
|
|
$db = DB::pdo();
|
|
self::ensureAnimalMediaDir($animalId);
|
|
|
|
$files = $_FILES['photos'];
|
|
$count = is_array($files['name']) ? count($files['name']) : 1;
|
|
|
|
// Y a-t-il déjà une photo principale ?
|
|
$hasPrimary = (bool) $db
|
|
->query(
|
|
'
|
|
SELECT 1 FROM animal_photos
|
|
WHERE animal_id=' .
|
|
(int) $animalId .
|
|
'
|
|
AND is_primary=1
|
|
LIMIT 1
|
|
',
|
|
)
|
|
->fetchColumn();
|
|
|
|
for ($i = 0; $i < $count; $i++) {
|
|
$name = is_array($files['name']) ? $files['name'][$i] : $files['name'];
|
|
$tmp = is_array($files['tmp_name']) ? $files['tmp_name'][$i] : $files['tmp_name'];
|
|
$err = is_array($files['error']) ? $files['error'][$i] : $files['error'];
|
|
|
|
if ($err !== UPLOAD_ERR_OK) {
|
|
continue;
|
|
}
|
|
if (!is_uploaded_file($tmp)) {
|
|
continue;
|
|
}
|
|
if (!self::isAllowedImage($tmp)) {
|
|
continue;
|
|
}
|
|
|
|
$base = self::safeFilename(pathinfo($name, PATHINFO_FILENAME));
|
|
$targetDir = $isPublic === 1 ? self::animalMediaDir($animalId) : PrivateMediaService::animalDir($animalId);
|
|
if ($isPublic === 0) {
|
|
PrivateMediaService::ensure($targetDir);
|
|
}
|
|
try {
|
|
$stored = ImageService::storeUploaded($tmp, $targetDir, $base, 'photo');
|
|
$final = $stored['filename'];
|
|
if ($isPublic === 0) {
|
|
@chmod($stored['path'], 0600);
|
|
}
|
|
} catch (Throwable) {
|
|
continue;
|
|
}
|
|
|
|
// RÈGLE : jamais une privée en principale
|
|
$isPrimary = !$hasPrimary && $isPublic === 1 ? 1 : 0;
|
|
if ($isPrimary === 1) {
|
|
$hasPrimary = true;
|
|
}
|
|
|
|
$st = $db->prepare('
|
|
INSERT INTO animal_photos(animal_id, filename, is_primary, is_public)
|
|
VALUES(:aid,:fn,:p,:pub)
|
|
');
|
|
$st->execute([
|
|
':aid' => $animalId,
|
|
':fn' => $final,
|
|
':p' => $isPrimary,
|
|
':pub' => $isPublic,
|
|
]);
|
|
}
|
|
|
|
$db->prepare(
|
|
"
|
|
UPDATE animals
|
|
SET updated_at=datetime('now')
|
|
WHERE id=:id
|
|
",
|
|
)->execute([':id' => $animalId]);
|
|
|
|
// Retour direct sur onglet photos
|
|
$hash = $redirectHash !== '' && $redirectHash[0] === '#' ? $redirectHash : '';
|
|
header('Location: /animal?id=' . $animalId . $hash);
|
|
exit();
|
|
}
|
|
|
|
public static function setPrimaryPhoto(): void
|
|
{
|
|
if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
|
|
http_response_code(405);
|
|
return;
|
|
}
|
|
|
|
$animalId = (int) ($_POST['animal_id'] ?? 0);
|
|
$photoId = (int) ($_POST['photo_id'] ?? 0);
|
|
if ($animalId <= 0 || $photoId <= 0) {
|
|
http_response_code(400);
|
|
return;
|
|
}
|
|
|
|
$db = DB::pdo();
|
|
$stmt = $db->prepare('SELECT filename,is_public FROM animal_photos WHERE id=:pid AND animal_id=:aid');
|
|
$stmt->execute([':pid' => $photoId, ':aid' => $animalId]);
|
|
$photo = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
if (!$photo) {
|
|
http_response_code(404);
|
|
echo h(t('error.photo_not_found'));
|
|
return;
|
|
}
|
|
$moved = false;
|
|
try {
|
|
if ((int) $photo['is_public'] !== 1) {
|
|
PrivateMediaService::moveVisibility($animalId, (string) $photo['filename'], true);
|
|
$moved = true;
|
|
}
|
|
$db->beginTransaction();
|
|
$db->prepare('UPDATE animal_photos SET is_primary=0 WHERE animal_id=:aid')->execute([':aid' => $animalId]);
|
|
$db->prepare('UPDATE animal_photos SET is_primary=1,is_public=1 WHERE id=:pid AND animal_id=:aid')->execute(
|
|
[':pid' => $photoId, ':aid' => $animalId],
|
|
);
|
|
$db->commit();
|
|
} catch (Throwable $e) {
|
|
if ($db->inTransaction()) {
|
|
$db->rollBack();
|
|
}
|
|
if ($moved) {
|
|
try {
|
|
PrivateMediaService::moveVisibility($animalId, (string) $photo['filename'], false);
|
|
} catch (Throwable) {
|
|
}
|
|
}
|
|
throw $e;
|
|
}
|
|
|
|
// Historique si tu veux
|
|
if (method_exists(__CLASS__, 'logHistory')) {
|
|
self::logHistory($animalId, 'photo', 'Photo principale modifiée');
|
|
}
|
|
|
|
header('Location: /animal?id=' . $animalId);
|
|
exit();
|
|
}
|
|
|
|
public static function deletePhoto(): void
|
|
{
|
|
if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
|
|
http_response_code(405);
|
|
return;
|
|
}
|
|
|
|
$animalId = (int) ($_POST['animal_id'] ?? 0);
|
|
$photoId = (int) ($_POST['photo_id'] ?? 0);
|
|
if ($animalId <= 0 || $photoId <= 0) {
|
|
http_response_code(400);
|
|
return;
|
|
}
|
|
|
|
$db = DB::pdo();
|
|
|
|
$st = $db->prepare(
|
|
'SELECT filename, is_primary, is_public FROM animal_photos WHERE id=:pid AND animal_id=:aid',
|
|
);
|
|
$st->execute([':pid' => $photoId, ':aid' => $animalId]);
|
|
$row = $st->fetch(PDO::FETCH_ASSOC);
|
|
if (!$row) {
|
|
header('Location: /animal?id=' . $animalId);
|
|
exit();
|
|
}
|
|
|
|
$filename = (string) $row['filename'];
|
|
$wasPrimary = (int) $row['is_primary'] === 1;
|
|
|
|
$db->prepare('DELETE FROM animal_photos WHERE id=:pid AND animal_id=:aid')->execute([
|
|
':pid' => $photoId,
|
|
':aid' => $animalId,
|
|
]);
|
|
|
|
$path =
|
|
((int) ($row['is_public'] ?? 1) === 1
|
|
? self::animalMediaDir($animalId)
|
|
: PrivateMediaService::animalDir($animalId)) .
|
|
'/' .
|
|
$filename;
|
|
if (is_file($path)) {
|
|
@unlink($path);
|
|
}
|
|
|
|
// Si on a supprimé la principale, on met la plus récente restante en principale
|
|
if ($wasPrimary) {
|
|
$pid = $db
|
|
->query('SELECT id FROM animal_photos WHERE animal_id=' . (int) $animalId . ' ORDER BY id DESC LIMIT 1')
|
|
->fetchColumn();
|
|
if ($pid) {
|
|
$db->prepare('UPDATE animal_photos SET is_primary=1 WHERE id=:pid')->execute([':pid' => (int) $pid]);
|
|
}
|
|
}
|
|
|
|
$db->prepare("UPDATE animals SET updated_at=datetime('now') WHERE id=:id")->execute([':id' => $animalId]);
|
|
|
|
if (method_exists(__CLASS__, 'logHistory')) {
|
|
self::logHistory($animalId, 'photo', 'Photo supprimée');
|
|
}
|
|
|
|
header('Location: /animal?id=' . $animalId);
|
|
exit();
|
|
}
|
|
}
|