- http://www.presta-module.com * @copyright Presta-Module 2019 - http://www.presta-module.com * @license Commercial * @version 1.4.7 * * ____ __ __ * | _ \ | \/ | * | |_) | | |\/| | * | __/ | | | | * |_| |_| |_| */ if (!defined('_PS_VERSION_')) { exit; } class PM_MultipleFeatures extends Module { public static $_module_prefix = 'MF'; public $_errors = array(); protected $submitted_tabs; protected $_copyright_link = array( 'link' => '', 'img' => '//www.presta-module.com/img/logo-module.JPG' ); protected $_support_link = false; protected $_getting_started = false; protected $defaultConfiguration = array( 'featureSeparator' => ', ', ); public function __construct() { $this->name = 'pm_multiplefeatures'; $this->tab = 'front_office_features'; $this->version = '1.4.7'; $this->author = 'Presta-Module'; $this->module_key = 'ba224a2fe8a2bd0c86589860fab0decb'; $this->need_instance = 0; $this->bootstrap = true; $this->ps_versions_compliancy = array('min' => '1.5.0.0', 'max' => '1.7.99.99'); parent::__construct(); $this->displayName = 'Multiple Features'; if ($this->onBackOffice()) { $this->description = $this->l('Allow to define multiple features values per features'); $doc_url_tab = array(); $doc_url_tab['fr'] = '#/fr/multiple-features/'; $doc_url_tab['en'] = '#/en/multiple-features-2/'; $doc_url_tab['es'] = '#/es/multiple-features-3/'; $doc_url = $doc_url_tab['en']; if ($this->context->language->iso_code == 'fr') { $doc_url = $doc_url_tab['fr']; } $this->_support_link = array( array('link' => 'http://addons.prestashop.com/contact-community.php?id_product=6356', 'target' => '_blank', 'label' => $this->l('Support contact')), ); $oldModuleVersion = Configuration::get('PM_'.self::$_module_prefix.'_LAST_VERSION', false); if ($oldModuleVersion != false && version_compare($oldModuleVersion, '1.3.0', '<=') || $oldModuleVersion != false && $oldModuleVersion != $this->version) { if (version_compare($oldModuleVersion, '1.4.1', '<=')) { $this->registerHook('actionProductAttributeUpdate'); } if (version_compare($oldModuleVersion, '1.4.6', '<=')) { $this->registerHook('actionAdminControllerSetMedia'); } $this->installDatabase(); } Configuration::updateValue('PM_'.self::$_module_prefix.'_LAST_VERSION', $this->version); } } private function installDatabase() { $result = Db::getInstance()->ExecuteS('SHOW INDEX FROM `' . _DB_PREFIX_ . 'feature_product` WHERE `Key_name` = "PRIMARY"'); if ($result) { Db::getInstance()->Execute('ALTER TABLE `' . _DB_PREFIX_ . 'feature_product` DROP PRIMARY KEY'); } $result = Db::getInstance()->ExecuteS('SHOW INDEX FROM `' . _DB_PREFIX_ . 'feature_product` WHERE `Key_name` = "mf_feature_product"'); if (!$result || !Db::getInstance()->numRows()) { Db::getInstance()->Execute('ALTER TABLE `' . _DB_PREFIX_ . 'feature_product` ADD INDEX `mf_feature_product` (`id_feature`, `id_product`)'); } $result = Db::getInstance()->ExecuteS('SHOW INDEX FROM `' . _DB_PREFIX_ . 'feature_product` WHERE `Key_name` = "mf_unique"'); if (!$result || !Db::getInstance()->numRows()) { $duplicateRows = Db::getInstance()->ExecuteS('SELECT *, COUNT(*) as count from `' . _DB_PREFIX_ . 'feature_product` GROUP BY id_feature, id_product, id_feature_value HAVING COUNT(*) > 1'); if ($duplicateRows && self::isFilledArray($duplicateRows)) { foreach ($duplicateRows as $duplicateRow) { Db::getInstance()->Execute('DELETE FROM `' . _DB_PREFIX_ . 'feature_product` WHERE `id_feature` = ' . (int)$duplicateRow['id_feature'] . ' AND `id_product` = ' . (int)$duplicateRow['id_product'] . ' AND `id_feature_value` = ' . (int)$duplicateRow['id_feature_value'] . ' LIMIT ' . ((int)$duplicateRow['count'] - 1)); } } Db::getInstance()->Execute('ALTER TABLE `' . _DB_PREFIX_ . 'feature_product` ADD UNIQUE INDEX `mf_unique` (`id_feature`, `id_product`, `id_feature_value`)'); } $this->columnExists('feature_product', 'position', true, 'tinyint(3) unsigned NOT NULL DEFAULT "0"', 'id_feature_value'); $result = Db::getInstance()->ExecuteS('SHOW INDEX FROM `' . _DB_PREFIX_ . 'feature_product` WHERE `Key_name` = "position"'); if (!$result || !Db::getInstance()->numRows()) { Db::getInstance()->Execute('ALTER TABLE `' . _DB_PREFIX_ . 'feature_product` ADD INDEX `position` (`position`)'); } } private function columnExists($table, $column, $createIfNotExist = false, $type = false, $insertAfter = false) { $resultset = Db::getInstance()->ExecuteS("SHOW COLUMNS FROM `" . _DB_PREFIX_ . $table . "`", true, false); foreach ($resultset as $row) { if ($row['Field'] == $column) { return true; } } if ($createIfNotExist && Db::getInstance()->Execute('ALTER TABLE `' . _DB_PREFIX_ . $table . '` ADD `' . $column . '` ' . $type . ' ' . ($insertAfter ? ' AFTER `' . $insertAfter . '`' : '') . '')) { return true; } return false; } public function install() { $this->installDatabase(); return ( parent::install() && $this->registerHook('backOfficeTop') && $this->registerHook('backOfficeHeader') && $this->registerHook('actionAdminControllerSetMedia') && ( (version_compare(_PS_VERSION_, '1.7.0.0', '>=') && $this->registerHook('actionGetProductPropertiesBefore')&& $this->registerHook('actionGetProductPropertiesAfter') && $this->registerHook('actionProductUpdate') && $this->registerHook('actionProductAttributeUpdate')) || (version_compare(_PS_VERSION_, '1.5.0.0', '>=') && version_compare(_PS_VERSION_, '1.7.0.0', '<') && $this->registerHook('displayOverrideTemplate')) )); } private function checkFeatures($languages, $feature_id, $use_old_key = false) { $rules = call_user_func(array('FeatureValue', 'getValidationRules'), 'FeatureValue'); $feature = Feature::getFeature(Configuration::get('PS_LANG_DEFAULT'), $feature_id); $val = 0; foreach ($languages as $language) { if (version_compare(_PS_VERSION_, '1.7.0.0', '>=') && !$use_old_key) { $customFeatureKey = 'pm_multiplefeatures_feature_'.$feature_id.'_custom_value_'.$language['id_lang']; } else { $customFeatureKey = 'custom_'.$feature_id.'_'.$language['id_lang']; } if ($val = Tools::getValue($customFeatureKey)) { $currentLanguage = new Language($language['id_lang']); if (Tools::strlen($val) > $rules['sizeLang']['value']) { $this->_errors[] = Tools::displayError('name for feature').' '.$feature['name'].' '.Tools::displayError('is too long in').' '.$currentLanguage->name; } elseif (!call_user_func(array('Validate', $rules['validateLang']['value']), $val)) { $this->_errors[] = Tools::displayError('Valid name required for feature.').' '.$feature['name'].' '.Tools::displayError('in').' '.$currentLanguage->name; } if (sizeof($this->_errors)) { return (0); } if ($language['id_lang'] == Configuration::get('PS_LANG_DEFAULT')) { return ($val); } } } return (0); } public static function getProductFeaturesStatic($id_product, $id_lang, $custom = true) { return Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS(' SELECT fp.id_feature, fp.id_product, fp.id_feature_value, vl.value, v.custom FROM `'._DB_PREFIX_.'feature_product` fp LEFT JOIN `'._DB_PREFIX_.'feature_value` v ON (fp.`id_feature_value` = v.`id_feature_value`) LEFT JOIN `'._DB_PREFIX_.'feature_value_lang` vl ON (v.`id_feature_value` = vl.`id_feature_value` AND vl.`id_lang` = '.(int)$id_lang.') WHERE fp.`id_product` = '.(int)$id_product . (!$custom ? ' AND v.`custom` = 0' : '') . ' ORDER BY fp.`position` ASC'); } public function getFrontFeatures($id_product, $separator = null, $id_feature = null) { if (!Feature::isFeatureActive()) { return array(); } $id_lang = (int)Context::getContext()->cookie->id_lang; if ($separator == null) { $config = $this->getModuleConfiguration(); $separator = $config['featureSeparator']; } $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS(' SELECT fp.id_feature, vl.value, fl.name FROM `'._DB_PREFIX_.'feature_product` fp LEFT JOIN `'._DB_PREFIX_.'feature_value` v ON (fp.`id_feature_value` = v.`id_feature_value`) LEFT JOIN `'._DB_PREFIX_.'feature_value_lang` vl ON (v.`id_feature_value` = vl.`id_feature_value` AND vl.`id_lang` = '.(int)$id_lang.') LEFT JOIN `'._DB_PREFIX_.'feature` f ON (f.`id_feature` = v.`id_feature`) '.(Shop::isFeatureActive() && Shop::getContext() == Shop::CONTEXT_SHOP ? Shop::addSqlAssociation('feature', 'f') : '').' LEFT JOIN `'._DB_PREFIX_.'feature_lang` fl ON (fl.`id_feature` = f.`id_feature` AND fl.`id_lang` = '.(int)$id_lang.') WHERE fp.`id_product` = '.(int)$id_product . ($id_feature != null && $id_feature ? ' AND f.`id_feature` = '.(int)$id_feature : '') . ' ORDER BY f.`position` ASC, fp.`position` ASC'); $return = array(); if ($result && is_array($result) && sizeof($result)) { foreach ($result as $row) { $return[$row['id_feature']]['values'][] = $row['value']; $return[$row['id_feature']]['name'] = $row['name']; $return[$row['id_feature']]['id_feature'] = $row['id_feature']; } foreach ($return as $key => $row) { $return[$key]['value'] = implode($separator, $row['values']); } } if ($id_feature != null && $id_feature && isset($return[$id_feature])) { return $return[$id_feature]['value']; } else { return $return; } } protected function getCurrentProductId() { if (is_object($this->context->controller) && preg_match('/^ProductController/i', get_class($this->context->controller))) { if (method_exists($this->context->controller, 'getProduct')) { $product = $this->context->controller->getProduct(); if (!Validate::isLoadedObject($product)) { $id_product = (int)Tools::getValue('id_product'); if (Validate::isUnsignedId($id_product) && $id_product > 0) { return $id_product; } } } else { $id_product = (int)Tools::getValue('id_product'); if (Validate::isUnsignedId($id_product) && $id_product > 0) { return $id_product; } } if (Validate::isLoadedObject($product)) { return $product->id; } } return false; } public function hookActionGetProductPropertiesBefore($params) { if (!Feature::isFeatureActive()) { return; } if (version_compare(_PS_VERSION_, '1.7.0.0', '>=') && version_compare(_PS_VERSION_, '1.7.1.0', '<')) { if (MFProduct::$preventHookLoop) { return; } $id_product = $this->getCurrentProductId(); if ($id_product && !empty($params['product']) && !empty($params['product']['id_product']) && $params['product']['id_product'] == $id_product) { MFProduct::setProductProperties($params['id_lang'], $params['product'], $this->getFrontFeatures($params['product']['id_product'])); } } } public function hookActionGetProductPropertiesAfter($params) { if (!Feature::isFeatureActive()) { return; } if (version_compare(_PS_VERSION_, '1.7.1.0', '>=')) { $params['product']['features'] = $this->getFrontFeatures($params['product']['id_product']); } } public function hookDisplayOverrideTemplate($params) { if (!Feature::isFeatureActive()) { return; } if (version_compare(_PS_VERSION_, '1.7.0.0', '>=')) { return; } $id_product = $this->getCurrentProductId(); if ($id_product !== false) { $this->context->smarty->assign('features', $this->getFrontFeatures($id_product)); } elseif (isset($this->context->controller) && is_object($this->context->controller) && isset($this->context->controller->php_self) && $this->context->controller->php_self == 'products-comparison') { $ids = null; if (($product_list = Tools::getValue('compare_product_list')) && ($postProducts = (isset($product_list) ? rtrim($product_list, '|') : ''))) { $ids = array_unique(explode('|', $postProducts)); } elseif (isset($this->context->cookie->id_compare)) { $ids = CompareProduct::getCompareProducts($this->context->cookie->id_compare); } $listFeatures = array(); foreach ($ids as $id) { $curProduct = new Product((int)$id, true, $this->context->language->id); if (Validate::isLoadedObject($curProduct) && $curProduct->active && $curProduct->isAssociatedToShop()) { foreach ($curProduct->getFrontFeatures($this->context->language->id) as $feature) { $listFeatures[$curProduct->id][$feature['id_feature']] = $this->getFrontFeatures($curProduct->id, null, $feature['id_feature']); } } } if (sizeof($listFeatures)) { $this->context->smarty->assign(array( 'product_features' => $listFeatures, )); } } } protected function renderForm() { $helper = new HelperForm(); $helper->show_toolbar = false; $helper->table = $this->table; $helper->module = $this; $helper->default_form_language = $this->context->language->id; $helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG', 0); $helper->identifier = $this->identifier; $helper->submit_action = 'submitModuleConfiguration'; $helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false) .'&configure='.$this->name.'&tab_module='.$this->tab.'&module_name='.$this->name; $helper->token = Tools::getAdminTokenLite('AdminModules'); $helper->tpl_vars = array( 'fields_value' => $this->getModuleConfiguration(), 'languages' => $this->context->controller->getLanguages(), 'id_language' => $this->context->language->id, ); return $helper->generateForm(array($this->getConfigForm())); } public function getContent() { if (((bool)Tools::isSubmit('submitModuleConfiguration')) == true) { $this->postProcess(); if (empty($this->context->controller->errors)) { $this->context->controller->confirmations[] = $this->l('Configuration has successfully been saved'); } } elseif (Tools::getIsset('dismissRating')) { if (version_compare(_PS_VERSION_, '1.5.0.0', '>=')) { Configuration::updateGlobalValue('PM_'.self::$_module_prefix.'_DISMISS_RATING', 1); } else { Configuration::updateValue('PM_'.self::$_module_prefix.'_DISMISS_RATING', 1); } die; } $this->context->controller->addCSS($this->_path . 'views/css/admin.css'); if (version_compare(_PS_VERSION_, '1.6.0.0', '<')) { $this->context->controller->addCSS($this->_path . 'views/css/admin15.css'); } $this->context->smarty->assign(array( 'module_dir' => $this->_path, )); return $this->showRating(true) . $this->renderForm() . $this->displaySupport(); } private function postProcess() { if (Tools::getIsset('submitModuleConfiguration') && Tools::isSubmit('submitModuleConfiguration')) { $config = $this->getModuleConfiguration(); foreach (array('featureSeparator') as $configKey) { $config[$configKey] = Tools::getValue($configKey); } $this->setModuleConfiguration($config); } } public function getConfigForm() { return array( 'form' => array( 'input' => array( array( 'type' => 'html', 'html_content' => '

'. $this->l('Configuration') .'

', 'name' => '', ), array( 'type' => 'text', 'label' => $this->l('Features separator'), 'desc' => $this->l('Define here the character used to separate multiple features values'), 'name' => 'featureSeparator', ), ), 'submit' => array( 'title' => $this->l('Save'), ), ), ); } protected function displaySupport() { $pm_addons_products = $this->getAddonsModulesFromApi(); $pm_products = $this->getPMModulesFromApi(); if (!is_array($pm_addons_products)) { $pm_addons_products = array(); } if (!is_array($pm_products)) { $pm_products = array(); } $this->shuffleArray($pm_addons_products); if (is_array($pm_addons_products)) { if (!empty($pm_products['ignoreList']) && is_array($pm_products['ignoreList']) && sizeof($pm_products['ignoreList'])) { foreach ($pm_products['ignoreList'] as $ignoreId) { if (isset($pm_addons_products[$ignoreId])) { unset($pm_addons_products[$ignoreId]); } } } $addonsList = $this->getPMAddons(); if ($addonsList && is_array($addonsList) && sizeof($addonsList)) { foreach (array_keys($addonsList) as $moduleName) { foreach ($pm_addons_products as $k => $pm_addons_product) { if ($pm_addons_product['name'] == $moduleName) { unset($pm_addons_products[$k]); break; } } } } } $vars = array( 'support_links' => (is_array($this->_support_link) && sizeof($this->_support_link) ? $this->_support_link : array()), 'copyright_link' => (is_array($this->_copyright_link) && sizeof($this->_copyright_link) ? $this->_copyright_link : false), 'pm_module_version' => $this->version, 'pm_data' => $this->getPMdata(), 'pm_products' => $pm_products, 'pm_addons_products' => $pm_addons_products, ); return $this->fetchTemplate('core/support.tpl', $vars); } protected function showRating($show = false) { $dismiss = (int)Configuration::getGlobalValue('PM_'.self::$_module_prefix .'_DISMISS_RATING'); if ($show && $dismiss != 1 && $this->getNbDaysModuleUsage() >= 3) { return $this->fetchTemplate('core/rating.tpl'); } return ''; } protected function getAddonsModulesFromApi() { $modules = Configuration::get('PM_' . self::$_module_prefix . '_AM'); $modules_date = Configuration::get('PM_' . self::$_module_prefix . '_AMD'); if ($modules && strtotime('+2 day', $modules_date) > time()) { return Tools::jsonDecode($modules, true); } $jsonResponse = $this->doHttpRequest(); if (empty($jsonResponse->products)) { return array(); } $dataToStore = array(); foreach ($jsonResponse->products as $addonsEntry) { $dataToStore[(int)$addonsEntry->id] = array( 'name' => $addonsEntry->name, 'displayName' => $addonsEntry->displayName, 'url' => $addonsEntry->url, 'compatibility' => $addonsEntry->compatibility, 'version' => $addonsEntry->version, 'description' => $addonsEntry->description, ); } Configuration::updateValue('PM_' . self::$_module_prefix . '_AM', Tools::jsonEncode($dataToStore)); Configuration::updateValue('PM_' . self::$_module_prefix . '_AMD', time()); return Tools::jsonDecode(Configuration::get('PM_' . self::$_module_prefix . '_AM'), true); } protected function getPMModulesFromApi() { $modules = Configuration::get('PM_' . self::$_module_prefix . '_PMM'); $modules_date = Configuration::get('PM_' . self::$_module_prefix . '_PMMD'); if ($modules && strtotime('+2 day', $modules_date) > time()) { return Tools::jsonDecode($modules, true); } $jsonResponse = $this->doHttpRequest(array('list' => $this->getPMAddons()), 'presta-module', 'api-addons'); if (empty($jsonResponse)) { return array(); } Configuration::updateValue('PM_' . self::$_module_prefix . '_PMM', Tools::jsonEncode($jsonResponse)); Configuration::updateValue('PM_' . self::$_module_prefix . '_PMMD', time()); return Tools::jsonDecode(Configuration::get('PM_' . self::$_module_prefix . '_PMM'), true); } protected function getPMAddons() { $pmAddons = array(); $result = Db::getInstance()->ExecuteS('SELECT DISTINCT name FROM '._DB_PREFIX_.'module WHERE name LIKE "pm_%"'); if ($result && is_array($result) && sizeof($result)) { foreach ($result as $module) { $instance = Module::getInstanceByName($module['name']); if ($instance && isset($instance->version)) { $pmAddons[$module['name']] = $instance->version; } } } return $pmAddons; } protected function shuffleArray(&$a) { if (is_array($a) && sizeof($a)) { $ks = array_keys($a); shuffle($ks); $new = array(); foreach ($ks as $k) { $new[$k] = $a[$k]; } $a = $new; return true; } return false; } protected function fetchTemplate($tpl, $customVars = array(), $configOptions = array()) { $this->context->smarty->assign(array( 'ps_major_version' => Tools::substr(str_replace('.', '', _PS_VERSION_), 0, 2), 'module_name' => $this->name, 'module_path' => $this->_path, 'current_iso_lang' => $this->context->language->iso_code, 'current_id_lang' => (int)$this->context->language->id, 'options' => $configOptions, )); if (sizeof($customVars)) { $this->context->smarty->assign($customVars); } return $this->context->smarty->fetch(_PS_MODULE_DIR_ . $this->name . '/views/templates/admin/' . $tpl); } protected function doHttpRequest($data = array(), $c = 'prestashop', $s = 'api.addons') { $data = array_merge(array( 'version' => _PS_VERSION_, 'iso_lang' => Tools::strtolower($this->context->language->iso_code), 'iso_code' => Tools::strtolower(Country::getIsoById(Configuration::get('PS_COUNTRY_DEFAULT'))), 'module_key' => $this->module_key, 'method' => 'contributor', 'action' => 'all_products', ), $data); $postData = http_build_query($data); $context = stream_context_create(array( 'http' => array( 'method' => 'POST', 'content' => $postData, 'header' => 'Content-type: application/x-www-form-urlencoded', 'timeout' => 15, ) )); $response = Tools::file_get_contents('https://' . $s . '.' . $c . '.com', false, $context); if (empty($response)) { return false; } $responseToJson = Tools::jsonDecode($response); if (empty($responseToJson)) { return false; } return $responseToJson; } protected function isTabSubmitted($tab_name) { if (!is_array($this->submitted_tabs)) { $this->submitted_tabs = Tools::getValue('submitted_tabs'); } if (is_array($this->submitted_tabs) && in_array($tab_name, $this->submitted_tabs)) { return true; } return false; } protected function deleteTabSubmitted($tab_name) { if (!is_array($this->submitted_tabs)) { $this->submitted_tabs = Tools::getValue('submitted_tabs'); } if (is_array($this->submitted_tabs) && in_array($tab_name, $this->submitted_tabs)) { unset($_POST['submitted_tabs'][array_search($tab_name, $_POST['submitted_tabs'])]); } } private function _initBackOfficeAssets($idProduct) { $idLang = (int)$this->context->cookie->id_lang; $obj = new Product($idProduct); if (Validate::isLoadedObject($obj)) { $selectedFeaturesList = array(); $selectedFeatures = self::getProductFeaturesStatic($obj->id, (int)$idLang, false); foreach ($selectedFeatures as $feature) { if (!isset($selectedFeaturesList[(int)$feature['id_feature']])) { $selectedFeaturesList[(int)$feature['id_feature']] = array(); } $selectedFeaturesList[(int)$feature['id_feature']][] = (int)$feature['id_feature_value']; } if (version_compare(_PS_VERSION_, '1.7.0.0', '>=')) { Media::addJsDef( array( 'pm_FeatureList' => $selectedFeaturesList, 'pm_FeatureAvailableListTitle' => $this->l('Available features:'), 'pm_FeatureAvailableListSearchTitle' => $this->l('Available features (%nbResults% found):'), 'pm_FeatureSearchInputPlaceHolder' => $this->l('Search'), 'pm_FeatureSelectedListTitle' => $this->l('Selected features:'), 'pm_FeatureAddAllButtonLabel' => $this->l('Add all'), 'pm_FeatureRemoveAllButtonLabel' => $this->l('Remove all'), ) ); } else { echo ' '; } if (version_compare(_PS_VERSION_, '1.5.0.0', '>=') && version_compare(_PS_VERSION_, '1.7.0.0', '<')) { echo ' '; } } } protected function getCurrentProductIdFromRequest() { try { // Note Team Validation - Requiert une globale pour obtenir l'objet Request global $kernel; if (version_compare(_PS_VERSION_, '1.7.4.0', '>=')) { $request = $kernel->getContainer()->get('request_stack')->getCurrentRequest(); } else { $request = $kernel->getContainer()->get('request'); } if (!is_object($request)) { return null; } $currentIdProduct = $request->get('id'); return (int)$currentIdProduct; } catch (Exception $e) { } return null; } protected function processMultipleFeatures($product, $refreshProduct = false) { if ($refreshProduct) { $product = new Product($product->id); } $product->deleteFeatures(); $languages = Language::getLanguages(false); $hasCustom = array(); if (isset($_POST['form']['step1']['features']) && is_array($_POST['form']['step1']['features'])) { foreach ($_POST['form']['step1']['features'] as $key => $val) { if (empty($val['feature'])) { continue; } if (is_array($val['custom_value'])) { $hasCustom[(int)$val['feature']] = true; $default_value = $this->checkFeatures($languages, (int)$val['feature'], true); $id_value = $product->addFeaturesToDB((int)$val['feature'], 0, 1); foreach ($languages as $language) { if ($cust = $val['custom_value'][(int)$language['id_lang']]) { $product->addFeaturesCustomToDB($id_value, (int)$language['id_lang'], $cust); } else { $product->addFeaturesCustomToDB($id_value, (int)$language['id_lang'], $default_value); } } } } } foreach ($_POST as $key => $val) { if (preg_match('/^pm_multiplefeatures_feature_([0-9]+)_custom_value_([0-9]+)/i', $key, $match)) { if (empty($match[1])) { continue; } if ($match[2] == Configuration::get('PS_LANG_DEFAULT') && $val) { $hasCustom[(int)$match[1]] = true; if ($default_value = $this->checkFeatures($languages, $match[1])) { $id_value = $product->addFeaturesToDB($match[1], 0, 1); foreach ($languages as $language) { if ($cust = Tools::getValue('pm_multiplefeatures_feature_'.$match[1].'_custom_value_'.(int)$language['id_lang'])) { $product->addFeaturesCustomToDB($id_value, (int)$language['id_lang'], $cust); } else { $product->addFeaturesCustomToDB($id_value, (int)$language['id_lang'], $default_value); } } } } } } foreach ($_POST as $key => $val) { if (preg_match('/^pm_multiplefeatures_feature_([0-9]+)_value/i', $key, $match)) { if (empty($match[1])) { continue; } if (empty($hasCustom[(int)$match[1]]) && preg_match('/^pm_multiplefeatures_feature/i', $key) && ((is_array($val) && sizeof($val)) || (!is_array($val) && $val))) { if (is_array($val)) { foreach ($val as $pos => $val2) { $id_feature = (int)$match[1]; $id_feature_value = (int)$val2; if (empty($id_feature_value)) { continue; } $row = array( 'id_feature' => (int)$id_feature, 'id_product' => (int)$product->id, 'id_feature_value' => (int)$id_feature_value, 'position' => (int)$pos, ); Db::getInstance()->insert('feature_product', $row); } SpecificPriceRule::applyAllRules(array((int)$product->id)); } else { $product->addFeaturesToDB($match[1], $val); } } } } self::$preventHookLoop = true; $product->save(); self::$preventHookLoop = false; } public function customShutdownProcess($product) { if (self::$preventHookLoop) { return; } $this->processMultipleFeatures($product, true); } private static $preventHookLoop = false; public function hookActionProductUpdate($params) { static $registerShutdownFunction = false; if (self::$preventHookLoop) { return; } if (version_compare(_PS_VERSION_, '1.7.0.0', '>=') && ($this->context->controller instanceof AdminProductsControllerCore || $this->context->controller instanceof AdminProductsController) && Tools::getValue('id_product')) { if (!empty($params['product'])) { $product = $params['product']; } else { $product = new Product((int)Tools::getValue('id_product')); } if (Validate::isLoadedObject($product)) { if (version_compare(_PS_VERSION_, '1.7.0.0', '>=') && !$registerShutdownFunction) { $registerShutdownFunction = true; register_shutdown_function(array($this, 'customShutdownProcess'), $product); } else { $this->processMultipleFeatures($product); } } } } public function hookActionProductAttributeUpdate($params) { static $alreadyRun = false; if (!$alreadyRun) { $this->hookActionProductUpdate($params); $alreadyRun = true; } } public function hookActionAdminControllerSetMedia($params) { if (version_compare(_PS_VERSION_, '1.7.6.0', '>=') && isset($this->context->controller->controller_name) && $this->context->controller->controller_name == 'AdminProducts') { $idProduct = (int)$this->getCurrentProductIdFromRequest(); if (empty($idProduct)) { return; } $this->context->controller->addJqueryUI('ui.core'); $this->context->controller->addJqueryUI('ui.widget'); $this->context->controller->addJqueryUI('ui.mouse'); $this->context->controller->addJqueryUI('ui.draggable'); $this->context->controller->addJqueryUI('ui.sortable'); $this->context->controller->addJqueryUI('ui.droppable'); $this->context->controller->addCSS($this->_path . 'views/css/connected-list/connected-list.min.css', 'all'); $this->context->controller->addJS($this->_path . 'views/js/connected-list/connected-list.min.js'); $this->context->controller->addJS($this->_path . 'views/js/product-tab-17.js'); $this->_initBackOfficeAssets($idProduct); } } public function hookBackOfficeHeader($params) { if (!$this->active) { return; } if (version_compare(_PS_VERSION_, '1.7.0.0', '>=') && version_compare(_PS_VERSION_, '1.7.6.0', '<') && isset($this->context->controller->controller_name) && $this->context->controller->controller_name == 'AdminProducts') { $idProduct = (int)$this->getCurrentProductIdFromRequest(); if (empty($idProduct)) { return; } $this->context->controller->addJquery(); $this->context->controller->addJqueryUI('ui.core'); $this->context->controller->addJqueryUI('ui.widget'); $this->context->controller->addJqueryUI('ui.mouse'); $this->context->controller->addJqueryUI('ui.draggable'); $this->context->controller->addJqueryUI('ui.sortable'); $this->context->controller->addJqueryUI('ui.droppable'); $this->context->controller->addCSS($this->_path . 'views/css/connected-list/connected-list.min.css', 'all'); $this->context->controller->addJS($this->_path . 'views/js/connected-list/connected-list.min.js'); $this->context->controller->addJS($this->_path . 'views/js/product-tab-17.js'); $this->_initBackOfficeAssets($idProduct); } elseif (version_compare(_PS_VERSION_, '1.5.0.0', '>=') && (Tools::getValue('controller') == 'adminproducts' || Tools::getValue('controller') == 'AdminProducts') && Tools::getValue('id_product')) { $this->context->controller->addJquery(); $this->context->controller->addJqueryUI('ui.core'); $this->context->controller->addJqueryUI('ui.widget'); $this->context->controller->addJqueryUI('ui.mouse'); $this->context->controller->addJqueryUI('ui.draggable'); $this->context->controller->addJqueryUI('ui.sortable'); $this->context->controller->addJqueryUI('ui.droppable'); $this->context->controller->addCSS($this->_path . 'views/css/connected-list/connected-list.min.css', 'all'); $this->context->controller->addJS($this->_path . 'views/js/connected-list/connected-list.min.js'); $this->context->controller->addJS($this->_path . 'views/js/product-tab.js'); } if (version_compare(_PS_VERSION_, '1.5.0.0', '>=') && ((Tools::getValue('controller') == 'adminproducts' || Tools::getValue('controller') == 'AdminProducts') && Tools::getValue('id_product') && (Tools::getIsset('updateproduct') || Tools::getIsset('addproduct')) && Tools::getIsset('ajax') && Tools::getValue('action') == 'Features')) { $this->_initBackOfficeAssets(Tools::getValue('id_product')); } elseif (version_compare(_PS_VERSION_, '1.5.0.0', '>=') && $this->isTabSubmitted('Features')) { if (Validate::isLoadedObject($product = new Product((int)(Tools::getValue('id_product'))))) { $product->deleteFeatures(); $languages = Language::getLanguages(false); foreach ($_POST as $key => $val) { if (preg_match('/^(?:feature|custom)_([0-9]+)_(value|[0-9]+)/i', $key, $match)) { if (preg_match('/^feature/i', $key) && ((is_array($val) && sizeof($val)) || (!is_array($val) && $val))) { if (is_array($val)) { foreach ($val as $pos => $val2) { $id_feature = (int)$match[1]; $id_feature_value = (int)$val2; if (empty($id_feature) || empty($id_feature_value)) { continue; } $row = array( 'id_feature' => (int)$id_feature, 'id_product' => (int)$product->id, 'id_feature_value' => (int)$id_feature_value, 'position' => (int)$pos, ); Db::getInstance()->insert('feature_product', $row); } SpecificPriceRule::applyAllRules(array((int)$product->id)); } else { $product->addFeaturesToDB($match[1], $val); } } elseif (preg_match('/^custom/i', $key) && $match[2] == Configuration::get('PS_LANG_DEFAULT') && $val) { if ($default_value = $this->checkFeatures($languages, $match[1])) { $id_value = $product->addFeaturesToDB($match[1], 0, 1); foreach ($languages as $language) { if ($cust = Tools::getValue('custom_'.$match[1].'_'.(int)$language['id_lang'])) { $product->addFeaturesCustomToDB($id_value, (int)$language['id_lang'], $cust); } else { $product->addFeaturesCustomToDB($id_value, (int)$language['id_lang'], $default_value); } } } } } } $this->deleteTabSubmitted('Features'); } } elseif (Tools::getValue('key_tab') == 'Features') { $_GET['key_tab_onload'] = 'Features'; unset($_GET['key_tab']); } } public function hookBackOfficeTop($params) { if (version_compare(_PS_VERSION_, '1.7.0.0', '>=')) { return; } if ((Tools::getValue('tab') == 'AdminCatalog' && Tools::getValue('id_product') && (Tools::getIsset('updateproduct') || Tools::getIsset('addproduct'))) || (Tools::getValue('controller') == 'adminproducts' || Tools::getValue('controller') == 'AdminProducts') && Tools::getValue('id_product') && (Tools::getIsset('updateproduct') || Tools::getIsset('addproduct')) && !Tools::getIsset('ajax')) { if (Tools::getValue('key_tab_onload') == 'Features') { return ' '; } } } public static function isFilledArray($array) { return ($array && is_array($array) && sizeof($array)); } protected static function getDataSerialized($data, $type = 'base64') { if (is_array($data)) { return array_map($type . '_encode', array($data)); } else { return current(array_map($type . '_encode', array($data))); } } protected static function getDataUnserialized($data, $type = 'base64') { if (is_array($data)) { return array_map($type . '_decode', array($data)); } else { return current(array_map($type . '_decode', array($data))); } } private function getPMdata() { $param = array(); $param[] = 'ver-'._PS_VERSION_; $param[] = 'current-'.$this->name; $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS('SELECT DISTINCT name FROM '._DB_PREFIX_.'module WHERE name LIKE "pm_%"'); if ($result && self::isFilledArray($result)) { foreach ($result as $module) { $instance = Module::getInstanceByName($module['name']); if ($instance && isset($instance->version)) { $param[] = $module['name'].'-'.$instance->version; } } } return urlencode(self::getDataSerialized(implode('|', $param))); } private static function getNbDaysModuleUsage() { $sql = 'SELECT DATEDIFF(NOW(),date_add) FROM '._DB_PREFIX_.'configuration WHERE name = \''.pSQL('PM_'.self::$_module_prefix.'_LAST_VERSION').'\' ORDER BY date_add ASC'; return (int)Db::getInstance()->getValue($sql); } protected function onBackOffice() { if (isset($this->context->cookie->id_employee) && Validate::isUnsignedId($this->context->cookie->id_employee)) { return true; } return false; } protected function getModuleConfiguration() { $conf = Configuration::get('PM_' . self::$_module_prefix . '_CONF'); if (!empty($conf)) { return Tools::jsonDecode($conf, true); } else { return $this->defaultConfiguration; } } public static function getModuleConfigurationStatic() { $conf = Configuration::get('PM_' . self::$_module_prefix . '_CONF'); if (!empty($conf)) { return Tools::jsonDecode($conf, true); } else { return array(); } } protected function setModuleConfiguration($newConf) { Configuration::updateValue('PM_' . self::$_module_prefix . '_CONF', Tools::jsonEncode($newConf)); } protected function setDefaultConfiguration() { if (!is_array($this->getModuleConfiguration()) || !sizeof($this->getModuleConfiguration())) { Configuration::updateValue('PM_' . self::$_module_prefix . '_CONF', Tools::jsonEncode($this->defaultConfiguration)); } return true; } } if (version_compare(_PS_VERSION_, '1.7.0.0', '>=') && version_compare(_PS_VERSION_, '1.7.1.0', '<')) { class MFProduct extends Product { public static $preventHookLoop = false; public static function setProductProperties($id_lang, $row, $features) { self::$preventHookLoop = true; $row = parent::getProductProperties($id_lang, $row); self::$preventHookLoop = false; $id_product_attribute = $row['id_product_attribute'] = (!empty($row['id_product_attribute']) ? (int)$row['id_product_attribute'] : null); $row['allow_oosp'] = Product::isAvailableWhenOutOfStock($row['out_of_stock']); if (Combination::isFeatureActive() && $id_product_attribute === null && ((isset($row['cache_default_attribute']) && ($ipa_default = $row['cache_default_attribute']) !== null) || ($ipa_default = Product::getDefaultAttribute($row['id_product'], !$row['allow_oosp'])))) { $id_product_attribute = $row['id_product_attribute'] = $ipa_default; } if (!Combination::isFeatureActive() || !isset($row['id_product_attribute'])) { $id_product_attribute = $row['id_product_attribute'] = 0; } $usetax = !Tax::excludeTaxeOption(); $cache_key = $row['id_product'].'-'.$id_product_attribute.'-'.$id_lang.'-'.(int)$usetax; if (isset($row['id_product_pack'])) { $cache_key .= '-pack'.$row['id_product_pack']; } $row['features'] = $features; self::$producPropertiesCache[$cache_key] = $row; } } }