123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451 |
- <?php
- /**
- * Link tool for DB_DataObject
- *
- * PHP versions 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt. If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category Database
- * @package DB_DataObject
- * @author Alan Knowles <alan@akbkhome.com>
- * @copyright 1997-2006 The PHP Group
- * @license http://www.php.net/license/3_01.txt PHP License 3.01
- * @version : FIXME
- * @link http://pear.php.net/package/DB_DataObject
- */
- /**
- *
- * Example of how this could be used..
- *
- * The lind method are now in here.
- *
- * Currenly only supports existing methods, and new 'link()' method
- *
- */
- /**
- * Links class
- *
- * @package DB_DataObject
- */
- class DB_DataObject_Links
- {
- /**
- * @property {DB_DataObject} do DataObject to apply this to.
- */
- public $do = false;
- /**
- * @property {Array|String} load What to load, 'all' or an array of properties. (default all)
- */
- public $load = 'all';
- /**
- * @property {String|Boolean} scanf use part of column name as resulting
- * property name. (default false)
- */
- public $scanf = false;
- /**
- * @property {String|Boolean} printf use column name as sprintf for resulting property name..
- * (default %s_link if apply is true, otherwise it is %s)
- */
- public $printf = false;
- /**
- * @property {Boolean} cached cache the result, so future queries will use cache rather
- * than running the expensive sql query.
- */
- public $cached = false;
- /**
- * @property {Boolean} apply apply the result to this object, (default true)
- */
- public $apply = true;
- //------------------------- RETURN ------------------------------------
- /**
- * @property {Array} links key value associative array of links.
- */
- public $links;
- /**
- * Constructor
- * -- good ole style..
- * @param {DB_DataObject} do DataObject to apply to.
- * @param array $cfg
- */
- public function __construct($do, $cfg = array())
- {
- // check if do is set!!!?
- $this->do = $do;
- foreach ($cfg as $k => $v) {
- $this->$k = $v;
- }
- }
- /**
- * a generic geter/setter provider..
- *
- * provides a generic getter setter for the referenced object
- * eg.
- * $link->link('company_id') returns getLink for the object
- * if nothing is linked (it will return an empty dataObject)
- * $link->link('company_id', array(1)) - just sets the
- *
- * also array as the field speck supports
- * $link->link(array('company_id', 'company:id'))
- *
- *
- * @param string|array $field the field to fetch or link spec.
- * @param array $args
- * @return mixed true of false on set, the object on getter.
- * @params array $args the arguments sent to the getter setter
- */
- public function link($field, $args = array())
- {
- $info = $this->linkInfo($field);
- if (!$info) {
- $this->do->raiseError(
- "getLink:Could not find link for row $field",
- DB_DATAOBJECT_ERROR_INVALIDCONFIG
- );
- return false;
- }
- $field = $info[2];
- if (empty($args)) { // either an empty array or really empty....
- if (!isset($this->do->$field)) {
- return $info[0]; // empty dataobject.
- }
- $ret = $this->getLink($field);
- // nothing linked -- return new object..
- return ($ret === 0) ? $info[0] : $ret;
- }
- $assign = is_array($args) ? $args[0] : $args;
- // otherwise it's a set call..
- if (!is_a($assign, 'DB_DataObject')) {
- if (is_numeric($assign) && is_integer($assign * 1)) {
- if ($assign > 0) {
- if (!$info) {
- return false;
- }
- // check that record exists..
- if (!$info[0]->get($info[1], $assign)) {
- return false;
- }
- }
- $this->do->$field = $assign;
- return true;
- }
- return false;
- }
- // otherwise we are assigning it ...
- $this->do->$field = $assign->{$info[1]};
- return true;
- }
- /**
- * get link information for a field or field specification
- *
- * alll link (and join methods accept the 'link' info ) in various ways
- * string : 'field' = which field to get (uses ???.links.ini to work out what)
- * array(2) : 'field', 'table:remote_col' << just like the links.ini def.
- * array(3) : 'field', $dataobject, 'remote_col' (handy for joinAdd to do nested joins.)
- *
- * @param string|array $field or link spec to use.
- * @return array|bool (false|array) array of dataobject and linked field or false.
- *
- */
- public function linkInfo($field)
- {
- if (is_array($field)) {
- if (count($field) == 3) {
- // array with 3 args:
- // local_col , dataobject, remote_col
- return array(
- $field[1],
- $field[2],
- $field[0]
- );
- }
- list($table, $link) = explode(':', $field[1]);
- return array(
- $this->do->factory($table),
- $link,
- $field[0]
- );
- }
- // work out the link.. (classic way)
- $links = $this->do->links();
- if (empty($links) || !is_array($links)) {
- return false;
- }
- if (!isset($links[$field])) {
- return false;
- }
- list($table, $link) = explode(':', $links[$field]);
- //??? needed???
- if ($p = strpos($field, ".")) {
- $field = substr($field, 0, $p);
- }
- return array(
- $this->do->factory($table),
- $link,
- $field
- );
- }
- /**
- * return name from related object
- *
- * The relies on a <dbname>.links.ini file, unless you specify the arguments.
- *
- * you can also use $this->getLink('thisColumnName','otherTable','otherTableColumnName')
- *
- *
- * @param string $field |array either row or row.xxxxx or links spec.
- * @param bool $table (optional) name of table to look up value in
- * @param string $link (optional) name of column in other table to match
- * @return mixed object on success false on failure or '0' when not linked
- * @author Tim White <tim@cyface.com>
- * @access public
- */
- public function getLink($field, $table = false, $link = '')
- {
- static $cache = array();
- // GUESS THE LINKED TABLE.. (if found - recursevly call self)
- if ($table == false) {
- $info = $this->linkInfo($field);
- if ($info) {
- return $this->getLink($field, $info[0], $link === false ? $info[1] : $link);
- }
- // no links defined.. - use borked BC method...
- // use the old _ method - this shouldnt happen if called via getLinks()
- if (!($p = strpos($field, '_'))) {
- return false;
- }
- $table = substr($field, 0, $p);
- return $this->getLink($field, $table);
- }
- $tn = is_string($table) ? $table : $table->tableName();
- if (!isset($this->do->$field)) {
- $this->do->raiseError("getLink: row not set $field", DB_DATAOBJECT_ERROR_NODATA);
- return false;
- }
- // check to see if we know anything about this table..
- if (empty($this->do->$field) || $this->do->$field < 0) {
- return 0; // no record.
- }
- if ($this->cached && isset($cache[$tn . ':' . $link . ':' . $this->do->$field])) {
- return $cache[$tn . ':' . $link . ':' . $this->do->$field];
- }
- $obj = is_string($table) ? $this->do->factory($tn) : $table;;
- if (!is_a($obj, 'DB_DataObject')) {
- $this->do->raiseError(
- "getLink:Could not find class for row $field, table $tn",
- DB_DATAOBJECT_ERROR_INVALIDCONFIG
- );
- return false;
- }
- // -1 or 0 -- no referenced record..
- $ret = false;
- if ($link) {
- if ($obj->get($link, $this->do->$field)) {
- $ret = $obj;
- }
- // this really only happens when no link config is set (old BC stuff)
- } elseif ($obj->get($this->do->$field)) {
- $ret = $obj;
- }
- if ($this->cached) {
- $cache[$tn . ':' . $link . ':' . $this->do->$field] = $ret;
- }
- return $ret;
- }
- /**
- * load related objects
- *
- * Generally not recommended to use this.
- * The generator should support creating getter_setter methods which are better suited.
- *
- * Relies on <dbname>.links.ini
- *
- * Sets properties on the calling dataobject you can change what
- * object vars the links are stored in by changeing the format parameter
- *
- *
- * @param string format (default _%s) where %s is the table name.
- * @return boolean , true on success
- * @author Tim White <tim@cyface.com>
- * @access public
- */
- public function applyLinks($format = '_%s')
- {
- // get table will load the options.
- if ($this->do->_link_loaded) {
- return true;
- }
- $this->do->_link_loaded = false;
- $cols = $this->do->table();
- $links = $this->do->links();
- $loaded = array();
- if ($links) {
- foreach ($links as $key => $match) {
- list($table, $link) = explode(':', $match);
- $k = sprintf($format, str_replace('.', '_', $key));
- // makes sure that '.' is the end of the key;
- if ($p = strpos($key, '.')) {
- $key = substr($key, 0, $p);
- }
- $this->do->$k = $this->getLink($key, $table, $link);
- if (is_object($this->do->$k)) {
- $loaded[] = $k;
- }
- }
- $this->do->_link_loaded = $loaded;
- return true;
- }
- // this is the autonaming stuff..
- // it sends the column name down to getLink and lets that sort it out..
- // if there is a links file then it is not used!
- // IT IS DEPRECATED!!!! - DO NOT USE
- if (!is_null($links)) {
- return false;
- }
- foreach (array_keys($cols) as $key) {
- if (!($p = strpos($key, '_'))) {
- continue;
- }
- // does the table exist.
- $k = sprintf($format, $key);
- $this->do->$k = $this->getLink($key);
- if (is_object($this->do->$k)) {
- $loaded[] = $k;
- }
- }
- $this->do->_link_loaded = $loaded;
- return true;
- }
- /**
- * getLinkArray
- * Fetch an array of related objects. This should be used in conjunction with a
- * <dbname>.links.ini file configuration (see the introduction on linking for details on this).
- *
- * You may also use this with all parameters to specify, the column and related table.
- *
- * @access public
- * @param string $field - either column or column.xxxxx
- * @param string $table (optional) name of table to look up value in
- * @param bool $fkey (optional) fetchall key see DB_DataObject::fetchAll()
- * @param bool $fval (optional) fetchall method DB_DataObject::fetchAll()
- * @param bool $fmethod
- * @return array - array of results (empty array on failure)
- *
- * Example - Getting the related objects
- *
- * $person = new DataObjects_Person;
- * $person->get(12);
- * $children = $person->getLinkArray('children');
- *
- * echo 'There are ', count($children), ' descendant(s):<br />';
- * foreach ($children as $child) {
- * echo $child->name, '<br />';
- * }
- */
- public function getLinkArray($field, $table = null, $fkey = false, $fval = false, $fmethod = false)
- {
- $ret = array();
- if (!$table) {
- $links = $this->do->links();
- if (is_array($links)) {
- if (!isset($links[$field])) {
- // failed..
- return $ret;
- }
- list($table, $link) = explode(':', $links[$field]);
- return $this->getLinkArray($field, $table);
- }
- if (!($p = strpos($field, '_'))) {
- return $ret;
- }
- return $this->getLinkArray($field, substr($field, 0, $p));
- }
- $c = $this->do->factory($table);
- if (!is_object($c) || !is_a($c, 'DB_DataObject')) {
- $this->do->raiseError(
- "getLinkArray:Could not find class for row $field, table $table",
- DB_DATAOBJECT_ERROR_INVALIDCONFIG
- );
- return $ret;
- }
- // if the user defined method list exists - use it...
- if (method_exists($c, 'listFind')) {
- $c->listFind($this->id);
- while ($c->fetch()) {
- $ret[] = clone($c);
- }
- return $ret;
- }
- return $c->fetchAll($fkey, $fval, $fmethod);
- }
- }
|