1
0
mirror of synced 2025-01-17 22:11:41 +03:00

started refactoring to final mapper structure for 1.0. different mapping strategies are factored out as separate strategy classes instead of inheritance.

This commit is contained in:
romanb 2008-02-20 20:54:20 +00:00
parent dcc2a54e63
commit eb02b4d002
24 changed files with 591 additions and 405 deletions

View File

@ -77,22 +77,6 @@ class Doctrine_ClassMetadata extends Doctrine_Configurable implements Serializab
*/
protected $_inheritanceType = Doctrine::INHERITANCETYPE_TABLE_PER_CLASS;
/**
* The name of the column that acts as a discriminator to identify the type of an
* object. Used in Single Table Inheritance and Class Table Inheritance.
*
* @var string
*/
protected $_discriminatorColumn;
/**
* The discriminator map contains the mapping of discriminator values (keys)
* to class names (values).
*
* @var array
*/
protected $_discriminatorMap;
/**
* An array containing all templates attached to the class.
*
@ -120,10 +104,10 @@ class Doctrine_ClassMetadata extends Doctrine_Configurable implements Serializab
protected $_filters = array();
/**
* An array of column definitions,
* keys are column names and values are column definitions
* The mapped columns and their mapping definitions.
* Keys are column names and values are definitions.
*
* the definition array has atleast the following values:
* The definition array has atleast the following values:
*
* -- type the column type, eg. 'integer'
* -- length the column length, eg. 11
@ -156,6 +140,12 @@ class Doctrine_ClassMetadata extends Doctrine_Configurable implements Serializab
*/
protected $_columnNames = array();
/**
* Caches enum value mappings. Keys are field names and values arrays with the
* mapping.
*/
protected $_enumValues = array();
/**
* @todo Implementation.
*/
@ -164,7 +154,8 @@ class Doctrine_ClassMetadata extends Doctrine_Configurable implements Serializab
/**
* Tree object associated with the class.
*
* @var Doctrine_Tree
* @var Doctrine_Tree
* @todo Belongs to the NestedSet Behavior plugin.
*/
protected $_tree;
@ -692,18 +683,25 @@ class Doctrine_ClassMetadata extends Doctrine_Configurable implements Serializab
* @return mixed
*/
public function enumValue($fieldName, $index)
{
{
if ($index instanceof Doctrine_Null) {
return $index;
}
if (isset($this->_enumValues[$fieldName][$index])) {
return $this->_enumValues[$fieldName][$index];
}
$columnName = $this->getColumnName($fieldName);
if ( ! $this->_conn->getAttribute(Doctrine::ATTR_USE_NATIVE_ENUM) &&
isset($this->_columns[$columnName]['values'][$index])) {
return $this->_columns[$columnName]['values'][$index];
$enumValue = $this->_columns[$columnName]['values'][$index];
} else {
$enumValue = $index;
}
return $index;
$this->_enumValues[$fieldName][$index] = $enumValue;
return $enumValue;
}
/**

View File

@ -13,6 +13,10 @@ class Doctrine_ClassMetadata_CodeDriver
*/
public function loadMetadataForClass($className, Doctrine_ClassMetadata $metadata)
{
if ( ! method_exists($className, 'initMetadata')) {
throw new Doctrine_ClassMetadata_Exception("Unable to load metadata for class"
. " '$className'. Callback method 'initMetadata' not found.");
}
call_user_func_array(array($className, 'initMetadata'), array($metadata));
}
}

View File

@ -165,6 +165,11 @@ class Doctrine_ClassMetadata_Factory
} while ($className = get_parent_class($className));
if ($className === false) {
try {
throw new Exception();
} catch (Exception $e) {
echo $e->getTraceAsString() . "<br />";
}
throw new Doctrine_ClassMetadata_Factory_Exception("Unknown component '$className'.");
}

View File

@ -109,7 +109,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
$this->_mapper = $mapper;
if ($keyColumn === null) {
$keyColumn = $mapper->getBoundQueryPart('indexBy');
$keyColumn = $mapper->getClassMetadata()->getBoundQueryPart('indexBy');
}
if ($keyColumn === null) {
@ -214,7 +214,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
$keyColumn = isset($array['keyColumn']) ? $array['keyColumn'] : null;
if ($keyColumn === null) {
$keyColumn = $this->_mapper->getBoundQueryPart('indexBy');
$keyColumn = $this->_mapper->getClassMetadata()->getBoundQueryPart('indexBy');
}
if ($keyColumn !== null) {

View File

@ -1128,31 +1128,57 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
* @return Doctrine_Mapper The mapper object.
* @todo package:orm
*/
public function getMapper($entityClassName)
/*public function getMapper($entityName)
{
if (isset($this->_mappers[$entityClassName])) {
return $this->_mappers[$entityClassName];
if (isset($this->_mappers[$entityName])) {
return $this->_mappers[$entityName];
}
$metadata = $this->getClassMetadata($entityClassName);
$metadata = $this->getClassMetadata($entityName);
$customMapperClassName = $metadata->getCustomMapperClass();
if ($customMapperClassName !== null) {
$mapper = new $customMapperClassName($entityClassName, $metadata);
$mapper = new $customMapperClassName($entityName, $metadata);
} else {
// instantiate correct mapper type
$inheritanceType = $metadata->getInheritanceType();
if ($inheritanceType == Doctrine::INHERITANCETYPE_JOINED) {
$mapper = new Doctrine_Mapper_Joined($entityClassName, $metadata);
$mapper = new Doctrine_Mapper_Joined($entityName, $metadata);
} else if ($inheritanceType == Doctrine::INHERITANCETYPE_SINGLE_TABLE) {
$mapper = new Doctrine_Mapper_SingleTable($entityClassName, $metadata);
$mapper = new Doctrine_Mapper_SingleTable($entityName, $metadata);
} else if ($inheritanceType == Doctrine::INHERITANCETYPE_TABLE_PER_CLASS) {
$mapper = new Doctrine_Mapper_TablePerClass($entityClassName, $metadata);
$mapper = new Doctrine_Mapper_TablePerClass($entityName, $metadata);
} else {
throw new Doctrine_Connection_Exception("Unknown inheritance type '$inheritanceType'. Can't create mapper.");
}
}
$this->_mappers[$entityClassName] = $mapper;
$this->_mappers[$entityName] = $mapper;
return $mapper;
}*/
/**
* Gets a mapper for the specified domain class that is used to map instances of
* the class between the relational database and their object representation.
*
* @param string $entityClassName The name of the entity class.
* @return Doctrine_Mapper The mapper object.
* @todo package:orm
*/
public function getMapper($entityName)
{
if (isset($this->_mappers[$entityName])) {
return $this->_mappers[$entityName];
}
$metadata = $this->getClassMetadata($entityName);
$customMapperClassName = $metadata->getCustomMapperClass();
if ($customMapperClassName !== null) {
$mapper = new $customMapperClassName($entityName, $metadata);
} else {
$mapper = new Doctrine_Mapper($entityName, $metadata);
}
$this->_mappers[$entityName] = $mapper;
return $mapper;
}

View File

@ -92,7 +92,7 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module
{
$tree = array();
foreach ($mappers as $k => $mapper) {
if ( ! ($mapper instanceof Doctrine_Mapper_Abstract)) {
if ( ! ($mapper instanceof Doctrine_Mapper)) {
$mapper = $this->conn->getMapper($mapper);
}
$nm = $mapper->getComponentName();

View File

@ -1159,7 +1159,6 @@ class Doctrine_Export extends Doctrine_Connection_Module
// as soon as ONE table is exported, because the data of one class is stored
// across many tables.
if ($classMetadata->getInheritanceType() == Doctrine::INHERITANCETYPE_JOINED) {
//echo "joined.<br />";
$parents = $classMetadata->getOption('parents');
foreach ($parents as $parent) {
$data = $classMetadata->getConnection()->getClassMetadata($parent)->getExportableFormat();

View File

@ -1,6 +1,6 @@
<?php
/*
* $Id: Hydrate.php 3192 2007-11-19 17:55:23Z romanb $
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@ -20,9 +20,8 @@
*/
/**
* Doctrine_Hydrate is a base class for Doctrine_RawSql and Doctrine_Query.
* Its purpose is to populate object graphs.
*
* The hydrator has the tedious task to construct object or array graphs out of
* a database result set.
*
* @package Doctrine
* @subpackage Hydrate
@ -31,6 +30,7 @@
* @since 1.0
* @version $Revision: 3192 $
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Roman Borschel <roman@code-factory.org>
*/
class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
{
@ -56,7 +56,7 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
* 'map' => Custom index to use as the key in the result (if any)
* )
* )
* @return array
* @return mixed The created object/array graph.
*/
public function hydrateResultSet($stmt, $tableAliases, $hydrationMode = null)
{
@ -224,7 +224,7 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
}
$id[$rootAlias] = '';
}
$stmt->closeCursor();
$driver->flush();
@ -294,6 +294,7 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
foreach ($data as $key => $value) {
// Parse each column name only once. Cache the results.
if ( ! isset($cache[$key])) {
// cache general information like the column name <-> field name mapping
$e = explode('__', $key);
$last = strtolower(array_pop($e));
$cache[$key]['dqlAlias'] = $this->_tableAliases[strtolower(implode('__', $e))];
@ -301,15 +302,20 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
$table = $mapper->getTable();
$fieldName = $mapper->getFieldName($last);
$cache[$key]['fieldName'] = $fieldName;
// cache identifier information
if ($table->isIdentifier($fieldName)) {
$cache[$key]['isIdentifier'] = true;
} else {
$cache[$key]['isIdentifier'] = false;
}
// cache type information
$type = $table->getTypeOfColumn($last);
if ($type == 'integer' || $type == 'string') {
$cache[$key]['isSimpleType'] = true;
} else {
$cache[$key]['type'] = $type;
$cache[$key]['isSimpleType'] = false;
}
}
@ -329,7 +335,8 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
if ($cache[$key]['isSimpleType']) {
$rowData[$dqlAlias][$fieldName] = $value;
} else {
$rowData[$dqlAlias][$fieldName] = $mapper->prepareValue($fieldName, $value);
$rowData[$dqlAlias][$fieldName] = $mapper->prepareValue(
$fieldName, $value, $cache[$key]['type']);
}
if ( ! isset($nonemptyComponents[$dqlAlias]) && $value !== null) {

View File

@ -31,7 +31,7 @@
* @link www.phpdoctrine.org
* @since 1.0
*/
abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements Countable
class Doctrine_Mapper extends Doctrine_Configurable implements Countable
{
/**
* @var Doctrine_Table Metadata container that represents the database table this
@ -43,11 +43,6 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
* The name of the domain class this mapper is used for.
*/
protected $_domainClassName;
/**
* The names of all the fields that are available on entities created by this mapper.
*/
protected $_fieldNames = array();
/**
* The Doctrine_Connection object that the database connection of this mapper.
@ -55,6 +50,11 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
* @var Doctrine_Connection $conn
*/
protected $_conn;
/**
* The concrete mapping strategy that is used.
*/
protected $_mappingStrategy;
/**
* @var array $identityMap first level cache
@ -81,13 +81,18 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
* @param Doctrine_Table $table The table object used for the mapping procedure.
* @throws Doctrine_Connection_Exception if there are no opened connections
*/
public function __construct($name, Doctrine_ClassMetadata $metadata)
public function __construct($name, Doctrine_ClassMetadata $classMetadata)
{
$this->_domainClassName = $name;
$this->_conn = $metadata->getConnection();
$this->_classMetadata = $metadata;
$this->_conn = $classMetadata->getConnection();
$this->_classMetadata = $classMetadata;
$this->setParent($this->_conn);
$this->_repository = new Doctrine_Table_Repository($this);
$this->_repository = new Doctrine_Table_Repository($this);
if ($classMetadata->getInheritanceType() == Doctrine::INHERITANCETYPE_JOINED) {
$this->_mappingStrategy = new Doctrine_Mapper_JoinedStrategy($this);
} else {
$this->_mappingStrategy = new Doctrine_Mapper_DefaultStrategy($this);
}
}
public function getMethodOwner($method)
@ -150,6 +155,7 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
* getRepository
*
* @return Doctrine_Table_Repository
* @todo refactor
*/
public function getRepository()
{
@ -161,6 +167,7 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
*
* @params Doctrine_Connection a connection object
* @return Doctrine_Table this object
* @todo refactor
*/
public function setConnection(Doctrine_Connection $conn)
{
@ -195,7 +202,7 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
}
/**
* finds a record by its identifier
* Finds an entity by its primary key.
*
* @param $id database row id
* @param int $hydrationMode Doctrine::HYDRATE_ARRAY or Doctrine::HYDRATE_RECORD
@ -215,10 +222,10 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
}
/**
* findAll
* returns a collection of records
* Finds all entities of the mapper's class.
* Use with care.
*
* @param int $hydrationMode Doctrine::FETCH_ARRAY or Doctrine::FETCH_RECORD
* @param int $hydrationMode Doctrine::HYDRATE_ARRAY or Doctrine::HYDRATE_RECORD
* @return Doctrine_Collection
*/
public function findAll($hydrationMode = null)
@ -262,50 +269,20 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
return $query->query($dql, $params, $hydrationMode);
}
/**
* execute
* fetches data using the provided queryKey and
* the associated query in the query registry
*
* if no query for given queryKey is being found a
* Doctrine_Query_Registry exception is being thrown
*
* @param string $queryKey the query key
* @param array $params prepared statement params (if any)
* @return mixed the fetched data
*/
public function execute($queryKey, $params = array(), $hydrationMode = Doctrine::HYDRATE_RECORD)
{
return Doctrine_Manager::getInstance()
->getQueryRegistry()
->get($queryKey, $this->getComponentName())
->execute($params, $hydrationMode);
}
/**
* Executes a named query.
*
* @param string $queryName The name that was used when storing the query.
* @param array $params The query parameters.
* @return mixed The result.
* @deprecated
*/
public function executeNamedQuery($queryName, $params = array(), $hydrationMode = Doctrine::HYDRATE_RECORD)
{
return $this->execute($queryName, $params, $hydrationMode);
}
/**
* executeOne
* fetches data using the provided queryKey and
* the associated query in the query registry
*
* if no query for given queryKey is being found a
* Doctrine_Query_Registry exception is being thrown
*
* @param string $queryKey the query key
* @param array $params prepared statement params (if any)
* @return mixed the fetched data
*/
public function executeOne($queryKey, $params = array(), $hydrationMode = Doctrine::HYDRATE_RECORD)
{
return Doctrine_Manager::getInstance()
->getQueryRegistry()
->get($queryKey, $this->getComponentName())
->fetchOne($params, $hydrationMode);
->createNamedQuery($queryName)
->execute($params, $hydrationMode);
}
/**
@ -364,8 +341,8 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
/**
* getRecord
* first checks if record exists in identityMap, if not
* returns a new record
* First checks if record exists in identityMap, if not
* returns a new record.
*
* @return Doctrine_Record
*/
@ -414,7 +391,6 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
/**
* @param $id database row id
* @throws Doctrine_Find_Exception
*/
final public function getProxy($id = null)
{
@ -470,20 +446,11 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
*/
public function count()
{
$a = $this->_conn->execute('SELECT COUNT(1) FROM ' . $this->_classMetadata->getOption('tableName'))->fetch(Doctrine::FETCH_NUM);
$a = $this->_conn->execute('SELECT COUNT(1) FROM ' . $this->_classMetadata->getTableName())
->fetch(Doctrine::FETCH_NUM);
return current($a);
}
/**
* @return Doctrine_Query a Doctrine_Query object
*/
public function getQueryObject()
{
$graph = new Doctrine_Query($this->getConnection());
$graph->load($this->getComponentName());
return $graph;
}
/**
* prepareValue
* this method performs special data preparation depending on
@ -505,17 +472,19 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
* @throws Doctrine_Table_Exception if uncompression of gzip typed column fails *
* @param string $field the name of the field
* @param string $value field value
* @param string $typeHint A hint on the type of the value. If provided, the type lookup
* for the field can be skipped. Used i.e. during hydration to
* improve performance on large and/or complex results.
* @return mixed prepared value
*/
public function prepareValue($fieldName, $value)
public function prepareValue($fieldName, $value, $typeHint = null)
{
if ($value === self::$_null) {
return self::$_null;
} else if ($value === null) {
return null;
} else {
$type = $this->_classMetadata->getTypeOf($fieldName);
$type = is_null($typeHint) ? $this->_classMetadata->getTypeOf($fieldName) : $typeHint;
switch ($type) {
case 'integer':
case 'string';
@ -548,6 +517,17 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
}
return $value;
}
/**
* Hydrates the given data into the entity.
*
*/
public function hydrate(Doctrine_Record $entity, array $data)
{
$this->_values = array_merge($this->_values, $this->cleanData($data));
$this->_data = array_merge($this->_data, $data);
$this->_extractIdentifier(true);
}
/**
* getTree
@ -579,11 +559,20 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
* getComponentName
*
* @return void
* @deprecated Use getMappedClassName()
*/
public function getComponentName()
{
return $this->_domainClassName;
}
/**
* Gets the name of the class the mapper is used for.
*/
public function getMappedClassName()
{
return $this->_domainClassName;
}
/**
* returns a string representation of this object
@ -620,7 +609,7 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
{
$results = $this->createQuery()->where($fieldName . ' = ?')->limit(1)->execute(
array($value), $hydrationMode);
return $hydrationMode === Doctrine::HYDRATE_ARRAY ? $results[0] : $results->getFirst();
return $hydrationMode === Doctrine::HYDRATE_ARRAY ? array_shift($results) : $results->getFirst();
}
/**
@ -631,6 +620,9 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
* findById, findByContactId, etc.
*
* @return void
* @throws Doctrine_Mapper_Exception If the method called is an invalid find* method
* or no find* method at all and therefore an invalid
* method call.
*/
public function __call($method, $arguments)
{
@ -640,13 +632,13 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
} else if (substr($method, 0, 9) == 'findOneBy') {
$by = substr($method, 9, strlen($method));
$method = 'findOneBy';
}/* else {
throw new Doctrine_Mapper_Exception("Unknown method '$method'.");
}*/
} else {
throw new Doctrine_Mapper_Exception("Undefined method '$method'.");
}
if (isset($by)) {
if ( ! isset($arguments[0])) {
throw new Doctrine_Mapper_Exception('You must specify the value to findBy');
throw new Doctrine_Mapper_Exception('You must specify the value to findBy.');
}
$fieldName = Doctrine::tableize($by);
@ -656,11 +648,9 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
return $this->$method($fieldName, $arguments[0], $hydrationMode);
} else if ($this->_classMetadata->hasRelation($by)) {
$relation = $this->_classMetadata->getRelation($by);
if ($relation['type'] === Doctrine_Relation::MANY) {
throw new Doctrine_Table_Exception('Cannot findBy many relationship.');
throw new Doctrine_Mapper_Exception('Cannot findBy many relationship.');
}
return $this->$method($relation['local'], $arguments[0], $hydrationMode);
} else {
throw new Doctrine_Mapper_Exception('Cannot find by: ' . $by . '. Invalid field or relationship alias.');
@ -674,7 +664,7 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
* @param Doctrine_Record $record The entity to save.
* @param Doctrine_Connection $conn The connection to use. Will default to the mapper's
* connection.
* @throws Doctrine_Mapper_Exception If the mapper is unable to save the given record.
* @throws Doctrine_Mapper_Exception If the mapper is unable to save the given entity.
*/
public function save(Doctrine_Record $record, Doctrine_Connection $conn = null)
{
@ -697,34 +687,11 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
try {
$conn->beginInternalTransaction();
$saveLater = $this->_saveRelated($record);
//echo "num savelater:" . count($saveLater) . "<br />";
$record->state($state);
if ($record->isValid()) {
$event = new Doctrine_Event($record, Doctrine_Event::RECORD_SAVE);
$record->preSave($event);
$this->getRecordListener()->preSave($event);
$state = $record->state();
if ( ! $event->skipOperation) {
switch ($state) {
case Doctrine_Record::STATE_TDIRTY:
$this->insert($record);
break;
case Doctrine_Record::STATE_DIRTY:
case Doctrine_Record::STATE_PROXY:
$this->update($record);
break;
case Doctrine_Record::STATE_CLEAN:
case Doctrine_Record::STATE_TCLEAN:
break;
}
}
$this->getRecordListener()->postSave($event);
$record->postSave($event);
$this->_insertOrUpdate($record);
} else {
$conn->transaction->addInvalid($record);
}
@ -757,57 +724,34 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
}
/**
* Inserts a single entity into the database, without any related entities.
* Inserts or updates an entity, depending on it's state.
*
* @param Doctrine_Record $record The entity to insert.
* @param Doctrine_Record $record The entity to insert/update.
*/
protected function insertSingleRecord(Doctrine_Record $record)
protected function _insertOrUpdate(Doctrine_Record $record)
{
$fields = $record->getPrepared();
if (empty($fields)) {
return false;
}
$event = new Doctrine_Event($record, Doctrine_Event::RECORD_SAVE);
$record->preSave($event);
$this->getRecordListener()->preSave($event);
$class = $record->getClassMetadata();
$identifier = (array) $class->getIdentifier();
$fields = $this->_convertFieldToColumnNames($fields, $class);
$seq = $class->getTableOption('sequenceName');
if ( ! empty($seq)) {
$id = $this->_conn->sequence->nextId($seq);
$seqName = $class->getIdentifier();
$fields[$seqName] = $id;
$record->assignIdentifier($id);
}
$this->_conn->insert($class->getTableName(), $fields);
if (empty($seq) && count($identifier) == 1 && $identifier[0] == $class->getIdentifier() &&
$class->getIdentifierType() != Doctrine::IDENTIFIER_NATURAL) {
if (strtolower($this->_conn->getName()) == 'pgsql') {
$seq = $class->getTableName() . '_' . $identifier[0];
if ( ! $event->skipOperation) {
switch ($record->state()) {
case Doctrine_Record::STATE_TDIRTY:
$this->_insert($record);
break;
case Doctrine_Record::STATE_DIRTY:
case Doctrine_Record::STATE_PROXY:
$this->_update($record);
break;
case Doctrine_Record::STATE_CLEAN:
case Doctrine_Record::STATE_TCLEAN:
// do nothing
break;
}
$id = $this->_conn->sequence->lastInsertId($seq);
if ( ! $id) {
throw new Doctrine_Connection_Exception("Couldn't get last insert identifier.");
}
$record->assignIdentifier($id);
} else {
$record->assignIdentifier(true);
}
}
protected function _convertFieldToColumnNames(array $fields, Doctrine_ClassMetadata $class)
{
$converted = array();
foreach ($fields as $fieldName => $value) {
$converted[$class->getColumnName($fieldName)] = $value;
}
return $converted;
$this->getRecordListener()->postSave($event);
$record->postSave($event);
}
/**
@ -818,28 +762,7 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
*/
public function saveSingleRecord(Doctrine_Record $record)
{
$event = new Doctrine_Event($record, Doctrine_Event::RECORD_SAVE);
$record->preSave($event);
$this->getRecordListener()->preSave($event);
if ( ! $event->skipOperation) {
switch ($record->state()) {
case Doctrine_Record::STATE_TDIRTY:
$this->insert($record);
break;
case Doctrine_Record::STATE_DIRTY:
case Doctrine_Record::STATE_PROXY:
$this->update($record);
break;
case Doctrine_Record::STATE_CLEAN:
case Doctrine_Record::STATE_TCLEAN:
// do nothing
break;
}
}
$this->getRecordListener()->postSave($event);
$record->postSave($event);
$this->_insertOrUpdate($record);
}
/**
@ -913,13 +836,14 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
. ' AND ' . $rel->getLocal() . ' = ?';
$this->_conn->execute($query, array($r->getIncremented(), $record->getIncremented()));
}
foreach ($relatedObject->getInsertDiff() as $r) {
$assocRecord = $this->_conn->getMapper($assocTable->getComponentName())->create();
$assocMapper = $this->_conn->getMapper($assocTable->getComponentName());
foreach ($relatedObject->getInsertDiff() as $r) {
$assocRecord = $assocMapper->create();
$assocRecord->set($assocTable->getFieldName($rel->getForeign()), $r);
$assocRecord->set($assocTable->getFieldName($rel->getLocal()), $record);
$this->saveSingleRecord($assocRecord);
$assocMapper->save($assocRecord);
//$this->saveSingleRecord($assocRecord);
}
}
}
@ -932,7 +856,7 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
* @return boolean whether or not the update was successful
* @todo Move to Doctrine_Table (which will become Doctrine_Mapper).
*/
protected function update(Doctrine_Record $record)
protected function _update(Doctrine_Record $record)
{
$event = new Doctrine_Event($record, Doctrine_Event::RECORD_UPDATE);
$record->preUpdate($event);
@ -940,7 +864,7 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
$this->getRecordListener()->preUpdate($event);
if ( ! $event->skipOperation) {
$this->_doUpdate($record);
$this->_mappingStrategy->doUpdate($record);
}
$this->getRecordListener()->postUpdate($event);
@ -952,13 +876,13 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
/**
* Updates an entity.
*/
protected function _doUpdate(Doctrine_Record $record)
/*protected function _doUpdate(Doctrine_Record $record)
{
$identifier = $this->_convertFieldToColumnNames($record->identifier(), $this->_classMetadata);
$data = $this->_convertFieldToColumnNames($record->getPrepared(), $this->_classMetadata);
$this->_conn->update($this->_classMetadata->getTableName(), $data, $identifier);
$record->assignIdentifier(true);
}
}*/
/**
* Inserts an entity.
@ -966,7 +890,7 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
* @param Doctrine_Record $record record to be inserted
* @return boolean
*/
protected function insert(Doctrine_Record $record)
protected function _insert(Doctrine_Record $record)
{
// trigger event
$event = new Doctrine_Event($record, Doctrine_Event::RECORD_INSERT);
@ -974,7 +898,7 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
$this->getRecordListener()->preInsert($event);
if ( ! $event->skipOperation) {
$this->_doInsert($record);
$this->_mappingStrategy->doInsert($record);
}
// trigger event
@ -986,21 +910,66 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
}
/**
* Inserts an entity.
* Inserts a single entity into the database, without any related entities.
*
* @param Doctrine_Record $record The entity to insert.
*/
protected function _doInsert(Doctrine_Record $record)
/*protected function _doInsert(Doctrine_Record $record)
{
$this->insertSingleRecord($record);
}
$fields = $record->getPrepared();
if (empty($fields)) {
return false;
}
if ($record->getClassMetadata() !== $this->_classMetadata) {
echo $record->getClassMetadata()->getClassname() . ' != ' . $this->_classMetadata->getClassName() . "<br /><br />";
try {
throw new Exception();
} catch (Exception $e) {
echo $e->getTraceAsString() . "<br /><br />";
}
}
//$class = $record->getClassMetadata();
$class = $this->_classMetadata;
$identifier = (array) $class->getIdentifier();
$fields = $this->_convertFieldToColumnNames($fields, $class);
$seq = $class->getTableOption('sequenceName');
if ( ! empty($seq)) {
$id = $this->_conn->sequence->nextId($seq);
$seqName = $class->getIdentifier();
$fields[$seqName] = $id;
$record->assignIdentifier($id);
}
$this->_conn->insert($class->getTableName(), $fields);
if (empty($seq) && count($identifier) == 1 && $identifier[0] == $class->getIdentifier() &&
$class->getIdentifierType() != Doctrine::IDENTIFIER_NATURAL) {
if (strtolower($this->_conn->getName()) == 'pgsql') {
$seq = $class->getTableName() . '_' . $identifier[0];
}
$id = $this->_conn->sequence->lastInsertId($seq);
if ( ! $id) {
throw new Doctrine_Mapper_Exception("Couldn't get last insert identifier.");
}
$record->assignIdentifier($id);
} else {
$record->assignIdentifier(true);
}
}*/
/**
* deletes given record and all the related composites
* this operation is isolated by a transaction
* Deletes given entity and all it's related entities.
*
* this event can be listened by the onPreDelete and onDelete listeners
* Triggered Events: onPreDelete, onDelete.
*
* @return boolean true on success, false on failure
* @todo Move to Doctrine_Table (which will become Doctrine_Mapper).
* @throws Doctrine_Mapper_Exception
*/
public function delete(Doctrine_Record $record, Doctrine_Connection $conn = null)
{
@ -1027,7 +996,7 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
$record->state(Doctrine_Record::STATE_LOCKED);
if ( ! $event->skipOperation) {
$this->_doDelete($record, $conn);
$this->_mappingStrategy->doDelete($record);
} else {
// return to original state
$record->state($state);
@ -1042,26 +1011,26 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
/**
* Deletes an entity.
*/
protected function _doDelete(Doctrine_Record $record, Doctrine_Connection $conn)
/*protected function _doDelete(Doctrine_Record $record)
{
try {
$conn->beginInternalTransaction();
$this->_conn->beginInternalTransaction();
$this->_deleteComposites($record);
$record->state(Doctrine_Record::STATE_TDIRTY);
$identifier = $this->_convertFieldToColumnNames($record->identifier(), $this->_classMetadata);
$conn->delete($this->_classMetadata->getTableName(), $identifier);
$this->_conn->delete($this->_classMetadata->getTableName(), $identifier);
$record->state(Doctrine_Record::STATE_TCLEAN);
$this->removeRecord($record);
$conn->commit();
$this->_conn->commit();
} catch (Exception $e) {
$conn->rollback();
$this->_conn->rollback();
throw $e;
}
}
}*/
/**
* deletes all related composites
@ -1070,7 +1039,7 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
* @throws PDOException if something went wrong at database level
* @return void
*/
protected function _deleteComposites(Doctrine_Record $record)
/*protected function _deleteComposites(Doctrine_Record $record)
{
foreach ($this->_classMetadata->getRelations() as $fk) {
if ($fk->isComposite()) {
@ -1081,7 +1050,7 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
}
}
}
}
}*/
public function executeQuery(Doctrine_Query $query)
{
@ -1092,22 +1061,8 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
{
return $this->_classMetadata;
}
public function getFieldName($columnName)
{
return $this->_classMetadata->getFieldName($columnName);
}
public function getFieldNames()
{
if ($this->_fieldNames) {
return $this->_fieldNames;
}
$this->_fieldNames = $this->_classMetadata->getFieldNames();
return $this->_fieldNames;
}
public function getOwningTable($fieldName)
public function getClassMetadata()
{
return $this->_classMetadata;
}
@ -1122,6 +1077,10 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
var_dump($this->_invokedMethods);
}
public function free()
{
$this->_mappingStrategy = null;
}
/*public function addToWhere($componentAlias, array &$sqlWhereParts, Doctrine_Query $query)
{
@ -1133,6 +1092,21 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
}*/
public function getFieldName($columnName)
{
return $this->_mappingStrategy->getFieldName($columnName);
}
public function getFieldNames()
{
return $this->_mappingStrategy->getFieldNames();
}
public function getOwningTable($fieldName)
{
return $this->_mappingStrategy->getOwningTable($fieldName);
}
/* Hooks used during SQL query construction to manipulate the query. */
/**
@ -1140,7 +1114,7 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
*/
public function getCustomJoins()
{
return array();
return $this->_mappingStrategy->getCustomJoins();
}
/**
@ -1148,6 +1122,6 @@ abstract class Doctrine_Mapper_Abstract extends Doctrine_Configurable implements
*/
public function getCustomFields()
{
return array();
return $this->_mappingStrategy->getCustomFields();
}
}

View File

@ -0,0 +1,117 @@
<?php
/**
* The default strategy maps a single instance to a single database table, as is
* the case in Single Table Inheritance & Concrete Table Inheritance.
*
* @since 1.0
*/
class Doctrine_Mapper_DefaultStrategy extends Doctrine_Mapper_Strategy
{
/**
* Deletes an entity.
*/
public function doDelete(Doctrine_Record $record)
{
$conn = $this->_mapper->getConnection();
$metadata = $this->_mapper->getClassMetadata();
try {
$conn->beginInternalTransaction();
$this->_deleteComposites($record);
$record->state(Doctrine_Record::STATE_TDIRTY);
$identifier = $this->_convertFieldToColumnNames($record->identifier(), $metadata);
$this->_deleteRow($metadata->getTableName(), $identifier);
$record->state(Doctrine_Record::STATE_TCLEAN);
$this->_mapper->removeRecord($record);
$conn->commit();
} catch (Exception $e) {
$conn->rollback();
throw $e;
}
}
/**
* deletes all related composites
* this method is always called internally when a record is deleted
*
* @throws PDOException if something went wrong at database level
* @return void
*/
protected function _deleteComposites(Doctrine_Record $record)
{
$classMetadata = $this->_mapper->getClassMetadata();
foreach ($classMetadata->getRelations() as $fk) {
if ($fk->isComposite()) {
$obj = $record->get($fk->getAlias());
if ($obj instanceof Doctrine_Record &&
$obj->state() != Doctrine_Record::STATE_LOCKED) {
$obj->delete($this->_mapper->getConnection());
}
}
}
}
/**
* Inserts a single entity into the database, without any related entities.
*
* @param Doctrine_Record $record The entity to insert.
*/
public function doInsert(Doctrine_Record $record)
{
$conn = $this->_mapper->getConnection();
$fields = $record->getPrepared();
if (empty($fields)) {
return false;
}
//$class = $record->getClassMetadata();
$class = $this->_mapper->getClassMetadata();
$identifier = (array) $class->getIdentifier();
$fields = $this->_convertFieldToColumnNames($fields, $class);
$seq = $class->getTableOption('sequenceName');
if ( ! empty($seq)) {
$id = $conn->sequence->nextId($seq);
$seqName = $class->getIdentifier();
$fields[$seqName] = $id;
$record->assignIdentifier($id);
}
$this->_insertRow($class->getTableName(), $fields);
if (empty($seq) && count($identifier) == 1 && $identifier[0] == $class->getIdentifier() &&
$class->getIdentifierType() != Doctrine::IDENTIFIER_NATURAL) {
if (strtolower($conn->getName()) == 'pgsql') {
$seq = $class->getTableName() . '_' . $identifier[0];
}
$id = $conn->sequence->lastInsertId($seq);
if ( ! $id) {
throw new Doctrine_Mapper_Exception("Couldn't get last insert identifier.");
}
$record->assignIdentifier($id);
} else {
$record->assignIdentifier(true);
}
}
/**
* Updates an entity.
*/
public function doUpdate(Doctrine_Record $record)
{
$conn = $this->_mapper->getConnection();
$classMetadata = $this->_mapper->getClassMetadata();
$identifier = $this->_convertFieldToColumnNames($record->identifier(), $classMetadata);
$data = $this->_convertFieldToColumnNames($record->getPrepared(), $classMetadata);
$this->_updateRow($classMetadata->getTableName(), $data, $identifier);
$record->assignIdentifier(true);
}
}

View File

@ -1,6 +1,6 @@
<?php
class Doctrine_Mapper_Joined extends Doctrine_Mapper_Abstract
class Doctrine_Mapper_JoinedStrategy extends Doctrine_Mapper_Strategy
{
protected $_columnNameFieldNameMap = array();
@ -10,31 +10,32 @@ class Doctrine_Mapper_Joined extends Doctrine_Mapper_Abstract
* @param Doctrine_Record $record record to be inserted
* @return boolean
*/
protected function _doInsert(Doctrine_Record $record)
public function doInsert(Doctrine_Record $record)
{
$class = $this->_classMetadata;
$class = $this->_mapper->getClassMetadata();
$conn = $this->_mapper->getConnection();
$dataSet = $this->_formatDataSet($record);
$dataSet = $this->_groupFieldsByDefiningClass($record);
$component = $class->getClassName();
$classes = $class->getParentClasses();
array_unshift($classes, $component);
try {
$this->_conn->beginInternalTransaction();
$conn->beginInternalTransaction();
$identifier = null;
foreach (array_reverse($classes) as $k => $parent) {
$parentClass = $this->_conn->getClassMetadata($parent);
$parentClass = $conn->getClassMetadata($parent);
if ($k == 0) {
$identifierType = $parentClass->getIdentifierType();
if ($identifierType == Doctrine::IDENTIFIER_AUTOINC) {
$this->_conn->insert($parentClass->getTableName(), $dataSet[$parent]);
$identifier = $this->_conn->sequence->lastInsertId();
$this->_insertRow($parentClass->getTableName(), $dataSet[$parent]);
$identifier = $conn->sequence->lastInsertId();
} else if ($identifierType == Doctrine::IDENTIFIER_SEQUENCE) {
$seq = $record->getClassMetadata()->getTableOption('sequenceName');
if ( ! empty($seq)) {
$identifier = $this->_conn->sequence->nextId($seq);
$identifier = $conn->sequence->nextId($seq);
$dataSet[$parent][$parentClass->getIdentifier()] = $identifier;
$this->_conn->insert($parentClass->getTableName(), $dataSet[$parent]);
$this->_insertRow($parentClass->getTableName(), $dataSet[$parent]);
}
} else {
throw new Doctrine_Mapper_Exception("Unsupported identifier type '$identifierType'.");
@ -44,12 +45,12 @@ class Doctrine_Mapper_Joined extends Doctrine_Mapper_Abstract
foreach ((array) $record->identifier() as $id => $value) {
$dataSet[$parent][$parentClass->getColumnName($id)] = $value;
}
$this->_conn->insert($parentClass->getTableName(), $dataSet[$parent]);
$this->_insertRow($parentClass->getTableName(), $dataSet[$parent]);
}
}
$this->_conn->commit();
$conn->commit();
} catch (Exception $e) {
$this->_conn->rollback();
$conn->rollback();
throw $e;
}
@ -63,13 +64,14 @@ class Doctrine_Mapper_Joined extends Doctrine_Mapper_Abstract
* @return boolean whether or not the update was successful
* @todo Move to Doctrine_Table (which will become Doctrine_Mapper).
*/
protected function _doUpdate(Doctrine_Record $record)
public function doUpdate(Doctrine_Record $record)
{
$table = $this->_classMetadata;
$identifier = $this->_convertFieldToColumnNames($record->identifier(), $this->_classMetadata);
$dataSet = $this->_formatDataSet($record);
$component = $table->getClassName();
$classes = $table->getParentClasses();
$conn = $this->_mapper->getConnection();
$classMetadata = $this->_mapper->getClassMetadata();
$identifier = $this->_convertFieldToColumnNames($record->identifier(), $classMetadata);
$dataSet = $this->_groupFieldsByDefiningClass($record);
$component = $classMetadata->getClassName();
$classes = $classMetadata->getParentClasses();
array_unshift($classes, $component);
foreach ($record as $field => $value) {
@ -82,8 +84,8 @@ class Doctrine_Mapper_Joined extends Doctrine_Mapper_Abstract
}
foreach (array_reverse($classes) as $class) {
$parentTable = $this->_conn->getClassMetadata($class);
$this->_conn->update($parentTable->getTableName(), $dataSet[$class], $identifier);
$parentTable = $conn->getClassMetadata($class);
$this->_updateRow($parentTable->getTableName(), $dataSet[$class], $identifier);
}
$record->assignIdentifier(true);
@ -95,10 +97,11 @@ class Doctrine_Mapper_Joined extends Doctrine_Mapper_Abstract
* Deletes an entity that is part of a Class Table Inheritance hierarchy.
*
*/
protected function _doDelete(Doctrine_Record $record, Doctrine_Connection $conn)
public function doDelete(Doctrine_Record $record)
{
$conn = $this->_mapper->getConnection();
try {
$class = $this->_classMetadata;
$class = $this->_mapper->getClassMetadata();
$conn->beginInternalTransaction();
$this->deleteComposites($record);
@ -108,13 +111,13 @@ class Doctrine_Mapper_Joined extends Doctrine_Mapper_Abstract
foreach ($class->getParentClasses() as $parent) {
$parentClass = $conn->getClassMetadata($parent);
$conn->delete($parentClass->getTableName(), $identifier);
$this->_deleteRow($parentClass->getTableName(), $identifier);
}
$conn->delete($class->getTableName(), $identifier);
$record->state(Doctrine_Record::STATE_TCLEAN);
$this->removeRecord($record);
$this->_mapper->removeRecord($record);
$conn->commit();
} catch (Exception $e) {
$conn->rollback();
@ -135,11 +138,12 @@ class Doctrine_Mapper_Joined extends Doctrine_Mapper_Abstract
public function getCustomJoins()
{
$customJoins = array();
foreach ($this->_classMetadata->getParentClasses() as $parentClass) {
$classMetadata = $this->_mapper->getClassMetadata();
foreach ($classMetadata->getParentClasses() as $parentClass) {
$customJoins[$parentClass] = 'INNER';
}
foreach ((array)$this->_classMetadata->getSubclasses() as $subClass) {
if ($subClass != $this->_domainClassName) {
foreach ((array)$classMetadata->getSubclasses() as $subClass) {
if ($subClass != $this->_mapper->getComponentName()) {
$customJoins[$subClass] = 'LEFT';
}
}
@ -158,10 +162,12 @@ class Doctrine_Mapper_Joined extends Doctrine_Mapper_Abstract
*/
public function getCustomFields()
{
$fields = array($this->_classMetadata->getInheritanceOption('discriminatorColumn'));
if ($this->_classMetadata->getSubclasses()) {
foreach ($this->_classMetadata->getSubclasses() as $subClass) {
$fields = array_merge($this->_conn->getMetadata($subClass)->getFieldNames(), $fields);
$classMetadata = $this->_mapper->getClassMetadata();
$conn = $this->_mapper->getConnection();
$fields = array($classMetadata->getInheritanceOption('discriminatorColumn'));
if ($classMetadata->getSubclasses()) {
foreach ($classMetadata->getSubclasses() as $subClass) {
$fields = array_merge($conn->getMetadata($subClass)->getFieldNames(), $fields);
}
}
@ -177,7 +183,7 @@ class Doctrine_Mapper_Joined extends Doctrine_Mapper_Abstract
return $this->_fieldNames;
}
$fieldNames = $this->_classMetadata->getFieldNames();
$fieldNames = $this->_mapper->getClassMetadata()->getFieldNames();
$this->_fieldNames = array_unique($fieldNames);
return $fieldNames;
@ -192,21 +198,24 @@ class Doctrine_Mapper_Joined extends Doctrine_Mapper_Abstract
return $this->_columnNameFieldNameMap[$columnName];
}
if ($this->_classMetadata->hasColumn($columnName)) {
$this->_columnNameFieldNameMap[$columnName] = $this->_classMetadata->getFieldName($columnName);
$classMetadata = $this->_mapper->getClassMetadata();
$conn = $this->_mapper->getConnection();
if ($classMetadata->hasColumn($columnName)) {
$this->_columnNameFieldNameMap[$columnName] = $classMetadata->getFieldName($columnName);
return $this->_columnNameFieldNameMap[$columnName];
}
foreach ($this->_classMetadata->getParentClasses() as $parentClass) {
$parentTable = $this->_conn->getMetadata($parentClass);
foreach ($classMetadata->getParentClasses() as $parentClass) {
$parentTable = $conn->getClassMetadata($parentClass);
if ($parentTable->hasColumn($columnName)) {
$this->_columnNameFieldNameMap[$columnName] = $parentTable->getFieldName($columnName);
return $this->_columnNameFieldNameMap[$columnName];
}
}
foreach ((array)$this->_classMetadata->getSubclasses() as $subClass) {
$subTable = $this->_conn->getMetadata($subClass);
foreach ((array)$classMetadata->getSubclasses() as $subClass) {
$subTable = $conn->getClassMetadata($subClass);
if ($subTable->hasColumn($columnName)) {
$this->_columnNameFieldNameMap[$columnName] = $subTable->getFieldName($columnName);
return $this->_columnNameFieldNameMap[$columnName];
@ -221,20 +230,22 @@ class Doctrine_Mapper_Joined extends Doctrine_Mapper_Abstract
* @todo Looks like this better belongs into the ClassMetadata class.
*/
public function getOwningTable($fieldName)
{
if ($this->_classMetadata->hasField($fieldName) && ! $this->_classMetadata->isInheritedField($fieldName)) {
return $this->_classMetadata;
{
$conn = $this->_mapper->getConnection();
$classMetadata = $this->_mapper->getClassMetadata();
if ($classMetadata->hasField($fieldName) && ! $classMetadata->isInheritedField($fieldName)) {
return $classMetadata;
}
foreach ($this->_classMetadata->getParentClasses() as $parentClass) {
$parentTable = $this->_conn->getMetadata($parentClass);
foreach ($classMetadata->getParentClasses() as $parentClass) {
$parentTable = $conn->getClassMetadata($parentClass);
if ($parentTable->hasField($fieldName) && ! $parentTable->isInheritedField($fieldName)) {
return $parentTable;
}
}
foreach ((array)$this->_classMetadata->getSubclasses() as $subClass) {
$subTable = $this->_conn->getMetadata($subClass);
foreach ((array)$classMetadata->getSubclasses() as $subClass) {
$subTable = $conn->getClassMetadata($subClass);
if ($subTable->hasField($fieldName) && ! $subTable->isInheritedField($fieldName)) {
return $subTable;
}
@ -248,24 +259,25 @@ class Doctrine_Mapper_Joined extends Doctrine_Mapper_Abstract
* are grouped by the class names they belong to.
*
*/
protected function _formatDataSet(Doctrine_Record $record)
protected function _groupFieldsByDefiningClass(Doctrine_Record $record)
{
$table = $this->_classMetadata;
$conn = $this->_mapper->getConnection();
$classMetadata = $this->_mapper->getClassMetadata();
$dataSet = array();
$component = $table->getClassName();
$component = $classMetadata->getClassName();
$array = $record->getPrepared();
$classes = array_merge(array($component), $this->_classMetadata->getParentClasses());
$classes = array_merge(array($component), $classMetadata->getParentClasses());
foreach ($classes as $class) {
$dataSet[$class] = array();
$metadata = $this->_conn->getMetadata($class);
foreach ($metadata->getColumns() as $columnName => $definition) {
$parentClassMetadata = $conn->getClassMetadata($class);
foreach ($parentClassMetadata->getColumns() as $columnName => $definition) {
if ((isset($definition['primary']) && $definition['primary'] === true) ||
(isset($definition['inherited']) && $definition['inherited'] === true)) {
continue;
}
$fieldName = $table->getFieldName($columnName);
$fieldName = $classMetadata->getFieldName($columnName);
if ( ! array_key_exists($fieldName, $array)) {
continue;
}

View File

@ -1,57 +0,0 @@
<?php
class Doctrine_Mapper_SingleTable extends Doctrine_Mapper_Abstract
{
/*public function addToWhere($componentAlias, array &$sqlWhereParts, Doctrine_Query $query)
{
$array = array();
$componentParts = $query->getQueryComponent($componentAlias);
$sqlTableAlias = $query->getSqlTableAlias($componentAlias);
$array[$sqlTableAlias][] = $this->getDiscriminatorColumn();
// apply inheritance maps
$str = '';
$c = array();
$index = 0;
foreach ($array as $tableAlias => $maps) {
$a = array();
// don't use table aliases if the query isn't a select query
if ($query->getType() !== Doctrine_Query::SELECT) {
$tableAlias = '';
} else {
$tableAlias .= '.';
}
foreach ($maps as $map) {
$b = array();
foreach ($map as $field => $value) {
$identifier = $this->_conn->quoteIdentifier($tableAlias . $field);
if ($index > 0) {
$b[] = '(' . $identifier . ' = ' . $this->_conn->quote($value)
. ' OR ' . $identifier . ' IS NULL)';
} else {
$b[] = $identifier . ' = ' . $this->_conn->quote($value);
}
}
if ( ! empty($b)) {
$a[] = implode(' AND ', $b);
}
}
if ( ! empty($a)) {
$c[] = implode(' AND ', $a);
}
$index++;
}
$str .= implode(' AND ', $c);
return $str;
}*/
}

View File

@ -0,0 +1,105 @@
<?php
abstract class Doctrine_Mapper_Strategy
{
protected $_mapper;
/**
* The names of all the fields that are available on entities created by this mapper.
*/
protected $_fieldNames = array();
public function __construct(Doctrine_Mapper $mapper)
{
$this->_mapper = $mapper;
}
/**
* Assumes that the keys of the given field array are field names and converts
* them to column names.
*
* @return array
*/
protected function _convertFieldToColumnNames(array $fields, Doctrine_ClassMetadata $class)
{
$converted = array();
foreach ($fields as $fieldName => $value) {
$converted[$class->getColumnName($fieldName)] = $value;
}
return $converted;
}
/**
* Callback that is invoked during the SQL construction process.
*/
public function getCustomJoins()
{
return array();
}
/**
* Callback that is invoked during the SQL construction process.
*/
public function getCustomFields()
{
return array();
}
public function getFieldName($columnName)
{
return $this->_mapper->getClassMetadata()->getFieldName($columnName);
}
public function getFieldNames()
{
if ($this->_fieldNames) {
return $this->_fieldNames;
}
$this->_fieldNames = $this->_mapper->getClassMetadata()->getFieldNames();
return $this->_fieldNames;
}
public function getOwningTable($fieldName)
{
return $this->_mapper->getClassMetadata();
}
abstract public function doDelete(Doctrine_Record $record);
abstract public function doInsert(Doctrine_Record $record);
abstract public function doUpdate(Doctrine_Record $record);
/**
* Inserts a row into a table.
*
* @todo This method could be used to allow mapping to secondary table(s).
* @see http://www.oracle.com/technology/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html#SecondaryTable
*/
protected function _insertRow($tableName, array $data)
{
$this->_mapper->getConnection()->insert($tableName, $data);
}
/**
* Deletes rows of a table.
*
* @todo This method could be used to allow mapping to secondary table(s).
* @see http://www.oracle.com/technology/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html#SecondaryTable
*/
protected function _deleteRow($tableName, array $identifierToMatch)
{
$this->_mapper->getConnection()->delete($tableName, $identifierToMatch);
}
/**
* Deletes rows of a table.
*
* @todo This method could be used to allow mapping to secondary table(s).
* @see http://www.oracle.com/technology/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html#SecondaryTable
*/
protected function _updateRow($tableName, array $data, array $identifierToMatch)
{
$this->_mapper->getConnection()->update($tableName, $data, $identifierToMatch);
}
}

View File

@ -1,8 +0,0 @@
<?php
class Doctrine_Mapper_TablePerClass extends Doctrine_Mapper_Abstract
{
}

View File

@ -562,7 +562,7 @@ abstract class Doctrine_Query_Abstract
$array = array();
foreach ($this->_queryComponents as $componentAlias => $data) {
$sqlTableAlias = $this->getSqlTableAlias($componentAlias);
if ( ! $data['mapper'] instanceof Doctrine_Mapper_SingleTable) {
if ($data['table']->getInheritanceType() != Doctrine::INHERITANCETYPE_SINGLE_TABLE) {
$array[$sqlTableAlias][] = array();
} else {
$discCol = $data['table']->getInheritanceOption('discriminatorColumn');

View File

@ -56,6 +56,11 @@ class Doctrine_Query_Registry
$query = $this->_queries[$namespace][$key];
} else {
if ( ! isset($this->_queries[$key])) {
try {
throw new Exception();
} catch (Exception $e) {
echo $e->getTraceAsString() ."<br /><br />";
}
throw new Doctrine_Query_Registry_Exception('A query with the name ' . $key . ' does not exist.');
}
$query = $this->_queries[$key];

View File

@ -31,6 +31,8 @@ Doctrine::autoload('Doctrine_Record_Abstract');
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision$
* @todo Remove the depdency on the ClassMetadata. All operations that involve the metadata
* should be left to the mapper.
*/
abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Countable, IteratorAggregate, Serializable
{
@ -169,14 +171,14 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count
*/
public function __construct($mapper = null, $isNewEntry = false, array $data = array())
{
if (isset($mapper) && $mapper instanceof Doctrine_Mapper_Abstract) {
if (isset($mapper) && $mapper instanceof Doctrine_Mapper) {
$class = get_class($this);
$this->_mapper = Doctrine_Manager::getInstance()->getMapper($class);
$this->_table = $this->_mapper->getTable();
$this->_table = $this->_mapper->getClassMetadata();
$exists = ! $isNewEntry;
} else {
$this->_mapper = Doctrine_Manager::getInstance()->getMapper(get_class($this));
$this->_table = $this->_mapper->getTable();
$this->_table = $this->_mapper->getClassMetadata();
$exists = false;
}
@ -193,7 +195,7 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count
$this->_values = $this->cleanData($this->_data);
$this->prepareIdentifiers($exists);
$this->_extractIdentifier($exists);
if ( ! $exists) {
if ($count > count($this->_values)) {
@ -212,7 +214,6 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count
}
}
$this->_errorStack = new Doctrine_Validator_ErrorStack(get_class($this));
$repository = $this->_mapper->getRepository();
$repository->add($this);
@ -270,8 +271,9 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count
if ( ! $this->_mapper->getAttribute(Doctrine::ATTR_VALIDATE)) {
return true;
}
// Clear the stack from any previous errors.
$this->_errorStack->clear();
$this->getErrorStack()->clear();
// Run validation process
$validator = new Doctrine_Validator();
@ -283,7 +285,7 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count
$this->validateOnUpdate();
}
return $this->_errorStack->count() == 0 ? true : false;
return $this->getErrorStack()->count() == 0 ? true : false;
}
/**
@ -405,6 +407,9 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count
*/
public function getErrorStack()
{
if (is_null($this->_errorStack)) {
$this->_errorStack = new Doctrine_Validator_ErrorStack();
}
return $this->_errorStack;
}
@ -423,7 +428,7 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count
}
$this->_errorStack = $stack;
} else {
return $this->_errorStack;
return $this->getErrorStack();
}
}
@ -496,7 +501,7 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count
{
$this->_values = array_merge($this->_values, $this->cleanData($data));
$this->_data = array_merge($this->_data, $data);
$this->prepareIdentifiers(true);
$this->_extractIdentifier(true);
}
/**
@ -507,7 +512,7 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count
* @return void
* @todo Maybe better placed in the Mapper?
*/
private function prepareIdentifiers($exists = true)
private function _extractIdentifier($exists = true)
{
switch ($this->_table->getIdentifierType()) {
case Doctrine::IDENTIFIER_AUTOINC:
@ -637,7 +642,7 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count
$this->_mapper->getRepository()->add($this);
$this->cleanData($this->_data);
$this->prepareIdentifiers($this->exists());
$this->_extractIdentifier($this->exists());
$this->postUnserialize($event);
}
@ -730,7 +735,7 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count
$this->_modified = array();
$this->prepareIdentifiers();
$this->_extractIdentifier();
$this->_state = Doctrine_Record::STATE_CLEAN;
@ -1485,7 +1490,7 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count
$this->_state = Doctrine_Record::STATE_TCLEAN;
$this->_modified = array();
} else if ($id === true) {
$this->prepareIdentifiers(true);
$this->_extractIdentifier(true);
$this->_state = Doctrine_Record::STATE_CLEAN;
$this->_modified = array();
} else {

View File

@ -5,6 +5,7 @@
*
* @todo Support different drivers for loading the meta data from different sources.
* @package Doctrine
* @deprecated
*/
class Doctrine_Table_Factory
{

View File

@ -51,7 +51,7 @@ class Doctrine_Table_Repository implements Countable, IteratorAggregate
*
* @param Doctrine_Table $table
*/
public function __construct(Doctrine_Mapper_Abstract $mapper)
public function __construct($mapper)
{
$this->table = $mapper;
}

View File

@ -54,14 +54,14 @@ class Doctrine_Query_Registry_TestCase extends Doctrine_UnitTestCase
{
$registry = new Doctrine_Query_Registry();
$registry->add('User/all', 'SELECT u.* FROM User u');
$registry->add('User.all', 'SELECT u.* FROM User u');
$this->assertEqual($registry->get('all', 'User')->getDql(), 'SELECT u.* FROM User u');
$this->assertEqual($registry->get('User.all')->getDql(), 'SELECT u.* FROM User u');
$this->manager->setQueryRegistry($registry);
$user = new User();
$user->getMapper()->execute('all');
$user->getMapper()->executeNamedQuery('User.all');
}
}

View File

@ -391,15 +391,12 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
$this->assertEqual($user->name, "Jack Daniels");
$this->assertEqual($user->created, null);
$this->assertEqual($user->updated, null);
$this->assertEqual($user->getMapper()->getData(), array());
}
public function testNewOperator()
{
$table = $this->connection->getClassMetadata("User");
$this->assertEqual($this->connection->getMapper("User")->getData(), array());
$user = new User();
$this->assertEqual(Doctrine_Lib::getRecordStateAsString($user->state()), Doctrine_Lib::getRecordStateAsString(Doctrine_Record::STATE_TCLEAN));
$user->name = "John Locke";

View File

@ -78,6 +78,7 @@ class Doctrine_Relation_ManyToMany2_TestCase extends Doctrine_UnitTestCase
->from('TestMovie d, d.MovieBookmarks i, i.UserVotes u, u.User c')
->execute()
->getFirst();
$newdata['MovieBookmarks'][0]['UserVotes'][0]['User']['name'] = 'user2';
try {
$newdata->save();

View File

@ -137,11 +137,6 @@ class Doctrine_Table_TestCase extends Doctrine_UnitTestCase
$this->assertTrue($this->objTable->getConnection() instanceof Doctrine_Connection);
}
public function testGetData()
{
$this->assertTrue($this->objTable->getData() == array());
}
public function testSetSequenceName()
{
$this->objTable->sequenceName = 'test-seq';

View File

@ -1,5 +1,5 @@
<?php
class PluginSymfonyRecordTable extends Doctrine_Mapper_TablePerClass
class PluginSymfonyRecordTable extends Doctrine_Mapper
{
}