Compare commits

...

48 Commits
2.0.5 ... 2.0.7

Author SHA1 Message Date
Benjamin Eberlei
b7a15316a0 Release 2.0.7 2011-08-17 21:47:50 +00:00
Benjamin Eberlei
2b878fc15d Bump dependency DBAL to 2.0.7 2011-08-17 21:46:43 +00:00
Benjamin Eberlei
4fea26c833 Fix: YamlDriver does not support orphanRemoval 2011-08-17 21:23:13 +02:00
Benjamin Eberlei
bf3ae5f2cf Merge branch 'DDC-1302' into 2.0.x 2011-07-31 11:36:02 +02:00
Benjamin Eberlei
2836d14c31 DDC-1302 - Fix bug in XmlDriver not handling orphan removal 2011-07-31 11:35:50 +02:00
Benjamin Eberlei
a342c87a32 Merge branch 'DDC-1276' into 2.0.x 2011-07-26 22:18:21 +02:00
Benjamin Eberlei
192eedc6a7 DDC-1276 - Fix bug where merge managed and new entitiy share the same collection that is cascaded, cleared during the process and then empty afterwards. 2011-07-26 22:17:13 +02:00
Benjamin Eberlei
ed78cdb937 Merge remote-tracking branch 'origin/2.0.x' into 2.0.x 2011-07-12 22:52:35 +02:00
Benjamin Eberlei
793c383aa2 Merge branch 'DDC-1240' into 2.0.x 2011-07-12 22:52:18 +02:00
Benjamin Eberlei
7595b021cc DDC-1240 - Fix optimistic lock exception loosing the message 2011-07-12 22:52:09 +02:00
Benjamin Eberlei
f1bcb3cb80 Merge branch 'DDC-1257' into 2.0.x 2011-07-09 15:15:53 +02:00
Benjamin Eberlei
35ea4ed1fd DDC-1257 - Fix bug where validation callbacks are added multiple times in EntityGenerator 2011-07-09 15:15:34 +02:00
Benjamin Eberlei
ac8a36cda3 Merge branch 'DDC-1251' into 2.0.x 2011-07-09 14:55:12 +02:00
Benjamin Eberlei
0917ed5ced DDC-1251 - Fix bug in token parsing of EntityGenerator 2011-07-09 14:54:56 +02:00
Benjamin Eberlei
8068f34c66 DDC-1022 - Call __wakeup() with the same semantics then ClassMetadata::newInstance() does inside UnitOfWork 2011-07-09 14:34:21 +02:00
Benjamin Eberlei
91a9d4f27c Merge branch 'DDC-1230' into 2.0.x 2011-06-28 21:38:54 +02:00
Benjamin Eberlei
7c8590ea74 DDC-1230 - Fix bug where UnitOfWork does not set STATE_REMOVE when calling EntityManager#remove() on an entity 2011-06-28 21:38:44 +02:00
Benjamin Eberlei
d1cea4f77c Merge branch 'DDC-1224' into 2.0.x 2011-06-26 10:12:08 +02:00
Benjamin Eberlei
ae958e73d1 DDC-1224 - Bugfix with temporary table ids and tables in schema (in postgresql) 2011-06-26 10:11:57 +02:00
Benjamin Eberlei
3b841883d3 Merge branch 'DDC-1211' into 2.0.x 2011-06-19 10:27:21 +02:00
Benjamin Eberlei
cfe36f9a31 DDC-1211 - Fix bug with empty numeric literal 2011-06-19 10:26:36 +02:00
Benjamin Eberlei
d2eea18977 Merge branch 'DDC-1189' into 2.0.x 2011-06-19 09:44:21 +02:00
Benjamin Eberlei
247887ec0e DDC-1189 - Bugfix with PersistentCollection#clear() in combination with lazy loading 2011-06-19 09:43:33 +02:00
Benjamin Eberlei
2b309a3682 Merge remote-tracking branch 'origin/2.0.x' into 2.0.x 2011-06-16 22:47:28 +02:00
Benjamin Eberlei
5ebe7ca89e Merge branch 'DDC-1172' into 2.0.x 2011-06-16 22:47:08 +02:00
Benjamin Eberlei
c582b7790a DDC-1172 - Adjust patch to 2.0.x code base 2011-06-16 22:43:06 +02:00
Benjamin Eberlei
a98a21b269 DDC-1172 - Handle sequence dropping in SchemaTool. 2011-06-16 22:34:56 +02:00
Benjamin Eberlei
5c9b3d0b92 Bump Dev Version to 2.0.7-DEV 2011-06-15 21:45:09 +00:00
Benjamin Eberlei
7f3bdab34c Release 2.0.6 2011-06-15 21:44:59 +00:00
Benjamin Eberlei
e075ab6958 Update dependency of DBAL to 2.0.6 2011-06-15 21:43:17 +00:00
Benjamin Eberlei
a1bc743568 Merge branch 'DDC-1208' into 2.0.x 2011-06-15 18:33:24 +02:00
Benjamin Eberlei
20d8ebfd43 DDC-1208 - Allow namespace separator in <discriminator-mapping /> 2011-06-15 18:33:12 +02:00
Fabien Potencier
3587f3bcb3 Update Symfony2 vendors 2011-06-15 11:44:04 +02:00
Benjamin Eberlei
ec87cb779c Merge branch 'DDC-1163' into 2.0.x 2011-06-05 16:20:56 +02:00
Benjamin Eberlei
ac40ce8042 DDC-1163 - Fix nasty bug with inheritance in UnitOfWork::executeUpdates() and executeRemovals() 2011-06-05 16:20:41 +02:00
Benjamin Eberlei
d4302b32e1 Merge branch 'DDC-1192' into 2.0.x 2011-06-05 14:50:35 +02:00
Benjamin Eberlei
3c95b0ec35 DDC-1192 - Fix notice in XmlDriver, removed unnecessary code. 2011-06-05 14:50:25 +02:00
Benjamin Eberlei
c12c6e82b6 Merge remote-tracking branch 'origin/2.0.x' into 2.0.x 2011-06-05 10:09:26 +02:00
Benjamin Eberlei
505f7bd252 Merge branch 'DDC-1193' into 2.0.x 2011-06-05 10:08:29 +02:00
Benjamin Eberlei
d5459616d2 DDC-733, DDC-1193 - Proxy has only _load() in 2.0.x - Change to __load() for consinstent code. 2011-06-05 10:08:05 +02:00
Benjamin Eberlei
97d9fb7efa DDC-733, DDC-1193 - Proxy has only _load() in 2.0.x 2011-06-05 10:06:56 +02:00
Benjamin Eberlei
2da1fadaf1 DDC-1193 - Fix previous commit. 2011-06-05 10:05:25 +02:00
Benjamin Eberlei
a612ca7231 DDC-1193 - Fix bug with cascade remove and proxy classes. 2011-06-05 10:05:12 +02:00
Benjamin Eberlei
bd4faa6a7d DDC-733 - Add UnitOfWork::initializeObject() method. 2011-06-05 10:04:23 +02:00
Benjamin Eberlei
be03811753 Merge pull request #66 from fabpot/feat-doctrine-mapping-configuration
Feat doctrine mapping configuration
2011-06-04 23:18:52 -07:00
Fabien Potencier
636fa34136 Made orm:convert-mapping command more configurable (allow to change the extension of the generated files for instance) 2011-06-05 08:03:41 +02:00
Benjamin Eberlei
016810af7f [DDC-952] Add Persister hydration performance tests. 2011-05-14 16:09:40 +02:00
Benjamin Eberlei
178fe38a39 Bump Dev Version to 2.0.6-DEV 2011-05-14 13:36:43 +00:00
33 changed files with 845 additions and 66 deletions

View File

@@ -168,7 +168,7 @@
<xs:complexType name="discriminator-mapping">
<xs:attribute name="value" type="xs:NMTOKEN" use="required"/>
<xs:attribute name="class" type="xs:NMTOKEN" use="required"/>
<xs:attribute name="class" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="discriminator-map">

View File

@@ -1137,7 +1137,8 @@ class ClassMetadataInfo
*/
public function getTemporaryIdTableName()
{
return $this->table['name'] . '_id_tmp';
// replace dots with underscores because PostgreSQL creates temporary tables in a special schema
return str_replace('.', '_', $this->table['name'] . '_id_tmp');
}
/**

View File

@@ -262,8 +262,8 @@ class XmlDriver extends AbstractFileDriver
$mapping['cascade'] = $this->_getCascadeMappings($oneToOneElement->cascade);
}
if (isset($oneToOneElement->{'orphan-removal'})) {
$mapping['orphanRemoval'] = (bool)$oneToOneElement->{'orphan-removal'};
if (isset($oneToOneElement['orphan-removal'])) {
$mapping['orphanRemoval'] = (bool)$oneToOneElement['orphan-removal'];
}
$metadata->mapOneToOne($mapping);
@@ -287,8 +287,8 @@ class XmlDriver extends AbstractFileDriver
$mapping['cascade'] = $this->_getCascadeMappings($oneToManyElement->cascade);
}
if (isset($oneToManyElement->{'orphan-removal'})) {
$mapping['orphanRemoval'] = (bool)$oneToManyElement->{'orphan-removal'};
if (isset($oneToManyElement['orphan-removal'])) {
$mapping['orphanRemoval'] = (bool)$oneToManyElement['orphan-removal'];
}
if (isset($oneToManyElement->{'order-by'})) {
@@ -325,9 +325,6 @@ class XmlDriver extends AbstractFileDriver
$joinColumns[] = $this->_getJoinColumnMapping($manyToOneElement->{'join-column'});
} else if (isset($manyToOneElement->{'join-columns'})) {
foreach ($manyToOneElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
if (!isset($joinColumnElement['name'])) {
$joinColumnElement['name'] = $name;
}
$joinColumns[] = $this->_getJoinColumnMapping($joinColumnElement);
}
}

View File

@@ -266,6 +266,10 @@ class YamlDriver extends AbstractFileDriver
$mapping['cascade'] = $oneToOneElement['cascade'];
}
if (isset($oneToOneElement['orphanRemoval'])) {
$mapping['orphanRemoval'] = (bool)$oneToOneElement['orphanRemoval'];
}
$metadata->mapOneToOne($mapping);
}
}
@@ -283,6 +287,10 @@ class YamlDriver extends AbstractFileDriver
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToManyElement['fetch']);
}
if (isset($oneToManyElement['orphanRemoval'])) {
$mapping['orphanRemoval'] = (bool)$oneToManyElement['orphanRemoval'];
}
if (isset($oneToManyElement['cascade'])) {
$mapping['cascade'] = $oneToManyElement['cascade'];
}
@@ -450,6 +458,6 @@ class YamlDriver extends AbstractFileDriver
*/
protected function _loadMappingFile($file)
{
return \Symfony\Component\Yaml\Yaml::load($file);
return \Symfony\Component\Yaml\Yaml::parse($file);
}
}

View File

@@ -33,6 +33,7 @@ class OptimisticLockException extends ORMException
public function __construct($msg, $entity)
{
parent::__construct($msg);
$this->entity = $entity;
}

View File

@@ -576,6 +576,7 @@ final class PersistentCollection implements Collection
}
}
$this->coll->clear();
$this->initialized = true; // direct call, {@link initialize()} is too expensive
if ($this->association['isOwningSide']) {
$this->changed();
$this->em->getUnitOfWork()->scheduleCollectionDeletion($this);

View File

@@ -209,7 +209,7 @@ class ProxyFactory
$methods .= $parameterString . ')';
$methods .= PHP_EOL . ' {' . PHP_EOL;
$methods .= ' $this->_load();' . PHP_EOL;
$methods .= ' $this->__load();' . PHP_EOL;
$methods .= ' return parent::' . $method->getName() . '(' . $argumentString . ');';
$methods .= PHP_EOL . ' }' . PHP_EOL;
}
@@ -269,17 +269,26 @@ class <proxyClassName> extends \<className> implements \Doctrine\ORM\Proxy\Proxy
$this->_entityPersister = $entityPersister;
$this->_identifier = $identifier;
}
private function _load()
/** @private */
public function __load()
{
if (!$this->__isInitialized__ && $this->_entityPersister) {
$this->__isInitialized__ = true;
if (method_exists($this, "__wakeup")) {
// call this after __isInitialized__to avoid infinite recursion
// but before loading to emulate what ClassMetadata::newInstance()
// provides.
$this->__wakeup();
}
if ($this->_entityPersister->load($this->_identifier, $this) === null) {
throw new \Doctrine\ORM\EntityNotFoundException();
}
unset($this->_entityPersister, $this->_identifier);
}
}
<methods>
public function __sleep()

View File

@@ -55,7 +55,7 @@ abstract class Base
public function add($arg)
{
if ( ! empty($arg) || ($arg instanceof self && $arg->count() > 0)) {
if ( $arg !== null || ($arg instanceof self && $arg->count() > 0)) {
// If we decide to keep Expr\Base instances, we can use this check
if ( ! is_string($arg)) {
$class = get_class($arg);

View File

@@ -137,8 +137,7 @@ EOT
$toType = strtolower($input->getArgument('to-type'));
$cme = new ClassMetadataExporter();
$exporter = $cme->getExporter($toType, $destPath);
$exporter = $this->getExporter($toType, $destPath);
$exporter->setOverwriteExistingFiles( ($input->getOption('force') !== false) );
if ($toType == 'annotation') {
@@ -167,4 +166,11 @@ EOT
$output->write('No Metadata Classes to process.' . PHP_EOL);
}
}
protected function getExporter($toType, $destPath)
{
$cme = new ClassMetadataExporter();
return $cme->getExporter($toType, $destPath);
}
}

View File

@@ -70,10 +70,10 @@ class ConvertDoctrine1Schema
if (is_dir($path)) {
$files = glob($path . '/*.yml');
foreach ($files as $file) {
$schema = array_merge($schema, (array) \Symfony\Component\Yaml\Yaml::load($file));
$schema = array_merge($schema, (array) \Symfony\Component\Yaml\Yaml::parse($file));
}
} else {
$schema = array_merge($schema, (array) \Symfony\Component\Yaml\Yaml::load($path));
$schema = array_merge($schema, (array) \Symfony\Component\Yaml\Yaml::parse($path));
}
}

View File

@@ -439,7 +439,7 @@ public function <methodName>()
} else if ($token[0] == T_FUNCTION) {
if ($tokens[$i+2][0] == T_STRING) {
$this->_staticReflection[$lastSeenClass]['methods'][] = $tokens[$i+2][1];
} else if ($tokens[$i+2][0] == T_AMPERSAND && $tokens[$i+3][0] == T_STRING) {
} else if ($tokens[$i+2] == "&" && $tokens[$i+3][0] == T_STRING) {
$this->_staticReflection[$lastSeenClass]['methods'][] = $tokens[$i+3][1];
}
} else if (in_array($token[0], array(T_VAR, T_PUBLIC, T_PRIVATE, T_PROTECTED)) && $tokens[$i+2][0] != T_FUNCTION) {
@@ -679,6 +679,7 @@ public function <methodName>()
if ($this->_hasMethod($methodName, $metadata)) {
return;
}
$this->_staticReflection[$metadata->name]['methods'][] = $methodName;
$var = sprintf('_%sMethodTemplate', $type);
$template = self::$$var;
@@ -711,6 +712,7 @@ public function <methodName>()
if ($this->_hasMethod($methodName, $metadata)) {
return;
}
$this->_staticReflection[$metadata->name]['methods'][] = $methodName;
$replacements = array(
'<name>' => $this->_annotationsPrefix . $name,

View File

@@ -570,6 +570,26 @@ class SchemaTool
}
}
}
if ($this->_platform->supportsSequences()) {
foreach ($schema->getSequences() AS $sequence) {
$visitor->acceptSequence($sequence);
}
foreach ($schema->getTables() AS $table) {
/* @var $sequence Table */
foreach ($table->getIndexes() AS $index) {
if ($index->isPrimary()) {
$columns = $index->getColumns();
if (count($columns) == 1) {
$checkSequence = $table->getName() . "_" . $columns[0] . "_seq";
if ($fullSchema->hasSequence($checkSequence)) {
$visitor->acceptSequence($fullSchema->getSequence($checkSequence));
}
}
}
}
}
}
return $visitor->getQueries();
}

View File

@@ -741,7 +741,7 @@ class UnitOfWork implements PropertyChangedListener
$hasPostUpdateListeners = $this->evm->hasListeners(Events::postUpdate);
foreach ($this->entityUpdates as $oid => $entity) {
if (get_class($entity) == $className || $entity instanceof Proxy && $entity instanceof $className) {
if (get_class($entity) == $className || $entity instanceof Proxy && get_parent_class($entity) == $className) {
if ($hasPreUpdateLifecycleCallbacks) {
$class->invokeLifecycleCallbacks(Events::preUpdate, $entity);
@@ -781,7 +781,7 @@ class UnitOfWork implements PropertyChangedListener
$hasListeners = $this->evm->hasListeners(Events::postRemove);
foreach ($this->entityDeletions as $oid => $entity) {
if (get_class($entity) == $className || $entity instanceof Proxy && $entity instanceof $className) {
if (get_class($entity) == $className || $entity instanceof Proxy && get_parent_class($entity) == $className) {
$persister->delete($entity);
unset(
$this->entityDeletions[$oid],
@@ -975,7 +975,7 @@ class UnitOfWork implements PropertyChangedListener
if ($this->isInIdentityMap($entity)) {
$this->removeFromIdentityMap($entity);
}
unset($this->entityInsertions[$oid]);
unset($this->entityInsertions[$oid], $this->entityStates[$oid]);
return; // entity has not been persisted yet, so nothing more to do.
}
@@ -990,6 +990,7 @@ class UnitOfWork implements PropertyChangedListener
}
if ( ! isset($this->entityDeletions[$oid])) {
$this->entityDeletions[$oid] = $entity;
$this->entityStates[$oid] = self::STATE_REMOVED;
}
}
@@ -1285,6 +1286,10 @@ class UnitOfWork implements PropertyChangedListener
}
$visited[$oid] = $entity; // mark visited
// Cascade first, because scheduleForDelete() removes the entity from the identity map, which
// can cause problems when a lazy proxy has to be initialized for the cascade operation.
$this->cascadeRemove($entity, $visited);
$class = $this->em->getClassMetadata(get_class($entity));
$entityState = $this->getEntityState($entity);
@@ -1308,7 +1313,6 @@ class UnitOfWork implements PropertyChangedListener
throw new UnexpectedValueException("Unexpected entity state: $entityState.");
}
$this->cascadeRemove($entity, $visited);
}
/**
@@ -1443,7 +1447,8 @@ class UnitOfWork implements PropertyChangedListener
}
if ($assoc2['isCascadeMerge']) {
$managedCol->initialize();
if (!$managedCol->isEmpty()) {
// clear and set dirty a managed collection if its not also the same collection to merge from.
if (!$managedCol->isEmpty() && $managedCol != $mergeCol) {
$managedCol->unwrap()->clear();
$managedCol->setDirty(true);
if ($assoc2['isOwningSide'] && $assoc2['type'] == ClassMetadata::MANY_TO_MANY && $class->isChangeTrackingNotify()) {
@@ -1642,6 +1647,10 @@ class UnitOfWork implements PropertyChangedListener
}
$relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
if ($relatedEntities instanceof Collection) {
if ($relatedEntities === $class->reflFields[$assoc['fieldName']]->getValue($managedCopy)) {
continue;
}
if ($relatedEntities instanceof PersistentCollection) {
// Unwrap so that foreach() does not initialize
$relatedEntities = $relatedEntities->unwrap();
@@ -1669,6 +1678,7 @@ class UnitOfWork implements PropertyChangedListener
if ( ! $assoc['isCascadePersist']) {
continue;
}
$relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
if (($relatedEntities instanceof Collection || is_array($relatedEntities))) {
if ($relatedEntities instanceof PersistentCollection) {
@@ -1697,7 +1707,11 @@ class UnitOfWork implements PropertyChangedListener
if ( ! $assoc['isCascadeRemove']) {
continue;
}
//TODO: If $entity instanceof Proxy => Initialize ?
if ($entity instanceof Proxy && !$entity->__isInitialized__) {
$entity->__load();
}
$relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
if ($relatedEntities instanceof Collection || is_array($relatedEntities)) {
// If its a PersistentCollection initialization is intended! No unwrap!
@@ -1848,8 +1862,8 @@ class UnitOfWork implements PropertyChangedListener
$idHash = $data[$class->identifier[0]];
$id = array($class->identifier[0] => $idHash);
}
if (isset($this->identityMap[$class->rootEntityName][$idHash])) {
if (isset($this->identityMap[$class->rootEntityName][$idHash])) {
$entity = $this->identityMap[$class->rootEntityName][$idHash];
$oid = spl_object_hash($entity);
if ($entity instanceof Proxy && ! $entity->__isInitialized__) {
@@ -2260,7 +2274,28 @@ class UnitOfWork implements PropertyChangedListener
{
return $this->collectionUpdates;
}
/**
* Helper method to initialize a lazy loading proxy or persistent collection.
*
* @param object
* @return void
*/
public function initializeObject($obj)
{
if ($obj instanceof Proxy) {
$obj->__load();
} else if ($obj instanceof PersistentCollection) {
$obj->initialize();
}
}
/**
* Helper method to show an object as string.
*
* @param object $obj
* @return string
*/
private static function objToStr($obj)
{
return method_exists($obj, '__toString') ? (string)$obj : get_class($obj).'@'.spl_object_hash($obj);

View File

@@ -36,7 +36,7 @@ class Version
/**
* Current Doctrine Version
*/
const VERSION = '2.0.5';
const VERSION = '2.0.7';
/**
* Compares a Doctrine version with the current one.

View File

@@ -56,6 +56,7 @@ class ECommerceProduct
private $related;
public $isCloned = false;
public $wakeUp = false;
public function __construct()
{
@@ -166,4 +167,12 @@ class ECommerceProduct
{
$this->isCloned = true;
}
/**
* Testing docblock contents here
*/
public function __wakeup()
{
$this->wakeUp = true;
}
}

View File

@@ -140,6 +140,40 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertFalse($user2->address instanceof \Doctrine\ORM\Proxy\Proxy);
}
/**
* @group DDC-1230
*/
public function testRemove()
{
$user = new CmsUser;
$user->name = 'Guilherme';
$user->username = 'gblanco';
$user->status = 'developer';
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_NEW, $this->_em->getUnitOfWork()->getEntityState($user));
$this->_em->persist($user);
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_MANAGED, $this->_em->getUnitOfWork()->getEntityState($user));
$this->_em->remove($user);
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_NEW, $this->_em->getUnitOfWork()->getEntityState($user));
$this->_em->persist($user);
$this->_em->flush();
$id = $user->getId();
$this->_em->remove($user);
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_REMOVED, $this->_em->getUnitOfWork()->getEntityState($user));
$this->_em->flush();
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_NEW, $this->_em->getUnitOfWork()->getEntityState($user));
$this->assertNull($this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $id));
}
public function testOneToManyOrphanRemoval()
{
$user = new CmsUser;
@@ -827,36 +861,6 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals(0, $this->_em->getConnection()->fetchColumn("select count(*) from cms_addresses where id=".$addressId.""));
}
public function testClearingCollectionDoesNotInitialize()
{
$user = new CmsUser();
$user->username = "beberlei";
$user->name = "Benjamin E.";
$user->status = 'active';
$grp = new CmsGroup();
$grp->setName("The Dudes");
$grp->addUser($user);
$user->addGroup($grp);
$this->_em->persist($user);
$this->_em->persist($grp);
$this->_em->flush();
$this->_em->clear();
$this->assertEquals(1, $this->_em->getConnection()->fetchColumn("select count(*) from cms_users_groups"));
$user2 = $this->_em->find(get_class($user), $user->id);
$this->assertFalse($user2->groups->isInitialized());
$user2->groups->clear();
$this->assertFalse($user2->groups->isInitialized());
$this->_em->flush();
$this->assertFalse($user2->groups->isInitialized());
$this->assertEquals(0, $this->_em->getConnection()->fetchColumn("select count(*) from cms_users_groups"));
}
public function testGetPartialReferenceToUpdateObjectWithoutLoadingIt()
{
//$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger);

View File

@@ -342,4 +342,39 @@ class ManyToManyBasicAssociationTest extends \Doctrine\Tests\OrmFunctionalTestCa
$this->assertEquals('Developers_New1', $user->groups[0]->name);
$this->assertEquals('Developers_New2', $user->groups[1]->name);
}
/**
* @group DDC-733
*/
public function testInitializePersistentCollection()
{
$user = $this->addCmsUserGblancoWithGroups(2);
$this->_em->clear();
$user = $this->_em->find(get_class($user), $user->id);
$this->assertFalse($user->groups->isInitialized(), "Pre-condition: lazy collection");
$this->_em->getUnitOfWork()->initializeObject($user->groups);
$this->assertTrue($user->groups->isInitialized(), "Collection should be initialized after calling UnitOfWork::initializeObject()");
}
/**
* @group DDC-1189
* @group DDC-956
*/
public function testClearBeforeLazyLoad()
{
$user = $this->addCmsUserGblancoWithGroups(4);
$this->_em->clear();
$user = $this->_em->find(get_class($user), $user->id);
$user->groups->clear();
$this->assertEquals(0, count($user->groups));
$this->_em->flush();
$user = $this->_em->find(get_class($user), $user->id);
$this->assertEquals(0, count($user->groups));
}
}

View File

@@ -97,4 +97,54 @@ class ReferenceProxyTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertTrue($clone->isCloned);
$this->assertFalse($entity->isCloned);
}
/**
* @group DDC-733
*/
public function testInitializeProxy()
{
$id = $this->createProduct();
/* @var $entity Doctrine\Tests\Models\ECommerce\ECommerceProduct */
$entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id);
$this->assertFalse($entity->__isInitialized__, "Pre-Condition: Object is unitialized proxy.");
$this->_em->getUnitOfWork()->initializeObject($entity);
$this->assertTrue($entity->__isInitialized__, "Should be initialized after called UnitOfWork::initializeObject()");
}
/**
* @group DDC-1163
*/
public function testInitializeChangeAndFlushProxy()
{
$id = $this->createProduct();
/* @var $entity Doctrine\Tests\Models\ECommerce\ECommerceProduct */
$entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id);
$entity->setName('Doctrine 2 Cookbook');
$this->_em->flush();
$this->_em->clear();
$entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id);
$this->assertEquals('Doctrine 2 Cookbook', $entity->getName());
}
/**
* @group DDC-1022
*/
public function testWakeupCalledOnProxy()
{
$id = $this->createProduct();
/* @var $entity Doctrine\Tests\Models\ECommerce\ECommerceProduct */
$entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id);
$this->assertFalse($entity->wakeUp);
$entity->setName('Doctrine 2 Cookbook');
$this->assertTrue($entity->wakeUp, "Loading the proxy should call __wakeup().");
}
}

View File

@@ -80,4 +80,25 @@ class PostgreSqlSchemaToolTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals("CREATE TABLE boolean_model (id INT NOT NULL, booleanField BOOLEAN NOT NULL, PRIMARY KEY(id))", $sql[0]);
$this->assertEquals("CREATE SEQUENCE boolean_model_id_seq INCREMENT BY 1 MINVALUE 1 START 1", $sql[1]);
}
public function testGetDropSchemaSql()
{
$classes = array(
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'),
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'),
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'),
);
$tool = new SchemaTool($this->_em);
$sql = $tool->getDropSchemaSQL($classes);
$this->assertEquals(13, count($sql));
$dropSequenceSQLs = 0;
foreach ($sql AS $stmt) {
if (strpos($stmt, "DROP SEQUENCE") === 0) {
$dropSequenceSQLs++;
}
}
$this->assertEquals(4, $dropSequenceSQLs, "Expect 4 sequences to be dropped.");
}
}

View File

@@ -0,0 +1,215 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
require_once __DIR__ . '/../../../TestInit.php';
/**
* @group DDC-1163
*/
class DDC1163Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
protected function setUp()
{
parent::setUp();
//$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger);
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1163Product'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1163SpecialProduct'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1163ProxyHolder'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1163Tag'),
));
}
public function testIssue()
{
$this->createSpecialProductAndProxyHolderReferencingIt();
$this->_em->clear();
$this->createProxyForSpecialProduct();
$this->setPropertyAndAssignTagToSpecialProduct();
// fails
$this->_em->flush();
}
private function createSpecialProductAndProxyHolderReferencingIt()
{
$specialProduct = new DDC1163SpecialProduct();
$this->_em->persist($specialProduct);
$proxyHolder = new DDC1163ProxyHolder();
$this->_em->persist($proxyHolder);
$proxyHolder->setSpecialProduct($specialProduct);
$this->_em->flush();
$this->productId = $specialProduct->getId();
$this->proxyHolderId = $proxyHolder->getId();
}
/**
* We want Doctrine to instantiate a lazy-load proxy for the previously created
* 'SpecialProduct' and register it.
*
* When Doctrine loads the 'ProxyHolder', it will do just that because the 'ProxyHolder'
* references the 'SpecialProduct'.
*/
private function createProxyForSpecialProduct()
{
/* @var $proxyHolder ProxyHolder */
$proxyHolder = $this->_em->find(__NAMESPACE__ . '\\DDC1163ProxyHolder', $this->proxyHolderId);
$this->assertInstanceOf(__NAMESPACE__.'\\DDC1163SpecialProduct', $proxyHolder->getSpecialProduct());
}
private function setPropertyAndAssignTagToSpecialProduct()
{
/* @var $specialProduct SpecialProduct */
$specialProduct = $this->_em->find(__NAMESPACE__ . '\\DDC1163SpecialProduct', $this->productId);
$this->assertInstanceOf(__NAMESPACE__.'\\DDC1163SpecialProduct', $specialProduct);
$this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $specialProduct);
$specialProduct->setSubclassProperty('foobar');
// this screams violation of law of demeter ;)
$this->assertEquals(
__NAMESPACE__.'\\DDC1163SpecialProduct',
$this->_em->getUnitOfWork()->getEntityPersister(get_class($specialProduct))->getClassMetadata()->name
);
$tag = new DDC1163Tag('Foo');
$this->_em->persist($tag);
$tag->setProduct($specialProduct);
}
}
/**
* @Entity
*/
class DDC1163ProxyHolder
{
/**
* @var int
* @Column(name="id", type="integer")
* @Id
* @GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var SpecialProduct
* @OneToOne(targetEntity="DDC1163SpecialProduct")
*/
private $specialProduct;
public function getId()
{
return $this->id;
}
public function setSpecialProduct(DDC1163SpecialProduct $specialProduct)
{
$this->specialProduct = $specialProduct;
}
public function getSpecialProduct()
{
return $this->specialProduct;
}
}
/**
* @Entity
* @InheritanceType("JOINED")
* @DiscriminatorColumn(name="type", type="string")
* @DiscriminatorMap({"special" = "DDC1163SpecialProduct"})
*/
abstract class DDC1163Product
{
/**
* @var int
* @Column(name="id", type="integer")
* @Id
* @GeneratedValue(strategy="AUTO")
*/
protected $id;
public function getId()
{
return $this->id;
}
}
/**
* @Entity
*/
class DDC1163SpecialProduct extends DDC1163Product
{
/**
* @var string
* @Column(name="subclass_property", type="string", nullable=true)
*/
private $subclassProperty;
/**
* @param string $value
*/
public function setSubclassProperty($value)
{
$this->subclassProperty = $value;
}
}
/**
* @Entity
*/
class DDC1163Tag
{
/**
* @var int
* @Column(name="id", type="integer")
* @Id
* @GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
* @Column(name="name", type="string")
*/
private $name;
/**
* @var Product
* @ManyToOne(targetEntity="DDC1163Product", inversedBy="tags")
* @JoinColumns({
* @JoinColumn(name="product_id", referencedColumnName="id")
* })
*/
private $product;
/**
* @param string $name
*/
public function __construct($name)
{
$this->name = $name;
}
/**
* @param Product $product
*/
public function setProduct(DDC1163Product $product)
{
$this->product = $product;
}
}

View File

@@ -0,0 +1,93 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
require_once __DIR__ . '/../../../TestInit.php';
use DateTime, Doctrine\DBAL\Types\Type;
class DDC1193Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
protected function setUp()
{
parent::setUp();
//$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger);
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1193Company'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1193Person'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1193Account')
));
}
/**
* @group DDC-1193
*/
public function testIssue()
{
$company = new DDC1193Company();
$person = new DDC1193Person();
$account = new DDC1193Account();
$person->account = $account;
$person->company = $company;
$company->member = $person;
$this->_em->persist($company);
$this->_em->flush();
$companyId = $company->id;
$accountId = $account->id;
$this->_em->clear();
$company = $this->_em->find(get_class($company), $companyId);
$this->assertTrue($this->_em->getUnitOfWork()->isInIdentityMap($company), "Company is in identity map.");
$this->assertFalse($company->member->__isInitialized__, "Pre-Condition");
$this->assertTrue($this->_em->getUnitOfWork()->isInIdentityMap($company->member), "Member is in identity map.");
$this->_em->remove($company);
$this->_em->flush();
$this->assertEquals(count($this->_em->getRepository(get_class($account))->findAll()), 0);
}
}
/** @Entity */
class DDC1193Company {
/**
* @Id @Column(type="integer")
* @GeneratedValue
*/
public $id;
/** @OneToOne(targetEntity="DDC1193Person", cascade={"persist", "remove"}) */
public $member;
}
/** @Entity */
class DDC1193Person {
/**
* @Id @Column(type="integer")
* @GeneratedValue
*/
public $id;
/**
* @OneToOne(targetEntity="DDC1193Account", cascade={"persist", "remove"})
*/
public $account;
}
/** @Entity */
class DDC1193Account {
/**
* @Id @Column(type="integer")
* @GeneratedValue
*/
public $id;
}

View File

@@ -0,0 +1,50 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Tests\Models\CMS\CmsUser;
use Doctrine\Tests\Models\CMS\CmsGroup;
require_once __DIR__ . '/../../../TestInit.php';
/**
* @group DDC-1276
*/
class DDC1276Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
public function setUp()
{
$this->useModelSet('cms');
parent::setUp();
}
public function testIssue()
{
$user = new CmsUser();
$user->name = "Benjamin";
$user->username = "beberlei";
$user->status = "active";
$this->_em->persist($user);
for ($i = 0; $i < 2; $i++) {
$group = new CmsGroup();
$group->name = "group".$i;
$user->groups[] = $group;
$this->_em->persist($group);
}
$this->_em->flush();
$this->_em->clear();
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $user->id);
$cloned = clone $user;
$this->assertSame($user->groups, $cloned->groups);
$this->assertEquals(2, count($user->groups));
$this->_em->merge($cloned);
$this->assertEquals(2, count($user->groups));
$this->_em->flush();
}
}

View File

@@ -186,6 +186,7 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeRefresh']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeDetach']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeMerge']);
$this->assertTrue($class->associationMappings['phonenumbers']['orphanRemoval']);
// Test Order By
$this->assertEquals(array('number' => 'ASC'), $class->associationMappings['phonenumbers']['orderBy']);
@@ -329,7 +330,7 @@ class User
public $address;
/**
* @OneToMany(targetEntity="Phonenumber", mappedBy="user", cascade={"persist"})
* @OneToMany(targetEntity="Phonenumber", mappedBy="user", cascade={"persist"}, orphanRemoval=true)
* @OrderBy({"number"="ASC"})
*/
public $phonenumbers;
@@ -425,7 +426,7 @@ class User
1 => 'persist',
),
'mappedBy' => 'user',
'orphanRemoval' => false,
'orphanRemoval' => true,
'orderBy' =>
array(
'number' => 'ASC',

View File

@@ -232,6 +232,17 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException');
$cm->mapField(array('fieldName' => 'name', 'columnName' => 'name'));
}
/**
* @group DDC-1224
*/
public function testGetTemporaryTableNameSchema()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->setTableName('foo.bar');
$this->assertEquals('foo_bar_id_tmp', $cm->getTemporaryIdTableName());
}
public function testDefaultTableName()
{

View File

@@ -60,7 +60,7 @@ $metadata->mapOneToMany(array(
1 => 'persist',
),
'mappedBy' => 'user',
'orphanRemoval' => false,
'orphanRemoval' => true,
'orderBy' =>
array(
'number' => 'ASC',

View File

@@ -35,7 +35,7 @@
<join-column name="address_id" referenced-column-name="id" on-delete="CASCADE" on-update="CASCADE"/>
</one-to-one>
<one-to-many field="phonenumbers" target-entity="Phonenumber" mapped-by="user">
<one-to-many field="phonenumbers" target-entity="Phonenumber" mapped-by="user" orphan-removal="true">
<cascade>
<cascade-persist/>
</cascade>

View File

@@ -33,6 +33,7 @@ Doctrine\Tests\ORM\Mapping\User:
oneToMany:
phonenumbers:
targetEntity: Phonenumber
orphanRemoval: true
mappedBy: user
orderBy:
number: ASC

View File

@@ -0,0 +1,63 @@
<?php
namespace Doctrine\Tests\ORM\Performance;
use Doctrine\ORM\Tools\SchemaTool;
use Doctrine\ORM\Query;
require_once __DIR__ . '/../../TestInit.php';
class InheritancePersisterPerformanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
{
protected function setUp()
{
$this->useModelSet('company');
parent::setUp();
}
public function testCompanyContract()
{
$person = new \Doctrine\Tests\Models\Company\CompanyEmployee();
$person->setName('Poor Sales Guy');
$person->setDepartment('Sales');
$person->setSalary(100);
$this->_em->persist($person);
for ($i = 0; $i < 33; $i++) {
$fix = new \Doctrine\Tests\Models\Company\CompanyFixContract();
$fix->setFixPrice(1000);
$fix->setSalesPerson($person);
$fix->markCompleted();
$this->_em->persist($fix);
$flex = new \Doctrine\Tests\Models\Company\CompanyFlexContract();
$flex->setSalesPerson($person);
$flex->setHoursWorked(100);
$flex->setPricePerHour(100);
$flex->markCompleted();
$this->_em->persist($flex);
$ultra = new \Doctrine\Tests\Models\Company\CompanyFlexUltraContract();
$ultra->setSalesPerson($person);
$ultra->setHoursWorked(150);
$ultra->setPricePerHour(150);
$ultra->setMaxPrice(7000);
$this->_em->persist($ultra);
}
$this->_em->flush();
$this->_em->clear();
$start = microtime(true);
$contracts = $this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyContract')->findAll();
echo "99 CompanyContract: " . number_format(microtime(true) - $start, 6) . "\n";
$this->assertEquals(99, count($contracts));
$this->_em->clear();
$start = microtime(true);
$contracts = $this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyContract')->findAll();
echo "99 CompanyContract: " . number_format(microtime(true) - $start, 6) . "\n";
$this->assertEquals(99, count($contracts));
}
}

View File

@@ -0,0 +1,118 @@
<?php
namespace Doctrine\Tests\ORM\Performance;
use Doctrine\ORM\Tools\SchemaTool;
use Doctrine\ORM\Query;
use Doctrine\Tests\Models\CMS\CmsUser;
use Doctrine\Tests\Models\CMS\CmsPhonenumber;
use Doctrine\Tests\Models\CMS\CmsAddress;
use Doctrine\Tests\Models\CMS\CmsGroup;
use Doctrine\Tests\Models\CMS\CmsArticle;
use Doctrine\Tests\Models\CMS\CmsComment;
require_once __DIR__ . '/../../TestInit.php';
class PersisterPerformanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
{
protected function setUp()
{
$this->useModelSet('cms');
parent::setUp();
}
public function testFindCmsArticle()
{
$author = new CmsUser();
$author->name = "beberlei";
$author->status = "active";
$author->username = "beberlei";
$this->_em->persist($author);
$ids = array();
for ($i = 0; $i < 100; $i++) {
$article = new CmsArticle();
$article->text = "foo";
$article->topic = "bar";
$article->user = $author;
$this->_em->persist($article);
$ids[] = $article;
}
$this->_em->flush();
$this->_em->clear();
$start = microtime(true);
$articles = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsArticle')->findAll();
echo "100 CmsArticle findAll(): " . number_format(microtime(true) - $start, 6) . "\n";
$this->_em->clear();
$start = microtime(true);
$articles = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsArticle')->findAll();
echo "100 CmsArticle findAll(): " . number_format(microtime(true) - $start, 6) . "\n";
$this->_em->clear();
$start = microtime(true);
for ($i = 0; $i < 100; $i++) {
$articles = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsArticle')->find($ids[$i]->id);
}
echo "100 CmsArticle find(): " . number_format(microtime(true) - $start, 6) . "\n";
$this->_em->clear();
$start = microtime(true);
for ($i = 0; $i < 100; $i++) {
$articles = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsArticle')->find($ids[$i]->id);
}
echo "100 CmsArticle find(): " . number_format(microtime(true) - $start, 6) . "\n";
}
public function testFindCmsGroup()
{
for ($i = 0; $i < 100; $i++) {
$group = new CmsGroup();
$group->name = "foo" . $i;
$this->_em->persist($group);
}
$this->_em->flush();
$this->_em->clear();
$start = microtime(true);
$articles = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsGroup')->findAll();
echo "100 CmsGroup: " . number_format(microtime(true) - $start, 6) . "\n";
$this->_em->clear();
$start = microtime(true);
$articles = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsGroup')->findAll();
echo "100 CmsGroup: " . number_format(microtime(true) - $start, 6) . "\n";
}
public function testFindCmsUser()
{
for ($i = 0; $i < 100; $i++) {
$user = new CmsUser();
$user->name = "beberlei";
$user->status = "active";
$user->username = "beberlei".$i;
$this->_em->persist($user);
}
$this->_em->flush();
$this->_em->clear();
$start = microtime(true);
$articles = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser')->findAll();
echo "100 CmsUser: " . number_format(microtime(true) - $start, 6) . "\n";
$this->_em->clear();
$start = microtime(true);
$articles = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser')->findAll();
echo "100 CmsUser: " . number_format(microtime(true) - $start, 6) . "\n";
}
}

View File

@@ -589,4 +589,32 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals(2, $expr->count(), "Modifying the second query should affect the first one.");
}
/**
* @group DDC-1211
*/
public function testEmptyStringLiteral()
{
$expr = $this->_em->getExpressionBuilder();
$qb = $this->_em->createQueryBuilder()
->select('u')
->from('Doctrine\Tests\Models\CMS\CmsUser', 'u')
->where($expr->eq('u.username', $expr->literal("")));
$this->assertEquals("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = ''", $qb->getDQL());
}
/**
* @group DDC-1211
*/
public function testEmptyNumericLiteral()
{
$expr = $this->_em->getExpressionBuilder();
$qb = $this->_em->createQueryBuilder()
->select('u')
->from('Doctrine\Tests\Models\CMS\CmsUser', 'u')
->where($expr->eq('u.username', $expr->literal(0)));
$this->assertEquals('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = 0', $qb->getDQL());
}
}