1<?php 2/** 3 * PEAR_Command, command pattern class 4 * 5 * PHP versions 4 and 5 6 * 7 * @category pear 8 * @package PEAR 9 * @author Stig Bakken <ssb@php.net> 10 * @author Greg Beaver <cellog@php.net> 11 * @copyright 1997-2009 The Authors 12 * @license http://opensource.org/licenses/bsd-license.php New BSD License 13 * @link http://pear.php.net/package/PEAR 14 * @since File available since Release 0.1 15 */ 16 17/** 18 * Needed for error handling 19 */ 20require_once 'PEAR.php'; 21require_once 'PEAR/Frontend.php'; 22require_once 'PEAR/XMLParser.php'; 23 24/** 25 * List of commands and what classes they are implemented in. 26 * @var array command => implementing class 27 */ 28$GLOBALS['_PEAR_Command_commandlist'] = array(); 29 30/** 31 * List of commands and their descriptions 32 * @var array command => description 33 */ 34$GLOBALS['_PEAR_Command_commanddesc'] = array(); 35 36/** 37 * List of shortcuts to common commands. 38 * @var array shortcut => command 39 */ 40$GLOBALS['_PEAR_Command_shortcuts'] = array(); 41 42/** 43 * Array of command objects 44 * @var array class => object 45 */ 46$GLOBALS['_PEAR_Command_objects'] = array(); 47 48/** 49 * PEAR command class, a simple factory class for administrative 50 * commands. 51 * 52 * How to implement command classes: 53 * 54 * - The class must be called PEAR_Command_Nnn, installed in the 55 * "PEAR/Common" subdir, with a method called getCommands() that 56 * returns an array of the commands implemented by the class (see 57 * PEAR/Command/Install.php for an example). 58 * 59 * - The class must implement a run() function that is called with three 60 * params: 61 * 62 * (string) command name 63 * (array) assoc array with options, freely defined by each 64 * command, for example: 65 * array('force' => true) 66 * (array) list of the other parameters 67 * 68 * The run() function returns a PEAR_CommandResponse object. Use 69 * these methods to get information: 70 * 71 * int getStatus() Returns PEAR_COMMAND_(SUCCESS|FAILURE|PARTIAL) 72 * *_PARTIAL means that you need to issue at least 73 * one more command to complete the operation 74 * (used for example for validation steps). 75 * 76 * string getMessage() Returns a message for the user. Remember, 77 * no HTML or other interface-specific markup. 78 * 79 * If something unexpected happens, run() returns a PEAR error. 80 * 81 * - DON'T OUTPUT ANYTHING! Return text for output instead. 82 * 83 * - DON'T USE HTML! The text you return will be used from both Gtk, 84 * web and command-line interfaces, so for now, keep everything to 85 * plain text. 86 * 87 * - DON'T USE EXIT OR DIE! Always use pear errors. From static 88 * classes do PEAR::raiseError(), from other classes do 89 * $this->raiseError(). 90 * @category pear 91 * @package PEAR 92 * @author Stig Bakken <ssb@php.net> 93 * @author Greg Beaver <cellog@php.net> 94 * @copyright 1997-2009 The Authors 95 * @license http://opensource.org/licenses/bsd-license.php New BSD License 96 * @version Release: @package_version@ 97 * @link http://pear.php.net/package/PEAR 98 * @since Class available since Release 0.1 99 */ 100class PEAR_Command 101{ 102 // {{{ factory() 103 104 /** 105 * Get the right object for executing a command. 106 * 107 * @param string $command The name of the command 108 * @param object $config Instance of PEAR_Config object 109 * 110 * @return object the command object or a PEAR error 111 */ 112 public static function &factory($command, &$config) 113 { 114 if (empty($GLOBALS['_PEAR_Command_commandlist'])) { 115 PEAR_Command::registerCommands(); 116 } 117 if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { 118 $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; 119 } 120 if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { 121 $a = PEAR::raiseError("unknown command `$command'"); 122 return $a; 123 } 124 $class = $GLOBALS['_PEAR_Command_commandlist'][$command]; 125 if (!class_exists($class)) { 126 require_once $GLOBALS['_PEAR_Command_objects'][$class]; 127 } 128 if (!class_exists($class)) { 129 $a = PEAR::raiseError("unknown command `$command'"); 130 return $a; 131 } 132 $ui =& PEAR_Command::getFrontendObject(); 133 $obj = new $class($ui, $config); 134 return $obj; 135 } 136 137 // }}} 138 // {{{ & getObject() 139 public static function &getObject($command) 140 { 141 $class = $GLOBALS['_PEAR_Command_commandlist'][$command]; 142 if (!class_exists($class)) { 143 require_once $GLOBALS['_PEAR_Command_objects'][$class]; 144 } 145 if (!class_exists($class)) { 146 return PEAR::raiseError("unknown command `$command'"); 147 } 148 $ui =& PEAR_Command::getFrontendObject(); 149 $config = &PEAR_Config::singleton(); 150 $obj = new $class($ui, $config); 151 return $obj; 152 } 153 154 // }}} 155 // {{{ & getFrontendObject() 156 157 /** 158 * Get instance of frontend object. 159 * 160 * @return object|PEAR_Error 161 */ 162 public static function &getFrontendObject() 163 { 164 $a = &PEAR_Frontend::singleton(); 165 return $a; 166 } 167 168 // }}} 169 // {{{ & setFrontendClass() 170 171 /** 172 * Load current frontend class. 173 * 174 * @param string $uiclass Name of class implementing the frontend 175 * 176 * @return object the frontend object, or a PEAR error 177 */ 178 public static function &setFrontendClass($uiclass) 179 { 180 $a = &PEAR_Frontend::setFrontendClass($uiclass); 181 return $a; 182 } 183 184 // }}} 185 // {{{ setFrontendType() 186 187 /** 188 * Set current frontend. 189 * 190 * @param string $uitype Name of the frontend type (for example "CLI") 191 * 192 * @return object the frontend object, or a PEAR error 193 */ 194 public static function setFrontendType($uitype) 195 { 196 $uiclass = 'PEAR_Frontend_' . $uitype; 197 return PEAR_Command::setFrontendClass($uiclass); 198 } 199 200 // }}} 201 // {{{ registerCommands() 202 203 /** 204 * Scan through the Command directory looking for classes 205 * and see what commands they implement. 206 * 207 * @param bool (optional) if FALSE (default), the new list of 208 * commands should replace the current one. If TRUE, 209 * new entries will be merged with old. 210 * 211 * @param string (optional) where (what directory) to look for 212 * classes, defaults to the Command subdirectory of 213 * the directory from where this file (__FILE__) is 214 * included. 215 * 216 * @return bool TRUE on success, a PEAR error on failure 217 */ 218 public static function registerCommands($merge = false, $dir = null) 219 { 220 $parser = new PEAR_XMLParser; 221 if ($dir === null) { 222 $dir = dirname(__FILE__) . '/Command'; 223 } 224 if (!is_dir($dir)) { 225 return PEAR::raiseError("registerCommands: opendir($dir) '$dir' does not exist or is not a directory"); 226 } 227 $dp = @opendir($dir); 228 if (empty($dp)) { 229 return PEAR::raiseError("registerCommands: opendir($dir) failed"); 230 } 231 if (!$merge) { 232 $GLOBALS['_PEAR_Command_commandlist'] = array(); 233 } 234 235 while ($file = readdir($dp)) { 236 if ($file{0} == '.' || substr($file, -4) != '.xml') { 237 continue; 238 } 239 240 $f = substr($file, 0, -4); 241 $class = "PEAR_Command_" . $f; 242 // List of commands 243 if (empty($GLOBALS['_PEAR_Command_objects'][$class])) { 244 $GLOBALS['_PEAR_Command_objects'][$class] = "$dir/" . $f . '.php'; 245 } 246 247 $parser->parse(file_get_contents("$dir/$file")); 248 $implements = $parser->getData(); 249 foreach ($implements as $command => $desc) { 250 if ($command == 'attribs') { 251 continue; 252 } 253 254 if (isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { 255 return PEAR::raiseError('Command "' . $command . '" already registered in ' . 256 'class "' . $GLOBALS['_PEAR_Command_commandlist'][$command] . '"'); 257 } 258 259 $GLOBALS['_PEAR_Command_commandlist'][$command] = $class; 260 $GLOBALS['_PEAR_Command_commanddesc'][$command] = $desc['summary']; 261 if (isset($desc['shortcut'])) { 262 $shortcut = $desc['shortcut']; 263 if (isset($GLOBALS['_PEAR_Command_shortcuts'][$shortcut])) { 264 return PEAR::raiseError('Command shortcut "' . $shortcut . '" already ' . 265 'registered to command "' . $command . '" in class "' . 266 $GLOBALS['_PEAR_Command_commandlist'][$command] . '"'); 267 } 268 $GLOBALS['_PEAR_Command_shortcuts'][$shortcut] = $command; 269 } 270 271 if (isset($desc['options']) && $desc['options']) { 272 foreach ($desc['options'] as $oname => $option) { 273 if (isset($option['shortopt']) && strlen($option['shortopt']) > 1) { 274 return PEAR::raiseError('Option "' . $oname . '" short option "' . 275 $option['shortopt'] . '" must be ' . 276 'only 1 character in Command "' . $command . '" in class "' . 277 $class . '"'); 278 } 279 } 280 } 281 } 282 } 283 284 ksort($GLOBALS['_PEAR_Command_shortcuts']); 285 ksort($GLOBALS['_PEAR_Command_commandlist']); 286 @closedir($dp); 287 return true; 288 } 289 290 // }}} 291 // {{{ getCommands() 292 293 /** 294 * Get the list of currently supported commands, and what 295 * classes implement them. 296 * 297 * @return array command => implementing class 298 */ 299 public static function getCommands() 300 { 301 if (empty($GLOBALS['_PEAR_Command_commandlist'])) { 302 PEAR_Command::registerCommands(); 303 } 304 return $GLOBALS['_PEAR_Command_commandlist']; 305 } 306 307 // }}} 308 // {{{ getShortcuts() 309 310 /** 311 * Get the list of command shortcuts. 312 * 313 * @return array shortcut => command 314 */ 315 public static function getShortcuts() 316 { 317 if (empty($GLOBALS['_PEAR_Command_shortcuts'])) { 318 PEAR_Command::registerCommands(); 319 } 320 return $GLOBALS['_PEAR_Command_shortcuts']; 321 } 322 323 // }}} 324 // {{{ getGetoptArgs() 325 326 /** 327 * Compiles arguments for getopt. 328 * 329 * @param string $command command to get optstring for 330 * @param string $short_args (reference) short getopt format 331 * @param array $long_args (reference) long getopt format 332 * 333 * @return void 334 */ 335 public static function getGetoptArgs($command, &$short_args, &$long_args) 336 { 337 if (empty($GLOBALS['_PEAR_Command_commandlist'])) { 338 PEAR_Command::registerCommands(); 339 } 340 if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { 341 $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; 342 } 343 if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { 344 return null; 345 } 346 $obj = &PEAR_Command::getObject($command); 347 return $obj->getGetoptArgs($command, $short_args, $long_args); 348 } 349 350 // }}} 351 // {{{ getDescription() 352 353 /** 354 * Get description for a command. 355 * 356 * @param string $command Name of the command 357 * 358 * @return string command description 359 */ 360 public static function getDescription($command) 361 { 362 if (!isset($GLOBALS['_PEAR_Command_commanddesc'][$command])) { 363 return null; 364 } 365 return $GLOBALS['_PEAR_Command_commanddesc'][$command]; 366 } 367 368 // }}} 369 // {{{ getHelp() 370 371 /** 372 * Get help for command. 373 * 374 * @param string $command Name of the command to return help for 375 */ 376 public static function getHelp($command) 377 { 378 $cmds = PEAR_Command::getCommands(); 379 if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { 380 $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; 381 } 382 if (isset($cmds[$command])) { 383 $obj = &PEAR_Command::getObject($command); 384 return $obj->getHelp($command); 385 } 386 return false; 387 } 388 // }}} 389}