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