1
0
mirror of synced 2025-01-18 22:41:43 +03:00

Checkin of occasional work from the past weeks.

This commit is contained in:
romanb 2008-07-20 20:13:24 +00:00
parent c43f9588be
commit d9975c36a3
40 changed files with 2621 additions and 1410 deletions

View File

@ -0,0 +1,228 @@
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
#namespace Doctrine::ORM::Mapping;
/**
* Base class for association mappings.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @todo Rename to AssociationMapping.
*/
class Doctrine_Association implements Serializable
{
const FETCH_MANUAL = 1;
const FETCH_LAZY = 2;
const FETCH_EAGER = 3;
/**
* Cascade types enumeration.
*
* @var array
*/
protected static $_cascadeTypes = array(
'all',
'none',
'save',
'delete',
'refresh'
);
protected $_cascades = array();
protected $_isCascadeDelete;
protected $_isCascadeSave;
protected $_isCascadeRefresh;
/**
* The fetch mode used for the association.
*
* @var integer
*/
protected $_fetchMode = self::FETCH_MANUAL;
/**
* Flag that indicates whether the class that defines this mapping is
* the owning side of the association.
*
* @var boolean
*/
protected $_isOwningSide = true;
/**
* The name of the source Entity (the Entity that defines this mapping).
*
* @var string
*/
protected $_sourceEntityName;
/**
* The name of the target Entity (the Enitity that is the target of the
* association).
*
* @var unknown_type
*/
protected $_targetEntityName;
/**
* Identifies the field on the source class (the class this AssociationMapping
* belongs to) that represents the association.
*
* @var string
*/
protected $_sourceFieldName;
/**
* Identifies the field on the owning side that has the mapping for the
* association.
*
* @var string
*/
protected $_mappedByFieldName;
/**
* Constructor.
* Creates a new AssociationMapping.
*
* @param array $mapping The mapping definition.
*/
public function __construct(array $mapping)
{
$this->_validateMapping($mapping);
if ($this->_isOwningSide) {
$this->_sourceEntityName = $mapping['sourceEntity'];
$this->_targetEntityName = $mapping['targetEntity'];
$this->_sourceFieldName = $mapping['fieldName'];
} else {
$this->_mappedByFieldName = $mapping['mappedBy'];
}
}
/**
* Validates & completes the mapping. Mapping defaults are applied here.
*
* @param array $mapping
* @return array The validated & completed mapping.
*/
protected function _validateMapping(array $mapping)
{
if (isset($mapping['mappedBy'])) {
$this->_isOwningSide = false;
}
if ($this->_isOwningSide) {
if ( ! isset($mapping['targetEntity'])) {
throw Doctrine_MappingException::missingTargetEntity();
} else if ( ! isset($mapping['fieldName'])) {
throw Doctrine_MappingException::missingFieldName();
}
}
return $mapping;
}
public function isCascadeDelete()
{
if (is_null($this->_isCascadeDelete)) {
$this->_isCascadeDelete = in_array('delete', $this->_cascades);
}
return $this->_isCascadeDelete;
}
public function isCascadeSave()
{
if (is_null($this->_isCascadeSave)) {
$this->_isCascadeSave = in_array('save', $this->_cascades);
}
return $this->_isCascadeSave;
}
public function isCascadeRefresh()
{
if (is_null($this->_isCascadeRefresh)) {
$this->_isCascadeRefresh = in_array('refresh', $this->_cascades);
}
return $this->_isCascadeRefresh;
}
public function isEagerlyFetched()
{
return $this->_fetchMode == self::FETCH_EAGER;
}
public function isLazilyFetched()
{
return $this->_fetchMode == self::FETCH_LAZY;
}
public function isManuallyFetched()
{
return $this->_fetchMode == self::FETCH_MANUAL;
}
public function isOwningSide()
{
return $this->_isOwningSide;
}
public function isInverseSide()
{
return ! $this->_isOwningSide;
}
public function getSourceEntityName()
{
return $this->_sourceEntityName;
}
public function getTargetEntityName()
{
return $this->_targetEntityName;
}
/**
* Get the name of the field the association is mapped into.
*
*/
public function getSourceFieldName()
{
return $this->_sourceFieldName;
}
public function getMappedByFieldName()
{
return $this->_mappedByFieldName;
}
/* Serializable implementation */
public function serialize()
{
return "";
}
public function unserialize($serialized)
{
return true;
}
}
?>

View File

@ -0,0 +1,80 @@
<?php
#namespace Doctrine::ORM::Mappings;
/**
* A many-to-many mapping describes the mapping between two collections of
* entities.
*
* @since 2.0
* @todo Rename to ManyToManyMapping
*/
class Doctrine_Association_ManyToMany extends Doctrine_Association
{
/**
* Whether the mapping uses an association class.
*
* @var boolean
*/
private $_usesAssociationClass;
/**
* The name of the association class (if an association class is used).
*
* @var string
*/
private $_associationClassName;
/**
* The name of the intermediate table.
*
* @var string
*/
private $_relationTableName;
/** The field in the source table that corresponds to the key in the relation table */
protected $_sourceKeyFields;
/** The field in the target table that corresponds to the key in the relation table */
protected $_targetKeyFields;
/** The field in the intermediate table that corresponds to the key in the source table */
protected $_sourceRelationKeyFields;
/** The field in the intermediate table that corresponds to the key in the target table */
protected $_targetRelationKeyFields;
/**
* Whether the mapping uses an association class for the intermediary
* table.
*
* @return boolean
*/
public function usesAssociationClass()
{
}
/**
* Gets the name of the intermediate table.
*
* @return string
*/
public function getRelationTableName()
{
return $this->_relationTableName;
}
/**
* Gets the name of the association class.
*
* @return string
*/
public function getAssociationClassName()
{
return $this->_associationClassName;
}
}
?>

View File

@ -0,0 +1,28 @@
<?php
#namespace Doctrine::ORM::Mappings;
class Doctrine_Association_OneToMany extends Doctrine_Association
{
/** The target foreign key fields that reference the sourceKeyFields. */
protected $_targetForeignKeyFields;
/** The (typically primary) source key fields that are referenced by the targetForeignKeyFields. */
protected $_sourceKeyFields;
/** This maps the target foreign key fields to the corresponding (primary) source key fields. */
protected $_targetForeignKeysToSourceKeys;
/** This maps the (primary) source key fields to the corresponding target foreign key fields. */
protected $_sourceKeysToTargetForeignKeys;
/** Whether to delete orphaned elements (removed from the collection) */
protected $_isCascadeDeleteOrphan = false;
public function isCascadeDeleteOrphan()
{
return $this->_isCascadeDeleteOrphan;
}
}
?>

View File

@ -0,0 +1,139 @@
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
#namespace Doctrine::ORM::Mappings;
#use Doctrine::ORM::Entity;
/**
* A one-to-one mapping describes a uni-directional mapping from one entity
* to another entity.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @todo Rename to OneToOneMapping
*/
class Doctrine_Association_OneToOne extends Doctrine_Association
{
/**
* Maps the source foreign/primary key fields to the target primary/foreign key fields.
* i.e. source.id (pk) => target.user_id (fk).
* Reverse mapping of _targetToSourceKeyFields.
*/
protected $_sourceToTargetKeyColumns = array();
/**
* Maps the target primary/foreign key fields to the source foreign/primary key fields.
* i.e. target.user_id (fk) => source.id (pk).
* Reverse mapping of _sourceToTargetKeyFields.
*/
protected $_targetToSourceKeyColumns = array();
/**
* Constructor.
* Creates a new OneToOneMapping.
*
* @param array $mapping The mapping info.
*/
public function __construct(array $mapping)
{
parent::__construct($mapping);
if ($this->isOwningSide()) {
$this->_sourceToTargetKeyColumns = $mapping['joinColumns'];
$this->_targetToSourceKeyColumns = array_flip($this->_sourceToTargetKeyColumns);
}
}
/**
* Validates & completes the mapping. Mapping defaults are applied here.
*
* @param array $mapping The mapping to validate & complete.
* @return array The validated & completed mapping.
* @override
*/
protected function _validateMapping(array $mapping)
{
$mapping = parent::_validateMapping($mapping);
if ($this->isOwningSide()) {
if ( ! isset($mapping['joinColumns'])) {
throw Doctrine_MappingException::missingJoinColumns();
}
}
return $mapping;
}
/**
* Gets the source-to-target key column mapping.
*
* @return unknown
*/
public function getSourceToTargetKeyColumns()
{
return $this->_sourceToTargetKeyColumns;
}
/**
* Gets the target-to-source key column mapping.
*
* @return unknown
*/
public function getTargetToSourceKeyColumns()
{
return $this->_targetToSourceKeyColumns;
}
/**
* Lazy-loads the associated entity for a given entity.
*
* @param Doctrine::ORM::Entity $entity
* @return void
*/
public function lazyLoadFor(Doctrine_Entity $entity)
{
if ($entity->getClassName() != $this->_sourceClass->getClassName()) {
//error?
}
$dql = 'SELECT t.* FROM ' . $this->_targetClass->getClassName() . ' t WHERE ';
$params = array();
foreach ($this->_sourceToTargetKeyFields as $sourceKeyField => $targetKeyField) {
if ($params) {
$dql .= " AND ";
}
$dql .= "t.$targetKeyField = ?";
$params[] = $entity->_rawGetField($sourceKeyField);
}
$otherEntity = $this->_targetClass->getEntityManager()
->query($dql, $params)
->getFirst();
if ( ! $otherEntity) {
$otherEntity = Doctrine_Null::$INSTANCE;
}
$entity->_rawSetReference($this->_sourceFieldName, $otherEntity);
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@ -19,6 +19,8 @@
* <http://www.phpdoctrine.org>.
*/
#namespace Doctrine::ORM::Internal;
/**
* The metadata factory is used to create ClassMetadata objects that contain all the
* metadata of a class.
@ -31,10 +33,11 @@
* @version $Revision$
* @link www.phpdoctrine.org
* @since 2.0
* @todo Rename to ClassMetadataFactory.
*/
class Doctrine_ClassMetadata_Factory
{
protected $_conn;
protected $_em;
protected $_driver;
/**
@ -52,7 +55,7 @@ class Doctrine_ClassMetadata_Factory
*/
public function __construct(Doctrine_EntityManager $em, $driver)
{
$this->_conn = $em;
$this->_em = $em;
$this->_driver = $driver;
}
@ -101,7 +104,7 @@ class Doctrine_ClassMetadata_Factory
$class = $classes[$loadedParentClass];
} else {
$rootClassOfHierarchy = count($parentClasses) > 0 ? array_shift($parentClasses) : $name;
$class = new Doctrine_ClassMetadata($rootClassOfHierarchy, $this->_conn);
$class = new Doctrine_ClassMetadata($rootClassOfHierarchy, $this->_em);
$this->_loadMetadata($class, $rootClassOfHierarchy);
$classes[$rootClassOfHierarchy] = $class;
}
@ -115,7 +118,7 @@ class Doctrine_ClassMetadata_Factory
$parent = $class;
foreach ($parentClasses as $subclassName) {
$subClass = new Doctrine_ClassMetadata($subclassName, $this->_conn);
$subClass = new Doctrine_ClassMetadata($subclassName, $this->_em);
$subClass->setInheritanceType($parent->getInheritanceType(), $parent->getInheritanceOptions());
$this->_addInheritedFields($subClass, $parent);
$this->_addInheritedRelations($subClass, $parent);
@ -130,14 +133,10 @@ class Doctrine_ClassMetadata_Factory
protected function _addInheritedFields($subClass, $parentClass)
{
foreach ($parentClass->getFieldMappings() as $name => $definition) {
foreach ($parentClass->getFieldMappings() as $fieldName => $mapping) {
$fullName = "$name as " . $parentClass->getFieldName($name);
$definition['inherited'] = true;
$subClass->mapColumn(
$fullName,
$definition['type'],
$definition['length'],
$definition);
$mapping['inherited'] = true;
$subClass->mapField($mapping);
}
}
@ -163,6 +162,7 @@ class Doctrine_ClassMetadata_Factory
$names = array();
$className = $name;
// get parent classes
//TODO: Skip Entity types MappedSuperclass/Transient
do {
if ($className === 'Doctrine_Entity') {
break;
@ -182,11 +182,13 @@ class Doctrine_ClassMetadata_Factory
// load further metadata
$this->_driver->loadMetadataForClass($name, $class);
// set default table name, if necessary
$tableName = $class->getTableName();
if ( ! isset($tableName)) {
$class->setTableName(Doctrine::tableize($class->getClassName()));
}
// complete identifier mapping
$this->_initIdentifier($class);
return $class;
@ -199,7 +201,7 @@ class Doctrine_ClassMetadata_Factory
*/
protected function _initIdentifier(Doctrine_ClassMetadata $class)
{
switch (count((array)$class->getIdentifier())) {
/*switch (count($class->getIdentifier())) {
case 0: // No identifier in the class mapping yet
// If its a subclass, inherit the identifier from the parent.
@ -217,7 +219,7 @@ class Doctrine_ClassMetadata_Factory
}
// add all inherited primary keys
foreach ((array) $class->getIdentifier() as $id) {
foreach ($class->getIdentifier() as $id) {
$definition = $rootClass->getDefinitionOf($id);
// inherited primary keys shouldn't contain autoinc
@ -231,16 +233,7 @@ 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->mapColumn('id', $definition['type'], $definition['length'], $definition, true);
$class->setIdentifier(array('id'));
$class->setIdentifierType(Doctrine::IDENTIFIER_AUTOINC);
*/
throw Doctrine_MappingException::identifierRequired($class->getClassName());
}
break;
case 1: // A single identifier is in the mapping
@ -293,6 +286,36 @@ class Doctrine_ClassMetadata_Factory
break;
default: // Multiple identifiers are in the mapping so its a composite id
$class->setIdentifierType(Doctrine::IDENTIFIER_COMPOSITE);
}*/
// If the chosen generator type is "auto", then pick the one appropriate for
// the database.
// FIXME: This is very ugly here. Such switch()es on the database driver
// are unnecessary as we can easily replace them with polymorphic calls on
// the connection (or another) object. We just need to decide where to put
// the id generation types.
if ($class->getIdGeneratorType() == Doctrine_ClassMetadata::GENERATOR_TYPE_AUTO) {
switch (strtolower($this->_em->getConnection()->getDriverName())) {
case 'mysql':
// pick IDENTITY
$class->setIdGeneratorType(Doctrine_ClassMetadata::GENERATOR_TYPE_IDENTITY);
break;
case 'oracle':
//pick SEQUENCE
break;
case 'postgres':
//pick SEQUENCE
break;
case 'firebird':
//pick what?
break;
case 'mssql':
//pick what?
default:
throw new Doctrine_Exception("Encountered unknown database driver: "
. $this->_em->getConnection()->getDriverName());
}
}
}

View File

@ -33,10 +33,10 @@
* @since 1.0
* @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @todo Rename to EntityCollection
*/
class Doctrine_Collection extends Doctrine_Access implements Countable, IteratorAggregate, Serializable
{
{
protected $_entityBaseType;
/**
@ -44,42 +44,30 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
*
* @var array
*/
protected $data = array();
/**
* The mapper object used to map the records of this collection to the database.
*
* @var Doctrine_Mapper
*/
protected $_mapper;
protected $_data = array();
/**
* A snapshot of the fetched data.
* A snapshot of the collection at the moment it was fetched from the database.
* This is used to create a diff of the collection at commit time.
*
* @var array
* @var array
*/
protected $_snapshot = array();
/**
* This record this collection is attached to, if any.
* This entity that owns this collection.
*
* @var Doctrine_Entity
* @var Doctrine::ORM::Entity
*/
protected $_owner;
/**
* The reference field of the collection.
* The association mapping the collection belongs to.
* This is currently either a OneToManyMapping or a ManyToManyMapping.
*
* @var string $referenceField
* @var Doctrine::ORM::Mapping::AssociationMapping
*/
protected $referenceField;
/**
* The relation this collection is related to, if any.
*
* @var Doctrine_Relation
*/
protected $relation;
protected $_associationMapping;
/**
* The name of the column that is used for collection key mapping.
@ -101,6 +89,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
* @var EntityManager
*/
protected $_em;
protected $_isDirty = false;
/**
* Constructor.
@ -113,18 +102,9 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
{
$this->_entityBaseType = $entityBaseType;
$this->_em = Doctrine_EntityManagerFactory::getManager($entityBaseType);
$this->_mapper = $this->_em->getEntityPersister($entityBaseType);
if ($keyField === null) {
$keyField = $this->_mapper->getClassMetadata()->getBoundQueryPart('indexBy');
}
if ($keyField === null) {
//$keyField = $mapper->getClassMetadata()->getAttribute(Doctrine::ATTR_COLL_KEY);
}
if ($keyField !== null) {
if ( ! $this->_mapper->getClassMetadata()->hasField($keyField)) {
if ( ! $this->_em->getClassMetadata($entityBaseType)->hasField($keyField)) {
throw new Doctrine_Collection_Exception("Invalid field '$keyField' can't be uses as key.");
}
$this->_keyField = $keyField;
@ -139,7 +119,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
*/
public function setData(array $data)
{
$this->data = $data;
$this->_data = $data;
}
/**
@ -155,14 +135,11 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
$vars = get_object_vars($this);
unset($vars['reference']);
unset($vars['reference_field']);
unset($vars['relation']);
unset($vars['expandable']);
unset($vars['expanded']);
unset($vars['generator']);
$vars['_mapper'] = $vars['_mapper']->getComponentName();
return serialize($vars);
}
@ -187,12 +164,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
$this->$name = $values;
}
$this->_mapper = $manager->getEntityPersister($this->_entityBaseType);
$keyColumn = isset($array['keyField']) ? $array['keyField'] : null;
if ($keyColumn === null) {
$keyColumn = $this->_mapper->getClassMetadata()->getBoundQueryPart('indexBy');
}
if ($keyColumn !== null) {
$this->_keyField = $keyColumn;
@ -231,7 +203,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
*/
public function getData()
{
return $this->data;
return $this->_data;
}
/**
@ -242,7 +214,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
*/
public function getFirst()
{
return reset($this->data);
return reset($this->_data);
}
/**
@ -253,7 +225,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
*/
public function getLast()
{
return end($this->data);
return end($this->_data);
}
/**
@ -263,7 +235,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
*/
public function end()
{
return end($this->data);
return end($this->_data);
}
/**
@ -273,7 +245,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
*/
public function key()
{
return key($this->data);
return key($this->_data);
}
/**
@ -285,13 +257,13 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
public function setReference(Doctrine_Entity $entity, Doctrine_Relation $relation)
{
$this->_owner = $entity;
$this->relation = $relation;
//$this->relation = $relation;
if ($relation instanceof Doctrine_Relation_ForeignKey ||
/*if ($relation instanceof Doctrine_Relation_ForeignKey ||
$relation instanceof Doctrine_Relation_LocalKey) {
$this->referenceField = $relation->getForeignFieldName();
$value = $entity->get($relation->getLocalFieldName());
foreach ($this->data as $entity) {
foreach ($this->_data as $entity) {
if ($value !== null) {
$entity->set($this->referenceField, $value, false);
} else {
@ -300,7 +272,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
}
} else if ($relation instanceof Doctrine_Relation_Association) {
}
}*/
}
/**
@ -322,8 +294,8 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
*/
public function remove($key)
{
$removed = $this->data[$key];
unset($this->data[$key]);
$removed = $this->_data[$key];
unset($this->_data[$key]);
return $removed;
}
@ -336,7 +308,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
*/
public function contains($key)
{
return isset($this->data[$key]);
return isset($this->_data[$key]);
}
/**
@ -344,7 +316,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
*/
public function search(Doctrine_Entity $record)
{
return array_search($record, $this->data, true);
return array_search($record, $this->_data, true);
}
/**
@ -357,8 +329,8 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
*/
public function get($key)
{
if (isset($this->data[$key])) {
return $this->data[$key];
if (isset($this->_data[$key])) {
return $this->_data[$key];
}
return null;
}
@ -374,7 +346,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
$list = array();
$idFieldNames = (array)$this->_mapper->getClassMetadata()->getIdentifier();
foreach ($this->data as $record) {
foreach ($this->_data as $record) {
if (is_array($record)) {
if (count($idFieldNames) > 1) {
$id = array();
@ -406,7 +378,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
*/
public function getKeys()
{
return array_keys($this->data);
return array_keys($this->_data);
}
/**
@ -418,7 +390,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
*/
public function count()
{
return count($this->data);
return count($this->_data);
}
/**
@ -429,69 +401,49 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
* @internal Can't type-hint the second parameter to Doctrine_Entity because we need
* to adhere to the Doctrine_Access::set() signature.
*/
public function set($key, $entity)
public function set($key, $value)
{
if ( ! $entity instanceof Doctrine_Entity) {
if ( ! $value instanceof Doctrine_Entity) {
throw new Doctrine_Collection_Exception('Value variable in set is not an instance of Doctrine_Entity');
}
if (isset($this->referenceField)) {
$entity->set($this->referenceField, $this->_owner, false);
}
$this->data[$key] = $entity;
$this->_data[$key] = $value;
}
/**
* adds a record to collection
*
* @param Doctrine_Entity $record record to be added
* @param string $key optional key for the record
* @return boolean
*/
public function add($record, $key = null)
public function add($value, $key = null)
{
/** @TODO Use raw getters/setters */
if ( ! $record instanceof Doctrine_Entity) {
if ( ! $value instanceof Doctrine_Entity) {
throw new Doctrine_Record_Exception('Value variable in set is not an instance of Doctrine_Entity.');
}
if (isset($this->referenceField)) {
$value = $this->_owner->get($this->relation->getLocalFieldName());
if ($value !== null) {
$record->set($this->referenceField, $value, false);
} else {
$record->set($this->referenceField, $this->_owner, false);
}
}
/*
* for some weird reason in_array cannot be used here (php bug ?)
*
* if used it results in fatal error : [ nesting level too deep ]
*/
foreach ($this->data as $val) {
if ($val === $record) {
foreach ($this->_data as $val) {
if ($val === $value) {
return false;
}
}
if (isset($key)) {
if (isset($this->data[$key])) {
if (isset($this->_data[$key])) {
return false;
}
$this->data[$key] = $record;
$this->_data[$key] = $value;
return true;
}
// why is this not checked when the keyColumn is set?
if (isset($this->_keyField)) {
$value = $record->get($this->_keyField);
if ($value === null) {
throw new Doctrine_Collection_Exception("Couldn't create collection index. Record field '".$this->_keyField."' was null.");
}
$this->data[$value] = $record;
} else {
$this->data[] = $record;
}
$this->_data[] = $value;
return true;
}
@ -509,7 +461,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
$query = new Doctrine_Query($this->_mapper->getConnection());
if ( ! isset($name)) {
foreach ($this->data as $record) {
foreach ($this->_data as $record) {
// FIXME: composite key support
$ids = $record->identifier();
$value = count($ids) > 0 ? array_pop($ids) : null;
@ -528,11 +480,11 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
$rel = $this->_mapper->getTable()->getRelation($name);
if ($rel instanceof Doctrine_Relation_LocalKey || $rel instanceof Doctrine_Relation_ForeignKey) {
foreach ($this->data as $record) {
foreach ($this->_data as $record) {
$list[] = $record[$rel->getLocal()];
}
} else {
foreach ($this->data as $record) {
foreach ($this->_data as $record) {
$ids = $record->identifier();
$value = count($ids) > 0 ? array_pop($ids) : null;
if ($value !== null) {
@ -563,15 +515,15 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
$local = $rel->getLocal();
if ($rel instanceof Doctrine_Relation_LocalKey) {
foreach ($this->data as $key => $record) {
foreach ($this->_data as $key => $record) {
foreach ($coll as $k => $related) {
if ($related[$foreign] == $record[$local]) {
$this->data[$key]->_setRelated($name, $related);
$this->_data[$key]->_setRelated($name, $related);
}
}
}
} else if ($rel instanceof Doctrine_Relation_ForeignKey) {
foreach ($this->data as $key => $record) {
foreach ($this->_data as $key => $record) {
if ( ! $record->exists()) {
continue;
}
@ -584,7 +536,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
}
}
$this->data[$key]->_setRelated($name, $sub);
$this->_data[$key]->_setRelated($name, $sub);
}
} else if ($rel instanceof Doctrine_Relation_Association) {
// @TODO composite key support
@ -592,7 +544,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
$asf = $rel->getAssociationFactory();
$name = $table->getComponentName();
foreach ($this->data as $key => $record) {
foreach ($this->_data as $key => $record) {
if ( ! $record->exists()) {
continue;
}
@ -603,7 +555,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
$sub->add($related->get($name));
}
}
$this->data[$key]->_setRelated($name, $sub);
$this->_data[$key]->_setRelated($name, $sub);
}
}
@ -635,7 +587,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
*/
public function takeSnapshot()
{
$this->_snapshot = $this->data;
$this->_snapshot = $this->_data;
return $this;
}
@ -664,7 +616,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
*/
public function processDiff()
{
foreach (array_udiff($this->_snapshot, $this->data, array($this, "_compareRecords")) as $record) {
foreach (array_udiff($this->_snapshot, $this->_data, array($this, "_compareRecords")) as $record) {
$record->delete();
}
return $this;
@ -686,6 +638,11 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
return $data;
}
public function isEmpty()
{
return $this->count() == 0;
}
/**
* fromArray
@ -776,7 +733,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
*/
public function getDeleteDiff()
{
return array_udiff($this->_snapshot, $this->data, array($this, "_compareRecords"));
return array_udiff($this->_snapshot, $this->_data, array($this, "_compareRecords"));
}
/**
@ -786,7 +743,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
*/
public function getInsertDiff()
{
return array_udiff($this->data, $this->_snapshot, array($this, "_compareRecords"));
return array_udiff($this->_data, $this->_snapshot, array($this, "_compareRecords"));
}
/**
@ -803,7 +760,6 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
}
/**
* save
* Saves all records of this collection and processes the
* difference of the last snapshot and the current data.
*
@ -869,7 +825,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
}
}
$this->data = array();
$this->_data = array();
if ($this->_owner) {
$this->_owner->free($deep);
@ -884,7 +840,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
*/
public function getIterator()
{
$data = $this->data;
$data = $this->_data;
return new ArrayIterator($data);
}
@ -907,6 +863,6 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
public function clear()
{
$this->data = array();
$this->_data = array();
}
}

View File

@ -138,8 +138,9 @@ abstract class Doctrine_Connection implements Countable
* @var array $properties
*/
protected $properties = array(
'sql_comments' => array(array('start' => '--', 'end' => "\n", 'escape' => false),
array('start' => '/*', 'end' => '*/', 'escape' => false)),
'sql_comments' => array(
array('start' => '--', 'end' => "\n", 'escape' => false),
array('start' => '/*', 'end' => '*/', 'escape' => false)),
'identifier_quoting' => array('start' => '"', 'end' => '"','escape' => '"'),
'string_quoting' => array('start' => "'", 'end' => "'", 'escape' => false,
'escape_pattern' => false),
@ -154,6 +155,8 @@ abstract class Doctrine_Connection implements Countable
/**
* The parameters used during creation of the Connection.
*
* @var array
*/
protected $_params = array();
@ -364,24 +367,24 @@ abstract class Doctrine_Connection implements Countable
//$this->getListener()->preConnect($event);
// TODO: the extension_loaded check can happen earlier, maybe in the factory
if (extension_loaded('pdo')) {
$driverOptions = isset($this->_params['driverOptions']) ?
$this->_params['driverOptions'] : array();
$user = isset($this->_params['user']) ?
$this->_params['user'] : null;
$password = isset($this->_params['password']) ?
$this->_params['password'] : null;
$this->_pdo = new PDO(
$this->_constructPdoDsn(),
$user,
$password,
$driverOptions
);
$this->_pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->_pdo->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
} else {
if ( ! extension_loaded('pdo')) {
throw new Doctrine_Connection_Exception("Couldn't locate driver named " . $e[0]);
}
$driverOptions = isset($this->_params['driverOptions']) ?
$this->_params['driverOptions'] : array();
$user = isset($this->_params['user']) ?
$this->_params['user'] : null;
$password = isset($this->_params['password']) ?
$this->_params['password'] : null;
$this->_pdo = new PDO(
$this->_constructPdoDsn(),
$user,
$password,
$driverOptions
);
$this->_pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->_pdo->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
// attach the pending attributes to adapter
/*foreach($this->pendingAttributes as $attr => $value) {
@ -427,9 +430,8 @@ abstract class Doctrine_Connection implements Countable
*/
public function supports($feature)
{
return (isset($this->supported[$feature])
&& ($this->supported[$feature] === 'emulated'
|| $this->supported[$feature]));
return (isset($this->supported[$feature]) &&
($this->supported[$feature] === 'emulated' || $this->supported[$feature]));
}
/**
@ -662,8 +664,7 @@ abstract class Doctrine_Connection implements Countable
}
/**
* quote
* quotes given input parameter
* Quotes given input parameter
*
* @param mixed $input parameter to be quoted
* @param string $type
@ -794,10 +795,9 @@ abstract class Doctrine_Connection implements Countable
$this->getAttribute(Doctrine::ATTR_LISTENER)->postPrepare($event);
return new Doctrine_Connection_Statement($this, $stmt);
} catch(Doctrine_Adapter_Exception $e) {
} catch(PDOException $e) { }
$this->rethrowException($e, $this);
} catch (PDOException $e) {
$this->rethrowException($e, $this);
}
}
/**
@ -859,10 +859,9 @@ abstract class Doctrine_Connection implements Countable
return $stmt;
}
} catch (Doctrine_Adapter_Exception $e) {
} catch (PDOException $e) { }
$this->rethrowException($e, $this);
} catch (PDOException $e) {
$this->rethrowException($e, $this);
}
}
/**
@ -894,10 +893,9 @@ abstract class Doctrine_Connection implements Countable
return $count;
}
} catch (Doctrine_Adapter_Exception $e) {
} catch (PDOException $e) { }
$this->rethrowException($e, $this);
} catch (PDOException $e) {
$this->rethrowException($e, $this);
}
}
/**
@ -923,7 +921,7 @@ abstract class Doctrine_Connection implements Countable
}
/**
* rethrowException
* Wraps the given exception into a driver-specific exception and rethrows it.
*
* @throws Doctrine_Connection_Exception
*/
@ -940,9 +938,7 @@ abstract class Doctrine_Connection implements Countable
}
$exc->processErrorInfo($e->errorInfo);
if ($this->getAttribute(Doctrine::ATTR_THROW_EXCEPTIONS)) {
throw $exc;
}
throw $exc;
//$this->getListener()->postError($event);
}
@ -1178,7 +1174,6 @@ abstract class Doctrine_Connection implements Countable
}
}
public function getFormatter()
{
if ( ! $this->modules['formatter']) {
@ -1186,4 +1181,25 @@ abstract class Doctrine_Connection implements Countable
}
return $this->modules['formatter'];
}
public function getSequenceModule()
{
if ( ! $this->modules['sequence']) {
$class = "Doctrine_Sequence_" . $this->_driverName;
$this->modules['sequence'] = new $class;
}
return $this->modules['sequence'];
}
/**
* Gets the default (preferred) Id generation strategy of the database platform.
*
* @todo Sure, the id generator types are more ORM functionality but they're
* still kind of dbal related. Maybe we need another set of classes (DatabasePlatform?)
* but im not so sure...
*/
/*abstract*/ public function getDefaultIdGeneratorType()
{
}
}

File diff suppressed because it is too large Load Diff

View File

@ -37,45 +37,23 @@
* @link www.phpdoctrine.org
* @since 2.0
* @version $Revision: 4342 $
* @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.
* @todo Split up into "Entity" and "ActiveEntity" (extends Entity).
*/
abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
{
/**
* DIRTY STATE
* An Entity is in dirty state when its properties are changed.
* MANAGED
* An Entity is in managed state when it has a primary key/identifier and is
* managed by an EntityManager (registered in the identity map).
*/
const STATE_DIRTY = 1;
const STATE_MANAGED_DIRTY = 1;
const STATE_MANAGED = 1;
/**
* TDIRTY STATE
* An Entity is in transient dirty state when it is created and some of its
* fields are modified but it is NOT yet persisted into database.
* NEW
* An Entity is new if it does not yet have an identifier/primary key
* and is not (yet) managed by an EntityManager.
*/
const STATE_TDIRTY = 2;
const STATE_NEW_DIRTY = 2;
/**
* CLEAN STATE
* An Entity is in clean state when all of its properties are loaded from the database
* and none of its properties are changed.
*/
const STATE_CLEAN = 3;
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;
const STATE_NEW = 2;
/**
* LOCKED STATE
@ -93,14 +71,14 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
* (or no longer) associated with an EntityManager (and a UnitOfWork).
* This means its no longer in the identity map.
*/
const STATE_DETACHED = 7;
const STATE_DETACHED = 3;
/**
* 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;
const STATE_DELETED = 4;
/**
* Index used for creating object identifiers (oid's).
@ -144,12 +122,6 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
*/
private $_entityName;
/**
* @var Doctrine_Node_<TreeImpl> node object
* @todo Specific to the NestedSet Behavior plugin. Move outta here.
*/
//protected $_node;
/**
* The values that make up the ID/primary key of the entity.
*
@ -167,16 +139,16 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
/**
* The state of the object.
*
* @var integer
* @see STATE_* constants
* @var integer
*/
private $_state;
/**
* The names of fields that have been modified but not yet persisted.
* Keys are field names, values oldValue => newValue tuples.
*
* @var array
* @todo Better name? $_modifiedFields?
* @var array
* @todo Rename to $_changeSet
*/
private $_modified = array();
@ -204,6 +176,7 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
/**
* Constructor.
* Creates a new Entity instance.
*/
public function __construct()
{
@ -214,9 +187,9 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
$this->_data = $this->_em->_getTmpEntityData();
if ($this->_data) {
$this->_extractIdentifier();
$this->_state = self::STATE_CLEAN;
$this->_state = self::STATE_MANAGED;
} else {
$this->_state = self::STATE_TCLEAN;
$this->_state = self::STATE_NEW;
}
// @todo read from attribute the first time and move this initialization elsewhere.
@ -265,7 +238,7 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
}*/
/**
* hydrates this object from given array
* Hydrates this object from given array
*
* @param array $data
* @return boolean
@ -278,33 +251,26 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
/**
* Copies the identifier names and values from _data into _id.
*
* @param boolean $exists whether or not this record exists in persistent data store
* @return void
* @todo Looks like its better placed elsewhere (EntityManager?)
*/
private function _extractIdentifier()
{
switch ($this->_class->getIdentifierType()) {
case Doctrine::IDENTIFIER_AUTOINC:
case Doctrine::IDENTIFIER_SEQUENCE:
case Doctrine::IDENTIFIER_NATURAL:
$name = $this->_class->getIdentifier();
$name = $name[0];
if (isset($this->_data[$name]) && $this->_data[$name] !== Doctrine_Null::$INSTANCE) {
if ( ! $this->_class->isIdentifierComposite()) {
// Single field identifier
$name = $this->_class->getIdentifier();
$name = $name[0];
if (isset($this->_data[$name]) && $this->_data[$name] !== Doctrine_Null::$INSTANCE) {
$this->_id[$name] = $this->_data[$name];
}
} else {
// Composite identifier
$names = $this->_class->getIdentifier();
foreach ($names as $name) {
if ($this->_data[$name] === Doctrine_Null::$INSTANCE) {
$this->_id[$name] = null;
} else {
$this->_id[$name] = $this->_data[$name];
}
break;
case Doctrine::IDENTIFIER_COMPOSITE:
$names = $this->_class->getIdentifier();
foreach ($names as $name) {
if ($this->_data[$name] === Doctrine_Null::$INSTANCE) {
$this->_id[$name] = null;
} else {
$this->_id[$name] = $this->_data[$name];
}
}
break;
}
}
}
@ -438,22 +404,16 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
/* TODO: Do we really need this check? This is only for internal use after all. */
switch ($state) {
case self::STATE_TCLEAN:
case self::STATE_CLEAN:
case self::STATE_TDIRTY:
case self::STATE_DIRTY:
case self::STATE_PROXY:
case self::STATE_MANAGED:
case self::STATE_DELETED:
case self::STATE_DETACHED:
case self::STATE_NEW:
case self::STATE_LOCKED:
$this->_state = $state;
break;
default:
throw Doctrine_Entity_Exception::invalidState($state);
}
if ($this->_state === Doctrine_Entity::STATE_TCLEAN ||
$this->_state === Doctrine_Entity::STATE_CLEAN) {
$this->_modified = array();
}
}
/**
@ -878,23 +838,13 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
}*/
$old = isset($this->_data[$fieldName]) ? $this->_data[$fieldName] : null;
//FIXME: null == 0 => true
if ($old != $value) {
$this->_data[$fieldName] = $value;
$this->_modified[$fieldName] = array($old => $value);
if ($this->isNew() && $this->_class->isIdentifier($fieldName)) {
$this->_id[$fieldName] = $value;
}
switch ($this->_state) {
case Doctrine_Entity::STATE_CLEAN:
$this->_state = Doctrine_Entity::STATE_DIRTY;
break;
case Doctrine_Entity::STATE_TCLEAN:
$this->_state = Doctrine_Entity::STATE_TDIRTY;
break;
}
}
} else if ($this->_class->hasRelation($fieldName)) {
$this->_rawSetReference($fieldName, $value);
@ -1253,7 +1203,7 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
*/
final public function isNew()
{
return $this->_state == self::STATE_TCLEAN || $this->_state == self::STATE_TDIRTY;
return $this->_state == self::STATE_NEW;
}
/**
@ -1264,8 +1214,7 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
*/
final public function isModified()
{
return ($this->_state === Doctrine_Entity::STATE_DIRTY ||
$this->_state === Doctrine_Entity::STATE_TDIRTY);
return count($this->_modified) > 0;
}
/**
@ -1349,44 +1298,33 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
/**
* INTERNAL:
* Assigns an identifier to the entity. This is only intended for use by
* the EntityPersisters or the UnitOfWork.
*
* @param integer $id
* @return void
* @todo Not sure this is the right place here.
* @param mixed $id
*/
final public function assignIdentifier($id = false)
final public function _assignIdentifier($id)
{
if ($id === false) {
$this->_id = array();
$this->_state = Doctrine_Entity::STATE_TCLEAN;
$this->_modified = array();
} else if ($id === true) {
$this->_extractIdentifier(true);
$this->_state = Doctrine_Entity::STATE_CLEAN;
$this->_modified = array();
} else {
if (is_array($id)) {
foreach ($id as $fieldName => $value) {
$this->_id[$fieldName] = $value;
$this->_data[$fieldName] = $value;
}
} else {
$idFieldNames = $this->_class->getIdentifier();
$name = $idFieldNames[0];
$this->_id[$name] = $id;
$this->_data[$name] = $id;
if (is_array($id)) {
foreach ($id as $fieldName => $value) {
$this->_id[$fieldName] = $value;
$this->_data[$fieldName] = $value;
}
$this->_state = self::STATE_CLEAN;
$this->_modified = array();
} else {
$name = $this->_class->getSingleIdentifierFieldName();
$this->_id[$name] = $id;
$this->_data[$name] = $id;
}
$this->_modified = array();
}
/**
* returns the primary keys of this object
* INTERNAL:
* Returns the primary keys of the entity (key => value pairs).
*
* @return array
*/
final public function identifier()
final public function _identifier()
{
return $this->_id;
}
@ -1656,13 +1594,13 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
{
$this->getNode()->delete();
}*/
/**
* Gets the ClassMetadata object that describes the entity class.
*
* @return Doctrine::ORM::Mapping::ClassMetadata
*/
final public function getClassMetadata()
final public function getClass()
{
return $this->_class;
}

View File

@ -42,6 +42,10 @@
*/
class Doctrine_EntityManager
{
const FLUSHMODE_AUTO = 'auto';
const FLUSHMODE_COMMIT = 'commit';
const FLUSHMODE_MANUAL = 'manual';
/**
* The unique name of the EntityManager. The name is used to bind entity classes
* to certain EntityManagers.
@ -70,11 +74,11 @@ class Doctrine_EntityManager
private static $_flushModes = array(
// auto: Flush occurs automatically after each operation that issues database
// queries. No operations are queued.
'auto',
self::FLUSHMODE_AUTO,
// commit: Flush occurs automatically at transaction commit.
'commit',
self::FLUSHMODE_COMMIT,
// manual: Flush occurs never automatically.
'manual'
self::FLUSHMODE_MANUAL
);
/**
@ -242,7 +246,7 @@ class Doctrine_EntityManager
*/
public function detach(Doctrine_Entity $entity)
{
return $this->_unitOfWork->unregisterIdentity($entity);
return $this->_unitOfWork->removeFromIdentityMap($entity);
}
/**
@ -287,7 +291,7 @@ class Doctrine_EntityManager
*/
public function flush()
{
$this->_unitOfWork->flush();
$this->_unitOfWork->commit();
}
/**
@ -386,6 +390,9 @@ class Doctrine_EntityManager
public function save(Doctrine_Entity $entity)
{
$this->_unitOfWork->save($entity);
if ($this->_flushMode == self::FLUSHMODE_AUTO) {
$this->flush();
}
}
/**
@ -453,7 +460,7 @@ class Doctrine_EntityManager
return $entity;
} else {
$entity = new $className;
$this->_unitOfWork->registerIdentity($entity);
$this->_unitOfWork->addToIdentityMap($entity);
}
}
} else {
@ -469,6 +476,17 @@ class Doctrine_EntityManager
return $entity;
}
/**
* Checks if the instance is managed by the EntityManager.
*
* @return boolean
*/
public function contains(Doctrine_Entity $entity)
{
return $this->_unitOfWork->isInIdentityMap($entity) &&
! $this->_unitOfWork->isRegisteredRemoved($entity);
}
/**
* INTERNAL:
* For internal hydration purposes only.
@ -546,7 +564,7 @@ class Doctrine_EntityManager
}
/**
* Gets the COnfiguration used by the EntityManager.
* Gets the Configuration used by the EntityManager.
*
* @return Configuration
*/
@ -555,6 +573,16 @@ class Doctrine_EntityManager
return $this->_config;
}
/**
* Gets the UnitOfWork used by the EntityManager to coordinate operations.
*
* @return Doctrine::ORM::UnitOfWork
*/
public function getUnitOfWork()
{
return $this->_unitOfWork;
}
}
?>

View File

@ -1,6 +1,6 @@
<?php
/*
* $Id$
* $Id: EventListener.php 4653 2008-07-10 17:17:58Z romanb $
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@ -20,18 +20,13 @@
*/
/**
* Doctrine_EventListener all event listeners extend this base class
* the empty methods allow child classes to only implement the methods they need to implement
*
* EventSubscriber.
*
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @package Doctrine
* @subpackage EventListener
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 2.0
* @version $Revision$
* @todo Remove. The 2.0 event system has no listener interfaces.
* @version $Revision: 4653 $
*/
interface Doctrine_EventSubscriber
{

View File

@ -31,7 +31,8 @@
* @since 1.0
* @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Roman Borschel <roman@code-factory.org>
* @author Roman Borschel <roman@code-factory.org>
* @todo Rename to DoctrineException
*/
class Doctrine_Exception extends Exception
{

View File

@ -72,7 +72,7 @@ class Doctrine_Hydrator_RecordDriver
public function initRelatedCollection(Doctrine_Entity $entity, $name)
{
if ( ! isset($this->_initializedRelations[$entity->getOid()][$name])) {
$relation = $entity->getClassMetadata()->getRelation($name);
$relation = $entity->getClass()->getRelation($name);
$relatedClass = $relation->getTable();
$coll = $this->getElementCollection($relatedClass->getClassName());
$coll->setReference($entity, $relation);

View File

@ -519,16 +519,12 @@ class Doctrine_HydratorNew extends Doctrine_Hydrator_Abstract
* $table->prepareValue($field, $value); // Doctrine_Null
* </code>
*
* @throws Doctrine_Table_Exception if unserialization of array/object typed column fails or
* @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
* @todo To EntityManager. Make private and use in createEntity().
* .. Or, maybe better: Move to hydrator for performance reasons.
*/
public function prepareValue(Doctrine_ClassMetadata $class, $fieldName, $value, $typeHint = null)
{
@ -540,15 +536,17 @@ class Doctrine_HydratorNew extends Doctrine_Hydrator_Abstract
$type = is_null($typeHint) ? $class->getTypeOf($fieldName) : $typeHint;
switch ($type) {
case 'integer':
case 'string';
// don't do any casting here PHP INT_MAX is smaller than what the databases support
break;
case 'string':
case 'enum':
return $class->enumValue($fieldName, $value);
break;
case 'boolean':
return (boolean) $value;
// don't do any conversions on primitive types
break;
//case 'enum':
// return $class->enumValue($fieldName, $value);
//break;
//case 'boolean':
// return (boolean) $value;
//break;
case 'array':
case 'object':
if (is_string($value)) {

View File

@ -0,0 +1,110 @@
<?php
#namespace Doctrine::ORM::Internal;
/**
* The CommitOrderCalculator is used by the UnitOfWork to sort out the
* correct order in which changes to entities need to be persisted.
*
* @since 2.0
* @todo Rename to: CommitOrderCalculator
* @author Roman Borschel <roman@code-factory.org>
*/
class Doctrine_Internal_CommitOrderCalculator
{
private $_currentTime;
/**
* The node list used for sorting.
*
* @var array
*/
private $_nodes = array();
/**
* The topologically sorted list of items. Note that these are not nodes
* but the wrapped items.
*
* @var array
*/
private $_sorted;
/**
* Orders the given list of CommitOrderNodes based on their dependencies.
*
* Uses a depth-first search (DFS) to traverse the graph.
* The desired topological sorting is the reverse postorder of these searches.
*
* @param array $nodes The list of (unordered) CommitOrderNodes.
* @return array The list of ordered items. These are the items wrapped in the nodes.
*/
public function getCommitOrder()
{
// Check whether we need to do anything. 0 or 1 node is easy.
$nodeCount = count($this->_nodes);
if ($nodeCount == 0) {
return array();
} else if ($nodeCount == 1) {
$node = array_pop($this->_nodes);
return array($node->getClass());
}
$this->_sorted = array();
// Init
foreach ($this->_nodes as $node) {
$node->markNotVisited();
$node->setPredecessor(null);
}
$this->_currentTime = 0;
// Go
foreach ($this->_nodes as $node) {
if ($node->isNotVisited()) {
$node->visit();
}
}
return $this->_sorted;
}
public function addNode($key, $node)
{
$this->_nodes[$key] = $node;
}
public function addNodeWithItem($key, $item)
{
$this->_nodes[$key] = new Doctrine_Internal_CommitOrderNode($item, $this);
}
public function getNodeForKey($key)
{
return $this->_nodes[$key];
}
public function hasNodeWithKey($key)
{
return isset($this->_nodes[$key]);
}
public function clear()
{
$this->_nodes = array();
$this->_sorted = array();
}
public function getNextTime()
{
return ++$this->_currentTime;
}
public function prependNode($node)
{
array_unshift($this->_sorted, $node->getClass());
}
}
?>

View File

@ -0,0 +1,136 @@
<?php
#namespace Doctrine::ORM::Internal;
#use Doctrine::ORM::Mapping::ClassMetadata;
/**
* A CommitOrderNode is a temporary wrapper around ClassMetadata objects
* that is used to sort the order of commits.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
*/
class Doctrine_Internal_CommitOrderNode
{
const NOT_VISITED = 1;
const IN_PROGRESS = 2;
const VISITED = 3;
private $_traversalState;
private $_predecessor;
private $_status;
private $_calculator;
private $_relatedNodes = array();
private $_discoveryTime;
private $_finishingTime;
private $_wrappedObj;
private $_relationEdges = array();
public function __construct($wrappedObj, Doctrine_Internal_CommitOrderCalculator $calc)
{
$this->_wrappedObj = $wrappedObj;
$this->_calculator = $calc;
}
public function getClass()
{
return $this->_wrappedObj;
}
public function setPredecessor($node)
{
$this->_predecessor = $node;
}
public function getPredecessor()
{
return $this->_predecessor;
}
public function markNotVisited()
{
$this->_traversalState = self::NOT_VISITED;
}
public function markInProgress()
{
$this->_traversalState = self::IN_PROGRESS;
}
public function markVisited()
{
$this->_traversalState = self::VISITED;
}
public function isNotVisited()
{
return $this->_traversalState == self::NOT_VISITED;
}
public function isInProgress()
{
return $this->_traversalState == self::IN_PROGRESS;
}
public function visit()
{
$this->markInProgress();
$this->setDiscoveryTime($this->_calculator->getNextTime());
foreach ($this->getRelatedNodes() as $node) {
if ($node->isNotVisited()) {
$node->setPredecessor($this);
$node->visit();
}
if ($node->isInProgress()) {
// back edge => cycle
//TODO: anything to do here?
}
}
$this->markVisited();
$this->_calculator->prependNode($this);
$this->setFinishingTime($this->_calculator->getNextTime());
}
public function setDiscoveryTime($time)
{
$this->_discoveryTime = $time;
}
public function setFinishingTime($time)
{
$this->_finishingTime = $time;
}
public function getDiscoveryTime()
{
return $this->_discoveryTime;
}
public function getFinishingTime()
{
return $this->_finishingTime;
}
public function getRelatedNodes()
{
return $this->_relatedNodes;
}
/**
* Adds a directed dependency (an edge). "$this -before-> $other".
*
* @param Doctrine_Internal_CommitOrderNode $node
*/
public function before(Doctrine_Internal_CommitOrderNode $node)
{
$this->_relatedNodes[] = $node;
}
}
?>

View File

@ -12,6 +12,22 @@ class Doctrine_MappingException extends Doctrine_Exception
return new self("No identifier specified for Entity '$entityName'."
. " Every Entity must have an identifier.");
}
public static function invalidInheritanceType($type)
{
return new self("The inheritance type '$type' does not exist.");
}
public static function invalidInheritanceOption($name)
{
return new self("The inheritance option '$name' does not exist.");
}
public static function generatorNotAllowedWithCompositeId()
{
return new self("Id generators can't be used with a composite id.");
}
}
?>

View File

@ -30,7 +30,7 @@
* @since 1.0
* @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @todo Really needed?
* @todo Really needed? Remove.
*/
interface Doctrine_Overloadable {
/**

View File

@ -28,6 +28,7 @@
* @since 1.0
* @version $Revision$
* @author Joe Simms <joe.simms@websites4.com>
* @todo Move to NestedSet behavior.
*/
class Doctrine_Tree
{

View File

@ -33,6 +33,7 @@
* @version $Revision$
* @author Roman Borschel <roman@code-factory.org>
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @todo Move to validator package.
*/
class Doctrine_Validator
{

View File

@ -0,0 +1,74 @@
<?php
require_once 'lib/DoctrineTestInit.php';
class Orm_Associations_CascadeTest extends Doctrine_OrmTestCase
{
protected function setUp() {
;
}
protected function tearDown() {
;
}
public function testDeleteCascade()
{
$container = array();
$cascade = new DeleteCascade();
$cascade->cascade($entity, $container);
}
}
abstract class Cascade
{
public function cascade(Doctrine_Entity $record, array &$container)
{
if ($this->shouldCascadeTo($record)) {
$container[$record->getOid()] = $record;
}
foreach ($record->getTable()->getRelations() as $relation) {
if ($this->doCascade($relation)) {
$this->prepareCascade($record, $relation);
$relatedObjects = $record->get($relation->getAlias());
if ($relatedObjects instanceof Doctrine_Record && $this->shouldCascadeTo($relatedObjects)
&& ! isset($container[$relatedObjects->getOid()])) {
$this->cascade($relatedObjects, $container);
} else if ($relatedObjects instanceof Doctrine_Collection && count($relatedObjects) > 0) {
foreach ($relatedObjects as $object) {
if ( ! isset($container[$object->getOid()])) {
$this->cascade($object, $container);
}
}
}
}
}
}
}
class DeleteCascade extends Cascade
{
public function doCascade($relation)
{
return $relation->isCascadeDelete();
}
public function prepareCascade($record, $relation)
{
$fieldName = $relation->getAlias();
// if it's a xToOne relation and the related object is already loaded
// we don't need to refresh, else we need to.
if ( ! ($relation->getType() == Doctrine_Relation::ONE && isset($record->$fieldName))) {
$record->refreshRelated($relation->getAlias());
}
}
public function shouldCascadeTo(Doctrine_Entity $entity)
{
//TODO: also ignore removed Entities. incorporate that in exists() with a new
// state? (DELETED?)
return ! $entity->exists();
}
}

View File

@ -0,0 +1,36 @@
<?php
require_once 'lib/DoctrineTestInit.php';
class Orm_Associations_OneToOneMappingTest extends Doctrine_OrmTestCase
{
public function testCorrectOneToOneBidirectionalMapping()
{
$owningSideMapping = array(
'fieldName' => 'address',
'targetEntity' => 'Address',
'joinColumns' => array('address_id' => 'id'),
'sourceEntity' => 'Person' // This is normally filled by ClassMetadata
);
$oneToOneMapping = new Doctrine_Association_OneToOne($owningSideMapping);
$this->assertEquals(array('address_id' => 'id'), $oneToOneMapping->getSourceToTargetKeyColumns());
$this->assertEquals(array('id' => 'address_id'), $oneToOneMapping->getTargetToSourceKeyColumns());
$this->assertEquals('Address', $oneToOneMapping->getTargetEntityName());
$this->assertEquals('Person', $oneToOneMapping->getSourceEntityName());
$this->assertEquals('address', $oneToOneMapping->getSourceFieldName());
$this->assertTrue($oneToOneMapping->isOwningSide());
$inverseSideMapping = array(
'mappedBy' => 'address'
);
$oneToOneMapping = new Doctrine_Association_OneToOne($inverseSideMapping);
$this->assertEquals('address', $oneToOneMapping->getMappedByFieldName());
$this->assertTrue($oneToOneMapping->isInverseSide());
}
}
?>

View File

@ -106,17 +106,17 @@ class Orm_Component_CollectionTest extends Doctrine_OrmTestCase
/**
* @test
*/
public function shouldSetKeyColumnWhenAddingNewRowAsArray()
/*public function shouldSetKeyColumnWhenAddingNewRowAsArray()
{
$this->assertTrue(isset($this->cmsColl['test']));
$this->assertEquals($this->cmsUser, $this->cmsColl['test']);
}
}*/
/**
* @test
*/
public function shouldSerializeAndUnserializeCollectionWithData()
/*public function shouldSerializeAndUnserializeCollectionWithData()
{
$serialized = serialize($this->cmsColl);
$coll = unserialize($serialized);
@ -126,6 +126,6 @@ class Orm_Component_CollectionTest extends Doctrine_OrmTestCase
$user = $coll['test'];
$this->assertTrue($user instanceOf CmsUser);
$this->assertEquals('test', $user['username']);
}
}*/
}

View File

@ -22,12 +22,21 @@ class Orm_Entity_AccessorTest extends Doctrine_OrmTestCase
class CustomAccessorMutatorTestEntity extends Doctrine_Entity
{
public static function initMetadata($class)
public static function initMetadata($mapping)
{
$class->mapColumn('id', 'integer', 4, array('primary'));
$class->mapColumn('username', 'string', 50, array(
'accessor' => 'getUsernameCustom',
'mutator' => 'setUsernameCustom'));
$mapping->mapField(array(
'fieldName' => 'id',
'type' => 'integer',
'length' => 4,
'id' => true
));
$mapping->mapField(array(
'fieldName' => 'username',
'type' => 'string',
'length' => 50,
'accessor' => 'getUsernameCustom',
'mutator' => 'setUsernameCustom'
));
}
public function getUsernameCustom()
@ -43,10 +52,19 @@ class CustomAccessorMutatorTestEntity extends Doctrine_Entity
class MagicAccessorMutatorTestEntity extends Doctrine_Entity
{
public static function initMetadata($class)
public static function initMetadata($mapping)
{
$class->mapColumn('id', 'integer', 4, array('primary'));
$class->mapColumn('username', 'string', 50, array());
$mapping->mapField(array(
'fieldName' => 'id',
'type' => 'integer',
'length' => 4,
'id' => true
));
$mapping->mapField(array(
'fieldName' => 'username',
'type' => 'string',
'length' => 50
));
}
public function getUsername()

View File

@ -22,10 +22,19 @@ class ConstructorTestEntity1 extends Doctrine_Entity
}
/* The mapping definition */
public static function initMetadata($class)
public static function initMetadata($mapping)
{
$class->mapColumn('id', 'integer', 4, array('primary'));
$class->mapColumn('username', 'string', 50, array());
$mapping->mapField(array(
'fieldName' => 'id',
'type' => 'integer',
'length' => 4,
'id' => true
));
$mapping->mapField(array(
'fieldName' => 'username',
'type' => 'string',
'length' => 50
));
}
}

View File

@ -1,59 +1,160 @@
<?php
require_once 'lib/DoctrineTestInit.php';
require_once 'lib/mocks/Doctrine_EntityManagerMock.php';
require_once 'lib/mocks/Doctrine_ConnectionMock.php';
/**
* UnitOfWork tests.
* These tests run without a database through mocking the
* persister/connection/sequence used by the UnitOfWork.
*/
class Orm_UnitOfWorkTest extends Doctrine_OrmTestCase
{
private $_unitOfWork;
private $_user;
// Mocks
// Provides a sequence mock to the UnitOfWork
private $_connectionMock;
// The sequence mock
private $_sequenceMock;
// The persister mock used by the UnitOfWork
private $_persisterMock;
// The EntityManager mock that provides the mock persister
private $_emMock;
protected function setUp() {
parent::setUp();
$this->_user = new ForumUser();
$this->_unitOfWork = new Doctrine_Connection_UnitOfWork($this->_em);
$this->_user->id = 1;
$this->_user->username = 'romanb';
$this->_connectionMock = new Doctrine_ConnectionMock(array());
$this->_sequenceMock = $this->_connectionMock->getSequenceModule();
$this->_emMock = new Doctrine_EntityManagerMock($this->_connectionMock);
$this->_persisterMock = $this->_emMock->getEntityPersister("ForumUser");
$this->_unitOfWork = $this->_emMock->getUnitOfWork();
}
protected function tearDown() {
$this->_user->free();
}
/* Basic registration tests */
public function testRegisterNew()
{
$this->_user->username = 'romanb';
$this->_user->id = 1;
// registerNew() is normally called in save()/persist()
$this->_unitOfWork->registerNew($this->_user);
$this->assertTrue($this->_unitOfWork->isRegisteredNew($this->_user));
$this->assertTrue($this->_unitOfWork->contains($this->_user));
$this->assertTrue($this->_unitOfWork->isInIdentityMap($this->_user));
$this->assertFalse($this->_unitOfWork->isRegisteredDirty($this->_user));
$this->assertFalse($this->_unitOfWork->isRegisteredRemoved($this->_user));
}
/*public function testRegisterNewPerf() {
$s = microtime(true);
for ($i=1; $i<40000; $i++) {
$user = new ForumUser();
$user->id = $i;
$this->_unitOfWork->registerNew($user);
}
$e = microtime(true);
echo $e - $s . " seconds" . PHP_EOL;
}*/
public function testRegisterDirty()
{
$this->_user->username = 'romanb';
$this->_user->id = 1;
$this->assertEquals(Doctrine_Entity::STATE_TDIRTY, $this->_user->_state());
$this->assertFalse($this->_unitOfWork->contains($this->_user));
$this->assertEquals(Doctrine_Entity::STATE_NEW, $this->_user->_state());
$this->assertFalse($this->_unitOfWork->isInIdentityMap($this->_user));
$this->_unitOfWork->registerDirty($this->_user);
$this->assertTrue($this->_unitOfWork->isRegisteredDirty($this->_user));
$this->assertFalse($this->_unitOfWork->isRegisteredNew($this->_user));
$this->assertFalse($this->_unitOfWork->isRegisteredRemoved($this->_user));
}
public function testRegisterRemovedOnTransientEntityIsIgnored()
public function testRegisterRemovedOnNewEntityIsIgnored()
{
$this->_user->username = 'romanb';
$this->_user->id = 1;
$this->assertFalse($this->_unitOfWork->isRegisteredRemoved($this->_user));
$this->_unitOfWork->registerRemoved($this->_user);
$this->_unitOfWork->registerDeleted($this->_user);
$this->assertFalse($this->_unitOfWork->isRegisteredRemoved($this->_user));
}
/*public function testSavedEntityHasIdentityAndIsManaged()
/* Operational tests */
public function testSavingSingleEntityWithIdentityColumnForcesInsert()
{
$this->_user->username = 'romanb';
$this->_user->save();
$this->assertTrue($this->_unitOfWork->hasIdentity($this->_user));
$this->assertTrue($this->_unitOfWork->isManaged($this->_user));
}*/
$this->assertEquals(Doctrine_Entity::STATE_NEW, $this->_user->_state());
$this->_unitOfWork->save($this->_user);
$this->assertEquals(1, count($this->_persisterMock->getInserts())); // insert forced
$this->assertEquals(0, count($this->_persisterMock->getUpdates()));
$this->assertEquals(0, count($this->_persisterMock->getDeletes()));
$this->assertTrue($this->_unitOfWork->isInIdentityMap($this->_user));
$this->assertEquals(Doctrine_Entity::STATE_MANAGED, $this->_user->_state());
// should no longer be scheduled for insert
$this->assertFalse($this->_unitOfWork->isRegisteredNew($this->_user));
// should have an id
$this->assertTrue(is_numeric($this->_user->id));
// Now lets check whether a subsequence commit() does anything
$this->_persisterMock->reset();
$this->_unitOfWork->commit(); // shouldnt do anything
// verify that nothing happened
$this->assertEquals(0, count($this->_persisterMock->getInserts()));
$this->assertEquals(0, count($this->_persisterMock->getUpdates()));
$this->assertEquals(0, count($this->_persisterMock->getDeletes()));
}
public function testSavingSingleEntityWithSequenceIdGeneratorSchedulesInsert()
{
//...
}
public function testSavingSingleEntityWithTableIdGeneratorSchedulesInsert()
{
//...
}
public function testSavingSingleEntityWithSingleNaturalIdForcesInsert()
{
//...
}
public function testSavingSingleEntityWithCompositeIdForcesInsert()
{
//...
}
public function testSavingEntityGraphWithIdentityColumnsForcesInserts()
{
//...
}
public function testSavingEntityGraphWithSequencesDelaysInserts()
{
//...
}
public function testSavingEntityGraphWithNaturalIdsForcesInserts()
{
//...
}
public function testSavingEntityGraphWithMixedIdGenerationStrategies()
{
//...
}
}

View File

@ -0,0 +1,20 @@
<?php
require_once 'lib/mocks/Doctrine_SequenceMock.php';
class Doctrine_ConnectionMock extends Doctrine_Connection
{
protected $_driverName = 'Mysql';
private $_sequenceModuleMock;
public function getSequenceModule()
{
if ( ! $this->_sequenceModuleMock) {
$this->_sequenceModuleMock = new Doctrine_SequenceMock($this);
}
return $this->_sequenceModuleMock;
}
}
?>

View File

@ -0,0 +1,25 @@
<?php
require_once 'lib/mocks/Doctrine_EntityPersisterMock.php';
class Doctrine_EntityManagerMock extends Doctrine_EntityManager
{
private $_persisterMock;
/**
* Enter description here...
*
* @param unknown_type $entityName
* @override
*/
public function getEntityPersister($entityName)
{
if ( ! $this->_persisterMock) {
$this->_persisterMock = new Doctrine_EntityPersisterMock($this, $this->getClassMetadata($entityName));
}
return $this->_persisterMock;
}
}
?>

View File

@ -0,0 +1,56 @@
<?php
class Doctrine_EntityPersisterMock extends Doctrine_EntityPersister_Standard
{
private $_inserts = array();
private $_updates = array();
private $_deletes = array();
private $_identityColumnValueCounter = 0;
public function insert($entity)
{
if ($entity->getClass()->isIdGeneratorIdentity()) {
$entity->_assignIdentifier($this->_identityColumnValueCounter++);
$this->_em->getUnitOfWork()->addToIdentityMap($entity);
}
$this->_inserts[] = $entity;
}
public function update($entity)
{
$this->_updates[] = $entity;
}
public function delete($entity)
{
$this->_deletes[] = $entity;
}
public function getInserts()
{
return $this->_inserts;
}
public function getUpdates()
{
return $this->_updates;
}
public function getDeletes()
{
return $this->_deletes;
}
public function reset()
{
$this->_identityColumnValueCounter = 0;
$this->_inserts = array();
$this->_updates = array();
$this->_deletes = array();
}
}
?>

View File

@ -0,0 +1,37 @@
<?php
class Doctrine_SequenceMock extends Doctrine_Sequence
{
private $_sequenceNumber = 0;
/**
* @override
*/
public function nextId($seqName, $ondemand = true)
{
return $this->_sequenceNumber++;
}
/**
* @override
*/
public function lastInsertId($table = null, $field = null)
{
return $this->_sequenceNumber - 1;
}
/**
* @override
*/
public function currId($seqName)
{
return $this->_sequenceNumber;
}
public function reset()
{
$this->_sequenceNumber = 0;
}
}
?>

View File

@ -1,13 +1,40 @@
<?php
#namespace Doctrine::Tests::ORM::Models::CMS;
#use Doctrine::ORM::Entity;
class CmsArticle extends Doctrine_Entity
{
public static function initMetadata($class)
{
$class->mapColumn('id', 'integer', 4, array('primary' => true, 'autoincrement' => true));
$class->mapColumn('topic', 'string', 255);
$class->mapColumn('text', 'string');
$class->mapColumn('user_id', 'integer', 4);
$class->hasMany('CmsComment as comments', array(
'local' => 'id', 'foreign' => 'article_id'));
}
#protected $id;
#protected $topic;
#protected $text;
#protected $user_id;
public static function initMetadata($mapping)
{
$mapping->mapField(array(
'fieldName' => 'id',
'type' => 'integer',
'length' => 4,
'id' => true,
'generatorType' => 'auto'
));
$mapping->mapField(array(
'fieldName' => 'topic',
'type' => 'string',
'length' => 255
));
$mapping->mapField(array(
'fieldName' => 'text',
'type' => 'string'
));
$mapping->mapField(array(
'fieldName' => 'user_id',
'type' => 'integer',
'length' => 4
));
$mapping->hasMany('CmsComment as comments', array(
'local' => 'id', 'foreign' => 'article_id'));
}
}

View File

@ -1,11 +1,38 @@
<?php
#namespace Doctrine::Tests::ORM::Models::CMS;
#use Doctrine::ORM::Entity;
class CmsComment extends Doctrine_Entity
{
public static function initMetadata($class)
{
$class->mapColumn('id', 'integer', 4, array('primary' => true, 'autoincrement' => true));
$class->mapColumn('topic', 'string', 255);
$class->mapColumn('text', 'string');
$class->mapColumn('article_id', 'integer', 4);
}
#protected $id;
#protected $topic;
#protected $text;
#protected $article_id;
public static function initMetadata($mapping)
{
$mapping->mapField(array(
'fieldName' => 'id',
'type' => 'integer',
'length' => 4,
'id' => true,
'generatorType' => 'auto'
));
$mapping->mapField(array(
'fieldName' => 'topic',
'type' => 'string',
'length' => 255
));
$mapping->mapField(array(
'fieldName' => 'text',
'type' => 'string'
));
$mapping->mapField(array(
'fieldName' => 'article_id',
'type' => 'integer',
'length' => 4
));
}
}

View File

@ -1,9 +1,21 @@
<?php
class CmsPhonenumber extends Doctrine_Entity
{
public static function initMetadata($class)
{
$class->mapColumn('user_id', 'integer', 4);
$class->mapColumn('phonenumber', 'string', 50, array('primary' => true));
}
#protected $user_id;
#protected $phonenumber;
public static function initMetadata($mapping)
{
$mapping->mapField(array(
'fieldName' => 'user_id',
'type' => 'integer',
'length' => 4
));
$mapping->mapField(array(
'fieldName' => 'phonenumber',
'type' => 'string',
'length' => 50,
'id' => true
));
}
}

View File

@ -1,16 +1,44 @@
<?php
#namespace Doctrine::Test::ORM::Models;
#use Doctrine::ORM::Entity;
class CmsUser extends Doctrine_Entity
{
public static function initMetadata($class)
{
$class->mapColumn('id', 'integer', 4, array('primary' => true, 'autoincrement' => true));
$class->mapColumn('status', 'string', 50);
$class->mapColumn('username', 'string', 255);
$class->mapColumn('name', 'string', 255);
$class->hasMany('CmsPhonenumber as phonenumbers', array(
#protected $id;
#protected $status;
#protected $username;
#protected $name;
public static function initMetadata($mapping)
{
$mapping->mapField(array(
'fieldName' => 'id',
'type' => 'integer',
'length' => 4,
'id' => true,
'generatorType' => 'auto'
));
$mapping->mapField(array(
'fieldName' => 'status',
'type' => 'string',
'length' => 50
));
$mapping->mapField(array(
'fieldName' => 'username',
'type' => 'string',
'length' => 255
));
$mapping->mapField(array(
'fieldName' => 'name',
'type' => 'string',
'length' => 255
));
$mapping->hasMany('CmsPhonenumber as phonenumbers', array(
'local' => 'id', 'foreign' => 'user_id'));
$class->hasMany('CmsArticle as articles', array(
$mapping->hasMany('CmsArticle as articles', array(
'local' => 'id', 'foreign' => 'user_id'));
}
}
}

View File

@ -2,9 +2,14 @@
class ForumAdministrator extends ForumUser
{
public static function initMetadata($class)
public static function initMetadata($mapping)
{
$class->mapColumn('access_level as accessLevel', 'integer', 1);
$mapping->mapField(array(
'fieldName' => 'accessLevel',
'columnName' => 'access_level',
'type' => 'integer',
'length' => 1
));
}
public function banUser(ForumUser $user) {}

View File

@ -1,6 +1,8 @@
<?php
class ForumBoard extends Doctrine_Entity {
public static function initMetadata($metadata) {
class ForumBoard extends Doctrine_Entity
{
public static function initMetadata($mapping)
{
/*$metadata->mapField(array(
'fieldName' => 'id',
'id' => true,
@ -8,10 +10,22 @@ class ForumBoard extends Doctrine_Entity {
'length' => 4
));
*/
$metadata->mapColumn('id', 'integer', 4, array('primary'));
$metadata->mapColumn('position', 'integer');
$metadata->mapColumn('category_id', 'integer');
$metadata->hasOne('ForumCategory as category',
$mapping->mapField(array(
'fieldName' => 'id',
'type' => 'integer',
'length' => 4,
'id' => true
));
$mapping->mapField(array(
'fieldName' => 'position',
'type' => 'integer'
));
$mapping->mapField(array(
'fieldName' => 'category_id',
'type' => 'integer'
));
$mapping->hasOne('ForumCategory as category',
array('local' => 'category_id', 'foreign' => 'id'));
/*
$metadata->mapOneToOne(array(

View File

@ -1,10 +1,26 @@
<?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(
class ForumCategory extends Doctrine_Entity
{
public static function initMetadata($mapping)
{
$mapping->mapField(array(
'fieldName' => 'id',
'type' => 'integer',
'length' => 4,
'id' => true
));
$mapping->mapField(array(
'fieldName' => 'position',
'type' => 'integer'
));
$mapping->mapField(array(
'fieldName' => 'name',
'type' => 'string',
'length' => 255
));
$mapping->hasMany('ForumBoard as boards', array(
'local' => 'id' , 'foreign' => 'category_id'));
}
}

View File

@ -0,0 +1,32 @@
<?php
#namespace Doctrine::Test::ORM::Models;
#use Doctrine::ORM::Entity;
class ForumEntry extends Doctrine_Entity
{
#protected $id;
#protected $topic;
public static function initMetadata($mapping)
{
$mapping->mapField(array(
'fieldName' => 'id',
'type' => 'integer',
'length' => 4,
'id' => true,
'generatorType' => 'auto'
));
$mapping->mapField(array(
'fieldName' => 'topic',
'type' => 'string',
'length' => 50
));
}
}
?>

View File

@ -1,26 +1,46 @@
<?php
#namespace Doctrine::Tests::ORM::Models::Forum;
#use Doctrine::ORM::Entity;
class ForumUser extends Doctrine_Entity
{
public static function initMetadata($class)
#protected $dtype;
#protected $id;
#protected $username;
public static function initMetadata($mapping)
{
// inheritance mapping
$class->setInheritanceType(Doctrine::INHERITANCE_TYPE_JOINED, array(
$mapping->setInheritanceType('joined', array(
'discriminatorColumn' => 'dtype',
'discriminatorMap' => array(
'user' => 'ForumUser',
'admin' => 'ForumAdministrator')
));
// register subclasses
$class->setSubclasses(array('ForumAdministrator'));
$mapping->setSubclasses(array('ForumAdministrator'));
// the discriminator column
$class->mapColumn('dtype', 'string', 50);
$mapping->mapField(array(
'fieldName' => 'dtype',
'type' => 'string',
'length' => 50
));
// column-to-field mapping
$class->mapColumn('id', 'integer', 4, array(
'primary' => true,
'autoincrement' => true));
$class->mapColumn('username', 'string', 50, array());
$mapping->mapField(array(
'fieldName' => 'id',
'type' => 'integer',
'length' => 4,
'id' => true,
'generatorType' => 'auto'
));
$mapping->mapField(array(
'fieldName' => 'username',
'type' => 'string',
'length' => 50
));
}