==Yaf开发指南==
===说明===
;本文档仅作为[http://yaf.laruence.com/manual/ http://yaf.laruence.com/manual/]的补充,也会指出一些在使用中容易忽略的地方,以及一些使用技巧
===入口文件===
<?phpdefine('IN_DEBUG',true);IN_DEBUG ? error_reporting(E_ALL) : error_reporting(0);$environ=ini_get('yaf.environ'); //默认是productdefine("APPLICATION_PATH", realpath(dirname(__FILE__).'/../') );$app = new Yaf_Application(APPLICATION_PATH."/conf/application.{$environ}.ini");$app->bootstrap()->run();
*入口文件注意3个地方:
**yaf.environ, 该配置属于PHP_INI_SYSTEM,仅在php.ini配置生效。可以配置成你想要的值,默认是product。当用ini作配置文件时,它会使用该值为名的节
**Yaf_Application的构造函数有2个参数。第一个参数是配置项,可以传一个数组,或者一个ini文件的地址。第2个参数是个字符串,传值后如果使用ini文件作为配置,将使用该值对应的节作为配置,默认为yaf.environ的值
**在new Yaf_Application("conf.ini")之后,Yaf_Application::run之前,如果调用Yaf_Application::bootstrap()( 即代码中的$app->bootstrap()->run() ),将会依次执行Bootstrap.php中所有以_init开头的方法
===配置文件===
[yaf]application.directory=APPLICATION_PATH "/application"application.dispatcher.throwException=TRUEapplication.dispatcher.catchException=TRUEapplication.dispatcher.defaultController="site"application.dispatcher.defaultAction = "index"application.view.ext="php"[common : yaf]site.title=" 我的官网"site.discountMin=100site.limitPerOrder=30
*Yaf支持用php和ini两种文件格式的配置文件,其中php文件需返回一个数组,ini文件传入后也会被转换成一个对应的多维数组(实际是一个对象)
*如果使用使用ini作为配置文件,site.title="我的官网" 等效于 array('site'=>array('title'=>"我的官网") )
*代码中[yaf]定义了一个名叫yaf的配置节,[common : yaf]定义了一个叫common的配置节,它继承yaf配置节。
*如果打开yaf.cache_config,ini配置文件将会被缓存
===插件[plugin]===
;插件需要向Yaf_Dispatcher注册才能生效。插件文件放APPLICATION_PATH下的plugins目录下由自动加载器加载,放在其他目录则由普通加载规则加载,详细请参考:[http://yaf.laruence.com/manual/yaf.plugin.html 第7章-使用插件]
===模板[view]===
*Yaf_View_Simple是Yaf自带的视图引擎, 它追求性能,使用纯PHP语法,所以并没有提供类似Smarty那样的多样功能, 和复杂的语法.如果需要使用smarty,也可以替换。
*关于layout
layout对于维护代码是非常必要的,而Yaf本身并没有提供这样的功能。网上的实现一般是通过Yaf的插件机制来实现,
在新版商城中,我们简洁的实现了一套render layout方法。
<pre>
//Base_Ctrl所有controller的父类
class Base_Ctrl extends Yaf_Controller_Abstract {public $layoutfile = 'column_main';public $main_view='main';public $pageTitle=''; //页面title//等等等等。。。。这些变量可以在view里面通过$C来直接传输和调用public function render($phtml,$params=array(),$return=false) {$paramsExtra = array_merge($params,array('actionName'=>$this->getActionId(),'controllerName'=>$this->getControllerId()));$paramsExtra['C'] = $this;//把controller实例传给view, 方便传一些参数和方法过去$html1 = $this->render($phtml, $paramsExtra);//先渲染action自身的viewif ( !empty($this->layoutfile) ) {//如果需要layout, 则渲染layout$html1 = $this->getView()->render(PATH_TPL.'/layout/'.$this->layoutfile.'.php', array_merge($paramsExtra,array('content'=>$html1)) );}//最后渲染最外层的公共layout$html1 = $this->getView()->render(PATH_TPL.'/layout/'.$this->main_view.'.php', array_merge($paramsExtra,array('content'=>$html1)));if ( $return ) {return $html1;} else {echo $html1;exit;}}//这个方法主要用于应对不需要layout的情况public function renderPartial($phtml,$params=array(),$return=false) {$paramsExtra = array_merge($params,array('actionName'=>$this->getActionId(),'controllerName'=>$this->getControllerId()));$paramsExtra['C'] = $this;$html1 = $this->render($phtml,$paramsExtra); if ( $return ) {return $html1;} else {echo $html1;exit;}}
}
</pre>===路由===
*路由注册的顺序很重要, 最后注册的路由协议, 最先尝试路由, 这就有个陷阱. 请注意.
*路由解析仅仅发生一次,某一个路由协议返回成功以后, 就匹配成功
*路由配置好后需要Yaf_Config::addConfig和Yaf_Router::addRoute两种方法来添加路由协议,才会生效
*路由注册示例代码:
<pre>
class Bootstrap extends Yaf_Bootstrap_Abstract{public function _initConfig(){Yaf_Registry::set("config", Yaf_Application::app()->getConfig());}public function _initRoute() {$config = Yaf_Registry::get('config');$routeconfigs = isset($config['routes']) ? $config['routes'] : array();Yaf_Dispatcher::getInstance()->getRouter()->addConfig($routeconfigs);}
}
</pre>
===扩展(此部分非yaf框架自带)===
;商城在对yaf的使用时,引入了一些yii的好的使用起来方便的东西,其使用习惯跟yii基本一样。
*models/BaseForm.php BaseFormModel是一个表单基础类,继承后可使用rules方法来实现验证规则的定义
public function rules() {return array(array('contact, content', 'required'),);}
*controller中可以跟yii一样使用accessRules方法定义未登录和登录用户对action的访问权限public function accessRules() {return array(array('allow','actions' => array('*'),'users' => array('@'),),);}
*libray/Redis 是一个封装好的redis类,支持单台和多台服务器的常用操作
;使用方法
$redis = new Redis_Connection();$redis->$key = $value; //配置$redis->get('key');//多台服务器redis4.class="Redis_Connection"redis4.servers.0.host="10.237.2.72"redis4.servers.0.port=6379redis4.servers.1.host="10.237.2.73"redis4.servers.1.port=6379//单台服务器redis7.class="Redis_Connection"redis7.host="10.237.2.72"redis7.port=8379
;view中$C是当前contrlloer的实例,对其赋值后可以在页面做相应的展示,如$C->breadcrumbs = array('服务支持' => '/c/service','建议留言',);$C->pageTitle = "建议留言";$C->description = "销售渠道。";$C->keywords = "建议留言";$C->addCssFile('http://www.baidu.com/css/ui.common.min.css');$C->addScriptFile('http://www.baidu.com/js/xm.base.min.js');
*PDO的封装,curl的封装等
===GET & POST===
*Yaf_Request_Abstract::getParam
本方法在controller中可以使用$this->getRequest()->getParam($name, $defaultValue)方式调用。
请注意:不要试图用此方法取get和post里的参数,因为此方法取出的值都是由路由而产生的键值对。
比如:/site/index/id/aaa?name=bbb
$this->getRequest()->getParam(“id”)可以正确取到值,但是$this->getRequest()->getParam("name")并不一定能取到(默认路由情况下).
如果需要,请使用下面两个方法。
*Yaf_Request_Http::getQuery()
本方法在controller中可以使用$this->getRequest()->getQuery($name, $defaultValue)方式调用。
注意:这个方法取的是get形式的参数,并且该值是只读的,也就是即使修改了$_GET对应的值,它也不会改变。因此,使用时,请进行必要的参数处理。
*Yaf_Request_Http::getPost()
本方法在controller中可以使用$this->getRequest()->getPost($name, $defaultValue)方式调用。
注意:这个方法取的是post的参数。同上,该值是只读的.
;在sdk版本中,对三个方法进行了封装,调用的时候直接使用$controller->getParam/getQuery/getPost即可,对数据都做了转义检查。如下:
<pre>
//Base_Ctrl所有controller的父类
class Base_Ctrl extends Yaf_Controller_Abstract {
.....public function getParam($name, $defaultValue=null) {$value = (null === $defaultValue) ? $this->getRequest()->getParam($name) : $this->getRequest()->getParam($name, $defaultValue);return !empty($value) ? addslashes($value) : $value;}public function getPost($name, $defaultValue=null) {$value = (null === $defaultValue) ? $this->getRequest()->getPost($name) : $this->getRequest()->getPost($name, $defaultValue);return !empty($value) ? Common::daddslashes($value) : $value;}public function getQuery($name, $defaultValue=null) {$value = (null === $defaultValue) ? $this->getRequest()->getQuery($name) : $this->getRequest()->getQuery($name, $defaultValue);return !empty($value) ? Common::daddslashes($value) : $value;}
.....
}
</pre>
===错误与异常机制===
*关注如下两个配置
<pre>
application.dispatcher.throwException=TRUE
application.dispatcher.catchException=TRUE
</pre>
;手册中描述:
Yaf实现了一套错误和异常捕获机制, 主要是对常见的错误处理和异常捕获方法做了一个简单抽象, 方便应用组织自己的错误统一处理逻辑.
Yaf自身出错时候, 根据配置可以分别采用抛异常或者触发错误的方式来通知错误.
在appliation.dispatcher.throwException(配置文件, 或者通过Yaf_Dispatcher::throwException(true))打开的情况下, Yaf会抛异常, 否则则会触发错误.
在application.dispatcher.catchException(配置文件, 或者可通过Yaf_Dispatcher::catchException(true))开启的情况下, 当Yaf遇到未捕获异常的时候, 就会把运行权限, 交给当前模块的Error Controller的Error Action动作, 而异常或作为请求的一个参数, 传递给ErrorAction.
在Error Action中可以通过$request->getRequest()->getParam("exception")获取当前发生的异常.
在程序中,我们需要自己捕捉并且必须适当的显示错误。所以我们两个配置均为TRUE
*sdk版本ErrorController的实现
<pre>
class ErrorController extends Base_Ctrl {public function errorAction($exception) {$exceptionType = get_class($exception);$this->getView()->assign("error", $exception);$this->getView()->assign("exceptionType", $exceptionType);$this->render('error');}}
</pre>
*sdk版本errorAction的模板
<pre>
//当定义了IN_DEBUG表示的是开发测试环境,显示相关错误信息
if ( defined('IN_DEBUG') && IN_DEBUG ) { ?>
<div>
<h1>Debug Mode:</h1>
<p>Msg : <?php echo $error->getMessage();?></p>
<p>File: <?php echo $error->getFile();?></p>
<p>Line: <?php echo $error->getLine();?></p>
<p>Code: <?php echo $error->getCode();?></p>
</div>
<? } ?>
//标准错误异常处理情况
//Exception是标准的开发抛出的错误,可以信任并且直接显示
<?php if($exceptionType=='Exception'){ ?>
<h3><?php echo $error->getMessage();?></h3>
//这两个是属于没有找到controller或者action的情况,可以以404来处理
<?php }elseif(in_array($exceptionType,array('Yaf_Exception_LoadFailed_Controller','Yaf_Exception_LoadFailed_Action'))){?>
<h3>您訪問的地址不存在</h3>
<?php }else{?>
//其他情况
<h3>系統繁忙,請稍候再試</h3>
<?php }?>
</pre>
==思维导图==
[[文件:YAF.png]]
==参考资料==
;[http://www.php.net/manual/en/book.yaf.php Yaf官方文档]
;[http://www.laruence.com/2012/07/06/2649.html Yaf的一些资源]