1.第一次启动会向DB导入必要的数据,并根据设定重写配置文件,以及生成入口的index.php文件
index.php文件最终运行
Tiny::createWebApp($config)->run();
2.类Tiny在文件tiny.php中创建。
public static function createWebApp($config=null)
{
return self::createApp('WebApp',$config);
}
public static function createApp($className,$config=null)
{
//加载项目的时区,默认为中国
date_default_timezone_set('Asia/Shanghai');
//注册脚本执行完毕后调用的动作
register_shutdown_function(array('Tiny','exitScript'));
Tiny::initSystemHandler();
return new $className($config);
}
3.类WebApp位于文件webapp_class.php中,而run方法,是在其父类App也就是文件application_class.php中
public function run()
{
//实现对Application的扩展
Tiny::$_iserror = true;
$appExtension = ExtensionFactory::getFactory('appExtension');
if($appExtension !== null )
{
$appExtension->before();
$this->doRequest();
$appExtension->after();
}
else $this->doRequest();
Tiny::$_iserror = false;
}
4.接下来看看类WebApp里的方法doRequest
public function doRequest()
{
Url::urlReWrite();
$this->runController();
}
public function runController()
{
$this->controller = $this->createController();
$this->controller->run();
}
public function createController()
{
$controllerName = Req::args('con')!==null?ucfirst(Req::args('con')):$this->defaultController;
$controllerClass = $controllerName.'Controller';
$widgetClass = $controllerName.'Widget';
if(class_exists($controllerClass))
{
return new $controllerClass(strtolower($controllerName),$this);
}
else if(class_exists($widgetClass))
{
return new $widgetClass($controllerName,$this);
}
else if(Tiny::getErrorsController()!==null)
{
$errorsController = Tiny::getErrorsController();
return $errorsController;
}
else
{
return new Controller($controllerName,$this);
}
}
可以看出webapp是通过con来寻找controller的,如果请求里没有设置con,那么默认使用的是index。寻找的规则大写con值得第一个字母,并且链接字符串“Controller”,比如con=admin,那么寻找的controller类名就是AdminController
5.既然找到了相应的controller了,那么看看调用的run方法是怎样的。run方法存在于controller的父类Controller里,也就是文件controller_class.php里
public function run()
{
if(Tiny::app()->checkToken('redirect')){
$data = Req::args();
unset($data['con'],$data['act'],$data['tiny_token_redirect']);
$this->setDatas($data);
}
$this->init();
$id = Req::args('act');
if($id ===null) $id = $this->defaultAction;
//防止页面的循环调用
if(!$this->module->popRequestStack($this->id.'@'.$id))$this->module->pushRequestStack($this->id.'@'.$id);
else if($this->module->popRequestStack($this->id.'@'.$id)) {throw new Exception("Can't repeat redirect to the same position, you action is {$this->id}.",E_USER_ERROR);}
$this->action = $this->createAction($id);
//所有Controller处理的扩展处理
$contExtensions = ExtensionFactory::getFactory('controllerExtension');
if($contExtensions !== null )
{
$contExtensions->before($this);
if(!is_null($this->action))$this->action->run();
$contExtensions->after($this);
}
else if(!is_null($this->action))$this->action->run();
}
根据参数act的值来查找其对应的action,默认是index。这里为了防止循环调用,会把以字符串“con@act”的形式把调用过的action存起来,然后检查是否调用过。
接下来看看action是如何创建的
public function createAction($id)
{
if($id ==='') $actionId = $this->defaultAction;
//统一拦截权限控制
if($this->checkRight($id) == false)
{
$this->noRight();
}else{
//如果控制器直接定义了方式
if(method_exists($this,$id))
{
return new InlineAction($this,$id);
}
else
{
return new Action($this, $id);
}
}
}
如果这个controller类里有以action命名的方法,那么就创建InlineAction类,如果没有,就创建Action类
linlineAction类的run方法很简单,就是直接执行那个方法
class InlineAction extends BaseAction
{
//Action运行入口
public function run()
{
$controller=$this->getController();
$methodName=$this->getId();
$controller->$methodName();
}
}
如果以act值命名的方法不存在的话, 那么再来看看Action类,它的run方法比较长,那么我们就来看看关键的几个地方。
$methodName = preg_split("/_(?=(save|del|edit)$)/i",$this->getId());
$operator = array('save'=>'save','del'=>'delete','edit'=>'find');
if($controller->getAutoActionRight() && array_key_exists($op,$operator))
{
$model = new Model($modelName);
$data=$model->data(Req::args())->$operator[$op]();
}
当方法名也就是act的值是以xxxx_save,xxxx_del,xxxx_edit命名时,且登录者有自动action权限时(权限的判断可参考controller_class类的$autoActionRight值设定),可以自动对表(xxxx)进行插入,删除,更新操作。
如果方法名并没有这个规则,或者没有权限的话。那么
else
{
$action = new ViewAction($controller, $this->getId());
$action->run();
//exit;
}
继续跟踪一下类ViewAction可以看到其实就是直接输出view目录下,以con的值为子目录名,以act的值为文件名的php文件。