Overview

Packages

  • application
    • commands
    • components
      • actions
      • filters
      • leftWidget
      • permissions
      • sortableWidget
      • util
      • webupdater
      • x2flow
        • actions
        • triggers
      • X2GridView
      • X2Settings
    • controllers
    • models
      • embedded
    • modules
      • accounts
        • controllers
        • models
      • actions
        • controllers
        • models
      • calendar
        • controllers
        • models
      • charts
        • models
      • contacts
        • controllers
        • models
      • docs
        • components
        • controllers
        • models
      • groups
        • controllers
        • models
      • marketing
        • components
        • controllers
        • models
      • media
        • controllers
        • models
      • mobile
        • components
      • opportunities
        • controllers
        • models
      • products
        • controllers
        • models
      • quotes
        • controllers
        • models
      • services
        • controllers
        • models
      • template
        • models
      • users
        • controllers
        • models
      • workflow
        • controllers
        • models
      • x2Leads
        • controllers
        • models
  • Net
  • None
  • PHP
  • system
    • base
    • caching
      • dependencies
    • collections
    • console
    • db
      • ar
      • schema
        • cubrid
        • mssql
        • mysql
        • oci
        • pgsql
        • sqlite
    • i18n
      • gettext
    • logging
    • test
    • utils
    • validators
    • web
      • actions
      • auth
      • filters
      • form
      • helpers
      • renderers
      • services
      • widgets
        • captcha
        • pagers
  • Text
    • Highlighter
  • zii
    • behaviors
    • widgets
      • grid
      • jui

Classes

  • CConsoleApplication
  • CConsoleCommand
  • CConsoleCommandBehavior
  • CConsoleCommandEvent
  • CConsoleCommandRunner
  • CHelpCommand
  • ThemeBuildCommand
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * CConsoleCommand class file.
  4:  *
  5:  * @author Qiang Xue <qiang.xue@gmail.com>
  6:  * @link http://www.yiiframework.com/
  7:  * @copyright 2008-2013 Yii Software LLC
  8:  * @license http://www.yiiframework.com/license/
  9:  */
 10: 
 11: /**
 12:  * CConsoleCommand represents an executable console command.
 13:  *
 14:  * It works like {@link CController} by parsing command line options and dispatching
 15:  * the request to a specific action with appropriate option values.
 16:  *
 17:  * Users call a console command via the following command format:
 18:  * <pre>
 19:  * yiic CommandName ActionName --Option1=Value1 --Option2=Value2 ...
 20:  * </pre>
 21:  *
 22:  * Child classes mainly needs to implement various action methods whose name must be
 23:  * prefixed with "action". The parameters to an action method are considered as options
 24:  * for that specific action. The action specified as {@link defaultAction} will be invoked
 25:  * when a user does not specify the action name in his command.
 26:  *
 27:  * Options are bound to action parameters via parameter names. For example, the following
 28:  * action method will allow us to run a command with <code>yiic sitemap --type=News</code>:
 29:  * <pre>
 30:  * class SitemapCommand extends CConsoleCommand {
 31:  *     public function actionIndex($type) {
 32:  *         ....
 33:  *     }
 34:  * }
 35:  * </pre>
 36:  *
 37:  * Since version 1.1.11 the return value of action methods will be used as application exit code if it is an integer value.
 38:  *
 39:  * @property string $name The command name.
 40:  * @property CConsoleCommandRunner $commandRunner The command runner instance.
 41:  * @property string $help The command description. Defaults to 'Usage: php entry-script.php command-name'.
 42:  * @property array $optionHelp The command option help information. Each array element describes
 43:  * the help information for a single action.
 44:  *
 45:  * @author Qiang Xue <qiang.xue@gmail.com>
 46:  * @package system.console
 47:  * @since 1.0
 48:  */
 49: abstract class CConsoleCommand extends CComponent
 50: {
 51:     /**
 52:      * @var string the name of the default action. Defaults to 'index'.
 53:      * @since 1.1.5
 54:      */
 55:     public $defaultAction='index';
 56: 
 57:     private $_name;
 58:     private $_runner;
 59: 
 60:     /**
 61:      * Constructor.
 62:      * @param string $name name of the command
 63:      * @param CConsoleCommandRunner $runner the command runner
 64:      */
 65:     public function __construct($name,$runner)
 66:     {
 67:         $this->_name=$name;
 68:         $this->_runner=$runner;
 69:         $this->attachBehaviors($this->behaviors());
 70:     }
 71: 
 72:     /**
 73:      * Initializes the command object.
 74:      * This method is invoked after a command object is created and initialized with configurations.
 75:      * You may override this method to further customize the command before it executes.
 76:      * @since 1.1.6
 77:      */
 78:     public function init()
 79:     {
 80:     }
 81: 
 82:     /**
 83:      * Returns a list of behaviors that this command should behave as.
 84:      * The return value should be an array of behavior configurations indexed by
 85:      * behavior names. Each behavior configuration can be either a string specifying
 86:      * the behavior class or an array of the following structure:
 87:      * <pre>
 88:      * 'behaviorName'=>array(
 89:      *     'class'=>'path.to.BehaviorClass',
 90:      *     'property1'=>'value1',
 91:      *     'property2'=>'value2',
 92:      * )
 93:      * </pre>
 94:      *
 95:      * Note, the behavior classes must implement {@link IBehavior} or extend from
 96:      * {@link CBehavior}. Behaviors declared in this method will be attached
 97:      * to the controller when it is instantiated.
 98:      *
 99:      * For more details about behaviors, see {@link CComponent}.
100:      * @return array the behavior configurations (behavior name=>behavior configuration)
101:      * @since 1.1.11
102:      */
103:     public function behaviors()
104:     {
105:         return array();
106:     }
107: 
108:     /**
109:      * Executes the command.
110:      * The default implementation will parse the input parameters and
111:      * dispatch the command request to an appropriate action with the corresponding
112:      * option values
113:      * @param array $args command line parameters for this command.
114:      * @return integer application exit code, which is returned by the invoked action. 0 if the action did not return anything.
115:      * (return value is available since version 1.1.11)
116:      */
117:     public function run($args)
118:     {
119:         list($action, $options, $args)=$this->resolveRequest($args);
120:         $methodName='action'.$action;
121:         if(!preg_match('/^\w+$/',$action) || !method_exists($this,$methodName))
122:             $this->usageError("Unknown action: ".$action);
123: 
124:         $method=new ReflectionMethod($this,$methodName);
125:         $params=array();
126:         // named and unnamed options
127:         foreach($method->getParameters() as $i=>$param)
128:         {
129:             $name=$param->getName();
130:             if(isset($options[$name]))
131:             {
132:                 if($param->isArray())
133:                     $params[]=is_array($options[$name]) ? $options[$name] : array($options[$name]);
134:                 elseif(!is_array($options[$name]))
135:                     $params[]=$options[$name];
136:                 else
137:                     $this->usageError("Option --$name requires a scalar. Array is given.");
138:             }
139:             elseif($name==='args')
140:                 $params[]=$args;
141:             elseif($param->isDefaultValueAvailable())
142:                 $params[]=$param->getDefaultValue();
143:             else
144:                 $this->usageError("Missing required option --$name.");
145:             unset($options[$name]);
146:         }
147: 
148:         // try global options
149:         if(!empty($options))
150:         {
151:             $class=new ReflectionClass(get_class($this));
152:             foreach($options as $name=>$value)
153:             {
154:                 if($class->hasProperty($name))
155:                 {
156:                     $property=$class->getProperty($name);
157:                     if($property->isPublic() && !$property->isStatic())
158:                     {
159:                         $this->$name=$value;
160:                         unset($options[$name]);
161:                     }
162:                 }
163:             }
164:         }
165: 
166:         if(!empty($options))
167:             $this->usageError("Unknown options: ".implode(', ',array_keys($options)));
168: 
169:         $exitCode=0;
170:         if($this->beforeAction($action,$params))
171:         {
172:             $exitCode=$method->invokeArgs($this,$params);
173:             $exitCode=$this->afterAction($action,$params,is_int($exitCode)?$exitCode:0);
174:         }
175:         return $exitCode;
176:     }
177: 
178:     /**
179:      * This method is invoked right before an action is to be executed.
180:      * You may override this method to do last-minute preparation for the action.
181:      * @param string $action the action name
182:      * @param array $params the parameters to be passed to the action method.
183:      * @return boolean whether the action should be executed.
184:      */
185:     protected function beforeAction($action,$params)
186:     {
187:         if($this->hasEventHandler('onBeforeAction'))
188:         {
189:             $event = new CConsoleCommandEvent($this,$params,$action);
190:             $this->onBeforeAction($event);
191:             return !$event->stopCommand;
192:         }
193:         else
194:         {
195:             return true;
196:         }
197:     }
198: 
199:     /**
200:      * This method is invoked right after an action finishes execution.
201:      * You may override this method to do some postprocessing for the action.
202:      * @param string $action the action name
203:      * @param array $params the parameters to be passed to the action method.
204:      * @param integer $exitCode the application exit code returned by the action method.
205:      * @return integer application exit code (return value is available since version 1.1.11)
206:      */
207:     protected function afterAction($action,$params,$exitCode=0)
208:     {
209:         $event=new CConsoleCommandEvent($this,$params,$action,$exitCode);
210:         if($this->hasEventHandler('onAfterAction'))
211:             $this->onAfterAction($event);
212:         return $event->exitCode;
213:     }
214: 
215:     /**
216:      * Parses the command line arguments and determines which action to perform.
217:      * @param array $args command line arguments
218:      * @return array the action name, named options (name=>value), and unnamed options
219:      * @since 1.1.5
220:      */
221:     protected function resolveRequest($args)
222:     {
223:         $options=array();   // named parameters
224:         $params=array();    // unnamed parameters
225:         foreach($args as $arg)
226:         {
227:             if(preg_match('/^--(\w+)(=(.*))?$/',$arg,$matches))  // an option
228:             {
229:                 $name=$matches[1];
230:                 $value=isset($matches[3]) ? $matches[3] : true;
231:                 if(isset($options[$name]))
232:                 {
233:                     if(!is_array($options[$name]))
234:                         $options[$name]=array($options[$name]);
235:                     $options[$name][]=$value;
236:                 }
237:                 else
238:                     $options[$name]=$value;
239:             }
240:             elseif(isset($action))
241:                 $params[]=$arg;
242:             else
243:                 $action=$arg;
244:         }
245:         if(!isset($action))
246:             $action=$this->defaultAction;
247: 
248:         return array($action,$options,$params);
249:     }
250: 
251:     /**
252:      * @return string the command name.
253:      */
254:     public function getName()
255:     {
256:         return $this->_name;
257:     }
258: 
259:     /**
260:      * @return CConsoleCommandRunner the command runner instance
261:      */
262:     public function getCommandRunner()
263:     {
264:         return $this->_runner;
265:     }
266: 
267:     /**
268:      * Provides the command description.
269:      * This method may be overridden to return the actual command description.
270:      * @return string the command description. Defaults to 'Usage: php entry-script.php command-name'.
271:      */
272:     public function getHelp()
273:     {
274:         $help='Usage: '.$this->getCommandRunner()->getScriptName().' '.$this->getName();
275:         $options=$this->getOptionHelp();
276:         if(empty($options))
277:             return $help."\n";
278:         if(count($options)===1)
279:             return $help.' '.$options[0]."\n";
280:         $help.=" <action>\nActions:\n";
281:         foreach($options as $option)
282:             $help.='    '.$option."\n";
283:         return $help;
284:     }
285: 
286:     /**
287:      * Provides the command option help information.
288:      * The default implementation will return all available actions together with their
289:      * corresponding option information.
290:      * @return array the command option help information. Each array element describes
291:      * the help information for a single action.
292:      * @since 1.1.5
293:      */
294:     public function getOptionHelp()
295:     {
296:         $options=array();
297:         $class=new ReflectionClass(get_class($this));
298:         foreach($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method)
299:         {
300:             $name=$method->getName();
301:             if(!strncasecmp($name,'action',6) && strlen($name)>6)
302:             {
303:                 $name=substr($name,6);
304:                 $name[0]=strtolower($name[0]);
305:                 $help=$name;
306: 
307:                 foreach($method->getParameters() as $param)
308:                 {
309:                     $optional=$param->isDefaultValueAvailable();
310:                     $defaultValue=$optional ? $param->getDefaultValue() : null;
311:                     if(is_array($defaultValue)) {
312:                         $defaultValue = str_replace(array("\r\n", "\n", "\r"), "", print_r($defaultValue, true));
313:                     }
314:                     $name=$param->getName();
315: 
316:                     if($name==='args')
317:                         continue;
318: 
319:                     if($optional)
320:                         $help.=" [--$name=$defaultValue]";
321:                     else
322:                         $help.=" --$name=value";
323:                 }
324:                 $options[]=$help;
325:             }
326:         }
327:         return $options;
328:     }
329: 
330:     /**
331:      * Displays a usage error.
332:      * This method will then terminate the execution of the current application.
333:      * @param string $message the error message
334:      */
335:     public function usageError($message)
336:     {
337:         echo "Error: $message\n\n".$this->getHelp()."\n";
338:         exit(1);
339:     }
340: 
341:     /**
342:      * Copies a list of files from one place to another.
343:      * @param array $fileList the list of files to be copied (name=>spec).
344:      * The array keys are names displayed during the copy process, and array values are specifications
345:      * for files to be copied. Each array value must be an array of the following structure:
346:      * <ul>
347:      * <li>source: required, the full path of the file/directory to be copied from</li>
348:      * <li>target: required, the full path of the file/directory to be copied to</li>
349:      * <li>callback: optional, the callback to be invoked when copying a file. The callback function
350:      *   should be declared as follows:
351:      *   <pre>
352:      *   function foo($source,$params)
353:      *   </pre>
354:      *   where $source parameter is the source file path, and the content returned
355:      *   by the function will be saved into the target file.</li>
356:      * <li>params: optional, the parameters to be passed to the callback</li>
357:      * </ul>
358:      * @see buildFileList
359:      */
360:     public function copyFiles($fileList)
361:     {
362:         $overwriteAll=false;
363:         foreach($fileList as $name=>$file)
364:         {
365:             $source=strtr($file['source'],'/\\',DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR);
366:             $target=strtr($file['target'],'/\\',DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR);
367:             $callback=isset($file['callback']) ? $file['callback'] : null;
368:             $params=isset($file['params']) ? $file['params'] : null;
369: 
370:             if(is_dir($source))
371:             {
372:                 $this->ensureDirectory($target);
373:                 continue;
374:             }
375: 
376:             if($callback!==null)
377:                 $content=call_user_func($callback,$source,$params);
378:             else
379:                 $content=file_get_contents($source);
380:             if(is_file($target))
381:             {
382:                 if($content===file_get_contents($target))
383:                 {
384:                     echo "  unchanged $name\n";
385:                     continue;
386:                 }
387:                 if($overwriteAll)
388:                     echo "  overwrite $name\n";
389:                 else
390:                 {
391:                     echo "      exist $name\n";
392:                     echo "            ...overwrite? [Yes|No|All|Quit] ";
393:                     $answer=trim(fgets(STDIN));
394:                     if(!strncasecmp($answer,'q',1))
395:                         return;
396:                     elseif(!strncasecmp($answer,'y',1))
397:                         echo "  overwrite $name\n";
398:                     elseif(!strncasecmp($answer,'a',1))
399:                     {
400:                         echo "  overwrite $name\n";
401:                         $overwriteAll=true;
402:                     }
403:                     else
404:                     {
405:                         echo "       skip $name\n";
406:                         continue;
407:                     }
408:                 }
409:             }
410:             else
411:             {
412:                 $this->ensureDirectory(dirname($target));
413:                 echo "   generate $name\n";
414:             }
415:             file_put_contents($target,$content);
416:         }
417:     }
418: 
419:     /**
420:      * Builds the file list of a directory.
421:      * This method traverses through the specified directory and builds
422:      * a list of files and subdirectories that the directory contains.
423:      * The result of this function can be passed to {@link copyFiles}.
424:      * @param string $sourceDir the source directory
425:      * @param string $targetDir the target directory
426:      * @param string $baseDir base directory
427:      * @param array $ignoreFiles list of the names of files that should
428:      * be ignored in list building process. Argument available since 1.1.11.
429:      * @param array $renameMap hash array of file names that should be
430:      * renamed. Example value: array('1.old.txt'=>'2.new.txt').
431:      * Argument available since 1.1.11.
432:      * @return array the file list (see {@link copyFiles})
433:      */
434:     public function buildFileList($sourceDir, $targetDir, $baseDir='', $ignoreFiles=array(), $renameMap=array())
435:     {
436:         $list=array();
437:         $handle=opendir($sourceDir);
438:         while(($file=readdir($handle))!==false)
439:         {
440:             if(in_array($file,array('.','..','.svn','.gitignore')) || in_array($file,$ignoreFiles))
441:                 continue;
442:             $sourcePath=$sourceDir.DIRECTORY_SEPARATOR.$file;
443:             $targetPath=$targetDir.DIRECTORY_SEPARATOR.strtr($file,$renameMap);
444:             $name=$baseDir===''?$file : $baseDir.'/'.$file;
445:             $list[$name]=array('source'=>$sourcePath, 'target'=>$targetPath);
446:             if(is_dir($sourcePath))
447:                 $list=array_merge($list,$this->buildFileList($sourcePath,$targetPath,$name,$ignoreFiles,$renameMap));
448:         }
449:         closedir($handle);
450:         return $list;
451:     }
452: 
453:     /**
454:      * Creates all parent directories if they do not exist.
455:      * @param string $directory the directory to be checked
456:      */
457:     public function ensureDirectory($directory)
458:     {
459:         if(!is_dir($directory))
460:         {
461:             $this->ensureDirectory(dirname($directory));
462:             echo "      mkdir ".strtr($directory,'\\','/')."\n";
463:             mkdir($directory);
464:         }
465:     }
466: 
467:     /**
468:      * Renders a view file.
469:      * @param string $_viewFile_ view file path
470:      * @param array $_data_ optional data to be extracted as local view variables
471:      * @param boolean $_return_ whether to return the rendering result instead of displaying it
472:      * @return mixed the rendering result if required. Null otherwise.
473:      */
474:     public function renderFile($_viewFile_,$_data_=null,$_return_=false)
475:     {
476:         if(is_array($_data_))
477:             extract($_data_,EXTR_PREFIX_SAME,'data');
478:         else
479:             $data=$_data_;
480:         if($_return_)
481:         {
482:             ob_start();
483:             ob_implicit_flush(false);
484:             require($_viewFile_);
485:             return ob_get_clean();
486:         }
487:         else
488:             require($_viewFile_);
489:     }
490: 
491:     /**
492:      * Converts a word to its plural form.
493:      * @param string $name the word to be pluralized
494:      * @return string the pluralized word
495:      */
496:     public function pluralize($name)
497:     {
498:         $rules=array(
499:             '/(m)ove$/i' => '\1oves',
500:             '/(f)oot$/i' => '\1eet',
501:             '/(c)hild$/i' => '\1hildren',
502:             '/(h)uman$/i' => '\1umans',
503:             '/(m)an$/i' => '\1en',
504:             '/(s)taff$/i' => '\1taff',
505:             '/(t)ooth$/i' => '\1eeth',
506:             '/(p)erson$/i' => '\1eople',
507:             '/([m|l])ouse$/i' => '\1ice',
508:             '/(x|ch|ss|sh|us|as|is|os)$/i' => '\1es',
509:             '/([^aeiouy]|qu)y$/i' => '\1ies',
510:             '/(?:([^f])fe|([lr])f)$/i' => '\1\2ves',
511:             '/(shea|lea|loa|thie)f$/i' => '\1ves',
512:             '/([ti])um$/i' => '\1a',
513:             '/(tomat|potat|ech|her|vet)o$/i' => '\1oes',
514:             '/(bu)s$/i' => '\1ses',
515:             '/(ax|test)is$/i' => '\1es',
516:             '/s$/' => 's',
517:         );
518:         foreach($rules as $rule=>$replacement)
519:         {
520:             if(preg_match($rule,$name))
521:                 return preg_replace($rule,$replacement,$name);
522:         }
523:         return $name.'s';
524:     }
525: 
526:     /**
527:      * Reads input via the readline PHP extension if that's available, or fgets() if readline is not installed.
528:      *
529:      * @param string $message to echo out before waiting for user input
530:      * @param string $default the default string to be returned when user does not write anything.
531:      * Defaults to null, means that default string is disabled. This parameter is available since version 1.1.11.
532:      * @return mixed line read as a string, or false if input has been closed
533:      *
534:      * @since 1.1.9
535:      */
536:     public function prompt($message,$default=null)
537:     {
538:         if($default!==null)
539:             $message.=" [$default] ";
540:         else
541:             $message.=' ';
542: 
543:         if(extension_loaded('readline'))
544:         {
545:             $input=readline($message);
546:             if($input!==false)
547:                 readline_add_history($input);
548:         }
549:         else
550:         {
551:             echo $message;
552:             $input=fgets(STDIN);
553:         }
554: 
555:         if($input===false)
556:             return false;
557:         else{
558:             $input=trim($input);
559:             return ($input==='' && $default!==null) ? $default : $input;
560:         }
561:     }
562: 
563:     /**
564:      * Asks user to confirm by typing y or n.
565:      *
566:      * @param string $message to echo out before waiting for user input
567:      * @param boolean $default this value is returned if no selection is made. This parameter has been available since version 1.1.11.
568:      * @return boolean whether user confirmed
569:      *
570:      * @since 1.1.9
571:      */
572:     public function confirm($message,$default=false)
573:     {
574:         echo $message.' (yes|no) [' . ($default ? 'yes' : 'no') . ']:';
575: 
576:         $input = trim(fgets(STDIN));
577:         return empty($input) ? $default : !strncasecmp($input,'y',1);
578:     }
579: 
580:     /**
581:      * This event is raised before an action is to be executed.
582:      * @param CConsoleCommandEvent $event the event parameter
583:      * @since 1.1.11
584:      */
585:     public function onBeforeAction($event)
586:     {
587:         $this->raiseEvent('onBeforeAction',$event);
588:     }
589: 
590:     /**
591:      * This event is raised after an action finishes execution.
592:      * @param CConsoleCommandEvent $event the event parameter
593:      * @since 1.1.11
594:      */
595:     public function onAfterAction($event)
596:     {
597:         $this->raiseEvent('onAfterAction',$event);
598:     }
599: }
600: 
API documentation generated by ApiGen 2.8.0