daa5f87fd4
We have to replace this database engine with a modern one
451 lines
14 KiB
PHP
451 lines
14 KiB
PHP
<?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);
|
|
}
|
|
}
|