UpdateCurrencyRate.php
[Pman.Core] / UpdateCurrencyRate.php
1 <?php
2
3
4 require_once 'Pman.php';
5 class Pman_Core_UpdateCurrencyRate extends Pman
6 {
7     
8     static $cli_desc = "Update Currency Exchange Rate";
9  
10     static $cli_opts = array(
11         
12     );
13     
14     static function cli_opts()
15     {
16         
17         $ret = self::$cli_opts;
18         $ff = HTML_FlexyFramework::get();
19         $a = new Pman();
20         $mods = $a->modulesList();
21         foreach($mods as $m) {
22             
23             $fd = $ff->rootDir. "/Pman/$m/UpdateDatabase.php";
24             if (!file_exists($fd)) {
25                 continue;
26             }
27             
28             require_once $fd;
29             
30             $cls = new ReflectionClass('Pman_'. $m . '_UpdateDatabase');
31             
32             $ret = array_merge($ret, $cls->getStaticPropertyValue('cli_opts'));
33             
34             
35         }
36         
37         return $ret;
38     }
39     
40     var $opts = false;
41     
42     
43     var $cli = false;
44     function getAuth() {
45         
46         
47         $ff = HTML_FlexyFramework::get();
48         if (!empty($ff->cli)) {
49             $this->cli = true;
50             return true;
51         }
52         
53         parent::getAuth(); // load company!
54         $au = $this->getAuthUser();
55         if (!$au || $au->company()->comptype != 'OWNER') {
56             $this->jerr("Not authenticated", array('authFailure' => true));
57         }
58         $this->authUser = $au;
59         return true;
60     }
61      
62     function get($args, $opts)
63     {
64         PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array($this, 'onPearError'));
65    
66         
67         //$this->fixSequencesPgsql();exit;
68         $this->opts = $opts;
69         
70         // ask all the modules to verify the opts
71         
72         $this->checkOpts($opts);
73         
74         
75      
76         if (empty($opts['data-only'])) {
77             $this->importSQL();
78         }
79         if (!empty($opts['only-module-sql'])) {
80             return;
81         }
82         
83         $this->runUpdateModulesData();
84         
85         
86         if (!empty($opts['add-company'])) {
87             // make sure we have a good cache...?
88            
89             DB_DataObject::factory('companies')->initCompanies($this, $opts);
90         }
91          
92     }
93     function output() {
94         return '';
95     }
96      /**
97      * imports SQL files from all DataObjects directories....
98      * 
99      * except any matching /migrate/
100      */
101     function importSQL()
102     {
103         
104         // loop through all the modules, and see if they have a importSQL method?
105         
106         
107         $ff = HTML_Flexyframework::get();
108         
109         $dburl = parse_url($ff->DB_DataObject['database']);
110         
111         //$this->{'import' . $url['scheme']}($url);
112         
113         $dbtype = $dburl['scheme'];
114         $dirmethod = 'import' . $dburl['scheme'] . 'dir';
115         
116         
117        
118         
119         $ar = $this->modulesList();
120        
121         
122         foreach($ar as $m) {
123              echo "Importing SQL from module $m\n";
124             if (!empty($this->opts['only-module-sql']) && $m != $this->opts['only-module-sql']) {
125                 continue;
126             }
127             
128             
129             // check to see if the class has
130             
131             
132             
133             $file = $this->rootDir. "/Pman/$m/UpdateDatabase.php";
134             if($m != 'Core' && file_exists($file)){
135                 
136                 require_once $file;
137                 $class = "Pman_{$m}_UpdateDatabase";
138                 $x = new $class;
139                 if(method_exists($x, 'importModuleSQL')){
140                     echo "Importing SQL from module $m using Module::importModuleSQL\n";
141                     $x->opts = $this->opts;
142                     $x->rootDir = $this->rootDir;
143                     $x->importModuleSQL($dburl);
144                     continue;
145                 }
146             };
147
148             echo "Importing SQL from module $m\n";
149             
150             
151             // if init has been called
152             // look in pgsql.ini
153             if (!empty($this->opts['init'])) {
154                 $this->{$dirmethod}($dburl, $this->rootDir. "/Pman/$m/{$dbtype}.init");
155                 
156             }
157             
158             
159             
160             $fd = $this->rootDir. "/Pman/$m/DataObjects";
161             
162             $this->{$dirmethod}($dburl, $fd);
163             
164             // new -- sql directory..
165             // new style will not support migrate ... they have to go into mysql-migrate.... directories..
166             // new style will not support pg.sql etc.. naming - that's what the direcotries are for..
167             
168             $this->{$dirmethod}($dburl, $this->rootDir. "/Pman/$m/sql");
169             $this->{$dirmethod}($dburl, $this->rootDir. "/Pman/$m/{$dbtype}");
170             
171             
172             
173             if (!empty($this->opts['init']) && file_exists($this->rootDir. "/Pman/$m/{$dbtype}.initdata")) {
174                 HTML_FlexyFramework::get()->generateDataobjectsCache(true);
175                 
176                 $this->{$dirmethod}($dburl, $this->rootDir. "/Pman/$m/{$dbtype}.initdata");
177                 $this->{'fixSequences'. $dbtype}();
178                 
179             }
180               
181             
182         }
183         
184     }
185     
186     
187     
188      
189     /** -------------- code to handle importing a whole directory of files into the database  -------  **/
190     
191     
192     function importpgsqldir($url, $dir, $disable_triggers = false)
193     {
194         $ff = HTML_FlexyFramework::get();
195         
196         require_once 'System.php';
197         $cat = System::which('cat');
198         $psql = System::which('psql');
199         
200          
201         if (!empty($url['pass'])) { 
202             putenv("PGPASSWORD=". $url['pass']);
203         }
204            
205         $psql_cmd = $psql .
206             ' -h ' . $url['host'] .
207             ' -U' . escapeshellarg($url['user']) .
208              ' ' . basename($url['path']);
209         
210         
211         echo $psql_cmd . "\n" ;
212         echo "scan : $dir\n";
213         if (is_file($dir)) {
214             $files = array($dir);
215
216         } else {
217         
218         
219             $files = glob($dir.'/*.sql');
220             uksort($files, 'strcasecmp');
221         }
222         //$lsort = create_function('$a,$b','return strlen($a) > strlen($b) ? 1 : -1;');
223         //usort($files, $lsort);
224         
225         
226         
227         foreach($files as $bfn) {
228
229
230             if (preg_match('/migrate/i', basename($bfn))) { // skip migration scripts at present..
231                 continue;
232             }
233             if (preg_match('#\.[a-z]{2}\.sql#i', basename($bfn))
234                 && !preg_match('#\.pg\.sql#i', basename($bfn))
235             ) { // skip migration scripts at present..
236                 continue;
237             }
238             $fn = false;
239
240             if (!preg_match('/pgsql/', basename($dir) )) {
241                  if ( !preg_match('#\.pg\.sql$#', basename($bfn))) {
242                     $fn = $this->convertToPG($bfn);
243                 }
244             }
245
246             // files ending in .pg.sql are native postgres files.. ## depricated
247
248
249             $cmd = "$psql_cmd  < " . escapeshellarg($fn ? $fn : $bfn) . ' 2>&1' ;
250
251             echo "$bfn:   $cmd ". ($ff->cli ? "\n" : "<BR>\n");
252
253
254             passthru($cmd);
255
256             if ($fn) {
257                 unlink($fn);
258             }
259         }
260
261               
262              
263         
264     }
265     
266     
267     /**
268      * mysql - does not support conversions.
269      * 
270      *
271      */
272     
273     
274     function importmysqldir($dburl, $dir)
275     {
276         echo "Import MYSQL :: $dir\n";
277         
278         
279         require_once 'System.php';
280         $cat = System::which('cat');
281         $mysql = System::which('mysql');
282         
283        
284            
285         $mysql_cmd = $mysql .
286             ' -h ' . $dburl['host'] .
287             ' -u' . escapeshellarg($dburl['user']) .
288             (!empty($dburl['pass']) ? ' -p' . escapeshellarg($dburl['pass'])  :  '') .
289             ' ' . basename($dburl['path']);
290         //echo $mysql_cmd . "\n" ;
291         
292         $files = glob($dir.'/*.sql');
293         uksort($files, 'strcasecmp');
294         
295        
296         foreach($files as $fn) {
297                 
298                  
299                 if (preg_match('/migrate/i', basename($fn))) { // skip migration scripts at present..
300                     continue;
301                 }
302                 // .my.sql but not .pg.sql
303                 if (preg_match('#\.[a-z]{2}\.sql#i', basename($fn))
304                     && !preg_match('#\.my\.sql#i', basename($fn))
305                 ) { // skip migration scripts at present..
306                     continue;
307                 }
308                 if (!strlen(trim($fn))) {
309                     continue;
310                 }
311                 
312                 $cmd = "$mysql_cmd -f < " . escapeshellarg($fn) ;
313                 
314                 echo basename($dir).'/'. basename($fn) .    '::' .  $cmd. ($this->cli ? "\n" : "<BR>\n");
315                 
316                 passthru($cmd);
317             
318                 
319         }
320        
321         
322         
323     }
324     
325     
326     /**
327      * simple regex based convert mysql to pgsql...
328      */
329     function convertToPG($src)
330     {
331         //echo "Convert $src\n";
332                
333         $fn = $this->tempName('sql');
334         
335         $ret = array( ); // pad it a bit.
336         $extra = array("", "" );
337         
338         $tbl = false;
339         foreach(file($src) as $l) {
340             $l = trim($l);
341             
342             if (!strlen($l) || $l[0] == '#') {
343                 continue;
344             }
345             $m = array();
346             if (preg_match('#create\s+table\s+([a-z0-9_]+)#i',  $l, $m)) {
347                 $tbl = $m[1];
348              }
349             if (preg_match('#create\s+table\s+\`([a-z0-9_]+)\`#i',  $l, $m)) {
350                 $tbl = 'shop_' . strtolower($m[1]);
351                 $l = preg_replace('#create\s+table\s+\`([a-z0-9_]+)\`#i', "CREATE TABLE {$tbl}", $l);
352             }
353             if (preg_match('#\`([a-z0-9_]+)\`#i',  $l, $m) && !preg_match('#alter\s+table\s+#i',  $l)) {
354                 $l = preg_replace('#\`([a-z0-9_]+)\`#i', "{$m[1]}_name", $l);
355             }
356             // autoinc
357             if ($tbl && preg_match('#auto_increment#i',  $l, $m)) {
358                 $l = preg_replace('#auto_increment#i', "default nextval('{$tbl}_seq')", $l);
359                 $extra[]  =   "create sequence {$tbl}_seq;";
360               
361             }
362             
363             if (preg_match('#alter\s+table\s+(\`[a-z0-9_]+\`)#i',  $l, $m)){
364                 $l = preg_replace('#alter\s+table\s+(\`[a-z0-9_]+\`)#i', "ALTER TABLE {$tbl}", $l);
365             }
366             
367             // enum value -- use the text instead..
368             
369             if ($tbl && preg_match('#([\w]+)\s+(enum\([\w|\W]+\))#i',  $l, $m)) {
370                 $l = preg_replace('#enum\([\w|\W]+\)#i', "TEXT", $l);
371             }
372             // ignore the alter enum
373             if ($tbl && preg_match('#alter\s+table\s+([\w|\W]+)\s+enum\([\w|\W]+\)#i',  $l, $m)) {
374                 continue;
375             }
376             
377             // UNIQUE KEY .. ignore
378             if ($tbl && preg_match('#UNIQUE KEY#i',  $l, $m)) {
379                 $last = array_pop($ret);
380                 $ret[] = trim($last, ",");
381                 continue;
382             }
383             
384             if ($tbl && preg_match('#RENAME\s+TO#i',  $l, $m)) {
385                 continue;
386             }
387             
388             if ($tbl && preg_match('#change\s+column#i',  $l, $m)) {
389                 continue;
390             }
391             
392             // INDEX lookup ..ignore
393             if ($tbl && preg_match('#INDEX lookup+([\w|\W]+)#i',  $l, $m)) {
394                $last = array_pop($ret);
395                $ret[] = trim($last, ",");
396                continue;
397                
398             }
399             
400             // CREATE INDEX ..ignore
401             if (preg_match('#alter\s+table\s+([a-z0-9_]+)\s+add\s+index\s+#i',  $l, $m)) {
402 //               $l = "CREATE INDEX  {$m[1]}_{$m[2]} ON {$m[1]} {$m[3]}";
403                 continue;
404              }
405              
406             // basic types..
407             $l = preg_replace('#int\([0-9]+\)#i', 'INT', $l);
408             
409             $l = preg_replace('# datetime#i', ' TIMESTAMP WITHOUT TIME ZONE', $l);
410             $l = preg_replace('# blob#i', ' TEXT', $l);
411             $l = preg_replace('# longtext#i', ' TEXT', $l);
412             $l = preg_replace('# tinyint#i', ' INT', $l);
413             
414             $ret[] = $l;
415             
416         }
417         
418         $ret = array_merge($extra,$ret);
419 //        echo implode("\n", $ret); exit;
420         
421         file_put_contents($fn, implode("\n", $ret));
422         
423         return $fn;
424     }
425     
426     
427     function checkOpts($opts)
428     {
429         
430         
431         foreach($opts as $o=>$v) {
432             if (!preg_match('/^json-/', $o) || empty($v)) {
433                 continue;
434             }
435             if (!file_exists($v)) {
436                 die("File does not exist : OPTION --{$o} = {$v} \n");
437             }
438         }
439         
440         $modules = array_reverse($this->modulesList());
441         
442         // move 'project' one to the end...
443         
444         foreach ($modules as $module){
445             $file = $this->rootDir. "/Pman/$module/UpdateDatabase.php";
446             if($module == 'Core' || !file_exists($file)){
447                 continue;
448             }
449             require_once $file;
450             $class = "Pman_{$module}_UpdateDatabase";
451             $x = new $class;
452             if(!method_exists($x, 'checkOpts')){
453                 continue;
454             };
455             $x->checkOpts($opts);
456         }
457                 
458     }
459     static function jsonImportFromArray($opts)
460     {
461         foreach($opts as $o=>$v) {
462             if (!preg_match('/^json-/', $o) || empty($v)) {
463                 continue;
464             }
465             $type = str_replace('_', '-', substr($o,5));
466             
467             $data= json_decode(file_get_contents($v),true);
468             $pg = HTML_FlexyFramework::get()->page;
469             DB_DataObject::factory($type)->importFromArray($pg ,$data,$opts);
470             
471         }
472         
473         
474         
475     }
476     
477     
478     
479     function runUpdateModulesData()
480     {
481         
482         
483         HTML_FlexyFramework::get()->generateDataobjectsCache(true);
484         echo "Running jsonImportFromArray\n";
485         Pman_Core_UpdateDatabase::jsonImportFromArray($this->opts);
486         
487         
488         echo "Running updateData on modules\n";
489         // runs core...
490         echo "Core\n";
491         $this->updateData(); 
492         $modules = array_reverse($this->modulesList());
493         
494         // move 'project' one to the end...
495         
496         foreach ($modules as $module){
497             $file = $this->rootDir. "/Pman/$module/UpdateDatabase.php";
498             if($module == 'Core' || !file_exists($file)){
499                 continue;
500             }
501             
502             require_once $file;
503             $class = "Pman_{$module}_UpdateDatabase";
504             $x = new $class;
505             if(!method_exists($x, 'updateData')){
506                 continue;
507             };
508             echo "$module\n";
509             $x->updateData();
510         }
511                 
512     }
513     
514     
515     function updateDataEnums()
516     {
517         
518         $enum = DB_DataObject::Factory('core_enum');
519         //DB_DAtaObject::debugLevel(1);
520         $enum->initEnums(
521             array(
522                 array(
523                     'etype' => '',
524                     'name' => 'COMPTYPE',
525                     'display_name' =>  'Company Types',
526                     'is_system_enum' => 1,
527                     'cn' => array(
528                         array(
529                             'name' => 'OWNER',
530                             'display_name' => 'Owner',
531                             'seqid' => 999, // last...
532                             'is_system_enum' => 1,
533                         )
534                         
535                     )
536                 ),
537                 array(
538                     'etype' => '',
539                     'name' => 'HtmlEditor.font-family',
540                     'display_name' =>  'HTML Editor font families',
541                     'is_system_enum' => 1,
542                     'cn' => array(
543                         array(
544                             'name' => 'Helvetica,Arial,sans-serif',
545                             'display_name' => 'Helvetica',
546                             
547                         ),
548                         
549                         array(
550                             'name' => 'Courier New',
551                             'display_name' => 'Courier',
552                              
553                         ),
554                         array(
555                             'name' => 'Tahoma',
556                             'display_name' => 'Tahoma',
557                             
558                         ),
559                         array(
560                             'name' => 'Times New Roman,serif',
561                             'display_name' => 'Times',
562                            
563                         ),
564                         array(
565                             'name' => 'Verdana',
566                             'display_name' => 'Verdana',
567                             
568                         ),
569                         
570                             
571                         
572                     )
573                 ),
574             )
575         ); 
576         
577     }
578     function updateDataGroups()
579     {
580          
581         $groups = DB_DataObject::factory('groups');
582         $groups->initGroups();
583         
584         $groups->initDatabase($this,array(
585             array(
586                 'name' => 'bcc-email', // group who are bcc'ed on all requests.
587                 'type' => 0, // system
588             ),
589             array(
590                 'name' => 'system-email-from',
591                 'type' => 0, // system
592             ),
593         ));
594         
595     }
596     
597     function updateDataCompanies()
598     {
599          
600         // fix comptypes enums..
601         $c = DB_DataObject::Factory('Companies');
602         $c->selectAdd();
603         $c->selectAdd('distinct(comptype) as comptype');
604         $c->whereAdd("comptype != ''");
605         
606         $ctb = array();
607         foreach($c->fetchAll('comptype') as $cts) {
608             
609             
610             
611            $ctb[]= array( 'etype'=>'COMPTYPE', 'name' => $cts, 'display_name' => ucfirst(strtolower($cts)));
612         
613         }
614          $c = DB_DataObject::Factory('core_enum');
615          
616         $c->initEnums($ctb);
617         //DB_DataObject::debugLevel(1);
618         // fix comptypeid
619         $c = DB_DataObject::Factory('Companies');
620         $c->query("
621             UPDATE Companies 
622                 SET
623                     comptype_id = (SELECT id FROM core_enum where etype='comptype' and name=Companies.comptype LIMIT 1)
624                 WHERE
625                     comptype_id = 0
626                     AND
627                     LENGTH(comptype) > 0
628                   
629                   
630                   ");
631          
632         
633         
634     }
635     
636     function updateData()
637     {
638         // fill i18n data..
639         HTML_FlexyFramework::get()->generateDataobjectsCache(true);
640         $this->updateDataEnums();
641         $this->updateDataGroups();
642         $this->updateDataCompanies();
643         
644         $c = DB_DataObject::Factory('I18n');
645         $c->buildDB();
646          
647        
648         
649         
650     }
651     
652     /** ------------- schema fixing ... there is an issue with data imported having the wrong sequence names... --- */
653     
654     function fixSequencesMysql()
655     {
656         // not required...
657     }
658     
659     function fixSequencesPgsql()
660     {
661      
662      
663         //DB_DataObject::debugLevel(1);
664         $cs = DB_DataObject::factory('core_enum');
665         $cs->query("
666          SELECT
667                     'ALTER SEQUENCE '||
668                     CASE WHEN strpos(seq_name, '.') > 0 THEN
669                         min(seq_name)
670                     ELSE 
671                         quote_ident(min(schema_name)) ||'.'|| quote_ident(min(seq_name))
672                     END 
673                     
674                     ||' OWNED BY '|| quote_ident(min(schema_name)) || '.' ||
675                     quote_ident(min(table_name)) ||'.'|| quote_ident(min(column_name)) ||';' as cmd
676              FROM (
677                       
678                        SELECT 
679                      n.nspname AS schema_name,
680                      c.relname AS table_name,
681                      a.attname AS column_name, 
682                      regexp_replace(regexp_replace(d.adsrc, E'nextval\\\\(+[''\\\"]*', ''),E'[''\\\"]*::.*\$','') AS seq_name 
683                  FROM pg_class c 
684                  JOIN pg_attribute a ON (c.oid=a.attrelid) 
685                  JOIN pg_attrdef d ON (a.attrelid=d.adrelid AND a.attnum=d.adnum) 
686                  JOIN pg_namespace n ON (c.relnamespace=n.oid)
687                  WHERE has_schema_privilege(n.oid,'USAGE')
688                    AND n.nspname NOT LIKE 'pg!_%' escape '!'
689                    AND has_table_privilege(c.oid,'SELECT')
690                    AND (NOT a.attisdropped)
691                    AND d.adsrc ~ '^nextval'
692               
693              ) seq
694              WHERE
695                  CASE WHEN strpos(seq_name, '.') > 0 THEN
696                      substring(seq_name, 1,strpos(seq_name,'.')-1)
697                 ELSE
698                     schema_name
699                 END = schema_name
700              
701              GROUP BY seq_name HAVING count(*)=1
702              ");
703         $cmds = array();
704         while ($cs->fetch()) {
705             $cmds[] = $cs->cmd;
706         }
707         foreach($cmds as $cmd) {
708             $cs = DB_DataObject::factory('core_enum');
709             echo "$cmd\n";
710             $cs->query($cmd);
711         }
712         $cs = DB_DataObject::factory('core_enum');
713          $cs->query("
714                SELECT  'SELECT SETVAL(' ||
715                          quote_literal(quote_ident(nspname) || '.' || quote_ident(S.relname)) ||
716                         ', MAX(' || quote_ident(C.attname)|| ')::integer )  FROM ' || nspname || '.' || quote_ident(T.relname)|| ';' as cmd 
717                 FROM pg_class AS S,
718                     pg_depend AS D,
719                     pg_class AS T,
720                     pg_attribute AS C,
721                     pg_namespace AS NS
722                 WHERE S.relkind = 'S'
723                     AND S.oid = D.objid
724                     AND D.refobjid = T.oid
725                     AND D.refobjid = C.attrelid
726                     AND D.refobjsubid = C.attnum
727                     AND NS.oid = T.relnamespace
728                 ORDER BY S.relname   
729         ");
730          $cmds = array();
731         while ($cs->fetch()) {
732             $cmds[] = $cs->cmd;
733         }
734         foreach($cmds as $cmd) {
735             $cs = DB_DataObject::factory('core_enum');
736             echo "$cmd\n";
737             $cs->query($cmd);
738         }
739        
740     }
741     
742 }