From 552f86fe84983c473c163990e0449e4115860792 Mon Sep 17 00:00:00 2001
From: leemyongpakvn <leemyongpakvn@gmail.com>
Date: Mon, 27 Jun 2022 09:30:34 +0700
Subject: [PATCH 01/35] Replace deprecated CHARSET utf8 in install.sql

---
 install.sql | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/install.sql b/install.sql
index 53ee6cb6..bb775562 100644
--- a/install.sql
+++ b/install.sql
@@ -14,35 +14,35 @@ CREATE TABLE IF NOT EXISTS `PREFIX_product_comment` (
   KEY `id_product` (`id_product`),
   KEY `id_customer` (`id_customer`),
   KEY `id_guest` (`id_guest`)
-) ENGINE=ENGINE_TYPE  DEFAULT CHARSET=utf8;
+) ENGINE=ENGINE_TYPE  DEFAULT CHARSET=utf8mb4;
 
 CREATE TABLE IF NOT EXISTS `PREFIX_product_comment_criterion` (
   `id_product_comment_criterion` int(10) unsigned NOT NULL auto_increment,
   `id_product_comment_criterion_type` tinyint(1) NOT NULL,
   `active` tinyint(1) NOT NULL,
   PRIMARY KEY (`id_product_comment_criterion`)
-) ENGINE=ENGINE_TYPE  DEFAULT CHARSET=utf8;
+) ENGINE=ENGINE_TYPE  DEFAULT CHARSET=utf8mb4;
 
 CREATE TABLE IF NOT EXISTS `PREFIX_product_comment_criterion_product` (
   `id_product` int(10) unsigned NOT NULL,
   `id_product_comment_criterion` int(10) unsigned NOT NULL,
   PRIMARY KEY(`id_product`, `id_product_comment_criterion`),
   KEY `id_product_comment_criterion` (`id_product_comment_criterion`)
-) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8;
+) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8mb4;
 
 CREATE TABLE IF NOT EXISTS `PREFIX_product_comment_criterion_lang` (
   `id_product_comment_criterion` INT(11) UNSIGNED NOT NULL ,
   `id_lang` INT(11) UNSIGNED NOT NULL ,
   `name` VARCHAR(64) NOT NULL ,
   PRIMARY KEY ( `id_product_comment_criterion` , `id_lang` )
-) ENGINE=ENGINE_TYPE  DEFAULT CHARSET=utf8;
+) ENGINE=ENGINE_TYPE  DEFAULT CHARSET=utf8mb4;
 
 CREATE TABLE IF NOT EXISTS `PREFIX_product_comment_criterion_category` (
   `id_product_comment_criterion` int(10) unsigned NOT NULL,
   `id_category` int(10) unsigned NOT NULL,
   PRIMARY KEY(`id_product_comment_criterion`, `id_category`),
   KEY `id_category` (`id_category`)
-) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8;
+) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8mb4;
 
 CREATE TABLE IF NOT EXISTS `PREFIX_product_comment_grade` (
   `id_product_comment` int(10) unsigned NOT NULL,
@@ -50,20 +50,20 @@ CREATE TABLE IF NOT EXISTS `PREFIX_product_comment_grade` (
   `grade` int(10) unsigned NOT NULL,
   PRIMARY KEY (`id_product_comment`, `id_product_comment_criterion`),
   KEY `id_product_comment_criterion` (`id_product_comment_criterion`)
-) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8;
+) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8mb4;
 
 CREATE TABLE IF NOT EXISTS `PREFIX_product_comment_usefulness` (
   `id_product_comment` int(10) unsigned NOT NULL,
   `id_customer` int(10) unsigned NOT NULL,
   `usefulness` tinyint(1) unsigned NOT NULL,
   PRIMARY KEY (`id_product_comment`, `id_customer`)
-) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8;
+) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8mb4;
 
 CREATE TABLE IF NOT EXISTS `PREFIX_product_comment_report` (
   `id_product_comment` int(10) unsigned NOT NULL,
   `id_customer` int(10) unsigned NOT NULL,
   PRIMARY KEY (`id_product_comment`, `id_customer`)
-) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8;
+) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8mb4;
 
 INSERT IGNORE INTO `PREFIX_product_comment_criterion` VALUES ('1', '1', '1');
 

From 46e110694203b2b7d0c73c4863bbbe3c322c029c Mon Sep 17 00:00:00 2001
From: leemyongpakvn <leemyongpakvn@gmail.com>
Date: Tue, 28 Jun 2022 09:56:49 +0700
Subject: [PATCH 02/35] Upgrade deprecated charset utf8 by newer utfmb4

install.sql in root directory of module prior v5.0.1 CREATE TABLE with deprecated CHARSET=utf8. It need to be fixed in the upgrade of next version.
---
 upgrade/install-5.0.2.php | 40 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)
 create mode 100644 upgrade/install-5.0.2.php

diff --git a/upgrade/install-5.0.2.php b/upgrade/install-5.0.2.php
new file mode 100644
index 00000000..96a9d37a
--- /dev/null
+++ b/upgrade/install-5.0.2.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Copyright since 2007 PrestaShop SA and Contributors
+ * PrestaShop is an International Registered Trademark & Property of PrestaShop SA
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License 3.0 (AFL-3.0)
+ * that is bundled with this package in the file LICENSE.md.
+ * It is also available through the world-wide-web at this URL:
+ * https://opensource.org/licenses/AFL-3.0
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@prestashop.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
+ * versions in the future. If you wish to customize PrestaShop for your
+ * needs please refer to https://devdocs.prestashop.com/ for more information.
+ *
+ * @author    PrestaShop SA and Contributors <contact@prestashop.com>
+ * @copyright Since 2007 PrestaShop SA and Contributors
+ * @license   https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
+ */
+if (!defined('_PS_VERSION_')) {
+    exit;
+}
+
+function upgrade_module_5_0_2($object)
+{
+    return Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
+        &&  Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
+        &&  Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion_product` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
+        &&  Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion_lang` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
+        &&  Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion_category` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
+        &&  Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_grade` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
+        &&  Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_usefulness` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
+        &&  Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_report` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;');
+}

From 27d13295ddd234b3f58ca47a14db05988c348eba Mon Sep 17 00:00:00 2001
From: leemyongpakvn <leemyongpakvn@gmail.com>
Date: Mon, 26 Sep 2022 14:28:31 +0700
Subject: [PATCH 03/35] Update and rename install-5.0.2.php to
 install-5.0.3.php

We are on v5.0.2 now.
---
 upgrade/{install-5.0.2.php => install-5.0.3.php} | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
 rename upgrade/{install-5.0.2.php => install-5.0.3.php} (98%)

diff --git a/upgrade/install-5.0.2.php b/upgrade/install-5.0.3.php
similarity index 98%
rename from upgrade/install-5.0.2.php
rename to upgrade/install-5.0.3.php
index 96a9d37a..e9ac756d 100644
--- a/upgrade/install-5.0.2.php
+++ b/upgrade/install-5.0.3.php
@@ -27,7 +27,7 @@
     exit;
 }
 
-function upgrade_module_5_0_2($object)
+function upgrade_module_5_0_3($object)
 {
     return Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
         &&  Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')

From 0ee9c91658b1e58868d50939dae352a5446b6cd3 Mon Sep 17 00:00:00 2001
From: leemyongpakvn <leemyongpakvn@gmail.com>
Date: Mon, 26 Sep 2022 18:10:54 +0700
Subject: [PATCH 04/35] php-cs-fixer 1 space less

---
 upgrade/install-5.0.3.php | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/upgrade/install-5.0.3.php b/upgrade/install-5.0.3.php
index e9ac756d..30543dc2 100644
--- a/upgrade/install-5.0.3.php
+++ b/upgrade/install-5.0.3.php
@@ -30,11 +30,11 @@
 function upgrade_module_5_0_3($object)
 {
     return Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
-        &&  Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
-        &&  Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion_product` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
-        &&  Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion_lang` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
-        &&  Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion_category` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
-        &&  Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_grade` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
-        &&  Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_usefulness` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
-        &&  Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_report` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;');
+        && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
+        && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion_product` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
+        && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion_lang` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
+        && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion_category` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
+        && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_grade` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
+        && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_usefulness` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
+        && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_report` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;');
 }

From d18b4b106c554618203a8bbcec568baf1650c220 Mon Sep 17 00:00:00 2001
From: leemyongpakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Sun, 26 Feb 2023 13:53:28 +0700
Subject: [PATCH 05/35] Update upgrade/install-5.0.3.php

@kpodemski Nearly perfect. :thumbsup: When run directly in phpMyAdmin: my code only upgrade table collation, your code upgrade both table and its fields collation.
The remaining issue is Upgrade via BO interface does not call install-**5.0.3**.php. BO upgrade suggest upgrade v5.0.2 -> v5.0.2, and I guess it called  install-**5.0.2**.php instead :(

Co-authored-by: Krystian Podemski <kpodemski@users.noreply.github.com>
---
 upgrade/install-5.0.3.php | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/upgrade/install-5.0.3.php b/upgrade/install-5.0.3.php
index 30543dc2..93816131 100644
--- a/upgrade/install-5.0.3.php
+++ b/upgrade/install-5.0.3.php
@@ -29,12 +29,12 @@
 
 function upgrade_module_5_0_3($object)
 {
-    return Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
-        && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
-        && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion_product` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
-        && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion_lang` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
-        && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion_category` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
-        && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_grade` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
-        && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_usefulness` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;')
-        && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_report` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci;');
+    return Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci')
+        && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci')
+        && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion_product` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci')
+        && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion_lang` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci')
+        && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion_category` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci')
+        && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_grade` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci')
+        && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_usefulness` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci')
+        && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_report` CHARACTER SET = utf8mb4 COLLATE utf8mb4_general_ci');
 }

From 352c6338dd111cff315280756a07bc8eb895c5c8 Mon Sep 17 00:00:00 2001
From: leemyongpakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Thu, 24 Aug 2023 16:27:43 +0700
Subject: [PATCH 06/35] Rename install-5.0.3.php to install-6.0.1.php

---
 upgrade/{install-5.0.3.php => install-6.0.1.php} | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename upgrade/{install-5.0.3.php => install-6.0.1.php} (100%)

diff --git a/upgrade/install-5.0.3.php b/upgrade/install-6.0.1.php
similarity index 100%
rename from upgrade/install-5.0.3.php
rename to upgrade/install-6.0.1.php

From b49b55d3ac25e2f93e85d0a8b6139ee696ff2f82 Mon Sep 17 00:00:00 2001
From: leemyongpakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Thu, 24 Aug 2023 16:31:07 +0700
Subject: [PATCH 07/35] Update install-6.0.1.php - new v6

---
 upgrade/install-6.0.1.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/upgrade/install-6.0.1.php b/upgrade/install-6.0.1.php
index 93816131..cdb05fb5 100644
--- a/upgrade/install-6.0.1.php
+++ b/upgrade/install-6.0.1.php
@@ -27,7 +27,7 @@
     exit;
 }
 
-function upgrade_module_5_0_3($object)
+function upgrade_module_6_0_1($object)
 {
     return Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci')
         && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci')

From 39a9a8c21f7dc591594bc08a178f06f1e31388df Mon Sep 17 00:00:00 2001
From: leemyongpakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Tue, 5 Sep 2023 16:48:50 +0700
Subject: [PATCH 08/35] Rename install-6.0.1.php to install-6.0.3.php

We are on v6.0.2 now
---
 upgrade/{install-6.0.1.php => install-6.0.3.php} | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename upgrade/{install-6.0.1.php => install-6.0.3.php} (100%)

diff --git a/upgrade/install-6.0.1.php b/upgrade/install-6.0.3.php
similarity index 100%
rename from upgrade/install-6.0.1.php
rename to upgrade/install-6.0.3.php

From 3fb17dc5c9fef759209a1a6af04852578f64fff7 Mon Sep 17 00:00:00 2001
From: leemyong pakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Mon, 11 Sep 2023 09:58:51 +0700
Subject: [PATCH 09/35] rm with --user root

---
 tests/phpstan.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/phpstan.sh b/tests/phpstan.sh
index 9fcc0c62..c86154ff 100755
--- a/tests/phpstan.sh
+++ b/tests/phpstan.sh
@@ -14,7 +14,7 @@ docker run -tid --rm -v ps-volume:/var/www/html --name temp-ps prestashop/presta
 # Clear previous instance of the module in the PrestaShop volume
 echo "Clear previous module"
 
-docker exec -t temp-ps rm -rf /var/www/html/modules/productcomments
+docker exec -t --user root temp-ps sh -c 'find /var/www/html/modules/productcomments -type f -exec rm {} +'
 
 # Run a container for PHPStan, having access to the module content and PrestaShop sources.
 # This tool is outside the composer.json because of the compatibility with PHP 5.6

From b79bfefc1217a5ce4f682af402ba9f86dd6fcc07 Mon Sep 17 00:00:00 2001
From: leemyong pakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Wed, 4 Oct 2023 10:28:03 +0700
Subject: [PATCH 10/35] mark deprecated funtions

---
 ProductCommentCriterion.php | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/ProductCommentCriterion.php b/ProductCommentCriterion.php
index 7e412aaa..01ea988b 100644
--- a/ProductCommentCriterion.php
+++ b/ProductCommentCriterion.php
@@ -47,6 +47,9 @@ class ProductCommentCriterion extends ObjectModel
         ],
     ];
 
+    /**
+     * @deprecated 6.0.0
+     */
     public function delete()
     {
         if (!parent::delete()) {
@@ -96,6 +99,8 @@ public function update($nullValues = false)
      * Link a Comment Criterion to a product
      *
      * @return bool succeed
+     * 
+     * @deprecated 6.0.0
      */
     public function addProduct($id_product)
     {
@@ -113,6 +118,8 @@ public function addProduct($id_product)
      * Link a Comment Criterion to a category
      *
      * @return bool succeed
+     * 
+     * @deprecated 6.0.0
      */
     public function addCategory($id_category)
     {

From b05b70d85a46fb3c5e70330de7ae643177a7e631 Mon Sep 17 00:00:00 2001
From: leemyong pakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Wed, 4 Oct 2023 13:23:01 +0700
Subject: [PATCH 11/35] mark deprecated functions since v4.0.0 n v6.0.0

---
 ProductComment.php          | 8 ++++++++
 ProductCommentCriterion.php | 6 +++---
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/ProductComment.php b/ProductComment.php
index f3fc56a6..02a31885 100644
--- a/ProductComment.php
+++ b/ProductComment.php
@@ -438,6 +438,8 @@ public static function deleteUsefulness($id_product_comment)
      * Report comment
      *
      * @return bool
+     * 
+     * @deprecated 4.0.0 - migrated to controllers/front/ReportComment and src/Entity/ProductCommentReport
      */
     public static function reportComment($id_product_comment, $id_customer)
     {
@@ -450,6 +452,8 @@ public static function reportComment($id_product_comment, $id_customer)
      * Comment already report
      *
      * @return bool
+     * 
+     * @deprecated 4.0.0 - migrated to controllers/front/ReportComment and src/Entity/ProductCommentReport
      */
     public static function isAlreadyReport($id_product_comment, $id_customer)
     {
@@ -464,6 +468,8 @@ public static function isAlreadyReport($id_product_comment, $id_customer)
      * Set comment usefulness
      *
      * @return bool
+     * 
+     * @deprecated 4.0.0 - migrated to controllers/front/UpdateCommentUsefulness and src/Entity/ProductCommentUsefulness
      */
     public static function setCommentUsefulness($id_product_comment, $usefulness, $id_customer)
     {
@@ -476,6 +482,8 @@ public static function setCommentUsefulness($id_product_comment, $usefulness, $i
      * Usefulness already set
      *
      * @return bool
+     * 
+     * @deprecated 4.0.0 - migrated to controllers/front/UpdateCommentUsefulness and src/Entity/ProductCommentUsefulness
      */
     public static function isAlreadyUsefulness($id_product_comment, $id_customer)
     {
diff --git a/ProductCommentCriterion.php b/ProductCommentCriterion.php
index 01ea988b..c65e3032 100644
--- a/ProductCommentCriterion.php
+++ b/ProductCommentCriterion.php
@@ -48,7 +48,7 @@ class ProductCommentCriterion extends ObjectModel
     ];
 
     /**
-     * @deprecated 6.0.0
+     * @deprecated 6.0.0 - migrated to src/Repository/ProductCommentCriterionRepository
      */
     public function delete()
     {
@@ -100,7 +100,7 @@ public function update($nullValues = false)
      *
      * @return bool succeed
      * 
-     * @deprecated 6.0.0
+     * @deprecated 6.0.0 - migrated to src/Repository/ProductCommentCriterionRepository
      */
     public function addProduct($id_product)
     {
@@ -119,7 +119,7 @@ public function addProduct($id_product)
      *
      * @return bool succeed
      * 
-     * @deprecated 6.0.0
+     * @deprecated 6.0.0 - migrated to src/Repository/ProductCommentCriterionRepository
      */
     public function addCategory($id_category)
     {

From d6078d14b76c89a42b31042f025ee3a35bfd5b73 Mon Sep 17 00:00:00 2001
From: leemyong pakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Wed, 4 Oct 2023 13:24:14 +0700
Subject: [PATCH 12/35] correct function name

---
 upgrade/install-6.0.3.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/upgrade/install-6.0.3.php b/upgrade/install-6.0.3.php
index cdb05fb5..b32ad47c 100644
--- a/upgrade/install-6.0.3.php
+++ b/upgrade/install-6.0.3.php
@@ -27,7 +27,7 @@
     exit;
 }
 
-function upgrade_module_6_0_1($object)
+function upgrade_module_6_0_3($object)
 {
     return Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci')
         && Db::getInstance()->execute('ALTER TABLE `' . _DB_PREFIX_ . 'product_comment_criterion` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci')

From cbe39e0325d9ad2a7236a44d349239554c0798d1 Mon Sep 17 00:00:00 2001
From: leemyong pakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Wed, 4 Oct 2023 13:28:34 +0700
Subject: [PATCH 13/35] CS fix

---
 ProductComment.php          | 8 ++++----
 ProductCommentCriterion.php | 4 ++--
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/ProductComment.php b/ProductComment.php
index 02a31885..53cca302 100644
--- a/ProductComment.php
+++ b/ProductComment.php
@@ -438,7 +438,7 @@ public static function deleteUsefulness($id_product_comment)
      * Report comment
      *
      * @return bool
-     * 
+     *
      * @deprecated 4.0.0 - migrated to controllers/front/ReportComment and src/Entity/ProductCommentReport
      */
     public static function reportComment($id_product_comment, $id_customer)
@@ -452,7 +452,7 @@ public static function reportComment($id_product_comment, $id_customer)
      * Comment already report
      *
      * @return bool
-     * 
+     *
      * @deprecated 4.0.0 - migrated to controllers/front/ReportComment and src/Entity/ProductCommentReport
      */
     public static function isAlreadyReport($id_product_comment, $id_customer)
@@ -468,7 +468,7 @@ public static function isAlreadyReport($id_product_comment, $id_customer)
      * Set comment usefulness
      *
      * @return bool
-     * 
+     *
      * @deprecated 4.0.0 - migrated to controllers/front/UpdateCommentUsefulness and src/Entity/ProductCommentUsefulness
      */
     public static function setCommentUsefulness($id_product_comment, $usefulness, $id_customer)
@@ -482,7 +482,7 @@ public static function setCommentUsefulness($id_product_comment, $usefulness, $i
      * Usefulness already set
      *
      * @return bool
-     * 
+     *
      * @deprecated 4.0.0 - migrated to controllers/front/UpdateCommentUsefulness and src/Entity/ProductCommentUsefulness
      */
     public static function isAlreadyUsefulness($id_product_comment, $id_customer)
diff --git a/ProductCommentCriterion.php b/ProductCommentCriterion.php
index c65e3032..0a739915 100644
--- a/ProductCommentCriterion.php
+++ b/ProductCommentCriterion.php
@@ -99,7 +99,7 @@ public function update($nullValues = false)
      * Link a Comment Criterion to a product
      *
      * @return bool succeed
-     * 
+     *
      * @deprecated 6.0.0 - migrated to src/Repository/ProductCommentCriterionRepository
      */
     public function addProduct($id_product)
@@ -118,7 +118,7 @@ public function addProduct($id_product)
      * Link a Comment Criterion to a category
      *
      * @return bool succeed
-     * 
+     *
      * @deprecated 6.0.0 - migrated to src/Repository/ProductCommentCriterionRepository
      */
     public function addCategory($id_category)

From d10632a7f0f71c2ebd30c79894890e6cb4c515da Mon Sep 17 00:00:00 2001
From: leemyong pakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Fri, 13 Oct 2023 09:03:32 +0700
Subject: [PATCH 14/35] replace jQueryAJAX by FetchAPI

---
 controllers/front/ReportComment.php           |  4 +-
 controllers/front/UpdateCommentUsefulness.php |  6 +-
 views/js/list-comments.js                     | 58 +++++++++++++------
 3 files changed, 47 insertions(+), 21 deletions(-)

diff --git a/controllers/front/ReportComment.php b/controllers/front/ReportComment.php
index 9be0af98..7183bb76 100644
--- a/controllers/front/ReportComment.php
+++ b/controllers/front/ReportComment.php
@@ -47,7 +47,9 @@ public function display()
             return false;
         }
 
-        $id_product_comment = (int) Tools::getValue('id_product_comment');
+        $content = trim(file_get_contents('php://input'));
+        $decoded = json_decode($content, true);
+        $id_product_comment = (int) $decoded['id_product_comment'];
 
         /** @var EntityManagerInterface $entityManager */
         $entityManager = $this->container->get('doctrine.orm.entity_manager');
diff --git a/controllers/front/UpdateCommentUsefulness.php b/controllers/front/UpdateCommentUsefulness.php
index 774435b9..60fdf02d 100644
--- a/controllers/front/UpdateCommentUsefulness.php
+++ b/controllers/front/UpdateCommentUsefulness.php
@@ -70,8 +70,10 @@ public function display()
             return false;
         }
 
-        $id_product_comment = (int) Tools::getValue('id_product_comment');
-        $usefulness = (bool) Tools::getValue('usefulness');
+        $content = trim(file_get_contents('php://input'));
+        $decoded = json_decode($content, true);
+        $id_product_comment = (int) $decoded['id_product_comment'];
+        $usefulness = (bool) $decoded['usefulness'];
 
         /** @var EntityManagerInterface $entityManager */
         $entityManager = $this->container->get('doctrine.orm.entity_manager');
diff --git a/views/js/list-comments.js b/views/js/list-comments.js
index 89bc6c40..dece197d 100644
--- a/views/js/list-comments.js
+++ b/views/js/list-comments.js
@@ -180,9 +180,18 @@ jQuery(document).ready(function () {
     commentsList.append($comment);
   }
 
-  function updateCommentUsefulness($comment, commentId, usefulness) {
-    $.post(updateCommentUsefulnessUrl, {id_product_comment: commentId, usefulness: usefulness}, function(jsonData){
-      if (jsonData) {
+  async function updateCommentUsefulness($comment, commentId, usefulness) {
+    try {
+      const response = await fetch(updateCommentUsefulnessUrl, {
+        method: "POST",
+        headers: {
+          "Content-Type": "application/json",
+        },
+        body: JSON.stringify({id_product_comment: commentId, usefulness: usefulness}),
+      });
+
+      if (response.status === 200) {        
+        const jsonData = await response.json();
         if (jsonData.success) {
           $('.useful-review-value', $comment).html(jsonData.usefulness);
           $('.not-useful-review-value', $comment).html(jsonData.total_usefulness - jsonData.usefulness);
@@ -193,9 +202,9 @@ jQuery(document).ready(function () {
       } else {
         showUpdatePostCommentErrorModal(productCommentUpdatePostErrorMessage);
       }
-    }).fail(function() {
-      showUpdatePostCommentErrorModal(productCommentUpdatePostErrorMessage);
-    });
+    } catch (error) {      
+      showUpdatePostCommentErrorModal(error);
+    }
   }
 
   function confirmCommentAbuse(commentId) {
@@ -204,22 +213,35 @@ jQuery(document).ready(function () {
       if (!confirm) {
         return;
       }
-      $.post(reportCommentUrl, {id_product_comment: commentId}, function(jsonData){
-        if (jsonData) {
-          if (jsonData.success) {
-            reportCommentPostedModal.modal('show');
-          } else {
-            showReportCommentErrorModal(jsonData.error);
-          }
+      confirmCommentAbuseFetch(commentId);
+    })
+  }
+
+  async function confirmCommentAbuseFetch(commentId) {
+    try {
+      const response = await fetch(reportCommentUrl, {
+        method: "POST",
+        headers: {
+          "Content-Type": "application/json",
+        },
+        body: JSON.stringify({id_product_comment: commentId}),
+      });
+
+      if (response.status === 200) {        
+        const jsonData = await response.json();
+        if (jsonData.success) {
+          reportCommentPostedModal.modal('show');
         } else {
-          showReportCommentErrorModal(productCommentAbuseReportErrorMessage);
+          showReportCommentErrorModal(jsonData.error);
         }
-      }).fail(function() {
+      } else {
         showReportCommentErrorModal(productCommentAbuseReportErrorMessage);
-      });
-    })
+      }
+    } catch (error) {
+      showReportCommentErrorModal(error);
+    }
   }
-
+  
   if (totalPages <= 1)
     $(pagesListId).hide();
     

From c72a8c52bc9e809b0354d8695f3c72dbce241899 Mon Sep 17 00:00:00 2001
From: leemyong pakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Fri, 13 Oct 2023 10:12:43 +0700
Subject: [PATCH 15/35] lint fix

---
 views/js/list-comments.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/views/js/list-comments.js b/views/js/list-comments.js
index dece197d..ec591b59 100644
--- a/views/js/list-comments.js
+++ b/views/js/list-comments.js
@@ -202,7 +202,7 @@ jQuery(document).ready(function () {
       } else {
         showUpdatePostCommentErrorModal(productCommentUpdatePostErrorMessage);
       }
-    } catch (error) {      
+    } catch (error) {
       showUpdatePostCommentErrorModal(error);
     }
   }
@@ -241,7 +241,7 @@ jQuery(document).ready(function () {
       showReportCommentErrorModal(error);
     }
   }
-  
+
   if (totalPages <= 1)
     $(pagesListId).hide();
     

From 1a6a64ac08a4aa91824d7366c91f4c64076f1a80 Mon Sep 17 00:00:00 2001
From: leemyong pakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Thu, 26 Oct 2023 14:29:29 +0700
Subject: [PATCH 16/35] use application/x-www-form-urlencoded to avoid changes
 in PHP code

---
 controllers/front/ReportComment.php           |  4 +---
 controllers/front/UpdateCommentUsefulness.php |  6 ++----
 views/js/list-comments.js                     | 10 +++++-----
 3 files changed, 8 insertions(+), 12 deletions(-)

diff --git a/controllers/front/ReportComment.php b/controllers/front/ReportComment.php
index 7183bb76..9be0af98 100644
--- a/controllers/front/ReportComment.php
+++ b/controllers/front/ReportComment.php
@@ -47,9 +47,7 @@ public function display()
             return false;
         }
 
-        $content = trim(file_get_contents('php://input'));
-        $decoded = json_decode($content, true);
-        $id_product_comment = (int) $decoded['id_product_comment'];
+        $id_product_comment = (int) Tools::getValue('id_product_comment');
 
         /** @var EntityManagerInterface $entityManager */
         $entityManager = $this->container->get('doctrine.orm.entity_manager');
diff --git a/controllers/front/UpdateCommentUsefulness.php b/controllers/front/UpdateCommentUsefulness.php
index 60fdf02d..774435b9 100644
--- a/controllers/front/UpdateCommentUsefulness.php
+++ b/controllers/front/UpdateCommentUsefulness.php
@@ -70,10 +70,8 @@ public function display()
             return false;
         }
 
-        $content = trim(file_get_contents('php://input'));
-        $decoded = json_decode($content, true);
-        $id_product_comment = (int) $decoded['id_product_comment'];
-        $usefulness = (bool) $decoded['usefulness'];
+        $id_product_comment = (int) Tools::getValue('id_product_comment');
+        $usefulness = (bool) Tools::getValue('usefulness');
 
         /** @var EntityManagerInterface $entityManager */
         $entityManager = $this->container->get('doctrine.orm.entity_manager');
diff --git a/views/js/list-comments.js b/views/js/list-comments.js
index ec591b59..06de9d5c 100644
--- a/views/js/list-comments.js
+++ b/views/js/list-comments.js
@@ -185,9 +185,9 @@ jQuery(document).ready(function () {
       const response = await fetch(updateCommentUsefulnessUrl, {
         method: "POST",
         headers: {
-          "Content-Type": "application/json",
+          "Content-Type": "application/x-www-form-urlencoded",
         },
-        body: JSON.stringify({id_product_comment: commentId, usefulness: usefulness}),
+        body: "id_product_comment=" + commentId + "&usefulness=" + usefulness,
       });
 
       if (response.status === 200) {        
@@ -222,9 +222,9 @@ jQuery(document).ready(function () {
       const response = await fetch(reportCommentUrl, {
         method: "POST",
         headers: {
-          "Content-Type": "application/json",
-        },
-        body: JSON.stringify({id_product_comment: commentId}),
+          "Content-Type": "application/x-www-form-urlencoded",
+        },        
+        body: "id_product_comment=" + commentId,
       });
 
       if (response.status === 200) {        

From 4d00c37af2370ad04fff05a1d6d0e5557dc31ad1 Mon Sep 17 00:00:00 2001
From: matks <mathieu.ferment@prestashop.com>
Date: Thu, 16 Nov 2023 15:48:46 +0100
Subject: [PATCH 17/35] Handle bad deletion page call

---
 productcomments.php | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/productcomments.php b/productcomments.php
index 74c44069..3d00f268 100644
--- a/productcomments.php
+++ b/productcomments.php
@@ -207,7 +207,13 @@ protected function _postProcess()
             $commentRepository->deleteReports($id_product_comment);
         } elseif (Tools::isSubmit('deleteproductcomments')) {
             $comment = $commentRepository->find($id_product_comment);
-            $commentRepository->delete($comment);
+
+            if ($comment ===  null) {
+                $this->_html .= $this->displayError($this->trans('The comment cannot be deleted', [], 'Modules.Productcomments.Admin'));
+            } else {
+                $commentRepository->delete($comment);
+                Tools::redirectAdmin($this->context->link->getAdminLink('AdminModules', true, [], ['configure' => $this->name]));
+            }
         } elseif (Tools::isSubmit('submitEditCriterion')) {
             $criterion = $criterionRepository->findRelation((int) Tools::getValue('id_product_comment_criterion'));
             $criterion->setType((int) Tools::getValue('id_product_comment_criterion_type'));

From 9ccab004560ff9baaff5eb7ad01157c498e27699 Mon Sep 17 00:00:00 2001
From: Mathieu Ferment <mathieu.ferment@prestashop.com>
Date: Thu, 16 Nov 2023 17:36:06 +0100
Subject: [PATCH 18/35] Apply suggestions from code review
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Nicolas LÅ“uillet <nicolas@loeuillet.org>
---
 productcomments.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/productcomments.php b/productcomments.php
index 3d00f268..473f5ed5 100644
--- a/productcomments.php
+++ b/productcomments.php
@@ -208,7 +208,7 @@ protected function _postProcess()
         } elseif (Tools::isSubmit('deleteproductcomments')) {
             $comment = $commentRepository->find($id_product_comment);
 
-            if ($comment ===  null) {
+            if ($comment === null) {
                 $this->_html .= $this->displayError($this->trans('The comment cannot be deleted', [], 'Modules.Productcomments.Admin'));
             } else {
                 $commentRepository->delete($comment);

From 35125b4026113e813123c8d7fd3708ae4613c6d2 Mon Sep 17 00:00:00 2001
From: leemyong pakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Sat, 9 Dec 2023 16:36:02 +0700
Subject: [PATCH 19/35] partial migration to Symfony FormData Provider n
 Handler

---
 config/admin/services.yml                     |  16 +++
 ...ProductCommentCriterionFormDataHandler.php | 121 ++++++++++++++++++
 ...roductCommentCriterionFormDataProvider.php |  89 +++++++++++++
 src/Form/index.php                            |  34 +++++
 4 files changed, 260 insertions(+)
 create mode 100644 src/Form/ProductCommentCriterionFormDataHandler.php
 create mode 100644 src/Form/ProductCommentCriterionFormDataProvider.php
 create mode 100644 src/Form/index.php

diff --git a/config/admin/services.yml b/config/admin/services.yml
index 6e16e432..02ce511d 100644
--- a/config/admin/services.yml
+++ b/config/admin/services.yml
@@ -1,2 +1,18 @@
 imports:
   - { resource: ../common.yml }
+
+services:
+    product_comment_criterion_form_data_provider:
+        class: 'PrestaShop\Module\ProductComment\Form\ProductCommentCriterionFormDataProvider'
+        public: true
+        arguments:
+            - '@product_comment_criterion_repository'
+            - '@prestashop.core.admin.lang.repository'
+            
+    product_comment_criterion_form_data_handler:
+        class: 'PrestaShop\Module\ProductComment\Form\ProductCommentCriterionFormDataHandler'
+        public: true
+        arguments:
+            - '@product_comment_criterion_repository'
+            - '@prestashop.core.admin.lang.repository'
+            - '@doctrine.orm.default_entity_manager'
\ No newline at end of file
diff --git a/src/Form/ProductCommentCriterionFormDataHandler.php b/src/Form/ProductCommentCriterionFormDataHandler.php
new file mode 100644
index 00000000..8e0437d9
--- /dev/null
+++ b/src/Form/ProductCommentCriterionFormDataHandler.php
@@ -0,0 +1,121 @@
+<?php
+/**
+ * Copyright since 2007 PrestaShop SA and Contributors
+ * PrestaShop is an International Registered Trademark & Property of PrestaShop SA
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License version 3.0
+ * that is bundled with this package in the file LICENSE.md.
+ * It is also available through the world-wide-web at this URL:
+ * https://opensource.org/licenses/AFL-3.0
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@prestashop.com so we can send you a copy immediately.
+ *
+ * @author    PrestaShop SA and Contributors <contact@prestashop.com>
+ * @copyright Since 2007 PrestaShop SA and Contributors
+ * @license   https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
+ */
+declare(strict_types=1);
+
+namespace PrestaShop\Module\ProductComment\Form;
+
+use Doctrine\ORM\EntityManagerInterface;
+use PrestaShop\Module\ProductComment\Entity\ProductCommentCriterion;
+use PrestaShop\Module\ProductComment\Entity\ProductCommentCriterionLang;
+use PrestaShop\Module\ProductComment\Repository\ProductCommentCriterionRepository;
+use PrestaShop\PrestaShop\Core\Form\IdentifiableObject\DataHandler\FormDataHandlerInterface;
+use PrestaShopBundle\Entity\Repository\LangRepository;
+
+class ProductCommentCriterionFormDataHandler implements FormDataHandlerInterface
+{
+    /**
+     * @var ProductCommentCriterionRepository
+     */
+    private $pccriterionRepository;
+
+    /**
+     * @var LangRepository
+     */
+    private $langRepository;
+
+    /**
+     * @var EntityManagerInterface
+     */
+    private $entityManager;
+
+    /**
+     * @param ProductCommentCriterionRepository $pccriterionRepository
+     * @param LangRepository $langRepository
+     * @param EntityManagerInterface $entityManager
+     */
+    public function __construct(
+        ProductCommentCriterionRepository $pccriterionRepository,
+        LangRepository $langRepository,
+        EntityManagerInterface $entityManager
+    ) {
+        $this->pccriterionRepository = $pccriterionRepository;
+        $this->langRepository = $langRepository;
+        $this->entityManager = $entityManager;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function create(array $data)
+    {
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function update($id, array $data)
+    {
+    }
+
+    /**
+     * @param ProductCommentCriterion $pccriterion
+     * @param array $pcc_languages
+     *
+     * @todo migrate this temporary function to above standard function create
+     */
+    public function createLangs($pccriterion, $pcc_languages): void
+    {
+        foreach ($pcc_languages as $langId => $langContent) {
+            $lang = $this->langRepository->find($langId);
+            $pccriterionLang = new ProductCommentCriterionLang();
+            $pccriterionLang
+                ->setLang($lang)
+                ->setName($langContent)
+            ;
+            $pccriterion->addCriterionLang($pccriterionLang);
+        }
+
+        $this->entityManager->persist($pccriterion);
+        $this->entityManager->flush();
+    }
+
+    /**
+     * @param ProductCommentCriterion $pccriterion
+     * @param array $pcc_languages
+     *
+     * @todo migrate this temporary function to above standard function update
+     */
+    public function updateLangs($pccriterion, $pcc_languages): void
+    {
+        foreach ($pcc_languages as $langId => $langContent) {
+            $lang = $this->langRepository->find($langId);
+            $pccriterionLang = $pccriterion->getCriterionLangByLangId($langId);
+            if (null === $pccriterionLang) {
+                continue;
+            }
+            $pccriterionLang
+                ->setName($langContent)
+            ;
+        }
+
+        $this->entityManager->persist($pccriterion);
+        $this->entityManager->flush();
+    }
+}
diff --git a/src/Form/ProductCommentCriterionFormDataProvider.php b/src/Form/ProductCommentCriterionFormDataProvider.php
new file mode 100644
index 00000000..a02cb840
--- /dev/null
+++ b/src/Form/ProductCommentCriterionFormDataProvider.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * Copyright since 2007 PrestaShop SA and Contributors
+ * PrestaShop is an International Registered Trademark & Property of PrestaShop SA
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License version 3.0
+ * that is bundled with this package in the file LICENSE.md.
+ * It is also available through the world-wide-web at this URL:
+ * https://opensource.org/licenses/AFL-3.0
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@prestashop.com so we can send you a copy immediately.
+ *
+ * @author    PrestaShop SA and Contributors <contact@prestashop.com>
+ * @copyright Since 2007 PrestaShop SA and Contributors
+ * @license   https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
+ */
+declare(strict_types=1);
+
+namespace PrestaShop\Module\ProductComment\Form;
+
+use PrestaShop\Module\ProductComment\Repository\ProductCommentCriterionRepository;
+use PrestaShop\PrestaShop\Core\Form\IdentifiableObject\DataProvider\FormDataProviderInterface;
+use PrestaShopBundle\Entity\Repository\LangRepository;
+
+class ProductCommentCriterionFormDataProvider implements FormDataProviderInterface
+{
+    /**
+     * @var ProductCommentCriterionRepository
+     */
+    private $pccriterionRepository;
+
+    /**
+     * @var LangRepository
+     */
+    private $langRepository;
+
+    /**
+     * @param ProductCommentCriterionRepository $pccriterionRepository
+     * @param LangRepository $langRepository
+     */
+    public function __construct(
+        ProductCommentCriterionRepository $pccriterionRepository,
+        LangRepository $langRepository
+    ) {
+        $this->pccriterionRepository = $pccriterionRepository;
+        $this->langRepository = $langRepository;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getData($criterionId)
+    {
+        $criterion = $this->pccriterionRepository->find($criterionId);
+
+        $criterionData = [
+            'type' => $criterion->getType(),
+            'active' => $criterion->isActive(),
+        ];
+        foreach ($criterion->getCriterionLangs() as $criterionLang) {
+            $criterionData['name'][$criterionLang->getLang()->getId()] = $criterionLang->getName();
+        }
+
+        return $criterionData;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getDefaultData()
+    {
+        $default_name = [];
+
+        //$langIsoIds = Language::getIsoIds();
+        $langEntities = $this->langRepository->findBy(['active' => 1]);
+        foreach ($langEntities as $langEntity) {
+            $default_name[$langEntity->getId()] = $langEntity->getIsoCode();
+        }
+
+        return [
+            'type' => '',
+            'active' => false,
+            'name' => $default_name,
+        ];
+    }
+}
diff --git a/src/Form/index.php b/src/Form/index.php
new file mode 100644
index 00000000..45df26c5
--- /dev/null
+++ b/src/Form/index.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Copyright since 2007 PrestaShop SA and Contributors
+ * PrestaShop is an International Registered Trademark & Property of PrestaShop SA
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License 3.0 (AFL-3.0)
+ * that is bundled with this package in the file LICENSE.md.
+ * It is also available through the world-wide-web at this URL:
+ * https://opensource.org/licenses/AFL-3.0
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@prestashop.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
+ * versions in the future. If you wish to customize PrestaShop for your
+ * needs please refer to https://devdocs.prestashop.com/ for more information.
+ *
+ * @author    PrestaShop SA and Contributors <contact@prestashop.com>
+ * @copyright Since 2007 PrestaShop SA and Contributors
+ * @license   https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
+ */
+header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
+header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
+
+header('Cache-Control: no-store, no-cache, must-revalidate');
+header('Cache-Control: post-check=0, pre-check=0', false);
+header('Pragma: no-cache');
+
+header('Location: ../');
+exit;

From d7a89ad098fd66f459cd725ff3c265a0d8cd7722 Mon Sep 17 00:00:00 2001
From: leemyong pakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Sat, 9 Dec 2023 16:38:56 +0700
Subject: [PATCH 20/35] replace Manual lang field process by Doctrine Entity
 Relation

---
 src/Entity/ProductCommentCriterion.php     | 107 ++++++++++++---------
 src/Entity/ProductCommentCriterionLang.php |  97 +++++++++++++++++++
 2 files changed, 161 insertions(+), 43 deletions(-)
 create mode 100644 src/Entity/ProductCommentCriterionLang.php

diff --git a/src/Entity/ProductCommentCriterion.php b/src/Entity/ProductCommentCriterion.php
index b2421472..de610006 100644
--- a/src/Entity/ProductCommentCriterion.php
+++ b/src/Entity/ProductCommentCriterion.php
@@ -26,8 +26,8 @@
 
 namespace PrestaShop\Module\ProductComment\Entity;
 
+use Doctrine\Common\Collections\ArrayCollection;
 use Doctrine\ORM\Mapping as ORM;
-use Language;
 use Validate;
 
 /**
@@ -67,34 +67,79 @@ class ProductCommentCriterion
     /**
      * @var array
      *
-     * Need to be implemented as ORM\OneToMany in the future
+     * @deprecated 6.0.3 - use criterionLangs instead
      */
     private $names;
 
+    /**
+     * @ORM\OneToMany(targetEntity="PrestaShop\Module\ProductComment\Entity\ProductCommentCriterionLang", cascade={"persist", "remove"}, mappedBy="productcommentcriterion")
+     */
+    private $criterionLangs;
+
     /**
      * @var array
      *
-     * Need to be implemented as ORM\OneToMany in the future
+     * @todo implement as ORM\OneToMany in the future
      */
     private $categories;
 
     /**
      * @var array
      *
-     * Need to be implemented as ORM\OneToMany in the future
+     * @todo implement as ORM\OneToMany in the future
      */
     private $products;
 
     public function __construct()
     {
-        $langIsoIds = Language::getIsoIds();
-        foreach ($langIsoIds as $langIsoId) {
-            $this->names[$langIsoId['id_lang']] = $langIsoId['iso_code'];
+        $this->criterionLangs = new ArrayCollection();
+    }
+
+    /**
+     * @return ArrayCollection
+     */
+    public function getCriterionLangs()
+    {
+        return $this->criterionLangs;
+    }
+
+    /**
+     * @return ProductCommentCriterionLang|null
+     */
+    public function getCriterionLangByLangId(int $langId)
+    {
+        foreach ($this->criterionLangs as $criterionLang) {
+            if ($langId === $criterionLang->getLang()->getId()) {
+                return $criterionLang;
+            }
+        }
+
+        return null;
+    }
+
+    public function addCriterionLang(ProductCommentCriterionLang $criterionLang): self
+    {
+        $criterionLang->setProductCommentCriterion($this);
+        $this->criterionLangs->add($criterionLang);
+
+        return $this;
+    }
+
+    public function getCriterionName(): string
+    {
+        if ($this->criterionLangs->count() <= 0) {
+            return '';
         }
+
+        $criterionLang = $this->criterionLangs->first();
+
+        return $criterionLang->getName();
     }
 
     /**
      * @return array
+     *
+     * @deprecated 6.0.3 - migrated to Form\ProductCommentCriterionFormDataProvider
      */
     public function getNames()
     {
@@ -105,6 +150,8 @@ public function getNames()
      * @param array $langNames
      *
      * @return ProductCommentCriterion
+     *
+     * @deprecated 6.0.3
      */
     public function setNames($langNames)
     {
@@ -123,10 +170,8 @@ public function getCategories()
 
     /**
      * @param array $selectedCategories
-     *
-     * @return ProductCommentCriterion
      */
-    public function setCategories($selectedCategories)
+    public function setCategories($selectedCategories): self
     {
         $this->categories = $selectedCategories;
 
@@ -143,71 +188,47 @@ public function getProducts()
 
     /**
      * @param array $selectedProducts
-     *
-     * @return ProductCommentCriterion
      */
-    public function setProducts($selectedProducts)
+    public function setProducts($selectedProducts): self
     {
         $this->products = $selectedProducts;
 
         return $this;
     }
 
-    /**
-     * @return int
-     */
-    public function getId()
+    public function getId(): int
     {
         return $this->id;
     }
 
-    /**
-     * @return int
-     */
-    public function getType()
+    public function getType(): int
     {
         return $this->type;
     }
 
-    /**
-     * @param int $type
-     *
-     * @return ProductCommentCriterion
-     */
-    public function setType($type)
+    public function setType(int $type): self
     {
         $this->type = $type;
 
         return $this;
     }
 
-    /**
-     * @return bool
-     */
-    public function isActive()
+    public function isActive(): bool
     {
         return $this->active;
     }
 
-    /**
-     * @param bool $active
-     *
-     * @return ProductCommentCriterion
-     */
-    public function setActive($active)
+    public function setActive(bool $active): self
     {
         $this->active = $active;
 
         return $this;
     }
 
-    /**
-     * @return bool
-     */
-    public function isValid()
+    public function isValid(): bool
     {
-        foreach ($this->names as $value) {
-            if (!Validate::isGenericName($value)) {
+        foreach ($this->criterionLangs as $criterionLang) {
+            if (!Validate::isGenericName($criterionLang->getName())) {
                 return false;
             }
         }
diff --git a/src/Entity/ProductCommentCriterionLang.php b/src/Entity/ProductCommentCriterionLang.php
new file mode 100644
index 00000000..19373f7f
--- /dev/null
+++ b/src/Entity/ProductCommentCriterionLang.php
@@ -0,0 +1,97 @@
+<?php
+/**
+ * 2007-2020 PrestaShop SA and Contributors
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License 3.0 (AFL-3.0).
+ * It is also available through the world-wide-web at this URL: https://opensource.org/licenses/AFL-3.0
+ */
+declare(strict_types=1);
+
+namespace PrestaShop\Module\ProductComment\Entity;
+
+use Doctrine\ORM\Mapping as ORM;
+use PrestaShopBundle\Entity\Lang;
+
+/**
+ * @ORM\Table()
+ *
+ * @ORM\Entity()
+ */
+class ProductCommentCriterionLang
+{
+    /**
+     * @var ProductCommentCriterion
+     *
+     * @ORM\Id
+     *
+     * @ORM\ManyToOne(targetEntity="PrestaShop\Module\ProductComment\Entity\ProductCommentCriterion", inversedBy="criterionLangs")
+     *
+     * @ORM\JoinColumn(name="id_product_comment_criterion", referencedColumnName="id_product_comment_criterion", nullable=false)
+     */
+    private $productcommentcriterion;
+
+    /**
+     * @var Lang
+     *
+     * @ORM\Id
+     *
+     * @ORM\ManyToOne(targetEntity="PrestaShopBundle\Entity\Lang")
+     *
+     * @ORM\JoinColumn(name="id_lang", referencedColumnName="id_lang", nullable=false, onDelete="CASCADE")
+     */
+    private $lang;
+
+    /**
+     * @var string
+     *
+     * @ORM\Column(name="name", type="string", nullable=false)
+     */
+    private $name;
+
+    /**
+     * @return ProductCommentCriterion
+     */
+    public function getProductCommentCriterion()
+    {
+        return $this->productcommentcriterion;
+    }
+
+    public function setProductCommentCriterion(ProductCommentCriterion $productcommentcriterion): self
+    {
+        $this->productcommentcriterion = $productcommentcriterion;
+
+        return $this;
+    }
+
+    /**
+     * @return Lang
+     */
+    public function getLang()
+    {
+        return $this->lang;
+    }
+
+    /**
+     * @param Lang $lang
+     */
+    public function setLang(Lang $lang): self
+    {
+        $this->lang = $lang;
+
+        return $this;
+    }
+
+    public function getName(): string
+    {
+        return $this->name;
+    }
+
+    public function setName(string $name): self
+    {
+        $this->name = $name;
+
+        return $this;
+    }
+}

From a99f0172df3aef331efc9484fb717e6d9b0ee363 Mon Sep 17 00:00:00 2001
From: leemyong pakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Sat, 9 Dec 2023 16:41:06 +0700
Subject: [PATCH 21/35] mark deprcated functions, replace migrated functions
 call by new one

---
 productcomments.php                           | 48 +++++++++++----
 .../ProductCommentCriterionRepository.php     | 61 ++++++++-----------
 2 files changed, 62 insertions(+), 47 deletions(-)

diff --git a/productcomments.php b/productcomments.php
index 473f5ed5..75745ac5 100644
--- a/productcomments.php
+++ b/productcomments.php
@@ -169,8 +169,10 @@ public function getCacheId($id_product = null)
     protected function _postProcess()
     {
         $id_product_comment = (int) Tools::getValue('id_product_comment');
+        $id_product_comment_criterion = (int) Tools::getValue('id_product_comment_criterion');
         $commentRepository = $this->get('product_comment_repository');
         $criterionRepository = $this->get('product_comment_criterion_repository');
+        $criterionFormHandler = $this->get('product_comment_criterion_form_data_handler');
 
         if (Tools::isSubmit('submitModerate')) {
             $errors = [];
@@ -215,7 +217,12 @@ protected function _postProcess()
                 Tools::redirectAdmin($this->context->link->getAdminLink('AdminModules', true, [], ['configure' => $this->name]));
             }
         } elseif (Tools::isSubmit('submitEditCriterion')) {
-            $criterion = $criterionRepository->findRelation((int) Tools::getValue('id_product_comment_criterion'));
+            if ($id_product_comment_criterion > 0) {
+                $criterion = $criterionRepository->find($id_product_comment_criterion);
+            } else {
+                $criterion = new ProductCommentCriterion();
+            }
+
             $criterion->setType((int) Tools::getValue('id_product_comment_criterion_type'));
             $criterion->setActive(Tools::getValue('active'));
 
@@ -224,7 +231,12 @@ protected function _postProcess()
             foreach ($languages as $key => $value) {
                 $name[$value['id_lang']] = Tools::getValue('name_' . $value['id_lang']);
             }
-            $criterion->setNames($name);
+
+            if ($id_product_comment_criterion > 0) {
+                $criterionFormHandler->updateLangs($criterion, $name);
+            } else {
+                $criterionFormHandler->createLangs($criterion, $name);
+            }
 
             if (!$criterion->isValid()) {
                 $this->_html .= $this->displayError($this->trans('The criterion cannot be saved', [], 'Modules.Productcomments.Admin'));
@@ -238,14 +250,18 @@ protected function _postProcess()
                 }
             }
         } elseif (Tools::isSubmit('deleteproductcommentscriterion')) {
-            $criterion = $criterionRepository->findRelation((int) Tools::getValue('id_product_comment_criterion'));
+            $criterion = $criterionRepository->find($id_product_comment_criterion);
             if ($criterionRepository->delete($criterion)) {
-                $this->_html .= $this->displayConfirmation($this->trans('Criterion deleted', [], 'Modules.Productcomments.Admin'));
+                Tools::redirectAdmin($this->context->link->getAdminLink('AdminModules', true, [], ['configure' => $this->name]));
+            } else {
+                $this->_html .= $this->displayError($this->trans('Criterion cannot be deleted', [], 'Modules.Productcomments.Admin'));
             }
         } elseif (Tools::isSubmit('statusproductcommentscriterion')) {
-            $criterion = $criterionRepository->findRelation((int) Tools::getValue('id_product_comment_criterion'));
+            $criterion = $criterionRepository->find($id_product_comment_criterion);
             $criterion->setActive(!$criterion->isActive());
-            Tools::redirectAdmin($this->context->link->getAdminLink('AdminModules', true, [], ['configure' => $this->name, 'tab_module' => $this->tab, 'conf' => 4, 'module_name' => $this->name]));
+            $criterionRepository->updateGeneral($criterion);
+
+            Tools::redirectAdmin($this->context->link->getAdminLink('AdminModules', true, [], ['configure' => $this->name]));
         } elseif ($id_product_comment = (int) Tools::getValue('approveComment')) {
             $comment = $commentRepository->find($id_product_comment);
             $commentRepository->validate($comment, 1);
@@ -602,16 +618,22 @@ public function getConfigFieldsValues()
         ];
     }
 
-    public function getCriterionFieldsValues($id = 0)
+    public function getCriterionFieldsValues(int $id = 0)
     {
         $criterionRepos = $this->get('product_comment_criterion_repository');
-        $criterion = $criterionRepos->findRelation($id);
+        $criterionFormProvider = $this->get('product_comment_criterion_form_data_provider');
+
+        if ($id > 0) {
+            $criterionData = $criterionFormProvider->getData($id);
+        } else {
+            $criterionData = $criterionFormProvider->getDefaultData();
+        }
 
         return [
-            'name' => $criterion->getNames(),
-            'id_product_comment_criterion_type' => $criterion->getType(),
-            'active' => $criterion->isActive(),
-            'id_product_comment_criterion' => $criterion->getId(),
+            'name' => $criterionData['name'],
+            'id_product_comment_criterion_type' => $criterionData['type'],
+            'active' => $criterionData['active'],
+            'id_product_comment_criterion' => $id,
         ];
     }
 
@@ -702,7 +724,7 @@ public function renderCriterionForm($id_criterion = 0)
 
         $criterionRepository = $this->get('product_comment_criterion_repository');
 
-        $criterion = $criterionRepository->findRelation($id_criterion);
+        $criterion = $criterionRepository->find($id_criterion);
         $selected_categories = $criterionRepository->getCategories($id_criterion);
 
         $product_table_values = Product::getSimpleProducts($this->langId);
diff --git a/src/Repository/ProductCommentCriterionRepository.php b/src/Repository/ProductCommentCriterionRepository.php
index 7446f671..c978e5b4 100644
--- a/src/Repository/ProductCommentCriterionRepository.php
+++ b/src/Repository/ProductCommentCriterionRepository.php
@@ -88,6 +88,9 @@ public function remove(ProductCommentCriterion $entity, bool $flush = false): vo
         }
     }
 
+    /**
+     * @deprecated 6.0.3 - cascade remove by Entity setting instead
+     */
     private function deleteLangs($criterion): int
     {
         return $this->connection->executeUpdate('
@@ -112,33 +115,34 @@ private function deleteProducts($criterion): int
     private function deleteGrades($criterion): int
     {
         return $this->connection->executeUpdate('
-            DELETE FROM `' . _DB_PREFIX_ . 'product_comment_criterion_grade`
+            DELETE FROM `' . _DB_PREFIX_ . 'product_comment_grade`
             WHERE `id_product_comment_criterion` = ' . $criterion->getId());
     }
 
-    /* Remove a criterion and Delete its manual relation _lang, _category, _product, _grade */
+    /* Remove a criterion and Delete its manual relation _category, _product, _grade */
     public function delete(ProductCommentCriterion $criterion): int
     {
         $res = 0;
 
         $criterionType = $criterion->getType();
 
-        $this->remove($criterion, true);
-
-        $res += $this->deleteLangs($criterion);
-
         if ($criterionType == ProductCommentCriterion::CATEGORIES_TYPE) {
             $res += $this->deleteCategories($criterion);
         } elseif ($criterionType == ProductCommentCriterion::PRODUCTS_TYPE) {
             $res += $this->deleteProducts($criterion);
+        } else {
+            $res = 1;
         }
 
         $res += $this->deleteGrades($criterion);
 
+        $this->remove($criterion, true);
+
+        // todo: return void, and use try catch Exception instead
         return $res;
     }
 
-    /* Update a criterion and Update its manual relation _lang, _category, _product, _grade */
+    /* Update a criterion and Update its manual relation _category, _product */
     public function update(ProductCommentCriterion $criterion): int
     {
         $res = 0;
@@ -148,20 +152,23 @@ public function update(ProductCommentCriterion $criterion): int
         $this->getEntityManager()->persist($criterion);
         $this->getEntityManager()->flush();
 
-        $res += $this->deleteLangs($criterion);
-        $res += $this->updateLangs($criterion);
-
         if ($criterionType == ProductCommentCriterion::CATEGORIES_TYPE) {
             $res += $this->deleteCategories($criterion);
             $res += $this->updateCategories($criterion);
         } elseif ($criterionType == ProductCommentCriterion::PRODUCTS_TYPE) {
             $res += $this->deleteProducts($criterion);
             $res += $this->updateProducts($criterion);
+        } else {
+            $res = 1;
         }
 
+        // todo: return void, and use try catch Exception instead
         return $res;
     }
 
+    /**
+     * @deprecated 6.0.3 - migrated to Form\ProductCommentCriterionFormDataHandler
+     */
     private function updateLangs($criterion): int
     {
         $res = 0;
@@ -217,15 +224,18 @@ private function updateProducts($criterion): int
         return $res;
     }
 
+    public function updateGeneral(ProductCommentCriterion $criterion): void
+    {
+        $this->getEntityManager()->persist($criterion);
+        $this->getEntityManager()->flush();
+    }
+
     /**
-     * @param int $idProduct
-     * @param int $idLang
-     *
      * @return array
      *
      * @throws \PrestaShopException
      */
-    public function getByProduct($idProduct, $idLang)
+    public function getByProduct(int $idProduct, int $idLang)
     {
         /** @var QueryBuilder $qb */
         $qb = $this->connection->createQueryBuilder();
@@ -255,11 +265,9 @@ public function getByProduct($idProduct, $idLang)
     }
 
     /**
-     * Get Criterions
-     *
      * @return array Criterions
      */
-    public function getCriterions($id_lang, $type = false, $active = false)
+    public function getCriterions(int $id_lang, $type = false, $active = false)
     {
         $sql = '
             SELECT pcc.`id_product_comment_criterion`, pcc.id_product_comment_criterion_type, pccl.`name`, pcc.active
@@ -278,8 +286,6 @@ public function getCriterions($id_lang, $type = false, $active = false)
     }
 
     /**
-     * @param int $id_criterion
-     *
      * @return array
      */
     public function getProducts(int $id_criterion)
@@ -302,8 +308,6 @@ public function getProducts(int $id_criterion)
     }
 
     /**
-     * @param int $id_criterion
-     *
      * @return array
      */
     public function getCategories(int $id_criterion)
@@ -340,25 +344,14 @@ public function getTypes()
     }
 
     /**
-     * Get Criterion with names in active languages
-     *
      * @return ProductCommentCriterion
+     *
+     * @deprecated 6.0.3 - use standard find() instead
      */
     public function findRelation($id_criterion)
     {
         if ($id_criterion > 0) {
             $criterion = $this->find($id_criterion);
-            $sql = '
-            SELECT `id_lang`, `name`
-            FROM `' . _DB_PREFIX_ . 'product_comment_criterion_lang` pccl			
-            WHERE pccl.id_product_comment_criterion = ' . $id_criterion . '
-            ORDER BY pccl.`id_lang` ASC';
-            $langNames = $this->connection->executeQuery($sql)->fetchAll();
-            $langArray = [];
-            foreach ($langNames as $langName) {
-                $langArray[$langName['id_lang']] = $langName['name'];
-            }
-            $criterion->setNames($langArray);
         } else {
             $criterion = new ProductCommentCriterion();
         }

From 28fb21410a28fd05b1f37ac17a3608a2eebd220b Mon Sep 17 00:00:00 2001
From: leemyong pakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Thu, 14 Dec 2023 09:38:20 +0700
Subject: [PATCH 22/35] redundant comment

---
 src/Form/ProductCommentCriterionFormDataProvider.php | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/Form/ProductCommentCriterionFormDataProvider.php b/src/Form/ProductCommentCriterionFormDataProvider.php
index a02cb840..9b8397d9 100644
--- a/src/Form/ProductCommentCriterionFormDataProvider.php
+++ b/src/Form/ProductCommentCriterionFormDataProvider.php
@@ -74,7 +74,6 @@ public function getDefaultData()
     {
         $default_name = [];
 
-        //$langIsoIds = Language::getIsoIds();
         $langEntities = $this->langRepository->findBy(['active' => 1]);
         foreach ($langEntities as $langEntity) {
             $default_name[$langEntity->getId()] = $langEntity->getIsoCode();

From 499fc048ad4c55bb8e13f3c1f1a3dd9ddfe8fdd6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Hlav=C3=A1=C4=8Dek?= <daniel.hlavacek@hotmail.cz>
Date: Sat, 30 Dec 2023 14:21:33 +0100
Subject: [PATCH 23/35] Remove unneeded check

---
 ProductCommentCriterion.php | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/ProductCommentCriterion.php b/ProductCommentCriterion.php
index 0a739915..b82271df 100644
--- a/ProductCommentCriterion.php
+++ b/ProductCommentCriterion.php
@@ -172,13 +172,6 @@ public static function getByProduct($id_product, $id_lang)
             !Validate::isUnsignedId($id_lang)) {
             exit(Tools::displayError());
         }
-        $alias = 'p';
-        $table = '';
-        // check if version > 1.5 to add shop association
-        if (version_compare(_PS_VERSION_, '1.5', '>')) {
-            $table = '_shop';
-            $alias = 'ps';
-        }
 
         $cache_id = 'ProductCommentCriterion::getByProduct_' . $id_product . '-' . $id_lang;
         if (!Cache::isStored($cache_id)) {
@@ -191,7 +184,7 @@ public static function getByProduct($id_product, $id_lang)
 					ON (pcc.`id_product_comment_criterion` = pccp.`id_product_comment_criterion` AND pccp.`id_product` = ' . $id_product . ')
 				LEFT JOIN `' . _DB_PREFIX_ . 'product_comment_criterion_category` pccc
 					ON (pcc.`id_product_comment_criterion` = pccc.`id_product_comment_criterion`)
-				LEFT JOIN `' . _DB_PREFIX_ . 'product' . $table . '` ' . $alias . '
+				LEFT JOIN `' . _DB_PREFIX_ . 'product_shop` ps
 					ON (' . $alias . '.id_category_default = pccc.id_category AND ' . $alias . '.id_product = ' . $id_product . ')
 				WHERE pccl.`id_lang` = ' . $id_lang . '
 				AND (

From 00614983c09c62c7a6181836dedc17e17db75381 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Hlav=C3=A1=C4=8Dek?= <daniel.hlavacek@hotmail.cz>
Date: Sat, 30 Dec 2023 14:39:06 +0100
Subject: [PATCH 24/35] Remove remaining alias usage

---
 ProductCommentCriterion.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ProductCommentCriterion.php b/ProductCommentCriterion.php
index b82271df..1ae4df3f 100644
--- a/ProductCommentCriterion.php
+++ b/ProductCommentCriterion.php
@@ -185,7 +185,7 @@ public static function getByProduct($id_product, $id_lang)
 				LEFT JOIN `' . _DB_PREFIX_ . 'product_comment_criterion_category` pccc
 					ON (pcc.`id_product_comment_criterion` = pccc.`id_product_comment_criterion`)
 				LEFT JOIN `' . _DB_PREFIX_ . 'product_shop` ps
-					ON (' . $alias . '.id_category_default = pccc.id_category AND ' . $alias . '.id_product = ' . $id_product . ')
+					ON (ps.id_category_default = pccc.id_category AND ps.id_product = ' . $id_product . ')
 				WHERE pccl.`id_lang` = ' . $id_lang . '
 				AND (
 					pccp.id_product IS NOT NULL

From e7e83f200514c7e1142c4701990d83a975b2cf31 Mon Sep 17 00:00:00 2001
From: leemyong pakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Wed, 10 Jan 2024 11:15:51 +0700
Subject: [PATCH 25/35] disable Write your view in QuickView refresh action

---
 productcomments.php | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/productcomments.php b/productcomments.php
index 75745ac5..271722b4 100644
--- a/productcomments.php
+++ b/productcomments.php
@@ -1072,9 +1072,16 @@ public function renderWidget($hookName = null, array $configuration = [])
             $idProduct = $this->context->controller->getProduct()->id;
             $variables = $this->getWidgetVariables($hookName, ['id_product' => $idProduct]);
 
-            $filePath = 'quickview' === Tools::getValue('action')
-                ? $tplHookPath . 'product-additional-info-quickview.tpl'
-                : $tplHookPath . 'product-additional-info.tpl';
+            switch (Tools::getValue('action')) {
+                case 'quickview':
+                    $filePath = $tplHookPath . 'product-additional-info-quickview.tpl';
+                    break;
+                case '':
+                    $filePath = $tplHookPath . 'product-additional-info.tpl';
+                    break;
+                default:    // 'refresh' and other unpredicted cases
+                    $filePath = '';
+            }
         }
 
         if (empty($variables) || empty($filePath)) {

From 045816c2576e527bf2a31584f52901f55dff967c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Hlav=C3=A1=C4=8Dek?= <daniel.hlavacek@hotmail.cz>
Date: Thu, 11 Jan 2024 13:14:56 +0100
Subject: [PATCH 26/35] Update and rename install-2.4.php to install-2.4.0.php

---
 upgrade/{install-2.4.php => install-2.4.0.php} | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
 rename upgrade/{install-2.4.php => install-2.4.0.php} (96%)

diff --git a/upgrade/install-2.4.php b/upgrade/install-2.4.0.php
similarity index 96%
rename from upgrade/install-2.4.php
rename to upgrade/install-2.4.0.php
index da9bae79..af6d0a32 100644
--- a/upgrade/install-2.4.php
+++ b/upgrade/install-2.4.0.php
@@ -27,7 +27,7 @@
     exit;
 }
 
-function upgrade_module_2_4($object)
+function upgrade_module_2_4_0($object)
 {
     return $object->registerHook('displayProductListReviews') && $object->registerHook('top');
 }

From 96574312e5af0c2022f0fa1b1c62ddace04949ed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Hlav=C3=A1=C4=8Dek?= <daniel.hlavacek@hotmail.cz>
Date: Thu, 11 Jan 2024 13:37:04 +0100
Subject: [PATCH 27/35] Update productcomments.php

---
 productcomments.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/productcomments.php b/productcomments.php
index 75745ac5..92de3458 100644
--- a/productcomments.php
+++ b/productcomments.php
@@ -47,7 +47,7 @@ public function __construct()
     {
         $this->name = 'productcomments';
         $this->tab = 'front_office_features';
-        $this->version = '6.0.2';
+        $this->version = '6.0.3';
         $this->author = 'PrestaShop';
         $this->need_instance = 0;
         $this->bootstrap = true;

From 4cbdb610f7215b379b7c1629fab45e7d671a7d12 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Hlav=C3=A1=C4=8Dek?= <daniel.hlavacek@hotmail.cz>
Date: Thu, 11 Jan 2024 13:38:06 +0100
Subject: [PATCH 28/35] Update config.xml

---
 config.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.xml b/config.xml
index b378a090..bba666f0 100644
--- a/config.xml
+++ b/config.xml
@@ -2,7 +2,7 @@
 <module>
     <name>productcomments</name>
     <displayName><![CDATA[Product Comments]]></displayName>
-    <version><![CDATA[6.0.2]]></version>
+    <version><![CDATA[6.0.3]]></version>
     <description><![CDATA[Allows users to post reviews and rate products on specific criteria.]]></description>
     <author><![CDATA[PrestaShop]]></author>
     <tab><![CDATA[front_office_features]]></tab>

From fea6fa7191ce99a914f8548dd031d72b4d310cc4 Mon Sep 17 00:00:00 2001
From: leemyong pakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Sat, 20 Jan 2024 18:21:19 +0700
Subject: [PATCH 29/35] make rating mandatory

---
 views/js/jquery.rating.plugin.js            | 1 +
 views/js/post-comment.js                    | 5 +++++
 views/templates/hook/post-comment-modal.tpl | 2 ++
 3 files changed, 8 insertions(+)

diff --git a/views/js/jquery.rating.plugin.js b/views/js/jquery.rating.plugin.js
index b466e9fd..755dbdbc 100644
--- a/views/js/jquery.rating.plugin.js
+++ b/views/js/jquery.rating.plugin.js
@@ -96,6 +96,7 @@ jQuery.fn.rating = function(generalOptions) {
         newStar.on('click', function selectGrade() {
           var selectedGrade = $(this).data('grade');
           ratingInput.val(selectedGrade);
+          ratingChosen = true;
         });
         fullStars.append(newStar);
       }
diff --git a/views/js/post-comment.js b/views/js/post-comment.js
index 3601f882..26a28bbb 100644
--- a/views/js/post-comment.js
+++ b/views/js/post-comment.js
@@ -124,6 +124,11 @@ jQuery(document).ready(function () {
       }
     });
 
+    if (!ratingChosen) {
+      showPostErrorModal(productCommentRatingNotChosen);
+      isValid = false;
+    }
+
     return isValid;
   }
 
diff --git a/views/templates/hook/post-comment-modal.tpl b/views/templates/hook/post-comment-modal.tpl
index 81a75659..c559a594 100644
--- a/views/templates/hook/post-comment-modal.tpl
+++ b/views/templates/hook/post-comment-modal.tpl
@@ -25,6 +25,8 @@
 
 <script type="text/javascript">
   var productCommentPostErrorMessage = '{l s='Sorry, your review cannot be posted.' d='Modules.Productcomments.Shop' js=1}';
+  var productCommentRatingNotChosen = '{l s='Please choose a rating for your review.' d='Modules.Productcomments.Shop' js=1}';
+  var ratingChosen = false;
 </script>
 
 <div id="post-product-comment-modal" class="modal fade product-comment-modal" role="dialog" aria-hidden="true">

From 10ddd325eb3f7221221ff9fcd2746f9ab967235d Mon Sep 17 00:00:00 2001
From: leemyong pakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Sun, 21 Jan 2024 07:42:14 +0700
Subject: [PATCH 30/35] put Mandatory message inside the current modal instead
 of a new modal

---
 views/css/productcomments.css               |  6 ++++++
 views/js/post-comment.js                    | 18 ++++++++++++------
 views/templates/hook/post-comment-modal.tpl |  2 +-
 3 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/views/css/productcomments.css b/views/css/productcomments.css
index 106d2808..13e69982 100644
--- a/views/css/productcomments.css
+++ b/views/css/productcomments.css
@@ -291,6 +291,12 @@
   font-weight: bold;
 }
 
+#ratingNotChosen {
+  font-size: smaller;
+  color: #ff0000;
+  text-align: center;
+}
+
 #post-product-comment-form input.error,
 #post-product-comment-form textarea.error {
   background-color: #f2dede;
diff --git a/views/js/post-comment.js b/views/js/post-comment.js
index 26a28bbb..d9f76fdf 100644
--- a/views/js/post-comment.js
+++ b/views/js/post-comment.js
@@ -39,6 +39,10 @@ jQuery(document).ready(function () {
   const commentPostedModal = $('#product-comment-posted-modal');
   const commentPostErrorModal = $('#product-comment-post-error');
 
+  const criterionsList = $('#criterions_list');
+  criterionsList.append('<div id="ratingNotChosen">* ' + productCommentMandatoryMessage + '</div>');
+  $('#ratingNotChosen').hide();
+
   function showPostCommentModal() {
     commentPostedModal.modal('hide');
     commentPostErrorModal.modal('hide');
@@ -122,12 +126,14 @@ jQuery(document).ready(function () {
         $(fieldSelector).removeClass('error');
         $(fieldSelector).addClass('valid');
       }
-    });
-
-    if (!ratingChosen) {
-      showPostErrorModal(productCommentRatingNotChosen);
-      isValid = false;
-    }
+           
+      if (!ratingChosen) {
+        $('#ratingNotChosen').show();
+        isValid = false;
+      } else {
+        $('#ratingNotChosen').hide();
+      }
+    });  
 
     return isValid;
   }
diff --git a/views/templates/hook/post-comment-modal.tpl b/views/templates/hook/post-comment-modal.tpl
index c559a594..4c682ace 100644
--- a/views/templates/hook/post-comment-modal.tpl
+++ b/views/templates/hook/post-comment-modal.tpl
@@ -25,7 +25,7 @@
 
 <script type="text/javascript">
   var productCommentPostErrorMessage = '{l s='Sorry, your review cannot be posted.' d='Modules.Productcomments.Shop' js=1}';
-  var productCommentRatingNotChosen = '{l s='Please choose a rating for your review.' d='Modules.Productcomments.Shop' js=1}';
+  var productCommentMandatoryMessage = '{l s='Please choose a rating for your review.' d='Modules.Productcomments.Shop' js=1}';
   var ratingChosen = false;
 </script>
 

From dc9c3f3b5637254258c78a4bbdd61539feb65bcc Mon Sep 17 00:00:00 2001
From: leemyong pakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Sun, 21 Jan 2024 11:20:25 +0700
Subject: [PATCH 31/35] unify

---
 views/js/post-comment.js | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/views/js/post-comment.js b/views/js/post-comment.js
index d9f76fdf..c0a14921 100644
--- a/views/js/post-comment.js
+++ b/views/js/post-comment.js
@@ -41,7 +41,8 @@ jQuery(document).ready(function () {
 
   const criterionsList = $('#criterions_list');
   criterionsList.append('<div id="ratingNotChosen">* ' + productCommentMandatoryMessage + '</div>');
-  $('#ratingNotChosen').hide();
+  const criterionsInfo = $('#ratingNotChosen');
+  criterionsInfo.hide();
 
   function showPostCommentModal() {
     commentPostedModal.modal('hide');
@@ -128,10 +129,10 @@ jQuery(document).ready(function () {
       }
            
       if (!ratingChosen) {
-        $('#ratingNotChosen').show();
+        criterionsInfo.show();
         isValid = false;
       } else {
-        $('#ratingNotChosen').hide();
+        criterionsInfo.hide();
       }
     });  
 

From 36d69ce5810fb64ba32bc035241af352a30f0919 Mon Sep 17 00:00:00 2001
From: leemyong pakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Tue, 23 Jan 2024 21:39:42 +0700
Subject: [PATCH 32/35] tweak message color and alignment

---
 views/css/productcomments.css | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/views/css/productcomments.css b/views/css/productcomments.css
index 13e69982..d87f2dbe 100644
--- a/views/css/productcomments.css
+++ b/views/css/productcomments.css
@@ -293,8 +293,8 @@
 
 #ratingNotChosen {
   font-size: smaller;
-  color: #ff0000;
-  text-align: center;
+  color: #ab4746;
+  text-align: right;
 }
 
 #post-product-comment-form input.error,

From 415fee76c218b8ca39ef5a3164110d8be786ec5d Mon Sep 17 00:00:00 2001
From: leemyong pakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Mon, 29 Jan 2024 22:36:54 +0700
Subject: [PATCH 33/35] hide Mandatory message at each showPostCommentModal
 call

---
 views/js/post-comment.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/views/js/post-comment.js b/views/js/post-comment.js
index c0a14921..9941d5bc 100644
--- a/views/js/post-comment.js
+++ b/views/js/post-comment.js
@@ -41,13 +41,13 @@ jQuery(document).ready(function () {
 
   const criterionsList = $('#criterions_list');
   criterionsList.append('<div id="ratingNotChosen">* ' + productCommentMandatoryMessage + '</div>');
-  const criterionsInfo = $('#ratingNotChosen');
-  criterionsInfo.hide();
+  const criterionsInfo = $('#ratingNotChosen');  
 
   function showPostCommentModal() {
     commentPostedModal.modal('hide');
     commentPostErrorModal.modal('hide');
     postCommentModal.modal('show');
+    criterionsInfo.hide();
   }
 
   function showCommentPostedModal() {

From 51a0320c41e82a1ba08b6ee2a648a1a670019f74 Mon Sep 17 00:00:00 2001
From: SharakPL <git@sharak.pl>
Date: Thu, 1 Feb 2024 00:40:05 +0100
Subject: [PATCH 34/35] fix compatibility with hummingbird theme

---
 views/js/productListingComments.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/views/js/productListingComments.js b/views/js/productListingComments.js
index c384f755..2c21269b 100644
--- a/views/js/productListingComments.js
+++ b/views/js/productListingComments.js
@@ -43,7 +43,7 @@ var productListingComments = (function () {
         productListReviewsContainer: '.product-list-reviews',
         productListReviewsNumberOfComments: '.comments-nb',
         productListReviewsStarsContainer: '.grade-stars',
-        productContainer: '.thumbnail-container'
+        productContainer: '.js-product-miniature'
     };
 
     var DOMClasses =  {

From 357a3f6f4ec38a1bd6f8d3255f1c9a200b030aa5 Mon Sep 17 00:00:00 2001
From: leemyong pakvn <3759923+leemyongpakvn@users.noreply.github.com>
Date: Mon, 5 Feb 2024 20:47:52 +0700
Subject: [PATCH 35/35] forced to chose rating in any new review

---
 views/js/post-comment.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/views/js/post-comment.js b/views/js/post-comment.js
index 9941d5bc..cf593b54 100644
--- a/views/js/post-comment.js
+++ b/views/js/post-comment.js
@@ -47,6 +47,7 @@ jQuery(document).ready(function () {
     commentPostedModal.modal('hide');
     commentPostErrorModal.modal('hide');
     postCommentModal.modal('show');
+    ratingChosen = false;
     criterionsInfo.hide();
   }