[php]应用控制器(2)

WBOY
リリース: 2016-06-13 11:36:54
オリジナル
792 人が閲覧しました

[php]应用控制器(二)

        为了能更清晰地了解应用控制器总体实现的结构,代码中需要使用到的类都已经在之前实现了,现在只剩下的是核心的部分: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循环是为了处理中有可能出现的元素的值是对应的Command子类,这些的关系都已经被映射到ControllerMap中去了。

        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,但它能够利用来控制程序的流程,而且能够为一个可以产生许多不同反馈的页面安排不同的视图(比如表单,提交后可能是error、success等其它反馈视图)。


        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
ログイン後にコピー

        下面为入口文件runner.php的代码:
use demo\controller\Controller;require_once 'demo/controller/Controller.php';Controller::run();
ログイン後にコピー


        现在已经能完成对请求的处理了,还控制了程序流程。一般的情况下很少用到应用控制器。如果只需要实现单一入口功能的话,一个入口文件(runner.php)直接解析url就能完成了。
        控制器层已经完成了,那么接下来需要实现持久化层了。
関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート