[PHP] Application controller (i)
The front-end controller has been able to centrally process requests and select the appropriate command in one place, but the command subclass object handles the assignment of the view itself. The ability to use a class (based on the status value returned by command processing) to determine the view and return to the front controller, and then the front controller to invoke the view display, so that the front controller is in the middle of the view layer and the business layer, but also good to separate the command and view . The application controller is a good solution.
The application controller is responsible for mapping the request to the command and mapping the command to the view. It allows you to change the process of the application without needing to modify the core code. It frees the command class and lets the command class focus on its work, including handling input, invoking application logic, and processing results.
An application controller is a class (or set of classes) that helps the front-end control take over the task of processing the request and returns the appropriate view to the front-end controller invocation. So how does application control work? It is the way that command and view work is determined through an XML configuration file. For example, the following XML file (a bit like the way struts does):
sqlite://data/demo.db
root
root
main
main
error
list_students
add_student
liststudents
simple_
Add_student
you can see in the XML can contain , three types of child elements, respectively, the command corresponding to the view, command processing service after the state value, command processing after the jump (jump to another CO Mmand).
from the XML structure, you can see that the command class needs some new attribute status.
Namespace demo\command;/** * Abstract parent Class */abstract class Command {//state value mapping private static $STATUS _strings = Array ( ' Cmd_defau LT ' = 0, ' cmd_ok ' = 1, ' cmd_error ' = 2, ' Cmd_insufficient_data ' and ' 3 ';//current status value private $status = 0;public final function __construct () {//subclass cannot override constructor}/** * Returns status value by Status String * @param unknown_type $staStr */public static Fun Ction status ($stauStr = ' Cmd_default ') {if (empty ($stauStr)) {$stauStr = ' cmd_default ';} Return self:: $STATUS _strings[$stauStr];} /** * Call Subclass Implementation of Doexecute * @param \demo\controller\request $request */public function execute (\demo\controller\request $ Request) {$this->doexecute ($request);} protected abstract function Doexecute (\demo\controller\request $request);}
In the system, there is an assistant class Applicationhelper for configuration that can read the XML configuration. Because the structure of the elements in XML is relatively flexible, a controllermap is required to manage the values in each element and the one by one mapping of the command and view.
Namespace Demo\controller;class Controllermap {private $classrootMap = array ();p rivate $forwardMap = Array ();p rivate $ Viewmap = Array ();p ublic 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;}}
You first need to get the getoptions of the configuration Applicationhelper class in the XML.
Namespace demo\controller;/** * Helper class: Get XML Configuration * Singleton mode * */class applicationhelper {private static $instance;p rivate $config = ' Data/config.xml ';p rivate function __construct () {}public static function getinstance () {if (Isset (self:: $instance) = = False) {self:: $instance = new self ();} Return self:: $instance;} Public Function init () {///Initialize configuration gets $DSN = \demo\base\applicationregistry::getinstance ()->getdsn () from the serialization file; $camp = \ Demo\base\applicationregistry::getinstance ()->getcontrollermap (); if (Is_null ($DSN) | | is_null ($CAMP)) {$this- >getoptions ();}} /** * Get XML configuration */public function GetOptions () {//XML $this->ensure (file_exists ($this->config), "Could not fin D options File! "); $options = @simplexml_load_file ($this->config); Var_dump ($options); $this->ensure ($options instanceof \simplexmlelement, ' Could not resolve options file! '); //
$DSN = (string) $options->dsn; $this->ensure ($DSN, ' No DSN found! '); \demo\base\applicationregistry::getinstance ()->setdsn ($DSN); //
$map = new Controllermap (); //
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); } //
foreach ($options->controller->command as $CVF) {$cmd = Trim ((string) $CVF [' name ']); //</command>
if ($cvf->classalias) {$classroot = (string) $cvf->classalias[' name ']; $map->addclassroot ($cmd, $classroot); }//
,
if ($cvf->view) {$view = Trim ((string) $cvf->view); $forward = Trim ((string) $CVF->f Orward); $map->addview ($cmd, 0, $view); if ($forward) {$map->addforward ($cmd, 0, $forward);}}
foreach ($CVF->status as $status) {$stauStr = Trim ((string) $status [' value ']), $view = Trim ((string) $s Tatus->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);}}
The process of getting an XML configuration is a time-consuming operation that serializes a Controllermap object into a file, which can then be retrieved by Applicationregistry and cached as a global data.
/** * Application scope */class Applicationregistry extends Registry {private static $instance; Private $freezedir = "./data"; Hard code here, specific to the actual configuration of the 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;} /** * Get $key data from a serialized file */protected function Get ($key) {$path = $this->freezedir. Directory_separator. $key; if (file_exists ($path)) {//Clear file cache Clearstatcache (); $mtime = Filemtime ($path); if (Isset ($this->mtimes[$key]) = = False) {$this->mtimes[$key]=0; }//file has been modified recently, re-deserialized new data 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\controll Er\controllermap $map) {self::getinstance ()->set (' CMap ', $map); } public Function Getcontrollermap () {if (Isset ($this->values[' cmap ')) {return $this->values[' CMap ']; } return Self::getinstance ()->get (' CMap '); }/** * gets AppController */Public Function Getappcontroller () {$obj = Self::instance (); if (!isset ($obj->appcontroller)) {$cmap = $obj->getcontrollermap (); $obj->appcontroller = new \demo\controller\appcontroller ($CMAP); } return $obj->appcontroller; }//Some other column getter and setter//...}
To make more complex calls this time, such as forward, it is necessary to simply modify the code of the request class so that it conforms to the call logic.
Namespace demo\controller;/** * Package user request * Requesting */class request {private $properties;p rivate $feedback = Array ();// Save the business object, you can supply the view using private $objects = Array ();//Save the last executed command object 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 ']) {$thi S->properties = $_request; return; }}//command-line mode foreach ($_server[' argv ') as $arg) {if (Strpos ($arg, ' = ')) {list ($key, $val) = Explode (' = ', $arg); $this->setproperties ($key, $val); }}} Public function filterproperties () {//filter user request ...} 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); The 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; }}
The class Controllermap, which can save the mapping relationship, has now been added, modifying the request, Command, Applicationhelper, Applicationregistry , the main is to add, a small number of changes before the code.
The above classes have been able to complete the initialization of the system, including reading XML configuration (applicationhelper), global variable access (Registry);
Then there is the core: Controller and AppController two classes.