1
0
mirror of synced 2024-12-13 22:56:04 +03:00
doctrine2/lib/Doctrine/Table/Factory.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!";
}
}