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