时间:2021-07-01 10:21:17 帮助过:2人阅读
为了能更清晰地了解应用控制器总体实现的结构,代码中需要使用到的类都已经在之前实现了,现在只剩下的是核心的部分:AppController和Controller。
namespace demo\controller; /** * Controller */ class Controller { private $appHelper; // 不能实例化,只能通过Controller::run()的方式来执行 private function __construct() { } public static function run() { $instance = new self(); // 加载配置 $instance->init(); // 处理请求 $instance->handleReuqest(); } private function init() { $appHelper = \demo\controller\ApplicationHelper::getInstance(); $appHelper->init(); } private function handleReuqest() { $request = new \demo\controller\Request(); $appController = \demo\base\ApplicationRegistry::getInstance()->getAppController(); // 执行完所有Command,有可能存在forward while ($cmd = $appController->getCommand($request)) { // var_dump($cmd); $cmd->execute($request); // 把当前Command设为已执行过 $request->setLastCommand($cmd); } // 获取视图 $view = $appController->getView($request); // 显示视图 $this->invokeView($view); /* $cmdReslover = new \demo\command\CommandReslover(); $cmd = $cmdReslover->getCommand($request); $cmd->execute($request); */ } private function invokeView($view) { include("demo/view/{$view}.php"); exit(); } }handleRequest()里面的while循环是为了处理
Controller执行流程:
1)读取xml配置到controllerMap对象;
2)得到$request;
3)由appController解析$request->getProperty('cmd'),返回$cmd;
4)$cmd->execute($request),如果controllerMap中存在cmd对应的$forward,则$request->setProperties('cmd', $forward),跳到3),否则跳到5);
5)由appController->getView($request)取得视图$view;
6)调用视图invokeView($view);
应用控制器AppController:
namespace demo\controller; /** * AppController */ class AppController { private static $baseCmd; private static $defaultCmd; private $controllerMap; // 标记已经执行过的Command,防止出现forward循环 private $invoked = array(); public function __construct(\demo\controller\ControllerMap $camp) { if (!isset(self::$baseCmd)) { self::$baseCmd = new \ReflectionClass('\demo\command\Command'); self::$defaultCmd = new \demo\command\DefaultCommand(); } $this->controllerMap = $camp; } public function getView(\demo\controller\Request $request) { $view = $this->getResource($request, 'View'); return $view; } public function getForward(\demo\controller\Request $request) { $forward = $this->getResource($request, 'Forward'); if ($forward) { // 设置forward为新的请求 $request->setProperties('cmd', $forward); } return $forward; } /** * getView、getForward * @param \demo\controller\Request $request * @param string $resType */ private function getResource(\demo\controller\Request $request, $resType) { $cmd = $request->getProperty('cmd'); $previous = $request->getLastCommand(); $status = $previous->getStatus(); $status = $status ? $status : 0; $acquire = "get{$resType}"; // 按指定优先级获取view或forward $resource = $this->controllerMap->$acquire($cmd, $status); if (!$resource) { $resource = $this->controllerMap->$acquire('default', $status); } if (!$resource) { $resource = $this->controllerMap->$acquire($cmd, 0); } if (!$resource) { $resource = $this->controllerMap->$acquire('default', 0); } return $resource; } public function getCommand(\demo\controller\Request $request) { $previous = $request->getLastCommand(); if (!$previous) { // 当前为第一次请求 $cmd = $request->getProperty('cmd'); if (!$cmd) { // cmd为空,返回default $request->setProperties('cmd', 'default'); return self::$defaultCmd; } } else { // 返回forward $cmd = $this->getForward($request); if (!$cmd) { return null; } } // 取得Command对象 $cmdObj = $this->resloveCommand($cmd); if (!$cmdObj) { throw new \demo\base\AppException("'Command {$cmd} not found!"); } // 判断是否forward循环 $cmdClass = get_class($cmdObj); if (isset($this->invoked[$cmdClass])) { throw new \demo\base\AppException('Circular Forwarding!'); } $this->invoked[$cmdClass] = true; return $cmdObj; } /** * 从ControllerMap中获取$cmd对应的映射 * @param string $cmd */ public function resloveCommand($cmd) { $classroot = $this->controllerMap->getClassroot($cmd); $sep = DIRECTORY_SEPARATOR; $filePath = "demo{$sep}command{$sep}{$classroot}.php"; $className = "\\demo\\command\\{$classroot}"; if (file_exists($filePath)) { @require_once $filePath; if (class_exists($className)) { $cmdClass = new \ReflectionClass($className); if ($cmdClass->isSubclassOf(self::$baseCmd)) { return $cmdClass->newInstance(); } } } return null; } }
要注意的是Request对象,getResource和getCommand都是根据Request对象里面的cmd或者lastCommand来处理的。
应用控制器依然需要从请求的url中获取cmd来判断调用Command,但它能够利用
Controller和AppController都已经完成了,那么来看个具体的例子吧。
一个具体的Command子类,Login:
namespace demo\command; require_once 'demo/command/Command.php'; require_once 'demo/base/Registry.php'; class Login extends Command { protected function doExecute(\demo\controller\Request $request) { $userName = $request->getProperty('userName'); $password = $request->getProperty('password'); if (!$userName || !$password) { return self::status('CMD_INSUFFICIENT_DATA'); } if ($userName == 'root' && $password == 'root') { return self::status('CMD_OK'); } else { return self::status('CMD_ERROR'); } } }对于下面三个url请求,控制器都能得到预期的结果:
runner.php?cmd=Login&userName=root&password // CMD_INSUFFICIENT_DATA runner.php?cmd=Login&userName=root&password=root // CMD_OK runner.php?cmd=Login&userName=root&password=123 // CMD_ERROR
use demo\controller\Controller; require_once 'demo/controller/Controller.php'; Controller::run();