Microsoft_Console
[ class tree: Microsoft_Console ] [ index: Microsoft_Console ] [ all elements ]

Source for file Command.php

Documentation is available at Command.php

  1. <?php
  2. /**
  3.  * Copyright (c) 2009 - 2011, RealDolmen
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions are met:
  8.  *     * Redistributions of source code must retain the above copyright
  9.  *       notice, this list of conditions and the following disclaimer.
  10.  *     * Redistributions in binary form must reproduce the above copyright
  11.  *       notice, this list of conditions and the following disclaimer in the
  12.  *       documentation and/or other materials provided with the distribution.
  13.  *     * Neither the name of RealDolmen nor the
  14.  *       names of its contributors may be used to endorse or promote products
  15.  *       derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY RealDolmen ''AS IS'' AND ANY
  18.  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20.  * DISCLAIMED. IN NO EVENT SHALL RealDolmen BE LIABLE FOR ANY
  21.  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  22.  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  23.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  24.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  26.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  *
  28.  * @category   Microsoft
  29.  * @package    Microsoft_Console
  30.  * @version    $Id: Exception.php 55733 2011-01-03 09:17:16Z unknown $
  31.  * @copyright  Copyright (c) 2009 - 2011, RealDolmen (http://www.realdolmen.com)
  32.  * @license    http://phpazure.codeplex.com/license
  33.  */
  34.  
  35. /**
  36.  * @see Microsoft_AutoLoader
  37.  */
  38. require_once dirname(__FILE__'/../AutoLoader.php';
  39.  
  40. /**
  41.  * @category   Microsoft
  42.  * @package    Microsoft_Console
  43.  * @copyright  Copyright (c) 2009 - 2011, RealDolmen (http://www.realdolmen.com)
  44.  * @license    http://phpazure.codeplex.com/license
  45.  */
  46. {
  47.     /**
  48.      * The handler.
  49.      *
  50.      * @var array 
  51.      */
  52.     protected $_handler;
  53.     
  54.     /**
  55.      * Gets the handler.
  56.      * 
  57.      * @return array 
  58.      */
  59.     public function getHandler()
  60.     {
  61.         return $this->_handler;
  62.     }
  63.     
  64.     /**
  65.      * Sets the handler.
  66.      * 
  67.      * @param array $handler 
  68.      * @return Microsoft_Console_Command 
  69.      */
  70.     public function setHandler($handler)
  71.     {
  72.         $this->_handler = $handler;
  73.         return $this;
  74.     }
  75.     
  76.     /**
  77.      * Replaces PHP's error handler
  78.      * 
  79.      * @param mixed $errno 
  80.      * @param mixed $errstr 
  81.      * @param mixed $errfile 
  82.      * @param mixed $errline 
  83.      */
  84.     public static function phpstderr($errno$errstr$errfile$errline)
  85.     {
  86.         self::stderr($errno ': Error in ' $errfile ':' $errline ' - ' $errstr);
  87.     }
  88.     
  89.     /**
  90.      * Replaces PHP's exception handler
  91.      * 
  92.      * @param Exception $exception 
  93.      */
  94.     public static function phpstdex($exception)
  95.     {
  96.         self::stderr('Error: ' $exception->getMessage());
  97.     }
  98.     
  99.     /**
  100.      * Writes output to STDERR, followed by a newline (optional)
  101.      * 
  102.      * @param string $errorMessage 
  103.      * @param string $newLine 
  104.      */
  105.     public static function stderr($errorMessage$newLine true)
  106.     {
  107.         if (error_reporting(=== 0{
  108.             return;
  109.         }
  110.         file_put_contents('php://stderr'$errorMessage ($newLine "\r\n" ''));
  111.     }
  112.     
  113.     /**
  114.      * Bootstrap the shell command.
  115.      * 
  116.      * @param array $argv PHP argument values.
  117.      */
  118.     public static function bootstrap($argv)
  119.     {
  120.         // Abort bootstrapping depending on the MICROSOFT_CONSOLE_COMMAND_HOST constant.
  121.         if (defined('MICROSOFT_CONSOLE_COMMAND_HOST'&& strtolower(MICROSOFT_CONSOLE_COMMAND_HOST!= 'console'{
  122.             return;
  123.         }
  124.         
  125.         // Replace error handler
  126.         set_error_handler(array('Microsoft_Console_Command''phpstderr'));
  127.         set_exception_handler(array('Microsoft_Console_Command''phpstdex'));
  128.         
  129.         // Build the application model
  130.         $model self::_buildModel();
  131.         
  132.         // Find a class that corresponds to the $argv[0] script name
  133.         $requiredHandlerName str_replace('.bat'''str_replace('.sh'''str_replace('.php'''strtolower(basename($argv[0])))));
  134.         $handler null;
  135.         foreach ($model as $possibleHandler{
  136.             if ($possibleHandler->handler == strtolower($requiredHandlerName)) {
  137.                 $handler $possibleHandler;
  138.                 break;
  139.             }
  140.         }
  141.         if (is_null($handler)) {
  142.             self::stderr("No class found that implements handler '" $requiredHandlerName "'. Create a class that is named '" $requiredHandlerName "' and extends Microsoft_Console_Command or is decorated with a docblock comment '@command-handler " $requiredHandlerName "'. Make sure it is loaded either through an autoloader or explicitly using require_once().");
  143.             die();
  144.         }
  145.         
  146.         // Find a method that matches the command name
  147.         $command null;
  148.         foreach ($handler->commands as $possibleCommand{
  149.             if (in_array(strtolower(isset($argv[1]$argv[1'<default>')$possibleCommand->aliases)) {
  150.                 $command $possibleCommand;
  151.                 break;
  152.             }
  153.         }
  154.         if (is_null($command)) {
  155.             $commandName (isset($argv[1]$argv[1'<default>');
  156.             self::stderr("No method found that implements command " $commandName ". Create a method in class '" $handler->class "' that is named '" strtolower($commandName"Command' or is decorated with a docblock comment '@command-name " $commandName "'.");
  157.             die();
  158.         }
  159.  
  160.         // Parse parameter values
  161.         $parameterValues array();
  162.         $missingParameterValues array();
  163.         $parameterInputs array_splice($argv2);
  164.         foreach ($command->parameters as $parameter{
  165.             // Default value: null
  166.             $value null;
  167.             
  168.             // Consult value providers for value. First one wins.
  169.             foreach ($parameter->valueproviders as $valueProviderName{
  170.                 if (!class_exists($valueProviderName)) {
  171.                     $valueProviderName 'Microsoft_Console_Command_ParameterSource_' $valueProviderName;
  172.                 }
  173.                 $valueProvider new $valueProviderName();
  174.                 
  175.                 $value $valueProvider->getValueForParameter($parameter$parameterInputs);
  176.                 if (!is_null($value)) {
  177.                     break;
  178.                 }
  179.             }
  180.             if (is_null($value&& $parameter->required{
  181.                 $missingParameterValues[$parameter->aliases[0];
  182.             else if (is_null($value)) {
  183.                 $value $parameter->defaultvalue;
  184.             }
  185.             
  186.             // Set value
  187.             $parameterValues[$value;
  188.             $argvValues[$parameter->aliases[0]] $value;
  189.         }
  190.  
  191.         // Mising parameters?
  192.         if (count($missingParameterValues0{
  193.             self::stderr("Some parameters are missing:\r\n" implode("\r\n"$missingParameterValues));
  194.             die();
  195.         }
  196.         
  197.         // Supply argv in a nice way
  198.         $parameterValues['argv'$parameterInputs;
  199.         
  200.         // Run the command
  201.         $className $handler->class;
  202.         $classInstance new $className();
  203.         $classInstance->setHandler($handler);
  204.         call_user_func_array(array($classInstance$command->method)$parameterValues);
  205.         
  206.         // Restore error handler
  207.         restore_exception_handler();
  208.         restore_error_handler();
  209.     }
  210.     
  211.     /**
  212.      * Builds the handler model.
  213.      * 
  214.      * @return array 
  215.      */
  216.     protected static function _buildModel()
  217.     {
  218.         $model array();
  219.         
  220.         $classes get_declared_classes();
  221.         foreach ($classes as $class{
  222.             $type new ReflectionClass($class);
  223.             
  224.             $handlers self::_findValueForDocComment('@command-handler'$type->getDocComment());
  225.             if (count($handlers== && $type->isSubclassOf('Microsoft_Console_Command')) {
  226.                 // Fallback: if the class extends Microsoft_Console_Command, register it as
  227.                 // a command handler.
  228.                 $handlers[$class
  229.             }
  230.             $handlerDescriptions self::_findValueForDocComment('@command-handler-description'$type->getDocComment());
  231.             $handlerHeaders self::_findValueForDocComment('@command-handler-header'$type->getDocComment());
  232.             $handlerFooters self::_findValueForDocComment('@command-handler-footer'$type->getDocComment());
  233.             
  234.             for ($hi 0$hi count($handlers)$hi++{
  235.                 $handler $handlers[$hi];
  236.                 $handlerDescription = isset($handlerDescriptions[$hi]$handlerDescriptions[$hi: isset($handlerDescriptions[0]$handlerDescriptions[0'';
  237.                 $handlerDescription str_replace('\r\n'"\r\n"$handlerDescription);
  238.                 $handlerDescription str_replace('\n'"\n"$handlerDescription);
  239.                 
  240.                 $handlerModel = (object)array(
  241.                     'handler'     => strtolower($handler),
  242.                     'description' => $handlerDescription,
  243.                     'headers'     => $handlerHeaders,
  244.                     'footers'     => $handlerFooters,
  245.                     'class'       => $class,
  246.                     'commands'    => array()
  247.                 );
  248.                     
  249.                 $methods $type->getMethods();
  250.                 foreach ($methods as $method{
  251.                        $commands self::_findValueForDocComment('@command-name'$method->getDocComment());
  252.                     if (substr($method->getName()-7== 'Command' && !in_array(substr($method->getName()0-7)$commands)) {
  253.                         // Fallback: if the method is named <commandname>Command,
  254.                         // register it as a command.
  255.                         $commands[substr($method->getName()0-7)
  256.                     }
  257.                        for ($x 0$x count($commands)$x++{
  258.                            $commands[$xstrtolower($commands[$x]);
  259.                        }
  260.                        $commands array_unique($commands);
  261.                        $commandDescriptions self::_findValueForDocComment('@command-description'$method->getDocComment());
  262.                        $commandExamples self::_findValueForDocComment('@command-example'$method->getDocComment());
  263.                        
  264.                        if (count($commands0{
  265.                         $command $commands[0];
  266.                         $commandDescription = isset($commandDescriptions[0]$commandDescriptions[0'';
  267.                                 
  268.                         $commandModel = (object)array(
  269.                             'command'     => $command,
  270.                             'aliases'     => $commands,
  271.                             'description' => $commandDescription,
  272.                             'examples'    => $commandExamples,
  273.                             'class'       => $class,
  274.                             'method'      => $method->getName(),
  275.                             'parameters'  => array()
  276.                         );
  277.  
  278.                         $parameters $method->getParameters();
  279.                         $parametersFor self::_findValueForDocComment('@command-parameter-for'$method->getDocComment());
  280.                         for ($pi 0$pi count($parameters)$pi++{
  281.                             // Initialize
  282.                             $parameter $parameters[$pi];
  283.                             $parameterFor null;
  284.                             $parameterForDefaultValue null;
  285.                             
  286.                             // Is it a "catch-all" parameter?
  287.                             if ($parameter->getName(== 'argv'{
  288.                                 continue;
  289.                             }
  290.                             
  291.                             // Find the $parametersFor with the same name defined
  292.                             foreach ($parametersFor as $possibleParameterFor{
  293.                                 $possibleParameterFor explode(' '$possibleParameterFor4);
  294.                                 if ($possibleParameterFor[0== '$' $parameter->getName()) {
  295.                                     $parameterFor $possibleParameterFor;
  296.                                     break;
  297.                                 }
  298.                             }
  299.                             if (is_null($parameterFor)) {
  300.                                 die('@command-parameter-for missing for parameter $' $parameter->getName());    
  301.                             }
  302.                             
  303.                             if (is_null($parameterForDefaultValue&& $parameter->isOptional()) {
  304.                                 $parameterForDefaultValue $parameter->getDefaultValue();
  305.                             }
  306.                             
  307.                             $parameterModel = (object)array(
  308.                                 'name'           => '$' $parameter->getName(),
  309.                                 'defaultvalue'   => $parameterForDefaultValue,
  310.                                 'valueproviders' => explode('|'$parameterFor[1]),
  311.                                 'aliases'        => explode('|'$parameterFor[2]),
  312.                                 'description'    => (isset($parameterFor[3]$parameterFor[3''),
  313.                                 'required'       => (isset($parameterFor[3]strpos(strtolower($parameterFor[3])'required'!== false && strpos(strtolower($parameterFor[3])'required if'=== false false),
  314.                             );
  315.                             
  316.                             // Add to model
  317.                             $commandModel->parameters[$parameterModel;
  318.                         }
  319.  
  320.                         // Add to model
  321.                         $handlerModel->commands[$commandModel;
  322.                        }
  323.                 }
  324.                     
  325.                 // Add to model
  326.                 $model[$handlerModel;
  327.             }
  328.         }
  329.     
  330.         return $model;
  331.     }
  332.     
  333.     /**
  334.      * Finds the value for a specific docComment.
  335.      * 
  336.      * @param string $docCommentName Comment name
  337.      * @param unknown_type $docComment Comment object
  338.      * @return array 
  339.      */
  340.     protected static function _findValueForDocComment($docCommentName$docComment)
  341.     {
  342.         $returnValue array();
  343.         
  344.         $commentLines explode("\n"$docComment);
  345.         foreach ($commentLines as $commentLine{
  346.             if (strpos($commentLine$docCommentName ' '!== false{
  347.                 $returnValue[trim(substr($commentLinestrpos($commentLine$docCommentNamestrlen($docCommentName1));
  348.             }
  349.         }
  350.         
  351.         return $returnValue;
  352.     }
  353.     
  354.     /**
  355.      * Display information on an object
  356.      * 
  357.      * @param object $object Object
  358.      * @param array $propertiesToDump Property names to display
  359.      */
  360.     protected function _displayObjectInformation($object$propertiesToDump array())
  361.     {
  362.         foreach ($propertiesToDump as $property{
  363.             printf('%-16s: %s' "\r\n"$property$object->$property);
  364.         }
  365.         printf("\r\n");
  366.     }
  367.     
  368.     /**
  369.      * Displays the help information.
  370.      * 
  371.      * @command-name <default>
  372.      * @command-name -h
  373.      * @command-name -help
  374.      * @command-description Displays the current help information.
  375.      */
  376.     public function helpCommand({
  377.         $handler $this->getHandler();
  378.         $newline "\r\n";
  379.         
  380.         if (count($handler->headers0{
  381.             foreach ($handler->headers as $header{
  382.                 printf('%s%s'$header$newline);        
  383.             }
  384.             printf($newline);
  385.         }
  386.         printf('%s%s'$handler->description$newline);
  387.         printf($newline);
  388.         printf('Available commands:%s'$newline);
  389.         foreach ($handler->commands as $command{
  390.             $description str_split($command->description50);
  391.             printf('  %-25s %s%s'implode(', '$command->aliases)$description[0]$newline);
  392.             for ($di 1$di count($description)$di++{
  393.                 printf('  %-25s %s%s'''$description[$di]$newline);
  394.             }
  395.             printf($newline);            
  396.             
  397.             if (count($command->parameters0{
  398.                 foreach ($command->parameters as $parameter{
  399.                     $description str_split($parameter->description50);
  400.                     printf('    %-23s %s%s'implode(', '$parameter->aliases)$description[0]$newline);
  401.                     for ($di 1$di count($description)$di++{
  402.                         printf('    %-23s %s%s'''$description[$di]$newline);
  403.                     }
  404.                     printf($newline);
  405.                 }
  406.             }
  407.             printf($newline);
  408.             
  409.             if (count($command->examples0{
  410.                 printf('    Example usage:%s'$newline);
  411.                 foreach ($command->examples as $example{
  412.                     printf('      %s%s'$example$newline);
  413.                 }
  414.                 printf($newline);
  415.             }
  416.         }
  417.         
  418.         if (count($handler->footers0{
  419.             printf($newline);
  420.             foreach ($handler->footers as $footer{
  421.                 printf('%s%s'$footer$newline);        
  422.             }
  423.             printf($newline);
  424.         }
  425.     }
  426. }

Documentation generated on Sat, 03 Dec 2011 13:59:16 +0100 by phpDocumentor 1.4.3