PageRenderTime 67ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/modules/blocklayered/blocklayered.php

https://bitbucket.org/marcenuc/prestashop
PHP | 4229 lines | 3761 code | 362 blank | 106 comment | 598 complexity | eda597ac1a48f2650aec10c29cc20341 MD5 | raw file
Possible License(s): LGPL-2.1, LGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /*
  3. * 2007-2012 PrestaShop
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Academic Free License (AFL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/afl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@prestashop.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
  18. * versions in the future. If you wish to customize PrestaShop for your
  19. * needs please refer to http://www.prestashop.com for more information.
  20. *
  21. * @author PrestaShop SA <contact@prestashop.com>
  22. * @copyright 2007-2012 PrestaShop SA
  23. * @version Release: $Revision: 14437 $
  24. * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
  25. * International Registred Trademark & Property of PrestaShop SA
  26. */
  27. if (!defined('_PS_VERSION_'))
  28. exit;
  29. class BlockLayered extends Module
  30. {
  31. private $products;
  32. private $nbr_products;
  33. private $page = 1;
  34. public function __construct()
  35. {
  36. $this->name = 'blocklayered';
  37. $this->tab = 'front_office_features';
  38. $this->version = '1.8.9';
  39. $this->author = 'PrestaShop';
  40. $this->need_instance = 0;
  41. parent::__construct();
  42. $this->displayName = $this->l('Layered navigation block');
  43. $this->description = $this->l('Displays a block with layered navigation filters.');
  44. if ((int)Tools::getValue('p'))
  45. $this->page = (int)Tools::getValue('p');
  46. }
  47. public function install()
  48. {
  49. if (parent::install() && $this->registerHook('leftColumn') && $this->registerHook('header') && $this->registerHook('footer')
  50. && $this->registerHook('categoryAddition') && $this->registerHook('categoryUpdate') && $this->registerHook('attributeGroupForm')
  51. && $this->registerHook('afterSaveAttributeGroup') && $this->registerHook('afterDeleteAttributeGroup') && $this->registerHook('featureForm')
  52. && $this->registerHook('afterDeleteFeature') && $this->registerHook('afterSaveFeature') && $this->registerHook('categoryDeletion')
  53. && $this->registerHook('afterSaveProduct') && $this->registerHook('productListAssign') && $this->registerHook('postProcessAttributeGroup')
  54. && $this->registerHook('postProcessFeature') && $this->registerHook('featureValueForm') && $this->registerHook('postProcessFeatureValue')
  55. && $this->registerHook('afterDeleteFeatureValue') && $this->registerHook('afterSaveFeatureValue') && $this->registerHook('attributeForm')
  56. && $this->registerHook('postProcessAttribute') && $this->registerHook('afterDeleteAttribute') && $this->registerHook('afterSaveAttribute'))
  57. {
  58. Configuration::updateValue('PS_LAYERED_HIDE_0_VALUES', 1);
  59. Configuration::updateValue('PS_LAYERED_SHOW_QTIES', 1);
  60. Configuration::updateValue('PS_LAYERED_FULL_TREE', 1);
  61. Configuration::updateValue('PS_LAYERED_FILTER_PRICE_USETAX', 1);
  62. Configuration::updateValue('PS_LAYERED_FILTER_CATEGORY_DEPTH', 1);
  63. Configuration::updateValue('PS_LAYERED_FILTER_INDEX_QTY', 0);
  64. Configuration::updateValue('PS_LAYERED_FILTER_INDEX_CDT', 0);
  65. Configuration::updateValue('PS_LAYERED_FILTER_INDEX_MNF', 0);
  66. Configuration::updateValue('PS_LAYERED_FILTER_INDEX_CAT', 0);
  67. $this->rebuildLayeredStructure();
  68. $products_count = Db::getInstance()->getValue('SELECT COUNT(*) FROM `'._DB_PREFIX_.'product`');
  69. if ($products_count < 20000) // Lock template filter creation if too many products
  70. $this->rebuildLayeredCache();
  71. self::installPriceIndexTable();
  72. $this->installFriendlyUrlTable();
  73. $this->installIndexableAttributeTable();
  74. $this->installProductAttributeTable();
  75. if ($products_count < 5000) // Lock indexation if too many products
  76. {
  77. $this->indexUrl();
  78. $this->indexAttribute();
  79. self::fullPricesIndexProcess();
  80. }
  81. return true;
  82. }
  83. else
  84. {
  85. // Installation failed (or hook registration) => uninstall the module
  86. $this->uninstall();
  87. return false;
  88. }
  89. }
  90. public function uninstall()
  91. {
  92. /* Delete all configurations */
  93. Configuration::deleteByName('PS_LAYERED_HIDE_0_VALUES');
  94. Configuration::deleteByName('PS_LAYERED_SHOW_QTIES');
  95. Configuration::deleteByName('PS_LAYERED_FULL_TREE');
  96. Configuration::deleteByName('PS_LAYERED_INDEXED');
  97. Configuration::deleteByName('PS_LAYERED_FILTER_PRICE_USETAX');
  98. Configuration::deleteByName('PS_LAYERED_FILTER_CATEGORY_DEPTH');
  99. Configuration::deleteByName('PS_LAYERED_FILTER_INDEX_QTY');
  100. Configuration::deleteByName('PS_LAYERED_FILTER_INDEX_CDT');
  101. Configuration::deleteByName('PS_LAYERED_FILTER_INDEX_MNF');
  102. Configuration::deleteByName('PS_LAYERED_FILTER_INDEX_CAT');
  103. Db::getInstance()->execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'layered_price_index');
  104. Db::getInstance()->execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'layered_friendly_url');
  105. Db::getInstance()->execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'layered_indexable_attribute_group');
  106. Db::getInstance()->execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'layered_indexable_feature');
  107. Db::getInstance()->execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'layered_indexable_attribute_group_lang_value');
  108. Db::getInstance()->execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'layered_indexable_feature_lang_value');
  109. Db::getInstance()->execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'layered_category');
  110. Db::getInstance()->execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'layered_filter');
  111. Db::getInstance()->Execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'layered_filter_shop');
  112. Db::getInstance()->execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'layered_product_attribute');
  113. return parent::uninstall();
  114. }
  115. private static function installPriceIndexTable()
  116. {
  117. Db::getInstance()->execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.'layered_price_index`');
  118. Db::getInstance()->execute('
  119. CREATE TABLE `'._DB_PREFIX_.'layered_price_index` (
  120. `id_product` INT NOT NULL,
  121. `id_currency` INT NOT NULL,
  122. `id_shop` INT NOT NULL,
  123. `price_min` INT NOT NULL,
  124. `price_max` INT NOT NULL,
  125. PRIMARY KEY (`id_product`, `id_currency`, `id_shop`),
  126. INDEX `id_currency` (`id_currency`),
  127. INDEX `price_min` (`price_min`), INDEX `price_max` (`price_max`)
  128. ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;');
  129. }
  130. private function installFriendlyUrlTable()
  131. {
  132. Db::getInstance()->execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.'layered_friendly_url`');
  133. Db::getInstance()->execute('
  134. CREATE TABLE `'._DB_PREFIX_.'layered_friendly_url` (
  135. `id_layered_friendly_url` INT NOT NULL AUTO_INCREMENT,
  136. `url_key` varchar(32) NOT NULL,
  137. `data` varchar(200) NOT NULL,
  138. `id_lang` INT NOT NULL,
  139. PRIMARY KEY (`id_layered_friendly_url`),
  140. INDEX `id_lang` (`id_lang`)
  141. ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;');
  142. Db::getInstance()->execute('CREATE INDEX `url_key` ON `'._DB_PREFIX_.'layered_friendly_url`(url_key(5))');
  143. }
  144. private function installIndexableAttributeTable()
  145. {
  146. // Attributes Groups
  147. Db::getInstance()->execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.'layered_indexable_attribute_group`');
  148. Db::getInstance()->execute('
  149. CREATE TABLE `'._DB_PREFIX_.'layered_indexable_attribute_group` (
  150. `id_attribute_group` INT NOT NULL,
  151. `indexable` BOOL NOT NULL DEFAULT 0,
  152. PRIMARY KEY (`id_attribute_group`)
  153. ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;');
  154. Db::getInstance()->execute('
  155. INSERT INTO `'._DB_PREFIX_.'layered_indexable_attribute_group`
  156. SELECT id_attribute_group, 1 FROM `'._DB_PREFIX_.'attribute_group`');
  157. Db::getInstance()->execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.'layered_indexable_attribute_group_lang_value`');
  158. Db::getInstance()->execute('
  159. CREATE TABLE `'._DB_PREFIX_.'layered_indexable_attribute_group_lang_value` (
  160. `id_attribute_group` INT NOT NULL,
  161. `id_lang` INT NOT NULL,
  162. `url_name` VARCHAR(20),
  163. `meta_title` VARCHAR(20),
  164. PRIMARY KEY (`id_attribute_group`, `id_lang`)
  165. ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;');
  166. // Attributes
  167. Db::getInstance()->execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.'layered_indexable_attribute_lang_value`');
  168. Db::getInstance()->execute('
  169. CREATE TABLE `'._DB_PREFIX_.'layered_indexable_attribute_lang_value` (
  170. `id_attribute` INT NOT NULL,
  171. `id_lang` INT NOT NULL,
  172. `url_name` VARCHAR(20),
  173. `meta_title` VARCHAR(20),
  174. PRIMARY KEY (`id_attribute`, `id_lang`)
  175. ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;');
  176. // Features
  177. Db::getInstance()->execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.'layered_indexable_feature`');
  178. Db::getInstance()->execute('
  179. CREATE TABLE `'._DB_PREFIX_.'layered_indexable_feature` (
  180. `id_feature` INT NOT NULL,
  181. `indexable` BOOL NOT NULL DEFAULT 0,
  182. PRIMARY KEY (`id_feature`)
  183. ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;');
  184. Db::getInstance()->execute('
  185. INSERT INTO `'._DB_PREFIX_.'layered_indexable_feature`
  186. SELECT id_feature, 1 FROM `'._DB_PREFIX_.'feature`');
  187. Db::getInstance()->execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.'layered_indexable_feature_lang_value`');
  188. Db::getInstance()->execute('
  189. CREATE TABLE `'._DB_PREFIX_.'layered_indexable_feature_lang_value` (
  190. `id_feature` INT NOT NULL,
  191. `id_lang` INT NOT NULL,
  192. `url_name` VARCHAR(20) NOT NULL,
  193. `meta_title` VARCHAR(20),
  194. PRIMARY KEY (`id_feature`, `id_lang`)
  195. ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;');
  196. // Features values
  197. Db::getInstance()->execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.'layered_indexable_feature_value_lang_value`');
  198. Db::getInstance()->execute('
  199. CREATE TABLE `'._DB_PREFIX_.'layered_indexable_feature_value_lang_value` (
  200. `id_feature_value` INT NOT NULL,
  201. `id_lang` INT NOT NULL,
  202. `url_name` VARCHAR(20),
  203. `meta_title` VARCHAR(20),
  204. PRIMARY KEY (`id_feature_value`, `id_lang`)
  205. ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;');
  206. }
  207. /**
  208. *
  209. * create table product attribute
  210. */
  211. public function installProductAttributeTable()
  212. {
  213. Db::getInstance()->execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.'layered_product_attribute`');
  214. Db::getInstance()->execute('
  215. CREATE TABLE `'._DB_PREFIX_.'layered_product_attribute` (
  216. `id_attribute` int(10) unsigned NOT NULL,
  217. `id_product` int(10) unsigned NOT NULL,
  218. `id_attribute_group` int(10) unsigned NOT NULL DEFAULT "0",
  219. `id_shop` int(10) unsigned NOT NULL DEFAULT "1",
  220. KEY `id_attribute` (`id_attribute`)
  221. ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;');
  222. }
  223. /**
  224. *
  225. * Generate data product attribute
  226. */
  227. public function indexAttribute($id_product = null)
  228. {
  229. if (is_null($id_product))
  230. Db::getInstance()->execute('TRUNCATE '._DB_PREFIX_.'layered_product_attribute');
  231. else
  232. Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_product_attribute WHERE id_product = '.(int)$id_product);
  233. Db::getInstance()->execute('INSERT INTO `'._DB_PREFIX_.'layered_product_attribute` (`id_attribute`, `id_product`, `id_attribute_group`, `id_shop`)
  234. SELECT pac.id_attribute, pa.id_product, ag.id_attribute_group, '.(version_compare(_PS_VERSION_,'1.5','>') ? 'product_attribute_shop.`id_shop`' : '1').'
  235. FROM '._DB_PREFIX_.'product_attribute pa
  236. '.(version_compare(_PS_VERSION_,'1.5','>') ? Shop::addSqlAssociation('product_attribute', 'pa') : '').'
  237. INNER JOIN '._DB_PREFIX_.'product_attribute_combination pac ON pac.id_product_attribute = pa.id_product_attribute
  238. INNER JOIN '._DB_PREFIX_.'attribute a ON (a.id_attribute = pac.id_attribute)
  239. INNER JOIN '._DB_PREFIX_.'attribute_group ag ON ag.id_attribute_group = a.id_attribute_group
  240. '.(is_null($id_product) ? '' : 'AND pa.id_product = '.(int)$id_product).'
  241. GROUP BY a.id_attribute, pa.id_product '.(version_compare(_PS_VERSION_,'1.5','>') ? ', product_attribute_shop.`id_shop`' : ''));
  242. return 1;
  243. }
  244. /*
  245. * Url indexation
  246. */
  247. public function indexUrl($ajax = false, $truncate = true)
  248. {
  249. if ($truncate)
  250. Db::getInstance()->execute('TRUNCATE '._DB_PREFIX_.'layered_friendly_url');
  251. $attribute_values_by_lang = array();
  252. $filters = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('SELECT lc.*, id_lang, name, link_rewrite, cl.id_category
  253. FROM '._DB_PREFIX_.'layered_category lc
  254. INNER JOIN '._DB_PREFIX_.'category_lang cl ON (cl.id_category = lc.id_category AND lc.id_category <> 1 )
  255. GROUP BY type, id_value, id_lang');
  256. if (!$filters)
  257. return;
  258. foreach ($filters as $filter)
  259. switch ($filter['type'])
  260. {
  261. case 'id_attribute_group':
  262. $attributes = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
  263. SELECT agl.public_name name, a.id_attribute_group id_name, al.name value, a.id_attribute id_value, al.id_lang,
  264. liagl.url_name name_url_name, lial.url_name value_url_name
  265. FROM '._DB_PREFIX_.'attribute_group ag
  266. INNER JOIN '._DB_PREFIX_.'attribute_group_lang agl ON (agl.id_attribute_group = ag.id_attribute_group)
  267. INNER JOIN '._DB_PREFIX_.'attribute a ON (a.id_attribute_group = ag.id_attribute_group)
  268. INNER JOIN '._DB_PREFIX_.'attribute_lang al ON (al.id_attribute = a.id_attribute)
  269. LEFT JOIN '._DB_PREFIX_.'layered_indexable_attribute_group liag ON (liag.id_attribute_group = a.id_attribute_group)
  270. LEFT JOIN '._DB_PREFIX_.'layered_indexable_attribute_group_lang_value liagl
  271. ON (liagl.id_attribute_group = ag.id_attribute_group AND liagl.id_lang = '.(int)$filter['id_lang'].')
  272. LEFT JOIN '._DB_PREFIX_.'layered_indexable_attribute_lang_value lial
  273. ON (lial.id_attribute = a.id_attribute AND lial.id_lang = '.(int)$filter['id_lang'].')
  274. WHERE a.id_attribute_group = '.(int)$filter['id_value'].' AND agl.id_lang = al.id_lang AND agl.id_lang = '.(int)$filter['id_lang']);
  275. foreach ($attributes as $attribute)
  276. {
  277. if (!isset($attribute_values_by_lang[$attribute['id_lang']]))
  278. $attribute_values_by_lang[$attribute['id_lang']] = array();
  279. if (!isset($attribute_values_by_lang[$attribute['id_lang']]['c'.$attribute['id_name']]))
  280. $attribute_values_by_lang[$attribute['id_lang']]['c'.$attribute['id_name']] = array();
  281. $attribute_values_by_lang[$attribute['id_lang']]['c'.$attribute['id_name']][] = array(
  282. 'name' => (!empty($attribute['name_url_name']) ? $attribute['name_url_name'] : $attribute['name']),
  283. 'id_name' => 'c'.$attribute['id_name'],
  284. 'value' => (!empty($attribute['value_url_name']) ? $attribute['value_url_name'] : $attribute['value']),
  285. 'id_value' => $attribute['id_name'].'_'.$attribute['id_value'],
  286. 'id_id_value' => $attribute['id_value'],
  287. 'category_name' => $filter['link_rewrite'],
  288. 'type' => $filter['type']);
  289. }
  290. break;
  291. case 'id_feature':
  292. $features = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
  293. SELECT fl.name name, fl.id_feature id_name, fvl.id_feature_value id_value, fvl.value value, fl.id_lang, fl.id_lang,
  294. lifl.url_name name_url_name, lifvl.url_name value_url_name
  295. FROM '._DB_PREFIX_.'feature_lang fl
  296. LEFT JOIN '._DB_PREFIX_.'layered_indexable_feature lif ON (lif.id_feature = fl.id_feature)
  297. INNER JOIN '._DB_PREFIX_.'feature_value fv ON (fv.id_feature = fl.id_feature)
  298. INNER JOIN '._DB_PREFIX_.'feature_value_lang fvl ON (fvl.id_feature_value = fv.id_feature_value)
  299. LEFT JOIN '._DB_PREFIX_.'layered_indexable_feature_lang_value lifl
  300. ON (lifl.id_feature = fl.id_feature AND lifl.id_lang = '.(int)$filter['id_lang'].')
  301. LEFT JOIN '._DB_PREFIX_.'layered_indexable_feature_value_lang_value lifvl
  302. ON (lifvl.id_feature_value = fvl.id_feature_value AND lifvl.id_lang = '.(int)$filter['id_lang'].')
  303. WHERE fl.id_feature = '.(int)$filter['id_value'].' AND fvl.id_lang = fl.id_lang AND fvl.id_lang = '.(int)$filter['id_lang']);
  304. foreach ($features as $feature)
  305. {
  306. if (!isset($attribute_values_by_lang[$feature['id_lang']]))
  307. $attribute_values_by_lang[$feature['id_lang']] = array();
  308. if (!isset($attribute_values_by_lang[$feature['id_lang']]['f'.$feature['id_name']]))
  309. $attribute_values_by_lang[$feature['id_lang']]['f'.$feature['id_name']] = array();
  310. $attribute_values_by_lang[$feature['id_lang']]['f'.$feature['id_name']][] = array(
  311. 'name' => (!empty($feature['name_url_name']) ? $feature['name_url_name'] : $feature['name']),
  312. 'id_name' => 'f'.$feature['id_name'],
  313. 'value' => (!empty($feature['value_url_name']) ? $feature['value_url_name'] : $feature['value']),
  314. 'id_value' => $feature['id_name'].'_'.$feature['id_value'],
  315. 'id_id_value' => $feature['id_value'],
  316. 'category_name' => $filter['link_rewrite'],
  317. 'type' => $filter['type']);
  318. }
  319. break;
  320. case 'category':
  321. $categories = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
  322. SELECT cl.name, cl.id_lang, c.id_category
  323. FROM '._DB_PREFIX_.'category c
  324. INNER JOIN '._DB_PREFIX_.'category_lang cl ON (c.id_category = cl.id_category)
  325. WHERE cl.id_lang = '.(int)$filter['id_lang']);
  326. foreach ($categories as $category)
  327. {
  328. if (!isset($attribute_values_by_lang[$category['id_lang']]))
  329. $attribute_values_by_lang[$category['id_lang']] = array();
  330. if (!isset($attribute_values_by_lang[$category['id_lang']]['category']))
  331. $attribute_values_by_lang[$category['id_lang']]['category'] = array();
  332. $attribute_values_by_lang[$category['id_lang']]['category'][] = array('name' => $this->translateWord('Categories', $category['id_lang']),
  333. 'id_name' => null, 'value' => $category['name'], 'id_value' => $category['id_category'],
  334. 'category_name' => $filter['link_rewrite'], 'type' => $filter['type']);
  335. }
  336. break;
  337. case 'manufacturer':
  338. $manufacturers = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
  339. SELECT m.name as name,l.id_lang as id_lang, id_manufacturer
  340. FROM '._DB_PREFIX_.'manufacturer m , '._DB_PREFIX_.'lang l
  341. WHERE l.id_lang = '.(int)$filter['id_lang'].' ');
  342. foreach ($manufacturers as $manufacturer)
  343. {
  344. if (!isset($attribute_values_by_lang[$manufacturer['id_lang']]))
  345. $attribute_values_by_lang[$manufacturer['id_lang']] = array();
  346. if (!isset($attribute_values_by_lang[$manufacturer['id_lang']]['manufacturer']))
  347. $attribute_values_by_lang[$manufacturer['id_lang']]['manufacturer'] = array();
  348. $attribute_values_by_lang[$manufacturer['id_lang']]['manufacturer'][] = array('name' => $this->translateWord('Manufacturer', $manufacturer['id_lang']),
  349. 'id_name' => null, 'value' => $manufacturer['name'], 'id_value' => $manufacturer['id_manufacturer'],
  350. 'category_name' => $filter['link_rewrite'], 'type' => $filter['type']);
  351. }
  352. break;
  353. case 'quantity':
  354. $avaibility_list = array(
  355. $this->translateWord('Not available', (int)$filter['id_lang']),
  356. $this->translateWord('In stock', (int)$filter['id_lang'])
  357. );
  358. foreach ($avaibility_list as $key => $quantity)
  359. $attribute_values_by_lang[$filter['id_lang']]['quantity'][] = array('name' => $this->translateWord('Availability', (int)$filter['id_lang']),
  360. 'id_name' => null, 'value' => $quantity, 'id_value' => $key, 'id_id_value' => 0,
  361. 'category_name' => $filter['link_rewrite'], 'type' => $filter['type']);
  362. break;
  363. case 'condition':
  364. $condition_list = array(
  365. 'new' => $this->translateWord('New', (int)$filter['id_lang']),
  366. 'used' => $this->translateWord('Used', (int)$filter['id_lang']),
  367. 'refurbished' => $this->translateWord('Refurbished', (int)$filter['id_lang'])
  368. );
  369. foreach ($condition_list as $key => $condition)
  370. $attribute_values_by_lang[$filter['id_lang']]['condition'][] = array('name' => $this->translateWord('Condition', (int)$filter['id_lang']),
  371. 'id_name' => null, 'value' => $condition, 'id_value' => $key,
  372. 'category_name' => $filter['link_rewrite'], 'type' => $filter['type']);
  373. break;
  374. }
  375. // Foreach langs
  376. foreach ($attribute_values_by_lang as $id_lang => $attribute_values)
  377. {
  378. // Foreach attributes generate a couple "/<attribute_name>_<atttribute_value>". For example: color_blue
  379. foreach ($attribute_values as $attribute)
  380. foreach ($attribute as $param)
  381. {
  382. $selected_filters = array();
  383. $link = '/'.str_replace('-', '_', Tools::link_rewrite($param['name'])).'-'.str_replace('-', '_', Tools::link_rewrite($param['value']));
  384. $selected_filters[$param['type']] = array();
  385. if (!isset($param['id_id_value']))
  386. $param['id_id_value'] = $param['id_value'];
  387. $selected_filters[$param['type']][$param['id_id_value']] = $param['id_value'];
  388. $url_key = md5($link);
  389. $id_layered_friendly_url = Db::getInstance()->getValue('SELECT id_layered_friendly_url
  390. FROM `'._DB_PREFIX_.'layered_friendly_url` WHERE `id_lang` = '.$id_lang.' AND `url_key` = \''.$url_key.'\'');
  391. if ($id_layered_friendly_url == false)
  392. {
  393. Db::getInstance()->AutoExecute(_DB_PREFIX_.'layered_friendly_url', array('url_key' => $url_key, 'data' => serialize($selected_filters), 'id_lang' => $id_lang), 'INSERT');
  394. $id_layered_friendly_url = Db::getInstance()->Insert_ID();
  395. }
  396. }
  397. }
  398. if ($ajax)
  399. return '{"result": 1}';
  400. else
  401. return 1;
  402. }
  403. public function translateWord($string, $id_lang )
  404. {
  405. static $_MODULES = array();
  406. global $_MODULE;
  407. $file = _PS_MODULE_DIR_.$this->name.'/'.Language::getIsoById($id_lang).'.php';
  408. if (!array_key_exists($id_lang, $_MODULES))
  409. {
  410. if (!file_exists($file))
  411. return $string;
  412. include($file);
  413. $_MODULES[$id_lang] = $_MODULE;
  414. }
  415. $string = str_replace('\'', '\\\'', $string);
  416. // set array key to lowercase for 1.3 compatibility
  417. $_MODULES[$id_lang] = array_change_key_case($_MODULES[$id_lang]);
  418. $current_key = '<{'.strtolower( $this->name).'}'.strtolower(_THEME_NAME_).'>'.strtolower($this->name).'_'.md5($string);
  419. $default_key = '<{'.strtolower( $this->name).'}prestashop>'.strtolower($this->name).'_'.md5($string);
  420. if (isset($_MODULES[$id_lang][$current_key]))
  421. $ret = stripslashes($_MODULES[$id_lang][$current_key]);
  422. else if (isset($_MODULES[$id_lang][Tools::strtolower($current_key)]))
  423. $ret = stripslashes($_MODULES[$id_lang][Tools::strtolower($current_key)]);
  424. else if (isset($_MODULES[$id_lang][$default_key]))
  425. $ret = stripslashes($_MODULES[$id_lang][$default_key]);
  426. else if (isset($_MODULES[$id_lang][Tools::strtolower($default_key)]))
  427. $ret = stripslashes($_MODULES[$id_lang][Tools::strtolower($default_key)]);
  428. else
  429. $ret = stripslashes($string);
  430. return str_replace('"', '&quot;', $ret);
  431. }
  432. public function hookProductListAssign($params)
  433. {
  434. global $smarty;
  435. if (version_compare(_PS_VERSION_,'1.5','<') && !Configuration::get('PS_LAYERED_INDEXED')
  436. || version_compare(_PS_VERSION_,'1.5','>') && !Configuration::getGlobalValue('PS_LAYERED_INDEXED'))
  437. return;
  438. // Inform the hook was executed
  439. $params['hookExecuted'] = true;
  440. // List of product to overrride categoryController
  441. $params['catProducts'] = array();
  442. $selected_filters = $this->getSelectedFilters();
  443. $filter_block = $this->getFilterBlock($selected_filters);
  444. $title = '';
  445. if (is_array($filter_block['title_values']))
  446. foreach ($filter_block['title_values'] as $key => $val)
  447. $title .= ' – '.$key.' '.implode('/', $val);
  448. $smarty->assign('categoryNameComplement', $title);
  449. $this->getProducts($selected_filters, $params['catProducts'], $params['nbProducts'], $p, $n, $pages_nb, $start, $stop, $range);
  450. // Need a nofollow on the pagination links?
  451. $smarty->assign('no_follow', $filter_block['no_follow']);
  452. }
  453. public function hookAfterSaveProduct($params)
  454. {
  455. if (!$params['id_product'])
  456. return;
  457. self::indexProductPrices((int)$params['id_product']);
  458. $this->indexAttribute((int)$params['id_product']);
  459. }
  460. public function hookAfterSaveFeature($params)
  461. {
  462. if (!$params['id_feature'] || Tools::getValue('layered_indexable') === false)
  463. return;
  464. Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_indexable_feature WHERE id_feature = '.(int)$params['id_feature']);
  465. Db::getInstance()->execute('INSERT INTO '._DB_PREFIX_.'layered_indexable_feature VALUES ('.(int)$params['id_feature'].', '.(int)Tools::getValue('layered_indexable').')');
  466. Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_indexable_feature_lang_value WHERE id_feature = '.(int)$params['id_feature']); // don't care about the id_lang
  467. foreach (Language::getLanguages(false) as $language)
  468. {
  469. // Data are validated by method "hookPostProcessFeature"
  470. $id_lang = (int)$language['id_lang'];
  471. Db::getInstance()->execute('INSERT INTO '._DB_PREFIX_.'layered_indexable_feature_lang_value
  472. VALUES ('.(int)$params['id_feature'].', '.$id_lang.', \''.pSQL(Tools::link_rewrite(Tools::getValue('url_name_'.$id_lang))).'\',
  473. \''.pSQL(Tools::safeOutput(Tools::getValue('meta_title_'.$id_lang), true)).'\')');
  474. }
  475. }
  476. public function hookAfterSaveFeatureValue($params)
  477. {
  478. if (!$params['id_feature_value'])
  479. return;
  480. Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_indexable_feature_value_lang_value WHERE id_feature_value = '.(int)$params['id_feature_value']); // don't care about the id_lang
  481. foreach (Language::getLanguages(false) as $language)
  482. {
  483. // Data are validated by method "hookPostProcessFeatureValue"
  484. $id_lang = (int)$language['id_lang'];
  485. Db::getInstance()->execute('INSERT INTO '._DB_PREFIX_.'layered_indexable_feature_value_lang_value
  486. VALUES ('.(int)$params['id_feature_value'].', '.$id_lang.', \''.pSQL(Tools::link_rewrite(Tools::getValue('url_name_'.$id_lang))).'\',
  487. \''.pSQL(Tools::safeOutput(Tools::getValue('meta_title_'.$id_lang), true)).'\')');
  488. }
  489. }
  490. public function hookAfterDeleteFeatureValue($params)
  491. {
  492. if (!$params['id_feature_value'])
  493. return;
  494. Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_indexable_feature_value_lang_value WHERE id_feature_value = '.(int)$params['id_feature_value']);
  495. }
  496. public function hookPostProcessFeatureValue($params)
  497. {
  498. $this->hookPostProcessAttributeGroup($params);
  499. }
  500. public function hookFeatureValueForm($params)
  501. {
  502. $languages = Language::getLanguages(false);
  503. $default_form_language = (int)(Configuration::get('PS_LANG_DEFAULT'));
  504. $lang_value = array();
  505. if (version_compare(_PS_VERSION_,'1.5','>'))
  506. $return = '
  507. <script type="text/javascript">
  508. flag_fields = \'\';
  509. </script>';
  510. else
  511. $return = '';
  512. $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(
  513. 'SELECT url_name, meta_title, id_lang FROM '._DB_PREFIX_.'layered_indexable_feature_value_lang_value
  514. WHERE id_feature_value = '.(int)$params['id_feature_value']);
  515. if ($result)
  516. foreach ($result as $data)
  517. $lang_value[$data['id_lang']] = array('url_name' => $data['url_name'], 'meta_title' => $data['meta_title']);
  518. $return .= '<div class="clear"></div>
  519. <label>'.$this->l('URL:').'</label>
  520. <div class="margin-form">
  521. <script type="text/javascript">
  522. flag_fields += \'¤url_name¤meta_title\';
  523. </script>
  524. <div class="translatable">';
  525. foreach ($languages as $language)
  526. $return .= '
  527. <div class="lang_'.$language['id_lang'].'" id="url_name_'.$language['id_lang'].'" style="display: '.($language['id_lang'] == $default_form_language ? 'block' : 'none').'; float: left;">
  528. <input size="33" type="text" name="url_name_'.$language['id_lang'].'" value="'.Tools::safeOutput(@$lang_value[$language['id_lang']]['url_name'], true).'" />
  529. <span class="hint" name="help_box">'.$this->l('Invalid characters:').' <>;=#{}_<span class="hint-pointer">&nbsp;</span></span>
  530. <p style="clear: both">'.$this->l('Specific URL format in block layered generation').'</p>
  531. </div>';
  532. if (version_compare(_PS_VERSION_,'1.5','<'))
  533. $return .= $this->displayFlags($languages, $default_form_language, 'flag_fields', 'url_name', true, true);
  534. $return .= '
  535. </div>
  536. <div class="clear"></div>
  537. </div>
  538. <label>'.$this->l('Meta title:').' </label>
  539. <div class="margin-form">
  540. <div class="translatable">';
  541. foreach ($languages as $language)
  542. $return .= '
  543. <div class="lang_'.$language['id_lang'].'" id="meta_title_'.$language['id_lang'].'" style="display: '.($language['id_lang'] == $default_form_language ? 'block' : 'none').'; float: left;">
  544. <input size="33" type="text" name="meta_title_'.$language['id_lang'].'" value="'.Tools::safeOutput(@$lang_value[$language['id_lang']]['meta_title'], true).'" />
  545. <p style="clear: both">'.$this->l('Specific format for meta title').'</p>
  546. </div>';
  547. if (version_compare(_PS_VERSION_,'1.5','<'))
  548. $return .= $this->displayFlags($languages, $default_form_language, 'flag_fields', 'meta_title', true, true);
  549. $return .= '
  550. </div>
  551. <div class="clear"></div>
  552. </div>';
  553. return $return;
  554. }
  555. public function hookAfterSaveAttribute($params)
  556. {
  557. if (!$params['id_attribute'])
  558. return;
  559. Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_indexable_attribute_lang_value WHERE id_attribute = '.(int)$params['id_attribute']); // don't care about the id_lang
  560. foreach (Language::getLanguages(false) as $language)
  561. {
  562. // Data are validated by method "hookPostProcessAttribute"
  563. $id_lang = (int)$language['id_lang'];
  564. Db::getInstance()->execute('INSERT INTO '._DB_PREFIX_.'layered_indexable_attribute_lang_value
  565. VALUES ('.(int)$params['id_attribute'].', '.$id_lang.', \''.pSQL(Tools::link_rewrite(Tools::getValue('url_name_'.$id_lang))).'\',
  566. \''.pSQL(Tools::safeOutput(Tools::getValue('meta_title_'.$id_lang), true)).'\')');
  567. }
  568. }
  569. public function hookAfterDeleteAttribute($params)
  570. {
  571. if (!$params['id_attribute'])
  572. return;
  573. Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_indexable_attribute_lang_value WHERE id_attribute = '.(int)$params['id_attribute']);
  574. }
  575. public function hookPostProcessAttribute($params)
  576. {
  577. $this->hookPostProcessAttributeGroup($params);
  578. }
  579. public function hookAttributeForm($params)
  580. {
  581. $languages = Language::getLanguages(false);
  582. $default_form_language = (int)(Configuration::get('PS_LANG_DEFAULT'));
  583. $lang_value = array();
  584. if (version_compare(_PS_VERSION_,'1.5','>'))
  585. $return = '
  586. <script type="text/javascript">
  587. flag_fields = \'\';
  588. </script>';
  589. else
  590. $return = '';
  591. $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(
  592. 'SELECT url_name, meta_title, id_lang FROM '._DB_PREFIX_.'layered_indexable_attribute_lang_value
  593. WHERE id_attribute = '.(int)$params['id_attribute']);
  594. if ($result)
  595. foreach ($result as $data)
  596. $lang_value[$data['id_lang']] = array('url_name' => $data['url_name'], 'meta_title' => $data['meta_title']);
  597. $return .= '<div class="clear"></div>
  598. <label>'.$this->l('URL:').'</label>
  599. <div class="margin-form">
  600. <script type="text/javascript">
  601. flag_fields += \'¤url_name¤meta_title\';
  602. </script>
  603. <div class="translatable">';
  604. foreach ($languages as $language)
  605. $return .= '
  606. <div class="lang_'.$language['id_lang'].'" id="url_name_'.$language['id_lang'].'" style="display: '.($language['id_lang'] == $default_form_language ? 'block' : 'none').'; float: left;">
  607. <input size="33" type="text" name="url_name_'.$language['id_lang'].'" value="'.Tools::safeOutput(@$lang_value[$language['id_lang']]['url_name'], true).'" />
  608. <span class="hint" name="help_box">'.$this->l('Invalid characters:').' <>;=#{}_<span class="hint-pointer">&nbsp;</span></span>
  609. <p style="clear: both">'.$this->l('Specific URL format in block layered generation').'</p>
  610. </div>';
  611. if (version_compare(_PS_VERSION_,'1.5','<'))
  612. $return .= $this->displayFlags($languages, $default_form_language, 'flag_fields', 'url_name', true, true);
  613. $return .= '
  614. </div>
  615. <div class="clear"></div>
  616. </div>
  617. <label>'.$this->l('Meta title:').' </label>
  618. <div class="margin-form">
  619. <div class="translatable">';
  620. foreach ($languages as $language)
  621. $return .= '
  622. <div class="lang_'.$language['id_lang'].'" id="meta_title_'.$language['id_lang'].'" style="display: '.($language['id_lang'] == $default_form_language ? 'block' : 'none').'; float: left;">
  623. <input size="33" type="text" name="meta_title_'.$language['id_lang'].'" value="'.Tools::safeOutput(@$lang_value[$language['id_lang']]['meta_title'], true).'" />
  624. <p style="clear: both">'.$this->l('Specific format for meta title').'</p>
  625. </div>';
  626. if (version_compare(_PS_VERSION_,'1.5','<'))
  627. $return .= $this->displayFlags($languages, $default_form_language, 'flag_fields', 'meta_title', true, true);
  628. $return .= '
  629. </div>
  630. <div class="clear"></div>
  631. </div>';
  632. return $return;
  633. }
  634. public function hookPostProcessFeature($params)
  635. {
  636. $this->hookPostProcessAttributeGroup($params);
  637. }
  638. public function hookAfterDeleteFeature($params)
  639. {
  640. if (!$params['id_feature'])
  641. return;
  642. Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_indexable_feature WHERE id_feature = '.(int)$params['id_feature']);
  643. }
  644. public function hookAfterSaveAttributeGroup($params)
  645. {
  646. if (!$params['id_attribute_group'] || Tools::getValue('layered_indexable') === false)
  647. return;
  648. Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_indexable_attribute_group WHERE id_attribute_group = '.(int)$params['id_attribute_group']);
  649. Db::getInstance()->execute('INSERT INTO '._DB_PREFIX_.'layered_indexable_attribute_group VALUES ('.(int)$params['id_attribute_group'].', '.(int)Tools::getValue('layered_indexable').')');
  650. Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_indexable_attribute_group_lang_value WHERE id_attribute_group = '.(int)$params['id_attribute_group']); // don't care about the id_lang
  651. foreach (Language::getLanguages(false) as $language)
  652. {
  653. // Data are validated by method "hookPostProcessAttributeGroup"
  654. $id_lang = (int)$language['id_lang'];
  655. Db::getInstance()->execute('INSERT INTO '._DB_PREFIX_.'layered_indexable_attribute_group_lang_value
  656. VALUES ('.(int)$params['id_attribute_group'].', '.$id_lang.', \''.pSQL(Tools::link_rewrite(Tools::getValue('url_name_'.$id_lang))).'\',
  657. \''.pSQL(Tools::safeOutput(Tools::getValue('meta_title_'.$id_lang), true)).'\')');
  658. }
  659. }
  660. public function hookPostProcessAttributeGroup($params)
  661. {
  662. // Limit to one call
  663. static $once = false;
  664. if ($once)
  665. return;
  666. $once = true;
  667. $errors = array();
  668. foreach (Language::getLanguages(false) as $language)
  669. {
  670. $id_lang = $language['id_lang'];
  671. if (Tools::getValue('url_name_'.$id_lang))
  672. if (Tools::link_rewrite(Tools::getValue('url_name_'.$id_lang)) != strtolower( Tools::getValue('url_name_'.$id_lang)))
  673. {
  674. // Here use the reference "errors" to stop saving process
  675. $params['errors'][] = Tools::displayError(sprintf($this->l('"%s" is not a valid url'), Tools::getValue('url_name_'.$id_lang)));
  676. }
  677. }
  678. }
  679. public function hookAfterDeleteAttributeGroup($params)
  680. {
  681. if (!$params['id_attribute_group'])
  682. return;
  683. Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_indexable_attribute_group WHERE id_attribute_group = '.(int)$params['id_attribute_group']);
  684. Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_indexable_attribute_group_lang_value WHERE id_attribute_group = '.(int)$params['id_attribute_group']);
  685. }
  686. public function hookAttributeGroupForm($params)
  687. {
  688. $languages = Language::getLanguages(false);
  689. $default_form_language = (int)(Configuration::get('PS_LANG_DEFAULT'));
  690. $indexable = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('SELECT indexable FROM '._DB_PREFIX_.'layered_indexable_attribute_group
  691. WHERE id_attribute_group = '.(int)$params['id_attribute_group']);
  692. $lang_value = array();
  693. $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(
  694. 'SELECT url_name, meta_title, id_lang FROM '._DB_PREFIX_.'layered_indexable_attribute_group_lang_value
  695. WHERE id_attribute_group = '.(int)$params['id_attribute_group']);
  696. if ($result)
  697. foreach ($result as $data)
  698. $lang_value[$data['id_lang']] = array('url_name' => $data['url_name'], 'meta_title' => $data['meta_title']);
  699. if ($indexable === false)
  700. $on = true;
  701. else
  702. $on = (bool)$indexable;
  703. if (version_compare(_PS_VERSION_,'1.5','>'))
  704. $return = '
  705. <script type="text/javascript">
  706. flag_fields = \'\';
  707. </script>';
  708. else
  709. $return = '';
  710. $return .= '<div class="clear"></div>
  711. <label>'.$this->l('URL:').'</label>
  712. <div class="margin-form">
  713. <script type="text/javascript">
  714. flag_fields += \'¤url_name¤meta_title\';
  715. </script>
  716. <div class="translatable">';
  717. foreach ($languages as $language)
  718. $return .= '
  719. <div class="lang_'.$language['id_lang'].'" id="url_name_'.$language['id_lang'].'" style="display: '.($language['id_lang'] == $default_form_language ? 'block' : 'none').'; float: left;">
  720. <input size="33" type="text" name="url_name_'.$language['id_lang'].'" value="'.Tools::safeOutput(@$lang_value[$language['id_lang']]['url_name'], true).'" />
  721. <span class="hint" name="help_box">'.$this->l('Invalid characters:').' <>;=#{}_<span class="hint-pointer">&nbsp;</span></span>
  722. <p style="clear: both">'.$this->l('Specific URL format in block layered generation').'</p>
  723. </div>';
  724. if (version_compare(_PS_VERSION_,'1.5','<'))
  725. $return .= $this->displayFlags($languages, $default_form_language, 'flag_fields', 'url_name', true, true);
  726. $return .= '
  727. </div>
  728. <div class="clear"></div>
  729. </div>
  730. <label>'.$this->l('Meta title:').' </label>
  731. <div class="margin-form">
  732. <div class="translatable">';
  733. foreach ($languages as $language)
  734. $return .= '
  735. <div class="lang_'.$language['id_lang'].'" id="meta_title_'.$language['id_lang'].'" style="display: '.($language['id_lang'] == $default_form_language ? 'block' : 'none').'; float: left;">
  736. <input size="33" type="text" name="meta_title_'.$language['id_lang'].'" value="'.Tools::safeOutput(@$lang_value[$language['id_lang']]['meta_title'], true).'" />
  737. <p style="clear: both">'.$this->l('Specific format for meta title').'</p>
  738. </div>';
  739. if (version_compare(_PS_VERSION_,'1.5','<'))
  740. $return .= $this->displayFlags($languages, $default_form_language, 'flag_fields', 'meta_title', true, true);
  741. $return .= '
  742. </div>
  743. <div class="clear"></div>
  744. </div>
  745. <label>'.$this->l('Indexable:').' </label>
  746. <div class="margin-form">
  747. <input type="radio" '.(($on) ? 'checked="checked"' : '').' value="1" id="indexable_on" name="layered_indexable">
  748. <label for="indexable_on" class="t"><img title="Yes" alt="Enabled" src="../img/admin/enabled.gif"></label>
  749. <input type="radio" '.((!$on) ? 'checked="checked"' : '').' value="0" id="indexable_off" name="layered_indexable">
  750. <label for="indexable_off" class="t"><img title="No" alt="Disabled" src="../img/admin/disabled.gif"></label>
  751. <p>'.$this->l('Use this attribute in URL generated by the layered navigation module').'</p>
  752. </div>';
  753. return $return;
  754. }
  755. public function hookFeatureForm($params)
  756. {
  757. $languages = Language::getLanguages(false);
  758. $default_form_language = (int)(Configuration::get('PS_LANG_DEFAULT'));
  759. $indexable = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('SELECT indexable FROM '._DB_PREFIX_.'layered_indexable_feature WHERE id_feature = '.(int)$params['id_feature']);
  760. $lang_value = array();
  761. $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(
  762. 'SELECT url_name, meta_title, id_lang FROM '._DB_PREFIX_.'layered_indexable_feature_lang_value
  763. WHERE id_feature = '.(int)$params['id_feature']);
  764. if ($result)
  765. foreach ($result as $data)
  766. $lang_value[$data['id_lang']] = array('url_name' => $data['url_name'], 'meta_title' => $data['meta_title']);
  767. if ($indexable === false)
  768. $on = true;
  769. else
  770. $on = (bool)$indexable;
  771. if (version_compare(_PS_VERSION_,'1.5','>'))
  772. $return = '
  773. <script type="text/javascript">
  774. flag_fields = \'\';
  775. </script>';
  776. else
  777. $return = '';
  778. $return .= '<div class="clear"></div>
  779. <label>'.$this->l('URL:').'</label>
  780. <div class="margin-form">
  781. <script type="text/javascript">
  782. flag_fields += \'¤url_name¤meta_title\';
  783. </script>
  784. <div class="translatable">';
  785. foreach ($languages as $language)
  786. $return .= '
  787. <div class="lang_'.$language['id_lang'].'" id="url_name_'.$language['id_lang'].'" style="display: '.($language['id_lang'] == $default_form_language ? 'block' : 'none').'; float: left;">
  788. <input size="33" type="text" name="url_name_'.$language['id_lang'].'" value="'.Tools::safeOutput(@$lang_value[$language['id_lang']]['url_name'], true).'" />
  789. <span class="hint" name="help_box">'.$this->l('Invalid characters:').' <>;=#{}_<span class="hint-pointer">&nbsp;</span></span>
  790. <p style="clear: both">'.$this->l('Specific URL format in block layered generation').'</p>
  791. </div>';
  792. if (version_compare(_PS_VERSION_,'1.5','<'))
  793. $return .= $this->displayFlags($languages, $default_form_language, 'flag_fields', 'url_name', true, true);
  794. $return .= '
  795. </div>
  796. <div class="clear"></div>
  797. </div>
  798. <label>'.$this->l('Meta title:').' </label>
  799. <div class="margin-form">
  800. <div class="translatable">';
  801. foreach ($languages as $language)
  802. $return .= '
  803. <div class="lang_'.$language['id_lang'].'" id="meta_title_'.$language['id_lang'].'" style="display: '.($language['id_lang'] == $default_form_language ? 'block' : 'none').'; float: left;">
  804. <input size="33" type="text" name="meta_title_'.$language['id_lang'].'" value="'.Tools::safeOutput(@$lang_value[$language['id_lang']]['meta_title'], true).'" />
  805. <p style="clear: both">'.$this->l('Specific format for meta title').'</p>
  806. </div>';
  807. if (version_compare(_PS_VERSION_,'1.5','<'))
  808. $return .= $this->displayFlags($languages, $default_form_language, 'flag_fields', 'meta_title', true, true);
  809. $return .= '
  810. </div>
  811. <div class="clear"></div>
  812. </div>
  813. <label>'.$this->l('Indexable:').' </label>
  814. <div class="margin-form">
  815. <input type="radio" '.(($on) ? 'checked="checked"' : '').' value="1" id="indexable_on" name="layered_indexable">
  816. <label for="indexable_on" class="t"><img title="Yes" alt="Enabled" src="../img/admin/enabled.gif"></label>
  817. <input type="radio" '.((!$on) ? 'checked="checked"' : '').' value="0" id="indexable_off" name="layered_indexable">
  818. <label for="indexable_off" class="t"><img title="No" alt="Disabled" src="../img/admin/disabled.gif"></label>
  819. <p>'.$this->l('Use this attribute in URL generated by the layered navigation module').'</p>
  820. </div>';
  821. return $return;
  822. }
  823. /*
  824. * $cursor $cursor in order to restart indexing from the last state
  825. */
  826. public static function fullPricesIndexProcess($cursor = 0, $ajax = false, $smart = false)
  827. {
  828. if ($cursor == 0 && !$smart)
  829. self::installPriceIndexTable();
  830. return self::indexPrices($cursor, true, $ajax, $smart);
  831. }
  832. /*
  833. * $cursor $cursor in order to restart indexing from the last state
  834. */
  835. public static function pricesIndexProcess($cursor = 0, $ajax = false)
  836. {
  837. return self::indexPrices($cursor, false, $ajax);
  838. }
  839. private static function indexPrices($cursor = null, $full = false, $ajax = false, $smart = false)
  840. {
  841. if ($full)
  842. if (version_compare(_PS_VERSION_,'1.5','>'))
  843. $nb_products = (int)Db::getInstance()->getValue('
  844. SELECT count(DISTINCT p.`id_product`)
  845. FROM '._DB_PREFIX_.'product p
  846. INNER JOIN `'._DB_PREFIX_.'product_shop` ps
  847. ON (ps.`id_product` = p.`id_product` AND ps.`active` = 1)');
  848. else
  849. $nb_products = (int)Db::getInstance()->getValue('
  850. SELECT count(DISTINCT p.`id_product`)
  851. FROM '._DB_PREFIX_.'product p
  852. WHERE `active` = 1');
  853. else
  854. if (version_compare(_PS_VERSION_,'1.5','>'))
  855. $nb_products = (int)Db::getInstance()->getValue('
  856. SELECT COUNT(DISTINCT p.`id_product`) FROM `'._DB_PREFIX_.'product` p
  857. INNER JOIN `'._DB_PREFIX_.'product_shop` ps
  858. ON (ps.`id_product` = p.`id_product` AND ps.`active` = 1)
  859. LEFT JOIN `'._DB_PREFIX_.'layered_price_index` psi ON (psi.id_product = p.id_product)
  860. WHERE psi.id_product IS NULL');
  861. else
  862. $nb_products = (int)Db::getInstance()->getValue('
  863. SELECT COUNT(DISTINCT p.`id_product`) FROM `'._DB_PREFIX_.'product` p
  864. LEFT JOIN `'._DB_PREFIX_.'layered_price_index` psi ON (psi.id_product = p.id_product)
  865. WHERE `active` = 1 AND psi.id_product IS NULL');
  866. $max_executiontime = @ini_get('max_execution_time');
  867. if ($max_executiontime > 5 || $max_executiontime <= 0)
  868. $max_executiontime = 5;
  869. $start_time = microtime(true);
  870. do
  871. {
  872. $cursor = (int)self::indexPricesUnbreakable((int)$cursor, $full, $smart);
  873. $time_elapsed = microtime(true) - $start_time;
  874. }
  875. while ($cursor < $nb_products && (Tools::getMemoryLimit()) > memory_get_peak_usage() && $time_elapsed < $max_executiontime);
  876. if (($nb_products > 0 && !$full || $cursor < $nb_products && $full) && !$ajax)
  877. {
  878. $token = substr(Tools::encrypt('blocklayered/index'), 0, 10);
  879. if (Tools::usingSecureMode())
  880. $domain = Tools::getShopDomainSsl(true);
  881. else
  882. $domain = Tools::getShopDomain(true);
  883. if (!Tools::file_get_contents($domain.__PS_BASE_URI__.'modules/blocklayered/blocklayered-price-indexer.php?token='.$token.'&cursor='.(int)$cursor.'&full='.(int)$full))
  884. self::indexPrices((int)$cursor, (int)$full);
  885. return $cursor;
  886. }
  887. if ($ajax && $nb_products > 0 && $cursor < $nb_products && $full)
  888. return '{"cursor": '.$cursor.', "count": '.($nb_products - $cursor).'}';
  889. else if ($ajax && $nb_products > 0 && !$full)
  890. return '{"cursor": '.$cursor.', "count": '.($nb_products).'}';
  891. else
  892. {
  893. if (version_compare(_PS_VERSION_,'1.5','>'))
  894. Configuration::updateGlobalValue('PS_LAYERED_INDEXED', 1);
  895. else
  896. Configuration::updateValue('PS_LAYERED_INDEXED', 1);
  897. if ($ajax)
  898. return '{"result": "ok"}';
  899. else
  900. return -1;
  901. }
  902. }
  903. /*
  904. * $cursor $cursor in order to restart indexing from the last state
  905. */
  906. private static function indexPricesUnbreakable($cursor, $full = false, $smart = false)
  907. {
  908. static $length = 100; // Nb of products to index
  909. if (is_null($cursor))
  910. $cursor = 0;
  911. if ($full)
  912. if (version_compare(_PS_VERSION_,'1.5','>'))
  913. $query = '
  914. SELECT p.`id_product`
  915. FROM `'._DB_PREFIX_.'product` p
  916. INNER JOIN `'._DB_PREFIX_.'product_shop` ps
  917. ON (ps.`id_product` = p.`id_product` AND ps.`active` = 1)
  918. GROUP BY p.`id_product`
  919. ORDER BY p.`id_product` LIMIT '.(int)$cursor.','.(int)$length;
  920. else
  921. $query = '
  922. SELECT p.`id_product`
  923. FROM `'._DB_PREFIX_.'product` p
  924. WHERE `active` = 1
  925. GROUP BY p.`id_product`
  926. ORDER BY p.`id_product` LIMIT '.(int)$cursor.','.(int)$length;
  927. else
  928. if (version_compare(_PS_VERSION_,'1.5','>'))
  929. $query = '
  930. SELECT p.`id_product`
  931. FROM `'._DB_PREFIX_.'product` p
  932. INNER JOIN `'._DB_PREFIX_.'product_shop` ps
  933. ON (ps.`id_product` = p.`id_product` AND ps.`active` = 1)
  934. LEFT JOIN `'._DB_PREFIX_.'layered_price_index` psi ON (psi.id_product = p.id_product)
  935. WHERE psi.id_product IS NULL
  936. GROUP BY p.`id_product`
  937. ORDER BY p.`id_product` LIMIT 0,'.(int)$length;
  938. else
  939. $query = '
  940. SELECT p.`id_product`
  941. FROM `'._DB_PREFIX_.'product` p
  942. LEFT JOIN `'._DB_PREFIX_.'layered_price_index` psi ON (psi.id_product = p.id_product)
  943. WHERE `active` = 1 AND psi.id_product IS NULL
  944. GROUP BY p.`id_product`
  945. ORDER BY p.`id_product` LIMIT 0,'.(int)$length;
  946. foreach (Db::getInstance()->executeS($query) as $product)
  947. self::indexProductPrices((int)$product['id_product'], ($smart && $full));
  948. return (int)($cursor + $length);
  949. }
  950. public static function indexProductPrices($id_product, $smart = true)
  951. {
  952. static $groups = null;
  953. if (is_null($groups))
  954. {
  955. $groups = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('SELECT id_group FROM `'._DB_PREFIX_.'group_reduction`');
  956. if (!$groups)
  957. $groups = array();
  958. }
  959. $shop_list = array();
  960. if (version_compare(_PS_VERSION_,'1.5','>'))
  961. $shop_list = Shop::getShops(false, null, true);
  962. else
  963. $shop_list[] = 0;
  964. foreach ($shop_list as $id_shop)
  965. {
  966. static $currency_list = null;
  967. if (is_null($currency_list))
  968. {
  969. if (version_compare(_PS_VERSION_,'1.5','>'))
  970. $currency_list = Currency::getCurrencies(false, 1, new Shop($id_shop));
  971. else
  972. $currency_list = Currency::getCurrencies(false, 1);
  973. }
  974. $min_price = array();
  975. $max_price = array();
  976. if ($smart)
  977. Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'layered_price_index` WHERE `id_product` = '.(int)$id_product.' AND `id_shop` = '.(int)$id_shop);
  978. if (Configuration::get('PS_LAYERED_FILTER_PRICE_USETAX'))
  979. {
  980. if (version_compare(_PS_VERSION_,'1.5','>'))
  981. $max_tax_rate = Db::getInstance()->getValue('
  982. SELECT max(t.rate) max_rate
  983. FROM `'._DB_PREFIX_.'product_shop` p
  984. LEFT JOIN `'._DB_PREFIX_.'tax_rules_group` trg ON (trg.id_tax_rules_group = p.id_tax_rules_group AND p.id_shop = '.(int)$shop_list.')
  985. LEFT JOIN `'._DB_PREFIX_.'tax_rule` tr ON (tr.id_tax_rules_group = trg.id_tax_rules_group)
  986. LEFT JOIN `'._DB_PREFIX_.'tax` t ON (t.id_tax = tr.id_tax AND t.active = 1)
  987. WHERE id_product = '.(int)$id_product.'
  988. GROUP BY id_product');
  989. else
  990. $max_tax_rate = Db::getInstance()->getValue('
  991. SELECT max(t.rate) max_rate
  992. FROM `'._DB_PREFIX_.'product` p
  993. LEFT JOIN `'._DB_PREFIX_.'tax_rules_group` trg ON (trg.id_tax_rules_group = p.id_tax_rules_group)
  994. LEFT JOIN `'._DB_PREFIX_.'tax_rule` tr ON (tr.id_tax_rules_group = trg.id_tax_rules_group)
  995. LEFT JOIN `'._DB_PREFIX_.'tax` t ON (t.id_tax = tr.id_tax AND t.active = 1)
  996. WHERE id_product = '.(int)$id_product.'
  997. GROUP BY id_product');
  998. }
  999. else
  1000. $max_tax_rate = 0;
  1001. $product_min_prices = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
  1002. SELECT id_shop, id_currency, id_country, id_group, from_quantity
  1003. FROM `'._DB_PREFIX_.'specific_price`
  1004. WHERE id_product = '.(int)$id_product);
  1005. // Get min price
  1006. foreach ($currency_list as…

Large files files are truncated, but you can click here to view the full file