PageRenderTime 43ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/lithium-0.6/libraries/lithium/console/Dispatcher.php

https://github.com/ochoto/framework-benchs
PHP | 193 lines | 125 code | 12 blank | 56 comment | 4 complexity | 2aedd8d3180b7ff70370bc3d5ca73c4b MD5 | raw file
  1. <?php
  2. /**
  3. * Lithium: the most rad php framework
  4. *
  5. * @copyright Copyright 2010, Union of RAD (http://union-of-rad.org)
  6. * @license http://opensource.org/licenses/bsd-license.php The BSD License
  7. */
  8. namespace lithium\console;
  9. use \UnexpectedValueException;
  10. use \lithium\core\Libraries;
  11. use \lithium\util\String;
  12. use \lithium\util\Inflector;
  13. class Dispatcher extends \lithium\core\StaticObject {
  14. /**
  15. * Fully-namespaced router class reference. Class must implement a `parse()` method,
  16. * which must return an array with (at a minimum) 'command' and 'action' keys.
  17. *
  18. * @see lithium\console\Router::parse()
  19. * @var array
  20. */
  21. protected static $_classes = array(
  22. 'request' => '\lithium\console\Request',
  23. 'router' => '\lithium\console\Router'
  24. );
  25. /**
  26. * Contains pre-process format strings for changing Dispatcher's behavior based on 'rules'.
  27. * Each key in the array represents a 'rule'; if a key that matches the rule is present (and
  28. * not empty) in a route, (i.e. the result of `lithium\console\Router::parse()`) then the rule's
  29. * value will be applied to the route before it is dispatched. When applying a rule, any array
  30. * elements array elements of the flag which are present in the route will be modified using a
  31. * `lithium\util\String::insert()`-formatted string.
  32. *
  33. * For example, to implement action prefixes (i.e. `admin_index()`), set a rule named 'admin',
  34. * with a value array containing a modifier key for the `action` element of a route, i.e.:
  35. * `array('action' => 'admin_{:action}')`. See `lithium\console\Dispatcher::config()` for
  36. * examples on setting rules.
  37. *
  38. * @see lithium\console\Dispatcher::config()
  39. * @see lithium\util\String::insert()
  40. */
  41. protected static $_rules = array(
  42. //'plugin' => array('command' => '{:plugin}.{:command}')
  43. );
  44. /**
  45. * Used to set configuration parameters for the Dispatcher.
  46. *
  47. * @param array $config
  48. * @return array|void If no parameters are passed, returns an associative array with the
  49. * current configuration, otherwise returns null.
  50. */
  51. public static function config($config = array()) {
  52. if (empty($config)) {
  53. return array('rules' => static::$_rules);
  54. }
  55. foreach ($config as $key => $val) {
  56. if (isset(static::${'_' . $key})) {
  57. static::${'_' . $key} = $val + static::${'_' . $key};
  58. }
  59. }
  60. }
  61. /**
  62. * Dispatches a request based on a request object (an instance of `lithium\console\Request`).
  63. * If `$request` is `null`, a new request object is instantiated based on the value of the
  64. * `'request'` key in the `$_classes` array.
  65. *
  66. * @param object $request An instance of a request object with HTTP request information. If
  67. * `null`, an instance will be created.
  68. * @param array $options
  69. * @return object The command action result which is an instance of `lithium\console\Response`.
  70. * @todo Add exception-handling/error page rendering
  71. */
  72. public static function run($request = null, $options = array()) {
  73. $defaults = array('request' => array());
  74. $options += $defaults;
  75. $classes = static::$_classes;
  76. $params = compact('request', 'options');
  77. $method = __FUNCTION__;
  78. return static::_filter($method, $params, function($self, $params, $chain) use ($classes) {
  79. extract($params);
  80. $router = $classes['router'];
  81. $request = $request ?: new $classes['request']($options['request']);
  82. $request->params = $router::parse($request);
  83. $params = $self::invokeMethod('_applyRules', array($request->params));
  84. try {
  85. $callable = $self::invokeMethod('_callable', array($request, $params, $options));
  86. return $self::invokeMethod('_call', array($callable, $request, $params));
  87. } catch (UnexpectedValueException $e) {
  88. return (object) array('status' => $e->getMessage() . "\n");
  89. }
  90. });
  91. }
  92. /**
  93. * Determines Command to use for current request. If
  94. *
  95. * @param string $request
  96. * @param string $params
  97. * @param string $options
  98. * @return class \lithium\console\COmmand
  99. */
  100. protected static function _callable($request, $params, $options) {
  101. $params = compact('request', 'params', 'options');
  102. return static::_filter(__FUNCTION__, $params, function($self, $params, $chain) {
  103. extract($params, EXTR_OVERWRITE);
  104. $name = $class = $params['command'];
  105. if (!$name) {
  106. $request->params['args'][0] = $name;
  107. $name = $class = '\lithium\console\command\Help';
  108. }
  109. if ($class[0] !== '\\') {
  110. $name = Inflector::camelize($class);
  111. $class = Libraries::locate('command', $name);
  112. }
  113. if (class_exists($class)) {
  114. return new $class(compact('request'));
  115. }
  116. throw new UnexpectedValueException("Command `{$name}` not found");
  117. });
  118. }
  119. /**
  120. * Call class method
  121. *
  122. * @param string $callable
  123. * @param string $request
  124. * @param string $params
  125. * @return void
  126. */
  127. protected static function _call($callable, $request, $params) {
  128. $params = compact('callable', 'request', 'params');
  129. return static::_filter(__FUNCTION__, $params, function($self, $params, $chain) {
  130. if (is_callable($callable = $params['callable'])) {
  131. $request = $params['request'];
  132. if (!method_exists($callable, $request->params['action'])) {
  133. array_unshift($request->params['args'], $request->params['action']);
  134. $request->params['action'] = 'run';
  135. }
  136. $isHelp = (
  137. !empty($request->params['help']) || !empty($request->params['h'])
  138. || !method_exists($callable, $request->params['action'])
  139. );
  140. if ($isHelp) {
  141. $request->params['action'] = '_help';
  142. }
  143. return $callable($request->params['action'], $request->params['args']);
  144. }
  145. throw new UnexpectedValueException("{$callable} not callable");
  146. });
  147. }
  148. /**
  149. * Attempts to apply a set of formatting rules from `$_rules` to a `$params` array, where each
  150. * formatting rule is applied if the key of the rule in `$_rules` is present and not empty in
  151. * `$params`. Also performs sanity checking against `$params` to ensure that no value
  152. * matching a rule is present unless the rule check passes.
  153. *
  154. * @param array $params An array of route parameters to which rules will be applied.
  155. * @return array Returns the $params array with formatting rules applied to array values.
  156. */
  157. protected static function _applyRules($params) {
  158. foreach (static::$_rules as $rule => $value) {
  159. foreach ($value as $k => $v) {
  160. if (!empty($params[$rule])) {
  161. $params[$k] = String::insert($v, $params);
  162. }
  163. $match = preg_replace('/\{:\w+\}/', '@', $v);
  164. $match = preg_replace('/@/', '.+', preg_quote($match, '/'));
  165. if (preg_match('/' . $match . '/i', $params[$k])) {
  166. return false;
  167. }
  168. }
  169. }
  170. return $params;
  171. }
  172. }
  173. ?>