* @copyright 2007-2023 PrestaShop SA * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) * International Registered Trademark & Property of PrestaShop SA * * @property \AddLivePhoto $module */ class AdminAddLivePhotoController extends ModuleAdminController { public function __construct() { $this->bootstrap = true; // The table is not for a list view, but it's good practice to set it. $this->table = 'product'; parent::__construct(); } /** * This is the entry point for the controller page. * It sets up the main template. */ public function initContent() { parent::initContent(); // Pass the ajax URL to the template $ajax_url = $this->context->link->getAdminLink( 'AdminAddLivePhoto', true, // Keep the token [], // No route params ['ajax' => 1] // Add ajax=1 to the query string ); $this->context->smarty->assign([ 'ajax_url' => $ajax_url, ]); // We use a custom template for our camera interface. $this->setTemplate('uploader.tpl'); } /** * This method is automatically called by PrestaShop when an AJAX request is made to this controller. * We use a 'action' parameter to decide what to do. */ public function ajaxProcess() { $action = Tools::getValue('action'); switch ($action) { case 'searchProduct': $this->ajaxProcessSearchProduct(); break; case 'uploadImage': $this->ajaxProcessUploadImage(); break; case 'deleteImage': $this->ajaxProcessDeleteImage(); break; } // No further processing needed for AJAX exit; } /** * Handles searching for a product by EAN13 barcode or ID. */ protected function ajaxProcessSearchProduct() { $identifier = Tools::getValue('identifier'); if (empty($identifier)) { $this->jsonError($this->trans('Identifier cannot be empty.',[], 'Modules.Addlivephoto.Admin')); } $id_product = 0; if (is_numeric($identifier)) { // Check if it's an EAN or a Product ID $id_product_by_ean = (int)Db::getInstance()->getValue(' SELECT id_product FROM `' . _DB_PREFIX_ . 'product` WHERE ean13 = \'' . pSQL($identifier) . '\' '); if ($id_product_by_ean) { $id_product = $id_product_by_ean; } else { // Assume it's a product ID if not found by EAN $id_product = (int)$identifier; } } if (!$id_product || !Validate::isLoadedObject($product = new Product($id_product, false, $this->context->language->id))) { $this->jsonError($this->trans('Product not found.',[], 'Modules.Addlivephoto.Admin')); } // Get product prices $retail_price = Product::getPriceStatic($product->id, true, null, 2, null, false, true); $discounted_price = Product::getPriceStatic($product->id, true, null, 2, null, true, true); // Fetch existing live photos for this product $live_photos = $this->getLivePhotosForProduct($product->id); $response = [ 'id_product' => $product->id, 'name' => $product->name, 'wholesale_price' => $product->wholesale_price, 'retail_price' => $retail_price, 'discounted_price' => ($retail_price !== $discounted_price) ? $discounted_price : null, 'existing_photos' => $live_photos, ]; $this->jsonSuccess($response); } /** * Handles the image upload process. */ protected function ajaxProcessUploadImage() { $id_product = (int)Tools::getValue('id_product'); $imageData = Tools::getValue('imageData'); if (!$id_product || !$imageData) { $this->jsonError($this->trans('Missing product ID or image data.',[], 'Modules.Addlivephoto.Admin')); } // Remove the data URI scheme header list($type, $imageData) = explode(';', $imageData); list(, $imageData) = explode(',', $imageData); $imageData = base64_decode($imageData); if ($imageData === false) { $this->jsonError($this->trans('Invalid image data.',[], 'Modules.Addlivephoto.Admin')); } $image_name = uniqid() . '.webp'; $path = $this->module->getProductImageServerPath($id_product); if (!$path || !file_put_contents($path . $image_name, $imageData)) { $this->jsonError($this->trans('Could not save image file. Check permissions for /var/modules/addlivephoto/',[], 'Modules.Addlivephoto.Admin')); } // Save to database $success = Db::getInstance()->insert(AddLivePhoto::TABLE_NAME, [ 'id_product' => $id_product, 'image_name' => pSQL($image_name), 'date_add' => date('Y-m-d H:i:s'), ]); if (!$success) { // Clean up the created file if DB insert fails @unlink($path . $image_name); $this->jsonError($this->trans('Could not save image information to the database.',[], 'Modules.Addlivephoto.Admin')); } $new_photo_data = [ 'name' => $image_name, 'url' => $this->module->getProductImageUri($id_product, $image_name), 'full_url' => $this->module->getProductImageUri($id_product, $image_name), ]; $this->jsonSuccess(['message' => $this->trans('Image uploaded successfully!',[], 'Modules.Addlivephoto.Admin'), 'new_photo' => $new_photo_data]); } /** * Handles deleting a specific image. */ protected function ajaxProcessDeleteImage() { $id_product = (int)Tools::getValue('id_product'); $image_name = Tools::getValue('image_name'); if (!$id_product || !$image_name) { $this->jsonError($this->trans('Missing product ID or image name.',[], 'Modules.Addlivephoto.Admin')); } // Use the method from the main module class if ($this->module->deleteProductImage($id_product, $image_name)) { $this->jsonSuccess(['message' => $this->trans('Image deleted successfully.')]); } else { $this->jsonError($this->trans('Failed to delete image.',[], 'Modules.Addlivephoto.Admin')); } } /** * Fetches all live photos for a given product ID. * @param int $id_product * @return array */ private function getLivePhotosForProduct($id_product) { $sql = new DbQuery(); $sql->select('`image_name`'); $sql->from(AddLivePhoto::TABLE_NAME); $sql->where('`id_product` = ' . (int)$id_product); $sql->orderBy('`date_add` DESC'); $results = Db::getInstance()->executeS($sql); $photos = []; if ($results) { foreach ($results as $row) { $photos[] = [ 'name' => $row['image_name'], 'url' => $this->module->getProductImageUri($id_product, $row['image_name']), ]; } } return $photos; } /** Helper functions for consistent JSON responses */ private function jsonSuccess($data) { header('Content-Type: application/json'); echo json_encode(['success' => true, 'data' => $data]); } }