yii框架源码分析之创建controller代码
程序员文章站
2023-02-26 17:06:27
使用yii框架的url路径一般形如hostname/?r=xxxx/xxxx/xxxx&sdfs=dsfdsf 我们可以看到有时会使用protected目录下的contro...
使用yii框架的url路径一般形如hostname/?r=xxxx/xxxx/xxxx&sdfs=dsfdsf
我们可以看到有时会使用protected目录下的controller,有时会使用module中controller,具体是如何处理的呢,请看如下的分析:
以下代码摘自yii框架核心代码%yiiroot%/framework/web/cwebapplication.php
=================================================================================================
//1.runcontroller是执行一个controller的方法,$route是$_get['r']
public function runcontroller($route)
{
//在这里调用createcontroller先去创建一个controller实例,由此可见createcontroller是选择controller的关键
if(($ca=$this->createcontroller($route))!==null)
{
list($controller,$actionid)=$ca;
$oldcontroller=$this->_controller;
$this->_controller=$controller;
$controller->init();
$controller->run($actionid);
$this->_controller=$oldcontroller;
}
else
throw new chttpexception(404,yii::t('yii','unable to resolve the request "{route}".',
array('{route}'=>$route===''?$this->defaultcontroller:$route)));
}
==================================================================================================
//2.接下来我们分析createcontroller,假设我们访问的route是site/contact
public function createcontroller($route,$owner=null)
{
//首次进入这个函数,$owner参数为空
if($owner===null)
$owner=$this;
//如果$route参数中不含/,那么使用默认的controller
if(($route=trim($route,'/'))==='')
$route=$owner->defaultcontroller;
$casesensitive=$this->geturlmanager()->casesensitive;
//为了能够完整运行下面的循环,给$route后面加一个/
$route.='/';
//将/的位置保存在$pos中
while(($pos=strpos($route,'/'))!==false)
{
//$id是前半部分,即site
$id=substr($route,0,$pos);
if(!preg_match('/^\w+$/',$id))
return null;
if(!$casesensitive)
$id=strtolower($id);
//$route变成后半部分,即contact
$route=(string)substr($route,$pos+1);
//controller根目录或子目录前缀
if(!isset($basepath)) // first segment
{
//首次进入,$owner为空,没有这个成员变量
//非首次进入或$owner有值,有可能设置了这个成员变量,参见cwebmodule类
if(isset($owner->controllermap[$id]))
{
return array(
yii::createcomponent($owner->controllermap[$id],$id,$owner===$this?null:$owner),
$this->parseactionparams($route),
);
}
//如果能通过getmodule方法获取到一个独立模块,则再次调用createcontroller,适用于site是module名的情况,参考protected/config/main.php配置文件,例如你的controller在%webroot%/protected/module/site/controller/contactcontroller.php
if(($module=$owner->getmodule($id))!==null)
return $this->createcontroller($route,$module);
//controller的目录:
//对于cwebapplication,对应config['basepath'](参见配置文件)./controller/,例如你的controller在%webroot%/protected/controller/sitecontroller.php
//对于cmodule的子类,对应改子类所在文件夹./contoller/,例如你的controller在%webroot%/protected/module/site/controller/contactcontroller.php
$basepath=$owner->getcontrollerpath();
$controllerid='';
}
else
$controllerid.='/';
$classname=ucfirst($id).'controller';
$classfile=$basepath.directory_separator.$classname.'.php';
//如果$classfile存在,根据上面所得到的controller类文件路径,创建类实例
//如果不存在,则是子目录下的controller,继续循环寻找最终的controller,例如你的controller在%webroot%/protected/controller/somedir/sitecontroller
if(is_file($classfile))
{
if(!class_exists($classname,false))
require($classfile);
if(class_exists($classname,false) && is_subclass_of($classname,'ccontroller'))
{
$id[0]=strtolower($id[0]);
return array(
new $classname($controllerid.$id,$owner===$this?null:$owner),
$this->parseactionparams($route),
);
}
return null;
}
$controllerid.=$id;
$basepath.=directory_separator.$id;
}
}
我们可以看到有时会使用protected目录下的controller,有时会使用module中controller,具体是如何处理的呢,请看如下的分析:
以下代码摘自yii框架核心代码%yiiroot%/framework/web/cwebapplication.php
复制代码 代码如下:
=================================================================================================
//1.runcontroller是执行一个controller的方法,$route是$_get['r']
public function runcontroller($route)
{
//在这里调用createcontroller先去创建一个controller实例,由此可见createcontroller是选择controller的关键
if(($ca=$this->createcontroller($route))!==null)
{
list($controller,$actionid)=$ca;
$oldcontroller=$this->_controller;
$this->_controller=$controller;
$controller->init();
$controller->run($actionid);
$this->_controller=$oldcontroller;
}
else
throw new chttpexception(404,yii::t('yii','unable to resolve the request "{route}".',
array('{route}'=>$route===''?$this->defaultcontroller:$route)));
}
==================================================================================================
//2.接下来我们分析createcontroller,假设我们访问的route是site/contact
public function createcontroller($route,$owner=null)
{
//首次进入这个函数,$owner参数为空
if($owner===null)
$owner=$this;
//如果$route参数中不含/,那么使用默认的controller
if(($route=trim($route,'/'))==='')
$route=$owner->defaultcontroller;
$casesensitive=$this->geturlmanager()->casesensitive;
//为了能够完整运行下面的循环,给$route后面加一个/
$route.='/';
//将/的位置保存在$pos中
while(($pos=strpos($route,'/'))!==false)
{
//$id是前半部分,即site
$id=substr($route,0,$pos);
if(!preg_match('/^\w+$/',$id))
return null;
if(!$casesensitive)
$id=strtolower($id);
//$route变成后半部分,即contact
$route=(string)substr($route,$pos+1);
//controller根目录或子目录前缀
if(!isset($basepath)) // first segment
{
//首次进入,$owner为空,没有这个成员变量
//非首次进入或$owner有值,有可能设置了这个成员变量,参见cwebmodule类
if(isset($owner->controllermap[$id]))
{
return array(
yii::createcomponent($owner->controllermap[$id],$id,$owner===$this?null:$owner),
$this->parseactionparams($route),
);
}
//如果能通过getmodule方法获取到一个独立模块,则再次调用createcontroller,适用于site是module名的情况,参考protected/config/main.php配置文件,例如你的controller在%webroot%/protected/module/site/controller/contactcontroller.php
if(($module=$owner->getmodule($id))!==null)
return $this->createcontroller($route,$module);
//controller的目录:
//对于cwebapplication,对应config['basepath'](参见配置文件)./controller/,例如你的controller在%webroot%/protected/controller/sitecontroller.php
//对于cmodule的子类,对应改子类所在文件夹./contoller/,例如你的controller在%webroot%/protected/module/site/controller/contactcontroller.php
$basepath=$owner->getcontrollerpath();
$controllerid='';
}
else
$controllerid.='/';
$classname=ucfirst($id).'controller';
$classfile=$basepath.directory_separator.$classname.'.php';
//如果$classfile存在,根据上面所得到的controller类文件路径,创建类实例
//如果不存在,则是子目录下的controller,继续循环寻找最终的controller,例如你的controller在%webroot%/protected/controller/somedir/sitecontroller
if(is_file($classfile))
{
if(!class_exists($classname,false))
require($classfile);
if(class_exists($classname,false) && is_subclass_of($classname,'ccontroller'))
{
$id[0]=strtolower($id[0]);
return array(
new $classname($controllerid.$id,$owner===$this?null:$owner),
$this->parseactionparams($route),
);
}
return null;
}
$controllerid.=$id;
$basepath.=directory_separator.$id;
}
}