// Context part 10

This commit is contained in:
rMalie
2011-07-18 15:27:32 +00:00
parent bc5d36821d
commit e16a8ab8d3
24 changed files with 375 additions and 304 deletions
+16 -14
View File
@@ -861,7 +861,7 @@ abstract class AdminTabCore
}
if (!sizeof($assos))
return;
Db::getInstance()->Execute('DELETE FROM '._DB_PREFIX_.$this->table.'_group_shop'.($id_object ? ' WHERE id_object='.(int)$id_object : ''));
Db::getInstance()->Execute('DELETE FROM '._DB_PREFIX_.$this->table.'_group_shop'.($id_object ? ' WHERE `'.$this->identifier.'`='.(int)$id_object : ''));
foreach ($assos AS $asso)
Db::getInstance()->Execute('INSERT INTO '._DB_PREFIX_.$this->table.'_group_shop(`'.pSQL($this->identifier).'`, id_group_shop)
VALUES('.(int)$asso['id_object'].', '.(int)$asso['id_group_shop'].')');
@@ -1170,25 +1170,28 @@ abstract class AdminTabCore
ON a.id_'.$this->shopLinkType.' = shop.id_'.$this->shopLinkType;
$whereShop = Shop::sqlRestriction($this->shopShareDatas, 'a', null, null, $this->shopLinkType);
}
$filterShop = '';
if ($context->shop->getContextType() != Shop::CONTEXT_ALL)
if (Context::shop() != Shop::CONTEXT_ALL)
{
if ($context->shop->getContextType() == Shop::CONTEXT_SHOP)
$assos = Shop::getAssoTables();
if (isset($assos[$this->table]) && $assos[$this->table]['type'] == 'shop')
{
$assos = Shop::getAssoTables();
if (isset($assos[$this->table]) AND $assos[$this->table]['type'] == 'shop')
$filterKey = $assos[$this->table]['type'];
$idenfierShop = $context->shop->getID();
$filterKey = $assos[$this->table]['type'];
$idenfierShop = Shop::getListFromContext();
}
elseif ($context->shop->getContextType() == Shop::CONTEXT_GROUP)
else if (Context::shop() == Shop::CONTEXT_GROUP)
{
$assos = GroupShop::getAssoTables();
if (isset($assos[$this->table]) AND $assos[$this->table]['type'] == 'group_shop')
{
$filterKey = $assos[$this->table]['type'];
$idenfierShop = $context->shop->getGroupID();
$idenfierShop = array($context->shop->getGroupID());
}
}
if (isset($filterKey))
$filterShop = 'JOIN `'._DB_PREFIX_.$this->table.'_'.$filterKey.'` sa ON (sa.'.$this->identifier.' = a.'.$this->identifier.' AND sa.id_'.$filterKey.'='.(int)$idenfierShop.')';
$filterShop = 'JOIN `'._DB_PREFIX_.$this->table.'_'.$filterKey.'` sa ON (sa.'.$this->identifier.' = a.'.$this->identifier.' AND sa.id_'.$filterKey.' IN ('.implode(', ', $idenfierShop).'))';
}
/* Query in order to get results with all fields */
@@ -1206,7 +1209,6 @@ abstract class AdminTabCore
ORDER BY '.(($orderBy == $this->identifier) ? 'a.' : '').'`'.pSQL($orderBy).'` '.pSQL($orderWay).
($this->_tmpTableFilter ? ') tmpTable WHERE 1'.$this->_tmpTableFilter : '').'
LIMIT '.(int)($start).','.(int)($limit);
//p($sql);
$this->_list = Db::getInstance()->ExecuteS($sql);
$this->_listTotal = Db::getInstance()->getValue('SELECT FOUND_ROWS() AS `'._DB_PREFIX_.$this->table.'`');
@@ -1691,7 +1693,7 @@ abstract class AdminTabCore
if (!Validate::isCleanHtml($val))
$val = Configuration::get($key);
$isDisabled = (isset($field['visibility']) && $field['visibility'] > $context->shop->getContextType()) ? true : false;
$isDisabled = (Tools::isMultiShopActivated() && isset($field['visibility']) && $field['visibility'] > $context->shop->getContextType()) ? true : false;
echo $this->getHtmlDefaultConfigurationValue($key, $this->_languages);
echo '<label>'.$field['title'].' </label>
@@ -2021,7 +2023,7 @@ abstract class AdminTabCore
$html = '<table class="table" cellpadding="0" cellspacing="0">
<tr><th>'.$this->l('Shop').'</th><th>'.$this->l('Association').'</th></tr>';
foreach ($shops AS $shop)
$html .= '<tr><td>'.$shop['name'].'</td><td><input type="checkbox" name="checkBoxShopAsso_'.$this->table.'_'.$this->_object->id.'_'.$shop['id_shop'].'" id="checkedBox_'.$shop['id_shop'].'" '.(((isset($assos[$shop['id_shop']]) AND in_array($this->_object->id, $assos[$shop['id_shop']])) || !$this->_object->id) ? 'checked="checked"' : '').'></td></tr>';
$html .= '<tr><td>'.$shop['name'].'</td><td><input type="checkbox" name="checkBoxShopAsso_'.$this->table.'_'.$this->_object->id.'_'.$shop['id_shop'].'" id="checkedBox_'.$shop['id_shop'].'" '.(((isset($assos[$shop['id_shop']]) AND in_array($this->_object->id, $assos[$shop['id_shop']])) || !$this->_object->id) ? 'checked="checked"' : '').'></td></tr>';
$html .= '</table>';
}
echo $html;
@@ -2081,7 +2083,7 @@ abstract class AdminTabCore
$html = '<table class="table" cellpadding="0" cellspacing="0">
<tr><th>'.$this->l('Shop').'</th><th>'.$this->l('Association').'</th></tr>';
foreach ($groups_shop as $group_shop)
$html .= '<tr><td>'.$group_shop['name'].'</td><td><input type="checkbox" name="checkBoxGroupShopAsso_'.$this->table.'_'.$this->_object->id.'_'.$group_shop['id_group_shop'].'" id="checkedBox_'.$group_shop['id_group_shop'].'" '.((isset($assos[$group_shop['id_group_shop']]) AND in_array($this->id, $assos[$group_shop['id_group_shop']])) ? 'checked="checked"' : '').'></td></tr>';
$html .= '<tr><td>'.$group_shop['name'].'</td><td><input type="checkbox" name="checkBoxGroupShopAsso_'.$this->table.'_'.$this->_object->id.'_'.$group_shop['id_group_shop'].'" id="checkedBox_'.$group_shop['id_group_shop'].'" '.(((isset($assos[$group_shop['id_group_shop']]) AND in_array($this->_object->id, $assos[$group_shop['id_group_shop']])) || !$this->_object->id) ? 'checked="checked"' : '').'></td></tr>';
$html .= '</table>';
}
echo $html;
+18 -17
View File
@@ -348,7 +348,7 @@ class CartCore extends ObjectModel
SELECT cp.`id_product_attribute`, cp.`id_product`, cu.`id_customization`, cp.`quantity` AS cart_quantity, cu.`quantity` AS customization_quantity, pl.`name`,
pl.`description_short`, pl.`available_now`, pl.`available_later`, p.`id_product`, p.`id_category_default`, p.`id_supplier`, p.`id_manufacturer`, p.`on_sale`, p.`ecotax`, p.`additional_shipping_cost`, p.`available_for_order`,
p.`price`, p.`weight`, p.`width`, p.`height`, p.`depth`, p.`out_of_stock`, p.`active`, p.`date_add`, p.`date_upd`, IFNULL(pa.`minimal_quantity`, p.`minimal_quantity`) as minimal_quantity,
t.`id_tax`, tl.`name` AS tax, t.`rate`, pa.`price` AS price_attribute, s.quantity,
t.`id_tax`, tl.`name` AS tax, t.`rate`, pa.`price` AS price_attribute, stock.quantity,
pa.`ecotax` AS ecotax_attr, i.`id_image`, il.`legend`, pl.`link_rewrite`, cl.`link_rewrite` AS category, CONCAT(cp.`id_product`, cp.`id_product_attribute`) AS unique_id,
IF (IFNULL(pa.`reference`, \'\') = \'\', p.`reference`, pa.`reference`) AS reference,
IF (IFNULL(pa.`supplier_reference`, \'\') = \'\', p.`supplier_reference`, pa.`supplier_reference`) AS supplier_reference,
@@ -378,7 +378,7 @@ class CartCore extends ObjectModel
)
LEFT JOIN `'._DB_PREFIX_.'image_lang` il ON (i.`id_image` = il.`id_image` AND il.`id_lang` = '.(int)$this->id_lang.')
LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON (p.`id_category_default` = cl.`id_category` AND cl.`id_lang` = '.(int)$this->id_lang.')
LEFT JOIN '._DB_PREFIX_.'stock s ON cp.id_product = s.id_product AND cp.id_product_attribute = s.id_product_attribute '.Shop::sqlSharedStock('s').'
'.Product::sqlStock('cp', 'cp').'
WHERE cp.`id_cart` = '.(int)$this->id.'
'.($id_product ? ' AND cp.`id_product` = '.(int)$id_product : '').'
AND p.`id_product` IS NOT NULL
@@ -533,13 +533,15 @@ class CartCore extends ObjectModel
* @param integer $id_product_attribute Attribute ID if needed
* @param string $operator Indicate if quantity must be increased or decreased
*/
public function updateQty($quantity, $id_product, $id_product_attribute = NULL, $id_customization = false, $operator = 'up', $id_shop = NULL, $id_group_shop = NULL)
public function updateQty($quantity, $id_product, $id_product_attribute = NULL, $id_customization = false, $operator = 'up', Context $context = null)
{
if (is_null($id_shop)) $id_shop = Context::getContext()->shop->getID();
if (!$context)
$context = Context::getContext();
$quantity = (int)$quantity;
$id_product = (int)$id_product;
$id_product_attribute = (int)$id_product_attribute;
$product = new Product($id_product, false, Configuration::get('PS_LANG_DEFAULT'), $id_shop);
$product = new Product($id_product, false, Configuration::get('PS_LANG_DEFAULT'), $context->shop->getID());
/* If we have a product combination, the minimal quantity is set with the one of this combination */
if (!empty($id_product_attribute))
@@ -568,12 +570,10 @@ class CartCore extends ObjectModel
{
if ($operator == 'up')
{
$sql = 'SELECT p.out_of_stock, s.quantity
$sql = 'SELECT p.out_of_stock, stock.quantity
FROM '._DB_PREFIX_.'product p
LEFT JOIN '._DB_PREFIX_.'stock s ON s.id_product = p.id_product
WHERE s.id_product = '.$id_product.'
AND s.id_product_attribute = '.$id_product_attribute
.Shop::sqlSharedStock('s', $id_shop, $id_group_shop);
'.Product::sqlStock('p', $id_product_attribute, true, $context).'
WHERE p.id_product = '.$id_product;
$result2 = Db::getInstance()->getRow($sql);
$productQty = (int)$result2['quantity'];
$newQty = (int)$result['quantity'] + (int)$quantity;
@@ -611,12 +611,10 @@ class CartCore extends ObjectModel
/* Add product to the cart */
else
{
$sql = 'SELECT p.out_of_stock, s.quantity
$sql = 'SELECT p.out_of_stock, stock.quantity
FROM '._DB_PREFIX_.'product p
LEFT JOIN '._DB_PREFIX_.'stock s ON s.id_product = p.id_product
WHERE s.id_product = '.$id_product.'
AND s.id_product_attribute = '.$id_product_attribute
.Shop::sqlSharedStock('s', $id_shop, $id_group_shop);
'.Product::sqlStock('p', $id_product_attribute, true, $context).'
WHERE p.id_product = '.$id_product;
$result2 = Db::getInstance()->getRow($sql);
if (!Product::isAvailableWhenOutOfStock((int)$result2['out_of_stock']))
if ((int)$quantity > $result2['quantity'])
@@ -1602,9 +1600,12 @@ class CartCore extends ObjectModel
return false;
$success = true;
$products = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS('SELECT * FROM `'._DB_PREFIX_.'cart_product` WHERE `id_cart` = '.(int)$this->id);
$newContext = Context::cloneContext();
$newContext->shop = new Shop($cart->id_shop);
foreach ($products AS $product)
$success &= $cart->updateQty($product['quantity'], (int)$product['id_product'], (int)$product['id_product_attribute'], NULL, 'up', (int)$cart->id_shop, (int)$cart->id_group_shop);
$success &= $cart->updateQty($product['quantity'], (int)$product['id_product'], (int)$product['id_product_attribute'], NULL, 'up', $newContext);
// Customized products
$customs = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS('
SELECT *
+16 -25
View File
@@ -451,18 +451,13 @@ class CategoryCore extends ObjectModel
* @param boolean $checkAccess set to false to return all products (even if customer hasn't access)
* @return mixed Products or number of products
*/
public function getProducts($id_lang, $p, $n, $orderBy = NULL, $orderWay = NULL, $getTotal = false, $active = true, $random = false, $randomNumberProducts = 1, $checkAccess = true, $id_shop = null, $context = null)
public function getProducts($id_lang, $p, $n, $orderBy = NULL, $orderWay = NULL, $getTotal = false, $active = true, $random = false, $randomNumberProducts = 1, $checkAccess = true, $context = null)
{
if (!$context)
$context = Context::getContext();
if (!$checkAccess OR !$this->checkAccess($context->customer->id))
return false;
if (!$id_shop)
$id_shop_lang = (int)Configuration::get('PS_SHOP_DEFAULT');
else
$id_shop_lang = (int)$id_shop;
if ($p < 1) $p = 1;
if (empty($orderBy))
@@ -498,24 +493,23 @@ class CategoryCore extends ObjectModel
{
$sql = 'SELECT COUNT(cp.`id_product`) AS total
FROM `'._DB_PREFIX_.'product` p
'.($id_shop ? 'LEFT JOIN '._DB_PREFIX_.'product_shop ps ON (ps.id_product = p.id_product)' : '').'
'.Shop::sqlAsso('product', 'p', $context).'
LEFT JOIN `'._DB_PREFIX_.'category_product` cp ON p.`id_product` = cp.`id_product`
WHERE cp.`id_category` = '.(int)($this->id).
($active ? ' AND p.`active` = 1' : '').
($id_shop ? ' AND ps.id_shop='.(int)$id_shop : '').
($id_supplier ? 'AND p.id_supplier = '.(int)($id_supplier) : '');
return (int)Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($sql);
}
$sql = 'SELECT p.*, s.quantity, pa.`id_product_attribute`, pl.`description`, pl.`description_short`, pl.`available_now`, pl.`available_later`, pl.`link_rewrite`, pl.`meta_description`, pl.`meta_keywords`, pl.`meta_title`, pl.`name`, i.`id_image`, il.`legend`, m.`name` AS manufacturer_name, tl.`name` AS tax_name, t.`rate`, cl.`name` AS category_default, DATEDIFF(p.`date_add`, DATE_SUB(NOW(), INTERVAL '.(Validate::isUnsignedInt(Configuration::get('PS_NB_DAYS_NEW_PRODUCT')) ? Configuration::get('PS_NB_DAYS_NEW_PRODUCT') : 20).' DAY)) > 0 AS new,
$sql = 'SELECT p.*, stock.quantity, pa.`id_product_attribute`, pl.`description`, pl.`description_short`, pl.`available_now`, pl.`available_later`, pl.`link_rewrite`, pl.`meta_description`, pl.`meta_keywords`, pl.`meta_title`, pl.`name`, i.`id_image`, il.`legend`, m.`name` AS manufacturer_name, tl.`name` AS tax_name, t.`rate`, cl.`name` AS category_default, DATEDIFF(p.`date_add`, DATE_SUB(NOW(), INTERVAL '.(Validate::isUnsignedInt(Configuration::get('PS_NB_DAYS_NEW_PRODUCT')) ? Configuration::get('PS_NB_DAYS_NEW_PRODUCT') : 20).' DAY)) > 0 AS new,
(p.`price` * IF(t.`rate`,((100 + (t.`rate`))/100),1)) AS orderprice
FROM `'._DB_PREFIX_.'category_product` cp
LEFT JOIN `'._DB_PREFIX_.'product` p ON p.`id_product` = cp.`id_product`
'.($id_shop ? 'LEFT JOIN '._DB_PREFIX_.'product_shop ps ON (ps.id_product = p.id_product)' : '').'
LEFT JOIN `'._DB_PREFIX_.'product_attribute` pa ON (p.`id_product` = pa.`id_product` AND default_on = 1)
LEFT JOIN '._DB_PREFIX_.'stock s ON s.id_product = p.id_product AND s.id_product_attribute = IFNULL(pa.id_product_attribute, 0) '.Shop::sqlSharedStock('s', $id_shop).'
LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON (p.`id_category_default` = cl.`id_category` AND cl.`id_lang` = '.(int)$id_lang.' AND cl.`id_shop` = '.(int)$id_shop_lang.')
LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (p.`id_product` = pl.`id_product` AND pl.`id_lang` = '.(int)$id_lang.' AND pl.`id_shop` = '.(int)$id_shop_lang.')
'.Shop::sqlAsso('product', 'p', $context).'
'.Product::sqlStock('p', 'pa', false, $context).'
LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON (p.`id_category_default` = cl.`id_category` AND cl.`id_lang` = '.(int)$id_lang.Shop::sqlLang('cl', $context).')
LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (p.`id_product` = pl.`id_product` AND pl.`id_lang` = '.(int)$id_lang.Shop::sqlLang('pl', $context).')
LEFT JOIN `'._DB_PREFIX_.'image` i ON (i.`id_product` = p.`id_product` AND i.`cover` = 1)
LEFT JOIN `'._DB_PREFIX_.'image_lang` il ON (i.`id_image` = il.`id_image` AND il.`id_lang` = '.(int)$id_lang.')
LEFT JOIN `'._DB_PREFIX_.'tax_rule` tr ON (p.`id_tax_rules_group` = tr.`id_tax_rules_group`
@@ -526,8 +520,7 @@ class CategoryCore extends ObjectModel
LEFT JOIN `'._DB_PREFIX_.'manufacturer` m ON m.`id_manufacturer` = p.`id_manufacturer`
WHERE cp.`id_category` = '.(int)($this->id)
.($active ? ' AND p.`active` = 1' : '')
.($id_supplier ? ' AND p.id_supplier = '.(int)$id_supplier : '')
.($id_shop ? ' AND ps.id_shop='.(int)$id_shop : '');
.($id_supplier ? ' AND p.id_supplier = '.(int)$id_supplier : '');
if ($random === true)
{
$sql .= ' ORDER BY RAND()';
@@ -576,11 +569,11 @@ class CategoryCore extends ObjectModel
static public function getRootCategory($id_lang = NULL, $id_shop = false, $context = null)
{
if (!$id_shop)
$id_shop = Configuration::get('PS_SHOP_DEFAULT');
$shop = new Shop($id_shop);
if (!$context)
$context = Context::getContext();
$shop = new Shop($context->shop->getID(true));
return new Category ($shop->id_category, is_null($id_lang) ? $context->language->id : $id_lang);
return new Category($shop->getCategory(), is_null($id_lang) ? $context->language->id : $id_lang);
}
/**
@@ -724,21 +717,19 @@ class CategoryCore extends ObjectModel
return $context->link->getCategoryLink($this->id, $this->link_rewrite);
}
public function getName($id_lang = NULL, $id_shop = false, $context = null)
public function getName($id_lang = NULL, $context = null)
{
if (!$id_shop)
$id_shop = Context::getContext()->shop->getID();
if (!$id_lang)
{
if (!$context)
$context = Context::getContext();
if (isset($this->name[(int)$id_shop][$context->language->id]))
if (isset($this->name[$context->language->id]))
$id_lang = $context->language->id;
else
$id_lang = (int)(Configuration::get('PS_LANG_DEFAULT'));
}
return isset($this->name[(int)$id_shop][$id_lang]) ? $this->name[(int)$id_shop][$id_lang] : '';
return isset($this->name[$id_lang]) ? $this->name[$id_lang] : '';
}
/**
+44 -72
View File
@@ -30,90 +30,42 @@
*/
class ContextCore
{
/**
* @var Context
*/
/** @var Context */
protected static $instance;
/**
* @var Cart
*/
/** @var Cart */
public $cart;
/**
* @var Customer
*/
/** @var Customer */
public $customer;
/**
* @var Cookie
*/
/** @var Cookie */
public $cookie;
/**
* @var Link
*/
/** @var Link */
public $link;
/**
* @var Country
*/
/** @var Country */
public $country;
/**
* @var Employee
*/
/** @var Employee */
public $employee;
/**
* @var Controller
*/
/** @var Controller */
public $controller;
/**
* @var Language
*/
/** @var Language */
public $language;
/**
* @var Currency
*/
/** @var Currency */
public $currency;
/**
* @var AdminTab
*/
/** @var AdminTab */
public $tab;
/**
* @var Shop
*/
/** @var Shop */
public $shop;
/**
* Create a context without singleton constraint
*/
public function __construct($cart = null,
$customer = null,
$cookie = null,
$link = null,
$country = null,
$employee = null,
$language = null,
$currency = null,
$tab = null)
{
$this->cart = $cart;
$this->customer = $customer;
$this->cookie = $cookie;
$this->link = $link;
$this->country = $country;
$this->employee = $employee;
$this->language = $language;
$this->currency = $currency;
$this->tab = $tab;
}
/**
* Get a singleton context
*
@@ -122,7 +74,27 @@ class ContextCore
public static function getContext()
{
if (!isset(self::$instance))
self::$instance = new self();
self::$instance = new Context();
return self::$instance;
}
/**
* Clone current context (
*
* @return Context
*/
public function cloneContext()
{
return clone($this);
}
/**
* @return int Shop context type (Shop::CONTEXT_ALL, etc.)
*/
public static function shop()
{
if (!self::$instance->shop->getContextType())
return Shop::CONTEXT_ALL;
return self::$instance->shop->getContextType();
}
}
+1 -1
View File
@@ -75,7 +75,7 @@ abstract class DbCore
* Get Db object instance (Singleton)
*
* @param boolean $master Decides wether the connection to be returned by the master server or the slave server
* @return object Db instance
* @return Db instance
*/
public static function getInstance($master = 1)
{
+56 -32
View File
@@ -35,6 +35,8 @@ abstract class ObjectModelCore
protected $id_shop = NULL;
private $getShopFromContext = true;
/** @var string SQL Table name */
protected $table = NULL;
@@ -116,11 +118,16 @@ abstract class ObjectModelCore
$this->id_lang = $id_lang;
elseif ($id_lang != NULL)
die(Tools::displayError());
if ($this->langMultiShop AND $id_shop == NULL)
$id_shop = Context::getContext()->shop->getID();
if ($id_shop AND $this->langMultiShop)
$this->id_shop = $id_shop;
if ($id_shop && $this->langMultiShop)
{
$this->id_shop = (int)$id_shop;
$this->getShopFromContext = false;
}
if ($this->langMultiShop && !$this->id_shop)
$this->id_shop = Context::getContext()->shop->getID(true);
/* Connect to database and check SQL table/identifier */
if (!Validate::isTableOrIdentifier($this->identifier) OR !Validate::isTableOrIdentifier($this->table))
die(Tools::displayError());
@@ -130,12 +137,15 @@ abstract class ObjectModelCore
if ($id)
{
if (!isset(self::$_cache[$this->table][(int)$id][(int)$id_shop][(int)$id_lang]))
self::$_cache[$this->table][(int)($id)][(int)$id_shop][(int)$id_lang] = $db->getRow('
SELECT *
FROM `'._DB_PREFIX_.$this->table.'` a '.
($id_lang ? ('LEFT JOIN `'.pSQL(_DB_PREFIX_.$this->table).'_lang` b ON (a.`'.$this->identifier.'` = b.`'.$this->identifier).'` AND `id_lang` = '.(int)($id_lang).')' : '')
.' WHERE 1 AND a.`'.$this->identifier.'` = '.(int)$id.
(($this->langMultiShop AND $id_shop AND $id_lang) ? ' AND b.id_shop='.(int)$id_shop : ''));
{
$sql = 'SELECT *
FROM `'._DB_PREFIX_.$this->table.'` a '.
($id_lang ? ('LEFT JOIN `'.pSQL(_DB_PREFIX_.$this->table).'_lang` b ON (a.`'.$this->identifier.'` = b.`'.$this->identifier).'` AND `id_lang` = '.(int)($id_lang).')' : '')
.' WHERE 1 AND a.`'.$this->identifier.'` = '.(int)$id.
(($this->id_shop AND $id_lang) ? ' AND b.id_shop='.$this->id_shop : '');
self::$_cache[$this->table][(int)($id)][(int)$id_shop][(int)$id_lang] = $db->getRow($sql);
}
$result = self::$_cache[$this->table][(int)$id][(int)$id_shop][(int)$id_lang];
if ($result)
{
@@ -146,9 +156,10 @@ abstract class ObjectModelCore
if (!$id_lang AND method_exists($this, 'getTranslationsFieldsChild'))
{
$result = $db->ExecuteS('SELECT * FROM `'.pSQL(_DB_PREFIX_.$this->table).'_lang`
WHERE `'.$this->identifier.'` = '.(int)$id
.(($this->langMultiShop AND $id_shop) ? ' AND `id_shop`='.(int)$id_shop : ''));
$sql = 'SELECT * FROM `'.pSQL(_DB_PREFIX_.$this->table).'_lang`
WHERE `'.$this->identifier.'` = '.(int)$id
.(($this->id_shop) ? ' AND `id_shop` = '.$this->id_shop : '');
$result = $db->ExecuteS($sql);
if ($result)
foreach ($result as $row)
foreach ($row AS $key => $value)
@@ -157,8 +168,7 @@ abstract class ObjectModelCore
{
if (!is_array($this->{$key}))
$this->{$key} = array();
else
$this->{$key}[$row['id_lang']] = stripslashes($value);
$this->{$key}[$row['id_lang']] = stripslashes($value);
}
}
}
@@ -224,17 +234,17 @@ abstract class ObjectModelCore
if (!Validate::isTableOrIdentifier($key))
die(Tools::displayError());
$field[$this->identifier] = (int)$this->id;
$result = Db::getInstance()->AutoExecute(_DB_PREFIX_.$this->table.'_lang', $field, 'INSERT') && $result;
if (isset($assos[$this->table.'_lang']) && $assos[$this->table.'_lang']['type'] == 'fk_shop')
{
foreach ($shops as $id_shop)
{
if ($this->id_shop == (int)$id_shop)
continue;
$field['id_shop'] = (int)$id_shop;
$result = Db::getInstance()->AutoExecute(_DB_PREFIX_.$this->table.'_lang', $field, 'INSERT') && $result;
$result &= Db::getInstance()->AutoExecute(_DB_PREFIX_.$this->table.'_lang', $field, 'INSERT');
}
}
else
$result &= Db::getInstance()->AutoExecute(_DB_PREFIX_.$this->table.'_lang', $field, 'INSERT');
}
}
@@ -252,7 +262,7 @@ abstract class ObjectModelCore
/**
* Update current object to database
*
* return boolean Update result
* @return boolean Update result
*/
public function update($nullValues = false)
{
@@ -283,20 +293,34 @@ abstract class ObjectModelCore
foreach ($field as $key => $value)
if (!Validate::isTableOrIdentifier($key))
die(Tools::displayError());
// If this table is linked to multishop system, update / insert for all shops from context
if ($this->langMultiShop)
$field['id_shop'] = ($this->id_shop ? $this->id_shop : Context::getContext()->shop->getID());
{
$listShops = ($this->id_shop && !$this->getShopFromContext) ? array($this->id_shop) : Shop::getListFromContext();
foreach ($listShops as $shop)
{
$field['id_shop'] = $shop;
$where = pSQL($this->identifier).' = '.(int)$this->id
.' AND id_lang = '.(int)$field['id_lang']
.' AND id_shop = '.$field['id_shop'];
// used to insert missing lang entries
$where_lang = '`'.pSQL($this->identifier).'` = '.(int)$this->id.
' AND `id_lang` = '.(int)$field['id_lang'].
(($this->langMultiShop AND $this->id_shop) ? ' AND `id_shop`='.$this->id_shop : '');
$lang_found = Db::getInstance()->getValue('SELECT COUNT(*) FROM `'.pSQL(_DB_PREFIX_.$this->table).'_lang` WHERE '. $where_lang);
if (!$lang_found)
$result &= Db::getInstance()->AutoExecute(_DB_PREFIX_.$this->table.'_lang', $field, 'INSERT');
if (Db::getInstance()->getValue('SELECT COUNT(*) FROM '.pSQL(_DB_PREFIX_.$this->table).'_lang WHERE '.$where))
$result &= Db::getInstance()->AutoExecute(_DB_PREFIX_.$this->table.'_lang', $field, 'UPDATE', $where);
else
$result &= Db::getInstance()->AutoExecute(_DB_PREFIX_.$this->table.'_lang', $field, 'INSERT');
}
}
// If this table is not linked to multishop system ...
else
$result &= Db::getInstance()->AutoExecute(_DB_PREFIX_.$this->table.'_lang', $field, 'UPDATE', $where_lang);
{
$where = pSQL($this->identifier).' = '.(int)$this->id
.' AND id_lang = '.(int)$field['id_lang'];
if (Db::getInstance()->getValue('SELECT COUNT(*) FROM '.pSQL(_DB_PREFIX_.$this->table).'_lang WHERE '.$where))
$result &= Db::getInstance()->AutoExecute(_DB_PREFIX_.$this->table.'_lang', $field, 'UPDATE', $where);
else
$result &= Db::getInstance()->AutoExecute(_DB_PREFIX_.$this->table.'_lang', $field, 'INSERT');
}
}
}
}
+42 -17
View File
@@ -390,7 +390,7 @@ class ProductCore extends ObjectModel
{
$fields[$language['id_lang']]['id_lang'] = $language['id_lang'];
$fields[$language['id_lang']][$this->identifier] = (int)($this->id);
$fields[$language['id_lang']]['id_shop'] = (int)$this->id_shop;
$fields[$language['id_lang']]['id_shop'] = (int)$this->id_shop; // @todo ID shop in product ???
$fields[$language['id_lang']]['description'] = (isset($this->description[$language['id_lang']])) ? pSQL($this->description[$language['id_lang']], true) : '';
$fields[$language['id_lang']]['description_short'] = (isset($this->description_short[$language['id_lang']])) ? pSQL($this->description_short[$language['id_lang']], true) : '';
foreach ($fieldsArray as $field)
@@ -507,9 +507,9 @@ class ProductCore extends ObjectModel
{
$sql = 'SELECT pa.id_product_attribute
FROM '._DB_PREFIX_.'product_attribute pa'
.($minimumQuantity > 0 ? ' LEFT JOIN '._DB_PREFIX_.'stock s ON s.id_product = pa.id_product AND pa.id_product_attribute = s.id_product_attribute '.Shop::sqlSharedStock('s') : '').
.($minimumQuantity > 0 ? Product::sqlStock('pa', 'pa') : '').
' WHERE pa.default_on = 1 '
.($minimumQuantity > 0 ? ' AND s.quantity >= '.(int)$minimumQuantity : '').
.($minimumQuantity > 0 ? ' AND stock.quantity >= '.(int)$minimumQuantity : '').
' AND pa.id_product = '.(int)$id_product;
$result = Db::getInstance()->getRow($sql);
@@ -517,7 +517,7 @@ class ProductCore extends ObjectModel
{
$sql = 'SELECT pa.id_product_attribute
FROM '._DB_PREFIX_.'product_attribute pa'
.($minimumQuantity > 0 ? ' LEFT JOIN '._DB_PREFIX_.'stock s ON s.id_product = pa.id_product AND pa.id_product_attribute = s.id_product_attribute '.Shop::sqlSharedStock('s') : '').
.($minimumQuantity > 0 ? Product::sqlStock('pa', 'pa') : '').
' WHERE pa.id_product = '.(int)$id_product
.($minimumQuantity > 0 ? ' AND s.quantity >= '.(int)$minimumQuantity : '');
$result = Db::getInstance()->getRow($sql);
@@ -1490,12 +1490,12 @@ class ProductCore extends ObjectModel
* @param boolean $count Only in order to get total number (optional)
* @return array Prices drop
*/
public static function getPricesDrop($id_lang, $pageNumber = 0, $nbProducts = 10, $count = false, $orderBy = NULL, $orderWay = NULL, $beginning = false, $ending = false, $id_shop = null)
public static function getPricesDrop($id_lang, $pageNumber = 0, $nbProducts = 10, $count = false, $orderBy = NULL, $orderWay = NULL, $beginning = false, $ending = false, Context $context = null)
{
if (!Validate::isBool($count))
die(Tools::displayError());
if (is_null($id_shop)) $id_shop = Context::getContext()->shop->getID();
if (is_null($context)) $context = Context::getContext();
if ($pageNumber < 0) $pageNumber = 0;
if ($nbProducts < 1) $nbProducts = 10;
if (empty($orderBy) || $orderBy == 'position') $orderBy = 'price';
@@ -1516,9 +1516,8 @@ class ProductCore extends ObjectModel
{
$sql = 'SELECT COUNT(DISTINCT p.`id_product`) AS nb
FROM `'._DB_PREFIX_.'product` p
LEFT JOIN '._DB_PREFIX_.'product_shop ps ON (ps.id_product = p.id_product)
'.Shop::sqlAsso('product', 'p', $context).'
WHERE p.`active` = 1
AND ps.id_shop='.(int)$id_shop.'
AND p.`show_price` = 1
'.((!$beginning AND !$ending) ? ' AND p.`id_product` IN('.((is_array($ids_product) AND sizeof($ids_product)) ? implode(', ', $ids_product) : 0).')' : '').'
AND p.`id_product` IN (
@@ -1536,8 +1535,8 @@ class ProductCore extends ObjectModel
DATEDIFF(p.`date_add`, DATE_SUB(NOW(), INTERVAL '.(Validate::isUnsignedInt(Configuration::get('PS_NB_DAYS_NEW_PRODUCT')) ? Configuration::get('PS_NB_DAYS_NEW_PRODUCT') : 20).' DAY)) > 0 AS new
FROM `'._DB_PREFIX_.'product` p
LEFT JOIN '._DB_PREFIX_.'product_shop ps ON (ps.id_product = p.id_product)
LEFT JOIN '._DB_PREFIX_.'stock s ON p.id_product = s.id_product AND s.id_product_attribute = 0 '.Shop::sqlSharedStock('s', $id_shop).'
LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (p.`id_product` = pl.`id_product` AND pl.`id_lang` = '.(int)$id_lang.' AND pl.id_shop = '.(int)$id_shop.')
'.Shop::sqlAsso('product', 'p', $context).'
LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (p.`id_product` = pl.`id_product` AND pl.`id_lang` = '.(int)$id_lang.Shop::sqlLang('pl', $context).')
LEFT JOIN `'._DB_PREFIX_.'image` i ON (i.`id_product` = p.`id_product` AND i.`cover` = 1)
LEFT JOIN `'._DB_PREFIX_.'image_lang` il ON (i.`id_image` = il.`id_image` AND il.`id_lang` = '.(int)$id_lang.')
LEFT JOIN `'._DB_PREFIX_.'tax_rule` tr ON (p.`id_tax_rules_group` = tr.`id_tax_rules_group`
@@ -1546,7 +1545,6 @@ class ProductCore extends ObjectModel
LEFT JOIN `'._DB_PREFIX_.'tax` t ON (t.`id_tax` = tr.`id_tax`)
LEFT JOIN `'._DB_PREFIX_.'manufacturer` m ON (m.`id_manufacturer` = p.`id_manufacturer`)
WHERE p.`active` = 1
AND ps.id_shop = '.(int)$id_shop.'
AND p.`show_price` = 1
'.((!$beginning AND !$ending) ? ' AND p.`id_product` IN ('.((is_array($ids_product) AND sizeof($ids_product)) ? implode(', ', $ids_product) : 0).')' : '').'
AND p.`id_product` IN (
@@ -2046,6 +2044,33 @@ class ProductCore extends ObjectModel
return $product->getStock($id_product_attribute);
}
/**
* Create JOIN query with 'stock' table
*
* @param string $productAlias Alias of product table
* @param string|int $productAttribute If string : alias of PA table ; if int : value of PA ; if null : nothing about PA
* @param bool $innerJoin LEFT JOIN or INNER JOIN
* @param Context $context
* @return string
*/
public static function sqlStock($productAlias, $productAttribute = 0, $innerJoin = false, Context $context = null)
{
if (!$context)
$context = Context::getContext();
$sql = (($innerJoin) ? ' INNER ' : ' LEFT ').'JOIN '._DB_PREFIX_.'stock stock ON stock.id_product = '.pSQL($productAlias).'.id_product';
if (!is_null($productAttribute))
{
if (is_numeric($productAttribute))
$sql .= ' AND stock.id_product_attribute = '.$productAttribute;
else if (is_string($productAttribute))
$sql .= ' AND stock.id_product_attribute = '.pSQL($productAttribute).'.id_product_attribute';
}
$sql .= Shop::sqlSharedStock('stock', $context) . ' ';
return $sql;
}
/**
* Set the stock quantity of current product
*
@@ -2088,7 +2113,7 @@ class ProductCore extends ObjectModel
// Change stock quantity on product attribute
if ($id_product_attribute)
{
if ($id_stock = Stock::getStockId($this->id, $id_product_attribute, $shop->getID()))
if ($id_stock = Stock::getStockId($this->id, $id_product_attribute, $shop->getID(true)))
{
$sql = 'UPDATE '._DB_PREFIX_.'stock
SET quantity = '.(($update) ? 'quantity + '. $quantity : $quantity).'
@@ -2106,7 +2131,7 @@ class ProductCore extends ObjectModel
}
// Change stock quantity on product
if ($id_stock = Stock::getStockId($this->id, $id_product_attribute, $shop->getID()))
if ($id_stock = Stock::getStockId($this->id, $id_product_attribute, $shop->getID(true)))
{
$sql = 'UPDATE '._DB_PREFIX_.'stock
SET quantity = '.(($update) ? 'quantity + '. $quantity : $quantity).'
@@ -2142,7 +2167,7 @@ class ProductCore extends ObjectModel
FROM '._DB_PREFIX_.'stock
WHERE id_product = '.$this->id.'
AND id_product_attribute = '.(int)$id_product_attribute
.Shop::sqlSharedStock();
.Shop::sqlSharedStock('', $context);
return (int)Db::getInstance()->getValue($sql);
}
@@ -2260,9 +2285,9 @@ class ProductCore extends ObjectModel
public function getAttributesGroups($id_lang)
{
$sql = 'SELECT ag.`id_attribute_group`, ag.`is_color_group`, agl.`name` AS group_name, agl.`public_name` AS public_group_name, a.`id_attribute`, al.`name` AS attribute_name,
a.`color` AS attribute_color, pa.`id_product_attribute`, s.quantity, pa.`price`, pa.`ecotax`, pa.`weight`, pa.`default_on`, pa.`reference`, pa.`unit_price_impact`, pa.`minimal_quantity`
a.`color` AS attribute_color, pa.`id_product_attribute`, stock.quantity, pa.`price`, pa.`ecotax`, pa.`weight`, pa.`default_on`, pa.`reference`, pa.`unit_price_impact`, pa.`minimal_quantity`
FROM `'._DB_PREFIX_.'product_attribute` pa
LEFT JOIN '._DB_PREFIX_.'stock s ON s.id_product = pa.id_product AND s.id_product_attribute = pa.id_product_attribute '.Shop::sqlSharedStock('s').'
'.Product::sqlStock('pa', 'pa').'
LEFT JOIN `'._DB_PREFIX_.'product_attribute_combination` pac ON pac.`id_product_attribute` = pa.`id_product_attribute`
LEFT JOIN `'._DB_PREFIX_.'attribute` a ON a.`id_attribute` = pac.`id_attribute`
LEFT JOIN `'._DB_PREFIX_.'attribute_group` ag ON ag.`id_attribute_group` = a.`id_attribute_group`
@@ -3154,7 +3179,7 @@ class ProductCore extends ObjectModel
// Add a new stock movement
$stockMvt = new StockMvt();
$stockMvt->id_stock = Stock::getStockId($this->id, $id_product_attribute, $this->id_shop);
$stockMvt->id_stock = Stock::getStockId($this->id, $id_product_attribute, Context::getContext()->shop->getID(true));
$stockMvt->id_product = $this->id;
$stockMvt->id_product_attribute = (int)$id_product_attribute;
$stockMvt->id_order = (int)$id_order;
+122 -69
View File
@@ -252,7 +252,7 @@ class ShopCore extends ObjectModel
public function getGroup($asObject = false)
{
if (!$this->group)
$this->group = new GroupShop($this->id_group_shop);
$this->group = new GroupShop($this->getGroupID());
return $this->group;
}
@@ -261,11 +261,11 @@ class ShopCore extends ObjectModel
*
* @return int
*/
public function getID()
public function getID($useDefault = false)
{
return (int)$this->id;
return (!$this->id && $useDefault) ? (int)Configuration::get('PS_SHOP_DEFAULT') : (int)$this->id;
}
/**
* Get current shop group ID
*
@@ -273,6 +273,8 @@ class ShopCore extends ObjectModel
*/
public function getGroupID()
{
if (defined('PS_ADMIN_DIR'))
return Shop::getContextGroupID();
return (int)$this->id_group_shop;
}
@@ -281,9 +283,9 @@ class ShopCore extends ObjectModel
*
* @return int
*/
public function getRootCategory()
public function getCategory()
{
return $this->id_category;
return ($this->id_category) ? $this->id_category : 1;
}
/**
@@ -296,10 +298,10 @@ class ShopCore extends ObjectModel
$sql = 'SELECT *
FROM '._DB_PREFIX.'shop_url
WHERE active = 1
AND id_shop='.(int)$this->id;
AND id_shop = '.(int)$this->id;
return Db::getInstance()->ExecuteS($sql);
}
/**
* Check if current shop ID is the same as default shop in configuration
*
@@ -438,60 +440,6 @@ class ShopCore extends ObjectModel
return array_keys($groupData['shops']);
return array($shopID);
}
/**
* Retrieve the current shop context in FO or BO
*
* @param string null|shop|group
* @param bool If true, this method will return default shop ID if no shop was found in context (for BO)
* @return array(id_shop, id_group_shop)|int
*/
public static function getContext($type = null, $useDefault = false)
{
static $executed = false, $shopID = 0, $shopGroupID = 0;
if (!$executed)
{
$context = Context::getContext();
if (defined('PS_ADMIN_DIR'))
{
// While cookie is not instancied in admin, we wait ...
if (!isset($context->cookie))
return ($type == 'shop' || $type == 'group') ? '' : array('', '');
// Parse shopContext cookie value (E.g. s-2, g-4)
$split = explode('-', Context::getContext()->cookie->shopContext);
$shopID = $shopGroupID = '';
if (count($split) == 2)
{
if ($split[0] == 's')
$shopID = (int)$split[1];
else if ($split[0] == 'g')
$shopGroupID = (int)$split[1];
if ($shopID && !$shopGroupID)
$shopGroupID = Shop::getGroupFromShop($shopID);
}
}
else
{
$shopID = $context->shop->getID();
$shopGroupID = $context->shop->getGroupID();
}
$executed = true;
}
if ($useDefault && !$shopID)
$shopID = Configuration::get('PS_SHOP_DEFAULT');
if ($useDefault && !$shopGroupID)
$shopID = Shop::getGroupFromShop(Configuration::get('PS_SHOP_DEFAULT'));
if ($type == 'shop')
return $shopID;
else if ($type == 'group')
return $shopGroupID;
return array($shopID, $shopGroupID);
}
/**
* Get a list of ID concerned by the shop context (E.g. if context is shop group, get list of children shop ID)
@@ -513,15 +461,84 @@ class ShopCore extends ObjectModel
return $list;
}
/**
* Retrieve the current shop context in FO or BO
*
* @param string null|shop|group
* @return array(id_shop, id_group_shop)|int
*/
public static function getContext($type = null)
{
static $executed = false, $shopID = 0, $shopGroupID = 0;
if (!$executed)
{
$context = Context::getContext();
if (defined('PS_ADMIN_DIR'))
{
// While cookie is not instancied in admin, we wait ...
if (!isset($context->cookie))
return ($type == 'shop' || $type == 'group') ? '' : array('', '');
// Parse shopContext cookie value (E.g. s-2, g-4)
$split = explode('-', Context::getContext()->cookie->shopContext);
if (count($split) == 2)
{
if ($split[0] == 's')
$shopID = (int)$split[1];
else if ($split[0] == 'g')
$shopGroupID = (int)$split[1];
if ($shopID && !$shopGroupID)
$shopGroupID = Shop::getGroupFromShop($shopID);
}
}
else
{
$shopID = (int)$context->shop->id_shop;
$shopGroupID = (int)$context->shop->id_group_shop;
}
$executed = true;
}
if ($type == 'shop')
return $shopID;
else if ($type == 'group')
return $shopGroupID;
return array($shopID, $shopGroupID);
}
/**
* Get ID shop from context
*
* @return int
*/
public static function getContextID()
{
return Shop::getContext('shop');
}
/**
* Get ID shop from context
*
* @return int
*/
public static function getContextGroupID()
{
return Shop::getContext('group');
}
/**
* Get a list of ID concerned by the shop context (E.g. if context is shop group, get list of children shop ID)
*
* @param Context $context
* @return array
*/
public static function getListFromContext()
public static function getListFromContext(Context $context = null)
{
list($shopID, $shopGroupID) = Shop::getContext();
return Shop::getListOfID($shopID, $shopGroupID);
if (!$context)
$context = Context::getContext();
return Shop::getListOfID($context->shop->getID(), $context->shop->getGroupID());
}
/**
@@ -569,14 +586,15 @@ class ShopCore extends ObjectModel
return $restriction;
}
public static function sqlSharedStock($alias = null, $shopID = null, $shopGroupID = null)
public static function sqlSharedStock($alias = null, Context $context = null)
{
if ($alias)
$alias .= '.';
if (!$context)
$context = Context::getContext();
if (is_null($shopID))
$shopID = Context::getContext()->shop->getID();
$shopID = $context->shop->getID();
$shopGroupID = $context->shop->getGroupID();
if (!$shopID)
return ($shopGroupID) ? ' AND '.$alias.'id_group_shop = '.(int)$shopGroupID : '';
@@ -586,6 +604,41 @@ class ShopCore extends ObjectModel
return ' AND '.$alias.'id_group_shop = '.$groupID;
return ' AND '.$alias.'id_shop = '.$shopID;
}
/**
* Add an SQL JOIN in query between a table and its associated table in multishop
*
* @param string $table Table name (E.g. product, module, etc.)
* @param string $alias Alias of table
* @param Context $context
* @return string
*/
public static function sqlAsso($table, $alias, Context $context = null)
{
if (!$context)
$context = Context::getContext();
$assoTables = Shop::getAssoTables();
if (!isset($assoTables[$table]) || $assoTables[$table]['type'] != 'shop')
return ;
$sql = ' LEFT JOIN '._DB_PREFIX_.$table.'_shop asso_shop_'.$table.'
ON asso_shop_'.$table.'.id_'.$table.' = '.$alias.'.id_'.$table.'
AND asso_shop_'.$table.'.id_shop IN('.implode(', ', Shop::getListFromContext($context)).') ';
return $sql;
}
/**
* Add a restriction on id_shop for multishop lang table
*
* @param string $alias
* @param Context $context
* @return string
*/
public static function sqlLang($alias, Context $context = null)
{
return ' AND '.$alias.'.id_shop = '.$context->shop->getID(true). ' ';
}
/**
* Get all groups and associated shops as subarrays
+3 -3
View File
@@ -54,13 +54,13 @@ class Stock extends ObjectModel
return $fields;
}
public static function getStockId($id_product, $id_product_attribute, $shopID = null)
public static function getStockId($id_product, $id_product_attribute, $shopID)
{
$sql = 'SELECT id_stock
FROM '._DB_PREFIX_.'stock
WHERE id_product = '.(int)$id_product.'
AND id_product_attribute = '.(int)$id_product_attribute
.Shop::sqlSharedStock('', $shopID);
AND id_product_attribute = '.(int)$id_product_attribute.'
AND id_shop = '.(int)$shopID;
return (int)Db::getInstance()->getValue($sql);
}
}
+1 -2
View File
@@ -90,14 +90,13 @@ class StockMvtCore extends ObjectModel
// Search missing stock movement on products without attributes
$sql = 'SELECT s.id_stock, (s.quantity - SUM(IFNULL(sm.quantity, 0))) AS qty
FROM '._DB_PREFIX_.'product p
INNER JOIN '._DB_PREFIX_.'stock s ON s.id_product = p.id_product
'.Product::sqlStock('p', null, true).'
LEFT JOIN '._DB_PREFIX_.'stock_mvt sm ON s.id_stock = sm.id_stock
WHERE (
SELECT COUNT(*) FROM '._DB_PREFIX_.'stock s2
WHERE s2.id_product = p.id_product
AND s2.id_product_attribute > 0
) = 0
'.Shop::sqlSharedStock('s').'
GROUP BY s.id_product, s.id_shop
HAVING qty <> 0';
$products_without_attributes = Db::getInstance()->ExecuteS($sql);