Commit 71338c3d authored by zYne's avatar zYne

drafting the new relation model, still a lot of work

parent b3b1f617
......@@ -257,10 +257,11 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module
}
}
/**
* update
* updates the given record
*
* @param Doctrine_Record $record
* @return boolean
* @param Doctrine_Record $record record to be updated
* @return boolean whether or not the update was successful
*/
public function update(Doctrine_Record $record)
{
......@@ -301,7 +302,7 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module
. ' WHERE ' . implode(' = ? AND ', $record->getTable()->getPrimaryKeys())
. ' = ?';
$stmt = $this->conn->getDBH()->prepare($sql);
$stmt = $this->conn->getDbh()->prepare($sql);
$stmt->execute($params);
$record->assignIdentifier(true);
......
......@@ -205,7 +205,11 @@ class Doctrine_Db_Statement implements Doctrine_Adapter_Statement_Interface
$skip = $this->adapter->getListener()->onPreExecute($event);
if ( ! $skip) {
$this->stmt->execute($params);
if (isset($params[0]) && is_array($params[0])) {
print_r($params);
throw new Exception();
}
$this->stmt->execute((array) $params);
$this->adapter->incrementQueryCount();
}
......
......@@ -66,6 +66,13 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable
* @var array $_enumParams an array containing the keys of the parameters that should be enumerated
*/
protected $_enumParams = array();
/**
* @var array $_options an array of options
*/
protected $_options = array(
'fetchMode' => Doctrine::FETCH_RECORD,
'cacheMode' => null,
);
/**
* @var array $_dqlParts an array containing all DQL query parts
*/
......@@ -483,7 +490,7 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable
$q = 'UPDATE ';
break;
case self::SELECT:
$distinct = ($this->isDistinct()) ? 'DISTINCT ' : '';
$distinct = ($this->parts['distinct']) ? 'DISTINCT ' : '';
$q = 'SELECT ' . $distinct . implode(', ', $this->parts['select']) . ' FROM ';
break;
......@@ -565,11 +572,6 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable
// build the basic query
$str = '';
if ($this->isDistinct()) {
$str = 'DISTINCT ';
}
$q = $this->getQueryBase();
$q .= $this->buildFromPart();
......
......@@ -901,8 +901,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
}
foreach ($saveLater as $fk) {
$table = $fk->getTable();
$alias = $this->_table->getAlias($table->getComponentName());
$alias = $fk->getAlias();
if (isset($this->_references[$alias])) {
$obj = $this->_references[$alias];
......@@ -1011,8 +1010,9 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
$a[$v] = $this->_table->enumIndex($v,$this->_data[$v]);
break;
default:
if ($this->_data[$v] instanceof Doctrine_Record)
if ($this->_data[$v] instanceof Doctrine_Record) {
$this->_data[$v] = $this->_data[$v]->getIncremented();
}
$a[$v] = $this->_data[$v];
}
......@@ -1273,48 +1273,61 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
}
}
/**
* ownsOne
* binds One-to-One composite relation
*
* @param string $objTableName
* @param string $fkField
* @return void
* @param string $componentName the name of the related component
* @param string $options relation options
* @see Doctrine_Relation::_$definition
* @return Doctrine_Record this object
*/
final public function ownsOne($componentName, $foreignKey, $options = null)
public function ownsOne()
{
$this->_table->bind($componentName, $foreignKey, Doctrine_Relation::ONE_COMPOSITE, $options);
$this->_table->bind(func_get_args(), Doctrine_Relation::ONE_COMPOSITE);
return $this;
}
/**
* binds One-to-Many composite relation
* ownsMany
* binds One-to-Many / Many-to-Many composite relation
*
* @param string $objTableName
* @param string $fkField
* @return void
* @param string $componentName the name of the related component
* @param string $options relation options
* @see Doctrine_Relation::_$definition
* @return Doctrine_Record this object
*/
final public function ownsMany($componentName, $foreignKey, $options = null)
public function ownsMany()
{
$this->_table->bind($componentName, $foreignKey, Doctrine_Relation::MANY_COMPOSITE, $options);
$this->_table->bind(func_get_args(), Doctrine_Relation::MANY_COMPOSITE);
return $this;
}
/**
* hasOne
* binds One-to-One aggregate relation
*
* @param string $objTableName
* @param string $fkField
* @return void
* @param string $componentName the name of the related component
* @param string $options relation options
* @see Doctrine_Relation::_$definition
* @return Doctrine_Record this object
*/
final public function hasOne($componentName, $foreignKey, $options = null)
public function hasOne()
{
$this->_table->bind($componentName, $foreignKey, Doctrine_Relation::ONE_AGGREGATE, $options);
$this->_table->bind(func_get_args(), Doctrine_Relation::ONE_AGGREGATE);
return $this;
}
/**
* binds One-to-Many aggregate relation
* hasMany
* binds One-to-Many / Many-to-Many aggregate relation
*
* @param string $objTableName
* @param string $fkField
* @return void
* @param string $componentName the name of the related component
* @param string $options relation options
* @see Doctrine_Relation::_$definition
* @return Doctrine_Record this object
*/
final public function hasMany($componentName, $foreignKey, $options = null)
public function hasMany()
{
$this->_table->bind($componentName, $foreignKey, Doctrine_Relation::MANY_AGGREGATE, $options);
$this->_table->bind(func_get_args(), Doctrine_Relation::MANY_AGGREGATE);
return $this;
}
/**
* hasColumn
......
......@@ -62,7 +62,7 @@ abstract class Doctrine_Relation
'class' => true,
'type' => true,
'name' => false,
'assocTable' => false,
'refTable' => false,
'onDelete' => false,
'onUpdate' => false,
'deferred' => false,
......@@ -80,7 +80,7 @@ abstract class Doctrine_Relation
*
* table the foreign table object
*
* assocTable the association table object (if any)
* refTable the reference table object (if any)
*
* onDelete referential delete action
*
......
......@@ -40,11 +40,11 @@ class Doctrine_Relation_Association extends Doctrine_Relation
*/
public function getAssociationFactory()
{
return $this->definition['assocTable'];
return $this->definition['refTable'];
}
public function getAssociationTable()
{
return $this->definition['assocTable'];
return $this->definition['refTable'];
}
/**
* getRelationDql
......@@ -54,7 +54,7 @@ class Doctrine_Relation_Association extends Doctrine_Relation
*/
public function getRelationDql($count, $context = 'record')
{
$component = $this->definition['assocTable']->getComponentName();
$component = $this->definition['refTable']->getComponentName();
switch ($context) {
case "record":
$sub = 'SQL:SELECT ' . $this->definition['foreign'].
......
......@@ -43,17 +43,17 @@ class Doctrine_Relation_Association_Self extends Doctrine_Relation_Association
switch ($context) {
case 'record':
$sub = 'SELECT '.$this->definition['foreign']
. ' FROM '.$this->definition['assocTable']->getTableName()
. ' FROM '.$this->definition['refTable']->getTableName()
. ' WHERE '.$this->definition['local']
. ' = ?';
$sub2 = 'SELECT '.$this->definition['local']
. ' FROM '.$this->definition['assocTable']->getTableName()
. ' FROM '.$this->definition['refTable']->getTableName()
. ' WHERE '.$this->definition['foreign']
. ' = ?';
$dql = 'FROM ' . $this->definition['table']->getComponentName()
. '.' . $this->definition['assocTable']->getComponentName()
. '.' . $this->definition['refTable']->getComponentName()
. ' WHERE ' . $this->definition['table']->getComponentName()
. '.' . $this->definition['table']->getIdentifier()
. ' IN (' . $sub . ')'
......@@ -63,9 +63,9 @@ class Doctrine_Relation_Association_Self extends Doctrine_Relation_Association
break;
case 'collection':
$sub = substr(str_repeat('?, ', $count),0,-2);
$dql = 'FROM '.$this->definition['assocTable']->getComponentName()
$dql = 'FROM '.$this->definition['refTable']->getComponentName()
. '.' . $this->definition['table']->getComponentName()
. ' WHERE '.$this->definition['assocTable']->getComponentName()
. ' WHERE '.$this->definition['refTable']->getComponentName()
. '.' . $this->definition['local'] . ' IN (' . $sub . ')';
};
......
......@@ -45,7 +45,7 @@ class Doctrine_Relation_ForeignKey extends Doctrine_Relation
{
$id = array();
foreach ((array) $this->definition['local'] as $local) {
$id = $record->get($local);
$id[] = $record->get($local);
}
if ($this->isOneToOne()) {
if (empty($id)) {
......@@ -54,7 +54,7 @@ class Doctrine_Relation_ForeignKey extends Doctrine_Relation
$dql = 'FROM ' . $this->getTable()->getComponentName()
. ' WHERE ' . $this->getCondition();
$coll = $this->getTable()->getConnection()->query($dql, array($id));
$coll = $this->getTable()->getConnection()->query($dql, $id);
$related = $coll[0];
}
......@@ -66,7 +66,7 @@ class Doctrine_Relation_ForeignKey extends Doctrine_Relation
$related = new Doctrine_Collection($this->getTable());
} else {
$query = $this->getRelationDql(1);
$related = $this->getTable()->getConnection()->query($query, array($id));
$related = $this->getTable()->getConnection()->query($query, $id);
}
$related->setReference($record, $this);
}
......
......@@ -126,6 +126,8 @@ class Doctrine_Relation_Parser
if (isset($this->_pending[$alias])) {
$def = $this->_pending[$alias];
// check if reference class name exists
// if it does we are dealing with association relation
if (isset($def['refClass'])) {
$def = $this->completeAssocDefinition($def);
$localClasses = array_merge($this->_table->getOption('parents'), array($this->_table->getComponentName()));
......@@ -134,7 +136,10 @@ class Doctrine_Relation_Parser
! isset($this->_relations[$def['refClass']])) {
$def['refTable']->getRelationParser()->bind($this->_table->getComponentName(),
array('type' => Doctrine_Relation::ONE));
array('type' => Doctrine_Relation::ONE,
'local' => $def['local'],
'foreign' => $this->_table->getIdentifier(),
));
$this->bind($def['refClass'], array('type' => Doctrine_Relation::MANY,
'foreign' => $def['local']));
......@@ -145,15 +150,20 @@ class Doctrine_Relation_Parser
$rel = new Doctrine_Relation_Association($def);
}
} else {
// simple foreign key relation
$def = $this->completeDefinition($def);
if ( ! isset($def['foreign'])) {
Doctrine::dump($def);
}
if (isset($def['localKey'])) {
$rel = new Doctrine_Relation_LocalKey($def);
} else {
$rel = new Doctrine_Relation_ForeignKey($def);
}
}
if (isset($rel)) {
unset($this->_pending[$name]);
// unset pending relation
unset($this->_pending[$alias]);
$this->_relations[$alias] = $rel;
return $rel;
}
}
......@@ -288,6 +298,7 @@ class Doctrine_Relation_Parser
// the foreign field is likely to be the
// identifier of the foreign class
$def['foreign'] = $def['table']->getIdentifier();
$def['localKey'] = true;
}
}
} else {
......@@ -295,6 +306,7 @@ class Doctrine_Relation_Parser
// local key not set, but foreign key is set
// try to guess the local key
if ($def['foreign'] === $def['table']->getIdentifier()) {
$def['localKey'] = true;
$def['local'] = $this->guessColumns($foreignClasses, $this->_table);
} else {
$def['local'] = $this->_table->getIdentifier();
......@@ -316,6 +328,7 @@ class Doctrine_Relation_Parser
if ($table2->hasColumn($column)) {
$def['foreign'] = $column;
$def['local'] = $table->getIdentifier();
$def['localKey'] = true;
return $def;
}
}
......@@ -334,7 +347,7 @@ class Doctrine_Relation_Parser
return $def;
}
}
} Doctrine::dump($this->_table->getComponentName());
}
Doctrine::dump($def);
throw new Doctrine_Relation_Parser_Exception("Couldn't complete relation definition.");
}
......
......@@ -37,10 +37,6 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable
* @var array $data temporary data which is then loaded into Doctrine_Record::$data
*/
private $data = array();
/**
* @var array $relations an array containing all the Doctrine_Relation objects for this table
*/
private $relations = array();
/**
* @var array $primaryKeys an array containing all primary key column names
*/
......@@ -96,14 +92,6 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable
* keys as column aliases and values as column names
*/
protected $columnAliases = array();
/**
* @var array $bound bound relations
*/
private $bound = array();
/**
* @var array $boundAliases bound relation aliases
*/
private $boundAliases = array();
/**
* @var integer $columnCount cached column count, Doctrine_Record uses this column count in when
* determining its state
......@@ -161,6 +149,7 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable
'treeImpl' => null,
'treeOptions' => null,
'indexes' => array(),
'parents' => array(),
);
/**
* @var Doctrine_Tree $tree tree object associated with this table
......@@ -207,6 +196,9 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable
// reverse names
$names = array_reverse($names);
// save parents
array_pop($names);
$this->options['parents'] = $names;
// create database table
if (method_exists($record, 'setTableDefinition')) {
......@@ -303,11 +295,6 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable
if ($this->isTree()) {
$this->getTree()->setUp();
}
// save parents
array_pop($names);
$this->options['parents'] = $names;
$this->repository = new Doctrine_Table_Repository($this);
}
/**
......@@ -472,6 +459,61 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable
return false;
}
public function bind($args, $type)
{
$options = array();
$options['type'] = $type;
// the following is needed for backwards compatibility
if (is_string($args[1])) {
if ( ! isset($args[2])) {
$args[2] = array();
} elseif (is_string($args[2])) {
$args[2] = (array) $args[2];
}
$classes = array_merge($this->options['parents'], array($this->getComponentName()));
$e = explode('.', $args[1]);
if (in_array($e[0], $classes)) {
$options['local'] = $e[1];
} else {
$e2 = explode(' as ', $args[0]);
if ($e[0] !== $e2[0] && ( ! isset($e2[1]) || $e[0] !== $e2[1])) {
$options['refClass'] = $e[0];
}
$options['foreign'] = $e[1];
}
$options = array_merge($args[2], $options);
$this->_parser->bind($args[0], $options);
} else {
$options = array_merge($args[1], $options);
$this->_parser->bind($args[0], $options);
}
}
/**
* getRelation
*
* @param string $alias relation alias
*/
public function getRelation($alias, $recursive = true)
{
return $this->_parser->getRelation($alias, $recursive);
}
/**
* getRelations
* returns an array containing all relation objects
*
* @return array an array of Doctrine_Relation objects
*/
public function getRelations()
{
return $this->_parser->getRelations();
}
/**
* createQuery
* creates a new Doctrine_Query object and adds the component name
......@@ -683,148 +725,6 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable
{
return in_array($key,$this->primaryKeys);
}
/**
* returns all bound relations
*
* @return array
*/
public function getBounds()
{
return $this->bound;
}
/**
* returns a bound relation array
*
* @param string $name
* @return array
*/
public function getBound($name)
{
if ( ! isset($this->bound[$name])) {
throw new Doctrine_Table_Exception('Unknown bound ' . $name);
}
return $this->bound[$name];
}
/**
* returns a bound relation array
*
* @param string $name
* @return array
*/
public function getBoundForName($name, $component)
{
foreach ($this->bound as $k => $bound) {
$e = explode('.', $bound['field']);
if ($bound['class'] == $name && $e[0] == $component) {
return $this->bound[$k];
}
}
throw new Doctrine_Table_Exception('Unknown bound ' . $name);
}
/**
* returns the alias for given component name
*
* @param string $name
* @return string
*/
public function getAlias($name)
{
if (isset($this->boundAliases[$name])) {
return $this->boundAliases[$name];
}
return $name;
}
/**
* returns component name for given alias
*
* @param string $alias
* @return string
*/
public function getAliasName($alias)
{
if ($name = array_search($alias, $this->boundAliases)) {
return $name;
}
return $alias;
}
/**
* unbinds all relations
*
* @return void
*/
public function unbindAll()
{
$this->bound = array();
$this->relations = array();
$this->boundAliases = array();
}
/**
* unbinds a relation
* returns true on success, false on failure
*
* @param $name
* @return boolean
*/
public function unbind($name)
{
if ( ! isset($this->bound[$name])) {
return false;
}
unset($this->bound[$name]);
if (isset($this->relations[$name])) {
unset($this->relations[$name]);
}
if (isset($this->boundAliases[$name])) {
unset($this->boundAliases[$name]);
}
return true;
}
/**
* binds a relation
*
* @param string $name
* @param string $field
* @return void
*/
public function bind($name, $field, $type, $options = null)
{
if (isset($this->relations[$name])) {
unset($this->relations[$name]);
}
$lower = strtolower($name);
if (isset($this->columns[$lower])) {
throw new Doctrine_Table_Exception("Couldn't bind relation. Column with name " . $lower . ' already exists!');
}
$e = explode(' as ', $name);
$name = $e[0];
if (isset($e[1])) {
$alias = $e[1];
$this->boundAliases[$name] = $alias;
} else {
$alias = $name;
}
$this->bound[$alias] = array('field' => $field,
'type' => $type,
'class' => $name,
'alias' => $alias);
if ($options !== null) {
$opt = array();
if (is_string($options)) {
$opt['local'] = $options;
} else {
$opt = (array) $options;
}
$this->bound[$alias] = array_merge($this->bound[$alias], $opt);
}
}
/**
* @return Doctrine_Connection
*/
......@@ -832,212 +732,6 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable
{
return $this->conn;
}
/**
* hasRelatedComponent
* @return boolean
*/
public function hasRelatedComponent($name, $component)
{
return (strpos($this->bound[$name]['field'], $component . '.') !== false);
}
/**
* @param string $name component name of which a foreign key object is bound
* @return boolean
*/
final public function hasRelation($name)
{
if (isset($this->bound[$name])) {
return true;
}
foreach ($this->bound as $k=>$v) {
if ($this->hasRelatedComponent($k, $name)) {
return true;
}
}
return false;
}
/**
* getRelation
*
* @param string $name component name of which a foreign key object is bound
* @return Doctrine_Relation
*/
public function getRelation($name, $recursive = true)
{
if (isset($this->relations[$name])) {
return $this->relations[$name];
}
if ( ! $this->conn->hasTable($this->options['name'])) {
$allowExport = true;
} else {
$allowExport = false;
}
if (isset($this->bound[$name])) {
$definition = $this->bound[$name];
list($component, $tmp) = explode('.', $definition['field']);
if ( ! isset($definition['foreign'])) {
$definition['foreign'] = $tmp;
}
unset($definition['field']);
$definition['table'] = $this->conn->getTable($definition['class'], $allowExport);
$definition['constraint'] = false;
if ($component == $this->options['name'] || in_array($component, $this->options['parents'])) {
// ONE-TO-ONE
if ($definition['type'] == Doctrine_Relation::ONE_COMPOSITE ||
$definition['type'] == Doctrine_Relation::ONE_AGGREGATE) {
// tree structure parent relation found
if ( ! isset($definition['local'])) {
$definition['local'] = $definition['foreign'];
$definition['foreign'] = $definition['table']->getIdentifier();
}
$relation = new Doctrine_Relation_LocalKey($definition);
} else {
// tree structure children relation found
if ( ! isset($definition['local'])) {
$tmp = $definition['table']->getIdentifier();
$definition['local'] = $tmp;
}
//$definition['foreign'] = $tmp;
$definition['constraint'] = true;
$relation = new Doctrine_Relation_ForeignKey($definition);
}
} elseif ($component == $definition['class'] ||
($component == $definition['alias'])) { // && ($name == $this->options['name'] || in_array($name,$this->parents))
if ( ! isset($defintion['local'])) {
$definition['local'] = $this->identifier;
}
$definition['constraint'] = true;
// ONE-TO-MANY or ONE-TO-ONE
$relation = new Doctrine_Relation_ForeignKey($definition);
} else {
// MANY-TO-MANY
// only aggregate relations allowed
if ($definition['type'] != Doctrine_Relation::MANY_AGGREGATE) {
throw new Doctrine_Table_Exception("Only aggregate relations are allowed for many-to-many relations");
}
$classes = array_merge($this->options['parents'], array($this->options['name']));
foreach (array_reverse($classes) as $class) {
try {
$bound = $definition['table']->getBoundForName($class, $component);
break;
} catch(Doctrine_Table_Exception $exc) { }
}
if ( ! isset($bound)) {
throw new Doctrine_Table_Exception("Couldn't map many-to-many relation for "
. $this->options['name'] . " and $name. Components use different join tables.");
}
if ( ! isset($definition['local'])) {
$definition['local'] = $this->identifier;
}
$e2 = explode('.', $bound['field']);
$fields = explode('-', $e2[1]);
if ($e2[0] != $component) {
throw new Doctrine_Table_Exception($e2[0] . ' doesn\'t match ' . $component);
}
$associationTable = $this->conn->getTable($e2[0], $allowExport);
if (count($fields) > 1) {
// SELF-REFERENCING THROUGH JOIN TABLE
$def['table'] = $associationTable;
$def['local'] = $this->identifier;
$def['foreign'] = $fields[0];
$def['alias'] = $e2[0];
$def['class'] = $e2[0];
$def['type'] = Doctrine_Relation::MANY_COMPOSITE;
$this->relations[$e2[0]] = new Doctrine_Relation_ForeignKey($def);
$definition['assocTable'] = $associationTable;
$definition['local'] = $fields[0];
$definition['foreign'] = $fields[1];
$relation = new Doctrine_Relation_Association_Self($definition);
} else {
if($definition['table'] === $this) {
} else {
// auto initialize a new one-to-one relationships for association table
$associationTable->bind($this->getComponentName(),
$associationTable->getComponentName(). '.' . $e2[1],
Doctrine_Relation::ONE_AGGREGATE
);
$associationTable->bind($definition['table']->getComponentName(),
$associationTable->getComponentName(). '.' . $definition['foreign'],
Doctrine_Relation::ONE_AGGREGATE
);
// NORMAL MANY-TO-MANY RELATIONSHIP
$def['table'] = $associationTable;
$def['foreign'] = $e2[1];
$def['local'] = $definition['local'];
$def['alias'] = $e2[0];
$def['class'] = $e2[0];
$def['type'] = Doctrine_Relation::MANY_COMPOSITE;
$this->relations[$e2[0]] = new Doctrine_Relation_ForeignKey($def);
$definition['local'] = $e2[1];
$definition['assocTable'] = $associationTable;
$relation = new Doctrine_Relation_Association($definition);
}
}
}
$this->relations[$name] = $relation;
return $this->relations[$name];
}
// load all relations
$this->getRelations();
if ($recursive) {
return $this->getRelation($name, false);
} else {
throw new Doctrine_Table_Exception($this->options['name'] . " doesn't have a relation to " . $name);
}
}
/**
* returns an array containing all foreign key objects
*
* @return array
*/
final public function getRelations()
{
foreach ($this->bound as $k => $v) {
$this->getRelation($k);
}
return $this->relations;
}
/**
* create
* creates a new record
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment