Pman/Roo.php
[Pman.Base] / Pman / Roo.php
1 <?php
2
3
4 require_once 'Pman.php';
5 /**
6  * 
7  * 
8  * not really sure how save our factory method is....!!!
9  * 
10  * 
11  * Uses these methods of the dataobjects:
12  * - checkPerm('L'/'E'/'A', $authuser) - can we list the stuff
13  * 
14  * - applySort($au, $sortcol, $direction)
15  * - applyFilters($_REQUEST, $authUser) -- apply any query filters on data. and hide stuff not to be seen.
16  * - postListExtra - add extra column data on the results (like new messages etc.)
17  * -postListFilter($data, $authUser, $request) return $data - add extra data to an object
18  * 
19  * - toRooSingleArray() // single fetch, add data..
20  * - toRooArray($request) /// toArray if you need to return different data.. for a list fetch.
21  * 
22  * 
23  * - beforeDelete() -- return false for fail and set DO->err;
24  * - onUpdate($old, $request,$roo) - after update
25  * - onInsert($request,$roo) - after insert
26  * - onUpload($roo)
27  * - setFromRoo($ar) - values from post (deal with dates etc.) - return true|error string.
28  * 
29  * - toEventString (for logging)
30  */
31
32 class Pman_Roo extends Pman
33 {
34     
35    function getAuth() {
36         parent::getAuth(); // load company!
37         $au = $this->getAuthUser();
38         if (!$au) {
39             $this->jerr("Not authenticated", array('authFailure' => true));
40         }
41         $this->authUser = $au;
42         return true;
43     }
44     /**
45      * GET method   Roo/TABLENAME.php 
46      * -- defaults to listing data. with args.
47      * 
48      * other opts:
49      * _post      = simulate a post with debuggin on.
50      * lookup     =  array( k=>v) single fetch based on a key/value pair
51      * _id        =  single fetch based on id.
52      * _delete    = delete a list of ids element. (seperated by ,);
53      * _columns   = comma seperated list of columns.
54      * csvCols    = return data as csv
55      * csvTitles  = return data as csv
56      *
57      * sort        = sort column
58      * dir         = sort direction
59      * start       = limit start
60      * limit       = limit number 
61      * 
62      * _toggleActive !:!:!:! - this hsould not really be here..
63      * query[add_blank] - add a line in with an empty option...  - not really needed???
64      * 
65      */
66     function get($tab)
67     {
68          //  $this->jerr("Not authenticated", array('authFailure' => true));
69          //DB_DataObject::debuglevel(1);
70         
71         // debugging...
72         if (!empty($_GET['_post'])) {
73             $_POST  = $_GET;
74             DB_DAtaObject::debuglevel(1);
75             return $this->post($tab);
76         }
77         $tab = str_replace('/', '',$tab); // basic protection??
78         $x = DB_DataObject::factory($tab);
79         if (!is_a($x, 'DB_DataObject')) {
80             $this->jerr('invalid url');
81         }
82         $_columns = !empty($_REQUEST['_columns']) ? explode(',', $_REQUEST['_columns']) : false;
83         
84         if (isset( $_REQUEST['lookup'] )) { // single fetch based on key/value pairs
85             if (method_exists($x, 'checkPerm') && !$x->checkPerm('S', $this->authUser))  {
86                 $this->jerr("PERMISSION DENIED");
87             }
88             $this->loadMap($x, $_columns);
89             $x->setFrom($_REQUEST['lookup'] );
90             $x->limit(1);
91             if (!$x->find(true)) {
92                 $this->jok(false);
93             }
94             $this->jok($x->toArray());
95         }
96         
97         
98         
99         if (isset($_REQUEST['_id'])) { // single fetch
100             
101             if (empty($_REQUEST['_id'])) {
102                 $this->jok($x->toArray());  // return an empty array!
103             }
104            
105             $this->loadMap($x, $_columns);
106             
107             if (!$x->get($_REQUEST['_id'])) {
108                 $this->jerr("no such record");
109             }
110             
111             if (method_exists($x, 'checkPerm') && !$x->checkPerm('S', $this->authUser))  {
112                 $this->jerr("PERMISSION DENIED");
113             }
114             
115             $this->jok(method_exists($x, 'toRooSingleArray') ? $x->toRooSingleArray($this->authUser) : $x->toArray());
116             
117         }
118         if (isset($_REQUEST['_delete'])) {
119             // do we really delete stuff!?!?!?
120            
121             
122             $clean = create_function('$v', 'return (int)$v;');
123             
124             $bits = array_map($clean, explode(',', $_REQUEST['_delete']));
125             $x->whereAdd('id IN ('. implode(',', $bits) .')');
126             $x->find();
127             $errs = array();
128             while ($x->fetch()) {
129                 $xx = clone($x);
130                 
131                 if (method_exists($x, 'checkPerm') && !$x->checkPerm('D', $this->authUser))  {
132                     $this->jerr("PERMISSION DENIED");
133                 }
134                 
135                 $this->addEvent("DELETE", $x, $x->toEventString());
136                 if ( method_exists($xx, 'beforeDelete') && ($xx->beforeDelete() === false)) {
137                     $errs[] = "Delete failed ({$xx->id})\n". (isset($xx->err) ? $xx->err : '');
138                     continue;
139                 }
140                 $xx->delete();
141             }
142             if ($errs) {
143                 $this->jerr(implode("\n<BR>", $errs));
144             }
145             $this->jok("Deleted");
146             
147         }
148         if (isset($_REQUEST['_toggleActive'])) {
149             // do we really delete stuff!?!?!?
150             if (!$this->hasPerm("Core.Staff", 'E'))  {
151                 $this->jerr("PERMISSION DENIED");
152             }
153             $clean = create_function('$v', 'return (int)$v;');
154             $bits = array_map($clean, explode(',', $_REQUEST['_toggleActive']));
155             if (in_array($this->authUser->id, $bits) && $this->authUser->active) {
156                 $this->jerr("you can not disable yourself");
157             }
158             $x->query('UPDATE Person SET active = !active WHERE id IN (' .implode(',', $bits).')');
159             $this->addEvent("USERTOGGLE", false, implode(',', $bits));
160             $this->jok("Updated");
161             
162         }
163       // DB_DataObject::debugLevel(1);
164         if (method_exists($x, 'checkPerm') && !$x->checkPerm('S', $this->authUser))  {
165             $this->jerr("PERMISSION DENIED");
166         }
167         $map = $this->loadMap($x, $_columns);
168         
169         $this->setFilters($x,$_REQUEST);
170         
171          
172         
173         // build join if req.
174         $countWhat = false;
175         if (!empty($_REQUEST['_distinct'])) {
176             $cols = $x->table();
177            // print_r($cols);
178           
179             if (isset($cols[$_REQUEST['_distinct']])) {
180                 $countWhat = 'distinct ' . $_REQUEST['_distinct'];
181             }
182              
183         }
184         $total = $x->count($countWhat);
185         // sorting..
186       //   DB_DataObject::debugLevel(1);
187         
188         $sort = empty($_REQUEST['sort']) ? '' : $_REQUEST['sort'];
189         $dir = (empty($_REQUEST['dir']) || strtoupper($_REQUEST['dir']) == 'ASC' ? 'ASC' : 'DESC');
190         
191         $sorted = false;
192         if (method_exists($x, 'applySort')) {
193             $sorted = $x->applySort($this->authUser, $sort, $dir, $this->cols);
194         }
195         if ($sorted === false) {
196             
197             $cols = $x->table();
198            // echo '<PRE>';print_r(array($sort, $this->cols));
199             // other sorts??? 
200            // $otherSorts = array('person_id_name');
201             
202             if (strlen($sort) && isset($cols[$sort]) ) {
203                 $sort = $x->tableName() .'.'.$sort . ' ' . $dir ;
204                 $x->orderBy($sort );
205             } else if (in_array($sort, $this->cols)) {
206                 $sort = $sort . ' ' . $dir ;
207                 $x->orderBy($sort );
208             }// else other formatas?
209             //if ( in_array($sort, $otherSorts)) {
210             //    $x->orderBy($sort . ' ' . $dir);
211             ////}
212         }
213         
214         
215  
216         $x->limit(
217             empty($_REQUEST['start']) ? 0 : (int)$_REQUEST['start'],
218             min(empty($_REQUEST['limit']) ? 25 : (int)$_REQUEST['limit'], 1000)
219         );
220         
221         $queryObj = clone($x);
222         
223         $x->find();
224         $ret = array();
225         
226         if (!empty($_REQUEST['query']['add_blank'])) {
227             $ret[] = array( 'id' => 0, 'name' => '----');
228             $total+=1;
229         }
230         // MOVE ME...
231         
232         //if (($tab == 'Groups') && ($_REQUEST['type'] != 0))  { // then it's a list of teams..
233         if ($tab == 'Groups') {
234             
235             $ret[] = array( 'id' => 0, 'name' => 'EVERYONE');
236             $ret[] = array( 'id' => -1, 'name' => 'NOT_IN_GROUP');
237             //$ret[] = array( 'id' => 999999, 'name' => 'ADMINISTRATORS');
238             $total+=2;
239         }
240         
241         // DOWNLOAD...
242         
243         if (!empty($_REQUEST['csvCols']) && !empty($_REQUEST['csvTitles']) ) {
244             header('Content-type: text/csv');
245             
246             header('Content-Disposition: attachment; filename="documentlist-export-'.date('Y-m-d') . '.csv"');
247             //header('Content-type: text/plain');
248             $fh = fopen('php://output', 'w');
249             fputcsv($fh, $_REQUEST['csvTitles']);
250             while ($x->fetch()) {
251                 //echo "<PRE>"; print_r(array($_REQUEST['csvCols'], $x->toArray())); exit;
252                 $line = array();
253                 foreach($_REQUEST['csvCols'] as $k) {
254                     $line[] = isset($x->$k) ? $x->$k : '';
255                 }
256                 fputcsv($fh, $line);
257             }
258             fclose($fh);
259             exit;
260             
261         
262         }
263         //die("DONE?");
264         
265         $rooar = method_exists($x, 'toRooArray');
266         
267         while ($x->fetch()) {
268             $add = $rooar  ? $x->toRooArray($_REQUEST) : $x->toArray();
269             
270             $ret[] =  !$_columns ? $add : array_intersect_key($add, array_flip($_columns));
271         }
272         //if ($x->tableName() == 'Documents_Tracking') {
273         //    $ret = $this->replaceSubject(&$ret, 'doc_id_subject');
274        // }
275         
276         $extra = false;
277         if (method_exists($queryObj ,'postListExtra')) {
278             $extra = $queryObj->postListExtra($_REQUEST);
279         }
280         // filter results, and add any data that is needed...
281         if (method_exists($x,'postListFilter')) {
282             $ret = $x->postListFilter($ret, $this->authUser, $_REQUEST);
283         }
284         
285         
286         
287        // echo "<PRE>"; print_r($ret);
288         $this->jdata($ret,$total, $extra );
289
290     
291     }
292      /**
293      * POST method   Roo/TABLENAME.php 
294      * -- updates the data..
295      * 
296      * other opts:
297      * _debug - forces debugging on.
298      * _get - forces a get request
299      * _ids - multiple update of records.
300      * {colid} - forces fetching
301      * 
302      */
303     function post($tab) // update / insert (?? dleete??)
304     {
305        // DB_DataObject::debugLevel(1);
306         if (!empty($_REQUEST['_debug'])) {
307             DB_DataObject::debugLevel(1);
308         }
309         
310         if (!empty($_REQUEST['_get'])) {
311             return $this->get($tab);
312         }
313         $_columns = !empty($_REQUEST['_columns']) ? explode(',', $_REQUEST['_columns']) : false;
314         
315         $tab = str_replace('/', '',$tab); // basic protection??
316         $x = DB_DataObject::factory($tab);
317         if (!is_a($x, 'DB_DataObject')) {
318             $this->jerr('invalid url');
319         }
320         // find the key and use that to get the thing..
321         $keys = $x->keys();
322         if (empty($keys) ) {
323             $this->jerr('no key');
324         }
325         $old = false;
326         
327         if (!empty($_REQUEST['_ids'])) {
328             $ids = explode(',',$_REQUEST['_ids']);
329             $x->whereAddIn($keys[0], $ids, 'int');
330             $ar = $x->fetchAll();
331             foreach($ar as $x) {
332                 $this->update($x, $_REQUEST);
333                 
334             }
335             // all done..
336             $this->jok("UPDATED");
337             
338             
339         }
340         
341         
342         if (!empty($_REQUEST[$keys[0]])) {
343             // it's a create..
344             if (!$x->get($keys[0], $_REQUEST[$keys[0]]))  {
345                 $this->jerr("Invalid request");
346             }
347             $this->jok($this->update($x, $_REQUEST));
348         } else {
349             $this->jok($this->insert($x, $_REQUEST));
350             
351         }
352         
353         
354         
355     }
356     function insert($x, $req)
357     {
358         
359     
360         if (method_exists($x, 'checkPerm') && !$x->checkPerm('A', $this->authUser, $req))  {
361             $this->jerr("PERMISSION DENIED");
362         }
363         
364         $_columns = !empty($req['_columns']) ? explode(',', $req['_columns']) : false;
365    
366         if (method_exists($x, 'setFromRoo')) {
367             $res = $x->setFromRoo($req, $this);
368             if (is_string($res)) {
369                 $this->jerr($res);
370             }
371         } else {
372             $x->setFrom($req);
373         }
374         
375          
376         $cols = $x->table();
377      
378         if (isset($cols['created'])) {
379             $x->created = date('Y-m-d H:i:s');
380         }
381         if (isset($cols['created_dt'])) {
382             $x->created_dt = date('Y-m-d H:i:s');
383         }
384         if (isset($cols['created_by'])) {
385             $x->created_by = $this->authUser->id;
386         }
387         
388      
389          if (isset($cols['modified'])) {
390             $x->modified = date('Y-m-d H:i:s');
391         }
392         if (isset($cols['modified_dt'])) {
393             $x->modified_dt = date('Y-m-d H:i:s');
394         }
395         if (isset($cols['modified_by'])) {
396             $x->modified_by = $this->authUser->id;
397         }
398         
399         if (isset($cols['updated'])) {
400             $x->updated = date('Y-m-d H:i:s');
401         }
402         if (isset($cols['updated_dt'])) {
403             $x->updated_dt = date('Y-m-d H:i:s');
404         }
405         if (isset($cols['updated_by'])) {
406             $x->updated_by = $this->authUser->id;
407         }
408         
409      
410         
411         
412         
413         $x->insert();
414         if (method_exists($x, 'onInsert')) {
415             $x->onInsert($_REQUEST, $this);
416         }
417         $this->addEvent("ADD", $x, $x->toEventString());
418         
419         // note setFrom might handle this before hand...!??!
420         if (!empty($_FILES) && method_exists($x, 'onUpload')) {
421             $x->onUpload($this);
422         }
423         
424         $r = DB_DataObject::factory($x->tableName());
425         $r->id = $x->id;
426         $this->loadMap($r, $_columns);
427         $r->limit(1);
428         $r->find(true);
429         
430         $rooar = method_exists($r, 'toRooArray');
431         //print_r(var_dump($rooar)); exit;
432         return $rooar  ? $r->toRooArray() : $r->toArray();
433     }
434     
435     
436     function update($x, $req)
437     {
438         if (method_exists($x, 'checkPerm') && !$x->checkPerm('E', $this->authUser, $_REQUEST))  {
439             $this->jerr("PERMISSION DENIED");
440         }
441        
442         $_columns = !empty($req['_columns']) ? explode(',', $req['_columns']) : false;
443
444        
445         $old = clone($x);
446         $this->old = $x;
447         // this lot is generic.. needs moving 
448         if (method_exists($x, 'setFromRoo')) {
449             $res = $x->setFromRoo($req, $this);
450             if (is_string($res)) {
451                 $this->jerr($res);
452             }
453         } else {
454             $x->setFrom($req);
455         }
456         $this->addEvent("EDIT", $x, $x->toEventString());
457         //print_r($x);
458         //print_r($old);
459         
460         $cols = $x->table();
461         
462         if (isset($cols['modified'])) {
463             $x->modified = date('Y-m-d H:i:s');
464         }
465         if (isset($cols['modified_dt'])) {
466             $x->modified_dt = date('Y-m-d H:i:s');
467         }
468         if (isset($cols['modified_by'])) {
469             $x->modified_by = $this->authUser->id;
470         }
471         
472         if (isset($cols['updated'])) {
473             $x->updated = date('Y-m-d H:i:s');
474         }
475         if (isset($cols['updated_dt'])) {
476             $x->updated_dt = date('Y-m-d H:i:s');
477         }
478         if (isset($cols['updated_by'])) {
479             $x->updated_by = $this->authUser->id;
480         }
481         
482         
483         $x->update($old);
484         if (method_exists($x, 'onUpdate')) {
485             $x->onUpdate($old, $req, $this);
486         }
487         
488         $r = DB_DataObject::factory($x->tableName());
489         $r->id = $x->id;
490         $this->loadMap($r, $_columns);
491         $r->limit(1);
492         $r->find(true);
493         $rooar = method_exists($r, 'toRooArray');
494         //print_r(var_dump($rooar)); exit;
495         return $rooar  ? $r->toRooArray() : $r->toArray();
496     }
497     
498     
499     
500     var $cols = array();
501     function loadMap($do, $filter=false) 
502     {
503         //DB_DataObject::debugLevel(1);
504         $conf = array();
505         
506         
507         $this->init();
508         $mods = explode(',',$this->appModules);
509         
510         $ff = HTML_FlexyFramework::geT();
511         //$db->databaseName();
512         
513         //$ff->DB_DataObject['ini_'. $db->database()];
514         //echo '<PRE>';print_r($do->links());exit;
515         //var_dump($mods);
516         
517         if (in_array('Builder', $mods) ) {
518             
519             foreach(in_array('Builder', $mods) ? scandir($this->rootDir.'/Pman') : $mods as $m) {
520                 
521                 if (!strlen($m) || $m[0] == '.' || !is_dir($this->rootDir."/Pman/$m")) {
522                     continue;
523                 }
524                 $ini = $this->rootDir."/Pman/$m/DataObjects/pman.links.ini";
525                 if (!file_exists($ini)) {
526                     continue;
527                 }
528                 $conf = array_merge($conf, parse_ini_file($ini,true));
529                 if (!isset($conf[$do->tableName()])) {
530                     return;
531                 }
532                 $map = $conf[$do->tableName()];
533             } 
534         } else {
535             $map = $do->links();
536         }
537          
538         
539         
540         
541         // current table..
542         $tabdef = $do->table();
543         if (isset($tabdef['passwd'])) {
544             // prevent exposure of passwords..
545             unset($tabdef['passwd']);     
546         }
547         $xx = clone($do);
548         $xx = array_keys($tabdef);
549         $do->selectAdd(); // we need thsi as normally it's only cleared by an empty selectAs call.
550         
551         if ($filter) {
552             $cols = array();
553          
554             foreach($xx as $c) {
555                 if (in_array($c, $filter)) {
556                     $cols[] = $c;
557                 }
558             }
559             $do->selectAs($cols);
560         } else {
561             $do->selectAs($xx);
562         }
563         
564         
565         
566         
567         $this->cols = $xx;
568         
569         
570         
571          
572         
573         foreach($map as $ocl=>$info) {
574             
575             list($tab,$col) = explode(':', $info);
576             // what about multiple joins on the same table!!!
577             $xx = DB_DataObject::factory($tab);
578             if (!is_a($xx, 'DB_DataObject')) {
579                 continue;
580             }
581             // this is borked ... for multiple jions..
582             $do->joinAdd($xx, 'LEFT', 'join_'.$ocl.'_'. $col, $ocl);
583             $tabdef = $xx->table();
584             $table = $xx->tableName();
585             if (isset($tabdef['passwd'])) {
586              
587                 unset($tabdef['passwd']);
588               
589             } 
590             $xx = array_keys($tabdef);
591             
592             
593             if ($filter) {
594                 $cols = array();
595                 foreach($xx as $c) {
596                     
597                     $tn = sprintf($ocl.'_%s', $c);
598                     if (in_array($tn, $filter)) {
599                         $cols[] = $c;
600                     }
601                 }
602                 $do->selectAs($cols, $ocl.'_%s', 'join_'.$ocl.'_'. $col);
603             } else {
604                 $do->selectAs($xx,  $ocl.'_%s', 'join_'.$ocl.'_'. $col);
605             }
606             
607              
608             
609             
610             
611             foreach($xx as $k) {
612                 $this->cols[] = sprintf($ocl.'_%s', $k);
613             }
614             
615             
616         }
617         //DB_DataObject::debugLevel(1);
618         
619         
620         
621     }
622     function setFilters($x, $q)
623     {
624         // if a column is type int, and we get ',' -> the it should be come an inc clause..
625        // DB_DataObject::debugLevel(1);
626         if (method_exists($x, 'applyFilters')) {
627            // DB_DataObject::debugLevel(1);
628             $x->applyFilters($q, $this->authUser);
629         }
630         $q_filtered = array();
631         
632         foreach($q as $key=>$val) {
633             
634             if (is_array($val)) {
635                 continue;
636             }
637             if ($key[0] == '!' && in_array(substr($key, 1), $this->cols)) {
638                     
639                 $x->whereAdd( $x->tableName() .'.' .substr($key, 1) . ' != ' .
640                     (is_numeric($val) ? $val : "'".  $x->escape($val) . "'")
641                 );
642                 continue;
643                 
644             }
645             
646             
647             
648             switch($key) {
649                     
650                 // Events and remarks
651                 case 'on_id':  // where TF is this used...
652                     if (!empty($q['query']['original'])) {
653                       //  DB_DataObject::debugLevel(1);
654                         $o = (int) $q['query']['original'];
655                         $oid = (int) $val;
656                         $x->whereAdd("(on_id = $oid  OR 
657                                 on_id IN ( SELECT distinct(id) FROM Documents WHERE original = $o ) 
658                             )");
659                         continue;
660                                 
661                     }
662                     $x->on_id = $val;
663                 
664                 
665                 default:
666                     if (strlen($val)) {
667                         $q_filtered[$key] = $val;
668                     }
669                     
670                     continue;
671             }
672         }
673         $x->setFrom($q_filtered);
674        
675         // nice generic -- let's get rid of it.. where is it used!!!!
676         // used by: 
677         // Person / Group
678         if (!empty($q['query']['name'])) {
679             $x->whereAdd($x->tableName().".name LIKE '". $x->escape($q['query']['name']) . "%'");
680         }
681         
682         // - projectdirectory staff list - persn queuy
683       
684          
685        
686          
687           
688         
689         
690     }
691     
692 }