HTML/FlexyFramework/Cli.php
[pear] / HTML / FlexyFramework / Cli.php
1 <?php
2
3 /**
4  *
5  * handles the cli features of Flexy Framework.
6  *
7  *
8  * usage :
9  *
10  *   $x = new HTML_FlexyFramework_Cli($ff);
11  *   $x->cliHelp(); // summary of all classes which can be run with cli.
12  *             (contain static $cli_desc)
13  *   $x->cliParse($classname);
14  *
15  *
16  */
17 class HTML_FlexyFramework_Cli
18 {
19     
20     /**
21      * Default options that allow modification of the framewoek behaviour
22      * 
23      *
24      */
25     
26       
27     static $cli_opts = array(
28         
29         // this is a flag argument
30         'pman-nodatabase' => array(
31             'desc' => 'Turn off database',
32             'max' => 0,
33         )
34          
35     );
36     
37     
38     
39     
40     
41     
42     
43     var $ff; // the Framework instance.
44     
45     
46     function __construct($ff)
47     {
48         $this->ff = $ff;
49     }
50     /**
51       * looks for Cli.php files and runs available() on them
52      * this should return a list of classes that can be used.
53      * - we should the load each one, and find the summary..
54      *
55      *
56      */
57     function cliHelp()
58     {
59      
60         $fn = basename($_SERVER["SCRIPT_FILENAME"]);
61       
62         echo "\n-------------------------------------------------
63 FlexyFramework Cli Application Usage:
64
65 #php -d include_path=.:/var/www/pear $fn [COMMAND] --help
66 or
67 #php  $fn [COMMAND] --help
68
69 -------------------------------------------------
70 Available commands:
71
72 ";
73         // add cli files..
74         //$this->cliShortHelp('Database');
75         
76         
77         $p = dirname(realpath($_SERVER["SCRIPT_FILENAME"])); 
78         $pr = $this->ff->project;
79         
80         $this->cliHelpSearch($p,$pr);
81         if (!empty($this->ff->projectExtends)) {
82             foreach($this->ff->projectExtends as $pr) {
83                 $this->cliHelpSearch($p,$pr);
84             }
85         }
86         
87         echo "\n\n";
88         exit;
89     }
90     
91     
92     function cliHelpSearch($p,$pr, $path=false) {
93         
94         
95         
96         $full_path = array($p,$pr);
97         $class_path = array();
98         if ($path !== false)  {
99             $full_path= array_merge($full_path, $path);
100             $class_path = array_merge($class_path, $path);
101         }
102         //print_r("CHKDIR:    ". implode('/', $full_path)."\n");
103         
104         foreach(scandir(implode('/', $full_path)) as $d) {
105             
106             if (!strlen($d) || $d[0] == '.') {
107                 continue;
108             }
109             $chk = $full_path;
110             $chk[] = $d;
111             
112             $clp = $class_path;
113             
114             
115             
116             //print_r("CHK:          " . implode('/', $chk)."\n");
117             // is it a file.. and .PHP...
118             if (!is_dir(implode('/', $chk))) {
119                 if (!preg_match('/\.php$/',$d)) {
120                     continue;
121                 }
122                 $clp[] = preg_replace('/\.php$/','', $d);
123                 
124                 //print_r("CLP:          " . implode('/', $clp)."\n");
125                 $this->cliShortHelp(implode('/', $clp ));
126                 continue;
127             }
128             // skip special directories..
129             if ($d == 'templates') {
130                 continue;
131             }
132             if ($d == 'DataObjects') {
133                 continue;
134             }
135             
136             
137             $clp[] = $d;
138             // otherwise recurse...
139             //print_r("RECURSE:        " . implode('/', $clp)."\n");
140             
141             $this->cliHelpSearch($p,$pr, $clp);
142             
143             
144         }
145         
146         //print_r("COMPLETE:    ". implode('/', $full_path)."\n");
147         
148         
149         
150         
151     }
152     
153     
154     
155     
156     /**
157      * creates an instance of all the CLI classes and prints out class + title..
158      *
159      */
160     function cliShortHelp($p) { 
161         ////print_r("CHKFILE:         $p\n ");
162         list($classname,$subRequest) = $this->ff->requestToClassName($p,FALSE);
163         //var_dump($classname);
164         // does it have a description.
165         try { 
166             $cls = new ReflectionClass($classname);        
167             $val = $cls->getStaticPropertyValue('cli_desc');
168         } catch (Exception $e) {
169             return;
170         }
171         if (empty($val)) {
172             return;
173         }
174         echo str_pad($p,40," ") . $val ."\n";
175         
176         
177          
178     }
179      
180     /**
181     * cliParse - parse command line arguments, and return the values.
182     *  Will die with help message if --help or error is found..
183     * 
184     * @param {String} $classname name of class - should be loaded..
185     * @return {Array|false} array of key=>value arguments.. or false if not parsed
186     * 
187     */
188     function cliParse($classname)
189     {
190     
191     // cli static $classname::$cli_opts
192     
193         try {
194             // look up the parent tree for core opts.
195             $val = array();
196             //var_dump($classname);
197             $cls = new ReflectionClass($classname);
198             if (method_exists($classname, 'cli_opts')) {
199                 $val = $classname::cli_opts();
200             } else {
201                 $ar = $cls->getStaticProperties();
202                  if (isset($ar['cli_opts'])) {
203                     //echo "getting cli opts?\n";
204                     $val = $cls->getStaticPropertyValue('cli_opts');
205                 }
206             }
207              
208             $val = is_array($val) ? $val : array();
209             while ($cls = $cls->getParentClass()) {
210                 //var_dump($cls->name);
211                  
212                 try {
213                     $vadd  = array();
214                     if (method_exists($cls->name, 'cli_opts')) {
215                         $cn = $cls->name;
216                         $vadd = $cn::cli_opts();
217                     } else {
218                         $ar = $cls->getStaticProperties();
219                         if (isset($ar['cli_opts'])) {
220                             $vadd = $cls->getStaticPropertyValue('cli_opts');
221                         }
222                          
223                     }
224                     $val = array_merge($val, is_array($vadd) ? $vadd : array()  );
225                 } catch (ReflectionException $e) {
226                     continue;
227                 }
228             }
229             
230             
231             
232         } catch (ReflectionException $e) {
233             //print_r($e);
234             echo "cliParse:Warning:  {$e->getMessage()}\n";
235             exit;
236         }
237         if (empty($val)) {
238             return false;
239         }
240         
241         $val = array_merge(self::$cli_opts, $val);
242         
243         
244         require_once 'Console/Getargs.php';
245         $ar = $_SERVER['argv'];
246         $call = array(array_shift($ar)); // remove index.php
247         $call[] = array_shift($ar); // remove our class...
248         //var_dump($ar);
249         
250         $newargs = Console_Getargs::factory($val, $ar);
251         
252         if (!is_a($newargs, 'PEAR_Error')) {
253             return $newargs->getValues();
254         }
255         
256         list($optional, $required, $params) = Console_Getargs::getOptionalRequired($val);
257         
258         $helpHeader = 'Usage: php ' . implode (' ', $call) . ' '. 
259               $optional . ' ' . $required . ' ' . $params . "\n\n";           
260         
261         
262         if ($newargs->getCode() === CONSOLE_GETARGS_ERROR_USER) {
263             // User put illegal values on the command line.
264             echo Console_Getargs::getHelp($val,
265                     $helpHeader, "\n\n".$newargs->getMessage(), 78, 4)."\n\n";
266             exit;
267         }
268         if ($newargs->getCode() === CONSOLE_GETARGS_HELP) {
269             // User needs help.
270             echo Console_Getargs::getHelp($val,
271                     $helpHeader, NULL, 78, 4)."\n\n";
272             exit;
273         }
274         
275         die($newargs->getMessage()); 
276         
277             
278     }
279     
280     
281     
282     /**
283      * the framework can be run without a database even if it's configured.
284      * to support this, we need to handle things like
285      *  --pman-nodatabase=1 on the command line.
286      *
287      *  
288      * @returns   array() - args, false - nothing matched / invalid, true = help! 
289      *
290      */
291     
292     function parseDefaultOpts()
293     {
294         require_once 'Console/Getargs.php';
295         $ar = $_SERVER['argv'];
296         $call = array(array_shift($ar)); // remove index.php
297         $has_class = false;
298         if (isset($ar[0]) && $ar[0][0] != '-') {
299             $call[] = array_shift($ar); // remove our class...
300             $has_class = true;
301         }  
302         $val = self::$cli_opts;
303         
304         $newargs = Console_Getargs::factory($val, $ar);
305         
306         if (is_a($newargs, 'PEAR_Error')) {
307             list($optional, $required, $params) = Console_Getargs::getOptionalRequired($val);
308         
309             $helpHeader = 'Usage: php ' . implode (' ', $call) . ' '. 
310                 $optional . ' ' . $required . ' ' . $params . "\n\n";           
311        
312             if ($newargs->getCode() === CONSOLE_GETARGS_ERROR_USER) {
313                 // since we do not handle all the arguemnts here...
314                 // skip errors if we find unknown arguments.
315                 if (preg_match('/^Unknown argument/', $newargs->getMessage())) {
316                     return false;
317                 }
318                 
319                 // User put illegal values on the command line.
320                 echo Console_Getargs::getHelp($val,
321                         $helpHeader, "\n\n".$newargs->getMessage(), 78, 4)."\n\n";
322                 exit;
323             }
324             if ($newargs->getCode() === CONSOLE_GETARGS_HELP) {
325                 if (!$has_class) {
326                     
327                     echo Console_Getargs::getHelp($val,
328                             $helpHeader, NULL, 78, 4)."\n\n";
329                     exit;
330                 }
331                 return true;// help is handled later in the flow?
332             }
333             
334             return false;
335         }
336        
337         
338         // now handle real arguments..
339         
340         $ret =  $newargs->getValues();
341         
342          
343         foreach($ret as $k=>$v) {
344             switch($k) {
345                 case 'pman-nodatabase':
346                     echo "Turning off database\n";
347                     $this->ff->nodatabase = true;
348                     
349                     break;
350                 
351                 default:
352                     die("need to fix option $k");
353             }
354             
355         }
356         return false;
357         
358     }
359     
360     
361     
362 }