1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
20: App::import('Controller', 'Controller', false);
21: include_once dirname(__FILE__) . DS . 'bake.php';
22:
23: 24: 25: 26: 27: 28:
29: class ViewTask extends BakeTask {
30:
31: 32: 33: 34: 35: 36:
37: var $tasks = array('Project', 'Controller', 'DbConfig', 'Template');
38:
39: 40: 41: 42: 43: 44:
45: var $path = VIEWS;
46:
47: 48: 49: 50: 51: 52:
53: var $controllerName = null;
54:
55: 56: 57: 58: 59: 60:
61: var $controllerPath = null;
62:
63: 64: 65: 66: 67: 68:
69: var $template = null;
70:
71: 72: 73: 74: 75: 76:
77: var $scaffoldActions = array('index', 'view', 'add', 'edit');
78:
79: 80: 81: 82: 83: 84: 85:
86: var $noTemplateActions = array('delete');
87:
88: 89: 90: 91: 92:
93: function initialize() {
94: }
95:
96: 97: 98: 99: 100:
101: function execute() {
102: if (empty($this->args)) {
103: $this->__interactive();
104: }
105: if (empty($this->args[0])) {
106: return;
107: }
108: if (!isset($this->connection)) {
109: $this->connection = 'default';
110: }
111: $controller = $action = $alias = null;
112: $this->controllerName = $this->_controllerName($this->args[0]);
113: $this->controllerPath = $this->_controllerPath($this->controllerName);
114:
115: $this->Project->interactive = false;
116: if (strtolower($this->args[0]) == 'all') {
117: return $this->all();
118: }
119:
120: if (isset($this->args[1])) {
121: $this->template = $this->args[1];
122: }
123: if (isset($this->args[2])) {
124: $action = $this->args[2];
125: }
126: if (!$action) {
127: $action = $this->template;
128: }
129: if ($action) {
130: return $this->bake($action, true);
131: }
132:
133: $vars = $this->__loadController();
134: $methods = $this->_methodsToBake();
135:
136: foreach ($methods as $method) {
137: $content = $this->getContent($method, $vars);
138: if ($content) {
139: $this->bake($method, $content);
140: }
141: }
142: }
143:
144: 145: 146: 147: 148:
149: function _methodsToBake() {
150: $methods = array_diff(
151: array_map('strtolower', get_class_methods($this->controllerName . 'Controller')),
152: array_map('strtolower', get_class_methods('appcontroller'))
153: );
154: $scaffoldActions = false;
155: if (empty($methods)) {
156: $scaffoldActions = true;
157: $methods = $this->scaffoldActions;
158: }
159: $adminRoute = $this->Project->getPrefix();
160: foreach ($methods as $i => $method) {
161: if ($adminRoute && isset($this->params['admin'])) {
162: if ($scaffoldActions) {
163: $methods[$i] = $adminRoute . $method;
164: continue;
165: } elseif (strpos($method, $adminRoute) === false) {
166: unset($methods[$i]);
167: }
168: }
169: if ($method[0] === '_' || $method == strtolower($this->controllerName . 'Controller')) {
170: unset($methods[$i]);
171: }
172: }
173: return $methods;
174: }
175:
176: 177: 178: 179: 180:
181: function all() {
182: $this->Controller->interactive = false;
183: $tables = $this->Controller->listAll($this->connection, false);
184:
185: $actions = null;
186: if (isset($this->args[1])) {
187: $actions = array($this->args[1]);
188: }
189: $this->interactive = false;
190: foreach ($tables as $table) {
191: $model = $this->_modelName($table);
192: $this->controllerName = $this->_controllerName($model);
193: $this->controllerPath = Inflector::underscore($this->controllerName);
194: if (App::import('Model', $model)) {
195: $vars = $this->__loadController();
196: if (!$actions) {
197: $actions = $this->_methodsToBake();
198: }
199: $this->bakeActions($actions, $vars);
200: $actions = null;
201: }
202: }
203: }
204:
205: 206: 207: 208: 209:
210: function __interactive() {
211: $this->hr();
212: $this->out(sprintf("Bake View\nPath: %s", $this->path));
213: $this->hr();
214:
215: $this->DbConfig->interactive = $this->Controller->interactive = $this->interactive = true;
216:
217: if (empty($this->connection)) {
218: $this->connection = $this->DbConfig->getConfig();
219: }
220:
221: $this->Controller->connection = $this->connection;
222: $this->controllerName = $this->Controller->getName();
223:
224: $this->controllerPath = strtolower(Inflector::underscore($this->controllerName));
225:
226: $prompt = sprintf(__("Would you like bake to build your views interactively?\nWarning: Choosing no will overwrite %s views if it exist.", true), $this->controllerName);
227: $interactive = $this->in($prompt, array('y', 'n'), 'n');
228:
229: if (strtolower($interactive) == 'n') {
230: $this->interactive = false;
231: }
232:
233: $prompt = __("Would you like to create some CRUD views\n(index, add, view, edit) for this controller?\nNOTE: Before doing so, you'll need to create your controller\nand model classes (including associated models).", true);
234: $wannaDoScaffold = $this->in($prompt, array('y','n'), 'y');
235:
236: $wannaDoAdmin = $this->in(__("Would you like to create the views for admin routing?", true), array('y','n'), 'n');
237:
238: if (strtolower($wannaDoScaffold) == 'y' || strtolower($wannaDoAdmin) == 'y') {
239: $vars = $this->__loadController();
240: if (strtolower($wannaDoScaffold) == 'y') {
241: $actions = $this->scaffoldActions;
242: $this->bakeActions($actions, $vars);
243: }
244: if (strtolower($wannaDoAdmin) == 'y') {
245: $admin = $this->Project->getPrefix();
246: $regularActions = $this->scaffoldActions;
247: $adminActions = array();
248: foreach ($regularActions as $action) {
249: $adminActions[] = $admin . $action;
250: }
251: $this->bakeActions($adminActions, $vars);
252: }
253: $this->hr();
254: $this->out();
255: $this->out(__("View Scaffolding Complete.\n", true));
256: } else {
257: $this->customAction();
258: }
259: }
260:
261: 262: 263: 264: 265: 266: 267: 268: 269: 270:
271: function __loadController() {
272: if (!$this->controllerName) {
273: $this->err(__('Controller not found', true));
274: }
275:
276: $import = $this->controllerName;
277: if ($this->plugin) {
278: $import = $this->plugin . '.' . $this->controllerName;
279: }
280:
281: if (!App::import('Controller', $import)) {
282: $file = $this->controllerPath . '_controller.php';
283: $this->err(sprintf(__("The file '%s' could not be found.\nIn order to bake a view, you'll need to first create the controller.", true), $file));
284: $this->_stop();
285: }
286: $controllerClassName = $this->controllerName . 'Controller';
287: $controllerObj =& new $controllerClassName();
288: $controllerObj->plugin = $this->plugin;
289: $controllerObj->constructClasses();
290: $modelClass = $controllerObj->modelClass;
291: $modelObj =& $controllerObj->{$controllerObj->modelClass};
292:
293: if ($modelObj) {
294: $primaryKey = $modelObj->primaryKey;
295: $displayField = $modelObj->displayField;
296: $singularVar = Inflector::variable($modelClass);
297: $singularHumanName = $this->_singularHumanName($this->controllerName);
298: $schema = $modelObj->schema(true);
299: $fields = array_keys($schema);
300: $associations = $this->__associations($modelObj);
301: } else {
302: $primaryKey = $displayField = null;
303: $singularVar = Inflector::variable(Inflector::singularize($this->controllerName));
304: $singularHumanName = $this->_singularHumanName($this->controllerName);
305: $fields = $schema = $associations = array();
306: }
307: $pluralVar = Inflector::variable($this->controllerName);
308: $pluralHumanName = $this->_pluralHumanName($this->controllerName);
309:
310: return compact('modelClass', 'schema', 'primaryKey', 'displayField', 'singularVar', 'pluralVar',
311: 'singularHumanName', 'pluralHumanName', 'fields','associations');
312: }
313:
314: 315: 316: 317: 318: 319:
320: function bakeActions($actions, $vars) {
321: foreach ($actions as $action) {
322: $content = $this->getContent($action, $vars);
323: $this->bake($action, $content);
324: }
325: }
326:
327: 328: 329: 330: 331:
332: function customAction() {
333: $action = '';
334: while ($action == '') {
335: $action = $this->in(__('Action Name? (use lowercase_underscored function name)', true));
336: if ($action == '') {
337: $this->out(__('The action name you supplied was empty. Please try again.', true));
338: }
339: }
340: $this->out();
341: $this->hr();
342: $this->out(__('The following view will be created:', true));
343: $this->hr();
344: $this->out(sprintf(__('Controller Name: %s', true), $this->controllerName));
345: $this->out(sprintf(__('Action Name: %s', true), $action));
346: $this->out(sprintf(__('Path: %s', true), $this->params['app'] . DS . 'views' . DS . $this->controllerPath . DS . Inflector::underscore($action) . ".ctp"));
347: $this->hr();
348: $looksGood = $this->in(__('Look okay?', true), array('y','n'), 'y');
349: if (strtolower($looksGood) == 'y') {
350: $this->bake($action, true);
351: $this->_stop();
352: } else {
353: $this->out(__('Bake Aborted.', true));
354: }
355: }
356:
357: 358: 359: 360: 361: 362: 363: 364:
365: function bake($action, $content = '') {
366: if ($content === true) {
367: $content = $this->getContent($action);
368: }
369: if (empty($content)) {
370: return false;
371: }
372: $path = $this->getPath();
373: $filename = $path . $this->controllerPath . DS . Inflector::underscore($action) . '.ctp';
374: return $this->createFile($filename, $content);
375: }
376:
377: 378: 379: 380: 381: 382: 383: 384:
385: function getContent($action, $vars = null) {
386: if (!$vars) {
387: $vars = $this->__loadController();
388: }
389:
390: $this->Template->set('action', $action);
391: $this->Template->set('plugin', $this->plugin);
392: $this->Template->set($vars);
393: $template = $this->getTemplate($action);
394: if ($template) {
395: return $this->Template->generate('views', $template);
396: }
397: return false;
398: }
399:
400: 401: 402: 403: 404: 405: 406:
407: function getTemplate($action) {
408: if ($action != $this->template && in_array($action, $this->noTemplateActions)) {
409: return false;
410: }
411: if (!empty($this->template) && $action != $this->template) {
412: return $this->template;
413: }
414: $template = $action;
415: $prefixes = Configure::read('Routing.prefixes');
416: foreach ((array)$prefixes as $prefix) {
417: if (strpos($template, $prefix) !== false) {
418: $template = str_replace($prefix . '_', '', $template);
419: }
420: }
421: if (in_array($template, array('add', 'edit'))) {
422: $template = 'form';
423: } elseif (preg_match('@(_add|_edit)$@', $template)) {
424: $template = str_replace(array('_add', '_edit'), '_form', $template);
425: }
426: return $template;
427: }
428:
429: 430: 431: 432: 433:
434: function help() {
435: $this->hr();
436: $this->out("Usage: cake bake view <arg1> <arg2>...");
437: $this->hr();
438: $this->out('Arguments:');
439: $this->out();
440: $this->out("<controller>");
441: $this->out("\tName of the controller views to bake. Can use Plugin.name");
442: $this->out("\tas a shortcut for plugin baking.");
443: $this->out();
444: $this->out("<action>");
445: $this->out("\tName of the action view to bake");
446: $this->out();
447: $this->out('Commands:');
448: $this->out();
449: $this->out("view <controller>");
450: $this->out("\tWill read the given controller for methods");
451: $this->out("\tand bake corresponding views.");
452: $this->out("\tUsing the -admin flag will only bake views for actions");
453: $this->out("\tthat begin with Routing.admin.");
454: $this->out("\tIf var scaffold is found it will bake the CRUD actions");
455: $this->out("\t(index,view,add,edit)");
456: $this->out();
457: $this->out("view <controller> <action>");
458: $this->out("\tWill bake a template. core templates: (index, add, edit, view)");
459: $this->out();
460: $this->out("view <controller> <template> <alias>");
461: $this->out("\tWill use the template specified");
462: $this->out("\tbut name the file based on the alias");
463: $this->out();
464: $this->out("view all");
465: $this->out("\tBake all CRUD action views for all controllers.");
466: $this->out("\tRequires that models and controllers exist.");
467: $this->_stop();
468: }
469:
470: 471: 472: 473: 474: 475:
476: function __associations(&$model) {
477: $keys = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany');
478: $associations = array();
479:
480: foreach ($keys as $key => $type) {
481: foreach ($model->{$type} as $assocKey => $assocData) {
482: $associations[$type][$assocKey]['primaryKey'] = $model->{$assocKey}->primaryKey;
483: $associations[$type][$assocKey]['displayField'] = $model->{$assocKey}->displayField;
484: $associations[$type][$assocKey]['foreignKey'] = $assocData['foreignKey'];
485: $associations[$type][$assocKey]['controller'] = Inflector::pluralize(Inflector::underscore($assocData['className']));
486: $associations[$type][$assocKey]['fields'] = array_keys($model->{$assocKey}->schema(true));
487: }
488: }
489: return $associations;
490: }
491: }
492: