[Php] application controller (1)

Source: Internet
Author: User
[Php] application controller (1) & nbsp; the front-end controller can process requests in one place and select the appropriate Command, however, the Command subclass object handles the assignment of views by itself. If you can use a class (status returned after processing by Command & #20540 [php] application controller (1)

The front-end controller can process requests in a centralized manner and select an appropriate Command. However, the sub-object of the Command class handles the assignment of views by itself. If you can use a class (the status value returned after Command processing) to determine the view and return it to the front-end controller, then the front-end controller calls the view display, in this way, the front-end controller is in the middle of the view layer and the business layer, and the Command and view are well separated. Application controller is a good solution.

The application controller maps requests to commands and maps commands to views. It allows you to change the application process without modifying the core code. It frees the Command class and enables the Command class to focus on its work, including processing input, calling application logic, and processing results.

An application controller is a class (or a group of classes) that helps the front-end control take over the request processing tasks and return the appropriate view to the front-end controller for calling. So how does application control run? It uses an xml configuration file to determine how Command and view work. For example, the following xml file (a bit like struts ):

 
 
  
   sqlite://data/demo.db
  
  
   root
  
  
   root
  
  
   
    main
   
   
    main
   
   
    error
   
   
   
    list_students
   
   
   
    add_student
   
   
    
     ListStudents
    
   
   
   
   
    simple_add_student
   
  
 
We can see the xml Can contain , , The three sub-elements represent the view corresponding to the Command, the status value after the Command processes the service, and the jump after the Command process (jump to another Command here ).


From the xml structure, we can see that the Command class requires some new attributes.

Namespace demo \ command;/*** abstract parent class */abstract class Command {// state value ing private static $ STATUS_STRINGS = array ('cmd _ default' => 0, 'command _ OK '=> 1, 'command _ error' => 2, 'command _ INSUFFICIENT_DATA' => 3); // The current status value is private $ status = 0; public final function _ construct () {// The subclass cannot override the constructor}/*** returns the status value by status string * @ param unknown_type $ staStr */public static function status ($ stauStr = 'cmd _ default') {if (empty ($ stauStr) {$ stauStr = 'cmd _ Default';} return self: $ STATUS_STRINGS [$ stauStr];} /*** call doExecute implemented by subclass * @ 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, ApplicationHelper, a helper class for configuration retrieval, can read the xml configuration. Because the element structure in xml is relatively flexible, a ControllerMap is required to manage the one-to-one ing between values and commands and views of each element.

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;}}

First, you must obtain the getOptions for configuring the ApplicationHelper class in xml.

Namespace demo \ controller;/*** helper class: get xml configuration * Singleton mode **/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 () {// Get the initialization configuration from the serialization file $ dsn =\demo \ base \ ApplicationRegistry: getInstance ()-> ge TDSN (); $ 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), "cocould not find 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']); //
       
        
If ($ cvf-> classalias) {$ classroot = (string) $ cvf-> classalias ['name']; $ map-> addClassroot ($ cmd, $ classroot );} //
        
         
,
         
           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 );}}//
          
            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 );}}}
          
         
        
       
      
     
    

Obtaining xml configuration is a time-consuming operation. you can first serialize the ControllerMap object to a file, and then obtain it through ApplicationRegistry and cache it as global data.

/*** Application scope */class ApplicationRegistry extends Registry {private static $ instance; private $ freezedir = ". /data "; // hard encoding here. configure private $ values = array (); private $ mtimes = array (); private function _ construct () according to the actual situation () {} public static function getInstance () {if (isset (self: $ instance) = false) {self: $ instance = new self ();} return self :: $ instance;}/*** get $ key data from the serialized file */protected fun Ction get ($ key) {$ path = $ this-> freezedir. DIRECTORY_SEPARATOR. $ key; if (file_exists ($ path) {// clear the file cache clearstatcache (); $ mtime = filemtime ($ path ); if (isset ($ this-> mtimes [$ key]) = false) {$ this-> mtimes [$ key] = 0;} // The file has been recently modified, re-deserialize 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 \ 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');}/*** get AppController */public function getAppController () {$ obj = self: instance (); if (! Isset ($ obj-> appController) {$ cmap = $ obj-> getControllerMap (); $ obj-> appController = new \ demo \ controller \ AppController ($ cmap );} return $ obj-> appController;} // Other columns: getter and setter //......}

This time we need to implement more complex calls, such as forward, so we need to simply modify the Request class code so that it can meet the call logic needs.

Namespace demo \ controller;/*** encapsulate user requests * Request */class Request {private $ properties; private $ feedback = array (); // save the business object, you can supply the view with 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']) {$ this-> properties =$ _ REQUEST; return ;}// method foreach ($ _ SERVER ['argv'] as $ arg) in the command line) {if (strpos ($ arg, '=') {list ($ key, $ val) = explode ('=', $ arg ); $ this-> setProperties ($ key, $ val) ;}} public function filterProperties () {// filter user requests ...} 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 ;}}

Now you have added the ControllerMap class that can save the ing relationship, modified the Request, Command, ApplicationHelper, ApplicationRegistry, mainly to add, a few changes to the previous code.

The above classes have been able to complete system initialization, including reading the xml configuration (ApplicationHelper) and accessing global variables (Registry );

Then there is the core part: Controller and AppController.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.