1c092effc0811ded877e835e5412122ee4acfba8
[pear] / HTML / FlexyFramework / Generator.php
1 <?php
2
3
4 require_once 'DB/DataObject/Generator.php';
5
6
7 class HTML_FlexyFramework_Generator extends DB_DataObject_Generator 
8 {
9     // block class generation.
10     static $generateClasses = false;
11     
12     function generateClasses()
13     {
14 //        echo "GENERATE CLASSES?";
15         if (!HTML_FlexyFramework_Generator::$generateClasses ) {
16             return;
17         }
18        
19         //echo "GENERATE CLASSES?";
20         parent::generateClasses();
21     }
22     
23     
24     function generateReaders()
25     {
26         $options = &PEAR::getStaticProperty('DB_DataObject','options');
27         
28         $out = array();
29         foreach($this->tables as $this->table) {
30             $this->table        = trim($this->table);
31             
32             $out = array_merge($out, $this->_generateReader($this->table));
33             
34             
35         }
36         //echo '<PRE>';print_r($out);exit;
37          
38         file_put_contents($options["ini_{$this->_database}"] . '.reader', serialize($out));
39          
40     }
41     /**
42      * Generate the cached readers used for meta data in the queries.
43      * 
44      */
45     function _generateReader($table)
46     {
47         $DB = $this->getDatabaseConnection();
48         $dbtype = $DB->phptype;
49         $def = $this->_definitions[$table] ;
50         $ret = array();
51         foreach($def as $t) {
52              switch (strtoupper($t->type)) {
53
54                 case 'INT':
55                 case 'INT2':    // postgres
56                 case 'INT4':    // postgres
57                 case 'INT8':    // postgres
58                 case 'SERIAL4': // postgres
59                 case 'SERIAL8': // postgres
60                 case 'INTEGER':
61                 case 'TINYINT':
62                 case 'SMALLINT':
63                 case 'MEDIUMINT':
64                 case 'BIGINT':
65                 // wierd ones..
66                 case 'YEAR':
67                 
68                     $ret[$table.'.'.$t->name] = array('type' => 'int');
69                     continue 2;
70                
71                 case 'REAL':
72                 case 'DOUBLE':
73                 case 'DOUBLE PRECISION': // double precision (firebird)
74                 case 'FLOAT':
75                 case 'FLOAT4': // real (postgres)
76                 case 'FLOAT8': // double precision (postgres)
77                 case 'DECIMAL':
78                 case 'MONEY':  // mssql and maybe others
79                 case 'NUMERIC':
80                 case 'NUMBER': // oci8 
81                     $ret[$table.'.'.$t->name] = array('type' => 'float'); //???
82                     break;
83                     
84                 case 'BIT':
85                 case 'BOOL':   
86                 case 'BOOLEAN':   
87                     $ret[$table.'.'.$t->name] = array('type' => 'boolean'); //???
88                     // postgres needs to quote '0'
89                     if ($dbtype == 'pgsql') {
90                         ///$type +=  DB_DATAOBJECT_STR;
91                     }
92                     break;
93                     
94                 case 'STRING':
95                 case 'CHAR':
96                 case 'VARCHAR':
97                 case 'VARCHAR2':
98                 case 'TINYTEXT':
99                 
100                 case 'ENUM':
101                 case 'SET':         // not really but oh well
102                 
103                 case 'POINT':       // mysql geometry stuff - not really string - but will do..
104                 
105                 case 'TIMESTAMPTZ': // postgres
106                 case 'BPCHAR':      // postgres
107                 case 'INTERVAL':    // postgres (eg. '12 days')
108                 
109                 case 'CIDR':        // postgres IP net spec
110                 case 'INET':        // postgres IP
111                 case 'MACADDR':     // postgress network Mac address.
112                 
113                 case 'INTEGER[]':   // postgres type
114                 case 'BOOLEAN[]':   // postgres type
115                 
116                 
117                 case 'TEXT':
118                 case 'MEDIUMTEXT':
119                 case 'LONGTEXT':
120                 case 'BLOB':       /// these should really be ignored!!!???
121                 case 'TINYBLOB':
122                 case 'MEDIUMBLOB':
123                 case 'LONGBLOB':
124                 
125                 case 'CLOB': // oracle character lob support
126                 
127                 case 'BYTEA':   // postgres blob support..
128                     $ret[$table.'.'.$t->name] =  $t->name; // strings are not sent as arrays..
129                    // $type = DB_DATAOBJECT_STR;
130                     break;
131                 
132                 
133                 
134                 
135                 case 'DATE':    
136                     $ret[$table.'.'.$t->name] = array('type' => 'date', 'dateFormat' => 'Y-m-d'); //???
137                     break;
138                     
139                 case 'TIME':    
140                     $ret[$table.'.'.$t->name] = $t->name; // technically not...
141                     break;    
142                     
143                 
144                 case 'DATETIME': 
145                     $ret[$table.'.'.$t->name] = array('type' => 'date', 'dateFormat' => 'Y-m-d H:i:s'); //???
146                     break;    
147                     
148                 case 'TIMESTAMP': // do other databases use this???
149                     
150                     $ret[$table.'.'.$t->name] =   ($dbtype == 'mysql') ?
151                          array('type' => 'float') : 
152                         array('type' => 'date', 'dateFormat' => 'Y-m-d H:i:s');
153                     break;    
154                     
155                 
156                 
157                     
158                     
159                 default:     
160                     $ret[$table.'.'.$t->name] = $t->name;
161                     break;
162             }
163         }
164         
165         return $ret;
166         
167         
168     }
169     /**
170      * Generate the cached *.ini and links.ini files (merged for all components)
171      * @param string $iniCacheTmp a temporary file
172      * @param string $iniCache the real target.
173      */
174     static function writeCache($iniCacheTmp, $iniCache, $replace = array())
175     {
176         
177         $fp = fopen($iniCache.".lock", "a+");
178         flock($fp,LOCK_EX);
179
180         $ff = HTML_FlexyFramework::get();
181         $ff->debug('Framework Generator:writeCache ' . $iniCacheTmp .  ' ' . $iniCache);
182           
183         //var_dump($iniCacheTmp);
184        // echo '<PRE>';echo file_get_contents($iniCacheTmp);exit;
185         // only unpdate if nothing went wrong.
186         clearstatcache();
187         if (file_exists($iniCacheTmp) && filesize($iniCacheTmp)) {
188             // is the replace file exist?
189             
190             if (isset($replace[$iniCache]) && $replace[$iniCache] != md5_file($iniCacheTmp)) {
191                 // file has changed.
192                 // it seems to happen that in this case if there are less elements in the file than before, then we might have an error
193                 // it's better to just die here, than continue.
194                 $old = parse_ini_file($iniCache,true);
195                 $new = parse_ini_file($iniCacheTmp,true);
196                 if (count(array_keys($new)) < count(array_keys($old))) {
197                     die("Generated INI file failed, try reloading");
198                 }
199             }
200             
201             if (!isset($replace[$iniCache]) || $replace[$iniCache] != md5_file($iniCacheTmp)) {
202                 
203             
204                 if (file_exists($iniCache)) {
205                     unlink($iniCache);
206                 }
207                 $ff->debug("Writing merged ini file : $iniCache\n");
208                 rename($iniCacheTmp, $iniCache);
209             } else {
210                 touch($iniCache);
211                 unlink($iniCacheTmp);
212             }
213         }
214         
215         // readers..??? not needed??? (historical)
216         if (file_exists($iniCacheTmp.'.reader') &&  filesize($iniCacheTmp.'.reader')) {
217             
218             
219             if (file_exists($iniCache.'.reader') ) {
220                 if (!isset($replace[$iniCache] ) || $replace[$iniCache] != md5_file($iniCacheTmp.'.reader')) {
221                     unlink($iniCache.'.reader');
222                     rename($iniCacheTmp.'.reader', $iniCache.'.reader');
223                 } else {
224                     // do not need to touch..
225                     unlink($iniCacheTmp.'.reader');
226                 }
227             } else {
228                 rename($iniCacheTmp.'.reader', $iniCache.'.reader');
229             }
230         
231              
232         }
233        
234         // merge and set links.. test for generated links file..
235         
236         $linksCacheTmp = preg_replace('/\.ini/', '.links.ini', $iniCacheTmp );
237         $links = array();
238         if (file_exists($linksCacheTmp )) {
239             $links = self::mergeIni( parse_ini_file($linksCacheTmp, true), $links);
240             unlink($linksCacheTmp);
241         }
242         // we are going to use the DataObject directories..
243         
244         $inis = explode(PATH_SEPARATOR,$ff->DB_DataObject['class_location']);
245         //print_r($inis);exit;
246         $ff->debug("class_location = ". $ff->DB_DataObject['class_location']);
247         
248         
249         $lproject = strtolower(explode('/', $ff->project)[0]);
250         
251         foreach($inis as $path) {
252             $ini = $path . '/'. strtolower( $lproject ) . '.links.ini';
253              //var_dump($ini);
254             if (!file_exists($ini)) {
255                 $ff->debug("Framework Generator:writeCache PROJECT.links.ini does not exist in $path - trying glob");
256        
257                 // try scanning the directory for another ini file..
258                 $ar = glob(dirname($ini).'/*.links.ini');
259                 
260                 
261                 if (empty($ar)) {
262                     continue;
263                 }
264                 
265                 
266                 sort($ar);
267                 $ff->debug("Framework Generator:writeCache using {$ar[0]}");
268                 
269                 // first file.. = with links removed..
270                 $ini = preg_replace('/\.links\./' , '.', $ar[0]);
271                 $ini = preg_replace('/\.ini$/', '.links.ini', $ini);
272             }
273             
274             // why do this twice???
275             if (!file_exists($ini)) {
276                 continue;
277             }
278             $ff->debug("Adding in $ini");
279             // prefer first ?
280             $links = self::mergeIni( parse_ini_file($ini, true), $links);   
281         }
282         $iniLinksCache = preg_replace('/\.ini$/', '.links.ini', $iniCache);
283         $out = array();
284         foreach($links as $tbl=>$ar) {
285             $out[] = '['. $tbl  .']';
286             foreach ($ar as $k=>$v) {
287                 $out[] = $k . '=' .$v;
288             }
289             $out[] = '';
290         }
291         if (count($out)) {
292             $ff->debug("Writing merged Links file : $iniLinksCache \n");
293             $out_str = implode("\n", $out);
294             // is target file different?
295             if (!isset($replace[$iniLinksCache]) || $replace[$iniLinksCache] != md5($out_str)) {
296           
297                  file_put_contents($iniCacheTmp. '.links.ini', $out_str);
298                  if (file_exists($iniLinksCache)) {                
299                      unlink($iniLinksCache);
300                  }
301                  rename($iniCacheTmp. '.links.ini', $iniLinksCache);
302             } else {
303                 touch($iniLinksCache);
304                 
305             }
306         }
307         
308         flock($fp, LOCK_UN);
309         fclose($fp);
310         // this sometimes seems to fail..
311         @unlink($iniCache.".lock");
312         
313     }
314     /* bit like merge recursive, but it avoids doing stuff with arrays.. */
315     static function mergeIni($new, $old) 
316     {
317         foreach($new as $g => $ar) {
318             if (!isset($old[$g])) {
319                 $old[$g] = $ar;
320                 continue;
321             }
322             foreach($ar as $k=>$v) {
323                 if (isset($old[$g][$k])) {
324                     continue;
325                 }
326                 $old[$g][$k] = $v;
327             }
328         }
329         return $old;
330         
331         
332     }
333     
334 }