Home > Backend Development > PHP Tutorial > [php]应用控制器(2)

[php]应用控制器(2)

WBOY
Release: 2016-06-13 12:36:15
Original
894 people have browsed it

[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();
	}
}
Copy after login

        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;
	}
}
Copy after login

        要注意的是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');
		}
	}
}
Copy after login
        对于下面三个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
Copy after login

        下面为入口文件runner.php的代码:
use demo\controller\Controller;
require_once 'demo/controller/Controller.php';

Controller::run();
Copy after login


        现在已经能完成对请求的处理了,还控制了程序流程。一般的情况下很少用到应用控制器。如果只需要实现单一入口功能的话,一个入口文件(runner.php)直接解析url就能完成了。
        控制器层已经完成了,那么接下来需要实现持久化层了。
Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template