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 * @version CVS: $Id: Command.php 313023 2011-07-06 19:17:11Z dufuz $
14 * @link http://pear.php.net/package/PEAR
15 * @since File available since Release 0.1
19 * Needed for error handling
21 require_once 'PEAR.php';
22 require_once 'PEAR/Frontend.php';
23 require_once 'PEAR/XMLParser.php';
26 * List of commands and what classes they are implemented in.
27 * @var array command => implementing class
29 $GLOBALS['_PEAR_Command_commandlist'] = array();
32 * List of commands and their descriptions
33 * @var array command => description
35 $GLOBALS['_PEAR_Command_commanddesc'] = array();
38 * List of shortcuts to common commands.
39 * @var array shortcut => command
41 $GLOBALS['_PEAR_Command_shortcuts'] = array();
44 * Array of command objects
45 * @var array class => object
47 $GLOBALS['_PEAR_Command_objects'] = array();
50 * PEAR command class, a simple factory class for administrative
53 * How to implement command classes:
55 * - The class must be called PEAR_Command_Nnn, installed in the
56 * "PEAR/Common" subdir, with a method called getCommands() that
57 * returns an array of the commands implemented by the class (see
58 * PEAR/Command/Install.php for an example).
60 * - The class must implement a run() function that is called with three
63 * (string) command name
64 * (array) assoc array with options, freely defined by each
65 * command, for example:
66 * array('force' => true)
67 * (array) list of the other parameters
69 * The run() function returns a PEAR_CommandResponse object. Use
70 * these methods to get information:
72 * int getStatus() Returns PEAR_COMMAND_(SUCCESS|FAILURE|PARTIAL)
73 * *_PARTIAL means that you need to issue at least
74 * one more command to complete the operation
75 * (used for example for validation steps).
77 * string getMessage() Returns a message for the user. Remember,
78 * no HTML or other interface-specific markup.
80 * If something unexpected happens, run() returns a PEAR error.
82 * - DON'T OUTPUT ANYTHING! Return text for output instead.
84 * - DON'T USE HTML! The text you return will be used from both Gtk,
85 * web and command-line interfaces, so for now, keep everything to
88 * - DON'T USE EXIT OR DIE! Always use pear errors. From static
89 * classes do PEAR::raiseError(), from other classes do
90 * $this->raiseError().
93 * @author Stig Bakken <ssb@php.net>
94 * @author Greg Beaver <cellog@php.net>
95 * @copyright 1997-2009 The Authors
96 * @license http://opensource.org/licenses/bsd-license.php New BSD License
97 * @version Release: 1.9.4
98 * @link http://pear.php.net/package/PEAR
99 * @since Class available since Release 0.1
106 * Get the right object for executing a command.
108 * @param string $command The name of the command
109 * @param object $config Instance of PEAR_Config object
111 * @return object the command object or a PEAR error
116 function &factory($command, &$config)
118 if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
119 PEAR_Command::registerCommands();
121 if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
122 $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
124 if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
125 $a = PEAR::raiseError("unknown command `$command'");
128 $class = $GLOBALS['_PEAR_Command_commandlist'][$command];
129 if (!class_exists($class)) {
130 require_once $GLOBALS['_PEAR_Command_objects'][$class];
132 if (!class_exists($class)) {
133 $a = PEAR::raiseError("unknown command `$command'");
136 $ui =& PEAR_Command::getFrontendObject();
137 $obj = &new $class($ui, $config);
143 function &getObject($command)
145 $class = $GLOBALS['_PEAR_Command_commandlist'][$command];
146 if (!class_exists($class)) {
147 require_once $GLOBALS['_PEAR_Command_objects'][$class];
149 if (!class_exists($class)) {
150 return PEAR::raiseError("unknown command `$command'");
152 $ui =& PEAR_Command::getFrontendObject();
153 $config = &PEAR_Config::singleton();
154 $obj = &new $class($ui, $config);
159 // {{{ & getFrontendObject()
162 * Get instance of frontend object.
164 * @return object|PEAR_Error
167 function &getFrontendObject()
169 $a = &PEAR_Frontend::singleton();
174 // {{{ & setFrontendClass()
177 * Load current frontend class.
179 * @param string $uiclass Name of class implementing the frontend
181 * @return object the frontend object, or a PEAR error
184 function &setFrontendClass($uiclass)
186 $a = &PEAR_Frontend::setFrontendClass($uiclass);
191 // {{{ setFrontendType()
194 * Set current frontend.
196 * @param string $uitype Name of the frontend type (for example "CLI")
198 * @return object the frontend object, or a PEAR error
201 function setFrontendType($uitype)
203 $uiclass = 'PEAR_Frontend_' . $uitype;
204 return PEAR_Command::setFrontendClass($uiclass);
208 // {{{ registerCommands()
211 * Scan through the Command directory looking for classes
212 * and see what commands they implement.
214 * @param bool (optional) if FALSE (default), the new list of
215 * commands should replace the current one. If TRUE,
216 * new entries will be merged with old.
218 * @param string (optional) where (what directory) to look for
219 * classes, defaults to the Command subdirectory of
220 * the directory from where this file (__FILE__) is
223 * @return bool TRUE on success, a PEAR error on failure
228 function registerCommands($merge = false, $dir = null)
230 $parser = new PEAR_XMLParser;
232 $dir = dirname(__FILE__) . '/Command';
235 return PEAR::raiseError("registerCommands: opendir($dir) '$dir' does not exist or is not a directory");
237 $dp = @opendir($dir);
239 return PEAR::raiseError("registerCommands: opendir($dir) failed");
242 $GLOBALS['_PEAR_Command_commandlist'] = array();
245 while ($file = readdir($dp)) {
246 if ($file{0} == '.' || substr($file, -4) != '.xml') {
250 $f = substr($file, 0, -4);
251 $class = "PEAR_Command_" . $f;
253 if (empty($GLOBALS['_PEAR_Command_objects'][$class])) {
254 $GLOBALS['_PEAR_Command_objects'][$class] = "$dir/" . $f . '.php';
257 $parser->parse(file_get_contents("$dir/$file"));
258 $implements = $parser->getData();
259 foreach ($implements as $command => $desc) {
260 if ($command == 'attribs') {
264 if (isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
265 return PEAR::raiseError('Command "' . $command . '" already registered in ' .
266 'class "' . $GLOBALS['_PEAR_Command_commandlist'][$command] . '"');
269 $GLOBALS['_PEAR_Command_commandlist'][$command] = $class;
270 $GLOBALS['_PEAR_Command_commanddesc'][$command] = $desc['summary'];
271 if (isset($desc['shortcut'])) {
272 $shortcut = $desc['shortcut'];
273 if (isset($GLOBALS['_PEAR_Command_shortcuts'][$shortcut])) {
274 return PEAR::raiseError('Command shortcut "' . $shortcut . '" already ' .
275 'registered to command "' . $command . '" in class "' .
276 $GLOBALS['_PEAR_Command_commandlist'][$command] . '"');
278 $GLOBALS['_PEAR_Command_shortcuts'][$shortcut] = $command;
281 if (isset($desc['options']) && $desc['options']) {
282 foreach ($desc['options'] as $oname => $option) {
283 if (isset($option['shortopt']) && strlen($option['shortopt']) > 1) {
284 return PEAR::raiseError('Option "' . $oname . '" short option "' .
285 $option['shortopt'] . '" must be ' .
286 'only 1 character in Command "' . $command . '" in class "' .
294 ksort($GLOBALS['_PEAR_Command_shortcuts']);
295 ksort($GLOBALS['_PEAR_Command_commandlist']);
304 * Get the list of currently supported commands, and what
305 * classes implement them.
307 * @return array command => implementing class
312 function getCommands()
314 if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
315 PEAR_Command::registerCommands();
317 return $GLOBALS['_PEAR_Command_commandlist'];
321 // {{{ getShortcuts()
324 * Get the list of command shortcuts.
326 * @return array shortcut => command
331 function getShortcuts()
333 if (empty($GLOBALS['_PEAR_Command_shortcuts'])) {
334 PEAR_Command::registerCommands();
336 return $GLOBALS['_PEAR_Command_shortcuts'];
340 // {{{ getGetoptArgs()
343 * Compiles arguments for getopt.
345 * @param string $command command to get optstring for
346 * @param string $short_args (reference) short getopt format
347 * @param array $long_args (reference) long getopt format
354 function getGetoptArgs($command, &$short_args, &$long_args)
356 if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
357 PEAR_Command::registerCommands();
359 if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
360 $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
362 if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
365 $obj = &PEAR_Command::getObject($command);
366 return $obj->getGetoptArgs($command, $short_args, $long_args);
370 // {{{ getDescription()
373 * Get description for a command.
375 * @param string $command Name of the command
377 * @return string command description
382 function getDescription($command)
384 if (!isset($GLOBALS['_PEAR_Command_commanddesc'][$command])) {
387 return $GLOBALS['_PEAR_Command_commanddesc'][$command];
394 * Get help for command.
396 * @param string $command Name of the command to return help for
401 function getHelp($command)
403 $cmds = PEAR_Command::getCommands();
404 if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
405 $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
407 if (isset($cmds[$command])) {
408 $obj = &PEAR_Command::getObject($command);
409 return $obj->getHelp($command);