在用yii2做大型网站的时候,尤其是做产品的时候,譬如做电商系统,在很多页面的侧栏,或者内容部分的底部等部分,我们希望通过配置的方式,很容易的把某个块加入,譬如在分类页面限制客户的浏览产品记录和newsletter,在产品页面,我们同样想显示这些,我们可能做出来很多这样的显示独立块,让客户在后台通过配置的方式就可以加入这些块,我们需要考虑的如下
- 这些块由两部分组成,数据提供者block部分,view html部分,通过block提供的动态数据,画出整个页面。
- 当前功能块可能包含其他的功能块,也就是多个功能块嵌套。
- 实现上述功能,我们就可以做出来很多独立功能块,在各个页面很容易的配置。下面是实现的方法
我的yii2 fec扩展已经实现这个功能,github地址:https://github.com/fancyecommerce/yii2-fec
下面讲述的是实现原理。
- 这个是实现的原理文件:
<?php namespace fec\helpers; use Yii; use yii\base\View; use yii\base\InvalidConfigException; class CView { # 功能块: # 本功能的作用是通过一个类文件,和一个view 文件,生成一个html块,而且在这个html中还可以嵌套其他的块 # 这样设计的好处:譬如在前端,我们在很多url中都会有一些公用的侧栏块,我们很希望我们的块可以通过配置的方式很容易的加入到侧栏 # 譬如电商网站侧栏的:客户的浏览记录,我们在多个页面都想加入这个功能,我们就可以很方便的做加入。 # 默认的方法,功能块的提供数据的默认方法。可以在配置中配置method方法自定义。 const DATA_METHOD = 'getLastData'; /* 你可以在view 文件中通过下面的方式使用 <?php use fec\helpers\CView; $config = [ # 必填 'class' => 'fec\block\TestMenu', 'view' => '@fec/views/testmenu/index.php', # 下面为选填 'method'=> 'getLastData', 'terry1'=> 'My1', 'terry2'=> 'My2', ]; echo CView::getChildHtml($config) ?> */ public static function getChildHtml($config) { if(!isset($config['class']) || empty($config['class']) || !isset($config['view']) || empty($config['view']) ){ throw new InvalidConfigException('view and class must exist in array config!'); } $method = self::DATA_METHOD; if(isset($config['method']) && !empty($config['method'])){ $method = $config['method']; unset($config['method']); } $view = $config['view']; unset($config['view']); $ob = Yii::createObject($config); $params = $ob->$method(); return Yii::$app->view->render($view, $params); } # 通过配置 /* 1.add config param to modules params or application params. params.php [ 'params' => [ 'block' =>[ 'menu' =>[ # 必填 'class' => 'fec\block\TestMenu', 'view' => '@fec/views/testmenu/index.php', # 下面为选填 'method'=> 'getLastData', 'terry1'=> 'My1', 'terry2'=> 'My2', ], ] ] ] 2. use fec\helpers\CView; CView::getConfigChildHtml('menu'); */ public static function getConfigChildHtml($configKey){ $config = []; # get config from module param if($module = Yii::$app->controller->module){ $module_config = CModule::param("block"); if(isset($module_config[$configKey])){ $config = $module_config[$configKey]; } } # if module config param is empty or not exist, # get config from application if(empty($config)){ $app_config = CConfig::param("block"); if(isset($app_config[$configKey])){ $config = $app_config[$configKey]; } } if(!isset($config['class']) || empty($config['class']) || !isset($config['view']) || empty($config['view']) ){ throw new InvalidConfigException('view and class must exist in array config!'); }else{ return self::getChildHtml($config); } } }
2.新建功能块的block文件:
<?php namespace fec\block; use Yii; class TestMenu { public $terry1; public $terry2; public function getLastData() { $arr = [ 'terry1' =>$this->terry1, 'terry2' =>$this->terry2, ]; return $arr; } }
3.新建view显示部分:
<div>My Name is <?php echo $terry1."_".$terry2; ?> </div>
4.在其他的view文件中调用:
<?php use fec\helpers\CView; $config = [ 'class' => 'fec\block\TestMenu', 'view' => '@fec/views/testmenu/index.php', # 下面为选填 'method'=> 'getLastData', 'terry1'=> 'My111', 'terry2'=> 'My222', ]; echo CView::getChildHtml($config); ?>
也就是通过上面的配置数组指定block的提供者, view文件的实现文件,也就是上面的步骤 2 和3,method为选填,如果不填写,默认为getLastData函数,terry1,terry2为初始化提供变量,然后我们就可以看到输出了
My Name is My111_My222
5.我们通过配置的方式调用CView::getConfigChildHtml()函数
5.1 加入module配置:(在report 配置中)
<?php return [ 'report' => [ 'class' => 'appadmin\code\Report\Module', 'components'=>[ 'mycomponent' => [ 'class' => 'appadmin\component\MyComponent', 'terry' => 'xxxx', ], ], 'params' => [ 'water' => 'good', 'block' =>[ 'menu' =>[ # 必填 'class' => 'fec\block\TestMenu', 'view' => '@fec/views/testmenu/index.php', # 下面为选填 'method'=> 'getLastData', 'terry1'=> 'My1', 'terry2'=> 'My2', ], ] ], ], ];
当然,您如果不使用模块,可以在params.php中直接加入block的配置部分:
'params' => [ 'water' => 'good', 'block' =>[ 'menu' =>[ # 必填 'class' => 'fec\block\TestMenu', 'view' => '@fec/views/testmenu/index.php', # 下面为选填 'method'=> 'getLastData', 'terry1'=> 'My1', 'terry2'=> 'My2', ], ] ],
如果application 和module同时配置,那么在当前module下面,module下面的配置有限,
使用:
<?php use fec\helpers\CView; echo CView::getConfigChildHtml('menu') ?>
My Name is My1_My2
总结:这个功能是可以深度嵌套,譬如在view1.php调用了child -> menu,
在menu的view文件中又调用了child–>product ,…..,深入嵌套,这是魅力所在。