Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
16591 anikendra 1
<?php
2
/**
3
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
4
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
5
 *
6
 * Licensed under The MIT License
7
 * For full copyright and license information, please see the LICENSE.txt
8
 * Redistributions of files must retain the above copyright notice.
9
 *
10
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
11
 * @link          http://cakephp.org CakePHP(tm) Project
12
 * @since         CakePHP(tm) v 1.2.0.5012
13
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
14
 */
15
 
16
App::uses('AppShell', 'Console/Command');
17
 
18
/**
19
 * Provides a very basic 'interactive' console for CakePHP apps.
20
 *
21
 * @package       Cake.Console.Command
22
 * @deprecated 3.0.0 Deprecated since version 2.4, will be removed in 3.0
23
 */
24
class ConsoleShell extends AppShell {
25
 
26
/**
27
 * Available binding types
28
 *
29
 * @var array
30
 */
31
	public $associations = array('hasOne', 'hasMany', 'belongsTo', 'hasAndBelongsToMany');
32
 
33
/**
34
 * Chars that describe invalid commands
35
 *
36
 * @var array
37
 */
38
	public $badCommandChars = array('$', ';');
39
 
40
/**
41
 * Available models
42
 *
43
 * @var array
44
 */
45
	public $models = array();
46
 
47
/**
48
 * _finished
49
 *
50
 * This shell is perpetual, setting this property to true exits the process
51
 *
52
 * @var mixed
53
 */
54
	protected $_finished = false;
55
 
56
/**
57
 * _methodPatterns
58
 *
59
 * @var array
60
 */
61
	protected $_methodPatterns = array(
62
		'help' => '/^(help|\?)/',
63
		'_exit' => '/^(quit|exit)/',
64
		'_models' => '/^models/i',
65
		'_bind' => '/^(\w+) bind (\w+) (\w+)/',
66
		'_unbind' => '/^(\w+) unbind (\w+) (\w+)/',
67
		'_find' => '/.+->find/',
68
		'_save' => '/.+->save/',
69
		'_columns' => '/^(\w+) columns/',
70
		'_routesReload' => '/^routes\s+reload/i',
71
		'_routesShow' => '/^routes\s+show/i',
72
		'_routeToString' => '/^route\s+(\(.*\))$/i',
73
		'_routeToArray' => '/^route\s+(.*)$/i',
74
	);
75
 
76
/**
77
 * Override startup of the Shell
78
 *
79
 * @return void
80
 */
81
	public function startup() {
82
		App::uses('Dispatcher', 'Routing');
83
		$this->Dispatcher = new Dispatcher();
84
		$this->models = App::objects('Model');
85
 
86
		foreach ($this->models as $model) {
87
			$class = $model;
88
			App::uses($class, 'Model');
89
			$this->{$class} = new $class();
90
		}
91
		$this->out(__d('cake_console', 'Model classes:'));
92
		$this->hr();
93
 
94
		foreach ($this->models as $model) {
95
			$this->out(" - {$model}");
96
		}
97
 
98
		if (!$this->_loadRoutes()) {
99
			$message = __d(
100
				'cake_console',
101
				'There was an error loading the routes config. Please check that the file exists and contains no errors.'
102
			);
103
			$this->err($message);
104
		}
105
	}
106
 
107
/**
108
 * Gets the option parser instance and configures it.
109
 *
110
 * @return ConsoleOptionParser
111
 */
112
	public function getOptionParser() {
113
		$parser = parent::getOptionParser();
114
 
115
		$parser->description(array(
116
			'The interactive console is a tool for testing parts of your',
117
			'app before you write code.',
118
			'',
119
			'See below for a list of supported commands.'
120
		))->epilog(array(
121
			'<info>Model testing</info>',
122
			'',
123
			'To test model results, use the name of your model without a leading $',
124
			'e.g. Foo->find("all")',
125
			"",
126
			'To dynamically set associations, you can do the following:',
127
			'',
128
			"\tModelA bind <association> ModelB",
129
			'',
130
			"where the supported associations are hasOne, hasMany, belongsTo, hasAndBelongsToMany",
131
			"",
132
			'To dynamically remove associations, you can do the following:',
133
			'',
134
			"\t ModelA unbind <association> ModelB",
135
			'',
136
			"where the supported associations are the same as above",
137
			"",
138
			"To save a new field in a model, you can do the following:",
139
			'',
140
			"\tModelA->save(array('foo' => 'bar', 'baz' => 0))",
141
			'',
142
			"where you are passing a hash of data to be saved in the format",
143
			"of field => value pairs",
144
			"",
145
			"To get column information for a model, use the following:",
146
			'',
147
			"\tModelA columns",
148
			'',
149
			"which returns a list of columns and their type",
150
			"",
151
			'<info>Route testing</info>',
152
			"",
153
			'To test URLs against your app\'s route configuration, type:',
154
			"",
155
			"\tRoute <url>",
156
			"",
157
			"where url is the path to your your action plus any query parameters,",
158
			"minus the application's base path. For example:",
159
			"",
160
			"\tRoute /posts/view/1",
161
			"",
162
			"will return something like the following:",
163
			"",
164
			"\tarray(",
165
			"\t  [...]",
166
			"\t  'controller' => 'posts',",
167
			"\t  'action' => 'view',",
168
			"\t  [...]",
169
			"\t)",
170
			"",
171
			'Alternatively, you can use simple array syntax to test reverse',
172
			'To reload your routes config (Config/routes.php), do the following:',
173
			"",
174
			"\tRoutes reload",
175
			"",
176
			'To show all connected routes, do the following:',
177
			'',
178
			"\tRoutes show",
179
		));
180
 
181
		return $parser;
182
	}
183
/**
184
 * Prints the help message
185
 *
186
 * @return void
187
 */
188
	public function help() {
189
		$optionParser = $this->getOptionParser();
190
		$this->out($optionParser->epilog());
191
	}
192
 
193
/**
194
 * Override main() to handle action
195
 *
196
 * @param string $command The command to run.
197
 * @return void
198
 */
199
	public function main($command = null) {
200
		$this->_finished = false;
201
		while (!$this->_finished) {
202
			if (empty($command)) {
203
				$command = trim($this->in(''));
204
			}
205
 
206
			$method = $this->_method($command);
207
 
208
			if ($method) {
209
				$this->$method($command);
210
			} else {
211
				$this->out(__d('cake_console', "Invalid command"));
212
				$this->out();
213
			}
214
			$command = '';
215
		}
216
	}
217
 
218
/**
219
 * Determine the method to process the current command
220
 *
221
 * @param string $command The command to run.
222
 * @return string or false
223
 */
224
	protected function _method($command) {
225
		foreach ($this->_methodPatterns as $method => $pattern) {
226
			if (preg_match($pattern, $command)) {
227
				return $method;
228
			}
229
		}
230
 
231
		return false;
232
	}
233
 
234
/**
235
 * Set the finiished property so that the loop in main method ends
236
 *
237
 * @return void
238
 */
239
	protected function _exit() {
240
		$this->_finished = true;
241
	}
242
 
243
/**
244
 * List all models
245
 *
246
 * @return void
247
 */
248
	protected function _models() {
249
		$this->out(__d('cake_console', 'Model classes:'));
250
		$this->hr();
251
		foreach ($this->models as $model) {
252
			$this->out(" - {$model}");
253
		}
254
	}
255
 
256
/**
257
 * Bind an association
258
 *
259
 * @param mixed $command The command to run.
260
 * @return void
261
 */
262
	protected function _bind($command) {
263
		preg_match($this->_methodPatterns[__FUNCTION__], $command, $tmp);
264
 
265
		foreach ($tmp as $data) {
266
			$data = strip_tags($data);
267
			$data = str_replace($this->badCommandChars, "", $data);
268
		}
269
 
270
		$modelA = $tmp[1];
271
		$association = $tmp[2];
272
		$modelB = $tmp[3];
273
 
274
		if ($this->_isValidModel($modelA) && $this->_isValidModel($modelB) && in_array($association, $this->associations)) {
275
			$this->{$modelA}->bindModel(array($association => array($modelB => array('className' => $modelB))), false);
276
			$this->out(__d('cake_console', "Created %s association between %s and %s",
277
				$association, $modelA, $modelB));
278
		} else {
279
			$this->out(__d('cake_console', "Please verify you are using valid models and association types"));
280
		}
281
	}
282
 
283
/**
284
 * Unbind an association
285
 *
286
 * @param mixed $command The command to run.
287
 * @return void
288
 */
289
	protected function _unbind($command) {
290
		preg_match($this->_methodPatterns[__FUNCTION__], $command, $tmp);
291
 
292
		foreach ($tmp as $data) {
293
			$data = strip_tags($data);
294
			$data = str_replace($this->badCommandChars, "", $data);
295
		}
296
 
297
		$modelA = $tmp[1];
298
		$association = $tmp[2];
299
		$modelB = $tmp[3];
300
 
301
		// Verify that there is actually an association to unbind
302
		$currentAssociations = $this->{$modelA}->getAssociated();
303
		$validCurrentAssociation = false;
304
 
305
		foreach ($currentAssociations as $model => $currentAssociation) {
306
			if ($model === $modelB && $association === $currentAssociation) {
307
				$validCurrentAssociation = true;
308
			}
309
		}
310
 
311
		if ($this->_isValidModel($modelA) && $this->_isValidModel($modelB) && in_array($association, $this->associations) && $validCurrentAssociation) {
312
			$this->{$modelA}->unbindModel(array($association => array($modelB)));
313
			$this->out(__d('cake_console', "Removed %s association between %s and %s",
314
				$association, $modelA, $modelB));
315
		} else {
316
			$this->out(__d('cake_console', "Please verify you are using valid models, valid current association, and valid association types"));
317
		}
318
	}
319
 
320
/**
321
 * Perform a find
322
 *
323
 * @param mixed $command The command to run.
324
 * @return void
325
 */
326
	protected function _find($command) {
327
		$command = strip_tags($command);
328
		$command = str_replace($this->badCommandChars, "", $command);
329
 
330
		// Do we have a valid model?
331
		list($modelToCheck) = explode('->', $command);
332
 
333
		if ($this->_isValidModel($modelToCheck)) {
334
			$findCommand = "\$data = \$this->$command;";
335
			//@codingStandardsIgnoreStart
336
			@eval($findCommand);
337
			//@codingStandardsIgnoreEnd
338
 
339
			if (is_array($data)) {
340
				foreach ($data as $idx => $results) {
341
					if (is_numeric($idx)) { // findAll() output
342
						foreach ($results as $modelName => $result) {
343
							$this->out("$modelName");
344
 
345
							foreach ($result as $field => $value) {
346
								if (is_array($value)) {
347
									foreach ($value as $field2 => $value2) {
348
										$this->out("\t$field2: $value2");
349
									}
350
 
351
									$this->out();
352
								} else {
353
									$this->out("\t$field: $value");
354
								}
355
							}
356
						}
357
					} else { // find() output
358
						$this->out($idx);
359
 
360
						foreach ($results as $field => $value) {
361
							if (is_array($value)) {
362
								foreach ($value as $field2 => $value2) {
363
									$this->out("\t$field2: $value2");
364
								}
365
 
366
								$this->out();
367
							} else {
368
								$this->out("\t$field: $value");
369
							}
370
						}
371
					}
372
				}
373
			} else {
374
				$this->out();
375
				$this->out(__d('cake_console', "No result set found"));
376
			}
377
		} else {
378
			$this->out(__d('cake_console', "%s is not a valid model", $modelToCheck));
379
		}
380
	}
381
 
382
/**
383
 * Save a record
384
 *
385
 * @param mixed $command The command to run.
386
 * @return void
387
 */
388
	protected function _save($command) {
389
		// Validate the model we're trying to save here
390
		$command = strip_tags($command);
391
		$command = str_replace($this->badCommandChars, "", $command);
392
		list($modelToSave) = explode("->", $command);
393
 
394
		if ($this->_isValidModel($modelToSave)) {
395
			// Extract the array of data we are trying to build
396
			list(, $data) = explode("->save", $command);
397
			$data = preg_replace('/^\(*(array)?\(*(.+?)\)*$/i', '\\2', $data);
398
			$saveCommand = "\$this->{$modelToSave}->save(array('{$modelToSave}' => array({$data})));";
399
			//@codingStandardsIgnoreStart
400
			@eval($saveCommand);
401
			//@codingStandardsIgnoreEnd
402
			$this->out(__d('cake_console', 'Saved record for %s', $modelToSave));
403
		}
404
	}
405
 
406
/**
407
 * Show the columns for a model
408
 *
409
 * @param mixed $command The command to run.
410
 * @return void
411
 */
412
	protected function _columns($command) {
413
		preg_match($this->_methodPatterns[__FUNCTION__], $command, $tmp);
414
 
415
		$modelToCheck = strip_tags(str_replace($this->badCommandChars, "", $tmp[1]));
416
 
417
		if ($this->_isValidModel($modelToCheck)) {
418
			// Get the column info for this model
419
			$fieldsCommand = "\$data = \$this->{$modelToCheck}->getColumnTypes();";
420
			//@codingStandardsIgnoreStart
421
			@eval($fieldsCommand);
422
			//@codingStandardsIgnoreEnd
423
 
424
			if (is_array($data)) {
425
				foreach ($data as $field => $type) {
426
					$this->out("\t{$field}: {$type}");
427
				}
428
			}
429
		} else {
430
			$this->out(__d('cake_console', "Please verify that you selected a valid model"));
431
		}
432
	}
433
 
434
/**
435
 * Reload route definitions
436
 *
437
 * @return void
438
 */
439
	protected function _routesReload() {
440
		if (!$this->_loadRoutes()) {
441
			return $this->err(__d('cake_console', "There was an error loading the routes config. Please check that the file exists and is free of parse errors."));
442
		}
443
		$this->out(__d('cake_console', "Routes configuration reloaded, %d routes connected", count(Router::$routes)));
444
	}
445
 
446
/**
447
 * Show all routes
448
 *
449
 * @return void
450
 */
451
	protected function _routesShow() {
452
		$this->out(print_r(Hash::combine(Router::$routes, '{n}.template', '{n}.defaults'), true));
453
	}
454
 
455
/**
456
 * Parse an array URL and show the equivalent URL as a string
457
 *
458
 * @param mixed $command The command to run.
459
 * @return void
460
 */
461
	protected function _routeToString($command) {
462
		preg_match($this->_methodPatterns[__FUNCTION__], $command, $tmp);
463
 
464
		//@codingStandardsIgnoreStart
465
		if ($url = eval('return array' . $tmp[1] . ';')) {
466
			//@codingStandardsIgnoreEnd
467
			$this->out(Router::url($url));
468
		}
469
	}
470
 
471
/**
472
 * Parse a string URL and show as an array
473
 *
474
 * @param mixed $command The command to run.
475
 * @return void
476
 */
477
	protected function _routeToArray($command) {
478
		preg_match($this->_methodPatterns[__FUNCTION__], $command, $tmp);
479
 
480
		$this->out(var_export(Router::parse($tmp[1]), true));
481
	}
482
 
483
/**
484
 * Tells if the specified model is included in the list of available models
485
 *
486
 * @param string $modelToCheck The model to check.
487
 * @return bool true if is an available model, false otherwise
488
 */
489
	protected function _isValidModel($modelToCheck) {
490
		return in_array($modelToCheck, $this->models);
491
	}
492
 
493
/**
494
 * Reloads the routes configuration from app/Config/routes.php, and compiles
495
 * all routes found
496
 *
497
 * @return bool True if config reload was a success, otherwise false
498
 */
499
	protected function _loadRoutes() {
500
		Router::reload();
501
		extract(Router::getNamedExpressions());
502
 
503
		//@codingStandardsIgnoreStart
504
		if (!@include APP . 'Config' . DS . 'routes.php') {
505
			//@codingStandardsIgnoreEnd
506
			return false;
507
		}
508
		CakePlugin::routes();
509
 
510
		Router::parse('/');
511
		return true;
512
	}
513
 
514
}