3 * PEAR_Command, command pattern class
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
18 * Needed for error handling
20 require_once 'PEAR.php';
21 require_once 'PEAR/Frontend.php';
22 require_once 'PEAR/XMLParser.php';
25 * List of commands and what classes they are implemented in.
26 * @var array command => implementing class
28 $GLOBALS['_PEAR_Command_commandlist'] = array();
31 * List of commands and their descriptions
32 * @var array command => description
34 $GLOBALS['_PEAR_Command_commanddesc'] = array();
37 * List of shortcuts to common commands.
38 * @var array shortcut => command
40 $GLOBALS['_PEAR_Command_shortcuts'] = array();
43 * Array of command objects
44 * @var array class => object
46 $GLOBALS['_PEAR_Command_objects'] = array();
49 * PEAR command class, a simple factory class for administrative
52 * How to implement command classes:
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).
59 * - The class must implement a run() function that is called with three
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
68 * The run() function returns a PEAR_CommandResponse object. Use
69 * these methods to get information:
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).
76 * string getMessage() Returns a message for the user. Remember,
77 * no HTML or other interface-specific markup.
79 * If something unexpected happens, run() returns a PEAR error.
81 * - DON'T OUTPUT ANYTHING! Return text for output instead.
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
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().
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: 1.10.5
97 * @link http://pear.php.net/package/PEAR
98 * @since Class available since Release 0.1
105 * Get the right object for executing a command.
107 * @param string $command The name of the command
108 * @param object $config Instance of PEAR_Config object
110 * @return object the command object or a PEAR error
112 public static function &factory($command, &$config)
114 if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
115 PEAR_Command::registerCommands();
117 if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
118 $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
120 if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
121 $a = PEAR::raiseError("unknown command `$command'");
124 $class = $GLOBALS['_PEAR_Command_commandlist'][$command];
125 if (!class_exists($class)) {
126 require_once $GLOBALS['_PEAR_Command_objects'][$class];
128 if (!class_exists($class)) {
129 $a = PEAR::raiseError("unknown command `$command'");
132 $ui =& PEAR_Command::getFrontendObject();
133 $obj = new $class($ui, $config);
139 public static function &getObject($command)
141 $class = $GLOBALS['_PEAR_Command_commandlist'][$command];
142 if (!class_exists($class)) {
143 require_once $GLOBALS['_PEAR_Command_objects'][$class];
145 if (!class_exists($class)) {
146 return PEAR::raiseError("unknown command `$command'");
148 $ui =& PEAR_Command::getFrontendObject();
149 $config = &PEAR_Config::singleton();
150 $obj = new $class($ui, $config);
155 // {{{ & getFrontendObject()
158 * Get instance of frontend object.
160 * @return object|PEAR_Error
162 public static function &getFrontendObject()
164 $a = &PEAR_Frontend::singleton();
169 // {{{ & setFrontendClass()
172 * Load current frontend class.
174 * @param string $uiclass Name of class implementing the frontend
176 * @return object the frontend object, or a PEAR error
178 public static function &setFrontendClass($uiclass)
180 $a = &PEAR_Frontend::setFrontendClass($uiclass);
185 // {{{ setFrontendType()
188 * Set current frontend.
190 * @param string $uitype Name of the frontend type (for example "CLI")
192 * @return object the frontend object, or a PEAR error
194 public static function setFrontendType($uitype)
196 $uiclass = 'PEAR_Frontend_' . $uitype;
197 return PEAR_Command::setFrontendClass($uiclass);
201 // {{{ registerCommands()
204 * Scan through the Command directory looking for classes
205 * and see what commands they implement.
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.
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
216 * @return bool TRUE on success, a PEAR error on failure
218 public static function registerCommands($merge = false, $dir = null)
220 $parser = new PEAR_XMLParser;
222 $dir = dirname(__FILE__) . '/Command';
225 return PEAR::raiseError("registerCommands: opendir($dir) '$dir' does not exist or is not a directory");
227 $dp = @opendir($dir);
229 return PEAR::raiseError("registerCommands: opendir($dir) failed");
232 $GLOBALS['_PEAR_Command_commandlist'] = array();
235 while ($file = readdir($dp)) {
236 if ($file{0} == '.' || substr($file, -4) != '.xml') {
240 $f = substr($file, 0, -4);
241 $class = "PEAR_Command_" . $f;
243 if (empty($GLOBALS['_PEAR_Command_objects'][$class])) {
244 $GLOBALS['_PEAR_Command_objects'][$class] = "$dir/" . $f . '.php';
247 $parser->parse(file_get_contents("$dir/$file"));
248 $implements = $parser->getData();
249 foreach ($implements as $command => $desc) {
250 if ($command == 'attribs') {
254 if (isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
255 return PEAR::raiseError('Command "' . $command . '" already registered in ' .
256 'class "' . $GLOBALS['_PEAR_Command_commandlist'][$command] . '"');
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] . '"');
268 $GLOBALS['_PEAR_Command_shortcuts'][$shortcut] = $command;
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 "' .
284 ksort($GLOBALS['_PEAR_Command_shortcuts']);
285 ksort($GLOBALS['_PEAR_Command_commandlist']);
294 * Get the list of currently supported commands, and what
295 * classes implement them.
297 * @return array command => implementing class
299 public static function getCommands()
301 if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
302 PEAR_Command::registerCommands();
304 return $GLOBALS['_PEAR_Command_commandlist'];
308 // {{{ getShortcuts()
311 * Get the list of command shortcuts.
313 * @return array shortcut => command
315 public static function getShortcuts()
317 if (empty($GLOBALS['_PEAR_Command_shortcuts'])) {
318 PEAR_Command::registerCommands();
320 return $GLOBALS['_PEAR_Command_shortcuts'];
324 // {{{ getGetoptArgs()
327 * Compiles arguments for getopt.
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
335 public static function getGetoptArgs($command, &$short_args, &$long_args)
337 if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
338 PEAR_Command::registerCommands();
340 if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
341 $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
343 if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
346 $obj = &PEAR_Command::getObject($command);
347 return $obj->getGetoptArgs($command, $short_args, $long_args);
351 // {{{ getDescription()
354 * Get description for a command.
356 * @param string $command Name of the command
358 * @return string command description
360 public static function getDescription($command)
362 if (!isset($GLOBALS['_PEAR_Command_commanddesc'][$command])) {
365 return $GLOBALS['_PEAR_Command_commanddesc'][$command];
372 * Get help for command.
374 * @param string $command Name of the command to return help for
376 public static function getHelp($command)
378 $cmds = PEAR_Command::getCommands();
379 if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
380 $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
382 if (isset($cmds[$command])) {
383 $obj = &PEAR_Command::getObject($command);
384 return $obj->getHelp($command);