Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
13532 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 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
 * getOptionParser
109
 *
110
 * @return void
111
 */
112
	public function getOptionParser() {
113
		$description = array(
114
			'The interactive console is a tool for testing parts of your',
115
			'app before you write code.',
116
			'',
117
			'See below for a list of supported commands.'
118
		);
119
 
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
		return parent::getOptionParser()
181
			->description($description)
182
			->epilog($epilog);
183
	}
184
/**
185
 * Prints the help message
186
 *
187
 * @return void
188
 */
189
	public function help() {
190
		$optionParser = $this->getOptionParser();
191
		$this->out($optionParser->epilog());
192
	}
193
 
194
/**
195
 * Override main() to handle action
196
 *
197
 * @param string $command
198
 * @return void
199
 */
200
	public function main($command = null) {
201
		$this->_finished = false;
202
		while (!$this->_finished) {
203
			if (empty($command)) {
204
				$command = trim($this->in(''));
205
			}
206
 
207
			$method = $this->_method($command);
208
 
209
			if ($method) {
210
				$this->$method($command);
211
			} else {
212
				$this->out(__d('cake_console', "Invalid command"));
213
				$this->out();
214
			}
215
			$command = '';
216
		}
217
	}
218
 
219
/**
220
 * Determine the method to process the current command
221
 *
222
 * @param string $command
223
 * @return string or false
224
 */
225
	protected function _method($command) {
226
		foreach ($this->_methodPatterns as $method => $pattern) {
227
			if (preg_match($pattern, $command)) {
228
				return $method;
229
			}
230
		}
231
 
232
		return false;
233
	}
234
 
235
/**
236
 * Set the finiished property so that the loop in main method ends
237
 *
238
 * @return void
239
 */
240
	protected function _exit() {
241
		$this->_finished = true;
242
	}
243
 
244
/**
245
 * List all models
246
 *
247
 * @return void
248
 */
249
	protected function _models() {
250
		$this->out(__d('cake_console', 'Model classes:'));
251
		$this->hr();
252
		foreach ($this->models as $model) {
253
			$this->out(" - {$model}");
254
		}
255
	}
256
 
257
/**
258
 * Bind an association
259
 *
260
 * @param mixed $command
261
 * @return void
262
 */
263
	protected function _bind($command) {
264
		preg_match($this->_methodPatterns[__FUNCTION__], $command, $tmp);
265
 
266
		foreach ($tmp as $data) {
267
			$data = strip_tags($data);
268
			$data = str_replace($this->badCommandChars, "", $data);
269
		}
270
 
271
		$modelA = $tmp[1];
272
		$association = $tmp[2];
273
		$modelB = $tmp[3];
274
 
275
		if ($this->_isValidModel($modelA) && $this->_isValidModel($modelB) && in_array($association, $this->associations)) {
276
			$this->{$modelA}->bindModel(array($association => array($modelB => array('className' => $modelB))), false);
277
			$this->out(__d('cake_console', "Created %s association between %s and %s",
278
				$association, $modelA, $modelB));
279
		} else {
280
			$this->out(__d('cake_console', "Please verify you are using valid models and association types"));
281
		}
282
	}
283
 
284
/**
285
 * Unbind an association
286
 *
287
 * @param mixed $command
288
 * @return void
289
 */
290
	protected function _unbind($command) {
291
		preg_match($this->_methodPatterns[__FUNCTION__], $command, $tmp);
292
 
293
		foreach ($tmp as $data) {
294
			$data = strip_tags($data);
295
			$data = str_replace($this->badCommandChars, "", $data);
296
		}
297
 
298
		$modelA = $tmp[1];
299
		$association = $tmp[2];
300
		$modelB = $tmp[3];
301
 
302
		// Verify that there is actually an association to unbind
303
		$currentAssociations = $this->{$modelA}->getAssociated();
304
		$validCurrentAssociation = false;
305
 
306
		foreach ($currentAssociations as $model => $currentAssociation) {
307
			if ($model == $modelB && $association == $currentAssociation) {
308
				$validCurrentAssociation = true;
309
			}
310
		}
311
 
312
		if ($this->_isValidModel($modelA) && $this->_isValidModel($modelB) && in_array($association, $this->associations) && $validCurrentAssociation) {
313
			$this->{$modelA}->unbindModel(array($association => array($modelB)));
314
			$this->out(__d('cake_console', "Removed %s association between %s and %s",
315
				$association, $modelA, $modelB));
316
		} else {
317
			$this->out(__d('cake_console', "Please verify you are using valid models, valid current association, and valid association types"));
318
		}
319
	}
320
 
321
/**
322
 * Perform a find
323
 *
324
 * @param mixed $command
325
 * @return void
326
 */
327
	protected function _find($command) {
328
		$command = strip_tags($command);
329
		$command = str_replace($this->badCommandChars, "", $command);
330
 
331
		// Do we have a valid model?
332
		list($modelToCheck, $tmp) = explode('->', $command);
333
 
334
		if ($this->_isValidModel($modelToCheck)) {
335
			$findCommand = "\$data = \$this->$command;";
336
			//@codingStandardsIgnoreStart
337
			@eval($findCommand);
338
			//@codingStandardsIgnoreEnd
339
 
340
			if (is_array($data)) {
341
				foreach ($data as $idx => $results) {
342
					if (is_numeric($idx)) { // findAll() output
343
						foreach ($results as $modelName => $result) {
344
							$this->out("$modelName");
345
 
346
							foreach ($result as $field => $value) {
347
								if (is_array($value)) {
348
									foreach ($value as $field2 => $value2) {
349
										$this->out("\t$field2: $value2");
350
									}
351
 
352
									$this->out();
353
								} else {
354
									$this->out("\t$field: $value");
355
								}
356
							}
357
						}
358
					} else { // find() output
359
						$this->out($idx);
360
 
361
						foreach ($results as $field => $value) {
362
							if (is_array($value)) {
363
								foreach ($value as $field2 => $value2) {
364
									$this->out("\t$field2: $value2");
365
								}
366
 
367
								$this->out();
368
							} else {
369
								$this->out("\t$field: $value");
370
							}
371
						}
372
					}
373
				}
374
			} else {
375
				$this->out();
376
				$this->out(__d('cake_console', "No result set found"));
377
			}
378
		} else {
379
			$this->out(__d('cake_console', "%s is not a valid model", $modelToCheck));
380
		}
381
	}
382
 
383
/**
384
 * Save a record
385
 *
386
 * @param mixed $command
387
 * @return void
388
 */
389
	protected function _save($command) {
390
		// Validate the model we're trying to save here
391
		$command = strip_tags($command);
392
		$command = str_replace($this->badCommandChars, "", $command);
393
		list($modelToSave, $tmp) = explode("->", $command);
394
 
395
		if ($this->_isValidModel($modelToSave)) {
396
			// Extract the array of data we are trying to build
397
			list(, $data) = explode("->save", $command);
398
			$data = preg_replace('/^\(*(array)?\(*(.+?)\)*$/i', '\\2', $data);
399
			$saveCommand = "\$this->{$modelToSave}->save(array('{$modelToSave}' => array({$data})));";
400
			//@codingStandardsIgnoreStart
401
			@eval($saveCommand);
402
			//@codingStandardsIgnoreEnd
403
			$this->out(__d('cake_console', 'Saved record for %s', $modelToSave));
404
		}
405
	}
406
 
407
/**
408
 * Show the columns for a model
409
 *
410
 * @param mixed $command
411
 * @return void
412
 */
413
	protected function _columns($command) {
414
		preg_match($this->_methodPatterns[__FUNCTION__], $command, $tmp);
415
 
416
		$modelToCheck = strip_tags(str_replace($this->badCommandChars, "", $tmp[1]));
417
 
418
		if ($this->_isValidModel($modelToCheck)) {
419
			// Get the column info for this model
420
			$fieldsCommand = "\$data = \$this->{$modelToCheck}->getColumnTypes();";
421
			//@codingStandardsIgnoreStart
422
			@eval($fieldsCommand);
423
			//@codingStandardsIgnoreEnd
424
 
425
			if (is_array($data)) {
426
				foreach ($data as $field => $type) {
427
					$this->out("\t{$field}: {$type}");
428
				}
429
			}
430
		} else {
431
			$this->out(__d('cake_console', "Please verify that you selected a valid model"));
432
		}
433
	}
434
 
435
/**
436
 * Reload route definitions
437
 *
438
 * @return void
439
 */
440
	protected function _routesReload() {
441
		if (!$this->_loadRoutes()) {
442
			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."));
443
		}
444
		$this->out(__d('cake_console', "Routes configuration reloaded, %d routes connected", count(Router::$routes)));
445
	}
446
 
447
/**
448
 * Show all routes
449
 *
450
 * @return void
451
 */
452
	protected function _routesShow() {
453
		$this->out(print_r(Hash::combine(Router::$routes, '{n}.template', '{n}.defaults'), true));
454
	}
455
 
456
/**
457
 * Parse an array URL and show the equivalent URL as a string
458
 *
459
 * @param mixed $command
460
 * @return void
461
 */
462
	protected function _routeToString($command) {
463
		preg_match($this->_methodPatterns[__FUNCTION__], $command, $tmp);
464
 
465
		//@codingStandardsIgnoreStart
466
		if ($url = eval('return array' . $tmp[1] . ';')) {
467
			//@codingStandardsIgnoreEnd
468
			$this->out(Router::url($url));
469
		}
470
	}
471
 
472
/**
473
 * Parse a string URL and show as an array
474
 *
475
 * @param mixed $command
476
 * @return void
477
 */
478
	protected function _routeToArray($command) {
479
		preg_match($this->_methodPatterns[__FUNCTION__], $command, $tmp);
480
 
481
		$this->out(var_export(Router::parse($tmp[1]), true));
482
	}
483
 
484
/**
485
 * Tells if the specified model is included in the list of available models
486
 *
487
 * @param string $modelToCheck
488
 * @return boolean true if is an available model, false otherwise
489
 */
490
	protected function _isValidModel($modelToCheck) {
491
		return in_array($modelToCheck, $this->models);
492
	}
493
 
494
/**
495
 * Reloads the routes configuration from app/Config/routes.php, and compiles
496
 * all routes found
497
 *
498
 * @return boolean True if config reload was a success, otherwise false
499
 */
500
	protected function _loadRoutes() {
501
		Router::reload();
502
		extract(Router::getNamedExpressions());
503
 
504
		//@codingStandardsIgnoreStart
505
		if (!@include APP . 'Config' . DS . 'routes.php') {
506
			//@codingStandardsIgnoreEnd
507
			return false;
508
		}
509
		CakePlugin::routes();
510
 
511
		Router::parse('/');
512
		return true;
513
	}
514
 
515
}