* @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 .= '
';
else
$output .= '
';
$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 '- '.$error.'
';
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 .= '
';
}
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)));
}
}