Files
newwalls.pl/modules/pp_carousel/pp_carousel.php

772 lines
30 KiB
PHP

<?php
if (!defined('_PS_VERSION_')) {
exit;
}
use PrestaShop\PrestaShop\Adapter\Image\ImageRetriever;
use PrestaShop\PrestaShop\Adapter\Product\PriceFormatter;
use PrestaShop\PrestaShop\Adapter\Product\ProductColorsRetriever;
use PrestaShop\PrestaShop\Core\Product\ProductListingPresenter;
class Pp_Carousel extends Module
{
public function __construct()
{
$this->name = 'pp_carousel';
$this->tab = 'front_office_features';
$this->version = '1.0.0';
$this->author = 'Project-Pro';
$this->author_uri = 'https://www.project-pro.pl';
$this->need_instance = 0;
$this->bootstrap = true;
parent::__construct();
$this->displayName = $this->l('Project-Pro Karuzela Produktów');
$this->description = $this->l('Wyświetla konfigurowalne karuzele produktów w dowolnych hookach.');
$this->ps_versions_compliancy = ['min' => '1.7.0.0', 'max' => _PS_VERSION_];
}
public function install()
{
return $this->executeSqlFile('install')
&& parent::install()
&& $this->registerHook('displayHeader')
&& $this->registerHook('displayHome')
&& $this->registerHook('displayFooterBefore')
&& $this->registerHook('displayTopColumn')
&& $this->registerHook('displayLeftColumn')
&& $this->registerHook('displayRightColumn')
&& $this->registerHook('displayFooter');
}
public function uninstall()
{
return $this->executeSqlFile('uninstall') && parent::uninstall();
}
private function executeSqlFile($filename)
{
$path = dirname(__FILE__) . '/sql/' . $filename . '.sql';
if (!file_exists($path)) {
return false;
}
$sql = file_get_contents($path);
$sql = str_replace('PREFIX_', _DB_PREFIX_, $sql);
$sql = str_replace('ENGINE_TYPE', _MYSQL_ENGINE_, $sql);
$queries = preg_split('/;\s*[\r\n]+/', $sql);
foreach ($queries as $query) {
$query = trim($query);
if (!empty($query)) {
if (!Db::getInstance()->execute($query)) {
return false;
}
}
}
return true;
}
// ─── ADMIN PANEL ────────────────────────────────────────────
public function getContent()
{
$output = '';
if (Tools::isSubmit('deletepp_carousel')) {
$output .= $this->deleteCarousel((int) Tools::getValue('id_carousel'));
}
if (Tools::isSubmit('statuspp_carousel')) {
$output .= $this->toggleCarouselStatus((int) Tools::getValue('id_carousel'));
}
if (Tools::isSubmit('submitPpCarousel')) {
$output .= $this->saveCarousel();
}
if (Tools::isSubmit('addpp_carousel') || Tools::isSubmit('updatepp_carousel') || Tools::getValue('id_carousel')) {
return $output . $this->renderForm((int) Tools::getValue('id_carousel'));
}
return $output . $this->renderList();
}
private function renderList()
{
$fieldsList = [
'id_carousel' => ['title' => 'ID', 'align' => 'center', 'class' => 'fixed-width-xs'],
'title' => ['title' => $this->l('Tytuł')],
'hook_name' => ['title' => $this->l('Hook')],
'source_type' => ['title' => $this->l('Źródło')],
'limit_products' => ['title' => $this->l('Limit'), 'align' => 'center', 'class' => 'fixed-width-xs'],
'active' => ['title' => $this->l('Aktywna'), 'active' => 'status', 'align' => 'center', 'class' => 'fixed-width-sm', 'type' => 'bool'],
];
$helper = new HelperList();
$helper->shopLinkType = '';
$helper->simple_header = false;
$helper->actions = ['edit', 'delete'];
$helper->identifier = 'id_carousel';
$helper->show_toolbar = true;
$helper->title = $this->l('Karuzele produktów');
$helper->table = $this->name;
$helper->token = Tools::getAdminTokenLite('AdminModules');
$helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name;
$helper->toolbar_btn['new'] = [
'href' => AdminController::$currentIndex . '&configure=' . $this->name . '&add' . $this->name . '&token=' . Tools::getAdminTokenLite('AdminModules'),
'desc' => $this->l('Dodaj karuzelę'),
];
return $helper->generateList($this->getCarouselList(), $fieldsList);
}
private function getCarouselList()
{
$idLang = (int) $this->context->language->id;
$sql = 'SELECT c.*, cl.title
FROM `' . _DB_PREFIX_ . 'pp_carousel` c
LEFT JOIN `' . _DB_PREFIX_ . 'pp_carousel_lang` cl
ON c.id_carousel = cl.id_carousel AND cl.id_lang = ' . $idLang . '
WHERE c.id_shop = ' . (int) $this->context->shop->id . '
ORDER BY c.position ASC, c.id_carousel ASC';
return Db::getInstance()->executeS($sql) ?: [];
}
private function renderForm($idCarousel = 0)
{
$carousel = $idCarousel ? $this->getCarousel($idCarousel) : [];
$defaultLang = (int) Configuration::get('PS_LANG_DEFAULT');
$langs = Language::getLanguages(false);
$categories = $this->flattenCategories(Category::getCategories($defaultLang, true, false));
$hookOptions = $this->getAvailableHooks();
$predefinedHookIds = array_column($hookOptions, 'id');
// Detect if saved hook_name is a custom hook
$savedHookName = isset($carousel['hook_name']) ? $carousel['hook_name'] : 'displayHome';
$isCustomHook = !empty($savedHookName) && !in_array($savedHookName, $predefinedHookIds);
$sourceOptions = [
['id' => 'new', 'name' => $this->l('Nowości')],
['id' => 'bestseller', 'name' => $this->l('Bestsellery')],
['id' => 'category', 'name' => $this->l('Produkty z kategorii')],
['id' => 'manual', 'name' => $this->l('Ręczne ID produktów')],
];
$fieldsForm = [
'form' => [
'legend' => [
'title' => $idCarousel ? $this->l('Edytuj karuzelę') : $this->l('Dodaj karuzelę'),
'icon' => 'icon-cogs',
],
'input' => [
[
'type' => 'hidden',
'name' => 'id_carousel',
],
[
'type' => 'select',
'label' => $this->l('Hook (miejsce wyświetlania)'),
'name' => 'hook_name',
'options' => ['query' => $hookOptions, 'id' => 'id', 'name' => 'name'],
'desc' => $this->l('Wybierz hook lub wpisz niestandardowy poniżej.'),
],
[
'type' => 'text',
'label' => $this->l('Niestandardowy hook'),
'name' => 'custom_hook',
'desc' => $this->l('Jeśli wypełnione, zostanie użyte zamiast wybranego powyżej. Hook zostanie utworzony automatycznie.'),
],
[
'type' => 'select',
'label' => $this->l('Źródło produktów'),
'name' => 'source_type',
'options' => ['query' => $sourceOptions, 'id' => 'id', 'name' => 'name'],
'id' => 'source_type_select',
],
[
'type' => 'select',
'label' => $this->l('Kategoria'),
'name' => 'id_category',
'options' => ['query' => $categories, 'id' => 'id', 'name' => 'name'],
'desc' => $this->l('Widoczne gdy źródło = "Produkty z kategorii".'),
'form_group_class' => 'pp-field-category',
],
[
'type' => 'textarea',
'label' => $this->l('ID produktów (ręczne)'),
'name' => 'product_ids',
'desc' => $this->l('ID produktów rozdzielone przecinkami, np. 12,45,67. Widoczne gdy źródło = "Ręczne ID".'),
'form_group_class' => 'pp-field-manual',
],
[
'type' => 'text',
'label' => $this->l('Limit produktów'),
'name' => 'limit_products',
'class' => 'fixed-width-sm',
],
[
'type' => 'text',
'label' => $this->l('Tytuł'),
'name' => 'title',
'lang' => true,
],
[
'type' => 'text',
'label' => $this->l('Podtytuł'),
'name' => 'subtitle',
'lang' => true,
],
[
'type' => 'text',
'label' => $this->l('Tekst przycisku'),
'name' => 'button_label',
'lang' => true,
],
[
'type' => 'text',
'label' => $this->l('URL przycisku'),
'name' => 'button_url',
'desc' => $this->l('Pozostaw puste, aby linkować do kategorii automatycznie.'),
],
[
'type' => 'text',
'label' => $this->l('Sufiks ceny'),
'name' => 'price_suffix',
'lang' => true,
'desc' => $this->l('Np. /m²'),
],
[
'type' => 'text',
'label' => $this->l('Pozycja'),
'name' => 'position',
'class' => 'fixed-width-sm',
],
[
'type' => 'switch',
'label' => $this->l('Aktywna'),
'name' => 'active',
'values' => [
['id' => 'active_on', 'value' => 1, 'label' => $this->l('Tak')],
['id' => 'active_off', 'value' => 0, 'label' => $this->l('Nie')],
],
],
],
'submit' => [
'title' => $this->l('Zapisz'),
'name' => 'submitPpCarousel',
],
],
];
$helper = new HelperForm();
$helper->show_toolbar = false;
$helper->table = $this->table;
$helper->module = $this;
$helper->default_form_language = $defaultLang;
$helper->allow_employee_form_lang = (int) Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG');
$helper->identifier = 'id_carousel';
$helper->submit_action = 'submitPpCarousel';
$helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name;
$helper->token = Tools::getAdminTokenLite('AdminModules');
$helper->languages = $this->context->controller->getLanguages();
$helper->id_language = (int) $this->context->language->id;
// Fill form values
$helper->fields_value['id_carousel'] = $idCarousel;
$helper->fields_value['hook_name'] = $isCustomHook ? 'displayHome' : $savedHookName;
$helper->fields_value['custom_hook'] = $isCustomHook ? $savedHookName : '';
$helper->fields_value['source_type'] = isset($carousel['source_type']) ? $carousel['source_type'] : 'new';
$helper->fields_value['id_category'] = isset($carousel['id_category']) ? (int) $carousel['id_category'] : 0;
$helper->fields_value['product_ids'] = isset($carousel['product_ids']) ? $carousel['product_ids'] : '';
$helper->fields_value['limit_products'] = isset($carousel['limit_products']) ? (int) $carousel['limit_products'] : 12;
$helper->fields_value['button_url'] = isset($carousel['button_url']) ? $carousel['button_url'] : '';
$helper->fields_value['position'] = isset($carousel['position']) ? (int) $carousel['position'] : 0;
$helper->fields_value['active'] = isset($carousel['active']) ? (int) $carousel['active'] : 1;
foreach ($langs as $lang) {
$id = (int) $lang['id_lang'];
$langData = $idCarousel ? $this->getCarouselLang($idCarousel, $id) : [];
$helper->fields_value['title'][$id] = isset($langData['title']) ? $langData['title'] : '';
$helper->fields_value['subtitle'][$id] = isset($langData['subtitle']) ? $langData['subtitle'] : '';
$helper->fields_value['button_label'][$id] = isset($langData['button_label']) ? $langData['button_label'] : '';
$helper->fields_value['price_suffix'][$id] = isset($langData['price_suffix']) ? $langData['price_suffix'] : '';
}
$formHtml = $helper->generateForm([$fieldsForm]);
// Inject JS for conditional field visibility
$formHtml .= $this->getAdminFormJs();
return $formHtml;
}
private function getAdminFormJs()
{
return '
<script>
(function() {
function toggleSourceFields() {
var val = document.querySelector("[name=source_type]").value;
var catRow = document.querySelector(".pp-field-category");
var manualRow = document.querySelector(".pp-field-manual");
if (catRow) catRow.style.display = (val === "category") ? "" : "none";
if (manualRow) manualRow.style.display = (val === "manual") ? "" : "none";
}
var sel = document.querySelector("[name=source_type]");
if (sel) {
sel.addEventListener("change", toggleSourceFields);
toggleSourceFields();
}
})();
</script>';
}
private function saveCarousel()
{
$idCarousel = (int) Tools::getValue('id_carousel');
$hookName = trim(Tools::getValue('custom_hook'));
if (empty($hookName)) {
$hookName = trim(Tools::getValue('hook_name'));
}
if (empty($hookName)) {
$hookName = 'displayHome';
}
$sourceType = Tools::getValue('source_type');
$idCategory = (int) Tools::getValue('id_category');
$productIds = trim(Tools::getValue('product_ids'));
$limitProducts = (int) Tools::getValue('limit_products');
$buttonUrl = trim(Tools::getValue('button_url'));
$position = (int) Tools::getValue('position');
$active = (int) Tools::getValue('active');
if ($limitProducts <= 0) {
$limitProducts = 12;
}
// Sanitize manual product IDs
if ($sourceType === 'manual' && $productIds) {
$ids = array_filter(array_map('intval', explode(',', $productIds)));
$productIds = implode(',', $ids);
}
$now = date('Y-m-d H:i:s');
$db = Db::getInstance();
if ($idCarousel > 0) {
$db->update('pp_carousel', [
'hook_name' => pSQL($hookName),
'source_type' => pSQL($sourceType),
'id_category' => $idCategory,
'product_ids' => pSQL($productIds),
'limit_products' => $limitProducts,
'button_url' => pSQL($buttonUrl),
'position' => $position,
'active' => $active,
'date_upd' => $now,
], 'id_carousel = ' . $idCarousel);
} else {
$db->insert('pp_carousel', [
'hook_name' => pSQL($hookName),
'source_type' => pSQL($sourceType),
'id_category' => $idCategory,
'product_ids' => pSQL($productIds),
'limit_products' => $limitProducts,
'button_url' => pSQL($buttonUrl),
'position' => $position,
'active' => $active,
'id_shop' => (int) $this->context->shop->id,
'date_add' => $now,
'date_upd' => $now,
]);
$idCarousel = (int) $db->Insert_ID();
}
// Save lang fields
$langs = Language::getLanguages(false);
foreach ($langs as $lang) {
$id = (int) $lang['id_lang'];
$title = Tools::substr(trim(Tools::getValue('title_' . $id)), 0, 255);
$subtitle = Tools::substr(trim(Tools::getValue('subtitle_' . $id)), 0, 255);
$buttonLabel = Tools::substr(trim(Tools::getValue('button_label_' . $id)), 0, 255);
$priceSuffix = Tools::substr(trim(Tools::getValue('price_suffix_' . $id)), 0, 64);
$exists = $db->getValue(
'SELECT COUNT(*) FROM `' . _DB_PREFIX_ . 'pp_carousel_lang`
WHERE id_carousel = ' . $idCarousel . ' AND id_lang = ' . $id
);
$langData = [
'title' => pSQL($title),
'subtitle' => pSQL($subtitle),
'button_label' => pSQL($buttonLabel),
'price_suffix' => pSQL($priceSuffix),
];
if ($exists) {
$db->update('pp_carousel_lang', $langData, 'id_carousel = ' . $idCarousel . ' AND id_lang = ' . $id);
} else {
$langData['id_carousel'] = $idCarousel;
$langData['id_lang'] = $id;
$db->insert('pp_carousel_lang', $langData);
}
}
// Register custom hook if needed
$this->ensureHookRegistered($hookName);
return $this->displayConfirmation($this->l('Karuzela została zapisana.'));
}
private function deleteCarousel($idCarousel)
{
if ($idCarousel <= 0) {
return '';
}
$db = Db::getInstance();
$db->delete('pp_carousel_lang', 'id_carousel = ' . $idCarousel);
$db->delete('pp_carousel', 'id_carousel = ' . $idCarousel);
return $this->displayConfirmation($this->l('Karuzela została usunięta.'));
}
private function toggleCarouselStatus($idCarousel)
{
if ($idCarousel <= 0) {
return '';
}
$current = (int) Db::getInstance()->getValue(
'SELECT active FROM `' . _DB_PREFIX_ . 'pp_carousel` WHERE id_carousel = ' . $idCarousel
);
Db::getInstance()->update('pp_carousel', [
'active' => $current ? 0 : 1,
], 'id_carousel = ' . $idCarousel);
return $this->displayConfirmation($this->l('Status karuzeli został zmieniony.'));
}
private function getCarousel($idCarousel)
{
return Db::getInstance()->getRow(
'SELECT * FROM `' . _DB_PREFIX_ . 'pp_carousel` WHERE id_carousel = ' . (int) $idCarousel
);
}
private function getCarouselLang($idCarousel, $idLang)
{
return Db::getInstance()->getRow(
'SELECT * FROM `' . _DB_PREFIX_ . 'pp_carousel_lang`
WHERE id_carousel = ' . (int) $idCarousel . ' AND id_lang = ' . (int) $idLang
) ?: [];
}
private function getAvailableHooks()
{
$hooks = [
'displayHome', 'displayTopColumn', 'displayFooterBefore',
'displayFooter', 'displayLeftColumn', 'displayRightColumn',
'displayOrderConfirmation2', 'displayCrossSellingShoppingCart',
];
$options = [];
foreach ($hooks as $h) {
$options[] = ['id' => $h, 'name' => $h];
}
return $options;
}
private function flattenCategories($tree, $depth = 0, &$out = [])
{
foreach ($tree as $node) {
if (!isset($node['id_category'], $node['name'])) {
continue;
}
$prefix = str_repeat('— ', max(0, $depth));
$out[] = [
'id' => (int) $node['id_category'],
'name' => $prefix . $node['name'],
];
if (!empty($node['children'])) {
$this->flattenCategories($node['children'], $depth + 1, $out);
}
}
return $out;
}
private function ensureHookRegistered($hookName)
{
$idHook = (int) Hook::getIdByName($hookName);
if (!$idHook) {
Db::getInstance()->insert('hook', [
'name' => pSQL($hookName),
'title' => pSQL($hookName),
]);
}
if (!$this->isRegisteredInHook($hookName)) {
$this->registerHook($hookName);
}
// Clear PrestaShop hook cache
if (Cache::isStored('hook_module_list')) {
Cache::clean('hook_module_list');
}
}
public function isRegisteredInHook($hookName)
{
$idHook = (int) Hook::getIdByName($hookName);
if (!$idHook) {
return false;
}
$count = (int) Db::getInstance()->getValue(
'SELECT COUNT(*) FROM `' . _DB_PREFIX_ . 'hook_module`
WHERE id_hook = ' . $idHook . ' AND id_module = ' . (int) $this->id
);
return $count > 0;
}
// ─── FRONT HOOKS ────────────────────────────────────────────
public function hookDisplayHeader()
{
$this->context->controller->registerStylesheet(
'pp_carousel_swiper_css',
'modules/' . $this->name . '/views/lib/swiper/swiper-bundle.min.css',
['media' => 'all', 'priority' => 150]
);
$this->context->controller->registerStylesheet(
'pp_carousel_css',
'modules/' . $this->name . '/views/css/pp_carousel.css',
['media' => 'all', 'priority' => 151]
);
$this->context->controller->registerJavascript(
'pp_carousel_swiper_js',
'modules/' . $this->name . '/views/lib/swiper/swiper-bundle.min.js',
['position' => 'bottom', 'priority' => 150]
);
$this->context->controller->registerJavascript(
'pp_carousel_js',
'modules/' . $this->name . '/views/js/pp_carousel.js',
['position' => 'bottom', 'priority' => 151]
);
}
public function hookDisplayHome($params)
{
return $this->renderCarouselsForHook('displayHome');
}
public function hookDisplayTopColumn($params)
{
return $this->renderCarouselsForHook('displayTopColumn');
}
public function hookDisplayFooterBefore($params)
{
return $this->renderCarouselsForHook('displayFooterBefore');
}
public function hookDisplayFooter($params)
{
return $this->renderCarouselsForHook('displayFooter');
}
public function hookDisplayLeftColumn($params)
{
return $this->renderCarouselsForHook('displayLeftColumn');
}
public function hookDisplayRightColumn($params)
{
return $this->renderCarouselsForHook('displayRightColumn');
}
/**
* Catch-all: render carousels for any hook not explicitly defined above.
*/
public function __call($method, $args)
{
if (strpos($method, 'hook') === 0) {
$hookName = lcfirst(substr($method, 4));
return $this->renderCarouselsForHook($hookName);
}
return '';
}
// ─── RENDERING ──────────────────────────────────────────────
private function renderCarouselsForHook($hookName)
{
$carousels = Db::getInstance()->executeS(
'SELECT c.*, cl.title, cl.subtitle, cl.button_label, cl.price_suffix
FROM `' . _DB_PREFIX_ . 'pp_carousel` c
LEFT JOIN `' . _DB_PREFIX_ . 'pp_carousel_lang` cl
ON c.id_carousel = cl.id_carousel AND cl.id_lang = ' . (int) $this->context->language->id . '
WHERE c.hook_name = "' . pSQL($hookName) . '"
AND c.active = 1
AND c.id_shop = ' . (int) $this->context->shop->id . '
ORDER BY c.position ASC, c.id_carousel ASC'
);
if (empty($carousels)) {
return '';
}
$html = '';
foreach ($carousels as $carousel) {
$products = $this->getProductsByCarousel($carousel);
if (empty($products)) {
continue;
}
$buttonUrl = trim($carousel['button_url']);
if (empty($buttonUrl) && $carousel['source_type'] === 'category' && $carousel['id_category'] > 0) {
$cat = new Category((int) $carousel['id_category'], (int) $this->context->language->id);
if (Validate::isLoadedObject($cat)) {
$buttonUrl = $this->context->link->getCategoryLink($cat);
}
}
$this->context->smarty->assign([
'ppc_id' => (int) $carousel['id_carousel'],
'ppc_title' => $carousel['title'] ?: '',
'ppc_subtitle' => $carousel['subtitle'] ?: '',
'ppc_button_label' => $carousel['button_label'] ?: '',
'ppc_button_url' => $buttonUrl,
'ppc_price_suffix' => $carousel['price_suffix'] ?: '',
'ppc_products' => $products,
]);
$html .= $this->fetch('module:' . $this->name . '/views/templates/hook/pp_carousel.tpl');
}
return $html;
}
// ─── PRODUCT SOURCES ────────────────────────────────────────
private function getProductsByCarousel($carousel)
{
$limit = (int) $carousel['limit_products'];
if ($limit <= 0) {
$limit = 12;
}
switch ($carousel['source_type']) {
case 'new':
return $this->getNewProducts($limit);
case 'bestseller':
return $this->getBestsellers($limit);
case 'category':
return $this->getCategoryProducts((int) $carousel['id_category'], $limit);
case 'manual':
return $this->getManualProducts($carousel['product_ids'], $limit);
default:
return [];
}
}
private function getNewProducts($limit)
{
$idLang = (int) $this->context->language->id;
$raw = Product::getNewProducts($idLang, 0, $limit);
return is_array($raw) ? $this->presentProducts($raw) : [];
}
private function getBestsellers($limit)
{
$idLang = (int) $this->context->language->id;
$raw = ProductSale::getBestSales($idLang, 0, $limit);
return is_array($raw) ? $this->presentProducts($raw) : [];
}
private function getCategoryProducts($idCategory, $limit)
{
if ($idCategory <= 0) {
return [];
}
$idLang = (int) $this->context->language->id;
$category = new Category($idCategory, $idLang);
if (!Validate::isLoadedObject($category)) {
return [];
}
$raw = $category->getProducts($idLang, 1, $limit, 'position', 'asc');
return is_array($raw) ? $this->presentProducts($raw) : [];
}
private function getManualProducts($productIdsStr, $limit)
{
if (empty($productIdsStr)) {
return [];
}
$ids = array_filter(array_map('intval', explode(',', $productIdsStr)));
if (empty($ids)) {
return [];
}
$idLang = (int) $this->context->language->id;
$idShop = (int) $this->context->shop->id;
$sql = 'SELECT p.*, pl.`name`, pl.`description_short`, pl.`link_rewrite`,
cl.`name` AS category_default, cl.`link_rewrite` AS category_link_rewrite,
i.`id_image`, il.`legend`,
m.`name` AS manufacturer_name,
p.`id_category_default`
FROM `' . _DB_PREFIX_ . 'product` p
LEFT JOIN `' . _DB_PREFIX_ . 'product_lang` pl
ON p.id_product = pl.id_product AND pl.id_lang = ' . $idLang . ' AND pl.id_shop = ' . $idShop . '
LEFT JOIN `' . _DB_PREFIX_ . 'category_lang` cl
ON p.id_category_default = cl.id_category AND cl.id_lang = ' . $idLang . ' AND cl.id_shop = ' . $idShop . '
LEFT JOIN `' . _DB_PREFIX_ . 'image` i
ON p.id_product = i.id_product AND i.cover = 1
LEFT JOIN `' . _DB_PREFIX_ . 'image_lang` il
ON i.id_image = il.id_image AND il.id_lang = ' . $idLang . '
LEFT JOIN `' . _DB_PREFIX_ . 'manufacturer` m
ON p.id_manufacturer = m.id_manufacturer
LEFT JOIN `' . _DB_PREFIX_ . 'product_shop` ps
ON p.id_product = ps.id_product AND ps.id_shop = ' . $idShop . '
WHERE p.id_product IN (' . implode(',', $ids) . ')
AND ps.active = 1
LIMIT ' . (int) $limit;
$raw = Db::getInstance()->executeS($sql);
return is_array($raw) ? $this->presentProducts($raw) : [];
}
private function presentProducts(array $rawProducts)
{
$assembler = new \ProductAssembler($this->context);
$presenterFactory = new \ProductPresenterFactory($this->context);
$presentationSettings = $presenterFactory->getPresentationSettings();
$presenter = $presenterFactory->getPresenter();
$products = [];
foreach ($rawProducts as $raw) {
try {
$assembled = $assembler->assembleProduct($raw);
$products[] = $presenter->present(
$presentationSettings,
$assembled,
$this->context->language
);
} catch (Exception $e) {
continue;
}
}
return $products;
}
}