370 lines
14 KiB
PHP
370 lines
14 KiB
PHP
<?php
|
|
|
|
/**
|
|
* A table factory is used to create table objects and load them with meta data.
|
|
*
|
|
* @todo Support different drivers for loading the meta data from different sources.
|
|
* @package Doctrine
|
|
*/
|
|
class Doctrine_Table_Factory
|
|
{
|
|
protected $_conn;
|
|
protected $_driver;
|
|
|
|
public function __construct(Doctrine_Connection $conn /*Doctrine_Table_Factory_Driver $driver*/)
|
|
{
|
|
$this->_conn = $conn;
|
|
//$this->_driver = $driver;
|
|
$name = "Doctrine_Table_Factory";
|
|
//call_user_func_array(array($name, 'foobar'), array());
|
|
}
|
|
|
|
/**
|
|
* Loads the metadata of the class in question and all it's ancestors whose metadata
|
|
* is still not loaded.
|
|
*
|
|
* @param string $name The name of the class for which the metadata should get loaded.
|
|
* @param array $tables The metadata collection to which the loaded metadata is added.
|
|
*/
|
|
public function loadTables($name, array &$tables)
|
|
{
|
|
$parentClass = $name;
|
|
$parentClasses = array();
|
|
$parentClassWithTable = false;
|
|
while ($parentClass = get_parent_class($parentClass)) {
|
|
if ($parentClass == 'Doctrine_Record') {
|
|
break;
|
|
}
|
|
if (isset($tables[$parentClass])) {
|
|
$parentClassWithTable = $parentClass;
|
|
break;
|
|
}
|
|
$class = new ReflectionClass($parentClass);
|
|
if ($class->isAbstract()) {
|
|
continue;
|
|
}
|
|
$parentClasses[] = $parentClass;
|
|
}
|
|
$parentClasses = array_reverse($parentClasses);
|
|
$parentClasses[] = $name;
|
|
|
|
if ($parentClassWithTable) {
|
|
$table = $tables[$parentClassWithTable];
|
|
} else {
|
|
$rootClassOfHierarchy = count($parentClasses) > 0 ? array_shift($parentClasses) : $name;
|
|
$table = new Doctrine_Table($rootClassOfHierarchy, $this->_conn);
|
|
$this->_loadMetaDataFromCode($table, $rootClassOfHierarchy);
|
|
$tables[$rootClassOfHierarchy] = $table;
|
|
}
|
|
|
|
if (count($parentClasses) == 0) {
|
|
return $table;
|
|
}
|
|
//var_dump($parentClasses);
|
|
//echo "<br /><br />";
|
|
|
|
// load meta data of subclasses
|
|
if ($table->getInheritanceType() == Doctrine::INHERITANCETYPE_JOINED) {
|
|
foreach ($parentClasses as $subclass) {
|
|
$subTable = new Doctrine_Table($subclass, $this->_conn);
|
|
$subTable->setInheritanceType(Doctrine::INHERITANCETYPE_JOINED);
|
|
$this->_loadMetaDataFromCode($subTable, $subclass);
|
|
$tables[$subclass] = $subTable;
|
|
}
|
|
} else if ($table->getInheritanceType() == Doctrine::INHERITANCETYPE_SINGLE_TABLE) {
|
|
foreach ($parentClasses as $subclass) {
|
|
$this->_mergeInto($table, $subclass);
|
|
$tables[$subclass] = $table;
|
|
}
|
|
} else if ($table->getInheritanceType() == Doctrine::INHERITANCETYPE_TABLE_PER_CLASS) {
|
|
$parents = array();
|
|
foreach ($parentClasses as $subclass) {
|
|
$class = new ReflectionClass($subclass);
|
|
if ($class->isAbstract()) {
|
|
$parents[] = $subclass;
|
|
continue;
|
|
}
|
|
$subTable = new Doctrine_Table($subclass, $this->_conn);
|
|
$subTable->setInheritanceType(Doctrine::INHERITANCETYPE_TABLE_PER_CLASS);
|
|
$this->_loadMetaDataFromCode($subTable, $subclass);
|
|
$this->_mergeColumnsInto($table, $subTable, true);
|
|
foreach ($parents as $parent) {
|
|
$this->_mergeColumnsInto($this->_conn->getTable($parent), $subTable, true);
|
|
}
|
|
// currently relying on parent::setTableDefinition();
|
|
/*foreach ($abstracts as $abstractParent) {
|
|
Doctrine_Table_Factory::mergeInto($subTable, $abstractParent);
|
|
}*/
|
|
$tables[$subclass] = $subTable;
|
|
$parents[] = $subclass;
|
|
}
|
|
} else {
|
|
throw new Doctrine_Table_Factory_Exception("Failed to load meta data. Unknown inheritance type "
|
|
. "or no inheritance type specified for hierarchy.");
|
|
}
|
|
}
|
|
|
|
|
|
protected function _createTable($domainClassName)
|
|
{
|
|
return $this->_loadMetaDataFromCode($table, $domainClassName);
|
|
|
|
}
|
|
|
|
/**
|
|
* Initializes the in-memory metadata for the domain class this mapper belongs to.
|
|
* Uses reflection and code setup.
|
|
*/
|
|
protected function _loadMetaDataFromCode(Doctrine_Table $table, $name)
|
|
{
|
|
if ($name == 'Doctrine_Locator_Injectable') {
|
|
try {
|
|
throw new Exception();
|
|
} catch (Exception $e) {
|
|
echo $e->getTraceAsString() . "<br /><br />";
|
|
}
|
|
}
|
|
|
|
if ( ! class_exists($name) || empty($name)) {
|
|
//try {
|
|
throw new Doctrine_Exception("Couldn't find class " . $name);
|
|
//} catch (Exception $e) {
|
|
// echo $e->getTraceAsString() . "<br /><br />";
|
|
//}
|
|
}
|
|
$record = new $name($table);
|
|
|
|
$names = array();
|
|
$class = $name;
|
|
// get parent classes
|
|
do {
|
|
if ($class === 'Doctrine_Record') {
|
|
break;
|
|
}
|
|
$name = $class;
|
|
$names[] = $name;
|
|
} while ($class = get_parent_class($class));
|
|
|
|
if ($class === false) {
|
|
throw new Doctrine_Table_Exception('Unknown component.');
|
|
}
|
|
|
|
// reverse names
|
|
$names = array_reverse($names);
|
|
// save parents
|
|
array_pop($names);
|
|
$table->setOption('parents', $names);
|
|
|
|
/*echo "<br />";
|
|
var_dump($names);
|
|
echo "<br /><br />";*/
|
|
|
|
// set up metadata mapping
|
|
if (method_exists($record, 'setTableDefinition')) {
|
|
$record->setTableDefinition();
|
|
// get the declaring class of setTableDefinition method
|
|
$method = new ReflectionMethod($name, 'setTableDefinition');
|
|
$class = $method->getDeclaringClass();
|
|
} else {
|
|
$class = new ReflectionClass($class);
|
|
}
|
|
|
|
if ($table->getInheritanceType() == Doctrine::INHERITANCETYPE_JOINED) {
|
|
$joinedParents = array();
|
|
foreach (array_reverse($names) as $parent) {
|
|
$parentTable = $table->getConnection()->getTable($parent);
|
|
$parentColumns = $parentTable->getColumns();
|
|
$thisColumns = $table->getColumns();
|
|
|
|
foreach ($parentColumns as $columnName => $definition) {
|
|
if ( ! isset($definition['primary'])) {
|
|
if (isset($thisColumns[$columnName])) {
|
|
continue;
|
|
} else {
|
|
/*if ( ! isset($parentColumns[$columnName]['owner'])) {
|
|
$parentColumns[$columnName]['owner'] = $parentTable->getComponentName();
|
|
}
|
|
$joinedParents[] = $parentColumns[$columnName]['owner'];*/
|
|
$joinedParents[] = $parentTable->getComponentName();
|
|
}
|
|
} else {
|
|
unset($definition['autoincrement']);
|
|
$fullName = $columnName . ' as ' . $parentTable->getFieldName($columnName);
|
|
$table->setColumn($fullName, $definition['type'], $definition['length'], $definition, true);
|
|
}
|
|
}
|
|
}
|
|
$table->setOption('joinedParents', array_values(array_unique($joinedParents)));
|
|
}
|
|
|
|
$table->setOption('declaringClass', $class);
|
|
|
|
// set the table definition for the given tree implementation
|
|
if ($table->isTree()) {
|
|
$table->getTree()->setTableDefinition();
|
|
}
|
|
|
|
$table->setColumnCount(count($table->getColumns()));
|
|
|
|
$tableName = $table->getOption('tableName');
|
|
if ( ! isset($tableName)) {
|
|
$table->setOption('tableName', Doctrine::tableize($class->getName()));
|
|
}
|
|
|
|
$this->_initIdentifier($table);
|
|
|
|
// set up domain class relations
|
|
$record->setUp();
|
|
|
|
// if tree, set up tree relations
|
|
if ($table->isTree()) {
|
|
$table->getTree()->setUp();
|
|
}
|
|
|
|
return $table;
|
|
}
|
|
|
|
protected function _mergeInto(Doctrine_Table $table, $domainClassName)
|
|
{
|
|
if ( ! class_exists($domainClassName) || empty($domainClassName)) {
|
|
throw new Doctrine_Exception("Couldn't find class " . $domainClassName);
|
|
}
|
|
|
|
$record = new $domainClassName($table);
|
|
$record->setTableDefinition();
|
|
$record->setUp();
|
|
|
|
}
|
|
|
|
protected function _mergeColumnsInto(Doctrine_Table $sourceTable, Doctrine_Table $targetTable, $skipPk = false)
|
|
{
|
|
|
|
$sourceColumns = $sourceTable->getColumns();
|
|
foreach ($sourceColumns as $columnName => $definition) {
|
|
if ($skipPk && isset($definition['primary'])) {
|
|
continue;
|
|
}
|
|
$fullName = $columnName . ' as ' . $sourceTable->getFieldName($columnName);
|
|
$targetTable->setColumn($fullName, $definition['type'], $definition['length'], $definition);
|
|
}
|
|
|
|
}
|
|
|
|
protected function _mergeRelationsInto(Doctrine_Table $table, $domainClassName)
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Initializes the table identifier(s)/primary key(s)
|
|
*
|
|
*/
|
|
protected function _initIdentifier(Doctrine_Table $table)
|
|
{
|
|
switch (count($table->getIdentifier())) {
|
|
case 0:
|
|
if ($table->getInheritanceType() == Doctrine::INHERITANCETYPE_JOINED &&
|
|
count($table->getOption('joinedParents')) > 0) {
|
|
|
|
$root = current($table->getOption('joinedParents'));
|
|
|
|
$rootTable = $table->getConnection()->getTable($root);
|
|
|
|
$table->setIdentifier($rootTable->getIdentifier());
|
|
|
|
if ($table->getIdentifierType() !== Doctrine::IDENTIFIER_AUTOINC) {
|
|
$table->setIdentifierType($rootTable->getIdentifierType());
|
|
} else {
|
|
$table->setIdentifierType(Doctrine::IDENTIFIER_NATURAL);
|
|
}
|
|
|
|
// add all inherited primary keys
|
|
foreach ((array) $table->getIdentifier() as $id) {
|
|
$definition = $rootTable->getDefinitionOf($id);
|
|
|
|
// inherited primary keys shouldn't contain autoinc
|
|
// and sequence definitions
|
|
unset($definition['autoincrement']);
|
|
unset($definition['sequence']);
|
|
|
|
// add the inherited primary key column
|
|
$fullName = $id . ' as ' . $rootTable->getFieldName($id);
|
|
$table->setColumn($fullName, $definition['type'], $definition['length'],
|
|
$definition, true);
|
|
}
|
|
} else {
|
|
$definition = array('type' => 'integer',
|
|
'length' => 20,
|
|
'autoincrement' => true,
|
|
'primary' => true);
|
|
$table->setColumn('id', $definition['type'], $definition['length'], $definition, true);
|
|
$table->setIdentifier('id');
|
|
$table->setIdentifierType(Doctrine::IDENTIFIER_AUTOINC);
|
|
}
|
|
$currentCount = $table->getColumnCount();
|
|
$table->setColumnCount(++$currentCount);
|
|
break;
|
|
case 1:
|
|
foreach ($table->getIdentifier() as $pk) {
|
|
$columnName = $table->getColumnName($pk);
|
|
$thisColumns = $table->getColumns();
|
|
$e = $thisColumns[$columnName];
|
|
|
|
$found = false;
|
|
|
|
foreach ($e as $option => $value) {
|
|
if ($found) {
|
|
break;
|
|
}
|
|
|
|
$e2 = explode(':', $option);
|
|
|
|
switch (strtolower($e2[0])) {
|
|
case 'autoincrement':
|
|
case 'autoinc':
|
|
$table->setIdentifierType(Doctrine::IDENTIFIER_AUTOINC);
|
|
$found = true;
|
|
break;
|
|
case 'seq':
|
|
case 'sequence':
|
|
$table->setIdentifierType(Doctrine::IDENTIFIER_SEQUENCE);
|
|
$found = true;
|
|
|
|
if ($value) {
|
|
$table->setOption('sequenceName', $value);
|
|
} else {
|
|
if (($sequence = $table->getAttribute(Doctrine::ATTR_DEFAULT_SEQUENCE)) !== null) {
|
|
$table->setOption('sequenceName', $sequence);
|
|
} else {
|
|
$table->setOption('sequenceName', $table->getConnection()
|
|
->getSequenceName($this->getOption('tableName')));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
$identifierType = $table->getIdentifierType();
|
|
if ( ! isset($identifierType)) {
|
|
$table->setIdentifierType(Doctrine::IDENTIFIER_NATURAL);
|
|
}
|
|
}
|
|
|
|
$table->setIdentifier($pk);
|
|
|
|
break;
|
|
default:
|
|
$table->setIdentifierType(Doctrine::IDENTIFIER_COMPOSITE);
|
|
}
|
|
}
|
|
|
|
public static function foobar()
|
|
{
|
|
echo "bar!";
|
|
}
|
|
|
|
}
|
|
|