Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
13532 anikendra 1
<?php
2
/**
3
 * The ControllerTask handles creating and updating controller files.
4
 *
5
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
6
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
7
 *
8
 * Licensed under The MIT License
9
 * For full copyright and license information, please see the LICENSE.txt
10
 * Redistributions of files must retain the above copyright notice.
11
 *
12
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
13
 * @link          http://cakephp.org CakePHP(tm) Project
14
 * @since         CakePHP(tm) v 1.2
15
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
16
 */
17
 
18
App::uses('AppShell', 'Console/Command');
19
App::uses('BakeTask', 'Console/Command/Task');
20
App::uses('AppModel', 'Model');
21
 
22
/**
23
 * Task class for creating and updating controller files.
24
 *
25
 * @package       Cake.Console.Command.Task
26
 */
27
class ControllerTask extends BakeTask {
28
 
29
/**
30
 * Tasks to be loaded by this Task
31
 *
32
 * @var array
33
 */
34
	public $tasks = array('Model', 'Test', 'Template', 'DbConfig', 'Project');
35
 
36
/**
37
 * path to Controller directory
38
 *
39
 * @var array
40
 */
41
	public $path = null;
42
 
43
/**
44
 * Override initialize
45
 *
46
 * @return void
47
 */
48
	public function initialize() {
49
		$this->path = current(App::path('Controller'));
50
	}
51
 
52
/**
53
 * Execution method always used for tasks
54
 *
55
 * @return void
56
 */
57
	public function execute() {
58
		parent::execute();
59
		if (empty($this->args)) {
60
			return $this->_interactive();
61
		}
62
 
63
		if (isset($this->args[0])) {
64
			if (!isset($this->connection)) {
65
				$this->connection = 'default';
66
			}
67
			if (strtolower($this->args[0]) === 'all') {
68
				return $this->all();
69
			}
70
 
71
			$controller = $this->_controllerName($this->args[0]);
72
			$actions = '';
73
 
74
			if (!empty($this->params['public'])) {
75
				$this->out(__d('cake_console', 'Baking basic crud methods for ') . $controller);
76
				$actions .= $this->bakeActions($controller);
77
			}
78
			if (!empty($this->params['admin'])) {
79
				$admin = $this->Project->getPrefix();
80
				if ($admin) {
81
					$this->out(__d('cake_console', 'Adding %s methods', $admin));
82
					$actions .= "\n" . $this->bakeActions($controller, $admin);
83
				}
84
			}
85
			if (empty($actions)) {
86
				$actions = 'scaffold';
87
			}
88
 
89
			if ($this->bake($controller, $actions)) {
90
				if ($this->_checkUnitTest()) {
91
					$this->bakeTest($controller);
92
				}
93
			}
94
		}
95
	}
96
 
97
/**
98
 * Bake All the controllers at once. Will only bake controllers for models that exist.
99
 *
100
 * @return void
101
 */
102
	public function all() {
103
		$this->interactive = false;
104
		$this->listAll($this->connection, false);
105
		ClassRegistry::config('Model', array('ds' => $this->connection));
106
		$unitTestExists = $this->_checkUnitTest();
107
 
108
		$admin = false;
109
		if (!empty($this->params['admin'])) {
110
			$admin = $this->Project->getPrefix();
111
		}
112
 
113
		foreach ($this->__tables as $table) {
114
			$model = $this->_modelName($table);
115
			$controller = $this->_controllerName($model);
116
			App::uses($model, 'Model');
117
			if (class_exists($model)) {
118
				$actions = $this->bakeActions($controller);
119
				if ($admin) {
120
					$this->out(__d('cake_console', 'Adding %s methods', $admin));
121
					$actions .= "\n" . $this->bakeActions($controller, $admin);
122
				}
123
				if ($this->bake($controller, $actions) && $unitTestExists) {
124
					$this->bakeTest($controller);
125
				}
126
			}
127
		}
128
	}
129
 
130
/**
131
 * Interactive
132
 *
133
 * @return void
134
 */
135
	protected function _interactive() {
136
		$this->interactive = true;
137
		$this->hr();
138
		$this->out(__d('cake_console', "Bake Controller\nPath: %s", $this->getPath()));
139
		$this->hr();
140
 
141
		if (empty($this->connection)) {
142
			$this->connection = $this->DbConfig->getConfig();
143
		}
144
 
145
		$controllerName = $this->getName();
146
		$this->hr();
147
		$this->out(__d('cake_console', 'Baking %sController', $controllerName));
148
		$this->hr();
149
 
150
		$helpers = $components = array();
151
		$actions = '';
152
		$wannaUseSession = 'y';
153
		$wannaBakeAdminCrud = 'n';
154
		$useDynamicScaffold = 'n';
155
		$wannaBakeCrud = 'y';
156
 
157
		$question[] = __d('cake_console', "Would you like to build your controller interactively?");
158
		if (file_exists($this->path . $controllerName . 'Controller.php')) {
159
			$question[] = __d('cake_console', "Warning: Choosing no will overwrite the %sController.", $controllerName);
160
		}
161
		$doItInteractive = $this->in(implode("\n", $question), array('y', 'n'), 'y');
162
 
163
		if (strtolower($doItInteractive) === 'y') {
164
			$this->interactive = true;
165
			$useDynamicScaffold = $this->in(
166
				__d('cake_console', "Would you like to use dynamic scaffolding?"), array('y', 'n'), 'n'
167
			);
168
 
169
			if (strtolower($useDynamicScaffold) === 'y') {
170
				$wannaBakeCrud = 'n';
171
				$actions = 'scaffold';
172
			} else {
173
				list($wannaBakeCrud, $wannaBakeAdminCrud) = $this->_askAboutMethods();
174
 
175
				$helpers = $this->doHelpers();
176
				$components = $this->doComponents();
177
 
178
				$wannaUseSession = $this->in(
179
					__d('cake_console', "Would you like to use Session flash messages?"), array('y', 'n'), 'y'
180
				);
181
			}
182
		} else {
183
			list($wannaBakeCrud, $wannaBakeAdminCrud) = $this->_askAboutMethods();
184
		}
185
 
186
		if (strtolower($wannaBakeCrud) === 'y') {
187
			$actions = $this->bakeActions($controllerName, null, strtolower($wannaUseSession) === 'y');
188
		}
189
		if (strtolower($wannaBakeAdminCrud) === 'y') {
190
			$admin = $this->Project->getPrefix();
191
			$actions .= $this->bakeActions($controllerName, $admin, strtolower($wannaUseSession) === 'y');
192
		}
193
 
194
		$baked = false;
195
		if ($this->interactive === true) {
196
			$this->confirmController($controllerName, $useDynamicScaffold, $helpers, $components);
197
			$looksGood = $this->in(__d('cake_console', 'Look okay?'), array('y', 'n'), 'y');
198
 
199
			if (strtolower($looksGood) === 'y') {
200
				$baked = $this->bake($controllerName, $actions, $helpers, $components);
201
				if ($baked && $this->_checkUnitTest()) {
202
					$this->bakeTest($controllerName);
203
				}
204
			}
205
		} else {
206
			$baked = $this->bake($controllerName, $actions, $helpers, $components);
207
			if ($baked && $this->_checkUnitTest()) {
208
				$this->bakeTest($controllerName);
209
			}
210
		}
211
		return $baked;
212
	}
213
 
214
/**
215
 * Confirm a to be baked controller with the user
216
 *
217
 * @param string $controllerName
218
 * @param string $useDynamicScaffold
219
 * @param array $helpers
220
 * @param array $components
221
 * @return void
222
 */
223
	public function confirmController($controllerName, $useDynamicScaffold, $helpers, $components) {
224
		$this->out();
225
		$this->hr();
226
		$this->out(__d('cake_console', 'The following controller will be created:'));
227
		$this->hr();
228
		$this->out(__d('cake_console', "Controller Name:\n\t%s", $controllerName));
229
 
230
		if (strtolower($useDynamicScaffold) === 'y') {
231
			$this->out("public \$scaffold;");
232
		}
233
 
234
		$properties = array(
235
			'helpers' => __d('cake_console', 'Helpers:'),
236
			'components' => __d('cake_console', 'Components:'),
237
		);
238
 
239
		foreach ($properties as $var => $title) {
240
			if (count($$var)) {
241
				$output = '';
242
				$length = count($$var);
243
				foreach ($$var as $i => $propElement) {
244
					if ($i != $length - 1) {
245
						$output .= ucfirst($propElement) . ', ';
246
					} else {
247
						$output .= ucfirst($propElement);
248
					}
249
				}
250
				$this->out($title . "\n\t" . $output);
251
			}
252
		}
253
		$this->hr();
254
	}
255
 
256
/**
257
 * Interact with the user and ask about which methods (admin or regular they want to bake)
258
 *
259
 * @return array Array containing (bakeRegular, bakeAdmin) answers
260
 */
261
	protected function _askAboutMethods() {
262
		$wannaBakeCrud = $this->in(
263
			__d('cake_console', "Would you like to create some basic class methods \n(index(), add(), view(), edit())?"),
264
			array('y', 'n'), 'n'
265
		);
266
		$wannaBakeAdminCrud = $this->in(
267
			__d('cake_console', "Would you like to create the basic class methods for admin routing?"),
268
			array('y', 'n'), 'n'
269
		);
270
		return array($wannaBakeCrud, $wannaBakeAdminCrud);
271
	}
272
 
273
/**
274
 * Bake scaffold actions
275
 *
276
 * @param string $controllerName Controller name
277
 * @param string $admin Admin route to use
278
 * @param boolean $wannaUseSession Set to true to use sessions, false otherwise
279
 * @return string Baked actions
280
 */
281
	public function bakeActions($controllerName, $admin = null, $wannaUseSession = true) {
282
		$currentModelName = $modelImport = $this->_modelName($controllerName);
283
		$plugin = $this->plugin;
284
		if ($plugin) {
285
			$plugin .= '.';
286
		}
287
		App::uses($modelImport, $plugin . 'Model');
288
		if (!class_exists($modelImport)) {
289
			$this->err(__d('cake_console', 'You must have a model for this class to build basic methods. Please try again.'));
290
			return $this->_stop();
291
		}
292
 
293
		$modelObj = ClassRegistry::init($currentModelName);
294
		$controllerPath = $this->_controllerPath($controllerName);
295
		$pluralName = $this->_pluralName($currentModelName);
296
		$singularName = Inflector::variable($currentModelName);
297
		$singularHumanName = $this->_singularHumanName($controllerName);
298
		$pluralHumanName = $this->_pluralName($controllerName);
299
		$displayField = $modelObj->displayField;
300
		$primaryKey = $modelObj->primaryKey;
301
 
302
		$this->Template->set(compact(
303
			'plugin', 'admin', 'controllerPath', 'pluralName', 'singularName',
304
			'singularHumanName', 'pluralHumanName', 'modelObj', 'wannaUseSession', 'currentModelName',
305
			'displayField', 'primaryKey'
306
		));
307
		$actions = $this->Template->generate('actions', 'controller_actions');
308
		return $actions;
309
	}
310
 
311
/**
312
 * Assembles and writes a Controller file
313
 *
314
 * @param string $controllerName Controller name already pluralized and correctly cased.
315
 * @param string $actions Actions to add, or set the whole controller to use $scaffold (set $actions to 'scaffold')
316
 * @param array $helpers Helpers to use in controller
317
 * @param array $components Components to use in controller
318
 * @return string Baked controller
319
 */
320
	public function bake($controllerName, $actions = '', $helpers = null, $components = null) {
321
		$this->out("\n" . __d('cake_console', 'Baking controller class for %s...', $controllerName), 1, Shell::QUIET);
322
 
323
		$isScaffold = ($actions === 'scaffold') ? true : false;
324
 
325
		$this->Template->set(array(
326
			'plugin' => $this->plugin,
327
			'pluginPath' => empty($this->plugin) ? '' : $this->plugin . '.'
328
		));
329
 
330
		if (!in_array('Paginator', (array)$components)) {
331
			$components[] = 'Paginator';
332
		}
333
 
334
		$this->Template->set(compact('controllerName', 'actions', 'helpers', 'components', 'isScaffold'));
335
		$contents = $this->Template->generate('classes', 'controller');
336
 
337
		$path = $this->getPath();
338
		$filename = $path . $controllerName . 'Controller.php';
339
		if ($this->createFile($filename, $contents)) {
340
			return $contents;
341
		}
342
		return false;
343
	}
344
 
345
/**
346
 * Assembles and writes a unit test file
347
 *
348
 * @param string $className Controller class name
349
 * @return string Baked test
350
 */
351
	public function bakeTest($className) {
352
		$this->Test->plugin = $this->plugin;
353
		$this->Test->connection = $this->connection;
354
		$this->Test->interactive = $this->interactive;
355
		return $this->Test->bake('Controller', $className);
356
	}
357
 
358
/**
359
 * Interact with the user and get a list of additional helpers
360
 *
361
 * @return array Helpers that the user wants to use.
362
 */
363
	public function doHelpers() {
364
		return $this->_doPropertyChoices(
365
			__d('cake_console', "Would you like this controller to use other helpers\nbesides HtmlHelper and FormHelper?"),
366
			__d('cake_console', "Please provide a comma separated list of the other\nhelper names you'd like to use.\nExample: 'Text, Js, Time'")
367
		);
368
	}
369
 
370
/**
371
 * Interact with the user and get a list of additional components
372
 *
373
 * @return array Components the user wants to use.
374
 */
375
	public function doComponents() {
376
		$components = array('Paginator');
377
		return array_merge($components, $this->_doPropertyChoices(
378
			__d('cake_console', "Would you like this controller to use other components\nbesides PaginatorComponent?"),
379
			__d('cake_console', "Please provide a comma separated list of the component names you'd like to use.\nExample: 'Acl, Security, RequestHandler'")
380
		));
381
	}
382
 
383
/**
384
 * Common code for property choice handling.
385
 *
386
 * @param string $prompt A yes/no question to precede the list
387
 * @param string $example A question for a comma separated list, with examples.
388
 * @return array Array of values for property.
389
 */
390
	protected function _doPropertyChoices($prompt, $example) {
391
		$proceed = $this->in($prompt, array('y', 'n'), 'n');
392
		$property = array();
393
		if (strtolower($proceed) === 'y') {
394
			$propertyList = $this->in($example);
395
			$propertyListTrimmed = str_replace(' ', '', $propertyList);
396
			$property = explode(',', $propertyListTrimmed);
397
		}
398
		return array_filter($property);
399
	}
400
 
401
/**
402
 * Outputs and gets the list of possible controllers from database
403
 *
404
 * @param string $useDbConfig Database configuration name
405
 * @return array Set of controllers
406
 */
407
	public function listAll($useDbConfig = null) {
408
		if ($useDbConfig === null) {
409
			$useDbConfig = $this->connection;
410
		}
411
		$this->__tables = $this->Model->getAllTables($useDbConfig);
412
 
413
		if ($this->interactive) {
414
			$this->out(__d('cake_console', 'Possible Controllers based on your current database:'));
415
			$this->hr();
416
			$this->_controllerNames = array();
417
			$count = count($this->__tables);
418
			for ($i = 0; $i < $count; $i++) {
419
				$this->_controllerNames[] = $this->_controllerName($this->_modelName($this->__tables[$i]));
420
				$this->out(sprintf("%2d. %s", $i + 1, $this->_controllerNames[$i]));
421
			}
422
			return $this->_controllerNames;
423
		}
424
		return $this->__tables;
425
	}
426
 
427
/**
428
 * Forces the user to specify the controller he wants to bake, and returns the selected controller name.
429
 *
430
 * @param string $useDbConfig Connection name to get a controller name for.
431
 * @return string Controller name
432
 */
433
	public function getName($useDbConfig = null) {
434
		$controllers = $this->listAll($useDbConfig);
435
		$enteredController = '';
436
 
437
		while (!$enteredController) {
438
			$enteredController = $this->in(__d('cake_console', "Enter a number from the list above,\ntype in the name of another controller, or 'q' to exit"), null, 'q');
439
			if ($enteredController === 'q') {
440
				$this->out(__d('cake_console', 'Exit'));
441
				return $this->_stop();
442
			}
443
 
444
			if (!$enteredController || intval($enteredController) > count($controllers)) {
445
				$this->err(__d('cake_console', "The Controller name you supplied was empty,\nor the number you selected was not an option. Please try again."));
446
				$enteredController = '';
447
			}
448
		}
449
 
450
		if (intval($enteredController) > 0 && intval($enteredController) <= count($controllers)) {
451
			$controllerName = $controllers[intval($enteredController) - 1];
452
		} else {
453
			$controllerName = Inflector::camelize($enteredController);
454
		}
455
		return $controllerName;
456
	}
457
 
458
/**
459
 * get the option parser.
460
 *
461
 * @return void
462
 */
463
	public function getOptionParser() {
464
		$parser = parent::getOptionParser();
465
		return $parser->description(
466
				__d('cake_console', 'Bake a controller for a model. Using options you can bake public, admin or both.')
467
			)->addArgument('name', array(
468
				'help' => __d('cake_console', 'Name of the controller to bake. Can use Plugin.name to bake controllers into plugins.')
469
			))->addOption('public', array(
470
				'help' => __d('cake_console', 'Bake a controller with basic crud actions (index, view, add, edit, delete).'),
471
				'boolean' => true
472
			))->addOption('admin', array(
473
				'help' => __d('cake_console', 'Bake a controller with crud actions for one of the Routing.prefixes.'),
474
				'boolean' => true
475
			))->addOption('plugin', array(
476
				'short' => 'p',
477
				'help' => __d('cake_console', 'Plugin to bake the controller into.')
478
			))->addOption('connection', array(
479
				'short' => 'c',
480
				'help' => __d('cake_console', 'The connection the controller\'s model is on.')
481
			))->addOption('theme', array(
482
				'short' => 't',
483
				'help' => __d('cake_console', 'Theme to use when baking code.')
484
			))->addOption('force', array(
485
				'short' => 'f',
486
				'help' => __d('cake_console', 'Force overwriting existing files without prompting.')
487
			))->addSubcommand('all', array(
488
				'help' => __d('cake_console', 'Bake all controllers with CRUD methods.')
489
			))->epilog(__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.'));
490
	}
491
 
492
}