]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - extlib/DB/DataObject/Links.php
Remember to purify HTML...
[quix0rs-gnu-social.git] / extlib / DB / DataObject / Links.php
1 <?php
2 /**
3  * Link tool for DB_DataObject
4  *
5  * PHP versions 5
6  *
7  * LICENSE: This source file is subject to version 3.01 of the PHP license
8  * that is available through the world-wide-web at the following URI:
9  * http://www.php.net/license/3_01.txt.  If you did not receive a copy of
10  * the PHP License and are unable to obtain it through the web, please
11  * send a note to license@php.net so we can mail you a copy immediately.
12  *
13  * @category   Database
14  * @package    DB_DataObject
15  * @author     Alan Knowles <alan@akbkhome.com>
16  * @copyright  1997-2006 The PHP Group
17  * @license    http://www.php.net/license/3_01.txt  PHP License 3.01
18  * @version    : FIXME
19  * @link       http://pear.php.net/package/DB_DataObject
20  */
21
22
23 /**
24  *
25  * Example of how this could be used..
26  * 
27  * The lind method are now in here.
28  *
29  * Currenly only supports existing methods, and new 'link()' method
30  *
31  */
32   
33   
34 /**
35  * Links class
36  *
37  * @package DB_DataObject
38  */
39 class DB_DataObject_Links 
40 {
41      /**
42      * @property {DB_DataObject}      do   DataObject to apply this to.
43      */
44     var $do = false;
45     
46     
47     /**
48      * @property {Array|String} load    What to load, 'all' or an array of properties. (default all)
49      */
50     var $load = 'all';
51     /**
52      * @property {String|Boolean}       scanf   use part of column name as resulting
53      *                                          property name. (default false)
54      */
55     var $scanf = false;
56     /**
57      * @property {String|Boolean}       printf  use column name as sprintf for resulting property name..
58      *                                     (default %s_link if apply is true, otherwise it is %s)
59      */
60     var $printf = false;
61     /**
62      * @property {Boolean}      cached  cache the result, so future queries will use cache rather
63      *                                  than running the expensive sql query.
64      */
65     var $cached = false;
66     /**
67      * @property {Boolean}      apply   apply the result to this object, (default true)
68      */
69     var $apply = true;
70    
71     
72     //------------------------- RETURN ------------------------------------
73     /**
74      * @property {Array}      links    key value associative array of links.
75      */
76     var $links;
77     
78     
79     /**
80      * Constructor
81      *   -- good ole style..
82      *  @param {DB_DataObject}           do  DataObject to apply to.
83      *  @param {Array}           cfg  Configuration (basically properties of this object)
84      */
85     
86     function DB_DataObject_Links($do,$cfg= array())
87     {
88         // check if do is set!!!?
89         $this->do = $do;
90         
91         foreach($cfg as $k=>$v) {
92             $this->$k = $v;
93         }
94        
95         
96     }
97      
98     /**
99      * return name from related object
100      *
101      * The relies on  a <dbname>.links.ini file, unless you specify the arguments.
102      * 
103      * you can also use $this->getLink('thisColumnName','otherTable','otherTableColumnName')
104      *
105      *
106      * @param string $field|array    either row or row.xxxxx or links spec.
107      * @param string|DB_DataObject $table  (optional) name of table to look up value in
108      * @param string $link   (optional)  name of column in other table to match
109      * @author Tim White <tim@cyface.com>
110      * @access public
111      * @return mixed object on success false on failure or '0' when not linked
112      */
113     function getLink($field, $table= false, $link='')
114     {
115         
116         static $cache = array();
117         
118         // GUESS THE LINKED TABLE.. (if found - recursevly call self)
119         
120         if ($table == false) {
121             
122             
123             $info = $this->linkInfo($field);
124             
125             if ($info) {
126                 return $this->getLink($field, $info[0],  $link === false ? $info[1] : $link );
127             }
128             
129             // no links defined.. - use borked BC method...
130                   // use the old _ method - this shouldnt happen if called via getLinks()
131             if (!($p = strpos($field, '_'))) {
132                 return false;
133             }
134             $table = substr($field, 0, $p);
135             return $this->getLink($field, $table);
136             
137             
138
139         }
140          
141         $tn = is_string($table) ? $table : $table->tableName();
142          
143             
144  
145         if (!isset($this->do->$field)) {
146             $this->do->raiseError("getLink: row not set $field", DB_DATAOBJECT_ERROR_NODATA);
147             return false;
148         }
149         
150         // check to see if we know anything about this table..
151         
152       
153         if (empty($this->do->$field) || $this->do->$field < 0) {
154             return 0; // no record. 
155         }
156         
157         if ($this->cached && isset($cache[$tn.':'. $link .':'. $this->do->$field])) {
158             return $cache[$tn.':'. $link .':'. $this->do->$field];    
159         }
160         
161         $obj = is_string($table) ? $this->do->factory($tn) : $table;;
162         
163         if (!is_a($obj,'DB_DataObject')) {
164             $this->do->raiseError(
165                 "getLink:Could not find class for row $field, table $tn", 
166                 DB_DATAOBJECT_ERROR_INVALIDCONFIG);
167             return false;
168         }
169         // -1 or 0 -- no referenced record..
170        
171         $ret = false;
172         if ($link) {
173             
174             if ($obj->get($link, $this->do->$field)) {
175                 $ret = $obj;
176             }
177             
178             
179         // this really only happens when no link config is set (old BC stuff)    
180         } else if ($obj->get($this->do->$field)) {
181             $ret= $obj;
182              
183         }
184         if ($this->cached) {
185             $cache[$tn.':'. $link .':'. $this->do->$field] = $ret;
186         }
187         return $ret;
188         
189     }
190     /**
191      * get link information for a field or field specification
192      *
193      * alll link (and join methods accept the 'link' info ) in various ways
194      * string : 'field' = which field to get (uses ???.links.ini to work out what)
195      * array(2) : 'field', 'table:remote_col' << just like the links.ini def.
196      * array(3) : 'field', $dataobject, 'remote_col'  (handy for joinAdd to do nested joins.)
197      *
198      * @param string|array $field or link spec to use. 
199      * @return (false|array) array of dataobject and linked field or false.
200      *
201      *
202      */
203     
204     function linkInfo($field)
205     {
206          
207         if (is_array($field)) {
208             if (count($field) == 3) {
209                 // array with 3 args:
210                 // local_col , dataobject, remote_col
211                 return array(
212                     $field[1],
213                     $field[2],
214                     $field[0]
215                 );
216                 
217             } 
218             list($table,$link) = explode(':', $field[1]);
219             
220             return array(
221                 $this->do->factory($table),
222                 $link,
223                 $field[0]
224             );
225             
226         }
227         // work out the link.. (classic way)
228         
229         $links = $this->do->links();
230         
231         if (empty($links) || !is_array($links)) {
232              
233             return false;
234         }
235             
236             
237         if (!isset($links[$field])) {
238             
239             return false;
240         }
241         list($table,$link) = explode(':', $links[$field]);
242     
243         
244         //??? needed???
245         if ($p = strpos($field,".")) {
246             $field = substr($field,0,$p);
247         }
248         
249         return array(
250             $this->do->factory($table),
251             $link,
252             $field
253         );
254         
255         
256          
257         
258     }
259     
260     
261         
262     /**
263      *  a generic geter/setter provider..
264      *
265      *  provides a generic getter setter for the referenced object
266      *  eg.
267      *  $link->link('company_id') returns getLink for the object
268      *  if nothing is linked (it will return an empty dataObject)
269      *  $link->link('company_id', array(1)) - just sets the 
270      *
271      *  also array as the field speck supports
272      *      $link->link(array('company_id', 'company:id'))
273      *  
274      *
275      *  @param  string|array   $field   the field to fetch or link spec.
276      *  @params array          $args    the arguments sent to the getter setter
277      *  @return mixed true of false on set, the object on getter.
278      *
279      */
280     function link($field, $args = array())
281     {
282         $info = $this->linkInfo($field);
283          
284         if (!$info) {
285             $this->do->raiseError(
286                 "getLink:Could not find link for row $field", 
287                 DB_DATAOBJECT_ERROR_INVALIDCONFIG);
288             return false;
289         }
290         $field = $info[2];
291         
292         
293         if (empty($args)) { // either an empty array or really empty....
294             
295             if (!isset($this->do->$field)) {
296                 return $info[0]; // empty dataobject.
297             }
298             
299             $ret = $this->getLink($field);
300             // nothing linked -- return new object..
301             return ($ret === 0) ? $info[0] : $ret;
302             
303         }
304         $assign = is_array($args) ? $args[0] : $args;
305          
306         // otherwise it's a set call..
307         if (!is_a($assign , 'DB_DataObject')) {
308             
309             if (is_numeric($assign) && is_integer($assign * 1)) {
310                 if ($assign  > 0) {
311                     
312                     if (!$info) {
313                         return false;
314                     }
315                     // check that record exists..
316                     if (!$info[0]->get($info[1], $assign )) {
317                         return false;
318                     }
319                     
320                 }
321                 
322                 $this->do->$field = $assign ;
323                 return true;
324             }
325             
326             return false;
327         }
328         
329         // otherwise we are assigning it ...
330         
331         $this->do->$field = $assign->{$info[1]};
332         return true;
333         
334         
335     }
336     /**
337      * load related objects
338      *
339      * Generally not recommended to use this.
340      * The generator should support creating getter_setter methods which are better suited.
341      *
342      * Relies on  <dbname>.links.ini
343      *
344      * Sets properties on the calling dataobject  you can change what
345      * object vars the links are stored in by  changeing the format parameter
346      *
347      *
348      * @param  string format (default _%s) where %s is the table name.
349      * @author Tim White <tim@cyface.com>
350      * @access public
351      * @return boolean , true on success
352      */
353     
354     function applyLinks($format = '_%s')
355     {
356          
357         // get table will load the options.
358         if ($this->do->_link_loaded) {
359             return true;
360         }
361         
362         $this->do->_link_loaded = false;
363         $cols  = $this->do->table();
364         $links = $this->do->links();
365          
366         $loaded = array();
367         
368         if ($links) {   
369             foreach($links as $key => $match) {
370                 list($table,$link) = explode(':', $match);
371                 $k = sprintf($format, str_replace('.', '_', $key));
372                 // makes sure that '.' is the end of the key;
373                 if ($p = strpos($key,'.')) {
374                       $key = substr($key, 0, $p);
375                 }
376                 
377                 $this->do->$k = $this->getLink($key, $table, $link);
378                 
379                 if (is_object($this->do->$k)) {
380                     $loaded[] = $k; 
381                 }
382             }
383             $this->do->_link_loaded = $loaded;
384             return true;
385         }
386         // this is the autonaming stuff..
387         // it sends the column name down to getLink and lets that sort it out..
388         // if there is a links file then it is not used!
389         // IT IS DEPRECATED!!!! - DO NOT USE 
390         if (!is_null($links)) {    
391             return false;
392         }
393         
394         
395         foreach (array_keys($cols) as $key) {
396             if (!($p = strpos($key, '_'))) {
397                 continue;
398             }
399             // does the table exist.
400             $k =sprintf($format, $key);
401             $this->do->$k = $this->getLink($key);
402             if (is_object($this->do->$k)) {
403                 $loaded[] = $k; 
404             }
405         }
406         $this->do->_link_loaded = $loaded;
407         return true;
408     }
409     
410     /**
411      * getLinkArray
412      * Fetch an array of related objects. This should be used in conjunction with a
413      * <dbname>.links.ini file configuration (see the introduction on linking for details on this).
414      *
415      * You may also use this with all parameters to specify, the column and related table.
416      * 
417      * @access public
418      * @param string $field- either column or column.xxxxx
419      * @param string $table (optional) name of table to look up value in
420      * @param string $fkey (optional) fetchall key see DB_DataObject::fetchAll()
421      * @param string $fval (optional)fetchall val DB_DataObject::fetchAll()
422      * @param string $fval (optional) fetchall method DB_DataObject::fetchAll()
423      * @return array - array of results (empty array on failure)
424      * 
425      * Example - Getting the related objects
426      * 
427      * $person = new DataObjects_Person;
428      * $person->get(12);
429      * $children = $person->getLinkArray('children');
430      * 
431      * echo 'There are ', count($children), ' descendant(s):<br />';
432      * foreach ($children as $child) {
433      *     echo $child->name, '<br />';
434      * }
435      * 
436      */
437     function getLinkArray($field, $table = null, $fkey = false, $fval = false, $fmethod = false)
438     {
439         
440         $ret = array();
441         if (!$table)  {
442             
443             
444             $links = $this->do->links();
445             
446             if (is_array($links)) {
447                 if (!isset($links[$field])) {
448                     // failed..
449                     return $ret;
450                 }
451                 list($table,$link) = explode(':',$links[$field]);
452                 return $this->getLinkArray($field,$table);
453             } 
454             if (!($p = strpos($field,'_'))) {
455                 return $ret;
456             }
457             return $this->getLinkArray($field,substr($field,0,$p));
458
459
460         }
461         
462         $c  = $this->do->factory($table);
463         
464         if (!is_object($c) || !is_a($c,'DB_DataObject')) {
465             $this->do->raiseError(
466                 "getLinkArray:Could not find class for row $field, table $table", 
467                 DB_DATAOBJECT_ERROR_INVALIDCONFIG
468             );
469             return $ret;
470         }
471
472         // if the user defined method list exists - use it...
473         if (method_exists($c, 'listFind')) {
474             $c->listFind($this->id);
475             while ($c->fetch()) {
476                 $ret[] = clone($c);
477             }
478             return $ret;
479         } 
480         return $c->fetchAll($fkey, $fval, $fmethod);
481         
482         
483     }
484
485 }