diff --git a/Config/module.xml b/Config/module.xml index 73ffb79..d9271c2 100644 --- a/Config/module.xml +++ b/Config/module.xml @@ -13,7 +13,7 @@ en_US fr_FR - 3.0.0 + 3.0.1 Bertrand TOURLONIAS diff --git a/Config/routing.xml b/Config/routing.xml index e8f7a94..938dd12 100644 --- a/Config/routing.xml +++ b/Config/routing.xml @@ -65,6 +65,10 @@ GoogleShoppingXml\Controller\GoogleFieldAssociationController::setEanRuleAction + + GoogleShoppingXml\Controller\GoogleFieldAssociationController::setCompatibilitySqlAction + + diff --git a/Controller/GoogleFieldAssociationController.php b/Controller/GoogleFieldAssociationController.php index 579ebdb..805ce9f 100644 --- a/Controller/GoogleFieldAssociationController.php +++ b/Controller/GoogleFieldAssociationController.php @@ -2,6 +2,7 @@ namespace GoogleShoppingXml\Controller; +use GoogleShoppingXml\Form\CompatibilitySqlForm; use GoogleShoppingXml\GoogleShoppingXml; use GoogleShoppingXml\Model\GoogleshoppingxmlGoogleFieldAssociation; use GoogleShoppingXml\Model\GoogleshoppingxmlGoogleFieldAssociationQuery; @@ -9,7 +10,9 @@ use Thelia\Core\HttpFoundation\Request; use Thelia\Core\Security\AccessManager; use Thelia\Core\Security\Resource\AdminResources; +use Thelia\Core\Template\ParserContext; use Thelia\Core\Translation\Translator; +use Thelia\Log\Tlog; class GoogleFieldAssociationController extends BaseAdminController { @@ -232,4 +235,28 @@ public function setEanRuleAction(Request $httpRequest) return $this->generateRedirectFromRoute("admin.module.configure", array(), $redirectParameters); } + + public function setCompatibilitySqlAction(ParserContext $parserContext) + { + $form = $this->createForm(CompatibilitySqlForm::getName()); + + try { + $compatibilityForm = $this->validateForm($form); + + GoogleShoppingXml::setConfigValue(GoogleShoppingXml::ENABLE_SQL_8_COMPATIBILITY, $compatibilityForm->get('enable_optimisation')->getData()); + + return $this->generateSuccessRedirect($form); + }catch (\Exception $exception) { + Tlog::getInstance()->error($exception->getMessage()); + + $form->setErrorMessage($exception->getMessage()); + + $parserContext + ->addForm($form) + ->setGeneralError($exception->getMessage()) + ; + + return $this->generateErrorRedirect($form); + } + } } diff --git a/Form/CompatibilitySqlForm.php b/Form/CompatibilitySqlForm.php new file mode 100644 index 0000000..51e229d --- /dev/null +++ b/Form/CompatibilitySqlForm.php @@ -0,0 +1,29 @@ +formBuilder + ->add( + 'enable_optimisation', + CheckboxType::class, + [ + 'label' => Translator::getInstance()->trans("Enable sql 8 optimisations"), + 'label_attr' => array( + 'for' => 'enable_sql_8' + ), + 'data' => (bool)GoogleShoppingXml::getConfigValue(GoogleShoppingXml::ENABLE_SQL_8_COMPATIBILITY), + 'required'=> false + ] + ); + } + +} \ No newline at end of file diff --git a/GoogleShoppingXml.php b/GoogleShoppingXml.php index d4a4209..fa1fe7a 100644 --- a/GoogleShoppingXml.php +++ b/GoogleShoppingXml.php @@ -17,6 +17,8 @@ class GoogleShoppingXml extends BaseModule /* @var string */ const UPDATE_PATH = __DIR__ . DS . 'Config' . DS . 'update'; + const ENABLE_SQL_8_COMPATIBILITY = 'enable_sql_8_compatibility'; + public function preActivation(ConnectionInterface $con = null) { if (!$this->getConfigValue('is_initialized', false)) { diff --git a/Service/GoogleModel/GoogleProductModel.php b/Service/GoogleModel/GoogleProductModel.php index 61c70af..032a315 100644 --- a/Service/GoogleModel/GoogleProductModel.php +++ b/Service/GoogleModel/GoogleProductModel.php @@ -207,7 +207,7 @@ public function setPrice(float $price): GoogleProductModel * @param string $item_group_id * @return GoogleProductModel */ - public function setItemGroupId(string $item_group_id): GoogleProductModel + public function setItemGroupId(?string $item_group_id): GoogleProductModel { $this->item_group_id = $item_group_id; return $this; @@ -217,7 +217,7 @@ public function setItemGroupId(string $item_group_id): GoogleProductModel * @param string $brand * @return GoogleProductModel */ - public function setBrand(string $brand): GoogleProductModel + public function setBrand(?string $brand): GoogleProductModel { $this->brand = $brand; return $this; @@ -227,7 +227,7 @@ public function setBrand(string $brand): GoogleProductModel * @param string $google_product_category * @return GoogleProductModel */ - public function setGoogleProductCategory(string $google_product_category): GoogleProductModel + public function setGoogleProductCategory(?string $google_product_category): GoogleProductModel { $this->google_product_category = $google_product_category; return $this; @@ -247,7 +247,7 @@ public function setCondition($condition = null): GoogleProductModel * @param string $product_type * @return GoogleProductModel */ - public function setProductType(string $product_type): GoogleProductModel + public function setProductType(?string $product_type): GoogleProductModel { $this->product_type = $product_type; return $this; @@ -257,7 +257,7 @@ public function setProductType(string $product_type): GoogleProductModel * @param array $shipping * @return GoogleProductModel */ - public function setshipping(array $shipping): GoogleProductModel + public function setshipping(?array $shipping): GoogleProductModel { $this->shipping = $shipping; return $this; @@ -266,7 +266,7 @@ public function setshipping(array $shipping): GoogleProductModel /** * @param int $imageId */ - public function setImageLink(int $imageId): void + public function setImageLink(?int $imageId): void { $this->image_link = URL::getInstance()->absoluteUrl("legacy-image-library/product_image_$imageId/full/max/0/default.jpg"); } diff --git a/Service/Provider/ProductProvider.php b/Service/Provider/ProductProvider.php index c40e625..b41e9d7 100644 --- a/Service/Provider/ProductProvider.php +++ b/Service/Provider/ProductProvider.php @@ -2,6 +2,8 @@ namespace GoogleShoppingXml\Service\Provider; +use GoogleShoppingXml\GoogleShoppingXml; +use OpenApi\Model\Api\Product; use PDO; use Generator; use GoogleShoppingXml\Model\GoogleshoppingxmlFeed; @@ -9,7 +11,13 @@ use GoogleShoppingXml\Service\ShippingService; use Propel\Runtime\Exception\PropelException; use Symfony\Component\HttpFoundation\RequestStack; +use Thelia\Core\Template\Loop\ProductSaleElementsImage; +use Thelia\Model\Base\ProductQuery; +use Thelia\Model\Category; +use Thelia\Model\CategoryQuery; use Thelia\Model\ConfigQuery; +use Thelia\Model\ProductImageQuery; +use Thelia\Model\ProductSaleElementsProductImageQuery; use Thelia\Model\TaxRuleQuery; use Thelia\TaxEngine\Calculator; use Thelia\Tools\MoneyFormat; @@ -55,18 +63,66 @@ public function getDataGenerator(GoogleshoppingxmlFeed $feed, MoneyFormat $money $taxCalculator = new Calculator(); $taxeRules = $this->getTaxeRules(); + $shipping = $this->shipingService->buildShippingArray($feed, $moneyFormat); + + $optimisation = GoogleShoppingXml::getConfigValue(GoogleShoppingXml::ENABLE_SQL_8_COMPATIBILITY); /** @var $resultStatement */ - $resultStatement = $this->sqlQueryService->getPses($locale); - $shipping = $this->shipingService->buildShippingArray($feed, $moneyFormat); + + if ($optimisation) { + $resultStatement = $this->sqlQueryService->getPsesWithSqlOptimisation($locale); + } else { + $resultStatement = $this->sqlQueryService->getPses($locale); + } while ($row = $resultStatement->fetch(PDO::FETCH_ASSOC)) { $taxCalculator->loadTaxRuleWithoutProduct($taxeRules[$row['TAX_RULE_ID']], $feed->getCountry()); + $row['title'] = $row['product_title']; + + if (null !== $row['attrib_title']) { + $row['title'] .= ' - '.$row['attrib_title']; + } + + if (!$optimisation) { + + $pseImage = ProductSaleElementsProductImageQuery::create() + ->filterByProductSaleElementsId($row['id']) + ->findOne(); + + $productImage = ProductImageQuery::create() + ->useProductQuery() + ->useProductSaleElementsQuery() + ->filterById($row['id']) + ->endUse() + ->endUse() + ->orderByPosition() + ->findOne(); + + $row['image_link'] = $pseImage ? $pseImage->getProductImageId() : $productImage?->getId(); + + $path = $this->getCategories(CategoryQuery::create()->findPk($row['default_category_id']), $locale); + + $row['product_type'] = implode(' > ', $path); + } + yield (new GoogleProductModel($taxCalculator, $moneyFormat, $shipping, $feed->getCurrency(), 'g:'))->build($row); } } + private function getCategories(Category $category, $locale) + { + if ($category->getParent() !== 0){ + $parentCategory = CategoryQuery::create()->findPk($category->getParent()); + $path = $this->getCategories($parentCategory, $locale); + } + + $category->setLocale($locale); + $path[] = $category->getTitle(); + + return $path; + } + /** * @return array */ diff --git a/Service/Provider/SQLQueryService.php b/Service/Provider/SQLQueryService.php index d8fc8a0..36410bf 100644 --- a/Service/Provider/SQLQueryService.php +++ b/Service/Provider/SQLQueryService.php @@ -3,6 +3,8 @@ namespace GoogleShoppingXml\Service\Provider; use Propel\Runtime\Propel; +use Thelia\Model\Map\ProductSaleElementsTableMap; +use Thelia\Model\ProductSaleElementsQuery; use Thelia\Tools\URL; class SQLQueryService @@ -10,7 +12,7 @@ class SQLQueryService /** * @param string $locale */ - public function getPses(string $locale) + public function getPsesWithSqlOptimisation(string $locale) { $baseUrl = URL::getInstance()->absoluteUrl('/'); @@ -30,9 +32,9 @@ public function getPses(string $locale) ), attribute_title AS ( SELECT ac.product_sale_elements_id AS id, GROUP_CONCAT(DISTINCT avi.title ORDER BY a.id SEPARATOR " - ") AS title from attribute_combination AS ac - JOIN attribute a ON a.id = ac.attribute_id - JOIN attribute_av av ON ac.attribute_av_id = av.id - JOIN attribute_av_i18n avi ON av.id = avi.id + LEFT JOIN attribute a ON a.id = ac.attribute_id + LEFT JOIN attribute_av av ON ac.attribute_av_id = av.id + LEFT JOIN attribute_av_i18n avi ON av.id = avi.id WHERE avi.locale=:p1 GROUP BY ac.product_sale_elements_id @@ -52,7 +54,8 @@ public function getPses(string $locale) SELECT pse.id AS "id", - CONCAT(pi.title," - ", attrib.title) AS "title", + pi.title AS "product_title", + attrib.title AS "attrib_title", pi.description AS "description", IF(pse.quantity>0, "in stock", "out of stock") AS "availability", CONCAT(@BASEURL := "' . $baseUrl . '",rurl.url) AS "link", @@ -69,19 +72,19 @@ public function getPses(string $locale) FROM `product_sale_elements`AS pse - JOIN product AS p ON pse.product_id = p.id - JOIN product_i18n AS pi ON p.id = pi.id - JOIN attribute_title AS attrib ON attrib.id = pse.id - JOIN rewriting_url AS rurl ON rurl.view = "product" AND rurl.view_id = p.id - JOIN product_price AS pp ON pp.product_sale_elements_id = pse.id - JOIN brand AS b ON b.id = p.brand_id - JOIN brand_i18n AS bi ON b.id = bi.id - JOIN product_category AS pc ON pc.product_id=p.id AND pc.default_category=1 - JOIN product_images_query AS pimgs ON pimgs.pid=p.id + LEFT JOIN product AS p ON pse.product_id = p.id + LEFT JOIN product_i18n AS pi ON p.id = pi.id + LEFT JOIN attribute_title AS attrib ON attrib.id = pse.id + LEFT JOIN rewriting_url AS rurl ON rurl.view = "product" AND rurl.view_id = p.id + LEFT JOIN product_price AS pp ON pp.product_sale_elements_id = pse.id + LEFT JOIN brand AS b ON b.id = p.brand_id + LEFT JOIN brand_i18n AS bi ON b.id = bi.id + LEFT JOIN product_category AS pc ON pc.product_id=p.id AND pc.default_category=1 + LEFT JOIN product_images_query AS pimgs ON pimgs.pid=p.id LEFT JOIN pse_images_query AS pseimgs ON pseimgs.pseid=pse.id - JOIN category AS c ON c.id=pc.category_id - JOIN googleshoppingxml_taxonomy AS gt ON gt.thelia_category_id = c.id - JOIN category_path cp ON cp.id = pc.category_id + LEFT JOIN category AS c ON c.id=pc.category_id + LEFT JOIN googleshoppingxml_taxonomy AS gt ON gt.thelia_category_id = c.id + LEFT JOIN category_path cp ON cp.id = pc.category_id WHERE @@ -110,4 +113,69 @@ public function getPses(string $locale) return $stmt; } + + public function getPses(string $locale) + { + $baseUrl = URL::getInstance()->absoluteUrl('/'); + + $sql = ' + SELECT + pse.id AS "id", + pi.title AS "product_title", + GROUP_CONCAT(DISTINCT avi.title ORDER BY a.id SEPARATOR " - ") AS "attrib_title", + pi.description AS "description", + IF(pse.quantity>0, "in stock", "out of stock") AS "availability", + CONCAT(@BASEURL := "' . $baseUrl . '",rurl.url) AS "link", + IF(pse.promo=1, pp.promo_price, pp.price) AS "price", + bi.title AS "brand", + IF(pse.ean_code!="", "yes", "no") AS "identifier_exists", + pse.ean_code AS "gtin", + p.ref AS "item_group_id", + gt.google_category AS "google_product_category", + "new" AS "condition", + p.tax_rule_id AS "TAX_RULE_ID", + c.id AS "default_category_id" + + FROM `product_sale_elements`AS pse + + LEFT JOIN product AS p ON pse.product_id = p.id + LEFT JOIN product_i18n AS pi ON p.id = pi.id + LEFT JOIN attribute_combination AS ac ON ac.product_sale_elements_id = pse.id + LEFT JOIN attribute AS a ON a.id = ac.attribute_id + LEFT JOIN attribute_av AS av ON ac.attribute_av_id = av.id + LEFT JOIN attribute_av_i18n AS avi ON av.id = avi.id + LEFT JOIN rewriting_url AS rurl ON rurl.view = "product" AND rurl.view_id = p.id + LEFT JOIN product_price AS pp ON pp.product_sale_elements_id = pse.id + LEFT JOIN brand AS b ON b.id = p.brand_id + LEFT JOIN brand_i18n AS bi ON b.id = bi.id + LEFT JOIN product_category AS pc ON pc.product_id=p.id AND pc.default_category=1 + LEFT JOIN category AS c ON c.id=pc.category_id + LEFT JOIN googleshoppingxml_taxonomy AS gt ON gt.thelia_category_id = c.id + + WHERE + + pi.locale=:p2 + AND rurl.view_locale=:p3 + AND bi.locale=:p4 + AND p.visible=1 + AND pi.title!="" + AND pi.description!="" + + GROUP BY pse.id'; + + $con = Propel::getConnection(); + + /** @var PDOStatement $stmt */ + $stmt = $con->prepare($sql); + + //$stmt->bindValue(':p1', $locale); + $stmt->bindValue(':p2', $locale); + $stmt->bindValue(':p3', $locale); + $stmt->bindValue(':p4', $locale); + + $stmt->execute(); + + return $stmt; + + } } \ No newline at end of file diff --git a/templates/backOffice/default/include/config_tab_advanced.html b/templates/backOffice/default/include/config_tab_advanced.html index 58f36a8..4498074 100644 --- a/templates/backOffice/default/include/config_tab_advanced.html +++ b/templates/backOffice/default/include/config_tab_advanced.html @@ -180,4 +180,26 @@ + +
+
+
+
+ {intl l='Compatibility SQL'} +
+
+
+ {form name="googleshoppingxml_form_compatibility_sql_form"} +
+ {form_hidden_fields} + {render_form_field field="success_url" value={url path="/admin/module/GoogleShoppingXml"}} + {render_form_field field="enable_optimisation"} +
+ +
+
+ {/form} +
+
+
\ No newline at end of file diff --git a/templates/backOffice/default/module-configuration.html b/templates/backOffice/default/module-configuration.html new file mode 100644 index 0000000..e69de29