From 3052d65eee5b54a68caebe8c173daba3dd8fc16a Mon Sep 17 00:00:00 2001 From: Fabrice Creuzot Date: Sat, 12 Dec 2020 20:00:00 +0000 Subject: [PATCH] Version 6.5.0 --- README.md | 2 +- composer.json | 4 + .../Luigifab/Apijs/Helper/Rewrite/Image.php | 22 +- .../community/Luigifab/Apijs/Model/Python.php | 6 +- .../controllers/Apijs/CacheController.php | 38 ++-- .../controllers/Apijs/MediaController.php | 153 ++++++++----- .../controllers/Apijs/WysiwygController.php | 4 +- .../community/Luigifab/Apijs/etc/config.xml | 4 +- .../community/Luigifab/Apijs/etc/system.xml | 12 +- .../community/Luigifab/Apijs/lib/image.py | 5 +- src/app/code/community/Luigifab/Apijs/readme | 4 +- .../template/luigifab/apijs/gallery.phtml | 205 +++++++++++++----- src/app/locale/cs_CZ/Luigifab_Apijs.csv | 4 +- src/app/locale/de_AT/Luigifab_Apijs.csv | 4 +- src/app/locale/de_CH/Luigifab_Apijs.csv | 4 +- src/app/locale/de_DE/Luigifab_Apijs.csv | 4 +- src/app/locale/fr_CA/Luigifab_Apijs.csv | 6 +- src/app/locale/fr_FR/Luigifab_Apijs.csv | 6 +- src/app/locale/pl_PL/Luigifab_Apijs.csv | 4 +- .../css/luigifab/apijs/apijs-openmage.min.css | 2 +- .../css/luigifab/apijs/apijs-print.min.css | 2 +- .../luigifab/apijs/apijs-screen-rtl.min.css | 2 +- .../css/luigifab/apijs/apijs-screen.min.css | 2 +- .../default/css/luigifab/apijs/styles.css | 34 ++- .../js/luigifab/apijs/apijs-openmage.min.js | 2 +- .../default/js/luigifab/apijs/apijs.min.js | 4 +- .../default/default/js/luigifab/apijs/app.js | 134 ++++++++++-- .../css/luigifab/apijs/apijs-print.min.css | 2 +- .../luigifab/apijs/apijs-screen-rtl.min.css | 2 +- .../css/luigifab/apijs/apijs-screen.min.css | 2 +- .../default/js/luigifab/apijs/apijs.min.js | 4 +- src/var/connect/luigifab-apijs.xml | 4 +- 32 files changed, 491 insertions(+), 196 deletions(-) diff --git a/README.md b/README.md index 4ea832f..9b13923 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ For more information, go to https://www.luigifab.fr/apijs or https://www.luigifa This repository is a mirror. To install the module, please use the extension key or the composer key available in the documentation. -- Current version: 6.4.0 (10/10/2020) +- Current version: 6.5.0 (12/12/2020) - Compatibility: OpenMage 19+, Magento Community 1.9+, PHP 7.2 / 7.3 / 7.4 / 8.0 - Client compatibility: Firefox 36+, Chrome 31+, Opera 19+, Edge 16+, Safari 9+ - Translations: English (en), French (fr-FR/fr-CA), German (de), Italian (it), Portuguese (pt-PT/pt-BR), Spanish (es) diff --git a/composer.json b/composer.json index e307612..dea9a83 100644 --- a/composer.json +++ b/composer.json @@ -23,6 +23,10 @@ { "type": "other", "url": "https://gandi.link/f/4b904048" + }, + { + "type": "other", + "url": "https://ekwateur.fr/?parrain=EKW001147103" } ], "require": { diff --git a/src/app/code/community/Luigifab/Apijs/Helper/Rewrite/Image.php b/src/app/code/community/Luigifab/Apijs/Helper/Rewrite/Image.php index 92ff083..db7a2f8 100644 --- a/src/app/code/community/Luigifab/Apijs/Helper/Rewrite/Image.php +++ b/src/app/code/community/Luigifab/Apijs/Helper/Rewrite/Image.php @@ -1,7 +1,7 @@ * Copyright 2019-2020 | Fabrice Creuzot @@ -97,7 +97,7 @@ public function init($product, $attribute, $path = null, $fixed = true) { $this->_svg = (!empty($path) && (mb_substr($path, -4) == '.svg')); $this->setImageFile($path); - $this->setBaseFile($model, $path); + $this->trySetBaseFile($model, $path); if ($this->_config['apijs/general/python']) { $processor = Mage::getSingleton('apijs/python')->setFilename($model->getBaseFile())->setFixed($fixed); @@ -119,11 +119,11 @@ public function getOriginalHeight() { return empty($this->_svg) ? parent::getOriginalHeight() : 0; } - public function setBaseFile($model, $path) { + private function trySetBaseFile($model, $path) { try { // essaye le fichier source - $model->setBaseFile($path); + $this->wrapSetBaseFile($model, $path); } catch (Exception $e) { try { @@ -147,6 +147,18 @@ public function setBaseFile($model, $path) { } } + private function wrapSetBaseFile($model, $file) { + + $filename = Mage::helper('apijs')->getCatalogProductImageDir().$file; + + // pour avoir une url unique + // par exemple, en cas de suppression de l'image a.jpg, puis de l'ajout de l'image a.jpg, même nom mais contenu différent + $old = $model->getWatermarkFile(); + $model->setWatermarkFile(is_file($filename) ? $old.filemtime($filename) : $old); + $model->setBaseFile($file); + $model->setWatermarkFile($old); + } + public function validateUploadFile($path) { return (is_file($path) && in_array(mime_content_type($path), ['image/svg', 'image/svg+xml'])) ? true : parent::validateUploadFile($path); } @@ -166,7 +178,7 @@ public function __toString() { } try { - $model->setBaseFile($this->getImageFile()); + $this->wrapSetBaseFile($model, $this->getImageFile()); if ($model->getDestinationSubdir() == 'wysiwyg') { // if ($model->isCached()) diff --git a/src/app/code/community/Luigifab/Apijs/Model/Python.php b/src/app/code/community/Luigifab/Apijs/Model/Python.php index ccc7a29..d4fb774 100644 --- a/src/app/code/community/Luigifab/Apijs/Model/Python.php +++ b/src/app/code/community/Luigifab/Apijs/Model/Python.php @@ -1,7 +1,7 @@ * https://www.luigifab.fr/openmage/apijs @@ -29,7 +29,7 @@ class Luigifab_Apijs_Model_Python extends Varien_Image { public function __construct($file = null, $adapter = null) { - exec('command -v python3 || command -v python || command -v python2', $cmd); + exec('command -v python3', $cmd); $this->_python = trim(implode($cmd)); exec('nproc', $core); @@ -53,7 +53,7 @@ public function getProgramVersions($helpPil, $helpSco) { $cmd = $this->_python; - if (empty($cmd)) { // pas de mb_strpos + if (empty($cmd)) { $pyt = 'not found'; $pil = $pyt; $sco = $pyt; diff --git a/src/app/code/community/Luigifab/Apijs/controllers/Apijs/CacheController.php b/src/app/code/community/Luigifab/Apijs/controllers/Apijs/CacheController.php index fac2fcd..e79296d 100644 --- a/src/app/code/community/Luigifab/Apijs/controllers/Apijs/CacheController.php +++ b/src/app/code/community/Luigifab/Apijs/controllers/Apijs/CacheController.php @@ -1,7 +1,7 @@ * Copyright 2019-2020 | Fabrice Creuzot @@ -22,6 +22,10 @@ class Luigifab_Apijs_Apijs_CacheController extends Mage_Adminhtml_System_ConfigController { + protected function _isAllowed() { + return Mage::getSingleton('admin/session')->isAllowed('system/config/apijs'); + } + public function getUsedModuleName() { return 'Luigifab_Apijs'; } @@ -34,36 +38,36 @@ public function clearCacheAction() { if ($type == 'wysiwyg') { // thumb - $directory = trim(Mage::helper('apijs')->getWysiwygImageDir(true, true)); - $io = new Varien_Io_File(); - if (mb_strlen($directory) > 5) - $io->rmdir($directory, true); + $dir = trim(Mage::helper('apijs')->getWysiwygImageDir(true, true)); + $iof = new Varien_Io_File(); + if (mb_strlen($dir) > 5) + $iof->rmdir($dir, true); // cache - $directory = trim(Mage::helper('apijs')->getWysiwygImageDir(true)); - $io = new Varien_Io_File(); - if (mb_strlen($directory) > 5) - $io->rmdir($directory, true); + $dir = trim(Mage::helper('apijs')->getWysiwygImageDir(true)); + $iof = new Varien_Io_File(); + if (mb_strlen($dir) > 5) + $iof->rmdir($dir, true); $this->_getSession()->addSuccess($this->__('The image cache was cleaned.')); } else if ($type == 'product') { // cache - $directory = trim(Mage::helper('apijs')->getCatalogProductImageDir(true)); - $io = new Varien_Io_File(); - if (mb_strlen($directory) > 5) - $io->rmdir($directory, true); + $dir = trim(Mage::helper('apijs')->getCatalogProductImageDir(true)); + $iof = new Varien_Io_File(); + if (mb_strlen($dir) > 5) + $iof->rmdir($dir, true); $this->_getSession()->addSuccess($this->__('The image cache was cleaned.')); } else if ($type == 'category') { // cache - $directory = trim(Mage::helper('apijs')->getCatalogCategoryImageDir(true)); - $io = new Varien_Io_File(); - if (mb_strlen($directory) > 5) - $io->rmdir($directory, true); + $dir = trim(Mage::helper('apijs')->getCatalogCategoryImageDir(true)); + $iof = new Varien_Io_File(); + if (mb_strlen($dir) > 5) + $iof->rmdir($dir, true); $this->_getSession()->addSuccess($this->__('The image cache was cleaned.')); } diff --git a/src/app/code/community/Luigifab/Apijs/controllers/Apijs/MediaController.php b/src/app/code/community/Luigifab/Apijs/controllers/Apijs/MediaController.php index cc2c602..257ed0e 100644 --- a/src/app/code/community/Luigifab/Apijs/controllers/Apijs/MediaController.php +++ b/src/app/code/community/Luigifab/Apijs/controllers/Apijs/MediaController.php @@ -1,7 +1,7 @@ * Copyright 2019-2020 | Fabrice Creuzot @@ -32,7 +32,7 @@ private function disableAllBuffer() { header('Cache-Control: no-cache, must-revalidate'); ini_set('output_buffering', 0); ini_set('implicit_flush', 1); - ob_implicit_flush(true); + ob_implicit_flush(); try { for ($i = 0; $i < ob_get_level(); $i++) @@ -125,13 +125,16 @@ public function uploadProductAction() { $storeId = (int) $this->getRequest()->getParam('store', 0); $database = Mage::getSingleton('core/resource'); + $read = $database->getConnection('core_read'); $write = $database->getConnection('core_write'); $table = $database->getTableName('catalog_product_entity_media_gallery'); + $elbat = $database->getTableName('catalog_product_entity_media_gallery_value'); $success = []; $errors = []; try { + $help = Mage::helper('apijs'); if (empty($productId)) Mage::throwException('Invalid product id.'); if (empty($_FILES)) @@ -151,7 +154,7 @@ public function uploadProductAction() { $uploader->addValidateCallback('catalog_product_image', Mage::helper('catalog/image'), 'validateUploadFile'); - $filepath = $uploader->save(Mage::helper('apijs')->getCatalogProductImageDir()); + $filepath = $uploader->save($help->getCatalogProductImageDir()); Mage::dispatchEvent('catalog_product_gallery_upload_image_after', ['result' => $filepath, 'action' => $this]); $filepath = array_pop($filepath); @@ -159,13 +162,44 @@ public function uploadProductAction() { 'INSERT INTO '.$table.' (attribute_id, entity_id, value) VALUES (?, ?, ?)', [$attribute, $productId, $filepath] ); - $write->query( - 'INSERT INTO '.$database->getTableName('catalog_product_entity_media_gallery_value').' - (value_id, store_id, position, disabled) VALUES (?, 0, ( - SELECT COUNT(entity_id) AS nb FROM '.$table.' WHERE entity_id = ? - ), 0)', - [$write->lastInsertId(), $productId] - ); + + $valueId = $write->lastInsertId(); + if (($storeId > 0) && Mage::getStoreConfigFlag('apijs/general/sort_by_store')) { + $nb = max($storeId * 100 + 1, (int) $read->fetchOne( + 'SELECT MAX(position) FROM '.$table.' cpemg + LEFT JOIN '.$elbat.' cpemgv + ON cpemg.value_id = cpemgv.value_id + WHERE entity_id = ? AND CAST(position / 100 AS UNSIGNED) = ?', + [$productId, $storeId] + ) + 1); + $write->query( + 'INSERT INTO '.$elbat.' + (value_id, store_id, position, disabled) VALUES (?, 0, ?, ?)', + [$valueId, $nb, empty($this->getRequest()->getParam('exclude')) ? 0 : 1] + ); + } + else { + $nb = max(1, (int) $read->fetchOne( + 'SELECT MAX(position) FROM '.$table.' cpemg + LEFT JOIN '.$elbat.' cpemgv + ON cpemg.value_id = cpemgv.value_id + WHERE entity_id = ? AND store_id = 0 AND LENGTH(position) < 3', + [$productId] + ) + 1, $read->fetchOne('SELECT COUNT(entity_id) AS nb FROM '.$table.' WHERE entity_id = ?', [$productId])); + $write->query( + 'INSERT INTO '.$elbat.' + (value_id, store_id, position, disabled) VALUES (?, 0, ?, ?)', + [$valueId, $nb, empty($this->getRequest()->getParam('exclude')) ? 0 : 1] + ); + } + + if (($storeId > 0) && !empty($this->getRequest()->getParam('exclude'))) { + $write->query( + 'INSERT INTO '.$elbat.' + (value_id, store_id, position, disabled) VALUES (?, ?, NULL, 0)', + [$valueId, $storeId] + ); + } $success[] = $filepath; } @@ -174,30 +208,30 @@ public function uploadProductAction() { } } - // image par défaut + // image par défaut (global uniquement) $product = Mage::getModel('catalog/product')->load($productId); if (!empty($success) && !empty($product->getMediaGallery('images'))) { $attributes = $product->getMediaAttributes(); foreach ($attributes as $code => $attribute) { + $value = $product->getData($code); // si dans eav_attribute, attribute_model = xyz/source_xyz // $attribute = Xyz_Xyz_Model_Source_Xyz extends Mage_Catalog_Model_Resource_Eav_Attribute - if (($attribute->getIsCheckbox() !== true) && empty($product->getData($code))) + if ((empty($value) || ($value == 'no_selection')) && ($attribute->getIsCheckbox() !== true)) $product->setData($code, $success[0]); } - $product->save(); + if ($product->hasDataChanges()) + $product->save(); } - if (!empty($storeId)) - $product->setStoreId($storeId)->load($product->getId()); - + // reload + $product->setStoreId($storeId)->load($product->getId()); // très important car les chemins et les urls sont aussi mis en cache Mage::app()->getCacheInstance()->cleanType('block_html'); - // html - $result = $this->formatResult($success, $errors, Mage::helper('apijs')->renderGalleryBlock($product)); + $result = $this->formatResult($success, $errors, $help->renderGalleryBlock($product)); } catch (Exception $e) { $result = $e->getMessage(); @@ -234,12 +268,10 @@ public function saveAction() { $product->save(); } - if (!empty($storeId)) // reload - $product->setStoreId($storeId)->load($product->getId()); - + // reload + $product->setStoreId($storeId)->load($product->getId()); // très important car les chemins et les urls sont aussi mis en cache Mage::app()->getCacheInstance()->cleanType('block_html'); - // html $result = $this->formatResult(null, null, Mage::helper('apijs')->renderGalleryBlock($product)); } @@ -262,59 +294,74 @@ public function removeAction() { $database = Mage::getSingleton('core/resource'); $read = $database->getConnection('core_read'); $write = $database->getConnection('core_write'); + $table = $database->getTableName('catalog_product_entity_media_gallery'); + $elbat = $database->getTableName('catalog_product_entity_varchar'); + + if (empty($imageId) && ($this->getRequest()->getParam('image') == 'all')) + $imageId = true; try { + $help = Mage::helper('apijs'); if (empty($productId) || empty($imageId)) - Mage::throwException('Invalid product/image id.'); + Mage::throwException('Invalid product/image ids ('.$productId.'/'.$imageId.')'); + + // trouve les ids + $ids = [$imageId]; + if ($imageId === true) + $ids = array_filter(explode(',', $read->fetchOne('SELECT GROUP_CONCAT(value_id) AS ids FROM '.$table. + ' WHERE entity_id = '.$productId.' GROUP BY entity_id'))); - // recherche et supprime le nom du fichier - $table = $database->getTableName('catalog_product_entity_media_gallery'); - $filepath = $read->fetchOne('SELECT value FROM '.$table.' WHERE value_id = '.$imageId); - $filename = basename($filepath); + // supprime les images + $paths = []; + foreach ($ids as $id) { - if (empty($filepath) || empty($filename)) - Mage::throwException('File does not exist.'); + // recherche et supprime le nom du fichier + $filepath = $read->fetchOne('SELECT value FROM '.$table.' WHERE value_id = '.$id); + $filename = basename($filepath); + $paths[] = $filepath; - $write->query('DELETE FROM '.$table.' WHERE value_id = ?', $imageId); + if (empty($filepath) || empty($filename)) + Mage::throwException('File does not exist (id: '.$id.').'); - // supprime lorsque l'image supprimée est l'image par défaut - $table = $database->getTableName('catalog_product_entity_varchar'); - $write->query('DELETE FROM '.$table.' WHERE entity_id = ? AND value = ?', [$productId, $filepath]); + $write->query('DELETE FROM '.$table.' WHERE value_id = ?', $id); + $write->query('DELETE FROM '.$elbat.' WHERE entity_id = ? AND value = ?', [$productId, $filepath]); // si par défaut - foreach (['image_label', 'small_image_label', 'thumbnail_label'] as $code) { - $attrId = Mage::getModel('eav/config')->getAttribute('catalog_product', $code)->getId(); - $write->query('DELETE FROM '.$table.' WHERE entity_id = ? AND attribute_id = ?', [$productId, $attrId]); + // supprime enfin les fichiers + $help->removeFiles($help->getCatalogProductImageDir(), $filename); // pas uniquement dans le cache } - // image par défaut - $product = Mage::getModel('catalog/product')->load($productId); + // image par défaut (global uniquement) + // et s'il n'y a plus d'image supprime la config des images sur toutes les vues + $product = Mage::getModel('catalog/product')->load($productId); + $attributes = $product->getMediaAttributes(); if (!empty($product->getMediaGallery('images'))) { - $value = $product->getMediaGallery('images')[0]['file']; - - $attributes = $product->getMediaAttributes(); + $newvalue = $product->getMediaGallery('images')[0]['file']; foreach ($attributes as $code => $attribute) { + $value = $product->getData($code); // si dans eav_attribute, attribute_model = xyz/source_xyz // $attribute = Xyz_Xyz_Model_Source_Xyz extends Mage_Catalog_Model_Resource_Eav_Attribute - if (($attribute->getIsCheckbox() !== true) && (empty($product->getData($code)) || ($product->getData($code) == $filepath))) - $product->setData($code, $value); + if ((empty($value) || ($value == 'no_selection') || in_array($value, $paths)) && ($attribute->getIsCheckbox() !== true)) + $product->setData($code, $newvalue); } - } - - if ($product->hasDataChanges()) - $product->save(); - if (!empty($storeId)) // reload - $product->setStoreId($storeId)->load($product->getId()); - // supprime enfin les fichiers - Mage::helper('apijs')->removeFiles(Mage::helper('apijs')->getCatalogProductImageDir(), $filename); // pas uniquement dans le cache + if ($product->hasDataChanges()) + $product->save(); + } + else { + foreach ($attributes as $attribute) { + $write->query('DELETE FROM '.str_replace('_varchar', '_'.$attribute->getData('backend_type'), $elbat). + ' WHERE entity_id = ? AND attribute_id = ?', [$productId, $attribute->getId()]); + } + } + // reload + $product->setStoreId($storeId)->load($product->getId()); // très important car les chemins et les urls sont aussi mis en cache Mage::app()->getCacheInstance()->cleanType('block_html'); - // html - $result = $this->formatResult(null, null, Mage::helper('apijs')->renderGalleryBlock($product)); + $result = $this->formatResult(null, null, $help->renderGalleryBlock($product)); } catch (Exception $e) { $result = $e->getMessage(); diff --git a/src/app/code/community/Luigifab/Apijs/controllers/Apijs/WysiwygController.php b/src/app/code/community/Luigifab/Apijs/controllers/Apijs/WysiwygController.php index 5100751..f01c1a2 100644 --- a/src/app/code/community/Luigifab/Apijs/controllers/Apijs/WysiwygController.php +++ b/src/app/code/community/Luigifab/Apijs/controllers/Apijs/WysiwygController.php @@ -1,7 +1,7 @@ * Copyright 2019-2020 | Fabrice Creuzot @@ -151,7 +151,7 @@ public function renameFileAction() { } catch (Exception $e) { $result = ['error' => true, 'message' => $e->getMessage()]; - $this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result)); + $this->getResponse()->setBody(json_encode($result)); } } } \ No newline at end of file diff --git a/src/app/code/community/Luigifab/Apijs/etc/config.xml b/src/app/code/community/Luigifab/Apijs/etc/config.xml index a082f1a..ed83646 100644 --- a/src/app/code/community/Luigifab/Apijs/etc/config.xml +++ b/src/app/code/community/Luigifab/Apijs/etc/config.xml @@ -1,7 +1,7 @@