1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
18:
19: 20: 21: 22: 23:
24: class ShellDispatcher {
25:
26: 27: 28: 29: 30:
31: public $params = array();
32:
33: 34: 35: 36: 37:
38: public $args = array();
39:
40: 41: 42: 43: 44: 45: 46: 47: 48:
49: public function __construct($args = array(), $bootstrap = true) {
50: set_time_limit(0);
51:
52: if ($bootstrap) {
53: $this->_initConstants();
54: }
55: $this->parseParams($args);
56: if ($bootstrap) {
57: $this->_initEnvironment();
58: }
59: }
60:
61: 62: 63: 64: 65: 66:
67: public static function run($argv) {
68: $dispatcher = new ShellDispatcher($argv);
69: $dispatcher->_stop($dispatcher->dispatch() === false ? 1 : 0);
70: }
71:
72: 73: 74: 75: 76:
77: protected function _initConstants() {
78: if (function_exists('ini_set')) {
79: ini_set('html_errors', false);
80: ini_set('implicit_flush', true);
81: ini_set('max_execution_time', 0);
82: }
83:
84: if (!defined('CAKE_CORE_INCLUDE_PATH')) {
85: define('DS', DIRECTORY_SEPARATOR);
86: define('CAKE_CORE_INCLUDE_PATH', dirname(dirname(dirname(__FILE__))));
87: define('CAKEPHP_SHELL', true);
88: if (!defined('CORE_PATH')) {
89: define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS);
90: }
91: }
92: }
93:
94: 95: 96: 97: 98: 99:
100: protected function _initEnvironment() {
101: if (!$this->_bootstrap()) {
102: $message = "Unable to load CakePHP core.\nMake sure " . DS . 'lib' . DS . 'Cake exists in ' . CAKE_CORE_INCLUDE_PATH;
103: throw new CakeException($message);
104: }
105:
106: if (!isset($this->args[0]) || !isset($this->params['working'])) {
107: $message = "This file has been loaded incorrectly and cannot continue.\n" .
108: "Please make sure that " . DS . 'lib' . DS . 'Cake' . DS . "Console is in your system path,\n" .
109: "and check the cookbook for the correct usage of this command.\n" .
110: "(http://book.cakephp.org/)";
111: throw new CakeException($message);
112: }
113:
114: $this->shiftArgs();
115: }
116:
117: 118: 119: 120: 121:
122: protected function _bootstrap() {
123: define('ROOT', $this->params['root']);
124: define('APP_DIR', $this->params['app']);
125: define('APP', $this->params['working'] . DS);
126: define('WWW_ROOT', APP . $this->params['webroot'] . DS);
127: if (!is_dir(ROOT . DS . APP_DIR . DS . 'tmp')) {
128: define('TMP', CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'Console' . DS . 'Templates' . DS . 'skel' . DS . 'tmp' . DS);
129: }
130: $boot = file_exists(ROOT . DS . APP_DIR . DS . 'Config' . DS . 'bootstrap.php');
131: require CORE_PATH . 'Cake' . DS . 'bootstrap.php';
132:
133: if (!file_exists(APP . 'Config' . DS . 'core.php')) {
134: include_once CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'Console' . DS . 'Templates' . DS . 'skel' . DS . 'Config' . DS . 'core.php';
135: App::build();
136: }
137: require_once CAKE . 'Console' . DS . 'ConsoleErrorHandler.php';
138: $ErrorHandler = new ConsoleErrorHandler();
139: set_exception_handler(array($ErrorHandler, 'handleException'));
140: set_error_handler(array($ErrorHandler, 'handleError'), Configure::read('Error.level'));
141:
142: if (!defined('FULL_BASE_URL')) {
143: define('FULL_BASE_URL', 'http://localhost');
144: }
145:
146: return true;
147: }
148:
149: 150: 151: 152: 153: 154:
155: public function dispatch() {
156: $shell = $this->shiftArgs();
157:
158: if (!$shell) {
159: $this->help();
160: return false;
161: }
162: if (in_array($shell, array('help', '--help', '-h'))) {
163: $this->help();
164: return true;
165: }
166:
167: $Shell = $this->_getShell($shell);
168:
169: $command = null;
170: if (isset($this->args[0])) {
171: $command = $this->args[0];
172: }
173:
174: if ($Shell instanceof Shell) {
175: $Shell->initialize();
176: $Shell->loadTasks();
177: return $Shell->runCommand($command, $this->args);
178: }
179: $methods = array_diff(get_class_methods($Shell), get_class_methods('Shell'));
180: $added = in_array($command, $methods);
181: $private = $command[0] == '_' && method_exists($Shell, $command);
182:
183: if (!$private) {
184: if ($added) {
185: $this->shiftArgs();
186: $Shell->startup();
187: return $Shell->{$command}();
188: }
189: if (method_exists($Shell, 'main')) {
190: $Shell->startup();
191: return $Shell->main();
192: }
193: }
194: throw new MissingShellMethodException(array('shell' => $shell, 'method' => $arg));
195: }
196:
197: 198: 199: 200: 201: 202: 203: 204: 205:
206: protected function _getShell($shell) {
207: list($plugin, $shell) = pluginSplit($shell, true);
208:
209: $plugin = Inflector::camelize($plugin);
210: $class = Inflector::camelize($shell) . 'Shell';
211:
212: App::uses('Shell', 'Console');
213: App::uses('AppShell', 'Console/Command');
214: App::uses($class, $plugin . 'Console/Command');
215:
216: if (!class_exists($class)) {
217: throw new MissingShellException(array(
218: 'class' => $class
219: ));
220: }
221: $Shell = new $class();
222: $Shell->plugin = trim($plugin, '.');
223: return $Shell;
224: }
225:
226: 227: 228: 229: 230: 231:
232: public function parseParams($args) {
233: $this->_parsePaths($args);
234:
235: $defaults = array(
236: 'app' => 'app',
237: 'root' => dirname(dirname(dirname(dirname(__FILE__)))),
238: 'working' => null,
239: 'webroot' => 'webroot'
240: );
241: $params = array_merge($defaults, array_intersect_key($this->params, $defaults));
242: $isWin = false;
243: foreach ($defaults as $default => $value) {
244: if (strpos($params[$default], '\\') !== false) {
245: $isWin = true;
246: break;
247: }
248: }
249: $params = str_replace('\\', '/', $params);
250:
251: if (isset($params['working'])) {
252: $params['working'] = trim($params['working']);
253: }
254: if (!empty($params['working']) && (!isset($this->args[0]) || isset($this->args[0]) && $this->args[0]{0} !== '.')) {
255: if (empty($this->params['app']) && $params['working'] != $params['root']) {
256: $params['root'] = dirname($params['working']);
257: $params['app'] = basename($params['working']);
258: } else {
259: $params['root'] = $params['working'];
260: }
261: }
262:
263: if ($params['app'][0] == '/' || preg_match('/([a-z])(:)/i', $params['app'], $matches)) {
264: $params['root'] = dirname($params['app']);
265: } elseif (strpos($params['app'], '/')) {
266: $params['root'] .= '/' . dirname($params['app']);
267: }
268:
269: $params['app'] = basename($params['app']);
270: $params['working'] = rtrim($params['root'], '/');
271: if (!$isWin || !preg_match('/^[A-Z]:$/i', $params['app'])) {
272: $params['working'] .= '/' . $params['app'];
273: }
274:
275: if (!empty($matches[0]) || !empty($isWin)) {
276: $params = str_replace('/', '\\', $params);
277: }
278:
279: $this->params = array_merge($this->params, $params);
280: }
281:
282: 283: 284: 285: 286: 287:
288: protected function _parsePaths($args) {
289: $parsed = array();
290: $keys = array('-working', '--working', '-app', '--app', '-root', '--root');
291: foreach ($keys as $key) {
292: while (($index = array_search($key, $args)) !== false) {
293: $keyname = str_replace('-', '', $key);
294: $valueIndex = $index + 1;
295: $parsed[$keyname] = $args[$valueIndex];
296: array_splice($args, $index, 2);
297: }
298: }
299: $this->args = $args;
300: $this->params = $parsed;
301: }
302:
303: 304: 305: 306: 307:
308: public function shiftArgs() {
309: return array_shift($this->args);
310: }
311:
312: 313: 314: 315: 316:
317: public function help() {
318: $this->args = array_merge(array('command_list'), $this->args);
319: $this->dispatch();
320: }
321:
322: 323: 324: 325: 326: 327:
328: protected function _stop($status = 0) {
329: exit($status);
330: }
331:
332: }
333: