* Copyright 2005-2007, Cake Software Foundation, Inc. * 1785 E. Sahara Avenue, Suite 490-204 * Las Vegas, Nevada 89104 * * Licensed under The MIT License * Redistributions of files must retain the above copyright notice. * * @filesource * @copyright Copyright 2005-2007, Cake Software Foundation, Inc. * @link http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project * @package cake * @subpackage cake.cake.console.libs.tasks * @since CakePHP(tm) v 1.2 * @version $Revision$ * @modifiedby $LastChangedBy$ * @lastmodified $Date$ * @license http://www.opensource.org/licenses/mit-license.php The MIT License */ /** * Task class for creating and updating view files. * * @package cake * @subpackage cake.cake.console.libs.tasks */ class ViewTask extends Shell { /** * Tasks to be loaded by this Task * * @var array */ var $tasks = array('Project', 'Controller'); /** * name of the controller being used * * @var string */ var $controllerName = null; /** * path to controller to put views * * @var string */ var $controllerPath = null; /** * the template file to use * * @var string */ var $template = null; /** * Actions to use for scaffolding * * @var array */ var $scaffoldActions = array('index', 'view', 'add', 'edit'); /** * Override initialize * * @return void */ function initialize() {} /** * Execution method always used for tasks * * @return void */ function execute() { if(empty($this->args)) { $this->__interactive(); } $controller = $action = $alias = null; if(isset($this->args[0])) { $this->controllerName = Inflector::camelize($this->args[0]); $this->controllerPath = Inflector::underscore($this->controllerName); } if(isset($this->args[1])) { $this->template = $this->args[1]; } if(isset($this->args[2])) { $action = $this->args[2]; } if(!$action) { $action = $this->template; } if(in_array($action, $this->scaffoldActions)) { $this->bake($action, true); } else if($action) { $this->bake($action, true); } else { $vars = $this->__loadController(); if($vars) { $protected = array( 'object', low($this->controllerName. 'Controller'), 'controller', 'appcontroller', 'tostring', 'requestaction', 'log', 'cakeerror', 'constructclasses', 'redirect', 'set', 'setaction', 'validate', 'validateerrors', 'render', 'referer', 'flash', 'flashout', 'generatefieldnames', 'postconditions', 'cleanupfields', 'beforefilter', 'beforerender', 'afterfilter', 'disablecache', 'paginate'); $classVars = get_class_vars($this->controllerName . 'Controller'); if(array_key_exists('scaffold', $classVars)) { $methods = $this->scaffoldActions; } else { $methods = get_class_methods($this->controllerName . 'Controller'); } foreach($methods as $method) { if($method{0} != '_' && !in_array(low($method), am($protected, array('delete', CAKE_ADMIN.'_delete')))) { $content = $this->getContent($method, $vars); $this->bake($method, $content); } } } } } /** * Handles interactive baking * * @access private * @return void */ function __interactive() { $this->hr(); $this->out('View Bake:'); $this->hr(); $wannaDoAdmin = 'n'; $wannaDoScaffold = 'y'; $this->controllerName = $this->Controller->getName(); $this->controllerPath = low(Inflector::underscore($this->controllerName)); $interactive = $this->in("Would you like bake to build your views interactively?\nWarning: Choosing no will overwrite {$this->controllerName} views if it exist.", array('y','n'), 'y'); if (low($interactive) == 'y' || low($interactive) == 'yes') { $wannaDoScaffold = $this->in("Would you like to create some scaffolded views (index, add, view, edit) for this controller?\nNOTE: Before doing so, you'll need to create your controller and model classes (including associated models).", array('y','n'), 'n'); } if (low($wannaDoScaffold) == 'y' || low($wannaDoScaffold) == 'yes') { $wannaDoAdmin = $this->in("Would you like to create the views for admin routing?", array('y','n'), 'y'); } $admin = ''; if ((low($wannaDoAdmin) == 'y' || low($wannaDoAdmin) == 'yes')) { if(defined('CAKE_ADMIN')) { $admin = CAKE_ADMIN . '_'; } else { $this->out('You need to enable CAKE_ADMIN in /app/config/core.php to use admin routing.'); $this->out('What would you like the admin route to be?'); $this->out('Example: www.example.com/admin/controller'); while ($admin == '') { $admin = $this->in("What would you like the admin route to be?", null, 'admin'); } if($this->Project->cakeAdmin($admin) !== true){ $this->err('Unable to write to /app/config/core.php.'); $this->err('You need to enable CAKE_ADMIN in /app/config/core.php to use admin routing.'); exit(); } else { $admin = $admin . '_'; } } } if (low($wannaDoScaffold) == 'y' || low($wannaDoScaffold) == 'yes') { $file = CONTROLLERS . $this->controllerPath . '_controller.php'; if($admin) { foreach($this->scaffoldActions as $action) { $this->scaffoldActions[] = $admin . $action; } } $vars = $this->__loadController(); if($vars) { foreach($this->scaffoldActions as $action) { $content = $this->getContent($action, $vars); $this->bake($action, $content); } } $this->hr(); $this->out(''); $this->out('View Scaffolding Complete.'."\n"); } else { $action = ''; while ($action == '') { $action = $this->in('Action Name? (use camelCased function name)'); if ($action == '') { $this->out('The action name you supplied was empty. Please try again.'); } } $this->out(''); $this->hr(); $this->out('The following view will be created:'); $this->hr(); $this->out("Controller Name: {$this->controllerName}"); $this->out("Action Name: {$action}"); $this->out("Path: ".$this->params['app'] . DS . $this->controllerPath . DS . Inflector::underscore($action) . ".ctp"); $this->hr(); $looksGood = $this->in('Look okay?', array('y','n'), 'y'); if (low($looksGood) == 'y' || low($looksGood) == 'yes') { $this->bake($action); exit(); } else { $this->out('Bake Aborted.'); exit(); } } } /** * Loads Controller and sets variables for the template * Available template variables * 'modelClass', 'primaryKey', 'displayField', 'singularVar', 'pluralVar', * 'singularHumanName', 'pluralHumanName', 'fields', 'foreignKeys', * 'belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany' * * @access private * @return array Returns an variables to be made available to a view template */ function __loadController() { if(!$this->controllerName) { $this->err('could not find the controller'); } if(!loadController($this->controllerName)) { $file = CONTROLLERS . $this->controllerPath . '_controller.php'; $shortPath = $this->shortPath($file); $this->err("The file '{$shortPath}' could not be found.\nIn order to bake a view, you'll need to first create the controller."); exit(); } $controllerClassName = $this->controllerName . 'Controller'; $controllerObj = & new $controllerClassName(); $controllerObj->constructClasses(); $modelClass = $controllerObj->modelClass; $modelKey = $controllerObj->modelKey; $modelObj =& ClassRegistry::getObject($modelKey); $primaryKey = $modelObj->primaryKey; $displayField = $modelObj->displayField; $singularVar = Inflector::variable($modelClass); $pluralVar = Inflector::variable($this->controllerName); $singularHumanName = Inflector::humanize($modelClass); $pluralHumanName = Inflector::humanize($this->controllerName); $fields = $modelObj->_tableInfo->value; $foreignKeys = $modelObj->keyToTable; $belongsTo = $modelObj->belongsTo; $hasOne = $modelObj->hasOne; $hasMany = $modelObj->hasMany; $hasAndBelongsToMany = $modelObj->hasAndBelongsToMany; return compact('modelClass', 'primaryKey', 'displayField', 'singularVar', 'pluralVar', 'singularHumanName', 'pluralHumanName', 'fields', 'foreignKeys', 'belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany'); } /** * Assembles and writes bakes the view file. * * @param string $action * @param string $content * @return bool */ function bake($action, $content = '') { if($content === true) { $content = $this->getContent(); } $filename = VIEWS . $this->controllerPath . DS . Inflector::underscore($action) . '.ctp'; $Folder =& new Folder(VIEWS . $this->controllerPath, true); $errors = $Folder->errors(); if(empty($errors)) { $path = $Folder->slashTerm($Folder->pwd()); return $this->createFile($filename, $content); } else { foreach($errors as $error) { $this->err($error); } } return false; } /** * Builds content from template and variables * * @param string $template file to use * @param array $vars passed for use in templates * @return string content from template */ function getContent($template = null, $vars = null) { if(!$template) { $template = $this->template; } $action = $template; if(strpos($template, CAKE_ADMIN) !== false) { $template = str_replace(CAKE_ADMIN.'_', '', $template); } if(in_array($template, array('add', 'edit'))) { $action = $template; $template = 'form'; } $loaded = false; foreach($this->Dispatch->shellPaths as $path) { $templatePath = $path . 'templates' . DS . 'views' . DS .Inflector::underscore($template).'.ctp'; if (file_exists($templatePath) && is_file($templatePath)) { $loaded = true; break; } } if(!$vars) { $vars = $this->__loadController(); } if($loaded) { extract($vars); ob_start(); ob_implicit_flush(0); include($templatePath); $content = ob_get_clean(); return $content; } $this->err('Template for '. $template .' could not be found'); return false; } /** * Displays help contents * * @return void */ function help() { $this->hr(); $this->out("Usage: cake bake view ..."); $this->hr(); $this->out('Commands:'); $this->out("\n\tview \n\t\twill read the given controller for methods\n\t\tand bake corresponding views.\n\t\tIf var scaffold is found it will bake the scaffolded actions\n\t\t(index,view,add,edit)"); $this->out("\n\tview \n\t\twill bake a template. core templates: (index, add, edit, view)"); $this->out("\n\tview