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

Source for file Abstract.php

Documentation is available at Abstract.php

  1. <?php
  2. /**
  3.  * Console Library
  4.  *
  5.  * LICENSE
  6.  *
  7.  * "THE BEER-WARE LICENSE" (Revision 42):
  8.  * "Sven Strittmatter" <ausserirdisch@sven-space.de> wrote this file.
  9.  * As long as you retain this notice you can do whatever you want with
  10.  * this stuff. If we meet some day, and you think this stuff is worth it,
  11.  * you can buy me a beer in return.
  12.  *
  13.  * $Author: sxs $
  14.  * $Revision: 161 $
  15.  * 
  16.  * @category    Console
  17.  * @package     Console_Application
  18.  * @copyright   Copyright (c) 2009 Sven Strittmatter
  19.  */
  20.  
  21. /**
  22.  * Console_Application_Interface.
  23.  *
  24.  * @see Console_Application_Interface
  25.  */
  26. require_once('Console/Application/Interface.php');
  27. /**
  28.  * Console_Enviroment.
  29.  *
  30.  * @see Console_Enviroment
  31.  */
  32. require_once('Console/Enviroment.php');
  33. /**
  34.  * Console_Exception.
  35.  *
  36.  * @see Console_Exception
  37.  */
  38. require_once('Console/Exception.php');
  39. /**
  40.  * Console_Exception_MissingParameter.
  41.  *
  42.  * @see Console_Exception_MissingParameter
  43.  */
  44. require_once('Console/Exception/MissingParameter.php');
  45.  
  46. /**
  47.  * Template method class for CLI commands.
  48.  *
  49.  * @see HelloWorldApplication for an example implementation.
  50.  *
  51.  * @abstract
  52.  * @category   Console
  53.  * @package    Console_Application
  54.  * @uses       Console_Application_Interface
  55.  * @uses       Console_Exception
  56.  * @copyright  Copyright (c) 2009 Sven Strittmatter
  57.  */
  58.     implements Console_Application_Interface {
  59.     /**
  60.      * Name of the script. Appended with 'Application' its the
  61.      * Classname of your concrete implementation.
  62.      *
  63.      * @access protected
  64.      * @var string 
  65.      */
  66.     protected $scriptname;
  67.     /**
  68.      * Flag signals wheter the object is executed or not.
  69.      *
  70.      * @access private
  71.      * @var boolean 
  72.      */
  73.     private $isExecuted;
  74.     /**
  75.      * Saves old php ini settings in for restoring.
  76.      *
  77.      * @access private
  78.      * @var array 
  79.      */
  80.     private $iniSet;
  81.     /**
  82.      * Flag signals whether the object is in verbose mode or not.
  83.      *
  84.      * @access private
  85.      * @var boolean 
  86.      */
  87.     private $isVerbose;
  88.  
  89.     /**
  90.      * On construction time a sapiCheck is done for CLI sapi.
  91.      * The php enviroment will be set and some default signal handlers are
  92.      * registered.
  93.      *
  94.      * Throws a excpetion if the php enviroment ist not the command line.
  95.      *
  96.      * @access public
  97.      * @param  string $scriptname 
  98.      * @param  int $maxExecTime Optional;
  99.      * @param  string $memoryLimit Optional;
  100.      * @throws RuntimeException if registerig signal handlers fails
  101.      * @throws RuntimeException if sapi check fails
  102.      */
  103.     public function __construct($scriptname$maxExecTime 60$memoryLimit '128M'{
  104.         $this->scriptname = strtolower($scriptname'.sh';
  105.         $this->isExecuted false;
  106.         $this->iniSet     array();
  107.         $this->isVerbose  false;
  108.  
  109.         if (!Console_Enviroment::isSapiCli()) {
  110.             $message  'This is a command line script. ';
  111.             $message .= 'You have to call the shell script on ';
  112.             $message .= 'a terminal like bash.';
  113.             throw new RuntimeException($message);
  114.         }
  115.         
  116.         $this->setPhpEnviroment($memoryLimit$maxExecTime);
  117.         $this->registerSignalHandlers();
  118.     }
  119.  
  120.     /**
  121.      * Restores the php ini settings stored in $iniSet.
  122.      *
  123.      * @access private
  124.      */
  125.     private function resetPhpEnviroment({
  126.         foreach ($this->iniSet as $name => $value{
  127.             $this->iniSet($name$value);
  128.         }
  129.     }
  130.  
  131.     /**
  132.      * Returns whether the application object is executed or not.
  133.      *
  134.      * @access public
  135.      * @return bool 
  136.      */
  137.     public function isExecuted({
  138.         return $this->isExecuted;
  139.     }
  140.  
  141.     /**
  142.      * Returns whether the application object is verbose or not.
  143.      * This is set by the comandline option -v (in
  144.      * Console_Application_Abstract::findConsoleParameters()).
  145.      *
  146.      * @access protectd
  147.      * @return bool 
  148.      */
  149.     protected function isVerbose({
  150.         return $this->isVerbose;
  151.     }
  152.  
  153.     /**
  154.      * Sets object executed.
  155.      *
  156.      * @access protected
  157.      */
  158.     protected function setExecuted({
  159.         $this->isExecuted true;
  160.     }
  161.  
  162.     /**
  163.      * This method wraps the php internal ini_set() that way,
  164.      * that it returns the old value.
  165.      * 
  166.      * @access protected
  167.      * @param  string $name 
  168.      * @param  mixed $value 
  169.      * @return mixed 
  170.      */
  171.     protected function iniSet($name$value{
  172.         $this->iniSet[$nameini_get($name);
  173.         ini_set($name$value);
  174.  
  175.         return $this->iniSet[$name];
  176.     }
  177.  
  178.     /**
  179.      * Template method. Try to run some method stubs in this order:
  180.      * <ol>
  181.      *  <li>Console_Application_Abstract::findConsoleParameters()</li>
  182.      *  <li>Console_Application_Abstract::setUp()</li>
  183.      *  <li>Console_Application_Abstract::run()</li>
  184.      *  <li>Console_Application_Abstract::tearDown()</li>
  185.      * </ol>
  186.      *
  187.      * If Console_Application_Abstract::findConsoleParameters() returns true the
  188.      * script execution aborts imediately.
  189.      *
  190.      * If in the templateed method structure any exception occures it is catched
  191.      * an the method Console_Application_Abstract::onError() is called. The
  192.      * exception object is passed to it.
  193.      *
  194.      * After that procedure two additional tear down methods will be called:
  195.      * <ol>
  196.      *  <li>Console_Application_Abstract::setExecuted()</li>
  197.      *  <li>Console_Application_Abstract::resetPhpEnviroment()</li>
  198.      * </ol>
  199.      *
  200.      * @final
  201.      * @access public
  202.      */
  203.     final public function execute({
  204.         try {
  205.             if (!$this->findConsoleParameters()) {
  206.                 return;
  207.             }
  208.  
  209.             $this->setUp();
  210.             $this->run();
  211.             $this->tearDown();
  212.         catch (Exception $e{
  213.             $this->onError($e);
  214.         }
  215.  
  216.         $this->setExecuted();
  217.         $this->resetPhpEnviroment();
  218.     }
  219.  
  220.     /**
  221.      * This method listens by default to the console parameters -v and -h.
  222.      * By default -v enables the verbose mode
  223.      * (see Console_Application_Abstract::isVerbose()).
  224.      *
  225.      * By default -h calls Console_Application_Abstract::printHelpMessage() and
  226.      * returns with false.
  227.      *
  228.      * To retrieve custom options overwite this mithed. Call the method an checks
  229.      * against false. Then check your options. If a required option is not
  230.      * set you should throw an Console_Exception_MissingParameter. This errors
  231.      * are handled in an default way to the console user
  232.      * (see Console_Exception_MissingParameter::onError()).
  233.      *
  234.      * Example implementation. Full example @see HelloWorldApplication
  235.      * <code>
  236.      * protected function findConsoleParameters() {
  237.      *  $options = getopt('n:s:');
  238.      *
  239.      *  if (!parent::findConsoleParameters()) {
  240.      *       return false;
  241.      *   }
  242.      *
  243.      *   if (isset($options['n']) && !empty($options['n'])) {
  244.      *       $this->name = $options['n'];
  245.      *   }
  246.      *
  247.      *   if (isset($options['s']) && !empty($options['s'])) {
  248.      *       $this->sleep = (int) $options['s'];
  249.      *   }
  250.      *
  251.      *   return true;
  252.      * }
  253.      * </code>
  254.      *
  255.      * To brek the script if a user omitted a required console option you
  256.      * should implement it that way, because the onError() method handles
  257.      * Console_Exception_MissingParameter by default with nice user experience.
  258.      *
  259.      * <code>
  260.      * protected function findConsoleParameters() {
  261.      *  $options = getopt('n:');
  262.      *
  263.      *  if (!parent::findConsoleParameters()) {
  264.      *       return false;
  265.      *   }
  266.      *
  267.      *   if (isset($options['n']) && !empty($options['n'])) {
  268.      *       $this->name = $options['n'];
  269.      *   } else {
  270.      *      throw new Console_Exception_MissingParameter('n');
  271.      *   }
  272.      *
  273.      *   return true;
  274.      * }
  275.      * </code>
  276.      *
  277.      * For more details about getting options by getopt()
  278.      * @link http://de.php.net/manual/en/function.getopt.php
  279.      * 
  280.      * @access protected
  281.      * @return bool Must return false to abort script execution!
  282.      */
  283.     protected function findConsoleParameters({
  284.         $options getopt('hv');
  285.  
  286.         if (isset($options['h'])) {
  287.             $this->getHelpMessage();
  288.             return false;
  289.         }
  290.  
  291.         if (isset($options['v'])) {
  292.             $this->isVerbose true;
  293.         }
  294.  
  295.         return true;
  296.     }
  297.  
  298.     /**
  299.      * Template method stub. Overwrite this method to hook the set up phase of
  300.      * your script. This method is called after
  301.      * Console_Application_Abstract::findConsoleParameters(),
  302.      * unless it returns false. And before Console_Application_Abstract::run().
  303.      *
  304.      * By default this method does nothing!
  305.      *
  306.      * Return values are not evaluated.
  307.      *
  308.      * @access protected
  309.      */
  310.     protected function setUp({
  311.         
  312.     }
  313.  
  314.     /**
  315.      * You need to implement this method. Put your stuff to do here.
  316.      *
  317.      * Return values are not evaluated.
  318.      *
  319.      * @abstract
  320.      * @accedd proteced
  321.      */
  322.  
  323.     abstract protected function run();
  324.     /**
  325.      * Template method stub. Overwrite this method to hook the tear down phase
  326.      * of your script. This method is called after
  327.      * Console_Application_Abstract::run(), unless any exception was throwed.
  328.      * And before Console_Application_Abstract::setExecuted().
  329.      *
  330.      * By default this method does nothing!
  331.      *
  332.      * Return values are not evaluated.
  333.      *
  334.      * @access protected
  335.      */
  336.     protected function tearDown({
  337.         
  338.     }
  339.  
  340.     /**
  341.      * This method is called if in the three followed methods a exception was
  342.      * throwed:
  343.      * <ul>
  344.      *  <li>Console_Application_Abstract::findConsoleParameters()</li>
  345.      *  <li>Console_Application_Abstract::setUp()</li>
  346.      *  <li>Console_Application_Abstract::run()</li>
  347.      *  <li>Console_Application_Abstract::tearDown()</li>
  348.      * </ul>
  349.      *
  350.      * Exceptions of the (sub)type Console_Exception are handled by defaukt
  351.      * in a special way:
  352.      * <dl>
  353.      *      <dt>Console_Exception_MissingParameter</dt>
  354.      *      <dd>The exeption message and the return string of getUsage() will
  355.      *      be echoed.</dd>
  356.      *      <dt>Console_Exception</dt>
  357.      *      <dd>The excpetion message will be echoed.</dd>
  358.      * </dl>
  359.      *
  360.      * @todo php catchabel errors abfangen: error_handler setzen.
  361.      * @param mixed 
  362.      */
  363.     protected function onError($errorData{
  364.         if ($errorData instanceof Console_Exception_MissingParameter{
  365.             $this->echoMsg($errorData->getMessage());
  366.             $this->echoMsg($this->getUsage());
  367.         else if ($errorData instanceof Console_Exception{
  368.             $this->echoMsg($errorData->getMessage());
  369.         else {
  370.             $this->echoMsg('Fatal error occured! Script aborts...');
  371.         }
  372.     }
  373.  
  374.     /**
  375.      * Returns a help message. Its called by default object behavier, if you
  376.      * suply -h to the script. By default it returns a line break formatted
  377.      * help message like:
  378.      *
  379.      * <pre>
  380.      *  This is a sample console application. It prints some hello world statements.
  381.      *
  382.      *  Usage:  {$scriptName} [-h] [-v]
  383.      *          {$scriptName} -v : Sets the script in verbose mode.
  384.      *          {$scriptName} -h : prints this help message.
  385.      *
  386.      *  For bug reporting or issues contact: foo@bar.de
  387.      * </pre>
  388.      * 
  389.      * You can customize the help message your wy. See an example implementation
  390.      * (@see HelloWorldApplication)
  391.      * <code>
  392.      * protected function getHelpMessage($author = '...', $email = '...') {
  393.      *      $message  = "This is a sample console application. It prints some ";
  394.      *      $message .= "hello world statements." . PHP_EOL . PHP_EOL;
  395.      *      $message .= $this->getUsage() . PHP_EOL;
  396.      *      $message .= "\t{$this->scriptname} -n : You can specify a name to ";
  397.      *      $message .= §be hellowed" . PHP_EOL;
  398.      *      $message .= "\t{$this->scriptname} -s : You can specify the seconds ";
  399.      *      $message .= §to sleep between hello and name."  . PHP_EOL;
  400.      *      $message .= parent::getHelpMessage($author, $email);
  401.      *
  402.      *      throw new Console_Exception($message);
  403.      * }
  404.      * </code>
  405.      *
  406.      * @access protected
  407.      * @param string $author 
  408.      * @param string $email 
  409.      * @return string 
  410.      */
  411.     public function getHelpMessage($author ''$email 'foo@bar.de'{
  412.         $message '';
  413.  
  414.         $message .= "\t{$this->scriptname} -v : Sets the script in verbose mode.";
  415.         $message .=  PHP_EOL;
  416.         $message .= "\t{$this->scriptname} -h : prints this help message.";
  417.         $message .=  PHP_EOL . PHP_EOL;
  418.  
  419.         if (!empty($author)) {
  420.             $message .= "Written by $author."  . PHP_EOL;
  421.         }
  422.  
  423.         $message .= "For bug reporting or issues contact: $email"  . PHP_EOL;
  424.  
  425.         return $message;
  426.     }
  427.  
  428.     /**
  429.      * Returns a usage string like:
  430.      * <pre>
  431.      * Usage: {$scriptName} {$options} [-h] [-v]
  432.      * </pre>
  433.      *
  434.      * By example implementation (@see HelloWorldApplication) its:
  435.      * <pre>
  436.      * Usage:  helloworld.sh [-n] [-s] [-h] [-v]
  437.      * </pre>
  438.      *
  439.      * @param string $options
  440.      * @return string
  441.      */
  442.     public function getUsage($options = '') {
  443.         return "Usage:\t{$this->scriptname" .
  444.                ( ('' !== $options) ? $options . ' ' : '' ) .
  445.                '[-h] [-v]';
  446.     }
  447.  
  448.     /**
  449.      * Echoes a string appended with PHP_EOL.
  450.      *
  451.      * If you call it without parameter it makes newlines ;-)
  452.      *
  453.      * @param string $msg
  454.      */
  455.     public function echoMsg($msg = '') {
  456.         if (defined('TESTS_CONSOLE_APPLICATION')) {
  457.             return $msg . PHP_EOL;
  458.         } else {
  459.             echo $msg . PHP_EOL;
  460.         }
  461.     }
  462.  
  463.     /**
  464.      * Registers some signal handlers:
  465.      * <dl>
  466.      *  <dd>SIGTERM</dd>
  467.      *  <dt>Console_Application_Abstract::signalTerm()</dt>
  468.      *  <dd>SIGINT</dd>
  469.      *  <dt>Console_Application_Abstract::signalInt()</dt>
  470.      *  <dd>SIGHUP</dd>
  471.      *  <dt>Console_Application_Abstract::signalHangUp()</dt>
  472.      * </dl>
  473.      *
  474.      * IS called on construction time. Overwrite this methid
  475.      * @access protected
  476.      * @throws RuntimeException If pcntl_signal() doesnt exists
  477.      *                          @link http://de.php.net/manual/en/pcntl.setup.php
  478.      * @throws RuntimeException If pcntl_signal() failes.
  479.      */
  480.     protected function registerSignalHandlers() {
  481.         if (!$this->isPcntlEnabled()) {
  482.             $messgae  = 'The function pcntl_signal() is not available! ';
  483.             $messgae .= 'Its neccessary to compile PHP with the option --enable-pcntl.';
  484.             throw new RuntimeException($messgae);
  485.         }
  486.  
  487.         $message = 'Cant register signal handler for ';
  488.  
  489.         if (!pcntl_signal(SIGTERM, array(&$this, 'signalTerm'))) {
  490.             throw new RuntimeException($message . 'SIGTERM!');
  491.         }
  492.  
  493.         if (!pcntl_signal(SIGINT, array(&$this, 'signalInt'))) {
  494.             throw new RuntimeException($message . ' SIGINT!');
  495.         }
  496.  
  497.         if (!pcntl_signal(SIGHUP, array(&$this, 'signalHangUp'))) {
  498.             throw new RuntimeException($message . ' SIGHUP!');
  499.         }
  500.     }
  501.  
  502.     protected function isPcntlEnabled() {
  503.         return function_exists('pcntl_signal');
  504.     }
  505.  
  506.     /**
  507.      * Signal handler registered by Console_Application_Abstract::registerSignalHandlers().
  508.      * By default it echoes a message and calls Console_Application_Abstract::tearDown().
  509.      *
  510.      * Overwrite this method to react on SIGTERM.
  511.      *
  512.      * @access public neccesary for pcntl_signal()
  513.      * @param int $signal
  514.      */
  515.     public function signalTerm($signal) {
  516.         $this->echoMsg('Script aborted by SIGTERM!');
  517.         $this->tearDown();
  518.     }
  519.  
  520.     /**
  521.      * Signal handler registered by Console_Application_Abstract::registerSignalHandlers().
  522.      * By default it echoes a message and calls Console_Application_Abstract::tearDown().
  523.      *
  524.      * Overwrite this method to react on SIGINT.
  525.      *
  526.      * @access public neccesary for pcntl_signal()
  527.      * @param int $signal
  528.      */
  529.     public function signalInt($signal) {
  530.         $this->echoMsg('Script aborted by SIGINT!');
  531.         $this->tearDown();
  532.     }
  533.  
  534.     /**
  535.      * Signal handler registered by Console_Application_Abstract::registerSignalHandlers().
  536.      * By default it echoes a message and calls Console_Application_Abstract::tearDown().
  537.      *
  538.      * Overwrite this method to react on SIGHUP.
  539.      *
  540.      * @access public neccesary for pcntl_signal()
  541.      * @param int $signal
  542.      */
  543.     public function signalHangUp($signal) {
  544.         $this->echoMsg('Script aborted by SIGHUP!');
  545.         $this->tearDown();
  546.     }
  547.  
  548.     /**
  549.      * Sets the  the php enviroment by ini settings to a proper default.
  550.      * These are:
  551.      * <ul>
  552.      *      <li>memory_limit</li>
  553.      *      <li>max_execution_time</li>
  554.      *      <li>html_errors = false</li>
  555.      *      <li>implicit_flush = true</li>
  556.      * </ul>
  557.      *
  558.      * The old values are stored in Console_Application_Abstract::iniSet array.
  559.      * So they can be restored by Console_Application_Abstract::resetPhpEnviroment().
  560.      *
  561.      * If you wanne make some custom ini settings in your script overwrite
  562.      * this method this way:
  563.      * <code>
  564.      * protected function setPhpEnviroment($memoryLimit, $maxExecutionTime) {
  565.      *  parent::setPhpEnviroment($memoryLimit, $maxExecutionTime);
  566.      *  $this->iniSet('YOUR_SETTED_INI_NAME', 'YOUR_CUSTOM_VALUE');
  567.      * }
  568.      * <code>
  569.      *
  570.      * If you do it this wy its guranted that the enviroment is resetted
  571.      * properly after execution.
  572.      *
  573.      * Do not use ini_set() directly!
  574.      *
  575.      *
  576.      * @param string $memoryLimit
  577.      * @param int $maxExecutionTime
  578.      */
  579.     protected function setPhpEnviroment($memoryLimit, $maxExecutionTime) {
  580.         $this->iniSet('memory_limit'$memoryLimit);
  581.         $this->iniSet('max_execution_time'$maxExecutionTime);
  582.         $this->iniSet('html_errors'false);
  583.         $this->iniSet('implicit_flush'true);
  584.     }

Documentation generated on Mon, 17 Aug 2009 15:52:02 +0200 by phpDocumentor 1.4.2