php7 fixes
[Pman.Builder] / Elements.php
1 <?php
2
3 /**
4  * 
5  * Supply the palete of elements..
6  * 
7  * Things it can supply:
8  * -> Basic Element information? - 
9  *   -- eg. our standard widget set (with all the options?) - grabed from our doc-code.?
10  * 
11  * -> Database Tables / Fields
12  *   == start off with just the table..
13  * 
14  * 
15  */
16
17
18 require_once 'Pman.php';
19
20 class Pman_Builder_Elements extends Pman 
21 {
22     function getAuth() {
23         parent::getAuth(); // load company!
24         $au = $this->getAuthUser();
25         if (!$au) {
26             $this->jerr("Not authenticated", array('authFailure' => true));
27         }
28         $this->authUser = $au;
29         return true;
30     }
31     
32     function get($args, $opts = array())
33     {
34         if (empty($_REQUEST['table'])) {
35             $this->getTableList();
36         }
37         $tb = $_REQUEST['table'];
38          
39         if ($tb == '*grids') {
40             $this->getGridElements();
41         }
42         if ($tb[0] == '*') {
43             $this->readElement(substr($tb,1));
44         }
45         $this->getTableFormElements($tb);
46         
47     }
48     
49     function getTableList() // fro pulldown list
50     {
51         $d = DB_DataObject::factory('Person');
52         $db = $d->getDatabaseConnection();
53         
54         
55         $tables = $db->getListOf('tables');
56         $ret= array(
57             array('name' => 'Layout Elements', 'table' => '*Layout'),
58             array('name' => 'Form Elements', 'table' => '*Form'),
59             array('name' => 'Grid Elements', 'table' => '*Grid'),
60             array('name' => 'Grids (from database)', 'table' => '*grids')
61         );
62         foreach($tables as $t) {
63             $ret[] = array('name' => 'Table: ' . $t, 'table' => $t);
64         }
65         //echo'<PRE>';print_r($tables);
66         $this->jdata($ret);
67         
68         //$__DB->tableInfo($quotedTable);
69         
70     }
71     function getTableFormElements($tb) 
72     {
73         $d = DB_DataObject::factory('Person');
74         $db = $d->getDatabaseConnection();
75         
76         $def=  $db->tableInfo($tb);
77         if (is_object($def)) {
78             $this->jerr($def->toString());
79         }
80         $ret = array( 
81         
82            array(
83                 'grp' => 'Forms', 
84                 'name' => 'Form: '. $tb, 
85                 'description' => "A Form for $tb", 
86                 
87                 'cfg' =>  array(
88                     'xtype'=>'Form',
89                     'style' => 'margin: 5px',
90                     '|url' => "baseURL + '/Roo/" . ucfirst($tb) . ".php'",
91                     'method' => 'POST',
92                     'listeners' => array(
93                         '|actionfailed' => 'function (_self, action)
94 {
95     _this.dialog.el.unmask();
96     Pman.standardActionFailed(_self, action);
97 }
98 ',
99                         '|actioncomplete' => "function (_self, action)
100 {
101    
102    if (action.type =='submit') {
103        
104        _this.dialog.el.unmask();
105        _this.dialog.hide();
106        
107         if (_this.callback) {
108            _this.callback.call(_this, _this.form.getValues());
109         }
110         _this.form.reset();
111         return;
112     }
113 }
114 ",                    
115                         '|rendered' => 'function (_self)
116 {
117     _this.form = _self;
118 }
119 ',
120                     ), 
121                     'items' => array()
122
123                 )
124             ),
125         );
126         
127         foreach($def as $r) {
128             $el = $this->rowToFormElement((object)$r,$tb);
129             if (!$el) {
130                 continue;
131             }
132             // next.. cros table detection!?!?!?
133             if ( $el['xtype'] == 'NumberField') {
134                 $el = $this->linkedToFormElement($r['name'], $tb, $el);
135             }
136             
137             /*
138             ['Forms','Row', 'A Row of form elements',
139                                 {
140                     xtype:'Row' ,
141                     autoHeight:true
142                 }
143             ],
144             */
145             $fn = $el['*fullname'];
146             
147             unset($el['*fullname']);
148             $title = isset($el['fieldLabel']) ?$el['fieldLabel'] : $fn;
149             if (isset($el['*title'])) {
150                 $title = $el['*title'];
151                 unset($el['*title']);
152             }
153             $ret[] = array(
154                 'grp' => $tb, 
155                 'name' => $title,
156                 'description' => $fn, 
157                 'cfg' => $el
158                 );
159             
160             $ret[0]['cfg']['items'][] = $el;
161             
162         }
163         $this->jdata($ret);
164          
165         
166     }
167     
168     function rowToFormElement($t,$tab)
169     {
170         
171         $el['name'] = $t->name;
172         $el['*fullname'] = $tab.'.' . $t->name; /// ???
173         $fl = preg_replace('/_/', ' ', $t->name);
174         $fl = preg_replace('/ id$/', ' ', $fl);
175         $el['fieldLabel'] = ucfirst($fl);
176         
177         
178         
179         switch (strtoupper($t->type)) {
180
181                 case 'INT':
182                 case 'INT2':    // postgres
183                 case 'INT4':    // postgres
184                 case 'INT8':    // postgres
185                 case 'SERIAL4': // postgres
186                 case 'SERIAL8': // postgres
187                 case 'INTEGER':
188                 case 'TINYINT':
189                 case 'SMALLINT':
190                 case 'MEDIUMINT':
191                 case 'BIGINT':
192                     if ($t->name == 'id') {
193                         $el['*title'] = 'Hidden: id';
194                         $el['xtype'] = 'Hidden';
195                         unset($el['fieldLabel']);
196                         break;
197                     }
198                     $el['width'] = 50;
199                     $el['xtype'] = 'NumberField';
200                     $el['allowDecimals'] = false;
201                     
202                     //bools???
203                     break;
204                
205                 case 'REAL':
206                 case 'DOUBLE':
207                 case 'DOUBLE PRECISION': // double precision (firebird)
208                 case 'FLOAT':
209                 case 'FLOAT4': // real (postgres)
210                 case 'FLOAT8': // double precision (postgres)
211                 case 'DECIMAL':
212                 case 'MONEY':  // mssql and maybe others
213                 case 'NUMERIC':
214                 case 'NUMBER': // oci8 
215                     $el['xtype'] = 'NumberField';
216                     break;
217                     
218                 case 'YEAR':
219                     
220                     $el['allowDecimals'] = false;
221                     $el['xtype'] = 'NumberField'; // YeaR?
222                     break;
223                     
224                 case 'BIT':
225                 case 'BOOL':   
226                 case 'BOOLEAN':   
227                     
228                     $el['xtype'] = 'CheckBox'; // fix - I think I've updated the api..
229                     
230                    
231                     break;
232                     
233                 case 'STRING':
234                 case 'CHAR':
235                 case 'VARCHAR':
236                 case 'VARCHAR2':
237                 case 'TINYTEXT':
238                 
239                 case 'ENUM':
240                 case 'SET':         // not really but oh well
241                 
242                 case 'POINT':       // mysql geometry stuff - not really string - but will do..
243                 
244                 case 'TIMESTAMPTZ': // postgres
245                 case 'BPCHAR':      // postgres
246                 case 'INTERVAL':    // postgres (eg. '12 days')
247                 
248                 case 'CIDR':        // postgres IP net spec
249                 case 'INET':        // postgres IP
250                 case 'MACADDR':     // postgress network Mac address.
251                 
252                 case 'INTEGER[]':   // postgres type
253                 case 'BOOLEAN[]':   // postgres type
254                   
255                     $el['width'] = isset($t->len) ? max(50, min(floor($t->len * 10), 200)) : 200;
256                     $el['xtype'] = 'TextField';
257                     break;
258                 
259                 case 'TEXT':
260                 case 'MEDIUMTEXT':
261                 case 'LONGTEXT':
262                     $el['width'] =  300;
263                     $el['height'] =  70;
264                     $el['xtype'] = 'TextArea'; // or HtmlEditor
265                     
266                     break;
267                 
268                 
269                 case 'DATE':    
270                     
271                     $el['xtype'] = 'DateField'; 
272                     $el['altFormats'] = 'Y-m-d|d/m/Y';
273                     $el['format'] = 'd/m/Y';
274                     $el['hiddenFormat'] = 'Y-m-d'; // not supported ATM
275         
276                     break;
277                     
278                 case 'TIME':    
279                     $el['xtype'] = 'TextField'; // time field.?
280                     break;    
281                     
282                 
283                 case 'DATETIME': 
284                     $el['xtype'] = 'TextField';
285                     $el['readOnly'] = 'true';
286                     break;    
287                     
288                 case 'TIMESTAMP': // do other databases use this???
289                     $el['xtype'] = 'TextField';
290                     $el['readOnly'] = 'true'; 
291                     break;    
292                     
293                 
294                 case 'BLOB':       /// these should really be ignored!!!???
295                 case 'TINYBLOB':
296                 case 'MEDIUMBLOB':
297                 case 'LONGBLOB':
298                 
299                 case 'CLOB': // oracle character lob support
300                 
301                 case 'BYTEA':   // postgres blob support..
302                     
303                     $el['xtype'] = 'TextArea'; // or HtmlEditor
304                     $el['width'] =  300;
305                     $el['height'] = 100;
306                     break;
307                     
308                 default:     
309                     return false;
310                     break;
311             }
312             return $el;
313     }
314     
315     
316     function readElement($fn)
317     {
318         
319         $fn = preg_replace('/[^a-z]+i/', '',$fn);
320         $f = dirname(__FILE__)."/Elements/$fn.js";
321         if (!file_exists($f)) {
322             $this->jerr("no such file");
323         }
324         
325         $lines = file($f);
326         $ret = array();
327         $atStart = true;
328         for ($i = 0; $i< count($lines); $i++) {
329             $l = $lines[$i];
330             if ($atStart && trim($l) != '[') {
331                 continue;
332             }
333             $atStart = false;
334             
335             if (!preg_match('/function/', $l)) {
336                 $ret[] = $l;
337                 continue;
338             }
339             // got a function def...
340             $lt = trim($l);
341             $pad = substr($l,0, strpos($l, $lt)) .'}';
342             list($k, $func) = explode(':', $l);
343             $rem = '';
344             while ($i < count($lines)) {
345                 $i++;
346                 $l = $lines[$i];
347                 
348                 if ($pad  == substr($l, 0, strlen($pad))) {
349                     $func.= "\n".$pad;
350                     $rem = substr($l, strlen($pad)); //left over..
351                     break;
352                 }
353                 $func.= "\n".$l;
354                 
355             }
356             $ret[] = $k .' : ' . json_encode($func."\n") . $rem;
357             
358             
359             
360         }
361         require_once 'Services/JSON.php';
362         $j = new Services_JSON();
363         //echo '<PRE>';
364         //print_R($ret);
365         $json= $j->decode(implode("\n", $ret));
366         
367       //  echo '<PRE>';print_r($json);exit;
368         $this->jdata($json);
369         exit;
370         
371         
372     }
373          
374        
375      
376
377     function links()
378     {
379         
380         static $conf = false;
381         if ($conf) {
382             return $conf;
383         }
384         $ff = HTML_FlexyFramework::get();
385         $top = $ff->rootDir.'/Pman/';
386         
387         
388         $conf = array('database__render'=>array());
389         foreach(scandir($top) as $m) {
390             $vf = $top .'/'.$m.'/DataObjects/pman.links.ini';
391             if (!strlen($m) ||  $m[0] == '.' ||  !file_exists($vf) ) {
392                 continue;
393             }
394             $c = parse_ini_file($vf,true);
395             if (isset($c['database__render'])) {
396                 $conf['database__render'] = array_merge($conf['database__render'], $c['database__render']);
397                 unset($c['database__render']);
398             }
399             $conf = array_merge($conf , $c);
400         }
401         
402         return $conf;
403        }
404     
405     function linkedToFormElement($r, $tb, $el) // creates combos for for elements.
406     {
407         // get the links..
408         $conf = $this->links();
409         //var_dump($conf);
410         if (!is_array($conf) || !isset($conf[$tb]) || !isset($conf[$tb][$r])) {
411             return $el;
412         }
413         list($mtb, $mr) = explode(':', $conf[$tb][$r]);
414         // work out the display field.
415         if (!isset($conf['database__render'][$mtb])) {
416             return $el;
417         }
418         $df = $conf['database__render'][$mtb];
419         
420         
421         $ret = array(
422             '*title'=> 'Combo: '. $el['fieldLabel'],
423             '*fullname' => $el['*fullname'],
424             'fieldLabel' => $el['fieldLabel'],
425             'name' => $el['name'] . '_' . $df,
426             'hiddenName' => $el['name'],
427             
428             'qtip' => 'Select ' . $el['fieldLabel'],   
429             'emptyText' => 'Select ' . $el['fieldLabel'],   
430
431             'xtype' => 'ComboBox',
432             'selectOnFocus' => true,
433                    
434             'allowBlank' => true,
435             'width'=> 300,
436             'listWidth' => 300,
437             'editable'=> false,
438             /*
439             'store'=> array(
440                 'xtype' => 'Store',
441                 'proxy'=> array(
442                     'xtype'=> 'HttpProxy',
443                      '|url'=> "baseURL + '/Roo/" . $mtb.".php'",
444                     'method'=> 'GET'
445                 ), 
446                 //'listeners' =>storeListeners,
447                 '|reader'=> 'Pman.Readers.'.$mtb,
448             ),
449             */
450             'displayField'=> $df,
451             'valueField' => $mr,  
452             
453             'typeAhead'=> true,
454             'forceSelection'=> true,
455            
456             'triggerAction'=> 'all',
457              
458             'tpl'=> '<div class="x-grid-cell-text x-btn button">'.
459                     '<b>{'.$df.'}</b> '.
460                 '</div>'
461             ,
462              
463             'queryParam'=> 'query['.$df.']',
464             'loadingText'=> "Searching...",
465             'listWidth'=> 400,
466            
467             'minChars'=> 2,
468             'pageSize'=>20,
469             
470             'items' => array(
471                 array(
472                     '*prop' => 'store',
473                     'xtype' => 'Store',
474                     'items' => array( array(
475                     
476                         '*prop' => 'proxy',
477                         'xtype'=> 'HttpProxy',
478                          '|url'=> "baseURL + '/Roo/" . ucfirst($mtb).".php'",
479                         'method'=> 'GET'
480                     )), 
481                 
482                     //'listeners' =>storeListeners,
483                     '|reader'=> 'Pman.Readers.'.ucfirst($mtb),
484                 )
485             )
486                 
487             
488             
489            // 'listeners' => {
490           //      'select' =>  function(cb, rec, ix) {
491            //         cb.lastData = rec.data;
492            //     }
493            // },
494             
495            
496         );
497         
498         return $ret;
499         
500         
501         
502         
503     }
504     
505
506     
507     function getGridElements()
508     {
509         $d = DB_DataObject::factory('Person');
510         $db = $d->getDatabaseConnection();
511         
512         $ret = array();
513         $tables = $db->getListOf('tables');
514         foreach($tables as $t) {
515             $ret[] = $this->tableToGrid($t);
516             
517             
518         }
519         $this->jdata($ret);
520         
521     }
522     
523     function tableToGrid($t)
524     {
525         $d = DB_DataObject::factory('Person');
526         $this->db = $d->getDatabaseConnection();
527         
528         $colmodel = $this->colModel($t);
529         $aec = isset($colmodel[0]['dataIndex']) ? $colmodel[0]['dataIndex'] : '';
530         $rawReader = $this->readerRaw($t); // usefull if no reader will be generated.
531         
532         
533         return array(
534             'grp' => 'Grids', 
535             'name' => $t,
536             'description' => "Grid for table . $t",
537             'cfg' =>  array(
538                 'xtype'=>'GridPanel',
539                 'title' => $t,
540                 'fitToframe' => true,
541                 'fitContainer' => true,
542                 'tableName' => $t,
543                 'background' => true,
544                 'listeners' => array(
545                     '|activate'  => "function() {
546     _this.panel = this;
547     if (_this.grid) {
548         _this.grid.footer.onClick('first');
549     }
550 }",
551                 ),
552                 'items' => array(
553                     array(
554                         '*prop' => 'grid',
555                         'xtype' => 'Grid',
556                         'autoExpandColumn' => $aec,
557                         'loadMask' => true,
558                         'listeners' => array(
559                             '|render' => 'function() { 
560     _this.grid = this; 
561     //_this.dialog = Pman.Dialog.FILL_IN
562     if (_this.panel.active) {
563        this.footer.onClick(\'first\');
564     }
565 }'
566                         ),
567                         'items' => array(
568                             array(
569                                 '*prop' => 'dataSource',
570                                 'xtype' => 'Store',
571                                 'items' => array( array(
572             
573                                     '*prop' => 'proxy',
574                                     'xtype'=> 'HttpProxy',
575                                     'method' => 'GET',
576                                     '|url'=> "baseURL + '/Roo/$t.php'"
577                                 )), 
578                                 '|reader'=> "Pman.Readers." . ucfirst($t),
579                                 '|readerRaw'=> $rawReader,
580                             ),
581                             array(
582                                 '*prop' => 'colModel',
583                                 'xtype' => 'Array',
584                                 'items' => $colmodel,
585                        
586                                 
587                                 
588                             ), 
589                              array(
590                                 '*prop' => 'footer',
591                                 'xtype' => 'PagingToolbar',
592                                 'pageSize' => 25,
593                                 'displayInfo' => true,
594                                 'displayMsg' => "Displaying $t  {0} - {1} of {2}",
595                                 'emptyMsg' => "No $t found"
596                             ),
597                                   
598                             array(
599                                 '*prop' => 'toolbar',
600                                 'xtype' => 'Toolbar',
601                                 'items' => array(
602                                     array(
603                                         'text'=> "Add",
604                                         'xtype' => 'Button',
605                                         'cls' => 'x-btn-text-icon',
606                                         '|icon' => "Roo.rootURL + 'images/default/dd/drop-add.gif'",
607                                         'listeners' => array(
608                                             '|click' => 'function()
609         {
610             _this.dialog.show( { id : 0 }, function() {
611                 _this.grid.footer.onClick(\'first\');
612
613             }); 
614
615         }
616         '
617                                         )
618                                     ), 
619                                     array(
620                                         'text'=> "Edit",
621                                         'xtype' => 'Button', 
622                                         'cls' => 'x-btn-text-icon',
623                                         '|icon' => "Roo.rootURL + 'images/default/tree/leaf.gif'",
624
625                                         'listeners' => array(
626                                             '|click' => 'function()
627         {
628             var s = _this.grid.getSelectionModel().getSelections();
629             if (!s.length || (s.length > 1))  {
630                 Roo.MessageBox.alert("Error", s.length ? "Select only one Row" : "Select a Row");
631                 return;
632             }
633             
634             _this.dialog.show(s[0].data, function() {
635                 _this.grid.footer.onClick(\'first\');
636                }); 
637             
638         }
639         '
640                                         )
641                                     ),  
642                                     array(
643                                         'text'=> "Delete",
644                                         'cls' => 'x-btn-text-icon',
645                                         '|icon' => "rootURL + '/Pman/templates/images/trash.gif'",
646                                         'xtype' => 'Button',
647                                         'listeners' => array(
648                                             '|click' => 'function()
649         {
650         Pman.genericDelete(_this, _this.grid.tableName); 
651         }
652         '
653                                         )
654                                     )
655
656                                 )
657                            )   
658                         ),
659                     
660                     ),
661                     
662                 )                
663                                     
664             )
665         );
666          
667     }
668     function colModel($tb)
669     {
670         // just ouput stuff...
671         
672         $def=  $this->db->tableInfo($tb);
673         $ret = array();
674         $conf = $this->links();
675         foreach($def as $r) {
676             $rn = $r['name'];
677             if ($r['name'] == 'id') {
678                 continue;
679             }
680             $fl = preg_replace('/_/', ' ', $r['name']);
681             $fl = preg_replace('/ id$/', ' ', $fl);
682             
683             $add =  array(
684                 'xtype'=> '*ColumnModel',
685                 'header'=> ucfirst($fl),
686                 'width' => 100,
687                 'dataIndex' => $rn,
688                 '|renderer' => "function(v) { return String.format('{0}', v); }",
689             );
690              
691             
692             //var_dump($conf);
693             if (!is_array($conf) || !isset($conf[$tb]) || !isset($conf[$tb][$rn])) {
694                 $ret[] = $add;
695                 continue;
696             }
697             list($mtb, $mr) = explode(':', $conf[$tb][$rn]);
698             // work out the display field.
699             if (!isset($conf['database__render'][$mtb])) {
700                 $ret[] = $add;
701                 continue;
702             }
703             // linkded colum...
704             
705             $add['dataIndex'] = $rn.'_'. $conf['database__render'][$mtb];
706             $ret[] = $add;
707         }
708         return $ret;
709     }
710     
711     function readerRaw($tb)
712     {
713         // just ouput stuff...
714         require_once 'Pman/Builder/Generator.php';
715         require_once 'Pman/Builder/Generator/JSON.php';
716         
717         $x = DB_DataObject::factory('Builder');
718         $basedef = $x->getDatabaseConnection()->tableInfo($tb);
719         $def = Pman_Builder_Generator::tableToData($tb, $basedef);
720         require_once 'Pman/Builder/Generator/JSON.php';
721         $j = new Pman_Builder_Generator_JSON(array('crlf' => "\n", 'tab' => '    '));
722         $j2 = new Pman_Builder_Generator_JSON(array('crlf' => '', 'tab' => ''));
723         
724         $x = 'new Roo.data.JsonReader(' . $j->encodeUnsafe($def['args']);
725         $ret =  trim(substr($x, 0, -1)) . ",\n"; // strip of trailing ;};
726         $ret .=  $j->tab . "fields : [\n". $j->tab.$j->tab;
727         $ar = array();
728         foreach($def['readers'] as $xr) {
729             $ar[] = $j2->encodeUnsafe($xr);
730         }
731         $ret .= implode(",\n". $j->tab.$j->tab, $ar);
732         $ret .= "\n".  $j->tab . "]\n})\n";
733         return $ret;    
734         
735         
736     }
737     
738     
739 }