Compare commits

..

63 Commits

Author SHA1 Message Date
Marco Pivetta
e3aa3f2d1d Preparing v2.5.8 release 2017-08-13 20:46:56 +02:00
Marco Pivetta
c83f479633 Merge pull request #6621 from Powerhamster/patch-1
fixed undefined variable
2017-08-13 20:27:18 +02:00
Thomas Rothe
741f1db198 fixed undefined variable
changed $conditions to $condition so $isConditionalJoin is working
2017-08-12 11:33:11 +02:00
Marco Pivetta
22546a3811 Correcting connection existence in tearDown operations 2017-08-11 23:28:20 +02:00
Marco Pivetta
efa058bd8f If no connection was enstablished, skip the tearDown operations 2017-08-11 22:56:02 +02:00
Marco Pivetta
767577cec6 Removing ::class pseudo-constant usage 2017-08-11 22:49:46 +02:00
Marco Pivetta
c0f593e422 Removing ::class syntax to make dinosaurs run against this codebase too 2017-08-11 22:22:50 +02:00
Marco Pivetta
d89d238594 Merge branch 'fix/#6464-#6475-correct-SQL-generated-with-JTI-and-WITH-condition-2.5' into 2.5
Backport #6464
Backport #6475
2017-08-11 21:43:05 +02:00
Marco Pivetta
2337b7aedd #6464 #6475 cleaning up test - removed invalid fetch join, CS 2017-08-11 21:41:05 +02:00
Stefan Siegl
9e6f061bfb #6464 code review updates 2017-08-11 21:40:53 +02:00
Stefan Siegl
bf1188127e generate nested join sql for CTIs, closes #6464 2017-08-11 21:40:16 +02:00
Stefan Siegl
c73ec2aa76 #6464 add test 2017-08-11 21:39:45 +02:00
Marco Pivetta
095611c4b6 Merge branch 'fix/#6614-clean-modified-collection-causing-double-dirty-object-persistence-2.5' into 2.5
Backport #6613
Backport #6614
Backport #6616
2017-08-11 21:25:27 +02:00
Marco Pivetta
96c6f4cf1d #6613 #6614 #6616 removed unused import 2017-08-11 21:25:10 +02:00
Marco Pivetta
5cacb6e14f #6613 #6614 #6616 minor performance optimisations around the new restoreNewObjectsInDirtyCollection implementation 2017-08-11 21:23:58 +02:00
Marco Pivetta
ab63628960 #6613 #6614 #6616 removing DDC6613 test, which was fully ported to unit tests 2017-08-11 21:23:55 +02:00
Marco Pivetta
15731c7bde #6613 #6614 #6616 ensuring that the collection is marked as non-dirty if all new items are contained in the initialized ones 2017-08-11 21:23:51 +02:00
Andreas Braun
abb429a0c9 Add failing test for dirty flag 2017-08-11 21:23:47 +02:00
Marco Pivetta
61cb03bf30 #6613 #6614 #6616 removing repeated PersistentCollectionTest chunks of code 2017-08-11 21:23:40 +02:00
Marco Pivetta
d6bcb5b1f8 #6613 #6614 #6616 initializing a dirty collection that has new items that are also coming from initialization data de-duplicates new and persisted items 2017-08-11 21:22:59 +02:00
Marco Pivetta
bdae362777 #6613 #6614 #6616 moved integration test basics to a unit test that verifies basic dirty collection initialization semantics 2017-08-11 21:22:54 +02:00
Marco Pivetta
59c5574554 #6613 #6614 correcting broken test that isn't using objects against a PersistentCollection 2017-08-11 21:22:43 +02:00
Marco Pivetta
9545bf9d8c #6613 #6614 correcting broken test that isn't using objects against a PersistentCollection 2017-08-11 21:22:40 +02:00
Marco Pivetta
5521d1f325 #6613 #6614 ensuring that only newly added items that weren't loaded are restored in the dirty state of the collection 2017-08-11 21:22:34 +02:00
Marco Pivetta
49694dc335 #6613 #6614 after initialization, the collection should be dirty anyway 2017-08-11 21:21:43 +02:00
Marco Pivetta
3155d970d3 #6613 #6614 adding assertions about collection initialization and dirty status 2017-08-11 21:21:40 +02:00
Marco Pivetta
09189fc021 #6613 #6614 removing IDE-generated header 2017-08-11 21:21:36 +02:00
Marco Pivetta
5a0d3e5fb8 #6613 #6614 removing phone/user specifics, using ORM naming for associations 2017-08-11 21:21:27 +02:00
Marco Pivetta
b9ba4e3207 #6613 #6614 correcting column mapping (was integer, should be string), segregating phone creation away 2017-08-11 21:21:24 +02:00
Marco Pivetta
d7919678e5 #6613 #6614 remove superfluous mappings 2017-08-11 21:21:21 +02:00
Marco Pivetta
8b185eb822 #6613 #6614 rewrote test logic to be less magic-constant-dependent 2017-08-11 21:21:17 +02:00
Marco Pivetta
693a0546d3 #6613 #6614 CS - applying @group annotation to the test 2017-08-11 21:21:14 +02:00
Marco Pivetta
5c5c8fc487 #6613 #6614 removing dedicated DDC6613 model directory 2017-08-11 21:21:10 +02:00
Marco Pivetta
85dc707cc8 #6613 #6614 smashing entity definitions into the test 2017-08-11 21:21:03 +02:00
Marco Pivetta
64a1251b61 #6613 #6614 better test specification - removing useless assertions 2017-08-11 21:20:42 +02:00
Marco Pivetta
65ed6a2c2f #6613 #6614 simplifying entity definition - using auto-assigned string identifiers to reduce moving parts 2017-08-11 21:20:34 +02:00
Marco Pivetta
d27a9fce7a Merge pull request #6580 from Tobion/patch-1
Allow DBAL 2.6 and common 2.8 to be installed
2017-07-25 05:02:26 +02:00
Tobias Schultze
11659f5cfe Allow common 2.8 to be installed 2017-07-24 16:38:01 +02:00
Tobias Schultze
68dad26482 Allow DBAL 2.6 to be installed
DBAL 2.6 is released but currently dependencies can't be resolved as ORM 2.5 does not allow DBAL 2.6 and ORM 2.6 is not relased yet.
2017-07-24 16:27:53 +02:00
Marco Pivetta
b3ceef0fb6 Merge branch 'fix/#6550-correct-return-value-of-extra-lazy-removeElement-calls' into 2.5
Backport #6550 to 2.5
2017-07-22 09:27:30 +02:00
Andreas Braun
095b365146 Add test for removing element not in collection 2017-07-22 09:27:13 +02:00
Andreas Braun
7c1ebd99bc Fix return of removeElement on collections
Fixes #5745
2017-07-22 09:27:01 +02:00
Marco Pivetta
c06f19db8d Merge branch 'fix/#1515-clean-hydrator-listeners-on-hydration-end-2.5' into 2.5
Close #1515

This is a backport of the original PR - the same patch should land in `master` too, after a cleanup
2017-06-24 03:23:19 +02:00
Emiel Nijpels
0be9be4e24 DDC-3146 remove event listener from event listener in abstract hydrator in cleanup function 2017-06-24 03:23:01 +02:00
Luís Cobucci
b2bf5ee92e Leave PHP 7.1 and nightly to master 2017-06-22 07:57:54 +02:00
Luís Cobucci
698bd813a2 Remove HHVM from build 2017-06-22 07:46:45 +02:00
Jáchym Toušek
b2ac8fdfd7 Fix CountOutputWalker for queries with GROUP BY 2017-06-22 07:15:35 +02:00
Marco Pivetta
9c2b54b748 Adding classes required by the SchemaToolTest that exist in 'master', but not in '2.5' 2017-06-21 07:27:41 +02:00
Marco Pivetta
910784213f Corrected duplicate import statements due to cherry picking 2017-06-21 06:49:45 +02:00
Marco Pivetta
1d1de7de80 Merge branch 'fix/#5798-undefined-schema-tool-index-2.5' into 2.5
Close #5798
2017-06-21 06:32:00 +02:00
Sergey Fedotov
741da6eed7 Fix undefined index for discriminator column in SchemaTool 2017-06-21 06:31:23 +02:00
Marco Pivetta
ad5397b581 Merge branch 'fix/#5715-fix-metadata-filtering-in-cli-tools-2.5' into 2.5
Close #5715
2017-06-21 06:15:42 +02:00
Guilliam Xavier
57bb46ca9d Add regex tests for MetadataFilter (PR #507) 2017-06-21 06:15:25 +02:00
Guilliam Xavier
0416d5e036 Add more basic tests for MetadataFilter 2017-06-21 06:15:14 +02:00
Guilliam Xavier
a14432117a Fix MetadataFilter not testing filters after first 2017-06-21 06:15:01 +02:00
Guilliam Xavier
824f62d3bb Add failing test for #5715 (unit test for MetadataFilter) 2017-06-21 06:14:48 +02:00
Marco Pivetta
c0f0fe060f Merge branch 'fix/#1541-minor-docblock-correction-in-resultset-mapping-builder' into 2.5
Backport #1541 to 2.5
2017-05-20 16:45:59 +02:00
aleeeftw
caffbe04a2 Minor docblock correction
The documentation for the method ‘addJoinedEntityFromClassMetadata’ is
wrong. As we can see currently says you need to pass an object and that
is wrong. The $relation variable is passed to ‘addJoinedEntityResult’
which is using it as a ‘string’.
2017-05-20 16:45:25 +02:00
Marco Pivetta
d2c805b071 Correcting PHP 5.4 compliance by removing ::class usage (moving to real constants) 2017-05-02 09:33:48 +02:00
Marco Pivetta
04fc7a9a1c Merge branch 'fix/#6367-#6362-inheritance-alias-hydration' into 2.5
Close #6367
Close #6362
2017-05-02 09:26:54 +02:00
Timothy Clissold
149b8f4e09 Fix inheritance join alias 2017-05-02 09:26:44 +02:00
Marco Pivetta
48e8c02cb8 Merge pull request #6381 from ElisDN/ElisDN-phpdoc
Fixed PHPDoc
2017-04-03 09:04:13 +02:00
Елисеев Дмитрий
e218866a69 Fixed PHPDoc 2017-04-02 20:29:46 +03:00
22 changed files with 802 additions and 65 deletions

View File

@@ -5,8 +5,6 @@ php:
- 5.5
- 5.6
- 7.0
- hhvm
- hhvm-nightly
env:
- DB=mysql
@@ -15,7 +13,7 @@ env:
before_script:
- if [[ $TRAVIS_PHP_VERSION = '5.6' && $DB = 'sqlite' ]]; then PHPUNIT_FLAGS="--coverage-clover ./build/logs/clover.xml"; else PHPUNIT_FLAGS=""; fi
- if [[ $TRAVIS_PHP_VERSION != '5.6' && $TRAVIS_PHP_VERSION != 'hhvm' && $TRAVIS_PHP_VERSION != 'hhvm-nightly' && $TRAVIS_PHP_VERSION != '7.0' ]]; then phpenv config-rm xdebug.ini; fi
- if [[ $PHPUNIT_FLAGS == "" ]]; then phpenv config-rm xdebug.ini; fi
- composer self-update
- composer install --prefer-source --dev
@@ -24,15 +22,10 @@ script:
- ENABLE_SECOND_LEVEL_CACHE=1 ./vendor/bin/phpunit -v -c tests/travis/$DB.travis.xml --exclude-group performance,non-cacheable,locking_functional
matrix:
exclude:
- php: hhvm
env: DB=pgsql # driver currently unsupported by HHVM
- php: hhvm
env: DB=mysqli # driver currently unsupported by HHVM
- php: hhvm-nightly
env: DB=pgsql # driver currently unsupported by HHVM
- php: hhvm-nightly
env: DB=mysqli # driver currently unsupported by HHVM
fast_finish: true
allow_failures:
- php: 7.0
- php: hhvm-nightly # hhvm-nightly currently chokes on composer installation
cache:
directories:
- $HOME/.composer/cache

View File

@@ -16,9 +16,9 @@
"php": ">=5.4",
"ext-pdo": "*",
"doctrine/collections": "~1.2",
"doctrine/dbal": ">=2.5-dev,<2.6-dev",
"doctrine/dbal": ">=2.5-dev,<2.7-dev",
"doctrine/instantiator": "~1.0.1",
"doctrine/common": ">=2.5-dev,<2.8-dev",
"doctrine/common": ">=2.5-dev,<2.9-dev",
"doctrine/cache": "~1.4",
"symfony/console": "~2.5|~3.0"
},

View File

@@ -30,7 +30,7 @@ use Doctrine\Common\Persistence\Event\LoadClassMetadataEventArgs as BaseLoadClas
* Note: method annotations are used instead of method overrides (due to BC policy)
*
* @method __construct(\Doctrine\ORM\Mapping\ClassMetadata $classMetadata, \Doctrine\ORM\EntityManager $objectManager)
* @method \Doctrine\ORM\EntityManager getClassMetadata()
* @method \Doctrine\ORM\Mapping\ClassMetadata getClassMetadata()
*/
class LoadClassMetadataEventArgs extends BaseLoadClassMetadataEventArgs
{

View File

@@ -210,6 +210,9 @@ abstract class AbstractHydrator
$this->_rsm = null;
$this->_cache = array();
$this->_metadataCache = array();
$evm = $this->_em->getEventManager();
$evm->removeEventListener(array(Events::onClear), $this);
}
/**

View File

@@ -360,8 +360,8 @@ class ObjectHydrator extends AbstractHydrator
// Get a reference to the parent object to which the joined element belongs.
if ($this->_rsm->isMixed && isset($this->rootAliases[$parentAlias])) {
$first = reset($this->resultPointers);
$parentObject = $first[key($first)];
$objectClass = $this->resultPointers[$parentAlias];
$parentObject = $objectClass[key($objectClass)];
} else if (isset($this->resultPointers[$parentAlias])) {
$parentObject = $this->resultPointers[$parentAlias];
} else {

View File

@@ -19,7 +19,6 @@
namespace Doctrine\ORM;
use Closure;
use Doctrine\Common\Collections\AbstractLazyCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
@@ -375,11 +374,7 @@ final class PersistentCollection extends AbstractLazyCollection implements Selec
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
if ($persister->removeElement($this, $element)) {
return $element;
}
return null;
return $persister->removeElement($this, $element);
}
$removed = parent::removeElement($element);
@@ -689,21 +684,41 @@ final class PersistentCollection extends AbstractLazyCollection implements Selec
protected function doInitialize()
{
// Has NEW objects added through add(). Remember them.
$newObjects = array();
$newlyAddedDirtyObjects = array();
if ($this->isDirty) {
$newObjects = $this->collection->toArray();
$newlyAddedDirtyObjects = $this->collection->toArray();
}
$this->collection->clear();
$this->em->getUnitOfWork()->loadCollection($this);
$this->takeSnapshot();
// Reattach NEW objects added through add(), if any.
if ($newObjects) {
foreach ($newObjects as $obj) {
$this->collection->add($obj);
}
if ($newlyAddedDirtyObjects) {
$this->restoreNewObjectsInDirtyCollection($newlyAddedDirtyObjects);
}
}
/**
* @param object[] $newObjects
*
* @return void
*
* Note: the only reason why this entire looping/complexity is performed via `spl_object_hash`
* is because we want to prevent using `array_udiff()`, which is likely to cause very
* high overhead (complexity of O(n^2)). `array_diff_key()` performs the operation in
* core, which is faster than using a callback for comparisons
*/
private function restoreNewObjectsInDirtyCollection(array $newObjects)
{
$loadedObjects = $this->collection->toArray();
$newObjectsByOid = \array_combine(\array_map('spl_object_hash', $newObjects), $newObjects);
$loadedObjectsByOid = \array_combine(\array_map('spl_object_hash', $loadedObjects), $loadedObjects);
$newObjectsThatWereNotLoaded = \array_diff_key($newObjectsByOid, $loadedObjectsByOid);
if ($newObjectsThatWereNotLoaded) {
// Reattach NEW objects added through add(), if any.
\array_walk($newObjectsThatWereNotLoaded, [$this->collection, 'add']);
$this->isDirty = true;
}

View File

@@ -110,7 +110,7 @@ class ResultSetMappingBuilder extends ResultSetMapping
* @param string $class The class name of the joined entity.
* @param string $alias The unique alias to use for the joined entity.
* @param string $parentAlias The alias of the entity result that is the parent of this joined result.
* @param object $relation The association field that connects the parent entity result
* @param string $relation The association field that connects the parent entity result
* with the joined entity result.
* @param array $renamedColumns Columns that have been renamed (tableColumnName => queryColumnName).
* @param int|null $renameMode One of the COLUMN_RENAMING_* constants or array for BC reasons (CUSTOM).

View File

@@ -870,6 +870,19 @@ class SqlWalker implements TreeWalker
* @return string
*/
public function walkRangeVariableDeclaration($rangeVariableDeclaration)
{
return $this->generateRangeVariableDeclarationSQL($rangeVariableDeclaration, false);
}
/**
* Generate appropriate SQL for RangeVariableDeclaration AST node
*
* @param AST\RangeVariableDeclaration $rangeVariableDeclaration
* @param bool $buildNestedJoins
*
* @return string
*/
private function generateRangeVariableDeclarationSQL($rangeVariableDeclaration, $buildNestedJoins)
{
$class = $this->em->getClassMetadata($rangeVariableDeclaration->abstractSchemaName);
$dqlAlias = $rangeVariableDeclaration->aliasIdentificationVariable;
@@ -885,7 +898,11 @@ class SqlWalker implements TreeWalker
);
if ($class->isInheritanceTypeJoined()) {
$sql .= $this->_generateClassTableInheritanceJoins($class, $dqlAlias);
if ($buildNestedJoins) {
$sql = '(' . $sql . $this->_generateClassTableInheritanceJoins($class, $dqlAlias) . ')';
} else {
$sql .= $this->_generateClassTableInheritanceJoins($class, $dqlAlias);
}
}
return $sql;
@@ -1121,16 +1138,17 @@ class SqlWalker implements TreeWalker
: ' INNER JOIN ';
switch (true) {
case ($joinDeclaration instanceof \Doctrine\ORM\Query\AST\RangeVariableDeclaration):
case ($joinDeclaration instanceof AST\RangeVariableDeclaration):
$class = $this->em->getClassMetadata($joinDeclaration->abstractSchemaName);
$dqlAlias = $joinDeclaration->aliasIdentificationVariable;
$tableAlias = $this->getSQLTableAlias($class->table['name'], $dqlAlias);
$condition = '(' . $this->walkConditionalExpression($join->conditionalExpression) . ')';
$condExprConjunction = ($class->isInheritanceTypeJoined() && $joinType != AST\Join::JOIN_TYPE_LEFT && $joinType != AST\Join::JOIN_TYPE_LEFTOUTER)
$isUnconditionalJoin = empty($condition);
$condExprConjunction = ($class->isInheritanceTypeJoined() && $joinType != AST\Join::JOIN_TYPE_LEFT && $joinType != AST\Join::JOIN_TYPE_LEFTOUTER && $isUnconditionalJoin)
? ' AND '
: ' ON ';
$sql .= $this->walkRangeVariableDeclaration($joinDeclaration);
$sql .= $this->generateRangeVariableDeclarationSQL($joinDeclaration, !$isUnconditionalJoin);
$conditions = array($condition);
@@ -1151,7 +1169,7 @@ class SqlWalker implements TreeWalker
$sql .= $condExprConjunction . implode(' AND ', $conditions);
break;
case ($joinDeclaration instanceof \Doctrine\ORM\Query\AST\JoinAssociationDeclaration):
case ($joinDeclaration instanceof AST\JoinAssociationDeclaration):
$sql .= $this->walkJoinAssociationDeclaration($joinDeclaration, $joinType, $join->conditionalExpression);
break;
}

View File

@@ -84,10 +84,6 @@ class MetadataFilter extends \FilterIterator implements \Countable
);
}
if ($pregResult === 0) {
return false;
}
if ($pregResult) {
return true;
}

View File

@@ -85,6 +85,14 @@ class CountOutputWalker extends SqlWalker
$sql = parent::walkSelectStatement($AST);
if ($AST->groupByClause) {
return sprintf(
'SELECT %s AS dctrn_count FROM (%s) dctrn_table',
$this->platform->getCountExpression('*'),
$sql
);
}
// Find out the SQL alias of the identifier column of the root entity
// It may be possible to make this work with multiple root entities but that
// would probably require issuing multiple queries or doing a UNION SELECT

View File

@@ -345,7 +345,7 @@ class SchemaTool
$discrColumn = $class->discriminatorColumn;
if ( ! isset($discrColumn['type']) ||
(strtolower($discrColumn['type']) == 'string' && $discrColumn['length'] === null)
(strtolower($discrColumn['type']) == 'string' && ! isset($discrColumn['length']))
) {
$discrColumn['type'] = 'string';
$discrColumn['length'] = 255;

View File

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

View File

@@ -636,11 +636,13 @@ class ExtraLazyCollectionTest extends OrmFunctionalTestCase
$group = $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId);
$queryCount = $this->getCurrentQueryCount();
$user->groups->removeElement($group);
$this->assertTrue($user->groups->removeElement($group));
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Removing a persisted entity should cause one query to be executed.");
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
$this->assertFalse($user->groups->removeElement($group), "Removing an already removed element returns false");
// Test Many to Many removal with Entity state as new
$group = new \Doctrine\Tests\Models\CMS\CmsGroup();
$group->name = "A New group!";

View File

@@ -0,0 +1,65 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
/**
* @group DDC-3146
* @author Emiel Nijpels <emiel@silverstreet.com>
*/
class DDC3146Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
/**
* Verify that the number of added events to the event listener from the abstract hydrator class is equal to the number of removed events
*/
public function testEventListeners()
{
// Create mock connection to be returned from the entity manager interface
$mockConnection = $this->getMockBuilder('Doctrine\DBAL\Connection')->disableOriginalConstructor()->getMock();
$mockEntityManagerInterface = $this->getMockBuilder('Doctrine\ORM\EntityManagerInterface')->disableOriginalConstructor()->getMock();
$mockEntityManagerInterface->expects($this->any())->method('getConnection')->will($this->returnValue($mockConnection));
// Create mock event manager to be returned from the entity manager interface
$mockEventManager = $this->getMockBuilder('Doctrine\Common\EventManager')->disableOriginalConstructor()->getMock();
$mockEntityManagerInterface->expects($this->any())->method('getEventManager')->will($this->returnValue($mockEventManager));
// Create mock statement and result mapping
$mockStatement = $this->getMockBuilder('Doctrine\DBAL\Driver\Statement')->disableOriginalConstructor()->getMock();
$mockStatement->expects($this->once())->method('fetch')->will($this->returnValue(false));
$mockResultMapping = $this->getMockBuilder('Doctrine\ORM\Query\ResultSetMapping')->disableOriginalConstructor()->getMock();
// Create mock abstract hydrator
$mockAbstractHydrator = $this->getMockBuilder('Doctrine\ORM\Internal\Hydration\AbstractHydrator')
->setConstructorArgs(array($mockEntityManagerInterface))
->setMethods(array('hydrateAllData'))
->getMock();
// Increase counter every time the event listener is added and decrease the counter every time the event listener is removed
$eventCounter = 0;
$mockEventManager->expects($this->any())
->method('addEventListener')
->will(
$this->returnCallback(
function () use (&$eventCounter) {
$eventCounter++;
}
)
);
$mockEventManager->expects($this->any())
->method('removeEventListener')
->will(
$this->returnCallback(
function () use (&$eventCounter) {
$eventCounter--;
}
)
);
// Create iterable result
$iterableResult = $mockAbstractHydrator->iterate($mockStatement, $mockResultMapping, array());
$iterableResult->next();
// Number of added events listeners should be equal or less than the number of removed events
$this->assertLessThanOrEqual(0, $eventCounter, 'More events added to the event listener than removed; this can create a memory leak when references are not cleaned up');
}
}

View File

@@ -0,0 +1,152 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Tests\OrmFunctionalTestCase;
use Doctrine\ORM\Query;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\Tests\Mocks\HydratorMockStatement;
final class GH6362Test extends OrmFunctionalTestCase
{
protected function setUp()
{
parent::setUp();
$this->_schemaTool->createSchema(
[
$this->_em->getClassMetadata(GH6362Start::CLASSNAME),
$this->_em->getClassMetadata(GH6362Base::CLASSNAME),
$this->_em->getClassMetadata(GH6362Child::CLASSNAME),
$this->_em->getClassMetadata(GH6362Join::CLASSNAME),
]
);
}
/**
* @group 6362
*
* SELECT a as base, b, c, d
* FROM Start a
* LEFT JOIN a.bases b
* LEFT JOIN Child c WITH b.id = c.id
* LEFT JOIN c.joins d
*/
public function testInheritanceJoinAlias()
{
$rsm = new ResultSetMapping;
$rsm->addEntityResult(GH6362Start::CLASSNAME, 'a', 'base');
$rsm->addJoinedEntityResult(GH6362Base::CLASSNAME, 'b', 'a', 'bases');
$rsm->addEntityResult(GH6362Child::CLASSNAME, 'c');
$rsm->addJoinedEntityResult(GH6362Join::CLASSNAME, 'd', 'c', 'joins');
$rsm->addFieldResult('a', 'id_0', 'id');
$rsm->addFieldResult('b', 'id_1', 'id');
$rsm->addFieldResult('c', 'id_2', 'id');
$rsm->addFieldResult('d', 'id_3', 'id');
$rsm->addMetaResult('a', 'bases_id_4', 'bases_id', false, 'integer');
$rsm->addMetaResult('b', 'type_5', 'type');
$rsm->addMetaResult('c', 'type_6', 'type');
$rsm->addMetaResult('d', 'child_id_7', 'child_id', false, 'integer');
$rsm->setDiscriminatorColumn('b', 'type_5');
$rsm->setDiscriminatorColumn('c', 'type_6');
$resultSet = [
[
'id_0' => '1',
'id_1' => '1',
'id_2' => '1',
'id_3' => '1',
'bases_id_4' => '1',
'type_5' => 'child',
'type_6' => 'child',
'child_id_7' => '1',
],
];
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm, [Query::HINT_FORCE_PARTIAL_LOAD => true]);
$this->assertInstanceOf(GH6362Start::CLASSNAME, $result[0]['base']);
$this->assertInstanceOf(GH6362Child::CLASSNAME, $result[1][0]);
}
}
/**
* @Entity
*/
class GH6362Start
{
const CLASSNAME = __CLASS__;
/**
* @Column(type="integer")
* @Id
* @GeneratedValue
*/
protected $id;
/**
* @ManyToOne(targetEntity="GH6362Base", inversedBy="starts")
*/
private $bases;
}
/**
* @InheritanceType("SINGLE_TABLE")
* @DiscriminatorColumn(name="type", type="string")
* @DiscriminatorMap({"child" = "GH6362Child"})
* @Entity
*/
abstract class GH6362Base
{
const CLASSNAME = __CLASS__;
/**
* @Column(type="integer")
* @Id
* @GeneratedValue
*/
protected $id;
/**
* @OneToMany(targetEntity="GH6362Start", mappedBy="bases")
*/
private $starts;
}
/**
* @Entity
*/
class GH6362Child extends GH6362Base
{
const CLASSNAME = __CLASS__;
/**
* @OneToMany(targetEntity="GH6362Join", mappedBy="child")
*/
private $joins;
}
/**
* @Entity
*/
class GH6362Join
{
const CLASSNAME = __CLASS__;
/**
* @Column(type="integer")
* @Id
* @GeneratedValue
*/
private $id;
/**
* @ManyToOne(targetEntity="GH6362Child", inversedBy="joins")
*/
private $child;
}

View File

@@ -0,0 +1,81 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Tests\OrmFunctionalTestCase;
/**
* @group GH-6464
*/
class GH6464Test extends OrmFunctionalTestCase
{
/**
* {@inheritDoc}
*/
protected function setUp()
{
parent::setUp();
$this->_schemaTool->createSchema([
$this->_em->getClassMetadata(GH6464Post::CLASS_NAME),
$this->_em->getClassMetadata(GH6464User::CLASS_NAME),
$this->_em->getClassMetadata(GH6464Author::CLASS_NAME),
]);
}
/**
* Verifies that SqlWalker generates valid SQL for an INNER JOIN to CTI table
*
* SqlWalker needs to generate nested INNER JOIN statements, otherwise there would be INNER JOIN
* statements without an ON clause, which are valid on e.g. MySQL but rejected by PostgreSQL.
*/
public function testIssue()
{
$query = $this->_em->createQueryBuilder()
->select('p')
->from(GH6464Post::CLASS_NAME, 'p')
->innerJoin(GH6464Author::CLASS_NAME, 'a', 'WITH', 'p.authorId = a.id')
->getQuery();
$this->assertNotRegExp(
'/INNER JOIN \w+ \w+ INNER JOIN/',
$query->getSQL(),
'As of GH-6464, every INNER JOIN should have an ON clause, which is missing here'
);
// Query shouldn't yield a result, yet it shouldn't crash (anymore)
$this->assertEquals([], $query->getResult());
}
}
/** @Entity */
class GH6464Post
{
const CLASS_NAME = __CLASS__;
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
/** @Column(type="integer") */
public $authorId;
}
/**
* @Entity
* @InheritanceType("JOINED")
* @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({"author" = "GH6464Author"})
*/
abstract class GH6464User
{
const CLASS_NAME = __CLASS__;
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
}
/** @Entity */
class GH6464Author extends GH6464User
{
const CLASS_NAME = __CLASS__;
}

View File

@@ -4,6 +4,7 @@ namespace Doctrine\Tests\ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\UnitOfWork;
use Doctrine\Tests\Mocks\ConnectionMock;
use Doctrine\Tests\Mocks\DriverMock;
use Doctrine\Tests\Mocks\EntityManagerMock;
@@ -23,7 +24,7 @@ class PersistentCollectionTest extends OrmTestCase
protected $collection;
/**
* @var \Doctrine\ORM\EntityManagerInterface
* @var EntityManagerMock
*/
private $_emMock;
@@ -32,6 +33,8 @@ class PersistentCollectionTest extends OrmTestCase
parent::setUp();
$this->_emMock = EntityManagerMock::create(new ConnectionMock([], new DriverMock()));
$this->setUpPersistentCollection();
}
/**
@@ -58,7 +61,6 @@ class PersistentCollectionTest extends OrmTestCase
*/
public function testCurrentInitializesCollection()
{
$this->setUpPersistentCollection();
$this->collection->current();
$this->assertTrue($this->collection->isInitialized());
}
@@ -68,7 +70,6 @@ class PersistentCollectionTest extends OrmTestCase
*/
public function testKeyInitializesCollection()
{
$this->setUpPersistentCollection();
$this->collection->key();
$this->assertTrue($this->collection->isInitialized());
}
@@ -78,7 +79,6 @@ class PersistentCollectionTest extends OrmTestCase
*/
public function testNextInitializesCollection()
{
$this->setUpPersistentCollection();
$this->collection->next();
$this->assertTrue($this->collection->isInitialized());
}
@@ -88,12 +88,12 @@ class PersistentCollectionTest extends OrmTestCase
*/
public function testRemovingElementsAlsoRemovesKeys()
{
$this->setUpPersistentCollection();
$dummy = new \stdClass();
$this->collection->add('dummy');
$this->collection->add($dummy);
$this->assertEquals([0], array_keys($this->collection->toArray()));
$this->collection->removeElement('dummy');
$this->collection->removeElement($dummy);
$this->assertEquals([], array_keys($this->collection->toArray()));
}
@@ -102,9 +102,7 @@ class PersistentCollectionTest extends OrmTestCase
*/
public function testClearWillAlsoClearKeys()
{
$this->setUpPersistentCollection();
$this->collection->add('dummy');
$this->collection->add(new \stdClass());
$this->collection->clear();
$this->assertEquals([], array_keys($this->collection->toArray()));
}
@@ -114,12 +112,142 @@ class PersistentCollectionTest extends OrmTestCase
*/
public function testClearWillAlsoResetKeyPositions()
{
$this->setUpPersistentCollection();
$dummy = new \stdClass();
$this->collection->add('dummy');
$this->collection->removeElement('dummy');
$this->collection->add($dummy);
$this->collection->removeElement($dummy);
$this->collection->clear();
$this->collection->add('dummy');
$this->collection->add($dummy);
$this->assertEquals([0], array_keys($this->collection->toArray()));
}
/**
* @group 6613
* @group 6614
* @group 6616
*/
public function testWillKeepNewItemsInDirtyCollectionAfterInitialization()
{
/* @var $unitOfWork UnitOfWork|\PHPUnit_Framework_MockObject_MockObject */
$unitOfWork = $this
->getMockBuilder('Doctrine\ORM\UnitOfWork')
->disableOriginalConstructor()
->getMock();
$this->_emMock->setUnitOfWork($unitOfWork);
$newElement = new \stdClass();
$persistedElement = new \stdClass();
$this->collection->add($newElement);
self::assertFalse($this->collection->isInitialized());
self::assertTrue($this->collection->isDirty());
$unitOfWork
->expects(self::once())
->method('loadCollection')
->with($this->collection)
->willReturnCallback(function (PersistentCollection $persistentCollection) use ($persistedElement) {
$persistentCollection->unwrap()->add($persistedElement);
});
$this->collection->initialize();
self::assertSame([$persistedElement, $newElement], $this->collection->toArray());
self::assertTrue($this->collection->isInitialized());
self::assertTrue($this->collection->isDirty());
}
/**
* @group 6613
* @group 6614
* @group 6616
*/
public function testWillDeDuplicateNewItemsThatWerePreviouslyPersistedInDirtyCollectionAfterInitialization()
{
/* @var $unitOfWork UnitOfWork|\PHPUnit_Framework_MockObject_MockObject */
$unitOfWork = $this
->getMockBuilder('Doctrine\ORM\UnitOfWork')
->disableOriginalConstructor()
->getMock();
$this->_emMock->setUnitOfWork($unitOfWork);
$newElement = new \stdClass();
$newElementThatIsAlsoPersisted = new \stdClass();
$persistedElement = new \stdClass();
$this->collection->add($newElementThatIsAlsoPersisted);
$this->collection->add($newElement);
self::assertFalse($this->collection->isInitialized());
self::assertTrue($this->collection->isDirty());
$unitOfWork
->expects(self::once())
->method('loadCollection')
->with($this->collection)
->willReturnCallback(function (PersistentCollection $persistentCollection) use (
$persistedElement,
$newElementThatIsAlsoPersisted
) {
$persistentCollection->unwrap()->add($newElementThatIsAlsoPersisted);
$persistentCollection->unwrap()->add($persistedElement);
});
$this->collection->initialize();
self::assertSame(
[$newElementThatIsAlsoPersisted, $persistedElement, $newElement],
$this->collection->toArray()
);
self::assertTrue($this->collection->isInitialized());
self::assertTrue($this->collection->isDirty());
}
/**
* @group 6613
* @group 6614
* @group 6616
*/
public function testWillNotMarkCollectionAsDirtyAfterInitializationIfNoElementsWereAdded()
{
/* @var $unitOfWork UnitOfWork|\PHPUnit_Framework_MockObject_MockObject */
$unitOfWork = $this
->getMockBuilder('Doctrine\ORM\UnitOfWork')
->disableOriginalConstructor()
->getMock();
$this->_emMock->setUnitOfWork($unitOfWork);
$newElementThatIsAlsoPersisted = new \stdClass();
$persistedElement = new \stdClass();
$this->collection->add($newElementThatIsAlsoPersisted);
self::assertFalse($this->collection->isInitialized());
self::assertTrue($this->collection->isDirty());
$unitOfWork
->expects(self::once())
->method('loadCollection')
->with($this->collection)
->willReturnCallback(function (PersistentCollection $persistentCollection) use (
$persistedElement,
$newElementThatIsAlsoPersisted
) {
$persistentCollection->unwrap()->add($newElementThatIsAlsoPersisted);
$persistentCollection->unwrap()->add($persistedElement);
});
$this->collection->initialize();
self::assertSame(
[$newElementThatIsAlsoPersisted, $persistedElement],
$this->collection->toArray()
);
self::assertTrue($this->collection->isInitialized());
self::assertFalse($this->collection->isDirty());
}
}

View File

@@ -153,12 +153,12 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
{
$this->assertSqlGeneration(
'SELECT e FROM Doctrine\Tests\Models\Company\CompanyEmployee e JOIN Doctrine\Tests\Models\Company\CompanyManager m WITH e.id = m.id',
'SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.salary AS salary_2, c1_.department AS department_3, c1_.startDate AS startDate_4, c0_.discr AS discr_5 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id INNER JOIN company_managers c2_ INNER JOIN company_employees c4_ ON c2_.id = c4_.id INNER JOIN company_persons c3_ ON c2_.id = c3_.id AND (c0_.id = c3_.id)'
'SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.salary AS salary_2, c1_.department AS department_3, c1_.startDate AS startDate_4, c0_.discr AS discr_5 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id INNER JOIN (company_managers c2_ INNER JOIN company_employees c4_ ON c2_.id = c4_.id INNER JOIN company_persons c3_ ON c2_.id = c3_.id) ON (c0_.id = c3_.id)'
);
$this->assertSqlGeneration(
'SELECT e FROM Doctrine\Tests\Models\Company\CompanyEmployee e LEFT JOIN Doctrine\Tests\Models\Company\CompanyManager m WITH e.id = m.id',
'SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.salary AS salary_2, c1_.department AS department_3, c1_.startDate AS startDate_4, c0_.discr AS discr_5 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN company_managers c2_ INNER JOIN company_employees c4_ ON c2_.id = c4_.id INNER JOIN company_persons c3_ ON c2_.id = c3_.id ON (c0_.id = c3_.id)'
'SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.salary AS salary_2, c1_.department AS department_3, c1_.startDate AS startDate_4, c0_.discr AS discr_5 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN (company_managers c2_ INNER JOIN company_employees c4_ ON c2_.id = c4_.id INNER JOIN company_persons c3_ ON c2_.id = c3_.id) ON (c0_.id = c3_.id)'
);
}
@@ -2165,7 +2165,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
// the where clause when not joining onto that table
$this->assertSqlGeneration(
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyContract c LEFT JOIN Doctrine\Tests\Models\Company\CompanyEmployee e WITH e.id = c.salesPerson WHERE c.completed = true',
"SELECT c0_.id AS id_0, c0_.completed AS completed_1, c0_.fixPrice AS fixPrice_2, c0_.hoursWorked AS hoursWorked_3, c0_.pricePerHour AS pricePerHour_4, c0_.maxPrice AS maxPrice_5, c0_.discr AS discr_6 FROM company_contracts c0_ LEFT JOIN company_employees c1_ INNER JOIN company_persons c2_ ON c1_.id = c2_.id ON (c2_.id = c0_.salesPerson_id) WHERE (c0_.completed = 1) AND c0_.discr IN ('fix', 'flexible', 'flexultra')"
"SELECT c0_.id AS id_0, c0_.completed AS completed_1, c0_.fixPrice AS fixPrice_2, c0_.hoursWorked AS hoursWorked_3, c0_.pricePerHour AS pricePerHour_4, c0_.maxPrice AS maxPrice_5, c0_.discr AS discr_6 FROM company_contracts c0_ LEFT JOIN (company_employees c1_ INNER JOIN company_persons c2_ ON c1_.id = c2_.id) ON (c2_.id = c0_.salesPerson_id) WHERE (c0_.completed = 1) AND c0_.discr IN ('fix', 'flexible', 'flexultra')"
);
}

View File

@@ -0,0 +1,195 @@
<?php
namespace Doctrine\Tests\ORM\Tools\Console;
use Doctrine\ORM\Tools\Console\MetadataFilter;
use Doctrine\ORM\Tools\DisconnectedClassMetadataFactory;
/**
* Tests for {@see \Doctrine\ORM\Tools\Console\MetadataFilter}
*
* @covers \Doctrine\ORM\Tools\Console\MetadataFilter
*/
class MetadataFilterTest extends \Doctrine\Tests\OrmTestCase
{
/**
* @var DisconnectedClassMetadataFactory
*/
private $cmf;
protected function setUp()
{
parent::setUp();
$driver = $this->createAnnotationDriver();
$em = $this->_getTestEntityManager();
$em->getConfiguration()->setMetadataDriverImpl($driver);
$this->cmf = new DisconnectedClassMetadataFactory();
$this->cmf->setEntityManager($em);
}
public function testFilterWithEmptyArray()
{
$originalMetadatas = array(
$metadataAaa = $this->cmf->getMetadataFor(MetadataFilterTestEntityAaa::CLASSNAME),
$metadataBbb = $this->cmf->getMetadataFor(MetadataFilterTestEntityBbb::CLASSNAME),
);
$metadatas = $originalMetadatas;
$metadatas = MetadataFilter::filter($metadatas, array());
$this->assertContains($metadataAaa, $metadatas);
$this->assertContains($metadataBbb, $metadatas);
$this->assertCount(count($originalMetadatas), $metadatas);
}
public function testFilterWithString()
{
$originalMetadatas = array(
$metadataAaa = $this->cmf->getMetadataFor(MetadataFilterTestEntityAaa::CLASSNAME),
$metadataBbb = $this->cmf->getMetadataFor(MetadataFilterTestEntityBbb::CLASSNAME),
$metadataCcc = $this->cmf->getMetadataFor(MetadataFilterTestEntityCcc::CLASSNAME),
);
$metadatas = $originalMetadatas;
$metadatas = MetadataFilter::filter($metadatas, 'MetadataFilterTestEntityAaa');
$this->assertContains($metadataAaa, $metadatas);
$this->assertNotContains($metadataBbb, $metadatas);
$this->assertNotContains($metadataCcc, $metadatas);
$this->assertCount(1, $metadatas);
$metadatas = $originalMetadatas;
$metadatas = MetadataFilter::filter($metadatas, 'MetadataFilterTestEntityBbb');
$this->assertNotContains($metadataAaa, $metadatas);
$this->assertContains($metadataBbb, $metadatas);
$this->assertNotContains($metadataCcc, $metadatas);
$this->assertCount(1, $metadatas);
$metadatas = $originalMetadatas;
$metadatas = MetadataFilter::filter($metadatas, 'MetadataFilterTestEntityCcc');
$this->assertNotContains($metadataAaa, $metadatas);
$this->assertNotContains($metadataBbb, $metadatas);
$this->assertContains($metadataCcc, $metadatas);
$this->assertCount(1, $metadatas);
}
public function testFilterWithString2()
{
$originalMetadatas = array(
$metadataFoo = $this->cmf->getMetadataFor(MetadataFilterTestEntityFoo::CLASSNAME),
$metadataFooBar = $this->cmf->getMetadataFor(MetadataFilterTestEntityFooBar::CLASSNAME),
$metadataBar = $this->cmf->getMetadataFor(MetadataFilterTestEntityBar::CLASSNAME),
);
$metadatas = $originalMetadatas;
$metadatas = MetadataFilter::filter($metadatas, 'MetadataFilterTestEntityFoo');
$this->assertContains($metadataFoo, $metadatas);
$this->assertContains($metadataFooBar, $metadatas);
$this->assertNotContains($metadataBar, $metadatas);
$this->assertCount(2, $metadatas);
}
public function testFilterWithArray()
{
$originalMetadatas = array(
$metadataAaa = $this->cmf->getMetadataFor(MetadataFilterTestEntityAaa::CLASSNAME),
$metadataBbb = $this->cmf->getMetadataFor(MetadataFilterTestEntityBbb::CLASSNAME),
$metadataCcc = $this->cmf->getMetadataFor(MetadataFilterTestEntityCcc::CLASSNAME),
);
$metadatas = $originalMetadatas;
$metadatas = MetadataFilter::filter($metadatas, array(
'MetadataFilterTestEntityAaa',
'MetadataFilterTestEntityCcc',
));
$this->assertContains($metadataAaa, $metadatas);
$this->assertNotContains($metadataBbb, $metadatas);
$this->assertContains($metadataCcc, $metadatas);
$this->assertCount(2, $metadatas);
}
public function testFilterWithRegex()
{
$originalMetadatas = array(
$metadataFoo = $this->cmf->getMetadataFor(MetadataFilterTestEntityFoo::CLASSNAME),
$metadataFooBar = $this->cmf->getMetadataFor(MetadataFilterTestEntityFooBar::CLASSNAME),
$metadataBar = $this->cmf->getMetadataFor(MetadataFilterTestEntityBar::CLASSNAME),
);
$metadatas = $originalMetadatas;
$metadatas = MetadataFilter::filter($metadatas, 'Foo$');
$this->assertContains($metadataFoo, $metadatas);
$this->assertNotContains($metadataFooBar, $metadatas);
$this->assertNotContains($metadataBar, $metadatas);
$this->assertCount(1, $metadatas);
$metadatas = $originalMetadatas;
$metadatas = MetadataFilter::filter($metadatas, 'Bar$');
$this->assertNotContains($metadataFoo, $metadatas);
$this->assertContains($metadataFooBar, $metadatas);
$this->assertContains($metadataBar, $metadatas);
$this->assertCount(2, $metadatas);
}
}
/** @Entity */
class MetadataFilterTestEntityAaa
{
const CLASSNAME = __CLASS__;
/** @Id @Column(type="integer") */
protected $id;
}
/** @Entity */
class MetadataFilterTestEntityBbb
{
const CLASSNAME = __CLASS__;
/** @Id @Column(type="integer") */
protected $id;
}
/** @Entity */
class MetadataFilterTestEntityCcc
{
const CLASSNAME = __CLASS__;
/** @Id @Column(type="integer") */
protected $id;
}
/** @Entity */
class MetadataFilterTestEntityFoo
{
const CLASSNAME = __CLASS__;
/** @Id @Column(type="integer") */
protected $id;
}
/** @Entity */
class MetadataFilterTestEntityBar
{
const CLASSNAME = __CLASS__;
/** @Id @Column(type="integer") */
protected $id;
}
/** @Entity */
class MetadataFilterTestEntityFooBar
{
const CLASSNAME = __CLASS__;
/** @Id @Column(type="integer") */
protected $id;
}

View File

@@ -30,6 +30,18 @@ class CountOutputWalkerTest extends PaginationTestCase
);
}
public function testCountQuery_GroupBy()
{
$query = $this->entityManager->createQuery(
'SELECT p.name FROM Doctrine\Tests\ORM\Tools\Pagination\Person p GROUP BY p.name');
$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\CountOutputWalker');
$query->setFirstResult(null)->setMaxResults(null);
$this->assertSame(
"SELECT COUNT(*) AS dctrn_count FROM (SELECT p0_.name AS name_0 FROM Person p0_ GROUP BY p0_.name) dctrn_table", $query->getSQL()
);
}
public function testCountQuery_Having()
{
$query = $this->entityManager->createQuery(
@@ -37,8 +49,8 @@ class CountOutputWalkerTest extends PaginationTestCase
$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\CountOutputWalker');
$query->setFirstResult(null)->setMaxResults(null);
$this->assertEquals(
"SELECT COUNT(*) AS dctrn_count FROM (SELECT DISTINCT id_1 FROM (SELECT count(u0_.id) AS sclr_0, g1_.id AS id_1, u0_.id AS id_2 FROM groups g1_ LEFT JOIN user_group u2_ ON g1_.id = u2_.group_id LEFT JOIN User u0_ ON u0_.id = u2_.user_id GROUP BY g1_.id HAVING sclr_0 > 0) dctrn_result) dctrn_table", $query->getSql()
$this->assertSame(
"SELECT COUNT(*) AS dctrn_count FROM (SELECT count(u0_.id) AS sclr_0, g1_.id AS id_1, u0_.id AS id_2 FROM groups g1_ LEFT JOIN user_group u2_ ON g1_.id = u2_.group_id LEFT JOIN User u0_ ON u0_.id = u2_.user_id GROUP BY g1_.id HAVING sclr_0 > 0) dctrn_table", $query->getSQL()
);
}

View File

@@ -2,10 +2,11 @@
namespace Doctrine\Tests\ORM\Tools;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
use Doctrine\ORM\Tools\Event\GenerateSchemaTableEventArgs;
use Doctrine\ORM\Tools\SchemaTool;
use Doctrine\ORM\Tools\ToolEvents;
use Doctrine\ORM\Tools\Event\GenerateSchemaTableEventArgs;
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
class SchemaToolTest extends \Doctrine\Tests\OrmTestCase
{
@@ -138,6 +139,26 @@ class SchemaToolTest extends \Doctrine\Tests\OrmTestCase
$this->assertTrue($table->hasIndex('primary'));
$this->assertTrue($table->hasIndex('uniq_hash'));
}
public function testSetDiscriminatorColumnWithoutLength()
{
$em = $this->_getTestEntityManager();
$schemaTool = new SchemaTool($em);
$metadata = $em->getClassMetadata(__NAMESPACE__ . '\\FirstEntity');
$metadata->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE);
$metadata->setDiscriminatorColumn(['name' => 'discriminator', 'type' => 'string']);
$schema = $schemaTool->getSchemaFromMetadata([$metadata]);
$this->assertTrue($schema->hasTable('first_entity'));
$table = $schema->getTable('first_entity');
$this->assertTrue($table->hasColumn('discriminator'));
$column = $table->getColumn('discriminator');
$this->assertEquals(255, $column->getLength());
}
}
/**
@@ -187,3 +208,45 @@ class UniqueConstraintAnnotationModel
*/
private $hash;
}
/**
* @Entity
* @Table(name="first_entity")
*/
class FirstEntity
{
/**
* @Id
* @Column(name="id")
*/
public $id;
/**
* @OneToOne(targetEntity="SecondEntity")
* @JoinColumn(name="id", referencedColumnName="fist_entity_id")
*/
public $secondEntity;
/**
* @Column(name="name")
*/
public $name;
}
/**
* @Entity
* @Table(name="second_entity")
*/
class SecondEntity
{
/**
* @Id
* @Column(name="fist_entity_id")
*/
public $fist_entity_id;
/**
* @Column(name="name")
*/
public $name;
}

View File

@@ -309,6 +309,12 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
protected function tearDown()
{
$conn = static::$_sharedConn;
// In case test is skipped, tearDown is called, but no setup may have run
if ( ! $conn) {
return;
}
$platform = $conn->getDatabasePlatform();
$this->_sqlLoggerStack->enabled = false;