Current File : //var/www/prestashop/src/PrestaShopBundle/Bridge/Helper/Listing/HelperBridge/HelperListBridge.php |
<?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 Open Software License (OSL 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/OSL-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/OSL-3.0 Open Software License (OSL 3.0)
*/
declare(strict_types=1);
namespace PrestaShopBundle\Bridge\Helper\Listing\HelperBridge;
use Context;
use Db;
use HelperList;
use PrestaShop\PrestaShop\Adapter\Configuration;
use PrestaShop\PrestaShop\Adapter\LegacyContext;
use PrestaShop\PrestaShop\Core\Hook\HookDispatcherInterface;
use PrestaShopBundle\Bridge\AdminController\FrameworkBridgeControllerInterface;
use PrestaShopBundle\Bridge\Helper\Listing\FilterPrefix;
use PrestaShopBundle\Bridge\Helper\Listing\HelperListConfiguration;
use PrestaShopBundle\Bridge\Helper\Listing\HelperListConfigurator;
use PrestaShopBundle\Service\DataProvider\UserProvider;
use PrestaShopException;
use Shop;
use Tools;
use Validate;
/**
* Acts as a bridge between symfony controller and the legacy HelperList to allow rendering the list
*
* @see HelperList
* @see FrameworkBridgeControllerInterface
*/
class HelperListBridge
{
/**
* @var Context
*/
private $context;
/**
* @var UserProvider
*/
private $userProvider;
/**
* @var HelperListConfigurator
*/
private $helperListConfigurator;
/**
* @var HookDispatcherInterface
*/
private $hookDispatcher;
/**
* @var Configuration
*/
private $configuration;
/**
* @param LegacyContext $legacyContext
* @param UserProvider $userProvider
* @param HelperListConfigurator $helperListVarsAssigner
* @param HookDispatcherInterface $hookDispatcher
* @param Configuration $configuration
*/
public function __construct(
LegacyContext $legacyContext,
UserProvider $userProvider,
HelperListConfigurator $helperListVarsAssigner,
HookDispatcherInterface $hookDispatcher,
Configuration $configuration
) {
$this->context = $legacyContext->getContext();
$this->userProvider = $userProvider;
$this->helperListConfigurator = $helperListVarsAssigner;
$this->hookDispatcher = $hookDispatcher;
$this->configuration = $configuration;
}
/**
* Generate the html for list using HelperList class
*
* @param HelperListConfiguration $helperListConfiguration
*
* @return string|null
*/
public function generateList(
HelperListConfiguration $helperListConfiguration
): ?string {
if (!($helperListConfiguration->fieldsList && is_array($helperListConfiguration->fieldsList))) {
return null;
}
$this->generateListQuery($helperListConfiguration, $this->context->language->id);
$helper = new HelperList();
$this->helperListConfigurator->setHelperDisplay($helperListConfiguration, $helper);
$helper->_default_pagination = $helperListConfiguration->defaultPagination;
$helper->_pagination = $helperListConfiguration->pagination;
$helper->tpl_delete_link_vars = $helperListConfiguration->deleteLinksVariableTemplate;
foreach ($helperListConfiguration->actionsAvailable as $action) {
if (!in_array($action, $helperListConfiguration->actions) && isset($helperListConfiguration->$action) && $helperListConfiguration->$action) {
$helperListConfiguration->actions[] = $action;
}
}
/* @phpstan-ignore-next-line */
$helper->sql = $helperListConfiguration->listsql;
return $helper->generateList($helperListConfiguration->list, $helperListConfiguration->fieldsList);
}
/**
* @param HelperListConfiguration $helperListConfiguration
* @param int $idLang
*
* @return void
*/
protected function generateListQuery(
HelperListConfiguration $helperListConfiguration,
int $idLang
): void {
if ($helperListConfiguration->table == 'feature_value') {
$helperListConfiguration->where .= ' AND (a.custom = 0 OR a.custom IS NULL)';
}
$this->hookDispatcher->dispatchWithParameters('action' . $helperListConfiguration->legacyControllerName . 'ListingFieldsModifier', [
'select' => &$helperListConfiguration->select,
'join' => &$helperListConfiguration->join,
'where' => &$helperListConfiguration->where,
'group_by' => &$helperListConfiguration->group,
'order_by' => &$helperListConfiguration->orderBy,
'order_way' => &$helperListConfiguration->orderWay,
'fields' => &$helperListConfiguration->fieldsList,
]);
if (!Validate::isTableOrIdentifier($helperListConfiguration->table)) {
throw new PrestaShopException(sprintf('Table name %s is invalid:', $helperListConfiguration->table));
}
$limit = $this->checkSqlLimit($helperListConfiguration);
/* Determine offset from current page */
$start = 0;
if ((int) Tools::getValue('submitFilter' . $helperListConfiguration->listId)) {
$start = ((int) Tools::getValue('submitFilter' . $helperListConfiguration->listId) - 1) * $limit;
} elseif (
isset($this->context->cookie->{$helperListConfiguration->listId . '_start'})
&& Tools::isSubmit('export' . $helperListConfiguration->table)
) {
$start = $this->context->cookie->{$helperListConfiguration->listId . '_start'};
}
// Either save or reset the offset in the cookie
if ($start) {
$this->context->cookie->{$helperListConfiguration->listId . '_start'} = $start;
} elseif (isset($this->context->cookie->{$helperListConfiguration->listId . '_start'})) {
unset($this->context->cookie->{$helperListConfiguration->listId . '_start'});
}
// Add SQL shop restriction
$select_shop = '';
if ($helperListConfiguration->shopLinkType) {
$select_shop = ', shop.name as shop_name ';
}
if ($helperListConfiguration->multishopContext && Shop::isTableAssociated($helperListConfiguration->table) && !empty($helperListConfiguration->objectModelClassName)) {
if (Shop::getContext() != Shop::CONTEXT_ALL || !$this->userProvider->getUser()->getData()->isSuperAdmin()) {
$helperListConfiguration->where .= ' AND EXISTS (
SELECT 1
FROM `' . _DB_PREFIX_ . $helperListConfiguration->table . '_shop` sa
WHERE a.`' . bqSQL($helperListConfiguration->identifier) . '` = sa.`' . bqSQL($helperListConfiguration->identifier) . '`
AND sa.id_shop IN (' . implode(', ', Shop::getContextListShopID()) . ')
)';
}
}
$fromClause = $this->getFromClause($helperListConfiguration);
$joinClause = $this->getJoinClause($helperListConfiguration, $idLang);
$whereClause = $this->getWhereClause($helperListConfiguration);
$orderByClause = $this->getOrderByClause($helperListConfiguration, $helperListConfiguration->orderBy, $helperListConfiguration->orderWay);
$shouldLimitSqlResults = $this->shouldLimitSqlResults($limit);
do {
$helperListConfiguration->listsql = '';
if ($helperListConfiguration->explicitSelect) {
foreach ($helperListConfiguration->fieldsList as $key => $array_value) {
if (preg_match('/[\s]`?' . preg_quote($key, '/') . '`?\s*,/', $helperListConfiguration->select)) {
continue;
}
if (isset($array_value['filter_key'])) {
$helperListConfiguration->listsql .= str_replace('!', '.`', $array_value['filter_key']) . '` AS `' . $key . '`, ';
} elseif ($key == 'id_' . $helperListConfiguration->table) {
$helperListConfiguration->listsql .= 'a.`' . bqSQL($key) . '`, ';
} elseif ($key != 'image' && !preg_match('/' . preg_quote($key, '/') . '/i', $helperListConfiguration->select)) {
$helperListConfiguration->listsql .= '`' . bqSQL($key) . '`, ';
}
}
$helperListConfiguration->listsql = rtrim(trim($helperListConfiguration->listsql), ',');
} else {
$helperListConfiguration->listsql .= ($helperListConfiguration->isJoinLanguageTableAuto ? 'b.*,' : '') . ' a.*';
}
$helperListConfiguration->listsql .= "\n" . (!empty($helperListConfiguration->select) ? ', ' . rtrim($helperListConfiguration->select, ', ') : '') . $select_shop;
$limitClause = ' ' . (($shouldLimitSqlResults) ? ' LIMIT ' . (int) $start . ', ' . (int) $limit : '');
if ($helperListConfiguration->useFoundRows) {
$helperListConfiguration->listsql = 'SELECT SQL_CALC_FOUND_ROWS ' .
$helperListConfiguration->listsql .
$fromClause .
$joinClause .
$whereClause .
$orderByClause .
$limitClause;
$list_count = 'SELECT FOUND_ROWS() AS `' . _DB_PREFIX_ . $helperListConfiguration->table . '`';
} else {
$helperListConfiguration->listsql = 'SELECT ' .
$helperListConfiguration->listsql .
$fromClause .
$joinClause .
$whereClause .
$orderByClause .
$limitClause;
$list_count = 'SELECT COUNT(*) AS `' . _DB_PREFIX_ . $helperListConfiguration->table . '` ' .
$fromClause .
$joinClause .
$whereClause;
}
$helperListConfiguration->list = Db::getInstance()->executeS($helperListConfiguration->listsql, true, false);
if ($helperListConfiguration->list === false) {
$helperListConfiguration->listError = Db::getInstance()->getMsgError();
break;
}
$helperListConfiguration->listTotal = (int) Db::getInstance()->getValue($list_count, false);
if ($shouldLimitSqlResults) {
$start = (int) $start - (int) $limit;
if ($start < 0) {
break;
}
} else {
break;
}
} while (empty($this->_list));
$this->hookDispatcher->dispatchWithParameters('action' . $helperListConfiguration->legacyControllerName . 'ListingResultsModifier', [
'list' => &$helperListConfiguration->list,
'list_total' => &$helperListConfiguration->listTotal,
]);
}
/**
* @param HelperListConfiguration $helperListConfiguration
* @param string|null $limit
*
* @return int
*/
private function checkSqlLimit(HelperListConfiguration $helperListConfiguration, ?string $limit = null): int
{
if (empty($limit)) {
if (
isset($this->context->cookie->{$helperListConfiguration->listId . '_pagination'}) &&
$this->context->cookie->{$helperListConfiguration->listId . '_pagination'}
) {
$limit = $this->context->cookie->{$helperListConfiguration->listId . '_pagination'};
} else {
$limit = $helperListConfiguration->defaultPagination;
}
}
$limit = (int) Tools::getValue($helperListConfiguration->listId . '_pagination', $limit);
if (in_array($limit, $helperListConfiguration->pagination) && $limit != $helperListConfiguration->defaultPagination) {
$this->context->cookie->{$helperListConfiguration->listId . '_pagination'} = $limit;
} else {
unset($this->context->cookie->{$helperListConfiguration->listId . '_pagination'});
}
if (!is_numeric($limit)) {
throw new PrestaShopException('Invalid limit. It should be a numeric.');
}
return $limit;
}
/**
* @param HelperListConfiguration $helperListConfiguration
*
* @return string
*/
private function getFromClause(HelperListConfiguration $helperListConfiguration)
{
$sqlTable = $helperListConfiguration->table == 'order' ? 'orders' : $helperListConfiguration->table;
return "\n" . 'FROM `' . _DB_PREFIX_ . $sqlTable . '` a ';
}
/**
* @param HelperListConfiguration $helperListConfiguration
* @param int $idLang
* @param int|bool $idLangShop
*
* @return string
*/
private function getJoinClause(HelperListConfiguration $helperListConfiguration, $idLang, $idLangShop = false)
{
$shopJoinClause = '';
if ($helperListConfiguration->shopLinkType) {
$shopJoinClause = ' LEFT JOIN `' . _DB_PREFIX_ . bqSQL($helperListConfiguration->shopLinkType) . '` shop
ON a.`id_' . bqSQL($helperListConfiguration->shopLinkType) . '` = shop.`id_' . bqSQL($helperListConfiguration->shopLinkType) . '`';
}
return "\n" . $this->getLanguageJoinClause($helperListConfiguration, $idLang, $idLangShop) .
"\n" . $helperListConfiguration->join . ' ' .
"\n" . $shopJoinClause;
}
/**
* @param HelperListConfiguration $helperListConfiguration
* @param int $idLang
* @param int $idLangShop
*
* @return string
*/
private function getLanguageJoinClause(HelperListConfiguration $helperListConfiguration, $idLang, $idLangShop)
{
$languageJoinClause = '';
if ($helperListConfiguration->isJoinLanguageTableAuto) {
$languageJoinClause = 'LEFT JOIN `' . _DB_PREFIX_ . bqSQL($helperListConfiguration->table) . '_lang` b
ON (b.`' . bqSQL($helperListConfiguration->identifier) . '` = a.`' . bqSQL($helperListConfiguration->identifier) . '` AND b.`id_lang` = ' . (int) $idLang;
if ($idLangShop) {
if (!Shop::isFeatureActive()) {
$languageJoinClause .= ' AND b.`id_shop` = ' . (int) $this->configuration->get('PS_SHOP_DEFAULT');
} elseif (Shop::getContext() == Shop::CONTEXT_SHOP) {
$languageJoinClause .= ' AND b.`id_shop` = ' . (int) $idLangShop;
} else {
$languageJoinClause .= ' AND b.`id_shop` = a.id_shop_default';
}
}
$languageJoinClause .= ')';
}
return $languageJoinClause;
}
/**
* @param HelperListConfiguration $helperListConfiguration
*
* @return string
*/
private function getWhereClause(HelperListConfiguration $helperListConfiguration): string
{
$whereShop = '';
if ($helperListConfiguration->shopLinkType) {
//$whereShop = Shop::addSqlRestriction($this->shopShareDatas, 'a');
$whereShop = Shop::addSqlRestriction(false, 'a');
}
return ' WHERE 1 ' . $helperListConfiguration->where . ' ' .
($helperListConfiguration->deleted ? 'AND a.`deleted` = 0 ' : '') .
$helperListConfiguration->filter . $whereShop . "\n" .
$helperListConfiguration->group . ' ' . "\n" .
$this->getHavingClause();
}
/**
* @return string
*/
private function getHavingClause(): string
{
$havingClause = '';
if (isset($this->_filterHaving) || isset($this->_having)) {
$havingClause = ' HAVING ';
if (isset($this->_filterHaving)) {
$havingClause .= ltrim($this->_filterHaving, ' AND ');
}
if (isset($this->_having)) {
$havingClause .= $this->_having . ' ';
}
}
return $havingClause;
}
/**
* @param HelperListConfiguration $helperListConfiguration
* @param string $orderBy
* @param string $orderDirection
*
* @return string
*/
private function getOrderByClause(HelperListConfiguration $helperListConfiguration, $orderBy, $orderDirection)
{
$helperListConfiguration->orderBy = $this->checkOrderBy($helperListConfiguration, $orderBy);
$helperListConfiguration->orderWay = $this->checkOrderDirection($helperListConfiguration, $orderDirection);
return ' ORDER BY '
. ((str_replace('`', '', $helperListConfiguration->orderBy) == $helperListConfiguration->identifier) ? 'a.' : '')
. $helperListConfiguration->orderBy
. ' '
. $helperListConfiguration->orderWay;
}
/**
* @param HelperListConfiguration $helperListConfiguration
* @param string $orderBy
*
* @return false|string
*/
private function checkOrderBy(HelperListConfiguration $helperListConfiguration, $orderBy)
{
if (empty($orderBy)) {
$prefix = FilterPrefix::getByClassName($helperListConfiguration->legacyControllerName);
if ($this->context->cookie->{$prefix . $helperListConfiguration->listId . 'Orderby'}) {
$orderBy = $this->context->cookie->{$prefix . $helperListConfiguration->listId . 'Orderby'};
} elseif ($helperListConfiguration->orderBy) {
$orderBy = $helperListConfiguration->orderBy;
} else {
$orderBy = $helperListConfiguration->defaultOrderBy;
}
}
/* Check params validity */
if (!Validate::isOrderBy($orderBy)) {
throw new PrestaShopException('Invalid "order by" clause.');
}
if (!isset($helperListConfiguration->fieldsList[$orderBy]['order_key']) && isset($helperListConfiguration->fieldsList[$orderBy]['filter_key'])) {
$helperListConfiguration->fieldsList[$orderBy]['order_key'] = $helperListConfiguration->fieldsList[$orderBy]['filter_key'];
}
if (isset($helperListConfiguration->fieldsList[$orderBy]['order_key'])) {
$orderBy = $helperListConfiguration->fieldsList[$orderBy]['order_key'];
}
if (preg_match('/[.!]/', $orderBy)) {
$orderBySplit = preg_split('/[.!]/', $orderBy);
$orderBy = bqSQL($orderBySplit[0]) . '.`' . bqSQL($orderBySplit[1]) . '`';
} elseif ($orderBy) {
$orderBy = bqSQL($orderBy);
}
return $orderBy;
}
/**
* @param HelperListConfiguration $helperListConfiguration
* @param string $orderDirection
*
* @return mixed|string
*/
private function checkOrderDirection(HelperListConfiguration $helperListConfiguration, $orderDirection)
{
$prefix = FilterPrefix::getByClassName($helperListConfiguration->legacyControllerName);
if (empty($orderDirection)) {
if ($this->context->cookie->{$prefix . $helperListConfiguration->listId . 'Orderway'}) {
$orderDirection = $this->context->cookie->{$prefix . $helperListConfiguration->listId . 'Orderway'};
} elseif ($helperListConfiguration->orderWay) {
$orderDirection = $helperListConfiguration->orderWay;
} else {
$orderDirection = $helperListConfiguration->defaultOrderWay;
}
}
if (!Validate::isOrderWay($orderDirection)) {
throw new PrestaShopException('Invalid order direction.');
}
return pSQL(Tools::strtoupper($orderDirection));
}
/**
* @param int $limit
*
* @return bool
*/
private function shouldLimitSqlResults($limit): bool
{
return $limit !== false;
}
}