1<? 2 3require_once dirname(__FILE__) . '/component_manager.php'; 4require_once dirname(__FILE__) . '/action.php'; 5 6define(DOKU_ACTION_ROOT, '/commands'); 7 8class ConflictActionException extends Exception { 9 private $first = ''; 10 private $second = ''; 11 public function first() { return $this->first; } 12 public function second() { return $this->second; } 13 public function __construct($first, $second) { 14 $this->first = $first; 15 $this->second = $second; 16 } 17} 18 19class Doku_Action_Manager extends Doku_Component_Manager { 20 // this holds the renderer of the specific action 21 private $renderer = NULL; 22 // this holds the handler of the specific action 23 private $handler = NULL; 24 // this holds all the loaded renderers 25 private $renderers = array(); 26 // this holds all the loaded handlers 27 private $handlers = array(); 28 // this is the default manager 29 private static $manager = NULL; 30 31 public static function manager() { 32 if (!self::$manager) 33 self::$manager = new Doku_Action_Manager; 34 return self::$manager; 35 } 36 37 // create an object and check if it responds to the correct action 38 private static function create($class, $action) { 39 $handler = new $class; 40 return ($handler->action() != $action) ? NULL : $handler; 41 } 42 43 /** 44 * handles a new class that is loaded in 45 * @param string $class the name of the new class. 46 */ 47 protected function handle($class) { 48 if (is_subclass_of($class, 'Doku_Action')) 49 $this->handlers[] = $class; 50 else if (is_subclass_of($class, 'Doku_Action_Renderer')) 51 $this->renderers[] = $class; 52 } 53 54 // filter the classes and find the handler that 55 // can handle the action, and is not extended 56 private function unique($classes, $action) { 57 $handler = NULL; 58 foreach ($classes as $class) { 59 $new = $this->create($class, $action); 60 if (!$handler) { 61 $handler = $new; 62 continue; 63 } 64 if ($new && $new->action() == $action) { 65 if (is_subclass_of($new, get_class($handler))) 66 $handler = $new; 67 else if (!is_subclass_of($handler, get_class($new))) 68 throw new ConflictActionException($handler, $new); 69 } 70 } 71 return $handler; 72 } 73 74 /** 75 * perform the action 76 * the action name must be plugin_name.action_name. 77 * @global string $ID the page ID 78 * @global array $INFO the page information array 79 * @param string $action the action to be peformed; 80 * @return bool whether the action has been performed (regardless of being successful). 81 */ 82 public function act(&$action) { 83 // some times the action is an array 84 if (is_array($action)) 85 list($action) = array_keys($action); 86 87 $this->handler = NULL; 88 $this->renderer = NULL; 89 $this->handlers = array(); 90 $this->renderers = array(); 91 92 $components = explode('.', $action); 93 if (count($components) <= 1) return FALSE; 94 $plugin = array_shift($components); 95 $action = implode('.', $components); 96 $path = DOKU_PLUGIN . $plugin . DOKU_ACTION_ROOT; 97 $this->load($path, $action); 98 99 $this->handler = $this->unique($this->handlers, $action); 100 $this->renderer = $this->unique($this->renderers, $action); 101 102 // check if the action is disabled 103 if (!actionOK($action)) { 104 msg('action disabled: ' . htmlspecialchars($action), -1); 105 $action = 'show'; 106 return self::act($action); 107 } 108 109 // check if we can handle the action 110 if (!$this->handler) return FALSE; 111 112 global $INFO; 113 // check permission 114 if ($this->handler->permission_required() > $INFO['perm']) { 115 $action = 'denied'; 116 return $this->act($action); 117 } 118 119 // handle the action 120 $new_action = $this->handler->handle(); 121 // handle the next action 122 if ($new_action && $new_action !== $action) { 123 $action = $new_action; 124 return $this->act($action); 125 } 126 127 return TRUE; 128 } 129 130 /** 131 * Doku_Action public interface to render the result of an action 132 * 133 * @param type $action the action to display 134 * @return boolean whether the results has been successfully displayed 135 */ 136 public function render($action) { 137 if (!$this->renderer) return FALSE; 138 if (is_array($action)) { 139 $result = ''; 140 foreach ($action as $act => $x) 141 $result .= $this->render($act); 142 return $result; 143 } 144 145 ob_start(); 146 $this->renderer->xhtml(); 147 $html_output = ob_get_clean(); 148 149 trigger_event('TPL_CONTENT_DISPLAY', $html_output, 'ptln'); 150 return !empty($html_output); 151 } 152}