Commit 3cd7b954 authored by romanb's avatar romanb

Refactorings. Merged hydrator fixes from 0.11/1.0

parent 4d752746
......@@ -24,9 +24,8 @@
/**
* A <tt>ClassMetadata</tt> instance holds all the information (metadata) of an entity and
* it's associations and how they're mapped to the relational database.
* It is the backbone of Doctrine's metadata mapping.
*
* @package Doctrine
* @subpackage ClassMetadata
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
*/
......@@ -115,8 +114,8 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
protected $_generators = array();
/**
* The mapped columns and their mapping definitions.
* Keys are column names and values are mapping definitions.
* The field mappings of the class.
* Keys are field names and values are mapping definitions.
*
* The mapping definition array has at least the following values:
*
......@@ -128,9 +127,9 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
* -- values enum values
* ... many more
*
* @var array $columns
*/
protected $_mappedColumns = array();
* @var array
*/
protected $_fieldMappings = array();
/**
* The mapped embedded values (value objects).
......@@ -282,7 +281,29 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
* @var array $_invokedMethods method invoker cache
*/
protected $_invokedMethods = array();
/**
* The cached lifecycle listeners. There is only one instance of each
* listener class at any time.
*
* @var array
*/
protected $_lifecycleListenerInstances = array();
/**
* The registered lifecycle callbacks for Entities of this class.
*
* @var array
*/
protected $_lifecycleCallbacks = array();
/**
* The registered lifecycle listeners for Entities of this class.
*
* @var array
*/
protected $_lifecycleListeners = array();
/**
* Constructs a new ClassMetadata instance.
......@@ -374,7 +395,7 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
*/
public function isUniqueField($fieldName)
{
$mapping = $this->getColumnMapping($fieldName);
$mapping = $this->getFieldMapping($fieldName);
if ($mapping !== false) {
return isset($mapping['unique']) && $mapping['unique'] == true;
......@@ -391,7 +412,7 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
*/
public function isNotNull($fieldName)
{
$mapping = $this->getColumnMapping($fieldName);
$mapping = $this->getFieldMapping($fieldName);
if ($mapping !== false) {
return isset($mapping['notnull']) && $mapping['notnull'] == true;
......@@ -531,7 +552,7 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
public function getColumnName($fieldName)
{
return isset($this->_columnNames[$fieldName]) ?
$this->_columnNames[$fieldName] : $fieldName;
$this->_columnNames[$fieldName] : $fieldName;
}
/**
......@@ -542,10 +563,10 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
return $this->getColumnMapping($columnName);
}
public function getColumnMapping($columnName)
public function getFieldMapping($fieldName)
{
return isset($this->_mappedColumns[$columnName]) ?
$this->_mappedColumns[$columnName] : false;
return isset($this->_fieldMappings[$fieldName]) ?
$this->_fieldMappings[$fieldName] : false;
}
/**
......@@ -593,6 +614,10 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
* found on this class mapping.
* This lookup on subclasses is costly but happens only *once* for a column
* during hydration because the hydrator caches effectively.
*
* @return string The field name.
* @throws Doctrine::ORM::Exceptions::ClassMetadataException if the field name could
* not be found.
*/
public function lookupFieldName($lcColumnName)
{
......@@ -626,7 +651,7 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
}
/**
* Maps a column of the class' database table to a field of the entity.
* Maps a field of the class to a database column.
*
* @param string $name The name of the column to map. Syntax: columnName [as propertyName].
* The property name is optional. If not used the column will be
......@@ -639,7 +664,7 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
*
* @throws Doctrine_ClassMetadata_Exception If trying use wrongly typed parameter.
*/
public function mapColumn($name, $type, $length = null, $options = array(), $prepend = false)
public function mapColumn($name, $type, $length = null, $options = array())
{
// converts 0 => 'primary' to 'primary' => true etc.
foreach ($options as $k => $option) {
......@@ -661,18 +686,14 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
$columnName = $parts[0];
$lcColumnName = strtolower($parts[0]);
if (isset($this->_mappedColumns[$columnName])) {
if (isset($this->_fieldMappings[$fieldName])) {
return;
}
// Fill column name <-> field name lookup maps
if ($prepend) {
$this->_columnNames = array_merge(array($fieldName => $columnName), $this->_columnNames);
$this->_fieldNames = array_merge(array($columnName => $fieldName), $this->_fieldNames);
} else {
$this->_columnNames[$fieldName] = $columnName;
$this->_fieldNames[$columnName] = $fieldName;
}
$this->_columnNames[$fieldName] = $columnName;
$this->_fieldNames[$columnName] = $fieldName;
$this->_lcColumnToFieldNames[$lcColumnName] = $fieldName;
$this->_lcColumnToFieldNames[$lcColumnName] = $fieldName;
......@@ -701,11 +722,7 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
$options['immutable'] = false;
}*/
if ($prepend) {
$this->_mappedColumns = array_merge(array($columnName => $options), $this->_mappedColumns);
} else {
$this->_mappedColumns[$columnName] = $options;
}
$this->_fieldMappings[$fieldName] = $options;
$this->_columnCount++;
}
......@@ -753,24 +770,6 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
//...
}
/**
* setColumn
*
* @param string $name
* @param string $type
* @param integer $length
* @param mixed $options
* @param boolean $prepend Whether to prepend or append the new column to the column list.
* By default the column gets appended.
* @throws Doctrine_Table_Exception if trying use wrongly typed parameter
* @return void
* @deprecated Use mapColumn()
*/
public function setColumn($name, $type, $length = null, $options = array(), $prepend = false)
{
return $this->mapColumn($name, $type, $length, $options, $prepend);
}
/**
* Gets the names of all validators that are applied on a field.
*
......@@ -779,9 +778,8 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
*/
public function getFieldValidators($fieldName)
{
$columnName = $this->getColumnName($fieldName);
return isset($this->_mappedColumns[$columnName]['validators']) ?
$this->_mappedColumns[$columnName]['validators'] : array();
return isset($this->_fieldMappings[$fieldName]['validators']) ?
$this->_fieldMappings[$fieldName]['validators'] : array();
}
/**
......@@ -803,12 +801,11 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
*/
public function getDefaultValueOf($fieldName)
{
$columnName = $this->getColumnName($fieldName);
if ( ! isset($this->_mappedColumns[$columnName])) {
throw new Doctrine_Table_Exception("Couldn't get default value. Column ".$columnName." doesn't exist.");
if ( ! isset($this->_fieldMappings[$fieldName])) {
throw new Doctrine_Table_Exception("Couldn't get default value. Column ".$fieldName." doesn't exist.");
}
if (isset($this->_mappedColumns[$columnName]['default'])) {
return $this->_mappedColumns[$columnName]['default'];
if (isset($this->_fieldMappings[$fieldName]['default'])) {
return $this->_fieldMappings[$fieldName]['default'];
} else {
return null;
}
......@@ -867,12 +864,12 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
*/
public function hasColumn($columnName)
{
return isset($this->_mappedColumns[$columnName]);
return isset($this->_fieldNames[$columnName]);
}
public function hasMappedColumn($columnName)
{
return isset($this->_mappedColumns[$columnName]);
return isset($this->_fieldNames[$columnName]);
}
/**
......@@ -890,9 +887,8 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
*/
public function getEnumValues($fieldName)
{
$columnName = $this->getColumnName($fieldName);
if (isset($this->_mappedColumns[$columnName]['values'])) {
return $this->_mappedColumns[$columnName]['values'];
if (isset($this->_fieldMappings[$fieldName]['values'])) {
return $this->_fieldMappings[$fieldName]['values'];
} else {
return array();
}
......@@ -917,8 +913,8 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
$columnName = $this->getColumnName($fieldName);
if ( ! $this->_em->getAttribute(Doctrine::ATTR_USE_NATIVE_ENUM) &&
isset($this->_mappedColumns[$columnName]['values'][$index])) {
$enumValue = $this->_mappedColumns[$columnName]['values'][$index];
isset($this->_fieldMappings[$fieldName]['values'][$index])) {
$enumValue = $this->_fieldMappings[$fieldName]['values'][$index];
} else {
$enumValue = $index;
}
......@@ -973,9 +969,8 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
*/
public function getCustomAccessor($fieldName)
{
$columnName = $this->getColumnName($fieldName);
return isset($this->_mappedColumns[$columnName]['accessor']) ?
$this->_mappedColumns[$columnName]['accessor'] : null;
return isset($this->_fieldMappings[$fieldName]['accessor']) ?
$this->_fieldMappings[$fieldName]['accessor'] : null;
}
/**
......@@ -985,9 +980,8 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
*/
public function getCustomMutator($fieldName)
{
$columnName = $this->getColumnName($fieldName);
return isset($this->_mappedColumns[$columnName]['mutator']) ?
$this->_mappedColumns[$columnName]['mutator'] : null;
return isset($this->_fieldMappings[$fieldName]['mutator']) ?
$this->_fieldMappings[$fieldName]['mutator'] : null;
}
/**
......@@ -998,7 +992,7 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
*/
public function getColumns()
{
return $this->_mappedColumns;
return $this->_fieldMappings;
}
/**
......@@ -1008,7 +1002,12 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
*/
public function getMappedColumns()
{
return $this->_mappedColumns;
return $this->_fieldMappings;
}
public function getFieldMappings()
{
return $this->_fieldMappings;
}
/**
......@@ -1023,8 +1022,8 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
unset($this->_fieldNames[$columnName]);
if (isset($this->_mappedColumns[$columnName])) {
unset($this->_mappedColumns[$columnName]);
if (isset($this->_fieldMappings[$fieldName])) {
unset($this->_fieldMappings[$fieldName]);
return true;
}
$this->_columnCount--;
......@@ -1040,7 +1039,7 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
public function getColumnNames(array $fieldNames = null)
{
if ($fieldNames === null) {
return array_keys($this->_mappedColumns);
return array_keys($this->_fieldNames);
} else {
$columnNames = array();
foreach ($fieldNames as $fieldName) {
......@@ -1092,8 +1091,7 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
*/
public function getMappingForField($fieldName)
{
$columnName = $this->getColumnName($fieldName);
return $this->getColumnDefinition($columnName);
return $this->_fieldMappings[$fieldName];
}
/**
......@@ -1104,6 +1102,7 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
*/
public function getTypeOf($fieldName)
{
return $this->getTypeOfColumn($this->getColumnName($fieldName));
}
......@@ -1115,7 +1114,8 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
*/
public function getTypeOfField($fieldName)
{
return $this->getTypeOfColumn($this->getColumnName($fieldName));
return isset($this->_fieldMappings[$fieldName]) ?
$this->_fieldMappings[$fieldName]['type'] : false;
}
/**
......@@ -1125,7 +1125,7 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
*/
public function getTypeOfColumn($columnName)
{
return isset($this->_mappedColumns[$columnName]) ? $this->_mappedColumns[$columnName]['type'] : false;
return $this->getTypeOfField($this->getFieldName($columnName));
}
/**
......@@ -1133,7 +1133,7 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
*/
public function getFieldLength($fieldName)
{
return $this->_mappedColumns[$this->getColumnName($fieldName)]['length'];
return $this->_fieldMappings[$fieldName]['length'];
}
/**
......@@ -1502,7 +1502,7 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
// Collect foreign keys from the relations
$options['foreignKeys'] = array();
if ($parseForeignKeys && $this->getAttribute(Doctrine::ATTR_EXPORT)
& Doctrine::EXPORT_CONSTRAINTS) {
& Doctrine::EXPORT_CONSTRAINTS) {
$constraints = array();
$emptyIntegrity = array('onUpdate' => null, 'onDelete' => null);
foreach ($this->getRelations() as $name => $relation) {
......@@ -1683,7 +1683,7 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
*/
public function isInheritedField($fieldName)
{
return isset($this->_mappedColumns[$this->getColumnName($fieldName)]['inherited']);
return isset($this->_fieldMappings[$fieldName]['inherited']);
}
/**
......@@ -1912,6 +1912,86 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
{
}
/**
* Dispatches the lifecycle event of the given Entity to the registered
* lifecycle callbacks and lifecycle listeners.
*
* @param string $event The lifecycle event.
* @param Entity $entity The Entity on which the event occured.
*/
public function invokeLifecycleCallbacks($lifecycleEvent, Doctrine_Entity $entity)
{
foreach ($this->getLifecycleCallbacks($lifecycleEvent) as $callback) {
$entity->$callback();
}
foreach ($this->getLifecycleListeners($lifecycleEvent) as $className => $callback) {
if ( ! isset($this->_lifecycleListenerInstances[$className])) {
$this->_lifecycleListenerInstances[$className] = new $className;
}
$this->_lifecycleListenerInstances[$className]->$callback($entity);
}
}
/**
* Gets the registered lifecycle callbacks for an event.
*
* @param string $event
* @return array
*/
public function getLifecycleCallbacks($event)
{
return isset($this->_lifecycleCallbacks[$event]) ?
$this->_lifecycleCallbacks[$event] : array();
}
/**
* Gets the registered lifecycle listeners for an event.
*
* @param string $event
* @return array
*/
public function getLifecycleListeners($event)
{
return isset($this->_lifecycleListeners[$event]) ?
$this->_lifecycleListeners[$event] : array();
}
/**
* Adds a lifecycle listener for Entities this class.
*
* Note: If the same listener class is registered more than once, the old
* one will be overridden.
*
* @param string $listenerClass
* @param array $callbacks
*/
public function addLifecycleListener($listenerClass, array $callbacks)
{
$this->_lifecycleListeners[$event][$listenerClass] = array();
foreach ($callbacks as $method => $event) {
$this->_lifecycleListeners[$event][$listenerClass][] = $method;
}
}
/**
* Adds a lifecycle callback for Entities of this class.
*
* Note: If a the same callback is registered more than once, the old one
* will be overridden.
*
* @param string $callback
* @param string $event
*/
public function addLifecycleCallback($callback, $event)
{
if ( ! isset($this->_lifecycleCallbacks[$event])) {
$this->_lifecycleCallbacks[$event] = array();
}
if ( ! in_array($callback, $this->_lifecycleCallbacks[$event])) {
$this->_lifecycleCallbacks[$event][$callback] = $callback;
}
}
/**
* @todo Implementation. Immutable entities can not be updated or deleted once
......
......@@ -34,12 +34,19 @@
*/
class Doctrine_ClassMetadata_CodeDriver
{
/**
* Name of the callback method.
*
* @todo We could make the name of the callback methods customizable for users.
*/
const CALLBACK_METHOD = 'initMetadata';
/**
* Loads the metadata for the specified class into the provided container.
*/
public function loadMetadataForClass($className, Doctrine_ClassMetadata $metadata)
{
if ( ! method_exists($className, 'initMetadata')) {
if ( ! method_exists($className, self::CALLBACK_METHOD)) {
throw new Doctrine_ClassMetadata_Exception("Unable to load metadata for class"
. " '$className'. Callback method 'initMetadata' not found.");
}
......
......@@ -133,7 +133,10 @@ class Doctrine_ClassMetadata_Factory
foreach ($parentClass->getColumns() as $name => $definition) {
$fullName = "$name as " . $parentClass->getFieldName($name);
$definition['inherited'] = true;
$subClass->mapColumn($fullName, $definition['type'], $definition['length'],
$subClass->mapColumn(
$fullName,
$definition['type'],
$definition['length'],
$definition);
}
}
......@@ -154,11 +157,6 @@ class Doctrine_ClassMetadata_Factory
protected function _loadMetadata(Doctrine_ClassMetadata $class, $name)
{
if ( ! class_exists($name) || empty($name)) {
/*try {
throw new Exception();
} catch (Exception $e) {
echo $e->getTraceAsString();
}*/
throw new Doctrine_Exception("Couldn't find class " . $name . ".");
}
......@@ -175,11 +173,6 @@ 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'.");
}
......@@ -207,10 +200,11 @@ class Doctrine_ClassMetadata_Factory
protected function _initIdentifier(Doctrine_ClassMetadata $class)
{
switch (count((array)$class->getIdentifier())) {
case 0:
case 0: // No identifier in the class mapping yet
// If its a subclass, inherit the identifier from the parent.
if ($class->getInheritanceType() == Doctrine::INHERITANCE_TYPE_JOINED &&
count($class->getParentClasses()) > 0) {
count($class->getParentClasses()) > 0) {
$parents = $class->getParentClasses();
$root = end($parents);
$rootClass = $class->getConnection()->getMetadata($root);
......@@ -237,17 +231,20 @@ class Doctrine_ClassMetadata_Factory
$definition, true);
}
} else {
throw Doctrine_MappingException::identifierRequired($class->getClassName());
/* Legacy behavior of auto-adding an id field
$definition = array('type' => 'integer',
'length' => 20,
'autoincrement' => true,
'primary' => true);
$class->setColumn('id', $definition['type'], $definition['length'], $definition, true);
$class->mapColumn('id', $definition['type'], $definition['length'], $definition, true);
$class->setIdentifier(array('id'));
$class->setIdentifierType(Doctrine::IDENTIFIER_AUTOINC);
*/
}
break;
case 1:
foreach ((array)$class->getIdentifier() as $pk) {
case 1: // A single identifier is in the mapping
foreach ($class->getIdentifier() as $pk) {
$columnName = $class->getColumnName($pk);
$thisColumns = $class->getColumns();
$e = $thisColumns[$columnName];
......@@ -294,7 +291,7 @@ class Doctrine_ClassMetadata_Factory
$class->setIdentifier(array($pk));
break;
default:
default: // Multiple identifiers are in the mapping so its a composite id
$class->setIdentifierType(Doctrine::IDENTIFIER_COMPOSITE);
}
}
......
......@@ -83,7 +83,7 @@ class Doctrine_Connection_UnitOfWork
protected $_removedEntities = array();
/**
* The EntityManager the unit of work belongs to.
* The EntityManager the UnitOfWork belongs to.
*/
protected $_em;
......@@ -98,7 +98,7 @@ class Doctrine_Connection_UnitOfWork
/**
* Constructor.
* Created a new UnitOfWork.
* Creates a new UnitOfWork.
*
* @param Doctrine_EntityManager $em
*/
......@@ -110,7 +110,8 @@ class Doctrine_Connection_UnitOfWork
/**
* Commits the unit of work, executing all operations that have been postponed
* up to this point.
*
*
* @todo Impl
*/
public function commit()
{
......@@ -191,7 +192,7 @@ class Doctrine_Connection_UnitOfWork
*/
public function registerRemoved(Doctrine_Entity $entity)
{
if ($entity->isTransient()) {
if ($entity->isNew()) {
return;
}
$this->unregisterIdentity($entity);
......@@ -511,4 +512,229 @@ class Doctrine_Connection_UnitOfWork
return isset($this->_identityMap[$rootClassName][$idHash]);
}
public function save(Doctrine_Entity $entity)
{
switch ($entity->_state()) {
case Doctrine_Entity::STATE_CLEAN:
//nothing to do
// ignore $entity but cascade
break;
case Doctrine_Entity::STATE_DIRTY:
// update
$this->registerDirty($entity);
// todo:cascade
break;
case Doctrine_Entity::STATE_TCLEAN:
case Doctrine_Entity::STATE_TDIRTY:
// insert
// if identifier type IDENTITY:
// cascade
// if no transaction is started yet, do it
// force insert (directly to persister)
// else
// cascade
// get & assign the identifier, then registerNew()
break;
}
}
private function _cascadeSave(Doctrine_Entity $entity)
{
}
private function _cascadeDelete(Doctrine_Entity $entity)
{
}
// Stuff from 0.11/1.0 that we will need later (need to modify it though)
/**
* Collects all records that need to be deleted by applying defined
* application-level delete cascades.
*
* @param array $deletions Map of the records to delete. Keys=Oids Values=Records.
*/
/*private function _collectDeletions(Doctrine_Record $record, array &$deletions)
{
if ( ! $record->exists()) {
return;
}
$deletions[$record->getOid()] = $record;
$this->_cascadeDelete($record, $deletions);
}*/
/**
* Cascades an ongoing delete operation to related objects. Applies only on relations
* that have 'delete' in their cascade options.
* This is an application-level cascade. Related objects that participate in the
* cascade and are not yet loaded are fetched from the database.
* Exception: many-valued relations are always (re-)fetched from the database to
* make sure we have all of them.
*
* @param Doctrine_Record The record for which the delete operation will be cascaded.
* @throws PDOException If something went wrong at database level
* @return void
*/
/*protected function _cascadeDelete(Doctrine_Record $record, array &$deletions)
{
foreach ($record->getTable()->getRelations() as $relation) {
if ($relation->isCascadeDelete()) {
$fieldName = $relation->getAlias();
// if it's a xToOne relation and the related object is already loaded
// we don't need to refresh.
if ( ! ($relation->getType() == Doctrine_Relation::ONE && isset($record->$fieldName))) {
$record->refreshRelated($relation->getAlias());
}
$relatedObjects = $record->get($relation->getAlias());
if ($relatedObjects instanceof Doctrine_Record && $relatedObjects->exists()
&& ! isset($deletions[$relatedObjects->getOid()])) {
$this->_collectDeletions($relatedObjects, $deletions);
} else if ($relatedObjects instanceof Doctrine_Collection && count($relatedObjects) > 0) {
// cascade the delete to the other objects
foreach ($relatedObjects as $object) {
if ( ! isset($deletions[$object->getOid()])) {
$this->_collectDeletions($object, $deletions);
}
}
}
}
}
}*/
/**
* Executes the deletions for all collected records during a delete operation
* (usually triggered through $record->delete()).
*
* @param array $deletions Map of the records to delete. Keys=Oids Values=Records.
*/
/*private function _executeDeletions(array $deletions)
{
// collect class names
$classNames = array();
foreach ($deletions as $record) {
$classNames[] = $record->getTable()->getComponentName();
}
$classNames = array_unique($classNames);
// order deletes
$executionOrder = $this->buildFlushTree($classNames);
// execute
try {
$this->conn->beginInternalTransaction();
for ($i = count($executionOrder) - 1; $i >= 0; $i--) {
$className = $executionOrder[$i];
$table = $this->conn->getTable($className);
// collect identifiers
$identifierMaps = array();
$deletedRecords = array();
foreach ($deletions as $oid => $record) {
if ($record->getTable()->getComponentName() == $className) {
$veto = $this->_preDelete($record);
if ( ! $veto) {
$identifierMaps[] = $record->identifier();
$deletedRecords[] = $record;
unset($deletions[$oid]);
}
}
}
if (count($deletedRecords) < 1) {
continue;
}
// extract query parameters (only the identifier values are of interest)
$params = array();
$columnNames = array();
foreach ($identifierMaps as $idMap) {
while (list($fieldName, $value) = each($idMap)) {
$params[] = $value;
$columnNames[] = $table->getColumnName($fieldName);
}
}
$columnNames = array_unique($columnNames);
// delete
$tableName = $table->getTableName();
$sql = "DELETE FROM " . $this->conn->quoteIdentifier($tableName) . " WHERE ";
if ($table->isIdentifierComposite()) {
$sql .= $this->_buildSqlCompositeKeyCondition($columnNames, count($identifierMaps));
$this->conn->exec($sql, $params);
} else {
$sql .= $this->_buildSqlSingleKeyCondition($columnNames, count($params));
$this->conn->exec($sql, $params);
}
// adjust state, remove from identity map and inform postDelete listeners
foreach ($deletedRecords as $record) {
// currently just for bc!
$this->_deleteCTIParents($table, $record);
//--
$record->state(Doctrine_Record::STATE_TCLEAN);
$record->getTable()->removeRecord($record);
$this->_postDelete($record);
}
}
$this->conn->commit();
// trigger postDelete for records skipped during the deletion (veto!)
foreach ($deletions as $skippedRecord) {
$this->_postDelete($skippedRecord);
}
return true;
} catch (Exception $e) {
$this->conn->rollback();
throw $e;
}
}*/
/**
* Builds the SQL condition to target multiple records who have a single-column
* primary key.
*
* @param Doctrine_Table $table The table from which the records are going to be deleted.
* @param integer $numRecords The number of records that are going to be deleted.
* @return string The SQL condition "pk = ? OR pk = ? OR pk = ? ..."
*/
/*private function _buildSqlSingleKeyCondition($columnNames, $numRecords)
{
$idColumn = $this->conn->quoteIdentifier($columnNames[0]);
return implode(' OR ', array_fill(0, $numRecords, "$idColumn = ?"));
}*/
/**
* Builds the SQL condition to target multiple records who have a composite primary key.
*
* @param Doctrine_Table $table The table from which the records are going to be deleted.
* @param integer $numRecords The number of records that are going to be deleted.
* @return string The SQL condition "(pk1 = ? AND pk2 = ?) OR (pk1 = ? AND pk2 = ?) ..."
*/
/*private function _buildSqlCompositeKeyCondition($columnNames, $numRecords)
{
$singleCondition = "";
foreach ($columnNames as $columnName) {
$columnName = $this->conn->quoteIdentifier($columnName);
if ($singleCondition === "") {
$singleCondition .= "($columnName = ?";
} else {
$singleCondition .= " AND $columnName = ?";
}
}
$singleCondition .= ")";
$fullCondition = implode(' OR ', array_fill(0, $numRecords, $singleCondition));
return $fullCondition;
}*/
}
......@@ -22,8 +22,8 @@
#namespace Doctrine::ORM;
/**
* Doctrine_Entity
* All record classes should inherit this super class.
* Base class for all Entities (objects with persistent state in a RDBMS that are
* managed by Doctrine).
*
* NOTE: Methods that are intended for internal use only but must be public
* are marked INTERNAL: and begin with an underscore "_" to indicate that they
......@@ -37,8 +37,10 @@
* @link www.phpdoctrine.org
* @since 2.0
* @version $Revision: 4342 $
* @todo Split up into "Entity" and "ActiveEntity (extends Entity)"???
* @todo Remove as many methods as possible.
* @todo Split up into "Entity" and "ActiveEntity" (extends Entity)
* @todo Move entity states into a separate enumeration (EntityStates).
* They do not need to be exposed to users in such a way. The states are mainly
* for internal use.
*/
abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
{
......@@ -47,6 +49,7 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
* An Entity is in dirty state when its properties are changed.
*/
const STATE_DIRTY = 1;
const STATE_MANAGED_DIRTY = 1;
/**
* TDIRTY STATE
......@@ -54,6 +57,7 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
* fields are modified but it is NOT yet persisted into database.
*/
const STATE_TDIRTY = 2;
const STATE_NEW_DIRTY = 2;
/**
* CLEAN STATE
......@@ -61,19 +65,17 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
* and none of its properties are changed.
*/
const STATE_CLEAN = 3;
/**
* PROXY STATE
* An Entity is in proxy state when its properties are not fully loaded.
*/
//const STATE_PROXY = 4;
const STATE_MANAGED_CLEAN = 3;
/**
* NEW TCLEAN
* An Entity is in transient clean state when it is created and none of its
* fields are modified.
* @todo Do we need this state? Just STATE_NEW may be enough without differentiating
* clean/dirty. A new entity is always "dirty".
*/
const STATE_TCLEAN = 5;
const STATE_NEW_CLEAN = 5;
/**
* LOCKED STATE
......@@ -81,9 +83,25 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
*
* This state is used internally to ensure that circular deletes
* and saves will not cause infinite loops.
* @todo Not sure this is a good idea. It is a problematic solution because
* it hides the original state while the locked state is active.
*/
const STATE_LOCKED = 6;
/**
* A detached Entity is an instance with a persistent identity that is not
* (or no longer) associated with an EntityManager (and a UnitOfWork).
* This means its no longer in the identity map.
*/
const STATE_DETACHED = 7;
/**
* A removed Entity instance is an instance with a persistent identity,
* associated with an EntityManager, that is scheduled for removal from the
* database.
*/
const STATE_DELETED = 8;
/**
* Index used for creating object identifiers (oid's).
*
......@@ -204,114 +222,16 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
// @todo read from attribute the first time and move this initialization elsewhere.
self::$_useAutoAccessorOverride = true;
}
/**
* _index
*
* @return integer
*/
/*public static function _index()
{
return self::$_index;
}*/
/**
* Returns the object identifier.
*
* @return integer
*/
public function getOid()
final public function getOid()
{
return $this->_oid;
}
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the serializing procedure.
*/
public function preSerialize()
{ }
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the serializing procedure.
*/
public function postSerialize()
{ }
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the serializing procedure.
*/
public function preUnserialize()
{ }
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the serializing procedure.
*/
public function postUnserialize()
{ }
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the saving procedure.
*/
public function preSave()
{ }
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the saving procedure.
*/
public function postSave()
{ }
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the deletion procedure.
*/
public function preDelete()
{ }
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the deletion procedure.
*/
public function postDelete()
{ }
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the saving procedure only when the record is going to be
* updated.
*/
public function preUpdate()
{ }
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the saving procedure only when the record is going to be
* updated.
*/
public function postUpdate()
{ }
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the saving procedure only when the record is going to be
* inserted into the data store the first time.
*/
public function preInsert()
{ }
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the saving procedure only when the record is going to be
* inserted into the data store the first time.
*/
public function postInsert()
{ }
/**
* setDefaultValues
......@@ -345,46 +265,15 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
}*/
/**
* cleanData
* leaves the $data array only with values whose key is a field inside this
* record and returns the values that were removed from $data. Also converts
* any values of 'null' to objects of type Doctrine_Null.
*
* @param array $data data array to be cleaned
* @return array $tmp values cleaned from data
* @todo Remove. Should not be necessary. Slows down instantiation.
*/
/*public function cleanData(&$data)
{
$tmp = $data;
$data = array();
$fieldNames = $this->_em->getEntityPersister($this->_entityName)->getFieldNames();
foreach ($fieldNames as $fieldName) {
if (isset($tmp[$fieldName])) {
$data[$fieldName] = $tmp[$fieldName];
} else if (array_key_exists($fieldName, $tmp)) {
$data[$fieldName] = Doctrine_Null::$INSTANCE;
} else if ( ! isset($this->_data[$fieldName])) {
$data[$fieldName] = Doctrine_Null::$INSTANCE;
}
unset($tmp[$fieldName]);
}
return $tmp;
}*/
/**
* hydrate
* hydrates this object from given array
*
* @param array $data
* @return boolean
*/
public function hydrate(array $data)
final public function hydrate(array $data)
{
$this->_data = array_merge($this->_data, $data);
//$this->_extractIdentifier(true);
$this->_extractIdentifier();
}
/**
......@@ -437,8 +326,8 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
*/
public function serialize()
{
//$event = new Doctrine_Event($this, Doctrine_Event::RECORD_SERIALIZE);
//$this->preSerialize($event);
//$this->_em->getEventManager()->dispatchEvent(Event::preSerialize);
//$this->_class->dispatchLifecycleEvent(Event::preSerialize, $this);
$vars = get_object_vars($this);
......@@ -533,7 +422,7 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
/**
* INTERNAL:
* returns / assigns the state of this record
* Gets or sets the state of this Entity.
*
* @param integer|string $state if set, this method tries to set the record state to $state
* @see Doctrine_Entity::STATE_* constants
......@@ -577,7 +466,7 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
* this record represents does not exist anymore)
* @return boolean
* @todo Implementation to EntityManager.
* @todo ActiveEntity method.
* @todo Move to ActiveEntity (extends Entity).
*/
public function refresh($deep = false)
{
......@@ -674,9 +563,10 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
}*/
/**
* INTERNAL: (Usage from within extending classes is fine)
* INTERNAL: (Usage from within extending classes is intended)
*
* Gets the value of a field (regular field or reference).
* If the property is not yet loaded this method does NOT load it.
* If the field is not yet loaded this method does NOT load it.
*
* NOTE: Use of this method from outside the scope of an extending class
* is strongly discouraged.
......@@ -684,6 +574,7 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
* @param $name name of the property
* @throws Doctrine_Entity_Exception if trying to get an unknown field
* @return mixed
* @todo Rename to _get()
*/
final public function _rawGet($fieldName)
{
......@@ -697,7 +588,8 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
}
/**
* INTERNAL: (Usage from within extending classes is fine)
* INTERNAL: (Usage from within extending classes is intended)
*
* Sets the value of a field (regular field or reference).
* If the field is not yet loaded this method does NOT load it.
*
......@@ -707,6 +599,7 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
* @param $name name of the field
* @throws Doctrine_Entity_Exception if trying to get an unknown field
* @return mixed
* @todo Rename to _set
*/
final public function _rawSet($fieldName, $value)
{
......@@ -805,7 +698,7 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
}
if (isset($this->_references[$name])) {
$this->_references[$name]->setData($value->getData());
return $this;
return;
}
} else {
$relatedTable = $value->getTable();
......@@ -819,12 +712,12 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
if ($rel instanceof Doctrine_Relation_LocalKey) {
$idFieldNames = $value->getTable()->getIdentifier();
if ( ! empty($foreignFieldName) && $foreignFieldName != $idFieldNames[0]) {
$this->set($localFieldName, $value->_rawGet($foreignFieldName), false);
$this->set($localFieldName, $value->_rawGet($foreignFieldName));
} else {
$this->set($localFieldName, $value, false);
$this->set($localFieldName, $value);
}
} else {
$value->set($foreignFieldName, $this, false);
$value->set($foreignFieldName, $this);
}
}
} else if ($rel instanceof Doctrine_Relation_Association) {
......@@ -894,6 +787,13 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
}
}
/**
* Gets the custom mutator method for a field, if it exists.
*
* @param string $fieldName The field name.
* @return mixed The name of the custom mutator or FALSE, if the field does
* not have a custom mutator.
*/
private function _getCustomMutator($fieldName)
{
if ( ! isset(self::$_mutatorCache[$this->_entityName][$fieldName])) {
......@@ -916,6 +816,13 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
return self::$_mutatorCache[$this->_entityName][$fieldName];
}
/**
* Gets the custom accessor method of a field, if it exists.
*
* @param string $fieldName The field name.
* @return mixed The name of the custom accessor method, or FALSE if the
* field does not have a custom accessor.
*/
private function _getCustomAccessor($fieldName)
{
if ( ! isset(self::$_accessorCache[$this->_entityName][$fieldName])) {
......@@ -952,10 +859,6 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
*
* @param mixed $name name of the property or reference
* @param mixed $value value of the property or reference
* @param boolean $load whether or not to refresh / load the uninitialized record data
*
* @throws Doctrine_Record_Exception if trying to set a value for unknown property / related component
* @throws Doctrine_Record_Exception if trying to set a value of wrong type for related component
*/
final public function set($fieldName, $value)
{
......@@ -978,9 +881,9 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
if ($old != $value) {
$this->_data[$fieldName] = $value;
$this->_modified[] = $fieldName;
$this->_modified[$fieldName] = array($old => $value);
if ($this->isTransient() && $this->_class->isIdentifier($fieldName)) {
if ($this->isNew() && $this->_class->isIdentifier($fieldName)) {
$this->_id[$fieldName] = $value;
}
......@@ -1001,7 +904,9 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
}
/**
* contains
* Checks whether a field is set (not null).
*
* NOTE: Invoked by Doctrine::ORM::Access#__isset().
*
* @param string $name
* @return boolean
......@@ -1025,6 +930,10 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
}
/**
* Clears the value of a field.
*
* NOTE: Invoked by Doctrine::ORM::Access#__unset().
*
* @param string $name
* @return void
*/
......@@ -1220,8 +1129,8 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
}
/**
* Merges this record with an array of values
* or with another existing instance of this object
* Merges this Entity with an array of values
* or with another existing instance of.
*
* @param mixed $data Data to merge. Either another instance of this model or an array
* @param bool $deep Bool value for whether or not to merge the data deep
......@@ -1341,41 +1250,17 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
* Checks whether the entity already has a persistent state.
*
* @return boolean TRUE if the object is new, FALSE otherwise.
* @deprecated Use isTransient()
*/
final public function isNew()
{
return $this->_state == self::STATE_TCLEAN || $this->_state == self::STATE_TDIRTY;
}
/**
* Checks whether the entity already has a persistent state.
*
* @return boolean TRUE if the object is new, FALSE otherwise.
*/
final public function isTransient()
{
return $this->_state == self::STATE_TCLEAN || $this->_state == self::STATE_TDIRTY;
}
/**
* Checks whether the entity has been modified since it was last synchronized
* with the database.
*
* @return boolean TRUE if the object has been modified, FALSE otherwise.
*/
final public function isDirty()
{
return ($this->_state === Doctrine_Entity::STATE_DIRTY ||
$this->_state === Doctrine_Entity::STATE_TDIRTY);
}
/**
* Checks whether the entity has been modified since it was last synchronized
* with the database.
*
* @return boolean TRUE if the object has been modified, FALSE otherwise.
* @deprecated Use isDirty()
*/
final public function isModified()
{
......@@ -1512,7 +1397,7 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
* @return boolean
* @todo Better name? hasAssociation() ?
*/
public function hasReference($name)
final public function hasReference($name)
{
return isset($this->_references[$name]);
}
......@@ -1523,7 +1408,7 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
* @param string $name
* @throws Doctrine_Record_Exception if trying to get an unknown related component
*/
public function obtainReference($name)
final public function obtainReference($name)
{
if (isset($this->_references[$name])) {
return $this->_references[$name];
......@@ -1774,6 +1659,8 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
/**
* Gets the ClassMetadata object that describes the entity class.
*
* @return Doctrine::ORM::Mapping::ClassMetadata
*/
final public function getClassMetadata()
{
......@@ -1781,9 +1668,10 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
}
/**
* Enter description here...
* Gets the EntityManager that is responsible for the persistence of
* the Entity.
*
* @return unknown
* @return Doctrine::ORM::EntityManager
*/
final public function getEntityManager()
{
......@@ -1791,9 +1679,9 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
}
/**
* Enter description here...
* Gets the EntityRepository of the Entity.
*
* @return unknown
* @return Doctrine::ORM::EntityRepository
*/
final public function getRepository()
{
......
......@@ -31,10 +31,8 @@
/**
* The EntityManager is a central access point to ORM functionality.
* The EntityManager is the central access point to ORM functionality.
*
* @package Doctrine
* @subpackage EntityManager
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 2.0
......@@ -88,7 +86,6 @@ class Doctrine_EntityManager
/**
* The EntityPersister instances.
* @todo Implementation.
*
* @var array
*/
......@@ -109,7 +106,7 @@ class Doctrine_EntityManager
private $_flushMode = 'commit';
/**
* The unit of work.
* The unit of work used to coordinate object-level transactions.
*
* @var UnitOfWork
*/
......@@ -122,13 +119,6 @@ class Doctrine_EntityManager
*/
private $_eventManager;
/**
* Enter description here...
*
* @var unknown_type
*/
//private $_dataTemplates = array();
/**
* Container that is used temporarily during hydration.
*
......@@ -163,7 +153,7 @@ class Doctrine_EntityManager
}
/**
* Returns the metadata for a class. Alias for getClassMetadata().
* Gets the metadata for a class. Alias for getClassMetadata().
*
* @return Doctrine_Metadata
* @todo package:orm
......@@ -172,6 +162,17 @@ class Doctrine_EntityManager
{
return $this->getClassMetadata($className);
}
/**
* Gets the transaction object used by the EntityManager to manage
* database transactions.
*
* @return Doctrine::DBAL::Transaction
*/
public function getTransaction()
{
return $this->_conn->getTransaction();
}
/**
* Returns the metadata for a class.
......@@ -184,8 +185,8 @@ class Doctrine_EntityManager
}
/**
* Sets the driver that is used to obtain metadata informations about entity
* classes.
* Sets the driver that is used to obtain metadata mapping information
* about Entities.
*
* @param $driver The driver to use.
*/
......@@ -197,7 +198,8 @@ class Doctrine_EntityManager
/**
* Creates a new Doctrine_Query object that operates on this connection.
*
* @return Doctrine_Query
* @param string The DQL string.
* @return Doctrine::ORM::Query
* @todo package:orm
*/
public function createQuery($dql = "")
......@@ -211,10 +213,12 @@ class Doctrine_EntityManager
}
/**
* Enter description here...
* Gets the EntityPersister for an Entity.
*
* This is usually not of interest for users, mainly for internal use.
*
* @param unknown_type $entityName
* @return unknown
* @param string $entityName The name of the Entity.
* @return Doctrine::ORM::Internal::EntityPersister
*/
public function getEntityPersister($entityName)
{
......@@ -241,30 +245,6 @@ class Doctrine_EntityManager
return $this->_unitOfWork->unregisterIdentity($entity);
}
/**
* Returns the current internal transaction nesting level.
*
* @return integer The nesting level. A value of 0 means theres no active transaction.
* @todo package:orm???
*/
public function getInternalTransactionLevel()
{
return $this->transaction->getInternalTransactionLevel();
}
/**
* Initiates a transaction.
*
* This method must only be used by Doctrine itself to initiate transactions.
* Userland-code must use {@link beginTransaction()}.
*
* @todo package:orm???
*/
public function beginInternalTransaction($savepoint = null)
{
return $this->transaction->beginInternalTransaction($savepoint);
}
/**
* Creates a query with the specified name.
*
......@@ -307,16 +287,16 @@ class Doctrine_EntityManager
*/
public function flush()
{
$this->beginInternalTransaction();
$this->_unitOfWork->flush();
$this->commit();
}
/**
* Enter description here...
* Finds an Entity by its identifier.
* This is just a convenient shortcut for getRepository()->find().
*
* @param unknown_type $entityName
* @param unknown_type $identifier
* @param string $entityName
* @param mixed $identifier
* @return Doctrine::ORM::Entity
*/
public function find($entityName, $identifier)
{
......@@ -356,11 +336,8 @@ class Doctrine_EntityManager
{
if ($entityName === null) {
$this->_unitOfWork->detachAll();
foreach ($this->_mappers as $mapper) {
$mapper->clear(); // clear identity map of each mapper
}
} else {
$this->getMapper($entityName)->clear();
//...
}
}
......@@ -370,7 +347,7 @@ class Doctrine_EntityManager
*/
public function close()
{
//Doctrine_EntityManagerFactory::releaseManager($this);
}
/**
......@@ -408,24 +385,7 @@ class Doctrine_EntityManager
*/
public function save(Doctrine_Entity $entity)
{
$state = $entity->_state();
if ($state == Doctrine_Entity::STATE_CLEAN || $state == Doctrine_Entity::STATE_LOCKED) {
return;
}
//...
//$this->_unitOfWork->
switch ($entity->_state()) {
case Doctrine_Entity::STATE_CLEAN:
//nothing to do
break;
case Doctrine_Entity::STATE_DIRTY:
$this->_unitOfWork->registerDirty($entity);
break;
case Doctrine_Entity::STATE_TCLEAN:
case Doctrine_Entity::STATE_TDIRTY:
//...
}
$this->_unitOfWork->save($entity);
}
/**
......@@ -433,14 +393,14 @@ class Doctrine_EntityManager
*/
public function delete(Doctrine_Entity $entity)
{
//...
$this->_unitOfWork->delete($entity);
}
/**
* Gets the repository for the given entity name.
* Gets the repository for an Entity.
*
* @return Doctrine_EntityRepository The repository.
* @todo Implementation.
* @param string $entityName The name of the Entity.
* @return Doctrine::ORM::EntityRepository The repository.
*/
public function getRepository($entityName)
{
......
......@@ -62,21 +62,11 @@ abstract class Doctrine_EntityPersister_Abstract
*/
protected $_em;
/**
* The concrete mapping strategy that is used.
*/
protected $_mappingStrategy;
/**
* Null object.
*/
private $_nullObject;
/**
* A list of registered entity listeners.
*/
private $_entityListeners = array();
/**
* Enter description here...
*
......@@ -318,8 +308,8 @@ abstract class Doctrine_EntityPersister_Abstract
*/
protected function _insertOrUpdate(Doctrine_Entity $record)
{
$record->preSave();
$this->notifyEntityListeners($record, 'preSave', Doctrine_Event::RECORD_SAVE);
//$record->preSave();
//$this->notifyEntityListeners($record, 'preSave', Doctrine_Event::RECORD_SAVE);
switch ($record->_state()) {
case Doctrine_Entity::STATE_TDIRTY:
......@@ -335,8 +325,8 @@ abstract class Doctrine_EntityPersister_Abstract
break;
}
$record->postSave();
$this->notifyEntityListeners($record, 'postSave', Doctrine_Event::RECORD_SAVE);
//$record->postSave();
//$this->notifyEntityListeners($record, 'postSave', Doctrine_Event::RECORD_SAVE);
}
/**
......@@ -351,7 +341,6 @@ abstract class Doctrine_EntityPersister_Abstract
}
/**
* _saveRelated
* saves all related records to $record
*
* @throws PDOException if something went wrong at database level
......
......@@ -20,12 +20,10 @@
*/
/**
* The joined mapping strategy maps a single entity instance to several tables in the
* The joined subclass persister maps a single entity instance to several tables in the
* database as it is defined by <tt>Class Table Inheritance</tt>.
*
* @author Roman Borschel <roman@code-factory.org>
* @package Doctrine
* @subpackage JoinedSubclass
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version $Revision$
* @link www.phpdoctrine.org
......@@ -33,7 +31,7 @@
*/
class Doctrine_EntityPersister_JoinedSubclass extends Doctrine_EntityPersister_Abstract
{
protected $_columnNameFieldNameMap = array();
//protected $_columnNameFieldNameMap = array();
/**
* Inserts an entity that is part of a Class Table Inheritance hierarchy.
......@@ -94,7 +92,6 @@ class Doctrine_EntityPersister_JoinedSubclass extends Doctrine_EntityPersister_A
*
* @param Doctrine_Entity $record record to be updated
* @return boolean whether or not the update was successful
* @todo Move to Doctrine_Table (which will become Doctrine_Mapper).
*/
protected function _doUpdate(Doctrine_Entity $record)
{
......@@ -223,34 +220,6 @@ class Doctrine_EntityPersister_JoinedSubclass extends Doctrine_EntityPersister_A
return $fieldNames;
}
/**
*
*/
/*public function getFieldName($columnName)
{
if (isset($this->_columnNameFieldNameMap[$columnName])) {
return $this->_columnNameFieldNameMap[$columnName];
}
$classMetadata = $this->_classMetadata;
$conn = $this->_conn;
if ($classMetadata->hasColumn($columnName)) {
$this->_columnNameFieldNameMap[$columnName] = $classMetadata->getFieldName($columnName);
return $this->_columnNameFieldNameMap[$columnName];
}
foreach ($classMetadata->getSubclasses() as $subClass) {
$subTable = $conn->getClassMetadata($subClass);
if ($subTable->hasColumn($columnName)) {
$this->_columnNameFieldNameMap[$columnName] = $subTable->getFieldName($columnName);
return $this->_columnNameFieldNameMap[$columnName];
}
}
throw new Doctrine_Mapper_Exception("No field name found for column name '$columnName'.");
}*/
/**
*
* @todo Looks like this better belongs into the ClassMetadata class.
......
......@@ -22,6 +22,7 @@
#namespace Doctrine::ORM;
/**
* A repository provides the illusion of an in-memory Entity store.
* Base class for all custom user-defined repositories.
* Provides basic finder methods, common to all repositories.
*
......@@ -48,7 +49,6 @@ class Doctrine_EntityRepository
}
/**
* createQuery
* creates a new Doctrine_Query object and adds the component name
* of this table as the query 'from' part
*
......
......@@ -29,93 +29,11 @@
* @subpackage EventListener
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 1.0
* @since 2.0
* @version $Revision$
* @todo Remove. The 2.0 event system has no listener interfaces.
*/
class Doctrine_EventListener implements Doctrine_EventListener_Interface
interface Doctrine_EventSubscriber
{
public function preClose(Doctrine_Event $event)
{ }
public function postClose(Doctrine_Event $event)
{ }
public function onCollectionDelete(Doctrine_Collection $collection)
{ }
public function onPreCollectionDelete(Doctrine_Collection $collection)
{ }
public function onOpen(Doctrine_Connection $connection)
{ }
public function preTransactionCommit(Doctrine_Event $event)
{ }
public function postTransactionCommit(Doctrine_Event $event)
{ }
public function preTransactionRollback(Doctrine_Event $event)
{ }
public function postTransactionRollback(Doctrine_Event $event)
{ }
public function preTransactionBegin(Doctrine_Event $event)
{ }
public function postTransactionBegin(Doctrine_Event $event)
{ }
public function preSavepointCommit(Doctrine_Event $event)
{ }
public function postSavepointCommit(Doctrine_Event $event)
{ }
public function preSavepointRollback(Doctrine_Event $event)
{ }
public function postSavepointRollback(Doctrine_Event $event)
{ }
public function preSavepointCreate(Doctrine_Event $event)
{ }
public function postSavepointCreate(Doctrine_Event $event)
{ }
public function postConnect(Doctrine_Event $event)
{ }
public function preConnect(Doctrine_Event $event)
{ }
public function preQuery(Doctrine_Event $event)
{ }
public function postQuery(Doctrine_Event $event)
{ }
public function prePrepare(Doctrine_Event $event)
{ }
public function postPrepare(Doctrine_Event $event)
{ }
public function preExec(Doctrine_Event $event)
{ }
public function postExec(Doctrine_Event $event)
{ }
public function preError(Doctrine_Event $event)
{ }
public function postError(Doctrine_Event $event)
{ }
public function preFetch(Doctrine_Event $event)
{ }
public function postFetch(Doctrine_Event $event)
{ }
public function preFetchAll(Doctrine_Event $event)
{ }
public function postFetchAll(Doctrine_Event $event)
{ }
public function preStmtExecute(Doctrine_Event $event)
{ }
public function postStmtExecute(Doctrine_Event $event)
{ }
public function getSubscribedEvents();
}
......@@ -56,9 +56,9 @@ class Doctrine_EventManager
foreach ($this->_listeners[$callback] as $listener) {
$listener->$callback($event);
}
return ! $event->getDefaultPrevented();
}
return ! $event->getDefaultPrevented();
return true;
}
/**
......
......@@ -227,6 +227,7 @@ class Doctrine_HydratorNew extends Doctrine_Hydrator_Abstract
} else if (isset($resultPointers[$parent])) {
$baseElement =& $resultPointers[$parent];
} else {
unset($prev[$dqlAlias]); // Ticket #1228
continue;
}
......@@ -256,7 +257,8 @@ class Doctrine_HydratorNew extends Doctrine_Hydrator_Abstract
} else {
// x-1 relation
$oneToOne = true;
if ( ! isset($nonemptyComponents[$dqlAlias])) {
if ( ! isset($nonemptyComponents[$dqlAlias]) &&
! $driver->isFieldSet($baseElement, $relationAlias)) {
$driver->setRelatedElement($baseElement, $relationAlias,
$driver->getNullPointer());
} else if ( ! $driver->isFieldSet($baseElement, $relationAlias)) {
......@@ -293,8 +295,6 @@ class Doctrine_HydratorNew extends Doctrine_Hydrator_Abstract
}
/**
* _setLastElement
*
* sets the last element of given data array / collection
* as previous element
*
......@@ -308,7 +308,8 @@ class Doctrine_HydratorNew extends Doctrine_Hydrator_Abstract
*/
protected function _setLastElement(&$resultPointers, &$coll, $index, $dqlAlias, $oneToOne)
{
if ($coll === $this->_nullObject) {
if ($coll === $this->_nullObject || $coll === null) {
unset($resultPointers[$dqlAlias]); // Ticket #1228
return false;
}
......@@ -330,8 +331,6 @@ class Doctrine_HydratorNew extends Doctrine_Hydrator_Abstract
$resultPointers[$dqlAlias] = $coll;
} else if (count($coll) > 0) {
$resultPointers[$dqlAlias] = $coll->getLast();
} else if (isset($resultPointers[$dqlAlias])) {
unset($resultPointers[$dqlAlias]);
}
}
......
......@@ -77,7 +77,7 @@ class Doctrine_Query_Production_IndexBy extends Doctrine_Query_Production
}
// The INDEXBY field must be either the (primary && not part of composite pk) || (unique && notnull)
$columnMapping = $classMetadata->getColumnMapping($this->_fieldName);
$columnMapping = $classMetadata->getFieldMapping($this->_fieldName);
if ( ! $classMetadata->isIdentifier($this->_fieldName) && ! $classMetadata->isUniqueField($this->_fieldName) && ! $classMetadata->isNotNull($this->_fieldName)) {
$this->_parser->semanticalError(
......
......@@ -22,6 +22,7 @@ class CustomAccessorMutatorTestEntity extends Doctrine_Entity
{
public static function initMetadata($class)
{
$class->mapColumn('id', 'integer', 4, array('primary'));
$class->mapColumn('username', 'string', 50, array(
'accessor' => 'getUsernameCustom',
'mutator' => 'setUsernameCustom'));
......@@ -42,6 +43,7 @@ class MagicAccessorMutatorTestEntity extends Doctrine_Entity
{
public static function initMetadata($class)
{
$class->mapColumn('id', 'integer', 4, array('primary'));
$class->mapColumn('username', 'string', 50, array());
}
......
......@@ -6,7 +6,7 @@ class Orm_Entity_ConstructorTest extends Doctrine_OrmTestCase
public function testFieldInitializationInConstructor()
{
$entity = new ConstructorTestEntity1("romanb");
$this->assertTrue($entity->isTransient());
$this->assertTrue($entity->isNew());
$this->assertEquals("romanb", $entity->username);
}
}
......@@ -16,7 +16,7 @@ class ConstructorTestEntity1 extends Doctrine_Entity
public function __construct($username = null)
{
parent::__construct();
if ($this->isTransient()) {
if ($this->isNew()) {
$this->username = $username;
}
}
......@@ -24,6 +24,7 @@ class ConstructorTestEntity1 extends Doctrine_Entity
/* The mapping definition */
public static function initMetadata($class)
{
$class->mapColumn('id', 'integer', 4, array('primary'));
$class->mapColumn('username', 'string', 50, array());
}
}
......
<?php
class ForumBoard extends Doctrine_Entity {
public static function initMetadata($class) {
$class->mapColumn('position', 'integer');
$class->mapColumn('category_id', 'integer');
$class->hasOne('ForumCategory as category',
public static function initMetadata($metadata) {
/*$metadata->mapField(array(
'fieldName' => 'id',
'id' => true,
'type' => 'integer',
'length' => 4
));
*/
$metadata->mapColumn('id', 'integer', 4, array('primary'));
$metadata->mapColumn('position', 'integer');
$metadata->mapColumn('category_id', 'integer');
$metadata->hasOne('ForumCategory as category',
array('local' => 'category_id', 'foreign' => 'id'));
/*
$metadata->mapOneToOne(array(
'fieldName' => 'category', // optional, defaults to targetEntity
'targetEntity' => 'ForumCategory',
'joinColumns' => array('category_id' => 'id')
));
*/
}
}
<?php
class ForumCategory extends Doctrine_Entity {
public static function initMetadata($class) {
$class->mapColumn('id', 'integer', 4, array('primary'));
$class->mapColumn('position', 'integer');
$class->mapColumn('name', 'string', 255);
$class->hasMany('ForumBoard as boards', array(
......
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