i-install_class.php => interface * => install-ctrl_class.php => controller, manage factory with config or sql install object * => install-sql AND install.config classes => manage install / uninstall of sql queries AND config values (register hook) * lib/admin * => i-admin_class.php => interface * => admin-ctrl_class.php => controller, manage factory with configure or update admin object * => configure and update admin classes => manage display of admin form and make action of updating config like (add, edit, delete, update, ... see PHP Doc in class) * lib/hook * => i-hook_class.php => interface * => hook-ctrl_class.php => controller, manage strategy with hook object. Like this, you can add hook easily with declare a new file class * => hook-home_class.php => manage displaying content on your home page * lib/module-dao_class.php * D A O = Data Access Object => manage all sql queries * lib/module-tools_class.php * declare all transverse functions which are unclassifiable in specific class * lib/warnings_class.php * manage all displaying warnings when module isn't already configured after installation * @date 28/09/2018 */ if (!defined('_PS_VERSION_')) { exit(1); } class HomeProductTabs extends Module { /** * @var array $aConfiguration : array of set configuration */ public static $aConfiguration = array(); /** * @var int $iDefaultLang : store id of default lang */ public static $iDefaultLang = null; /** * @var int $sCurrentLang : store iso of default lang */ public static $sCurrentLang = null; /** * @var obj $oCookie : store cookie obj */ public static $oCookie = null; /** * @var array $aOptions : stock options of way / sort / category type */ public static $aOptions = array(); /** * @var obj $oModule : obj module itself */ public static $oModule = array(); /** * @var string $sQueryMode : query mode - detect XHR */ public static $sQueryMode = null; /** * @var array $_aError : array get error */ private $_aError = array('msg' => null, 'code' => null); /** * @var int $iShopId : shop id used for 1.5 and for multi shop */ public static $iShopId = 1; /** * @var bool $bCompare15 : get compare version for PS 1.5 */ public static $bCompare15 = false; /** * @var bool $bCompare16 : get compare version for PS 1.6 */ public static $bCompare16 = false; /** * @var bool $bCompare17 : get compare version for PS 1.7 */ public static $bCompare17 = false; /** * @var bool $bCompare1750 : get compare version for PS 1.7.5.0 */ public static $bCompare1750 = false; /** * Magic Method __construct assigns few information about module and instantiate parent class */ public function __construct() { require_once(_PS_MODULE_DIR_ . 'homeproducttabs/conf/common.conf.php'); require_once(_HPPRTB_PATH_LIB . 'module-tools_class.php'); // use case - get context if (version_compare(_PS_VERSION_, '1.5', '>')) { $cookie = Context::getContext()->cookie; self::$iShopId = Context::getContext()->shop->id; } else { global $cookie; } // get cookie obj self::$oCookie = $cookie; // get default lang self::$iDefaultLang = self::$oCookie->id_lang; // get current lang iso self::$sCurrentLang = BT_ModuleTools::getLangIso(); // compare PS version self::$bCompare15 = version_compare(_PS_VERSION_, '1.5', '>='); self::$bCompare16 = version_compare(_PS_VERSION_, '1.6', '>='); self::$bCompare17 = version_compare(_PS_VERSION_, '1.7', '>='); self::$bCompare1750 = version_compare(_PS_VERSION_, '1.7.5.0', '>='); $this->name = 'homeproducttabs'; $this->tab = 'front_office_features'; $this->version = '3.4.4'; $this->author = 'Business Tech'; $this->module_key = '0cf13977c01fc05de48745b04755736d'; $this->need_instance = 0; parent::__construct(); $this->displayName = $this->l('Advanced Featured Products'); $this->description = $this->l('Configure and display custom product tabs on your Homepage'); $this->confirmUninstall = $this->l('Are you sure you want to remove it ? Your Advanced Featured Products will no longer work.'); // stock itself obj self::$oModule = $this; // get configuration options self::$aConfiguration = Configuration::getMultiple(array_keys($GLOBALS[_HPPRTB_MODULE_NAME . '_CONFIGURATION'])); // defines variable for setting configuration options to define tab type / sort type / way type self::$aOptions = array( 'aTabType' => array( 'category' => array( 'title' => $this->l('category'), 'filters' => array('date_add', 'price', 'name', 'manufacturer', 'position', 'random') ), 'home' => array( 'title' => $this->l('home featured'), 'filters' => array('date_add', 'price', 'name', 'manufacturer', 'position', 'random') ), 'best' => array('title' => $this->l('best sales'), 'filters' => array('price', 'position')), 'new' => array( 'title' => $this->l('new products'), 'filters' => array('date_add', 'price', 'name', 'position') ), 'promo' => array( 'title' => $this->l('promotion'), 'filters' => array('date_add', 'price', 'name', 'manufacturer', 'position') ), 'free' => array( 'title' => $this->l('free category'), 'filters' => array('date_add', 'price', 'name', 'position', 'random') ), ), 'aSortType' => array( 'date_add' => $this->l('Date product added'), 'price' => $this->l('Price'), 'name' => $this->l('Name'), 'manufacturer' => $this->l('Manufacturer'), 'position' => $this->l('Position in category'), 'random' => $this->l('Randomly'), ), 'aWayType' => array( 'asc' => $this->l('ascending'), 'desc' => $this->l('descending'), ), 'aNbByLines' => array( 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6, 7 => 7, 8 => 8 ), 'aStylesCss' => array( 'THEME' => $this->l('Use my theme layout'), 'MODULE' => $this->l('Use module theme (if you need customize the display)'), ), ); // get call mode - Ajax or dynamic - used for clean headers and footer in ajax request self::$sQueryMode = Tools::getValue('sMode'); } /** * install() method installs all mandatory structure (DB or Files) => sql queries and update values and hooks registered * * @return bool */ public function install() { require_once(_HPPRTB_PATH_CONF . 'install.conf.php'); require_once(_HPPRTB_PATH_LIB_INSTALL . 'install-ctrl_class.php'); // set return $bReturn = true; if (!parent::install() || !BT_InstallCtrl::run('install', 'sql', _HPPRTB_PATH_SQL . _HPPRTB_INSTALL_SQL_FILE) || !BT_InstallCtrl::run('install', 'config') ) { $bReturn = false; } return $bReturn; } /** * uninstall() method uninstalls all mandatory structure (DB or Files) * * @return bool */ public function uninstall() { require_once(_HPPRTB_PATH_CONF . 'install.conf.php'); require_once(_HPPRTB_PATH_LIB_INSTALL . 'install-ctrl_class.php'); // set return $bReturn = true; if (!parent::uninstall() || !BT_InstallCtrl::run('uninstall', 'sql', _HPPRTB_PATH_SQL . _HPPRTB_UNINSTALL_SQL_FILE) || !BT_InstallCtrl::run('uninstall', 'config') ) { $bReturn = false; } return $bReturn; } /** * setErrorHandler() method manages module error * * @param string $iErrno * @param string $sErrstr * @param string $sErrFile * @param string $iErrLine * @param array $aErrContext * @return string */ public function setErrorHandler($iErrno, $sErrstr, $sErrFile, $iErrLine, $aErrContext) { switch ($iErrno) { case E_USER_ERROR : $this->_aError['code'] = $iErrno; $this->_aError['msg'] = 'Fatal error ' . $sErrstr . ''; break; case E_USER_WARNING : $this->_aError['code'] = $iErrno; $this->_aError['msg'] = 'Warning ' . $sErrstr . ''; break; case E_USER_NOTICE : $this->_aError['code'] = $iErrno; $this->_aError['msg'] = 'Notice ' . $sErrstr . ''; break; default : $this->_aError['code'] = $iErrno; $this->_aError['msg'] = 'Unknow error ' . $sErrstr . ''; break; } return ( $this->displayErrorModule() ); } /** * getContent() method manages all data in Back Office * * @return string */ public function getContent() { set_error_handler(array($this, 'setErrorHandler')); try { require_once(_HPPRTB_PATH_CONF . 'admin.conf.php'); require_once(_HPPRTB_PATH_LIB_ADMIN . 'admin-ctrl_class.php'); // include tools of module - transverse static functions require_once(_HPPRTB_PATH_LIB . 'module-tools_class.php'); // set translated JS errors BT_ModuleTools::setTranslatedJsErrors(); // instantiate admin controller object $oAdmin = new BT_AdminCtrl(); /* * defines type to execute * use case : no key hpprtbAction sent in GET or POST mode (any form wans't posted => first page is displayed with admin-configure_class.php) * use case : key hpprtbAction sent in GET or POST mode (form or ajax query posted => use with edit / add / update / delete / getCategories / getFreeCategories */ $sType = (!Tools::getIsset(Tools::strtolower(_HPPRTB_MODULE_NAME) . 'Action') || Tools::getValue(Tools::strtolower(_HPPRTB_MODULE_NAME) . 'Action') === 'configure' ? 'configure' : 'update'); $aUpdateModule = array(); // make module update only in case of display general admin page if ($sType == 'configure') { // update module if necessary $aUpdateModule = $this->_updateModule(); // include DAO require_once(_HPPRTB_PATH_LIB . 'module-dao_class.php'); // fix shop id BT_ModuleDao::fixShopId(); } /* * execute good action in admin * only displayed with key : tpl and assign in order to display good smarty template */ $aDisplay = $oAdmin->run($sType, array_merge($_GET, $_POST)); // free memory unset($oAdmin); if (!empty($aDisplay)) { restore_error_handler(); $aDisplay['assign'] = array_merge($aDisplay['assign'], array( 'aUpdateErrors' => $aUpdateModule, 'bVersion15' => (version_compare(_PS_VERSION_, '1.5', '>') ? true : false), 'sCurrentIso' => BT_ModuleTools::getLangIso(), 'sTs' => time() )); $sContent = $this->displayModule($aDisplay['tpl'], $aDisplay['assign']); if (!empty(self::$sQueryMode)) { echo $sContent; } else { return $sContent; } } else { throw new Exception('action returns empty content', 110); } } catch (Exception $e) { $this->_aError['msg'] = $e->getMessage(); $this->_aError['code'] = $e->getCode(); restore_error_handler(); // get content $sContent = $this->displayErrorModule(); if (!empty(self::$sQueryMode)) { echo $sContent; } else { return $sContent; } } // exit clean in XHR mode if (!empty(self::$sQueryMode)) { exit(0); } } /** * hookHome() method displays customized module content on home page * * @return string */ public function hookHome() { return ( $this->_execHook('home', 'home') ); } /** * hookDisplayHome() method displays customized module content on home page * * @return string */ public function hookDisplayHome() { return ( $this->_execHook('home', 'home') ); } /** * hookDisplayTab() method displays customized module content on home page * * @return string */ public function hookDisplayHomeTab() { return ( $this->_execHook('home', 'tab') ); } /** * hookDisplayTabContent() method displays customized module content on home page * * @return string */ public function hookDisplayHomeTabContent() { return ( $this->_execHook('home', 'content') ); } /** * _execHook() method displays selected hook content * * @param string $sHookType * @param string $sMethod * @param array $aParams * @return string */ private function _execHook($sHookType, $sMethod, array $aParams = null) { require_once(_HPPRTB_PATH_CONF . 'hook.conf.php'); require_once(_HPPRTB_PATH_LIB_HOOK . 'hook-ctrl_class.php'); try { /* * define which hook class is executed in order to display good content in good zone in shop */ $oHook = new BT_HookCtrl($sHookType, $sMethod); // displays good block content $aDisplay = $oHook->run($aParams); // free memory unset($oHook); /* * execute good action in admin * only displayed with key : tpl and assign in order to display good smarty template */ if (!empty($aDisplay)) { return ( $this->displayModule($aDisplay['tpl'], $aDisplay['assign']) ); } else { throw new Exception('Chosen hook returns empty content', 110); } } catch (Exception $e) { $this->_aError['msg'] = $e->getMessage(); $this->_aError['code'] = $e->getCode(); restore_error_handler(); return ( $this->displayErrorModule() ); } } /** * displayModule() method displays view * * @param string $sTplName * @param array $aAssign * @return string */ public function displayModule($sTplName, $aAssign) { if (file_exists(_HPPRTB_PATH_TPL . $sTplName) && is_file(_HPPRTB_PATH_TPL . $sTplName)) { if (version_compare(_PS_VERSION_, '1.5', '>')) { $smarty = Context::getContext()->smarty; } else { global $smarty; } // set assign module name $aAssign = array_merge($aAssign, array( 'sModuleName' => Tools::strtolower(_HPPRTB_MODULE_NAME), 'oJsTranslatedErrors' => Tools::jsonEncode($GLOBALS[_HPPRTB_MODULE_NAME . '_JS_ERRORS']) )); $smarty->assign($aAssign); return ( $this->display(__FILE__, _HPPRTB_PATH_TPL_NAME . $sTplName) ); } else { throw new Exception('Template doesn\'t exists', 120); } } /** * displayErrorModule() method displays view with error * * @return string */ public function displayErrorModule() { if (version_compare(_PS_VERSION_, '1.5', '>')) { $smarty = Context::getContext()->smarty; } else { global $smarty; } $smarty->assign( array( 'sHomeURI' => (strstr($_SERVER['REQUEST_URI'], '&' . Tools::strtolower(_HPPRTB_MODULE_NAME) . 'Action') ? Tools::substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '&' . Tools::strtolower(_HPPRTB_MODULE_NAME) . 'Action')) : $_SERVER['REQUEST_URI']), 'aError' => $this->_aError, 'sModuleName' => Tools::strtolower(_HPPRTB_MODULE_NAME), 'bDebug' => _HPPRTB_DEBUG, ) ); return ( $this->display(__FILE__, _HPPRTB_PATH_TPL_NAME . _HPPRTB_TPL_ERROR) ); } /** * _updateModule() method updates module as necessary * * @return array */ private function _updateModule() { $aErrors = array(); // use case - table to add if (!empty($GLOBALS[_HPPRTB_MODULE_NAME . '_SQL_UPDATE']['table'])) { // loop on each elt to update SQL foreach ($GLOBALS[_HPPRTB_MODULE_NAME . '_SQL_UPDATE']['table'] as $sTable => $sSqlFile) { // execute query $bResult = Db::getInstance()->ExecuteS('SHOW TABLES LIKE "' . _DB_PREFIX_ . Tools::strtolower(_HPPRTB_MODULE_NAME) . '_' . $sTable . '"'); // if empty - update if (empty($bResult)) { require_once(_HPPRTB_PATH_CONF . 'install.conf.php'); require_once(_HPPRTB_PATH_LIB_INSTALL . 'install-ctrl_class.php'); // use case - KO update if (!BT_InstallCtrl::run('install', 'sql', _HPPRTB_PATH_SQL . $sSqlFile)) { $aErrors[] = array('table' => $sTable, 'file' => $sSqlFile); } } } } // use case - field to add if (!empty($GLOBALS[_HPPRTB_MODULE_NAME . '_SQL_UPDATE']['field'])) { // loop on each elt to update SQL foreach ($GLOBALS[_HPPRTB_MODULE_NAME . '_SQL_UPDATE']['field'] as $sFieldName => $aOption) { // execute query $bResult = Db::getInstance()->ExecuteS('SHOW COLUMNS FROM ' . _DB_PREFIX_ . Tools::strtolower(_HPPRTB_MODULE_NAME) . '_' . $aOption['table'] . ' LIKE "' . $sFieldName . '"'); // if empty - update if (empty($bResult)) { require_once(_HPPRTB_PATH_CONF . 'install.conf.php'); require_once(_HPPRTB_PATH_LIB_INSTALL . 'install-ctrl_class.php'); // use case - KO update if (!BT_InstallCtrl::run('install', 'sql', _HPPRTB_PATH_SQL . $aOption['file'])) { $aErrors[] = array( 'field' => $sFieldName, 'linked' => $aOption['table'], 'file' => $aOption['file'] ); } } } } if (empty($aErrors)) { // use case - compile templates files require_once(_HPPRTB_PATH_LIB_COMMON . 'dir-reader.class.php'); // get templates files $aTplFiles = DirReader::create()->run(array( 'path' => _HPPRTB_PATH_TPL, 'recursive' => true, 'extension' => 'tpl', 'subpath' => true )); if (!empty($aTplFiles)) { if (version_compare(_PS_VERSION_, '1.5', '>')) { $smarty = Context::getContext()->smarty; } else { global $smarty; } foreach ($aTplFiles as $aFile) { if (method_exists($smarty, 'clearCompiledTemplate')) { $smarty->clearCompiledTemplate($aFile['filename']); } elseif (method_exists($smarty, 'clear_compiled_tpl')) { $smarty->clear_compiled_tpl($aFile['filename']); } } } } return $aErrors; } }