Commit f9a22281 authored by romanb's avatar romanb

[2.0] Work on ID generators, functional tests and more.

parent 28123182
......@@ -25,13 +25,16 @@ class DoctrineException extends \Exception
public static function __callStatic($method, $arguments)
{
$class = get_called_class();
$messageKey = substr($class, strrpos($class, '\\') + 1) . "#$method";
$end = end($arguments);
if ($end instanceof Exception) {
$this->_innerException = $end;
unset($arguments[count($arguments) - 1]);
}
if ($message = self::getExceptionMessage($method)) {
if ($message = self::getExceptionMessage($messageKey)) {
$message = sprintf($message, $arguments);
} else {
$message = strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $method));
......@@ -42,22 +45,25 @@ class DoctrineException extends \Exception
}
$message .= ' (' . implode(', ', $args) . ')';
}
$class = get_called_class();
return new $class($message);
}
public static function getExceptionMessage($method)
public static function getExceptionMessage($messageKey)
{
if ( ! self::$_messages) {
// Lazy-init messages
self::$_messages = array(
'partialObjectsAreDangerous' =>
'DoctrineException#partialObjectsAreDangerous' =>
"Loading partial objects is dangerous. Fetch full objects or consider " .
"using a different fetch mode. If you really want partial objects, " .
"set the doctrine.forcePartialLoad query hint to TRUE."
"set the doctrine.forcePartialLoad query hint to TRUE.",
'QueryException#nonUniqueResult' =>
"The query contains more than one result."
);
}
if (isset(self::$_messages[$method])) {
return self::$_messages[$method];
if (isset(self::$_messages[$messageKey])) {
return self::$_messages[$messageKey];
}
return false;
}
......
......@@ -515,7 +515,7 @@ class Connection
{
$this->connect();
try {
echo $query . PHP_EOL;
echo "DBAL:" . $query . PHP_EOL;
if ( ! empty($params)) {
$stmt = $this->prepare($query);
$stmt->execute($params);
......@@ -756,6 +756,7 @@ class Connection
*/
public function getWrappedConnection()
{
$this->connect();
return $this->_conn;
}
......
......@@ -28,7 +28,18 @@ class Driver implements \Doctrine\DBAL\Driver
*/
private function _constructPdoDsn(array $params)
{
//TODO
$dsn = 'pgsql:';
if (isset($params['host'])) {
$dsn .= 'host=' . $params['host'] . ' ';
}
if (isset($params['port'])) {
$dsn .= 'port=' . $params['port'] . ' ';
}
if (isset($params['dbname'])) {
$dsn .= 'dbname=' . $params['dbname'] . ' ';
}
return $dsn;
}
public function getDatabasePlatform()
......
......@@ -108,13 +108,6 @@ class EntityManager
*/
private $_eventManager;
/**
* The maintained (cached) Id generators.
*
* @var array
*/
private $_idGenerators = array();
/**
* The maintained (cached) hydrators. One instance per type.
*
......@@ -202,38 +195,6 @@ class EntityManager
{
return $this->_metadataFactory->getMetadataFor($className);
}
/**
* Gets an IdGenerator that can be used to generate identifiers for the specified
* class.
*/
public function getIdGenerator($className)
{
if (!isset($this->_idGenerators[$className])) {
$this->_idGenerators[$className] = $this->_createIdGenerator(
$this->getClassMetadata($className)->getIdGeneratorType());
}
return $this->_idGenerators[$className];
}
/**
* Used to lazily create an ID generator.
*
* @param string $generatorType
* @return object
*/
protected function _createIdGenerator($generatorType)
{
if ($generatorType == ClassMetadata::GENERATOR_TYPE_IDENTITY) {
return new \Doctrine\ORM\Id\IdentityGenerator($this);
} else if ($generatorType == ClassMetadata::GENERATOR_TYPE_SEQUENCE) {
return new \Doctrine\ORM\Id\SequenceGenerator($this);
} else if ($generatorType == ClassMetadata::GENERATOR_TYPE_TABLE) {
return new \Doctrine\ORM\Id\TableGenerator($this);
} else {
return new \Doctrine\ORM\Id\Assigned($this);
}
}
/**
* Creates a new Query object.
......@@ -265,7 +226,7 @@ class EntityManager
* Creates a query with the specified name.
*
* @todo Implementation.
* @throws SomeException If there is no query registered with the given name.
* @throws DoctrineException If there is no query registered with the given name.
*/
public function createNamedQuery($name)
{
......
<?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.doctrine-project.org>.
*/
namespace Doctrine\ORM\Export;
use Doctrine\ORM\EntityManager;
/**
* The ClassExporter can generate database schemas/structures from ClassMetadata
* class descriptors.
*
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
* @author Roman Borschel <roman@code-factory.org>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision: 4805 $
*/
class ClassExporter
{
/** The SchemaManager */
private $_sm;
/** The EntityManager */
private $_em;
/** The DatabasePlatform */
private $_platform;
/**
* Initializes a new ClassExporter instance that uses the connection of the
* provided EntityManager.
*
* @param Doctrine\ORM\EntityManager $em
*/
public function __construct(EntityManager $em)
{
$this->_em = $em;
$this->_sm = $em->getConnection()->getSchemaManager();
$this->_platform = $em->getConnection()->getDatabasePlatform();
}
/**
* Exports an array of class meta data instances to your database
*
* @param array $classes
*/
public function exportClasses(array $classes)
{
$exportClassesSql = $this->getExportClassesSql($classes);
foreach ($exportClassesSql as $sql) {
$this->_em->getConnection()->execute($sql);
}
}
/**
* Get an array of sql statements for the specified array of class meta data instances
*
* @param array $classes
* @return array $sql
*/
public function getExportClassesSql(array $classes)
{
$sql = array();
$foreignKeyConstraints = array();
// First we create the tables
foreach ($classes as $class) {
$columns = array();
$options = array();
foreach ($class->getFieldMappings() as $fieldName => $mapping) {
$column = array();
$column['name'] = $mapping['columnName'];
$column['type'] = $mapping['type'];
$column['length'] = $mapping['length'];
$column['notnull'] = ! $mapping['nullable'];
if ($class->isIdentifier($fieldName)) {
$column['primary'] = true;
$options['primary'][] = $mapping['columnName'];
if ($class->isIdGeneratorIdentity()) {
$column['autoincrement'] = true;
}
}
$columns[$mapping['columnName']] = $column;
}
foreach ($class->getAssociationMappings() as $mapping) {
$foreignClass = $this->_em->getClassMetadata($mapping->getTargetEntityName());
if ($mapping->isOneToOne() && $mapping->isOwningSide()) {
$constraint = array();
$constraint['tableName'] = $class->getTableName();
$constraint['foreignTable'] = $foreignClass->getTableName();
$constraint['local'] = array();
$constraint['foreign'] = array();
foreach ($mapping->getJoinColumns() as $joinColumn) {
$column = array();
$column['name'] = $joinColumn['name'];
$column['type'] = $foreignClass->getTypeOfColumn($joinColumn['referencedColumnName']);
$columns[$joinColumn['name']] = $column;
$constraint['local'][] = $joinColumn['name'];
$constraint['foreign'][] = $joinColumn['referencedColumnName'];
}
$foreignKeyConstraints[] = $constraint;
} else if ($mapping->isOneToMany() && $mapping->isOwningSide()) {
//... create join table, one-many through join table supported later
\Doctrine\Common\DoctrineException::updateMe("Not yet implemented.");
} else if ($mapping->isManyToMany() && $mapping->isOwningSide()) {
//... create join table
$joinTableColumns = array();
$joinTableOptions = array();
$joinTable = $mapping->getJoinTable();
$constraint1 = array();
$constraint1['tableName'] = $joinTable['name'];
$constraint1['foreignTable'] = $class->getTableName();
$constraint1['local'] = array();
$constraint1['foreign'] = array();
foreach ($joinTable['joinColumns'] as $joinColumn) {
$column = array();
$column['primary'] = true;
$joinTableOptions['primary'][] = $joinColumn['name'];
$column['name'] = $joinColumn['name'];
$column['type'] = $class->getTypeOfColumn($joinColumn['referencedColumnName']);
$joinTableColumns[$joinColumn['name']] = $column;
$constraint1['local'][] = $joinColumn['name'];
$constraint1['foreign'][] = $joinColumn['referencedColumnName'];
}
$foreignKeyConstraints[] = $constraint1;
$constraint2 = array();
$constraint2['tableName'] = $joinTable['name'];
$constraint2['foreignTable'] = $foreignClass->getTableName();
$constraint2['local'] = array();
$constraint2['foreign'] = array();
foreach ($joinTable['inverseJoinColumns'] as $inverseJoinColumn) {
$column = array();
$column['primary'] = true;
$joinTableOptions['primary'][] = $inverseJoinColumn['name'];
$column['name'] = $inverseJoinColumn['name'];
$column['type'] = $this->_em->getClassMetadata($mapping->getTargetEntityName())
->getTypeOfColumn($inverseJoinColumn['referencedColumnName']);
$joinTableColumns[$inverseJoinColumn['name']] = $column;
$constraint2['local'][] = $inverseJoinColumn['name'];
$constraint2['foreign'][] = $inverseJoinColumn['referencedColumnName'];
}
$foreignKeyConstraints[] = $constraint2;
$sql = array_merge($sql, $this->_platform->getCreateTableSql(
$joinTable['name'], $joinTableColumns, $joinTableOptions));
}
}
$sql = array_merge($sql, $this->_platform->getCreateTableSql($class->getTableName(), $columns, $options));
}
// Now create the foreign key constraints
if ($this->_platform->supportsForeignKeyConstraints()) {
foreach ($foreignKeyConstraints as $fkConstraint) {
$sql = array_merge($sql, (array)$this->_platform->getCreateForeignKeySql($fkConstraint['tableName'], $fkConstraint));
}
}
return $sql;
}
}
\ No newline at end of file
......@@ -8,21 +8,14 @@ use Doctrine\ORM\EntityManager;
* Enter description here...
*/
abstract class AbstractIdGenerator
{
protected $_em;
public function __construct(EntityManager $em)
{
$this->_em = $em;
}
{
/**
* Generates an identifier for an entity.
*
* @param Doctrine\ORM\Entity $entity
* @return mixed
*/
abstract public function generate($entity);
abstract public function generate(EntityManager $em, $entity);
/**
* Gets whether this generator is a post-insert generator which means that
......
......@@ -21,6 +21,7 @@
namespace Doctrine\ORM\Id;
use Doctrine\ORM\EntityManager;
use Doctrine\Common\DoctrineException;
/**
......@@ -38,9 +39,9 @@ class Assigned extends AbstractIdGenerator
* @return mixed
* @override
*/
public function generate($entity)
public function generate(EntityManager $em, $entity)
{
$class = $this->_em->getClassMetadata(get_class($entity));
$class = $em->getClassMetadata(get_class($entity));
$identifier = null;
if ($class->isIdentifierComposite()) {
$identifier = array();
......@@ -61,7 +62,7 @@ class Assigned extends AbstractIdGenerator
}
if ( ! $identifier) {
\Doctrine\Common\DoctrineException::updateMe("Entity of type '" . get_class($entity) . "' is missing an assigned ID.");
throw DoctrineException::updateMe("Entity of type '" . get_class($entity) . "' is missing an assigned ID.");
}
return $identifier;
......
......@@ -2,18 +2,20 @@
namespace Doctrine\ORM\Id;
use Doctrine\ORM\EntityManager;
class IdentityGenerator extends AbstractIdGenerator
{
/**
* Enter description here...
* Generates an ID for the given entity.
*
* @param Doctrine_ORM_Entity $entity
* @return unknown
* @param object $entity
* @return integer|float
* @override
*/
public function generate($entity)
public function generate(EntityManager $em, $entity)
{
return $this->_em->getConnection()->lastInsertId();
return $em->getConnection()->lastInsertId();
}
/**
......
<?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.doctrine-project.org>.
*/
namespace Doctrine\ORM\Id;
use Doctrine\ORM\EntityManager;
class SequenceGenerator extends AbstractIdGenerator
/**
* Represents an ID generator that uses a database sequence.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
*/
class SequenceGenerator extends AbstractIdGenerator implements \Serializable
{
private $_allocationSize;
private $_sequenceName;
private $_nextValue = 0;
private $_maxValue = null;
public function __construct(EntityManager $em, $sequenceName, $allocationSize = 20)
/**
* Initializes a new sequence generator.
*
* @param Doctrine\ORM\EntityManager $em The EntityManager to use.
* @param string $sequenceName The name of the sequence.
* @param integer $allocationSize The allocation size of the sequence.
*/
public function __construct($sequenceName, $allocationSize)
{
parent::__construct($em);
$this->_sequenceName = $sequenceName;
$this->_allocationSize = $allocationSize;
}
......@@ -25,11 +56,11 @@ class SequenceGenerator extends AbstractIdGenerator
* @return integer|float The generated value.
* @override
*/
public function generate($entity)
public function generate(EntityManager $em, $entity)
{
if ($this->_maxValue === null || $this->_nextValue == $this->_maxValue) {
// Allocate new values
$conn = $this->_em->getConnection();
$conn = $em->getConnection();
$sql = $conn->getDatabasePlatform()->getSequenceNextValSql($this->_sequenceName);
$this->_maxValue = $conn->fetchOne($sql);
$this->_nextValue = $this->_maxValue - $this->_allocationSize;
......@@ -37,13 +68,38 @@ class SequenceGenerator extends AbstractIdGenerator
return $this->_nextValue++;
}
/**
* Gets the maximum value of the currently allocated bag of values.
*
* @return integer|float
*/
public function getCurrentMaxValue()
{
return $this->_maxValue;
}
/**
* Gets the next value that will be returned by generate().
*
* @return integer|float
*/
public function getNextValue()
{
return $this->_nextValue;
}
public function serialize()
{
return serialize(array(
'allocationSize' => $this->_allocationSize,
'sequenceName' => $this->_sequenceName
));
}
public function unserialize($serialized)
{
$array = unserialize($serialized);
$this->_sequenceName = $array['sequenceName'];
$this->_allocationSize = $array['allocationSize'];
}
}
......@@ -2,6 +2,8 @@
namespace Doctrine\ORM\Id;
use Doctrine\ORM\EntityManager;
class SequenceIdentityGenerator extends IdentityGenerator
{
private $_sequenceName;
......@@ -10,15 +12,18 @@ class SequenceIdentityGenerator extends IdentityGenerator
{
$this->_sequenceName = $sequenceName;
}
public function generate(EntityManager $em, $entity)
{
return $em->getConnection()->lastInsertId($this->_sequenceName);
}
/**
* Enter description here...
*
* @param Doctrine_Connection $conn
* @return boolean
* @override
*/
public function getPostInsertId()
public function isPostInsertGenerator()
{
return $this->_em->getConnection()->lastInsertId($this->_sequenceName);
return true;
}
}
\ No newline at end of file
......@@ -2,6 +2,8 @@
namespace Doctrine\ORM\Id;
use Doctrine\ORM\EntityManager;
/**
* Id generator that uses a single-row database table and a hi/lo algorithm.
*
......@@ -9,7 +11,7 @@ namespace Doctrine\ORM\Id;
*/
class TableGenerator extends AbstractIdGenerator
{
public function generate($entity)
public function generate(EntityManager $em, $entity)
{
throw \Doctrine\Common\DoctrineException::updateMe("Not implemented");
}
......
......@@ -333,6 +333,36 @@ final class ClassMetadata
private $_reflectionProperties;
//private $_insertSql;
/**
* The name of the ID generator used for this class. Only used for SEQUENCE
* and TABLE generation strategies.
*
* @var string
*/
//private $_idGeneratorName;
/**
* The ID generator used for generating IDs for this class.
*
* @var AbstractIdGenerator
*/
private $_idGenerator;
/**
* The definition of the sequence generator of this class. Only used for the
* SEQUENCE generation strategy.
*
* @var array
*/
private $_sequenceGeneratorDefinition;
/**
* The definition of the table generator of this class. Only used for the
* TABLE generation strategy.
*
* @var array
*/
//private $_tableGeneratorDefinition;
/**
* Initializes a new ClassMetadata instance that will hold the object-relational mapping
......@@ -389,7 +419,7 @@ final class ClassMetadata
public function getSingleIdReflectionProperty()
{
if ($this->_isIdentifierComposite) {
\Doctrine\Common\DoctrineException::updateMe("getSingleIdReflectionProperty called on entity with composite key.");
throw DoctrineException::updateMe("getSingleIdReflectionProperty called on entity with composite key.");
}
return $this->_reflectionProperties[$this->_identifier[0]];
}
......@@ -635,17 +665,6 @@ final class ClassMetadata
if ( ! in_array($mapping['fieldName'], $this->_identifier)) {
$this->_identifier[] = $mapping['fieldName'];
}
if (isset($mapping['idGenerator'])) {
if ( ! $this->_isIdGeneratorType($mapping['idGenerator'])) {
//TODO: check if the idGenerator specifies an existing generator by name
throw MappingException::invalidGeneratorType($mapping['idGenerator']);
} else if (count($this->_identifier) > 1) {
throw MappingException::generatorNotAllowedWithCompositeId();
}
$this->_generatorType = $mapping['idGenerator'];
}
// TODO: validate/complete 'tableGenerator' and 'sequenceGenerator' mappings
// Check for composite key
if ( ! $this->_isIdentifierComposite && count($this->_identifier) > 1) {
$this->_isIdentifierComposite = true;
......@@ -719,12 +738,23 @@ final class ClassMetadata
public function getSingleIdentifierFieldName()
{
if ($this->_isIdentifierComposite) {
throw \Doctrine\Common\DoctrineException::updateMe("Calling getSingleIdentifierFieldName "
throw DoctrineException::updateMe("Calling getSingleIdentifierFieldName "
. "on a class that uses a composite identifier is not allowed.");
}
return $this->_identifier[0];
}
/**
* Gets the column name of the single id column. Note that this only works on
* entity classes that have a single-field pk.
*
* @return string
*/
public function getSingleIdentifierColumnName()
{
return $this->getColumnName($this->getSingleIdentifierFieldName());
}
public function setIdentifier(array $identifier)
{
$this->_identifier = $identifier;
......@@ -1067,7 +1097,7 @@ final class ClassMetadata
}
/**
* Sets the primary table definition. The provided array must have th
* Sets the primary table definition. The provided array must have the
* following structure:
*
* name => <tableName>
......@@ -1471,7 +1501,82 @@ final class ClassMetadata
! $this->_associationMappings[$fieldName]->isOneToOne();
}
/** Creates a string representation of the instance. */
/**
* Gets the name of the ID generator used for this class.
* Only classes that use a SEQUENCE or TABLE ID generation strategy have a generator name.
*
* @return string|null The name of the ID generator or NULL if this class does not
* use a named ID generator.
*/
/*public function getIdGeneratorName()
{
return $this->_idGeneratorName;
}*/
/**
* Sets the ID generator used to generate IDs for instances of this class.
*
* @param AbstractIdGenerator $generator
*/
public function setIdGenerator($generator)
{
$this->_idGenerator = $generator;
}
/**
* Gets the ID generator used to generate IDs for instances of this class.
*
* @return AbstractIdGenerator
*/
public function getIdGenerator()
{
return $this->_idGenerator;
}
/**
* Gets the definition of the sequence ID generator for this class.
*
* The definition has the following structure:
* <code>
* array(
* 'sequenceName' => 'name',
* 'allocationSize' => 20,
* 'initialValue' => 1
* )
* </code>
*
* @return array|null An array with the generator definition or NULL if this class
* has no sequence generator definition.
*/
public function getSequenceGeneratorDefinition()
{
return $this->_sequenceGeneratorDefinition;
}
/**
* Sets the definition of the sequence ID generator for this class.
*
* The definition must have the following structure:
* <code>
* array(
* 'sequenceName' => 'name',
* 'allocationSize' => 20,
* 'initialValue' => 1
* )
* </code>
*
* @param array $definition
*/
public function setSequenceGeneratorDefinition(array $definition)
{
$this->_sequenceGeneratorDefinition = $definition;
}
/**
* Creates a string representation of this instance.
*
* @return string The string representation of this instance.
*/
public function __toString()
{
return __CLASS__ . '@' . spl_object_hash($this);
......
......@@ -21,6 +21,7 @@
namespace Doctrine\ORM\Mapping;
use Doctrine\Common\DoctrineException;
use Doctrine\DBAL\Platforms\AbstractPlatform;
/**
......@@ -134,6 +135,11 @@ class ClassMetadataFactory
// Invoke driver
$this->_driver->loadMetadataForClass($className, $class);
// Verify & complete identifier mapping
if ( ! $class->getIdentifier()) {
throw MappingException::identifierRequired($className);
}
$this->_completeIdGeneratorMapping($class);
if ($parent && $parent->isInheritanceTypeSingleTable()) {
......@@ -195,7 +201,8 @@ class ClassMetadataFactory
*/
private function _completeIdGeneratorMapping(ClassMetadata $class)
{
if ($class->getIdGeneratorType() == ClassMetadata::GENERATOR_TYPE_AUTO) {
$idGenType = $class->getIdGeneratorType();
if ($idGenType == ClassMetadata::GENERATOR_TYPE_AUTO) {
if ($this->_targetPlatform->prefersSequences()) {
$class->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_SEQUENCE);
} else if ($this->_targetPlatform->prefersIdentityColumns()) {
......@@ -204,5 +211,35 @@ class ClassMetadataFactory
$class->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_TABLE);
}
}
// Create & assign an appropriate ID generator instance
switch ($class->getIdGeneratorType()) {
case ClassMetadata::GENERATOR_TYPE_IDENTITY:
$class->setIdGenerator(new \Doctrine\ORM\Id\IdentityGenerator());
break;
case ClassMetadata::GENERATOR_TYPE_SEQUENCE:
// If there is no sequence definition yet, create a default definition
$definition = $class->getSequenceGeneratorDefinition();
if ( ! $definition) {
$definition['sequenceName'] = $class->getTableName() . '_' . $class->getSingleIdentifierColumnName() . '_seq';
$definition['allocationSize'] = 20;
$definition['initialValue'] = 1;
$class->setSequenceGeneratorDefinition($definition);
}
$sequenceGenerator = new \Doctrine\ORM\Id\SequenceGenerator(
$definition['sequenceName'],
$definition['allocationSize']
);
$class->setIdGenerator($sequenceGenerator);
break;
case ClassMetadata::GENERATOR_TYPE_NONE:
$class->setIdGenerator(new \Doctrine\ORM\Id\Assigned());
break;
case ClassMetadata::GENERATOR_TYPE_TABLE:
throw new DoctrineException("DoctrineTableGenerator not yet implemented.");
break;
default:
throw new DoctrineException("Unexhaustive match.");
}
}
}
\ No newline at end of file
......@@ -21,6 +21,7 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\DoctrineException;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\MappingException;
......@@ -48,7 +49,7 @@ class AnnotationDriver
// Evaluate DoctrineEntity annotation
if (($entityAnnot = $annotClass->getAnnotation('DoctrineEntity')) === false) {
throw \Doctrine\Common\DoctrineException::updateMe("$className is no entity.");
throw DoctrineException::updateMe("$className is no entity.");
}
$metadata->setCustomRepositoryClass($entityAnnot->repositoryClass);
......@@ -109,7 +110,7 @@ class AnnotationDriver
// DoctrineOneToOne, DoctrineOneToMany, DoctrineManyToOne, DoctrineManyToMany
if ($columnAnnot = $property->getAnnotation('DoctrineColumn')) {
if ($columnAnnot->type == null) {
throw \Doctrine\Common\DoctrineException::updateMe("Missing type on property " . $property->getName());
throw DoctrineException::updateMe("Missing type on property " . $property->getName());
}
$mapping['type'] = $columnAnnot->type;
$mapping['length'] = $columnAnnot->length;
......@@ -117,10 +118,22 @@ class AnnotationDriver
if ($idAnnot = $property->getAnnotation('DoctrineId')) {
$mapping['id'] = true;
}
if ($idGeneratorAnnot = $property->getAnnotation('DoctrineIdGenerator')) {
$mapping['idGenerator'] = $idGeneratorAnnot->value;
if ($generatedValueAnnot = $property->getAnnotation('DoctrineGeneratedValue')) {
$metadata->setIdGeneratorType($generatedValueAnnot->strategy);
}
$metadata->mapField($mapping);
// Check for SequenceGenerator/TableGenerator definition
if ($seqGeneratorAnnot = $property->getAnnotation('DoctrineSequenceGenerator')) {
$metadata->setSequenceGeneratorDefinition(array(
'sequenceName' => $seqGeneratorAnnot->sequenceName,
'allocationSize' => $seqGeneratorAnnot->allocationSize,
'initialValue' => $seqGeneratorAnnot->initialValue
));
} else if ($tblGeneratorAnnot = $property->getAnnotation('DoctrineTableGenerator')) {
throw new DoctrineException("DoctrineTableGenerator not yet implemented.");
}
} else if ($oneToOneAnnot = $property->getAnnotation('DoctrineOneToOne')) {
$mapping['targetEntity'] = $oneToOneAnnot->targetEntity;
$mapping['joinColumns'] = $joinColumns;
......
......@@ -33,7 +33,10 @@ final class DoctrineDiscriminatorColumn extends \Addendum\Annotation {
final class DoctrineDiscriminatorMap extends \Addendum\Annotation {}
final class DoctrineSubClasses extends \Addendum\Annotation {}
final class DoctrineId extends \Addendum\Annotation {}
final class DoctrineIdGenerator extends \Addendum\Annotation {}
final class DoctrineGeneratedValue extends \Addendum\Annotation {
public $strategy;
//public $generator;
}
final class DoctrineVersion extends \Addendum\Annotation {}
final class DoctrineJoinColumn extends \Addendum\Annotation {
public $name;
......@@ -85,7 +88,10 @@ final class DoctrineJoinTable extends \Addendum\Annotation {
public $inverseJoinColumns;
}
final class DoctrineSequenceGenerator extends \Addendum\Annotation {
public $name;
//public $name;
public $sequenceName;
public $allocationSize = 20;
public $initialValue;
public $initialValue = 1;
/** The name of the class that defines the generator. */
//public $definingClass;
}
......@@ -94,9 +94,9 @@ abstract class AbstractEntityPersister
$insertData = array();
$this->_prepareData($entity, $insertData, true);
$this->_conn->insert($this->_classMetadata->getTableName(), $insertData);
$idGen = $this->_em->getIdGenerator($this->_classMetadata->getClassName());
$idGen = $this->_classMetadata->getIdGenerator();
if ($idGen->isPostInsertGenerator()) {
return $idGen->generate($entity);
return $idGen->generate($this->_em, $entity);
}
return null;
}
......
......@@ -21,6 +21,7 @@
namespace Doctrine\ORM;
use Doctrine\ORM\Query\CacheHandler;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\QueryException;
......@@ -129,7 +130,7 @@ class Query extends AbstractQuery
}
/**
* Retrieves the assocated EntityManager to this Query instance.
* Retrieves the associated EntityManager of this Query instance.
*
* @return Doctrine\ORM\EntityManager
*/
......@@ -243,13 +244,13 @@ class Query extends AbstractQuery
if ($cached === false) {
// Cache does not exist, we have to create it.
$result = $this->_execute($params, self::HYDRATE_ARRAY);
$queryResult = \Doctrine\ORM\Query\CacheHandler::fromResultSet($this, $result);
$queryResult = CacheHandler::fromResultSet($this, $result);
$cacheDriver->save($hash, $queryResult->toCachedForm(), $this->_resultCacheTTL);
return $result;
} else {
// Cache exists, recover it and return the results.
$queryResult = \Doctrine\ORM\Query\CacheHandler::fromCachedResult($this, $cached);
$queryResult = CacheHandler::fromCachedResult($this, $cached);
return $queryResult->getResultSet();
}
......@@ -288,7 +289,7 @@ class Query extends AbstractQuery
$cacheDriver->save($hash, $this->_parserResult->toCachedForm(), $this->_queryCacheTTL);
} else {
// Cache exists, recover it and return the results.
$this->_parserResult = Doctrine\ORM\Query\CacheHandler::fromCachedQuery($this, $cached);
$this->_parserResult = CacheHandler::fromCachedQuery($this, $cached);
$executor = $this->_parserResult->getSqlExecutor();
}
......@@ -327,7 +328,7 @@ class Query extends AbstractQuery
public function setResultCache($resultCache)
{
if ($resultCache !== null && ! ($resultCache instanceof \Doctrine\ORM\Cache\Cache)) {
\Doctrine\Common\DoctrineException::updateMe(
throw DoctrineException::updateMe(
'Method setResultCache() accepts only an instance of Doctrine_Cache_Interface or null.'
);
}
......@@ -409,7 +410,7 @@ class Query extends AbstractQuery
public function setQueryCache($queryCache)
{
if ($queryCache !== null && ! ($queryCache instanceof \Doctrine\ORM\Cache\Cache)) {
\Doctrine\Common\DoctrineException::updateMe(
throw DoctrineException::updateMe(
'Method setResultCache() accepts only an instance of Doctrine_ORM_Cache_Interface or null.'
);
}
......@@ -510,7 +511,6 @@ class Query extends AbstractQuery
/**
* Gets the array of results for the query.
* Object graphs are represented as nested array structures.
*
* Alias for execute(array(), HYDRATE_ARRAY).
*
......@@ -575,9 +575,11 @@ class Query extends AbstractQuery
}
/**
* Executes the query and returns an IterableResult that can be iterated over.
* Objects in the result are initialized on-demand.
* Executes the query and returns an IterableResult that can be used to incrementally
* iterated over the result.
*
* @param array $params The query parameters.
* @param integer $hydrationMode The hydratio mode to use.
* @return IterableResult
*/
public function iterate(array $params = array(), $hydrationMode = self::HYDRATE_OBJECT)
......
......@@ -32,6 +32,7 @@ use Doctrine\Common\DoctrineException;
* @version $Revision: 1393 $
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Roman Borschel <roman@code-factory.org>
*/
abstract class AbstractResult
{
......
......@@ -11,10 +11,4 @@ namespace Doctrine\ORM\Query;
*
* @author robo
*/
class QueryException extends \Doctrine\Common\DoctrineException
{
public static function nonUniqueResult()
{
return new self("The query contains more than one result.");
}
}
\ No newline at end of file
class QueryException extends \Doctrine\Common\DoctrineException {}
\ No newline at end of file
......@@ -28,7 +28,6 @@ use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Mapping;
use Doctrine\ORM\Persisters;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Exceptions\UnitOfWorkException;
/**
* The UnitOfWork is responsible for tracking changes to objects during an
......@@ -440,9 +439,9 @@ class UnitOfWork
$oid = spl_object_hash($entry);
if ($state == self::STATE_NEW) {
// Get identifier, if possible (not post-insert)
$idGen = $this->_em->getIdGenerator($targetClass->getClassName());
$idGen = $targetClass->getIdGenerator();
if ( ! $idGen->isPostInsertGenerator()) {
$idValue = $idGen->generate($entry);
$idValue = $idGen->generate($this->_em, $entry);
$this->_entityStates[$oid] = self::STATE_MANAGED;
if ( ! $idGen instanceof \Doctrine\ORM\Id\Assigned) {
$this->_entityIdentifiers[$oid] = array($idValue);
......@@ -828,7 +827,7 @@ class UnitOfWork
$classMetadata = $this->_em->getClassMetadata(get_class($entity));
$idHash = $this->getIdentifierHash($this->_entityIdentifiers[$oid]);
if ($idHash === '') {
\Doctrine\Common\DoctrineException::updateMe("Entity with oid '" . spl_object_hash($entity)
throw DoctrineException::updateMe("Entity with oid '" . spl_object_hash($entity)
. "' has no identity and therefore can't be removed from the identity map.");
}
$className = $classMetadata->getRootClassName();
......@@ -974,11 +973,11 @@ class UnitOfWork
}
break;
case self::STATE_NEW:
$idGen = $this->_em->getIdGenerator($class->getClassName());
$idGen = $class->getIdGenerator();
if ($idGen->isPostInsertGenerator()) {
$insertNow[$oid] = $entity;
} else {
$idValue = $idGen->generate($entity);
$idValue = $idGen->generate($this->_em, $entity);
$this->_entityStates[$oid] = self::STATE_MANAGED;
if ( ! $idGen instanceof \Doctrine\ORM\Id\Assigned) {
$this->_entityIdentifiers[$oid] = array($idValue);
......@@ -990,7 +989,7 @@ class UnitOfWork
$this->registerNew($entity);
break;
case self::STATE_DETACHED:
\Doctrine\Common\DoctrineException::updateMe("Behavior of save() for a detached entity "
throw DoctrineException::updateMe("Behavior of save() for a detached entity "
. "is not yet defined.");
case self::STATE_DELETED:
// entity becomes managed again
......@@ -1004,7 +1003,7 @@ class UnitOfWork
break;
default:
//TODO: throw UnitOfWorkException::invalidEntityState()
\Doctrine\Common\DoctrineException::updateMe("Encountered invalid entity state.");
throw DoctrineException::updateMe("Encountered invalid entity state.");
}
$this->_cascadeSave($entity, $visited, $insertNow);
}
......@@ -1046,9 +1045,9 @@ class UnitOfWork
$this->registerDeleted($entity);
break;
case self::STATE_DETACHED:
\Doctrine\Common\DoctrineException::updateMe("A detached entity can't be deleted.");
throw DoctrineException::updateMe("A detached entity can't be deleted.");
default:
\Doctrine\Common\DoctrineException::updateMe("Encountered invalid entity state.");
throw DoctrineException::updateMe("Encountered invalid entity state.");
}
$this->_cascadeDelete($entity, $visited);
}
......@@ -1298,7 +1297,7 @@ class UnitOfWork
/**
* Gets the identifier of an entity.
* The returned value is always an array of identifier values. If the entity
* has a composite primary key then the identifier values are in the same
* has a composite identifier then the identifier values are in the same
* order as the identifier field names as returned by ClassMetadata#getIdentifierFieldNames().
*
* @param object $entity
......@@ -1343,8 +1342,6 @@ class UnitOfWork
/**
* Gets the EntityPersister for an Entity.
*
* This is usually not of interest for users, mainly for internal use.
*
* @param string $entityName The name of the Entity.
* @return Doctrine\ORM\Persister\AbstractEntityPersister
*/
......
......@@ -5,7 +5,8 @@ namespace Doctrine\Tests\Mocks;
class DatabasePlatformMock extends \Doctrine\DBAL\Platforms\AbstractPlatform
{
private $_sequenceNextValSql = "";
private $_prefersIdentityColumns = false;
private $_prefersIdentityColumns = true;
private $_prefersSequences = false;
/**
* @override
......@@ -25,6 +26,14 @@ class DatabasePlatformMock extends \Doctrine\DBAL\Platforms\AbstractPlatform
return $this->_prefersIdentityColumns;
}
/**
* @override
*/
public function prefersSequences()
{
return $this->_prefersSequences;
}
/** @override */
public function getSequenceNextValSql($sequenceName)
{
......@@ -37,15 +46,9 @@ class DatabasePlatformMock extends \Doctrine\DBAL\Platforms\AbstractPlatform
/** @override */
public function getBigIntTypeDeclarationSql(array $field) {}
/** @override */
public function getTinyIntTypeDeclarationSql(array $field) {}
/** @override */
public function getSmallIntTypeDeclarationSql(array $field) {}
/** @override */
public function getMediumIntTypeDeclarationSql(array $field) {}
/** @override */
protected function _getCommonIntegerTypeDeclarationSql(array $columnDef) {}
......@@ -56,7 +59,12 @@ class DatabasePlatformMock extends \Doctrine\DBAL\Platforms\AbstractPlatform
public function setPrefersIdentityColumns($bool)
{
$this->_prefersIdentityColumns = (bool)$bool;
$this->_prefersIdentityColumns = $bool;
}
public function setPrefersSequences($bool)
{
$this->_prefersSequences = $bool;
}
public function setSequenceNextValSql($sql)
......
......@@ -70,14 +70,14 @@ class EntityManagerMock extends \Doctrine\ORM\EntityManager
return new EntityManagerMock($conn, $config, $eventManager);
}
/*
public function setIdGenerator($className, $generator)
{
$this->_idGenerators[$className] = $generator;
}
*/
/** @override */
public function getIdGenerator($className)
/* public function getIdGenerator($className)
{
if (isset($this->_idGenerators[$className])) {
......@@ -86,4 +86,5 @@ class EntityManagerMock extends \Doctrine\ORM\EntityManager
return parent::getIdGenerator($className);
}
*/
}
\ No newline at end of file
......@@ -2,6 +2,8 @@
namespace Doctrine\Tests\Mocks;
use Doctrine\ORM\EntityManager;
class SequenceMock extends \Doctrine\ORM\Id\SequenceGenerator
{
private $_sequenceNumber = 0;
......@@ -9,10 +11,10 @@ class SequenceMock extends \Doctrine\ORM\Id\SequenceGenerator
/**
* Enter description here...
*
* @param Doctrine_Entity $entity
* @param object $entity
* @override
*/
public function generate($entity)
public function generate(EntityManager $em, $entity)
{
return $this->_sequenceNumber++;
}
......
......@@ -14,7 +14,7 @@ class CmsAddress
/**
* @DoctrineColumn(type="integer")
* @DoctrineId
* @DoctrineIdGenerator("auto")
* @DoctrineGeneratedValue(strategy="auto")
*/
public $id;
......
......@@ -11,7 +11,7 @@ class CmsArticle
/**
* @DoctrineId
* @DoctrineColumn(type="integer")
* @DoctrineIdGenerator("auto")
* @DoctrineGeneratedValue(strategy="auto")
*/
public $id;
/**
......
......@@ -11,7 +11,7 @@ class CmsComment
/**
* @DoctrineColumn(type="integer")
* @DoctrineId
* @DoctrineIdGenerator("auto")
* @DoctrineGeneratedValue(strategy="auto")
*/
public $id;
/**
......
......@@ -18,7 +18,7 @@ class CmsGroup
/**
* @DoctrineId
* @DoctrineColumn(type="integer")
* @DoctrineIdGenerator("auto")
* @DoctrineGeneratedValue(strategy="auto")
*/
public $id;
/**
......
......@@ -11,7 +11,7 @@ class CmsUser
/**
* @DoctrineId
* @DoctrineColumn(type="integer")
* @DoctrineIdGenerator("auto")
* @DoctrineGeneratedValue(strategy="auto")
*/
public $id;
/**
......
......@@ -17,7 +17,7 @@ class CompanyEmployee
/**
* @DoctrineId
* @DoctrineColumn(type="integer")
* @DoctrineIdGenerator("auto")
* @DoctrineGeneratedValue(strategy="auto")
*/
public $id;
......
......@@ -11,7 +11,7 @@ class ForumAvatar
/**
* @DoctrineId
* @DoctrineColumn(type="integer")
* @DoctrineIdGenerator("auto")
* @DoctrineGeneratedValue(strategy="auto")
*/
public $id;
}
......@@ -11,7 +11,7 @@ class ForumEntry
/**
* @DoctrineId
* @DoctrineColumn(type="integer")
* @DoctrineIdGenerator("auto")
* @DoctrineGeneratedValue(strategy="auto")
*/
public $id;
/**
......
......@@ -17,7 +17,7 @@ class ForumUser
/**
* @DoctrineColumn(type="integer")
* @DoctrineId
* @DoctrineIdGenerator("auto")
* @DoctrineGeneratedValue(strategy="auto")
*/
public $id;
/**
......
......@@ -36,7 +36,7 @@ class AllTests
$suite->addTest(Query\AllTests::suite());
$suite->addTest(Hydration\AllTests::suite());
$suite->addTest(Entity\AllTests::suite());
$suite->addTest(Export\AllTests::suite());
$suite->addTest(Tools\AllTests::suite());
$suite->addTest(Associations\AllTests::suite());
$suite->addTest(Mapping\AllTests::suite());
$suite->addTest(Functional\AllTests::suite());
......
......@@ -26,8 +26,8 @@ class EntityPersisterTest extends \Doctrine\Tests\OrmTestCase
$this->_emMock = EntityManagerMock::create($this->_connMock);
$this->_uowMock = new UnitOfWorkMock($this->_emMock);
$this->_emMock->setUnitOfWork($this->_uowMock);
$this->_idGenMock = new SequenceMock($this->_emMock, 'seq');
$this->_emMock->setIdGenerator('Doctrine\Tests\Models\Forum\ForumUser', $this->_idGenMock);
$this->_idGenMock = new SequenceMock($this->_emMock, 'seq', 20);
//$this->_emMock->setIdGenerator('Doctrine\Tests\Models\Forum\ForumUser', $this->_idGenMock);
}
public function testSimpleInsert()
......
<?php
namespace Doctrine\Tests\ORM\Export;
use Doctrine\ORM\Export\ClassExporter;
require_once __DIR__ . '/../../TestInit.php';
class ClassExporterTest extends \Doctrine\Tests\OrmTestCase
{
public function testGetExportClassesSql()
{
$driver = new \Doctrine\Tests\Mocks\DriverMock;
$conn = new \Doctrine\Tests\Mocks\ConnectionMock(array(), $driver);
$conn->setDatabasePlatform(new \Doctrine\DBAL\Platforms\MySqlPlatform());
$em = $this->_getTestEntityManager($conn);
$classes = array(
$em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'),
$em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'),
$em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'),
);
$exporter = new ClassExporter($em);
$sql = $exporter->getExportClassesSql($classes);
$this->assertEquals(count($sql), 8);
}
}
\ No newline at end of file
......@@ -19,7 +19,7 @@ class AllTests
{
$suite = new \Doctrine\Tests\OrmFunctionalTestSuite('Doctrine Orm Functional');
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\BasicCRUDTest');
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\BasicFunctionalTest');
return $suite;
}
......
......@@ -2,7 +2,7 @@
namespace Doctrine\Tests\ORM\Functional;
use Doctrine\ORM\Export\ClassExporter;
use Doctrine\ORM\Tools\SchemaTool;
use Doctrine\Tests\Models\CMS\CmsUser;
use Doctrine\Tests\Models\CMS\CmsPhonenumber;
use Doctrine\Tests\Models\CMS\CmsAddress;
......@@ -10,27 +10,16 @@ use Doctrine\Tests\Models\CMS\CmsGroup;
require_once __DIR__ . '/../../TestInit.php';
class BasicCRUDTest extends \Doctrine\Tests\OrmFunctionalTestCase
class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
{
protected function tearDown()
protected function setUp()
{
$conn = $this->_em->getConnection();
$conn->exec('DELETE FROM cms_users_groups');
$conn->exec('DELETE FROM cms_groups');
$conn->exec('DELETE FROM cms_addresses');
$conn->exec('DELETE FROM cms_phonenumbers');
$conn->exec('DELETE FROM cms_users');
$this->useModelSet('cms');
parent::setUp();
}
public function testBasicUnitsOfWorkWithOneToManyAssociation()
{
$this->_exporter->exportClasses(array(
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'),
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'),
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'),
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup')
));
// Create
$user = new CmsUser;
$user->name = 'Roman';
......@@ -175,7 +164,7 @@ class BasicCRUDTest extends \Doctrine\Tests\OrmFunctionalTestCase
$group->users[] = $user;
}
$this->_em->save($user); // Saves the user, cause of post-insert ID
$this->_em->save($user); // Saves the user, 'cause of post-insert ID
$this->_em->flush();
......@@ -215,6 +204,22 @@ class BasicCRUDTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals('developer', $users[0]->status);
$this->assertNull($users[0]->phonenumbers);
$this->assertNull($users[0]->articles);
$usersArray = $query->getResultArray();
$this->assertTrue(is_array($usersArray));
$this->assertEquals(1, count($usersArray));
$this->assertEquals('Guilherme', $usersArray[0]['name']);
$this->assertEquals('gblanco', $usersArray[0]['username']);
$this->assertEquals('developer', $usersArray[0]['status']);
$usersScalar = $query->getScalarResult();
$this->assertTrue(is_array($usersScalar));
$this->assertEquals(1, count($usersScalar));
$this->assertEquals('Guilherme', $usersScalar[0]['u_name']);
$this->assertEquals('gblanco', $usersScalar[0]['u_username']);
$this->assertEquals('developer', $usersScalar[0]['u_status']);
}
public function testBasicInnerJoin()
......
<?php
namespace Doctrine\Tests\ORM\Export;
namespace Doctrine\Tests\ORM\Id;
if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'Orm_Export_AllTests::main');
define('PHPUnit_MAIN_METHOD', 'Orm_Id_AllTests::main');
}
require_once __DIR__ . '/../../TestInit.php';
......@@ -19,14 +17,14 @@ class AllTests
public static function suite()
{
$suite = new \Doctrine\Tests\DoctrineTestSuite('Doctrine Orm Export');
$suite = new \Doctrine\Tests\DoctrineTestSuite('Doctrine Orm Id');
$suite->addTestSuite('Doctrine\Tests\ORM\Export\ClassExporterTest');
$suite->addTestSuite('Doctrine\Tests\ORM\Id\SequenceGeneratorTest');
return $suite;
}
}
if (PHPUnit_MAIN_METHOD == 'Orm_Export_AllTests::main') {
if (PHPUnit_MAIN_METHOD == 'Orm_Id_AllTests::main') {
AllTests::main();
}
\ No newline at end of file
<?php
namespace Doctrine\Tests\ORM\Id;
use Doctrine\ORM\Id\SequenceGenerator;
require_once __DIR__ . '/../../TestInit.php';
/**
* Description of SequenceGeneratorTest
*
* @author robo
*/
class SequenceGeneratorTest extends \Doctrine\Tests\OrmTestCase
{
private $_em;
private $_seqGen;
protected function setUp()
{
$this->_em = $this->_getTestEntityManager();
$this->_seqGen = new SequenceGenerator('seq', 10);
}
public function testGeneration()
{
for ($i=0; $i < 42; ++$i) {
if ($i % 10 == 0) {
$this->_em->getConnection()->setFetchOneResult((int)($i / 10) * 10 + 10);
}
$id = $this->_seqGen->generate($this->_em, null);
$this->assertEquals($i, $id);
$this->assertEquals((int)($i / 10) * 10 + 10, $this->_seqGen->getCurrentMaxValue());
$this->assertEquals($i + 1, $this->_seqGen->getNextValue());
}
}
}
......@@ -15,11 +15,15 @@ class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase
{
$mockPlatform = new DatabasePlatformMock();
$mockDriver = new MetadataDriverMock();
$mockPlatform->setPrefersSequences(true);
$mockPlatform->setPrefersIdentityColumns(false);
// Self-made metadata
$cm1 = new ClassMetadata('Doctrine\Tests\ORM\Mapping\TestEntity1');
// Add a mapped field
$cm1->mapField(array('fieldName' => 'name', 'type' => 'varchar'));
// Add a mapped field
$cm1->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true));
// and a mapped association
$cm1->mapOneToOne(array('fieldName' => 'other', 'targetEntity' => 'Other', 'mappedBy' => 'this'));
// and an id generator type
......@@ -41,8 +45,7 @@ class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals(array(), $cm1->getParentClasses());
$this->assertTrue($cm1->hasField('name'));
// The default fallback for id generation is the table strategy
$this->assertEquals('table', $cm1->getIdGeneratorType());
$this->assertEquals('sequence', $cm1->getIdGeneratorType());
}
public function testGetMetadataForClassInHierarchy()
......@@ -56,6 +59,8 @@ class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase
$cm1->setInheritanceType('singleTable');
// Add a mapped field
$cm1->mapField(array('fieldName' => 'name', 'type' => 'varchar'));
// Add a mapped field
$cm1->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true));
// and a mapped association
$cm1->mapOneToOne(array('fieldName' => 'other', 'targetEntity' => 'Other', 'mappedBy' => 'this'));
// and an id generator type
......@@ -144,6 +149,7 @@ class ClassMetadataFactoryTestSubject extends \Doctrine\ORM\Mapping\ClassMetadat
class TestEntity1
{
protected $id;
protected $name;
protected $other;
}
......
<?php
namespace Doctrine\Tests\ORM\Tools;
if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'Orm_Tools_AllTests::main');
}
require_once __DIR__ . '/../../TestInit.php';
class AllTests
{
public static function main()
{
\PHPUnit_TextUI_TestRunner::run(self::suite());
}
public static function suite()
{
$suite = new \Doctrine\Tests\DoctrineTestSuite('Doctrine Orm Tools');
$suite->addTestSuite('Doctrine\Tests\ORM\Tools\SchemaToolTest');
return $suite;
}
}
if (PHPUnit_MAIN_METHOD == 'Orm_Tools_AllTests::main') {
AllTests::main();
}
\ No newline at end of file
......@@ -54,8 +54,8 @@ class UnitOfWorkTest extends \Doctrine\Tests\OrmTestCase
// Setup fake persister and id generator for identity generation
$userPersister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\Models\Forum\ForumUser"));
$this->_unitOfWork->setEntityPersister('Doctrine\Tests\Models\Forum\ForumUser', $userPersister);
$idGeneratorMock = new IdentityIdGeneratorMock($this->_emMock);
$this->_emMock->setIdGenerator('Doctrine\Tests\Models\Forum\ForumUser', $idGeneratorMock);
//$idGeneratorMock = new IdentityIdGeneratorMock($this->_emMock);
//$this->_emMock->setIdGenerator('Doctrine\Tests\Models\Forum\ForumUser', $idGeneratorMock);
$userPersister->setMockIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_IDENTITY);
// Test
......@@ -95,14 +95,14 @@ class UnitOfWorkTest extends \Doctrine\Tests\OrmTestCase
//ForumUser
$userPersister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\Models\Forum\ForumUser"));
$this->_unitOfWork->setEntityPersister('Doctrine\Tests\Models\Forum\ForumUser', $userPersister);
$userIdGeneratorMock = new IdentityIdGeneratorMock($this->_emMock);
$this->_emMock->setIdGenerator('Doctrine\Tests\Models\Forum\ForumUser', $userIdGeneratorMock);
//$userIdGeneratorMock = new IdentityIdGeneratorMock($this->_emMock);
//$this->_emMock->setIdGenerator('Doctrine\Tests\Models\Forum\ForumUser', $userIdGeneratorMock);
$userPersister->setMockIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_IDENTITY);
// ForumAvatar
$avatarPersister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\Models\Forum\ForumAvatar"));
$this->_unitOfWork->setEntityPersister('Doctrine\Tests\Models\Forum\ForumAvatar', $avatarPersister);
$avatarIdGeneratorMock = new IdentityIdGeneratorMock($this->_emMock);
$this->_emMock->setIdGenerator('Doctrine\Tests\Models\Forum\ForumAvatar', $avatarIdGeneratorMock);
//$avatarIdGeneratorMock = new IdentityIdGeneratorMock($this->_emMock);
//$this->_emMock->setIdGenerator('Doctrine\Tests\Models\Forum\ForumAvatar', $avatarIdGeneratorMock);
$avatarPersister->setMockIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_IDENTITY);
// Test
......
......@@ -3,7 +3,7 @@
namespace Doctrine\Tests;
/**
* Base testcase class for all orm testcases.
* Base testcase class for all functional ORM testcases.
*
* @since 2.0
*/
......@@ -15,119 +15,88 @@ class OrmFunctionalTestCase extends OrmTestCase
/** The EntityManager for this testcase. */
protected $_em;
/** The ClassExporter for this testcase. */
protected $_exporter;
/** The SchemaTool. */
protected $_schemaTool;
/**
* The currently loaded model names of the fixtures for the testcase.
*/
private $_loadedFixtures = array();
/**
* All loaded fixtures during test execution. Common fixture cache.
*/
private static $_fixtures = array();
/**
* The names of all tables that were already exported. Each table is exported
* only once. Then it's just filled & erased for each testmethod in a testcase
* that uses one or more fixtures.
*/
private static $_exportedTables = array();
/**
* Loads a data fixture into the database. This method must only be called
* from within the setUp() method of testcases. The database will then be
* populated with fresh data of all loaded fixtures for each test method.
*
* WARNING: A single testcase should never load fixtures from different scenarios of
* the same package as the concistency and uniqueness of keys is not guaranteed.
*
* @param string $package The package name. Must be one of Doctrine's test model packages
* (forum, cms or ecommerce).
* @param string $scenario The fixture scenario. A model package can have many fixture
* scenarios. Within a scenario all primary keys and foreign keys
* of fixtures are consistent and unique.
* @param string $name The name of the fixture to load from the specified package.
*/
protected function loadFixture($package, $scenario, $name)
{
$uniqueName = $package . '/' . $scenario . '/' . $name;
if ( ! isset(self::$_fixtures[$uniqueName])) {
// load fixture file
$fixtureFile = 'fixtures'
. DIRECTORY_SEPARATOR . $package
. DIRECTORY_SEPARATOR . $scenario
. DIRECTORY_SEPARATOR . $name
. '.php';
require $fixtureFile;
self::$_fixtures[$uniqueName] = $fixture;
}
$fixture = self::$_fixtures[$uniqueName];
$this->_loadedFixtures[] = $fixture['table'];
$conn = $this->sharedFixture['conn'];
$tableName = $fixture['table'];
if ( ! in_array($tableName, self::$_exportedTables)) {
$conn->getSchemaManager()->exportClasses(array($fixture['model']));
self::$_exportedTables[] = $tableName;
}
foreach ($fixture['rows'] as $row) {
$conn->insert($tableName, $row);
}
}
/**
* Loads multiple fixtures of the same package and scenario.
* This method must only be called from within the setUp() method of testcases.
* The database will then be populated with fresh data of all loaded fixtures for each
* test method.
*
* WARNING: A single testcase should never load fixtures from different scenarios of
* the same package as the concistency and uniqueness of keys is not guaranteed.
*
* @param string $package The package name. Must be one of Doctrine's test model packages
* (forum, cms or ecommerce).
* @param string $scenario The fixture scenario. A model package can have many fixture
* scenarios. Within a scenario all primary keys and foreign keys
* of fixtures are consistent and unique.
* @param array $names The names of the fixtures to load from the specified package.
*/
protected function loadFixtures($package, $scenario, array $names)
/** The names of the model sets used in this testcase. */
private $_usedModelSets = array();
/** Whether the database schema has already been created. */
private static $_tablesCreated = array();
/** List of model sets and their classes. */
private static $_modelSets = array(
'cms' => array(
'Doctrine\Tests\Models\CMS\CmsUser',
'Doctrine\Tests\Models\CMS\CmsPhonenumber',
'Doctrine\Tests\Models\CMS\CmsAddress',
'Doctrine\Tests\Models\CMS\CmsGroup'
),
'forum' => array(),
'company' => array(),
'ecommerce' => array()
);
protected function useModelSet($setName)
{
foreach ($names as $name) {
$this->loadFixture($package, $scenario, $name);
}
$this->_usedModelSets[] = $setName;
}
/**
* Sweeps the database tables of all used fixtures and clears the EntityManager.
* Sweeps the database tables and clears the EntityManager.
*/
protected function tearDown()
{
$conn = $this->sharedFixture['conn'];
foreach (array_reverse($this->_loadedFixtures) as $table) {
$conn->exec("DELETE FROM " . $table);
if (in_array('cms', $this->_usedModelSets)) {
$conn->exec('DELETE FROM cms_users_groups');
$conn->exec('DELETE FROM cms_groups');
$conn->exec('DELETE FROM cms_addresses');
$conn->exec('DELETE FROM cms_phonenumbers');
$conn->exec('DELETE FROM cms_users');
}
$this->_em->clear();
}
/**
* Creates a connection to the test database, if there is none yet, and
* creates the necessary tables.
*/
protected function setUp()
{
$forceCreateTables = false;
if ( ! isset($this->sharedFixture['conn'])) {
echo PHP_EOL . " --- CREATE CONNECTION ----" . PHP_EOL;
$this->sharedFixture['conn'] = TestUtil::getConnection();
if ($this->sharedFixture['conn']->getDriver() instanceof \Doctrine\DBAL\Driver\PDOSqlite\Driver) {
$forceCreateTables = true;
}
}
if ( ! $this->_em) {
$this->_em = $this->_getEntityManager();
$this->_exporter = new \Doctrine\ORM\Export\ClassExporter($this->_em);
$this->_schemaTool = new \Doctrine\ORM\Tools\SchemaTool($this->_em);
}
$classes = array();
foreach ($this->_usedModelSets as $setName) {
if ( ! isset(self::$_tablesCreated[$setName]) || $forceCreateTables) {
foreach (self::$_modelSets[$setName] as $className) {
$classes[] = $this->_em->getClassMetadata($className);
}
self::$_tablesCreated[$setName] = true;
}
}
if ($classes) {
$this->_schemaTool->createSchema($classes);
}
}
/**
* Gets an EntityManager for testing purposes.
*
* @param Configuration $config The Configuration to pass to the EntityManager.
* @param EventManager $eventManager The EventManager to pass to the EntityManager.
* @return EntityManager
*/
protected function _getEntityManager($config = null, $eventManager = null) {
// NOTE: Functional tests use their own shared metadata cache, because
// the actual database platform used during execution has effect on some
......
<?php
$fixture = array(
'model' => 'ForumAdministrator',
'rows' => array(
array(
'id' => 1,
'access_level' => 4
)
)
);
\ No newline at end of file
<?php
$fixture = array(
'model' => 'ForumUser',
'rows' => array(
array(
'id' => 1,
'username' => 'romanb',
'dtype' => 'admin'
),
array(
'id' => 2,
'username' => 'jwage',
'dtype' => 'user'
)
)
);
\ No newline at end of file
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