Skip to content

Instantly share code, notes, and snippets.

@muemarco
Created March 7, 2023 21:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save muemarco/19fce9ab05c0abee18b077b4a3234a22 to your computer and use it in GitHub Desktop.
Save muemarco/19fce9ab05c0abee18b077b4a3234a22 to your computer and use it in GitHub Desktop.
Patched file: jtl_google_shopping/Exportformat/GoogleReviewXML.php
<?php declare(strict_types=1);
namespace Plugin\jtl_google_shopping\Exportformat;
use DateTime;
use Exception;
use stdClass;
/**
* Class GoogleReviewXML
* @package Plugin\jtl_google_shopping\Exportformat
*/
class GoogleReviewXML extends GoogleShoppingXML
{
/**
* @var string
*/
protected $header = /** @lang text */
'<?xml version="1.0" encoding="UTF-8"?>' . "\r"
. '<feed' . "\r"
. "\t" . 'xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"' . "\r"
. "\t" . 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' . "\r"
. "\t" . 'xsi:noNamespaceSchemaLocation="http://www.google.com/shopping/reviews/schema/product/2.3/product_reviews.xsd">' . "\r"
. "\t" . '<version>2.3</version>' . "\r"
. "\t" . '<aggregator>' . "\r"
. "\t\t" . '<name>JTL-Shop</name>' . "\r"
. "\t" . '</aggregator>' . "\r"
. "\t" . '<publisher>' . "\r"
. "\t\t" . '<name>###cShop###</name>' . "\r"
. "\t" . '</publisher>' . "\r"
. "\t" . '<reviews>' . "\r";
/**
* @var string
*/
protected $footer = "\t</reviews>\r</feed>";
/**
* @inheritdoc
*/
public function loadAttr(): self
{
return $this;
}
/**
* @inheritdoc
*/
public function writeFooter(): self
{
\fwrite($this->tmpFile, $this->footer);
\fclose($this->tmpFile);
return $this;
}
/**
* Ruft für jeden Artikel die Methode writeArticle auf
*
* @return self
* @throws Exception
*/
public function writeContent(): self
{
if (!\is_array($this->exportProducts) || !\is_array($this->attributes)) {
return $this;
}
foreach ($this->exportProductIDs as $productID) {
$this->loadProduct($productID);
$this->writeReview($this->exportProducts[$productID] ?? new Product());
unset($this->exportProducts[$productID]);
}
return $this;
}
/**
* @param int $productID
* @return self
* @throws Exception
*/
private function loadProduct(int $productID): self
{
if ($productID <= 0) {
return $this;
}
$opt = Product::getExportOptions();
$opt->nRatings = 1;
$product = new Product();
$this->exportProducts[$productID] = $product;
try {
$product->fuelleArtikel(
$productID,
$opt,
$this->exportformat->kKundengruppe,
$this->exportformat->kSprache,
$this->exportformat->nUseCache !== 1
);
} catch (Exception $e) {
unset($product);
return $this;
}
if ($product->kArtikel === null) {
unset($this->exportProducts[$productID]);
$this->logger->notice(
\sprintf(
\__('Product could not be exported because no product exists for current settings'),
$productID
)
);
return $this;
}
if ((int)$product->nIstVater === 0 && $product->kVaterArtikel > 0) {
$this->loadProduct($product->kVaterArtikel);
if (isset($this->exportProducts[$product->kVaterArtikel]->kArtikel)) {
if ((int)$this->settings->get('ext_artnr_child') === 1) {
$product->cArtNr .= '_' . $product->kArtikel;
}
$product->cVaterArtNr = $this->exportProducts[$product->kVaterArtikel]->cArtNr;
unset($this->exportProducts[$product->kVaterArtikel]);
} else {
unset(
$this->exportProducts[$productID],
$this->exportProducts[$product->kVaterArtikel]
);
$this->logger->notice(
\sprintf(\__('Product could not be exported because no parent product exists'), $productID)
);
return $this;
}
}
if ($this->settings['strip_tags'] ?? 'N' === 'Y') {
$product->cName = \strip_tags($product->cName);
}
$product->cName = \mb_substr($product->cName, 0, self::MAX_PRODUCT_NAME_LENGTH);
return $this;
}
/**
* @param Product $product
* @return string
*/
private function getGtin(Product $product): string
{
$product->cGtin = '';
if (!empty($product->cBarcode)) {
$product->cGtin = $product->cBarcode;
} elseif (!empty($product->cISBN)) {
$product->cGtin = $product->cISBN;
}
if (empty($product->cGtin)) {
return '';
}
$prefix = "\t\t\t\t\t\t";
return $prefix . "<gtins>\r"
. $prefix . "\t<gtin>" . $product->cGtin . "</gtin>\r"
. $prefix . "</gtins>\r";
}
/**
* @param Product $product
* @return string
*/
private function getBrand(Product $product): string
{
if (empty($product->cHersteller)) {
return '';
}
$prefix = "\t\t\t\t\t\t";
return $prefix . "<brands>\r"
. $prefix . "\t<brand>" . $product->cHersteller . "</brand>\r"
. $prefix . "</brands>\r";
}
/**
* @param Product $product
* @return string
*/
private function getAsin(Product $product): string
{
if (empty($product->cASIN)) {
return '';
}
$prefix = "\t\t\t\t\t\t";
return $prefix . "<asins>\r"
. $prefix . "\t<asin>" . $product->cASIN . "</asin>\r"
. $prefix . "</asins>\r";
}
/**
* @param Product $product
* @return string
*/
private function getMpn(Product $product): string
{
if (empty($product->cHAN)) {
return '';
}
$prefix = "\t\t\t\t\t\t";
return $prefix . "<mpns>\r"
. $prefix . "\t<mpn>" . $product->cHAN . "</mpn>\r"
. $prefix . "</mpns>\r";
}
/**
* @param Product $product
* @return string
*/
private function getSku(Product $product): string
{
if (empty($product->cArtNr)) {
return '';
}
$prefix = "\t\t\t\t\t\t";
return $prefix . "<skus>\r"
. $prefix . "\t<sku>" . $product->cArtNr . "</sku>\r"
. $prefix . "</skus>\r";
}
/**
* @param string $content
* @return string
*/
private function sanitize(string $content): string
{
return \str_replace(['>', '<'], ['&gt;', '&lt;'], \html_entity_decode($content));
}
/**
* @param stdClass $rating
* @return string
*/
private function getReviewXML(stdClass $rating): string
{
$prefix = "\t\t\t";
$prefix2 = "\t\t\t\t";
if ($rating->kKunde > 0 && $rating->cName !== 'Anonym') {
$name = '<name>' . $this->sanitize($rating->cName) . '</name>';
} else {
$name = '<name is_anonymous="true">' . $this->sanitize($rating->cName) . '</name>';
}
return $prefix . '<review_id>' . $rating->kBewertung . '</review_id>' . "\r"
. $prefix . '<reviewer>' . "\r"
. $prefix2 . $name . "\r"
. $prefix . '</reviewer>' . "\r"
. $prefix . '<review_timestamp>'
. (new DateTime($rating->dDatum))->format('Y-m-d\TH:i:sP')
. '</review_timestamp>' . "\r"
. $prefix . '<title><![CDATA[' . $this->sanitize($rating->cTitel) . ']]></title>' . "\r"
. $prefix . '<content><![CDATA[' . $this->sanitize(\strip_tags(\rtrim($rating->cText))) . ']]></content>' . "\r"
. $prefix . '<review_url type="group">' . $rating->url . '</review_url>' . "\r"
. $prefix . '<ratings>' . "\r"
. $prefix2 . '<overall min="1" max="5">' . $rating->nSterne . '</overall>' . "\r"
. $prefix . '</ratings>' . "\r";
}
/**
* @param stdClass $review
* @return bool
*/
private function isValidReview(stdClass $review): bool
{
return !empty($review->cName)
&& !empty($review->cText)
&& !empty($review->cTitel)
&& $review->nSterne > -1
&& $review->nSterne < 6
&& $review->kSprache === $this->exportformat->kSprache;
}
/**
* Schreibt Artikel in die Datei $f
*
* @param Product $product
* @return self
*/
public function writeReview(Product $product): self
{
if ($product->kArtikel < 1
|| $product->Bewertungen === null
|| \count($product->Bewertungen->oBewertung_arr) === 0
) {
return $this;
}
$prefix = "\t\t\t";
$prefix2 = "\t\t\t\t";
$productXML = $prefix . "<products>\r"
. $prefix2 . "<product>\r"
. $prefix2 . "\t<product_ids>\r"
. $this->getGtin($product)
. $this->getMpn($product)
. $this->getSku($product)
. $this->getBrand($product)
. $this->getAsin($product)
. $prefix2 . "\t</product_ids>\r"
. $prefix2 . "\t<product_name><![CDATA[" . $this->sanitize($product->cName) . "]]></product_name>\r"
. $prefix2 . "\t<product_url>" . $product->cURLFull . "</product_url>\r"
. $prefix2 . "</product>\r"
. $prefix . "</products>\r";
$xml = '';
$url = $product->cURLFull . '#tab-votes';
foreach ($product->Bewertungen->oBewertung_arr as $rating) {
if (!$this->isValidReview($rating)) {
continue;
}
$rating->url = $url;
$xml .= "\t\t<review>\r";
$xml .= $this->getReviewXML($rating);
$xml .= $productXML;
$xml .= "\t\t</review>\r";
}
\fwrite($this->tmpFile, $xml);
return $this;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment