最近要仿一个网站,准备用prestashop来做,一直没怎么深入研究过这个东西,都只是在改一些外部
的东西,从今天开始好好看看,方便做后面的开发。
从头开始index.php:
<?php include(dirname(__FILE__).'/config/config.inc.php');//加载一些配置信息 if(intval(Configuration::get('PS_REWRITING_SETTINGS')) === 1)//url重写 $rewrited_url = __PS_BASE_URI__; //这边很清楚的能看出页面结构了,头和尾定义在单独文件中,统一的头和尾,中间的内容可以变化, //也就是母版页技术 include(dirname(__FILE__).'/header.php'); //把挂载在home这个挂载点的模块加载进来,分配到tpl文件的变量HOOK_HOME是一个字符串, //保存了模块显示的html结构,在tpl文件中{$HOOK_HOME}这样使用,就可以把模块显示出来 //这部分在Module.php的类文件中可以 $smarty->assign('HOOK_HOME', Module::hookExec('home')); $smarty->display(_PS_THEME_DIR_.'index.tpl'); include(dirname(__FILE__).'/footer.php'); ?>
来看看header.php:
<?php // P3P Policies (http://www.w3.org/TR/2002/REC-P3P-20020416/#compact_policies) header('P3P: CP="IDC DSP COR CURa ADMa OUR IND PHY ONL COM STA"'); require_once(dirname(__FILE__).'/init.php');//初始化一些页面信息 /* CSS */ $css_files[_THEME_CSS_DIR_.'global.css'] = 'all';//定义css文件和media信息 /* Hooks are volontary out the initialize array (need those variables already assigned) */ $smarty->assign(array( 'HOOK_HEADER' => Module::hookExec('header'), 'HOOK_LEFT_COLUMN' => Module::hookExec('leftColumn'), 'HOOK_TOP' => Module::hookExec('top'), 'static_token' => Tools::getToken(false), 'token' => Tools::getToken(), 'priceDisplayPrecision' => _PS_PRICE_DISPLAY_PRECISION_, 'content_only' => intval(Tools::getValue('content_only')) )); //可以看到header,leftColumn和top这三个挂载点的模块,都是在这个文件中加载的 if(isset($css_files) AND !empty($css_files)) $smarty->assign('css_files', $css_files); if(isset($js_files) AND !empty($js_files)) $smarty->assign('js_files', $js_files); $smarty->display(_PS_THEME_DIR_.'header.tpl'); ?>
然后是footer.php:
<?php if (isset($smarty)) { $smarty->assign(array( 'HOOK_RIGHT_COLUMN' => Module::hookExec('rightColumn'), 'HOOK_FOOTER' => Module::hookExec('footer'), 'content_only' => intval(Tools::getValue('content_only')))); $smarty->display(_PS_THEME_DIR_.'footer.tpl'); } //这个比较简单,结构上来说主要是加载rightColumn和footer这两个挂载点的模块 ?>
从上面三个文件中,可以很清晰的看出prestashop的页面结构:
上面三个文件都有类似:'HOOK_RIGHT_COLUMN' => Module::hookExec('rightColumn')
这样的模块加载函数,有必要去看看里面的代码。
classes/Module.php中的hookExec函数:
/* * 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) { if ((!empty($id_module) AND !Validate::isUnsignedId($id_module)) OR !Validate::isHookName($hook_name)) die(Tools::displayError()); global $cart, $cookie; $altern = 0; if (!isset($hookArgs['cookie']) OR !$hookArgs['cookie']) $hookArgs['cookie'] = $cookie; if (!isset($hookArgs['cart']) OR !$hookArgs['cart']) $hookArgs['cart'] = $cart; $result = Db::getInstance()->ExecuteS(' SELECT h.`id_hook`, m.`name`, hm.`position` 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` WHERE h.`name` = /''.pSQL($hook_name).'/' AND m.`active` = 1 '.($id_module ? 'AND m.`id_module` = '.intval($id_module) : '').' ORDER BY hm.`position`, m.`name` DESC'); if (!$result) return false; $output = ''; foreach ($result AS $k => $module) { $moduleInstance = Module::getInstanceByName($module['name']); if (!$moduleInstance) continue; $exceptions = $moduleInstance->getExceptions(intval($module['id_hook']), intval($moduleInstance->id)); $fileindex = basename($_SERVER['PHP_SELF']); $show = true; if (!empty($exceptions) AND is_array($exceptions)) foreach ($exceptions as $exception) if ($fileindex == $exception['file_name']) $show = false; if (is_callable(array($moduleInstance, 'hook'.$hook_name)) AND $show) { $hookArgs['altern'] = ++$altern; $output .= call_user_func(array($moduleInstance, 'hook'.$hook_name), $hookArgs); } } return $output; }
大致的意思是这样,通过挂载点名称取得在这个挂载点上的模块的信息,然后遍历这些模块,
产生模块的实例,然后执行模块中的相应hook+hook_name的函数返回相应的html代码,
所有模块的html代码都以字符串型似记录在$output这个变量中,所以hook_Exec函数返回的就是
一个很长的构造好的html字符串,可以分配给tpl的变量直接使用。
这里用到了call_user_func()函数来动态执行模块中的方法,这个技巧很不错。