3 * Link tool for DB_DataObject
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.
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
19 * @link http://pear.php.net/package/DB_DataObject
25 * Example of how this could be used..
27 * The lind method are now in here.
29 * Currenly only supports existing methods, and new 'link()' method
37 * @package DB_DataObject
39 class DB_DataObject_Links
42 * @property {DB_DataObject} do DataObject to apply this to.
48 * @property {Array|String} load What to load, 'all' or an array of properties. (default all)
52 * @property {String|Boolean} scanf use part of column name as resulting
53 * property name. (default false)
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)
62 * @property {Boolean} cached cache the result, so future queries will use cache rather
63 * than running the expensive sql query.
67 * @property {Boolean} apply apply the result to this object, (default true)
72 //------------------------- RETURN ------------------------------------
74 * @property {Array} links key value associative array of links.
82 * @param {DB_DataObject} do DataObject to apply to.
83 * @param {Array} cfg Configuration (basically properties of this object)
86 function DB_DataObject_Links($do,$cfg= array())
88 // check if do is set!!!?
91 foreach($cfg as $k=>$v) {
99 * return name from related object
101 * The relies on a <dbname>.links.ini file, unless you specify the arguments.
103 * you can also use $this->getLink('thisColumnName','otherTable','otherTableColumnName')
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>
111 * @return mixed object on success false on failure or '0' when not linked
113 function getLink($field, $table= false, $link='')
116 static $cache = array();
118 // GUESS THE LINKED TABLE.. (if found - recursevly call self)
120 if ($table == false) {
123 $info = $this->linkInfo($field);
126 return $this->getLink($field, $info[0], $link === false ? $info[1] : $link );
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, '_'))) {
134 $table = substr($field, 0, $p);
135 return $this->getLink($field, $table);
141 $tn = is_string($table) ? $table : $table->tableName();
145 if (!isset($this->do->$field)) {
146 $this->do->raiseError("getLink: row not set $field", DB_DATAOBJECT_ERROR_NODATA);
150 // check to see if we know anything about this table..
153 if (empty($this->do->$field) || $this->do->$field < 0) {
154 return 0; // no record.
157 if ($this->cached && isset($cache[$tn.':'. $link .':'. $this->do->$field])) {
158 return $cache[$tn.':'. $link .':'. $this->do->$field];
161 $obj = is_string($table) ? $this->do->factory($tn) : $table;;
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);
169 // -1 or 0 -- no referenced record..
174 if ($obj->get($link, $this->do->$field)) {
179 // this really only happens when no link config is set (old BC stuff)
180 } else if ($obj->get($this->do->$field)) {
185 $cache[$tn.':'. $link .':'. $this->do->$field] = $ret;
191 * get link information for a field or field specification
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.)
198 * @param string|array $field or link spec to use.
199 * @return (false|array) array of dataobject and linked field or false.
204 function linkInfo($field)
207 if (is_array($field)) {
208 if (count($field) == 3) {
209 // array with 3 args:
210 // local_col , dataobject, remote_col
218 list($table,$link) = explode(':', $field[1]);
221 $this->do->factory($table),
227 // work out the link.. (classic way)
229 $links = $this->do->links();
231 if (empty($links) || !is_array($links)) {
237 if (!isset($links[$field])) {
241 list($table,$link) = explode(':', $links[$field]);
245 if ($p = strpos($field,".")) {
246 $field = substr($field,0,$p);
250 $this->do->factory($table),
263 * a generic geter/setter provider..
265 * provides a generic getter setter for the referenced object
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
271 * also array as the field speck supports
272 * $link->link(array('company_id', 'company:id'))
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.
280 function link($field, $args = array())
282 $info = $this->linkInfo($field);
285 $this->do->raiseError(
286 "getLink:Could not find link for row $field",
287 DB_DATAOBJECT_ERROR_INVALIDCONFIG);
293 if (empty($args)) { // either an empty array or really empty....
295 if (!isset($this->do->$field)) {
296 return $info[0]; // empty dataobject.
299 $ret = $this->getLink($field);
300 // nothing linked -- return new object..
301 return ($ret === 0) ? $info[0] : $ret;
304 $assign = is_array($args) ? $args[0] : $args;
306 // otherwise it's a set call..
307 if (!is_a($assign , 'DB_DataObject')) {
309 if (is_numeric($assign) && is_integer($assign * 1)) {
315 // check that record exists..
316 if (!$info[0]->get($info[1], $assign )) {
322 $this->do->$field = $assign ;
329 // otherwise we are assigning it ...
331 $this->do->$field = $assign->{$info[1]};
337 * load related objects
339 * Generally not recommended to use this.
340 * The generator should support creating getter_setter methods which are better suited.
342 * Relies on <dbname>.links.ini
344 * Sets properties on the calling dataobject you can change what
345 * object vars the links are stored in by changeing the format parameter
348 * @param string format (default _%s) where %s is the table name.
349 * @author Tim White <tim@cyface.com>
351 * @return boolean , true on success
354 function applyLinks($format = '_%s')
357 // get table will load the options.
358 if ($this->do->_link_loaded) {
362 $this->do->_link_loaded = false;
363 $cols = $this->do->table();
364 $links = $this->do->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);
377 $this->do->$k = $this->getLink($key, $table, $link);
379 if (is_object($this->do->$k)) {
383 $this->do->_link_loaded = $loaded;
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)) {
395 foreach (array_keys($cols) as $key) {
396 if (!($p = strpos($key, '_'))) {
399 // does the table exist.
400 $k =sprintf($format, $key);
401 $this->do->$k = $this->getLink($key);
402 if (is_object($this->do->$k)) {
406 $this->do->_link_loaded = $loaded;
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).
415 * You may also use this with all parameters to specify, the column and related table.
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)
425 * Example - Getting the related objects
427 * $person = new DataObjects_Person;
429 * $children = $person->getLinkArray('children');
431 * echo 'There are ', count($children), ' descendant(s):<br />';
432 * foreach ($children as $child) {
433 * echo $child->name, '<br />';
437 function getLinkArray($field, $table = null, $fkey = false, $fval = false, $fmethod = false)
444 $links = $this->do->links();
446 if (is_array($links)) {
447 if (!isset($links[$field])) {
451 list($table,$link) = explode(':',$links[$field]);
452 return $this->getLinkArray($field,$table);
454 if (!($p = strpos($field,'_'))) {
457 return $this->getLinkArray($field,substr($field,0,$p));
462 $c = $this->do->factory($table);
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
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()) {
480 return $c->fetchAll($fkey, $fval, $fmethod);