Initial commit

This commit is contained in:
2020-10-07 10:37:15 +02:00
commit ce5f440392
28157 changed files with 4429172 additions and 0 deletions

View File

@@ -0,0 +1,269 @@
<?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)
*/
namespace PrestaShop\Module\ProductComment\Addons;
use Doctrine\Common\Cache\FilesystemCache;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Subscriber\Cache\CacheStorage;
use GuzzleHttp\Subscriber\Cache\CacheSubscriber;
use PrestaShop\CircuitBreaker\AdvancedCircuitBreakerFactory;
use PrestaShop\CircuitBreaker\Contract\FactoryInterface;
use PrestaShop\CircuitBreaker\FactorySettings;
use PrestaShop\CircuitBreaker\Storage\DoctrineCache;
use Symfony\Component\CssSelector\CssSelectorConverter;
use DOMDocument;
use DOMXPath;
use DOMNode;
/**
* Class CategoryFetcher helps you to fetch an Addon category data. It calls the Addons
* API for name and link, and scrap the Addons platform to get its description.
* Every call is protected by a CircuitBreaker to avoid blocking the back-office.
*/
class CategoryFetcher
{
const CACHE_DURATION = 86400; //24 hours
const ADDONS_BASE_URL = 'https://addons.prestashop.com';
const ADDONS_API_URL = 'https://api-addons.prestashop.com';
const CLOSED_ALLOWED_FAILURES = 2;
const API_TIMEOUT_SECONDS = 0.6;
/**
* The timeout is longer for Addons platform as the content is bigger (HTML content)
*/
const PLATFORM_TIMEOUT_SECONDS = 2;
const OPEN_ALLOWED_FAILURES = 1;
const OPEN_TIMEOUT_SECONDS = 1.2;
const OPEN_THRESHOLD_SECONDS = 60;
/** @var int */
private $categoryId;
/** @var array */
private $defaultData;
/** @var FactoryInterface */
private $factory;
/** @var array */
private $apiSettings;
/** @var array */
private $platformSettings;
/**
* @param int $categoryId
* @param array $defaultData
*/
public function __construct(
$categoryId,
array $defaultData
) {
$this->categoryId = $categoryId;
$this->defaultData = array_merge([
'id_category' => (int) $categoryId,
], $defaultData);
//Doctrine cache used for Guzzle and CircuitBreaker storage
$doctrineCache = new FilesystemCache(_PS_CACHE_DIR_ . '/addons_category');
//Init Guzzle cache
$cacheStorage = new CacheStorage($doctrineCache, null, self::CACHE_DURATION);
$cacheSubscriber = new CacheSubscriber($cacheStorage, function (Request $request) { return true; });
//Init circuit breaker factory
$storage = new DoctrineCache($doctrineCache);
$this->apiSettings = new FactorySettings(self::CLOSED_ALLOWED_FAILURES, self::API_TIMEOUT_SECONDS, 0);
$this->apiSettings
->setThreshold(self::OPEN_THRESHOLD_SECONDS)
->setStrippedFailures(self::OPEN_ALLOWED_FAILURES)
->setStrippedTimeout(self::OPEN_TIMEOUT_SECONDS)
->setStorage($storage)
->setClientOptions([
'subscribers' => [$cacheSubscriber],
'method' => 'POST',
])
;
$this->platformSettings = new FactorySettings(self::CLOSED_ALLOWED_FAILURES, self::PLATFORM_TIMEOUT_SECONDS, 0);
$this->platformSettings
->setThreshold(self::OPEN_THRESHOLD_SECONDS)
->setStrippedFailures(self::OPEN_ALLOWED_FAILURES)
->setStrippedTimeout(self::OPEN_TIMEOUT_SECONDS)
->setStorage($storage)
->setClientOptions([
'subscribers' => [$cacheSubscriber],
'method' => 'GET',
])
;
$this->factory = new AdvancedCircuitBreakerFactory();
}
/**
* @param string $isoCode Two letters iso code to identify the country (ex: en, fr, es, ...)
*
* @return array
*/
public function getData($isoCode)
{
$category = $this->getCategoryFromApi($isoCode);
$category = $this->addTracking($category, $isoCode);
$category['description'] = $this->getDescription($category);
return $category;
}
/**
* @param string $isoCode
*
* @return array
*/
private function getCategoryFromApi($isoCode)
{
$circuitBreaker = $this->factory->create($this->apiSettings);
$apiJsonResponse = $circuitBreaker->call(
self::ADDONS_API_URL . '?iso_lang=' . $isoCode, //Include language in url to correctly cache results
[
'body' => [
'method' => 'listing',
'action' => 'categories',
'version' => '1.7',
'iso_lang' => $isoCode,
],
]
);
$apiResponse = !empty($apiJsonResponse) ? json_decode($apiJsonResponse, true) : false;
$category = null;
if (false !== $apiResponse && !empty($apiResponse['module']) && empty($apiResponse['errors'])) {
$category = $this->searchCategory($apiResponse['module'], $this->categoryId);
}
return null !== $category ? $category : $this->defaultData;
}
/**
* @param array $categories
* @param int $searchedCategoryId
*
* @return array|null
*/
private function searchCategory(array $categories, $searchedCategoryId)
{
foreach ($categories as $category) {
if (!empty($category['id_category']) && $searchedCategoryId == $category['id_category']) {
return $category;
}
if (!empty($category['categories'])) {
$subCategory = $this->searchCategory($category['categories'], $searchedCategoryId);
if (null !== $subCategory) {
return $subCategory;
}
}
}
return null;
}
/**
* @param array $category
*
* @return string
*/
private function getDescription(array $category)
{
$defaultDescription = !empty($this->defaultData['description']) ? $this->defaultData['description'] : '';
//Clean link used to fetch description (no need for tracking then)
if (empty($category['clean_link'])) {
return $defaultDescription;
}
$circuitBreaker = $this->factory->create($this->platformSettings);
$categoryResponse = $circuitBreaker->call($category['clean_link']);
if (empty($categoryResponse)) {
return $defaultDescription;
}
$cssSelector = new CssSelectorConverter();
$document = new DOMDocument();
// if fetched HTML is not valid, DOMDocument::loadHtml() will generate E_WARNING warnings
libxml_use_internal_errors(true);
$document->loadHTML($categoryResponse);
libxml_use_internal_errors(false);
$xpath = new DOMXPath($document);
$descriptionNode = $xpath->query($cssSelector->toXPath('#category_description'))->item(0);
$categoryDescription = '';
/** @var DOMNode $childNode */
foreach ($descriptionNode->childNodes as $childNode) {
$categoryDescription .= $childNode->ownerDocument->saveHTML($childNode);
}
return !empty($categoryDescription) ? $categoryDescription : $defaultDescription;
}
/**
* Updates link property with a correctly formatted url with tracking parameters
*
* @param array $category
* @param string $isoCode
*
* @return array
*/
private function addTracking(array $category, $isoCode)
{
if (empty($category['link'])) {
return $category;
}
$parsedUrl = parse_url($category['link']);
if (false === $parsedUrl) {
return $category;
}
$parameters = [];
if (!empty($parsedUrl['query'])) {
parse_str($parsedUrl['query'], $parameters);
}
$parameters['utm_source'] = 'back-office';
$parameters['utm_medium'] = 'modules';
$parameters['utm_campaign'] = 'back-office-' . strtoupper($isoCode);
//Clean link used to fetch description (no need for tracking then)
$category['clean_link'] = self::ADDONS_BASE_URL . $parsedUrl['path'];
$category['link'] = self::ADDONS_BASE_URL . $parsedUrl['path'] . '?' . http_build_query($parameters);
return $category;
}
}

View File

@@ -0,0 +1,352 @@
<?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)
*/
namespace PrestaShop\Module\ProductComment\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Table()
* @ORM\Entity()
*/
class ProductComment
{
const TITLE_MAX_LENGTH = 64;
const CUSTOMER_NAME_MAX_LENGTH = 64;
/**
* @var int
*
* @ORM\Id
* @ORM\Column(name="id_product_comment", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var int
*
* @ORM\Column(name="id_product", type="integer")
*/
private $productId;
/**
* @var int
*
* @ORM\Column(name="id_customer", type="integer")
*/
private $customerId;
/**
* @var int
*
* @ORM\Column(name="id_guest", type="integer")
*/
private $guestId;
/**
* @var string
*
* @ORM\Column(name="customer_name", type="string", length=64)
*/
private $customerName;
/**
* @var string
*
* @ORM\Column(name="title", type="string", length=64)
*/
private $title;
/**
* @var string
*
* @ORM\Column(name="content", type="text")
*/
private $content;
/**
* @var int
*
* @ORM\Column(name="grade", type="integer")
*/
private $grade;
/**
* @var bool
*
* @ORM\Column(name="validate", type="boolean")
*/
private $validate = 0;
/**
* @var bool
*
* @ORM\Column(name="deleted", type="boolean")
*/
private $deleted = 0;
/**
* @var \DateTime
*
* @ORM\Column(name="date_add", type="datetime")
*/
private $dateAdd;
public function __construct()
{
$this->criterions = new ArrayCollection();
}
/**
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* @return int
*/
public function getProductId()
{
return $this->productId;
}
/**
* @param int $productId
*
* @return ProductComment
*/
public function setProductId($productId)
{
$this->productId = $productId;
return $this;
}
/**
* @return int
*/
public function getCustomerId()
{
return $this->customerId;
}
/**
* @param int $customerId
*
* @return ProductComment
*/
public function setCustomerId($customerId)
{
$this->customerId = $customerId;
return $this;
}
/**
* @return int
*/
public function getGuestId()
{
return $this->guestId;
}
/**
* @param int $guestId
*
* @return ProductComment
*/
public function setGuestId($guestId)
{
$this->guestId = $guestId;
return $this;
}
/**
* @return string
*/
public function getCustomerName()
{
return $this->customerName;
}
/**
* @param string $customerName
*
* @return ProductComment
*/
public function setCustomerName($customerName)
{
$this->customerName = $customerName;
return $this;
}
/**
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* @param string $title
*
* @return ProductComment
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* @return string
*/
public function getContent()
{
return $this->content;
}
/**
* @param string $content
*
* @return ProductComment
*/
public function setContent($content)
{
$this->content = $content;
return $this;
}
/**
* @return int
*/
public function getGrade()
{
return $this->grade;
}
/**
* @param int $grade
*
* @return ProductComment
*/
public function setGrade($grade)
{
$this->grade = $grade;
return $this;
}
/**
* @return bool
*/
public function isValidate()
{
return $this->validate;
}
/**
* @param bool $validate
*
* @return ProductComment
*/
public function setValidate($validate)
{
$this->validate = $validate;
return $this;
}
/**
* @return bool
*/
public function isDeleted()
{
return $this->deleted;
}
/**
* @param bool $deleted
*
* @return ProductComment
*/
public function setDeleted($deleted)
{
$this->deleted = $deleted;
return $this;
}
/**
* @return \DateTime
*/
public function getDateAdd()
{
return $this->dateAdd;
}
/**
* Date is stored in UTC timezone
*
* @param \DateTime $dateAdd
*
* @return ProductComment
*/
public function setDateAdd($dateAdd)
{
$this->dateAdd = $dateAdd;
return $this;
}
/**
* @return array
*/
public function toArray()
{
return [
'id_product' => $this->getProductId(),
'id_product_comment' => $this->getId(),
'title' => $this->getTitle(),
'content' => $this->getContent(),
'customer_name' => $this->getCustomerName(),
'date_add' => $this->dateAdd->format(\DateTime::ATOM),
'grade' => $this->grade,
'usefulness' => 3,
'total_usefulness' => 5,
];
}
}

View File

@@ -0,0 +1,111 @@
<?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)
*/
namespace PrestaShop\Module\ProductComment\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Table()
* @ORM\Entity()
*/
class ProductCommentCriterion
{
const ENTIRE_CATALOG_TYPE = 1;
const CATEGORIES_TYPE = 2;
const PRODUCTS_TYPE = 3;
/**
* @var int
*
* @ORM\Id
* @ORM\Column(name="id_product_comment_criterion", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var int
*
* @ORM\Column(name="id_product_comment_criterion_type", type="integer")
*/
private $type;
/**
* @var bool
*
* @ORM\Column(name="active", type="boolean")
*/
private $active = 0;
/**
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* @return int
*/
public function getType()
{
return $this->type;
}
/**
* @param int $type
*
* @return ProductCommentCriterion
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* @return bool
*/
public function isActive()
{
return $this->active;
}
/**
* @param bool $active
*
* @return ProductCommentCriterion
*/
public function setActive($active)
{
$this->active = $active;
return $this;
}
}

View File

@@ -0,0 +1,88 @@
<?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)
*/
namespace PrestaShop\Module\ProductComment\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Table()
* @ORM\Entity()
*/
class ProductCommentGrade
{
/**
* @ORM\Id
* @ORM\ManyToOne(targetEntity="ProductComment")
* @ORM\JoinColumn(name="id_product_comment", referencedColumnName="id_product_comment")
*/
private $comment;
/**
* @ORM\Id
* @ORM\ManyToOne(targetEntity="ProductCommentCriterion")
* @ORM\JoinColumn(name="id_product_comment_criterion", referencedColumnName="id_product_comment_criterion")
*/
private $criterion;
/**
* @var int
*
* @ORM\Column(name="grade", type="integer")
*/
private $grade;
/**
* @param ProductComment $comment
* @param ProductCommentCriterion $criterion
* @param int $grade
*/
public function __construct(
ProductComment $comment,
ProductCommentCriterion $criterion,
$grade
) {
$this->comment = $comment;
$this->criterion = $criterion;
$this->grade = $grade;
}
/**
* @return mixed
*/
public function getComment()
{
return $this->comment;
}
/**
* @return mixed
*/
public function getCriterion()
{
return $this->criterion;
}
}

View File

@@ -0,0 +1,80 @@
<?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)
*/
namespace PrestaShop\Module\ProductComment\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Table()
* @ORM\Entity()
*/
class ProductCommentReport
{
/**
* @ORM\Id
* @ORM\ManyToOne(targetEntity="ProductComment")
* @ORM\JoinColumn(name="id_product_comment", referencedColumnName="id_product_comment")
*/
private $comment;
/**
* @var int
*
* @ORM\Id
* @ORM\Column(name="id_customer", type="integer")
*/
private $customerId;
/**
* @param ProductComment $comment
* @param int $customerId
* @param bool $usefulness
*/
public function __construct(
ProductComment $comment,
$customerId
) {
$this->comment = $comment;
$this->customerId = $customerId;
}
/**
* @return mixed
*/
public function getComment()
{
return $this->comment;
}
/**
* @return int
*/
public function getCustomerId()
{
return $this->customerId;
}
}

View File

@@ -0,0 +1,109 @@
<?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)
*/
namespace PrestaShop\Module\ProductComment\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Table()
* @ORM\Entity()
*/
class ProductCommentUsefulness
{
/**
* @ORM\Id
* @ORM\ManyToOne(targetEntity="ProductComment")
* @ORM\JoinColumn(name="id_product_comment", referencedColumnName="id_product_comment")
*/
private $comment;
/**
* @var int
*
* @ORM\Id
* @ORM\Column(name="id_customer", type="integer")
*/
private $customerId;
/**
* @var bool
*
* @ORM\Column(name="usefulness", type="boolean")
*/
private $usefulness;
/**
* @param ProductComment $comment
* @param int $customerId
* @param bool $usefulness
*/
public function __construct(
ProductComment $comment,
$customerId,
$usefulness
) {
$this->comment = $comment;
$this->customerId = $customerId;
$this->usefulness = $usefulness;
}
/**
* @return mixed
*/
public function getComment()
{
return $this->comment;
}
/**
* @return int
*/
public function getCustomerId()
{
return $this->customerId;
}
/**
* @return bool
*/
public function isUsefulness()
{
return $this->usefulness;
}
/**
* @param bool $usefulness
*
* @return ProductCommentUsefulness
*/
public function setUsefulness($usefulness)
{
$this->usefulness = $usefulness;
return $this;
}
}

View File

@@ -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;

View File

@@ -0,0 +1,91 @@
<?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)
*/
namespace PrestaShop\Module\ProductComment\Repository;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Query\QueryBuilder;
use PrestaShop\Module\ProductComment\Entity\ProductCommentCriterion;
class ProductCommentCriterionRepository
{
/**
* @var Connection the Database connection
*/
private $connection;
/**
* @var string the Database prefix
*/
private $databasePrefix;
/**
* @param Connection $connection
* @param string $databasePrefix
*/
public function __construct(Connection $connection, $databasePrefix)
{
$this->connection = $connection;
$this->databasePrefix = $databasePrefix;
}
/**
* @param int $idProduct
* @param int $idLang
*
* @return array
*
* @throws \PrestaShopException
*/
public function getByProduct($idProduct, $idLang)
{
/** @var QueryBuilder $qb */
$qb = $this->connection->createQueryBuilder();
$qb
->select('pcc.id_product_comment_criterion, pccl.name')
->from($this->databasePrefix . 'product_comment_criterion', 'pcc')
->leftJoin('pcc', $this->databasePrefix . 'product_comment_criterion_lang', 'pccl', 'pcc.id_product_comment_criterion = pccl.id_product_comment_criterion')
->leftJoin('pcc', $this->databasePrefix . 'product_comment_criterion_product', 'pccp', 'pcc.id_product_comment_criterion = pccp.id_product_comment_criterion')
->leftJoin('pcc', $this->databasePrefix . 'product_comment_criterion_category', 'pccc', 'pcc.id_product_comment_criterion = pccc.id_product_comment_criterion')
->leftJoin('pccc', $this->databasePrefix . 'category', 'c', 'pccc.id_category = c.id_category')
->leftJoin('c', $this->databasePrefix . 'category_product', 'cp', 'c.id_category = cp.id_category')
->andWhere($qb->expr()->orX(
$qb->expr()->eq('pcc.id_product_comment_criterion_type', ':catalog_type'),
$qb->expr()->eq('pccp.id_product', ':id_product'),
$qb->expr()->eq('cp.id_product', ':id_product')
))
->andWhere('pccl.id_lang = :id_lang')
->andWhere('pcc.active = :active')
->setParameter('catalog_type', ProductCommentCriterion::ENTIRE_CATALOG_TYPE)
->setParameter('active', 1)
->setParameter('id_product', $idProduct)
->setParameter('id_lang', $idLang)
->addGroupBy('pcc.id_product_comment_criterion')
;
return $qb->execute()->fetchAll();
}
}

View File

@@ -0,0 +1,415 @@
<?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)
*/
namespace PrestaShop\Module\ProductComment\Repository;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Query\QueryBuilder;
class ProductCommentRepository
{
/**
* @var Connection the Database connection
*/
private $connection;
/**
* @var string the Database prefix
*/
private $databasePrefix;
/**
* @var bool
*/
private $guestCommentsAllowed;
/**
* @var int
*/
private $commentsMinimalTime;
/**
* @param Connection $connection
* @param string $databasePrefix
* @param bool $guestCommentsAllowed
* @param int $commentsMinimalTime
*/
public function __construct(
Connection $connection,
$databasePrefix,
$guestCommentsAllowed,
$commentsMinimalTime
) {
$this->connection = $connection;
$this->databasePrefix = $databasePrefix;
$this->guestCommentsAllowed = (bool) $guestCommentsAllowed;
$this->commentsMinimalTime = (int) $commentsMinimalTime;
}
/**
* @param int $productId
* @param int $page
* @param int $commentsPerPage
* @param bool $validatedOnly
*
* @return array
*/
public function paginate($productId, $page, $commentsPerPage, $validatedOnly)
{
/** @var QueryBuilder $qb */
$qb = $this->connection->createQueryBuilder();
$qb
->addSelect('pc.id_product, pc.id_product_comment, pc.title, pc.content, pc.customer_name, pc.date_add, pc.grade')
->addSelect('c.firstname, c.lastname')
->from($this->databasePrefix . 'product_comment', 'pc')
->leftJoin('pc', $this->databasePrefix . 'customer', 'c', 'pc.id_customer = c.id_customer AND c.deleted = :not_deleted')
->andWhere('pc.id_product = :id_product')
->andWhere('pc.deleted = :not_deleted')
->setParameter('not_deleted', 0)
->setParameter('id_product', $productId)
->setMaxResults($commentsPerPage)
->setFirstResult(($page - 1) * $commentsPerPage)
->addGroupBy('pc.id_product_comment')
->addOrderBy('pc.date_add', 'DESC')
;
if ($validatedOnly) {
$qb
->andWhere('pc.validate = :validate')
->setParameter('validate', 1)
;
}
return $qb->execute()->fetchAll();
}
/**
* @param int $productCommentId
*
* @return array
*/
public function getProductCommentUsefulness($productCommentId)
{
/** @var QueryBuilder $qb */
$qb = $this->connection->createQueryBuilder();
$qb
->addSelect('pcu.usefulness')
->from($this->databasePrefix . 'product_comment_usefulness', 'pcu')
->andWhere('pcu.id_product_comment = :id_product_comment')
->setParameter('id_product_comment', $productCommentId)
;
$usefulnessInfos = [
'usefulness' => 0,
'total_usefulness' => 0,
];
$customerAppreciations = $qb->execute()->fetchAll();
foreach ($customerAppreciations as $customerAppreciation) {
if ((int) $customerAppreciation['usefulness']) {
++$usefulnessInfos['usefulness'];
}
++$usefulnessInfos['total_usefulness'];
}
return $usefulnessInfos;
}
/**
* @param int $productId
* @param bool $validatedOnly
*
* @return float
*/
public function getAverageGrade($productId, $validatedOnly)
{
/** @var QueryBuilder $qb */
$qb = $this->connection->createQueryBuilder();
$qb
->select('SUM(pc.grade) / COUNT(pc.grade) AS averageGrade')
->from($this->databasePrefix . 'product_comment', 'pc')
->andWhere('pc.id_product = :id_product')
->andWhere('pc.deleted = :deleted')
->setParameter('deleted', 0)
->setParameter('id_product', $productId)
;
if ($validatedOnly) {
$qb
->andWhere('pc.validate = :validate')
->setParameter('validate', 1)
;
}
return (float) $qb->execute()->fetchColumn();
}
/**
* @param array $productIds
* @param bool $validatedOnly
*
* @return array
*/
public function getAverageGrades(array $productIds, $validatedOnly)
{
$sql = 'SELECT';
$count = count($productIds);
foreach ($productIds as $index => $id) {
$esqID = pSQL($id);
$sql .= ' SUM(IF(id_product = ' . $esqID . ' AND deleted = 0';
if ($validatedOnly) {
$sql .= ' AND validate = 1';
}
$sql .= ',grade, 0))';
$sql .= ' / SUM(IF(id_product = ' . $esqID . ' AND deleted = 0';
if ($validatedOnly) {
$sql .= ' AND validate = 1';
}
$sql .= ',1, 0)) AS "' . $esqID . '"';
if ($count - 1 > $index) {
$sql .= ',';
}
}
$sql .= ' FROM ' . $this->databasePrefix . 'product_comment';
$query = $this->connection->prepare($sql);
$query->execute();
return (array) $query->fetch();
}
/**
* @param int $productId
* @param bool $validatedOnly
*
* @return int
*/
public function getCommentsNumber($productId, $validatedOnly)
{
/** @var QueryBuilder $qb */
$qb = $this->connection->createQueryBuilder();
$qb
->select('COUNT(pc.id_product_comment) AS commentNb')
->from($this->databasePrefix . 'product_comment', 'pc')
->andWhere('pc.id_product = :id_product')
->andWhere('pc.deleted = :deleted')
->setParameter('deleted', 0)
->setParameter('id_product', $productId)
;
if ($validatedOnly) {
$qb
->andWhere('pc.validate = :validate')
->setParameter('validate', 1)
;
}
return (int) $qb->execute()->fetchColumn();
}
/**
* @param array $productIds
* @param bool $validatedOnly
*
* @return array
*/
public function getCommentsNumberForProducts(array $productIds, $validatedOnly)
{
$sql = 'SELECT';
$count = count($productIds);
foreach ($productIds as $index => $id) {
$esqID = pSQL($id);
$sql .= ' SUM(IF(id_product = ' . $esqID . ' AND deleted = 0';
if ($validatedOnly) {
$sql .= ' AND validate = 1';
}
$sql .= ' ,1, 0)) AS "' . $esqID . '"';
if ($count - 1 > $index) {
$sql .= ',';
}
}
$sql .= ' FROM ' . $this->databasePrefix . 'product_comment';
// return $sql;
$query = $this->connection->prepare($sql);
$query->execute();
return (array) $query->fetch();
}
/**
* @param int $productId
* @param int $idCustomer
* @param int $idGuest
*
* @return bool
*/
public function isPostAllowed($productId, $idCustomer, $idGuest)
{
if (!$idCustomer && !$this->guestCommentsAllowed) {
$postAllowed = false;
} else {
$lastCustomerComment = null;
if ($idCustomer) {
$lastCustomerComment = $this->getLastCustomerComment($productId, $idCustomer);
} elseif ($idGuest) {
$lastCustomerComment = $this->getLastGuestComment($productId, $idGuest);
}
$postAllowed = true;
if (null !== $lastCustomerComment && isset($lastCustomerComment['date_add'])) {
$postDate = new \DateTime($lastCustomerComment['date_add'], new \DateTimeZone('UTC'));
if (time() - $postDate->getTimestamp() < $this->commentsMinimalTime) {
$postAllowed = false;
}
}
}
return $postAllowed;
}
/**
* @param int $productId
* @param int $idCustomer
*
* @return array
*/
public function getLastCustomerComment($productId, $idCustomer)
{
return $this->getLastComment(['id_product' => $productId, 'id_customer' => $idCustomer]);
}
/**
* @param int $productId
* @param int $idGuest
*
* @return array
*/
public function getLastGuestComment($productId, $idGuest)
{
return $this->getLastComment(['id_product' => $productId, 'id_guest' => $idGuest]);
}
/**
* @param int $customerId
*/
public function cleanCustomerData($customerId)
{
//We anonymize the customer comment by unlinking them (the name won't be visible any more but the grade and comment are still visible)
$qb = $this->connection->createQueryBuilder();
$qb
->update($this->databasePrefix . 'product_comment', 'pc')
->set('id_customer', 0)
->andWhere('pc.id_customer = :id_customer')
->setParameter('id_customer', $customerId)
;
$qb->execute();
//But we remove every report and votes for comments
$qb = $this->connection->createQueryBuilder();
$qb
->delete($this->databasePrefix . 'product_comment_report')
->andWhere('id_customer = :id_customer')
->setParameter('id_customer', $customerId)
;
$qb->execute();
$qb = $this->connection->createQueryBuilder();
$qb
->delete($this->databasePrefix . 'product_comment_usefulness')
->andWhere('id_customer = :id_customer')
->setParameter('id_customer', $customerId)
;
$qb->execute();
}
/**
* @param int $customerId
* @param int $langId
*
* @return array
*/
public function getCustomerData($customerId, $langId)
{
$qb = $this->connection->createQueryBuilder();
$qb
->select('pl.name, pc.id_product, pc.id_product_comment, pc.title, pc.content, pc.grade, pc.validate, pc.deleted, pcu.usefulness, pc.date_add')
->from($this->databasePrefix . 'product_comment', 'pc')
->leftJoin('pc', $this->databasePrefix . 'product_comment_usefulness', 'pcu', 'pc.id_product_comment = pcu.id_product_comment')
->leftJoin('pc', $this->databasePrefix . 'product', 'p', 'pc.id_product = p.id_product')
->leftJoin('p', $this->databasePrefix . 'product_lang', 'pl', 'p.id_product = pl.id_product')
->leftJoin('pl', $this->databasePrefix . 'lang', 'l', 'pl.id_lang = l.id_lang')
->andWhere('pc.id_customer = :id_customer')
->andWhere('l.id_lang = :id_lang')
->setParameter('id_customer', $customerId)
->setParameter('id_lang', $langId)
->addGroupBy('pc.id_product_comment')
->addOrderBy('pc.date_add', 'ASC')
;
return $qb->execute()->fetchAll();
}
/**
* @param array $criteria
*
* @return array
*/
private function getLastComment(array $criteria)
{
/** @var QueryBuilder $qb */
$qb = $this->connection->createQueryBuilder();
$qb
->select('pc.*')
->from($this->databasePrefix . 'product_comment', 'pc')
->andWhere('pc.deleted = :deleted')
->setParameter('deleted', 0)
->addOrderBy('pc.date_add', 'DESC')
->setMaxResults(1)
;
foreach ($criteria as $field => $value) {
$qb
->andWhere(sprintf('pc.%s = :%s', $field, $field))
->setParameter($field, $value)
;
}
$comments = $qb->execute()->fetchAll();
return empty($comments) ? [] : $comments[0];
}
}

View File

@@ -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;

View File

@@ -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;