ホームページ  >  記事  >  バックエンド開発  >  [php] アプリケーションコントローラー (1)

[php] アプリケーションコントローラー (1)

WBOY
WBOYオリジナル
2016-06-13 12:36:16952ブラウズ

[php] アプリケーション コントローラー (1)

フロントエンド コントローラーは既にリクエストを処理し、1 か所で適切なコマンドを選択できますが、Command サブクラス オブジェクトはビューの割り当てを独自に処理します。 (コマンド処理後に返されたステータス値に従って) クラスを使用してビューを決定し、それをフロントエンド コントローラーに返すことができ、その後フロントエンド コントローラーがビュー表示を呼び出す場合、フロントエンド コントローラーはendコントローラーはビュー層とビジネス層の真ん中にあり、コマンドとビューもしっかり分離します。アプリケーション コントローラーは優れたソリューションです。

アプリケーション コントローラーは、リクエストをコマンドにマッピングし、コマンドをビューにマッピングする責任があります。これにより、コア コードを変更せずにアプリケーションのフローを変更できます。これにより、Command クラスを解放し、Command クラスが入力の処理、アプリケーション ロジックの呼び出し、結果の処理などの独自の作業を完了することに集中できるようになります。

アプリケーション コントローラーは、フロントエンド コントロールがリクエストを処理するタスクを引き継ぎ、フロントエンド コントローラー呼び出しに適切なビューを返すのに役立つクラス (またはクラスのグループ) です。では、アプリケーション制御はどのように機能するのでしょうか? XML 構成ファイルを通じてコマンドとビューがどのように機能するかを決定します。たとえば、次の XML ファイル (Struts に少し似ています):

<?xml version="1.0" encoding="UTF-8"?>
<options>
	<dsn>sqlite://data/demo.db</dsn>
	<username>root</username>
	<password>root</password>
	
	<controller>
		<view>main</view>
		<view status="CMD_OK">main</view>
		<view status="CMD_ERROR">error</view>
		
		<command name="ListStudents">
			<view>list_students</view>
		</command>
		
		<command name="AddStudent">
			<view>add_student</view>
			<status value="CMD_OK">
				<forward>ListStudents</forward>
			</status>
		</command>
				
		<command name="SimpleAddStudent">
			<classalias name="AddStudent"/>
			<view>simple_add_student</view>
		</command>
	</controller>
</options>
xml の には、 という 3 種類のサブ要素を含めることができます。これらはそれぞれビューとコマンドに対応する業務処理後のステータス値と、コマンド処理後のジャンプ(ここでは別のコマンドにジャンプ)。


xml 構造から、Command クラスには新しい属性ステータスが必要であることがわかります。

namespace demo\command;

/**
 * 抽象父类
 */
abstract class Command {
	// 状态值映射
	private static $STATUS_STRINGS = array(
        'CMD_DEFAULT' => 0,
        'CMD_OK' => 1,
        'CMD_ERROR' => 2,
        'CMD_INSUFFICIENT_DATA' => 3
	);
	// 当前状态值
	private $status = 0;
	
	public final function __construct() {
		// 子类不能重写构造函数
	}
	
	/**
	 * 按状态字符串返回状态值
	 * @param unknown_type $staStr
	 */
	public static function status($stauStr = 'CMD_DEFAULT') {
		if (empty($stauStr)) {
			$stauStr = 'CMD_DEFAULT';
		}
		
		return self::$STATUS_STRINGS[$stauStr];
	} 
	
	/**
	 * 调用子类实现的doExecute
	 * @param \demo\controller\Request $request
	 */
	public function execute(\demo\controller\Request $request) {
		$this->doExecute($request);
	}
	
	protected abstract function doExecute(\demo\controller\Request $request);
}
                     

システムには、構成の取得に特化したヘルパー クラス ApplicationHelper があり、XML 構成を読み取ることができます。 XML の要素構造は比較的柔軟であるため、各要素の値とコマンドおよびビューの間の 1 対 1 のマッピング関係を管理するには、ControllerMap が必要です。

namespace demo\controller;

class ControllerMap {
	private $classrootMap = array();
	private $forwardMap = array();
	private $viewMap = array();
	
	public function addClassroot($cmd, $classroot) {
		$this->classrootMap[$cmd] = $classroot;
	}
	
	public function getClassroot($cmd) {
		if (isset($this->classrootMap[$cmd])) {
			return $this->classrootMap[$cmd];
		}
		
		return $cmd;
	}
	
	public function addForward($cmd = 'default', $status = 0, $newCmd) {
		$this->forwardMap[$cmd][$status] = $newCmd;
	}
	
	public function getForward($cmd, $status) {
		if (isset($this->forwardMap[$cmd][$status])) {
			return $this->forwardMap[$cmd][$status];
		}
		
		return  null;
	}
	
	public function addView($cmd = 'default', $status = 0, $view) {
		$this->viewMap[$cmd][$status] = $view;
	}
	
	public function getView($cmd, $status) {
		if (isset($this->viewMap[$cmd][$status])) {
			return $this->viewMap[$cmd][$status];
		}
		
		return  null;
	}
}

まず、構成 ApplicationHelper クラスの getOptions を xml で取得する必要があります。

namespace demo\controller;

/**
 * 助手类:获取xml配置
 * 单例模式 
 *
 */
class ApplicationHelper {
	private static $instance;
	private $config = 'data/config.xml';
	
	private function __construct() {
		
	}
	
	public static function getInstance() {
		if (isset(self::$instance) == false) {
			self::$instance = new self();
		}
		
		return self::$instance;
	}
	
	public function init() {
		// 初始化配置从序列化文件中获取
		$dsn = \demo\base\ApplicationRegistry::getInstance()->getDSN();
		$camp = \demo\base\ApplicationRegistry::getInstance()->getControllerMap();
		
		if (is_null($dsn) || is_null($camp)) {
			$this->getOptions();
		}
	}
	
	/**
	 * 获取xml配置
	 */
	public function getOptions() {
		// xml
        $this->ensure(file_exists($this->config), "Could not find options file!");
        $options = @simplexml_load_file($this->config);
        var_dump($options);
        $this->ensure($options instanceof \SimpleXMLElement, 'Could not resolve options file!');
        
        // <dsn>
        $dsn = (string)$options->dsn;
        $this->ensure($dsn, 'No dsn found!');
        \demo\base\ApplicationRegistry::getInstance()->setDSN($dsn);
        
        // <controller>
  		$map = new ControllerMap();
  		// <view>
  		foreach ($options->controller->view as $default_view) {
  			$stauStr = trim((string)$default_view['status']);
  			$status = \demo\command\Command::status($stauStr);
  			$map->addView('default', $status, (string)$default_view);
  		}
  		
  		// <command>
  		foreach ($options->controller->command as $cvf) {
  			$cmd = trim((string)$cvf['name']);
  			
  			// <classalias>
  			if($cvf->classalias) {
  				$classroot = (string)$cvf->classalias['name'];
  				$map->addClassroot($cmd, $classroot);
  			}
  			
  			// <view>、<forward>
  			if ($cvf->view) {
  				$view =  trim((string)$cvf->view);
  				$forward = trim((string)$cvf->forward);
  				$map->addView($cmd, 0, $view);
  				if ($forward) {
  					$map->addForward($cmd, 0, $forward);
  				}
  			}
  			
  			// <status>
  			foreach ($cvf->status as $status) {
  				$stauStr = trim((string)$status['value']);
  				$view = trim((string)$status->view);
  				$forward = trim((string)$status->forward);
  				$stau = \demo\command\Command::status($stauStr);
  				
  				if ($view) {
  					$map->addView($cmd, $stau, $view);
  				}
  				
  				if ($forward) {
  					$map->addForward($cmd, $stau, $forward);
  				}
  			}
  		}
  		var_dump($map);
  		 \demo\base\ApplicationRegistry::getInstance()->setControllerMap($map);
	}
	
	private function ensure($expr, $msg) {
		if (!$expr) {
			throw new \demo\base\AppException($msg);
		}
	}
}

XML 構成を取得するプロセスは、比較的時間のかかる操作です。まず、ControllerMap オブジェクトをファイルにシリアル化してから、ApplicationRegistry を通じて取得し、グローバル データとしてキャッシュします。

/**
 * Application作用域
 */
class ApplicationRegistry extends Registry {
    private static $instance;
    private $freezedir = "./data"; // 此处硬编码,具体根据实际情况配置
    private $values = array();
    private $mtimes = array();

    private function __construct() {
    
    }

	public static function getInstance() {
		if (isset(self::$instance) == false) {
			self::$instance = new self();
		}
		
		return self::$instance;
	}

	/**
	 * 从序列化文件中获取$key数据
	 */
    protected function get($key) {
        $path = $this->freezedir . DIRECTORY_SEPARATOR . $key;
        if (file_exists($path)) {
        	// 清楚文件缓存
            clearstatcache();
            $mtime = filemtime($path);
            if (isset($this->mtimes[$key])  == false) { 
            	$this->mtimes[$key]=0; 
            }
            
            // 文件最近被修改过,重新反序列化新的数据
            if ($mtime > $this->mtimes[$key] ) {
                $data = file_get_contents($path);
                $this->mtimes[$key] = $mtime;
                return ($this->values[$key] = unserialize($data));
            }
        }
        
        if (isset( $this->values[$key]) == true) {
            return $this->values[$key];
        }
        
        return null;
    }

    protected function set($key, $val) {
        $this->values[$key] = $val;
        $path = $this->freezedir . DIRECTORY_SEPARATOR . $key;
        if (file_exists($path)) {
        	touch($path);
        }	
        file_put_contents($path, serialize($val));
        $this->mtimes[$key]=time();
    }

    public function getDSN() {
        if (isset($this->values['dsn'])) {
        	return $this->values['dsn'];
        }
        
        return self::getInstance()->get('dsn');
    }

    public function setDSN($dsn) {
        return self::getInstance()->set('dsn', $dsn);
    }

    /**
     * 
     * @param \demo\controller\ControllerMap $map
     */
    public function setControllerMap(\demo\controller\ControllerMap $map) {
        self::getInstance()->set('cmap', $map);
    }

    public function getControllerMap() {
        if (isset($this->values['cmap'])) {
        	return $this->values['cmap'];
        }
        
        return self::getInstance()->get('cmap');
    }
    
    /**
     * 获取AppController
     */
    public function getAppController() {
        $obj = self::instance();
        if (!isset($obj->appController)) {
            $cmap = $obj->getControllerMap();
            $obj->appController = new \demo\controller\AppController($cmap);
        }
        
        return $obj->appController;
    } 
    
    // 其它一些列getter和setter
	// ......
}

今回は、forward などのより複雑な呼び出しを実装する必要があるため、呼び出しロジックのニーズを満たすように Request クラスのコードを変更するだけで済みます。

namespace demo\controller;

/**
 * 封装用户请求
 * Request 
 */
class Request {
    private $properties;
	private $feedback = array();
	
	// 保存业务对象,可以供给视图使用
	private $objects = array();
	// 保存上一个已执行的Command对象
	private $lastCommand;

    public function __construct() {
    	$this->init();
    	$this->filterProperties();
    	\demo\base\RequestRegistry::getInstance()->setRequest($this);
    }
    
    public function __clone() {
    	$this->properties = array();
    }
    
    public function init() {
    	if (isset($_SERVER['REQUEST_METHOD'])) {
    		if ($_SERVER['REQUEST_METHOD']) {
    			$this->properties = $_REQUEST;
    			
    			return ;
    		}
    	}
    	
    	// 命令行下的方式
    	foreach ($_SERVER['argv'] as $arg) {
    		if (strpos($arg, '=')) {
    			list($key, $val) = explode('=', $arg);
    			$this->setProperties($key, $val);
    		} 
    	}
    }

    public function filterProperties() {
    	// 过滤用户请求...
    }
    
    public function getProperty($key) {
    	return $this->properties[$key];
    }
    
    public function setProperties($key, $val) {
    	$this->properties[$key] = $val;
    }
    
    public function getFeedback() {
    	return $feedback;
    }
    
    public function addFeedback($msg) {
    	array_push($this->feedback, $msg);
    }
    
    public function getFeedbackString($separator = '\n') {
    	return implode('\n', $this->feedback);
    }
    
    /**
     *
     * @param \demo\command\Command $cmd
     */
    public function setCommand(\demo\command\Command $cmd) {
    	$this->lastCommand = $cmd;
    }
    
    public function getLastCommand() {
    	return $this->lastCommand;
    }
    
    /**
     * 
     * @param unknown_type $name
     * @param unknown_type $object
     */
    public function setObject($name, $object) {
    	$this->objects[$name] = $object;
    }
    
    public function getObject($name) {
    	if (isset($this->objects[$name])) {
    		return $this->objects[$name];
    	}
    	
    	return null;
    }
}

マッピング関係を保存できるControlMapクラス、クラスControllerMapが追加され、要求、コマンド、ApplicationHelper、およびApplicationRegistryは、主に追加され、以前のコードの少量の変更が変更されました。

上記のクラスは、XML 構成 (ApplicationHelper) の読み取りやグローバル変数へのアクセス (Registry) など、システムの初期化を完了できます。 その後に、Controller と AppController という 2 つのクラスのコア部分が続きます。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。