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 HTML_FlexyFramework_Cli($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         var_dump($this->ff->projectExtends );
82         foreach($this->ff->projectExtends as $pr) {
83             $this->cliHelpSearch($p,$pr);
84         }
85         
86         echo "\n\n";
87         exit;
88     }
89     
90     
91     function cliHelpSearch($p,$pr, $path=false) {
92         
93         
94         
95         $full_path = array($p,$pr);
96         $class_path = array();
97         if ($path !== false)  {
98             $full_path= array_merge($full_path, $path);
99             $class_path = array_merge($class_path, $path);
100         }
101         //print_r("CHKDIR:    ". implode('/', $full_path)."\n");
102         
103         foreach(scandir(implode('/', $full_path)) as $d) {
104             
105             if (!strlen($d) || $d[0] == '.') {
106                 continue;
107             }
108             $chk = $full_path;
109             $chk[] = $d;
110             
111             $clp = $class_path;
112             
113             
114             
115             //print_r("CHK:          " . implode('/', $chk)."\n");
116             // is it a file.. and .PHP...
117             if (!is_dir(implode('/', $chk))) {
118                 if (!preg_match('/\.php$/',$d)) {
119                     continue;
120                 }
121                 $clp[] = preg_replace('/\.php$/','', $d);
122                 
123                 //print_r("CLP:          " . implode('/', $clp)."\n");
124                 $this->cliShortHelp(implode('/', $clp ));
125                 continue;
126             }
127             // skip special directories..
128             if ($d == 'templates') {
129                 continue;
130             }
131             if ($d == 'DataObjects') {
132                 continue;
133             }
134             
135             
136             $clp[] = $d;
137             // otherwise recurse...
138             //print_r("RECURSE:        " . implode('/', $clp)."\n");
139             
140             $this->cliHelpSearch($p,$pr, $clp);
141             
142             
143         }
144         
145         //print_r("COMPLETE:    ". implode('/', $full_path)."\n");
146         
147         
148         
149         
150     }
151     
152     
153     
154     
155     /**
156      * creates an instance of all the CLI classes and prints out class + title..
157      *
158      */
159     function cliShortHelp($p) { 
160         ////print_r("CHKFILE:         $p\n ");
161         list($classname,$subRequest) = $this->ff->requestToClassName($p,FALSE);
162         //var_dump($classname);
163         // does it have a description.
164         try { 
165             $cls = new ReflectionClass($classname);        
166             $val = $cls->getStaticPropertyValue('cli_desc');
167         } catch (Exception $e) {
168             return;
169         }
170         if (empty($val)) {
171             return;
172         }
173         echo str_pad($p,40," ") . $val ."\n";
174         
175         
176          
177     }
178      
179     /**
180     * cliParse - parse command line arguments, and return the values.
181     *  Will die with help message if --help or error is found..
182     * 
183     * @param {String} $classname name of class - should be loaded..
184     * @return {Array|false} array of key=>value arguments.. or false if not parsed
185     * 
186     */
187     function cliParse($classname)
188     {
189     
190     // cli static $classname::$cli_opts
191     
192         try {
193             // look up the parent tree for core opts.
194             $cls = new ReflectionClass($classname);
195             if (method_exists($classname, 'cli_opts')) {
196                 $val = $classname::cli_opts();
197             } else {
198                 $val = $cls->getStaticPropertyValue('cli_opts');
199             }
200              
201             $val = is_array($val) ? $val : array();
202             while ($cls = $cls->getParentClass()) {
203                 //var_dump($cls);
204                  
205                 try {
206                     
207                     if (method_exists($cls->name, 'cli_opts')) {
208                         $cn = $cls->name;
209                         $vadd = $cn::cli_opts();
210                     } else {
211                         $vadd = $cls->getStaticPropertyValue('cli_opts') ;
212                         
213                     }
214                     $val = array_merge($val, is_array($vadd) ? $vadd : array()  );
215                 } catch (Exception $e) {
216                     continue;
217                 }
218             }
219             
220             
221             
222         } catch (Exception $e) {
223             echo "Warning:  {$e->getMessage()}\n";
224         }
225         if (empty($val)) {
226             return false;
227         }
228         
229         $val = array_merge(self::$cli_opts, $val);
230         
231         
232         require_once 'Console/Getargs.php';
233         $ar = $_SERVER['argv'];
234         $call = array(array_shift($ar)); // remove index.php
235         $call[] = array_shift($ar); // remove our class...
236         //var_dump($ar);
237         
238         $newargs = Console_Getargs::factory($val, $ar);
239         
240         if (!is_a($newargs, 'PEAR_Error')) {
241             return $newargs->getValues();
242         }
243         
244         list($optional, $required, $params) = Console_Getargs::getOptionalRequired($val);
245         
246         $helpHeader = 'Usage: php ' . implode (' ', $call) . ' '. 
247               $optional . ' ' . $required . ' ' . $params . "\n\n";           
248         
249         
250         if ($newargs->getCode() === CONSOLE_GETARGS_ERROR_USER) {
251             // User put illegal values on the command line.
252             echo Console_Getargs::getHelp($val,
253                     $helpHeader, "\n\n".$newargs->getMessage(), 78, 4)."\n\n";
254             exit;
255         }
256         if ($newargs->getCode() === CONSOLE_GETARGS_HELP) {
257             // User needs help.
258             echo Console_Getargs::getHelp($val,
259                     $helpHeader, NULL, 78, 4)."\n\n";
260             exit;
261         }
262         
263         die($newargs->getMessage()); 
264         
265             
266     }
267     
268     
269     
270     /**
271      * the framework can be run without a database even if it's configured.
272      * to support this, we need to handle things like
273      *  --pman-nodatabase=1 on the command line.
274      *
275      *  
276      * @returns   array() - args, false - nothing matched / invalid, true = help! 
277      *
278      */
279     
280     function parseDefaultOpts()
281     {
282         require_once 'Console/Getargs.php';
283         $ar = $_SERVER['argv'];
284         $call = array(array_shift($ar)); // remove index.php
285         $call[] = array_shift($ar); 
286         //var_dump($ar);
287         $val = self::$cli_opts;
288         
289         $newargs = Console_Getargs::factory($val, $ar);
290         
291         if (is_a($newargs, 'PEAR_Error')) {
292             
293             
294             
295             if ($newargs->getCode() === CONSOLE_GETARGS_ERROR_USER) {
296                 // since we do not handle all the arguemnts here...
297                 // skip errors if we find unknown arguments.
298                 if (preg_match('/^Unknown argument/', $newargs->getMessage())) {
299                     return false;
300                 }
301                 
302                 // User put illegal values on the command line.
303                 echo Console_Getargs::getHelp($val,
304                         $helpHeader, "\n\n".$newargs->getMessage(), 78, 4)."\n\n";
305                 exit;
306             }
307             if ($newargs->getCode() === CONSOLE_GETARGS_HELP) {
308                 
309                 return true;// hel
310             }
311             
312             return false;
313         }
314        
315         
316         // now handle real arguments..
317         
318         
319         $ret =  $newargs->getValues();
320             foreach($ret as $k=>$v) {
321                 switch($k) {
322                     case 'pman-nodatabase':
323                         //echo "Turning off database";
324                         $this->ff->nodatabase= true;
325                         
326                         break;
327                     
328                     default:
329                         die("need to fix option $k");
330                 }
331                 
332             }
333         return false;
334         
335     }
336     
337     
338     
339 }