SHOPNC 插件机制的实现记录

来源:互联网 发布:广告宣传单设计软件 编辑:程序博客网 时间:2024/06/05 15:18

shopnc 是一款非常前卫的商城系统,功能强大

但这样一款强大的系统,遗憾是的没有插件体制,如果想要什么新功能,就都得修改源文件,会很不方便

作为码农,我是这样想的,给她一个插孔,让很多人插偷笑

/global.php 添加:

       

defined('DIR_PLUGINS') ||define('DIR_PLUGINS',BASE_ROOT_PATH.'/plugins');//added by bruce.chou 2016-5-24

建立/core/plugins.php:

<?php/*** shopnc 插件管理类* @author bruce.chou @2016-5-25***/defined('InShopNC') or exit('AccessInvalid!');  defined('PLUGIN_EVENT_1') ||define('PLUGIN_EVENT_1','PLUGIN_EVENT_1'); class Plugins{        /**         * 保存所有插件         */        publicstatic $all_plugins = array();        /**        *取得所有插件        *        */         static function get_plugins(){            $result = array();            if($dh = opendir(DIR_PLUGINS)){                  while(($f= readdir($dh)) !== false)                  {                        if($f != '.' && $f != '..'&& is_dir($cur = DIR_PLUGINS.'/'.$f))                        {                            if($cfg = require($cur ."/config.php"))                            {                                 //if($cfg['active']){                                                 $cfg['path']= $cur;  //记录插件的安装目录                                                 $result[$f]= $cfg;                                 //}                            }                                         }                  }                  closedir($dh);            }            return self::$all_plugins=$result;        }        /**        *@description 供插件的视图中调用用于显示插件目录下的模板        *@author bruce.chou 2016-5-25        *@param string $page_name 要显示的模板文件        *@param string $layout    要包含的布局文件        *@param object $plugin    插件对象        *//@  string$obj_plugin->module_name    要加载的模块如 admin,home,salers,mobile等        */        publicstatic function tpl_showpage($page_name,$layout='',$obj_plugin=NULL ){                if(!empty($obj_plugin->plugin_name))                {                        if(array_key_exists($obj_plugin->plugin_name,self::$all_plugins)){                                $path= $obj_plugin->plugin_path.'/'.$obj_plugin->module_name;                                //echo$path;                                Tpl::output("this_plugin",$obj_plugin);                                Tpl::showpage($page_name,$layout,2000,$path);                        }else{                                exit("$obj_plugin->plugin_namenot found in plugins array");                        }                }                else{                        exit("lostplugin_name for show page!");                }                       }         /*函数转发*/        publicstatic function tpl_output($arg='',$args){                Tpl::output($arg,$args);        }        publicstatic function triger_event($evt,&$args){                foreach(self::$all_plugins as $key => $value) {                        foreach($value['listen'] as $e => $f) {                                 if($e==$evt){                                       $path= DIR_PLUGINS . '/' . $key . '/action.php';                                       $cls= ucwords($key)."Action";                                       if(file_exists($path)){                                               require_once($path);                                               $action_cls= new $cls();                                               if(method_exists($action_cls,$f)){                                                       $action_cls->$f($args);                                               }                                       }                                 }                        }                }        }        publicstatic function url($obj_plugin,$act='',$op='',$args=array()){                //plugin-mp-admin-mb_mpweixin                returnurl("plugin-".$obj_plugin->plugin_name.'-'.$obj_plugin->module_name.'-'.$act,$op,$args);        } }$all_plugins = Plugins::get_plugins();


 

插件目录设定在/plugins/插件名

目录结构:

插件名/

    config.php   //插件配置文件

    action.php   //插件监听处理类

         models/    ->模型类目录

                           数据库交互处理功能文件列表

     admin/     ->后台功能

        control/

               控制器文件列表

             templates/

               视图文件列表

         home/    ->前台功能

        control/

               控制器文件列表

             templates/

               视图文件列表

    mobile/   //手机端功能

                        …

    salers/   ->商户后台功能

                        …

修改过的原始核心文件:

/core/base.php

        /**

         * 控制器调度

         *

         */

        privatestatic function control(){

                //二级域名

               if($GLOBALS['setting_config']['enabled_subdomain'] == '1' && $_GET['act']== 'index' && $_GET['op'] == 'index'){

                        $store_id= subdomain();

                        if($store_id > 0) $_GET['act'] = 'show_store';

                }

                /*

                        addedby bruce.chou 2016-5-24

                       

                */

                $act= trim($_GET['act']);//'plugin.mp.mb_mpweixin',   //方法名 method

                $m=array();

                if(strpos($act,'plugin-') === 0){

                        //echoBASE_ROOT_PATH.$act;

                         $m = explode("-",$act);

                        //print_r($m);

                         $act_file = (BASE_ROOT_PATH.'/plugins/'.$m[1].'/'.$m[2].'/control/'.$m[3].'.php');

                         $_GET['act'] = $m[3];  

 

                }else{

                        $act_file= realpath(BASE_PATH.'/control/'.$_GET['act'].'.php');

                }

                //bybruce.chou

                //die($act_file);

               

                $class_name= $_GET['act'].'Control';

                if(!@include($act_file)){

                    if (C('debug')) {

                        throw_exception("Base Error:access file isn't exists!");

                    } else {

                        showMessage('抱歉!您访问的页面不存在','','html','error');

                    }

                }

                if(class_exists($class_name)){

                        $main= new $class_name();

                        //bybruce.chou 2016-5-25 给实例类添加动态属性 插件名,插件路径

                        if(!empty($m)){

                                $main->plugin_name= $m[1];

                                $main->plugin_path= BASE_ROOT_PATH.'/plugins/'.$m[1];//.'/'.$m[2];

                                $main->module_name= $m[2];

                                $main->act   = $_GET['act'];

                        }

                        $function= $_GET['op'].'Op';

                        if(method_exists($main,$function)){

                                $main->$function();

                        }elseif(method_exists($main,'indexOp')){

                                $main->indexOp();

                        }else{

                                $error= "Base Error: function $function not in $class_name!";

                                throw_exception($error);

                        }

                }else{

                        $error= "Base Error: class $class_name isn't exists!";

                        throw_exception($error);

                }

        }

/core/framework/libraries/tpl.php

其实就是新增参数$base_p

* 调用显示模板

         *

         * @param string $page_name

         * @param string $layout

         * @param int $time

         */

        publicstatic functionshowpage($page_name='',$layout='',$time=2000,$base_p=BASE_PATH){

                if(!defined('TPL_NAME')) define('TPL_NAME','default');

                self::getInstance();

                        if(!empty(self::$tpl_dir)){

                                $tpl_dir= self::$tpl_dir.DS;

                        }

                        //默认是带有布局文件

                        if(empty($layout)){

                                $layout= 'layout'.DS.self::$layout_file.'.php';

                        }else{

                                $layout= 'layout'.DS.$layout.'.php';

                        }

                        $layout_file= $base_p.'/templates/'.TPL_NAME.DS.$layout;

                        $tpl_file= $base_p.'/templates/'.TPL_NAME.DS.$tpl_dir.$page_name.'.php';

                         //echo $layout_file."  >$tpl_file";

                        if(file_exists($tpl_file)){

                                //对模板变量进行赋值

                                $output= self::$output_value;

                                //页头

                                $output['html_title']= $output['html_title']!='' ? $output['html_title']:$GLOBALS['setting_config']['site_name'];

                                $output['seo_keywords']= $output['seo_keywords']!='' ? $output['seo_keywords']:$GLOBALS['setting_config']['site_name'];

                                $output['seo_description']= $output['seo_description']!='' ? $output['seo_description']:$GLOBALS['setting_config']['site_name'];

                                $output['ref_url']= getReferer();

 

                                Language::read('common');

                                $lang= Language::getLangContent();

 

                                @header("Content-type:text/html; charset=".CHARSET);

                                //判断是否使用布局方式输出模板,如果是,那么包含布局文件,并且在布局文件中包含模板文件

                                if($layout != ''){

                                        if(file_exists($layout_file)){

                                                include_once($layout_file);

                                        }else{

                                                $error= 'Tpl ERROR:'.'templates'.DS.$layout.' is not exists';

                                                throw_exception($error);

                                        }

                                }else{

                                        include_once($tpl_file);

                                }

                        }else{

                                $error= 'Tpl ERROR:'.'templates'.DS.$tpl_dir.$page_name.'.php'.' is not exists';

                                throw_exception($error);

                        }

        }

修改/core/shopnc.php

//统一ACTION  添加 - 号为合法 bybruce.chou 2016-5-24

$_GET['act'] =preg_match('/^[\w\-]+$/i',$_GET['act']) ? $_GET['act'] : 'index';

$_GET['op'] =preg_match('/^[\w\-]+$/i',$_GET['op']) ? $_GET['op'] : 'index';

   并在未处添加

//by bruce.chou

if(file_exists(BASE_CORE_PATH."/plugins.php")){

        include(BASE_CORE_PATH."/plugins.php");

}

插件目录下/config.php示例:

<?php defined('InShopNC') or exit('AccessInvalid!');  return array(       'name' => 'mp',       'description' => '微信端功能扩展,提供后台界面,微信交互处理等',       'active'=>'1',                                                    //指示插件是否为活动状态       'install'=>'install.php',                              //安装文件,应该有MP_INSTALL类实现 install 和 uninstall方法       'listen' => array(                       PLUGIN_EVENT_1=>'doSomethings',    //要监听的事件数组               ),        'menu'=> array(                       'top'  => 'mobile',             //顶层KEY,如果存在原有的将会新增                       'text'=> '微信端',             //顶层菜单显示的名字,此参数仅在是新的顶层菜单会使用,如果是已存在的,则会忽略                       'left'=> array(                               array(                                       'act'=>'plugin-mp-admin-mb_mpweixin',    //模块名必须以plugin开头+plugin名称+目录名+control                                       'op'=>'mb_mpweixin',   //方法名 method                                       'nav'=>'mobile',        //必须和顶层KEY一样                                       'text'=>'微公众号',      //在左边要显示的名称                                       ),                               /*array(                                       'op'=>'mb_mpweixin',    //模块名 control                                       'act'=>'mb_mpweixin1',   //方法名 method                                       'nav'=>'mobile',        //必须和顶层KEY一样                                       'text'=>'微公众号1',      //在左边要显示的名称                                       ),*/                               ),                 ),        'limit'=> array('name'=>$lang['nc_mobile'], 'child'=>array(                array('name'=>'微公众号', 'op'=>NULL,'act'=>'mb_mpweixin'),                ))        );


添加菜单到后台操作:

/*                @bybruce.chou 2016-5-24                读取所有插件并加入到管理菜单中        **/        global$all_plugins;        $plugins= $all_plugins;//Plugins::get_plugins();        foreach($plugins  as $key => $value) {                //查找顶层菜单,如果未找到则添加顶层菜单                $found= -1;                foreach($array['top'] as $k=>$v) {                        if($v['args']==  $plugins[$key]['menu']['top'] ){                                $found= $k; //找到的话记住KEY                        }                }                               if($found == -1 ){                        $array['top'][]= array('args' => $plugins[$key]['menu']['top'] ,'text'=>$plugins[$key]['menu']['text'] );                        $found= count($array['top']) - 1;                        $array['left'][]= array('nav' => $plugins[$key]['menu']['top'],                                'text'=>$plugins[$key]['menu']['text'] );                }                               foreach($plugins[$key]['menu']['left'] as $i => $j) {                        #code...                        $array['left'][$found]['list'][]= array(                         'args' => $j['op'] . ',' . $j['act'] ."," . $j['nav'],                         'text' => $j['text'],                        );                }        }              /*by bruce.chou*/


在插件任何目录下的控制器类中要显示相关视图:

       Plugins::tpl_output('变量名', $变量);

       Plugins::tpl_showpage('视图文件','布局文件',$this );

插件目录/action.php示例:

<?phpclass MPAction{        functiondoSomethings(&$args){                echo"doSomethings:" . $args;        }}


 

 当然目前未做到尽善尽美,但基本在shopnc系统中实现了插件功能

 我的QQ:174487481,有兴趣的可以一起探讨

0 0