00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 class ConsoleShell extends Shell {
00032
00033
00034
00035
00036
00037
00038 var $associations = array('hasOne', 'hasMany', 'belongsTo', 'hasAndBelongsToMany');
00039
00040
00041
00042
00043
00044
00045 var $badCommandChars = array('$', ';');
00046
00047
00048
00049
00050
00051
00052 var $models = array();
00053
00054
00055
00056
00057
00058 function initialize() {
00059 require_once CAKE . 'dispatcher.php';
00060 $this->Dispatcher = new Dispatcher();
00061 $this->models = Configure::listObjects('model');
00062 App::import('Model', $this->models);
00063
00064 foreach ($this->models as $model) {
00065 $class = Inflector::camelize(r('.php', '', $model));
00066 $this->models[$model] = $class;
00067 $this->{$class} =& new $class();
00068 }
00069 $this->out('Model classes:');
00070 $this->out('--------------');
00071
00072 foreach ($this->models as $model) {
00073 $this->out(" - {$model}");
00074 }
00075 $this->__loadRoutes();
00076 }
00077
00078
00079
00080
00081
00082 function help() {
00083 $this->main('help');
00084 }
00085
00086
00087
00088
00089
00090 function main($command = null) {
00091 while (true) {
00092 if (empty($command)) {
00093 $command = trim($this->in(''));
00094 }
00095
00096 switch ($command) {
00097 case 'help':
00098 $this->out('Console help:');
00099 $this->out('-------------');
00100 $this->out('The interactive console is a tool for testing parts of your app before you commit code');
00101 $this->out('');
00102 $this->out('Model testing:');
00103 $this->out('To test model results, use the name of your model without a leading $');
00104 $this->out('e.g. Foo->find("all")');
00105 $this->out('');
00106 $this->out('To dynamically set associations, you can do the following:');
00107 $this->out("\tModelA bind <association> ModelB");
00108 $this->out("where the supported assocations are hasOne, hasMany, belongsTo, hasAndBelongsToMany");
00109 $this->out('');
00110 $this->out('To dynamically remove associations, you can do the following:');
00111 $this->out("\t ModelA unbind <association> ModelB");
00112 $this->out("where the supported associations are the same as above");
00113 $this->out('');
00114 $this->out("To save a new field in a model, you can do the following:");
00115 $this->out("\tModelA->save(array('foo' => 'bar', 'baz' => 0))");
00116 $this->out("where you are passing a hash of data to be saved in the format");
00117 $this->out("of field => value pairs");
00118 $this->out('');
00119 $this->out("To get column information for a model, use the following:");
00120 $this->out("\tModelA columns");
00121 $this->out("which returns a list of columns and their type");
00122 $this->out('');
00123 $this->out('Route testing:');
00124 $this->out('To test URLs against your app\'s route configuration, type:');
00125 $this->out("\tRoute <url>");
00126 $this->out("where url is the path to your your action plus any query parameters, minus the");
00127 $this->out("application's base path");
00128 $this->out('');
00129 $this->out('To reload your routes config (config/routes.php), do the following:');
00130 $this->out("\tRoutes reload");
00131 $this->out('');
00132 $this->out('');
00133 $this->out('To show all connected routes, do the following:');
00134 $this->out("\tRoutes show");
00135 $this->out('');
00136 break;
00137 case 'quit':
00138 case 'exit':
00139 return true;
00140 break;
00141 case 'models':
00142 $this->out('Model classes:');
00143 $this->hr();
00144 foreach ($this->models as $model) {
00145 $this->out(" - {$model}");
00146 }
00147 break;
00148 case (preg_match("/^(\w+) bind (\w+) (\w+)/", $command, $tmp) == true):
00149 foreach ($tmp as $data) {
00150 $data = strip_tags($data);
00151 $data = str_replace($this->badCommandChars, "", $data);
00152 }
00153
00154 $modelA = $tmp[1];
00155 $association = $tmp[2];
00156 $modelB = $tmp[3];
00157
00158 if ($this->__isValidModel($modelA) && $this->__isValidModel($modelB) && in_array($association, $this->associations)) {
00159 $this->{$modelA}->bindModel(array($association => array($modelB => array('className' => $modelB))), false);
00160 $this->out("Created $association association between $modelA and $modelB");
00161 } else {
00162 $this->out("Please verify you are using valid models and association types");
00163 }
00164 break;
00165 case (preg_match("/^(\w+) unbind (\w+) (\w+)/", $command, $tmp) == true):
00166 foreach ($tmp as $data) {
00167 $data = strip_tags($data);
00168 $data = str_replace($this->badCommandChars, "", $data);
00169 }
00170
00171 $modelA = $tmp[1];
00172 $association = $tmp[2];
00173 $modelB = $tmp[3];
00174
00175
00176 $currentAssociations = $this->{$modelA}->getAssociated();
00177 $validCurrentAssociation = false;
00178
00179 foreach ($currentAssociations as $model => $currentAssociation) {
00180 if ($model == $modelB && $association == $currentAssociation) {
00181 $validCurrentAssociation = true;
00182 }
00183 }
00184
00185 if ($this->__isValidModel($modelA) && $this->__isValidModel($modelB) && in_array($association, $this->associations) && $validCurrentAssociation) {
00186 $this->{$modelA}->unbindModel(array($association => array($modelB)));
00187 $this->out("Removed $association association between $modelA and $modelB");
00188 } else {
00189 $this->out("Please verify you are using valid models, valid current association, and valid association types");
00190 }
00191 break;
00192 case (strpos($command, "->find") > 0):
00193
00194 $command = strip_tags($command);
00195 $command = str_replace($this->badCommandChars, "", $command);
00196
00197
00198 list($modelToCheck, $tmp) = explode('->', $command);
00199
00200 if ($this->__isValidModel($modelToCheck)) {
00201 $findCommand = "\$data = \$this->$command;";
00202 @eval($findCommand);
00203
00204 if (is_array($data)) {
00205 foreach ($data as $idx => $results) {
00206 if (is_numeric($idx)) {
00207 foreach ($results as $modelName => $result) {
00208 $this->out("$modelName");
00209
00210 foreach ($result as $field => $value) {
00211 if (is_array($value)) {
00212 foreach ($value as $field2 => $value2) {
00213 $this->out("\t$field2: $value2");
00214 }
00215
00216 $this->out("");
00217 } else {
00218 $this->out("\t$field: $value");
00219 }
00220 }
00221 }
00222 } else {
00223 $this->out($idx);
00224
00225 foreach ($results as $field => $value) {
00226 if (is_array($value)) {
00227 foreach ($value as $field2 => $value2) {
00228 $this->out("\t$field2: $value2");
00229 }
00230
00231 $this->out("");
00232 } else {
00233 $this->out("\t$field: $value");
00234 }
00235 }
00236 }
00237 }
00238 } else {
00239 $this->out("\nNo result set found");
00240 }
00241 } else {
00242 $this->out("$modelToCheck is not a valid model");
00243 }
00244
00245 break;
00246 case (strpos($command, '->save') > 0):
00247
00248 $command = strip_tags($command);
00249 $command = str_replace($this->badCommandChars, "", $command);
00250 list($modelToSave, $tmp) = explode("->", $command);
00251
00252 if ($this->__isValidModel($modelToSave)) {
00253
00254 list($foo, $data) = explode("->save", $command);
00255 $data = preg_replace('/^\(*(array)?\(*(.+?)\)*$/i', '\\2', $data);
00256 $saveCommand = "\$this->{$modelToSave}->save(array('{$modelToSave}' => array({$data})));";
00257 @eval($saveCommand);
00258 $this->out('Saved record for ' . $modelToSave);
00259 }
00260 break;
00261 case (preg_match("/^(\w+) columns/", $command, $tmp) == true):
00262 $modelToCheck = strip_tags(str_replace($this->badCommandChars, "", $tmp[1]));
00263
00264 if ($this->__isValidModel($modelToCheck)) {
00265
00266 $fieldsCommand = "\$data = \$this->{$modelToCheck}->getColumnTypes();";
00267 @eval($fieldsCommand);
00268
00269 if (is_array($data)) {
00270 foreach ($data as $field => $type) {
00271 $this->out("\t{$field}: {$type}");
00272 }
00273 }
00274 } else {
00275 $this->out("Please verify that you selected a valid model");
00276 }
00277 break;
00278 case (preg_match("/^routes\s+reload/i", $command, $tmp) == true):
00279 $router =& Router::getInstance();
00280 if (!$this->__loadRoutes()) {
00281 $this->out("There was an error loading the routes config. Please check that the file");
00282 $this->out("exists and is free of parse errors.");
00283 break;
00284 }
00285 $this->out("Routes configuration reloaded, " . count($router->routes) . " routes connected");
00286 break;
00287 case (preg_match("/^routes\s+show/i", $command, $tmp) == true):
00288 $router =& Router::getInstance();
00289 $this->out(join("\n", Set::extract($router->routes, '{n}.0')));
00290 break;
00291 case (preg_match("/^route\s+(.*)/i", $command, $tmp) == true):
00292 $this->out(var_export(Router::parse($tmp[1]), true));
00293 break;
00294 default:
00295 $this->out("Invalid command\n");
00296 break;
00297 }
00298 $command = '';
00299 }
00300 }
00301
00302
00303
00304
00305
00306
00307
00308 function __isValidModel($modelToCheck) {
00309 return in_array($modelToCheck, $this->models);
00310 }
00311
00312
00313
00314
00315
00316
00317
00318 function __loadRoutes() {
00319 $router =& Router::getInstance();
00320
00321 $router->reload();
00322 extract($router->getNamedExpressions());
00323
00324 if (!@include(CONFIGS . 'routes.php')) {
00325 return false;
00326 }
00327 $router->parse('/');
00328
00329 foreach (array_keys($router->getNamedExpressions()) as $var) {
00330 unset(${$var});
00331 }
00332 for ($i = 0; $i < count($router->routes); $i++) {
00333 $router->compile($i);
00334 }
00335 return true;
00336 }
00337 }
00338 ?>