* @copyright 2007-2011 PrestaShop SA * @version Release: $Revision: 10322 $ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) * International Registered Trademark & Property of PrestaShop SA */ abstract class ModuleCore { /** @var integer Module ID */ public $id = NULL; /** @var float Version */ public $version; /** @var string Unique name */ public $name; /** @var string Human name */ public $displayName; /** @var string A little description of the module */ public $description; /** @var string author of the module */ public $author; /** @var int need_instance */ public $need_instance = 1; /** @var string Admin tab correponding to the module */ public $tab = NULL; /** @var boolean Status */ public $active = false; /** @var array current language translations */ protected $_lang = array(); /** @var string Module web path (eg. '/shop/modules/modulename/') */ protected $_path = NULL; /** @var string Fill it if the module is installed but not yet set up */ public $warning; /** @var string Message display before uninstall a module */ public $beforeUninstall = NULL; protected $_errors = false; protected $table = 'module'; protected $identifier = 'id_module'; public static $_db; /** @var array to store the limited country */ public $limited_countries = array(); /** * Constructor * * @param string $name Module unique name */ protected static $modulesCache; protected static $_hookModulesCache; protected static $_INSTANCE = array(); protected static $_generateConfigXmlMode = false; protected static $l_cache = array(); /** * @var array used by AdminTab to determine which lang file to use (admin.php or module lang file) */ public static $classInModule = array(); public function __construct($name = NULL) { if ($this->name == NULL) $this->name = $this->id; if ($this->name != NULL) { if (self::$modulesCache == NULL AND !is_array(self::$modulesCache)) { self::$modulesCache = array(); $result = Db::getInstance()->ExecuteS('SELECT * FROM `'.pSQL(_DB_PREFIX_.$this->table).'`'); foreach ($result as $row) self::$modulesCache[$row['name']] = $row; } if (isset(self::$modulesCache[$this->name])) { $this->active = true; $this->id = self::$modulesCache[$this->name]['id_module']; foreach (self::$modulesCache[$this->name] AS $key => $value) if (key_exists($key, $this)) $this->{$key} = $value; $this->_path = __PS_BASE_URI__.'modules/'.$this->name.'/'; } } } /** * Insert module into datable */ public function install() { if (!Validate::isModuleName($this->name)) die(Tools::displayError()); $result = Db::getInstance()->getRow(' SELECT `id_module` FROM `'._DB_PREFIX_.'module` WHERE `name` = \''.pSQL($this->name).'\''); if ($result) return false; $result = Db::getInstance()->AutoExecute(_DB_PREFIX_.$this->table, array('name' => $this->name, 'active' => 1), 'INSERT'); if (!$result) return false; $this->id = Db::getInstance()->Insert_ID(); return true; } /** * Delete module from datable * * @return boolean result */ public function uninstall() { if (!Validate::isUnsignedId($this->id)) return false; $result = Db::getInstance()->ExecuteS(' SELECT `id_hook` FROM `'._DB_PREFIX_.'hook_module` hm WHERE `id_module` = '.(int)($this->id)); foreach ($result AS $row) { Db::getInstance()->Execute(' DELETE FROM `'._DB_PREFIX_.'hook_module` WHERE `id_module` = '.(int)($this->id).' AND `id_hook` = '.(int)($row['id_hook'])); $this->cleanPositions($row['id_hook']); } return Db::getInstance()->Execute(' DELETE FROM `'._DB_PREFIX_.'module` WHERE `id_module` = '.(int)($this->id)); } /** * This function enable module $name. If an $name is an array, * this will enable all of them * * @param array|string $name * @return true if succeed * @since 1.4.1 */ public static function enableByName($name) { if (!is_array($name)) $name = array($name); foreach ($name as $k=>$v) $name[$k] = '"'.pSQL($v).'"'; return Db::getInstance()->Execute(' UPDATE `'._DB_PREFIX_.'module` SET `active`= 1 WHERE `name` IN ('.implode(',',$name).')'); } /** * Called when module is set to active */ public function enable() { return Db::getInstance()->Execute(' UPDATE `'._DB_PREFIX_.'module` SET `active`= 1 WHERE `name` = \''.pSQL($this->name).'\''); } /** * This function disable module $name. If an $name is an array, * this will disable all of them * * @param array|string $name * @return true if succeed * @since 1.4.1 */ public static function disableByName($name) { if (!is_array($name)) $name = array($name); foreach ($name as $k=>$v) $name[$k] = '"'.pSQL($v).'"'; return Db::getInstance()->Execute(' UPDATE `'._DB_PREFIX_.'module` SET `active`= 0 WHERE `name` IN ('.implode(',',$name).')'); } /** * Called when module is set to deactive */ public function disable() { return Module::disableByName($this->name); } /** * Connect module to a hook * * @param string $hook_name Hook name * @return boolean result */ public function registerHook($hook_name) { if (!Validate::isHookName($hook_name)) die(Tools::displayError()); if (!isset($this->id) OR !is_numeric($this->id)) return false; // Check if already register $result = Db::getInstance()->getRow(' SELECT hm.`id_module` FROM `'._DB_PREFIX_.'hook_module` hm, `'._DB_PREFIX_.'hook` h WHERE hm.`id_module` = '.(int)($this->id).' AND h.`name` = \''.pSQL($hook_name).'\' AND h.`id_hook` = hm.`id_hook`'); if ($result) return true; // Get hook id $result = Db::getInstance()->getRow(' SELECT `id_hook` FROM `'._DB_PREFIX_.'hook` WHERE `name` = \''.pSQL($hook_name).'\''); if (!isset($result['id_hook'])) return false; // Get module position in hook $result2 = Db::getInstance()->getRow(' SELECT MAX(`position`) AS position FROM `'._DB_PREFIX_.'hook_module` WHERE `id_hook` = '.(int)($result['id_hook'])); if (!$result2) return false; // Register module in hook $return = Db::getInstance()->Execute(' INSERT INTO `'._DB_PREFIX_.'hook_module` (`id_module`, `id_hook`, `position`) VALUES ('.(int)($this->id).', '.(int)($result['id_hook']).', '.(int)($result2['position'] + 1).')'); $this->cleanPositions((int)($result['id_hook'])); return $return; } /** * Display flags in forms for translations * * @param array $languages All languages available * @param integer $default_language Default language id * @param string $ids Multilingual div ids in form * @param string $id Current div id] * @param boolean $return define the return way : false for a display, true for a return * @param boolean $use_vars_instead_of_ids use an js vars instead of ids seperate by "ยค" */ public function displayFlags($languages, $default_language, $ids, $id, $return = false, $use_vars_instead_of_ids = false) { if (sizeof($languages) == 1) return false; $output = '
'.$this->l('Choose language:').'

'; foreach ($languages as $language) if($use_vars_instead_of_ids) $output .= ''.$language['name'].' '; else $output .= ''.$language['name'].' '; $output .= '
'; if ($return) return $output; echo $output; } /** * Unregister module from hook * * @param int $id_hook Hook id * @return boolean result */ public function unregisterHook($hook_id) { return Db::getInstance()->Execute(' DELETE FROM `'._DB_PREFIX_.'hook_module` WHERE `id_module` = '.(int)($this->id).' AND `id_hook` = '.(int)($hook_id)); } /** * Unregister exceptions linked to module * * @param int $id_hook Hook id * @return boolean result */ public function unregisterExceptions($hook_id) { return Db::getInstance()->Execute(' DELETE FROM `'._DB_PREFIX_.'hook_module_exceptions` WHERE `id_module` = '.(int)($this->id).' AND `id_hook` = '.(int)($hook_id)); } /** * Add exceptions for module->Hook * * @param int $id_hook Hook id * @param array $excepts List of file name * @return boolean result */ public function registerExceptions($id_hook, $excepts) { foreach ($excepts AS $except) { if (!empty($except)) { $result = Db::getInstance()->Execute(' INSERT INTO `'._DB_PREFIX_.'hook_module_exceptions` (`id_module`, `id_hook`, `file_name`) VALUES ('.(int)($this->id).', '.(int)($id_hook).', \''.pSQL(strval($except)).'\')'); if (!$result) return false; } } return true; } public function editExceptions($id_hook, $excepts) { // Cleaning... Db::getInstance()->Execute(' DELETE FROM `'._DB_PREFIX_.'hook_module_exceptions` WHERE `id_module` = '.(int)($this->id).' AND `id_hook` ='.(int)($id_hook)); return $this->registerExceptions($id_hook, $excepts); } /** * This function is used to determine the module name * of an AdminTab which belongs to a module, in order to keep translation * related to a module in its directory (instead of $_LANGADM) * * @param mixed $currentClass the * @return boolean|string if the class belongs to a module, will return the module name. Otherwise, return false. */ public static function getModuleNameFromClass($currentClass) { global $cookie; // Module can now define AdminTab keeping the module translations method, // i.e. in modules/[module name]/[iso_code].php if (!isset(self::$classInModule[$currentClass])) { global $_MODULES; $_MODULE = array(); $reflectionClass = new ReflectionClass($currentClass); $filePath = realpath($reflectionClass->getFileName()); $realpathModuleDir = realpath(_PS_MODULE_DIR_); if (substr(realpath($filePath), 0, strlen($realpathModuleDir)) == $realpathModuleDir) { self::$classInModule[$currentClass] = substr(dirname($filePath), strlen($realpathModuleDir)+1); $id_lang = (!isset($cookie) OR !is_object($cookie)) ? (int)(Configuration::get('PS_LANG_DEFAULT')) : (int)($cookie->id_lang); $file = _PS_MODULE_DIR_.self::$classInModule[$currentClass].'/'.Language::getIsoById($id_lang).'.php'; if (Tools::file_exists_cache($file) AND include_once($file)) $_MODULES = !empty($_MODULES) ? array_merge($_MODULES, $_MODULE) : $_MODULE; } else self::$classInModule[$currentClass] = false; } // return name of the module, or false return self::$classInModule[$currentClass]; } /** * Return an instance of the specified module * * @param string $moduleName Module name * @return Module instance */ public static function getInstanceByName($moduleName) { if (!Tools::file_exists_cache(_PS_MODULE_DIR_.$moduleName.'/'.$moduleName.'.php')) return false; include_once(_PS_MODULE_DIR_.$moduleName.'/'.$moduleName.'.php'); if (!class_exists($moduleName, false)) return false; if (!isset(self::$_INSTANCE[$moduleName])) self::$_INSTANCE[$moduleName] = new $moduleName; return self::$_INSTANCE[$moduleName]; } /** * Load modules Ids from Ids * * @param array|int $ids Modules ID * @return Array of module name */ public static function preloadModuleNameFromId($ids) { static $preloadedModuleNameFromId; if (!isset($preloadedModuleNameFromId)) { $preloadedModuleNameFromId = array(); } if (is_array($ids)) { foreach($ids as $id) $preloadedModuleNameFromId[$id] = false; $results = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' SELECT `name`,`id_module` FROM `'._DB_PREFIX_.'module` WHERE `id_module` IN ('.join(',',$ids) .');'); foreach($results as $result) $preloadedModuleNameFromId[$result['id_module']] = $result['name']; } elseif (!isset($preloadedModuleNameFromId[$ids])) { $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow(' SELECT `name` FROM `'._DB_PREFIX_.'module` WHERE `id_module` = '.(int)($ids)); if ($result) $preloadedModuleNameFromId[$ids] = $result['name']; else $preloadedModuleNameFromId[$ids] = false; } if (is_array($ids)) { return $preloadedModuleNameFromId; } else { if (!isset($preloadedModuleNameFromId[$ids])) return false; return $preloadedModuleNameFromId[$ids]; } } /** * Return an instance of the specified module * * @param integer $id_module Module ID * @return Module instance */ public static function getInstanceById($id_module) { $moduleName = Module::preloadModuleNameFromId($id_module); return ($moduleName ? Module::getInstanceByName($moduleName) : false); } public static function configXmlStringFormat($string) { return str_replace('\'', '\\\'', Tools::htmlentitiesDecodeUTF8($string)); } /** * Return available modules * * @param boolean $useConfig in order to use config.xml file in module dir * @return array Modules */ public static function getModulesOnDisk($useConfig = false) { global $cookie, $_MODULES; $moduleList = array(); $moduleListCursor = 0; $moduleNameList = array(); $modulesNameToCursor = array(); $errors = array(); $modules_dir = self::getModulesDirOnDisk(); $memory_limit = Tools::getMemoryLimit(); foreach ($modules_dir AS $module) { // Memory usage checking if (function_exists('memory_get_usage') && $memory_limit !== -1) { $current_memory = memory_get_usage(true); // memory_threshold in MB $memory_threshold = (Tools::isX86_64arch() ? 3 : 1.5); if (($memory_limit - $current_memory) <= ($memory_threshold * 1024 * 1024)) { $errors[] = Tools::displayError('All modules cannot be loaded due to memory limit restriction reason, please increase your memory_limit value on your server configuration'); break; } } $configFile = _PS_MODULE_DIR_.$module.'/config.xml'; $xml_exist = file_exists($configFile); if ($xml_exist) $needNewConfigFile = (filemtime($configFile) < filemtime(_PS_MODULE_DIR_.$module.'/'.$module.'.php')); else $needNewConfigFile = true; if ($useConfig AND $xml_exist) { libxml_use_internal_errors(true); $xml_module = simplexml_load_file($configFile); foreach (libxml_get_errors() as $error) $errors[] = '['.$module.'] '.Tools::displayError('Error found in config file:').' '.htmlentities($error->message); libxml_clear_errors(); if (!count($errors) AND (int)$xml_module->need_instance == 0 AND !$needNewConfigFile) { $file = _PS_MODULE_DIR_.$module.'/'.Language::getIsoById($cookie->id_lang).'.php'; if (Tools::file_exists_cache($file) AND include_once($file)) if (isset($_MODULE) AND is_array($_MODULE)) $_MODULES = !empty($_MODULES) ? array_merge($_MODULES, $_MODULE) : $_MODULE; $xml_module->displayName = Module::findTranslation($xml_module->name, self::configXmlStringFormat($xml_module->displayName), (string)$xml_module->name); $xml_module->description = Module::findTranslation($xml_module->name, self::configXmlStringFormat($xml_module->description), (string)$xml_module->name); $xml_module->author = Module::findTranslation($xml_module->name, self::configXmlStringFormat($xml_module->author), (string)$xml_module->name); if (isset($xml_module->confirmUninstall)) $xml_module->confirmUninstall = Module::findTranslation($xml_module->name, self::configXmlStringFormat($xml_module->confirmUninstall), (string)$xml_module->name); $moduleList[$moduleListCursor] = $xml_module; $moduleNameList[$moduleListCursor] = '\''.strval($xml_module->name).'\''; $modulesNameToCursor[strval($xml_module->name)] = $moduleListCursor; $moduleListCursor++; } } if (!$useConfig OR !$xml_exist OR (isset($xml_module->need_instance) AND (int)$xml_module->need_instance == 1) OR $needNewConfigFile) { // If class already exists, don't include the file if (!class_exists($module, false)) { $filepath = _PS_MODULE_DIR_.$module.'/'.$module.'.php'; $file = trim(file_get_contents(_PS_MODULE_DIR_.$module.'/'.$module.'.php')); if (substr($file, 0, 5) == '') $file = substr($file, 0, -2); // if (false) is a trick to not load the class with "eval". // this way require_once will works correctly if (eval('if (false){ '.$file.' }') !== false) require_once( _PS_MODULE_DIR_.$module.'/'.$module.'.php' ); else $errors[] = sprintf(Tools::displayError('%1$s (parse error in %2$s)'), $module, substr($filepath, strlen(_PS_ROOT_DIR_))); } if (class_exists($module,false)) { $moduleList[$moduleListCursor++] = new $module; if (!$xml_exist OR $needNewConfigFile) { self::$_generateConfigXmlMode = true; $tmpModule = new $module; $tmpModule->_generateConfigXml(); self::$_generateConfigXmlMode = false; } } else $errors[] = sprintf(Tools::displayError('%1$s (class missing in %2$s)'), $module, substr($filepath, strlen(_PS_ROOT_DIR_))); } } // Get modules information from database if (!empty($moduleNameList)) { $results = Db::getInstance()->executeS('SELECT `id_module`, `active`, `name` FROM `'._DB_PREFIX_.'module` WHERE `name` IN ('.join(',',$moduleNameList).')'); foreach($results as $result) { $moduleCursor = $modulesNameToCursor[$result['name']]; if (isset($result['active']) AND $result['active']) $moduleList[$moduleCursor]->active = $result['active']; if (isset($result['id_module']) AND $result['id_module']) $moduleList[$moduleCursor]->id = $result['id_module']; } } if (sizeof($errors)) { echo '

'.Tools::displayError('The following module(s) couldn\'t be loaded').':

    '; foreach ($errors AS $error) echo '
  1. '.$error.'
  2. '; echo '
'; } return $moduleList; } public static function getModulesDirOnDisk() { $moduleList = array(); $modules = scandir(_PS_MODULE_DIR_); foreach ($modules AS $name) { if (is_dir(_PS_MODULE_DIR_.$name) && Tools::file_exists_cache(_PS_MODULE_DIR_.$name.'/'.$name.'.php')) { if (!Validate::isModuleName($name)) die(Tools::displayError().' (Module '.$name.')'); $moduleList[] = $name; } } return $moduleList; } /** * Return non native module * * @param int $position Take only positionnables modules * @return array Modules */ public static function getNonNativeModuleList() { $db = Db::getInstance(); $module_list_xml = _PS_ROOT_DIR_.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'modules_list.xml'; $nativeModules = simplexml_load_file($module_list_xml); $nativeModules = $nativeModules->modules; foreach ($nativeModules as $nativeModulesType) if (in_array($nativeModulesType['type'],array('native','partner'))) { $arrNativeModules[] = '""'; foreach ($nativeModulesType->module as $module) $arrNativeModules[] = '"'.pSQL($module['name']).'"'; } return $db->ExecuteS(' SELECT * FROM `'._DB_PREFIX_.'module` m WHERE name NOT IN ('.implode(',',$arrNativeModules).') '); } /** * Return installed modules * * @param int $position Take only positionnables modules * @return array Modules */ public static function getModulesInstalled($position = 0) { return Db::getInstance()->ExecuteS(' SELECT * FROM `'._DB_PREFIX_.'module` m '.($position ? ' LEFT JOIN `'._DB_PREFIX_.'hook_module` hm ON m.`id_module` = hm.`id_module` LEFT JOIN `'._DB_PREFIX_.'hook` k ON hm.`id_hook` = k.`id_hook` WHERE k.`position` = 1' : '')); } /* * Execute modules for specified hook * * @param string $hook_name Hook Name * @param array $hookArgs Parameters for the functions * @return string modules output */ public static function hookExec($hook_name, $hookArgs = array(), $id_module = NULL) { global $cookie; if ((!empty($id_module) AND !Validate::isUnsignedId($id_module)) OR !Validate::isHookName($hook_name)) die(Tools::displayError()); global $cart, $cookie; $live_edit = false; if (!isset($hookArgs['cookie']) OR !$hookArgs['cookie']) $hookArgs['cookie'] = $cookie; if (!isset($hookArgs['cart']) OR !$hookArgs['cart']) $hookArgs['cart'] = $cart; $hook_name = strtolower($hook_name); if (!isset(self::$_hookModulesCache)) { $db = Db::getInstance(_PS_USE_SQL_SLAVE_); $result = $db->ExecuteS(' SELECT h.`name` as hook, m.`id_module`, h.`id_hook`, m.`name` as module, h.`live_edit` FROM `'._DB_PREFIX_.'module` m LEFT JOIN `'._DB_PREFIX_.'hook_module` hm ON hm.`id_module` = m.`id_module` LEFT JOIN `'._DB_PREFIX_.'hook` h ON hm.`id_hook` = h.`id_hook` AND m.`active` = 1 ORDER BY hm.`position`', false); self::$_hookModulesCache = array(); if ($result) while ($row = $db->nextRow()) { $row['hook'] = strtolower($row['hook']); if (!isset(self::$_hookModulesCache[$row['hook']])) self::$_hookModulesCache[$row['hook']] = array(); self::$_hookModulesCache[$row['hook']][] = array('id_hook' => $row['id_hook'], 'module' => $row['module'], 'id_module' => $row['id_module'], 'live_edit' => $row['live_edit']); } } if (!isset(self::$_hookModulesCache[$hook_name])) return; $altern = 0; $output = ''; foreach (self::$_hookModulesCache[$hook_name] AS $array) { if ($id_module AND $id_module != $array['id_module']) continue; if (!($moduleInstance = Module::getInstanceByName($array['module']))) continue; $exceptions = $moduleInstance->getExceptions((int)$array['id_hook'], (int)$array['id_module']); foreach ($exceptions AS $exception) if (strstr(basename($_SERVER['PHP_SELF']).'?'.$_SERVER['QUERY_STRING'], $exception['file_name']) && !strstr($_SERVER['QUERY_STRING'], $exception['file_name'])) continue 2; if (is_callable(array($moduleInstance, 'hook'.$hook_name))) { $hookArgs['altern'] = ++$altern; $display = call_user_func(array($moduleInstance, 'hook'.$hook_name), $hookArgs); if ($array['live_edit'] && ((Tools::isSubmit('live_edit') AND Tools::getValue('ad') AND (Tools::getValue('liveToken') == sha1(Tools::getValue('ad')._COOKIE_KEY_))))) { $live_edit = true; $output .= '
' .$moduleInstance->displayName.' '.$display.'
'; } else $output .= $display; } } return ($live_edit ? '
' : '').$output.($live_edit ? '
' : ''); } public static function hookExecPayment() { global $cart, $cookie; $hookArgs = array('cookie' => $cookie, 'cart' => $cart); $output = ''; $result = self::getPaymentModules(); if ($result) foreach ($result AS $module) if (($moduleInstance = Module::getInstanceByName($module['name'])) AND is_callable(array($moduleInstance, 'hookpayment'))) if (!$moduleInstance->currencies OR ($moduleInstance->currencies AND sizeof(Currency::checkPaymentCurrencies($moduleInstance->id)))) $output .= call_user_func(array($moduleInstance, 'hookpayment'), $hookArgs); return $output; } /** * Returns the list of the payment module associated to the current customer * @see PaymentModule::getInstalledPaymentModules() if you don't care about the context * * @return array module informations */ public static function getPaymentModules() { global $cart, $cookie; $id_customer = (int)($cookie->id_customer); $billing = new Address((int)($cart->id_address_invoice)); $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS(' SELECT DISTINCT h.`id_hook`, m.`name`, hm.`position` FROM `'._DB_PREFIX_.'module_country` mc LEFT JOIN `'._DB_PREFIX_.'module` m ON m.`id_module` = mc.`id_module` INNER JOIN `'._DB_PREFIX_.'module_group` mg ON (m.`id_module` = mg.`id_module`) INNER JOIN `'._DB_PREFIX_.'customer_group` cg on (cg.`id_group` = mg.`id_group` AND cg.`id_customer` = '.(int)($id_customer).') LEFT JOIN `'._DB_PREFIX_.'hook_module` hm ON hm.`id_module` = m.`id_module` LEFT JOIN `'._DB_PREFIX_.'hook` h ON hm.`id_hook` = h.`id_hook` WHERE h.`name` = \'payment\' AND mc.id_country = '.(int)($billing->id_country).' AND m.`active` = 1 ORDER BY hm.`position`, m.`name` DESC'); return $result; } /** * find translation from $_MODULES and put it in self::$l_cache if not already exist * and return it. * * @param string $name name of the module * @param string $string term to find * @param string $source additional param for building translation key * @return string */ public static function findTranslation($name, $string, $source) { global $_MODULES; $cache_key = $name . '|' . $string . '|' . $source; if (!isset(self::$l_cache[$cache_key])) { if (!is_array($_MODULES)) return str_replace('"', '"', $string); // set array key to lowercase for 1.3 compatibility $_MODULES = array_change_key_case($_MODULES); $currentKey = '<{'.strtolower($name).'}'.strtolower(_THEME_NAME_).'>'.strtolower($source).'_'.md5($string); $defaultKey = '<{'.strtolower($name).'}prestashop>'.strtolower($source).'_'.md5($string); if (isset($_MODULES[$currentKey])) $ret = stripslashes($_MODULES[$currentKey]); elseif (isset($_MODULES[Tools::strtolower($currentKey)])) $ret = stripslashes($_MODULES[Tools::strtolower($currentKey)]); elseif (isset($_MODULES[$defaultKey])) $ret = stripslashes($_MODULES[$defaultKey]); elseif (isset($_MODULES[Tools::strtolower($defaultKey)])) $ret = stripslashes($_MODULES[Tools::strtolower($defaultKey)]); else $ret = stripslashes($string); self::$l_cache[$cache_key] = str_replace('"', '"', $ret); } return self::$l_cache[$cache_key]; } /** * Get translation for a given module text * * Note: $specific parameter is mandatory for library files. * Otherwise, translation key will not match for Module library * when module is loaded with eval() Module::getModulesOnDisk() * * @param string $string String to translate * @param boolean|string $specific filename to use in translation key * @return string Translation */ public function l($string, $specific = false, $id_lang = null) { if (self::$_generateConfigXmlMode) return $string; global $_MODULES, $_MODULE, $cookie; if ($id_lang == null) $id_lang = (!isset($cookie) OR !is_object($cookie)) ? (int)(Configuration::get('PS_LANG_DEFAULT')) : (int)($cookie->id_lang); $file = _PS_MODULE_DIR_.$this->name.'/'.Language::getIsoById($id_lang).'.php'; if (Tools::file_exists_cache($file) AND include_once($file)) $_MODULES = !empty($_MODULES) ? array_merge($_MODULES, $_MODULE) : $_MODULE; $source = $specific ? $specific : $this->name; $string = str_replace('\'', '\\\'', $string); $ret = $this->findTranslation($this->name, $string, $source); return $ret; } /* * Reposition module * * @param boolean $id_hook Hook ID * @param boolean $way Up (1) or Down (0) * @param intger $position */ public function updatePosition($id_hook, $way, $position = NULL) { if (!$res = Db::getInstance()->ExecuteS(' SELECT hm.`id_module`, hm.`position`, hm.`id_hook` FROM `'._DB_PREFIX_.'hook_module` hm WHERE hm.`id_hook` = '.(int)($id_hook).' ORDER BY hm.`position` '.((int)($way) ? 'ASC' : 'DESC'))) return false; foreach ($res AS $key => $values) if ((int)($values[$this->identifier]) == (int)($this->id)) { $k = $key ; break ; } if (!isset($k) OR !isset($res[$k]) OR !isset($res[$k + 1])) return false; $from = $res[$k]; $to = $res[$k + 1]; if (isset($position) and !empty($position)) $to['position'] = (int)($position); return (Db::getInstance()->Execute(' UPDATE `'._DB_PREFIX_.'hook_module` SET `position`= position '.($way ? '-1' : '+1').' WHERE position between '.(int)(min(array($from['position'], $to['position']))) .' AND '.(int)(max(array($from['position'], $to['position']))).' AND `id_hook`='.(int)($from['id_hook'])) AND Db::getInstance()->Execute(' UPDATE `'._DB_PREFIX_.'hook_module` SET `position`='.(int)($to['position']).' WHERE `'.pSQL($this->identifier).'` = '.(int)($from[$this->identifier]).' AND `id_hook`='.(int)($to['id_hook'])) ); } /* * Reorder modules position * * @param boolean $id_hook Hook ID */ public function cleanPositions($id_hook) { $result = Db::getInstance()->ExecuteS(' SELECT `id_module` FROM `'._DB_PREFIX_.'hook_module` WHERE `id_hook` = '.(int)($id_hook).' ORDER BY `position`'); $sizeof = sizeof($result); for ($i = 0; $i < $sizeof; ++$i) Db::getInstance()->Execute(' UPDATE `'._DB_PREFIX_.'hook_module` SET `position` = '.(int)($i + 1).' WHERE `id_hook` = '.(int)($id_hook).' AND `id_module` = '.(int)($result[$i]['id_module'])); return true; } /* * Return module position for a given hook * * @param boolean $id_hook Hook ID * @return integer position */ public function getPosition($id_hook) { if (isset(Hook::$preloadModulesFromHooks)) if (isset(Hook::$preloadModulesFromHooks[$id_hook])) if (isset(Hook::$preloadModulesFromHooks[$id_hook]['module_position'][$this->id])) return Hook::$preloadModulesFromHooks[$id_hook]['module_position'][$this->id]; else return 0; $result = Db::getInstance()->getRow(' SELECT `position` FROM `'._DB_PREFIX_.'hook_module` WHERE `id_hook` = '.(int)($id_hook).' AND `id_module` = '.(int)($this->id)); return $result['position']; } public function displayError($error) { $output = '
'.$error.'
'; $this->error = true; return $output; } public function displayConfirmation($string) { $output = '
'.$string.'
'; return $output; } /* * Return exceptions for module in hook * * @param int $id_hook Hook ID * @return array Exceptions */ protected static $exceptionsCache = NULL; public function getExceptions($id_hook) { if (self::$exceptionsCache == NULL AND !is_array(self::$exceptionsCache)) { self::$exceptionsCache = array(); $result = Db::getInstance()->ExecuteS(' SELECT CONCAT(id_hook, \'-\', id_module) as `key`, `file_name` as value FROM `'._DB_PREFIX_.'hook_module_exceptions`'); foreach ($result as $row) { if (empty($row['value'])) continue; if (!array_key_exists($row['key'], self::$exceptionsCache)) self::$exceptionsCache[$row['key']] = array(); self::$exceptionsCache[$row['key']][] = array('file_name' => $row['value']); } } return (array_key_exists((int)($id_hook).'-'.(int)($this->id), self::$exceptionsCache) ? self::$exceptionsCache[(int)($id_hook).'-'.(int)($this->id)] : array()); } public static function isInstalled($moduleName) { Db::getInstance()->ExecuteS('SELECT `id_module` FROM `'._DB_PREFIX_.'module` WHERE `name` = \''.pSQL($moduleName).'\''); return (bool)Db::getInstance()->NumRows(); } public function isRegisteredInHook($hook) { if (!$this->id) return false; return Db::getInstance()->getValue(' SELECT COUNT(*) FROM `'._DB_PREFIX_.'hook_module` hm LEFT JOIN `'._DB_PREFIX_.'hook` h ON (h.`id_hook` = hm.`id_hook`) WHERE h.`name` = \''.pSQL($hook).'\' AND hm.`id_module` = '.(int)($this->id) ); } /* ** Template management (display, overload, cache) */ protected static function _isTemplateOverloadedStatic($moduleName, $template) { if (Tools::file_exists_cache(_PS_THEME_DIR_.'modules/'.$moduleName.'/'.$template)) return true; elseif (Tools::file_exists_cache(_PS_MODULE_DIR_.$moduleName.'/'.$template)) return false; return NULL; } protected function _isTemplateOverloaded($template) { return self::_isTemplateOverloadedStatic($this->name, $template); } public static function display($file, $template, $cacheId = NULL, $compileId = NULL) { global $smarty; if (Configuration::get('PS_FORCE_SMARTY_2')) /* Keep a backward compatibility for Smarty v2 */ { $previousTemplate = $smarty->currentTemplate; $smarty->currentTemplate = substr(basename($template), 0, -4); } $smarty->assign('module_dir', __PS_BASE_URI__.'modules/'.basename($file, '.php').'/'); if (($overloaded = self::_isTemplateOverloadedStatic(basename($file, '.php'), $template)) === NULL) $result = Tools::displayError('No template found for module').' '.basename($file,'.php'); else { $smarty->assign('module_template_dir', ($overloaded ? _THEME_DIR_ : __PS_BASE_URI__).'modules/'.basename($file, '.php').'/'); $result = $smarty->fetch(($overloaded ? _PS_THEME_DIR_.'modules/'.basename($file, '.php') : _PS_MODULE_DIR_.basename($file, '.php')).'/'.$template, $cacheId, $compileId); } if (Configuration::get('PS_FORCE_SMARTY_2')) /* Keep a backward compatibility for Smarty v2 */ $smarty->currentTemplate = $previousTemplate; return $result; } protected function _getApplicableTemplateDir($template) { return ($this->_isTemplateOverloaded($template) ? _PS_THEME_DIR_.'modules/' : _PS_MODULE_DIR_).$this->name.'/'; } public function isCached($template, $cacheId = NULL, $compileId = NULL) { global $smarty; /* Use Smarty 3 API calls */ if (!Configuration::get('PS_FORCE_SMARTY_2')) /* PHP version > 5.1.2 */ return $smarty->isCached($this->_getApplicableTemplateDir($template).$template, $cacheId, $compileId); /* or keep a backward compatibility if PHP version < 5.1.2 */ else return $smarty->is_cached($this->_getApplicableTemplateDir($template).$template, $cacheId, $compileId); } protected function _clearCache($template, $cacheId = NULL, $compileId = NULL) { global $smarty; Tools::clearCache($smarty); } protected function _generateConfigXml() { $xml = ' '.$this->name.' displayName).']]> version.']]> description).']]> author).']]> tab).']]>'.(isset($this->confirmUninstall) ? "\n\t".''.$this->confirmUninstall.'' : '').' '.(int)method_exists($this, 'getContent').' '.(int)$this->need_instance.''.(isset($this->limited_countries) ? "\n\t".''.(sizeof($this->limited_countries) == 1 ? $this->limited_countries[0] : '').'' : '').' '; if (is_writable(_PS_MODULE_DIR_.$this->name.'/')) file_put_contents(_PS_MODULE_DIR_.$this->name.'/config.xml', $xml); } /** * @param string $hook_name * @return bool if module can be transplanted on hook */ public function isHookableOn($hook_name) { return is_callable(array($this, 'hook'.ucfirst($hook_name))); } }