1
0
mirror of synced 2025-01-18 14:31:40 +03:00
doctrine2/classes/Table.class.php
doctrine 5607189453
2006-04-14 10:20:19 +00:00

616 lines
20 KiB
PHP

<?php
require_once("Configurable.class.php");
/**
* Doctrine_Table represents a database table
* each Doctrine_Table holds the information of foreignKeys and associations
*
*
* @author Konsta Vesterinen
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
* @version 1.0 alpha
*/
class Doctrine_Table extends Doctrine_Configurable {
/**
* constant for ONE_TO_ONE and MANY_TO_ONE aggregate relationships
*/
const ONE_AGGREGATE = 0;
/**
* constant for ONE_TO_ONE and MANY_TO_ONE composite relationships
*/
const ONE_COMPOSITE = 1;
/**
* constant for MANY_TO_MANY and ONE_TO_MANY aggregate relationships
*/
const MANY_AGGREGATE = 2;
/**
* constant for MANY_TO_MANY and ONE_TO_MANY composite relationships
*/
const MANY_COMPOSITE = 3;
/**
* @var boolean $isNewEntry whether ot not this table created a new record or not, used only internally
*/
private $isNewEntry = false;
/**
* @var array $data temporary data which is then loaded into Doctrine_Record::$data
*/
private $data = array();
/**
* @var array $foreignKeys an array containing all the Doctrine_ForeignKey objects for this table
*/
private $foreignKeys = array();
/**
* @var array $primaryKeys an array containing all primary key column names
*/
private $primaryKeys = array();
/**
* @var integer $primaryType
*/
private $primaryType;
/**
* @var string $query cached simple query
*/
private $query;
/**
* @var Doctrine_Session $session Doctrine_Session object that created this table
*/
private $session;
/**
* @var string $name name of the component, for example component name of the GroupTable is 'Group'
*/
private $name;
/**
* @var string $tableName database table name, in most cases this is the same as component name but in some cases
* where one-table-multi-class inheritance is used this will be the name of the inherited table
*/
private $tableName;
/**
* @var string $sequenceName Some databases need sequences instead of auto incrementation primary keys, you can set specific
* sequence for your table by calling setSequenceName()
*/
private $sequenceName;
/**
* @var Doctrine_Repository $repository first level cache
*/
private $repository;
/**
* @var Doctrine_Cache $cache second level cache
*/
private $cache;
/**
* @var Doctrine_Table_Description $description columns object for this table
*/
private $columns;
/**
* @var array $bound bound relations
*/
private $bound = array();
/**
* @var array $inheritanceMap inheritanceMap is used for inheritance mapping, keys representing columns and values
* the column values that should correspond to child classes
*/
private $inheritanceMap = array();
/**
* @var array $parents the parent classes of this component
*/
private $parents = array();
/**
* the constructor
* @throws Doctrine_ManagerException if there are no opened sessions
* @throws Doctrine_TableException if there is already an instance of this table
* @return void
*/
public function __construct($name) {
$this->session = Doctrine_Manager::getInstance()->getCurrentSession();
$this->setParent($this->session);
$name = ucwords(strtolower($name));
$this->name = $name;
if( ! class_exists($name) || empty($name))
throw new Doctrine_Exception("Couldn't find class $name");
$record = new $name($this);
$record->setUp();
$names = array();
$class = $name;
// get parent classes
do {
if($class == "Doctrine_Record") break;
$name = ucwords(strtolower($class));
$names[] = $name;
} while($class = get_parent_class($class));
// reverse names
$names = array_reverse($names);
// create database table
if(method_exists($record,"setTableDefinition")) {
$record->setTableDefinition();
if(isset($this->columns)) {
$method = new ReflectionMethod($name,"setTableDefinition");
$class = $method->getDeclaringClass();
if( ! isset($this->tableName))
$this->tableName = strtolower($class->getName());
switch(count($this->primaryKeys)):
case 0:
$this->columns = array_merge(array("id" => array("integer",11,"AUTOINCREMENT PRIMARY")), $this->columns);
$this->primaryKeys[] = "id";
break;
case 1:
break;
default:
endswitch;
if($this->getAttribute(Doctrine::ATTR_CREATE_TABLES)) {
$dict = new Doctrine_DataDict($this);
$dict->createTable($this->columns);
}
}
} else {
throw new Doctrine_Exception("Class '$name' has no table definition.");
}
// save parents
array_pop($names);
$this->parents = $names;
$this->query = "SELECT ".implode(", ",array_keys($this->columns))." FROM ".$this->getTableName();
// check if an instance of this table is already initialized
if( ! $this->session->addTable($this))
throw new Doctrine_Table_Exception();
$this->initComponents();
}
/**
* initializes components this table uses
*
* @return void
*/
final public function initComponents() {
$this->repository = new Doctrine_Repository($this);
switch($this->getAttribute(Doctrine::ATTR_CACHE)):
case Doctrine::CACHE_FILE:
$this->cache = new Doctrine_Cache_File($this);
break;
case Doctrine::CACHE_NONE:
$this->cache = new Doctrine_Cache($this);
break;
endswitch;
}
/**
* hasColumn
* @param string $name
* @param string $type
* @param integer $length
* @param mixed $options
* @return void
*/
final public function hasColumn($name, $type, $length, $options = "") {
$this->columns[$name] = array($type,$length,$options);
$e = explode("|",$options);
if(in_array("primary",$e)) {
$this->primaryKeys[] = $name;
}
}
/**
* returns all primary keys
* @return array
*/
final public function getPrimaryKeys() {
return $this->primaryKeys;
}
/**
* @return boolean
*/
final public function hasPrimaryKey($key) {
return in_array($key,$this->primaryKeys);
}
/**
* @param $sequence
* @return void
*/
final public function setSequenceName($sequence) {
$this->sequenceName = $sequence;
}
/**
* @return string sequence name
*/
final public function getSequenceName() {
return $this->sequenceName;
}
/**
* setInheritanceMap
* @param array $inheritanceMap
* @return void
*/
final public function setInheritanceMap(array $inheritanceMap) {
$this->inheritanceMap = $inheritanceMap;
}
/**
* @return array inheritance map (array keys as fields)
*/
final public function getInheritanceMap() {
return $this->inheritanceMap;
}
/**
* return all composite paths in the form [component1].[component2]. . .[componentN]
* @return array
*/
final public function getCompositePaths() {
$array = array();
$name = $this->getComponentName();
foreach($this->bound as $k=>$a) {
try {
$fk = $this->getForeignKey($k);
switch($fk->getType()):
case Doctrine_Table::ONE_COMPOSITE:
case Doctrine_Table::MANY_COMPOSITE:
$n = $fk->getTable()->getComponentName();
$array[] = $name.".".$n;
$e = $fk->getTable()->getCompositePaths();
if( ! empty($e)) {
foreach($e as $name) {
$array[] = $name.".".$n.".".$name;
}
}
break;
endswitch;
} catch(InvalidKeyException $e) {
}
}
return $array;
}
/**
* @var array bound relations
*/
final public function getBounds() {
return $this->bound;
}
/**
* @param string $name
*/
final public function getBound($name) {
if( ! isset($this->bound[$name]))
throw new InvalidKeyException();
return $this->bound[$name];
}
/**
* @param string $objTableName
* @param string $fkField
* @return void
*/
final public function bind($objTableName,$fkField,$type,$localKey) {
$name = (string) $objTableName;
$field = (string) $fkField;
if(isset($this->foreignKeys[$name]))
throw new InvalidKeyException();
$e = explode(".", $field);
// is reference table used?
if($e[0] != $name && $e[0] == $this->name)
$this->bound[$name] = array($field,Doctrine_Table::MANY_COMPOSITE);
$this->bound[$name] = array($field,$type,$localKey);
}
/**
* getComponentName
* @return string the component name
*/
final public function getComponentName() {
return $this->name;
}
/**
* @return Doctrine_Session
*/
final public function getSession() {
return $this->session;
}
/**
* @return Doctrine_Cache
*/
final public function getCache() {
return $this->cache;
}
/**
* @return Doctrine_Repository
*/
final public function getRepository() {
return $this->repository;
}
/**
* @param string $name component name of which a foreign key object is bound
* @return Doctrine_ForeignKey
*/
final public function getForeignKey($name) {
if(isset($this->foreignKeys[$name]))
return $this->foreignKeys[$name];
if(isset($this->bound[$name])) {
$type = $this->bound[$name][1];
$field = $this->bound[$name][0];
$e = explode(".",$field);
$objTable = $this->session->getTable($name);
switch($e[0]):
case $name:
// ONE-TO-MANY or ONE-TO-ONE
$foreignKey = new Doctrine_ForeignKey($objTable,$this->bound[$name][2],$e[1],$type);
break;
case $this->name:
// ONE-TO-ONE
if($type <= Doctrine_Table::ONE_COMPOSITE)
$foreignKey = new Doctrine_LocalKey($objTable,$e[1],$this->bound[$name][2],$type);
else
throw new Doctrine_Mapping_Exception();
break;
default:
if(in_array($e[0], $this->parents)) {
// ONE-TO-ONE
if($type <= Doctrine_Table::ONE_COMPOSITE)
$foreignKey = new Doctrine_LocalKey($objTable,$e[1],$this->bound[$name][2],$type);
else
throw new Doctrine_Mapping_Exception();
} else {
// POSSIBLY MANY-TO-MANY
$bound = $objTable->getBound($this->name);
$e2 = explode(".",$bound[0]);
if($e2[0] != $e[0])
throw new Doctrine_Mapping_Exception();
$associationTable = $this->session->getTable($e2[0]);
$this->foreignKeys[$e2[0]] = new Doctrine_ForeignKey($associationTable,$this->bound[$name][2],$e2[1],Doctrine_Table::MANY_COMPOSITE);
$foreignKey = new Doctrine_Association($objTable,$associationTable,$e2[1],$e[1],$type);
}
endswitch;
$this->foreignKeys[$name] = $foreignKey;
return $this->foreignKeys[$name];
} else {
throw new InvalidKeyException();
}
}
/**
* @return array an array containing all foreign key objects
*/
final public function getForeignKeys() {
$a = array();
foreach($this->bound as $k=>$v) {
$a[$k] = $this->getForeignKey($k);
}
return $a;
}
/**
* @return void
*/
final public function setTableName($name) {
$this->tableName = $name;
}
/**
* @return string database table name this class represents
*/
final public function getTableName() {
return $this->tableName;
}
/**
* createDAO
* @param $array an array where keys are field names and values representing field values
* @return Doctrine_Record A new Data Access Object. Uses an sql insert statement when saved
*/
final public function create(array $array = array()) {
$this->data = $array;
$this->isNewEntry = true;
$record = $this->getRecord();
$this->isNewEntry = false;
return $record;
}
/**
* @param $id database row id
* @throws Doctrine_Find_Exception
* @return Doctrine_Record a record for given database identifier
*/
final public function find($id = null) {
if($id !== null) {
try {
// try to get from cache
$record = $this->cache->fetch($id);
return $record;
} catch(InvalidKeyException $e) {
// do nothing
}
$query = $this->query." WHERE ".implode(" = ? && ",$this->primaryKeys)." = ?";
$query = $this->applyInheritance($query);
$params = array_merge(array($id), array_values($this->inheritanceMap));
$this->data = $this->session->execute($query,$params)->fetch(PDO::FETCH_ASSOC);
if($this->data === false)
throw new Doctrine_Find_Exception();
}
return new $this->name($this);
}
/**
* applyInheritance
* @param $where query where part to be modified
* @return query where part with column aggregation inheritance added
*/
final public function applyInheritance($where) {
if( ! empty($this->inheritanceMap)) {
$a = array();
foreach($this->inheritanceMap as $field => $value) {
$a[] = $field." = ?";
}
$i = implode(" && ",$a);
$where .= " && $i";
}
return $where;
}
/**
* findAll
* @return Doctrine_Collection a collection of all data access objects
*/
final public function findAll() {
$graph = new Doctrine_DQL_Parser($this->session);
$users = $graph->query("FROM ".$this->name);
return $users;
}
/**
* findBySql
* @return Doctrine_Collection a collection of data access objects
*/
final public function findBySql($sql) {
$graph = new Doctrine_DQL_Parser($this->session);
$users = $graph->query("FROM ".$this->name." WHERE ".$sql);
return $users;
}
/**
* getRecord
* @return Doctrine_Record
*/
public function getRecord() {
return new $this->name($this);
}
/**
* @param $id database row id
* @throws Doctrine_Find_Exception
* @return DAOProxy a proxy for given identifier
*/
final public function getProxy($id = null) {
if($id !== null) {
$id = (int) $id;
try {
// try to get from cache
$record = $this->cache->fetch($id);
return $record;
} catch(InvalidKeyException $e) {
// do nothing
}
$query = "SELECT ".implode(", ",$this->primaryKeys)." FROM ".$this->getTableName()." WHERE ".implode(" = ? && ",$this->primaryKeys)." = ?";
$query = $this->applyInheritance($query);
$params = array_merge(array($id), array_values($this->inheritanceMap));
$this->data = $this->session->execute($query,$params)->fetch(PDO::FETCH_ASSOC);
if($this->data === false)
throw new Doctrine_Find_Exception();
}
return $this->getRecord();
}
/**
* getTableDescription
* @return Doctrine_Table_Description the columns object for this factory
*/
final public function getTableDescription() {
return $this->columns;
}
/**
* @param integer $fetchMode
* @return Doctrine_DQL_Parser a Doctrine_DQL_Parser object
*/
public function getDQLParser() {
$graph = new Doctrine_DQL_Parser($this->getSession());
$graph->load($this->getComponentName());
return $graph;
}
/**
* execute
*/
public function execute($query, array $array = array()) {
$coll = new Doctrine_Collection($this);
$stmt = $this->session->getDBH()->prepare($query);
$stmt->execute($array);
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt->closeCursor();
foreach($data as $row) {
$this->data = $row;
try {
$record = $this->getCache()->fetch($this->data["id"]);
} catch(InvalidKeyException $e) {
$record = $this->getRecord();
}
$coll->add($record);
}
return $coll;
}
/**
* @return array
*/
final public function getColumns() {
return $this->columns;
}
/**
* @return array an array containing all the column names
*/
public function getColumnNames() {
return array_keys($this->columns);
}
/**
* setData
* @param array $data internal data, users are strongly discouraged to use this function
* @return void
*/
public function setData(array $data) {
$this->data = $data;
}
/**
* @return boolean whether or not a newly created object is new or not
*/
final public function isNewEntry() {
return $this->isNewEntry;
}
/**
* @return string simple cached query
*/
final public function getQuery() {
return $this->query;
}
/**
* @return array internal data, used by Doctrine_Record instances when retrieving data from database
*/
final public function getData() {
return $this->data;
}
/**
* @return string string representation of this object
*/
public function __toString() {
return Doctrine_Lib::getTableAsString($this);
}
}
?>