false, 'error' => 'Invalid input.']); exit; } $ingredients = json_decode($data['ingredients'], true); if (json_last_error() !== JSON_ERROR_NONE) { echo json_encode(['success' => false, 'error' => 'Invalid ingredients format.']); exit; } $pdo = db(); $imageUrl = null; try { // Handle file upload if (isset($files['image']) && $files['image']['error'] === UPLOAD_ERR_OK) { $uploadDir = __DIR__ . '/../assets/images/recipes/'; if (!is_dir($uploadDir)) { mkdir($uploadDir, 0777, true); } $filename = uniqid() . '-' . basename($files['image']['name']); $uploadFile = $uploadDir . $filename; if (move_uploaded_file($files['image']['tmp_name'], $uploadFile)) { $imageUrl = 'assets/images/recipes/' . $filename; } else { throw new Exception('Failed to move uploaded file.'); } } $pdo->beginTransaction(); if (isset($data['id']) && !empty($data['id'])) { // Update existing recipe $recipeId = $data['id']; $category = !empty($data['category']) ? $data['category'] : 'No category'; // Check if recipe belongs to user $stmt = $pdo->prepare("SELECT user_id, image_url FROM recipes WHERE id = ?"); $stmt->execute([$recipeId]); $existing = $stmt->fetch(); if (!$existing || ($existing['user_id'] !== null && $existing['user_id'] != $userId)) { throw new Exception('Unauthorized to update this recipe.'); } // Fetch existing image URL if a new one isn't uploaded if ($imageUrl === null) { $imageUrl = $existing['image_url']; } $stmt = $pdo->prepare("UPDATE recipes SET name = ?, guests = ?, category = ?, image_url = ?, instructions = ?, user_id = ? WHERE id = ?"); $stmt->execute([$data['name'], $data['guests'], $category, $imageUrl, $data['instructions'] ?? null, $userId, $recipeId]); // Easiest way to handle ingredients is to delete old ones and insert new ones $stmt = $pdo->prepare("DELETE FROM ingredients WHERE recipe_id = ?"); $stmt->execute([$recipeId]); } else { // Insert new recipe $category = !empty($data['category']) ? $data['category'] : 'No category'; $stmt = $pdo->prepare("INSERT INTO recipes (name, guests, category, image_url, instructions, user_id) VALUES (?, ?, ?, ?, ?, ?)"); $stmt->execute([$data['name'], $data['guests'], $category, $imageUrl, $data['instructions'] ?? null, $userId]); $recipeId = $pdo->lastInsertId(); } // Insert ingredients $stmt = $pdo->prepare("INSERT INTO ingredients (recipe_id, name, quantity, unit, category) VALUES (?, ?, ?, ?, ?)"); foreach ($ingredients as $ing) { $ingredientCategory = get_ingredient_category($ing['name']); $stmt->execute([$recipeId, $ing['name'], $ing['quantity'], $ing['unit'], $ingredientCategory]); } $pdo->commit(); // Fetch the newly created/updated recipe to return it to the client $stmt = $pdo->prepare("SELECT * FROM recipes WHERE id = ?"); $stmt->execute([$recipeId]); $recipe = $stmt->fetch(); $stmt = $pdo->prepare("SELECT * FROM ingredients WHERE recipe_id = ?"); $stmt->execute([$recipeId]); $recipe['ingredients'] = $stmt->fetchAll(); echo json_encode(['success' => true, 'recipe' => $recipe]); } catch (Exception $e) { if ($pdo->inTransaction()) { $pdo->rollBack(); } echo json_encode(['success' => false, 'error' => $e->getMessage()]); }