mirror of
https://github.com/brmlab/brmbiolab_sklad.git
synced 2025-10-29 06:24:01 +01:00
Initial commit
This commit is contained in:
commit
3b93da31de
1004 changed files with 265840 additions and 0 deletions
619
lib/Cake/Console/Command/AclShell.php
Normal file
619
lib/Cake/Console/Command/AclShell.php
Normal file
|
|
@ -0,0 +1,619 @@
|
|||
<?php
|
||||
/**
|
||||
* Acl Shell provides Acl access in the CLI environment
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 1.2.0.5012
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
App::uses('Controller', 'Controller');
|
||||
App::uses('ComponentCollection', 'Controller');
|
||||
App::uses('AclComponent', 'Controller/Component');
|
||||
App::uses('DbAcl', 'Model');
|
||||
App::uses('Hash', 'Utility');
|
||||
|
||||
/**
|
||||
* Shell for ACL management. This console is known to have issues with zend.ze1_compatibility_mode
|
||||
* being enabled. Be sure to turn it off when using this shell.
|
||||
*
|
||||
* @package Cake.Console.Command
|
||||
*/
|
||||
class AclShell extends AppShell {
|
||||
|
||||
/**
|
||||
* Contains instance of AclComponent
|
||||
*
|
||||
* @var AclComponent
|
||||
*/
|
||||
public $Acl;
|
||||
|
||||
/**
|
||||
* Contains arguments parsed from the command line.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $args;
|
||||
|
||||
/**
|
||||
* Contains database source to use
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $connection = 'default';
|
||||
|
||||
/**
|
||||
* Contains tasks to load and instantiate
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $tasks = array('DbConfig');
|
||||
|
||||
/**
|
||||
* Override startup of the Shell
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function startup() {
|
||||
parent::startup();
|
||||
if (isset($this->params['connection'])) {
|
||||
$this->connection = $this->params['connection'];
|
||||
}
|
||||
|
||||
$class = Configure::read('Acl.classname');
|
||||
list($plugin, $class) = pluginSplit($class, true);
|
||||
App::uses($class, $plugin . 'Controller/Component/Acl');
|
||||
if (!in_array($class, array('DbAcl', 'DB_ACL')) && !is_subclass_of($class, 'DbAcl')) {
|
||||
$out = "--------------------------------------------------\n";
|
||||
$out .= __d('cake_console', 'Error: Your current CakePHP configuration is set to an ACL implementation other than DB.') . "\n";
|
||||
$out .= __d('cake_console', 'Please change your core config to reflect your decision to use DbAcl before attempting to use this script') . "\n";
|
||||
$out .= "--------------------------------------------------\n";
|
||||
$out .= __d('cake_console', 'Current ACL Classname: %s', $class) . "\n";
|
||||
$out .= "--------------------------------------------------\n";
|
||||
$this->err($out);
|
||||
return $this->_stop();
|
||||
}
|
||||
|
||||
if ($this->command) {
|
||||
if (!config('database')) {
|
||||
$this->out(__d('cake_console', 'Your database configuration was not found. Take a moment to create one.'));
|
||||
$this->args = null;
|
||||
return $this->DbConfig->execute();
|
||||
}
|
||||
require_once APP . 'Config' . DS . 'database.php';
|
||||
|
||||
if (!in_array($this->command, array('initdb'))) {
|
||||
$collection = new ComponentCollection();
|
||||
$this->Acl = new AclComponent($collection);
|
||||
$controller = new Controller();
|
||||
$this->Acl->startup($controller);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override main() for help message hook
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function main() {
|
||||
$this->out($this->OptionParser->help());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ARO/ACO node
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function create() {
|
||||
extract($this->_dataVars());
|
||||
|
||||
$class = ucfirst($this->args[0]);
|
||||
$parent = $this->parseIdentifier($this->args[1]);
|
||||
|
||||
if (!empty($parent) && $parent !== '/' && $parent !== 'root') {
|
||||
$parent = $this->_getNodeId($class, $parent);
|
||||
} else {
|
||||
$parent = null;
|
||||
}
|
||||
|
||||
$data = $this->parseIdentifier($this->args[2]);
|
||||
if (is_string($data) && $data !== '/') {
|
||||
$data = array('alias' => $data);
|
||||
} elseif (is_string($data)) {
|
||||
$this->error(__d('cake_console', '/ can not be used as an alias!') . __d('cake_console', " / is the root, please supply a sub alias"));
|
||||
}
|
||||
|
||||
$data['parent_id'] = $parent;
|
||||
$this->Acl->{$class}->create();
|
||||
if ($this->Acl->{$class}->save($data)) {
|
||||
$this->out(__d('cake_console', "<success>New %s</success> '%s' created.", $class, $this->args[2]), 2);
|
||||
} else {
|
||||
$this->err(__d('cake_console', "There was a problem creating a new %s '%s'.", $class, $this->args[2]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an ARO/ACO node. Note there may be (as a result of poor configuration)
|
||||
* multiple records with the same logical identifier. All are deleted.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete() {
|
||||
extract($this->_dataVars());
|
||||
|
||||
$identifier = $this->parseIdentifier($this->args[1]);
|
||||
if (is_string($identifier)) {
|
||||
$identifier = array('alias' => $identifier);
|
||||
}
|
||||
|
||||
if ($this->Acl->{$class}->find('all', array('conditions' => $identifier))) {
|
||||
if (!$this->Acl->{$class}->deleteAll($identifier)) {
|
||||
$this->error(__d('cake_console', 'Node Not Deleted. ') . __d('cake_console', 'There was an error deleting the %s.', $class) . "\n");
|
||||
}
|
||||
$this->out(__d('cake_console', '<success>%s deleted.</success>', $class), 2);
|
||||
} else {
|
||||
$this->error(__d('cake_console', 'Node Not Deleted. ') . __d('cake_console', 'There was an error deleting the %s. Node does not exist.', $class) . "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set parent for an ARO/ACO node.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setParent() {
|
||||
extract($this->_dataVars());
|
||||
$target = $this->parseIdentifier($this->args[1]);
|
||||
$parent = $this->parseIdentifier($this->args[2]);
|
||||
|
||||
$data = array(
|
||||
$class => array(
|
||||
'id' => $this->_getNodeId($class, $target),
|
||||
'parent_id' => $this->_getNodeId($class, $parent)
|
||||
)
|
||||
);
|
||||
$this->Acl->{$class}->create();
|
||||
if (!$this->Acl->{$class}->save($data)) {
|
||||
$this->out(__d('cake_console', 'Error in setting new parent. Please make sure the parent node exists, and is not a descendant of the node specified.'));
|
||||
} else {
|
||||
$this->out(__d('cake_console', 'Node parent set to %s', $this->args[2]) . "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get path to specified ARO/ACO node.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getPath() {
|
||||
extract($this->_dataVars());
|
||||
$identifier = $this->parseIdentifier($this->args[1]);
|
||||
|
||||
$id = $this->_getNodeId($class, $identifier);
|
||||
$nodes = $this->Acl->{$class}->getPath($id);
|
||||
|
||||
if (empty($nodes)) {
|
||||
$this->error(
|
||||
__d('cake_console', "Supplied Node '%s' not found", $this->args[1]),
|
||||
__d('cake_console', 'No tree returned.')
|
||||
);
|
||||
}
|
||||
$this->out(__d('cake_console', 'Path:'));
|
||||
$this->hr();
|
||||
for ($i = 0, $len = count($nodes); $i < $len; $i++) {
|
||||
$this->_outputNode($class, $nodes[$i], $i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a single node, Either using the alias or Model.key
|
||||
*
|
||||
* @param string $class Class name that is being used.
|
||||
* @param array $node Array of node information.
|
||||
* @param int $indent indent level.
|
||||
* @return void
|
||||
*/
|
||||
protected function _outputNode($class, $node, $indent) {
|
||||
$indent = str_repeat(' ', $indent);
|
||||
$data = $node[$class];
|
||||
if ($data['alias']) {
|
||||
$this->out($indent . "[" . $data['id'] . "] " . $data['alias']);
|
||||
} else {
|
||||
$this->out($indent . "[" . $data['id'] . "] " . $data['model'] . '.' . $data['foreign_key']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check permission for a given ARO to a given ACO.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function check() {
|
||||
extract($this->_getParams());
|
||||
|
||||
if ($this->Acl->check($aro, $aco, $action)) {
|
||||
$this->out(__d('cake_console', '%s is <success>allowed</success>.', $aroName));
|
||||
} else {
|
||||
$this->out(__d('cake_console', '%s is <error>not allowed</error>.', $aroName));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Grant permission for a given ARO to a given ACO.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function grant() {
|
||||
extract($this->_getParams());
|
||||
|
||||
if ($this->Acl->allow($aro, $aco, $action)) {
|
||||
$this->out(__d('cake_console', 'Permission <success>granted</success>.'));
|
||||
} else {
|
||||
$this->out(__d('cake_console', 'Permission was <error>not granted</error>.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deny access for an ARO to an ACO.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deny() {
|
||||
extract($this->_getParams());
|
||||
|
||||
if ($this->Acl->deny($aro, $aco, $action)) {
|
||||
$this->out(__d('cake_console', 'Permission denied.'));
|
||||
} else {
|
||||
$this->out(__d('cake_console', 'Permission was not denied.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an ARO to inherit permission to an ACO.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function inherit() {
|
||||
extract($this->_getParams());
|
||||
|
||||
if ($this->Acl->inherit($aro, $aco, $action)) {
|
||||
$this->out(__d('cake_console', 'Permission inherited.'));
|
||||
} else {
|
||||
$this->out(__d('cake_console', 'Permission was not inherited.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a specific ARO/ACO node.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function view() {
|
||||
extract($this->_dataVars());
|
||||
|
||||
if (isset($this->args[1])) {
|
||||
$identity = $this->parseIdentifier($this->args[1]);
|
||||
|
||||
$topNode = $this->Acl->{$class}->find('first', array(
|
||||
'conditions' => array($class . '.id' => $this->_getNodeId($class, $identity))
|
||||
));
|
||||
|
||||
$nodes = $this->Acl->{$class}->find('all', array(
|
||||
'conditions' => array(
|
||||
$class . '.lft >=' => $topNode[$class]['lft'],
|
||||
$class . '.lft <=' => $topNode[$class]['rght']
|
||||
),
|
||||
'order' => $class . '.lft ASC'
|
||||
));
|
||||
} else {
|
||||
$nodes = $this->Acl->{$class}->find('all', array('order' => $class . '.lft ASC'));
|
||||
}
|
||||
|
||||
if (empty($nodes)) {
|
||||
if (isset($this->args[1])) {
|
||||
$this->error(__d('cake_console', '%s not found', $this->args[1]), __d('cake_console', 'No tree returned.'));
|
||||
} elseif (isset($this->args[0])) {
|
||||
$this->error(__d('cake_console', '%s not found', $this->args[0]), __d('cake_console', 'No tree returned.'));
|
||||
}
|
||||
}
|
||||
$this->out($class . ' tree:');
|
||||
$this->hr();
|
||||
|
||||
$stack = array();
|
||||
$last = null;
|
||||
|
||||
foreach ($nodes as $n) {
|
||||
$stack[] = $n;
|
||||
if (!empty($last)) {
|
||||
$end = end($stack);
|
||||
if ($end[$class]['rght'] > $last) {
|
||||
foreach ($stack as $k => $v) {
|
||||
$end = end($stack);
|
||||
if ($v[$class]['rght'] < $end[$class]['rght']) {
|
||||
unset($stack[$k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$last = $n[$class]['rght'];
|
||||
$count = count($stack);
|
||||
|
||||
$this->_outputNode($class, $n, $count);
|
||||
}
|
||||
$this->hr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize ACL database.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function initdb() {
|
||||
return $this->dispatchShell('schema create DbAcl');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the option parser instance and configures it.
|
||||
*
|
||||
* @return ConsoleOptionParser
|
||||
*/
|
||||
public function getOptionParser() {
|
||||
$parser = parent::getOptionParser();
|
||||
|
||||
$type = array(
|
||||
'choices' => array('aro', 'aco'),
|
||||
'required' => true,
|
||||
'help' => __d('cake_console', 'Type of node to create.')
|
||||
);
|
||||
|
||||
$parser->description(
|
||||
__d('cake_console', 'A console tool for managing the DbAcl')
|
||||
)->addSubcommand('create', array(
|
||||
'help' => __d('cake_console', 'Create a new ACL node'),
|
||||
'parser' => array(
|
||||
'description' => __d('cake_console', 'Creates a new ACL object <node> under the parent'),
|
||||
'epilog' => __d('cake_console', 'You can use `root` as the parent when creating nodes to create top level nodes.'),
|
||||
'arguments' => array(
|
||||
'type' => $type,
|
||||
'parent' => array(
|
||||
'help' => __d('cake_console', 'The node selector for the parent.'),
|
||||
'required' => true
|
||||
),
|
||||
'alias' => array(
|
||||
'help' => __d('cake_console', 'The alias to use for the newly created node.'),
|
||||
'required' => true
|
||||
)
|
||||
)
|
||||
)
|
||||
))->addSubcommand('delete', array(
|
||||
'help' => __d('cake_console', 'Deletes the ACL object with the given <node> reference'),
|
||||
'parser' => array(
|
||||
'description' => __d('cake_console', 'Delete an ACL node.'),
|
||||
'arguments' => array(
|
||||
'type' => $type,
|
||||
'node' => array(
|
||||
'help' => __d('cake_console', 'The node identifier to delete.'),
|
||||
'required' => true,
|
||||
)
|
||||
)
|
||||
)
|
||||
))->addSubcommand('setparent', array(
|
||||
'help' => __d('cake_console', 'Moves the ACL node under a new parent.'),
|
||||
'parser' => array(
|
||||
'description' => __d('cake_console', 'Moves the ACL object specified by <node> beneath <parent>'),
|
||||
'arguments' => array(
|
||||
'type' => $type,
|
||||
'node' => array(
|
||||
'help' => __d('cake_console', 'The node to move'),
|
||||
'required' => true,
|
||||
),
|
||||
'parent' => array(
|
||||
'help' => __d('cake_console', 'The new parent for <node>.'),
|
||||
'required' => true
|
||||
)
|
||||
)
|
||||
)
|
||||
))->addSubcommand('getpath', array(
|
||||
'help' => __d('cake_console', 'Print out the path to an ACL node.'),
|
||||
'parser' => array(
|
||||
'description' => array(
|
||||
__d('cake_console', "Returns the path to the ACL object specified by <node>."),
|
||||
__d('cake_console', "This command is useful in determining the inheritance of permissions for a certain object in the tree.")
|
||||
),
|
||||
'arguments' => array(
|
||||
'type' => $type,
|
||||
'node' => array(
|
||||
'help' => __d('cake_console', 'The node to get the path of'),
|
||||
'required' => true,
|
||||
)
|
||||
)
|
||||
)
|
||||
))->addSubcommand('check', array(
|
||||
'help' => __d('cake_console', 'Check the permissions between an ACO and ARO.'),
|
||||
'parser' => array(
|
||||
'description' => array(
|
||||
__d('cake_console', 'Use this command to check ACL permissions.')
|
||||
),
|
||||
'arguments' => array(
|
||||
'aro' => array('help' => __d('cake_console', 'ARO to check.'), 'required' => true),
|
||||
'aco' => array('help' => __d('cake_console', 'ACO to check.'), 'required' => true),
|
||||
'action' => array('help' => __d('cake_console', 'Action to check'), 'default' => 'all')
|
||||
)
|
||||
)
|
||||
))->addSubcommand('grant', array(
|
||||
'help' => __d('cake_console', 'Grant an ARO permissions to an ACO.'),
|
||||
'parser' => array(
|
||||
'description' => array(
|
||||
__d('cake_console', 'Use this command to grant ACL permissions. Once executed, the ARO specified (and its children, if any) will have ALLOW access to the specified ACO action (and the ACO\'s children, if any).')
|
||||
),
|
||||
'arguments' => array(
|
||||
'aro' => array('help' => __d('cake_console', 'ARO to grant permission to.'), 'required' => true),
|
||||
'aco' => array('help' => __d('cake_console', 'ACO to grant access to.'), 'required' => true),
|
||||
'action' => array('help' => __d('cake_console', 'Action to grant'), 'default' => 'all')
|
||||
)
|
||||
)
|
||||
))->addSubcommand('deny', array(
|
||||
'help' => __d('cake_console', 'Deny an ARO permissions to an ACO.'),
|
||||
'parser' => array(
|
||||
'description' => array(
|
||||
__d('cake_console', 'Use this command to deny ACL permissions. Once executed, the ARO specified (and its children, if any) will have DENY access to the specified ACO action (and the ACO\'s children, if any).')
|
||||
),
|
||||
'arguments' => array(
|
||||
'aro' => array('help' => __d('cake_console', 'ARO to deny.'), 'required' => true),
|
||||
'aco' => array('help' => __d('cake_console', 'ACO to deny.'), 'required' => true),
|
||||
'action' => array('help' => __d('cake_console', 'Action to deny'), 'default' => 'all')
|
||||
)
|
||||
)
|
||||
))->addSubcommand('inherit', array(
|
||||
'help' => __d('cake_console', 'Inherit an ARO\'s parent permissions.'),
|
||||
'parser' => array(
|
||||
'description' => array(
|
||||
__d('cake_console', "Use this command to force a child ARO object to inherit its permissions settings from its parent.")
|
||||
),
|
||||
'arguments' => array(
|
||||
'aro' => array('help' => __d('cake_console', 'ARO to have permissions inherit.'), 'required' => true),
|
||||
'aco' => array('help' => __d('cake_console', 'ACO to inherit permissions on.'), 'required' => true),
|
||||
'action' => array('help' => __d('cake_console', 'Action to inherit'), 'default' => 'all')
|
||||
)
|
||||
)
|
||||
))->addSubcommand('view', array(
|
||||
'help' => __d('cake_console', 'View a tree or a single node\'s subtree.'),
|
||||
'parser' => array(
|
||||
'description' => array(
|
||||
__d('cake_console', "The view command will return the ARO or ACO tree."),
|
||||
__d('cake_console', "The optional node parameter allows you to return"),
|
||||
__d('cake_console', "only a portion of the requested tree.")
|
||||
),
|
||||
'arguments' => array(
|
||||
'type' => $type,
|
||||
'node' => array('help' => __d('cake_console', 'The optional node to view the subtree of.'))
|
||||
)
|
||||
)
|
||||
))->addSubcommand('initdb', array(
|
||||
'help' => __d('cake_console', 'Initialize the DbAcl tables. Uses this command : cake schema create DbAcl')
|
||||
))->epilog(array(
|
||||
'Node and parent arguments can be in one of the following formats:',
|
||||
'',
|
||||
' - <model>.<id> - The node will be bound to a specific record of the given model.',
|
||||
'',
|
||||
' - <alias> - The node will be given a string alias (or path, in the case of <parent>)',
|
||||
" i.e. 'John'. When used with <parent>, this takes the form of an alias path,",
|
||||
" i.e. <group>/<subgroup>/<parent>.",
|
||||
'',
|
||||
"To add a node at the root level, enter 'root' or '/' as the <parent> parameter."
|
||||
));
|
||||
|
||||
return $parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that given node exists
|
||||
*
|
||||
* @return bool Success
|
||||
*/
|
||||
public function nodeExists() {
|
||||
if (!isset($this->args[0]) || !isset($this->args[1])) {
|
||||
return false;
|
||||
}
|
||||
$dataVars = $this->_dataVars($this->args[0]);
|
||||
extract($dataVars);
|
||||
$key = is_numeric($this->args[1]) ? $dataVars['secondary_id'] : 'alias';
|
||||
$conditions = array($class . '.' . $key => $this->args[1]);
|
||||
$possibility = $this->Acl->{$class}->find('all', compact('conditions'));
|
||||
if (empty($possibility)) {
|
||||
$this->error(__d('cake_console', '%s not found', $this->args[1]), __d('cake_console', 'No tree returned.'));
|
||||
}
|
||||
return $possibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an identifier into Model.foreignKey or an alias.
|
||||
* Takes an identifier determines its type and returns the result as used by other methods.
|
||||
*
|
||||
* @param string $identifier Identifier to parse
|
||||
* @return mixed a string for aliases, and an array for model.foreignKey
|
||||
*/
|
||||
public function parseIdentifier($identifier) {
|
||||
if (preg_match('/^([\w]+)\.(.*)$/', $identifier, $matches)) {
|
||||
return array(
|
||||
'model' => $matches[1],
|
||||
'foreign_key' => $matches[2],
|
||||
);
|
||||
}
|
||||
return $identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the node for a given identifier. $identifier can either be a string alias
|
||||
* or an array of properties to use in AcoNode::node()
|
||||
*
|
||||
* @param string $class Class type you want (Aro/Aco)
|
||||
* @param string|array $identifier A mixed identifier for finding the node.
|
||||
* @return int Integer of NodeId. Will trigger an error if nothing is found.
|
||||
*/
|
||||
protected function _getNodeId($class, $identifier) {
|
||||
$node = $this->Acl->{$class}->node($identifier);
|
||||
if (empty($node)) {
|
||||
if (is_array($identifier)) {
|
||||
$identifier = var_export($identifier, true);
|
||||
}
|
||||
$this->error(__d('cake_console', 'Could not find node using reference "%s"', $identifier));
|
||||
return;
|
||||
}
|
||||
return Hash::get($node, "0.{$class}.id");
|
||||
}
|
||||
|
||||
/**
|
||||
* get params for standard Acl methods
|
||||
*
|
||||
* @return array aro, aco, action
|
||||
*/
|
||||
protected function _getParams() {
|
||||
$aro = is_numeric($this->args[0]) ? intval($this->args[0]) : $this->args[0];
|
||||
$aco = is_numeric($this->args[1]) ? intval($this->args[1]) : $this->args[1];
|
||||
$aroName = $aro;
|
||||
$acoName = $aco;
|
||||
|
||||
if (is_string($aro)) {
|
||||
$aro = $this->parseIdentifier($aro);
|
||||
}
|
||||
if (is_string($aco)) {
|
||||
$aco = $this->parseIdentifier($aco);
|
||||
}
|
||||
$action = '*';
|
||||
if (isset($this->args[2]) && !in_array($this->args[2], array('', 'all'))) {
|
||||
$action = $this->args[2];
|
||||
}
|
||||
return compact('aro', 'aco', 'action', 'aroName', 'acoName');
|
||||
}
|
||||
|
||||
/**
|
||||
* Build data parameters based on node type
|
||||
*
|
||||
* @param string $type Node type (ARO/ACO)
|
||||
* @return array Variables
|
||||
*/
|
||||
protected function _dataVars($type = null) {
|
||||
if (!$type) {
|
||||
$type = $this->args[0];
|
||||
}
|
||||
$vars = array();
|
||||
$class = ucwords($type);
|
||||
$vars['secondary_id'] = (strtolower($class) === 'aro') ? 'foreign_key' : 'object_id';
|
||||
$vars['data_name'] = $type;
|
||||
$vars['table_name'] = $type . 's';
|
||||
$vars['class'] = $class;
|
||||
return $vars;
|
||||
}
|
||||
|
||||
}
|
||||
242
lib/Cake/Console/Command/ApiShell.php
Normal file
242
lib/Cake/Console/Command/ApiShell.php
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
<?php
|
||||
/**
|
||||
* API shell to get CakePHP core method signatures.
|
||||
*
|
||||
* Implementation of a Cake Shell to show CakePHP core method signatures.
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 1.2.0.5012
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
App::uses('File', 'Utility');
|
||||
|
||||
/**
|
||||
* API shell to show method signatures of CakePHP core classes.
|
||||
*
|
||||
* Implementation of a Cake Shell to show CakePHP core method signatures.
|
||||
*
|
||||
* @package Cake.Console.Command
|
||||
*/
|
||||
class ApiShell extends AppShell {
|
||||
|
||||
/**
|
||||
* Map between short name for paths and real paths.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $paths = array();
|
||||
|
||||
/**
|
||||
* Override initialize of the Shell
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function initialize() {
|
||||
$this->paths = array_merge($this->paths, array(
|
||||
'behavior' => CAKE . 'Model' . DS . 'Behavior' . DS,
|
||||
'cache' => CAKE . 'Cache' . DS,
|
||||
'controller' => CAKE . 'Controller' . DS,
|
||||
'component' => CAKE . 'Controller' . DS . 'Component' . DS,
|
||||
'helper' => CAKE . 'View' . DS . 'Helper' . DS,
|
||||
'model' => CAKE . 'Model' . DS,
|
||||
'view' => CAKE . 'View' . DS,
|
||||
'core' => CAKE
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Override main() to handle action
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function main() {
|
||||
if (empty($this->args)) {
|
||||
return $this->out($this->OptionParser->help());
|
||||
}
|
||||
|
||||
$type = strtolower($this->args[0]);
|
||||
|
||||
if (isset($this->paths[$type])) {
|
||||
$path = $this->paths[$type];
|
||||
} else {
|
||||
$path = $this->paths['core'];
|
||||
}
|
||||
|
||||
$count = count($this->args);
|
||||
if ($count > 1) {
|
||||
$file = Inflector::underscore($this->args[1]);
|
||||
$class = Inflector::camelize($this->args[1]);
|
||||
} elseif ($count) {
|
||||
$file = $type;
|
||||
$class = Inflector::camelize($type);
|
||||
}
|
||||
$objects = App::objects('class', $path);
|
||||
if (in_array($class, $objects)) {
|
||||
if (in_array($type, array('behavior', 'component', 'helper')) && $type !== $file) {
|
||||
if (!preg_match('/' . Inflector::camelize($type) . '$/', $class)) {
|
||||
$class .= Inflector::camelize($type);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
$this->error(__d('cake_console', '%s not found', $class));
|
||||
}
|
||||
|
||||
$parsed = $this->_parseClass($path . $class . '.php', $class);
|
||||
|
||||
if (!empty($parsed)) {
|
||||
if (isset($this->params['method'])) {
|
||||
if (!isset($parsed[$this->params['method']])) {
|
||||
$this->err(__d('cake_console', '%s::%s() could not be found', $class, $this->params['method']));
|
||||
return $this->_stop();
|
||||
}
|
||||
$method = $parsed[$this->params['method']];
|
||||
$this->out($class . '::' . $method['method'] . $method['parameters']);
|
||||
$this->hr();
|
||||
$this->out($method['comment'], true);
|
||||
} else {
|
||||
$this->out(ucwords($class));
|
||||
$this->hr();
|
||||
$i = 0;
|
||||
foreach ($parsed as $method) {
|
||||
$list[] = ++$i . ". " . $method['method'] . $method['parameters'];
|
||||
}
|
||||
$this->out($list);
|
||||
|
||||
$methods = array_keys($parsed);
|
||||
while ($number = strtolower($this->in(__d('cake_console', 'Select a number to see the more information about a specific method. q to quit. l to list.'), null, 'q'))) {
|
||||
if ($number === 'q') {
|
||||
$this->out(__d('cake_console', 'Done'));
|
||||
return $this->_stop();
|
||||
}
|
||||
|
||||
if ($number === 'l') {
|
||||
$this->out($list);
|
||||
}
|
||||
|
||||
if (isset($methods[--$number])) {
|
||||
$method = $parsed[$methods[$number]];
|
||||
$this->hr();
|
||||
$this->out($class . '::' . $method['method'] . $method['parameters']);
|
||||
$this->hr();
|
||||
$this->out($method['comment'], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the option parser instance and configures it.
|
||||
*
|
||||
* @return ConsoleOptionParser
|
||||
*/
|
||||
public function getOptionParser() {
|
||||
$parser = parent::getOptionParser();
|
||||
|
||||
$parser->description(
|
||||
__d('cake_console', 'Lookup doc block comments for classes in CakePHP.')
|
||||
)->addArgument('type', array(
|
||||
'help' => __d('cake_console', 'Either a full path or type of class (model, behavior, controller, component, view, helper)')
|
||||
))->addArgument('className', array(
|
||||
'help' => __d('cake_console', 'A CakePHP core class name (e.g: Component, HtmlHelper).')
|
||||
))->addOption('method', array(
|
||||
'short' => 'm',
|
||||
'help' => __d('cake_console', 'The specific method you want help on.')
|
||||
));
|
||||
|
||||
return $parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show help for this shell.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function help() {
|
||||
$head = "Usage: cake api [<type>] <className> [-m <method>]\n";
|
||||
$head .= "-----------------------------------------------\n";
|
||||
$head .= "Parameters:\n\n";
|
||||
|
||||
$commands = array(
|
||||
'path' => "\t<type>\n" .
|
||||
"\t\tEither a full path or type of class (model, behavior, controller, component, view, helper).\n" .
|
||||
"\t\tAvailable values:\n\n" .
|
||||
"\t\tbehavior\tLook for class in CakePHP behavior path\n" .
|
||||
"\t\tcache\tLook for class in CakePHP cache path\n" .
|
||||
"\t\tcontroller\tLook for class in CakePHP controller path\n" .
|
||||
"\t\tcomponent\tLook for class in CakePHP component path\n" .
|
||||
"\t\thelper\tLook for class in CakePHP helper path\n" .
|
||||
"\t\tmodel\tLook for class in CakePHP model path\n" .
|
||||
"\t\tview\tLook for class in CakePHP view path\n",
|
||||
'className' => "\t<className>\n" .
|
||||
"\t\tA CakePHP core class name (e.g: Component, HtmlHelper).\n"
|
||||
);
|
||||
|
||||
$this->out($head);
|
||||
if (!isset($this->args[1])) {
|
||||
foreach ($commands as $cmd) {
|
||||
$this->out("{$cmd}\n\n");
|
||||
}
|
||||
} elseif (isset($commands[strtolower($this->args[1])])) {
|
||||
$this->out($commands[strtolower($this->args[1])] . "\n\n");
|
||||
} else {
|
||||
$this->out(__d('cake_console', 'Command %s not found', $this->args[1]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a given class (located on given file) and get public methods and their
|
||||
* signatures.
|
||||
*
|
||||
* @param string $path File path
|
||||
* @param string $class Class name
|
||||
* @return array Methods and signatures indexed by method name
|
||||
*/
|
||||
protected function _parseClass($path, $class) {
|
||||
$parsed = array();
|
||||
|
||||
if (!class_exists($class)) {
|
||||
if (!include_once $path) {
|
||||
$this->err(__d('cake_console', '%s could not be found', $path));
|
||||
}
|
||||
}
|
||||
|
||||
$reflection = new ReflectionClass($class);
|
||||
|
||||
foreach ($reflection->getMethods() as $method) {
|
||||
if (!$method->isPublic() || strpos($method->getName(), '_') === 0) {
|
||||
continue;
|
||||
}
|
||||
if ($method->getDeclaringClass()->getName() != $class) {
|
||||
continue;
|
||||
}
|
||||
$args = array();
|
||||
foreach ($method->getParameters() as $param) {
|
||||
$paramString = '$' . $param->getName();
|
||||
if ($param->isDefaultValueAvailable()) {
|
||||
$paramString .= ' = ' . str_replace("\n", '', var_export($param->getDefaultValue(), true));
|
||||
}
|
||||
$args[] = $paramString;
|
||||
}
|
||||
$parsed[$method->getName()] = array(
|
||||
'comment' => str_replace(array('/*', '*/', '*'), '', $method->getDocComment()),
|
||||
'method' => $method->getName(),
|
||||
'parameters' => '(' . implode(', ', $args) . ')'
|
||||
);
|
||||
}
|
||||
ksort($parsed);
|
||||
return $parsed;
|
||||
}
|
||||
|
||||
}
|
||||
30
lib/Cake/Console/Command/AppShell.php
Normal file
30
lib/Cake/Console/Command/AppShell.php
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
/**
|
||||
* AppShell file
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 2.0
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('Shell', 'Console');
|
||||
|
||||
/**
|
||||
* Application Shell
|
||||
*
|
||||
* Add your application-wide methods in the class below, your shells
|
||||
* will inherit them.
|
||||
*
|
||||
* @package app.Console.Command
|
||||
*/
|
||||
class AppShell extends Shell {
|
||||
|
||||
}
|
||||
255
lib/Cake/Console/Command/BakeShell.php
Normal file
255
lib/Cake/Console/Command/BakeShell.php
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
<?php
|
||||
/**
|
||||
* Command-line code generation utility to automate programmer chores.
|
||||
*
|
||||
* Bake is CakePHP's code generation script, which can help you kickstart
|
||||
* application development by writing fully functional skeleton controllers,
|
||||
* models, and views. Going further, Bake can also write Unit Tests for you.
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 1.2.0.5012
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
App::uses('Model', 'Model');
|
||||
|
||||
/**
|
||||
* Command-line code generation utility to automate programmer chores.
|
||||
*
|
||||
* Bake is CakePHP's code generation script, which can help you kickstart
|
||||
* application development by writing fully functional skeleton controllers,
|
||||
* models, and views. Going further, Bake can also write Unit Tests for you.
|
||||
*
|
||||
* @package Cake.Console.Command
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells/code-generation-with-bake.html
|
||||
*/
|
||||
class BakeShell extends AppShell {
|
||||
|
||||
/**
|
||||
* Contains tasks to load and instantiate
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $tasks = array('Project', 'DbConfig', 'Model', 'Controller', 'View', 'Plugin', 'Fixture', 'Test');
|
||||
|
||||
/**
|
||||
* The connection being used.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $connection = 'default';
|
||||
|
||||
/**
|
||||
* Assign $this->connection to the active task if a connection param is set.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function startup() {
|
||||
parent::startup();
|
||||
Configure::write('debug', 2);
|
||||
Configure::write('Cache.disable', 1);
|
||||
|
||||
$task = Inflector::classify($this->command);
|
||||
if (isset($this->{$task}) && !in_array($task, array('Project', 'DbConfig'))) {
|
||||
if (isset($this->params['connection'])) {
|
||||
$this->{$task}->connection = $this->params['connection'];
|
||||
}
|
||||
}
|
||||
if (isset($this->params['connection'])) {
|
||||
$this->connection = $this->params['connection'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override main() to handle action
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function main() {
|
||||
if (!is_dir($this->DbConfig->path)) {
|
||||
$path = $this->Project->execute();
|
||||
if (!empty($path)) {
|
||||
$this->DbConfig->path = $path . 'Config' . DS;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!config('database')) {
|
||||
$this->out(__d('cake_console', 'Your database configuration was not found. Take a moment to create one.'));
|
||||
$this->args = null;
|
||||
return $this->DbConfig->execute();
|
||||
}
|
||||
$this->out(__d('cake_console', 'Interactive Bake Shell'));
|
||||
$this->hr();
|
||||
$this->out(__d('cake_console', '[D]atabase Configuration'));
|
||||
$this->out(__d('cake_console', '[M]odel'));
|
||||
$this->out(__d('cake_console', '[V]iew'));
|
||||
$this->out(__d('cake_console', '[C]ontroller'));
|
||||
$this->out(__d('cake_console', '[P]roject'));
|
||||
$this->out(__d('cake_console', '[F]ixture'));
|
||||
$this->out(__d('cake_console', '[T]est case'));
|
||||
$this->out(__d('cake_console', '[Q]uit'));
|
||||
|
||||
$classToBake = strtoupper($this->in(__d('cake_console', 'What would you like to Bake?'), array('D', 'M', 'V', 'C', 'P', 'F', 'T', 'Q')));
|
||||
switch ($classToBake) {
|
||||
case 'D':
|
||||
$this->DbConfig->execute();
|
||||
break;
|
||||
case 'M':
|
||||
$this->Model->execute();
|
||||
break;
|
||||
case 'V':
|
||||
$this->View->execute();
|
||||
break;
|
||||
case 'C':
|
||||
$this->Controller->execute();
|
||||
break;
|
||||
case 'P':
|
||||
$this->Project->execute();
|
||||
break;
|
||||
case 'F':
|
||||
$this->Fixture->execute();
|
||||
break;
|
||||
case 'T':
|
||||
$this->Test->execute();
|
||||
break;
|
||||
case 'Q':
|
||||
return $this->_stop();
|
||||
default:
|
||||
$this->out(__d('cake_console', 'You have made an invalid selection. Please choose a type of class to Bake by entering D, M, V, F, T, or C.'));
|
||||
}
|
||||
$this->hr();
|
||||
$this->main();
|
||||
}
|
||||
|
||||
/**
|
||||
* Quickly bake the MVC
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function all() {
|
||||
$this->out('Bake All');
|
||||
$this->hr();
|
||||
|
||||
if (!isset($this->params['connection']) && empty($this->connection)) {
|
||||
$this->connection = $this->DbConfig->getConfig();
|
||||
}
|
||||
|
||||
if (empty($this->args)) {
|
||||
$this->Model->interactive = true;
|
||||
$name = $this->Model->getName($this->connection);
|
||||
}
|
||||
|
||||
foreach (array('Model', 'Controller', 'View') as $task) {
|
||||
$this->{$task}->connection = $this->connection;
|
||||
$this->{$task}->interactive = false;
|
||||
}
|
||||
|
||||
if (!empty($this->args[0])) {
|
||||
$name = $this->args[0];
|
||||
}
|
||||
|
||||
$modelExists = false;
|
||||
$model = $this->_modelName($name);
|
||||
|
||||
App::uses('AppModel', 'Model');
|
||||
App::uses($model, 'Model');
|
||||
if (class_exists($model)) {
|
||||
$object = new $model();
|
||||
$modelExists = true;
|
||||
} else {
|
||||
$object = new Model(array('name' => $name, 'ds' => $this->connection));
|
||||
}
|
||||
|
||||
$modelBaked = $this->Model->bake($object, false);
|
||||
|
||||
if ($modelBaked && $modelExists === false) {
|
||||
if ($this->_checkUnitTest()) {
|
||||
$this->Model->bakeFixture($model);
|
||||
$this->Model->bakeTest($model);
|
||||
}
|
||||
$modelExists = true;
|
||||
}
|
||||
|
||||
if ($modelExists === true) {
|
||||
$controller = $this->_controllerName($name);
|
||||
if ($this->Controller->bake($controller, $this->Controller->bakeActions($controller))) {
|
||||
if ($this->_checkUnitTest()) {
|
||||
$this->Controller->bakeTest($controller);
|
||||
}
|
||||
}
|
||||
App::uses($controller . 'Controller', 'Controller');
|
||||
if (class_exists($controller . 'Controller')) {
|
||||
$this->View->args = array($name);
|
||||
$this->View->execute();
|
||||
}
|
||||
$this->out('', 1, Shell::QUIET);
|
||||
$this->out(__d('cake_console', '<success>Bake All complete</success>'), 1, Shell::QUIET);
|
||||
array_shift($this->args);
|
||||
} else {
|
||||
$this->error(__d('cake_console', 'Bake All could not continue without a valid model'));
|
||||
}
|
||||
return $this->_stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the option parser instance and configures it.
|
||||
*
|
||||
* @return ConsoleOptionParser
|
||||
*/
|
||||
public function getOptionParser() {
|
||||
$parser = parent::getOptionParser();
|
||||
|
||||
$parser->description(
|
||||
__d('cake_console', 'The Bake script generates controllers, views and models for your application.' .
|
||||
' If run with no command line arguments, Bake guides the user through the class creation process.' .
|
||||
' You can customize the generation process by telling Bake where different parts of your application are using command line arguments.')
|
||||
)->addSubcommand('all', array(
|
||||
'help' => __d('cake_console', 'Bake a complete MVC. optional <name> of a Model')
|
||||
))->addSubcommand('project', array(
|
||||
'help' => __d('cake_console', 'Bake a new app folder in the path supplied or in current directory if no path is specified'),
|
||||
'parser' => $this->Project->getOptionParser()
|
||||
))->addSubcommand('plugin', array(
|
||||
'help' => __d('cake_console', 'Bake a new plugin folder in the path supplied or in current directory if no path is specified.'),
|
||||
'parser' => $this->Plugin->getOptionParser()
|
||||
))->addSubcommand('db_config', array(
|
||||
'help' => __d('cake_console', 'Bake a database.php file in config directory.'),
|
||||
'parser' => $this->DbConfig->getOptionParser()
|
||||
))->addSubcommand('model', array(
|
||||
'help' => __d('cake_console', 'Bake a model.'),
|
||||
'parser' => $this->Model->getOptionParser()
|
||||
))->addSubcommand('view', array(
|
||||
'help' => __d('cake_console', 'Bake views for controllers.'),
|
||||
'parser' => $this->View->getOptionParser()
|
||||
))->addSubcommand('controller', array(
|
||||
'help' => __d('cake_console', 'Bake a controller.'),
|
||||
'parser' => $this->Controller->getOptionParser()
|
||||
))->addSubcommand('fixture', array(
|
||||
'help' => __d('cake_console', 'Bake a fixture.'),
|
||||
'parser' => $this->Fixture->getOptionParser()
|
||||
))->addSubcommand('test', array(
|
||||
'help' => __d('cake_console', 'Bake a unit test.'),
|
||||
'parser' => $this->Test->getOptionParser()
|
||||
))->addOption('connection', array(
|
||||
'help' => __d('cake_console', 'Database connection to use in conjunction with `bake all`.'),
|
||||
'short' => 'c',
|
||||
'default' => 'default'
|
||||
))->addOption('theme', array(
|
||||
'short' => 't',
|
||||
'help' => __d('cake_console', 'Theme to use when baking code.')
|
||||
));
|
||||
|
||||
return $parser;
|
||||
}
|
||||
|
||||
}
|
||||
143
lib/Cake/Console/Command/CommandListShell.php
Normal file
143
lib/Cake/Console/Command/CommandListShell.php
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP Project
|
||||
* @package Cake.Console.Command
|
||||
* @since CakePHP v 2.0
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
App::uses('Inflector', 'Utility');
|
||||
|
||||
/**
|
||||
* Shows a list of commands available from the console.
|
||||
*
|
||||
* @package Cake.Console.Command
|
||||
*/
|
||||
class CommandListShell extends AppShell {
|
||||
|
||||
/**
|
||||
* Contains tasks to load and instantiate
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $tasks = array('Command');
|
||||
|
||||
/**
|
||||
* startup
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function startup() {
|
||||
if (empty($this->params['xml'])) {
|
||||
parent::startup();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function Prints out the list of shells.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function main() {
|
||||
if (empty($this->params['xml'])) {
|
||||
$this->out(__d('cake_console', "<info>Current Paths:</info>"), 2);
|
||||
$this->out(" -app: " . APP_DIR);
|
||||
$this->out(" -working: " . rtrim(APP, DS));
|
||||
$this->out(" -root: " . rtrim(ROOT, DS));
|
||||
$this->out(" -core: " . rtrim(CORE_PATH, DS));
|
||||
$this->out("");
|
||||
$this->out(__d('cake_console', "<info>Changing Paths:</info>"), 2);
|
||||
$this->out(__d('cake_console', "Your working path should be the same as your application path. To change your path use the '-app' param."));
|
||||
$this->out(__d('cake_console', "Example: %s or %s", '-app relative/path/to/myapp', '-app /absolute/path/to/myapp'), 2);
|
||||
|
||||
$this->out(__d('cake_console', "<info>Available Shells:</info>"), 2);
|
||||
}
|
||||
|
||||
$shellList = $this->Command->getShellList();
|
||||
if (empty($shellList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($this->params['xml'])) {
|
||||
$this->_asText($shellList);
|
||||
} else {
|
||||
$this->_asXml($shellList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output text.
|
||||
*
|
||||
* @param array $shellList The shell list.
|
||||
* @return void
|
||||
*/
|
||||
protected function _asText($shellList) {
|
||||
foreach ($shellList as $plugin => $commands) {
|
||||
sort($commands);
|
||||
$this->out(sprintf('[<info>%s</info>] %s', $plugin, implode(', ', $commands)));
|
||||
$this->out();
|
||||
}
|
||||
|
||||
$this->out(__d('cake_console', "To run an app or core command, type <info>cake shell_name [args]</info>"));
|
||||
$this->out(__d('cake_console', "To run a plugin command, type <info>cake Plugin.shell_name [args]</info>"));
|
||||
$this->out(__d('cake_console', "To get help on a specific command, type <info>cake shell_name --help</info>"), 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output as XML
|
||||
*
|
||||
* @param array $shellList The shell list.
|
||||
* @return void
|
||||
*/
|
||||
protected function _asXml($shellList) {
|
||||
$plugins = CakePlugin::loaded();
|
||||
$shells = new SimpleXmlElement('<shells></shells>');
|
||||
foreach ($shellList as $plugin => $commands) {
|
||||
foreach ($commands as $command) {
|
||||
$callable = $command;
|
||||
if (in_array($plugin, $plugins)) {
|
||||
$callable = Inflector::camelize($plugin) . '.' . $command;
|
||||
}
|
||||
|
||||
$shell = $shells->addChild('shell');
|
||||
$shell->addAttribute('name', $command);
|
||||
$shell->addAttribute('call_as', $callable);
|
||||
$shell->addAttribute('provider', $plugin);
|
||||
$shell->addAttribute('help', $callable . ' -h');
|
||||
}
|
||||
}
|
||||
$this->stdout->outputAs(ConsoleOutput::RAW);
|
||||
$this->out($shells->saveXml());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the option parser instance and configures it.
|
||||
*
|
||||
* @return ConsoleOptionParser
|
||||
*/
|
||||
public function getOptionParser() {
|
||||
$parser = parent::getOptionParser();
|
||||
|
||||
$parser->description(
|
||||
__d('cake_console', 'Get the list of available shells for this CakePHP application.')
|
||||
)->addOption('sort', array(
|
||||
'help' => __d('cake_console', 'Does nothing (deprecated)'),
|
||||
'boolean' => true
|
||||
))->addOption('xml', array(
|
||||
'help' => __d('cake_console', 'Get the listing as XML.'),
|
||||
'boolean' => true
|
||||
));
|
||||
|
||||
return $parser;
|
||||
}
|
||||
|
||||
}
|
||||
155
lib/Cake/Console/Command/CompletionShell.php
Normal file
155
lib/Cake/Console/Command/CompletionShell.php
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP Project
|
||||
* @package Cake.Console.Command
|
||||
* @since CakePHP v 2.5
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
|
||||
/**
|
||||
* Provide command completion shells such as bash.
|
||||
*
|
||||
* @package Cake.Console.Command
|
||||
*/
|
||||
class CompletionShell extends AppShell {
|
||||
|
||||
/**
|
||||
* Contains tasks to load and instantiate
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $tasks = array('Command');
|
||||
|
||||
/**
|
||||
* Echo no header by overriding the startup method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function startup() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Not called by the autocomplete shell - this is for curious users
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function main() {
|
||||
return $this->out($this->getOptionParser()->help());
|
||||
}
|
||||
|
||||
/**
|
||||
* list commands
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function commands() {
|
||||
$options = $this->Command->commands();
|
||||
return $this->_output($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* list options for the named command
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function options() {
|
||||
$commandName = '';
|
||||
if (!empty($this->args[0])) {
|
||||
$commandName = $this->args[0];
|
||||
}
|
||||
$options = $this->Command->options($commandName);
|
||||
|
||||
return $this->_output($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* list subcommands for the named command
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function subCommands() {
|
||||
if (!$this->args) {
|
||||
return $this->_output();
|
||||
}
|
||||
|
||||
$options = $this->Command->subCommands($this->args[0]);
|
||||
return $this->_output($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Guess autocomplete from the whole argument string
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function fuzzy() {
|
||||
return $this->_output();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the option parser instance and configures it.
|
||||
*
|
||||
* @return ConsoleOptionParser
|
||||
*/
|
||||
public function getOptionParser() {
|
||||
$parser = parent::getOptionParser();
|
||||
|
||||
$parser->description(
|
||||
__d('cake_console', 'Used by shells like bash to autocomplete command name, options and arguments')
|
||||
)->addSubcommand('commands', array(
|
||||
'help' => __d('cake_console', 'Output a list of available commands'),
|
||||
'parser' => array(
|
||||
'description' => __d('cake_console', 'List all availables'),
|
||||
'arguments' => array(
|
||||
)
|
||||
)
|
||||
))->addSubcommand('subcommands', array(
|
||||
'help' => __d('cake_console', 'Output a list of available subcommands'),
|
||||
'parser' => array(
|
||||
'description' => __d('cake_console', 'List subcommands for a command'),
|
||||
'arguments' => array(
|
||||
'command' => array(
|
||||
'help' => __d('cake_console', 'The command name'),
|
||||
'required' => true,
|
||||
)
|
||||
)
|
||||
)
|
||||
))->addSubcommand('options', array(
|
||||
'help' => __d('cake_console', 'Output a list of available options'),
|
||||
'parser' => array(
|
||||
'description' => __d('cake_console', 'List options'),
|
||||
'arguments' => array(
|
||||
'command' => array(
|
||||
'help' => __d('cake_console', 'The command name'),
|
||||
'required' => false,
|
||||
)
|
||||
)
|
||||
)
|
||||
))->epilog(
|
||||
__d('cake_console', 'This command is not intended to be called manually')
|
||||
);
|
||||
|
||||
return $parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit results as a string, space delimited
|
||||
*
|
||||
* @param array $options The options to output
|
||||
* @return void
|
||||
*/
|
||||
protected function _output($options = array()) {
|
||||
if ($options) {
|
||||
return $this->out(implode($options, ' '));
|
||||
}
|
||||
}
|
||||
}
|
||||
514
lib/Cake/Console/Command/ConsoleShell.php
Normal file
514
lib/Cake/Console/Command/ConsoleShell.php
Normal file
|
|
@ -0,0 +1,514 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 1.2.0.5012
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
|
||||
/**
|
||||
* Provides a very basic 'interactive' console for CakePHP apps.
|
||||
*
|
||||
* @package Cake.Console.Command
|
||||
* @deprecated Deprecated since version 2.4, will be removed in 3.0
|
||||
*/
|
||||
class ConsoleShell extends AppShell {
|
||||
|
||||
/**
|
||||
* Available binding types
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $associations = array('hasOne', 'hasMany', 'belongsTo', 'hasAndBelongsToMany');
|
||||
|
||||
/**
|
||||
* Chars that describe invalid commands
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $badCommandChars = array('$', ';');
|
||||
|
||||
/**
|
||||
* Available models
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $models = array();
|
||||
|
||||
/**
|
||||
* _finished
|
||||
*
|
||||
* This shell is perpetual, setting this property to true exits the process
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $_finished = false;
|
||||
|
||||
/**
|
||||
* _methodPatterns
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_methodPatterns = array(
|
||||
'help' => '/^(help|\?)/',
|
||||
'_exit' => '/^(quit|exit)/',
|
||||
'_models' => '/^models/i',
|
||||
'_bind' => '/^(\w+) bind (\w+) (\w+)/',
|
||||
'_unbind' => '/^(\w+) unbind (\w+) (\w+)/',
|
||||
'_find' => '/.+->find/',
|
||||
'_save' => '/.+->save/',
|
||||
'_columns' => '/^(\w+) columns/',
|
||||
'_routesReload' => '/^routes\s+reload/i',
|
||||
'_routesShow' => '/^routes\s+show/i',
|
||||
'_routeToString' => '/^route\s+(\(.*\))$/i',
|
||||
'_routeToArray' => '/^route\s+(.*)$/i',
|
||||
);
|
||||
|
||||
/**
|
||||
* Override startup of the Shell
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function startup() {
|
||||
App::uses('Dispatcher', 'Routing');
|
||||
$this->Dispatcher = new Dispatcher();
|
||||
$this->models = App::objects('Model');
|
||||
|
||||
foreach ($this->models as $model) {
|
||||
$class = $model;
|
||||
App::uses($class, 'Model');
|
||||
$this->{$class} = new $class();
|
||||
}
|
||||
$this->out(__d('cake_console', 'Model classes:'));
|
||||
$this->hr();
|
||||
|
||||
foreach ($this->models as $model) {
|
||||
$this->out(" - {$model}");
|
||||
}
|
||||
|
||||
if (!$this->_loadRoutes()) {
|
||||
$message = __d(
|
||||
'cake_console',
|
||||
'There was an error loading the routes config. Please check that the file exists and contains no errors.'
|
||||
);
|
||||
$this->err($message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the option parser instance and configures it.
|
||||
*
|
||||
* @return ConsoleOptionParser
|
||||
*/
|
||||
public function getOptionParser() {
|
||||
$parser = parent::getOptionParser();
|
||||
|
||||
$parser->description(array(
|
||||
'The interactive console is a tool for testing parts of your',
|
||||
'app before you write code.',
|
||||
'',
|
||||
'See below for a list of supported commands.'
|
||||
))->epilog(array(
|
||||
'<info>Model testing</info>',
|
||||
'',
|
||||
'To test model results, use the name of your model without a leading $',
|
||||
'e.g. Foo->find("all")',
|
||||
"",
|
||||
'To dynamically set associations, you can do the following:',
|
||||
'',
|
||||
"\tModelA bind <association> ModelB",
|
||||
'',
|
||||
"where the supported associations are hasOne, hasMany, belongsTo, hasAndBelongsToMany",
|
||||
"",
|
||||
'To dynamically remove associations, you can do the following:',
|
||||
'',
|
||||
"\t ModelA unbind <association> ModelB",
|
||||
'',
|
||||
"where the supported associations are the same as above",
|
||||
"",
|
||||
"To save a new field in a model, you can do the following:",
|
||||
'',
|
||||
"\tModelA->save(array('foo' => 'bar', 'baz' => 0))",
|
||||
'',
|
||||
"where you are passing a hash of data to be saved in the format",
|
||||
"of field => value pairs",
|
||||
"",
|
||||
"To get column information for a model, use the following:",
|
||||
'',
|
||||
"\tModelA columns",
|
||||
'',
|
||||
"which returns a list of columns and their type",
|
||||
"",
|
||||
'<info>Route testing</info>',
|
||||
"",
|
||||
'To test URLs against your app\'s route configuration, type:',
|
||||
"",
|
||||
"\tRoute <url>",
|
||||
"",
|
||||
"where url is the path to your your action plus any query parameters,",
|
||||
"minus the application's base path. For example:",
|
||||
"",
|
||||
"\tRoute /posts/view/1",
|
||||
"",
|
||||
"will return something like the following:",
|
||||
"",
|
||||
"\tarray(",
|
||||
"\t [...]",
|
||||
"\t 'controller' => 'posts',",
|
||||
"\t 'action' => 'view',",
|
||||
"\t [...]",
|
||||
"\t)",
|
||||
"",
|
||||
'Alternatively, you can use simple array syntax to test reverse',
|
||||
'To reload your routes config (Config/routes.php), do the following:',
|
||||
"",
|
||||
"\tRoutes reload",
|
||||
"",
|
||||
'To show all connected routes, do the following:',
|
||||
'',
|
||||
"\tRoutes show",
|
||||
));
|
||||
|
||||
return $parser;
|
||||
}
|
||||
/**
|
||||
* Prints the help message
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function help() {
|
||||
$optionParser = $this->getOptionParser();
|
||||
$this->out($optionParser->epilog());
|
||||
}
|
||||
|
||||
/**
|
||||
* Override main() to handle action
|
||||
*
|
||||
* @param string $command The command to run.
|
||||
* @return void
|
||||
*/
|
||||
public function main($command = null) {
|
||||
$this->_finished = false;
|
||||
while (!$this->_finished) {
|
||||
if (empty($command)) {
|
||||
$command = trim($this->in(''));
|
||||
}
|
||||
|
||||
$method = $this->_method($command);
|
||||
|
||||
if ($method) {
|
||||
$this->$method($command);
|
||||
} else {
|
||||
$this->out(__d('cake_console', "Invalid command"));
|
||||
$this->out();
|
||||
}
|
||||
$command = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the method to process the current command
|
||||
*
|
||||
* @param string $command The command to run.
|
||||
* @return string or false
|
||||
*/
|
||||
protected function _method($command) {
|
||||
foreach ($this->_methodPatterns as $method => $pattern) {
|
||||
if (preg_match($pattern, $command)) {
|
||||
return $method;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the finiished property so that the loop in main method ends
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _exit() {
|
||||
$this->_finished = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* List all models
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _models() {
|
||||
$this->out(__d('cake_console', 'Model classes:'));
|
||||
$this->hr();
|
||||
foreach ($this->models as $model) {
|
||||
$this->out(" - {$model}");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind an association
|
||||
*
|
||||
* @param mixed $command The command to run.
|
||||
* @return void
|
||||
*/
|
||||
protected function _bind($command) {
|
||||
preg_match($this->_methodPatterns[__FUNCTION__], $command, $tmp);
|
||||
|
||||
foreach ($tmp as $data) {
|
||||
$data = strip_tags($data);
|
||||
$data = str_replace($this->badCommandChars, "", $data);
|
||||
}
|
||||
|
||||
$modelA = $tmp[1];
|
||||
$association = $tmp[2];
|
||||
$modelB = $tmp[3];
|
||||
|
||||
if ($this->_isValidModel($modelA) && $this->_isValidModel($modelB) && in_array($association, $this->associations)) {
|
||||
$this->{$modelA}->bindModel(array($association => array($modelB => array('className' => $modelB))), false);
|
||||
$this->out(__d('cake_console', "Created %s association between %s and %s",
|
||||
$association, $modelA, $modelB));
|
||||
} else {
|
||||
$this->out(__d('cake_console', "Please verify you are using valid models and association types"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbind an association
|
||||
*
|
||||
* @param mixed $command The command to run.
|
||||
* @return void
|
||||
*/
|
||||
protected function _unbind($command) {
|
||||
preg_match($this->_methodPatterns[__FUNCTION__], $command, $tmp);
|
||||
|
||||
foreach ($tmp as $data) {
|
||||
$data = strip_tags($data);
|
||||
$data = str_replace($this->badCommandChars, "", $data);
|
||||
}
|
||||
|
||||
$modelA = $tmp[1];
|
||||
$association = $tmp[2];
|
||||
$modelB = $tmp[3];
|
||||
|
||||
// Verify that there is actually an association to unbind
|
||||
$currentAssociations = $this->{$modelA}->getAssociated();
|
||||
$validCurrentAssociation = false;
|
||||
|
||||
foreach ($currentAssociations as $model => $currentAssociation) {
|
||||
if ($model === $modelB && $association === $currentAssociation) {
|
||||
$validCurrentAssociation = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->_isValidModel($modelA) && $this->_isValidModel($modelB) && in_array($association, $this->associations) && $validCurrentAssociation) {
|
||||
$this->{$modelA}->unbindModel(array($association => array($modelB)));
|
||||
$this->out(__d('cake_console', "Removed %s association between %s and %s",
|
||||
$association, $modelA, $modelB));
|
||||
} else {
|
||||
$this->out(__d('cake_console', "Please verify you are using valid models, valid current association, and valid association types"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a find
|
||||
*
|
||||
* @param mixed $command The command to run.
|
||||
* @return void
|
||||
*/
|
||||
protected function _find($command) {
|
||||
$command = strip_tags($command);
|
||||
$command = str_replace($this->badCommandChars, "", $command);
|
||||
|
||||
// Do we have a valid model?
|
||||
list($modelToCheck) = explode('->', $command);
|
||||
|
||||
if ($this->_isValidModel($modelToCheck)) {
|
||||
$findCommand = "\$data = \$this->$command;";
|
||||
//@codingStandardsIgnoreStart
|
||||
@eval($findCommand);
|
||||
//@codingStandardsIgnoreEnd
|
||||
|
||||
if (is_array($data)) {
|
||||
foreach ($data as $idx => $results) {
|
||||
if (is_numeric($idx)) { // findAll() output
|
||||
foreach ($results as $modelName => $result) {
|
||||
$this->out("$modelName");
|
||||
|
||||
foreach ($result as $field => $value) {
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $field2 => $value2) {
|
||||
$this->out("\t$field2: $value2");
|
||||
}
|
||||
|
||||
$this->out();
|
||||
} else {
|
||||
$this->out("\t$field: $value");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // find() output
|
||||
$this->out($idx);
|
||||
|
||||
foreach ($results as $field => $value) {
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $field2 => $value2) {
|
||||
$this->out("\t$field2: $value2");
|
||||
}
|
||||
|
||||
$this->out();
|
||||
} else {
|
||||
$this->out("\t$field: $value");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->out();
|
||||
$this->out(__d('cake_console', "No result set found"));
|
||||
}
|
||||
} else {
|
||||
$this->out(__d('cake_console', "%s is not a valid model", $modelToCheck));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a record
|
||||
*
|
||||
* @param mixed $command The command to run.
|
||||
* @return void
|
||||
*/
|
||||
protected function _save($command) {
|
||||
// Validate the model we're trying to save here
|
||||
$command = strip_tags($command);
|
||||
$command = str_replace($this->badCommandChars, "", $command);
|
||||
list($modelToSave) = explode("->", $command);
|
||||
|
||||
if ($this->_isValidModel($modelToSave)) {
|
||||
// Extract the array of data we are trying to build
|
||||
list(, $data) = explode("->save", $command);
|
||||
$data = preg_replace('/^\(*(array)?\(*(.+?)\)*$/i', '\\2', $data);
|
||||
$saveCommand = "\$this->{$modelToSave}->save(array('{$modelToSave}' => array({$data})));";
|
||||
//@codingStandardsIgnoreStart
|
||||
@eval($saveCommand);
|
||||
//@codingStandardsIgnoreEnd
|
||||
$this->out(__d('cake_console', 'Saved record for %s', $modelToSave));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the columns for a model
|
||||
*
|
||||
* @param mixed $command The command to run.
|
||||
* @return void
|
||||
*/
|
||||
protected function _columns($command) {
|
||||
preg_match($this->_methodPatterns[__FUNCTION__], $command, $tmp);
|
||||
|
||||
$modelToCheck = strip_tags(str_replace($this->badCommandChars, "", $tmp[1]));
|
||||
|
||||
if ($this->_isValidModel($modelToCheck)) {
|
||||
// Get the column info for this model
|
||||
$fieldsCommand = "\$data = \$this->{$modelToCheck}->getColumnTypes();";
|
||||
//@codingStandardsIgnoreStart
|
||||
@eval($fieldsCommand);
|
||||
//@codingStandardsIgnoreEnd
|
||||
|
||||
if (is_array($data)) {
|
||||
foreach ($data as $field => $type) {
|
||||
$this->out("\t{$field}: {$type}");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->out(__d('cake_console', "Please verify that you selected a valid model"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload route definitions
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _routesReload() {
|
||||
if (!$this->_loadRoutes()) {
|
||||
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."));
|
||||
}
|
||||
$this->out(__d('cake_console', "Routes configuration reloaded, %d routes connected", count(Router::$routes)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show all routes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _routesShow() {
|
||||
$this->out(print_r(Hash::combine(Router::$routes, '{n}.template', '{n}.defaults'), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an array URL and show the equivalent URL as a string
|
||||
*
|
||||
* @param mixed $command The command to run.
|
||||
* @return void
|
||||
*/
|
||||
protected function _routeToString($command) {
|
||||
preg_match($this->_methodPatterns[__FUNCTION__], $command, $tmp);
|
||||
|
||||
//@codingStandardsIgnoreStart
|
||||
if ($url = eval('return array' . $tmp[1] . ';')) {
|
||||
//@codingStandardsIgnoreEnd
|
||||
$this->out(Router::url($url));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a string URL and show as an array
|
||||
*
|
||||
* @param mixed $command The command to run.
|
||||
* @return void
|
||||
*/
|
||||
protected function _routeToArray($command) {
|
||||
preg_match($this->_methodPatterns[__FUNCTION__], $command, $tmp);
|
||||
|
||||
$this->out(var_export(Router::parse($tmp[1]), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if the specified model is included in the list of available models
|
||||
*
|
||||
* @param string $modelToCheck The model to check.
|
||||
* @return bool true if is an available model, false otherwise
|
||||
*/
|
||||
protected function _isValidModel($modelToCheck) {
|
||||
return in_array($modelToCheck, $this->models);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the routes configuration from app/Config/routes.php, and compiles
|
||||
* all routes found
|
||||
*
|
||||
* @return bool True if config reload was a success, otherwise false
|
||||
*/
|
||||
protected function _loadRoutes() {
|
||||
Router::reload();
|
||||
extract(Router::getNamedExpressions());
|
||||
|
||||
//@codingStandardsIgnoreStart
|
||||
if (!@include APP . 'Config' . DS . 'routes.php') {
|
||||
//@codingStandardsIgnoreEnd
|
||||
return false;
|
||||
}
|
||||
CakePlugin::routes();
|
||||
|
||||
Router::parse('/');
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
122
lib/Cake/Console/Command/I18nShell.php
Normal file
122
lib/Cake/Console/Command/I18nShell.php
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
/**
|
||||
* Internationalization Management Shell
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 1.2.0.5669
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
|
||||
/**
|
||||
* Shell for I18N management.
|
||||
*
|
||||
* @package Cake.Console.Command
|
||||
*/
|
||||
class I18nShell extends AppShell {
|
||||
|
||||
/**
|
||||
* Contains database source to use
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $dataSource = 'default';
|
||||
|
||||
/**
|
||||
* Contains tasks to load and instantiate
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $tasks = array('DbConfig', 'Extract');
|
||||
|
||||
/**
|
||||
* Override startup of the Shell
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function startup() {
|
||||
$this->_welcome();
|
||||
if (isset($this->params['datasource'])) {
|
||||
$this->dataSource = $this->params['datasource'];
|
||||
}
|
||||
|
||||
if ($this->command && !in_array($this->command, array('help'))) {
|
||||
if (!config('database')) {
|
||||
$this->out(__d('cake_console', 'Your database configuration was not found. Take a moment to create one.'));
|
||||
return $this->DbConfig->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override main() for help message hook
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function main() {
|
||||
$this->out(__d('cake_console', '<info>I18n Shell</info>'));
|
||||
$this->hr();
|
||||
$this->out(__d('cake_console', '[E]xtract POT file from sources'));
|
||||
$this->out(__d('cake_console', '[I]nitialize i18n database table'));
|
||||
$this->out(__d('cake_console', '[H]elp'));
|
||||
$this->out(__d('cake_console', '[Q]uit'));
|
||||
|
||||
$choice = strtolower($this->in(__d('cake_console', 'What would you like to do?'), array('E', 'I', 'H', 'Q')));
|
||||
switch ($choice) {
|
||||
case 'e':
|
||||
$this->Extract->execute();
|
||||
break;
|
||||
case 'i':
|
||||
$this->initdb();
|
||||
break;
|
||||
case 'h':
|
||||
$this->out($this->OptionParser->help());
|
||||
break;
|
||||
case 'q':
|
||||
return $this->_stop();
|
||||
default:
|
||||
$this->out(__d('cake_console', 'You have made an invalid selection. Please choose a command to execute by entering E, I, H, or Q.'));
|
||||
}
|
||||
$this->hr();
|
||||
$this->main();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize I18N database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function initdb() {
|
||||
$this->dispatchShell('schema create i18n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the option parser instance and configures it.
|
||||
*
|
||||
* @return ConsoleOptionParser
|
||||
*/
|
||||
public function getOptionParser() {
|
||||
$parser = parent::getOptionParser();
|
||||
|
||||
$parser->description(
|
||||
__d('cake_console', 'I18n Shell initializes i18n database table for your application and generates .pot files(s) with translations.')
|
||||
)->addSubcommand('initdb', array(
|
||||
'help' => __d('cake_console', 'Initialize the i18n table.')
|
||||
))->addSubcommand('extract', array(
|
||||
'help' => __d('cake_console', 'Extract the po translations from your application'),
|
||||
'parser' => $this->Extract->getOptionParser()
|
||||
));
|
||||
|
||||
return $parser;
|
||||
}
|
||||
|
||||
}
|
||||
577
lib/Cake/Console/Command/SchemaShell.php
Normal file
577
lib/Cake/Console/Command/SchemaShell.php
Normal file
|
|
@ -0,0 +1,577 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 1.2.0.5550
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
App::uses('File', 'Utility');
|
||||
App::uses('Folder', 'Utility');
|
||||
App::uses('CakeSchema', 'Model');
|
||||
|
||||
/**
|
||||
* Schema is a command-line database management utility for automating programmer chores.
|
||||
*
|
||||
* Schema is CakePHP's database management utility. This helps you maintain versions of
|
||||
* of your database.
|
||||
*
|
||||
* @package Cake.Console.Command
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells/schema-management-and-migrations.html
|
||||
*/
|
||||
class SchemaShell extends AppShell {
|
||||
|
||||
/**
|
||||
* Schema class being used.
|
||||
*
|
||||
* @var CakeSchema
|
||||
*/
|
||||
public $Schema;
|
||||
|
||||
/**
|
||||
* is this a dry run?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_dry = null;
|
||||
|
||||
/**
|
||||
* Override startup
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function startup() {
|
||||
$this->_welcome();
|
||||
$this->out('Cake Schema Shell');
|
||||
$this->hr();
|
||||
|
||||
Configure::write('Cache.disable', 1);
|
||||
|
||||
$name = $path = $connection = $plugin = null;
|
||||
if (!empty($this->params['name'])) {
|
||||
$name = $this->params['name'];
|
||||
} elseif (!empty($this->args[0]) && $this->args[0] !== 'snapshot') {
|
||||
$name = $this->params['name'] = $this->args[0];
|
||||
}
|
||||
|
||||
if (strpos($name, '.')) {
|
||||
list($this->params['plugin'], $splitName) = pluginSplit($name);
|
||||
$name = $this->params['name'] = $splitName;
|
||||
}
|
||||
|
||||
$defaultFile = 'schema.php';
|
||||
if (empty($this->params['file'])) {
|
||||
$this->params['file'] = $defaultFile;
|
||||
}
|
||||
if ($name && $this->params['file'] === $defaultFile) {
|
||||
$this->params['file'] = Inflector::underscore($name);
|
||||
}
|
||||
if (strpos($this->params['file'], '.php') === false) {
|
||||
$this->params['file'] .= '.php';
|
||||
}
|
||||
$file = $this->params['file'];
|
||||
|
||||
if (!empty($this->params['path'])) {
|
||||
$path = $this->params['path'];
|
||||
}
|
||||
|
||||
if (!empty($this->params['connection'])) {
|
||||
$connection = $this->params['connection'];
|
||||
}
|
||||
if (!empty($this->params['plugin'])) {
|
||||
$plugin = $this->params['plugin'];
|
||||
if (empty($name)) {
|
||||
$name = $plugin;
|
||||
}
|
||||
}
|
||||
$name = Inflector::classify($name);
|
||||
$this->Schema = new CakeSchema(compact('name', 'path', 'file', 'connection', 'plugin'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and output contents of schema object
|
||||
* path to read as second arg
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function view() {
|
||||
$File = new File($this->Schema->path . DS . $this->params['file']);
|
||||
if ($File->exists()) {
|
||||
$this->out($File->read());
|
||||
return $this->_stop();
|
||||
}
|
||||
$file = $this->Schema->path . DS . $this->params['file'];
|
||||
$this->err(__d('cake_console', 'Schema file (%s) could not be found.', $file));
|
||||
return $this->_stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read database and Write schema object
|
||||
* accepts a connection as first arg or path to save as second arg
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function generate() {
|
||||
$this->out(__d('cake_console', 'Generating Schema...'));
|
||||
$options = array();
|
||||
if ($this->params['force']) {
|
||||
$options['models'] = false;
|
||||
} elseif (!empty($this->params['models'])) {
|
||||
$options['models'] = String::tokenize($this->params['models']);
|
||||
}
|
||||
|
||||
$snapshot = false;
|
||||
if (isset($this->args[0]) && $this->args[0] === 'snapshot') {
|
||||
$snapshot = true;
|
||||
}
|
||||
|
||||
if (!$snapshot && file_exists($this->Schema->path . DS . $this->params['file'])) {
|
||||
$snapshot = true;
|
||||
$prompt = __d('cake_console', "Schema file exists.\n [O]verwrite\n [S]napshot\n [Q]uit\nWould you like to do?");
|
||||
$result = strtolower($this->in($prompt, array('o', 's', 'q'), 's'));
|
||||
if ($result === 'q') {
|
||||
return $this->_stop();
|
||||
}
|
||||
if ($result === 'o') {
|
||||
$snapshot = false;
|
||||
}
|
||||
}
|
||||
|
||||
$cacheDisable = Configure::read('Cache.disable');
|
||||
Configure::write('Cache.disable', true);
|
||||
|
||||
$content = $this->Schema->read($options);
|
||||
$content['file'] = $this->params['file'];
|
||||
|
||||
Configure::write('Cache.disable', $cacheDisable);
|
||||
|
||||
if (!empty($this->params['exclude']) && !empty($content)) {
|
||||
$excluded = String::tokenize($this->params['exclude']);
|
||||
foreach ($excluded as $table) {
|
||||
unset($content['tables'][$table]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($snapshot === true) {
|
||||
$fileName = rtrim($this->params['file'], '.php');
|
||||
$Folder = new Folder($this->Schema->path);
|
||||
$result = $Folder->read();
|
||||
|
||||
$numToUse = false;
|
||||
if (isset($this->params['snapshot'])) {
|
||||
$numToUse = $this->params['snapshot'];
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
if (!empty($result[1])) {
|
||||
foreach ($result[1] as $file) {
|
||||
if (preg_match('/' . preg_quote($fileName) . '(?:[_\d]*)?\.php$/', $file)) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($numToUse !== false) {
|
||||
if ($numToUse > $count) {
|
||||
$count = $numToUse;
|
||||
}
|
||||
}
|
||||
|
||||
$content['file'] = $fileName . '_' . $count . '.php';
|
||||
}
|
||||
|
||||
if ($this->Schema->write($content)) {
|
||||
$this->out(__d('cake_console', 'Schema file: %s generated', $content['file']));
|
||||
return $this->_stop();
|
||||
}
|
||||
$this->err(__d('cake_console', 'Schema file: %s generated'));
|
||||
return $this->_stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump Schema object to sql file
|
||||
* Use the `write` param to enable and control SQL file output location.
|
||||
* Simply using -write will write the sql file to the same dir as the schema file.
|
||||
* If -write contains a full path name the file will be saved there. If -write only
|
||||
* contains no DS, that will be used as the file name, in the same dir as the schema file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function dump() {
|
||||
$write = false;
|
||||
$Schema = $this->Schema->load();
|
||||
if (!$Schema) {
|
||||
$this->err(__d('cake_console', 'Schema could not be loaded'));
|
||||
return $this->_stop();
|
||||
}
|
||||
if (!empty($this->params['write'])) {
|
||||
if ($this->params['write'] == 1) {
|
||||
$write = Inflector::underscore($this->Schema->name);
|
||||
} else {
|
||||
$write = $this->params['write'];
|
||||
}
|
||||
}
|
||||
$db = ConnectionManager::getDataSource($this->Schema->connection);
|
||||
$contents = "\n\n" . $db->dropSchema($Schema) . "\n\n" . $db->createSchema($Schema);
|
||||
|
||||
if ($write) {
|
||||
if (strpos($write, '.sql') === false) {
|
||||
$write .= '.sql';
|
||||
}
|
||||
if (strpos($write, DS) !== false) {
|
||||
$File = new File($write, true);
|
||||
} else {
|
||||
$File = new File($this->Schema->path . DS . $write, true);
|
||||
}
|
||||
|
||||
if ($File->write($contents)) {
|
||||
$this->out(__d('cake_console', 'SQL dump file created in %s', $File->pwd()));
|
||||
return $this->_stop();
|
||||
}
|
||||
$this->err(__d('cake_console', 'SQL dump could not be created'));
|
||||
return $this->_stop();
|
||||
}
|
||||
$this->out($contents);
|
||||
return $contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run database create commands. Alias for run create.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function create() {
|
||||
list($Schema, $table) = $this->_loadSchema();
|
||||
$this->_create($Schema, $table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run database create commands. Alias for run create.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function update() {
|
||||
list($Schema, $table) = $this->_loadSchema();
|
||||
$this->_update($Schema, $table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the Schema objects for database operations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _loadSchema() {
|
||||
$name = $plugin = null;
|
||||
if (!empty($this->params['name'])) {
|
||||
$name = $this->params['name'];
|
||||
}
|
||||
if (!empty($this->params['plugin'])) {
|
||||
$plugin = $this->params['plugin'];
|
||||
}
|
||||
|
||||
if (!empty($this->params['dry'])) {
|
||||
$this->_dry = true;
|
||||
$this->out(__d('cake_console', 'Performing a dry run.'));
|
||||
}
|
||||
|
||||
$options = array(
|
||||
'name' => $name,
|
||||
'plugin' => $plugin,
|
||||
'connection' => $this->params['connection'],
|
||||
);
|
||||
if (!empty($this->params['snapshot'])) {
|
||||
$fileName = rtrim($this->Schema->file, '.php');
|
||||
$options['file'] = $fileName . '_' . $this->params['snapshot'] . '.php';
|
||||
}
|
||||
|
||||
$Schema = $this->Schema->load($options);
|
||||
|
||||
if (!$Schema) {
|
||||
$this->err(__d('cake_console', 'The chosen schema could not be loaded. Attempted to load:'));
|
||||
$this->err(__d('cake_console', 'File: %s', $this->Schema->path . DS . $this->Schema->file));
|
||||
$this->err(__d('cake_console', 'Name: %s', $this->Schema->name));
|
||||
return $this->_stop();
|
||||
}
|
||||
$table = null;
|
||||
if (isset($this->args[1])) {
|
||||
$table = $this->args[1];
|
||||
}
|
||||
return array(&$Schema, $table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create database from Schema object
|
||||
* Should be called via the run method
|
||||
*
|
||||
* @param CakeSchema $Schema The schema instance to create.
|
||||
* @param string $table The table name.
|
||||
* @return void
|
||||
*/
|
||||
protected function _create(CakeSchema $Schema, $table = null) {
|
||||
$db = ConnectionManager::getDataSource($this->Schema->connection);
|
||||
|
||||
$drop = $create = array();
|
||||
|
||||
if (!$table) {
|
||||
foreach ($Schema->tables as $table => $fields) {
|
||||
$drop[$table] = $db->dropSchema($Schema, $table);
|
||||
$create[$table] = $db->createSchema($Schema, $table);
|
||||
}
|
||||
} elseif (isset($Schema->tables[$table])) {
|
||||
$drop[$table] = $db->dropSchema($Schema, $table);
|
||||
$create[$table] = $db->createSchema($Schema, $table);
|
||||
}
|
||||
if (empty($drop) || empty($create)) {
|
||||
$this->out(__d('cake_console', 'Schema is up to date.'));
|
||||
return $this->_stop();
|
||||
}
|
||||
|
||||
$this->out("\n" . __d('cake_console', 'The following table(s) will be dropped.'));
|
||||
$this->out(array_keys($drop));
|
||||
|
||||
if (
|
||||
!empty($this->params['yes']) ||
|
||||
$this->in(__d('cake_console', 'Are you sure you want to drop the table(s)?'), array('y', 'n'), 'n') === 'y'
|
||||
) {
|
||||
$this->out(__d('cake_console', 'Dropping table(s).'));
|
||||
$this->_run($drop, 'drop', $Schema);
|
||||
}
|
||||
|
||||
$this->out("\n" . __d('cake_console', 'The following table(s) will be created.'));
|
||||
$this->out(array_keys($create));
|
||||
|
||||
if (
|
||||
!empty($this->params['yes']) ||
|
||||
$this->in(__d('cake_console', 'Are you sure you want to create the table(s)?'), array('y', 'n'), 'y') === 'y'
|
||||
) {
|
||||
$this->out(__d('cake_console', 'Creating table(s).'));
|
||||
$this->_run($create, 'create', $Schema);
|
||||
}
|
||||
$this->out(__d('cake_console', 'End create.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update database with Schema object
|
||||
* Should be called via the run method
|
||||
*
|
||||
* @param CakeSchema &$Schema The schema instance
|
||||
* @param string $table The table name.
|
||||
* @return void
|
||||
*/
|
||||
protected function _update(&$Schema, $table = null) {
|
||||
$db = ConnectionManager::getDataSource($this->Schema->connection);
|
||||
|
||||
$this->out(__d('cake_console', 'Comparing Database to Schema...'));
|
||||
$options = array();
|
||||
if (isset($this->params['force'])) {
|
||||
$options['models'] = false;
|
||||
}
|
||||
$Old = $this->Schema->read($options);
|
||||
$compare = $this->Schema->compare($Old, $Schema);
|
||||
|
||||
$contents = array();
|
||||
|
||||
if (empty($table)) {
|
||||
foreach ($compare as $table => $changes) {
|
||||
if (isset($compare[$table]['create'])) {
|
||||
$contents[$table] = $db->createSchema($Schema, $table);
|
||||
} else {
|
||||
$contents[$table] = $db->alterSchema(array($table => $compare[$table]), $table);
|
||||
}
|
||||
}
|
||||
} elseif (isset($compare[$table])) {
|
||||
if (isset($compare[$table]['create'])) {
|
||||
$contents[$table] = $db->createSchema($Schema, $table);
|
||||
} else {
|
||||
$contents[$table] = $db->alterSchema(array($table => $compare[$table]), $table);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($contents)) {
|
||||
$this->out(__d('cake_console', 'Schema is up to date.'));
|
||||
return $this->_stop();
|
||||
}
|
||||
|
||||
$this->out("\n" . __d('cake_console', 'The following statements will run.'));
|
||||
$this->out(array_map('trim', $contents));
|
||||
if (
|
||||
!empty($this->params['yes']) ||
|
||||
$this->in(__d('cake_console', 'Are you sure you want to alter the tables?'), array('y', 'n'), 'n') === 'y'
|
||||
) {
|
||||
$this->out();
|
||||
$this->out(__d('cake_console', 'Updating Database...'));
|
||||
$this->_run($contents, 'update', $Schema);
|
||||
}
|
||||
|
||||
$this->out(__d('cake_console', 'End update.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs sql from _create() or _update()
|
||||
*
|
||||
* @param array $contents The contents to execute.
|
||||
* @param string $event The event to fire
|
||||
* @param CakeSchema $Schema The schema instance.
|
||||
* @return void
|
||||
*/
|
||||
protected function _run($contents, $event, CakeSchema $Schema) {
|
||||
if (empty($contents)) {
|
||||
$this->err(__d('cake_console', 'Sql could not be run'));
|
||||
return;
|
||||
}
|
||||
Configure::write('debug', 2);
|
||||
$db = ConnectionManager::getDataSource($this->Schema->connection);
|
||||
|
||||
foreach ($contents as $table => $sql) {
|
||||
if (empty($sql)) {
|
||||
$this->out(__d('cake_console', '%s is up to date.', $table));
|
||||
} else {
|
||||
if ($this->_dry === true) {
|
||||
$this->out(__d('cake_console', 'Dry run for %s :', $table));
|
||||
$this->out($sql);
|
||||
} else {
|
||||
if (!$Schema->before(array($event => $table))) {
|
||||
return false;
|
||||
}
|
||||
$error = null;
|
||||
try {
|
||||
$db->execute($sql);
|
||||
} catch (PDOException $e) {
|
||||
$error = $table . ': ' . $e->getMessage();
|
||||
}
|
||||
|
||||
$Schema->after(array($event => $table, 'errors' => $error));
|
||||
|
||||
if (!empty($error)) {
|
||||
$this->err($error);
|
||||
} else {
|
||||
$this->out(__d('cake_console', '%s updated.', $table));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the option parser instance and configures it.
|
||||
*
|
||||
* @return ConsoleOptionParser
|
||||
*/
|
||||
public function getOptionParser() {
|
||||
$parser = parent::getOptionParser();
|
||||
|
||||
$plugin = array(
|
||||
'short' => 'p',
|
||||
'help' => __d('cake_console', 'The plugin to use.'),
|
||||
);
|
||||
$connection = array(
|
||||
'short' => 'c',
|
||||
'help' => __d('cake_console', 'Set the db config to use.'),
|
||||
'default' => 'default'
|
||||
);
|
||||
$path = array(
|
||||
'help' => __d('cake_console', 'Path to read and write schema.php'),
|
||||
'default' => APP . 'Config' . DS . 'Schema'
|
||||
);
|
||||
$file = array(
|
||||
'help' => __d('cake_console', 'File name to read and write.'),
|
||||
'default' => 'schema.php'
|
||||
);
|
||||
$name = array(
|
||||
'help' => __d('cake_console',
|
||||
'Classname to use. If its Plugin.class, both name and plugin options will be set.'
|
||||
)
|
||||
);
|
||||
$snapshot = array(
|
||||
'short' => 's',
|
||||
'help' => __d('cake_console', 'Snapshot number to use/make.')
|
||||
);
|
||||
$models = array(
|
||||
'short' => 'm',
|
||||
'help' => __d('cake_console', 'Specify models as comma separated list.'),
|
||||
);
|
||||
$dry = array(
|
||||
'help' => __d('cake_console',
|
||||
'Perform a dry run on create and update commands. Queries will be output instead of run.'
|
||||
),
|
||||
'boolean' => true
|
||||
);
|
||||
$force = array(
|
||||
'short' => 'f',
|
||||
'help' => __d('cake_console', 'Force "generate" to create a new schema'),
|
||||
'boolean' => true
|
||||
);
|
||||
$write = array(
|
||||
'help' => __d('cake_console', 'Write the dumped SQL to a file.')
|
||||
);
|
||||
$exclude = array(
|
||||
'help' => __d('cake_console', 'Tables to exclude as comma separated list.')
|
||||
);
|
||||
$yes = array(
|
||||
'short' => 'y',
|
||||
'help' => __d('cake_console', 'Do not prompt for confirmation. Be careful!'),
|
||||
'boolean' => true
|
||||
);
|
||||
|
||||
$parser->description(
|
||||
__d('cake_console', 'The Schema Shell generates a schema object from the database and updates the database from the schema.')
|
||||
)->addSubcommand('view', array(
|
||||
'help' => __d('cake_console', 'Read and output the contents of a schema file'),
|
||||
'parser' => array(
|
||||
'options' => compact('plugin', 'path', 'file', 'name', 'connection'),
|
||||
'arguments' => compact('name')
|
||||
)
|
||||
))->addSubcommand('generate', array(
|
||||
'help' => __d('cake_console', 'Reads from --connection and writes to --path. Generate snapshots with -s'),
|
||||
'parser' => array(
|
||||
'options' => compact('plugin', 'path', 'file', 'name', 'connection', 'snapshot', 'force', 'models', 'exclude'),
|
||||
'arguments' => array(
|
||||
'snapshot' => array('help' => __d('cake_console', 'Generate a snapshot.'))
|
||||
)
|
||||
)
|
||||
))->addSubcommand('dump', array(
|
||||
'help' => __d('cake_console', 'Dump database SQL based on a schema file to stdout.'),
|
||||
'parser' => array(
|
||||
'options' => compact('plugin', 'path', 'file', 'name', 'connection', 'write'),
|
||||
'arguments' => compact('name')
|
||||
)
|
||||
))->addSubcommand('create', array(
|
||||
'help' => __d('cake_console', 'Drop and create tables based on the schema file.'),
|
||||
'parser' => array(
|
||||
'options' => compact('plugin', 'path', 'file', 'name', 'connection', 'dry', 'snapshot', 'yes'),
|
||||
'args' => array(
|
||||
'name' => array(
|
||||
'help' => __d('cake_console', 'Name of schema to use.')
|
||||
),
|
||||
'table' => array(
|
||||
'help' => __d('cake_console', 'Only create the specified table.')
|
||||
)
|
||||
)
|
||||
)
|
||||
))->addSubcommand('update', array(
|
||||
'help' => __d('cake_console', 'Alter the tables based on the schema file.'),
|
||||
'parser' => array(
|
||||
'options' => compact('plugin', 'path', 'file', 'name', 'connection', 'dry', 'snapshot', 'force', 'yes'),
|
||||
'args' => array(
|
||||
'name' => array(
|
||||
'help' => __d('cake_console', 'Name of schema to use.')
|
||||
),
|
||||
'table' => array(
|
||||
'help' => __d('cake_console', 'Only create the specified table.')
|
||||
)
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
return $parser;
|
||||
}
|
||||
|
||||
}
|
||||
167
lib/Cake/Console/Command/ServerShell.php
Normal file
167
lib/Cake/Console/Command/ServerShell.php
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
<?php
|
||||
/**
|
||||
* built-in Server Shell
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 2.3.0
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
|
||||
/**
|
||||
* built-in Server Shell
|
||||
*
|
||||
* @package Cake.Console.Command
|
||||
*/
|
||||
class ServerShell extends AppShell {
|
||||
|
||||
/**
|
||||
* Default ServerHost
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const DEFAULT_HOST = 'localhost';
|
||||
|
||||
/**
|
||||
* Default ListenPort
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const DEFAULT_PORT = 80;
|
||||
|
||||
/**
|
||||
* server host
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_host = null;
|
||||
|
||||
/**
|
||||
* listen port
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_port = null;
|
||||
|
||||
/**
|
||||
* document root
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_documentRoot = null;
|
||||
|
||||
/**
|
||||
* Override initialize of the Shell
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function initialize() {
|
||||
$this->_host = self::DEFAULT_HOST;
|
||||
$this->_port = self::DEFAULT_PORT;
|
||||
$this->_documentRoot = WWW_ROOT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts up the Shell and displays the welcome message.
|
||||
* Allows for checking and configuring prior to command or main execution
|
||||
*
|
||||
* Override this method if you want to remove the welcome information,
|
||||
* or otherwise modify the pre-command flow.
|
||||
*
|
||||
* @return void
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::startup
|
||||
*/
|
||||
public function startup() {
|
||||
if (!empty($this->params['host'])) {
|
||||
$this->_host = $this->params['host'];
|
||||
}
|
||||
if (!empty($this->params['port'])) {
|
||||
$this->_port = $this->params['port'];
|
||||
}
|
||||
if (!empty($this->params['document_root'])) {
|
||||
$this->_documentRoot = $this->params['document_root'];
|
||||
}
|
||||
|
||||
// for windows
|
||||
if (substr($this->_documentRoot, -1, 1) === DIRECTORY_SEPARATOR) {
|
||||
$this->_documentRoot = substr($this->_documentRoot, 0, strlen($this->_documentRoot) - 1);
|
||||
}
|
||||
if (preg_match("/^([a-z]:)[\\\]+(.+)$/i", $this->_documentRoot, $m)) {
|
||||
$this->_documentRoot = $m[1] . '\\' . $m[2];
|
||||
}
|
||||
|
||||
parent::startup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a header for the shell
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _welcome() {
|
||||
$this->out();
|
||||
$this->out(__d('cake_console', '<info>Welcome to CakePHP %s Console</info>', 'v' . Configure::version()));
|
||||
$this->hr();
|
||||
$this->out(__d('cake_console', 'App : %s', APP_DIR));
|
||||
$this->out(__d('cake_console', 'Path: %s', APP));
|
||||
$this->out(__d('cake_console', 'DocumentRoot: %s', $this->_documentRoot));
|
||||
$this->hr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Override main() to handle action
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function main() {
|
||||
if (version_compare(PHP_VERSION, '5.4.0') < 0) {
|
||||
$this->out(__d('cake_console', '<warning>This command is available on %s or above</warning>', 'PHP5.4'));
|
||||
return;
|
||||
}
|
||||
|
||||
$command = sprintf("php -S %s:%d -t %s %s",
|
||||
$this->_host,
|
||||
$this->_port,
|
||||
escapeshellarg($this->_documentRoot),
|
||||
escapeshellarg($this->_documentRoot . '/index.php')
|
||||
);
|
||||
|
||||
$port = ($this->_port == self::DEFAULT_PORT) ? '' : ':' . $this->_port;
|
||||
$this->out(__d('cake_console', 'built-in server is running in http://%s%s/', $this->_host, $port));
|
||||
system($command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the option parser instance and configures it.
|
||||
*
|
||||
* @return ConsoleOptionParser
|
||||
*/
|
||||
public function getOptionParser() {
|
||||
$parser = parent::getOptionParser();
|
||||
|
||||
$parser->description(array(
|
||||
__d('cake_console', 'PHP Built-in Server for CakePHP'),
|
||||
__d('cake_console', '<warning>[WARN] Don\'t use this at the production environment</warning>')
|
||||
))->addOption('host', array(
|
||||
'short' => 'H',
|
||||
'help' => __d('cake_console', 'ServerHost')
|
||||
))->addOption('port', array(
|
||||
'short' => 'p',
|
||||
'help' => __d('cake_console', 'ListenPort')
|
||||
))->addOption('document_root', array(
|
||||
'short' => 'd',
|
||||
'help' => __d('cake_console', 'DocumentRoot')
|
||||
));
|
||||
|
||||
return $parser;
|
||||
}
|
||||
}
|
||||
92
lib/Cake/Console/Command/Task/BakeTask.php
Normal file
92
lib/Cake/Console/Command/Task/BakeTask.php
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
/**
|
||||
* Base class for Bake Tasks.
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 1.3
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
|
||||
/**
|
||||
* Base class for Bake Tasks.
|
||||
*
|
||||
* @package Cake.Console.Command.Task
|
||||
*/
|
||||
class BakeTask extends AppShell {
|
||||
|
||||
/**
|
||||
* Name of plugin
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $plugin = null;
|
||||
|
||||
/**
|
||||
* The db connection being used for baking
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $connection = null;
|
||||
|
||||
/**
|
||||
* Flag for interactive mode
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $interactive = false;
|
||||
|
||||
/**
|
||||
* Disable caching and enable debug for baking.
|
||||
* This forces the most current database schema to be used.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function startup() {
|
||||
Configure::write('debug', 2);
|
||||
Configure::write('Cache.disable', 1);
|
||||
parent::startup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path for output. Checks the plugin property
|
||||
* and returns the correct path.
|
||||
*
|
||||
* @return string Path to output.
|
||||
*/
|
||||
public function getPath() {
|
||||
$path = $this->path;
|
||||
if (isset($this->plugin)) {
|
||||
$path = $this->_pluginPath($this->plugin) . $this->name . DS;
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base execute method parses some parameters and sets some properties on the bake tasks.
|
||||
* call when overriding execute()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute() {
|
||||
foreach ($this->args as $i => $arg) {
|
||||
if (strpos($arg, '.')) {
|
||||
list($this->params['plugin'], $this->args[$i]) = pluginSplit($arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isset($this->params['plugin'])) {
|
||||
$this->plugin = $this->params['plugin'];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
183
lib/Cake/Console/Command/Task/CommandTask.php
Normal file
183
lib/Cake/Console/Command/Task/CommandTask.php
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 2.5
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
|
||||
/**
|
||||
* Base class for Shell Command reflection.
|
||||
*
|
||||
* @package Cake.Console.Command.Task
|
||||
*/
|
||||
class CommandTask extends AppShell {
|
||||
|
||||
/**
|
||||
* Gets the shell command listing.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getShellList() {
|
||||
$skipFiles = array('AppShell');
|
||||
|
||||
$plugins = CakePlugin::loaded();
|
||||
$shellList = array_fill_keys($plugins, null) + array('CORE' => null, 'app' => null);
|
||||
|
||||
$corePath = App::core('Console/Command');
|
||||
$shells = App::objects('file', $corePath[0]);
|
||||
$shells = array_diff($shells, $skipFiles);
|
||||
$this->_appendShells('CORE', $shells, $shellList);
|
||||
|
||||
$appShells = App::objects('Console/Command', null, false);
|
||||
$appShells = array_diff($appShells, $shells, $skipFiles);
|
||||
$this->_appendShells('app', $appShells, $shellList);
|
||||
|
||||
foreach ($plugins as $plugin) {
|
||||
$pluginShells = App::objects($plugin . '.Console/Command');
|
||||
$this->_appendShells($plugin, $pluginShells, $shellList);
|
||||
}
|
||||
|
||||
return array_filter($shellList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan the provided paths for shells, and append them into $shellList
|
||||
*
|
||||
* @param string $type The type of object.
|
||||
* @param array $shells The shell name.
|
||||
* @param array &$shellList List of shells.
|
||||
* @return void
|
||||
*/
|
||||
protected function _appendShells($type, $shells, &$shellList) {
|
||||
foreach ($shells as $shell) {
|
||||
$shellList[$type][] = Inflector::underscore(str_replace('Shell', '', $shell));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of all commands
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function commands() {
|
||||
$shellList = $this->getShellList();
|
||||
|
||||
$options = array();
|
||||
foreach ($shellList as $type => $commands) {
|
||||
$prefix = '';
|
||||
if (!in_array(strtolower($type), array('app', 'core'))) {
|
||||
$prefix = $type . '.';
|
||||
}
|
||||
|
||||
foreach ($commands as $shell) {
|
||||
$options[] = $prefix . $shell;
|
||||
}
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of subcommands for a given command
|
||||
*
|
||||
* @param string $commandName The command you want subcommands from.
|
||||
* @return array
|
||||
*/
|
||||
public function subCommands($commandName) {
|
||||
$Shell = $this->getShell($commandName);
|
||||
|
||||
if (!$Shell) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$taskMap = TaskCollection::normalizeObjectArray((array)$Shell->tasks);
|
||||
$return = array_keys($taskMap);
|
||||
$return = array_map('Inflector::underscore', $return);
|
||||
|
||||
$ShellReflection = new ReflectionClass('AppShell');
|
||||
$shellMethods = $ShellReflection->getMethods(ReflectionMethod::IS_PUBLIC);
|
||||
$shellMethodNames = array('main', 'help');
|
||||
foreach ($shellMethods as $method) {
|
||||
$shellMethodNames[] = $method->getName();
|
||||
}
|
||||
|
||||
$Reflection = new ReflectionClass($Shell);
|
||||
$methods = $Reflection->getMethods(ReflectionMethod::IS_PUBLIC);
|
||||
$methodNames = array();
|
||||
foreach ($methods as $method) {
|
||||
$methodNames[] = $method->getName();
|
||||
}
|
||||
|
||||
$return += array_diff($methodNames, $shellMethodNames);
|
||||
sort($return);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Shell instance for the given command
|
||||
*
|
||||
* @param mixed $commandName The command you want.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getShell($commandName) {
|
||||
list($pluginDot, $name) = pluginSplit($commandName, true);
|
||||
|
||||
if (in_array(strtolower($pluginDot), array('app.', 'core.'))) {
|
||||
$commandName = $name;
|
||||
$pluginDot = '';
|
||||
}
|
||||
|
||||
if (!in_array($commandName, $this->commands())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$name = Inflector::camelize($name);
|
||||
$pluginDot = Inflector::camelize($pluginDot);
|
||||
$class = $name . 'Shell';
|
||||
App::uses($class, $pluginDot . 'Console/Command');
|
||||
|
||||
$Shell = new $class();
|
||||
$Shell->plugin = trim($pluginDot, '.');
|
||||
$Shell->initialize();
|
||||
|
||||
return $Shell;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Shell instance for the given command
|
||||
*
|
||||
* @param mixed $commandName The command to get options for.
|
||||
* @return array
|
||||
*/
|
||||
public function options($commandName) {
|
||||
$Shell = $this->getShell($commandName);
|
||||
if (!$Shell) {
|
||||
$parser = new ConsoleOptionParser();
|
||||
} else {
|
||||
$parser = $Shell->getOptionParser();
|
||||
}
|
||||
|
||||
$options = array();
|
||||
$array = $parser->options();
|
||||
foreach ($array as $name => $obj) {
|
||||
$options[] = "--$name";
|
||||
$short = $obj->short();
|
||||
if ($short) {
|
||||
$options[] = "-$short";
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
}
|
||||
508
lib/Cake/Console/Command/Task/ControllerTask.php
Normal file
508
lib/Cake/Console/Command/Task/ControllerTask.php
Normal file
|
|
@ -0,0 +1,508 @@
|
|||
<?php
|
||||
/**
|
||||
* The ControllerTask handles creating and updating controller files.
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 1.2
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
App::uses('BakeTask', 'Console/Command/Task');
|
||||
App::uses('AppModel', 'Model');
|
||||
|
||||
/**
|
||||
* Task class for creating and updating controller files.
|
||||
*
|
||||
* @package Cake.Console.Command.Task
|
||||
*/
|
||||
class ControllerTask extends BakeTask {
|
||||
|
||||
/**
|
||||
* Tasks to be loaded by this Task
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $tasks = array('Model', 'Test', 'Template', 'DbConfig', 'Project');
|
||||
|
||||
/**
|
||||
* path to Controller directory
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $path = null;
|
||||
|
||||
/**
|
||||
* Override initialize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function initialize() {
|
||||
$this->path = current(App::path('Controller'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Execution method always used for tasks
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute() {
|
||||
parent::execute();
|
||||
if (empty($this->args)) {
|
||||
return $this->_interactive();
|
||||
}
|
||||
|
||||
if (isset($this->args[0])) {
|
||||
if (!isset($this->connection)) {
|
||||
$this->connection = 'default';
|
||||
}
|
||||
if (strtolower($this->args[0]) === 'all') {
|
||||
return $this->all();
|
||||
}
|
||||
|
||||
$controller = $this->_controllerName($this->args[0]);
|
||||
$actions = '';
|
||||
|
||||
if (!empty($this->params['public'])) {
|
||||
$this->out(__d('cake_console', 'Baking basic crud methods for ') . $controller);
|
||||
$actions .= $this->bakeActions($controller);
|
||||
}
|
||||
if (!empty($this->params['admin'])) {
|
||||
$admin = $this->Project->getPrefix();
|
||||
if ($admin) {
|
||||
$this->out(__d('cake_console', 'Adding %s methods', $admin));
|
||||
$actions .= "\n" . $this->bakeActions($controller, $admin);
|
||||
}
|
||||
}
|
||||
if (empty($actions)) {
|
||||
$actions = 'scaffold';
|
||||
}
|
||||
|
||||
if ($this->bake($controller, $actions)) {
|
||||
if ($this->_checkUnitTest()) {
|
||||
$this->bakeTest($controller);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bake All the controllers at once. Will only bake controllers for models that exist.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function all() {
|
||||
$this->interactive = false;
|
||||
$this->listAll($this->connection, false);
|
||||
ClassRegistry::config('Model', array('ds' => $this->connection));
|
||||
$unitTestExists = $this->_checkUnitTest();
|
||||
|
||||
$admin = false;
|
||||
if (!empty($this->params['admin'])) {
|
||||
$admin = $this->Project->getPrefix();
|
||||
}
|
||||
|
||||
$controllersCreated = 0;
|
||||
foreach ($this->__tables as $table) {
|
||||
$model = $this->_modelName($table);
|
||||
$controller = $this->_controllerName($model);
|
||||
App::uses($model, 'Model');
|
||||
if (class_exists($model)) {
|
||||
$actions = $this->bakeActions($controller);
|
||||
if ($admin) {
|
||||
$this->out(__d('cake_console', 'Adding %s methods', $admin));
|
||||
$actions .= "\n" . $this->bakeActions($controller, $admin);
|
||||
}
|
||||
if ($this->bake($controller, $actions) && $unitTestExists) {
|
||||
$this->bakeTest($controller);
|
||||
}
|
||||
$controllersCreated++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$controllersCreated) {
|
||||
$this->out(__d('cake_console', 'No Controllers were baked, Models need to exist before Controllers can be baked.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interactive
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _interactive() {
|
||||
$this->interactive = true;
|
||||
$this->hr();
|
||||
$this->out(__d('cake_console', "Bake Controller\nPath: %s", $this->getPath()));
|
||||
$this->hr();
|
||||
|
||||
if (empty($this->connection)) {
|
||||
$this->connection = $this->DbConfig->getConfig();
|
||||
}
|
||||
|
||||
$controllerName = $this->getName();
|
||||
$this->hr();
|
||||
$this->out(__d('cake_console', 'Baking %sController', $controllerName));
|
||||
$this->hr();
|
||||
|
||||
$helpers = $components = array();
|
||||
$actions = '';
|
||||
$wannaUseSession = 'y';
|
||||
$wannaBakeAdminCrud = 'n';
|
||||
$useDynamicScaffold = 'n';
|
||||
$wannaBakeCrud = 'y';
|
||||
|
||||
$question[] = __d('cake_console', "Would you like to build your controller interactively?");
|
||||
if (file_exists($this->path . $controllerName . 'Controller.php')) {
|
||||
$question[] = __d('cake_console', "Warning: Choosing no will overwrite the %sController.", $controllerName);
|
||||
}
|
||||
$doItInteractive = $this->in(implode("\n", $question), array('y', 'n'), 'y');
|
||||
|
||||
if (strtolower($doItInteractive) === 'y') {
|
||||
$this->interactive = true;
|
||||
$useDynamicScaffold = $this->in(
|
||||
__d('cake_console', "Would you like to use dynamic scaffolding?"), array('y', 'n'), 'n'
|
||||
);
|
||||
|
||||
if (strtolower($useDynamicScaffold) === 'y') {
|
||||
$wannaBakeCrud = 'n';
|
||||
$actions = 'scaffold';
|
||||
} else {
|
||||
list($wannaBakeCrud, $wannaBakeAdminCrud) = $this->_askAboutMethods();
|
||||
|
||||
$helpers = $this->doHelpers();
|
||||
$components = $this->doComponents();
|
||||
|
||||
$wannaUseSession = $this->in(
|
||||
__d('cake_console', "Would you like to use Session flash messages?"), array('y', 'n'), 'y'
|
||||
);
|
||||
|
||||
if (strtolower($wannaUseSession) === 'y') {
|
||||
array_push($components, 'Session');
|
||||
}
|
||||
array_unique($components);
|
||||
}
|
||||
} else {
|
||||
list($wannaBakeCrud, $wannaBakeAdminCrud) = $this->_askAboutMethods();
|
||||
}
|
||||
|
||||
if (strtolower($wannaBakeCrud) === 'y') {
|
||||
$actions = $this->bakeActions($controllerName, null, strtolower($wannaUseSession) === 'y');
|
||||
}
|
||||
if (strtolower($wannaBakeAdminCrud) === 'y') {
|
||||
$admin = $this->Project->getPrefix();
|
||||
$actions .= $this->bakeActions($controllerName, $admin, strtolower($wannaUseSession) === 'y');
|
||||
}
|
||||
|
||||
$baked = false;
|
||||
if ($this->interactive === true) {
|
||||
$this->confirmController($controllerName, $useDynamicScaffold, $helpers, $components);
|
||||
$looksGood = $this->in(__d('cake_console', 'Look okay?'), array('y', 'n'), 'y');
|
||||
|
||||
if (strtolower($looksGood) === 'y') {
|
||||
$baked = $this->bake($controllerName, $actions, $helpers, $components);
|
||||
if ($baked && $this->_checkUnitTest()) {
|
||||
$this->bakeTest($controllerName);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$baked = $this->bake($controllerName, $actions, $helpers, $components);
|
||||
if ($baked && $this->_checkUnitTest()) {
|
||||
$this->bakeTest($controllerName);
|
||||
}
|
||||
}
|
||||
return $baked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm a to be baked controller with the user
|
||||
*
|
||||
* @param string $controllerName The name of the controller.
|
||||
* @param string $useDynamicScaffold Whether or not to use dynamic scaffolds.
|
||||
* @param array $helpers The list of helpers to include.
|
||||
* @param array $components The list of components to include.
|
||||
* @return void
|
||||
*/
|
||||
public function confirmController($controllerName, $useDynamicScaffold, $helpers, $components) {
|
||||
$this->out();
|
||||
$this->hr();
|
||||
$this->out(__d('cake_console', 'The following controller will be created:'));
|
||||
$this->hr();
|
||||
$this->out(__d('cake_console', "Controller Name:\n\t%s", $controllerName));
|
||||
|
||||
if (strtolower($useDynamicScaffold) === 'y') {
|
||||
$this->out("public \$scaffold;");
|
||||
}
|
||||
|
||||
$properties = array(
|
||||
'helpers' => __d('cake_console', 'Helpers:'),
|
||||
'components' => __d('cake_console', 'Components:'),
|
||||
);
|
||||
|
||||
foreach ($properties as $var => $title) {
|
||||
if (count($$var)) {
|
||||
$output = '';
|
||||
$length = count($$var);
|
||||
foreach ($$var as $i => $propElement) {
|
||||
if ($i != $length - 1) {
|
||||
$output .= ucfirst($propElement) . ', ';
|
||||
} else {
|
||||
$output .= ucfirst($propElement);
|
||||
}
|
||||
}
|
||||
$this->out($title . "\n\t" . $output);
|
||||
}
|
||||
}
|
||||
$this->hr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Interact with the user and ask about which methods (admin or regular they want to bake)
|
||||
*
|
||||
* @return array Array containing (bakeRegular, bakeAdmin) answers
|
||||
*/
|
||||
protected function _askAboutMethods() {
|
||||
$wannaBakeCrud = $this->in(
|
||||
__d('cake_console', "Would you like to create some basic class methods \n(index(), add(), view(), edit())?"),
|
||||
array('y', 'n'), 'n'
|
||||
);
|
||||
$wannaBakeAdminCrud = $this->in(
|
||||
__d('cake_console', "Would you like to create the basic class methods for admin routing?"),
|
||||
array('y', 'n'), 'n'
|
||||
);
|
||||
return array($wannaBakeCrud, $wannaBakeAdminCrud);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bake scaffold actions
|
||||
*
|
||||
* @param string $controllerName Controller name
|
||||
* @param string $admin Admin route to use
|
||||
* @param bool $wannaUseSession Set to true to use sessions, false otherwise
|
||||
* @return string Baked actions
|
||||
*/
|
||||
public function bakeActions($controllerName, $admin = null, $wannaUseSession = true) {
|
||||
$currentModelName = $modelImport = $this->_modelName($controllerName);
|
||||
$plugin = $this->plugin;
|
||||
if ($plugin) {
|
||||
$plugin .= '.';
|
||||
}
|
||||
App::uses($modelImport, $plugin . 'Model');
|
||||
if (!class_exists($modelImport)) {
|
||||
$this->err(__d('cake_console', 'You must have a model for this class to build basic methods. Please try again.'));
|
||||
return $this->_stop();
|
||||
}
|
||||
|
||||
$modelObj = ClassRegistry::init($currentModelName);
|
||||
$controllerPath = $this->_controllerPath($controllerName);
|
||||
$pluralName = $this->_pluralName($currentModelName);
|
||||
$singularName = Inflector::variable($currentModelName);
|
||||
$singularHumanName = $this->_singularHumanName($controllerName);
|
||||
$pluralHumanName = $this->_pluralName($controllerName);
|
||||
$displayField = $modelObj->displayField;
|
||||
$primaryKey = $modelObj->primaryKey;
|
||||
|
||||
$this->Template->set(compact(
|
||||
'plugin', 'admin', 'controllerPath', 'pluralName', 'singularName',
|
||||
'singularHumanName', 'pluralHumanName', 'modelObj', 'wannaUseSession', 'currentModelName',
|
||||
'displayField', 'primaryKey'
|
||||
));
|
||||
$actions = $this->Template->generate('actions', 'controller_actions');
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assembles and writes a Controller file
|
||||
*
|
||||
* @param string $controllerName Controller name already pluralized and correctly cased.
|
||||
* @param string $actions Actions to add, or set the whole controller to use $scaffold (set $actions to 'scaffold')
|
||||
* @param array $helpers Helpers to use in controller
|
||||
* @param array $components Components to use in controller
|
||||
* @return string Baked controller
|
||||
*/
|
||||
public function bake($controllerName, $actions = '', $helpers = null, $components = null) {
|
||||
$this->out("\n" . __d('cake_console', 'Baking controller class for %s...', $controllerName), 1, Shell::QUIET);
|
||||
|
||||
$isScaffold = ($actions === 'scaffold') ? true : false;
|
||||
|
||||
$this->Template->set(array(
|
||||
'plugin' => $this->plugin,
|
||||
'pluginPath' => empty($this->plugin) ? '' : $this->plugin . '.'
|
||||
));
|
||||
|
||||
if (!in_array('Paginator', (array)$components)) {
|
||||
$components[] = 'Paginator';
|
||||
}
|
||||
|
||||
$this->Template->set(compact('controllerName', 'actions', 'helpers', 'components', 'isScaffold'));
|
||||
$contents = $this->Template->generate('classes', 'controller');
|
||||
|
||||
$path = $this->getPath();
|
||||
$filename = $path . $controllerName . 'Controller.php';
|
||||
if ($this->createFile($filename, $contents)) {
|
||||
return $contents;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assembles and writes a unit test file
|
||||
*
|
||||
* @param string $className Controller class name
|
||||
* @return string Baked test
|
||||
*/
|
||||
public function bakeTest($className) {
|
||||
$this->Test->plugin = $this->plugin;
|
||||
$this->Test->connection = $this->connection;
|
||||
$this->Test->interactive = $this->interactive;
|
||||
return $this->Test->bake('Controller', $className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interact with the user and get a list of additional helpers
|
||||
*
|
||||
* @return array Helpers that the user wants to use.
|
||||
*/
|
||||
public function doHelpers() {
|
||||
return $this->_doPropertyChoices(
|
||||
__d('cake_console', "Would you like this controller to use other helpers\nbesides HtmlHelper and FormHelper?"),
|
||||
__d('cake_console', "Please provide a comma separated list of the other\nhelper names you'd like to use.\nExample: 'Text, Js, Time'")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interact with the user and get a list of additional components
|
||||
*
|
||||
* @return array Components the user wants to use.
|
||||
*/
|
||||
public function doComponents() {
|
||||
$components = array('Paginator');
|
||||
return array_merge($components, $this->_doPropertyChoices(
|
||||
__d('cake_console', "Would you like this controller to use other components\nbesides PaginatorComponent?"),
|
||||
__d('cake_console', "Please provide a comma separated list of the component names you'd like to use.\nExample: 'Acl, Security, RequestHandler'")
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Common code for property choice handling.
|
||||
*
|
||||
* @param string $prompt A yes/no question to precede the list
|
||||
* @param string $example A question for a comma separated list, with examples.
|
||||
* @return array Array of values for property.
|
||||
*/
|
||||
protected function _doPropertyChoices($prompt, $example) {
|
||||
$proceed = $this->in($prompt, array('y', 'n'), 'n');
|
||||
$property = array();
|
||||
if (strtolower($proceed) === 'y') {
|
||||
$propertyList = $this->in($example);
|
||||
$propertyListTrimmed = str_replace(' ', '', $propertyList);
|
||||
$property = explode(',', $propertyListTrimmed);
|
||||
}
|
||||
return array_filter($property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs and gets the list of possible controllers from database
|
||||
*
|
||||
* @param string $useDbConfig Database configuration name
|
||||
* @return array Set of controllers
|
||||
*/
|
||||
public function listAll($useDbConfig = null) {
|
||||
if ($useDbConfig === null) {
|
||||
$useDbConfig = $this->connection;
|
||||
}
|
||||
$this->__tables = $this->Model->getAllTables($useDbConfig);
|
||||
|
||||
if ($this->interactive) {
|
||||
$this->out(__d('cake_console', 'Possible Controllers based on your current database:'));
|
||||
$this->hr();
|
||||
$this->_controllerNames = array();
|
||||
$count = count($this->__tables);
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$this->_controllerNames[] = $this->_controllerName($this->_modelName($this->__tables[$i]));
|
||||
$this->out(sprintf("%2d. %s", $i + 1, $this->_controllerNames[$i]));
|
||||
}
|
||||
return $this->_controllerNames;
|
||||
}
|
||||
return $this->__tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces the user to specify the controller he wants to bake, and returns the selected controller name.
|
||||
*
|
||||
* @param string $useDbConfig Connection name to get a controller name for.
|
||||
* @return string Controller name
|
||||
*/
|
||||
public function getName($useDbConfig = null) {
|
||||
$controllers = $this->listAll($useDbConfig);
|
||||
$enteredController = '';
|
||||
|
||||
while (!$enteredController) {
|
||||
$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');
|
||||
if ($enteredController === 'q') {
|
||||
$this->out(__d('cake_console', 'Exit'));
|
||||
return $this->_stop();
|
||||
}
|
||||
|
||||
if (!$enteredController || intval($enteredController) > count($controllers)) {
|
||||
$this->err(__d('cake_console', "The Controller name you supplied was empty,\nor the number you selected was not an option. Please try again."));
|
||||
$enteredController = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (intval($enteredController) > 0 && intval($enteredController) <= count($controllers)) {
|
||||
$controllerName = $controllers[intval($enteredController) - 1];
|
||||
} else {
|
||||
$controllerName = Inflector::camelize($enteredController);
|
||||
}
|
||||
return $controllerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the option parser instance and configures it.
|
||||
*
|
||||
* @return ConsoleOptionParser
|
||||
*/
|
||||
public function getOptionParser() {
|
||||
$parser = parent::getOptionParser();
|
||||
|
||||
$parser->description(
|
||||
__d('cake_console', 'Bake a controller for a model. Using options you can bake public, admin or both.'
|
||||
))->addArgument('name', array(
|
||||
'help' => __d('cake_console', 'Name of the controller to bake. Can use Plugin.name to bake controllers into plugins.')
|
||||
))->addOption('public', array(
|
||||
'help' => __d('cake_console', 'Bake a controller with basic crud actions (index, view, add, edit, delete).'),
|
||||
'boolean' => true
|
||||
))->addOption('admin', array(
|
||||
'help' => __d('cake_console', 'Bake a controller with crud actions for one of the Routing.prefixes.'),
|
||||
'boolean' => true
|
||||
))->addOption('plugin', array(
|
||||
'short' => 'p',
|
||||
'help' => __d('cake_console', 'Plugin to bake the controller into.')
|
||||
))->addOption('connection', array(
|
||||
'short' => 'c',
|
||||
'help' => __d('cake_console', 'The connection the controller\'s model is on.')
|
||||
))->addOption('theme', array(
|
||||
'short' => 't',
|
||||
'help' => __d('cake_console', 'Theme to use when baking code.')
|
||||
))->addOption('force', array(
|
||||
'short' => 'f',
|
||||
'help' => __d('cake_console', 'Force overwriting existing files without prompting.')
|
||||
))->addSubcommand('all', array(
|
||||
'help' => __d('cake_console', 'Bake all controllers with CRUD methods.')
|
||||
))->epilog(
|
||||
__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.')
|
||||
);
|
||||
|
||||
return $parser;
|
||||
}
|
||||
|
||||
}
|
||||
385
lib/Cake/Console/Command/Task/DbConfigTask.php
Normal file
385
lib/Cake/Console/Command/Task/DbConfigTask.php
Normal file
|
|
@ -0,0 +1,385 @@
|
|||
<?php
|
||||
/**
|
||||
* The DbConfig Task handles creating and updating the database.php
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 1.2
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
|
||||
/**
|
||||
* Task class for creating and updating the database configuration file.
|
||||
*
|
||||
* @package Cake.Console.Command.Task
|
||||
*/
|
||||
class DbConfigTask extends AppShell {
|
||||
|
||||
/**
|
||||
* path to CONFIG directory
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $path = null;
|
||||
|
||||
/**
|
||||
* Default configuration settings to use
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_defaultConfig = array(
|
||||
'name' => 'default',
|
||||
'datasource' => 'Database/Mysql',
|
||||
'persistent' => 'false',
|
||||
'host' => 'localhost',
|
||||
'login' => 'root',
|
||||
'password' => 'password',
|
||||
'database' => 'project_name',
|
||||
'schema' => null,
|
||||
'prefix' => null,
|
||||
'encoding' => null,
|
||||
'port' => null
|
||||
);
|
||||
|
||||
/**
|
||||
* String name of the database config class name.
|
||||
* Used for testing.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $databaseClassName = 'DATABASE_CONFIG';
|
||||
|
||||
/**
|
||||
* initialization callback
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function initialize() {
|
||||
$this->path = APP . 'Config' . DS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execution method always used for tasks
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute() {
|
||||
if (empty($this->args)) {
|
||||
$this->_interactive();
|
||||
return $this->_stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interactive interface
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _interactive() {
|
||||
$this->hr();
|
||||
$this->out(__d('cake_console', 'Database Configuration:'));
|
||||
$this->hr();
|
||||
$done = false;
|
||||
$dbConfigs = array();
|
||||
|
||||
while (!$done) {
|
||||
$name = '';
|
||||
|
||||
while (!$name) {
|
||||
$name = $this->in(__d('cake_console', "Name:"), null, 'default');
|
||||
if (preg_match('/[^a-z0-9_]/i', $name)) {
|
||||
$name = '';
|
||||
$this->out(__d('cake_console', 'The name may only contain unaccented latin characters, numbers or underscores'));
|
||||
} elseif (preg_match('/^[^a-z_]/i', $name)) {
|
||||
$name = '';
|
||||
$this->out(__d('cake_console', 'The name must start with an unaccented latin character or an underscore'));
|
||||
}
|
||||
}
|
||||
|
||||
$datasource = $this->in(__d('cake_console', 'Datasource:'), array('Mysql', 'Postgres', 'Sqlite', 'Sqlserver'), 'Mysql');
|
||||
|
||||
$persistent = $this->in(__d('cake_console', 'Persistent Connection?'), array('y', 'n'), 'n');
|
||||
if (strtolower($persistent) === 'n') {
|
||||
$persistent = 'false';
|
||||
} else {
|
||||
$persistent = 'true';
|
||||
}
|
||||
|
||||
$host = '';
|
||||
while (!$host) {
|
||||
$host = $this->in(__d('cake_console', 'Database Host:'), null, 'localhost');
|
||||
}
|
||||
|
||||
$port = '';
|
||||
while (!$port) {
|
||||
$port = $this->in(__d('cake_console', 'Port?'), null, 'n');
|
||||
}
|
||||
|
||||
if (strtolower($port) === 'n') {
|
||||
$port = null;
|
||||
}
|
||||
|
||||
$login = '';
|
||||
while (!$login) {
|
||||
$login = $this->in(__d('cake_console', 'User:'), null, 'root');
|
||||
}
|
||||
$password = '';
|
||||
$blankPassword = false;
|
||||
|
||||
while (!$password && !$blankPassword) {
|
||||
$password = $this->in(__d('cake_console', 'Password:'));
|
||||
|
||||
if (!$password) {
|
||||
$blank = $this->in(__d('cake_console', 'The password you supplied was empty. Use an empty password?'), array('y', 'n'), 'n');
|
||||
if ($blank === 'y') {
|
||||
$blankPassword = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$database = '';
|
||||
while (!$database) {
|
||||
$database = $this->in(__d('cake_console', 'Database Name:'), null, 'cake');
|
||||
}
|
||||
|
||||
$prefix = '';
|
||||
while (!$prefix) {
|
||||
$prefix = $this->in(__d('cake_console', 'Table Prefix?'), null, 'n');
|
||||
}
|
||||
if (strtolower($prefix) === 'n') {
|
||||
$prefix = null;
|
||||
}
|
||||
|
||||
$encoding = '';
|
||||
while (!$encoding) {
|
||||
$encoding = $this->in(__d('cake_console', 'Table encoding?'), null, 'n');
|
||||
}
|
||||
if (strtolower($encoding) === 'n') {
|
||||
$encoding = null;
|
||||
}
|
||||
|
||||
$schema = '';
|
||||
if ($datasource === 'postgres') {
|
||||
while (!$schema) {
|
||||
$schema = $this->in(__d('cake_console', 'Table schema?'), null, 'n');
|
||||
}
|
||||
}
|
||||
if (strtolower($schema) === 'n') {
|
||||
$schema = null;
|
||||
}
|
||||
|
||||
$config = compact('name', 'datasource', 'persistent', 'host', 'login', 'password', 'database', 'prefix', 'encoding', 'port', 'schema');
|
||||
|
||||
while (!$this->_verify($config)) {
|
||||
$this->_interactive();
|
||||
}
|
||||
|
||||
$dbConfigs[] = $config;
|
||||
$doneYet = $this->in(__d('cake_console', 'Do you wish to add another database configuration?'), null, 'n');
|
||||
|
||||
if (strtolower($doneYet === 'n')) {
|
||||
$done = true;
|
||||
}
|
||||
}
|
||||
|
||||
$this->bake($dbConfigs);
|
||||
config('database');
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output verification message and bake if it looks good
|
||||
*
|
||||
* @param array $config The config data.
|
||||
* @return bool True if user says it looks good, false otherwise
|
||||
*/
|
||||
protected function _verify($config) {
|
||||
$config += $this->_defaultConfig;
|
||||
extract($config);
|
||||
$this->out();
|
||||
$this->hr();
|
||||
$this->out(__d('cake_console', 'The following database configuration will be created:'));
|
||||
$this->hr();
|
||||
$this->out(__d('cake_console', "Name: %s", $name));
|
||||
$this->out(__d('cake_console', "Datasource: %s", $datasource));
|
||||
$this->out(__d('cake_console', "Persistent: %s", $persistent));
|
||||
$this->out(__d('cake_console', "Host: %s", $host));
|
||||
|
||||
if ($port) {
|
||||
$this->out(__d('cake_console', "Port: %s", $port));
|
||||
}
|
||||
|
||||
$this->out(__d('cake_console', "User: %s", $login));
|
||||
$this->out(__d('cake_console', "Pass: %s", str_repeat('*', strlen($password))));
|
||||
$this->out(__d('cake_console', "Database: %s", $database));
|
||||
|
||||
if ($prefix) {
|
||||
$this->out(__d('cake_console', "Table prefix: %s", $prefix));
|
||||
}
|
||||
|
||||
if ($schema) {
|
||||
$this->out(__d('cake_console', "Schema: %s", $schema));
|
||||
}
|
||||
|
||||
if ($encoding) {
|
||||
$this->out(__d('cake_console', "Encoding: %s", $encoding));
|
||||
}
|
||||
|
||||
$this->hr();
|
||||
$looksGood = $this->in(__d('cake_console', 'Look okay?'), array('y', 'n'), 'y');
|
||||
|
||||
if (strtolower($looksGood) === 'y') {
|
||||
return $config;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assembles and writes database.php
|
||||
*
|
||||
* @param array $configs Configuration settings to use
|
||||
* @return bool Success
|
||||
*/
|
||||
public function bake($configs) {
|
||||
if (!is_dir($this->path)) {
|
||||
$this->err(__d('cake_console', '%s not found', $this->path));
|
||||
return false;
|
||||
}
|
||||
|
||||
$filename = $this->path . 'database.php';
|
||||
$oldConfigs = array();
|
||||
|
||||
if (file_exists($filename)) {
|
||||
config('database');
|
||||
$db = new $this->databaseClassName;
|
||||
$temp = get_class_vars(get_class($db));
|
||||
|
||||
foreach ($temp as $configName => $info) {
|
||||
$info += $this->_defaultConfig;
|
||||
|
||||
if (!isset($info['schema'])) {
|
||||
$info['schema'] = null;
|
||||
}
|
||||
if (!isset($info['encoding'])) {
|
||||
$info['encoding'] = null;
|
||||
}
|
||||
if (!isset($info['port'])) {
|
||||
$info['port'] = null;
|
||||
}
|
||||
|
||||
$info['persistent'] = var_export((bool)$info['persistent'], true);
|
||||
|
||||
$oldConfigs[] = array(
|
||||
'name' => $configName,
|
||||
'datasource' => $info['datasource'],
|
||||
'persistent' => $info['persistent'],
|
||||
'host' => $info['host'],
|
||||
'port' => $info['port'],
|
||||
'login' => $info['login'],
|
||||
'password' => $info['password'],
|
||||
'database' => $info['database'],
|
||||
'prefix' => $info['prefix'],
|
||||
'schema' => $info['schema'],
|
||||
'encoding' => $info['encoding']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($oldConfigs as $key => $oldConfig) {
|
||||
foreach ($configs as $config) {
|
||||
if ($oldConfig['name'] === $config['name']) {
|
||||
unset($oldConfigs[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$configs = array_merge($oldConfigs, $configs);
|
||||
$out = "<?php\n";
|
||||
$out .= "class DATABASE_CONFIG {\n\n";
|
||||
|
||||
foreach ($configs as $config) {
|
||||
$config += $this->_defaultConfig;
|
||||
extract($config);
|
||||
|
||||
if (strpos($datasource, 'Database/') === false) {
|
||||
$datasource = "Database/{$datasource}";
|
||||
}
|
||||
$out .= "\tpublic \${$name} = array(\n";
|
||||
$out .= "\t\t'datasource' => '{$datasource}',\n";
|
||||
$out .= "\t\t'persistent' => {$persistent},\n";
|
||||
$out .= "\t\t'host' => '{$host}',\n";
|
||||
|
||||
if ($port) {
|
||||
$out .= "\t\t'port' => {$port},\n";
|
||||
}
|
||||
|
||||
$out .= "\t\t'login' => '{$login}',\n";
|
||||
$out .= "\t\t'password' => '{$password}',\n";
|
||||
$out .= "\t\t'database' => '{$database}',\n";
|
||||
|
||||
if ($schema) {
|
||||
$out .= "\t\t'schema' => '{$schema}',\n";
|
||||
}
|
||||
|
||||
if ($prefix) {
|
||||
$out .= "\t\t'prefix' => '{$prefix}',\n";
|
||||
}
|
||||
|
||||
if ($encoding) {
|
||||
$out .= "\t\t'encoding' => '{$encoding}'\n";
|
||||
}
|
||||
|
||||
$out .= "\t);\n";
|
||||
}
|
||||
|
||||
$out .= "}\n";
|
||||
$filename = $this->path . 'database.php';
|
||||
return $this->createFile($filename, $out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a user specified Connection name
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getConfig() {
|
||||
App::uses('ConnectionManager', 'Model');
|
||||
$configs = ConnectionManager::enumConnectionObjects();
|
||||
|
||||
$useDbConfig = key($configs);
|
||||
if (!is_array($configs) || empty($configs)) {
|
||||
return $this->execute();
|
||||
}
|
||||
$connections = array_keys($configs);
|
||||
|
||||
if (count($connections) > 1) {
|
||||
$useDbConfig = $this->in(__d('cake_console', 'Use Database Config') . ':', $connections, $useDbConfig);
|
||||
}
|
||||
return $useDbConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the option parser instance and configures it.
|
||||
*
|
||||
* @return ConsoleOptionParser
|
||||
*/
|
||||
public function getOptionParser() {
|
||||
$parser = parent::getOptionParser();
|
||||
|
||||
$parser->description(
|
||||
__d('cake_console', 'Bake new database configuration settings.')
|
||||
);
|
||||
|
||||
return $parser;
|
||||
}
|
||||
|
||||
}
|
||||
811
lib/Cake/Console/Command/Task/ExtractTask.php
Normal file
811
lib/Cake/Console/Command/Task/ExtractTask.php
Normal file
|
|
@ -0,0 +1,811 @@
|
|||
<?php
|
||||
/**
|
||||
* Language string extractor
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 1.2.0.5012
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
App::uses('File', 'Utility');
|
||||
App::uses('Folder', 'Utility');
|
||||
App::uses('Hash', 'Utility');
|
||||
|
||||
/**
|
||||
* Language string extractor
|
||||
*
|
||||
* @package Cake.Console.Command.Task
|
||||
*/
|
||||
class ExtractTask extends AppShell {
|
||||
|
||||
/**
|
||||
* Paths to use when looking for strings
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_paths = array();
|
||||
|
||||
/**
|
||||
* Files from where to extract
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_files = array();
|
||||
|
||||
/**
|
||||
* Merge all domain and category strings into the default.pot file
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_merge = false;
|
||||
|
||||
/**
|
||||
* Current file being processed
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_file = null;
|
||||
|
||||
/**
|
||||
* Contains all content waiting to be write
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_storage = array();
|
||||
|
||||
/**
|
||||
* Extracted tokens
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_tokens = array();
|
||||
|
||||
/**
|
||||
* Extracted strings indexed by category and domain.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_translations = array();
|
||||
|
||||
/**
|
||||
* Destination path
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_output = null;
|
||||
|
||||
/**
|
||||
* An array of directories to exclude.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_exclude = array();
|
||||
|
||||
/**
|
||||
* Holds whether this call should extract model validation messages
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_extractValidation = true;
|
||||
|
||||
/**
|
||||
* Holds the validation string domain to use for validation messages when extracting
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_validationDomain = 'default';
|
||||
|
||||
/**
|
||||
* Holds whether this call should extract the CakePHP Lib messages
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_extractCore = false;
|
||||
|
||||
/**
|
||||
* Method to interact with the User and get path selections.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _getPaths() {
|
||||
$defaultPath = APP;
|
||||
while (true) {
|
||||
$currentPaths = count($this->_paths) > 0 ? $this->_paths : array('None');
|
||||
$message = __d(
|
||||
'cake_console',
|
||||
"Current paths: %s\nWhat is the path you would like to extract?\n[Q]uit [D]one",
|
||||
implode(', ', $currentPaths)
|
||||
);
|
||||
$response = $this->in($message, null, $defaultPath);
|
||||
if (strtoupper($response) === 'Q') {
|
||||
$this->err(__d('cake_console', 'Extract Aborted'));
|
||||
return $this->_stop();
|
||||
} elseif (strtoupper($response) === 'D' && count($this->_paths)) {
|
||||
$this->out();
|
||||
return;
|
||||
} elseif (strtoupper($response) === 'D') {
|
||||
$this->err(__d('cake_console', '<warning>No directories selected.</warning> Please choose a directory.'));
|
||||
} elseif (is_dir($response)) {
|
||||
$this->_paths[] = $response;
|
||||
$defaultPath = 'D';
|
||||
} else {
|
||||
$this->err(__d('cake_console', 'The directory path you supplied was not found. Please try again.'));
|
||||
}
|
||||
$this->out();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execution method always used for tasks
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute() {
|
||||
if (!empty($this->params['exclude'])) {
|
||||
$this->_exclude = explode(',', $this->params['exclude']);
|
||||
}
|
||||
if (isset($this->params['files']) && !is_array($this->params['files'])) {
|
||||
$this->_files = explode(',', $this->params['files']);
|
||||
}
|
||||
if (isset($this->params['paths'])) {
|
||||
$this->_paths = explode(',', $this->params['paths']);
|
||||
} elseif (isset($this->params['plugin'])) {
|
||||
$plugin = Inflector::camelize($this->params['plugin']);
|
||||
if (!CakePlugin::loaded($plugin)) {
|
||||
CakePlugin::load($plugin);
|
||||
}
|
||||
$this->_paths = array(CakePlugin::path($plugin));
|
||||
$this->params['plugin'] = $plugin;
|
||||
} else {
|
||||
$this->_getPaths();
|
||||
}
|
||||
|
||||
if (isset($this->params['extract-core'])) {
|
||||
$this->_extractCore = !(strtolower($this->params['extract-core']) === 'no');
|
||||
} else {
|
||||
$response = $this->in(__d('cake_console', 'Would you like to extract the messages from the CakePHP core?'), array('y', 'n'), 'n');
|
||||
$this->_extractCore = strtolower($response) === 'y';
|
||||
}
|
||||
|
||||
if (!empty($this->params['exclude-plugins']) && $this->_isExtractingApp()) {
|
||||
$this->_exclude = array_merge($this->_exclude, App::path('plugins'));
|
||||
}
|
||||
|
||||
if (!empty($this->params['ignore-model-validation']) || (!$this->_isExtractingApp() && empty($plugin))) {
|
||||
$this->_extractValidation = false;
|
||||
}
|
||||
if (!empty($this->params['validation-domain'])) {
|
||||
$this->_validationDomain = $this->params['validation-domain'];
|
||||
}
|
||||
|
||||
if ($this->_extractCore) {
|
||||
$this->_paths[] = CAKE;
|
||||
$this->_exclude = array_merge($this->_exclude, array(
|
||||
CAKE . 'Test',
|
||||
CAKE . 'Console' . DS . 'Templates'
|
||||
));
|
||||
}
|
||||
|
||||
if (isset($this->params['output'])) {
|
||||
$this->_output = $this->params['output'];
|
||||
} elseif (isset($this->params['plugin'])) {
|
||||
$this->_output = $this->_paths[0] . DS . 'Locale';
|
||||
} else {
|
||||
$message = __d('cake_console', "What is the path you would like to output?\n[Q]uit", $this->_paths[0] . DS . 'Locale');
|
||||
while (true) {
|
||||
$response = $this->in($message, null, rtrim($this->_paths[0], DS) . DS . 'Locale');
|
||||
if (strtoupper($response) === 'Q') {
|
||||
$this->err(__d('cake_console', 'Extract Aborted'));
|
||||
return $this->_stop();
|
||||
} elseif ($this->_isPathUsable($response)) {
|
||||
$this->_output = $response . DS;
|
||||
break;
|
||||
} else {
|
||||
$this->err(__d('cake_console', 'The directory path you supplied was not found. Please try again.'));
|
||||
}
|
||||
$this->out();
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->params['merge'])) {
|
||||
$this->_merge = !(strtolower($this->params['merge']) === 'no');
|
||||
} else {
|
||||
$this->out();
|
||||
$response = $this->in(__d('cake_console', 'Would you like to merge all domain and category strings into the default.pot file?'), array('y', 'n'), 'n');
|
||||
$this->_merge = strtolower($response) === 'y';
|
||||
}
|
||||
|
||||
if (empty($this->_files)) {
|
||||
$this->_searchFiles();
|
||||
}
|
||||
|
||||
$this->_output = rtrim($this->_output, DS) . DS;
|
||||
if (!$this->_isPathUsable($this->_output)) {
|
||||
$this->err(__d('cake_console', 'The output directory %s was not found or writable.', $this->_output));
|
||||
return $this->_stop();
|
||||
}
|
||||
|
||||
$this->_extract();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a translation to the internal translations property
|
||||
*
|
||||
* Takes care of duplicate translations
|
||||
*
|
||||
* @param string $category The category
|
||||
* @param string $domain The domain
|
||||
* @param string $msgid The message string
|
||||
* @param array $details The file and line references
|
||||
* @return void
|
||||
*/
|
||||
protected function _addTranslation($category, $domain, $msgid, $details = array()) {
|
||||
if (empty($this->_translations[$category][$domain][$msgid])) {
|
||||
$this->_translations[$category][$domain][$msgid] = array(
|
||||
'msgid_plural' => false
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($details['msgid_plural'])) {
|
||||
$this->_translations[$category][$domain][$msgid]['msgid_plural'] = $details['msgid_plural'];
|
||||
}
|
||||
|
||||
if (isset($details['file'])) {
|
||||
$line = 0;
|
||||
if (isset($details['line'])) {
|
||||
$line = $details['line'];
|
||||
}
|
||||
$this->_translations[$category][$domain][$msgid]['references'][$details['file']][] = $line;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract text
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _extract() {
|
||||
$this->out();
|
||||
$this->out();
|
||||
$this->out(__d('cake_console', 'Extracting...'));
|
||||
$this->hr();
|
||||
$this->out(__d('cake_console', 'Paths:'));
|
||||
foreach ($this->_paths as $path) {
|
||||
$this->out(' ' . $path);
|
||||
}
|
||||
$this->out(__d('cake_console', 'Output Directory: ') . $this->_output);
|
||||
$this->hr();
|
||||
$this->_extractTokens();
|
||||
$this->_extractValidationMessages();
|
||||
$this->_buildFiles();
|
||||
$this->_writeFiles();
|
||||
$this->_paths = $this->_files = $this->_storage = array();
|
||||
$this->_translations = $this->_tokens = array();
|
||||
$this->_extractValidation = true;
|
||||
$this->out();
|
||||
$this->out(__d('cake_console', 'Done.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the option parser instance and configures it.
|
||||
*
|
||||
* @return ConsoleOptionParser
|
||||
*/
|
||||
public function getOptionParser() {
|
||||
$parser = parent::getOptionParser();
|
||||
|
||||
$parser->description(
|
||||
__d('cake_console', 'CakePHP Language String Extraction:')
|
||||
)->addOption('app', array(
|
||||
'help' => __d('cake_console', 'Directory where your application is located.')
|
||||
))->addOption('paths', array(
|
||||
'help' => __d('cake_console', 'Comma separated list of paths.')
|
||||
))->addOption('merge', array(
|
||||
'help' => __d('cake_console', 'Merge all domain and category strings into the default.po file.'),
|
||||
'choices' => array('yes', 'no')
|
||||
))->addOption('output', array(
|
||||
'help' => __d('cake_console', 'Full path to output directory.')
|
||||
))->addOption('files', array(
|
||||
'help' => __d('cake_console', 'Comma separated list of files.')
|
||||
))->addOption('exclude-plugins', array(
|
||||
'boolean' => true,
|
||||
'default' => true,
|
||||
'help' => __d('cake_console', 'Ignores all files in plugins if this command is run inside from the same app directory.')
|
||||
))->addOption('plugin', array(
|
||||
'help' => __d('cake_console', 'Extracts tokens only from the plugin specified and puts the result in the plugin\'s Locale directory.')
|
||||
))->addOption('ignore-model-validation', array(
|
||||
'boolean' => true,
|
||||
'default' => false,
|
||||
'help' => __d('cake_console', 'Ignores validation messages in the $validate property.' .
|
||||
' If this flag is not set and the command is run from the same app directory,' .
|
||||
' all messages in model validation rules will be extracted as tokens.'
|
||||
)
|
||||
))->addOption('validation-domain', array(
|
||||
'help' => __d('cake_console', 'If set to a value, the localization domain to be used for model validation messages.')
|
||||
))->addOption('exclude', array(
|
||||
'help' => __d('cake_console', 'Comma separated list of directories to exclude.' .
|
||||
' Any path containing a path segment with the provided values will be skipped. E.g. test,vendors'
|
||||
)
|
||||
))->addOption('overwrite', array(
|
||||
'boolean' => true,
|
||||
'default' => false,
|
||||
'help' => __d('cake_console', 'Always overwrite existing .pot files.')
|
||||
))->addOption('extract-core', array(
|
||||
'help' => __d('cake_console', 'Extract messages from the CakePHP core libs.'),
|
||||
'choices' => array('yes', 'no')
|
||||
));
|
||||
|
||||
return $parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract tokens out of all files to be processed
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _extractTokens() {
|
||||
foreach ($this->_files as $file) {
|
||||
$this->_file = $file;
|
||||
$this->out(__d('cake_console', 'Processing %s...', $file));
|
||||
|
||||
$code = file_get_contents($file);
|
||||
$allTokens = token_get_all($code);
|
||||
|
||||
$this->_tokens = array();
|
||||
foreach ($allTokens as $token) {
|
||||
if (!is_array($token) || ($token[0] != T_WHITESPACE && $token[0] != T_INLINE_HTML)) {
|
||||
$this->_tokens[] = $token;
|
||||
}
|
||||
}
|
||||
unset($allTokens);
|
||||
$this->_parse('__', array('singular'));
|
||||
$this->_parse('__n', array('singular', 'plural'));
|
||||
$this->_parse('__d', array('domain', 'singular'));
|
||||
$this->_parse('__c', array('singular', 'category'));
|
||||
$this->_parse('__dc', array('domain', 'singular', 'category'));
|
||||
$this->_parse('__dn', array('domain', 'singular', 'plural'));
|
||||
$this->_parse('__dcn', array('domain', 'singular', 'plural', 'count', 'category'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse tokens
|
||||
*
|
||||
* @param string $functionName Function name that indicates translatable string (e.g: '__')
|
||||
* @param array $map Array containing what variables it will find (e.g: category, domain, singular, plural)
|
||||
* @return void
|
||||
*/
|
||||
protected function _parse($functionName, $map) {
|
||||
$count = 0;
|
||||
$categories = array('LC_ALL', 'LC_COLLATE', 'LC_CTYPE', 'LC_MONETARY', 'LC_NUMERIC', 'LC_TIME', 'LC_MESSAGES');
|
||||
$tokenCount = count($this->_tokens);
|
||||
|
||||
while (($tokenCount - $count) > 1) {
|
||||
$countToken = $this->_tokens[$count];
|
||||
$firstParenthesis = $this->_tokens[$count + 1];
|
||||
if (!is_array($countToken)) {
|
||||
$count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
list($type, $string, $line) = $countToken;
|
||||
if (($type == T_STRING) && ($string == $functionName) && ($firstParenthesis === '(')) {
|
||||
$position = $count;
|
||||
$depth = 0;
|
||||
|
||||
while (!$depth) {
|
||||
if ($this->_tokens[$position] === '(') {
|
||||
$depth++;
|
||||
} elseif ($this->_tokens[$position] === ')') {
|
||||
$depth--;
|
||||
}
|
||||
$position++;
|
||||
}
|
||||
|
||||
$mapCount = count($map);
|
||||
$strings = $this->_getStrings($position, $mapCount);
|
||||
|
||||
if ($mapCount === count($strings)) {
|
||||
extract(array_combine($map, $strings));
|
||||
$category = isset($category) ? $category : 6;
|
||||
$category = intval($category);
|
||||
$categoryName = $categories[$category];
|
||||
$domain = isset($domain) ? $domain : 'default';
|
||||
$details = array(
|
||||
'file' => $this->_file,
|
||||
'line' => $line,
|
||||
);
|
||||
if (isset($plural)) {
|
||||
$details['msgid_plural'] = $plural;
|
||||
}
|
||||
$this->_addTranslation($categoryName, $domain, $singular, $details);
|
||||
} else {
|
||||
$this->_markerError($this->_file, $line, $functionName, $count);
|
||||
}
|
||||
}
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for models in the application and extracts the validation messages
|
||||
* to be added to the translation map
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _extractValidationMessages() {
|
||||
if (!$this->_extractValidation) {
|
||||
return;
|
||||
}
|
||||
|
||||
$plugins = array(null);
|
||||
if (empty($this->params['exclude-plugins'])) {
|
||||
$plugins = array_merge($plugins, App::objects('plugin', null, false));
|
||||
}
|
||||
foreach ($plugins as $plugin) {
|
||||
$this->_extractPluginValidationMessages($plugin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract validation messages from application or plugin models
|
||||
*
|
||||
* @param string $plugin Plugin name or `null` to process application models
|
||||
* @return void
|
||||
*/
|
||||
protected function _extractPluginValidationMessages($plugin = null) {
|
||||
App::uses('AppModel', 'Model');
|
||||
if (!empty($plugin)) {
|
||||
if (!CakePlugin::loaded($plugin)) {
|
||||
return;
|
||||
}
|
||||
App::uses($plugin . 'AppModel', $plugin . '.Model');
|
||||
$plugin = $plugin . '.';
|
||||
}
|
||||
$models = App::objects($plugin . 'Model', null, false);
|
||||
|
||||
foreach ($models as $model) {
|
||||
App::uses($model, $plugin . 'Model');
|
||||
$reflection = new ReflectionClass($model);
|
||||
if (!$reflection->isSubClassOf('Model')) {
|
||||
continue;
|
||||
}
|
||||
$properties = $reflection->getDefaultProperties();
|
||||
$validate = $properties['validate'];
|
||||
if (empty($validate)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$file = $reflection->getFileName();
|
||||
$domain = $this->_validationDomain;
|
||||
if (!empty($properties['validationDomain'])) {
|
||||
$domain = $properties['validationDomain'];
|
||||
}
|
||||
foreach ($validate as $field => $rules) {
|
||||
$this->_processValidationRules($field, $rules, $file, $domain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a validation rule for a field and looks for a message to be added
|
||||
* to the translation map
|
||||
*
|
||||
* @param string $field the name of the field that is being processed
|
||||
* @param array $rules the set of validation rules for the field
|
||||
* @param string $file the file name where this validation rule was found
|
||||
* @param string $domain default domain to bind the validations to
|
||||
* @param string $category the translation category
|
||||
* @return void
|
||||
*/
|
||||
protected function _processValidationRules($field, $rules, $file, $domain, $category = 'LC_MESSAGES') {
|
||||
if (!is_array($rules)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$dims = Hash::dimensions($rules);
|
||||
if ($dims === 1 || ($dims === 2 && isset($rules['message']))) {
|
||||
$rules = array($rules);
|
||||
}
|
||||
|
||||
foreach ($rules as $rule => $validateProp) {
|
||||
$msgid = null;
|
||||
if (isset($validateProp['message'])) {
|
||||
if (is_array($validateProp['message'])) {
|
||||
$msgid = $validateProp['message'][0];
|
||||
} else {
|
||||
$msgid = $validateProp['message'];
|
||||
}
|
||||
} elseif (is_string($rule)) {
|
||||
$msgid = $rule;
|
||||
}
|
||||
if ($msgid) {
|
||||
$msgid = $this->_formatString(sprintf("'%s'", $msgid));
|
||||
$details = array(
|
||||
'file' => $file,
|
||||
'line' => 'validation for field ' . $field
|
||||
);
|
||||
$this->_addTranslation($category, $domain, $msgid, $details);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the translate template file contents out of obtained strings
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _buildFiles() {
|
||||
$paths = $this->_paths;
|
||||
$paths[] = realpath(APP) . DS;
|
||||
foreach ($this->_translations as $category => $domains) {
|
||||
foreach ($domains as $domain => $translations) {
|
||||
foreach ($translations as $msgid => $details) {
|
||||
$plural = $details['msgid_plural'];
|
||||
$files = $details['references'];
|
||||
$occurrences = array();
|
||||
foreach ($files as $file => $lines) {
|
||||
$lines = array_unique($lines);
|
||||
$occurrences[] = $file . ':' . implode(';', $lines);
|
||||
}
|
||||
$occurrences = implode("\n#: ", $occurrences);
|
||||
$header = '#: ' . str_replace(DS, '/', str_replace($paths, '', $occurrences)) . "\n";
|
||||
|
||||
if ($plural === false) {
|
||||
$sentence = "msgid \"{$msgid}\"\n";
|
||||
$sentence .= "msgstr \"\"\n\n";
|
||||
} else {
|
||||
$sentence = "msgid \"{$msgid}\"\n";
|
||||
$sentence .= "msgid_plural \"{$plural}\"\n";
|
||||
$sentence .= "msgstr[0] \"\"\n";
|
||||
$sentence .= "msgstr[1] \"\"\n\n";
|
||||
}
|
||||
|
||||
$this->_store($category, $domain, $header, $sentence);
|
||||
if (($category !== 'LC_MESSAGES' || $domain !== 'default') && $this->_merge) {
|
||||
$this->_store('LC_MESSAGES', 'default', $header, $sentence);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare a file to be stored
|
||||
*
|
||||
* @param string $category The category
|
||||
* @param string $domain The domain
|
||||
* @param string $header The header content.
|
||||
* @param string $sentence The sentence to store.
|
||||
* @return void
|
||||
*/
|
||||
protected function _store($category, $domain, $header, $sentence) {
|
||||
if (!isset($this->_storage[$category])) {
|
||||
$this->_storage[$category] = array();
|
||||
}
|
||||
if (!isset($this->_storage[$category][$domain])) {
|
||||
$this->_storage[$category][$domain] = array();
|
||||
}
|
||||
if (!isset($this->_storage[$category][$domain][$sentence])) {
|
||||
$this->_storage[$category][$domain][$sentence] = $header;
|
||||
} else {
|
||||
$this->_storage[$category][$domain][$sentence] .= $header;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the files that need to be stored
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _writeFiles() {
|
||||
$overwriteAll = false;
|
||||
if (!empty($this->params['overwrite'])) {
|
||||
$overwriteAll = true;
|
||||
}
|
||||
foreach ($this->_storage as $category => $domains) {
|
||||
foreach ($domains as $domain => $sentences) {
|
||||
$output = $this->_writeHeader();
|
||||
foreach ($sentences as $sentence => $header) {
|
||||
$output .= $header . $sentence;
|
||||
}
|
||||
|
||||
$filename = $domain . '.pot';
|
||||
if ($category === 'LC_MESSAGES') {
|
||||
$File = new File($this->_output . $filename);
|
||||
} else {
|
||||
new Folder($this->_output . $category, true);
|
||||
$File = new File($this->_output . $category . DS . $filename);
|
||||
}
|
||||
$response = '';
|
||||
while ($overwriteAll === false && $File->exists() && strtoupper($response) !== 'Y') {
|
||||
$this->out();
|
||||
$response = $this->in(
|
||||
__d('cake_console', 'Error: %s already exists in this location. Overwrite? [Y]es, [N]o, [A]ll', $filename),
|
||||
array('y', 'n', 'a'),
|
||||
'y'
|
||||
);
|
||||
if (strtoupper($response) === 'N') {
|
||||
$response = '';
|
||||
while (!$response) {
|
||||
$response = $this->in(__d('cake_console', "What would you like to name this file?"), null, 'new_' . $filename);
|
||||
$File = new File($this->_output . $response);
|
||||
$filename = $response;
|
||||
}
|
||||
} elseif (strtoupper($response) === 'A') {
|
||||
$overwriteAll = true;
|
||||
}
|
||||
}
|
||||
$File->write($output);
|
||||
$File->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the translation template header
|
||||
*
|
||||
* @return string Translation template header
|
||||
*/
|
||||
protected function _writeHeader() {
|
||||
$output = "# LANGUAGE translation of CakePHP Application\n";
|
||||
$output .= "# Copyright YEAR NAME <EMAIL@ADDRESS>\n";
|
||||
$output .= "#\n";
|
||||
$output .= "#, fuzzy\n";
|
||||
$output .= "msgid \"\"\n";
|
||||
$output .= "msgstr \"\"\n";
|
||||
$output .= "\"Project-Id-Version: PROJECT VERSION\\n\"\n";
|
||||
$output .= "\"POT-Creation-Date: " . date("Y-m-d H:iO") . "\\n\"\n";
|
||||
$output .= "\"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\\n\"\n";
|
||||
$output .= "\"Last-Translator: NAME <EMAIL@ADDRESS>\\n\"\n";
|
||||
$output .= "\"Language-Team: LANGUAGE <EMAIL@ADDRESS>\\n\"\n";
|
||||
$output .= "\"MIME-Version: 1.0\\n\"\n";
|
||||
$output .= "\"Content-Type: text/plain; charset=utf-8\\n\"\n";
|
||||
$output .= "\"Content-Transfer-Encoding: 8bit\\n\"\n";
|
||||
$output .= "\"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\\n\"\n\n";
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the strings from the position forward
|
||||
*
|
||||
* @param int &$position Actual position on tokens array
|
||||
* @param int $target Number of strings to extract
|
||||
* @return array Strings extracted
|
||||
*/
|
||||
protected function _getStrings(&$position, $target) {
|
||||
$strings = array();
|
||||
$count = count($strings);
|
||||
while ($count < $target && ($this->_tokens[$position] === ',' || $this->_tokens[$position][0] == T_CONSTANT_ENCAPSED_STRING || $this->_tokens[$position][0] == T_LNUMBER)) {
|
||||
$count = count($strings);
|
||||
if ($this->_tokens[$position][0] == T_CONSTANT_ENCAPSED_STRING && $this->_tokens[$position + 1] === '.') {
|
||||
$string = '';
|
||||
while ($this->_tokens[$position][0] == T_CONSTANT_ENCAPSED_STRING || $this->_tokens[$position] === '.') {
|
||||
if ($this->_tokens[$position][0] == T_CONSTANT_ENCAPSED_STRING) {
|
||||
$string .= $this->_formatString($this->_tokens[$position][1]);
|
||||
}
|
||||
$position++;
|
||||
}
|
||||
$strings[] = $string;
|
||||
} elseif ($this->_tokens[$position][0] == T_CONSTANT_ENCAPSED_STRING) {
|
||||
$strings[] = $this->_formatString($this->_tokens[$position][1]);
|
||||
} elseif ($this->_tokens[$position][0] == T_LNUMBER) {
|
||||
$strings[] = $this->_tokens[$position][1];
|
||||
}
|
||||
$position++;
|
||||
}
|
||||
return $strings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a string to be added as a translatable string
|
||||
*
|
||||
* @param string $string String to format
|
||||
* @return string Formatted string
|
||||
*/
|
||||
protected function _formatString($string) {
|
||||
$quote = substr($string, 0, 1);
|
||||
$string = substr($string, 1, -1);
|
||||
if ($quote === '"') {
|
||||
$string = stripcslashes($string);
|
||||
} else {
|
||||
$string = strtr($string, array("\\'" => "'", "\\\\" => "\\"));
|
||||
}
|
||||
$string = str_replace("\r\n", "\n", $string);
|
||||
return addcslashes($string, "\0..\37\\\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate an invalid marker on a processed file
|
||||
*
|
||||
* @param string $file File where invalid marker resides
|
||||
* @param int $line Line number
|
||||
* @param string $marker Marker found
|
||||
* @param int $count Count
|
||||
* @return void
|
||||
*/
|
||||
protected function _markerError($file, $line, $marker, $count) {
|
||||
$this->err(__d('cake_console', "Invalid marker content in %s:%s\n* %s(", $file, $line, $marker));
|
||||
$count += 2;
|
||||
$tokenCount = count($this->_tokens);
|
||||
$parenthesis = 1;
|
||||
|
||||
while ((($tokenCount - $count) > 0) && $parenthesis) {
|
||||
if (is_array($this->_tokens[$count])) {
|
||||
$this->err($this->_tokens[$count][1], false);
|
||||
} else {
|
||||
$this->err($this->_tokens[$count], false);
|
||||
if ($this->_tokens[$count] === '(') {
|
||||
$parenthesis++;
|
||||
}
|
||||
|
||||
if ($this->_tokens[$count] === ')') {
|
||||
$parenthesis--;
|
||||
}
|
||||
}
|
||||
$count++;
|
||||
}
|
||||
$this->err("\n", true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search files that may contain translatable strings
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _searchFiles() {
|
||||
$pattern = false;
|
||||
if (!empty($this->_exclude)) {
|
||||
$exclude = array();
|
||||
foreach ($this->_exclude as $e) {
|
||||
if (DS !== '\\' && $e[0] !== DS) {
|
||||
$e = DS . $e;
|
||||
}
|
||||
$exclude[] = preg_quote($e, '/');
|
||||
}
|
||||
$pattern = '/' . implode('|', $exclude) . '/';
|
||||
}
|
||||
foreach ($this->_paths as $path) {
|
||||
$Folder = new Folder($path);
|
||||
$files = $Folder->findRecursive('.*\.(php|ctp|thtml|inc|tpl)', true);
|
||||
if (!empty($pattern)) {
|
||||
foreach ($files as $i => $file) {
|
||||
if (preg_match($pattern, $file)) {
|
||||
unset($files[$i]);
|
||||
}
|
||||
}
|
||||
$files = array_values($files);
|
||||
}
|
||||
$this->_files = array_merge($this->_files, $files);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this execution is meant to extract string only from directories in folder represented by the
|
||||
* APP constant, i.e. this task is extracting strings from same application.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function _isExtractingApp() {
|
||||
return $this->_paths === array(APP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not a given path is usable for writing.
|
||||
*
|
||||
* @param string $path Path to folder
|
||||
* @return bool true if it exists and is writable, false otherwise
|
||||
*/
|
||||
protected function _isPathUsable($path) {
|
||||
return is_dir($path) && is_writable($path);
|
||||
}
|
||||
}
|
||||
451
lib/Cake/Console/Command/Task/FixtureTask.php
Normal file
451
lib/Cake/Console/Command/Task/FixtureTask.php
Normal file
|
|
@ -0,0 +1,451 @@
|
|||
<?php
|
||||
/**
|
||||
* The FixtureTask handles creating and updating fixture files.
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 1.3
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
App::uses('BakeTask', 'Console/Command/Task');
|
||||
App::uses('Model', 'Model');
|
||||
|
||||
/**
|
||||
* Task class for creating and updating fixtures files.
|
||||
*
|
||||
* @package Cake.Console.Command.Task
|
||||
*/
|
||||
class FixtureTask extends BakeTask {
|
||||
|
||||
/**
|
||||
* Tasks to be loaded by this Task
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $tasks = array('DbConfig', 'Model', 'Template');
|
||||
|
||||
/**
|
||||
* path to fixtures directory
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $path = null;
|
||||
|
||||
/**
|
||||
* Schema instance
|
||||
*
|
||||
* @var CakeSchema
|
||||
*/
|
||||
protected $_Schema = null;
|
||||
|
||||
/**
|
||||
* Override initialize
|
||||
*
|
||||
* @param ConsoleOutput $stdout A ConsoleOutput object for stdout.
|
||||
* @param ConsoleOutput $stderr A ConsoleOutput object for stderr.
|
||||
* @param ConsoleInput $stdin A ConsoleInput object for stdin.
|
||||
*/
|
||||
public function __construct($stdout = null, $stderr = null, $stdin = null) {
|
||||
parent::__construct($stdout, $stderr, $stdin);
|
||||
$this->path = APP . 'Test' . DS . 'Fixture' . DS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the option parser instance and configures it.
|
||||
*
|
||||
* @return ConsoleOptionParser
|
||||
*/
|
||||
public function getOptionParser() {
|
||||
$parser = parent::getOptionParser();
|
||||
|
||||
$parser->description(
|
||||
__d('cake_console', 'Generate fixtures for use with the test suite. You can use `bake fixture all` to bake all fixtures.')
|
||||
)->addArgument('name', array(
|
||||
'help' => __d('cake_console', 'Name of the fixture to bake. Can use Plugin.name to bake plugin fixtures.')
|
||||
))->addOption('count', array(
|
||||
'help' => __d('cake_console', 'When using generated data, the number of records to include in the fixture(s).'),
|
||||
'short' => 'n',
|
||||
'default' => 10
|
||||
))->addOption('connection', array(
|
||||
'help' => __d('cake_console', 'Which database configuration to use for baking.'),
|
||||
'short' => 'c',
|
||||
'default' => 'default'
|
||||
))->addOption('plugin', array(
|
||||
'help' => __d('cake_console', 'CamelCased name of the plugin to bake fixtures for.'),
|
||||
'short' => 'p'
|
||||
))->addOption('schema', array(
|
||||
'help' => __d('cake_console', 'Importing schema for fixtures rather than hardcoding it.'),
|
||||
'short' => 's',
|
||||
'boolean' => true
|
||||
))->addOption('theme', array(
|
||||
'short' => 't',
|
||||
'help' => __d('cake_console', 'Theme to use when baking code.')
|
||||
))->addOption('force', array(
|
||||
'short' => 'f',
|
||||
'help' => __d('cake_console', 'Force overwriting existing files without prompting.')
|
||||
))->addOption('records', array(
|
||||
'help' => __d('cake_console', 'Used with --count and <name>/all commands to pull [n] records from the live tables, ' .
|
||||
'where [n] is either --count or the default of 10.'),
|
||||
'short' => 'r',
|
||||
'boolean' => true
|
||||
))->epilog(
|
||||
__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.')
|
||||
);
|
||||
|
||||
return $parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execution method always used for tasks
|
||||
* Handles dispatching to interactive, named, or all processes.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute() {
|
||||
parent::execute();
|
||||
if (empty($this->args)) {
|
||||
$this->_interactive();
|
||||
}
|
||||
|
||||
if (isset($this->args[0])) {
|
||||
$this->interactive = false;
|
||||
if (!isset($this->connection)) {
|
||||
$this->connection = 'default';
|
||||
}
|
||||
if (strtolower($this->args[0]) === 'all') {
|
||||
return $this->all();
|
||||
}
|
||||
$model = $this->_modelName($this->args[0]);
|
||||
$this->bake($model);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bake All the Fixtures at once. Will only bake fixtures for models that exist.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function all() {
|
||||
$this->interactive = false;
|
||||
$this->Model->interactive = false;
|
||||
$tables = $this->Model->listAll($this->connection, false);
|
||||
|
||||
foreach ($tables as $table) {
|
||||
$model = $this->_modelName($table);
|
||||
$importOptions = array();
|
||||
if (!empty($this->params['schema'])) {
|
||||
$importOptions['schema'] = $model;
|
||||
}
|
||||
$this->bake($model, false, $importOptions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interactive baking function
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _interactive() {
|
||||
$this->DbConfig->interactive = $this->Model->interactive = $this->interactive = true;
|
||||
$this->hr();
|
||||
$this->out(__d('cake_console', "Bake Fixture\nPath: %s", $this->getPath()));
|
||||
$this->hr();
|
||||
|
||||
if (!isset($this->connection)) {
|
||||
$this->connection = $this->DbConfig->getConfig();
|
||||
}
|
||||
$modelName = $this->Model->getName($this->connection);
|
||||
$useTable = $this->Model->getTable($modelName, $this->connection);
|
||||
$importOptions = $this->importOptions($modelName);
|
||||
$this->bake($modelName, $useTable, $importOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interacts with the User to setup an array of import options. For a fixture.
|
||||
*
|
||||
* @param string $modelName Name of model you are dealing with.
|
||||
* @return array Array of import options.
|
||||
*/
|
||||
public function importOptions($modelName) {
|
||||
$options = array();
|
||||
|
||||
if (!empty($this->params['schema'])) {
|
||||
$options['schema'] = $modelName;
|
||||
} else {
|
||||
$doSchema = $this->in(__d('cake_console', 'Would you like to import schema for this fixture?'), array('y', 'n'), 'n');
|
||||
if ($doSchema === 'y') {
|
||||
$options['schema'] = $modelName;
|
||||
}
|
||||
}
|
||||
if (!empty($this->params['records'])) {
|
||||
$doRecords = 'y';
|
||||
} else {
|
||||
$doRecords = $this->in(__d('cake_console', 'Would you like to use record importing for this fixture?'), array('y', 'n'), 'n');
|
||||
}
|
||||
if ($doRecords === 'y') {
|
||||
$options['records'] = true;
|
||||
}
|
||||
if ($doRecords === 'n') {
|
||||
$prompt = __d('cake_console', "Would you like to build this fixture with data from %s's table?", $modelName);
|
||||
$fromTable = $this->in($prompt, array('y', 'n'), 'n');
|
||||
if (strtolower($fromTable) === 'y') {
|
||||
$options['fromTable'] = true;
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assembles and writes a Fixture file
|
||||
*
|
||||
* @param string $model Name of model to bake.
|
||||
* @param string $useTable Name of table to use.
|
||||
* @param array $importOptions Options for public $import
|
||||
* @return string Baked fixture content
|
||||
*/
|
||||
public function bake($model, $useTable = false, $importOptions = array()) {
|
||||
App::uses('CakeSchema', 'Model');
|
||||
$table = $schema = $records = $import = $modelImport = null;
|
||||
$importBits = array();
|
||||
|
||||
if (!$useTable) {
|
||||
$useTable = Inflector::tableize($model);
|
||||
} elseif ($useTable != Inflector::tableize($model)) {
|
||||
$table = $useTable;
|
||||
}
|
||||
|
||||
if (!empty($importOptions)) {
|
||||
if (isset($importOptions['schema'])) {
|
||||
$modelImport = true;
|
||||
$importBits[] = "'model' => '{$importOptions['schema']}'";
|
||||
}
|
||||
if (isset($importOptions['records'])) {
|
||||
$importBits[] = "'records' => true";
|
||||
}
|
||||
if ($this->connection !== 'default') {
|
||||
$importBits[] .= "'connection' => '{$this->connection}'";
|
||||
}
|
||||
if (!empty($importBits)) {
|
||||
$import = sprintf("array(%s)", implode(', ', $importBits));
|
||||
}
|
||||
}
|
||||
|
||||
$this->_Schema = new CakeSchema();
|
||||
$data = $this->_Schema->read(array('models' => false, 'connection' => $this->connection));
|
||||
if (!isset($data['tables'][$useTable])) {
|
||||
$this->error('Could not find your selected table ' . $useTable);
|
||||
return false;
|
||||
}
|
||||
|
||||
$tableInfo = $data['tables'][$useTable];
|
||||
if ($modelImport === null) {
|
||||
$schema = $this->_generateSchema($tableInfo);
|
||||
}
|
||||
|
||||
if (empty($importOptions['records']) && !isset($importOptions['fromTable'])) {
|
||||
$recordCount = 1;
|
||||
if (isset($this->params['count'])) {
|
||||
$recordCount = $this->params['count'];
|
||||
}
|
||||
$records = $this->_makeRecordString($this->_generateRecords($tableInfo, $recordCount));
|
||||
}
|
||||
if (!empty($this->params['records']) || isset($importOptions['fromTable'])) {
|
||||
$records = $this->_makeRecordString($this->_getRecordsFromTable($model, $useTable));
|
||||
}
|
||||
$out = $this->generateFixtureFile($model, compact('records', 'table', 'schema', 'import'));
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the fixture file, and write to disk
|
||||
*
|
||||
* @param string $model name of the model being generated
|
||||
* @param string $otherVars Contents of the fixture file.
|
||||
* @return string Content saved into fixture file.
|
||||
*/
|
||||
public function generateFixtureFile($model, $otherVars) {
|
||||
$defaults = array('table' => null, 'schema' => null, 'records' => null, 'import' => null, 'fields' => null);
|
||||
$vars = array_merge($defaults, $otherVars);
|
||||
|
||||
$path = $this->getPath();
|
||||
$filename = Inflector::camelize($model) . 'Fixture.php';
|
||||
|
||||
$this->Template->set('model', $model);
|
||||
$this->Template->set($vars);
|
||||
$content = $this->Template->generate('classes', 'fixture');
|
||||
|
||||
$this->out("\n" . __d('cake_console', 'Baking test fixture for %s...', $model), 1, Shell::QUIET);
|
||||
$this->createFile($path . $filename, $content);
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the fixtures.
|
||||
*
|
||||
* @return string Path for the fixtures
|
||||
*/
|
||||
public function getPath() {
|
||||
$path = $this->path;
|
||||
if (isset($this->plugin)) {
|
||||
$path = $this->_pluginPath($this->plugin) . 'Test' . DS . 'Fixture' . DS;
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a string representation of a schema.
|
||||
*
|
||||
* @param array $tableInfo Table schema array
|
||||
* @return string fields definitions
|
||||
*/
|
||||
protected function _generateSchema($tableInfo) {
|
||||
$schema = trim($this->_Schema->generateTable('f', $tableInfo), "\n");
|
||||
return substr($schema, 13, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate String representation of Records
|
||||
*
|
||||
* @param array $tableInfo Table schema array
|
||||
* @param int $recordCount The number of records to generate.
|
||||
* @return array Array of records to use in the fixture.
|
||||
*/
|
||||
protected function _generateRecords($tableInfo, $recordCount = 1) {
|
||||
$records = array();
|
||||
for ($i = 0; $i < $recordCount; $i++) {
|
||||
$record = array();
|
||||
foreach ($tableInfo as $field => $fieldInfo) {
|
||||
if (empty($fieldInfo['type'])) {
|
||||
continue;
|
||||
}
|
||||
$insert = '';
|
||||
switch ($fieldInfo['type']) {
|
||||
case 'integer':
|
||||
case 'float':
|
||||
$insert = $i + 1;
|
||||
break;
|
||||
case 'string':
|
||||
case 'binary':
|
||||
$isPrimaryUuid = (
|
||||
isset($fieldInfo['key']) && strtolower($fieldInfo['key']) === 'primary' &&
|
||||
isset($fieldInfo['length']) && $fieldInfo['length'] == 36
|
||||
);
|
||||
if ($isPrimaryUuid) {
|
||||
$insert = String::uuid();
|
||||
} else {
|
||||
$insert = "Lorem ipsum dolor sit amet";
|
||||
if (!empty($fieldInfo['length'])) {
|
||||
$insert = substr($insert, 0, (int)$fieldInfo['length'] - 2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'timestamp':
|
||||
$insert = time();
|
||||
break;
|
||||
case 'datetime':
|
||||
$insert = date('Y-m-d H:i:s');
|
||||
break;
|
||||
case 'date':
|
||||
$insert = date('Y-m-d');
|
||||
break;
|
||||
case 'time':
|
||||
$insert = date('H:i:s');
|
||||
break;
|
||||
case 'boolean':
|
||||
$insert = 1;
|
||||
break;
|
||||
case 'text':
|
||||
$insert = "Lorem ipsum dolor sit amet, aliquet feugiat.";
|
||||
$insert .= " Convallis morbi fringilla gravida,";
|
||||
$insert .= " phasellus feugiat dapibus velit nunc, pulvinar eget sollicitudin";
|
||||
$insert .= " venenatis cum nullam, vivamus ut a sed, mollitia lectus. Nulla";
|
||||
$insert .= " vestibulum massa neque ut et, id hendrerit sit,";
|
||||
$insert .= " feugiat in taciti enim proin nibh, tempor dignissim, rhoncus";
|
||||
$insert .= " duis vestibulum nunc mattis convallis.";
|
||||
break;
|
||||
}
|
||||
$record[$field] = $insert;
|
||||
}
|
||||
$records[] = $record;
|
||||
}
|
||||
return $records;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a $records array into a a string.
|
||||
*
|
||||
* @param array $records Array of records to be converted to string
|
||||
* @return string A string value of the $records array.
|
||||
*/
|
||||
protected function _makeRecordString($records) {
|
||||
$out = "array(\n";
|
||||
foreach ($records as $record) {
|
||||
$values = array();
|
||||
foreach ($record as $field => $value) {
|
||||
$val = var_export($value, true);
|
||||
if ($val === 'NULL') {
|
||||
$val = 'null';
|
||||
}
|
||||
$values[] = "\t\t\t'$field' => $val";
|
||||
}
|
||||
$out .= "\t\tarray(\n";
|
||||
$out .= implode(",\n", $values);
|
||||
$out .= "\n\t\t),\n";
|
||||
}
|
||||
$out .= "\t)";
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interact with the user to get a custom SQL condition and use that to extract data
|
||||
* to build a fixture.
|
||||
*
|
||||
* @param string $modelName name of the model to take records from.
|
||||
* @param string $useTable Name of table to use.
|
||||
* @return array Array of records.
|
||||
*/
|
||||
protected function _getRecordsFromTable($modelName, $useTable = null) {
|
||||
if ($this->interactive) {
|
||||
$condition = null;
|
||||
$prompt = __d('cake_console', "Please provide a SQL fragment to use as conditions\nExample: WHERE 1=1");
|
||||
while (!$condition) {
|
||||
$condition = $this->in($prompt, null, 'WHERE 1=1');
|
||||
}
|
||||
$prompt = __d('cake_console', "How many records do you want to import?");
|
||||
$recordCount = $this->in($prompt, null, 10);
|
||||
} else {
|
||||
$condition = 'WHERE 1=1';
|
||||
$recordCount = (isset($this->params['count']) ? $this->params['count'] : 10);
|
||||
}
|
||||
$modelObject = new Model(array('name' => $modelName, 'table' => $useTable, 'ds' => $this->connection));
|
||||
$records = $modelObject->find('all', array(
|
||||
'conditions' => $condition,
|
||||
'recursive' => -1,
|
||||
'limit' => $recordCount
|
||||
));
|
||||
|
||||
$schema = $modelObject->schema(true);
|
||||
$out = array();
|
||||
foreach ($records as $record) {
|
||||
$row = array();
|
||||
foreach ($record[$modelObject->alias] as $field => $value) {
|
||||
if ($schema[$field]['type'] === 'boolean') {
|
||||
$value = (int)(bool)$value;
|
||||
}
|
||||
$row[$field] = $value;
|
||||
}
|
||||
$out[] = $row;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
}
|
||||
1049
lib/Cake/Console/Command/Task/ModelTask.php
Normal file
1049
lib/Cake/Console/Command/Task/ModelTask.php
Normal file
File diff suppressed because it is too large
Load diff
231
lib/Cake/Console/Command/Task/PluginTask.php
Normal file
231
lib/Cake/Console/Command/Task/PluginTask.php
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
<?php
|
||||
/**
|
||||
* The Plugin Task handles creating an empty plugin, ready to be used
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 1.2
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
App::uses('File', 'Utility');
|
||||
App::uses('Folder', 'Utility');
|
||||
|
||||
/**
|
||||
* The Plugin Task handles creating an empty plugin, ready to be used
|
||||
*
|
||||
* @package Cake.Console.Command.Task
|
||||
*/
|
||||
class PluginTask extends AppShell {
|
||||
|
||||
/**
|
||||
* path to plugins directory
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $path = null;
|
||||
|
||||
/**
|
||||
* Path to the bootstrap file. Changed in tests.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $bootstrap = null;
|
||||
|
||||
/**
|
||||
* initialize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function initialize() {
|
||||
$this->path = current(App::path('plugins'));
|
||||
$this->bootstrap = APP . 'Config' . DS . 'bootstrap.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Execution method always used for tasks
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute() {
|
||||
if (isset($this->args[0])) {
|
||||
$plugin = Inflector::camelize($this->args[0]);
|
||||
$pluginPath = $this->_pluginPath($plugin);
|
||||
if (is_dir($pluginPath)) {
|
||||
$this->out(__d('cake_console', 'Plugin: %s already exists, no action taken', $plugin));
|
||||
$this->out(__d('cake_console', 'Path: %s', $pluginPath));
|
||||
return false;
|
||||
}
|
||||
$this->_interactive($plugin);
|
||||
} else {
|
||||
return $this->_interactive();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interactive interface
|
||||
*
|
||||
* @param string $plugin The plugin name.
|
||||
* @return void
|
||||
*/
|
||||
protected function _interactive($plugin = null) {
|
||||
while ($plugin === null) {
|
||||
$plugin = $this->in(__d('cake_console', 'Enter the name of the plugin in CamelCase format'));
|
||||
}
|
||||
|
||||
if (!$this->bake($plugin)) {
|
||||
$this->error(__d('cake_console', "An error occurred trying to bake: %s in %s", $plugin, $this->path . $plugin));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bake the plugin, create directories and files
|
||||
*
|
||||
* @param string $plugin Name of the plugin in CamelCased format
|
||||
* @return bool
|
||||
*/
|
||||
public function bake($plugin) {
|
||||
$pathOptions = App::path('plugins');
|
||||
if (count($pathOptions) > 1) {
|
||||
$this->findPath($pathOptions);
|
||||
}
|
||||
$this->hr();
|
||||
$this->out(__d('cake_console', "<info>Plugin Name:</info> %s", $plugin));
|
||||
$this->out(__d('cake_console', "<info>Plugin Directory:</info> %s", $this->path . $plugin));
|
||||
$this->hr();
|
||||
|
||||
$looksGood = $this->in(__d('cake_console', 'Look okay?'), array('y', 'n', 'q'), 'y');
|
||||
|
||||
if (strtolower($looksGood) === 'y') {
|
||||
$Folder = new Folder($this->path . $plugin);
|
||||
$directories = array(
|
||||
'Config' . DS . 'Schema',
|
||||
'Model' . DS . 'Behavior',
|
||||
'Model' . DS . 'Datasource',
|
||||
'Console' . DS . 'Command' . DS . 'Task',
|
||||
'Controller' . DS . 'Component',
|
||||
'Lib',
|
||||
'View' . DS . 'Helper',
|
||||
'Test' . DS . 'Case' . DS . 'Controller' . DS . 'Component',
|
||||
'Test' . DS . 'Case' . DS . 'View' . DS . 'Helper',
|
||||
'Test' . DS . 'Case' . DS . 'Model' . DS . 'Behavior',
|
||||
'Test' . DS . 'Fixture',
|
||||
'Vendor',
|
||||
'webroot'
|
||||
);
|
||||
|
||||
foreach ($directories as $directory) {
|
||||
$dirPath = $this->path . $plugin . DS . $directory;
|
||||
$Folder->create($dirPath);
|
||||
new File($dirPath . DS . 'empty', true);
|
||||
}
|
||||
|
||||
foreach ($Folder->messages() as $message) {
|
||||
$this->out($message, 1, Shell::VERBOSE);
|
||||
}
|
||||
|
||||
$errors = $Folder->errors();
|
||||
if (!empty($errors)) {
|
||||
foreach ($errors as $message) {
|
||||
$this->error($message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$controllerFileName = $plugin . 'AppController.php';
|
||||
|
||||
$out = "<?php\n\n";
|
||||
$out .= "App::uses('AppController', 'Controller');\n\n";
|
||||
$out .= "class {$plugin}AppController extends AppController {\n\n";
|
||||
$out .= "}\n";
|
||||
$this->createFile($this->path . $plugin . DS . 'Controller' . DS . $controllerFileName, $out);
|
||||
|
||||
$modelFileName = $plugin . 'AppModel.php';
|
||||
|
||||
$out = "<?php\n\n";
|
||||
$out .= "App::uses('AppModel', 'Model');\n\n";
|
||||
$out .= "class {$plugin}AppModel extends AppModel {\n\n";
|
||||
$out .= "}\n";
|
||||
$this->createFile($this->path . $plugin . DS . 'Model' . DS . $modelFileName, $out);
|
||||
|
||||
$this->_modifyBootstrap($plugin);
|
||||
|
||||
$this->hr();
|
||||
$this->out(__d('cake_console', '<success>Created:</success> %s in %s', $plugin, $this->path . $plugin), 2);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the app's bootstrap.php file.
|
||||
*
|
||||
* @param string $plugin Name of plugin
|
||||
* @return void
|
||||
*/
|
||||
protected function _modifyBootstrap($plugin) {
|
||||
$bootstrap = new File($this->bootstrap, false);
|
||||
$contents = $bootstrap->read();
|
||||
if (!preg_match("@\n\s*CakePlugin::loadAll@", $contents)) {
|
||||
$bootstrap->append("\nCakePlugin::load('$plugin', array('bootstrap' => false, 'routes' => false));\n");
|
||||
$this->out('');
|
||||
$this->out(__d('cake_dev', '%s modified', $this->bootstrap));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* find and change $this->path to the user selection
|
||||
*
|
||||
* @param array $pathOptions The list of paths to look in.
|
||||
* @return void
|
||||
*/
|
||||
public function findPath($pathOptions) {
|
||||
$valid = false;
|
||||
foreach ($pathOptions as $i => $path) {
|
||||
if (!is_dir($path)) {
|
||||
unset($pathOptions[$i]);
|
||||
}
|
||||
}
|
||||
$pathOptions = array_values($pathOptions);
|
||||
|
||||
$max = count($pathOptions);
|
||||
while (!$valid) {
|
||||
foreach ($pathOptions as $i => $option) {
|
||||
$this->out($i + 1 . '. ' . $option);
|
||||
}
|
||||
$prompt = __d('cake_console', 'Choose a plugin path from the paths above.');
|
||||
$choice = $this->in($prompt, null, 1);
|
||||
if (intval($choice) > 0 && intval($choice) <= $max) {
|
||||
$valid = true;
|
||||
}
|
||||
}
|
||||
$this->path = $pathOptions[$choice - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the option parser instance and configures it.
|
||||
*
|
||||
* @return ConsoleOptionParser
|
||||
*/
|
||||
public function getOptionParser() {
|
||||
$parser = parent::getOptionParser();
|
||||
|
||||
$parser->description(
|
||||
__d('cake_console', 'Create the directory structure, AppModel and AppController classes for a new plugin. ' .
|
||||
'Can create plugins in any of your bootstrapped plugin paths.')
|
||||
)->addArgument('name', array(
|
||||
'help' => __d('cake_console', 'CamelCased name of the plugin to create.')
|
||||
));
|
||||
|
||||
return $parser;
|
||||
}
|
||||
|
||||
}
|
||||
448
lib/Cake/Console/Command/Task/ProjectTask.php
Normal file
448
lib/Cake/Console/Command/Task/ProjectTask.php
Normal file
|
|
@ -0,0 +1,448 @@
|
|||
<?php
|
||||
/**
|
||||
* The Project Task handles creating the base application
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 1.2
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
App::uses('File', 'Utility');
|
||||
App::uses('Folder', 'Utility');
|
||||
App::uses('String', 'Utility');
|
||||
App::uses('Security', 'Utility');
|
||||
|
||||
/**
|
||||
* Task class for creating new project apps and plugins
|
||||
*
|
||||
* @package Cake.Console.Command.Task
|
||||
*/
|
||||
class ProjectTask extends AppShell {
|
||||
|
||||
/**
|
||||
* configs path (used in testing).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $configPath = null;
|
||||
|
||||
/**
|
||||
* Checks that given project path does not already exist, and
|
||||
* finds the app directory in it. Then it calls bake() with that information.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function execute() {
|
||||
$project = null;
|
||||
if (isset($this->args[0])) {
|
||||
$project = $this->args[0];
|
||||
} else {
|
||||
$appContents = array_diff(scandir(APP), array('.', '..'));
|
||||
if (empty($appContents)) {
|
||||
$suggestedPath = rtrim(APP, DS);
|
||||
} else {
|
||||
$suggestedPath = APP . 'myapp';
|
||||
}
|
||||
}
|
||||
|
||||
while (!$project) {
|
||||
$prompt = __d('cake_console', "What is the path to the project you want to bake?");
|
||||
$project = $this->in($prompt, null, $suggestedPath);
|
||||
}
|
||||
|
||||
if ($project && !Folder::isAbsolute($project) && isset($_SERVER['PWD'])) {
|
||||
$project = $_SERVER['PWD'] . DS . $project;
|
||||
}
|
||||
|
||||
$response = false;
|
||||
while (!$response && is_dir($project) === true && file_exists($project . 'Config' . 'core.php')) {
|
||||
$prompt = __d('cake_console', '<warning>A project already exists in this location:</warning> %s Overwrite?', $project);
|
||||
$response = $this->in($prompt, array('y', 'n'), 'n');
|
||||
if (strtolower($response) === 'n') {
|
||||
$response = $project = false;
|
||||
}
|
||||
}
|
||||
|
||||
$success = true;
|
||||
if ($this->bake($project)) {
|
||||
$path = Folder::slashTerm($project);
|
||||
|
||||
if ($this->securitySalt($path) === true) {
|
||||
$this->out(__d('cake_console', ' * Random hash key created for \'Security.salt\''));
|
||||
} else {
|
||||
$this->err(__d('cake_console', 'Unable to generate random hash for \'Security.salt\', you should change it in %s', APP . 'Config' . DS . 'core.php'));
|
||||
$success = false;
|
||||
}
|
||||
|
||||
if ($this->securityCipherSeed($path) === true) {
|
||||
$this->out(__d('cake_console', ' * Random seed created for \'Security.cipherSeed\''));
|
||||
} else {
|
||||
$this->err(__d('cake_console', 'Unable to generate random seed for \'Security.cipherSeed\', you should change it in %s', APP . 'Config' . DS . 'core.php'));
|
||||
$success = false;
|
||||
}
|
||||
|
||||
if ($this->cachePrefix($path)) {
|
||||
$this->out(__d('cake_console', ' * Cache prefix set'));
|
||||
} else {
|
||||
$this->err(__d('cake_console', 'The cache prefix was <error>NOT</error> set'));
|
||||
$success = false;
|
||||
}
|
||||
|
||||
if ($this->consolePath($path) === true) {
|
||||
$this->out(__d('cake_console', ' * app/Console/cake.php path set.'));
|
||||
} else {
|
||||
$this->err(__d('cake_console', 'Unable to set console path for app/Console.'));
|
||||
$success = false;
|
||||
}
|
||||
|
||||
$hardCode = false;
|
||||
if ($this->cakeOnIncludePath()) {
|
||||
$this->out(__d('cake_console', '<info>CakePHP is on your `include_path`. CAKE_CORE_INCLUDE_PATH will be set, but commented out.</info>'));
|
||||
} else {
|
||||
$this->out(__d('cake_console', '<warning>CakePHP is not on your `include_path`, CAKE_CORE_INCLUDE_PATH will be hard coded.</warning>'));
|
||||
$this->out(__d('cake_console', 'You can fix this by adding CakePHP to your `include_path`.'));
|
||||
$hardCode = true;
|
||||
}
|
||||
$success = $this->corePath($path, $hardCode) === true;
|
||||
if ($success) {
|
||||
$this->out(__d('cake_console', ' * CAKE_CORE_INCLUDE_PATH set to %s in %s', CAKE_CORE_INCLUDE_PATH, 'webroot/index.php'));
|
||||
$this->out(__d('cake_console', ' * CAKE_CORE_INCLUDE_PATH set to %s in %s', CAKE_CORE_INCLUDE_PATH, 'webroot/test.php'));
|
||||
} else {
|
||||
$this->err(__d('cake_console', 'Unable to set CAKE_CORE_INCLUDE_PATH, you should change it in %s', $path . 'webroot' . DS . 'index.php'));
|
||||
$success = false;
|
||||
}
|
||||
if ($success && $hardCode) {
|
||||
$this->out(__d('cake_console', ' * <warning>Remember to check these values after moving to production server</warning>'));
|
||||
}
|
||||
|
||||
$Folder = new Folder($path);
|
||||
if (!$Folder->chmod($path . 'tmp', 0777)) {
|
||||
$this->err(__d('cake_console', 'Could not set permissions on %s', $path . DS . 'tmp'));
|
||||
$this->out('chmod -R 0777 ' . $path . DS . 'tmp');
|
||||
$success = false;
|
||||
}
|
||||
if ($success) {
|
||||
$this->out(__d('cake_console', '<success>Project baked successfully!</success>'));
|
||||
} else {
|
||||
$this->out(__d('cake_console', 'Project baked but with <warning>some issues.</warning>.'));
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks PHP's include_path for CakePHP.
|
||||
*
|
||||
* @return bool Indicates whether or not CakePHP exists on include_path
|
||||
*/
|
||||
public function cakeOnIncludePath() {
|
||||
$paths = explode(PATH_SEPARATOR, ini_get('include_path'));
|
||||
foreach ($paths as $path) {
|
||||
if (file_exists($path . DS . 'Cake' . DS . 'bootstrap.php')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for a skeleton template of a Cake application,
|
||||
* and if not found asks the user for a path. When there is a path
|
||||
* this method will make a deep copy of the skeleton to the project directory.
|
||||
*
|
||||
* @param string $path Project path
|
||||
* @param string $skel Path to copy from
|
||||
* @param string $skip array of directories to skip when copying
|
||||
* @return mixed
|
||||
*/
|
||||
public function bake($path, $skel = null, $skip = array('empty')) {
|
||||
if (!$skel && !empty($this->params['skel'])) {
|
||||
$skel = $this->params['skel'];
|
||||
}
|
||||
while (!$skel) {
|
||||
$skel = $this->in(
|
||||
__d('cake_console', "What is the path to the directory layout you wish to copy?"),
|
||||
null,
|
||||
CAKE . 'Console' . DS . 'Templates' . DS . 'skel'
|
||||
);
|
||||
if (!$skel) {
|
||||
$this->err(__d('cake_console', 'The directory path you supplied was empty. Please try again.'));
|
||||
} else {
|
||||
while (is_dir($skel) === false) {
|
||||
$skel = $this->in(
|
||||
__d('cake_console', 'Directory path does not exist please choose another:'),
|
||||
null,
|
||||
CAKE . 'Console' . DS . 'Templates' . DS . 'skel'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$app = basename($path);
|
||||
|
||||
$this->out(__d('cake_console', '<info>Skel Directory</info>: ') . $skel);
|
||||
$this->out(__d('cake_console', '<info>Will be copied to</info>: ') . $path);
|
||||
$this->hr();
|
||||
|
||||
$looksGood = $this->in(__d('cake_console', 'Look okay?'), array('y', 'n', 'q'), 'y');
|
||||
|
||||
switch (strtolower($looksGood)) {
|
||||
case 'y':
|
||||
$Folder = new Folder($skel);
|
||||
if (!empty($this->params['empty'])) {
|
||||
$skip = array();
|
||||
}
|
||||
|
||||
if ($Folder->copy(array('to' => $path, 'skip' => $skip))) {
|
||||
$this->hr();
|
||||
$this->out(__d('cake_console', '<success>Created:</success> %s in %s', $app, $path));
|
||||
$this->hr();
|
||||
} else {
|
||||
$this->err(__d('cake_console', "<error>Could not create</error> '%s' properly.", $app));
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($Folder->messages() as $message) {
|
||||
$this->out(String::wrap(' * ' . $message), 1, Shell::VERBOSE);
|
||||
}
|
||||
|
||||
return true;
|
||||
case 'n':
|
||||
unset($this->args[0]);
|
||||
$this->execute();
|
||||
return false;
|
||||
case 'q':
|
||||
$this->out(__d('cake_console', '<error>Bake Aborted.</error>'));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the correct path to the CakePHP libs that are generating the project
|
||||
* and points app/console/cake.php to the right place
|
||||
*
|
||||
* @param string $path Project path.
|
||||
* @return bool success
|
||||
*/
|
||||
public function consolePath($path) {
|
||||
$File = new File($path . 'Console' . DS . 'cake.php');
|
||||
$contents = $File->read();
|
||||
if (preg_match('/(__CAKE_PATH__)/', $contents, $match)) {
|
||||
$root = strpos(CAKE_CORE_INCLUDE_PATH, '/') === 0 ? " \$ds . '" : "'";
|
||||
$replacement = $root . str_replace(DS, "' . \$ds . '", trim(CAKE_CORE_INCLUDE_PATH, DS)) . "'";
|
||||
$result = str_replace($match[0], $replacement, $contents);
|
||||
if ($File->write($result)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and writes 'Security.salt'
|
||||
*
|
||||
* @param string $path Project path
|
||||
* @return bool Success
|
||||
*/
|
||||
public function securitySalt($path) {
|
||||
$File = new File($path . 'Config' . DS . 'core.php');
|
||||
$contents = $File->read();
|
||||
if (preg_match('/([\s]*Configure::write\(\'Security.salt\',[\s\'A-z0-9]*\);)/', $contents, $match)) {
|
||||
$string = Security::generateAuthKey();
|
||||
$result = str_replace($match[0], "\t" . 'Configure::write(\'Security.salt\', \'' . $string . '\');', $contents);
|
||||
if ($File->write($result)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and writes 'Security.cipherSeed'
|
||||
*
|
||||
* @param string $path Project path
|
||||
* @return bool Success
|
||||
*/
|
||||
public function securityCipherSeed($path) {
|
||||
$File = new File($path . 'Config' . DS . 'core.php');
|
||||
$contents = $File->read();
|
||||
if (preg_match('/([\s]*Configure::write\(\'Security.cipherSeed\',[\s\'A-z0-9]*\);)/', $contents, $match)) {
|
||||
App::uses('Security', 'Utility');
|
||||
$string = substr(bin2hex(Security::generateAuthKey()), 0, 30);
|
||||
$result = str_replace($match[0], "\t" . 'Configure::write(\'Security.cipherSeed\', \'' . $string . '\');', $contents);
|
||||
if ($File->write($result)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes cache prefix using app's name
|
||||
*
|
||||
* @param string $dir Path to project
|
||||
* @return bool Success
|
||||
*/
|
||||
public function cachePrefix($dir) {
|
||||
$app = basename($dir);
|
||||
$File = new File($dir . 'Config' . DS . 'core.php');
|
||||
$contents = $File->read();
|
||||
if (preg_match('/(\$prefix = \'myapp_\';)/', $contents, $match)) {
|
||||
$result = str_replace($match[0], '$prefix = \'' . $app . '_\';', $contents);
|
||||
return $File->write($result);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and writes CAKE_CORE_INCLUDE_PATH
|
||||
*
|
||||
* @param string $path Project path
|
||||
* @param bool $hardCode Whether or not define calls should be hardcoded.
|
||||
* @return bool Success
|
||||
*/
|
||||
public function corePath($path, $hardCode = true) {
|
||||
if (dirname($path) !== CAKE_CORE_INCLUDE_PATH) {
|
||||
$filename = $path . 'webroot' . DS . 'index.php';
|
||||
if (!$this->_replaceCorePath($filename, $hardCode)) {
|
||||
return false;
|
||||
}
|
||||
$filename = $path . 'webroot' . DS . 'test.php';
|
||||
if (!$this->_replaceCorePath($filename, $hardCode)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the __CAKE_PATH__ placeholder in the template files.
|
||||
*
|
||||
* @param string $filename The filename to operate on.
|
||||
* @param bool $hardCode Whether or not the define should be uncommented.
|
||||
* @return bool Success
|
||||
*/
|
||||
protected function _replaceCorePath($filename, $hardCode) {
|
||||
$contents = file_get_contents($filename);
|
||||
|
||||
$root = strpos(CAKE_CORE_INCLUDE_PATH, '/') === 0 ? " DS . '" : "'";
|
||||
$corePath = $root . str_replace(DS, "' . DS . '", trim(CAKE_CORE_INCLUDE_PATH, DS)) . "'";
|
||||
|
||||
$result = str_replace('__CAKE_PATH__', $corePath, $contents, $count);
|
||||
if ($hardCode) {
|
||||
$result = str_replace('//define(\'CAKE_CORE', 'define(\'CAKE_CORE', $result);
|
||||
}
|
||||
if (!file_put_contents($filename, $result)) {
|
||||
return false;
|
||||
}
|
||||
return (bool)$count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables Configure::read('Routing.prefixes') in /app/Config/core.php
|
||||
*
|
||||
* @param string $name Name to use as admin routing
|
||||
* @return bool Success
|
||||
*/
|
||||
public function cakeAdmin($name) {
|
||||
$path = (empty($this->configPath)) ? APP . 'Config' . DS : $this->configPath;
|
||||
$File = new File($path . 'core.php');
|
||||
$contents = $File->read();
|
||||
if (preg_match('%(\s*[/]*Configure::write\(\'Routing.prefixes\',[\s\'a-z,\)\(]*\);)%', $contents, $match)) {
|
||||
$result = str_replace($match[0], "\n" . 'Configure::write(\'Routing.prefixes\', array(\'' . $name . '\'));', $contents);
|
||||
if ($File->write($result)) {
|
||||
Configure::write('Routing.prefixes', array($name));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for Configure::read('Routing.prefixes') and forces user to input it if not enabled
|
||||
*
|
||||
* @return string Admin route to use
|
||||
*/
|
||||
public function getPrefix() {
|
||||
$admin = '';
|
||||
$prefixes = Configure::read('Routing.prefixes');
|
||||
if (!empty($prefixes)) {
|
||||
if (count($prefixes) === 1) {
|
||||
return $prefixes[0] . '_';
|
||||
}
|
||||
if ($this->interactive) {
|
||||
$this->out();
|
||||
$this->out(__d('cake_console', 'You have more than one routing prefix configured'));
|
||||
}
|
||||
$options = array();
|
||||
foreach ($prefixes as $i => $prefix) {
|
||||
$options[] = $i + 1;
|
||||
if ($this->interactive) {
|
||||
$this->out($i + 1 . '. ' . $prefix);
|
||||
}
|
||||
}
|
||||
$selection = $this->in(__d('cake_console', 'Please choose a prefix to bake with.'), $options, 1);
|
||||
return $prefixes[$selection - 1] . '_';
|
||||
}
|
||||
if ($this->interactive) {
|
||||
$this->hr();
|
||||
$this->out(__d('cake_console', 'You need to enable %s in %s to use prefix routing.',
|
||||
'Configure::write(\'Routing.prefixes\', array(\'admin\'))',
|
||||
'/app/Config/core.php'));
|
||||
$this->out(__d('cake_console', 'What would you like the prefix route to be?'));
|
||||
$this->out(__d('cake_console', 'Example: %s', 'www.example.com/admin/controller'));
|
||||
while (!$admin) {
|
||||
$admin = $this->in(__d('cake_console', 'Enter a routing prefix:'), null, 'admin');
|
||||
}
|
||||
if ($this->cakeAdmin($admin) !== true) {
|
||||
$this->out(__d('cake_console', '<error>Unable to write to</error> %s.', '/app/Config/core.php'));
|
||||
$this->out(__d('cake_console', 'You need to enable %s in %s to use prefix routing.',
|
||||
'Configure::write(\'Routing.prefixes\', array(\'admin\'))',
|
||||
'/app/Config/core.php'));
|
||||
return $this->_stop();
|
||||
}
|
||||
return $admin . '_';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the option parser instance and configures it.
|
||||
*
|
||||
* @return ConsoleOptionParser
|
||||
*/
|
||||
public function getOptionParser() {
|
||||
$parser = parent::getOptionParser();
|
||||
|
||||
$parser->description(
|
||||
__d('cake_console', 'Generate a new CakePHP project skeleton.')
|
||||
)->addArgument('name', array(
|
||||
'help' => __d('cake_console', 'Application directory to make, if it starts with "/" the path is absolute.')
|
||||
))->addOption('empty', array(
|
||||
'boolean' => true,
|
||||
'help' => __d('cake_console', 'Create empty files in each of the directories. Good if you are using git')
|
||||
))->addOption('theme', array(
|
||||
'short' => 't',
|
||||
'help' => __d('cake_console', 'Theme to use when baking code.')
|
||||
))->addOption('skel', array(
|
||||
'default' => current(App::core('Console')) . 'Templates' . DS . 'skel',
|
||||
'help' => __d('cake_console', 'The directory layout to use for the new application skeleton.' .
|
||||
' Defaults to cake/Console/Templates/skel of CakePHP used to create the project.')
|
||||
));
|
||||
|
||||
return $parser;
|
||||
}
|
||||
|
||||
}
|
||||
217
lib/Cake/Console/Command/Task/TemplateTask.php
Normal file
217
lib/Cake/Console/Command/Task/TemplateTask.php
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
<?php
|
||||
/**
|
||||
* Template Task can generate templated output Used in other Tasks
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 1.3
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
App::uses('Folder', 'Utility');
|
||||
|
||||
/**
|
||||
* Template Task can generate templated output Used in other Tasks.
|
||||
* Acts like a simplified View class.
|
||||
*
|
||||
* @package Cake.Console.Command.Task
|
||||
*/
|
||||
class TemplateTask extends AppShell {
|
||||
|
||||
/**
|
||||
* variables to add to template scope
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $templateVars = array();
|
||||
|
||||
/**
|
||||
* Paths to look for templates on.
|
||||
* Contains a list of $theme => $path
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $templatePaths = array();
|
||||
|
||||
/**
|
||||
* Initialize callback. Setup paths for the template task.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function initialize() {
|
||||
$this->templatePaths = $this->_findThemes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the paths to all the installed shell themes in the app.
|
||||
*
|
||||
* Bake themes are directories not named `skel` inside a `Console/Templates` path.
|
||||
* They are listed in this order: app -> plugin -> default
|
||||
*
|
||||
* @return array Array of bake themes that are installed.
|
||||
*/
|
||||
protected function _findThemes() {
|
||||
$paths = App::path('Console');
|
||||
|
||||
$plugins = App::objects('plugin');
|
||||
foreach ($plugins as $plugin) {
|
||||
$paths[] = $this->_pluginPath($plugin) . 'Console' . DS;
|
||||
}
|
||||
|
||||
$core = current(App::core('Console'));
|
||||
$separator = DS === '/' ? '/' : '\\\\';
|
||||
$core = preg_replace('#shells' . $separator . '$#', '', $core);
|
||||
|
||||
$Folder = new Folder($core . 'Templates' . DS . 'default');
|
||||
|
||||
$contents = $Folder->read();
|
||||
$themeFolders = $contents[0];
|
||||
|
||||
$paths[] = $core;
|
||||
|
||||
foreach ($paths as $i => $path) {
|
||||
$paths[$i] = rtrim($path, DS) . DS;
|
||||
}
|
||||
|
||||
$themes = array();
|
||||
foreach ($paths as $path) {
|
||||
$Folder = new Folder($path . 'Templates', false);
|
||||
$contents = $Folder->read();
|
||||
$subDirs = $contents[0];
|
||||
foreach ($subDirs as $dir) {
|
||||
if (empty($dir) || preg_match('@^skel$|_skel$@', $dir)) {
|
||||
continue;
|
||||
}
|
||||
$Folder = new Folder($path . 'Templates' . DS . $dir);
|
||||
$contents = $Folder->read();
|
||||
$subDirs = $contents[0];
|
||||
if (array_intersect($contents[0], $themeFolders)) {
|
||||
$templateDir = $path . 'Templates' . DS . $dir . DS;
|
||||
$themes[$dir] = $templateDir;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $themes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set variable values to the template scope
|
||||
*
|
||||
* @param string|array $one A string or an array of data.
|
||||
* @param string|array $two Value in case $one is a string (which then works as the key).
|
||||
* Unused if $one is an associative array, otherwise serves as the values to $one's keys.
|
||||
* @return void
|
||||
*/
|
||||
public function set($one, $two = null) {
|
||||
if (is_array($one)) {
|
||||
if (is_array($two)) {
|
||||
$data = array_combine($one, $two);
|
||||
} else {
|
||||
$data = $one;
|
||||
}
|
||||
} else {
|
||||
$data = array($one => $two);
|
||||
}
|
||||
|
||||
if (!$data) {
|
||||
return false;
|
||||
}
|
||||
$this->templateVars = $data + $this->templateVars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the template
|
||||
*
|
||||
* @param string $directory directory / type of thing you want
|
||||
* @param string $filename template name
|
||||
* @param array $vars Additional vars to set to template scope.
|
||||
* @return string contents of generated code template
|
||||
*/
|
||||
public function generate($directory, $filename, $vars = null) {
|
||||
if ($vars !== null) {
|
||||
$this->set($vars);
|
||||
}
|
||||
if (empty($this->templatePaths)) {
|
||||
$this->initialize();
|
||||
}
|
||||
$themePath = $this->getThemePath();
|
||||
$templateFile = $this->_findTemplate($themePath, $directory, $filename);
|
||||
if ($templateFile) {
|
||||
extract($this->templateVars);
|
||||
ob_start();
|
||||
ob_implicit_flush(0);
|
||||
include $templateFile;
|
||||
$content = ob_get_clean();
|
||||
return $content;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the theme name for the current operation.
|
||||
* If there is only one theme in $templatePaths it will be used.
|
||||
* If there is a -theme param in the cli args, it will be used.
|
||||
* If there is more than one installed theme user interaction will happen
|
||||
*
|
||||
* @return string returns the path to the selected theme.
|
||||
*/
|
||||
public function getThemePath() {
|
||||
if (count($this->templatePaths) === 1) {
|
||||
$paths = array_values($this->templatePaths);
|
||||
return $paths[0];
|
||||
}
|
||||
if (!empty($this->params['theme']) && isset($this->templatePaths[$this->params['theme']])) {
|
||||
return $this->templatePaths[$this->params['theme']];
|
||||
}
|
||||
|
||||
$this->hr();
|
||||
$this->out(__d('cake_console', 'You have more than one set of templates installed.'));
|
||||
$this->out(__d('cake_console', 'Please choose the template set you wish to use:'));
|
||||
$this->hr();
|
||||
|
||||
$i = 1;
|
||||
$indexedPaths = array();
|
||||
foreach ($this->templatePaths as $key => $path) {
|
||||
$this->out($i . '. ' . $key);
|
||||
$indexedPaths[$i] = $path;
|
||||
$i++;
|
||||
}
|
||||
$index = $this->in(__d('cake_console', 'Which bake theme would you like to use?'), range(1, $i - 1), 1);
|
||||
$themeNames = array_keys($this->templatePaths);
|
||||
$this->params['theme'] = $themeNames[$index - 1];
|
||||
return $indexedPaths[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a template inside a directory inside a path.
|
||||
* Will scan all other theme dirs if the template is not found in the first directory.
|
||||
*
|
||||
* @param string $path The initial path to look for the file on. If it is not found fallbacks will be used.
|
||||
* @param string $directory Subdirectory to look for ie. 'views', 'objects'
|
||||
* @param string $filename lower_case_underscored filename you want.
|
||||
* @return string filename will exit program if template is not found.
|
||||
*/
|
||||
protected function _findTemplate($path, $directory, $filename) {
|
||||
$themeFile = $path . $directory . DS . $filename . '.ctp';
|
||||
if (file_exists($themeFile)) {
|
||||
return $themeFile;
|
||||
}
|
||||
foreach ($this->templatePaths as $path) {
|
||||
$templatePath = $path . $directory . DS . $filename . '.ctp';
|
||||
if (file_exists($templatePath)) {
|
||||
return $templatePath;
|
||||
}
|
||||
}
|
||||
$this->err(__d('cake_console', 'Could not find template for %s', $filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
582
lib/Cake/Console/Command/Task/TestTask.php
Normal file
582
lib/Cake/Console/Command/Task/TestTask.php
Normal file
|
|
@ -0,0 +1,582 @@
|
|||
<?php
|
||||
/**
|
||||
* The TestTask handles creating and updating test files.
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 1.3
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
App::uses('BakeTask', 'Console/Command/Task');
|
||||
App::uses('ClassRegistry', 'Utility');
|
||||
|
||||
/**
|
||||
* Task class for creating and updating test files.
|
||||
*
|
||||
* @package Cake.Console.Command.Task
|
||||
*/
|
||||
class TestTask extends BakeTask {
|
||||
|
||||
/**
|
||||
* path to TESTS directory
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $path = TESTS;
|
||||
|
||||
/**
|
||||
* Tasks used.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $tasks = array('Template');
|
||||
|
||||
/**
|
||||
* class types that methods can be generated for
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $classTypes = array(
|
||||
'Model' => 'Model',
|
||||
'Controller' => 'Controller',
|
||||
'Component' => 'Controller/Component',
|
||||
'Behavior' => 'Model/Behavior',
|
||||
'Helper' => 'View/Helper'
|
||||
);
|
||||
|
||||
/**
|
||||
* Mapping between packages, and their baseclass + package.
|
||||
* This is used to generate App::uses() call to autoload base
|
||||
* classes if a developer has forgotten to do so.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $baseTypes = array(
|
||||
'Model' => array('Model', 'Model'),
|
||||
'Behavior' => array('ModelBehavior', 'Model'),
|
||||
'Controller' => array('Controller', 'Controller'),
|
||||
'Component' => array('Component', 'Controller'),
|
||||
'Helper' => array('Helper', 'View')
|
||||
);
|
||||
|
||||
/**
|
||||
* Internal list of fixtures that have been added so far.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_fixtures = array();
|
||||
|
||||
/**
|
||||
* Execution method always used for tasks
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute() {
|
||||
parent::execute();
|
||||
$count = count($this->args);
|
||||
if (!$count) {
|
||||
$this->_interactive();
|
||||
}
|
||||
|
||||
if ($count === 1) {
|
||||
$this->_interactive($this->args[0]);
|
||||
}
|
||||
|
||||
if ($count > 1) {
|
||||
$type = Inflector::classify($this->args[0]);
|
||||
if ($this->bake($type, $this->args[1])) {
|
||||
$this->out('<success>Done</success>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles interactive baking
|
||||
*
|
||||
* @param string $type The type of object to bake a test for.
|
||||
* @return string|bool
|
||||
*/
|
||||
protected function _interactive($type = null) {
|
||||
$this->interactive = true;
|
||||
$this->hr();
|
||||
$this->out(__d('cake_console', 'Bake Tests'));
|
||||
$this->out(__d('cake_console', 'Path: %s', $this->getPath()));
|
||||
$this->hr();
|
||||
|
||||
if ($type) {
|
||||
$type = Inflector::camelize($type);
|
||||
if (!isset($this->classTypes[$type])) {
|
||||
$this->error(__d('cake_console', 'Incorrect type provided. Please choose one of %s', implode(', ', array_keys($this->classTypes))));
|
||||
}
|
||||
} else {
|
||||
$type = $this->getObjectType();
|
||||
}
|
||||
$className = $this->getClassName($type);
|
||||
return $this->bake($type, $className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Completes final steps for generating data to create test case.
|
||||
*
|
||||
* @param string $type Type of object to bake test case for ie. Model, Controller
|
||||
* @param string $className the 'cake name' for the class ie. Posts for the PostsController
|
||||
* @return string|bool
|
||||
*/
|
||||
public function bake($type, $className) {
|
||||
$plugin = null;
|
||||
if ($this->plugin) {
|
||||
$plugin = $this->plugin . '.';
|
||||
}
|
||||
|
||||
$realType = $this->mapType($type, $plugin);
|
||||
$fullClassName = $this->getRealClassName($type, $className);
|
||||
|
||||
if ($this->typeCanDetectFixtures($type) && $this->isLoadableClass($realType, $fullClassName)) {
|
||||
$this->out(__d('cake_console', 'Bake is detecting possible fixtures...'));
|
||||
$testSubject = $this->buildTestSubject($type, $className);
|
||||
$this->generateFixtureList($testSubject);
|
||||
} elseif ($this->interactive) {
|
||||
$this->getUserFixtures();
|
||||
}
|
||||
list($baseClass, $baseType) = $this->getBaseType($type);
|
||||
App::uses($baseClass, $baseType);
|
||||
App::uses($fullClassName, $realType);
|
||||
|
||||
$methods = array();
|
||||
if (class_exists($fullClassName)) {
|
||||
$methods = $this->getTestableMethods($fullClassName);
|
||||
}
|
||||
$mock = $this->hasMockClass($type, $fullClassName);
|
||||
list($preConstruct, $construction, $postConstruct) = $this->generateConstructor($type, $fullClassName, $plugin);
|
||||
$uses = $this->generateUses($type, $realType, $fullClassName);
|
||||
|
||||
$this->out("\n" . __d('cake_console', 'Baking test case for %s %s ...', $className, $type), 1, Shell::QUIET);
|
||||
|
||||
$this->Template->set('fixtures', $this->_fixtures);
|
||||
$this->Template->set('plugin', $plugin);
|
||||
$this->Template->set(compact(
|
||||
'className', 'methods', 'type', 'fullClassName', 'mock',
|
||||
'realType', 'preConstruct', 'postConstruct', 'construction',
|
||||
'uses'
|
||||
));
|
||||
$out = $this->Template->generate('classes', 'test');
|
||||
|
||||
$filename = $this->testCaseFileName($type, $className);
|
||||
$made = $this->createFile($filename, $out);
|
||||
if ($made) {
|
||||
return $out;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interact with the user and get their chosen type. Can exit the script.
|
||||
*
|
||||
* @return string Users chosen type.
|
||||
*/
|
||||
public function getObjectType() {
|
||||
$this->hr();
|
||||
$this->out(__d('cake_console', 'Select an object type:'));
|
||||
$this->hr();
|
||||
|
||||
$keys = array();
|
||||
$i = 0;
|
||||
foreach ($this->classTypes as $option => $package) {
|
||||
$this->out(++$i . '. ' . $option);
|
||||
$keys[] = $i;
|
||||
}
|
||||
$keys[] = 'q';
|
||||
$selection = $this->in(__d('cake_console', 'Enter the type of object to bake a test for or (q)uit'), $keys, 'q');
|
||||
if ($selection === 'q') {
|
||||
return $this->_stop();
|
||||
}
|
||||
$types = array_keys($this->classTypes);
|
||||
return $types[$selection - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user chosen Class name for the chosen type
|
||||
*
|
||||
* @param string $objectType Type of object to list classes for i.e. Model, Controller.
|
||||
* @return string Class name the user chose.
|
||||
*/
|
||||
public function getClassName($objectType) {
|
||||
$type = ucfirst(strtolower($objectType));
|
||||
$typeLength = strlen($type);
|
||||
$type = $this->classTypes[$type];
|
||||
if ($this->plugin) {
|
||||
$plugin = $this->plugin . '.';
|
||||
$options = App::objects($plugin . $type);
|
||||
} else {
|
||||
$options = App::objects($type);
|
||||
}
|
||||
$this->out(__d('cake_console', 'Choose a %s class', $objectType));
|
||||
$keys = array();
|
||||
foreach ($options as $key => $option) {
|
||||
$this->out(++$key . '. ' . $option);
|
||||
$keys[] = $key;
|
||||
}
|
||||
while (empty($selection)) {
|
||||
$selection = $this->in(__d('cake_console', 'Choose an existing class, or enter the name of a class that does not exist'));
|
||||
if (is_numeric($selection) && isset($options[$selection - 1])) {
|
||||
$selection = $options[$selection - 1];
|
||||
}
|
||||
if ($type !== 'Model') {
|
||||
$selection = substr($selection, 0, $typeLength * - 1);
|
||||
}
|
||||
}
|
||||
return $selection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the chosen type can find its own fixtures.
|
||||
* Currently only model, and controller are supported
|
||||
*
|
||||
* @param string $type The Type of object you are generating tests for eg. controller
|
||||
* @return bool
|
||||
*/
|
||||
public function typeCanDetectFixtures($type) {
|
||||
$type = strtolower($type);
|
||||
return in_array($type, array('controller', 'model'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a class with the given package is loaded or can be loaded.
|
||||
*
|
||||
* @param string $package The package of object you are generating tests for eg. controller
|
||||
* @param string $class the Classname of the class the test is being generated for.
|
||||
* @return bool
|
||||
*/
|
||||
public function isLoadableClass($package, $class) {
|
||||
App::uses($class, $package);
|
||||
list($plugin, $ns) = pluginSplit($package);
|
||||
if ($plugin) {
|
||||
App::uses("{$plugin}AppController", $package);
|
||||
App::uses("{$plugin}AppModel", $package);
|
||||
App::uses("{$plugin}AppHelper", $package);
|
||||
}
|
||||
return class_exists($class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an instance of the class to be tested.
|
||||
* So that fixtures can be detected
|
||||
*
|
||||
* @param string $type The Type of object you are generating tests for eg. controller
|
||||
* @param string $class the Classname of the class the test is being generated for.
|
||||
* @return object And instance of the class that is going to be tested.
|
||||
*/
|
||||
public function buildTestSubject($type, $class) {
|
||||
ClassRegistry::flush();
|
||||
App::uses($class, $type);
|
||||
$class = $this->getRealClassName($type, $class);
|
||||
if (strtolower($type) === 'model') {
|
||||
$instance = ClassRegistry::init($class);
|
||||
} else {
|
||||
$instance = new $class();
|
||||
}
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the real class name from the cake short form. If the class name is already
|
||||
* suffixed with the type, the type will not be duplicated.
|
||||
*
|
||||
* @param string $type The Type of object you are generating tests for eg. controller
|
||||
* @param string $class the Classname of the class the test is being generated for.
|
||||
* @return string Real class name
|
||||
*/
|
||||
public function getRealClassName($type, $class) {
|
||||
if (strtolower($type) === 'model' || empty($this->classTypes[$type])) {
|
||||
return $class;
|
||||
}
|
||||
|
||||
$position = strpos($class, $type);
|
||||
|
||||
if ($position !== false && (strlen($class) - $position) === strlen($type)) {
|
||||
return $class;
|
||||
}
|
||||
return $class . $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the types that TestTask uses to concrete types that App::uses can use.
|
||||
*
|
||||
* @param string $type The type of thing having a test generated.
|
||||
* @param string $plugin The plugin name.
|
||||
* @return string
|
||||
* @throws CakeException When invalid object types are requested.
|
||||
*/
|
||||
public function mapType($type, $plugin) {
|
||||
$type = ucfirst($type);
|
||||
if (empty($this->classTypes[$type])) {
|
||||
throw new CakeException(__d('cake_dev', 'Invalid object type.'));
|
||||
}
|
||||
$real = $this->classTypes[$type];
|
||||
if ($plugin) {
|
||||
$real = trim($plugin, '.') . '.' . $real;
|
||||
}
|
||||
return $real;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base class and package name for a given type.
|
||||
*
|
||||
* @param string $type The type the class having a test
|
||||
* generated for is in.
|
||||
* @return array Array of (class, type)
|
||||
* @throws CakeException on invalid types.
|
||||
*/
|
||||
public function getBaseType($type) {
|
||||
if (empty($this->baseTypes[$type])) {
|
||||
throw new CakeException(__d('cake_dev', 'Invalid type name'));
|
||||
}
|
||||
return $this->baseTypes[$type];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get methods declared in the class given.
|
||||
* No parent methods will be returned
|
||||
*
|
||||
* @param string $className Name of class to look at.
|
||||
* @return array Array of method names.
|
||||
*/
|
||||
public function getTestableMethods($className) {
|
||||
$classMethods = get_class_methods($className);
|
||||
$parentMethods = get_class_methods(get_parent_class($className));
|
||||
$thisMethods = array_diff($classMethods, $parentMethods);
|
||||
$out = array();
|
||||
foreach ($thisMethods as $method) {
|
||||
if (substr($method, 0, 1) !== '_' && $method != strtolower($className)) {
|
||||
$out[] = $method;
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the list of fixtures that will be required to run this test based on
|
||||
* loaded models.
|
||||
*
|
||||
* @param object $subject The object you want to generate fixtures for.
|
||||
* @return array Array of fixtures to be included in the test.
|
||||
*/
|
||||
public function generateFixtureList($subject) {
|
||||
$this->_fixtures = array();
|
||||
if ($subject instanceof Model) {
|
||||
$this->_processModel($subject);
|
||||
} elseif ($subject instanceof Controller) {
|
||||
$this->_processController($subject);
|
||||
}
|
||||
return array_values($this->_fixtures);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a model recursively and pull out all the
|
||||
* model names converting them to fixture names.
|
||||
*
|
||||
* @param Model $subject A Model class to scan for associations and pull fixtures off of.
|
||||
* @return void
|
||||
*/
|
||||
protected function _processModel($subject) {
|
||||
$this->_addFixture($subject->name);
|
||||
$associated = $subject->getAssociated();
|
||||
foreach ($associated as $alias => $type) {
|
||||
$className = $subject->{$alias}->name;
|
||||
if (!isset($this->_fixtures[$className])) {
|
||||
$this->_processModel($subject->{$alias});
|
||||
}
|
||||
if ($type === 'hasAndBelongsToMany') {
|
||||
if (!empty($subject->hasAndBelongsToMany[$alias]['with'])) {
|
||||
list(, $joinModel) = pluginSplit($subject->hasAndBelongsToMany[$alias]['with']);
|
||||
} else {
|
||||
$joinModel = Inflector::classify($subject->hasAndBelongsToMany[$alias]['joinTable']);
|
||||
}
|
||||
if (!isset($this->_fixtures[$joinModel])) {
|
||||
$this->_processModel($subject->{$joinModel});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process all the models attached to a controller
|
||||
* and generate a fixture list.
|
||||
*
|
||||
* @param Controller $subject A controller to pull model names off of.
|
||||
* @return void
|
||||
*/
|
||||
protected function _processController($subject) {
|
||||
$subject->constructClasses();
|
||||
$models = array(Inflector::classify($subject->name));
|
||||
if (!empty($subject->uses)) {
|
||||
$models = $subject->uses;
|
||||
}
|
||||
foreach ($models as $model) {
|
||||
list(, $model) = pluginSplit($model);
|
||||
$this->_processModel($subject->{$model});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add class name to the fixture list.
|
||||
* Sets the app. or plugin.plugin_name. prefix.
|
||||
*
|
||||
* @param string $name Name of the Model class that a fixture might be required for.
|
||||
* @return void
|
||||
*/
|
||||
protected function _addFixture($name) {
|
||||
if ($this->plugin) {
|
||||
$prefix = 'plugin.' . Inflector::underscore($this->plugin) . '.';
|
||||
} else {
|
||||
$prefix = 'app.';
|
||||
}
|
||||
$fixture = $prefix . Inflector::underscore($name);
|
||||
$this->_fixtures[$name] = $fixture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interact with the user to get additional fixtures they want to use.
|
||||
*
|
||||
* @return array Array of fixtures the user wants to add.
|
||||
*/
|
||||
public function getUserFixtures() {
|
||||
$proceed = $this->in(__d('cake_console', 'Bake could not detect fixtures, would you like to add some?'), array('y', 'n'), 'n');
|
||||
$fixtures = array();
|
||||
if (strtolower($proceed) === 'y') {
|
||||
$fixtureList = $this->in(__d('cake_console', "Please provide a comma separated list of the fixtures names you'd like to use.\nExample: 'app.comment, app.post, plugin.forums.post'"));
|
||||
$fixtureListTrimmed = str_replace(' ', '', $fixtureList);
|
||||
$fixtures = explode(',', $fixtureListTrimmed);
|
||||
}
|
||||
$this->_fixtures = array_merge($this->_fixtures, $fixtures);
|
||||
return $fixtures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is a mock class required for this type of test?
|
||||
* Controllers require a mock class.
|
||||
*
|
||||
* @param string $type The type of object tests are being generated for eg. controller.
|
||||
* @return bool
|
||||
*/
|
||||
public function hasMockClass($type) {
|
||||
$type = strtolower($type);
|
||||
return $type === 'controller';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a constructor code snippet for the type and class name
|
||||
*
|
||||
* @param string $type The Type of object you are generating tests for eg. controller
|
||||
* @param string $fullClassName The Classname of the class the test is being generated for.
|
||||
* @param string $plugin The plugin name.
|
||||
* @return array Constructor snippets for the thing you are building.
|
||||
*/
|
||||
public function generateConstructor($type, $fullClassName, $plugin) {
|
||||
$type = strtolower($type);
|
||||
$pre = $construct = $post = '';
|
||||
if ($type === 'model') {
|
||||
$construct = "ClassRegistry::init('{$plugin}$fullClassName');\n";
|
||||
}
|
||||
if ($type === 'behavior') {
|
||||
$construct = "new $fullClassName();\n";
|
||||
}
|
||||
if ($type === 'helper') {
|
||||
$pre = "\$View = new View();\n";
|
||||
$construct = "new {$fullClassName}(\$View);\n";
|
||||
}
|
||||
if ($type === 'component') {
|
||||
$pre = "\$Collection = new ComponentCollection();\n";
|
||||
$construct = "new {$fullClassName}(\$Collection);\n";
|
||||
}
|
||||
return array($pre, $construct, $post);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the uses() calls for a type & class name
|
||||
*
|
||||
* @param string $type The Type of object you are generating tests for eg. controller
|
||||
* @param string $realType The package name for the class.
|
||||
* @param string $className The Classname of the class the test is being generated for.
|
||||
* @return array An array containing used classes
|
||||
*/
|
||||
public function generateUses($type, $realType, $className) {
|
||||
$uses = array();
|
||||
$type = strtolower($type);
|
||||
if ($type === 'component') {
|
||||
$uses[] = array('ComponentCollection', 'Controller');
|
||||
$uses[] = array('Component', 'Controller');
|
||||
}
|
||||
if ($type === 'helper') {
|
||||
$uses[] = array('View', 'View');
|
||||
$uses[] = array('Helper', 'View');
|
||||
}
|
||||
$uses[] = array($className, $realType);
|
||||
return $uses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the filename for the test case. resolve the suffixes for controllers
|
||||
* and get the plugin path if needed.
|
||||
*
|
||||
* @param string $type The Type of object you are generating tests for eg. controller
|
||||
* @param string $className the Classname of the class the test is being generated for.
|
||||
* @return string filename the test should be created on.
|
||||
*/
|
||||
public function testCaseFileName($type, $className) {
|
||||
$path = $this->getPath() . 'Case' . DS;
|
||||
$type = Inflector::camelize($type);
|
||||
if (isset($this->classTypes[$type])) {
|
||||
$path .= $this->classTypes[$type] . DS;
|
||||
}
|
||||
$className = $this->getRealClassName($type, $className);
|
||||
return str_replace('/', DS, $path) . Inflector::camelize($className) . 'Test.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the option parser instance and configures it.
|
||||
*
|
||||
* @return ConsoleOptionParser
|
||||
*/
|
||||
public function getOptionParser() {
|
||||
$parser = parent::getOptionParser();
|
||||
|
||||
$parser->description(
|
||||
__d('cake_console', 'Bake test case skeletons for classes.')
|
||||
)->addArgument('type', array(
|
||||
'help' => __d('cake_console', 'Type of class to bake, can be any of the following: controller, model, helper, component or behavior.'),
|
||||
'choices' => array(
|
||||
'Controller', 'controller',
|
||||
'Model', 'model',
|
||||
'Helper', 'helper',
|
||||
'Component', 'component',
|
||||
'Behavior', 'behavior'
|
||||
)
|
||||
))->addArgument('name', array(
|
||||
'help' => __d('cake_console', 'An existing class to bake tests for.')
|
||||
))->addOption('theme', array(
|
||||
'short' => 't',
|
||||
'help' => __d('cake_console', 'Theme to use when baking code.')
|
||||
))->addOption('plugin', array(
|
||||
'short' => 'p',
|
||||
'help' => __d('cake_console', 'CamelCased name of the plugin to bake tests for.')
|
||||
))->addOption('force', array(
|
||||
'short' => 'f',
|
||||
'help' => __d('cake_console', 'Force overwriting existing files without prompting.')
|
||||
))->epilog(
|
||||
__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.')
|
||||
);
|
||||
|
||||
return $parser;
|
||||
}
|
||||
|
||||
}
|
||||
477
lib/Cake/Console/Command/Task/ViewTask.php
Normal file
477
lib/Cake/Console/Command/Task/ViewTask.php
Normal file
|
|
@ -0,0 +1,477 @@
|
|||
<?php
|
||||
/**
|
||||
* The View Tasks handles creating and updating view files.
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 1.2
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
App::uses('Controller', 'Controller');
|
||||
App::uses('BakeTask', 'Console/Command/Task');
|
||||
|
||||
/**
|
||||
* Task class for creating and updating view files.
|
||||
*
|
||||
* @package Cake.Console.Command.Task
|
||||
*/
|
||||
class ViewTask extends BakeTask {
|
||||
|
||||
/**
|
||||
* Tasks to be loaded by this Task
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $tasks = array('Project', 'Controller', 'DbConfig', 'Template');
|
||||
|
||||
/**
|
||||
* path to View directory
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $path = null;
|
||||
|
||||
/**
|
||||
* Name of the controller being used
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $controllerName = null;
|
||||
|
||||
/**
|
||||
* The template file to use
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $template = null;
|
||||
|
||||
/**
|
||||
* Actions to use for scaffolding
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $scaffoldActions = array('index', 'view', 'add', 'edit');
|
||||
|
||||
/**
|
||||
* An array of action names that don't require templates. These
|
||||
* actions will not emit errors when doing bakeActions()
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $noTemplateActions = array('delete');
|
||||
|
||||
/**
|
||||
* Override initialize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function initialize() {
|
||||
$this->path = current(App::path('View'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Execution method always used for tasks
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function execute() {
|
||||
parent::execute();
|
||||
if (empty($this->args)) {
|
||||
$this->_interactive();
|
||||
}
|
||||
if (empty($this->args[0])) {
|
||||
return;
|
||||
}
|
||||
if (!isset($this->connection)) {
|
||||
$this->connection = 'default';
|
||||
}
|
||||
$action = null;
|
||||
$this->controllerName = $this->_controllerName($this->args[0]);
|
||||
|
||||
$this->Project->interactive = false;
|
||||
if (strtolower($this->args[0]) === 'all') {
|
||||
return $this->all();
|
||||
}
|
||||
|
||||
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 ($action) {
|
||||
return $this->bake($action, true);
|
||||
}
|
||||
|
||||
$vars = $this->_loadController();
|
||||
$methods = $this->_methodsToBake();
|
||||
|
||||
foreach ($methods as $method) {
|
||||
$content = $this->getContent($method, $vars);
|
||||
if ($content) {
|
||||
$this->bake($method, $content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of actions that can / should have views baked for them.
|
||||
*
|
||||
* @return array Array of action names that should be baked
|
||||
*/
|
||||
protected function _methodsToBake() {
|
||||
$methods = array_diff(
|
||||
array_map('strtolower', get_class_methods($this->controllerName . 'Controller')),
|
||||
array_map('strtolower', get_class_methods('AppController'))
|
||||
);
|
||||
$scaffoldActions = false;
|
||||
if (empty($methods)) {
|
||||
$scaffoldActions = true;
|
||||
$methods = $this->scaffoldActions;
|
||||
}
|
||||
$adminRoute = $this->Project->getPrefix();
|
||||
foreach ($methods as $i => $method) {
|
||||
if ($adminRoute && !empty($this->params['admin'])) {
|
||||
if ($scaffoldActions) {
|
||||
$methods[$i] = $adminRoute . $method;
|
||||
continue;
|
||||
} elseif (strpos($method, $adminRoute) === false) {
|
||||
unset($methods[$i]);
|
||||
}
|
||||
}
|
||||
if ($method[0] === '_' || $method === strtolower($this->controllerName . 'Controller')) {
|
||||
unset($methods[$i]);
|
||||
}
|
||||
}
|
||||
return $methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bake All views for All controllers.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function all() {
|
||||
$this->Controller->interactive = false;
|
||||
$tables = $this->Controller->listAll($this->connection, false);
|
||||
|
||||
$actions = null;
|
||||
if (isset($this->args[1])) {
|
||||
$actions = array($this->args[1]);
|
||||
}
|
||||
$this->interactive = false;
|
||||
foreach ($tables as $table) {
|
||||
$model = $this->_modelName($table);
|
||||
$this->controllerName = $this->_controllerName($model);
|
||||
App::uses($model, 'Model');
|
||||
if (class_exists($model)) {
|
||||
$vars = $this->_loadController();
|
||||
if (!$actions) {
|
||||
$actions = $this->_methodsToBake();
|
||||
}
|
||||
$this->bakeActions($actions, $vars);
|
||||
$actions = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles interactive baking
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _interactive() {
|
||||
$this->hr();
|
||||
$this->out(sprintf("Bake View\nPath: %s", $this->getPath()));
|
||||
$this->hr();
|
||||
|
||||
$this->DbConfig->interactive = $this->Controller->interactive = $this->interactive = true;
|
||||
|
||||
if (empty($this->connection)) {
|
||||
$this->connection = $this->DbConfig->getConfig();
|
||||
}
|
||||
|
||||
$this->Controller->connection = $this->connection;
|
||||
$this->controllerName = $this->Controller->getName();
|
||||
|
||||
$prompt = __d('cake_console', "Would you like bake to build your views interactively?\nWarning: Choosing no will overwrite %s views if it exist.", $this->controllerName);
|
||||
$interactive = $this->in($prompt, array('y', 'n'), 'n');
|
||||
|
||||
if (strtolower($interactive) === 'n') {
|
||||
$this->interactive = false;
|
||||
}
|
||||
|
||||
$prompt = __d('cake_console', "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).");
|
||||
$wannaDoScaffold = $this->in($prompt, array('y', 'n'), 'y');
|
||||
|
||||
$wannaDoAdmin = $this->in(__d('cake_console', "Would you like to create the views for admin routing?"), array('y', 'n'), 'n');
|
||||
|
||||
if (strtolower($wannaDoScaffold) === 'y' || strtolower($wannaDoAdmin) === 'y') {
|
||||
$vars = $this->_loadController();
|
||||
if (strtolower($wannaDoScaffold) === 'y') {
|
||||
$actions = $this->scaffoldActions;
|
||||
$this->bakeActions($actions, $vars);
|
||||
}
|
||||
if (strtolower($wannaDoAdmin) === 'y') {
|
||||
$admin = $this->Project->getPrefix();
|
||||
$regularActions = $this->scaffoldActions;
|
||||
$adminActions = array();
|
||||
foreach ($regularActions as $action) {
|
||||
$adminActions[] = $admin . $action;
|
||||
}
|
||||
$this->bakeActions($adminActions, $vars);
|
||||
}
|
||||
$this->hr();
|
||||
$this->out();
|
||||
$this->out(__d('cake_console', "View Scaffolding Complete.\n"));
|
||||
} else {
|
||||
$this->customAction();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads Controller and sets variables for the template
|
||||
* Available template variables
|
||||
* 'modelClass', 'primaryKey', 'displayField', 'singularVar', 'pluralVar',
|
||||
* 'singularHumanName', 'pluralHumanName', 'fields', 'foreignKeys',
|
||||
* 'belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany'
|
||||
*
|
||||
* @return array Returns an variables to be made available to a view template
|
||||
*/
|
||||
protected function _loadController() {
|
||||
if (!$this->controllerName) {
|
||||
$this->err(__d('cake_console', 'Controller not found'));
|
||||
}
|
||||
|
||||
$plugin = null;
|
||||
if ($this->plugin) {
|
||||
$plugin = $this->plugin . '.';
|
||||
}
|
||||
|
||||
$controllerClassName = $this->controllerName . 'Controller';
|
||||
App::uses($controllerClassName, $plugin . 'Controller');
|
||||
if (!class_exists($controllerClassName)) {
|
||||
$file = $controllerClassName . '.php';
|
||||
$this->err(__d('cake_console', "The file '%s' could not be found.\nIn order to bake a view, you'll need to first create the controller.", $file));
|
||||
return $this->_stop();
|
||||
}
|
||||
$controllerObj = new $controllerClassName();
|
||||
$controllerObj->plugin = $this->plugin;
|
||||
$controllerObj->constructClasses();
|
||||
$modelClass = $controllerObj->modelClass;
|
||||
$modelObj = $controllerObj->{$controllerObj->modelClass};
|
||||
|
||||
if ($modelObj) {
|
||||
$primaryKey = $modelObj->primaryKey;
|
||||
$displayField = $modelObj->displayField;
|
||||
$singularVar = Inflector::variable($modelClass);
|
||||
$singularHumanName = $this->_singularHumanName($this->controllerName);
|
||||
$schema = $modelObj->schema(true);
|
||||
$fields = array_keys($schema);
|
||||
$associations = $this->_associations($modelObj);
|
||||
} else {
|
||||
$primaryKey = $displayField = null;
|
||||
$singularVar = Inflector::variable(Inflector::singularize($this->controllerName));
|
||||
$singularHumanName = $this->_singularHumanName($this->controllerName);
|
||||
$fields = $schema = $associations = array();
|
||||
}
|
||||
$pluralVar = Inflector::variable($this->controllerName);
|
||||
$pluralHumanName = $this->_pluralHumanName($this->controllerName);
|
||||
|
||||
return compact('modelClass', 'schema', 'primaryKey', 'displayField', 'singularVar', 'pluralVar',
|
||||
'singularHumanName', 'pluralHumanName', 'fields', 'associations');
|
||||
}
|
||||
|
||||
/**
|
||||
* Bake a view file for each of the supplied actions
|
||||
*
|
||||
* @param array $actions Array of actions to make files for.
|
||||
* @param array $vars The template variables.
|
||||
* @return void
|
||||
*/
|
||||
public function bakeActions($actions, $vars) {
|
||||
foreach ($actions as $action) {
|
||||
$content = $this->getContent($action, $vars);
|
||||
$this->bake($action, $content);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* handle creation of baking a custom action view file
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function customAction() {
|
||||
$action = '';
|
||||
while (!$action) {
|
||||
$action = $this->in(__d('cake_console', 'Action Name? (use lowercase_underscored function name)'));
|
||||
if (!$action) {
|
||||
$this->out(__d('cake_console', 'The action name you supplied was empty. Please try again.'));
|
||||
}
|
||||
}
|
||||
$this->out();
|
||||
$this->hr();
|
||||
$this->out(__d('cake_console', 'The following view will be created:'));
|
||||
$this->hr();
|
||||
$this->out(__d('cake_console', 'Controller Name: %s', $this->controllerName));
|
||||
$this->out(__d('cake_console', 'Action Name: %s', $action));
|
||||
$this->out(__d('cake_console', 'Path: %s', $this->getPath() . $this->controllerName . DS . Inflector::underscore($action) . ".ctp"));
|
||||
$this->hr();
|
||||
$looksGood = $this->in(__d('cake_console', 'Look okay?'), array('y', 'n'), 'y');
|
||||
if (strtolower($looksGood) === 'y') {
|
||||
$this->bake($action, ' ');
|
||||
return $this->_stop();
|
||||
}
|
||||
$this->out(__d('cake_console', 'Bake Aborted.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assembles and writes bakes the view file.
|
||||
*
|
||||
* @param string $action Action to bake
|
||||
* @param string $content Content to write
|
||||
* @return bool Success
|
||||
*/
|
||||
public function bake($action, $content = '') {
|
||||
if ($content === true) {
|
||||
$content = $this->getContent($action);
|
||||
}
|
||||
if (empty($content)) {
|
||||
return false;
|
||||
}
|
||||
$this->out("\n" . __d('cake_console', 'Baking `%s` view file...', $action), 1, Shell::QUIET);
|
||||
$path = $this->getPath();
|
||||
$filename = $path . $this->controllerName . DS . Inflector::underscore($action) . '.ctp';
|
||||
return $this->createFile($filename, $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds content from template and variables
|
||||
*
|
||||
* @param string $action name to generate content to
|
||||
* @param array $vars passed for use in templates
|
||||
* @return string content from template
|
||||
*/
|
||||
public function getContent($action, $vars = null) {
|
||||
if (!$vars) {
|
||||
$vars = $this->_loadController();
|
||||
}
|
||||
|
||||
$this->Template->set('action', $action);
|
||||
$this->Template->set('plugin', $this->plugin);
|
||||
$this->Template->set($vars);
|
||||
$template = $this->getTemplate($action);
|
||||
if ($template) {
|
||||
return $this->Template->generate('views', $template);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the template name based on the action name
|
||||
*
|
||||
* @param string $action name
|
||||
* @return string template name
|
||||
*/
|
||||
public function getTemplate($action) {
|
||||
if ($action != $this->template && in_array($action, $this->noTemplateActions)) {
|
||||
return false;
|
||||
}
|
||||
if (!empty($this->template) && $action != $this->template) {
|
||||
return $this->template;
|
||||
}
|
||||
$themePath = $this->Template->getThemePath();
|
||||
if (file_exists($themePath . 'views' . DS . $action . '.ctp')) {
|
||||
return $action;
|
||||
}
|
||||
$template = $action;
|
||||
$prefixes = Configure::read('Routing.prefixes');
|
||||
foreach ((array)$prefixes as $prefix) {
|
||||
if (strpos($template, $prefix) !== false) {
|
||||
$template = str_replace($prefix . '_', '', $template);
|
||||
}
|
||||
}
|
||||
if (in_array($template, array('add', 'edit'))) {
|
||||
$template = 'form';
|
||||
} elseif (preg_match('@(_add|_edit)$@', $template)) {
|
||||
$template = str_replace(array('_add', '_edit'), '_form', $template);
|
||||
}
|
||||
return $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the option parser instance and configures it.
|
||||
*
|
||||
* @return ConsoleOptionParser
|
||||
*/
|
||||
public function getOptionParser() {
|
||||
$parser = parent::getOptionParser();
|
||||
|
||||
$parser->description(
|
||||
__d('cake_console', 'Bake views for a controller, using built-in or custom templates.')
|
||||
)->addArgument('controller', array(
|
||||
'help' => __d('cake_console', 'Name of the controller views to bake. Can be Plugin.name as a shortcut for plugin baking.')
|
||||
))->addArgument('action', array(
|
||||
'help' => __d('cake_console', "Will bake a single action's file. core templates are (index, add, edit, view)")
|
||||
))->addArgument('alias', array(
|
||||
'help' => __d('cake_console', 'Will bake the template in <action> but create the filename after <alias>.')
|
||||
))->addOption('plugin', array(
|
||||
'short' => 'p',
|
||||
'help' => __d('cake_console', 'Plugin to bake the view into.')
|
||||
))->addOption('admin', array(
|
||||
'help' => __d('cake_console', 'Set to only bake views for a prefix in Routing.prefixes'),
|
||||
'boolean' => true
|
||||
))->addOption('theme', array(
|
||||
'short' => 't',
|
||||
'help' => __d('cake_console', 'Theme to use when baking code.')
|
||||
))->addOption('connection', array(
|
||||
'short' => 'c',
|
||||
'help' => __d('cake_console', 'The connection the connected model is on.')
|
||||
))->addOption('force', array(
|
||||
'short' => 'f',
|
||||
'help' => __d('cake_console', 'Force overwriting existing files without prompting.')
|
||||
))->addSubcommand('all', array(
|
||||
'help' => __d('cake_console', 'Bake all CRUD action views for all controllers. Requires models and controllers to exist.')
|
||||
))->epilog(
|
||||
__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.')
|
||||
);
|
||||
|
||||
return $parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns associations for controllers models.
|
||||
*
|
||||
* @param Model $model The Model instance.
|
||||
* @return array associations
|
||||
*/
|
||||
protected function _associations(Model $model) {
|
||||
$keys = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany');
|
||||
$associations = array();
|
||||
|
||||
foreach ($keys as $type) {
|
||||
foreach ($model->{$type} as $assocKey => $assocData) {
|
||||
list(, $modelClass) = pluginSplit($assocData['className']);
|
||||
$associations[$type][$assocKey]['primaryKey'] = $model->{$assocKey}->primaryKey;
|
||||
$associations[$type][$assocKey]['displayField'] = $model->{$assocKey}->displayField;
|
||||
$associations[$type][$assocKey]['foreignKey'] = $assocData['foreignKey'];
|
||||
$associations[$type][$assocKey]['controller'] = Inflector::pluralize(Inflector::underscore($modelClass));
|
||||
$associations[$type][$assocKey]['fields'] = array_keys($model->{$assocKey}->schema(true));
|
||||
}
|
||||
}
|
||||
return $associations;
|
||||
}
|
||||
|
||||
}
|
||||
432
lib/Cake/Console/Command/TestShell.php
Normal file
432
lib/Cake/Console/Command/TestShell.php
Normal file
|
|
@ -0,0 +1,432 @@
|
|||
<?php
|
||||
/**
|
||||
* Test Shell
|
||||
*
|
||||
* This Shell allows the running of test suites via the cake command line
|
||||
*
|
||||
* CakePHP(tm) Tests <http://book.cakephp.org/2.0/en/development/testing.html>
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://book.cakephp.org/2.0/en/development/testing.html
|
||||
* @since CakePHP(tm) v 1.2.0.4433
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('Shell', 'Console');
|
||||
App::uses('CakeTestSuiteDispatcher', 'TestSuite');
|
||||
App::uses('CakeTestSuiteCommand', 'TestSuite');
|
||||
App::uses('CakeTestLoader', 'TestSuite');
|
||||
|
||||
/**
|
||||
* Provides a CakePHP wrapper around PHPUnit.
|
||||
* Adds in CakePHP's fixtures and gives access to plugin, app and core test cases
|
||||
*
|
||||
* @package Cake.Console.Command
|
||||
*/
|
||||
class TestShell extends Shell {
|
||||
|
||||
/**
|
||||
* Dispatcher object for the run.
|
||||
*
|
||||
* @var CakeTestDispatcher
|
||||
*/
|
||||
protected $_dispatcher = null;
|
||||
|
||||
/**
|
||||
* Gets the option parser instance and configures it.
|
||||
*
|
||||
* @return ConsoleOptionParser
|
||||
*/
|
||||
public function getOptionParser() {
|
||||
$parser = new ConsoleOptionParser($this->name);
|
||||
|
||||
$parser->description(
|
||||
__d('cake_console', 'The CakePHP Testsuite allows you to run test cases from the command line')
|
||||
)->addArgument('category', array(
|
||||
'help' => __d('cake_console', 'The category for the test, or test file, to test.'),
|
||||
'required' => false
|
||||
))->addArgument('file', array(
|
||||
'help' => __d('cake_console', 'The path to the file, or test file, to test.'),
|
||||
'required' => false
|
||||
))->addOption('log-junit', array(
|
||||
'help' => __d('cake_console', '<file> Log test execution in JUnit XML format to file.'),
|
||||
'default' => false
|
||||
))->addOption('log-json', array(
|
||||
'help' => __d('cake_console', '<file> Log test execution in JSON format to file.'),
|
||||
'default' => false
|
||||
))->addOption('log-tap', array(
|
||||
'help' => __d('cake_console', '<file> Log test execution in TAP format to file.'),
|
||||
'default' => false
|
||||
))->addOption('log-dbus', array(
|
||||
'help' => __d('cake_console', 'Log test execution to DBUS.'),
|
||||
'default' => false
|
||||
))->addOption('coverage-html', array(
|
||||
'help' => __d('cake_console', '<dir> Generate code coverage report in HTML format.'),
|
||||
'default' => false
|
||||
))->addOption('coverage-clover', array(
|
||||
'help' => __d('cake_console', '<file> Write code coverage data in Clover XML format.'),
|
||||
'default' => false
|
||||
))->addOption('testdox-html', array(
|
||||
'help' => __d('cake_console', '<file> Write agile documentation in HTML format to file.'),
|
||||
'default' => false
|
||||
))->addOption('testdox-text', array(
|
||||
'help' => __d('cake_console', '<file> Write agile documentation in Text format to file.'),
|
||||
'default' => false
|
||||
))->addOption('filter', array(
|
||||
'help' => __d('cake_console', '<pattern> Filter which tests to run.'),
|
||||
'default' => false
|
||||
))->addOption('group', array(
|
||||
'help' => __d('cake_console', '<name> Only runs tests from the specified group(s).'),
|
||||
'default' => false
|
||||
))->addOption('exclude-group', array(
|
||||
'help' => __d('cake_console', '<name> Exclude tests from the specified group(s).'),
|
||||
'default' => false
|
||||
))->addOption('list-groups', array(
|
||||
'help' => __d('cake_console', 'List available test groups.'),
|
||||
'boolean' => true
|
||||
))->addOption('loader', array(
|
||||
'help' => __d('cake_console', 'TestSuiteLoader implementation to use.'),
|
||||
'default' => false
|
||||
))->addOption('repeat', array(
|
||||
'help' => __d('cake_console', '<times> Runs the test(s) repeatedly.'),
|
||||
'default' => false
|
||||
))->addOption('tap', array(
|
||||
'help' => __d('cake_console', 'Report test execution progress in TAP format.'),
|
||||
'boolean' => true
|
||||
))->addOption('testdox', array(
|
||||
'help' => __d('cake_console', 'Report test execution progress in TestDox format.'),
|
||||
'default' => false,
|
||||
'boolean' => true
|
||||
))->addOption('no-colors', array(
|
||||
'help' => __d('cake_console', 'Do not use colors in output.'),
|
||||
'boolean' => true
|
||||
))->addOption('stderr', array(
|
||||
'help' => __d('cake_console', 'Write to STDERR instead of STDOUT.'),
|
||||
'boolean' => true
|
||||
))->addOption('stop-on-error', array(
|
||||
'help' => __d('cake_console', 'Stop execution upon first error or failure.'),
|
||||
'boolean' => true
|
||||
))->addOption('stop-on-failure', array(
|
||||
'help' => __d('cake_console', 'Stop execution upon first failure.'),
|
||||
'boolean' => true
|
||||
))->addOption('stop-on-skipped', array(
|
||||
'help' => __d('cake_console', 'Stop execution upon first skipped test.'),
|
||||
'boolean' => true
|
||||
))->addOption('stop-on-incomplete', array(
|
||||
'help' => __d('cake_console', 'Stop execution upon first incomplete test.'),
|
||||
'boolean' => true
|
||||
))->addOption('strict', array(
|
||||
'help' => __d('cake_console', 'Mark a test as incomplete if no assertions are made.'),
|
||||
'boolean' => true
|
||||
))->addOption('wait', array(
|
||||
'help' => __d('cake_console', 'Waits for a keystroke after each test.'),
|
||||
'boolean' => true
|
||||
))->addOption('process-isolation', array(
|
||||
'help' => __d('cake_console', 'Run each test in a separate PHP process.'),
|
||||
'boolean' => true
|
||||
))->addOption('no-globals-backup', array(
|
||||
'help' => __d('cake_console', 'Do not backup and restore $GLOBALS for each test.'),
|
||||
'boolean' => true
|
||||
))->addOption('static-backup', array(
|
||||
'help' => __d('cake_console', 'Backup and restore static attributes for each test.'),
|
||||
'boolean' => true
|
||||
))->addOption('syntax-check', array(
|
||||
'help' => __d('cake_console', 'Try to check source files for syntax errors.'),
|
||||
'boolean' => true
|
||||
))->addOption('bootstrap', array(
|
||||
'help' => __d('cake_console', '<file> A "bootstrap" PHP file that is run before the tests.'),
|
||||
'default' => false
|
||||
))->addOption('configuration', array(
|
||||
'help' => __d('cake_console', '<file> Read configuration from XML file.'),
|
||||
'default' => false
|
||||
))->addOption('no-configuration', array(
|
||||
'help' => __d('cake_console', 'Ignore default configuration file (phpunit.xml).'),
|
||||
'boolean' => true
|
||||
))->addOption('include-path', array(
|
||||
'help' => __d('cake_console', '<path(s)> Prepend PHP include_path with given path(s).'),
|
||||
'default' => false
|
||||
))->addOption('directive', array(
|
||||
'help' => __d('cake_console', 'key[=value] Sets a php.ini value.'),
|
||||
'default' => false
|
||||
))->addOption('fixture', array(
|
||||
'help' => __d('cake_console', 'Choose a custom fixture manager.')
|
||||
))->addOption('debug', array(
|
||||
'help' => __d('cake_console', 'More verbose output.')
|
||||
));
|
||||
|
||||
return $parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization method installs PHPUnit and loads all plugins
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function initialize() {
|
||||
$this->_dispatcher = new CakeTestSuiteDispatcher();
|
||||
$success = $this->_dispatcher->loadTestFramework();
|
||||
if (!$success) {
|
||||
throw new Exception(__d('cake_dev', 'Please install PHPUnit framework v3.7 <info>(http://www.phpunit.de)</info>'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the CLI options into an array CakeTestDispatcher can use.
|
||||
*
|
||||
* @return array Array of params for CakeTestDispatcher
|
||||
*/
|
||||
protected function _parseArgs() {
|
||||
if (empty($this->args)) {
|
||||
return;
|
||||
}
|
||||
$params = array(
|
||||
'core' => false,
|
||||
'app' => false,
|
||||
'plugin' => null,
|
||||
'output' => 'text',
|
||||
);
|
||||
|
||||
if (strpos($this->args[0], '.php')) {
|
||||
$category = $this->_mapFileToCategory($this->args[0]);
|
||||
$params['case'] = $this->_mapFileToCase($this->args[0], $category);
|
||||
} else {
|
||||
$category = $this->args[0];
|
||||
if (isset($this->args[1])) {
|
||||
$params['case'] = $this->args[1];
|
||||
}
|
||||
}
|
||||
|
||||
if ($category === 'core') {
|
||||
$params['core'] = true;
|
||||
} elseif ($category === 'app') {
|
||||
$params['app'] = true;
|
||||
} else {
|
||||
$params['plugin'] = $category;
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the options passed to the shell as options for the PHPUnit cli runner
|
||||
*
|
||||
* @return array Array of params for CakeTestDispatcher
|
||||
*/
|
||||
protected function _runnerOptions() {
|
||||
$options = array();
|
||||
$params = $this->params;
|
||||
unset($params['help']);
|
||||
|
||||
if (!empty($params['no-colors'])) {
|
||||
unset($params['no-colors'], $params['colors']);
|
||||
} else {
|
||||
$params['colors'] = true;
|
||||
}
|
||||
|
||||
foreach ($params as $param => $value) {
|
||||
if ($value === false) {
|
||||
continue;
|
||||
}
|
||||
$options[] = '--' . $param;
|
||||
if (is_string($value)) {
|
||||
$options[] = $value;
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main entry point to this shell
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function main() {
|
||||
$this->out(__d('cake_console', 'CakePHP Test Shell'));
|
||||
$this->hr();
|
||||
|
||||
$args = $this->_parseArgs();
|
||||
|
||||
if (empty($args['case'])) {
|
||||
return $this->available();
|
||||
}
|
||||
|
||||
$this->_run($args, $this->_runnerOptions());
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the test case from $runnerArgs
|
||||
*
|
||||
* @param array $runnerArgs list of arguments as obtained from _parseArgs()
|
||||
* @param array $options list of options as constructed by _runnerOptions()
|
||||
* @return void
|
||||
*/
|
||||
protected function _run($runnerArgs, $options = array()) {
|
||||
restore_error_handler();
|
||||
restore_error_handler();
|
||||
|
||||
$testCli = new CakeTestSuiteCommand('CakeTestLoader', $runnerArgs);
|
||||
$testCli->run($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a list of available test cases and gives the option to run one of them
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function available() {
|
||||
$params = $this->_parseArgs();
|
||||
$testCases = CakeTestLoader::generateTestList($params);
|
||||
$app = $params['app'];
|
||||
$plugin = $params['plugin'];
|
||||
|
||||
$title = "Core Test Cases:";
|
||||
$category = 'core';
|
||||
if ($app) {
|
||||
$title = "App Test Cases:";
|
||||
$category = 'app';
|
||||
} elseif ($plugin) {
|
||||
$title = Inflector::humanize($plugin) . " Test Cases:";
|
||||
$category = $plugin;
|
||||
}
|
||||
|
||||
if (empty($testCases)) {
|
||||
$this->out(__d('cake_console', "No test cases available \n\n"));
|
||||
return $this->out($this->OptionParser->help());
|
||||
}
|
||||
|
||||
$this->out($title);
|
||||
$i = 1;
|
||||
$cases = array();
|
||||
foreach ($testCases as $testCase) {
|
||||
$case = str_replace('Test.php', '', $testCase);
|
||||
$this->out("[$i] $case");
|
||||
$cases[$i] = $case;
|
||||
$i++;
|
||||
}
|
||||
|
||||
while ($choice = $this->in(__d('cake_console', 'What test case would you like to run?'), null, 'q')) {
|
||||
if (is_numeric($choice) && isset($cases[$choice])) {
|
||||
$this->args[0] = $category;
|
||||
$this->args[1] = $cases[$choice];
|
||||
$this->_run($this->_parseArgs(), $this->_runnerOptions());
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_string($choice) && in_array($choice, $cases)) {
|
||||
$this->args[0] = $category;
|
||||
$this->args[1] = $choice;
|
||||
$this->_run($this->_parseArgs(), $this->_runnerOptions());
|
||||
break;
|
||||
}
|
||||
|
||||
if ($choice === 'q') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the test case for the passed file. The file could itself be a test.
|
||||
*
|
||||
* @param string $file The file to map.
|
||||
* @param string $category The test file category.
|
||||
* @param bool $throwOnMissingFile Whether or not to throw an exception.
|
||||
* @return array array(type, case)
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function _mapFileToCase($file, $category, $throwOnMissingFile = true) {
|
||||
if (!$category || (substr($file, -4) !== '.php')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$_file = realpath($file);
|
||||
if ($_file) {
|
||||
$file = $_file;
|
||||
}
|
||||
|
||||
$testFile = $testCase = null;
|
||||
|
||||
if (preg_match('@Test[\\\/]@', $file)) {
|
||||
|
||||
if (substr($file, -8) === 'Test.php') {
|
||||
|
||||
$testCase = substr($file, 0, -8);
|
||||
$testCase = str_replace(DS, '/', $testCase);
|
||||
|
||||
if ($testCase = preg_replace('@.*Test\/Case\/@', '', $testCase)) {
|
||||
|
||||
if ($category === 'core') {
|
||||
$testCase = str_replace('lib/Cake', '', $testCase);
|
||||
}
|
||||
|
||||
return $testCase;
|
||||
}
|
||||
|
||||
throw new Exception(__d('cake_dev', 'Test case %s cannot be run via this shell', $testFile));
|
||||
}
|
||||
}
|
||||
|
||||
$file = substr($file, 0, -4);
|
||||
if ($category === 'core') {
|
||||
|
||||
$testCase = str_replace(DS, '/', $file);
|
||||
$testCase = preg_replace('@.*lib/Cake/@', '', $file);
|
||||
$testCase[0] = strtoupper($testCase[0]);
|
||||
$testFile = CAKE . 'Test/Case/' . $testCase . 'Test.php';
|
||||
|
||||
if (!file_exists($testFile) && $throwOnMissingFile) {
|
||||
throw new Exception(__d('cake_dev', 'Test case %s not found', $testFile));
|
||||
}
|
||||
|
||||
return $testCase;
|
||||
}
|
||||
|
||||
if ($category === 'app') {
|
||||
$testFile = str_replace(APP, APP . 'Test/Case/', $file) . 'Test.php';
|
||||
} else {
|
||||
$testFile = preg_replace(
|
||||
"@((?:plugins|Plugin)[\\/]{$category}[\\/])(.*)$@",
|
||||
'\1Test/Case/\2Test.php',
|
||||
$file
|
||||
);
|
||||
}
|
||||
|
||||
if (!file_exists($testFile) && $throwOnMissingFile) {
|
||||
throw new Exception(__d('cake_dev', 'Test case %s not found', $testFile));
|
||||
}
|
||||
|
||||
$testCase = substr($testFile, 0, -8);
|
||||
$testCase = str_replace(DS, '/', $testCase);
|
||||
$testCase = preg_replace('@.*Test/Case/@', '', $testCase);
|
||||
|
||||
return $testCase;
|
||||
}
|
||||
|
||||
/**
|
||||
* For the given file, what category of test is it? returns app, core or the name of the plugin
|
||||
*
|
||||
* @param string $file The file to map.
|
||||
* @return string
|
||||
*/
|
||||
protected function _mapFileToCategory($file) {
|
||||
$_file = realpath($file);
|
||||
if ($_file) {
|
||||
$file = $_file;
|
||||
}
|
||||
|
||||
$file = str_replace(DS, '/', $file);
|
||||
if (strpos($file, 'lib/Cake/') !== false) {
|
||||
return 'core';
|
||||
} elseif (preg_match('@(?:plugins|Plugin)/([^/]*)@', $file, $match)) {
|
||||
return $match[1];
|
||||
}
|
||||
return 'app';
|
||||
}
|
||||
|
||||
}
|
||||
100
lib/Cake/Console/Command/TestsuiteShell.php
Normal file
100
lib/Cake/Console/Command/TestsuiteShell.php
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
/**
|
||||
* Test Suite Shell
|
||||
*
|
||||
* This is a bc wrapper for the newer Test shell
|
||||
*
|
||||
* CakePHP(tm) Tests <http://book.cakephp.org/2.0/en/development/testing.html>
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://book.cakephp.org/2.0/en/development/testing.html
|
||||
* @since CakePHP(tm) v 1.2.0.4433
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('TestShell', 'Console/Command');
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
App::uses('CakeTestSuiteDispatcher', 'TestSuite');
|
||||
App::uses('CakeTestSuiteCommand', 'TestSuite');
|
||||
App::uses('CakeTestLoader', 'TestSuite');
|
||||
|
||||
/**
|
||||
* Provides a CakePHP wrapper around PHPUnit.
|
||||
* Adds in CakePHP's fixtures and gives access to plugin, app and core test cases
|
||||
*
|
||||
* @package Cake.Console.Command
|
||||
*/
|
||||
class TestsuiteShell extends TestShell {
|
||||
|
||||
/**
|
||||
* Gets the option parser instance and configures it.
|
||||
*
|
||||
* @return ConsoleOptionParser
|
||||
*/
|
||||
public function getOptionParser() {
|
||||
$parser = parent::getOptionParser();
|
||||
|
||||
$parser->description(array(
|
||||
__d('cake_console', 'The CakePHP Testsuite allows you to run test cases from the command line'),
|
||||
__d('cake_console', "<warning>This shell is for backwards-compatibility only</warning>\nuse the test shell instead")
|
||||
));
|
||||
|
||||
return $parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the CLI options into an array CakeTestDispatcher can use.
|
||||
*
|
||||
* @return array Array of params for CakeTestDispatcher
|
||||
*/
|
||||
protected function _parseArgs() {
|
||||
if (empty($this->args)) {
|
||||
return;
|
||||
}
|
||||
$params = array(
|
||||
'core' => false,
|
||||
'app' => false,
|
||||
'plugin' => null,
|
||||
'output' => 'text',
|
||||
);
|
||||
|
||||
$category = $this->args[0];
|
||||
|
||||
if ($category === 'core') {
|
||||
$params['core'] = true;
|
||||
} elseif ($category === 'app') {
|
||||
$params['app'] = true;
|
||||
} elseif ($category !== 'core') {
|
||||
$params['plugin'] = $category;
|
||||
}
|
||||
|
||||
if (isset($this->args[1])) {
|
||||
$params['case'] = $this->args[1];
|
||||
}
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main entry point to this shell
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function main() {
|
||||
$this->out(__d('cake_console', 'CakePHP Test Shell'));
|
||||
$this->hr();
|
||||
|
||||
$args = $this->_parseArgs();
|
||||
|
||||
if (empty($args['case'])) {
|
||||
return $this->available();
|
||||
}
|
||||
|
||||
$this->_run($args, $this->_runnerOptions());
|
||||
}
|
||||
|
||||
}
|
||||
888
lib/Cake/Console/Command/UpgradeShell.php
Normal file
888
lib/Cake/Console/Command/UpgradeShell.php
Normal file
|
|
@ -0,0 +1,888 @@
|
|||
<?php
|
||||
/**
|
||||
* Upgrade Shell
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Console.Command
|
||||
* @since CakePHP(tm) v 2.0
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
App::uses('Folder', 'Utility');
|
||||
App::uses('CakePlugin', 'Core');
|
||||
|
||||
/**
|
||||
* A shell class to help developers upgrade applications to CakePHP 2.0
|
||||
*
|
||||
* @package Cake.Console.Command
|
||||
*/
|
||||
class UpgradeShell extends AppShell {
|
||||
|
||||
/**
|
||||
* Files
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_files = array();
|
||||
|
||||
/**
|
||||
* Paths
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_paths = array();
|
||||
|
||||
/**
|
||||
* Map
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_map = array(
|
||||
'Controller' => 'Controller',
|
||||
'Component' => 'Controller/Component',
|
||||
'Model' => 'Model',
|
||||
'Behavior' => 'Model/Behavior',
|
||||
'Datasource' => 'Model/Datasource',
|
||||
'Dbo' => 'Model/Datasource/Database',
|
||||
'View' => 'View',
|
||||
'Helper' => 'View/Helper',
|
||||
'Shell' => 'Console/Command',
|
||||
'Task' => 'Console/Command/Task',
|
||||
'Case' => 'Test/Case',
|
||||
'Fixture' => 'Test/Fixture',
|
||||
'Error' => 'Lib/Error',
|
||||
);
|
||||
|
||||
/**
|
||||
* Shell startup, prints info message about dry run.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function startup() {
|
||||
parent::startup();
|
||||
if ($this->params['dry-run']) {
|
||||
$this->out(__d('cake_console', '<warning>Dry-run mode enabled!</warning>'), 1, Shell::QUIET);
|
||||
}
|
||||
if ($this->params['git'] && !is_dir('.git')) {
|
||||
$this->out(__d('cake_console', '<warning>No git repository detected!</warning>'), 1, Shell::QUIET);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run all upgrade steps one at a time
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function all() {
|
||||
foreach ($this->OptionParser->subcommands() as $command) {
|
||||
$name = $command->name();
|
||||
if ($name === 'all') {
|
||||
continue;
|
||||
}
|
||||
$this->out(__d('cake_console', 'Running %s', $name));
|
||||
$this->$name();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update tests.
|
||||
*
|
||||
* - Update tests class names to FooTest rather than FooTestCase.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function tests() {
|
||||
$this->_paths = array(APP . 'tests' . DS);
|
||||
if (!empty($this->params['plugin'])) {
|
||||
$this->_paths = array(CakePlugin::path($this->params['plugin']) . 'tests' . DS);
|
||||
}
|
||||
$patterns = array(
|
||||
array(
|
||||
'*TestCase extends CakeTestCase to *Test extends CakeTestCase',
|
||||
'/([a-zA-Z]*Test)Case extends CakeTestCase/',
|
||||
'\1 extends CakeTestCase'
|
||||
),
|
||||
);
|
||||
|
||||
$this->_filesRegexpUpdate($patterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move files and folders to their new homes
|
||||
*
|
||||
* Moves folders containing files which cannot necessarily be auto-detected (libs and templates)
|
||||
* and then looks for all php files except vendors, and moves them to where Cake 2.0 expects
|
||||
* to find them.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function locations() {
|
||||
$cwd = getcwd();
|
||||
|
||||
if (!empty($this->params['plugin'])) {
|
||||
chdir(CakePlugin::path($this->params['plugin']));
|
||||
}
|
||||
|
||||
if (is_dir('plugins')) {
|
||||
$Folder = new Folder('plugins');
|
||||
list($plugins) = $Folder->read();
|
||||
foreach ($plugins as $plugin) {
|
||||
chdir($cwd . DS . 'plugins' . DS . $plugin);
|
||||
$this->out(__d('cake_console', 'Upgrading locations for plugin %s', $plugin));
|
||||
$this->locations();
|
||||
}
|
||||
$this->_files = array();
|
||||
chdir($cwd);
|
||||
$this->out(__d('cake_console', 'Upgrading locations for app directory'));
|
||||
}
|
||||
$moves = array(
|
||||
'config' => 'Config',
|
||||
'Config' . DS . 'schema' => 'Config' . DS . 'Schema',
|
||||
'libs' => 'Lib',
|
||||
'tests' => 'Test',
|
||||
'views' => 'View',
|
||||
'models' => 'Model',
|
||||
'Model' . DS . 'behaviors' => 'Model' . DS . 'Behavior',
|
||||
'Model' . DS . 'datasources' => 'Model' . DS . 'Datasource',
|
||||
'Test' . DS . 'cases' => 'Test' . DS . 'Case',
|
||||
'Test' . DS . 'fixtures' => 'Test' . DS . 'Fixture',
|
||||
'vendors' . DS . 'shells' . DS . 'templates' => 'Console' . DS . 'Templates',
|
||||
);
|
||||
foreach ($moves as $old => $new) {
|
||||
if (is_dir($old)) {
|
||||
$this->out(__d('cake_console', 'Moving %s to %s', $old, $new));
|
||||
if (!$this->params['dry-run']) {
|
||||
if ($this->params['git']) {
|
||||
exec('git mv -f ' . escapeshellarg($old) . ' ' . escapeshellarg($old . '__'));
|
||||
exec('git mv -f ' . escapeshellarg($old . '__') . ' ' . escapeshellarg($new));
|
||||
} else {
|
||||
$Folder = new Folder($old);
|
||||
$Folder->move($new);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->_moveViewFiles();
|
||||
$this->_moveAppClasses();
|
||||
|
||||
$sourceDirs = array(
|
||||
'.' => array('recursive' => false),
|
||||
'Console',
|
||||
'controllers',
|
||||
'Controller',
|
||||
'Lib' => array('checkFolder' => false),
|
||||
'models',
|
||||
'Model',
|
||||
'tests',
|
||||
'Test' => array('regex' => '@class (\S*Test) extends CakeTestCase@'),
|
||||
'views',
|
||||
'View',
|
||||
'vendors/shells',
|
||||
);
|
||||
|
||||
$defaultOptions = array(
|
||||
'recursive' => true,
|
||||
'checkFolder' => true,
|
||||
'regex' => '@class (\S*) .*(\s|\v)*{@i'
|
||||
);
|
||||
foreach ($sourceDirs as $dir => $options) {
|
||||
if (is_numeric($dir)) {
|
||||
$dir = $options;
|
||||
$options = array();
|
||||
}
|
||||
$options += $defaultOptions;
|
||||
$this->_movePhpFiles($dir, $options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update helpers.
|
||||
*
|
||||
* - Converts helpers usage to new format.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function helpers() {
|
||||
$this->_paths = array_diff(App::path('views'), App::core('views'));
|
||||
|
||||
if (!empty($this->params['plugin'])) {
|
||||
$this->_paths = array(CakePlugin::path($this->params['plugin']) . 'views' . DS);
|
||||
}
|
||||
|
||||
$patterns = array();
|
||||
App::build(array(
|
||||
'View/Helper' => App::core('View/Helper'),
|
||||
), App::APPEND);
|
||||
$helpers = App::objects('helper');
|
||||
$plugins = App::objects('plugin');
|
||||
$pluginHelpers = array();
|
||||
foreach ($plugins as $plugin) {
|
||||
CakePlugin::load($plugin);
|
||||
$pluginHelpers = array_merge(
|
||||
$pluginHelpers,
|
||||
App::objects('helper', CakePlugin::path($plugin) . DS . 'views' . DS . 'helpers' . DS, false)
|
||||
);
|
||||
}
|
||||
$helpers = array_merge($pluginHelpers, $helpers);
|
||||
foreach ($helpers as $helper) {
|
||||
$helper = preg_replace('/Helper$/', '', $helper);
|
||||
$oldHelper = $helper;
|
||||
$oldHelper{0} = strtolower($oldHelper{0});
|
||||
$patterns[] = array(
|
||||
"\${$oldHelper} to \$this->{$helper}",
|
||||
"/\\\${$oldHelper}->/",
|
||||
"\\\$this->{$helper}->"
|
||||
);
|
||||
}
|
||||
|
||||
$this->_filesRegexpUpdate($patterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update i18n.
|
||||
*
|
||||
* - Removes extra true param.
|
||||
* - Add the echo to __*() calls that didn't need them before.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function i18n() {
|
||||
$this->_paths = array(
|
||||
APP
|
||||
);
|
||||
if (!empty($this->params['plugin'])) {
|
||||
$this->_paths = array(CakePlugin::path($this->params['plugin']));
|
||||
}
|
||||
|
||||
$patterns = array(
|
||||
array(
|
||||
'<?php __*(*) to <?php echo __*(*)',
|
||||
'/<\?php\s*(__[a-z]*\(.*?\))/',
|
||||
'<?php echo \1'
|
||||
),
|
||||
array(
|
||||
'<?php __*(*, true) to <?php echo __*()',
|
||||
'/<\?php\s*(__[a-z]*\(.*?)(,\s*true)(\))/',
|
||||
'<?php echo \1\3'
|
||||
),
|
||||
array('__*(*, true) to __*(*)', '/(__[a-z]*\(.*?)(,\s*true)(\))/', '\1\3')
|
||||
);
|
||||
|
||||
$this->_filesRegexpUpdate($patterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upgrade the removed basics functions.
|
||||
*
|
||||
* - a(*) -> array(*)
|
||||
* - e(*) -> echo *
|
||||
* - ife(*, *, *) -> !empty(*) ? * : *
|
||||
* - a(*) -> array(*)
|
||||
* - r(*, *, *) -> str_replace(*, *, *)
|
||||
* - up(*) -> strtoupper(*)
|
||||
* - low(*, *, *) -> strtolower(*)
|
||||
* - getMicrotime() -> microtime(true)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function basics() {
|
||||
$this->_paths = array(
|
||||
APP
|
||||
);
|
||||
if (!empty($this->params['plugin'])) {
|
||||
$this->_paths = array(CakePlugin::path($this->params['plugin']));
|
||||
}
|
||||
$patterns = array(
|
||||
array(
|
||||
'a(*) -> array(*)',
|
||||
'/\ba\((.*)\)/',
|
||||
'array(\1)'
|
||||
),
|
||||
array(
|
||||
'e(*) -> echo *',
|
||||
'/\be\((.*)\)/',
|
||||
'echo \1'
|
||||
),
|
||||
array(
|
||||
'ife(*, *, *) -> !empty(*) ? * : *',
|
||||
'/ife\((.*), (.*), (.*)\)/',
|
||||
'!empty(\1) ? \2 : \3'
|
||||
),
|
||||
array(
|
||||
'r(*, *, *) -> str_replace(*, *, *)',
|
||||
'/\br\(/',
|
||||
'str_replace('
|
||||
),
|
||||
array(
|
||||
'up(*) -> strtoupper(*)',
|
||||
'/\bup\(/',
|
||||
'strtoupper('
|
||||
),
|
||||
array(
|
||||
'low(*) -> strtolower(*)',
|
||||
'/\blow\(/',
|
||||
'strtolower('
|
||||
),
|
||||
array(
|
||||
'getMicrotime() -> microtime(true)',
|
||||
'/getMicrotime\(\)/',
|
||||
'microtime(true)'
|
||||
),
|
||||
);
|
||||
$this->_filesRegexpUpdate($patterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the properties moved to CakeRequest.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function request() {
|
||||
$views = array_diff(App::path('views'), App::core('views'));
|
||||
$controllers = array_diff(App::path('controllers'), App::core('controllers'), array(APP));
|
||||
$components = array_diff(App::path('components'), App::core('components'));
|
||||
|
||||
$this->_paths = array_merge($views, $controllers, $components);
|
||||
|
||||
if (!empty($this->params['plugin'])) {
|
||||
$pluginPath = CakePlugin::path($this->params['plugin']);
|
||||
$this->_paths = array(
|
||||
$pluginPath . 'controllers' . DS,
|
||||
$pluginPath . 'controllers' . DS . 'components' . DS,
|
||||
$pluginPath . 'views' . DS,
|
||||
);
|
||||
}
|
||||
$patterns = array(
|
||||
array(
|
||||
'$this->data -> $this->request->data',
|
||||
'/(\$this->data\b(?!\())/',
|
||||
'$this->request->data'
|
||||
),
|
||||
array(
|
||||
'$this->params -> $this->request->params',
|
||||
'/(\$this->params\b(?!\())/',
|
||||
'$this->request->params'
|
||||
),
|
||||
array(
|
||||
'$this->webroot -> $this->request->webroot',
|
||||
'/(\$this->webroot\b(?!\())/',
|
||||
'$this->request->webroot'
|
||||
),
|
||||
array(
|
||||
'$this->base -> $this->request->base',
|
||||
'/(\$this->base\b(?!\())/',
|
||||
'$this->request->base'
|
||||
),
|
||||
array(
|
||||
'$this->here -> $this->request->here',
|
||||
'/(\$this->here\b(?!\())/',
|
||||
'$this->request->here'
|
||||
),
|
||||
array(
|
||||
'$this->action -> $this->request->action',
|
||||
'/(\$this->action\b(?!\())/',
|
||||
'$this->request->action'
|
||||
),
|
||||
array(
|
||||
'$this->request->onlyAllow() -> $this->request->allowMethod()',
|
||||
'/\$this->request->onlyAllow\(/',
|
||||
'$this->request->allowMethod('
|
||||
)
|
||||
);
|
||||
$this->_filesRegexpUpdate($patterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Configure::read() calls with no params.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function configure() {
|
||||
$this->_paths = array(
|
||||
APP
|
||||
);
|
||||
if (!empty($this->params['plugin'])) {
|
||||
$this->_paths = array(CakePlugin::path($this->params['plugin']));
|
||||
}
|
||||
$patterns = array(
|
||||
array(
|
||||
"Configure::read() -> Configure::read('debug')",
|
||||
'/Configure::read\(\)/',
|
||||
'Configure::read(\'debug\')'
|
||||
),
|
||||
);
|
||||
$this->_filesRegexpUpdate($patterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* constants
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function constants() {
|
||||
$this->_paths = array(
|
||||
APP
|
||||
);
|
||||
if (!empty($this->params['plugin'])) {
|
||||
$this->_paths = array(CakePlugin::path($this->params['plugin']));
|
||||
}
|
||||
$patterns = array(
|
||||
array(
|
||||
"LIBS -> CAKE",
|
||||
'/\bLIBS\b/',
|
||||
'CAKE'
|
||||
),
|
||||
array(
|
||||
"CONFIGS -> APP . 'Config' . DS",
|
||||
'/\bCONFIGS\b/',
|
||||
'APP . \'Config\' . DS'
|
||||
),
|
||||
array(
|
||||
"CONTROLLERS -> APP . 'Controller' . DS",
|
||||
'/\bCONTROLLERS\b/',
|
||||
'APP . \'Controller\' . DS'
|
||||
),
|
||||
array(
|
||||
"COMPONENTS -> APP . 'Controller' . DS . 'Component' . DS",
|
||||
'/\bCOMPONENTS\b/',
|
||||
'APP . \'Controller\' . DS . \'Component\''
|
||||
),
|
||||
array(
|
||||
"MODELS -> APP . 'Model' . DS",
|
||||
'/\bMODELS\b/',
|
||||
'APP . \'Model\' . DS'
|
||||
),
|
||||
array(
|
||||
"BEHAVIORS -> APP . 'Model' . DS . 'Behavior' . DS",
|
||||
'/\bBEHAVIORS\b/',
|
||||
'APP . \'Model\' . DS . \'Behavior\' . DS'
|
||||
),
|
||||
array(
|
||||
"VIEWS -> APP . 'View' . DS",
|
||||
'/\bVIEWS\b/',
|
||||
'APP . \'View\' . DS'
|
||||
),
|
||||
array(
|
||||
"HELPERS -> APP . 'View' . DS . 'Helper' . DS",
|
||||
'/\bHELPERS\b/',
|
||||
'APP . \'View\' . DS . \'Helper\' . DS'
|
||||
),
|
||||
array(
|
||||
"LAYOUTS -> APP . 'View' . DS . 'Layouts' . DS",
|
||||
'/\bLAYOUTS\b/',
|
||||
'APP . \'View\' . DS . \'Layouts\' . DS'
|
||||
),
|
||||
array(
|
||||
"ELEMENTS -> APP . 'View' . DS . 'Elements' . DS",
|
||||
'/\bELEMENTS\b/',
|
||||
'APP . \'View\' . DS . \'Elements\' . DS'
|
||||
),
|
||||
array(
|
||||
"CONSOLE_LIBS -> CAKE . 'Console' . DS",
|
||||
'/\bCONSOLE_LIBS\b/',
|
||||
'CAKE . \'Console\' . DS'
|
||||
),
|
||||
array(
|
||||
"CAKE_TESTS_LIB -> CAKE . 'TestSuite' . DS",
|
||||
'/\bCAKE_TESTS_LIB\b/',
|
||||
'CAKE . \'TestSuite\' . DS'
|
||||
),
|
||||
array(
|
||||
"CAKE_TESTS -> CAKE . 'Test' . DS",
|
||||
'/\bCAKE_TESTS\b/',
|
||||
'CAKE . \'Test\' . DS'
|
||||
)
|
||||
);
|
||||
$this->_filesRegexpUpdate($patterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update controller redirects.
|
||||
*
|
||||
* - Make redirect statements return early.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function controller_redirects() {
|
||||
$this->_paths = App::Path('Controller');
|
||||
if (!empty($this->params['plugin'])) {
|
||||
$this->_paths = App::Path('Controller', $this->params['plugin']);
|
||||
}
|
||||
$patterns = array(
|
||||
array(
|
||||
'$this->redirect() to return $this->redirect()',
|
||||
'/\t\$this-\>redirect\(/',
|
||||
"\t" . 'return $this->redirect('
|
||||
),
|
||||
);
|
||||
|
||||
$this->_filesRegexpUpdate($patterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update components.
|
||||
*
|
||||
* - Make components that extend Object to extend Component.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function components() {
|
||||
$this->_paths = App::Path('Controller/Component');
|
||||
if (!empty($this->params['plugin'])) {
|
||||
$this->_paths = App::Path('Controller/Component', $this->params['plugin']);
|
||||
}
|
||||
$patterns = array(
|
||||
array(
|
||||
'*Component extends Object to *Component extends Component',
|
||||
'/([a-zA-Z]*Component extends) Object/',
|
||||
'\1 Component'
|
||||
),
|
||||
);
|
||||
|
||||
$this->_filesRegexpUpdate($patterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace cakeError with built-in exceptions.
|
||||
* NOTE: this ignores calls where you've passed your own secondary parameters to cakeError().
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function exceptions() {
|
||||
$controllers = array_diff(App::path('controllers'), App::core('controllers'), array(APP));
|
||||
$components = array_diff(App::path('components'), App::core('components'));
|
||||
|
||||
$this->_paths = array_merge($controllers, $components);
|
||||
|
||||
if (!empty($this->params['plugin'])) {
|
||||
$pluginPath = CakePlugin::path($this->params['plugin']);
|
||||
$this->_paths = array(
|
||||
$pluginPath . 'controllers' . DS,
|
||||
$pluginPath . 'controllers' . DS . 'components' . DS,
|
||||
);
|
||||
}
|
||||
$patterns = array(
|
||||
array(
|
||||
'$this->cakeError("error400") -> throw new BadRequestException()',
|
||||
'/(\$this->cakeError\(["\']error400["\']\));/',
|
||||
'throw new BadRequestException();'
|
||||
),
|
||||
array(
|
||||
'$this->cakeError("error404") -> throw new NotFoundException()',
|
||||
'/(\$this->cakeError\(["\']error404["\']\));/',
|
||||
'throw new NotFoundException();'
|
||||
),
|
||||
array(
|
||||
'$this->cakeError("error500") -> throw new InternalErrorException()',
|
||||
'/(\$this->cakeError\(["\']error500["\']\));/',
|
||||
'throw new InternalErrorException();'
|
||||
),
|
||||
);
|
||||
$this->_filesRegexpUpdate($patterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move application views files to where they now should be
|
||||
*
|
||||
* Find all view files in the folder and determine where cake expects the file to be
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _moveViewFiles() {
|
||||
if (!is_dir('View')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$dirs = scandir('View');
|
||||
foreach ($dirs as $old) {
|
||||
if (!is_dir('View' . DS . $old) || $old === '.' || $old === '..') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$new = 'View' . DS . Inflector::camelize($old);
|
||||
$old = 'View' . DS . $old;
|
||||
if ($new === $old) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->out(__d('cake_console', 'Moving %s to %s', $old, $new));
|
||||
if (!$this->params['dry-run']) {
|
||||
if ($this->params['git']) {
|
||||
exec('git mv -f ' . escapeshellarg($old) . ' ' . escapeshellarg($old . '__'));
|
||||
exec('git mv -f ' . escapeshellarg($old . '__') . ' ' . escapeshellarg($new));
|
||||
} else {
|
||||
$Folder = new Folder($old);
|
||||
$Folder->move($new);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the AppController, and AppModel classes.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _moveAppClasses() {
|
||||
$files = array(
|
||||
APP . 'app_controller.php' => APP . 'Controller' . DS . 'AppController.php',
|
||||
APP . 'controllers' . DS . 'app_controller.php' => APP . 'Controller' . DS . 'AppController.php',
|
||||
APP . 'app_model.php' => APP . 'Model' . DS . 'AppModel.php',
|
||||
APP . 'models' . DS . 'app_model.php' => APP . 'Model' . DS . 'AppModel.php',
|
||||
);
|
||||
foreach ($files as $old => $new) {
|
||||
if (file_exists($old)) {
|
||||
$this->out(__d('cake_console', 'Moving %s to %s', $old, $new));
|
||||
|
||||
if ($this->params['dry-run']) {
|
||||
continue;
|
||||
}
|
||||
if ($this->params['git']) {
|
||||
exec('git mv -f ' . escapeshellarg($old) . ' ' . escapeshellarg($old . '__'));
|
||||
exec('git mv -f ' . escapeshellarg($old . '__') . ' ' . escapeshellarg($new));
|
||||
} else {
|
||||
rename($old, $new);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move application php files to where they now should be
|
||||
*
|
||||
* Find all php files in the folder (honoring recursive) and determine where CakePHP expects the file to be
|
||||
* If the file is not exactly where CakePHP expects it - move it.
|
||||
*
|
||||
* @param string $path The path to move files in.
|
||||
* @param array $options array(recursive, checkFolder)
|
||||
* @return void
|
||||
*/
|
||||
protected function _movePhpFiles($path, $options) {
|
||||
if (!is_dir($path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$paths = $this->_paths;
|
||||
|
||||
$this->_paths = array($path);
|
||||
$this->_files = array();
|
||||
if ($options['recursive']) {
|
||||
$this->_findFiles('php');
|
||||
} else {
|
||||
$this->_files = scandir($path);
|
||||
foreach ($this->_files as $i => $file) {
|
||||
if (strlen($file) < 5 || substr($file, -4) !== '.php') {
|
||||
unset($this->_files[$i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$cwd = getcwd();
|
||||
foreach ($this->_files as &$file) {
|
||||
$file = $cwd . DS . $file;
|
||||
|
||||
$contents = file_get_contents($file);
|
||||
preg_match($options['regex'], $contents, $match);
|
||||
if (!$match) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$class = $match[1];
|
||||
|
||||
if (substr($class, 0, 3) === 'Dbo') {
|
||||
$type = 'Dbo';
|
||||
} else {
|
||||
preg_match('@([A-Z][^A-Z]*)$@', $class, $match);
|
||||
if ($match) {
|
||||
$type = $match[1];
|
||||
} else {
|
||||
$type = 'unknown';
|
||||
}
|
||||
}
|
||||
|
||||
preg_match('@^.*[\\\/]plugins[\\\/](.*?)[\\\/]@', $file, $match);
|
||||
$base = $cwd . DS;
|
||||
$plugin = false;
|
||||
if ($match) {
|
||||
$base = $match[0];
|
||||
$plugin = $match[1];
|
||||
}
|
||||
|
||||
if ($options['checkFolder'] && !empty($this->_map[$type])) {
|
||||
$folder = str_replace('/', DS, $this->_map[$type]);
|
||||
$new = $base . $folder . DS . $class . '.php';
|
||||
} else {
|
||||
$new = dirname($file) . DS . $class . '.php';
|
||||
}
|
||||
|
||||
if ($file === $new) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$dir = dirname($new);
|
||||
if (!is_dir($dir)) {
|
||||
new Folder($dir, true);
|
||||
}
|
||||
|
||||
$this->out(__d('cake_console', 'Moving %s to %s', $file, $new), 1, Shell::VERBOSE);
|
||||
if (!$this->params['dry-run']) {
|
||||
if ($this->params['git']) {
|
||||
exec('git mv -f ' . escapeshellarg($file) . ' ' . escapeshellarg($file . '__'));
|
||||
exec('git mv -f ' . escapeshellarg($file . '__') . ' ' . escapeshellarg($new));
|
||||
} else {
|
||||
rename($file, $new);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->_paths = $paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates files based on regular expressions.
|
||||
*
|
||||
* @param array $patterns Array of search and replacement patterns.
|
||||
* @return void
|
||||
*/
|
||||
protected function _filesRegexpUpdate($patterns) {
|
||||
$this->_findFiles($this->params['ext']);
|
||||
foreach ($this->_files as $file) {
|
||||
$this->out(__d('cake_console', 'Updating %s...', $file), 1, Shell::VERBOSE);
|
||||
$this->_updateFile($file, $patterns);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the paths and finds files based on extension.
|
||||
*
|
||||
* @param string $extensions The extensions to include. Defaults to none.
|
||||
* @return void
|
||||
*/
|
||||
protected function _findFiles($extensions = '') {
|
||||
$this->_files = array();
|
||||
foreach ($this->_paths as $path) {
|
||||
if (!is_dir($path)) {
|
||||
continue;
|
||||
}
|
||||
$Iterator = new RegexIterator(
|
||||
new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)),
|
||||
'/^.+\.(' . $extensions . ')$/i',
|
||||
RegexIterator::MATCH
|
||||
);
|
||||
foreach ($Iterator as $file) {
|
||||
if ($file->isFile()) {
|
||||
$this->_files[] = $file->getPathname();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a single file.
|
||||
*
|
||||
* @param string $file The file to update
|
||||
* @param array $patterns The replacement patterns to run.
|
||||
* @return void
|
||||
*/
|
||||
protected function _updateFile($file, $patterns) {
|
||||
$contents = file_get_contents($file);
|
||||
|
||||
foreach ($patterns as $pattern) {
|
||||
$this->out(__d('cake_console', ' * Updating %s', $pattern[0]), 1, Shell::VERBOSE);
|
||||
$contents = preg_replace($pattern[1], $pattern[2], $contents);
|
||||
}
|
||||
|
||||
$this->out(__d('cake_console', 'Done updating %s', $file), 1);
|
||||
if (!$this->params['dry-run']) {
|
||||
file_put_contents($file, $contents);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the option parser instance and configures it.
|
||||
*
|
||||
* @return ConsoleOptionParser
|
||||
*/
|
||||
public function getOptionParser() {
|
||||
$parser = parent::getOptionParser();
|
||||
|
||||
$subcommandParser = array(
|
||||
'options' => array(
|
||||
'plugin' => array(
|
||||
'short' => 'p',
|
||||
'help' => __d('cake_console', 'The plugin to update. Only the specified plugin will be updated.')
|
||||
),
|
||||
'ext' => array(
|
||||
'short' => 'e',
|
||||
'help' => __d('cake_console', 'The extension(s) to search. A pipe delimited list, or a preg_match compatible subpattern'),
|
||||
'default' => 'php|ctp|thtml|inc|tpl'
|
||||
),
|
||||
'git' => array(
|
||||
'short' => 'g',
|
||||
'help' => __d('cake_console', 'Use git command for moving files around.'),
|
||||
'boolean' => true
|
||||
),
|
||||
'dry-run' => array(
|
||||
'short' => 'd',
|
||||
'help' => __d('cake_console', 'Dry run the update, no files will actually be modified.'),
|
||||
'boolean' => true
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$parser->description(
|
||||
__d('cake_console', "A tool to help automate upgrading an application or plugin " .
|
||||
"from CakePHP 1.3 to 2.0. Be sure to have a backup of your application before " .
|
||||
"running these commands."
|
||||
))->addSubcommand('all', array(
|
||||
'help' => __d('cake_console', 'Run all upgrade commands.'),
|
||||
'parser' => $subcommandParser
|
||||
))->addSubcommand('tests', array(
|
||||
'help' => __d('cake_console', 'Update tests class names to FooTest rather than FooTestCase.'),
|
||||
'parser' => $subcommandParser
|
||||
))->addSubcommand('locations', array(
|
||||
'help' => __d('cake_console', 'Move files and folders to their new homes.'),
|
||||
'parser' => $subcommandParser
|
||||
))->addSubcommand('i18n', array(
|
||||
'help' => __d('cake_console', 'Update the i18n translation method calls.'),
|
||||
'parser' => $subcommandParser
|
||||
))->addSubcommand('helpers', array(
|
||||
'help' => __d('cake_console', 'Update calls to helpers.'),
|
||||
'parser' => $subcommandParser
|
||||
))->addSubcommand('basics', array(
|
||||
'help' => __d('cake_console', 'Update removed basics functions to PHP native functions.'),
|
||||
'parser' => $subcommandParser
|
||||
))->addSubcommand('request', array(
|
||||
'help' => __d('cake_console', 'Update removed request access, and replace with $this->request.'),
|
||||
'parser' => $subcommandParser
|
||||
))->addSubcommand('configure', array(
|
||||
'help' => __d('cake_console', "Update Configure::read() to Configure::read('debug')"),
|
||||
'parser' => $subcommandParser
|
||||
))->addSubcommand('constants', array(
|
||||
'help' => __d('cake_console', "Replace Obsolete constants"),
|
||||
'parser' => $subcommandParser
|
||||
))->addSubcommand('controller_redirects', array(
|
||||
'help' => __d('cake_console', 'Return early on controller redirect calls.'),
|
||||
'parser' => $subcommandParser
|
||||
))->addSubcommand('components', array(
|
||||
'help' => __d('cake_console', 'Update components to extend Component class.'),
|
||||
'parser' => $subcommandParser
|
||||
))->addSubcommand('exceptions', array(
|
||||
'help' => __d('cake_console', 'Replace use of cakeError with exceptions.'),
|
||||
'parser' => $subcommandParser
|
||||
));
|
||||
|
||||
return $parser;
|
||||
}
|
||||
|
||||
}
|
||||
105
lib/Cake/Console/ConsoleErrorHandler.php
Normal file
105
lib/Cake/Console/ConsoleErrorHandler.php
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
/**
|
||||
* ErrorHandler for Console Shells
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 2.0
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('ErrorHandler', 'Error');
|
||||
App::uses('ConsoleOutput', 'Console');
|
||||
App::uses('CakeLog', 'Log');
|
||||
|
||||
/**
|
||||
* Error Handler for Cake console. Does simple printing of the
|
||||
* exception that occurred and the stack trace of the error.
|
||||
*
|
||||
* @package Cake.Console
|
||||
*/
|
||||
class ConsoleErrorHandler {
|
||||
|
||||
/**
|
||||
* Standard error stream.
|
||||
*
|
||||
* @var ConsoleOutput
|
||||
*/
|
||||
public static $stderr;
|
||||
|
||||
/**
|
||||
* Get the stderr object for the console error handling.
|
||||
*
|
||||
* @return ConsoleOutput
|
||||
*/
|
||||
public static function getStderr() {
|
||||
if (empty(self::$stderr)) {
|
||||
self::$stderr = new ConsoleOutput('php://stderr');
|
||||
}
|
||||
return self::$stderr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a exception in the console environment. Prints a message to stderr.
|
||||
*
|
||||
* @param Exception $exception The exception to handle
|
||||
* @return void
|
||||
*/
|
||||
public function handleException(Exception $exception) {
|
||||
$stderr = self::getStderr();
|
||||
$stderr->write(__d('cake_console', "<error>Error:</error> %s\n%s",
|
||||
$exception->getMessage(),
|
||||
$exception->getTraceAsString()
|
||||
));
|
||||
$code = $exception->getCode();
|
||||
$code = ($code && is_int($code)) ? $code : 1;
|
||||
return $this->_stop($code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle errors in the console environment. Writes errors to stderr,
|
||||
* and logs messages if Configure::read('debug') is 0.
|
||||
*
|
||||
* @param int $code Error code
|
||||
* @param string $description Description of the error.
|
||||
* @param string $file The file the error occurred in.
|
||||
* @param int $line The line the error occurred on.
|
||||
* @param array $context The backtrace of the error.
|
||||
* @return void
|
||||
*/
|
||||
public function handleError($code, $description, $file = null, $line = null, $context = null) {
|
||||
if (error_reporting() === 0) {
|
||||
return;
|
||||
}
|
||||
$stderr = self::getStderr();
|
||||
list($name, $log) = ErrorHandler::mapErrorCode($code);
|
||||
$message = __d('cake_console', '%s in [%s, line %s]', $description, $file, $line);
|
||||
$stderr->write(__d('cake_console', "<error>%s Error:</error> %s\n", $name, $message));
|
||||
|
||||
if (!Configure::read('debug')) {
|
||||
CakeLog::write($log, $message);
|
||||
}
|
||||
|
||||
if ($log === LOG_ERR) {
|
||||
return $this->_stop(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for exit(), used for testing.
|
||||
*
|
||||
* @param int $code The exit code.
|
||||
* @return void
|
||||
*/
|
||||
protected function _stop($code = 0) {
|
||||
exit($code);
|
||||
}
|
||||
|
||||
}
|
||||
82
lib/Cake/Console/ConsoleInput.php
Normal file
82
lib/Cake/Console/ConsoleInput.php
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
/**
|
||||
* ConsoleInput file.
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Console
|
||||
* @since CakePHP(tm) v 2.0
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Object wrapper for interacting with stdin
|
||||
*
|
||||
* @package Cake.Console
|
||||
*/
|
||||
class ConsoleInput {
|
||||
|
||||
/**
|
||||
* Input value.
|
||||
*
|
||||
* @var resource
|
||||
*/
|
||||
protected $_input;
|
||||
|
||||
/**
|
||||
* Can this instance use readline?
|
||||
* Two conditions must be met:
|
||||
* 1. Readline support must be enabled.
|
||||
* 2. Handle we are attached to must be stdin.
|
||||
* Allows rich editing with arrow keys and history when inputting a string.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_canReadline;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $handle The location of the stream to use as input.
|
||||
*/
|
||||
public function __construct($handle = 'php://stdin') {
|
||||
$this->_canReadline = extension_loaded('readline') && $handle === 'php://stdin' ? true : false;
|
||||
$this->_input = fopen($handle, 'r');
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a value from the stream
|
||||
*
|
||||
* @return mixed The value of the stream
|
||||
*/
|
||||
public function read() {
|
||||
if ($this->_canReadline) {
|
||||
$line = readline('');
|
||||
if (!empty($line)) {
|
||||
readline_add_history($line);
|
||||
}
|
||||
return $line;
|
||||
}
|
||||
return fgets($this->_input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if data is available on the stream
|
||||
*
|
||||
* @param int $timeout An optional time to wait for data
|
||||
* @return bool True for data available, false otherwise
|
||||
*/
|
||||
public function dataAvailable($timeout = 0) {
|
||||
$readFds = array($this->_input);
|
||||
$readyFds = stream_select($readFds, $writeFds, $errorFds, $timeout);
|
||||
return ($readyFds > 0);
|
||||
}
|
||||
|
||||
}
|
||||
170
lib/Cake/Console/ConsoleInputArgument.php
Normal file
170
lib/Cake/Console/ConsoleInputArgument.php
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
<?php
|
||||
/**
|
||||
* ConsoleArgumentOption file
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 2.0
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
/**
|
||||
* An object to represent a single argument used in the command line.
|
||||
* ConsoleOptionParser creates these when you use addArgument()
|
||||
*
|
||||
* @see ConsoleOptionParser::addArgument()
|
||||
* @package Cake.Console
|
||||
*/
|
||||
class ConsoleInputArgument {
|
||||
|
||||
/**
|
||||
* Name of the argument.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_name;
|
||||
|
||||
/**
|
||||
* Help string
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_help;
|
||||
|
||||
/**
|
||||
* Is this option required?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_required;
|
||||
|
||||
/**
|
||||
* An array of valid choices for this argument.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_choices;
|
||||
|
||||
/**
|
||||
* Make a new Input Argument
|
||||
*
|
||||
* @param string|array $name The long name of the option, or an array with all the properties.
|
||||
* @param string $help The help text for this option
|
||||
* @param bool $required Whether this argument is required. Missing required args will trigger exceptions
|
||||
* @param array $choices Valid choices for this option.
|
||||
*/
|
||||
public function __construct($name, $help = '', $required = false, $choices = array()) {
|
||||
if (is_array($name) && isset($name['name'])) {
|
||||
foreach ($name as $key => $value) {
|
||||
$this->{'_' . $key} = $value;
|
||||
}
|
||||
} else {
|
||||
$this->_name = $name;
|
||||
$this->_help = $help;
|
||||
$this->_required = $required;
|
||||
$this->_choices = $choices;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the name attribute.
|
||||
*
|
||||
* @return string Value of this->_name.
|
||||
*/
|
||||
public function name() {
|
||||
return $this->_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the help for this argument.
|
||||
*
|
||||
* @param int $width The width to make the name of the option.
|
||||
* @return string
|
||||
*/
|
||||
public function help($width = 0) {
|
||||
$name = $this->_name;
|
||||
if (strlen($name) < $width) {
|
||||
$name = str_pad($name, $width, ' ');
|
||||
}
|
||||
$optional = '';
|
||||
if (!$this->isRequired()) {
|
||||
$optional = __d('cake_console', ' <comment>(optional)</comment>');
|
||||
}
|
||||
if (!empty($this->_choices)) {
|
||||
$optional .= __d('cake_console', ' <comment>(choices: %s)</comment>', implode('|', $this->_choices));
|
||||
}
|
||||
return sprintf('%s%s%s', $name, $this->_help, $optional);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the usage value for this argument
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function usage() {
|
||||
$name = $this->_name;
|
||||
if (!empty($this->_choices)) {
|
||||
$name = implode('|', $this->_choices);
|
||||
}
|
||||
$name = '<' . $name . '>';
|
||||
if (!$this->isRequired()) {
|
||||
$name = '[' . $name . ']';
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this argument is a required argument
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isRequired() {
|
||||
return (bool)$this->_required;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that $value is a valid choice for this argument.
|
||||
*
|
||||
* @param string $value The choice to validate.
|
||||
* @return bool
|
||||
* @throws ConsoleException
|
||||
*/
|
||||
public function validChoice($value) {
|
||||
if (empty($this->_choices)) {
|
||||
return true;
|
||||
}
|
||||
if (!in_array($value, $this->_choices)) {
|
||||
throw new ConsoleException(
|
||||
__d('cake_console', '"%s" is not a valid value for %s. Please use one of "%s"',
|
||||
$value, $this->_name, implode(', ', $this->_choices)
|
||||
));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append this arguments XML representation to the passed in SimpleXml object.
|
||||
*
|
||||
* @param SimpleXmlElement $parent The parent element.
|
||||
* @return SimpleXmlElement The parent with this argument appended.
|
||||
*/
|
||||
public function xml(SimpleXmlElement $parent) {
|
||||
$option = $parent->addChild('argument');
|
||||
$option->addAttribute('name', $this->_name);
|
||||
$option->addAttribute('help', $this->_help);
|
||||
$option->addAttribute('required', $this->isRequired());
|
||||
$choices = $option->addChild('choices');
|
||||
foreach ($this->_choices as $valid) {
|
||||
$choices->addChild('choice', $valid);
|
||||
}
|
||||
return $parent;
|
||||
}
|
||||
|
||||
}
|
||||
220
lib/Cake/Console/ConsoleInputOption.php
Normal file
220
lib/Cake/Console/ConsoleInputOption.php
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
<?php
|
||||
/**
|
||||
* ConsoleInputOption file
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 2.0
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
/**
|
||||
* An object to represent a single option used in the command line.
|
||||
* ConsoleOptionParser creates these when you use addOption()
|
||||
*
|
||||
* @see ConsoleOptionParser::addOption()
|
||||
* @package Cake.Console
|
||||
*/
|
||||
class ConsoleInputOption {
|
||||
|
||||
/**
|
||||
* Name of the option
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_name;
|
||||
|
||||
/**
|
||||
* Short (1 character) alias for the option.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_short;
|
||||
|
||||
/**
|
||||
* Help text for the option.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_help;
|
||||
|
||||
/**
|
||||
* Is the option a boolean option. Boolean options do not consume a parameter.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_boolean;
|
||||
|
||||
/**
|
||||
* Default value for the option
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $_default;
|
||||
|
||||
/**
|
||||
* An array of choices for the option.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_choices;
|
||||
|
||||
/**
|
||||
* Make a new Input Option
|
||||
*
|
||||
* @param string|array $name The long name of the option, or an array with all the properties.
|
||||
* @param string $short The short alias for this option
|
||||
* @param string $help The help text for this option
|
||||
* @param bool $boolean Whether this option is a boolean option. Boolean options don't consume extra tokens
|
||||
* @param string $default The default value for this option.
|
||||
* @param array $choices Valid choices for this option.
|
||||
* @throws ConsoleException
|
||||
*/
|
||||
public function __construct($name, $short = null, $help = '', $boolean = false, $default = '', $choices = array()) {
|
||||
if (is_array($name) && isset($name['name'])) {
|
||||
foreach ($name as $key => $value) {
|
||||
$this->{'_' . $key} = $value;
|
||||
}
|
||||
} else {
|
||||
$this->_name = $name;
|
||||
$this->_short = $short;
|
||||
$this->_help = $help;
|
||||
$this->_boolean = $boolean;
|
||||
$this->_default = $default;
|
||||
$this->_choices = $choices;
|
||||
}
|
||||
if (strlen($this->_short) > 1) {
|
||||
throw new ConsoleException(
|
||||
__d('cake_console', 'Short option "%s" is invalid, short options must be one letter.', $this->_short)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the name attribute.
|
||||
*
|
||||
* @return string Value of this->_name.
|
||||
*/
|
||||
public function name() {
|
||||
return $this->_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the short attribute.
|
||||
*
|
||||
* @return string Value of this->_short.
|
||||
*/
|
||||
public function short() {
|
||||
return $this->_short;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the help for this this option.
|
||||
*
|
||||
* @param int $width The width to make the name of the option.
|
||||
* @return string
|
||||
*/
|
||||
public function help($width = 0) {
|
||||
$default = $short = '';
|
||||
if (!empty($this->_default) && $this->_default !== true) {
|
||||
$default = __d('cake_console', ' <comment>(default: %s)</comment>', $this->_default);
|
||||
}
|
||||
if (!empty($this->_choices)) {
|
||||
$default .= __d('cake_console', ' <comment>(choices: %s)</comment>', implode('|', $this->_choices));
|
||||
}
|
||||
if (!empty($this->_short)) {
|
||||
$short = ', -' . $this->_short;
|
||||
}
|
||||
$name = sprintf('--%s%s', $this->_name, $short);
|
||||
if (strlen($name) < $width) {
|
||||
$name = str_pad($name, $width, ' ');
|
||||
}
|
||||
return sprintf('%s%s%s', $name, $this->_help, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the usage value for this option
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function usage() {
|
||||
$name = empty($this->_short) ? '--' . $this->_name : '-' . $this->_short;
|
||||
$default = '';
|
||||
if (!empty($this->_default) && $this->_default !== true) {
|
||||
$default = ' ' . $this->_default;
|
||||
}
|
||||
if (!empty($this->_choices)) {
|
||||
$default = ' ' . implode('|', $this->_choices);
|
||||
}
|
||||
return sprintf('[%s%s]', $name, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default value for this option
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function defaultValue() {
|
||||
return $this->_default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this option is a boolean option
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isBoolean() {
|
||||
return (bool)$this->_boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that a value is a valid choice for this option.
|
||||
*
|
||||
* @param string $value The choice to validate.
|
||||
* @return bool
|
||||
* @throws ConsoleException
|
||||
*/
|
||||
public function validChoice($value) {
|
||||
if (empty($this->_choices)) {
|
||||
return true;
|
||||
}
|
||||
if (!in_array($value, $this->_choices)) {
|
||||
throw new ConsoleException(
|
||||
__d('cake_console', '"%s" is not a valid value for --%s. Please use one of "%s"',
|
||||
$value, $this->_name, implode(', ', $this->_choices)
|
||||
));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the option's xml into the parent.
|
||||
*
|
||||
* @param SimpleXmlElement $parent The parent element.
|
||||
* @return SimpleXmlElement The parent with this option appended.
|
||||
*/
|
||||
public function xml(SimpleXmlElement $parent) {
|
||||
$option = $parent->addChild('option');
|
||||
$option->addAttribute('name', '--' . $this->_name);
|
||||
$short = '';
|
||||
if (strlen($this->_short)) {
|
||||
$short = $this->_short;
|
||||
}
|
||||
$option->addAttribute('short', '-' . $short);
|
||||
$option->addAttribute('boolean', $this->_boolean);
|
||||
$option->addChild('default', $this->_default);
|
||||
$choices = $option->addChild('choices');
|
||||
foreach ($this->_choices as $valid) {
|
||||
$choices->addChild('choice', $valid);
|
||||
}
|
||||
return $parent;
|
||||
}
|
||||
|
||||
}
|
||||
120
lib/Cake/Console/ConsoleInputSubcommand.php
Normal file
120
lib/Cake/Console/ConsoleInputSubcommand.php
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
/**
|
||||
* ConsoleInputSubcommand file
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 2.0
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
/**
|
||||
* An object to represent a single subcommand used in the command line.
|
||||
* Created when you call ConsoleOptionParser::addSubcommand()
|
||||
*
|
||||
* @see ConsoleOptionParser::addSubcommand()
|
||||
* @package Cake.Console
|
||||
*/
|
||||
class ConsoleInputSubcommand {
|
||||
|
||||
/**
|
||||
* Name of the subcommand
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_name;
|
||||
|
||||
/**
|
||||
* Help string for the subcommand
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_help;
|
||||
|
||||
/**
|
||||
* The ConsoleOptionParser for this subcommand.
|
||||
*
|
||||
* @var ConsoleOptionParser
|
||||
*/
|
||||
protected $_parser;
|
||||
|
||||
/**
|
||||
* Make a new Subcommand
|
||||
*
|
||||
* @param string|array $name The long name of the subcommand, or an array with all the properties.
|
||||
* @param string $help The help text for this option
|
||||
* @param ConsoleOptionParser|array $parser A parser for this subcommand. Either a ConsoleOptionParser, or an array that can be
|
||||
* used with ConsoleOptionParser::buildFromArray()
|
||||
*/
|
||||
public function __construct($name, $help = '', $parser = null) {
|
||||
if (is_array($name) && isset($name['name'])) {
|
||||
foreach ($name as $key => $value) {
|
||||
$this->{'_' . $key} = $value;
|
||||
}
|
||||
} else {
|
||||
$this->_name = $name;
|
||||
$this->_help = $help;
|
||||
$this->_parser = $parser;
|
||||
}
|
||||
if (is_array($this->_parser)) {
|
||||
$this->_parser['command'] = $this->_name;
|
||||
$this->_parser = ConsoleOptionParser::buildFromArray($this->_parser);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the name attribute.
|
||||
*
|
||||
* @return string Value of this->_name.
|
||||
*/
|
||||
public function name() {
|
||||
return $this->_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the help for this this subcommand.
|
||||
*
|
||||
* @param int $width The width to make the name of the subcommand.
|
||||
* @return string
|
||||
*/
|
||||
public function help($width = 0) {
|
||||
$name = $this->_name;
|
||||
if (strlen($name) < $width) {
|
||||
$name = str_pad($name, $width, ' ');
|
||||
}
|
||||
return $name . $this->_help;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the usage value for this option
|
||||
*
|
||||
* @return mixed Either false or a ConsoleOptionParser
|
||||
*/
|
||||
public function parser() {
|
||||
if ($this->_parser instanceof ConsoleOptionParser) {
|
||||
return $this->_parser;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append this subcommand to the Parent element
|
||||
*
|
||||
* @param SimpleXmlElement $parent The parent element.
|
||||
* @return SimpleXmlElement The parent with this subcommand appended.
|
||||
*/
|
||||
public function xml(SimpleXmlElement $parent) {
|
||||
$command = $parent->addChild('command');
|
||||
$command->addAttribute('name', $this->_name);
|
||||
$command->addAttribute('help', $this->_help);
|
||||
return $parent;
|
||||
}
|
||||
|
||||
}
|
||||
653
lib/Cake/Console/ConsoleOptionParser.php
Normal file
653
lib/Cake/Console/ConsoleOptionParser.php
Normal file
|
|
@ -0,0 +1,653 @@
|
|||
<?php
|
||||
/**
|
||||
* ConsoleOptionParser file
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 2.0
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('TaskCollection', 'Console');
|
||||
App::uses('ConsoleOutput', 'Console');
|
||||
App::uses('ConsoleInput', 'Console');
|
||||
App::uses('ConsoleInputSubcommand', 'Console');
|
||||
App::uses('ConsoleInputOption', 'Console');
|
||||
App::uses('ConsoleInputArgument', 'Console');
|
||||
App::uses('ConsoleOptionParser', 'Console');
|
||||
App::uses('HelpFormatter', 'Console');
|
||||
|
||||
/**
|
||||
* Handles parsing the ARGV in the command line and provides support
|
||||
* for GetOpt compatible option definition. Provides a builder pattern implementation
|
||||
* for creating shell option parsers.
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* Named arguments come in two forms, long and short. Long arguments are preceded
|
||||
* by two - and give a more verbose option name. i.e. `--version`. Short arguments are
|
||||
* preceded by one - and are only one character long. They usually match with a long option,
|
||||
* and provide a more terse alternative.
|
||||
*
|
||||
* ### Using Options
|
||||
*
|
||||
* Options can be defined with both long and short forms. By using `$parser->addOption()`
|
||||
* you can define new options. The name of the option is used as its long form, and you
|
||||
* can supply an additional short form, with the `short` option. Short options should
|
||||
* only be one letter long. Using more than one letter for a short option will raise an exception.
|
||||
*
|
||||
* Calling options can be done using syntax similar to most *nix command line tools. Long options
|
||||
* cane either include an `=` or leave it out.
|
||||
*
|
||||
* `cake myshell command --connection default --name=something`
|
||||
*
|
||||
* Short options can be defined signally or in groups.
|
||||
*
|
||||
* `cake myshell command -cn`
|
||||
*
|
||||
* Short options can be combined into groups as seen above. Each letter in a group
|
||||
* will be treated as a separate option. The previous example is equivalent to:
|
||||
*
|
||||
* `cake myshell command -c -n`
|
||||
*
|
||||
* Short options can also accept values:
|
||||
*
|
||||
* `cake myshell command -c default`
|
||||
*
|
||||
* ### Positional arguments
|
||||
*
|
||||
* If no positional arguments are defined, all of them will be parsed. If you define positional
|
||||
* arguments any arguments greater than those defined will cause exceptions. Additionally you can
|
||||
* declare arguments as optional, by setting the required param to false.
|
||||
*
|
||||
* `$parser->addArgument('model', array('required' => false));`
|
||||
*
|
||||
* ### Providing Help text
|
||||
*
|
||||
* By providing help text for your positional arguments and named arguments, the ConsoleOptionParser
|
||||
* can generate a help display for you. You can view the help for shells by using the `--help` or `-h` switch.
|
||||
*
|
||||
* @package Cake.Console
|
||||
*/
|
||||
class ConsoleOptionParser {
|
||||
|
||||
/**
|
||||
* Description text - displays before options when help is generated
|
||||
*
|
||||
* @see ConsoleOptionParser::description()
|
||||
* @var string
|
||||
*/
|
||||
protected $_description = null;
|
||||
|
||||
/**
|
||||
* Epilog text - displays after options when help is generated
|
||||
*
|
||||
* @see ConsoleOptionParser::epilog()
|
||||
* @var string
|
||||
*/
|
||||
protected $_epilog = null;
|
||||
|
||||
/**
|
||||
* Option definitions.
|
||||
*
|
||||
* @see ConsoleOptionParser::addOption()
|
||||
* @var array
|
||||
*/
|
||||
protected $_options = array();
|
||||
|
||||
/**
|
||||
* Map of short -> long options, generated when using addOption()
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_shortOptions = array();
|
||||
|
||||
/**
|
||||
* Positional argument definitions.
|
||||
*
|
||||
* @see ConsoleOptionParser::addArgument()
|
||||
* @var array
|
||||
*/
|
||||
protected $_args = array();
|
||||
|
||||
/**
|
||||
* Subcommands for this Shell.
|
||||
*
|
||||
* @see ConsoleOptionParser::addSubcommand()
|
||||
* @var array
|
||||
*/
|
||||
protected $_subcommands = array();
|
||||
|
||||
/**
|
||||
* Command name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_command = '';
|
||||
|
||||
/**
|
||||
* Construct an OptionParser so you can define its behavior
|
||||
*
|
||||
* @param string $command The command name this parser is for. The command name is used for generating help.
|
||||
* @param bool $defaultOptions Whether you want the verbose and quiet options set. Setting
|
||||
* this to false will prevent the addition of `--verbose` & `--quiet` options.
|
||||
*/
|
||||
public function __construct($command = null, $defaultOptions = true) {
|
||||
$this->command($command);
|
||||
|
||||
$this->addOption('help', array(
|
||||
'short' => 'h',
|
||||
'help' => __d('cake_console', 'Display this help.'),
|
||||
'boolean' => true
|
||||
));
|
||||
|
||||
if ($defaultOptions) {
|
||||
$this->addOption('verbose', array(
|
||||
'short' => 'v',
|
||||
'help' => __d('cake_console', 'Enable verbose output.'),
|
||||
'boolean' => true
|
||||
))->addOption('quiet', array(
|
||||
'short' => 'q',
|
||||
'help' => __d('cake_console', 'Enable quiet output.'),
|
||||
'boolean' => true
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Static factory method for creating new OptionParsers so you can chain methods off of them.
|
||||
*
|
||||
* @param string $command The command name this parser is for. The command name is used for generating help.
|
||||
* @param bool $defaultOptions Whether you want the verbose and quiet options set.
|
||||
* @return ConsoleOptionParser
|
||||
*/
|
||||
public static function create($command, $defaultOptions = true) {
|
||||
return new ConsoleOptionParser($command, $defaultOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a parser from an array. Uses an array like
|
||||
*
|
||||
* {{{
|
||||
* $spec = array(
|
||||
* 'description' => 'text',
|
||||
* 'epilog' => 'text',
|
||||
* 'arguments' => array(
|
||||
* // list of arguments compatible with addArguments.
|
||||
* ),
|
||||
* 'options' => array(
|
||||
* // list of options compatible with addOptions
|
||||
* ),
|
||||
* 'subcommands' => array(
|
||||
* // list of subcommands to add.
|
||||
* )
|
||||
* );
|
||||
* }}}
|
||||
*
|
||||
* @param array $spec The spec to build the OptionParser with.
|
||||
* @return ConsoleOptionParser
|
||||
*/
|
||||
public static function buildFromArray($spec) {
|
||||
$parser = new ConsoleOptionParser($spec['command']);
|
||||
if (!empty($spec['arguments'])) {
|
||||
$parser->addArguments($spec['arguments']);
|
||||
}
|
||||
if (!empty($spec['options'])) {
|
||||
$parser->addOptions($spec['options']);
|
||||
}
|
||||
if (!empty($spec['subcommands'])) {
|
||||
$parser->addSubcommands($spec['subcommands']);
|
||||
}
|
||||
if (!empty($spec['description'])) {
|
||||
$parser->description($spec['description']);
|
||||
}
|
||||
if (!empty($spec['epilog'])) {
|
||||
$parser->epilog($spec['epilog']);
|
||||
}
|
||||
return $parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set the command name for shell/task.
|
||||
*
|
||||
* @param string $text The text to set, or null if you want to read
|
||||
* @return string|$this If reading, the value of the command. If setting $this will be returned.
|
||||
*/
|
||||
public function command($text = null) {
|
||||
if ($text !== null) {
|
||||
$this->_command = Inflector::underscore($text);
|
||||
return $this;
|
||||
}
|
||||
return $this->_command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set the description text for shell/task.
|
||||
*
|
||||
* @param string|array $text The text to set, or null if you want to read. If an array the
|
||||
* text will be imploded with "\n"
|
||||
* @return string|$this If reading, the value of the description. If setting $this will be returned.
|
||||
*/
|
||||
public function description($text = null) {
|
||||
if ($text !== null) {
|
||||
if (is_array($text)) {
|
||||
$text = implode("\n", $text);
|
||||
}
|
||||
$this->_description = $text;
|
||||
return $this;
|
||||
}
|
||||
return $this->_description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set an epilog to the parser. The epilog is added to the end of
|
||||
* the options and arguments listing when help is generated.
|
||||
*
|
||||
* @param string|array $text Text when setting or null when reading. If an array the text will be imploded with "\n"
|
||||
* @return string|$this If reading, the value of the epilog. If setting $this will be returned.
|
||||
*/
|
||||
public function epilog($text = null) {
|
||||
if ($text !== null) {
|
||||
if (is_array($text)) {
|
||||
$text = implode("\n", $text);
|
||||
}
|
||||
$this->_epilog = $text;
|
||||
return $this;
|
||||
}
|
||||
return $this->_epilog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an option to the option parser. Options allow you to define optional or required
|
||||
* parameters for your console application. Options are defined by the parameters they use.
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - `short` - The single letter variant for this option, leave undefined for none.
|
||||
* - `help` - Help text for this option. Used when generating help for the option.
|
||||
* - `default` - The default value for this option. Defaults are added into the parsed params when the
|
||||
* attached option is not provided or has no value. Using default and boolean together will not work.
|
||||
* are added into the parsed parameters when the option is undefined. Defaults to null.
|
||||
* - `boolean` - The option uses no value, its just a boolean switch. Defaults to false.
|
||||
* If an option is defined as boolean, it will always be added to the parsed params. If no present
|
||||
* it will be false, if present it will be true.
|
||||
* - `choices` A list of valid choices for this option. If left empty all values are valid..
|
||||
* An exception will be raised when parse() encounters an invalid value.
|
||||
*
|
||||
* @param ConsoleInputOption|string $name The long name you want to the value to be parsed out as when options are parsed.
|
||||
* Will also accept an instance of ConsoleInputOption
|
||||
* @param array $options An array of parameters that define the behavior of the option
|
||||
* @return $this
|
||||
*/
|
||||
public function addOption($name, $options = array()) {
|
||||
if (is_object($name) && $name instanceof ConsoleInputOption) {
|
||||
$option = $name;
|
||||
$name = $option->name();
|
||||
} else {
|
||||
$defaults = array(
|
||||
'name' => $name,
|
||||
'short' => null,
|
||||
'help' => '',
|
||||
'default' => null,
|
||||
'boolean' => false,
|
||||
'choices' => array()
|
||||
);
|
||||
$options += $defaults;
|
||||
$option = new ConsoleInputOption($options);
|
||||
}
|
||||
$this->_options[$name] = $option;
|
||||
if ($option->short() !== null) {
|
||||
$this->_shortOptions[$option->short()] = $name;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a positional argument to the option parser.
|
||||
*
|
||||
* ### Params
|
||||
*
|
||||
* - `help` The help text to display for this argument.
|
||||
* - `required` Whether this parameter is required.
|
||||
* - `index` The index for the arg, if left undefined the argument will be put
|
||||
* onto the end of the arguments. If you define the same index twice the first
|
||||
* option will be overwritten.
|
||||
* - `choices` A list of valid choices for this argument. If left empty all values are valid..
|
||||
* An exception will be raised when parse() encounters an invalid value.
|
||||
*
|
||||
* @param ConsoleInputArgument|string $name The name of the argument. Will also accept an instance of ConsoleInputArgument
|
||||
* @param array $params Parameters for the argument, see above.
|
||||
* @return $this
|
||||
*/
|
||||
public function addArgument($name, $params = array()) {
|
||||
if (is_object($name) && $name instanceof ConsoleInputArgument) {
|
||||
$arg = $name;
|
||||
$index = count($this->_args);
|
||||
} else {
|
||||
$defaults = array(
|
||||
'name' => $name,
|
||||
'help' => '',
|
||||
'index' => count($this->_args),
|
||||
'required' => false,
|
||||
'choices' => array()
|
||||
);
|
||||
$options = $params + $defaults;
|
||||
$index = $options['index'];
|
||||
unset($options['index']);
|
||||
$arg = new ConsoleInputArgument($options);
|
||||
}
|
||||
$this->_args[$index] = $arg;
|
||||
ksort($this->_args);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add multiple arguments at once. Take an array of argument definitions.
|
||||
* The keys are used as the argument names, and the values as params for the argument.
|
||||
*
|
||||
* @param array $args Array of arguments to add.
|
||||
* @see ConsoleOptionParser::addArgument()
|
||||
* @return $this
|
||||
*/
|
||||
public function addArguments(array $args) {
|
||||
foreach ($args as $name => $params) {
|
||||
$this->addArgument($name, $params);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add multiple options at once. Takes an array of option definitions.
|
||||
* The keys are used as option names, and the values as params for the option.
|
||||
*
|
||||
* @param array $options Array of options to add.
|
||||
* @see ConsoleOptionParser::addOption()
|
||||
* @return $this
|
||||
*/
|
||||
public function addOptions(array $options) {
|
||||
foreach ($options as $name => $params) {
|
||||
$this->addOption($name, $params);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a subcommand to the subcommand list.
|
||||
* Subcommands are usually methods on your Shell, but can also be used to document Tasks.
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - `help` - Help text for the subcommand.
|
||||
* - `parser` - A ConsoleOptionParser for the subcommand. This allows you to create method
|
||||
* specific option parsers. When help is generated for a subcommand, if a parser is present
|
||||
* it will be used.
|
||||
*
|
||||
* @param ConsoleInputSubcommand|string $name Name of the subcommand. Will also accept an instance of ConsoleInputSubcommand
|
||||
* @param array $options Array of params, see above.
|
||||
* @return $this
|
||||
*/
|
||||
public function addSubcommand($name, $options = array()) {
|
||||
if (is_object($name) && $name instanceof ConsoleInputSubcommand) {
|
||||
$command = $name;
|
||||
$name = $command->name();
|
||||
} else {
|
||||
$defaults = array(
|
||||
'name' => $name,
|
||||
'help' => '',
|
||||
'parser' => null
|
||||
);
|
||||
$options += $defaults;
|
||||
$command = new ConsoleInputSubcommand($options);
|
||||
}
|
||||
$this->_subcommands[$name] = $command;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add multiple subcommands at once.
|
||||
*
|
||||
* @param array $commands Array of subcommands.
|
||||
* @return $this
|
||||
*/
|
||||
public function addSubcommands(array $commands) {
|
||||
foreach ($commands as $name => $params) {
|
||||
$this->addSubcommand($name, $params);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the arguments defined in the parser.
|
||||
*
|
||||
* @return array Array of argument descriptions
|
||||
*/
|
||||
public function arguments() {
|
||||
return $this->_args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the defined options in the parser.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function options() {
|
||||
return $this->_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array of defined subcommands
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function subcommands() {
|
||||
return $this->_subcommands;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the argv array into a set of params and args. If $command is not null
|
||||
* and $command is equal to a subcommand that has a parser, that parser will be used
|
||||
* to parse the $argv
|
||||
*
|
||||
* @param array $argv Array of args (argv) to parse.
|
||||
* @param string $command The subcommand to use. If this parameter is a subcommand, that has a parser,
|
||||
* That parser will be used to parse $argv instead.
|
||||
* @return Array array($params, $args)
|
||||
* @throws ConsoleException When an invalid parameter is encountered.
|
||||
*/
|
||||
public function parse($argv, $command = null) {
|
||||
if (isset($this->_subcommands[$command]) && $this->_subcommands[$command]->parser()) {
|
||||
return $this->_subcommands[$command]->parser()->parse($argv);
|
||||
}
|
||||
$params = $args = array();
|
||||
$this->_tokens = $argv;
|
||||
while (($token = array_shift($this->_tokens)) !== null) {
|
||||
if (substr($token, 0, 2) === '--') {
|
||||
$params = $this->_parseLongOption($token, $params);
|
||||
} elseif (substr($token, 0, 1) === '-') {
|
||||
$params = $this->_parseShortOption($token, $params);
|
||||
} else {
|
||||
$args = $this->_parseArg($token, $args);
|
||||
}
|
||||
}
|
||||
foreach ($this->_args as $i => $arg) {
|
||||
if ($arg->isRequired() && !isset($args[$i]) && empty($params['help'])) {
|
||||
throw new ConsoleException(
|
||||
__d('cake_console', 'Missing required arguments. %s is required.', $arg->name())
|
||||
);
|
||||
}
|
||||
}
|
||||
foreach ($this->_options as $option) {
|
||||
$name = $option->name();
|
||||
$isBoolean = $option->isBoolean();
|
||||
$default = $option->defaultValue();
|
||||
|
||||
if ($default !== null && !isset($params[$name]) && !$isBoolean) {
|
||||
$params[$name] = $default;
|
||||
}
|
||||
if ($isBoolean && !isset($params[$name])) {
|
||||
$params[$name] = false;
|
||||
}
|
||||
}
|
||||
return array($params, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets formatted help for this parser object.
|
||||
* Generates help text based on the description, options, arguments, subcommands and epilog
|
||||
* in the parser.
|
||||
*
|
||||
* @param string $subcommand If present and a valid subcommand that has a linked parser.
|
||||
* That subcommands help will be shown instead.
|
||||
* @param string $format Define the output format, can be text or xml
|
||||
* @param int $width The width to format user content to. Defaults to 72
|
||||
* @return string Generated help.
|
||||
*/
|
||||
public function help($subcommand = null, $format = 'text', $width = 72) {
|
||||
if (
|
||||
isset($this->_subcommands[$subcommand]) &&
|
||||
$this->_subcommands[$subcommand]->parser() instanceof self
|
||||
) {
|
||||
$subparser = $this->_subcommands[$subcommand]->parser();
|
||||
$subparser->command($this->command() . ' ' . $subparser->command());
|
||||
return $subparser->help(null, $format, $width);
|
||||
}
|
||||
$formatter = new HelpFormatter($this);
|
||||
if ($format === 'text' || $format === true) {
|
||||
return $formatter->text($width);
|
||||
} elseif ($format === 'xml') {
|
||||
return $formatter->xml();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the value for a long option out of $this->_tokens. Will handle
|
||||
* options with an `=` in them.
|
||||
*
|
||||
* @param string $option The option to parse.
|
||||
* @param array $params The params to append the parsed value into
|
||||
* @return array Params with $option added in.
|
||||
*/
|
||||
protected function _parseLongOption($option, $params) {
|
||||
$name = substr($option, 2);
|
||||
if (strpos($name, '=') !== false) {
|
||||
list($name, $value) = explode('=', $name, 2);
|
||||
array_unshift($this->_tokens, $value);
|
||||
}
|
||||
return $this->_parseOption($name, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the value for a short option out of $this->_tokens
|
||||
* If the $option is a combination of multiple shortcuts like -otf
|
||||
* they will be shifted onto the token stack and parsed individually.
|
||||
*
|
||||
* @param string $option The option to parse.
|
||||
* @param array $params The params to append the parsed value into
|
||||
* @return array Params with $option added in.
|
||||
* @throws ConsoleException When unknown short options are encountered.
|
||||
*/
|
||||
protected function _parseShortOption($option, $params) {
|
||||
$key = substr($option, 1);
|
||||
if (strlen($key) > 1) {
|
||||
$flags = str_split($key);
|
||||
$key = $flags[0];
|
||||
for ($i = 1, $len = count($flags); $i < $len; $i++) {
|
||||
array_unshift($this->_tokens, '-' . $flags[$i]);
|
||||
}
|
||||
}
|
||||
if (!isset($this->_shortOptions[$key])) {
|
||||
throw new ConsoleException(__d('cake_console', 'Unknown short option `%s`', $key));
|
||||
}
|
||||
$name = $this->_shortOptions[$key];
|
||||
return $this->_parseOption($name, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an option by its name index.
|
||||
*
|
||||
* @param string $name The name to parse.
|
||||
* @param array $params The params to append the parsed value into
|
||||
* @return array Params with $option added in.
|
||||
* @throws ConsoleException
|
||||
*/
|
||||
protected function _parseOption($name, $params) {
|
||||
if (!isset($this->_options[$name])) {
|
||||
throw new ConsoleException(__d('cake_console', 'Unknown option `%s`', $name));
|
||||
}
|
||||
$option = $this->_options[$name];
|
||||
$isBoolean = $option->isBoolean();
|
||||
$nextValue = $this->_nextToken();
|
||||
$emptyNextValue = (empty($nextValue) && $nextValue !== '0');
|
||||
if (!$isBoolean && !$emptyNextValue && !$this->_optionExists($nextValue)) {
|
||||
array_shift($this->_tokens);
|
||||
$value = $nextValue;
|
||||
} elseif ($isBoolean) {
|
||||
$value = true;
|
||||
} else {
|
||||
$value = $option->defaultValue();
|
||||
}
|
||||
if ($option->validChoice($value)) {
|
||||
$params[$name] = $value;
|
||||
return $params;
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if $name has an option (short/long) defined for it.
|
||||
*
|
||||
* @param string $name The name of the option.
|
||||
* @return bool
|
||||
*/
|
||||
protected function _optionExists($name) {
|
||||
if (substr($name, 0, 2) === '--') {
|
||||
return isset($this->_options[substr($name, 2)]);
|
||||
}
|
||||
if ($name{0} === '-' && $name{1} !== '-') {
|
||||
return isset($this->_shortOptions[$name{1}]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an argument, and ensure that the argument doesn't exceed the number of arguments
|
||||
* and that the argument is a valid choice.
|
||||
*
|
||||
* @param string $argument The argument to append
|
||||
* @param array $args The array of parsed args to append to.
|
||||
* @return array Args
|
||||
* @throws ConsoleException
|
||||
*/
|
||||
protected function _parseArg($argument, $args) {
|
||||
if (empty($this->_args)) {
|
||||
$args[] = $argument;
|
||||
return $args;
|
||||
}
|
||||
$next = count($args);
|
||||
if (!isset($this->_args[$next])) {
|
||||
throw new ConsoleException(__d('cake_console', 'Too many arguments.'));
|
||||
}
|
||||
|
||||
if ($this->_args[$next]->validChoice($argument)) {
|
||||
$args[] = $argument;
|
||||
return $args;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the next token in the argv set.
|
||||
*
|
||||
* @return string next token or ''
|
||||
*/
|
||||
protected function _nextToken() {
|
||||
return isset($this->_tokens[0]) ? $this->_tokens[0] : '';
|
||||
}
|
||||
|
||||
}
|
||||
303
lib/Cake/Console/ConsoleOutput.php
Normal file
303
lib/Cake/Console/ConsoleOutput.php
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
<?php
|
||||
/**
|
||||
* ConsoleOutput file.
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 2.0
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Object wrapper for outputting information from a shell application.
|
||||
* Can be connected to any stream resource that can be used with fopen()
|
||||
*
|
||||
* Can generate colorized output on consoles that support it. There are a few
|
||||
* built in styles
|
||||
*
|
||||
* - `error` Error messages.
|
||||
* - `warning` Warning messages.
|
||||
* - `info` Informational messages.
|
||||
* - `comment` Additional text.
|
||||
* - `question` Magenta text used for user prompts
|
||||
*
|
||||
* By defining styles with addStyle() you can create custom console styles.
|
||||
*
|
||||
* ### Using styles in output
|
||||
*
|
||||
* You can format console output using tags with the name of the style to apply. From inside a shell object
|
||||
*
|
||||
* `$this->out('<warning>Overwrite:</warning> foo.php was overwritten.');`
|
||||
*
|
||||
* This would create orange 'Overwrite:' text, while the rest of the text would remain the normal color.
|
||||
* See ConsoleOutput::styles() to learn more about defining your own styles. Nested styles are not supported
|
||||
* at this time.
|
||||
*
|
||||
* @package Cake.Console
|
||||
*/
|
||||
class ConsoleOutput {
|
||||
|
||||
/**
|
||||
* Raw output constant - no modification of output text.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const RAW = 0;
|
||||
|
||||
/**
|
||||
* Plain output - tags will be stripped.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const PLAIN = 1;
|
||||
|
||||
/**
|
||||
* Color output - Convert known tags in to ANSI color escape codes.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const COLOR = 2;
|
||||
|
||||
/**
|
||||
* Constant for a newline.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const LF = PHP_EOL;
|
||||
|
||||
/**
|
||||
* File handle for output.
|
||||
*
|
||||
* @var resource
|
||||
*/
|
||||
protected $_output;
|
||||
|
||||
/**
|
||||
* The current output type. Manipulated with ConsoleOutput::outputAs();
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $_outputAs = self::COLOR;
|
||||
|
||||
/**
|
||||
* text colors used in colored output.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $_foregroundColors = array(
|
||||
'black' => 30,
|
||||
'red' => 31,
|
||||
'green' => 32,
|
||||
'yellow' => 33,
|
||||
'blue' => 34,
|
||||
'magenta' => 35,
|
||||
'cyan' => 36,
|
||||
'white' => 37
|
||||
);
|
||||
|
||||
/**
|
||||
* background colors used in colored output.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $_backgroundColors = array(
|
||||
'black' => 40,
|
||||
'red' => 41,
|
||||
'green' => 42,
|
||||
'yellow' => 43,
|
||||
'blue' => 44,
|
||||
'magenta' => 45,
|
||||
'cyan' => 46,
|
||||
'white' => 47
|
||||
);
|
||||
|
||||
/**
|
||||
* formatting options for colored output
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $_options = array(
|
||||
'bold' => 1,
|
||||
'underline' => 4,
|
||||
'blink' => 5,
|
||||
'reverse' => 7,
|
||||
);
|
||||
|
||||
/**
|
||||
* Styles that are available as tags in console output.
|
||||
* You can modify these styles with ConsoleOutput::styles()
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $_styles = array(
|
||||
'emergency' => array('text' => 'red', 'underline' => true),
|
||||
'alert' => array('text' => 'red', 'underline' => true),
|
||||
'critical' => array('text' => 'red', 'underline' => true),
|
||||
'error' => array('text' => 'red', 'underline' => true),
|
||||
'warning' => array('text' => 'yellow'),
|
||||
'info' => array('text' => 'cyan'),
|
||||
'debug' => array('text' => 'yellow'),
|
||||
'success' => array('text' => 'green'),
|
||||
'comment' => array('text' => 'blue'),
|
||||
'question' => array('text' => 'magenta'),
|
||||
'notice' => array('text' => 'cyan')
|
||||
);
|
||||
|
||||
/**
|
||||
* Construct the output object.
|
||||
*
|
||||
* Checks for a pretty console environment. Ansicon allows pretty consoles
|
||||
* on windows, and is supported.
|
||||
*
|
||||
* @param string $stream The identifier of the stream to write output to.
|
||||
*/
|
||||
public function __construct($stream = 'php://stdout') {
|
||||
$this->_output = fopen($stream, 'w');
|
||||
|
||||
if (DS === '\\' && !(bool)env('ANSICON')) {
|
||||
$this->_outputAs = self::PLAIN;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a single or multiple messages to stdout. If no parameters
|
||||
* are passed, outputs just a newline.
|
||||
*
|
||||
* @param string|array $message A string or a an array of strings to output
|
||||
* @param int $newlines Number of newlines to append
|
||||
* @return int Returns the number of bytes returned from writing to stdout.
|
||||
*/
|
||||
public function write($message, $newlines = 1) {
|
||||
if (is_array($message)) {
|
||||
$message = implode(self::LF, $message);
|
||||
}
|
||||
return $this->_write($this->styleText($message . str_repeat(self::LF, $newlines)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply styling to text.
|
||||
*
|
||||
* @param string $text Text with styling tags.
|
||||
* @return string String with color codes added.
|
||||
*/
|
||||
public function styleText($text) {
|
||||
if ($this->_outputAs == self::RAW) {
|
||||
return $text;
|
||||
}
|
||||
if ($this->_outputAs == self::PLAIN) {
|
||||
$tags = implode('|', array_keys(self::$_styles));
|
||||
return preg_replace('#</?(?:' . $tags . ')>#', '', $text);
|
||||
}
|
||||
return preg_replace_callback(
|
||||
'/<(?P<tag>[a-z0-9-_]+)>(?P<text>.*?)<\/(\1)>/ims', array($this, '_replaceTags'), $text
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace tags with color codes.
|
||||
*
|
||||
* @param array $matches An array of matches to replace.
|
||||
* @return string
|
||||
*/
|
||||
protected function _replaceTags($matches) {
|
||||
$style = $this->styles($matches['tag']);
|
||||
if (empty($style)) {
|
||||
return '<' . $matches['tag'] . '>' . $matches['text'] . '</' . $matches['tag'] . '>';
|
||||
}
|
||||
|
||||
$styleInfo = array();
|
||||
if (!empty($style['text']) && isset(self::$_foregroundColors[$style['text']])) {
|
||||
$styleInfo[] = self::$_foregroundColors[$style['text']];
|
||||
}
|
||||
if (!empty($style['background']) && isset(self::$_backgroundColors[$style['background']])) {
|
||||
$styleInfo[] = self::$_backgroundColors[$style['background']];
|
||||
}
|
||||
unset($style['text'], $style['background']);
|
||||
foreach ($style as $option => $value) {
|
||||
if ($value) {
|
||||
$styleInfo[] = self::$_options[$option];
|
||||
}
|
||||
}
|
||||
return "\033[" . implode($styleInfo, ';') . 'm' . $matches['text'] . "\033[0m";
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a message to the output stream.
|
||||
*
|
||||
* @param string $message Message to write.
|
||||
* @return bool success
|
||||
*/
|
||||
protected function _write($message) {
|
||||
return fwrite($this->_output, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current styles offered, or append new ones in.
|
||||
*
|
||||
* ### Get a style definition
|
||||
*
|
||||
* `$this->output->styles('error');`
|
||||
*
|
||||
* ### Get all the style definitions
|
||||
*
|
||||
* `$this->output->styles();`
|
||||
*
|
||||
* ### Create or modify an existing style
|
||||
*
|
||||
* `$this->output->styles('annoy', array('text' => 'purple', 'background' => 'yellow', 'blink' => true));`
|
||||
*
|
||||
* ### Remove a style
|
||||
*
|
||||
* `$this->output->styles('annoy', false);`
|
||||
*
|
||||
* @param string $style The style to get or create.
|
||||
* @param array $definition The array definition of the style to change or create a style
|
||||
* or false to remove a style.
|
||||
* @return mixed If you are getting styles, the style or null will be returned. If you are creating/modifying
|
||||
* styles true will be returned.
|
||||
*/
|
||||
public function styles($style = null, $definition = null) {
|
||||
if ($style === null && $definition === null) {
|
||||
return self::$_styles;
|
||||
}
|
||||
if (is_string($style) && $definition === null) {
|
||||
return isset(self::$_styles[$style]) ? self::$_styles[$style] : null;
|
||||
}
|
||||
if ($definition === false) {
|
||||
unset(self::$_styles[$style]);
|
||||
return true;
|
||||
}
|
||||
self::$_styles[$style] = $definition;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get/Set the output type to use. The output type how formatting tags are treated.
|
||||
*
|
||||
* @param int $type The output type to use. Should be one of the class constants.
|
||||
* @return mixed Either null or the value if getting.
|
||||
*/
|
||||
public function outputAs($type = null) {
|
||||
if ($type === null) {
|
||||
return $this->_outputAs;
|
||||
}
|
||||
$this->_outputAs = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up and close handles
|
||||
*/
|
||||
public function __destruct() {
|
||||
if (is_resource($this->_output)) {
|
||||
fclose($this->_output);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
201
lib/Cake/Console/HelpFormatter.php
Normal file
201
lib/Cake/Console/HelpFormatter.php
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
<?php
|
||||
/**
|
||||
* HelpFormatter
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('String', 'Utility');
|
||||
|
||||
/**
|
||||
* HelpFormatter formats help for console shells. Can format to either
|
||||
* text or XML formats. Uses ConsoleOptionParser methods to generate help.
|
||||
*
|
||||
* Generally not directly used. Using $parser->help($command, 'xml'); is usually
|
||||
* how you would access help. Or via the `--help=xml` option on the command line.
|
||||
*
|
||||
* Xml output is useful for integration with other tools like IDE's or other build tools.
|
||||
*
|
||||
* @package Cake.Console
|
||||
* @since CakePHP(tm) v 2.0
|
||||
*/
|
||||
class HelpFormatter {
|
||||
|
||||
/**
|
||||
* The maximum number of arguments shown when generating usage.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $_maxArgs = 6;
|
||||
|
||||
/**
|
||||
* The maximum number of options shown when generating usage.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $_maxOptions = 6;
|
||||
|
||||
/**
|
||||
* Build the help formatter for a an OptionParser
|
||||
*
|
||||
* @param ConsoleOptionParser $parser The option parser help is being generated for.
|
||||
*/
|
||||
public function __construct(ConsoleOptionParser $parser) {
|
||||
$this->_parser = $parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the help as formatted text suitable for output on the command line.
|
||||
*
|
||||
* @param int $width The width of the help output.
|
||||
* @return string
|
||||
*/
|
||||
public function text($width = 72) {
|
||||
$parser = $this->_parser;
|
||||
$out = array();
|
||||
$description = $parser->description();
|
||||
if (!empty($description)) {
|
||||
$out[] = String::wrap($description, $width);
|
||||
$out[] = '';
|
||||
}
|
||||
$out[] = __d('cake_console', '<info>Usage:</info>');
|
||||
$out[] = $this->_generateUsage();
|
||||
$out[] = '';
|
||||
$subcommands = $parser->subcommands();
|
||||
if (!empty($subcommands)) {
|
||||
$out[] = __d('cake_console', '<info>Subcommands:</info>');
|
||||
$out[] = '';
|
||||
$max = $this->_getMaxLength($subcommands) + 2;
|
||||
foreach ($subcommands as $command) {
|
||||
$out[] = String::wrap($command->help($max), array(
|
||||
'width' => $width,
|
||||
'indent' => str_repeat(' ', $max),
|
||||
'indentAt' => 1
|
||||
));
|
||||
}
|
||||
$out[] = '';
|
||||
$out[] = __d('cake_console', 'To see help on a subcommand use <info>`cake %s [subcommand] --help`</info>', $parser->command());
|
||||
$out[] = '';
|
||||
}
|
||||
|
||||
$options = $parser->options();
|
||||
if (!empty($options)) {
|
||||
$max = $this->_getMaxLength($options) + 8;
|
||||
$out[] = __d('cake_console', '<info>Options:</info>');
|
||||
$out[] = '';
|
||||
foreach ($options as $option) {
|
||||
$out[] = String::wrap($option->help($max), array(
|
||||
'width' => $width,
|
||||
'indent' => str_repeat(' ', $max),
|
||||
'indentAt' => 1
|
||||
));
|
||||
}
|
||||
$out[] = '';
|
||||
}
|
||||
|
||||
$arguments = $parser->arguments();
|
||||
if (!empty($arguments)) {
|
||||
$max = $this->_getMaxLength($arguments) + 2;
|
||||
$out[] = __d('cake_console', '<info>Arguments:</info>');
|
||||
$out[] = '';
|
||||
foreach ($arguments as $argument) {
|
||||
$out[] = String::wrap($argument->help($max), array(
|
||||
'width' => $width,
|
||||
'indent' => str_repeat(' ', $max),
|
||||
'indentAt' => 1
|
||||
));
|
||||
}
|
||||
$out[] = '';
|
||||
}
|
||||
$epilog = $parser->epilog();
|
||||
if (!empty($epilog)) {
|
||||
$out[] = String::wrap($epilog, $width);
|
||||
$out[] = '';
|
||||
}
|
||||
return implode("\n", $out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the usage for a shell based on its arguments and options.
|
||||
* Usage strings favor short options over the long ones. and optional args will
|
||||
* be indicated with []
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _generateUsage() {
|
||||
$usage = array('cake ' . $this->_parser->command());
|
||||
$subcommands = $this->_parser->subcommands();
|
||||
if (!empty($subcommands)) {
|
||||
$usage[] = '[subcommand]';
|
||||
}
|
||||
$options = array();
|
||||
foreach ($this->_parser->options() as $option) {
|
||||
$options[] = $option->usage();
|
||||
}
|
||||
if (count($options) > $this->_maxOptions) {
|
||||
$options = array('[options]');
|
||||
}
|
||||
$usage = array_merge($usage, $options);
|
||||
$args = array();
|
||||
foreach ($this->_parser->arguments() as $argument) {
|
||||
$args[] = $argument->usage();
|
||||
}
|
||||
if (count($args) > $this->_maxArgs) {
|
||||
$args = array('[arguments]');
|
||||
}
|
||||
$usage = array_merge($usage, $args);
|
||||
return implode(' ', $usage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over a collection and find the longest named thing.
|
||||
*
|
||||
* @param array $collection The collection to find a max length of.
|
||||
* @return int
|
||||
*/
|
||||
protected function _getMaxLength($collection) {
|
||||
$max = 0;
|
||||
foreach ($collection as $item) {
|
||||
$max = (strlen($item->name()) > $max) ? strlen($item->name()) : $max;
|
||||
}
|
||||
return $max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the help as an xml string.
|
||||
*
|
||||
* @param bool $string Return the SimpleXml object or a string. Defaults to true.
|
||||
* @return string|SimpleXmlElement See $string
|
||||
*/
|
||||
public function xml($string = true) {
|
||||
$parser = $this->_parser;
|
||||
$xml = new SimpleXmlElement('<shell></shell>');
|
||||
$xml->addChild('command', $parser->command());
|
||||
$xml->addChild('description', $parser->description());
|
||||
|
||||
$xml->addChild('epilog', $parser->epilog());
|
||||
$subcommands = $xml->addChild('subcommands');
|
||||
foreach ($parser->subcommands() as $command) {
|
||||
$command->xml($subcommands);
|
||||
}
|
||||
$options = $xml->addChild('options');
|
||||
foreach ($parser->options() as $option) {
|
||||
$option->xml($options);
|
||||
}
|
||||
$arguments = $xml->addChild('arguments');
|
||||
foreach ($parser->arguments() as $argument) {
|
||||
$argument->xml($arguments);
|
||||
}
|
||||
return $string ? $xml->asXml() : $xml;
|
||||
}
|
||||
|
||||
}
|
||||
897
lib/Cake/Console/Shell.php
Normal file
897
lib/Cake/Console/Shell.php
Normal file
|
|
@ -0,0 +1,897 @@
|
|||
<?php
|
||||
/**
|
||||
* Base class for Shells
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 1.2.0.5012
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('TaskCollection', 'Console');
|
||||
App::uses('ConsoleOutput', 'Console');
|
||||
App::uses('ConsoleInput', 'Console');
|
||||
App::uses('ConsoleInputSubcommand', 'Console');
|
||||
App::uses('ConsoleOptionParser', 'Console');
|
||||
App::uses('ClassRegistry', 'Utility');
|
||||
App::uses('File', 'Utility');
|
||||
App::uses('ClassRegistry', 'Utility');
|
||||
|
||||
/**
|
||||
* Base class for command-line utilities for automating programmer chores.
|
||||
*
|
||||
* @package Cake.Console
|
||||
*/
|
||||
class Shell extends Object {
|
||||
|
||||
/**
|
||||
* Output constant making verbose shells.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const VERBOSE = 2;
|
||||
|
||||
/**
|
||||
* Output constant for making normal shells.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const NORMAL = 1;
|
||||
|
||||
/**
|
||||
* Output constants for making quiet shells.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const QUIET = 0;
|
||||
|
||||
/**
|
||||
* An instance of ConsoleOptionParser that has been configured for this class.
|
||||
*
|
||||
* @var ConsoleOptionParser
|
||||
*/
|
||||
public $OptionParser;
|
||||
|
||||
/**
|
||||
* If true, the script will ask for permission to perform actions.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $interactive = true;
|
||||
|
||||
/**
|
||||
* Contains command switches parsed from the command line.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $params = array();
|
||||
|
||||
/**
|
||||
* The command (method/task) that is being run.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $command;
|
||||
|
||||
/**
|
||||
* Contains arguments parsed from the command line.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $args = array();
|
||||
|
||||
/**
|
||||
* The name of the shell in camelized.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name = null;
|
||||
|
||||
/**
|
||||
* The name of the plugin the shell belongs to.
|
||||
* Is automatically set by ShellDispatcher when a shell is constructed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $plugin = null;
|
||||
|
||||
/**
|
||||
* Contains tasks to load and instantiate
|
||||
*
|
||||
* @var array
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::$tasks
|
||||
*/
|
||||
public $tasks = array();
|
||||
|
||||
/**
|
||||
* Contains the loaded tasks
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $taskNames = array();
|
||||
|
||||
/**
|
||||
* Contains models to load and instantiate
|
||||
*
|
||||
* @var array
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::$uses
|
||||
*/
|
||||
public $uses = array();
|
||||
|
||||
/**
|
||||
* This shell's primary model class name, the first model in the $uses property
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $modelClass = null;
|
||||
|
||||
/**
|
||||
* Task Collection for the command, used to create Tasks.
|
||||
*
|
||||
* @var TaskCollection
|
||||
*/
|
||||
public $Tasks;
|
||||
|
||||
/**
|
||||
* Normalized map of tasks.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_taskMap = array();
|
||||
|
||||
/**
|
||||
* stdout object.
|
||||
*
|
||||
* @var ConsoleOutput
|
||||
*/
|
||||
public $stdout;
|
||||
|
||||
/**
|
||||
* stderr object.
|
||||
*
|
||||
* @var ConsoleOutput
|
||||
*/
|
||||
public $stderr;
|
||||
|
||||
/**
|
||||
* stdin object
|
||||
*
|
||||
* @var ConsoleInput
|
||||
*/
|
||||
public $stdin;
|
||||
|
||||
/**
|
||||
* Constructs this Shell instance.
|
||||
*
|
||||
* @param ConsoleOutput $stdout A ConsoleOutput object for stdout.
|
||||
* @param ConsoleOutput $stderr A ConsoleOutput object for stderr.
|
||||
* @param ConsoleInput $stdin A ConsoleInput object for stdin.
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell
|
||||
*/
|
||||
public function __construct($stdout = null, $stderr = null, $stdin = null) {
|
||||
if (!$this->name) {
|
||||
$this->name = Inflector::camelize(str_replace(array('Shell', 'Task'), '', get_class($this)));
|
||||
}
|
||||
$this->Tasks = new TaskCollection($this);
|
||||
|
||||
$this->stdout = $stdout ? $stdout : new ConsoleOutput('php://stdout');
|
||||
$this->stderr = $stderr ? $stderr : new ConsoleOutput('php://stderr');
|
||||
$this->stdin = $stdin ? $stdin : new ConsoleInput('php://stdin');
|
||||
|
||||
$this->_useLogger();
|
||||
$parent = get_parent_class($this);
|
||||
if ($this->tasks !== null && $this->tasks !== false) {
|
||||
$this->_mergeVars(array('tasks'), $parent, true);
|
||||
}
|
||||
if (!empty($this->uses)) {
|
||||
$this->_mergeVars(array('uses'), $parent, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the Shell
|
||||
* acts as constructor for subclasses
|
||||
* allows configuration of tasks prior to shell execution
|
||||
*
|
||||
* @return void
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::initialize
|
||||
*/
|
||||
public function initialize() {
|
||||
$this->_loadModels();
|
||||
$this->loadTasks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts up the Shell and displays the welcome message.
|
||||
* Allows for checking and configuring prior to command or main execution
|
||||
*
|
||||
* Override this method if you want to remove the welcome information,
|
||||
* or otherwise modify the pre-command flow.
|
||||
*
|
||||
* @return void
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::startup
|
||||
*/
|
||||
public function startup() {
|
||||
$this->_welcome();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a header for the shell
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _welcome() {
|
||||
$this->out();
|
||||
$this->out(__d('cake_console', '<info>Welcome to CakePHP %s Console</info>', 'v' . Configure::version()));
|
||||
$this->hr();
|
||||
$this->out(__d('cake_console', 'App : %s', APP_DIR));
|
||||
$this->out(__d('cake_console', 'Path: %s', APP));
|
||||
$this->hr();
|
||||
}
|
||||
|
||||
/**
|
||||
* If $uses is an array load each of the models in the array
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function _loadModels() {
|
||||
if (is_array($this->uses)) {
|
||||
list(, $this->modelClass) = pluginSplit(current($this->uses));
|
||||
foreach ($this->uses as $modelClass) {
|
||||
$this->loadModel($modelClass);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazy loads models using the loadModel() method if declared in $uses
|
||||
*
|
||||
* @param string $name The name of the model to look for.
|
||||
* @return void
|
||||
*/
|
||||
public function __isset($name) {
|
||||
if (is_array($this->uses)) {
|
||||
foreach ($this->uses as $modelClass) {
|
||||
list(, $class) = pluginSplit($modelClass);
|
||||
if ($name === $class) {
|
||||
return $this->loadModel($modelClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads and instantiates models required by this shell.
|
||||
*
|
||||
* @param string $modelClass Name of model class to load
|
||||
* @param mixed $id Initial ID the instanced model class should have
|
||||
* @return mixed true when single model found and instance created, error returned if model not found.
|
||||
* @throws MissingModelException if the model class cannot be found.
|
||||
*/
|
||||
public function loadModel($modelClass = null, $id = null) {
|
||||
if ($modelClass === null) {
|
||||
$modelClass = $this->modelClass;
|
||||
}
|
||||
|
||||
$this->uses = ($this->uses) ? (array)$this->uses : array();
|
||||
if (!in_array($modelClass, $this->uses)) {
|
||||
$this->uses[] = $modelClass;
|
||||
}
|
||||
|
||||
list($plugin, $modelClass) = pluginSplit($modelClass, true);
|
||||
if (!isset($this->modelClass)) {
|
||||
$this->modelClass = $modelClass;
|
||||
}
|
||||
|
||||
$this->{$modelClass} = ClassRegistry::init(array(
|
||||
'class' => $plugin . $modelClass, 'alias' => $modelClass, 'id' => $id
|
||||
));
|
||||
if (!$this->{$modelClass}) {
|
||||
throw new MissingModelException($modelClass);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads tasks defined in public $tasks
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function loadTasks() {
|
||||
if ($this->tasks === true || empty($this->tasks) || empty($this->Tasks)) {
|
||||
return true;
|
||||
}
|
||||
$this->_taskMap = TaskCollection::normalizeObjectArray((array)$this->tasks);
|
||||
$this->taskNames = array_merge($this->taskNames, array_keys($this->_taskMap));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if this shell has a task with the provided name.
|
||||
*
|
||||
* @param string $task The task name to check.
|
||||
* @return bool Success
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::hasTask
|
||||
*/
|
||||
public function hasTask($task) {
|
||||
return isset($this->_taskMap[Inflector::camelize($task)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if this shell has a callable method by the given name.
|
||||
*
|
||||
* @param string $name The method name to check.
|
||||
* @return bool
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::hasMethod
|
||||
*/
|
||||
public function hasMethod($name) {
|
||||
try {
|
||||
$method = new ReflectionMethod($this, $name);
|
||||
if (!$method->isPublic() || substr($name, 0, 1) === '_') {
|
||||
return false;
|
||||
}
|
||||
if ($method->getDeclaringClass()->name === 'Shell') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (ReflectionException $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a command to another Shell. Similar to Object::requestAction()
|
||||
* but intended for running shells from other shells.
|
||||
*
|
||||
* ### Usage:
|
||||
*
|
||||
* With a string command:
|
||||
*
|
||||
* `return $this->dispatchShell('schema create DbAcl');`
|
||||
*
|
||||
* Avoid using this form if you have string arguments, with spaces in them.
|
||||
* The dispatched will be invoked incorrectly. Only use this form for simple
|
||||
* command dispatching.
|
||||
*
|
||||
* With an array command:
|
||||
*
|
||||
* `return $this->dispatchShell('schema', 'create', 'i18n', '--dry');`
|
||||
*
|
||||
* @return mixed The return of the other shell.
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::dispatchShell
|
||||
*/
|
||||
public function dispatchShell() {
|
||||
$args = func_get_args();
|
||||
if (is_string($args[0]) && count($args) === 1) {
|
||||
$args = explode(' ', $args[0]);
|
||||
}
|
||||
|
||||
$Dispatcher = new ShellDispatcher($args, false);
|
||||
return $Dispatcher->dispatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the Shell with the provided argv.
|
||||
*
|
||||
* Delegates calls to Tasks and resolves methods inside the class. Commands are looked
|
||||
* up with the following order:
|
||||
*
|
||||
* - Method on the shell.
|
||||
* - Matching task name.
|
||||
* - `main()` method.
|
||||
*
|
||||
* If a shell implements a `main()` method, all missing method calls will be sent to
|
||||
* `main()` with the original method name in the argv.
|
||||
*
|
||||
* @param string $command The command name to run on this shell. If this argument is empty,
|
||||
* and the shell has a `main()` method, that will be called instead.
|
||||
* @param array $argv Array of arguments to run the shell with. This array should be missing the shell name.
|
||||
* @return void
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::runCommand
|
||||
*/
|
||||
public function runCommand($command, $argv) {
|
||||
$isTask = $this->hasTask($command);
|
||||
$isMethod = $this->hasMethod($command);
|
||||
$isMain = $this->hasMethod('main');
|
||||
|
||||
if ($isTask || $isMethod && $command !== 'execute') {
|
||||
array_shift($argv);
|
||||
}
|
||||
|
||||
$this->OptionParser = $this->getOptionParser();
|
||||
try {
|
||||
list($this->params, $this->args) = $this->OptionParser->parse($argv, $command);
|
||||
} catch (ConsoleException $e) {
|
||||
$this->out($this->OptionParser->help($command));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($this->params['quiet'])) {
|
||||
$this->_useLogger(false);
|
||||
}
|
||||
if (!empty($this->params['plugin'])) {
|
||||
CakePlugin::load($this->params['plugin']);
|
||||
}
|
||||
$this->command = $command;
|
||||
if (!empty($this->params['help'])) {
|
||||
return $this->_displayHelp($command);
|
||||
}
|
||||
|
||||
if (($isTask || $isMethod || $isMain) && $command !== 'execute') {
|
||||
$this->startup();
|
||||
}
|
||||
|
||||
if ($isTask) {
|
||||
$command = Inflector::camelize($command);
|
||||
return $this->{$command}->runCommand('execute', $argv);
|
||||
}
|
||||
if ($isMethod) {
|
||||
return $this->{$command}();
|
||||
}
|
||||
if ($isMain) {
|
||||
return $this->main();
|
||||
}
|
||||
$this->out($this->OptionParser->help($command));
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the help in the correct format
|
||||
*
|
||||
* @param string $command The command to get help for.
|
||||
* @return void
|
||||
*/
|
||||
protected function _displayHelp($command) {
|
||||
$format = 'text';
|
||||
if (!empty($this->args[0]) && $this->args[0] === 'xml') {
|
||||
$format = 'xml';
|
||||
$this->stdout->outputAs(ConsoleOutput::RAW);
|
||||
} else {
|
||||
$this->_welcome();
|
||||
}
|
||||
return $this->out($this->OptionParser->help($command, $format));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the option parser instance and configures it.
|
||||
*
|
||||
* By overriding this method you can configure the ConsoleOptionParser before returning it.
|
||||
*
|
||||
* @return ConsoleOptionParser
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::getOptionParser
|
||||
*/
|
||||
public function getOptionParser() {
|
||||
$name = ($this->plugin ? $this->plugin . '.' : '') . $this->name;
|
||||
$parser = new ConsoleOptionParser($name);
|
||||
return $parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overload get for lazy building of tasks
|
||||
*
|
||||
* @param string $name The property name to access.
|
||||
* @return Shell Object of Task
|
||||
*/
|
||||
public function __get($name) {
|
||||
if (empty($this->{$name}) && in_array($name, $this->taskNames)) {
|
||||
$properties = $this->_taskMap[$name];
|
||||
$this->{$name} = $this->Tasks->load($properties['class'], $properties['settings']);
|
||||
$this->{$name}->args =& $this->args;
|
||||
$this->{$name}->params =& $this->params;
|
||||
$this->{$name}->initialize();
|
||||
$this->{$name}->loadTasks();
|
||||
}
|
||||
return $this->{$name};
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompts the user for input, and returns it.
|
||||
*
|
||||
* @param string $prompt Prompt text.
|
||||
* @param string|array $options Array or string of options.
|
||||
* @param string $default Default input value.
|
||||
* @return mixed Either the default value, or the user-provided input.
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::in
|
||||
*/
|
||||
public function in($prompt, $options = null, $default = null) {
|
||||
if (!$this->interactive) {
|
||||
return $default;
|
||||
}
|
||||
$originalOptions = $options;
|
||||
$in = $this->_getInput($prompt, $originalOptions, $default);
|
||||
|
||||
if ($options && is_string($options)) {
|
||||
if (strpos($options, ',')) {
|
||||
$options = explode(',', $options);
|
||||
} elseif (strpos($options, '/')) {
|
||||
$options = explode('/', $options);
|
||||
} else {
|
||||
$options = array($options);
|
||||
}
|
||||
}
|
||||
if (is_array($options)) {
|
||||
$options = array_merge(
|
||||
array_map('strtolower', $options),
|
||||
array_map('strtoupper', $options),
|
||||
$options
|
||||
);
|
||||
while ($in === '' || !in_array($in, $options)) {
|
||||
$in = $this->_getInput($prompt, $originalOptions, $default);
|
||||
}
|
||||
}
|
||||
return $in;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompts the user for input, and returns it.
|
||||
*
|
||||
* @param string $prompt Prompt text.
|
||||
* @param string|array $options Array or string of options.
|
||||
* @param string $default Default input value.
|
||||
* @return Either the default value, or the user-provided input.
|
||||
*/
|
||||
protected function _getInput($prompt, $options, $default) {
|
||||
if (!is_array($options)) {
|
||||
$printOptions = '';
|
||||
} else {
|
||||
$printOptions = '(' . implode('/', $options) . ')';
|
||||
}
|
||||
|
||||
if ($default === null) {
|
||||
$this->stdout->write('<question>' . $prompt . '</question>' . " $printOptions \n" . '> ', 0);
|
||||
} else {
|
||||
$this->stdout->write('<question>' . $prompt . '</question>' . " $printOptions \n" . "[$default] > ", 0);
|
||||
}
|
||||
$result = $this->stdin->read();
|
||||
|
||||
if ($result === false) {
|
||||
return $this->_stop(1);
|
||||
}
|
||||
$result = trim($result);
|
||||
|
||||
if ($default !== null && ($result === '' || $result === null)) {
|
||||
return $default;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a block of text.
|
||||
* Allows you to set the width, and indenting on a block of text.
|
||||
*
|
||||
* ### Options
|
||||
*
|
||||
* - `width` The width to wrap to. Defaults to 72
|
||||
* - `wordWrap` Only wrap on words breaks (spaces) Defaults to true.
|
||||
* - `indent` Indent the text with the string provided. Defaults to null.
|
||||
*
|
||||
* @param string $text Text the text to format.
|
||||
* @param string|int|array $options Array of options to use, or an integer to wrap the text to.
|
||||
* @return string Wrapped / indented text
|
||||
* @see String::wrap()
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::wrapText
|
||||
*/
|
||||
public function wrapText($text, $options = array()) {
|
||||
return String::wrap($text, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a single or multiple messages to stdout. If no parameters
|
||||
* are passed outputs just a newline.
|
||||
*
|
||||
* ### Output levels
|
||||
*
|
||||
* There are 3 built-in output level. Shell::QUIET, Shell::NORMAL, Shell::VERBOSE.
|
||||
* The verbose and quiet output levels, map to the `verbose` and `quiet` output switches
|
||||
* present in most shells. Using Shell::QUIET for a message means it will always display.
|
||||
* While using Shell::VERBOSE means it will only display when verbose output is toggled.
|
||||
*
|
||||
* @param string|array $message A string or a an array of strings to output
|
||||
* @param int $newlines Number of newlines to append
|
||||
* @param int $level The message's output level, see above.
|
||||
* @return int|bool Returns the number of bytes returned from writing to stdout.
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::out
|
||||
*/
|
||||
public function out($message = null, $newlines = 1, $level = Shell::NORMAL) {
|
||||
$currentLevel = Shell::NORMAL;
|
||||
if (!empty($this->params['verbose'])) {
|
||||
$currentLevel = Shell::VERBOSE;
|
||||
}
|
||||
if (!empty($this->params['quiet'])) {
|
||||
$currentLevel = Shell::QUIET;
|
||||
}
|
||||
if ($level <= $currentLevel) {
|
||||
return $this->stdout->write($message, $newlines);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a single or multiple error messages to stderr. If no parameters
|
||||
* are passed outputs just a newline.
|
||||
*
|
||||
* @param string|array $message A string or a an array of strings to output
|
||||
* @param int $newlines Number of newlines to append
|
||||
* @return void
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::err
|
||||
*/
|
||||
public function err($message = null, $newlines = 1) {
|
||||
$this->stderr->write($message, $newlines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a single or multiple linefeeds sequences.
|
||||
*
|
||||
* @param int $multiplier Number of times the linefeed sequence should be repeated
|
||||
* @return string
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::nl
|
||||
*/
|
||||
public function nl($multiplier = 1) {
|
||||
return str_repeat(ConsoleOutput::LF, $multiplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a series of minus characters to the standard output, acts as a visual separator.
|
||||
*
|
||||
* @param int $newlines Number of newlines to pre- and append
|
||||
* @param int $width Width of the line, defaults to 63
|
||||
* @return void
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::hr
|
||||
*/
|
||||
public function hr($newlines = 0, $width = 63) {
|
||||
$this->out(null, $newlines);
|
||||
$this->out(str_repeat('-', $width));
|
||||
$this->out(null, $newlines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a formatted error message
|
||||
* and exits the application with status code 1
|
||||
*
|
||||
* @param string $title Title of the error
|
||||
* @param string $message An optional error message
|
||||
* @return void
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::error
|
||||
*/
|
||||
public function error($title, $message = null) {
|
||||
$this->err(__d('cake_console', '<error>Error:</error> %s', $title));
|
||||
|
||||
if (!empty($message)) {
|
||||
$this->err($message);
|
||||
}
|
||||
return $this->_stop(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the console
|
||||
*
|
||||
* @return void
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::clear
|
||||
*/
|
||||
public function clear() {
|
||||
if (empty($this->params['noclear'])) {
|
||||
if (DS === '/') {
|
||||
passthru('clear');
|
||||
} else {
|
||||
passthru('cls');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a file at given path
|
||||
*
|
||||
* @param string $path Where to put the file.
|
||||
* @param string $contents Content to put in the file.
|
||||
* @return bool Success
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::createFile
|
||||
*/
|
||||
public function createFile($path, $contents) {
|
||||
$path = str_replace(DS . DS, DS, $path);
|
||||
|
||||
$this->out();
|
||||
|
||||
if (is_file($path) && empty($this->params['force']) && $this->interactive === true) {
|
||||
$this->out(__d('cake_console', '<warning>File `%s` exists</warning>', $path));
|
||||
$key = $this->in(__d('cake_console', 'Do you want to overwrite?'), array('y', 'n', 'q'), 'n');
|
||||
|
||||
if (strtolower($key) === 'q') {
|
||||
$this->out(__d('cake_console', '<error>Quitting</error>.'), 2);
|
||||
return $this->_stop();
|
||||
} elseif (strtolower($key) !== 'y') {
|
||||
$this->out(__d('cake_console', 'Skip `%s`', $path), 2);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$this->out(__d('cake_console', 'Creating file %s', $path));
|
||||
}
|
||||
|
||||
$File = new File($path, true);
|
||||
if ($File->exists() && $File->writable()) {
|
||||
$data = $File->prepare($contents);
|
||||
$File->write($data);
|
||||
$this->out(__d('cake_console', '<success>Wrote</success> `%s`', $path));
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->err(__d('cake_console', '<error>Could not write to `%s`</error>.', $path), 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Action to create a Unit Test
|
||||
*
|
||||
* @return bool Success
|
||||
*/
|
||||
protected function _checkUnitTest() {
|
||||
if (class_exists('PHPUnit_Framework_TestCase')) {
|
||||
return true;
|
||||
//@codingStandardsIgnoreStart
|
||||
} elseif (@include 'PHPUnit' . DS . 'Autoload.php') {
|
||||
//@codingStandardsIgnoreEnd
|
||||
return true;
|
||||
} elseif (App::import('Vendor', 'phpunit', array('file' => 'PHPUnit' . DS . 'Autoload.php'))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$prompt = __d('cake_console', 'PHPUnit is not installed. Do you want to bake unit test files anyway?');
|
||||
$unitTest = $this->in($prompt, array('y', 'n'), 'y');
|
||||
$result = strtolower($unitTest) === 'y' || strtolower($unitTest) === 'yes';
|
||||
|
||||
if ($result) {
|
||||
$this->out();
|
||||
$this->out(__d('cake_console', 'You can download PHPUnit from %s', 'http://phpunit.de'));
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes absolute file path easier to read
|
||||
*
|
||||
* @param string $file Absolute file path
|
||||
* @return string short path
|
||||
* @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::shortPath
|
||||
*/
|
||||
public function shortPath($file) {
|
||||
$shortPath = str_replace(ROOT, null, $file);
|
||||
$shortPath = str_replace('..' . DS, '', $shortPath);
|
||||
return str_replace(DS . DS, DS, $shortPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the proper controller path for the specified controller class name
|
||||
*
|
||||
* @param string $name Controller class name
|
||||
* @return string Path to controller
|
||||
*/
|
||||
protected function _controllerPath($name) {
|
||||
return Inflector::underscore($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the proper controller plural name for the specified controller class name
|
||||
*
|
||||
* @param string $name Controller class name
|
||||
* @return string Controller plural name
|
||||
*/
|
||||
protected function _controllerName($name) {
|
||||
return Inflector::pluralize(Inflector::camelize($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the proper model camelized name (singularized) for the specified name
|
||||
*
|
||||
* @param string $name Name
|
||||
* @return string Camelized and singularized model name
|
||||
*/
|
||||
protected function _modelName($name) {
|
||||
return Inflector::camelize(Inflector::singularize($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the proper underscored model key for associations
|
||||
*
|
||||
* @param string $name Model class name
|
||||
* @return string Singular model key
|
||||
*/
|
||||
protected function _modelKey($name) {
|
||||
return Inflector::underscore($name) . '_id';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the proper model name from a foreign key
|
||||
*
|
||||
* @param string $key Foreign key
|
||||
* @return string Model name
|
||||
*/
|
||||
protected function _modelNameFromKey($key) {
|
||||
return Inflector::camelize(str_replace('_id', '', $key));
|
||||
}
|
||||
|
||||
/**
|
||||
* creates the singular name for use in views.
|
||||
*
|
||||
* @param string $name The plural underscored value.
|
||||
* @return string name
|
||||
*/
|
||||
protected function _singularName($name) {
|
||||
return Inflector::variable(Inflector::singularize($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the plural name for views
|
||||
*
|
||||
* @param string $name Name to use
|
||||
* @return string Plural name for views
|
||||
*/
|
||||
protected function _pluralName($name) {
|
||||
return Inflector::variable(Inflector::pluralize($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the singular human name used in views
|
||||
*
|
||||
* @param string $name Controller name
|
||||
* @return string Singular human name
|
||||
*/
|
||||
protected function _singularHumanName($name) {
|
||||
return Inflector::humanize(Inflector::underscore(Inflector::singularize($name)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the plural human name used in views
|
||||
*
|
||||
* @param string $name Controller name
|
||||
* @return string Plural human name
|
||||
*/
|
||||
protected function _pluralHumanName($name) {
|
||||
return Inflector::humanize(Inflector::underscore($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the correct path for a plugin. Scans $pluginPaths for the plugin you want.
|
||||
*
|
||||
* @param string $pluginName Name of the plugin you want ie. DebugKit
|
||||
* @return string path path to the correct plugin.
|
||||
*/
|
||||
protected function _pluginPath($pluginName) {
|
||||
if (CakePlugin::loaded($pluginName)) {
|
||||
return CakePlugin::path($pluginName);
|
||||
}
|
||||
return current(App::path('plugins')) . $pluginName . DS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to enable or disable logging stream output to stdout and stderr
|
||||
* If you don't wish to see in your stdout or stderr everything that is logged
|
||||
* through CakeLog, call this function with first param as false
|
||||
*
|
||||
* @param bool $enable whether to enable CakeLog output or not
|
||||
* @return void
|
||||
*/
|
||||
protected function _useLogger($enable = true) {
|
||||
if (!$enable) {
|
||||
CakeLog::drop('stdout');
|
||||
CakeLog::drop('stderr');
|
||||
return;
|
||||
}
|
||||
CakeLog::config('stdout', array(
|
||||
'engine' => 'Console',
|
||||
'types' => array('notice', 'info'),
|
||||
'stream' => $this->stdout,
|
||||
));
|
||||
CakeLog::config('stderr', array(
|
||||
'engine' => 'Console',
|
||||
'types' => array('emergency', 'alert', 'critical', 'error', 'warning', 'debug'),
|
||||
'stream' => $this->stderr,
|
||||
));
|
||||
}
|
||||
}
|
||||
370
lib/Cake/Console/ShellDispatcher.php
Normal file
370
lib/Cake/Console/ShellDispatcher.php
Normal file
|
|
@ -0,0 +1,370 @@
|
|||
<?php
|
||||
/**
|
||||
* ShellDispatcher file
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 2.0
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Shell dispatcher handles dispatching cli commands.
|
||||
*
|
||||
* @package Cake.Console
|
||||
*/
|
||||
class ShellDispatcher {
|
||||
|
||||
/**
|
||||
* Contains command switches parsed from the command line.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $params = array();
|
||||
|
||||
/**
|
||||
* Contains arguments parsed from the command line.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $args = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* The execution of the script is stopped after dispatching the request with
|
||||
* a status code of either 0 or 1 according to the result of the dispatch.
|
||||
*
|
||||
* @param array $args the argv from PHP
|
||||
* @param bool $bootstrap Should the environment be bootstrapped.
|
||||
*/
|
||||
public function __construct($args = array(), $bootstrap = true) {
|
||||
set_time_limit(0);
|
||||
$this->parseParams($args);
|
||||
|
||||
if ($bootstrap) {
|
||||
$this->_initConstants();
|
||||
$this->_initEnvironment();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the dispatcher
|
||||
*
|
||||
* @param array $argv The argv from PHP
|
||||
* @return void
|
||||
*/
|
||||
public static function run($argv) {
|
||||
$dispatcher = new ShellDispatcher($argv);
|
||||
return $dispatcher->_stop($dispatcher->dispatch() === false ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines core configuration.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _initConstants() {
|
||||
if (function_exists('ini_set')) {
|
||||
ini_set('html_errors', false);
|
||||
ini_set('implicit_flush', true);
|
||||
ini_set('max_execution_time', 0);
|
||||
}
|
||||
|
||||
if (!defined('CAKE_CORE_INCLUDE_PATH')) {
|
||||
define('CAKE_CORE_INCLUDE_PATH', dirname(dirname(dirname(__FILE__))));
|
||||
define('CAKEPHP_SHELL', true);
|
||||
if (!defined('DS')) {
|
||||
define('DS', DIRECTORY_SEPARATOR);
|
||||
}
|
||||
if (!defined('CORE_PATH')) {
|
||||
define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines current working environment.
|
||||
*
|
||||
* @return void
|
||||
* @throws CakeException
|
||||
*/
|
||||
protected function _initEnvironment() {
|
||||
if (!$this->_bootstrap()) {
|
||||
$message = "Unable to load CakePHP core.\nMake sure " . DS . 'lib' . DS . 'Cake exists in ' . CAKE_CORE_INCLUDE_PATH;
|
||||
throw new CakeException($message);
|
||||
}
|
||||
|
||||
if (!isset($this->args[0]) || !isset($this->params['working'])) {
|
||||
$message = "This file has been loaded incorrectly and cannot continue.\n" .
|
||||
"Please make sure that " . DS . 'lib' . DS . 'Cake' . DS . "Console is in your system path,\n" .
|
||||
"and check the cookbook for the correct usage of this command.\n" .
|
||||
"(http://book.cakephp.org/)";
|
||||
throw new CakeException($message);
|
||||
}
|
||||
|
||||
$this->shiftArgs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the environment and loads the CakePHP core.
|
||||
*
|
||||
* @return bool Success.
|
||||
*/
|
||||
protected function _bootstrap() {
|
||||
if (!defined('ROOT')) {
|
||||
define('ROOT', $this->params['root']);
|
||||
}
|
||||
if (!defined('APP_DIR')) {
|
||||
define('APP_DIR', $this->params['app']);
|
||||
}
|
||||
if (!defined('APP')) {
|
||||
define('APP', $this->params['working'] . DS);
|
||||
}
|
||||
if (!defined('WWW_ROOT')) {
|
||||
define('WWW_ROOT', APP . $this->params['webroot'] . DS);
|
||||
}
|
||||
if (!defined('TMP') && !is_dir(APP . 'tmp')) {
|
||||
define('TMP', CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'Console' . DS . 'Templates' . DS . 'skel' . DS . 'tmp' . DS);
|
||||
}
|
||||
$boot = file_exists(ROOT . DS . APP_DIR . DS . 'Config' . DS . 'bootstrap.php');
|
||||
require CORE_PATH . 'Cake' . DS . 'bootstrap.php';
|
||||
|
||||
if (!file_exists(APP . 'Config' . DS . 'core.php')) {
|
||||
include_once CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'Console' . DS . 'Templates' . DS . 'skel' . DS . 'Config' . DS . 'core.php';
|
||||
App::build();
|
||||
}
|
||||
|
||||
$this->setErrorHandlers();
|
||||
|
||||
if (!defined('FULL_BASE_URL')) {
|
||||
$url = Configure::read('App.fullBaseUrl');
|
||||
define('FULL_BASE_URL', $url ? $url : 'http://localhost');
|
||||
Configure::write('App.fullBaseUrl', FULL_BASE_URL);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the error/exception handlers for the console
|
||||
* based on the `Error.consoleHandler`, and `Exception.consoleHandler` values
|
||||
* if they are set. If they are not set, the default ConsoleErrorHandler will be
|
||||
* used.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setErrorHandlers() {
|
||||
App::uses('ConsoleErrorHandler', 'Console');
|
||||
$error = Configure::read('Error');
|
||||
$exception = Configure::read('Exception');
|
||||
|
||||
$errorHandler = new ConsoleErrorHandler();
|
||||
if (empty($error['consoleHandler'])) {
|
||||
$error['consoleHandler'] = array($errorHandler, 'handleError');
|
||||
Configure::write('Error', $error);
|
||||
}
|
||||
if (empty($exception['consoleHandler'])) {
|
||||
$exception['consoleHandler'] = array($errorHandler, 'handleException');
|
||||
Configure::write('Exception', $exception);
|
||||
}
|
||||
set_exception_handler($exception['consoleHandler']);
|
||||
set_error_handler($error['consoleHandler'], Configure::read('Error.level'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches a CLI request
|
||||
*
|
||||
* @return bool
|
||||
* @throws MissingShellMethodException
|
||||
*/
|
||||
public function dispatch() {
|
||||
$shell = $this->shiftArgs();
|
||||
|
||||
if (!$shell) {
|
||||
$this->help();
|
||||
return false;
|
||||
}
|
||||
if (in_array($shell, array('help', '--help', '-h'))) {
|
||||
$this->help();
|
||||
return true;
|
||||
}
|
||||
|
||||
$Shell = $this->_getShell($shell);
|
||||
|
||||
$command = null;
|
||||
if (isset($this->args[0])) {
|
||||
$command = $this->args[0];
|
||||
}
|
||||
|
||||
if ($Shell instanceof Shell) {
|
||||
$Shell->initialize();
|
||||
return $Shell->runCommand($command, $this->args);
|
||||
}
|
||||
$methods = array_diff(get_class_methods($Shell), get_class_methods('Shell'));
|
||||
$added = in_array($command, $methods);
|
||||
$private = $command[0] === '_' && method_exists($Shell, $command);
|
||||
|
||||
if (!$private) {
|
||||
if ($added) {
|
||||
$this->shiftArgs();
|
||||
$Shell->startup();
|
||||
return $Shell->{$command}();
|
||||
}
|
||||
if (method_exists($Shell, 'main')) {
|
||||
$Shell->startup();
|
||||
return $Shell->main();
|
||||
}
|
||||
}
|
||||
|
||||
throw new MissingShellMethodException(array('shell' => $shell, 'method' => $command));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get shell to use, either plugin shell or application shell
|
||||
*
|
||||
* All paths in the loaded shell paths are searched.
|
||||
*
|
||||
* @param string $shell Optionally the name of a plugin
|
||||
* @return mixed An object
|
||||
* @throws MissingShellException when errors are encountered.
|
||||
*/
|
||||
protected function _getShell($shell) {
|
||||
list($plugin, $shell) = pluginSplit($shell, true);
|
||||
|
||||
$plugin = Inflector::camelize($plugin);
|
||||
$class = Inflector::camelize($shell) . 'Shell';
|
||||
|
||||
App::uses('Shell', 'Console');
|
||||
App::uses('AppShell', 'Console/Command');
|
||||
App::uses($class, $plugin . 'Console/Command');
|
||||
|
||||
if (!class_exists($class)) {
|
||||
throw new MissingShellException(array(
|
||||
'class' => $class
|
||||
));
|
||||
}
|
||||
$Shell = new $class();
|
||||
$Shell->plugin = trim($plugin, '.');
|
||||
return $Shell;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses command line options and extracts the directory paths from $params
|
||||
*
|
||||
* @param array $args Parameters to parse
|
||||
* @return void
|
||||
*/
|
||||
public function parseParams($args) {
|
||||
$this->_parsePaths($args);
|
||||
|
||||
$defaults = array(
|
||||
'app' => 'app',
|
||||
'root' => dirname(dirname(dirname(dirname(__FILE__)))),
|
||||
'working' => null,
|
||||
'webroot' => 'webroot'
|
||||
);
|
||||
$params = array_merge($defaults, array_intersect_key($this->params, $defaults));
|
||||
$isWin = false;
|
||||
foreach ($defaults as $default => $value) {
|
||||
if (strpos($params[$default], '\\') !== false) {
|
||||
$isWin = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$params = str_replace('\\', '/', $params);
|
||||
|
||||
if (isset($params['working'])) {
|
||||
$params['working'] = trim($params['working']);
|
||||
}
|
||||
|
||||
if (!empty($params['working']) && (!isset($this->args[0]) || isset($this->args[0]) && $this->args[0][0] !== '.')) {
|
||||
if ($params['working'][0] === '.') {
|
||||
$params['working'] = realpath($params['working']);
|
||||
}
|
||||
if (empty($this->params['app']) && $params['working'] != $params['root']) {
|
||||
$params['root'] = dirname($params['working']);
|
||||
$params['app'] = basename($params['working']);
|
||||
} else {
|
||||
$params['root'] = $params['working'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($params['app'][0] === '/' || preg_match('/([a-z])(:)/i', $params['app'], $matches)) {
|
||||
$params['root'] = dirname($params['app']);
|
||||
} elseif (strpos($params['app'], '/')) {
|
||||
$params['root'] .= '/' . dirname($params['app']);
|
||||
}
|
||||
|
||||
$params['app'] = basename($params['app']);
|
||||
$params['working'] = rtrim($params['root'], '/');
|
||||
if (!$isWin || !preg_match('/^[A-Z]:$/i', $params['app'])) {
|
||||
$params['working'] .= '/' . $params['app'];
|
||||
}
|
||||
|
||||
if (!empty($matches[0]) || !empty($isWin)) {
|
||||
$params = str_replace('/', '\\', $params);
|
||||
}
|
||||
|
||||
$this->params = $params + $this->params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses out the paths from from the argv
|
||||
*
|
||||
* @param array $args The argv to parse.
|
||||
* @return void
|
||||
*/
|
||||
protected function _parsePaths($args) {
|
||||
$parsed = array();
|
||||
$keys = array('-working', '--working', '-app', '--app', '-root', '--root');
|
||||
$args = (array)$args;
|
||||
foreach ($keys as $key) {
|
||||
while (($index = array_search($key, $args)) !== false) {
|
||||
$keyname = str_replace('-', '', $key);
|
||||
$valueIndex = $index + 1;
|
||||
$parsed[$keyname] = $args[$valueIndex];
|
||||
array_splice($args, $index, 2);
|
||||
}
|
||||
}
|
||||
$this->args = $args;
|
||||
$this->params = $parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes first argument and shifts other arguments up
|
||||
*
|
||||
* @return mixed Null if there are no arguments otherwise the shifted argument
|
||||
*/
|
||||
public function shiftArgs() {
|
||||
return array_shift($this->args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows console help. Performs an internal dispatch to the CommandList Shell
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function help() {
|
||||
$this->args = array_merge(array('command_list'), $this->args);
|
||||
$this->dispatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop execution of the current script
|
||||
*
|
||||
* @param int|string $status see http://php.net/exit for values
|
||||
* @return void
|
||||
*/
|
||||
protected function _stop($status = 0) {
|
||||
exit($status);
|
||||
}
|
||||
|
||||
}
|
||||
100
lib/Cake/Console/TaskCollection.php
Normal file
100
lib/Cake/Console/TaskCollection.php
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
/**
|
||||
* Task collection is used as a registry for loaded tasks and handles loading
|
||||
* and constructing task class objects.
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 2.0
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('ObjectCollection', 'Utility');
|
||||
|
||||
/**
|
||||
* Collection object for Tasks. Provides features
|
||||
* for lazily loading tasks, and firing callbacks on loaded tasks.
|
||||
*
|
||||
* @package Cake.Console
|
||||
*/
|
||||
class TaskCollection extends ObjectCollection {
|
||||
|
||||
/**
|
||||
* Shell to use to set params to tasks.
|
||||
*
|
||||
* @var Shell
|
||||
*/
|
||||
protected $_Shell;
|
||||
|
||||
/**
|
||||
* The directory inside each shell path that contains tasks.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $taskPathPrefix = 'tasks/';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Shell $Shell The shell this task collection is attached to.
|
||||
*/
|
||||
public function __construct(Shell $Shell) {
|
||||
$this->_Shell = $Shell;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads/constructs a task. Will return the instance in the registry if it already exists.
|
||||
*
|
||||
* You can alias your task as an existing task by setting the 'className' key, i.e.,
|
||||
* {{{
|
||||
* public $tasks = array(
|
||||
* 'DbConfig' => array(
|
||||
* 'className' => 'Bakeplus.DbConfigure'
|
||||
* );
|
||||
* );
|
||||
* }}}
|
||||
* All calls to the `DbConfig` task would use `DbConfigure` found in the `Bakeplus` plugin instead.
|
||||
*
|
||||
* @param string $task Task name to load
|
||||
* @param array $settings Settings for the task.
|
||||
* @return Task A task object, Either the existing loaded task or a new one.
|
||||
* @throws MissingTaskException when the task could not be found
|
||||
*/
|
||||
public function load($task, $settings = array()) {
|
||||
if (is_array($settings) && isset($settings['className'])) {
|
||||
$alias = $task;
|
||||
$task = $settings['className'];
|
||||
}
|
||||
list($plugin, $name) = pluginSplit($task, true);
|
||||
if (!isset($alias)) {
|
||||
$alias = $name;
|
||||
}
|
||||
|
||||
if (isset($this->_loaded[$alias])) {
|
||||
return $this->_loaded[$alias];
|
||||
}
|
||||
$taskClass = $name . 'Task';
|
||||
App::uses($taskClass, $plugin . 'Console/Command/Task');
|
||||
|
||||
$exists = class_exists($taskClass);
|
||||
if (!$exists) {
|
||||
throw new MissingTaskException(array(
|
||||
'class' => $taskClass,
|
||||
'plugin' => substr($plugin, 0, -1)
|
||||
));
|
||||
}
|
||||
|
||||
$this->_loaded[$alias] = new $taskClass(
|
||||
$this->_Shell->stdout, $this->_Shell->stderr, $this->_Shell->stdin
|
||||
);
|
||||
return $this->_loaded[$alias];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
<?php
|
||||
/**
|
||||
* Bake Template for Controller action generation.
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Console.Templates.default.actions
|
||||
* @since CakePHP(tm) v 1.3
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
?>
|
||||
|
||||
/**
|
||||
* <?php echo $admin ?>index method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function <?php echo $admin ?>index() {
|
||||
$this-><?php echo $currentModelName ?>->recursive = 0;
|
||||
$this->set('<?php echo $pluralName ?>', $this->Paginator->paginate());
|
||||
}
|
||||
|
||||
/**
|
||||
* <?php echo $admin ?>view method
|
||||
*
|
||||
* @throws NotFoundException
|
||||
* @param string $id
|
||||
* @return void
|
||||
*/
|
||||
public function <?php echo $admin ?>view($id = null) {
|
||||
if (!$this-><?php echo $currentModelName; ?>->exists($id)) {
|
||||
throw new NotFoundException(__('Invalid <?php echo strtolower($singularHumanName); ?>'));
|
||||
}
|
||||
$options = array('conditions' => array('<?php echo $currentModelName; ?>.' . $this-><?php echo $currentModelName; ?>->primaryKey => $id));
|
||||
$this->set('<?php echo $singularName; ?>', $this-><?php echo $currentModelName; ?>->find('first', $options));
|
||||
}
|
||||
|
||||
<?php $compact = array(); ?>
|
||||
/**
|
||||
* <?php echo $admin ?>add method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function <?php echo $admin ?>add() {
|
||||
if ($this->request->is('post')) {
|
||||
$this-><?php echo $currentModelName; ?>->create();
|
||||
if ($this-><?php echo $currentModelName; ?>->save($this->request->data)) {
|
||||
<?php if ($wannaUseSession): ?>
|
||||
$this->Session->setFlash(__('The <?php echo strtolower($singularHumanName); ?> has been saved.'));
|
||||
return $this->redirect(array('action' => 'index'));
|
||||
} else {
|
||||
$this->Session->setFlash(__('The <?php echo strtolower($singularHumanName); ?> could not be saved. Please, try again.'));
|
||||
<?php else: ?>
|
||||
return $this->flash(__('The <?php echo strtolower($singularHumanName); ?> has been saved.'), array('action' => 'index'));
|
||||
<?php endif; ?>
|
||||
}
|
||||
}
|
||||
<?php
|
||||
foreach (array('belongsTo', 'hasAndBelongsToMany') as $assoc):
|
||||
foreach ($modelObj->{$assoc} as $associationName => $relation):
|
||||
if (!empty($associationName)):
|
||||
$otherModelName = $this->_modelName($associationName);
|
||||
$otherPluralName = $this->_pluralName($associationName);
|
||||
echo "\t\t\${$otherPluralName} = \$this->{$currentModelName}->{$otherModelName}->find('list');\n";
|
||||
$compact[] = "'{$otherPluralName}'";
|
||||
endif;
|
||||
endforeach;
|
||||
endforeach;
|
||||
if (!empty($compact)):
|
||||
echo "\t\t\$this->set(compact(".join(', ', $compact)."));\n";
|
||||
endif;
|
||||
?>
|
||||
}
|
||||
|
||||
<?php $compact = array(); ?>
|
||||
/**
|
||||
* <?php echo $admin ?>edit method
|
||||
*
|
||||
* @throws NotFoundException
|
||||
* @param string $id
|
||||
* @return void
|
||||
*/
|
||||
public function <?php echo $admin; ?>edit($id = null) {
|
||||
if (!$this-><?php echo $currentModelName; ?>->exists($id)) {
|
||||
throw new NotFoundException(__('Invalid <?php echo strtolower($singularHumanName); ?>'));
|
||||
}
|
||||
if ($this->request->is(array('post', 'put'))) {
|
||||
if ($this-><?php echo $currentModelName; ?>->save($this->request->data)) {
|
||||
<?php if ($wannaUseSession): ?>
|
||||
$this->Session->setFlash(__('The <?php echo strtolower($singularHumanName); ?> has been saved.'));
|
||||
return $this->redirect(array('action' => 'index'));
|
||||
} else {
|
||||
$this->Session->setFlash(__('The <?php echo strtolower($singularHumanName); ?> could not be saved. Please, try again.'));
|
||||
<?php else: ?>
|
||||
return $this->flash(__('The <?php echo strtolower($singularHumanName); ?> has been saved.'), array('action' => 'index'));
|
||||
<?php endif; ?>
|
||||
}
|
||||
} else {
|
||||
$options = array('conditions' => array('<?php echo $currentModelName; ?>.' . $this-><?php echo $currentModelName; ?>->primaryKey => $id));
|
||||
$this->request->data = $this-><?php echo $currentModelName; ?>->find('first', $options);
|
||||
}
|
||||
<?php
|
||||
foreach (array('belongsTo', 'hasAndBelongsToMany') as $assoc):
|
||||
foreach ($modelObj->{$assoc} as $associationName => $relation):
|
||||
if (!empty($associationName)):
|
||||
$otherModelName = $this->_modelName($associationName);
|
||||
$otherPluralName = $this->_pluralName($associationName);
|
||||
echo "\t\t\${$otherPluralName} = \$this->{$currentModelName}->{$otherModelName}->find('list');\n";
|
||||
$compact[] = "'{$otherPluralName}'";
|
||||
endif;
|
||||
endforeach;
|
||||
endforeach;
|
||||
if (!empty($compact)):
|
||||
echo "\t\t\$this->set(compact(".join(', ', $compact)."));\n";
|
||||
endif;
|
||||
?>
|
||||
}
|
||||
|
||||
/**
|
||||
* <?php echo $admin ?>delete method
|
||||
*
|
||||
* @throws NotFoundException
|
||||
* @param string $id
|
||||
* @return void
|
||||
*/
|
||||
public function <?php echo $admin; ?>delete($id = null) {
|
||||
$this-><?php echo $currentModelName; ?>->id = $id;
|
||||
if (!$this-><?php echo $currentModelName; ?>->exists()) {
|
||||
throw new NotFoundException(__('Invalid <?php echo strtolower($singularHumanName); ?>'));
|
||||
}
|
||||
$this->request->allowMethod('post', 'delete');
|
||||
if ($this-><?php echo $currentModelName; ?>->delete()) {
|
||||
<?php if ($wannaUseSession): ?>
|
||||
$this->Session->setFlash(__('The <?php echo strtolower($singularHumanName); ?> has been deleted.'));
|
||||
} else {
|
||||
$this->Session->setFlash(__('The <?php echo strtolower($singularHumanName); ?> could not be deleted. Please, try again.'));
|
||||
}
|
||||
return $this->redirect(array('action' => 'index'));
|
||||
<?php else: ?>
|
||||
return $this->flash(__('The <?php echo strtolower($singularHumanName); ?> has been deleted.'), array('action' => 'index'));
|
||||
} else {
|
||||
return $this->flash(__('The <?php echo strtolower($singularHumanName); ?> could not be deleted. Please, try again.'), array('action' => 'index'));
|
||||
}
|
||||
<?php endif; ?>
|
||||
}
|
||||
82
lib/Cake/Console/Templates/default/classes/controller.ctp
Normal file
82
lib/Cake/Console/Templates/default/classes/controller.ctp
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
/**
|
||||
* Controller bake template file
|
||||
*
|
||||
* Allows templating of Controllers generated from bake.
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Console.Templates.default.classes
|
||||
* @since CakePHP(tm) v 1.3
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
echo "<?php\n";
|
||||
echo "App::uses('{$plugin}AppController', '{$pluginPath}Controller');\n";
|
||||
?>
|
||||
/**
|
||||
* <?php echo $controllerName; ?> Controller
|
||||
*
|
||||
<?php
|
||||
if (!$isScaffold) {
|
||||
$defaultModel = Inflector::singularize($controllerName);
|
||||
echo " * @property {$defaultModel} \${$defaultModel}\n";
|
||||
if (!empty($components)) {
|
||||
foreach ($components as $component) {
|
||||
echo " * @property {$component}Component \${$component}\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
*/
|
||||
class <?php echo $controllerName; ?>Controller extends <?php echo $plugin; ?>AppController {
|
||||
|
||||
<?php if ($isScaffold): ?>
|
||||
/**
|
||||
* Scaffold
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $scaffold;
|
||||
|
||||
<?php else:
|
||||
|
||||
if (count($helpers)):
|
||||
echo "/**\n * Helpers\n *\n * @var array\n */\n";
|
||||
echo "\tpublic \$helpers = array(";
|
||||
for ($i = 0, $len = count($helpers); $i < $len; $i++):
|
||||
if ($i != $len - 1):
|
||||
echo "'" . Inflector::camelize($helpers[$i]) . "', ";
|
||||
else:
|
||||
echo "'" . Inflector::camelize($helpers[$i]) . "'";
|
||||
endif;
|
||||
endfor;
|
||||
echo ");\n\n";
|
||||
endif;
|
||||
|
||||
if (count($components)):
|
||||
echo "/**\n * Components\n *\n * @var array\n */\n";
|
||||
echo "\tpublic \$components = array(";
|
||||
for ($i = 0, $len = count($components); $i < $len; $i++):
|
||||
if ($i != $len - 1):
|
||||
echo "'" . Inflector::camelize($components[$i]) . "', ";
|
||||
else:
|
||||
echo "'" . Inflector::camelize($components[$i]) . "'";
|
||||
endif;
|
||||
endfor;
|
||||
echo ");\n\n";
|
||||
endif;
|
||||
|
||||
if (!empty($actions)) {
|
||||
echo trim($actions) . "\n";
|
||||
}
|
||||
|
||||
endif; ?>
|
||||
}
|
||||
65
lib/Cake/Console/Templates/default/classes/fixture.ctp
Normal file
65
lib/Cake/Console/Templates/default/classes/fixture.ctp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
/**
|
||||
* Fixture Template file
|
||||
*
|
||||
* Fixture Template used when baking fixtures with bake
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Console.Templates.default.classes
|
||||
* @since CakePHP(tm) v 1.3
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
echo "<?php\n";
|
||||
?>
|
||||
/**
|
||||
* <?php echo $model; ?>Fixture
|
||||
*
|
||||
*/
|
||||
class <?php echo $model; ?>Fixture extends CakeTestFixture {
|
||||
|
||||
<?php if ($table): ?>
|
||||
/**
|
||||
* Table name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $table = '<?php echo $table; ?>';
|
||||
|
||||
<?php endif; ?>
|
||||
<?php if ($import): ?>
|
||||
/**
|
||||
* Import
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $import = <?php echo $import; ?>;
|
||||
|
||||
<?php endif; ?>
|
||||
<?php if ($schema): ?>
|
||||
/**
|
||||
* Fields
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $fields = <?php echo $schema; ?>;
|
||||
|
||||
<?php endif; ?>
|
||||
<?php if ($records): ?>
|
||||
/**
|
||||
* Records
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $records = <?php echo $records; ?>;
|
||||
|
||||
<?php endif; ?>
|
||||
}
|
||||
189
lib/Cake/Console/Templates/default/classes/model.ctp
Normal file
189
lib/Cake/Console/Templates/default/classes/model.ctp
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
<?php
|
||||
/**
|
||||
* Model template file.
|
||||
*
|
||||
* Used by bake to create new Model files.
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Console.Templates.default.classes
|
||||
* @since CakePHP(tm) v 1.3
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
echo "<?php\n";
|
||||
echo "App::uses('{$plugin}AppModel', '{$pluginPath}Model');\n";
|
||||
?>
|
||||
/**
|
||||
* <?php echo $name ?> Model
|
||||
*
|
||||
<?php
|
||||
foreach (array('hasOne', 'belongsTo', 'hasMany', 'hasAndBelongsToMany') as $assocType) {
|
||||
if (!empty($associations[$assocType])) {
|
||||
foreach ($associations[$assocType] as $relation) {
|
||||
echo " * @property {$relation['className']} \${$relation['alias']}\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
*/
|
||||
class <?php echo $name ?> extends <?php echo $plugin; ?>AppModel {
|
||||
|
||||
<?php if ($useDbConfig !== 'default'): ?>
|
||||
/**
|
||||
* Use database config
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $useDbConfig = '<?php echo $useDbConfig; ?>';
|
||||
|
||||
<?php endif;
|
||||
|
||||
if ($useTable && $useTable !== Inflector::tableize($name)):
|
||||
$table = "'$useTable'";
|
||||
echo "/**\n * Use table\n *\n * @var mixed False or table name\n */\n";
|
||||
echo "\tpublic \$useTable = $table;\n\n";
|
||||
endif;
|
||||
|
||||
if ($primaryKey !== 'id'): ?>
|
||||
/**
|
||||
* Primary key field
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $primaryKey = '<?php echo $primaryKey; ?>';
|
||||
|
||||
<?php endif;
|
||||
|
||||
if ($displayField): ?>
|
||||
/**
|
||||
* Display field
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $displayField = '<?php echo $displayField; ?>';
|
||||
|
||||
<?php endif;
|
||||
|
||||
if (!empty($actsAs)): ?>
|
||||
/**
|
||||
* Behaviors
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $actsAs = array(<?php echo "\n\t"; foreach ($actsAs as $behavior): echo "\t"; var_export($behavior); echo ",\n\t"; endforeach; ?>);
|
||||
|
||||
<?php endif;
|
||||
|
||||
if (!empty($validate)):
|
||||
echo "/**\n * Validation rules\n *\n * @var array\n */\n";
|
||||
echo "\tpublic \$validate = array(\n";
|
||||
foreach ($validate as $field => $validations):
|
||||
echo "\t\t'$field' => array(\n";
|
||||
foreach ($validations as $key => $validator):
|
||||
echo "\t\t\t'$key' => array(\n";
|
||||
echo "\t\t\t\t'rule' => array('$validator'),\n";
|
||||
echo "\t\t\t\t//'message' => 'Your custom message here',\n";
|
||||
echo "\t\t\t\t//'allowEmpty' => false,\n";
|
||||
echo "\t\t\t\t//'required' => false,\n";
|
||||
echo "\t\t\t\t//'last' => false, // Stop validation after this rule\n";
|
||||
echo "\t\t\t\t//'on' => 'create', // Limit validation to 'create' or 'update' operations\n";
|
||||
echo "\t\t\t),\n";
|
||||
endforeach;
|
||||
echo "\t\t),\n";
|
||||
endforeach;
|
||||
echo "\t);\n";
|
||||
endif;
|
||||
|
||||
foreach ($associations as $assoc):
|
||||
if (!empty($assoc)):
|
||||
?>
|
||||
|
||||
//The Associations below have been created with all possible keys, those that are not needed can be removed
|
||||
<?php
|
||||
break;
|
||||
endif;
|
||||
endforeach;
|
||||
|
||||
foreach (array('hasOne', 'belongsTo') as $assocType):
|
||||
if (!empty($associations[$assocType])):
|
||||
$typeCount = count($associations[$assocType]);
|
||||
echo "\n/**\n * $assocType associations\n *\n * @var array\n */";
|
||||
echo "\n\tpublic \$$assocType = array(";
|
||||
foreach ($associations[$assocType] as $i => $relation):
|
||||
$out = "\n\t\t'{$relation['alias']}' => array(\n";
|
||||
$out .= "\t\t\t'className' => '{$relation['className']}',\n";
|
||||
$out .= "\t\t\t'foreignKey' => '{$relation['foreignKey']}',\n";
|
||||
$out .= "\t\t\t'conditions' => '',\n";
|
||||
$out .= "\t\t\t'fields' => '',\n";
|
||||
$out .= "\t\t\t'order' => ''\n";
|
||||
$out .= "\t\t)";
|
||||
if ($i + 1 < $typeCount) {
|
||||
$out .= ",";
|
||||
}
|
||||
echo $out;
|
||||
endforeach;
|
||||
echo "\n\t);\n";
|
||||
endif;
|
||||
endforeach;
|
||||
|
||||
if (!empty($associations['hasMany'])):
|
||||
$belongsToCount = count($associations['hasMany']);
|
||||
echo "\n/**\n * hasMany associations\n *\n * @var array\n */";
|
||||
echo "\n\tpublic \$hasMany = array(";
|
||||
foreach ($associations['hasMany'] as $i => $relation):
|
||||
$out = "\n\t\t'{$relation['alias']}' => array(\n";
|
||||
$out .= "\t\t\t'className' => '{$relation['className']}',\n";
|
||||
$out .= "\t\t\t'foreignKey' => '{$relation['foreignKey']}',\n";
|
||||
$out .= "\t\t\t'dependent' => false,\n";
|
||||
$out .= "\t\t\t'conditions' => '',\n";
|
||||
$out .= "\t\t\t'fields' => '',\n";
|
||||
$out .= "\t\t\t'order' => '',\n";
|
||||
$out .= "\t\t\t'limit' => '',\n";
|
||||
$out .= "\t\t\t'offset' => '',\n";
|
||||
$out .= "\t\t\t'exclusive' => '',\n";
|
||||
$out .= "\t\t\t'finderQuery' => '',\n";
|
||||
$out .= "\t\t\t'counterQuery' => ''\n";
|
||||
$out .= "\t\t)";
|
||||
if ($i + 1 < $belongsToCount) {
|
||||
$out .= ",";
|
||||
}
|
||||
echo $out;
|
||||
endforeach;
|
||||
echo "\n\t);\n\n";
|
||||
endif;
|
||||
|
||||
if (!empty($associations['hasAndBelongsToMany'])):
|
||||
$habtmCount = count($associations['hasAndBelongsToMany']);
|
||||
echo "\n/**\n * hasAndBelongsToMany associations\n *\n * @var array\n */";
|
||||
echo "\n\tpublic \$hasAndBelongsToMany = array(";
|
||||
foreach ($associations['hasAndBelongsToMany'] as $i => $relation):
|
||||
$out = "\n\t\t'{$relation['alias']}' => array(\n";
|
||||
$out .= "\t\t\t'className' => '{$relation['className']}',\n";
|
||||
$out .= "\t\t\t'joinTable' => '{$relation['joinTable']}',\n";
|
||||
$out .= "\t\t\t'foreignKey' => '{$relation['foreignKey']}',\n";
|
||||
$out .= "\t\t\t'associationForeignKey' => '{$relation['associationForeignKey']}',\n";
|
||||
$out .= "\t\t\t'unique' => 'keepExisting',\n";
|
||||
$out .= "\t\t\t'conditions' => '',\n";
|
||||
$out .= "\t\t\t'fields' => '',\n";
|
||||
$out .= "\t\t\t'order' => '',\n";
|
||||
$out .= "\t\t\t'limit' => '',\n";
|
||||
$out .= "\t\t\t'offset' => '',\n";
|
||||
$out .= "\t\t\t'finderQuery' => '',\n";
|
||||
$out .= "\t\t)";
|
||||
if ($i + 1 < $habtmCount) {
|
||||
$out .= ",";
|
||||
}
|
||||
echo $out;
|
||||
endforeach;
|
||||
echo "\n\t);\n\n";
|
||||
endif;
|
||||
?>
|
||||
}
|
||||
82
lib/Cake/Console/Templates/default/classes/test.ctp
Normal file
82
lib/Cake/Console/Templates/default/classes/test.ctp
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
/**
|
||||
* Test Case bake template
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Console.Templates.default.classes
|
||||
* @since CakePHP(tm) v 1.3
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
echo "<?php\n";
|
||||
?>
|
||||
<?php foreach ($uses as $dependency): ?>
|
||||
App::uses('<?php echo $dependency[0]; ?>', '<?php echo $dependency[1]; ?>');
|
||||
<?php endforeach; ?>
|
||||
|
||||
/**
|
||||
* <?php echo $fullClassName; ?> Test Case
|
||||
*
|
||||
*/
|
||||
<?php if ($type === 'Controller'): ?>
|
||||
class <?php echo $fullClassName; ?>Test extends ControllerTestCase {
|
||||
<?php else: ?>
|
||||
class <?php echo $fullClassName; ?>Test extends CakeTestCase {
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($fixtures)): ?>
|
||||
/**
|
||||
* Fixtures
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $fixtures = array(
|
||||
'<?php echo join("',\n\t\t'", $fixtures); ?>'
|
||||
);
|
||||
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($construction)): ?>
|
||||
/**
|
||||
* setUp method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
<?php echo $preConstruct ? "\t\t" . $preConstruct : ''; ?>
|
||||
$this-><?php echo $className . ' = ' . $construction; ?>
|
||||
<?php echo $postConstruct ? "\t\t" . $postConstruct : ''; ?>
|
||||
}
|
||||
|
||||
/**
|
||||
* tearDown method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function tearDown() {
|
||||
unset($this-><?php echo $className; ?>);
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
<?php endif; ?>
|
||||
<?php foreach ($methods as $method): ?>
|
||||
/**
|
||||
* test<?php echo Inflector::camelize($method); ?> method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test<?php echo Inflector::camelize($method); ?>() {
|
||||
$this->markTestIncomplete('test<?php echo Inflector::camelize($method); ?> not implemented.');
|
||||
}
|
||||
|
||||
<?php endforeach; ?>
|
||||
}
|
||||
63
lib/Cake/Console/Templates/default/views/form.ctp
Normal file
63
lib/Cake/Console/Templates/default/views/form.ctp
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Console.Templates.default.views
|
||||
* @since CakePHP(tm) v 1.2.0.5234
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
?>
|
||||
<div class="<?php echo $pluralVar; ?> form">
|
||||
<?php echo "<?php echo \$this->Form->create('{$modelClass}'); ?>\n"; ?>
|
||||
<fieldset>
|
||||
<legend><?php printf("<?php echo __('%s %s'); ?>", Inflector::humanize($action), $singularHumanName); ?></legend>
|
||||
<?php
|
||||
echo "\t<?php\n";
|
||||
foreach ($fields as $field) {
|
||||
if (strpos($action, 'add') !== false && $field === $primaryKey) {
|
||||
continue;
|
||||
} elseif (!in_array($field, array('created', 'modified', 'updated'))) {
|
||||
echo "\t\techo \$this->Form->input('{$field}');\n";
|
||||
}
|
||||
}
|
||||
if (!empty($associations['hasAndBelongsToMany'])) {
|
||||
foreach ($associations['hasAndBelongsToMany'] as $assocName => $assocData) {
|
||||
echo "\t\techo \$this->Form->input('{$assocName}');\n";
|
||||
}
|
||||
}
|
||||
echo "\t?>\n";
|
||||
?>
|
||||
</fieldset>
|
||||
<?php
|
||||
echo "<?php echo \$this->Form->end(__('Submit')); ?>\n";
|
||||
?>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<h3><?php echo "<?php echo __('Actions'); ?>"; ?></h3>
|
||||
<ul>
|
||||
|
||||
<?php if (strpos($action, 'add') === false): ?>
|
||||
<li><?php echo "<?php echo \$this->Form->postLink(__('Delete'), array('action' => 'delete', \$this->Form->value('{$modelClass}.{$primaryKey}')), array(), __('Are you sure you want to delete # %s?', \$this->Form->value('{$modelClass}.{$primaryKey}'))); ?>"; ?></li>
|
||||
<?php endif; ?>
|
||||
<li><?php echo "<?php echo \$this->Html->link(__('List " . $pluralHumanName . "'), array('action' => 'index')); ?>"; ?></li>
|
||||
<?php
|
||||
$done = array();
|
||||
foreach ($associations as $type => $data) {
|
||||
foreach ($data as $alias => $details) {
|
||||
if ($details['controller'] != $this->name && !in_array($details['controller'], $done)) {
|
||||
echo "\t\t<li><?php echo \$this->Html->link(__('List " . Inflector::humanize($details['controller']) . "'), array('controller' => '{$details['controller']}', 'action' => 'index')); ?> </li>\n";
|
||||
echo "\t\t<li><?php echo \$this->Html->link(__('New " . Inflector::humanize(Inflector::underscore($alias)) . "'), array('controller' => '{$details['controller']}', 'action' => 'add')); ?> </li>\n";
|
||||
$done[] = $details['controller'];
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
93
lib/Cake/Console/Templates/default/views/index.ctp
Normal file
93
lib/Cake/Console/Templates/default/views/index.ctp
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Console.Templates.default.views
|
||||
* @since CakePHP(tm) v 1.2.0.5234
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
?>
|
||||
<div class="<?php echo $pluralVar; ?> index">
|
||||
<h2><?php echo "<?php echo __('{$pluralHumanName}'); ?>"; ?></h2>
|
||||
<table cellpadding="0" cellspacing="0">
|
||||
<thead>
|
||||
<tr>
|
||||
<?php foreach ($fields as $field): ?>
|
||||
<th><?php echo "<?php echo \$this->Paginator->sort('{$field}'); ?>"; ?></th>
|
||||
<?php endforeach; ?>
|
||||
<th class="actions"><?php echo "<?php echo __('Actions'); ?>"; ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
echo "<?php foreach (\${$pluralVar} as \${$singularVar}): ?>\n";
|
||||
echo "\t<tr>\n";
|
||||
foreach ($fields as $field) {
|
||||
$isKey = false;
|
||||
if (!empty($associations['belongsTo'])) {
|
||||
foreach ($associations['belongsTo'] as $alias => $details) {
|
||||
if ($field === $details['foreignKey']) {
|
||||
$isKey = true;
|
||||
echo "\t\t<td>\n\t\t\t<?php echo \$this->Html->link(\${$singularVar}['{$alias}']['{$details['displayField']}'], array('controller' => '{$details['controller']}', 'action' => 'view', \${$singularVar}['{$alias}']['{$details['primaryKey']}'])); ?>\n\t\t</td>\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($isKey !== true) {
|
||||
echo "\t\t<td><?php echo h(\${$singularVar}['{$modelClass}']['{$field}']); ?> </td>\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo "\t\t<td class=\"actions\">\n";
|
||||
echo "\t\t\t<?php echo \$this->Html->link(__('View'), array('action' => 'view', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?>\n";
|
||||
echo "\t\t\t<?php echo \$this->Html->link(__('Edit'), array('action' => 'edit', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?>\n";
|
||||
echo "\t\t\t<?php echo \$this->Form->postLink(__('Delete'), array('action' => 'delete', \${$singularVar}['{$modelClass}']['{$primaryKey}']), array(), __('Are you sure you want to delete # %s?', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?>\n";
|
||||
echo "\t\t</td>\n";
|
||||
echo "\t</tr>\n";
|
||||
|
||||
echo "<?php endforeach; ?>\n";
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>
|
||||
<?php echo "<?php
|
||||
echo \$this->Paginator->counter(array(
|
||||
'format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}')
|
||||
));
|
||||
?>"; ?>
|
||||
</p>
|
||||
<div class="paging">
|
||||
<?php
|
||||
echo "<?php\n";
|
||||
echo "\t\techo \$this->Paginator->prev('< ' . __('previous'), array(), null, array('class' => 'prev disabled'));\n";
|
||||
echo "\t\techo \$this->Paginator->numbers(array('separator' => ''));\n";
|
||||
echo "\t\techo \$this->Paginator->next(__('next') . ' >', array(), null, array('class' => 'next disabled'));\n";
|
||||
echo "\t?>\n";
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<h3><?php echo "<?php echo __('Actions'); ?>"; ?></h3>
|
||||
<ul>
|
||||
<li><?php echo "<?php echo \$this->Html->link(__('New " . $singularHumanName . "'), array('action' => 'add')); ?>"; ?></li>
|
||||
<?php
|
||||
$done = array();
|
||||
foreach ($associations as $type => $data) {
|
||||
foreach ($data as $alias => $details) {
|
||||
if ($details['controller'] != $this->name && !in_array($details['controller'], $done)) {
|
||||
echo "\t\t<li><?php echo \$this->Html->link(__('List " . Inflector::humanize($details['controller']) . "'), array('controller' => '{$details['controller']}', 'action' => 'index')); ?> </li>\n";
|
||||
echo "\t\t<li><?php echo \$this->Html->link(__('New " . Inflector::humanize(Inflector::underscore($alias)) . "'), array('controller' => '{$details['controller']}', 'action' => 'add')); ?> </li>\n";
|
||||
$done[] = $details['controller'];
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
134
lib/Cake/Console/Templates/default/views/view.ctp
Normal file
134
lib/Cake/Console/Templates/default/views/view.ctp
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Console.Templates.default.views
|
||||
* @since CakePHP(tm) v 1.2.0.5234
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
?>
|
||||
<div class="<?php echo $pluralVar; ?> view">
|
||||
<h2><?php echo "<?php echo __('{$singularHumanName}'); ?>"; ?></h2>
|
||||
<dl>
|
||||
<?php
|
||||
foreach ($fields as $field) {
|
||||
$isKey = false;
|
||||
if (!empty($associations['belongsTo'])) {
|
||||
foreach ($associations['belongsTo'] as $alias => $details) {
|
||||
if ($field === $details['foreignKey']) {
|
||||
$isKey = true;
|
||||
echo "\t\t<dt><?php echo __('" . Inflector::humanize(Inflector::underscore($alias)) . "'); ?></dt>\n";
|
||||
echo "\t\t<dd>\n\t\t\t<?php echo \$this->Html->link(\${$singularVar}['{$alias}']['{$details['displayField']}'], array('controller' => '{$details['controller']}', 'action' => 'view', \${$singularVar}['{$alias}']['{$details['primaryKey']}'])); ?>\n\t\t\t \n\t\t</dd>\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($isKey !== true) {
|
||||
echo "\t\t<dt><?php echo __('" . Inflector::humanize($field) . "'); ?></dt>\n";
|
||||
echo "\t\t<dd>\n\t\t\t<?php echo h(\${$singularVar}['{$modelClass}']['{$field}']); ?>\n\t\t\t \n\t\t</dd>\n";
|
||||
}
|
||||
}
|
||||
?>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<h3><?php echo "<?php echo __('Actions'); ?>"; ?></h3>
|
||||
<ul>
|
||||
<?php
|
||||
echo "\t\t<li><?php echo \$this->Html->link(__('Edit " . $singularHumanName ."'), array('action' => 'edit', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?> </li>\n";
|
||||
echo "\t\t<li><?php echo \$this->Form->postLink(__('Delete " . $singularHumanName . "'), array('action' => 'delete', \${$singularVar}['{$modelClass}']['{$primaryKey}']), array(), __('Are you sure you want to delete # %s?', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?> </li>\n";
|
||||
echo "\t\t<li><?php echo \$this->Html->link(__('List " . $pluralHumanName . "'), array('action' => 'index')); ?> </li>\n";
|
||||
echo "\t\t<li><?php echo \$this->Html->link(__('New " . $singularHumanName . "'), array('action' => 'add')); ?> </li>\n";
|
||||
|
||||
$done = array();
|
||||
foreach ($associations as $type => $data) {
|
||||
foreach ($data as $alias => $details) {
|
||||
if ($details['controller'] != $this->name && !in_array($details['controller'], $done)) {
|
||||
echo "\t\t<li><?php echo \$this->Html->link(__('List " . Inflector::humanize($details['controller']) . "'), array('controller' => '{$details['controller']}', 'action' => 'index')); ?> </li>\n";
|
||||
echo "\t\t<li><?php echo \$this->Html->link(__('New " . Inflector::humanize(Inflector::underscore($alias)) . "'), array('controller' => '{$details['controller']}', 'action' => 'add')); ?> </li>\n";
|
||||
$done[] = $details['controller'];
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php
|
||||
if (!empty($associations['hasOne'])) :
|
||||
foreach ($associations['hasOne'] as $alias => $details): ?>
|
||||
<div class="related">
|
||||
<h3><?php echo "<?php echo __('Related " . Inflector::humanize($details['controller']) . "'); ?>"; ?></h3>
|
||||
<?php echo "<?php if (!empty(\${$singularVar}['{$alias}'])): ?>\n"; ?>
|
||||
<dl>
|
||||
<?php
|
||||
foreach ($details['fields'] as $field) {
|
||||
echo "\t\t<dt><?php echo __('" . Inflector::humanize($field) . "'); ?></dt>\n";
|
||||
echo "\t\t<dd>\n\t<?php echo \${$singularVar}['{$alias}']['{$field}']; ?>\n </dd>\n";
|
||||
}
|
||||
?>
|
||||
</dl>
|
||||
<?php echo "<?php endif; ?>\n"; ?>
|
||||
<div class="actions">
|
||||
<ul>
|
||||
<li><?php echo "<?php echo \$this->Html->link(__('Edit " . Inflector::humanize(Inflector::underscore($alias)) . "'), array('controller' => '{$details['controller']}', 'action' => 'edit', \${$singularVar}['{$alias}']['{$details['primaryKey']}'])); ?></li>\n"; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
endforeach;
|
||||
endif;
|
||||
if (empty($associations['hasMany'])) {
|
||||
$associations['hasMany'] = array();
|
||||
}
|
||||
if (empty($associations['hasAndBelongsToMany'])) {
|
||||
$associations['hasAndBelongsToMany'] = array();
|
||||
}
|
||||
$relations = array_merge($associations['hasMany'], $associations['hasAndBelongsToMany']);
|
||||
foreach ($relations as $alias => $details):
|
||||
$otherSingularVar = Inflector::variable($alias);
|
||||
$otherPluralHumanName = Inflector::humanize($details['controller']);
|
||||
?>
|
||||
<div class="related">
|
||||
<h3><?php echo "<?php echo __('Related " . $otherPluralHumanName . "'); ?>"; ?></h3>
|
||||
<?php echo "<?php if (!empty(\${$singularVar}['{$alias}'])): ?>\n"; ?>
|
||||
<table cellpadding = "0" cellspacing = "0">
|
||||
<tr>
|
||||
<?php
|
||||
foreach ($details['fields'] as $field) {
|
||||
echo "\t\t<th><?php echo __('" . Inflector::humanize($field) . "'); ?></th>\n";
|
||||
}
|
||||
?>
|
||||
<th class="actions"><?php echo "<?php echo __('Actions'); ?>"; ?></th>
|
||||
</tr>
|
||||
<?php
|
||||
echo "\t<?php foreach (\${$singularVar}['{$alias}'] as \${$otherSingularVar}): ?>\n";
|
||||
echo "\t\t<tr>\n";
|
||||
foreach ($details['fields'] as $field) {
|
||||
echo "\t\t\t<td><?php echo \${$otherSingularVar}['{$field}']; ?></td>\n";
|
||||
}
|
||||
|
||||
echo "\t\t\t<td class=\"actions\">\n";
|
||||
echo "\t\t\t\t<?php echo \$this->Html->link(__('View'), array('controller' => '{$details['controller']}', 'action' => 'view', \${$otherSingularVar}['{$details['primaryKey']}'])); ?>\n";
|
||||
echo "\t\t\t\t<?php echo \$this->Html->link(__('Edit'), array('controller' => '{$details['controller']}', 'action' => 'edit', \${$otherSingularVar}['{$details['primaryKey']}'])); ?>\n";
|
||||
echo "\t\t\t\t<?php echo \$this->Form->postLink(__('Delete'), array('controller' => '{$details['controller']}', 'action' => 'delete', \${$otherSingularVar}['{$details['primaryKey']}']), array(), __('Are you sure you want to delete # %s?', \${$otherSingularVar}['{$details['primaryKey']}'])); ?>\n";
|
||||
echo "\t\t\t</td>\n";
|
||||
echo "\t\t</tr>\n";
|
||||
|
||||
echo "\t<?php endforeach; ?>\n";
|
||||
?>
|
||||
</table>
|
||||
<?php echo "<?php endif; ?>\n\n"; ?>
|
||||
<div class="actions">
|
||||
<ul>
|
||||
<li><?php echo "<?php echo \$this->Html->link(__('New " . Inflector::humanize(Inflector::underscore($alias)) . "'), array('controller' => '{$details['controller']}', 'action' => 'add')); ?>"; ?> </li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
5
lib/Cake/Console/Templates/skel/.htaccess
Normal file
5
lib/Cake/Console/Templates/skel/.htaccess
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine on
|
||||
RewriteRule ^$ webroot/ [L]
|
||||
RewriteRule (.*) webroot/$1 [L]
|
||||
</IfModule>
|
||||
82
lib/Cake/Console/Templates/skel/Config/Schema/db_acl.php
Normal file
82
lib/Cake/Console/Templates/skel/Config/Schema/db_acl.php
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
/**
|
||||
* This is Acl Schema file
|
||||
*
|
||||
* Use it to configure database for ACL
|
||||
*
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.Config.Schema
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* Using the Schema command line utility
|
||||
* cake schema run create DbAcl
|
||||
*
|
||||
*/
|
||||
class DbAclSchema extends CakeSchema {
|
||||
|
||||
/**
|
||||
* Before event.
|
||||
*
|
||||
* @param array $event The event data.
|
||||
* @return bool success
|
||||
*/
|
||||
public function before($event = array()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* After event.
|
||||
*
|
||||
* @param array $event The event data.
|
||||
* @return void
|
||||
*/
|
||||
public function after($event = array()) {
|
||||
}
|
||||
|
||||
/**
|
||||
* ACO - Access Control Object - Something that is wanted
|
||||
*/
|
||||
public $acos = array(
|
||||
'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => 10, 'key' => 'primary'),
|
||||
'parent_id' => array('type' => 'integer', 'null' => true, 'default' => null, 'length' => 10),
|
||||
'model' => array('type' => 'string', 'null' => true),
|
||||
'foreign_key' => array('type' => 'integer', 'null' => true, 'default' => null, 'length' => 10),
|
||||
'alias' => array('type' => 'string', 'null' => true),
|
||||
'lft' => array('type' => 'integer', 'null' => true, 'default' => null, 'length' => 10),
|
||||
'rght' => array('type' => 'integer', 'null' => true, 'default' => null, 'length' => 10),
|
||||
'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
|
||||
);
|
||||
|
||||
/**
|
||||
* ARO - Access Request Object - Something that wants something
|
||||
*/
|
||||
public $aros = array(
|
||||
'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => 10, 'key' => 'primary'),
|
||||
'parent_id' => array('type' => 'integer', 'null' => true, 'default' => null, 'length' => 10),
|
||||
'model' => array('type' => 'string', 'null' => true),
|
||||
'foreign_key' => array('type' => 'integer', 'null' => true, 'default' => null, 'length' => 10),
|
||||
'alias' => array('type' => 'string', 'null' => true),
|
||||
'lft' => array('type' => 'integer', 'null' => true, 'default' => null, 'length' => 10),
|
||||
'rght' => array('type' => 'integer', 'null' => true, 'default' => null, 'length' => 10),
|
||||
'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
|
||||
);
|
||||
|
||||
/**
|
||||
* Used by the Cake::Model:Permission class.
|
||||
* Checks if the given $aro has access to action $action in $aco.
|
||||
*/
|
||||
public $aros_acos = array(
|
||||
'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => 10, 'key' => 'primary'),
|
||||
'aro_id' => array('type' => 'integer', 'null' => false, 'length' => 10, 'key' => 'index'),
|
||||
'aco_id' => array('type' => 'integer', 'null' => false, 'length' => 10),
|
||||
'_create' => array('type' => 'string', 'null' => false, 'default' => '0', 'length' => 2),
|
||||
'_read' => array('type' => 'string', 'null' => false, 'default' => '0', 'length' => 2),
|
||||
'_update' => array('type' => 'string', 'null' => false, 'default' => '0', 'length' => 2),
|
||||
'_delete' => array('type' => 'string', 'null' => false, 'default' => '0', 'length' => 2),
|
||||
'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'ARO_ACO_KEY' => array('column' => array('aro_id', 'aco_id'), 'unique' => 1))
|
||||
);
|
||||
|
||||
}
|
||||
41
lib/Cake/Console/Templates/skel/Config/Schema/db_acl.sql
Normal file
41
lib/Cake/Console/Templates/skel/Config/Schema/db_acl.sql
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# $Id$
|
||||
#
|
||||
# Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
#
|
||||
# Licensed under The MIT License
|
||||
# For full copyright and license information, please see the LICENSE.txt
|
||||
# Redistributions of files must retain the above copyright notice.
|
||||
# MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
|
||||
CREATE TABLE acos (
|
||||
id INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
parent_id INTEGER(10) DEFAULT NULL,
|
||||
model VARCHAR(255) DEFAULT '',
|
||||
foreign_key INTEGER(10) UNSIGNED DEFAULT NULL,
|
||||
alias VARCHAR(255) DEFAULT '',
|
||||
lft INTEGER(10) DEFAULT NULL,
|
||||
rght INTEGER(10) DEFAULT NULL,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE aros_acos (
|
||||
id INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
aro_id INTEGER(10) UNSIGNED NOT NULL,
|
||||
aco_id INTEGER(10) UNSIGNED NOT NULL,
|
||||
_create CHAR(2) NOT NULL DEFAULT 0,
|
||||
_read CHAR(2) NOT NULL DEFAULT 0,
|
||||
_update CHAR(2) NOT NULL DEFAULT 0,
|
||||
_delete CHAR(2) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY(id)
|
||||
);
|
||||
|
||||
CREATE TABLE aros (
|
||||
id INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
parent_id INTEGER(10) DEFAULT NULL,
|
||||
model VARCHAR(255) DEFAULT '',
|
||||
foreign_key INTEGER(10) UNSIGNED DEFAULT NULL,
|
||||
alias VARCHAR(255) DEFAULT '',
|
||||
lft INTEGER(10) DEFAULT NULL,
|
||||
rght INTEGER(10) DEFAULT NULL,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
62
lib/Cake/Console/Templates/skel/Config/Schema/i18n.php
Normal file
62
lib/Cake/Console/Templates/skel/Config/Schema/i18n.php
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
/**
|
||||
* This is i18n Schema file
|
||||
*
|
||||
* Use it to configure database for i18n
|
||||
*
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.Config.Schema
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
*/
|
||||
|
||||
/**
|
||||
* Using the Schema command line utility
|
||||
*
|
||||
* Use it to configure database for i18n
|
||||
*
|
||||
* cake schema run create i18n
|
||||
*/
|
||||
class I18nSchema extends CakeSchema {
|
||||
|
||||
/**
|
||||
* The name property
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name = 'i18n';
|
||||
|
||||
/**
|
||||
* Before event.
|
||||
*
|
||||
* @param array $event The event data.
|
||||
* @return bool success
|
||||
*/
|
||||
public function before($event = array()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* After event.
|
||||
*
|
||||
* @param array $event The event data.
|
||||
* @return void
|
||||
*/
|
||||
public function after($event = array()) {
|
||||
}
|
||||
|
||||
/**
|
||||
* The i18n table property
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $i18n = array(
|
||||
'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => 10, 'key' => 'primary'),
|
||||
'locale' => array('type' => 'string', 'null' => false, 'length' => 6, 'key' => 'index'),
|
||||
'model' => array('type' => 'string', 'null' => false, 'key' => 'index'),
|
||||
'foreign_key' => array('type' => 'integer', 'null' => false, 'length' => 10, 'key' => 'index'),
|
||||
'field' => array('type' => 'string', 'null' => false, 'key' => 'index'),
|
||||
'content' => array('type' => 'text', 'null' => true, 'default' => null),
|
||||
'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'locale' => array('column' => 'locale', 'unique' => 0), 'model' => array('column' => 'model', 'unique' => 0), 'row_id' => array('column' => 'foreign_key', 'unique' => 0), 'field' => array('column' => 'field', 'unique' => 0))
|
||||
);
|
||||
|
||||
}
|
||||
27
lib/Cake/Console/Templates/skel/Config/Schema/i18n.sql
Normal file
27
lib/Cake/Console/Templates/skel/Config/Schema/i18n.sql
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# $Id$
|
||||
#
|
||||
# Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
#
|
||||
# Licensed under The MIT License
|
||||
# For full copyright and license information, please see the LICENSE.txt
|
||||
# Redistributions of files must retain the above copyright notice.
|
||||
# MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
|
||||
CREATE TABLE i18n (
|
||||
id int(10) NOT NULL auto_increment,
|
||||
locale varchar(6) NOT NULL,
|
||||
model varchar(255) NOT NULL,
|
||||
foreign_key int(10) NOT NULL,
|
||||
field varchar(255) NOT NULL,
|
||||
content mediumtext,
|
||||
PRIMARY KEY (id),
|
||||
# UNIQUE INDEX I18N_LOCALE_FIELD(locale, model, foreign_key, field),
|
||||
# INDEX I18N_LOCALE_ROW(locale, model, foreign_key),
|
||||
# INDEX I18N_LOCALE_MODEL(locale, model),
|
||||
# INDEX I18N_FIELD(model, foreign_key, field),
|
||||
# INDEX I18N_ROW(model, foreign_key),
|
||||
INDEX locale (locale),
|
||||
INDEX model (model),
|
||||
INDEX row_id (foreign_key),
|
||||
INDEX field (field)
|
||||
);
|
||||
57
lib/Cake/Console/Templates/skel/Config/Schema/sessions.php
Normal file
57
lib/Cake/Console/Templates/skel/Config/Schema/sessions.php
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
/**
|
||||
* This is Sessions Schema file
|
||||
*
|
||||
* Use it to configure database for Sessions
|
||||
*
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.Config.Schema
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
*/
|
||||
|
||||
/**
|
||||
* Using the Schema command line utility
|
||||
* cake schema run create Sessions
|
||||
*
|
||||
*/
|
||||
class SessionsSchema extends CakeSchema {
|
||||
|
||||
/**
|
||||
* Name property
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name = 'Sessions';
|
||||
|
||||
/**
|
||||
* Before event.
|
||||
*
|
||||
* @param array $event The event data.
|
||||
* @return bool Success
|
||||
*/
|
||||
public function before($event = array()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* After event.
|
||||
*
|
||||
* @param array $event The event data.
|
||||
* @return void
|
||||
*/
|
||||
public function after($event = array()) {
|
||||
}
|
||||
|
||||
/**
|
||||
* cake_sessions table definition
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $cake_sessions = array(
|
||||
'id' => array('type' => 'string', 'null' => false, 'key' => 'primary'),
|
||||
'data' => array('type' => 'text', 'null' => true, 'default' => null),
|
||||
'expires' => array('type' => 'integer', 'null' => true, 'default' => null),
|
||||
'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
|
||||
);
|
||||
|
||||
}
|
||||
17
lib/Cake/Console/Templates/skel/Config/Schema/sessions.sql
Normal file
17
lib/Cake/Console/Templates/skel/Config/Schema/sessions.sql
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# $Id$
|
||||
#
|
||||
# Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
# 1785 E. Sahara Avenue, Suite 490-204
|
||||
# Las Vegas, Nevada 89104
|
||||
#
|
||||
# Licensed under The MIT License
|
||||
# For full copyright and license information, please see the LICENSE.txt
|
||||
# Redistributions of files must retain the above copyright notice.
|
||||
# MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
|
||||
CREATE TABLE cake_sessions (
|
||||
id varchar(255) NOT NULL default '',
|
||||
data text,
|
||||
expires int(11) default NULL,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
57
lib/Cake/Console/Templates/skel/Config/acl.ini.php
Normal file
57
lib/Cake/Console/Templates/skel/Config/acl.ini.php
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
;<?php exit() ?>
|
||||
;/**
|
||||
; * ACL Configuration
|
||||
; *
|
||||
; * @link http://cakephp.org CakePHP(tm) Project
|
||||
; * @package app.Config
|
||||
; * @since CakePHP(tm) v 0.10.0.1076
|
||||
; */
|
||||
|
||||
; acl.ini.php - CakePHP ACL Configuration
|
||||
; ---------------------------------------------------------------------
|
||||
; Use this file to specify user permissions.
|
||||
; aco = access control object (something in your application)
|
||||
; aro = access request object (something requesting access)
|
||||
;
|
||||
; User records are added as follows:
|
||||
;
|
||||
; [uid]
|
||||
; groups = group1, group2, group3
|
||||
; allow = aco1, aco2, aco3
|
||||
; deny = aco4, aco5, aco6
|
||||
;
|
||||
; Group records are added in a similar manner:
|
||||
;
|
||||
; [gid]
|
||||
; allow = aco1, aco2, aco3
|
||||
; deny = aco4, aco5, aco6
|
||||
;
|
||||
; The allow, deny, and groups sections are all optional.
|
||||
; NOTE: groups names *cannot* ever be the same as usernames!
|
||||
;
|
||||
; ACL permissions are checked in the following order:
|
||||
; 1. Check for user denies (and DENY if specified)
|
||||
; 2. Check for user allows (and ALLOW if specified)
|
||||
; 3. Gather user's groups
|
||||
; 4. Check group denies (and DENY if specified)
|
||||
; 5. Check group allows (and ALLOW if specified)
|
||||
; 6. If no aro, aco, or group information is found, DENY
|
||||
;
|
||||
; ---------------------------------------------------------------------
|
||||
|
||||
;-------------------------------------
|
||||
;Users
|
||||
;-------------------------------------
|
||||
|
||||
[username-goes-here]
|
||||
groups = group1, group2
|
||||
deny = aco1, aco2
|
||||
allow = aco3, aco4
|
||||
|
||||
;-------------------------------------
|
||||
;Groups
|
||||
;-------------------------------------
|
||||
|
||||
[groupname-goes-here]
|
||||
deny = aco5, aco6
|
||||
allow = aco7, aco8
|
||||
124
lib/Cake/Console/Templates/skel/Config/acl.php
Normal file
124
lib/Cake/Console/Templates/skel/Config/acl.php
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
<?php
|
||||
/**
|
||||
* This is the PHP base ACL configuration file.
|
||||
*
|
||||
* Use it to configure access control of your CakePHP application.
|
||||
*
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.Config
|
||||
* @since CakePHP(tm) v 2.1
|
||||
*/
|
||||
|
||||
/**
|
||||
* Example
|
||||
* -------
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
* 1. In your application you created a User model with the following properties:
|
||||
* username, group_id, password, email, firstname, lastname and so on.
|
||||
* 2. You configured AuthComponent to authorize actions via
|
||||
* $this->Auth->authorize = array('Actions' => array('actionPath' => 'controllers/'),...)
|
||||
*
|
||||
* Now, when a user (i.e. jeff) authenticates successfully and requests a controller action (i.e. /invoices/delete)
|
||||
* that is not allowed by default (e.g. via $this->Auth->allow('edit') in the Invoices controller) then AuthComponent
|
||||
* will ask the configured ACL interface if access is granted. Under the assumptions 1. and 2. this will be
|
||||
* done via a call to Acl->check() with
|
||||
*
|
||||
* array('User' => array('username' => 'jeff', 'group_id' => 4, ...))
|
||||
*
|
||||
* as ARO and
|
||||
*
|
||||
* '/controllers/invoices/delete'
|
||||
*
|
||||
* as ACO.
|
||||
*
|
||||
* If the configured map looks like
|
||||
*
|
||||
* $config['map'] = array(
|
||||
* 'User' => 'User/username',
|
||||
* 'Role' => 'User/group_id',
|
||||
* );
|
||||
*
|
||||
* then PhpAcl will lookup if we defined a role like User/jeff. If that role is not found, PhpAcl will try to
|
||||
* find a definition for Role/4. If the definition isn't found then a default role (Role/default) will be used to
|
||||
* check rules for the given ACO. The search can be expanded by defining aliases in the alias configuration.
|
||||
* E.g. if you want to use a more readable name than Role/4 in your definitions you can define an alias like
|
||||
*
|
||||
* $config['alias'] = array(
|
||||
* 'Role/4' => 'Role/editor',
|
||||
* );
|
||||
*
|
||||
* In the roles configuration you can define roles on the lhs and inherited roles on the rhs:
|
||||
*
|
||||
* $config['roles'] = array(
|
||||
* 'Role/admin' => null,
|
||||
* 'Role/accountant' => null,
|
||||
* 'Role/editor' => null,
|
||||
* 'Role/manager' => 'Role/editor, Role/accountant',
|
||||
* 'User/jeff' => 'Role/manager',
|
||||
* );
|
||||
*
|
||||
* In this example manager inherits all rules from editor and accountant. Role/admin doesn't inherit from any role.
|
||||
* Lets define some rules:
|
||||
*
|
||||
* $config['rules'] = array(
|
||||
* 'allow' => array(
|
||||
* '*' => 'Role/admin',
|
||||
* 'controllers/users/(dashboard|profile)' => 'Role/default',
|
||||
* 'controllers/invoices/*' => 'Role/accountant',
|
||||
* 'controllers/articles/*' => 'Role/editor',
|
||||
* 'controllers/users/*' => 'Role/manager',
|
||||
* 'controllers/invoices/delete' => 'Role/manager',
|
||||
* ),
|
||||
* 'deny' => array(
|
||||
* 'controllers/invoices/delete' => 'Role/accountant, User/jeff',
|
||||
* 'controllers/articles/(delete|publish)' => 'Role/editor',
|
||||
* ),
|
||||
* );
|
||||
*
|
||||
* Ok, so as jeff inherits from Role/manager he's matched every rule that references User/jeff, Role/manager,
|
||||
* Role/editor, Role/accountant and Role/default. However, for jeff, rules for User/jeff are more specific than
|
||||
* rules for Role/manager, rules for Role/manager are more specific than rules for Role/editor and so on.
|
||||
* This is important when allow and deny rules match for a role. E.g. Role/accountant is allowed
|
||||
* controllers/invoices/* but at the same time controllers/invoices/delete is denied. But there is a more
|
||||
* specific rule defined for Role/manager which is allowed controllers/invoices/delete. However, the most specific
|
||||
* rule denies access to the delete action explicitly for User/jeff, so he'll be denied access to the resource.
|
||||
*
|
||||
* If we would remove the role definition for User/jeff, then jeff would be granted access as he would be resolved
|
||||
* to Role/manager and Role/manager has an allow rule.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The role map defines how to resolve the user record from your application
|
||||
* to the roles you defined in the roles configuration.
|
||||
*/
|
||||
$config['map'] = array(
|
||||
'User' => 'User/username',
|
||||
'Role' => 'User/group_id',
|
||||
);
|
||||
|
||||
/**
|
||||
* define aliases to map your model information to
|
||||
* the roles defined in your role configuration.
|
||||
*/
|
||||
$config['alias'] = array(
|
||||
'Role/4' => 'Role/editor',
|
||||
);
|
||||
|
||||
/**
|
||||
* role configuration
|
||||
*/
|
||||
$config['roles'] = array(
|
||||
'Role/admin' => null,
|
||||
);
|
||||
|
||||
/**
|
||||
* rule configuration
|
||||
*/
|
||||
$config['rules'] = array(
|
||||
'allow' => array(
|
||||
'*' => 'Role/admin',
|
||||
),
|
||||
'deny' => array(),
|
||||
);
|
||||
98
lib/Cake/Console/Templates/skel/Config/bootstrap.php
Normal file
98
lib/Cake/Console/Templates/skel/Config/bootstrap.php
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is loaded automatically by the app/webroot/index.php file after core.php
|
||||
*
|
||||
* This file should load/create any application wide configuration settings, such as
|
||||
* Caching, Logging, loading additional configuration files.
|
||||
*
|
||||
* You should also use this file to include any files that provide global functions/constants
|
||||
* that your application uses.
|
||||
*
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.Config
|
||||
* @since CakePHP(tm) v 0.10.8.2117
|
||||
*/
|
||||
|
||||
// Setup a 'default' cache configuration for use in the application.
|
||||
Cache::config('default', array('engine' => 'File'));
|
||||
|
||||
/**
|
||||
* The settings below can be used to set additional paths to models, views and controllers.
|
||||
*
|
||||
* App::build(array(
|
||||
* 'Model' => array('/path/to/models/', '/next/path/to/models/'),
|
||||
* 'Model/Behavior' => array('/path/to/behaviors/', '/next/path/to/behaviors/'),
|
||||
* 'Model/Datasource' => array('/path/to/datasources/', '/next/path/to/datasources/'),
|
||||
* 'Model/Datasource/Database' => array('/path/to/databases/', '/next/path/to/database/'),
|
||||
* 'Model/Datasource/Session' => array('/path/to/sessions/', '/next/path/to/sessions/'),
|
||||
* 'Controller' => array('/path/to/controllers/', '/next/path/to/controllers/'),
|
||||
* 'Controller/Component' => array('/path/to/components/', '/next/path/to/components/'),
|
||||
* 'Controller/Component/Auth' => array('/path/to/auths/', '/next/path/to/auths/'),
|
||||
* 'Controller/Component/Acl' => array('/path/to/acls/', '/next/path/to/acls/'),
|
||||
* 'View' => array('/path/to/views/', '/next/path/to/views/'),
|
||||
* 'View/Helper' => array('/path/to/helpers/', '/next/path/to/helpers/'),
|
||||
* 'Console' => array('/path/to/consoles/', '/next/path/to/consoles/'),
|
||||
* 'Console/Command' => array('/path/to/commands/', '/next/path/to/commands/'),
|
||||
* 'Console/Command/Task' => array('/path/to/tasks/', '/next/path/to/tasks/'),
|
||||
* 'Lib' => array('/path/to/libs/', '/next/path/to/libs/'),
|
||||
* 'Locale' => array('/path/to/locales/', '/next/path/to/locales/'),
|
||||
* 'Vendor' => array('/path/to/vendors/', '/next/path/to/vendors/'),
|
||||
* 'Plugin' => array('/path/to/plugins/', '/next/path/to/plugins/'),
|
||||
* ));
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Custom Inflector rules can be set to correctly pluralize or singularize table, model, controller names or whatever other
|
||||
* string is passed to the inflection functions
|
||||
*
|
||||
* Inflector::rules('singular', array('rules' => array(), 'irregular' => array(), 'uninflected' => array()));
|
||||
* Inflector::rules('plural', array('rules' => array(), 'irregular' => array(), 'uninflected' => array()));
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Plugins need to be loaded manually, you can either load them one by one or all of them in a single call
|
||||
* Uncomment one of the lines below, as you need. Make sure you read the documentation on CakePlugin to use more
|
||||
* advanced ways of loading plugins
|
||||
*
|
||||
* CakePlugin::loadAll(); // Loads all plugins at once
|
||||
* CakePlugin::load('DebugKit'); //Loads a single plugin named DebugKit
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* You can attach event listeners to the request lifecycle as Dispatcher Filter . By default CakePHP bundles two filters:
|
||||
*
|
||||
* - AssetDispatcher filter will serve your asset files (css, images, js, etc) from your themes and plugins
|
||||
* - CacheDispatcher filter will read the Cache.check configure variable and try to serve cached content generated from controllers
|
||||
*
|
||||
* Feel free to remove or add filters as you see fit for your application. A few examples:
|
||||
*
|
||||
* Configure::write('Dispatcher.filters', array(
|
||||
* 'MyCacheFilter', // will use MyCacheFilter class from the Routing/Filter package in your app.
|
||||
* 'MyPlugin.MyFilter', // will use MyFilter class from the Routing/Filter package in MyPlugin plugin.
|
||||
* array('callable' => $aFunction, 'on' => 'before', 'priority' => 9), // A valid PHP callback type to be called on beforeDispatch
|
||||
* array('callable' => $anotherMethod, 'on' => 'after'), // A valid PHP callback type to be called on afterDispatch
|
||||
*
|
||||
* ));
|
||||
*/
|
||||
Configure::write('Dispatcher.filters', array(
|
||||
'AssetDispatcher',
|
||||
'CacheDispatcher'
|
||||
));
|
||||
|
||||
/**
|
||||
* Configures default file logging options
|
||||
*/
|
||||
App::uses('CakeLog', 'Log');
|
||||
CakeLog::config('debug', array(
|
||||
'engine' => 'File',
|
||||
'types' => array('notice', 'info', 'debug'),
|
||||
'file' => 'debug',
|
||||
));
|
||||
CakeLog::config('error', array(
|
||||
'engine' => 'File',
|
||||
'types' => array('warning', 'error', 'critical', 'alert', 'emergency'),
|
||||
'file' => 'error',
|
||||
));
|
||||
367
lib/Cake/Console/Templates/skel/Config/core.php
Normal file
367
lib/Cake/Console/Templates/skel/Config/core.php
Normal file
|
|
@ -0,0 +1,367 @@
|
|||
<?php
|
||||
/**
|
||||
* This is core configuration file.
|
||||
*
|
||||
* Use it to configure core behavior of Cake.
|
||||
*
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.Config
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
*/
|
||||
|
||||
/**
|
||||
* CakePHP Debug Level:
|
||||
*
|
||||
* Production Mode:
|
||||
* 0: No error messages, errors, or warnings shown. Flash messages redirect.
|
||||
*
|
||||
* Development Mode:
|
||||
* 1: Errors and warnings shown, model caches refreshed, flash messages halted.
|
||||
* 2: As in 1, but also with full debug messages and SQL output.
|
||||
*
|
||||
* In production mode, flash messages redirect after a time interval.
|
||||
* In development mode, you need to click the flash message to continue.
|
||||
*/
|
||||
Configure::write('debug', 2);
|
||||
|
||||
/**
|
||||
* Configure the Error handler used to handle errors for your application. By default
|
||||
* ErrorHandler::handleError() is used. It will display errors using Debugger, when debug > 0
|
||||
* and log errors with CakeLog when debug = 0.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `handler` - callback - The callback to handle errors. You can set this to any callable type,
|
||||
* including anonymous functions.
|
||||
* Make sure you add App::uses('MyHandler', 'Error'); when using a custom handler class
|
||||
* - `level` - integer - The level of errors you are interested in capturing.
|
||||
* - `trace` - boolean - Include stack traces for errors in log files.
|
||||
*
|
||||
* @see ErrorHandler for more information on error handling and configuration.
|
||||
*/
|
||||
Configure::write('Error', array(
|
||||
'handler' => 'ErrorHandler::handleError',
|
||||
'level' => E_ALL & ~E_DEPRECATED,
|
||||
'trace' => true
|
||||
));
|
||||
|
||||
/**
|
||||
* Configure the Exception handler used for uncaught exceptions. By default,
|
||||
* ErrorHandler::handleException() is used. It will display a HTML page for the exception, and
|
||||
* while debug > 0, framework errors like Missing Controller will be displayed. When debug = 0,
|
||||
* framework errors will be coerced into generic HTTP errors.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `handler` - callback - The callback to handle exceptions. You can set this to any callback type,
|
||||
* including anonymous functions.
|
||||
* Make sure you add App::uses('MyHandler', 'Error'); when using a custom handler class
|
||||
* - `renderer` - string - The class responsible for rendering uncaught exceptions. If you choose a custom class you
|
||||
* should place the file for that class in app/Lib/Error. This class needs to implement a render method.
|
||||
* - `log` - boolean - Should Exceptions be logged?
|
||||
* - `skipLog` - array - list of exceptions to skip for logging. Exceptions that
|
||||
* extend one of the listed exceptions will also be skipped for logging.
|
||||
* Example: `'skipLog' => array('NotFoundException', 'UnauthorizedException')`
|
||||
*
|
||||
* @see ErrorHandler for more information on exception handling and configuration.
|
||||
*/
|
||||
Configure::write('Exception', array(
|
||||
'handler' => 'ErrorHandler::handleException',
|
||||
'renderer' => 'ExceptionRenderer',
|
||||
'log' => true
|
||||
));
|
||||
|
||||
/**
|
||||
* Application wide charset encoding
|
||||
*/
|
||||
Configure::write('App.encoding', 'UTF-8');
|
||||
|
||||
/**
|
||||
* To configure CakePHP *not* to use mod_rewrite and to
|
||||
* use CakePHP pretty URLs, remove these .htaccess
|
||||
* files:
|
||||
*
|
||||
* /.htaccess
|
||||
* /app/.htaccess
|
||||
* /app/webroot/.htaccess
|
||||
*
|
||||
* And uncomment the App.baseUrl below. But keep in mind
|
||||
* that plugin assets such as images, CSS and JavaScript files
|
||||
* will not work without URL rewriting!
|
||||
* To work around this issue you should either symlink or copy
|
||||
* the plugin assets into you app's webroot directory. This is
|
||||
* recommended even when you are using mod_rewrite. Handling static
|
||||
* assets through the Dispatcher is incredibly inefficient and
|
||||
* included primarily as a development convenience - and
|
||||
* thus not recommended for production applications.
|
||||
*/
|
||||
//Configure::write('App.baseUrl', env('SCRIPT_NAME'));
|
||||
|
||||
/**
|
||||
* To configure CakePHP to use a particular domain URL
|
||||
* for any URL generation inside the application, set the following
|
||||
* configuration variable to the http(s) address to your domain. This
|
||||
* will override the automatic detection of full base URL and can be
|
||||
* useful when generating links from the CLI (e.g. sending emails)
|
||||
*/
|
||||
//Configure::write('App.fullBaseUrl', 'http://example.com');
|
||||
|
||||
/**
|
||||
* Web path to the public images directory under webroot.
|
||||
* If not set defaults to 'img/'
|
||||
*/
|
||||
//Configure::write('App.imageBaseUrl', 'img/');
|
||||
|
||||
/**
|
||||
* Web path to the CSS files directory under webroot.
|
||||
* If not set defaults to 'css/'
|
||||
*/
|
||||
//Configure::write('App.cssBaseUrl', 'css/');
|
||||
|
||||
/**
|
||||
* Web path to the js files directory under webroot.
|
||||
* If not set defaults to 'js/'
|
||||
*/
|
||||
//Configure::write('App.jsBaseUrl', 'js/');
|
||||
|
||||
/**
|
||||
* Uncomment the define below to use CakePHP prefix routes.
|
||||
*
|
||||
* The value of the define determines the names of the routes
|
||||
* and their associated controller actions:
|
||||
*
|
||||
* Set to an array of prefixes you want to use in your application. Use for
|
||||
* admin or other prefixed routes.
|
||||
*
|
||||
* Routing.prefixes = array('admin', 'manager');
|
||||
*
|
||||
* Enables:
|
||||
* `admin_index()` and `/admin/controller/index`
|
||||
* `manager_index()` and `/manager/controller/index`
|
||||
*
|
||||
*/
|
||||
//Configure::write('Routing.prefixes', array('admin'));
|
||||
|
||||
/**
|
||||
* Turn off all caching application-wide.
|
||||
*
|
||||
*/
|
||||
//Configure::write('Cache.disable', true);
|
||||
|
||||
/**
|
||||
* Enable cache checking.
|
||||
*
|
||||
* If set to true, for view caching you must still use the controller
|
||||
* public $cacheAction inside your controllers to define caching settings.
|
||||
* You can either set it controller-wide by setting public $cacheAction = true,
|
||||
* or in each action using $this->cacheAction = true.
|
||||
*
|
||||
*/
|
||||
//Configure::write('Cache.check', true);
|
||||
|
||||
/**
|
||||
* Enable cache view prefixes.
|
||||
*
|
||||
* If set it will be prepended to the cache name for view file caching. This is
|
||||
* helpful if you deploy the same application via multiple subdomains and languages,
|
||||
* for instance. Each version can then have its own view cache namespace.
|
||||
* Note: The final cache file name will then be `prefix_cachefilename`.
|
||||
*/
|
||||
//Configure::write('Cache.viewPrefix', 'prefix');
|
||||
|
||||
/**
|
||||
* Session configuration.
|
||||
*
|
||||
* Contains an array of settings to use for session configuration. The defaults key is
|
||||
* used to define a default preset to use for sessions, any settings declared here will override
|
||||
* the settings of the default config.
|
||||
*
|
||||
* ## Options
|
||||
*
|
||||
* - `Session.cookie` - The name of the cookie to use. Defaults to 'CAKEPHP'
|
||||
* - `Session.timeout` - The number of minutes you want sessions to live for. This timeout is handled by CakePHP
|
||||
* - `Session.cookieTimeout` - The number of minutes you want session cookies to live for.
|
||||
* - `Session.checkAgent` - Do you want the user agent to be checked when starting sessions? You might want to set the
|
||||
* value to false, when dealing with older versions of IE, Chrome Frame or certain web-browsing devices and AJAX
|
||||
* - `Session.defaults` - The default configuration set to use as a basis for your session.
|
||||
* There are four builtins: php, cake, cache, database.
|
||||
* - `Session.handler` - Can be used to enable a custom session handler. Expects an array of callables,
|
||||
* that can be used with `session_save_handler`. Using this option will automatically add `session.save_handler`
|
||||
* to the ini array.
|
||||
* - `Session.autoRegenerate` - Enabling this setting, turns on automatic renewal of sessions, and
|
||||
* sessionids that change frequently. See CakeSession::$requestCountdown.
|
||||
* - `Session.ini` - An associative array of additional ini values to set.
|
||||
*
|
||||
* The built in defaults are:
|
||||
*
|
||||
* - 'php' - Uses settings defined in your php.ini.
|
||||
* - 'cake' - Saves session files in CakePHP's /tmp directory.
|
||||
* - 'database' - Uses CakePHP's database sessions.
|
||||
* - 'cache' - Use the Cache class to save sessions.
|
||||
*
|
||||
* To define a custom session handler, save it at /app/Model/Datasource/Session/<name>.php.
|
||||
* Make sure the class implements `CakeSessionHandlerInterface` and set Session.handler to <name>
|
||||
*
|
||||
* To use database sessions, run the app/Config/Schema/sessions.php schema using
|
||||
* the cake shell command: cake schema create Sessions
|
||||
*
|
||||
*/
|
||||
Configure::write('Session', array(
|
||||
'defaults' => 'php'
|
||||
));
|
||||
|
||||
/**
|
||||
* A random string used in security hashing methods.
|
||||
*/
|
||||
Configure::write('Security.salt', 'DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi');
|
||||
|
||||
/**
|
||||
* A random numeric string (digits only) used to encrypt/decrypt strings.
|
||||
*/
|
||||
Configure::write('Security.cipherSeed', '76859309657453542496749683645');
|
||||
|
||||
/**
|
||||
* Apply timestamps with the last modified time to static assets (js, css, images).
|
||||
* Will append a query string parameter containing the time the file was modified. This is
|
||||
* useful for invalidating browser caches.
|
||||
*
|
||||
* Set to `true` to apply timestamps when debug > 0. Set to 'force' to always enable
|
||||
* timestamping regardless of debug value.
|
||||
*/
|
||||
//Configure::write('Asset.timestamp', true);
|
||||
|
||||
/**
|
||||
* Compress CSS output by removing comments, whitespace, repeating tags, etc.
|
||||
* This requires a/var/cache directory to be writable by the web server for caching.
|
||||
* and /vendors/csspp/csspp.php
|
||||
*
|
||||
* To use, prefix the CSS link URL with '/ccss/' instead of '/css/' or use HtmlHelper::css().
|
||||
*/
|
||||
//Configure::write('Asset.filter.css', 'css.php');
|
||||
|
||||
/**
|
||||
* Plug in your own custom JavaScript compressor by dropping a script in your webroot to handle the
|
||||
* output, and setting the config below to the name of the script.
|
||||
*
|
||||
* To use, prefix your JavaScript link URLs with '/cjs/' instead of '/js/' or use JsHelper::link().
|
||||
*/
|
||||
//Configure::write('Asset.filter.js', 'custom_javascript_output_filter.php');
|
||||
|
||||
/**
|
||||
* The class name and database used in CakePHP's
|
||||
* access control lists.
|
||||
*/
|
||||
Configure::write('Acl.classname', 'DbAcl');
|
||||
Configure::write('Acl.database', 'default');
|
||||
|
||||
/**
|
||||
* Uncomment this line and correct your server timezone to fix
|
||||
* any date & time related errors.
|
||||
*/
|
||||
//date_default_timezone_set('UTC');
|
||||
|
||||
/**
|
||||
* Cache Engine Configuration
|
||||
* Default settings provided below
|
||||
*
|
||||
* File storage engine.
|
||||
*
|
||||
* Cache::config('default', array(
|
||||
* 'engine' => 'File', //[required]
|
||||
* 'duration' => 3600, //[optional]
|
||||
* 'probability' => 100, //[optional]
|
||||
* 'path' => CACHE, //[optional] use system tmp directory - remember to use absolute path
|
||||
* 'prefix' => 'cake_', //[optional] prefix every cache file with this string
|
||||
* 'lock' => false, //[optional] use file locking
|
||||
* 'serialize' => true, //[optional]
|
||||
* 'mask' => 0664, //[optional]
|
||||
* ));
|
||||
*
|
||||
* APC (http://pecl.php.net/package/APC)
|
||||
*
|
||||
* Cache::config('default', array(
|
||||
* 'engine' => 'Apc', //[required]
|
||||
* 'duration' => 3600, //[optional]
|
||||
* 'probability' => 100, //[optional]
|
||||
* 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string
|
||||
* ));
|
||||
*
|
||||
* Xcache (http://xcache.lighttpd.net/)
|
||||
*
|
||||
* Cache::config('default', array(
|
||||
* 'engine' => 'Xcache', //[required]
|
||||
* 'duration' => 3600, //[optional]
|
||||
* 'probability' => 100, //[optional]
|
||||
* 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string
|
||||
* 'user' => 'user', //user from xcache.admin.user settings
|
||||
* 'password' => 'password', //plaintext password (xcache.admin.pass)
|
||||
* ));
|
||||
*
|
||||
* Memcache (http://www.danga.com/memcached/)
|
||||
*
|
||||
* Cache::config('default', array(
|
||||
* 'engine' => 'Memcache', //[required]
|
||||
* 'duration' => 3600, //[optional]
|
||||
* 'probability' => 100, //[optional]
|
||||
* 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string
|
||||
* 'servers' => array(
|
||||
* '127.0.0.1:11211' // localhost, default port 11211
|
||||
* ), //[optional]
|
||||
* 'persistent' => true, // [optional] set this to false for non-persistent connections
|
||||
* 'compress' => false, // [optional] compress data in Memcache (slower, but uses less memory)
|
||||
* ));
|
||||
*
|
||||
* Wincache (http://php.net/wincache)
|
||||
*
|
||||
* Cache::config('default', array(
|
||||
* 'engine' => 'Wincache', //[required]
|
||||
* 'duration' => 3600, //[optional]
|
||||
* 'probability' => 100, //[optional]
|
||||
* 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string
|
||||
* ));
|
||||
*/
|
||||
|
||||
/**
|
||||
* Configure the cache handlers that CakePHP will use for internal
|
||||
* metadata like class maps, and model schema.
|
||||
*
|
||||
* By default File is used, but for improved performance you should use APC.
|
||||
*
|
||||
* Note: 'default' and other application caches should be configured in app/Config/bootstrap.php.
|
||||
* Please check the comments in bootstrap.php for more info on the cache engines available
|
||||
* and their settings.
|
||||
*/
|
||||
$engine = 'File';
|
||||
|
||||
// In development mode, caches should expire quickly.
|
||||
$duration = '+999 days';
|
||||
if (Configure::read('debug') > 0) {
|
||||
$duration = '+10 seconds';
|
||||
}
|
||||
|
||||
// Prefix each application on the same server with a different string, to avoid Memcache and APC conflicts.
|
||||
$prefix = 'myapp_';
|
||||
|
||||
/**
|
||||
* Configure the cache used for general framework caching. Path information,
|
||||
* object listings, and translation cache files are stored with this configuration.
|
||||
*/
|
||||
Cache::config('_cake_core_', array(
|
||||
'engine' => $engine,
|
||||
'prefix' => $prefix . 'cake_core_',
|
||||
'path' => CACHE . 'persistent' . DS,
|
||||
'serialize' => ($engine === 'File'),
|
||||
'duration' => $duration
|
||||
));
|
||||
|
||||
/**
|
||||
* Configure the cache for model and datasource caches. This cache configuration
|
||||
* is used to store schema descriptions, and table listings in connections.
|
||||
*/
|
||||
Cache::config('_cake_model_', array(
|
||||
'engine' => $engine,
|
||||
'prefix' => $prefix . 'cake_model_',
|
||||
'path' => CACHE . 'models' . DS,
|
||||
'serialize' => ($engine === 'File'),
|
||||
'duration' => $duration
|
||||
));
|
||||
77
lib/Cake/Console/Templates/skel/Config/database.php.default
Normal file
77
lib/Cake/Console/Templates/skel/Config/database.php.default
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.Config
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
*/
|
||||
|
||||
/**
|
||||
* Database configuration class.
|
||||
* You can specify multiple configurations for production, development and testing.
|
||||
*
|
||||
* datasource => The name of a supported datasource; valid options are as follows:
|
||||
* Database/Mysql - MySQL 4 & 5,
|
||||
* Database/Sqlite - SQLite (PHP5 only),
|
||||
* Database/Postgres - PostgreSQL 7 and higher,
|
||||
* Database/Sqlserver - Microsoft SQL Server 2005 and higher
|
||||
*
|
||||
* You can add custom database datasources (or override existing datasources) by adding the
|
||||
* appropriate file to app/Model/Datasource/Database. Datasources should be named 'MyDatasource.php',
|
||||
*
|
||||
*
|
||||
* persistent => true / false
|
||||
* Determines whether or not the database should use a persistent connection
|
||||
*
|
||||
* host =>
|
||||
* the host you connect to the database. To add a socket or port number, use 'port' => #
|
||||
*
|
||||
* prefix =>
|
||||
* Uses the given prefix for all the tables in this database. This setting can be overridden
|
||||
* on a per-table basis with the Model::$tablePrefix property.
|
||||
*
|
||||
* schema =>
|
||||
* For Postgres/Sqlserver specifies which schema you would like to use the tables in. Postgres defaults to 'public'. For Sqlserver, it defaults to empty and use
|
||||
* the connected user's default schema (typically 'dbo').
|
||||
*
|
||||
* encoding =>
|
||||
* For MySQL, Postgres specifies the character encoding to use when connecting to the
|
||||
* database. Uses database default not specified.
|
||||
*
|
||||
* unix_socket =>
|
||||
* For MySQL to connect via socket specify the `unix_socket` parameter instead of `host` and `port`
|
||||
*
|
||||
* settings =>
|
||||
* Array of key/value pairs, on connection it executes SET statements for each pair
|
||||
* For MySQL : http://dev.mysql.com/doc/refman/5.6/en/set-statement.html
|
||||
* For Postgres : http://www.postgresql.org/docs/9.2/static/sql-set.html
|
||||
* For Sql Server : http://msdn.microsoft.com/en-us/library/ms190356.aspx
|
||||
*
|
||||
* flags =>
|
||||
* A key/value array of driver specific connection options.
|
||||
*/
|
||||
class DATABASE_CONFIG {
|
||||
|
||||
public $default = array(
|
||||
'datasource' => 'Database/Mysql',
|
||||
'persistent' => false,
|
||||
'host' => 'localhost',
|
||||
'login' => 'user',
|
||||
'password' => 'password',
|
||||
'database' => 'database_name',
|
||||
'prefix' => '',
|
||||
//'encoding' => 'utf8',
|
||||
);
|
||||
|
||||
public $test = array(
|
||||
'datasource' => 'Database/Mysql',
|
||||
'persistent' => false,
|
||||
'host' => 'localhost',
|
||||
'login' => 'user',
|
||||
'password' => 'password',
|
||||
'database' => 'test_database_name',
|
||||
'prefix' => '',
|
||||
//'encoding' => 'utf8',
|
||||
);
|
||||
}
|
||||
83
lib/Cake/Console/Templates/skel/Config/email.php.default
Normal file
83
lib/Cake/Console/Templates/skel/Config/email.php.default
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
/**
|
||||
* This is email configuration file.
|
||||
*
|
||||
* Use it to configure email transports of Cake.
|
||||
*
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.Config
|
||||
* @since CakePHP(tm) v 2.0.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Email configuration class.
|
||||
* You can specify multiple configurations for production, development and testing.
|
||||
*
|
||||
* transport => The name of a supported transport; valid options are as follows:
|
||||
* Mail - Send using PHP mail function
|
||||
* Smtp - Send using SMTP
|
||||
* Debug - Do not send the email, just return the result
|
||||
*
|
||||
* You can add custom transports (or override existing transports) by adding the
|
||||
* appropriate file to app/Network/Email. Transports should be named 'YourTransport.php',
|
||||
* where 'Your' is the name of the transport.
|
||||
*
|
||||
* from =>
|
||||
* The origin email. See CakeEmail::from() about the valid values
|
||||
*
|
||||
*/
|
||||
class EmailConfig {
|
||||
|
||||
public $default = array(
|
||||
'transport' => 'Mail',
|
||||
'from' => 'you@localhost',
|
||||
//'charset' => 'utf-8',
|
||||
//'headerCharset' => 'utf-8',
|
||||
);
|
||||
|
||||
public $smtp = array(
|
||||
'transport' => 'Smtp',
|
||||
'from' => array('site@localhost' => 'My Site'),
|
||||
'host' => 'localhost',
|
||||
'port' => 25,
|
||||
'timeout' => 30,
|
||||
'username' => 'user',
|
||||
'password' => 'secret',
|
||||
'client' => null,
|
||||
'log' => false,
|
||||
//'charset' => 'utf-8',
|
||||
//'headerCharset' => 'utf-8',
|
||||
);
|
||||
|
||||
public $fast = array(
|
||||
'from' => 'you@localhost',
|
||||
'sender' => null,
|
||||
'to' => null,
|
||||
'cc' => null,
|
||||
'bcc' => null,
|
||||
'replyTo' => null,
|
||||
'readReceipt' => null,
|
||||
'returnPath' => null,
|
||||
'messageId' => true,
|
||||
'subject' => null,
|
||||
'message' => null,
|
||||
'headers' => null,
|
||||
'viewRender' => null,
|
||||
'template' => false,
|
||||
'layout' => false,
|
||||
'viewVars' => null,
|
||||
'attachments' => null,
|
||||
'emailFormat' => null,
|
||||
'transport' => 'Smtp',
|
||||
'host' => 'localhost',
|
||||
'port' => 25,
|
||||
'timeout' => 30,
|
||||
'username' => 'user',
|
||||
'password' => 'secret',
|
||||
'client' => null,
|
||||
'log' => true,
|
||||
//'charset' => 'utf-8',
|
||||
//'headerCharset' => 'utf-8',
|
||||
);
|
||||
|
||||
}
|
||||
35
lib/Cake/Console/Templates/skel/Config/routes.php
Normal file
35
lib/Cake/Console/Templates/skel/Config/routes.php
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
/**
|
||||
* Routes configuration
|
||||
*
|
||||
* In this file, you set up routes to your controllers and their actions.
|
||||
* Routes are very important mechanism that allows you to freely connect
|
||||
* different URLs to chosen controllers and their actions (functions).
|
||||
*
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.Config
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
*/
|
||||
|
||||
/**
|
||||
* Here, we are connecting '/' (base path) to controller called 'Pages',
|
||||
* its action called 'display', and we pass a param to select the view file
|
||||
* to use (in this case, /app/View/Pages/home.ctp)...
|
||||
*/
|
||||
Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
|
||||
/**
|
||||
* ...and connect the rest of 'Pages' controller's URLs.
|
||||
*/
|
||||
Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
|
||||
|
||||
/**
|
||||
* Load all plugin routes. See the CakePlugin documentation on
|
||||
* how to customize the loading of plugin routes.
|
||||
*/
|
||||
CakePlugin::routes();
|
||||
|
||||
/**
|
||||
* Load the CakePHP default routes. Only remove this if you do not want to use
|
||||
* the built-in default routes.
|
||||
*/
|
||||
require CAKE . 'Config' . DS . 'routes.php';
|
||||
21
lib/Cake/Console/Templates/skel/Console/Command/AppShell.php
Normal file
21
lib/Cake/Console/Templates/skel/Console/Command/AppShell.php
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
/**
|
||||
* AppShell file
|
||||
*
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 2.0
|
||||
*/
|
||||
|
||||
App::uses('Shell', 'Console');
|
||||
|
||||
/**
|
||||
* Application Shell
|
||||
*
|
||||
* Add your application-wide methods in the class below, your shells
|
||||
* will inherit them.
|
||||
*
|
||||
* @package app.Console.Command
|
||||
*/
|
||||
class AppShell extends Shell {
|
||||
|
||||
}
|
||||
0
lib/Cake/Console/Templates/skel/Console/Templates/empty
Normal file
0
lib/Cake/Console/Templates/skel/Console/Templates/empty
Normal file
41
lib/Cake/Console/Templates/skel/Console/cake
Normal file
41
lib/Cake/Console/Templates/skel/Console/cake
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/env bash
|
||||
################################################################################
|
||||
#
|
||||
# Bake is a shell script for running CakePHP bake script
|
||||
#
|
||||
# CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
# Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
#
|
||||
# Licensed under The MIT License
|
||||
# For full copyright and license information, please see the LICENSE.txt
|
||||
# Redistributions of files must retain the above copyright notice.
|
||||
#
|
||||
# @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
# @link http://cakephp.org CakePHP(tm) Project
|
||||
# @package app.Console
|
||||
# @since CakePHP(tm) v 1.2.0.5012
|
||||
# @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
#
|
||||
################################################################################
|
||||
|
||||
# Canonicalize by following every symlink of the given name recursively
|
||||
canonicalize() {
|
||||
NAME="$1"
|
||||
if [ -f "$NAME" ]
|
||||
then
|
||||
DIR=$(dirname -- "$NAME")
|
||||
NAME=$(cd -P "$DIR" && pwd -P)/$(basename -- "$NAME")
|
||||
fi
|
||||
while [ -h "$NAME" ]; do
|
||||
DIR=$(dirname -- "$NAME")
|
||||
SYM=$(readlink "$NAME")
|
||||
NAME=$(cd "$DIR" && cd $(dirname -- "$SYM") && pwd)/$(basename -- "$SYM")
|
||||
done
|
||||
echo "$NAME"
|
||||
}
|
||||
|
||||
CONSOLE=$(dirname -- "$(canonicalize "$0")")
|
||||
APP=$(dirname "$CONSOLE")
|
||||
|
||||
exec php -q "$CONSOLE"/cake.php -working "$APP" "$@"
|
||||
exit
|
||||
30
lib/Cake/Console/Templates/skel/Console/cake.bat
Normal file
30
lib/Cake/Console/Templates/skel/Console/cake.bat
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
::
|
||||
:: Bake is a shell script for running CakePHP bake script
|
||||
::
|
||||
:: CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
:: Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
::
|
||||
:: Licensed under The MIT License
|
||||
:: Redistributions of files must retain the above copyright notice.
|
||||
::
|
||||
:: @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
:: @link http://cakephp.org CakePHP(tm) Project
|
||||
:: @package app.Console
|
||||
:: @since CakePHP(tm) v 2.0
|
||||
::
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
:: In order for this script to work as intended, the cake\console\ folder must be in your PATH
|
||||
|
||||
@echo.
|
||||
@echo off
|
||||
|
||||
SET app=%0
|
||||
SET lib=%~dp0
|
||||
|
||||
php -q "%lib%cake.php" -working "%CD% " %*
|
||||
|
||||
echo.
|
||||
|
||||
exit /B %ERRORLEVEL%
|
||||
48
lib/Cake/Console/Templates/skel/Console/cake.php
Normal file
48
lib/Cake/Console/Templates/skel/Console/cake.php
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/php -q
|
||||
<?php
|
||||
/**
|
||||
* Command-line code generation utility to automate programmer chores.
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.Console
|
||||
* @since CakePHP(tm) v 2.0
|
||||
*/
|
||||
|
||||
if (!defined('DS')) {
|
||||
define('DS', DIRECTORY_SEPARATOR);
|
||||
}
|
||||
|
||||
$dispatcher = 'Cake' . DS . 'Console' . DS . 'ShellDispatcher.php';
|
||||
|
||||
if (function_exists('ini_set')) {
|
||||
$root = dirname(dirname(dirname(__FILE__)));
|
||||
$appDir = basename(dirname(dirname(__FILE__)));
|
||||
$install = $root . DS . 'lib';
|
||||
$composerInstall = $root . DS . $appDir . DS . 'Vendor' . DS . 'cakephp' . DS . 'cakephp' . DS . 'lib';
|
||||
|
||||
// the following lines differ from its sibling
|
||||
// /app/Console/cake.php
|
||||
if (file_exists($composerInstall . DS . $dispatcher)) {
|
||||
$install = $composerInstall;
|
||||
} elseif (!file_exists($install . DS . $dispatcher)) {
|
||||
$install = $root . PATH_SEPARATOR . __CAKE_PATH__;
|
||||
}
|
||||
|
||||
ini_set('include_path', $install . PATH_SEPARATOR . ini_get('include_path'));
|
||||
unset($root, $appDir, $install, $composerInstall);
|
||||
}
|
||||
|
||||
if (!include $dispatcher) {
|
||||
trigger_error('Could not locate CakePHP core files.', E_USER_ERROR);
|
||||
}
|
||||
unset($dispatcher);
|
||||
|
||||
return ShellDispatcher::run($argv);
|
||||
25
lib/Cake/Console/Templates/skel/Controller/AppController.php
Normal file
25
lib/Cake/Console/Templates/skel/Controller/AppController.php
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
/**
|
||||
* Application level Controller
|
||||
*
|
||||
* This file is application-wide controller file. You can put all
|
||||
* application-wide controller-related methods here.
|
||||
*
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.Controller
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
*/
|
||||
|
||||
App::uses('Controller', 'Controller');
|
||||
|
||||
/**
|
||||
* Application Controller
|
||||
*
|
||||
* Add your application-wide methods in the class below, your controllers
|
||||
* will inherit them.
|
||||
*
|
||||
* @package app.Controller
|
||||
* @link http://book.cakephp.org/2.0/en/controllers.html#the-app-controller
|
||||
*/
|
||||
class AppController extends Controller {
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
/**
|
||||
* Static content controller.
|
||||
*
|
||||
* This file will render views from views/pages/
|
||||
*
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.Controller
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
*/
|
||||
|
||||
App::uses('AppController', 'Controller');
|
||||
|
||||
/**
|
||||
* Static content controller
|
||||
*
|
||||
* Override this controller by placing a copy in controllers directory of an application
|
||||
*
|
||||
* @package app.Controller
|
||||
* @link http://book.cakephp.org/2.0/en/controllers/pages-controller.html
|
||||
*/
|
||||
class PagesController extends AppController {
|
||||
|
||||
/**
|
||||
* This controller does not use a model
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $uses = array();
|
||||
|
||||
/**
|
||||
* Displays a view
|
||||
*
|
||||
* @return void
|
||||
* @throws NotFoundException When the view file could not be found
|
||||
* or MissingViewException in debug mode.
|
||||
*/
|
||||
public function display() {
|
||||
$path = func_get_args();
|
||||
|
||||
$count = count($path);
|
||||
if (!$count) {
|
||||
return $this->redirect('/');
|
||||
}
|
||||
$page = $subpage = $title_for_layout = null;
|
||||
|
||||
if (!empty($path[0])) {
|
||||
$page = $path[0];
|
||||
}
|
||||
if (!empty($path[1])) {
|
||||
$subpage = $path[1];
|
||||
}
|
||||
if (!empty($path[$count - 1])) {
|
||||
$title_for_layout = Inflector::humanize($path[$count - 1]);
|
||||
}
|
||||
$this->set(compact('page', 'subpage', 'title_for_layout'));
|
||||
|
||||
try {
|
||||
$this->render(implode('/', $path));
|
||||
} catch (MissingViewException $e) {
|
||||
if (Configure::read('debug')) {
|
||||
throw $e;
|
||||
}
|
||||
throw new NotFoundException();
|
||||
}
|
||||
}
|
||||
}
|
||||
0
lib/Cake/Console/Templates/skel/Lib/empty
Normal file
0
lib/Cake/Console/Templates/skel/Lib/empty
Normal file
24
lib/Cake/Console/Templates/skel/Model/AppModel.php
Normal file
24
lib/Cake/Console/Templates/skel/Model/AppModel.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
/**
|
||||
* Application model for Cake.
|
||||
*
|
||||
* This file is application-wide model file. You can put all
|
||||
* application-wide model-related methods here.
|
||||
*
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.Model
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
*/
|
||||
|
||||
App::uses('Model', 'Model');
|
||||
|
||||
/**
|
||||
* Application model for Cake.
|
||||
*
|
||||
* Add your application-wide methods in the class below, your models
|
||||
* will inherit them.
|
||||
*
|
||||
* @package app.Model
|
||||
*/
|
||||
class AppModel extends Model {
|
||||
}
|
||||
0
lib/Cake/Console/Templates/skel/Model/Behavior/empty
Normal file
0
lib/Cake/Console/Templates/skel/Model/Behavior/empty
Normal file
0
lib/Cake/Console/Templates/skel/Model/Datasource/empty
Normal file
0
lib/Cake/Console/Templates/skel/Model/Datasource/empty
Normal file
0
lib/Cake/Console/Templates/skel/Plugin/empty
Normal file
0
lib/Cake/Console/Templates/skel/Plugin/empty
Normal file
31
lib/Cake/Console/Templates/skel/Test/Case/AllTestsTest.php
Normal file
31
lib/Cake/Console/Templates/skel/Test/Case/AllTestsTest.php
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
/**
|
||||
* AllTests file
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.Test.Case
|
||||
* @since CakePHP(tm) v 2.5
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
class AllTestsTest extends CakeTestSuite {
|
||||
|
||||
/**
|
||||
* Get the suite object.
|
||||
*
|
||||
* @return CakeTestSuite Suite class instance.
|
||||
*/
|
||||
public static function suite() {
|
||||
$suite = new CakeTestSuite('All application tests');
|
||||
$suite->addTestDirectoryRecursive(TESTS . 'Case');
|
||||
return $suite;
|
||||
}
|
||||
}
|
||||
0
lib/Cake/Console/Templates/skel/Test/Fixture/empty
Normal file
0
lib/Cake/Console/Templates/skel/Test/Fixture/empty
Normal file
0
lib/Cake/Console/Templates/skel/Vendor/empty
vendored
Normal file
0
lib/Cake/Console/Templates/skel/Vendor/empty
vendored
Normal file
0
lib/Cake/Console/Templates/skel/View/Elements/empty
Normal file
0
lib/Cake/Console/Templates/skel/View/Elements/empty
Normal file
23
lib/Cake/Console/Templates/skel/View/Emails/html/default.ctp
Normal file
23
lib/Cake/Console/Templates/skel/View/Emails/html/default.ctp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.View.Emails.html
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
?>
|
||||
<?php
|
||||
$content = explode("\n", $content);
|
||||
|
||||
foreach ($content as $line):
|
||||
echo '<p> ' . $line . "</p>\n";
|
||||
endforeach;
|
||||
?>
|
||||
17
lib/Cake/Console/Templates/skel/View/Emails/text/default.ctp
Normal file
17
lib/Cake/Console/Templates/skel/View/Emails/text/default.ctp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.View.Emails.text
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
?>
|
||||
<?php echo $content; ?>
|
||||
20
lib/Cake/Console/Templates/skel/View/Errors/error400.ctp
Normal file
20
lib/Cake/Console/Templates/skel/View/Errors/error400.ctp
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
/**
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.View.Errors
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
*/
|
||||
?>
|
||||
<h2><?php echo $message; ?></h2>
|
||||
<p class="error">
|
||||
<strong><?php echo __d('cake', 'Error'); ?>: </strong>
|
||||
<?php printf(
|
||||
__d('cake', 'The requested address %s was not found on this server.'),
|
||||
"<strong>'{$url}'</strong>"
|
||||
); ?>
|
||||
</p>
|
||||
<?php
|
||||
if (Configure::read('debug') > 0):
|
||||
echo $this->element('exception_stack_trace');
|
||||
endif;
|
||||
?>
|
||||
17
lib/Cake/Console/Templates/skel/View/Errors/error500.ctp
Normal file
17
lib/Cake/Console/Templates/skel/View/Errors/error500.ctp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
/**
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.View.Errors
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
*/
|
||||
?>
|
||||
<h2><?php echo $message; ?></h2>
|
||||
<p class="error">
|
||||
<strong><?php echo __d('cake', 'Error'); ?>: </strong>
|
||||
<?php echo __d('cake', 'An Internal Error Has Occurred.'); ?>
|
||||
</p>
|
||||
<?php
|
||||
if (Configure::read('debug') > 0):
|
||||
echo $this->element('exception_stack_trace');
|
||||
endif;
|
||||
?>
|
||||
24
lib/Cake/Console/Templates/skel/View/Helper/AppHelper.php
Normal file
24
lib/Cake/Console/Templates/skel/View/Helper/AppHelper.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
/**
|
||||
* Application level View Helper
|
||||
*
|
||||
* This file is application-wide helper file. You can put all
|
||||
* application-wide helper-related methods here.
|
||||
*
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.View.Helper
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
*/
|
||||
|
||||
App::uses('Helper', 'View');
|
||||
|
||||
/**
|
||||
* Application helper
|
||||
*
|
||||
* Add your application-wide methods in the class below, your helpers
|
||||
* will inherit them.
|
||||
*
|
||||
* @package app.View.Helper
|
||||
*/
|
||||
class AppHelper extends Helper {
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
/**
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.View.Layouts.Email.html
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
*/
|
||||
?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title><?php echo $this->fetch('title'); ?></title>
|
||||
</head>
|
||||
<body>
|
||||
<?php echo $this->fetch('content'); ?>
|
||||
|
||||
<p>This email was sent using the <a href="http://cakephp.org">CakePHP Framework</a></p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.View.Layouts.Email.text
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
?>
|
||||
<?php echo $this->fetch('content'); ?>
|
||||
|
||||
This email was sent using the CakePHP Framework, http://cakephp.org.
|
||||
8
lib/Cake/Console/Templates/skel/View/Layouts/ajax.ctp
Normal file
8
lib/Cake/Console/Templates/skel/View/Layouts/ajax.ctp
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
/**
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.View.Layouts
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
*/
|
||||
?>
|
||||
<?php echo $this->fetch('content'); ?>
|
||||
50
lib/Cake/Console/Templates/skel/View/Layouts/default.ctp
Normal file
50
lib/Cake/Console/Templates/skel/View/Layouts/default.ctp
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
/**
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.View.Layouts
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
*/
|
||||
|
||||
$cakeDescription = __d('cake_dev', 'CakePHP: the rapid development php framework');
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<?php echo $this->Html->charset(); ?>
|
||||
<title>
|
||||
<?php echo $cakeDescription ?>:
|
||||
<?php echo $this->fetch('title'); ?>
|
||||
</title>
|
||||
<?php
|
||||
echo $this->Html->meta('icon');
|
||||
|
||||
echo $this->Html->css('cake.generic');
|
||||
|
||||
echo $this->fetch('meta');
|
||||
echo $this->fetch('css');
|
||||
echo $this->fetch('script');
|
||||
?>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="header">
|
||||
<h1><?php echo $this->Html->link($cakeDescription, 'http://cakephp.org'); ?></h1>
|
||||
</div>
|
||||
<div id="content">
|
||||
|
||||
<?php echo $this->Session->flash(); ?>
|
||||
|
||||
<?php echo $this->fetch('content'); ?>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<?php echo $this->Html->link(
|
||||
$this->Html->image('cake.power.gif', array('alt' => $cakeDescription, 'border' => '0')),
|
||||
'http://www.cakephp.org/',
|
||||
array('target' => '_blank', 'escape' => false)
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php echo $this->element('sql_dump'); ?>
|
||||
</body>
|
||||
</html>
|
||||
50
lib/Cake/Console/Templates/skel/View/Layouts/error.ctp
Normal file
50
lib/Cake/Console/Templates/skel/View/Layouts/error.ctp
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
/**
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.View.Layouts
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
*/
|
||||
|
||||
$cakeDescription = __d('cake_dev', 'CakePHP: the rapid development php framework');
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<?php echo $this->Html->charset(); ?>
|
||||
<title>
|
||||
<?php echo $cakeDescription ?>:
|
||||
<?php echo $this->fetch('title'); ?>
|
||||
</title>
|
||||
<?php
|
||||
echo $this->Html->meta('icon');
|
||||
|
||||
echo $this->Html->css('cake.generic');
|
||||
|
||||
echo $this->fetch('meta');
|
||||
echo $this->fetch('css');
|
||||
echo $this->fetch('script');
|
||||
?>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="header">
|
||||
<h1><?php echo $this->Html->link($cakeDescription, 'http://cakephp.org'); ?></h1>
|
||||
</div>
|
||||
<div id="content">
|
||||
|
||||
<?php echo $this->Session->flash(); ?>
|
||||
|
||||
<?php echo $this->fetch('content'); ?>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<?php echo $this->Html->link(
|
||||
$this->Html->image('cake.power.gif', array('alt' => $cakeDescription, 'border' => '0')),
|
||||
'http://www.cakephp.org/',
|
||||
array('target' => '_blank', 'escape' => false)
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php echo $this->element('sql_dump'); ?>
|
||||
</body>
|
||||
</html>
|
||||
26
lib/Cake/Console/Templates/skel/View/Layouts/flash.ctp
Normal file
26
lib/Cake/Console/Templates/skel/View/Layouts/flash.ctp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
/**
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.View.Layouts
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
*/
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<?php echo $this->Html->charset(); ?>
|
||||
<title><?php echo $page_title; ?></title>
|
||||
|
||||
<?php if (!Configure::read('debug')): ?>
|
||||
<meta http-equiv="Refresh" content="<?php echo $pause; ?>;url=<?php echo $url; ?>"/>
|
||||
<?php endif ?>
|
||||
<style><!--
|
||||
P { text-align:center; font:bold 1.1em sans-serif }
|
||||
A { color:#444; text-decoration:none }
|
||||
A:HOVER { text-decoration: underline; color:#44E }
|
||||
--></style>
|
||||
</head>
|
||||
<body>
|
||||
<p><a href="<?php echo $url; ?>"><?php echo $message; ?></a></p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?php echo $scripts_for_layout; ?>
|
||||
<script type="text/javascript"><?php echo $this->fetch('content'); ?></script>
|
||||
13
lib/Cake/Console/Templates/skel/View/Layouts/rss/default.ctp
Normal file
13
lib/Cake/Console/Templates/skel/View/Layouts/rss/default.ctp
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
if (!isset($channel)):
|
||||
$channel = array();
|
||||
endif;
|
||||
if (!isset($channel['title'])):
|
||||
$channel['title'] = $this->fetch('title');
|
||||
endif;
|
||||
|
||||
echo $this->Rss->document(
|
||||
$this->Rss->channel(
|
||||
array(), $channel, $this->fetch('content')
|
||||
)
|
||||
);
|
||||
|
|
@ -0,0 +1 @@
|
|||
<?php echo $this->fetch('content'); ?>
|
||||
231
lib/Cake/Console/Templates/skel/View/Pages/home.ctp
Normal file
231
lib/Cake/Console/Templates/skel/View/Pages/home.ctp
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
<?php
|
||||
/**
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.View.Pages
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
*/
|
||||
|
||||
if (!Configure::read('debug')):
|
||||
throw new NotFoundException();
|
||||
endif;
|
||||
|
||||
App::uses('Debugger', 'Utility');
|
||||
?>
|
||||
<h2><?php echo __d('cake_dev', 'Release Notes for CakePHP %s.', Configure::version()); ?></h2>
|
||||
<p>
|
||||
<a href="http://cakephp.org/changelogs/<?php echo Configure::version(); ?>"><?php echo __d('cake_dev', 'Read the changelog'); ?> </a>
|
||||
</p>
|
||||
<?php
|
||||
if (Configure::read('debug') > 0):
|
||||
Debugger::checkSecurityKeys();
|
||||
endif;
|
||||
?>
|
||||
<?php
|
||||
if (file_exists(WWW_ROOT . 'css' . DS . 'cake.generic.css')):
|
||||
?>
|
||||
<p id="url-rewriting-warning" style="background-color:#e32; color:#fff;">
|
||||
<?php echo __d('cake_dev', 'URL rewriting is not properly configured on your server.'); ?>
|
||||
1) <a target="_blank" href="http://book.cakephp.org/2.0/en/installation/url-rewriting.html" style="color:#fff;">Help me configure it</a>
|
||||
2) <a target="_blank" href="http://book.cakephp.org/2.0/en/development/configuration.html#cakephp-core-configuration" style="color:#fff;">I don't / can't use URL rewriting</a>
|
||||
</p>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<p>
|
||||
<?php
|
||||
if (version_compare(PHP_VERSION, '5.2.8', '>=')):
|
||||
echo '<span class="notice success">';
|
||||
echo __d('cake_dev', 'Your version of PHP is 5.2.8 or higher.');
|
||||
echo '</span>';
|
||||
else:
|
||||
echo '<span class="notice">';
|
||||
echo __d('cake_dev', 'Your version of PHP is too low. You need PHP 5.2.8 or higher to use CakePHP.');
|
||||
echo '</span>';
|
||||
endif;
|
||||
?>
|
||||
</p>
|
||||
<p>
|
||||
<?php
|
||||
if (is_writable(TMP)):
|
||||
echo '<span class="notice success">';
|
||||
echo __d('cake_dev', 'Your tmp directory is writable.');
|
||||
echo '</span>';
|
||||
else:
|
||||
echo '<span class="notice">';
|
||||
echo __d('cake_dev', 'Your tmp directory is NOT writable.');
|
||||
echo '</span>';
|
||||
endif;
|
||||
?>
|
||||
</p>
|
||||
<p>
|
||||
<?php
|
||||
$settings = Cache::settings();
|
||||
if (!empty($settings)):
|
||||
echo '<span class="notice success">';
|
||||
echo __d('cake_dev', 'The %s is being used for core caching. To change the config edit %s', '<em>'. $settings['engine'] . 'Engine</em>', 'APP/Config/core.php');
|
||||
echo '</span>';
|
||||
else:
|
||||
echo '<span class="notice">';
|
||||
echo __d('cake_dev', 'Your cache is NOT working. Please check the settings in %s', 'APP/Config/core.php');
|
||||
echo '</span>';
|
||||
endif;
|
||||
?>
|
||||
</p>
|
||||
<p>
|
||||
<?php
|
||||
$filePresent = null;
|
||||
if (file_exists(APP . 'Config' . DS . 'database.php')):
|
||||
echo '<span class="notice success">';
|
||||
echo __d('cake_dev', 'Your database configuration file is present.');
|
||||
$filePresent = true;
|
||||
echo '</span>';
|
||||
else:
|
||||
echo '<span class="notice">';
|
||||
echo __d('cake_dev', 'Your database configuration file is NOT present.');
|
||||
echo '<br/>';
|
||||
echo __d('cake_dev', 'Rename %s to %s', 'APP/Config/database.php.default', 'APP/Config/database.php');
|
||||
echo '</span>';
|
||||
endif;
|
||||
?>
|
||||
</p>
|
||||
<?php
|
||||
if (isset($filePresent)):
|
||||
App::uses('ConnectionManager', 'Model');
|
||||
try {
|
||||
$connected = ConnectionManager::getDataSource('default');
|
||||
} catch (Exception $connectionError) {
|
||||
$connected = false;
|
||||
$errorMsg = $connectionError->getMessage();
|
||||
if (method_exists($connectionError, 'getAttributes')):
|
||||
$attributes = $connectionError->getAttributes();
|
||||
if (isset($errorMsg['message'])):
|
||||
$errorMsg .= '<br />' . $attributes['message'];
|
||||
endif;
|
||||
endif;
|
||||
}
|
||||
?>
|
||||
<p>
|
||||
<?php
|
||||
if ($connected && $connected->isConnected()):
|
||||
echo '<span class="notice success">';
|
||||
echo __d('cake_dev', 'CakePHP is able to connect to the database.');
|
||||
echo '</span>';
|
||||
else:
|
||||
echo '<span class="notice">';
|
||||
echo __d('cake_dev', 'CakePHP is NOT able to connect to the database.');
|
||||
echo '<br /><br />';
|
||||
echo $errorMsg;
|
||||
echo '</span>';
|
||||
endif;
|
||||
?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
App::uses('Validation', 'Utility');
|
||||
if (!Validation::alphaNumeric('cakephp')):
|
||||
echo '<p><span class="notice">';
|
||||
echo __d('cake_dev', 'PCRE has not been compiled with Unicode support.');
|
||||
echo '<br/>';
|
||||
echo __d('cake_dev', 'Recompile PCRE with Unicode support by adding <code>--enable-unicode-properties</code> when configuring');
|
||||
echo '</span></p>';
|
||||
endif;
|
||||
?>
|
||||
|
||||
<p>
|
||||
<?php
|
||||
if (CakePlugin::loaded('DebugKit')):
|
||||
echo '<span class="notice success">';
|
||||
echo __d('cake_dev', 'DebugKit plugin is present');
|
||||
echo '</span>';
|
||||
else:
|
||||
echo '<span class="notice">';
|
||||
echo __d('cake_dev', 'DebugKit is not installed. It will help you inspect and debug different aspects of your application.');
|
||||
echo '<br/>';
|
||||
echo __d('cake_dev', 'You can install it from %s', $this->Html->link('GitHub', 'https://github.com/cakephp/debug_kit'));
|
||||
echo '</span>';
|
||||
endif;
|
||||
?>
|
||||
</p>
|
||||
|
||||
<h3><?php echo __d('cake_dev', 'Editing this Page'); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
echo __d('cake_dev', 'To change the content of this page, edit: %s.<br />
|
||||
To change its layout, edit: %s.<br />
|
||||
You can also add some CSS styles for your pages at: %s.',
|
||||
'APP/View/Pages/home.ctp', 'APP/View/Layouts/default.ctp', 'APP/webroot/css');
|
||||
?>
|
||||
</p>
|
||||
|
||||
<h3><?php echo __d('cake_dev', 'Getting Started'); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
echo $this->Html->link(
|
||||
sprintf('<strong>%s</strong> %s', __d('cake_dev', 'New'), __d('cake_dev', 'CakePHP 2.0 Docs')),
|
||||
'http://book.cakephp.org/2.0/en/',
|
||||
array('target' => '_blank', 'escape' => false)
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<p>
|
||||
<?php
|
||||
echo $this->Html->link(
|
||||
__d('cake_dev', 'The 15 min Blog Tutorial'),
|
||||
'http://book.cakephp.org/2.0/en/tutorials-and-examples/blog/blog.html',
|
||||
array('target' => '_blank', 'escape' => false)
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
|
||||
<h3><?php echo __d('cake_dev', 'Official Plugins'); ?></h3>
|
||||
<p>
|
||||
<ul>
|
||||
<li>
|
||||
<?php echo $this->Html->link('DebugKit', 'https://github.com/cakephp/debug_kit') ?>:
|
||||
<?php echo __d('cake_dev', 'provides a debugging toolbar and enhanced debugging tools for CakePHP applications.'); ?>
|
||||
</li>
|
||||
<li>
|
||||
<?php echo $this->Html->link('Localized', 'https://github.com/cakephp/localized') ?>:
|
||||
<?php echo __d('cake_dev', 'contains various localized validation classes and translations for specific countries'); ?>
|
||||
</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<h3><?php echo __d('cake_dev', 'More about CakePHP'); ?></h3>
|
||||
<p>
|
||||
<?php echo __d('cake_dev', 'CakePHP is a rapid development framework for PHP which uses commonly known design patterns like Active Record, Association Data Mapping, Front Controller and MVC.'); ?>
|
||||
</p>
|
||||
<p>
|
||||
<?php echo __d('cake_dev', 'Our primary goal is to provide a structured framework that enables PHP users at all levels to rapidly develop robust web applications, without any loss to flexibility.'); ?>
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="http://cakephp.org">CakePHP</a>
|
||||
<ul><li><?php echo __d('cake_dev', 'The Rapid Development Framework'); ?></li></ul></li>
|
||||
<li><a href="http://book.cakephp.org"><?php echo __d('cake_dev', 'CakePHP Documentation'); ?> </a>
|
||||
<ul><li><?php echo __d('cake_dev', 'Your Rapid Development Cookbook'); ?></li></ul></li>
|
||||
<li><a href="http://api.cakephp.org"><?php echo __d('cake_dev', 'CakePHP API'); ?> </a>
|
||||
<ul><li><?php echo __d('cake_dev', 'Quick API Reference'); ?></li></ul></li>
|
||||
<li><a href="http://bakery.cakephp.org"><?php echo __d('cake_dev', 'The Bakery'); ?> </a>
|
||||
<ul><li><?php echo __d('cake_dev', 'Everything CakePHP'); ?></li></ul></li>
|
||||
<li><a href="http://plugins.cakephp.org"><?php echo __d('cake_dev', 'CakePHP Plugins'); ?> </a>
|
||||
<ul><li><?php echo __d('cake_dev', 'A comprehensive list of all CakePHP plugins created by the community'); ?></li></ul></li>
|
||||
<li><a href="http://community.cakephp.org"><?php echo __d('cake_dev', 'CakePHP Community Center'); ?> </a>
|
||||
<ul><li><?php echo __d('cake_dev', 'Everything related to the CakePHP community in one place'); ?></li></ul></li>
|
||||
<li><a href="https://groups.google.com/group/cake-php"><?php echo __d('cake_dev', 'CakePHP Google Group'); ?> </a>
|
||||
<ul><li><?php echo __d('cake_dev', 'Community mailing list'); ?></li></ul></li>
|
||||
<li><a href="irc://irc.freenode.net/cakephp">irc.freenode.net #cakephp</a>
|
||||
<ul><li><?php echo __d('cake_dev', 'Live chat about CakePHP'); ?></li></ul></li>
|
||||
<li><a href="https://github.com/cakephp/"><?php echo __d('cake_dev', 'CakePHP Code'); ?> </a>
|
||||
<ul><li><?php echo __d('cake_dev', 'Find the CakePHP code on GitHub and contribute to the framework'); ?></li></ul></li>
|
||||
<li><a href="https://github.com/cakephp/cakephp/issues"><?php echo __d('cake_dev', 'CakePHP Issues'); ?> </a>
|
||||
<ul><li><?php echo __d('cake_dev', 'CakePHP Issues'); ?></li></ul></li>
|
||||
<li><a href="https://github.com/cakephp/cakephp/wiki#roadmaps"><?php echo __d('cake_dev', 'CakePHP Roadmaps'); ?> </a>
|
||||
<ul><li><?php echo __d('cake_dev', 'CakePHP Roadmaps'); ?></li></ul></li>
|
||||
<li><a href="http://training.cakephp.org"><?php echo __d('cake_dev', 'Training'); ?> </a>
|
||||
<ul><li><?php echo __d('cake_dev', 'Join a live session and get skilled with the framework'); ?></li></ul></li>
|
||||
<li><a href="http://cakefest.org"><?php echo __d('cake_dev', 'CakeFest'); ?> </a>
|
||||
<ul><li><?php echo __d('cake_dev', 'Don\'t miss our annual CakePHP conference'); ?></li></ul></li>
|
||||
<li><a href="http://cakefoundation.org"><?php echo __d('cake_dev', 'Cake Software Foundation'); ?> </a>
|
||||
<ul><li><?php echo __d('cake_dev', 'Promoting development related to CakePHP'); ?></li></ul></li>
|
||||
</ul>
|
||||
0
lib/Cake/Console/Templates/skel/View/Scaffolds/empty
Normal file
0
lib/Cake/Console/Templates/skel/View/Scaffolds/empty
Normal file
8
lib/Cake/Console/Templates/skel/index.php
Normal file
8
lib/Cake/Console/Templates/skel/index.php
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
/**
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
*/
|
||||
|
||||
require 'webroot' . DIRECTORY_SEPARATOR . 'index.php';
|
||||
6
lib/Cake/Console/Templates/skel/webroot/.htaccess
Normal file
6
lib/Cake/Console/Templates/skel/webroot/.htaccess
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^ index.php [L]
|
||||
</IfModule>
|
||||
742
lib/Cake/Console/Templates/skel/webroot/css/cake.generic.css
Normal file
742
lib/Cake/Console/Templates/skel/webroot/css/cake.generic.css
Normal file
|
|
@ -0,0 +1,742 @@
|
|||
@charset "utf-8";
|
||||
/**
|
||||
*
|
||||
* Generic CSS for CakePHP
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package app.webroot.css
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
* {
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
/** General Style Info **/
|
||||
body {
|
||||
background: #003d4c;
|
||||
color: #fff;
|
||||
font-family:'lucida grande',verdana,helvetica,arial,sans-serif;
|
||||
font-size:90%;
|
||||
margin: 0;
|
||||
}
|
||||
a {
|
||||
color: #003d4c;
|
||||
text-decoration: underline;
|
||||
font-weight: bold;
|
||||
}
|
||||
a:hover {
|
||||
color: #367889;
|
||||
text-decoration:none;
|
||||
}
|
||||
a img {
|
||||
border:none;
|
||||
}
|
||||
h1, h2, h3, h4 {
|
||||
font-weight: normal;
|
||||
margin-bottom:0.5em;
|
||||
}
|
||||
h1 {
|
||||
background:#fff;
|
||||
color: #003d4c;
|
||||
font-size: 100%;
|
||||
}
|
||||
h2 {
|
||||
background:#fff;
|
||||
color: #e32;
|
||||
font-family:'Gill Sans','lucida grande', helvetica, arial, sans-serif;
|
||||
font-size: 190%;
|
||||
}
|
||||
h3 {
|
||||
color: #2c6877;
|
||||
font-family:'Gill Sans','lucida grande', helvetica, arial, sans-serif;
|
||||
font-size: 165%;
|
||||
}
|
||||
h4 {
|
||||
color: #993;
|
||||
font-weight: normal;
|
||||
}
|
||||
ul, li {
|
||||
margin: 0 12px;
|
||||
}
|
||||
p {
|
||||
margin: 0 0 1em 0;
|
||||
}
|
||||
|
||||
/** Layout **/
|
||||
#container {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#header{
|
||||
padding: 10px 20px;
|
||||
}
|
||||
#header h1 {
|
||||
line-height:20px;
|
||||
background: #003d4c url('../img/cake.icon.png') no-repeat left;
|
||||
color: #fff;
|
||||
padding: 0px 30px;
|
||||
}
|
||||
#header h1 a {
|
||||
color: #fff;
|
||||
background: #003d4c;
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
}
|
||||
#header h1 a:hover {
|
||||
color: #fff;
|
||||
background: #003d4c;
|
||||
text-decoration: underline;
|
||||
}
|
||||
#content{
|
||||
background: #fff;
|
||||
clear: both;
|
||||
color: #333;
|
||||
padding: 10px 20px 40px 20px;
|
||||
overflow: auto;
|
||||
}
|
||||
#footer {
|
||||
clear: both;
|
||||
padding: 6px 10px;
|
||||
text-align: right;
|
||||
}
|
||||
#header a, #footer a {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/** containers **/
|
||||
div.form,
|
||||
div.index,
|
||||
div.view {
|
||||
float:right;
|
||||
width:76%;
|
||||
border-left:1px solid #666;
|
||||
padding:10px 2%;
|
||||
}
|
||||
div.actions {
|
||||
float:left;
|
||||
width:16%;
|
||||
padding:10px 1.5%;
|
||||
}
|
||||
div.actions h3 {
|
||||
padding-top:0;
|
||||
color:#777;
|
||||
}
|
||||
|
||||
|
||||
/** Tables **/
|
||||
table {
|
||||
border-right:0;
|
||||
clear: both;
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
width: 100%;
|
||||
}
|
||||
th {
|
||||
border:0;
|
||||
border-bottom:2px solid #555;
|
||||
text-align: left;
|
||||
padding:4px;
|
||||
}
|
||||
th a {
|
||||
display: block;
|
||||
padding: 2px 4px;
|
||||
text-decoration: none;
|
||||
}
|
||||
th a.asc:after {
|
||||
content: ' ⇣';
|
||||
}
|
||||
th a.desc:after {
|
||||
content: ' ⇡';
|
||||
}
|
||||
table tr td {
|
||||
padding: 6px;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
border-bottom:1px solid #ddd;
|
||||
}
|
||||
table tr:nth-child(even) {
|
||||
background: #f9f9f9;
|
||||
}
|
||||
td.actions {
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
table td.actions a {
|
||||
margin: 0px 6px;
|
||||
padding:2px 5px;
|
||||
}
|
||||
|
||||
/* SQL log */
|
||||
.cake-sql-log {
|
||||
background: #fff;
|
||||
}
|
||||
.cake-sql-log td {
|
||||
padding: 4px 8px;
|
||||
text-align: left;
|
||||
font-family: Monaco, Consolas, "Courier New", monospaced;
|
||||
}
|
||||
.cake-sql-log caption {
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
/** Paging **/
|
||||
.paging {
|
||||
background:#fff;
|
||||
color: #ccc;
|
||||
margin-top: 1em;
|
||||
clear:both;
|
||||
}
|
||||
.paging .current,
|
||||
.paging .disabled,
|
||||
.paging a {
|
||||
text-decoration: none;
|
||||
padding: 5px 8px;
|
||||
display: inline-block
|
||||
}
|
||||
.paging > span {
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
border-left: 0;
|
||||
}
|
||||
.paging > span:hover {
|
||||
background: #efefef;
|
||||
}
|
||||
.paging .prev {
|
||||
border-left: 1px solid #ccc;
|
||||
-moz-border-radius: 4px 0 0 4px;
|
||||
-webkit-border-radius: 4px 0 0 4px;
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
.paging .next {
|
||||
-moz-border-radius: 0 4px 4px 0;
|
||||
-webkit-border-radius: 0 4px 4px 0;
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
.paging .disabled {
|
||||
color: #ddd;
|
||||
}
|
||||
.paging .disabled:hover {
|
||||
background: transparent;
|
||||
}
|
||||
.paging .current {
|
||||
background: #efefef;
|
||||
color: #c73e14;
|
||||
}
|
||||
|
||||
/** Scaffold View **/
|
||||
dl {
|
||||
line-height: 2em;
|
||||
margin: 0em 0em;
|
||||
width: 60%;
|
||||
}
|
||||
dl dd:nth-child(4n+2),
|
||||
dl dt:nth-child(4n+1) {
|
||||
background: #f4f4f4;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: bold;
|
||||
padding-left: 4px;
|
||||
vertical-align: top;
|
||||
width: 10em;
|
||||
}
|
||||
dd {
|
||||
margin-left: 10em;
|
||||
margin-top: -2em;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
/** Forms **/
|
||||
form {
|
||||
clear: both;
|
||||
margin-right: 20px;
|
||||
padding: 0;
|
||||
width: 95%;
|
||||
}
|
||||
fieldset {
|
||||
border: none;
|
||||
margin-bottom: 1em;
|
||||
padding: 16px 10px;
|
||||
}
|
||||
fieldset legend {
|
||||
color: #e32;
|
||||
font-size: 160%;
|
||||
font-weight: bold;
|
||||
}
|
||||
fieldset fieldset {
|
||||
margin-top: 0;
|
||||
padding: 10px 0 0;
|
||||
}
|
||||
fieldset fieldset legend {
|
||||
font-size: 120%;
|
||||
font-weight: normal;
|
||||
}
|
||||
fieldset fieldset div {
|
||||
clear: left;
|
||||
margin: 0 20px;
|
||||
}
|
||||
form div {
|
||||
clear: both;
|
||||
margin-bottom: 1em;
|
||||
padding: .5em;
|
||||
vertical-align: text-top;
|
||||
}
|
||||
form .input {
|
||||
color: #444;
|
||||
}
|
||||
form .required {
|
||||
font-weight: bold;
|
||||
}
|
||||
form .required label:after {
|
||||
color: #e32;
|
||||
content: '*';
|
||||
display:inline;
|
||||
}
|
||||
form div.submit {
|
||||
border: 0;
|
||||
clear: both;
|
||||
margin-top: 10px;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
font-size: 110%;
|
||||
margin-bottom:3px;
|
||||
}
|
||||
input, textarea {
|
||||
clear: both;
|
||||
font-size: 140%;
|
||||
font-family: "frutiger linotype", "lucida grande", "verdana", sans-serif;
|
||||
padding: 1%;
|
||||
width:98%;
|
||||
}
|
||||
select {
|
||||
clear: both;
|
||||
font-size: 120%;
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
select[multiple=multiple] {
|
||||
width: 100%;
|
||||
}
|
||||
option {
|
||||
font-size: 120%;
|
||||
padding: 0 3px;
|
||||
}
|
||||
input[type=checkbox] {
|
||||
clear: left;
|
||||
float: left;
|
||||
margin: 0px 6px 7px 2px;
|
||||
width: auto;
|
||||
}
|
||||
div.checkbox label {
|
||||
display: inline;
|
||||
}
|
||||
input[type=radio] {
|
||||
float:left;
|
||||
width:auto;
|
||||
margin: 6px 0;
|
||||
padding: 0;
|
||||
line-height: 26px;
|
||||
}
|
||||
.radio label {
|
||||
margin: 0 0 6px 20px;
|
||||
line-height: 26px;
|
||||
}
|
||||
input[type=submit] {
|
||||
display: inline;
|
||||
font-size: 110%;
|
||||
width: auto;
|
||||
}
|
||||
form .submit input[type=submit] {
|
||||
background:#62af56;
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#76BF6B), to(#3B8230));
|
||||
background-image: -webkit-linear-gradient(top, #76BF6B, #3B8230);
|
||||
background-image: -moz-linear-gradient(top, #76BF6B, #3B8230);
|
||||
border-color: #2d6324;
|
||||
color: #fff;
|
||||
text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px;
|
||||
padding: 8px 10px;
|
||||
}
|
||||
form .submit input[type=submit]:hover {
|
||||
background: #5BA150;
|
||||
}
|
||||
/* Form errors */
|
||||
form .error {
|
||||
background: #FFDACC;
|
||||
-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
font-weight: normal;
|
||||
}
|
||||
form .error-message {
|
||||
-moz-border-radius: none;
|
||||
-webkit-border-radius: none;
|
||||
border-radius: none;
|
||||
border: none;
|
||||
background: none;
|
||||
margin: 0;
|
||||
padding-left: 4px;
|
||||
padding-right: 0;
|
||||
}
|
||||
form .error,
|
||||
form .error-message {
|
||||
color: #9E2424;
|
||||
-webkit-box-shadow: none;
|
||||
-moz-box-shadow: none;
|
||||
-ms-box-shadow: none;
|
||||
-o-box-shadow: none;
|
||||
box-shadow: none;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
/** Notices and Errors **/
|
||||
.message {
|
||||
clear: both;
|
||||
color: #fff;
|
||||
font-size: 140%;
|
||||
font-weight: bold;
|
||||
margin: 0 0 1em 0;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.success,
|
||||
.message,
|
||||
.cake-error,
|
||||
.cake-debug,
|
||||
.notice,
|
||||
p.error,
|
||||
.error-message {
|
||||
background: #ffcc00;
|
||||
background-repeat: repeat-x;
|
||||
background-image: -moz-linear-gradient(top, #ffcc00, #E6B800);
|
||||
background-image: -ms-linear-gradient(top, #ffcc00, #E6B800);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#ffcc00), to(#E6B800));
|
||||
background-image: -webkit-linear-gradient(top, #ffcc00, #E6B800);
|
||||
background-image: -o-linear-gradient(top, #ffcc00, #E6B800);
|
||||
background-image: linear-gradient(top, #ffcc00, #E6B800);
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
margin-bottom: 18px;
|
||||
padding: 7px 14px;
|
||||
color: #404040;
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
|
||||
-moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
.success,
|
||||
.message,
|
||||
.cake-error,
|
||||
p.error,
|
||||
.error-message {
|
||||
clear: both;
|
||||
color: #fff;
|
||||
background: #c43c35;
|
||||
border: 1px solid rgba(0, 0, 0, 0.5);
|
||||
background-repeat: repeat-x;
|
||||
background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
|
||||
background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35));
|
||||
background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
|
||||
background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
|
||||
background-image: linear-gradient(top, #ee5f5b, #c43c35);
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.success {
|
||||
clear: both;
|
||||
color: #fff;
|
||||
border: 1px solid rgba(0, 0, 0, 0.5);
|
||||
background: #3B8230;
|
||||
background-repeat: repeat-x;
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#76BF6B), to(#3B8230));
|
||||
background-image: -webkit-linear-gradient(top, #76BF6B, #3B8230);
|
||||
background-image: -moz-linear-gradient(top, #76BF6B, #3B8230);
|
||||
background-image: -ms-linear-gradient(top, #76BF6B, #3B8230);
|
||||
background-image: -o-linear-gradient(top, #76BF6B, #3B8230);
|
||||
background-image: linear-gradient(top, #76BF6B, #3B8230);
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
p.error {
|
||||
font-family: Monaco, Consolas, Courier, monospace;
|
||||
font-size: 120%;
|
||||
padding: 0.8em;
|
||||
margin: 1em 0;
|
||||
}
|
||||
p.error em {
|
||||
font-weight: normal;
|
||||
line-height: 140%;
|
||||
}
|
||||
.notice {
|
||||
color: #000;
|
||||
display: block;
|
||||
font-size: 120%;
|
||||
padding: 0.8em;
|
||||
margin: 1em 0;
|
||||
}
|
||||
.success {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/** Actions **/
|
||||
.actions ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.actions li {
|
||||
margin:0 0 0.5em 0;
|
||||
list-style-type: none;
|
||||
white-space: nowrap;
|
||||
padding: 0;
|
||||
}
|
||||
.actions ul li a {
|
||||
font-weight: normal;
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* Buttons and button links */
|
||||
input[type=submit],
|
||||
.actions ul li a,
|
||||
.actions a {
|
||||
font-weight:normal;
|
||||
padding: 4px 8px;
|
||||
background: #dcdcdc;
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#fefefe), to(#dcdcdc));
|
||||
background-image: -webkit-linear-gradient(top, #fefefe, #dcdcdc);
|
||||
background-image: -moz-linear-gradient(top, #fefefe, #dcdcdc);
|
||||
background-image: -ms-linear-gradient(top, #fefefe, #dcdcdc);
|
||||
background-image: -o-linear-gradient(top, #fefefe, #dcdcdc);
|
||||
background-image: linear-gradient(top, #fefefe, #dcdcdc);
|
||||
color:#333;
|
||||
border:1px solid #bbb;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
text-shadow: #fff 0px 1px 0px;
|
||||
min-width: 0;
|
||||
-moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3), 0px 1px 1px rgba(0, 0, 0, 0.2);
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3), 0px 1px 1px rgba(0, 0, 0, 0.2);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3), 0px 1px 1px rgba(0, 0, 0, 0.2);
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.actions ul li a:hover,
|
||||
.actions a:hover {
|
||||
background: #ededed;
|
||||
border-color: #acacac;
|
||||
text-decoration: none;
|
||||
}
|
||||
input[type=submit]:active,
|
||||
.actions ul li a:active,
|
||||
.actions a:active {
|
||||
background: #eee;
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#dfdfdf), to(#eee));
|
||||
background-image: -webkit-linear-gradient(top, #dfdfdf, #eee);
|
||||
background-image: -moz-linear-gradient(top, #dfdfdf, #eee);
|
||||
background-image: -ms-linear-gradient(top, #dfdfdf, #eee);
|
||||
background-image: -o-linear-gradient(top, #dfdfdf, #eee);
|
||||
background-image: linear-gradient(top, #dfdfdf, #eee);
|
||||
text-shadow: #eee 0px 1px 0px;
|
||||
-moz-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.3);
|
||||
-webkit-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.3);
|
||||
box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.3);
|
||||
border-color: #aaa;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/** Related **/
|
||||
.related {
|
||||
clear: both;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/** Debugging **/
|
||||
pre {
|
||||
color: #000;
|
||||
background: #f0f0f0;
|
||||
padding: 15px;
|
||||
-moz-box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);
|
||||
-webkit-box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);
|
||||
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.cake-debug-output {
|
||||
padding: 0;
|
||||
position: relative;
|
||||
}
|
||||
.cake-debug-output > span {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
padding: 5px 6px;
|
||||
color: #000;
|
||||
display: block;
|
||||
float: left;
|
||||
-moz-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.25), 0 1px 0 rgba(255, 255, 255, 0.5);
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.25), 0 1px 0 rgba(255, 255, 255, 0.5);
|
||||
box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.25), 0 1px 0 rgba(255, 255, 255, 0.5);
|
||||
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
.cake-debug,
|
||||
.cake-error {
|
||||
font-size: 16px;
|
||||
line-height: 20px;
|
||||
clear: both;
|
||||
}
|
||||
.cake-error > a {
|
||||
text-shadow: none;
|
||||
}
|
||||
.cake-error {
|
||||
white-space: normal;
|
||||
}
|
||||
.cake-stack-trace {
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
color: #333;
|
||||
margin: 10px 0 5px 0;
|
||||
padding: 10px 10px 0 10px;
|
||||
font-size: 120%;
|
||||
line-height: 140%;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.cake-stack-trace a {
|
||||
text-shadow: none;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
padding: 5px;
|
||||
-moz-border-radius: 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
border-radius: 10px;
|
||||
margin: 0px 4px 10px 2px;
|
||||
font-family: sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 14px;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
-moz-box-shadow: inset 0px 1px 0 rgba(0, 0, 0, 0.3);
|
||||
-webkit-box-shadow: inset 0px 1px 0 rgba(0, 0, 0, 0.3);
|
||||
box-shadow: inset 0px 1px 0 rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.cake-code-dump pre {
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
}
|
||||
.cake-context {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.cake-stack-trace pre {
|
||||
color: #000;
|
||||
background-color: #F0F0F0;
|
||||
margin: 0px 0 10px 0;
|
||||
padding: 1em;
|
||||
overflow: auto;
|
||||
text-shadow: none;
|
||||
}
|
||||
.cake-stack-trace li {
|
||||
padding: 10px 5px 0px;
|
||||
margin: 0 0 4px 0;
|
||||
font-family: monospace;
|
||||
border: 1px solid #bbb;
|
||||
-moz-border-radius: 4px;
|
||||
-wekbkit-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
background: #dcdcdc;
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#fefefe), to(#dcdcdc));
|
||||
background-image: -webkit-linear-gradient(top, #fefefe, #dcdcdc);
|
||||
background-image: -moz-linear-gradient(top, #fefefe, #dcdcdc);
|
||||
background-image: -ms-linear-gradient(top, #fefefe, #dcdcdc);
|
||||
background-image: -o-linear-gradient(top, #fefefe, #dcdcdc);
|
||||
background-image: linear-gradient(top, #fefefe, #dcdcdc);
|
||||
}
|
||||
/* excerpt */
|
||||
.cake-code-dump pre,
|
||||
.cake-code-dump pre code {
|
||||
clear: both;
|
||||
font-size: 12px;
|
||||
line-height: 15px;
|
||||
margin: 4px 2px;
|
||||
padding: 4px;
|
||||
overflow: auto;
|
||||
}
|
||||
.cake-code-dump .code-highlight {
|
||||
display: block;
|
||||
background-color: rgba(255, 255, 0, 0.5);
|
||||
}
|
||||
.code-coverage-results div.code-line {
|
||||
padding-left:5px;
|
||||
display:block;
|
||||
margin-left:10px;
|
||||
}
|
||||
.code-coverage-results div.uncovered span.content {
|
||||
background:#ecc;
|
||||
}
|
||||
.code-coverage-results div.covered span.content {
|
||||
background:#cec;
|
||||
}
|
||||
.code-coverage-results div.ignored span.content {
|
||||
color:#aaa;
|
||||
}
|
||||
.code-coverage-results span.line-num {
|
||||
color:#666;
|
||||
display:block;
|
||||
float:left;
|
||||
width:20px;
|
||||
text-align:right;
|
||||
margin-right:5px;
|
||||
}
|
||||
.code-coverage-results span.line-num strong {
|
||||
color:#666;
|
||||
}
|
||||
.code-coverage-results div.start {
|
||||
border:1px solid #aaa;
|
||||
border-width:1px 1px 0px 1px;
|
||||
margin-top:30px;
|
||||
padding-top:5px;
|
||||
}
|
||||
.code-coverage-results div.end {
|
||||
border:1px solid #aaa;
|
||||
border-width:0px 1px 1px 1px;
|
||||
margin-bottom:30px;
|
||||
padding-bottom:5px;
|
||||
}
|
||||
.code-coverage-results div.realstart {
|
||||
margin-top:0px;
|
||||
}
|
||||
.code-coverage-results p.note {
|
||||
color:#bbb;
|
||||
padding:5px;
|
||||
margin:5px 0 10px;
|
||||
font-size:10px;
|
||||
}
|
||||
.code-coverage-results span.result-bad {
|
||||
color: #a00;
|
||||
}
|
||||
.code-coverage-results span.result-ok {
|
||||
color: #fa0;
|
||||
}
|
||||
.code-coverage-results span.result-good {
|
||||
color: #0a0;
|
||||
}
|
||||
|
||||
/** Elements **/
|
||||
#url-rewriting-warning {
|
||||
display:none;
|
||||
}
|
||||
BIN
lib/Cake/Console/Templates/skel/webroot/favicon.ico
Normal file
BIN
lib/Cake/Console/Templates/skel/webroot/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 372 B |
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue