From c6810861ca3cbcfc846a50c59e06681d84604332 Mon Sep 17 00:00:00 2001 From: Strate Date: Sun, 22 Dec 2013 21:02:14 +0400 Subject: [PATCH 01/18] Fix applying ON/WITH conditions to first join in Class Table Inheritance --- lib/Doctrine/ORM/Query/SqlWalker.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index 37f970843..549fe8d2d 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -982,6 +982,11 @@ class SqlWalker implements TreeWalker break; } + // FIXME: these should either be nested or all forced to be left joins (DDC-XXX) + if ($targetClass->isInheritanceTypeJoined()) { + $sql .= $this->_generateClassTableInheritanceJoins($targetClass, $joinedDqlAlias); + } + // Handle WITH clause if ($condExpr !== null) { // Phase 2 AST optimization: Skip processing of ConditionalExpression @@ -989,11 +994,6 @@ class SqlWalker implements TreeWalker $sql .= ' AND (' . $this->walkConditionalExpression($condExpr) . ')'; } - // FIXME: these should either be nested or all forced to be left joins (DDC-XXX) - if ($targetClass->isInheritanceTypeJoined()) { - $sql .= $this->_generateClassTableInheritanceJoins($targetClass, $joinedDqlAlias); - } - // Apply the indexes if ($indexBy) { // For Many-To-One or One-To-One associations this obviously makes no sense, but is ignored silently. From 41ec5fd56d6402096ab8e44fd16a1182c30055fd Mon Sep 17 00:00:00 2001 From: Strate Date: Sun, 19 Jan 2014 20:56:24 +0400 Subject: [PATCH 02/18] Fix applying ON/WITH conditions to first join in Class Table Inheritance Now we build nested joins for CTI when using ON/WITH clause. --- lib/Doctrine/ORM/Query/SqlWalker.php | 36 +++++++++++++------ .../ORM/Query/SelectSqlGenerationTest.php | 2 +- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index f2425dd90..1a63570f0 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -895,6 +895,8 @@ class SqlWalker implements TreeWalker } } + $targetTableJoin = null; + // This condition is not checking ClassMetadata::MANY_TO_ONE, because by definition it cannot // be the owning side and previously we ensured that $assoc is always the owning side of the associations. // The owning side is necessary at this point because only it contains the JoinColumn information. @@ -929,7 +931,10 @@ class SqlWalker implements TreeWalker $conditions[] = $filterExpr; } - $sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ' . implode(' AND ', $conditions); + $targetTableJoin = array( + 'table' => $targetTableName . ' ' . $targetTableAlias, + 'condition' => implode(' AND ', $conditions), + ); break; case ($assoc['type'] == ClassMetadata::MANY_TO_MANY): @@ -981,20 +986,29 @@ class SqlWalker implements TreeWalker $conditions[] = $filterExpr; } - $sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ' . implode(' AND ', $conditions); + $targetTableJoin = array( + 'table' => $targetTableName . ' ' . $targetTableAlias, + 'condition' => implode(' AND ', $conditions), + ); break; } - // FIXME: these should either be nested or all forced to be left joins (DDC-XXX) - if ($targetClass->isInheritanceTypeJoined()) { - $sql .= $this->_generateClassTableInheritanceJoins($targetClass, $joinedDqlAlias); - } - // Handle WITH clause - if ($condExpr !== null) { - // Phase 2 AST optimization: Skip processing of ConditionalExpression - // if only one ConditionalTerm is defined - $sql .= ' AND (' . $this->walkConditionalExpression($condExpr) . ')'; + $withCondition = (null !== $condExpr) ? ('(' . $this->walkConditionalExpression($condExpr) . ')') : ''; + + if ($targetClass->isInheritanceTypeJoined()) { + $ctiJoins = $this->_generateClassTableInheritanceJoins($targetClass, $joinedDqlAlias); + // If we have WITH condition, we need to build nested joins for target class table and cti joins + if ($withCondition) { + $sql .= '(' . $targetTableJoin['table'] . $ctiJoins . ') ON ' . $targetTableJoin['condition'] . ' AND ' . $withCondition; + } else { + $sql .= $targetTableJoin['table'] . ' ON ' . $targetTableJoin['condition'] . $ctiJoins; + } + } else { + $sql .= $targetTableJoin['table'] . ' ON ' . $targetTableJoin['condition']; + if ($withCondition) { + $sql .= ' AND ' . $withCondition; + } } // Apply the indexes diff --git a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php index f0afcc798..83c34ce36 100644 --- a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php +++ b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php @@ -2065,7 +2065,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( 'SELECT e.id FROM Doctrine\Tests\Models\Company\CompanyOrganization o JOIN o.events e WITH e.id = ?1', - 'SELECT c0_.id AS id0 FROM company_organizations c1_ INNER JOIN company_events c0_ ON c1_.id = c0_.org_id AND (c0_.id = ?) LEFT JOIN company_auctions c2_ ON c0_.id = c2_.id LEFT JOIN company_raffles c3_ ON c0_.id = c3_.id', + 'SELECT c0_.id AS id0 FROM company_organizations c1_ INNER JOIN (company_events c0_ LEFT JOIN company_auctions c2_ ON c0_.id = c2_.id LEFT JOIN company_raffles c3_ ON c0_.id = c3_.id) ON c1_.id = c0_.org_id AND (c0_.id = ?)', array(Query::HINT_FORCE_PARTIAL_LOAD => false) ); } From 04e6061584e2691c69e62b43e8ad18a2801773aa Mon Sep 17 00:00:00 2001 From: Strate Date: Mon, 20 Jan 2014 20:06:53 +0400 Subject: [PATCH 03/18] Added an exception when invalid case. Fixes after code review. --- lib/Doctrine/ORM/Query/SqlWalker.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index 1a63570f0..2482b7611 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -991,24 +991,28 @@ class SqlWalker implements TreeWalker 'condition' => implode(' AND ', $conditions), ); break; + + default: + throw new \BadMethodCallException('Type of association must be one of *_TO_ONE or MANY_TO_MANY'); } // Handle WITH clause - $withCondition = (null !== $condExpr) ? ('(' . $this->walkConditionalExpression($condExpr) . ')') : ''; + $withCondition = (null === $condExpr) ? '' : ('(' . $this->walkConditionalExpression($condExpr) . ')'); if ($targetClass->isInheritanceTypeJoined()) { $ctiJoins = $this->_generateClassTableInheritanceJoins($targetClass, $joinedDqlAlias); // If we have WITH condition, we need to build nested joins for target class table and cti joins if ($withCondition) { - $sql .= '(' . $targetTableJoin['table'] . $ctiJoins . ') ON ' . $targetTableJoin['condition'] . ' AND ' . $withCondition; + $sql .= '(' . $targetTableJoin['table'] . $ctiJoins . ') ON ' . $targetTableJoin['condition']; } else { $sql .= $targetTableJoin['table'] . ' ON ' . $targetTableJoin['condition'] . $ctiJoins; } } else { $sql .= $targetTableJoin['table'] . ' ON ' . $targetTableJoin['condition']; - if ($withCondition) { - $sql .= ' AND ' . $withCondition; - } + } + + if ($withCondition) { + $sql .= ' AND ' . $withCondition; } // Apply the indexes From 1f3290faae37605bf784c6c154372378ad3a11c3 Mon Sep 17 00:00:00 2001 From: Ilya Pleshakov Date: Thu, 6 Feb 2014 13:02:41 +0400 Subject: [PATCH 04/18] Remove incorrect (outdated) validation for public fields in SchemaValidator --- lib/Doctrine/ORM/Tools/SchemaValidator.php | 14 -------------- .../Tests/ORM/Functional/SchemaValidatorTest.php | 6 ------ 2 files changed, 20 deletions(-) diff --git a/lib/Doctrine/ORM/Tools/SchemaValidator.php b/lib/Doctrine/ORM/Tools/SchemaValidator.php index 11910138e..276b447ec 100644 --- a/lib/Doctrine/ORM/Tools/SchemaValidator.php +++ b/lib/Doctrine/ORM/Tools/SchemaValidator.php @@ -236,20 +236,6 @@ class SchemaValidator } } - foreach ($class->reflClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $publicAttr) { - if ($publicAttr->isStatic()) { - continue; - } - - if ( ! isset($class->fieldMappings[$publicAttr->getName()]) && - ! isset($class->associationMappings[$publicAttr->getName()])) { - continue; - } - - $ce[] = "Field '".$publicAttr->getName()."' in class '".$class->name."' must be private ". - "or protected. Public fields may break lazy-loading."; - } - foreach ($class->subClasses as $subClass) { if (!in_array($class->name, class_parents($subClass))) { $ce[] = "According to the discriminator map class '" . $subClass . "' has to be a child ". diff --git a/tests/Doctrine/Tests/ORM/Functional/SchemaValidatorTest.php b/tests/Doctrine/Tests/ORM/Functional/SchemaValidatorTest.php index a575db0c0..c09f336c9 100644 --- a/tests/Doctrine/Tests/ORM/Functional/SchemaValidatorTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/SchemaValidatorTest.php @@ -38,12 +38,6 @@ class SchemaValidatorTest extends \Doctrine\Tests\OrmFunctionalTestCase foreach ($classes as $class) { $ce = $validator->validateClass($class); - foreach ($ce as $key => $error) { - if (strpos($error, "must be private or protected. Public fields may break lazy-loading.") !== false) { - unset($ce[$key]); - } - } - $this->assertEquals(0, count($ce), "Invalid Modelset: " . $modelSet . " class " . $class->name . ": ". implode("\n", $ce)); } } From d31f7ebf574024994b69b68631f11bf34452193c Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Sat, 8 Feb 2014 17:01:55 +0100 Subject: [PATCH 05/18] [DDC-1985] Fix ordering preservation in SQL limit subquery output walker. --- .../Pagination/LimitSubqueryOutputWalker.php | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryOutputWalker.php b/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryOutputWalker.php index 7ab6f0e65..5b6ac09fd 100644 --- a/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryOutputWalker.php +++ b/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryOutputWalker.php @@ -100,9 +100,9 @@ class LimitSubqueryOutputWalker extends SqlWalker $hiddens[$idx] = $expr->hiddenAliasResultVariable; $expr->hiddenAliasResultVariable = false; } - + $innerSql = parent::walkSelectStatement($AST); - + // Restore hiddens foreach ($AST->selectClause->selectExpressions as $idx => $expr) { $expr->hiddenAliasResultVariable = $hiddens[$idx]; @@ -164,11 +164,8 @@ class LimitSubqueryOutputWalker extends SqlWalker $sql = sprintf('SELECT DISTINCT %s FROM (%s) dctrn_result', implode(', ', $sqlIdentifier), $innerSql); - if ($this->platform instanceof PostgreSqlPlatform || - $this->platform instanceof OraclePlatform) { - // http://www.doctrine-project.org/jira/browse/DDC-1958 - $this->preserveSqlOrdering($AST, $sqlIdentifier, $innerSql, $sql); - } + // http://www.doctrine-project.org/jira/browse/DDC-1958 + $sql = $this->preserveSqlOrdering($AST, $sqlIdentifier, $innerSql, $sql); // Apply the limit and offset. $sql = $this->platform->modifyLimitQuery( @@ -185,7 +182,7 @@ class LimitSubqueryOutputWalker extends SqlWalker return $sql; } - + /** * Generates new SQL for Postgresql or Oracle if necessary. * @@ -196,7 +193,7 @@ class LimitSubqueryOutputWalker extends SqlWalker * * @return void */ - public function preserveSqlOrdering(SelectStatement $AST, array $sqlIdentifier, $innerSql, &$sql) + public function preserveSqlOrdering(SelectStatement $AST, array $sqlIdentifier, $innerSql, $sql) { // For every order by, find out the SQL alias by inspecting the ResultSetMapping. $sqlOrderColumns = array(); @@ -219,11 +216,6 @@ class LimitSubqueryOutputWalker extends SqlWalker $sqlOrderColumns = array_diff($sqlOrderColumns, $sqlIdentifier); } - // We don't need orderBy in inner query. - // However at least on 5.4.6 I'm getting a segmentation fault and thus we don't clear it for now. - /*$AST->orderByClause = null; - $innerSql = parent::walkSelectStatement($AST);*/ - if (count($orderBy)) { $sql = sprintf( 'SELECT DISTINCT %s FROM (%s) dctrn_result ORDER BY %s', @@ -232,5 +224,7 @@ class LimitSubqueryOutputWalker extends SqlWalker implode(', ', $orderBy) ); } + + return $sql; } } From d7b917aa499b24102a928f5204860f31d229fb44 Mon Sep 17 00:00:00 2001 From: Wouter J Date: Sun, 9 Feb 2014 15:10:00 +0100 Subject: [PATCH 06/18] Fixed InputOption modes --- .../ORM/Tools/Console/Command/GenerateEntitiesCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Doctrine/ORM/Tools/Console/Command/GenerateEntitiesCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/GenerateEntitiesCommand.php index 61d226999..bca32b7ec 100644 --- a/lib/Doctrine/ORM/Tools/Console/Command/GenerateEntitiesCommand.php +++ b/lib/Doctrine/ORM/Tools/Console/Command/GenerateEntitiesCommand.php @@ -74,11 +74,11 @@ class GenerateEntitiesCommand extends Command 'Flag to define if generator should only update entity if it exists.', true ), new InputOption( - 'extend', null, InputOption::VALUE_OPTIONAL, + 'extend', null, InputOption::VALUE_REQUIRED, 'Defines a base class to be extended by generated entity classes.' ), new InputOption( - 'num-spaces', null, InputOption::VALUE_OPTIONAL, + 'num-spaces', null, InputOption::VALUE_REQUIRED, 'Defines the number of indentation spaces', 4 ), new InputOption( From 2a77a739dc07600c5d9931a0116f06dcbaf57ee8 Mon Sep 17 00:00:00 2001 From: Thomas Lallement Date: Sun, 9 Feb 2014 16:37:32 +0100 Subject: [PATCH 07/18] Fix CS --- lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php index 35b5fe0bb..81f4c2a71 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -2370,7 +2370,7 @@ class ClassMetadataInfo implements ClassMetadata $queryMapping['isSelfClass'] = false; if (isset($queryMapping['resultClass'])) { - if($queryMapping['resultClass'] === '__CLASS__') { + if ($queryMapping['resultClass'] === '__CLASS__') { $queryMapping['isSelfClass'] = true; $queryMapping['resultClass'] = $this->name; @@ -2410,7 +2410,7 @@ class ClassMetadataInfo implements ClassMetadata } $entityResult['isSelfClass'] = false; - if($entityResult['entityClass'] === '__CLASS__') { + if ($entityResult['entityClass'] === '__CLASS__') { $entityResult['isSelfClass'] = true; $entityResult['entityClass'] = $this->name; @@ -2430,7 +2430,7 @@ class ClassMetadataInfo implements ClassMetadata if (!isset($field['column'])) { $fieldName = $field['name']; - if(strpos($fieldName, '.')){ + if (strpos($fieldName, '.')) { list(, $fieldName) = explode('.', $fieldName); } @@ -2583,7 +2583,7 @@ class ClassMetadataInfo implements ClassMetadata */ public function addLifecycleCallback($callback, $event) { - if(isset($this->lifecycleCallbacks[$event]) && in_array($callback, $this->lifecycleCallbacks[$event])) { + if (isset($this->lifecycleCallbacks[$event]) && in_array($callback, $this->lifecycleCallbacks[$event])) { return; } From 412e4ab9dac1945b3aa97b7ef6d093560732c5a3 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Sun, 9 Feb 2014 22:12:51 +0000 Subject: [PATCH 08/18] Cleaned up unused imports --- lib/Doctrine/ORM/Event/LoadClassMetadataEventArgs.php | 3 --- lib/Doctrine/ORM/Proxy/ProxyFactory.php | 1 - lib/Doctrine/ORM/Query/QueryExpressionVisitor.php | 1 - .../ORM/Tools/Console/Command/SchemaTool/CreateCommand.php | 1 - .../ORM/Tools/Console/Command/SchemaTool/DropCommand.php | 1 - .../ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php | 1 - .../ORM/Tools/Pagination/LimitSubqueryOutputWalker.php | 1 - lib/Doctrine/ORM/Tools/SchemaTool.php | 1 - 8 files changed, 10 deletions(-) diff --git a/lib/Doctrine/ORM/Event/LoadClassMetadataEventArgs.php b/lib/Doctrine/ORM/Event/LoadClassMetadataEventArgs.php index 0111fa38e..5bebf7541 100644 --- a/lib/Doctrine/ORM/Event/LoadClassMetadataEventArgs.php +++ b/lib/Doctrine/ORM/Event/LoadClassMetadataEventArgs.php @@ -19,9 +19,6 @@ namespace Doctrine\ORM\Event; -use Doctrine\Common\EventArgs; -use Doctrine\ORM\Mapping\ClassMetadataInfo; -use Doctrine\ORM\EntityManager; use Doctrine\Common\Persistence\Event\LoadClassMetadataEventArgs as BaseLoadClassMetadataEventArgs; /** diff --git a/lib/Doctrine/ORM/Proxy/ProxyFactory.php b/lib/Doctrine/ORM/Proxy/ProxyFactory.php index aea572c2c..a190fc896 100644 --- a/lib/Doctrine/ORM/Proxy/ProxyFactory.php +++ b/lib/Doctrine/ORM/Proxy/ProxyFactory.php @@ -25,7 +25,6 @@ use Doctrine\Common\Proxy\ProxyDefinition; use Doctrine\Common\Util\ClassUtils; use Doctrine\Common\Proxy\Proxy as BaseProxy; use Doctrine\Common\Proxy\ProxyGenerator; -use Doctrine\ORM\ORMInvalidArgumentException; use Doctrine\ORM\Persisters\EntityPersister; use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityNotFoundException; diff --git a/lib/Doctrine/ORM/Query/QueryExpressionVisitor.php b/lib/Doctrine/ORM/Query/QueryExpressionVisitor.php index 825e31971..984820728 100644 --- a/lib/Doctrine/ORM/Query/QueryExpressionVisitor.php +++ b/lib/Doctrine/ORM/Query/QueryExpressionVisitor.php @@ -26,7 +26,6 @@ use Doctrine\Common\Collections\Expr\Comparison; use Doctrine\Common\Collections\Expr\CompositeExpression; use Doctrine\Common\Collections\Expr\Value; -use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\Query\Parameter; /** diff --git a/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/CreateCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/CreateCommand.php index 9a49c698d..b2af0ca2c 100644 --- a/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/CreateCommand.php +++ b/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/CreateCommand.php @@ -19,7 +19,6 @@ namespace Doctrine\ORM\Tools\Console\Command\SchemaTool; -use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; diff --git a/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/DropCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/DropCommand.php index b5daf798e..b22237831 100644 --- a/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/DropCommand.php +++ b/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/DropCommand.php @@ -19,7 +19,6 @@ namespace Doctrine\ORM\Tools\Console\Command\SchemaTool; -use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; diff --git a/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php index 884833ca5..9c5b16a2c 100644 --- a/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php +++ b/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php @@ -19,7 +19,6 @@ namespace Doctrine\ORM\Tools\Console\Command\SchemaTool; -use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; diff --git a/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryOutputWalker.php b/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryOutputWalker.php index 5b6ac09fd..1b32fc97c 100644 --- a/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryOutputWalker.php +++ b/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryOutputWalker.php @@ -16,7 +16,6 @@ namespace Doctrine\ORM\Tools\Pagination; use Doctrine\ORM\Query\SqlWalker; use Doctrine\ORM\Query\AST\SelectStatement; use Doctrine\DBAL\Platforms\PostgreSqlPlatform; -use Doctrine\DBAL\Platforms\OraclePlatform; /** * Wraps the query in order to select root entity IDs for pagination. diff --git a/lib/Doctrine/ORM/Tools/SchemaTool.php b/lib/Doctrine/ORM/Tools/SchemaTool.php index ab320dfa7..4ccbe117b 100644 --- a/lib/Doctrine/ORM/Tools/SchemaTool.php +++ b/lib/Doctrine/ORM/Tools/SchemaTool.php @@ -28,7 +28,6 @@ use Doctrine\DBAL\Schema\Visitor\DropSchemaSqlCollector; use Doctrine\DBAL\Schema\Visitor\RemoveNamespacedAssets; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\ClassMetadata; -use Doctrine\ORM\Internal\CommitOrderCalculator; use Doctrine\ORM\Tools\Event\GenerateSchemaTableEventArgs; use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs; From 08f6291350bcebf90a3a96e83fc2f658756d0290 Mon Sep 17 00:00:00 2001 From: Benjamin Morel Date: Sun, 9 Feb 2014 23:45:22 +0000 Subject: [PATCH 09/18] Cleaned up further unused imports. --- lib/Doctrine/ORM/AbstractQuery.php | 1 - lib/Doctrine/ORM/Cache.php | 2 -- lib/Doctrine/ORM/Cache/CacheConfiguration.php | 3 --- lib/Doctrine/ORM/Cache/CollectionHydrator.php | 2 -- lib/Doctrine/ORM/Cache/ConcurrentRegion.php | 2 -- lib/Doctrine/ORM/Cache/DefaultCacheFactory.php | 2 -- lib/Doctrine/ORM/Cache/DefaultCollectionHydrator.php | 2 -- lib/Doctrine/ORM/Cache/DefaultEntityHydrator.php | 2 -- lib/Doctrine/ORM/Cache/DefaultQueryCache.php | 3 --- lib/Doctrine/ORM/Cache/EntityHydrator.php | 2 -- lib/Doctrine/ORM/Cache/QueryCacheValidator.php | 2 -- lib/Doctrine/ORM/Cache/Region.php | 2 -- lib/Doctrine/ORM/Cache/TimestampQueryCacheValidator.php | 3 --- lib/Doctrine/ORM/Event/LifecycleEventArgs.php | 1 - lib/Doctrine/ORM/Event/PreUpdateEventArgs.php | 1 - lib/Doctrine/ORM/Mapping/AnsiQuoteStrategy.php | 1 - lib/Doctrine/ORM/Mapping/DefaultQuoteStrategy.php | 1 - lib/Doctrine/ORM/Mapping/QuoteStrategy.php | 1 - lib/Doctrine/ORM/Query/FilterCollection.php | 1 - lib/Doctrine/ORM/Query/QueryExpressionVisitor.php | 2 -- lib/Doctrine/ORM/Query/SqlWalker.php | 1 - lib/Doctrine/ORM/Tools/Export/ClassMetadataExporter.php | 2 -- lib/Doctrine/ORM/Tools/SchemaTool.php | 1 - 23 files changed, 40 deletions(-) diff --git a/lib/Doctrine/ORM/AbstractQuery.php b/lib/Doctrine/ORM/AbstractQuery.php index 5390c96d2..6ee6d1ae9 100644 --- a/lib/Doctrine/ORM/AbstractQuery.php +++ b/lib/Doctrine/ORM/AbstractQuery.php @@ -29,7 +29,6 @@ use Doctrine\DBAL\Cache\QueryCacheProfile; use Doctrine\ORM\Cache; use Doctrine\ORM\Query\QueryException; -use Doctrine\ORM\ORMInvalidArgumentException; /** * Base contract for ORM queries. Base class for Query and NativeQuery. diff --git a/lib/Doctrine/ORM/Cache.php b/lib/Doctrine/ORM/Cache.php index 37cc9a075..fec65f1f3 100644 --- a/lib/Doctrine/ORM/Cache.php +++ b/lib/Doctrine/ORM/Cache.php @@ -20,8 +20,6 @@ namespace Doctrine\ORM; -use Doctrine\ORM\EntityManagerInterface; - /** * Provides an API for querying/managing the second level cache regions. * diff --git a/lib/Doctrine/ORM/Cache/CacheConfiguration.php b/lib/Doctrine/ORM/Cache/CacheConfiguration.php index 9d3654a04..4a583c14c 100644 --- a/lib/Doctrine/ORM/Cache/CacheConfiguration.php +++ b/lib/Doctrine/ORM/Cache/CacheConfiguration.php @@ -21,10 +21,7 @@ namespace Doctrine\ORM\Cache; use Doctrine\ORM\ORMException; -use Doctrine\ORM\Cache\CacheFactory; use Doctrine\ORM\Cache\Logging\CacheLogger; -use Doctrine\ORM\Cache\QueryCacheValidator; -use Doctrine\ORM\Cache\TimestampQueryCacheValidator; /** * Configuration container for second-level cache. diff --git a/lib/Doctrine/ORM/Cache/CollectionHydrator.php b/lib/Doctrine/ORM/Cache/CollectionHydrator.php index 05f0d35a1..04cdde162 100644 --- a/lib/Doctrine/ORM/Cache/CollectionHydrator.php +++ b/lib/Doctrine/ORM/Cache/CollectionHydrator.php @@ -22,8 +22,6 @@ namespace Doctrine\ORM\Cache; use Doctrine\ORM\PersistentCollection; use Doctrine\ORM\Mapping\ClassMetadata; -use Doctrine\ORM\Cache\CollectionCacheKey; -use Doctrine\ORM\Cache\CollectionCacheEntry; /** * Hydrator cache entry for collections diff --git a/lib/Doctrine/ORM/Cache/ConcurrentRegion.php b/lib/Doctrine/ORM/Cache/ConcurrentRegion.php index 7bb50086b..12da6d615 100644 --- a/lib/Doctrine/ORM/Cache/ConcurrentRegion.php +++ b/lib/Doctrine/ORM/Cache/ConcurrentRegion.php @@ -20,8 +20,6 @@ namespace Doctrine\ORM\Cache; -use Doctrine\ORM\Cache\Lock; - /** * Defines contract for concurrently managed data region. * It should be able to lock an specific cache entry in an atomic operation. diff --git a/lib/Doctrine/ORM/Cache/DefaultCacheFactory.php b/lib/Doctrine/ORM/Cache/DefaultCacheFactory.php index 118fd30b1..9ae425df3 100644 --- a/lib/Doctrine/ORM/Cache/DefaultCacheFactory.php +++ b/lib/Doctrine/ORM/Cache/DefaultCacheFactory.php @@ -24,8 +24,6 @@ use Doctrine\Common\Cache\CacheProvider; use Doctrine\ORM\Cache; use Doctrine\ORM\Cache\Region; -use Doctrine\ORM\Cache\TimestampRegion; -use Doctrine\ORM\Cache\RegionsConfiguration; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Cache\Region\DefaultRegion; diff --git a/lib/Doctrine/ORM/Cache/DefaultCollectionHydrator.php b/lib/Doctrine/ORM/Cache/DefaultCollectionHydrator.php index 53ab2c58f..72409509d 100644 --- a/lib/Doctrine/ORM/Cache/DefaultCollectionHydrator.php +++ b/lib/Doctrine/ORM/Cache/DefaultCollectionHydrator.php @@ -24,8 +24,6 @@ use Doctrine\ORM\Query; use Doctrine\ORM\PersistentCollection; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\Cache\CollectionCacheKey; -use Doctrine\ORM\Cache\CollectionCacheEntry; /** * Default hydrator cache for collections diff --git a/lib/Doctrine/ORM/Cache/DefaultEntityHydrator.php b/lib/Doctrine/ORM/Cache/DefaultEntityHydrator.php index 8a5cb83e5..6d9ac53b8 100644 --- a/lib/Doctrine/ORM/Cache/DefaultEntityHydrator.php +++ b/lib/Doctrine/ORM/Cache/DefaultEntityHydrator.php @@ -23,10 +23,8 @@ namespace Doctrine\ORM\Cache; use Doctrine\Common\Util\ClassUtils; use Doctrine\ORM\Query; -use Doctrine\ORM\Cache\EntityCacheKey; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\Cache\EntityCacheEntry; /** * Default hydrator cache for entities diff --git a/lib/Doctrine/ORM/Cache/DefaultQueryCache.php b/lib/Doctrine/ORM/Cache/DefaultQueryCache.php index 479bfbfea..789792103 100644 --- a/lib/Doctrine/ORM/Cache/DefaultQueryCache.php +++ b/lib/Doctrine/ORM/Cache/DefaultQueryCache.php @@ -25,10 +25,7 @@ use Doctrine\ORM\Cache\Persister\CachedPersister; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Query\ResultSetMapping; use Doctrine\ORM\Mapping\ClassMetadata; -use Doctrine\ORM\Cache\QueryCacheEntry; -use Doctrine\ORM\Cache\EntityCacheKey; use Doctrine\ORM\PersistentCollection; -use Doctrine\ORM\Cache\CacheException; use Doctrine\Common\Proxy\Proxy; use Doctrine\ORM\Cache; use Doctrine\ORM\Query; diff --git a/lib/Doctrine/ORM/Cache/EntityHydrator.php b/lib/Doctrine/ORM/Cache/EntityHydrator.php index 569561101..05a394da7 100644 --- a/lib/Doctrine/ORM/Cache/EntityHydrator.php +++ b/lib/Doctrine/ORM/Cache/EntityHydrator.php @@ -20,9 +20,7 @@ namespace Doctrine\ORM\Cache; -use Doctrine\ORM\Cache\EntityCacheKey; use Doctrine\ORM\Mapping\ClassMetadata; -use Doctrine\ORM\Cache\EntityCacheEntry; /** * Hydrator cache entry for entities diff --git a/lib/Doctrine/ORM/Cache/QueryCacheValidator.php b/lib/Doctrine/ORM/Cache/QueryCacheValidator.php index dba7b0abe..682a41ec4 100644 --- a/lib/Doctrine/ORM/Cache/QueryCacheValidator.php +++ b/lib/Doctrine/ORM/Cache/QueryCacheValidator.php @@ -20,8 +20,6 @@ namespace Doctrine\ORM\Cache; -use Doctrine\ORM\Cache\QueryCacheEntry; - /** * Cache query validator interface. * diff --git a/lib/Doctrine/ORM/Cache/Region.php b/lib/Doctrine/ORM/Cache/Region.php index 91879f45a..894fd2f9b 100644 --- a/lib/Doctrine/ORM/Cache/Region.php +++ b/lib/Doctrine/ORM/Cache/Region.php @@ -20,8 +20,6 @@ namespace Doctrine\ORM\Cache; -use Doctrine\ORM\Cache\Lock; - /** * Defines a contract for accessing a particular named region. * diff --git a/lib/Doctrine/ORM/Cache/TimestampQueryCacheValidator.php b/lib/Doctrine/ORM/Cache/TimestampQueryCacheValidator.php index c213beefe..4e504e4f8 100644 --- a/lib/Doctrine/ORM/Cache/TimestampQueryCacheValidator.php +++ b/lib/Doctrine/ORM/Cache/TimestampQueryCacheValidator.php @@ -20,9 +20,6 @@ namespace Doctrine\ORM\Cache; -use Doctrine\ORM\Cache\QueryCacheEntry; -use Doctrine\ORM\Cache\QueryCacheKey; - /** * @since 2.5 * @author Fabio B. Silva diff --git a/lib/Doctrine/ORM/Event/LifecycleEventArgs.php b/lib/Doctrine/ORM/Event/LifecycleEventArgs.php index 8977a3573..9a5c8cf06 100644 --- a/lib/Doctrine/ORM/Event/LifecycleEventArgs.php +++ b/lib/Doctrine/ORM/Event/LifecycleEventArgs.php @@ -19,7 +19,6 @@ namespace Doctrine\ORM\Event; -use Doctrine\ORM\EntityManager; use Doctrine\Common\Persistence\Event\LifecycleEventArgs as BaseLifecycleEventArgs; /** diff --git a/lib/Doctrine/ORM/Event/PreUpdateEventArgs.php b/lib/Doctrine/ORM/Event/PreUpdateEventArgs.php index 0cae066af..9624e94da 100644 --- a/lib/Doctrine/ORM/Event/PreUpdateEventArgs.php +++ b/lib/Doctrine/ORM/Event/PreUpdateEventArgs.php @@ -19,7 +19,6 @@ namespace Doctrine\ORM\Event; -use Doctrine\Common\EventArgs; use Doctrine\ORM\EntityManager; /** diff --git a/lib/Doctrine/ORM/Mapping/AnsiQuoteStrategy.php b/lib/Doctrine/ORM/Mapping/AnsiQuoteStrategy.php index 440c3909f..526c5ac51 100644 --- a/lib/Doctrine/ORM/Mapping/AnsiQuoteStrategy.php +++ b/lib/Doctrine/ORM/Mapping/AnsiQuoteStrategy.php @@ -19,7 +19,6 @@ namespace Doctrine\ORM\Mapping; -use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\DBAL\Platforms\AbstractPlatform; /** diff --git a/lib/Doctrine/ORM/Mapping/DefaultQuoteStrategy.php b/lib/Doctrine/ORM/Mapping/DefaultQuoteStrategy.php index 70359de33..5adfa8b16 100644 --- a/lib/Doctrine/ORM/Mapping/DefaultQuoteStrategy.php +++ b/lib/Doctrine/ORM/Mapping/DefaultQuoteStrategy.php @@ -19,7 +19,6 @@ namespace Doctrine\ORM\Mapping; -use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\DBAL\Platforms\AbstractPlatform; /** diff --git a/lib/Doctrine/ORM/Mapping/QuoteStrategy.php b/lib/Doctrine/ORM/Mapping/QuoteStrategy.php index 2ad7e7c97..1a21ff1bb 100644 --- a/lib/Doctrine/ORM/Mapping/QuoteStrategy.php +++ b/lib/Doctrine/ORM/Mapping/QuoteStrategy.php @@ -19,7 +19,6 @@ namespace Doctrine\ORM\Mapping; -use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\DBAL\Platforms\AbstractPlatform; /** diff --git a/lib/Doctrine/ORM/Query/FilterCollection.php b/lib/Doctrine/ORM/Query/FilterCollection.php index 62fb32813..d1d340c65 100644 --- a/lib/Doctrine/ORM/Query/FilterCollection.php +++ b/lib/Doctrine/ORM/Query/FilterCollection.php @@ -19,7 +19,6 @@ namespace Doctrine\ORM\Query; -use Doctrine\ORM\Configuration; use Doctrine\ORM\EntityManager; /** diff --git a/lib/Doctrine/ORM/Query/QueryExpressionVisitor.php b/lib/Doctrine/ORM/Query/QueryExpressionVisitor.php index 984820728..da4577132 100644 --- a/lib/Doctrine/ORM/Query/QueryExpressionVisitor.php +++ b/lib/Doctrine/ORM/Query/QueryExpressionVisitor.php @@ -26,8 +26,6 @@ use Doctrine\Common\Collections\Expr\Comparison; use Doctrine\Common\Collections\Expr\CompositeExpression; use Doctrine\Common\Collections\Expr\Value; -use Doctrine\ORM\Query\Parameter; - /** * Converts Collection expressions to Query expressions. * diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index c54369aca..fe750cff4 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -23,7 +23,6 @@ use Doctrine\DBAL\LockMode; use Doctrine\DBAL\Types\Type; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Query; -use Doctrine\ORM\Query\QueryException; use Doctrine\ORM\OptimisticLockException; use Doctrine\ORM\Mapping\ClassMetadataInfo; diff --git a/lib/Doctrine/ORM/Tools/Export/ClassMetadataExporter.php b/lib/Doctrine/ORM/Tools/Export/ClassMetadataExporter.php index 478ae8473..1ea2a3735 100644 --- a/lib/Doctrine/ORM/Tools/Export/ClassMetadataExporter.php +++ b/lib/Doctrine/ORM/Tools/Export/ClassMetadataExporter.php @@ -19,8 +19,6 @@ namespace Doctrine\ORM\Tools\Export; -use Doctrine\ORM\Tools\Export\ExportException; - /** * Class used for converting your mapping information between the * supported formats: yaml, xml, and php/annotation. diff --git a/lib/Doctrine/ORM/Tools/SchemaTool.php b/lib/Doctrine/ORM/Tools/SchemaTool.php index 4ccbe117b..ad8b84f68 100644 --- a/lib/Doctrine/ORM/Tools/SchemaTool.php +++ b/lib/Doctrine/ORM/Tools/SchemaTool.php @@ -20,7 +20,6 @@ namespace Doctrine\ORM\Tools; use Doctrine\ORM\ORMException; -use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Schema\Comparator; use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Table; From 1c94c16234941903bb84d4745df0c51e43e25394 Mon Sep 17 00:00:00 2001 From: Asmir Mustafic Date: Tue, 11 Feb 2014 14:59:31 +0100 Subject: [PATCH 10/18] Can cache empty collections I should be able to cache an "empty" collection. I have a some objects, where 90% of these have on-to-many relations with zero associated elements. This causes doctrine to run a query each time, instead of cache it as empty relation. --- lib/Doctrine/ORM/Cache/Persister/AbstractEntityPersister.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Doctrine/ORM/Cache/Persister/AbstractEntityPersister.php b/lib/Doctrine/ORM/Cache/Persister/AbstractEntityPersister.php index e084405ed..eaca3d75e 100644 --- a/lib/Doctrine/ORM/Cache/Persister/AbstractEntityPersister.php +++ b/lib/Doctrine/ORM/Cache/Persister/AbstractEntityPersister.php @@ -543,7 +543,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister $list = $this->persister->loadOneToManyCollection($assoc, $sourceEntity, $coll); - if ($hasCache && ! empty($list)) { + if ($hasCache) { $persister->storeCollectionCache($key, $list); if ($this->cacheLogger) { From a5fbb20fbb58377fa876eb1ce8045541e0fbf01b Mon Sep 17 00:00:00 2001 From: Asmir Mustafic Date: Tue, 11 Feb 2014 15:08:49 +0100 Subject: [PATCH 11/18] Can cache many to many empty relations --- lib/Doctrine/ORM/Cache/Persister/AbstractEntityPersister.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Doctrine/ORM/Cache/Persister/AbstractEntityPersister.php b/lib/Doctrine/ORM/Cache/Persister/AbstractEntityPersister.php index eaca3d75e..3589e31a5 100644 --- a/lib/Doctrine/ORM/Cache/Persister/AbstractEntityPersister.php +++ b/lib/Doctrine/ORM/Cache/Persister/AbstractEntityPersister.php @@ -508,7 +508,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister $list = $this->persister->loadManyToManyCollection($assoc, $sourceEntity, $coll); - if ($hasCache && ! empty($list)) { + if ($hasCache) { $persister->storeCollectionCache($key, $list); if ($this->cacheLogger) { From 4a6d6e34f8a7a141f1c048a03e6b050ce5e8bfdc Mon Sep 17 00:00:00 2001 From: Asmir Mustafic Date: Tue, 11 Feb 2014 17:39:16 +0100 Subject: [PATCH 12/18] Test empty collections second level cache --- .../SecondLevelCacheAbstractTest.php | 7 ++-- .../SecondLevelCacheManyToManyTest.php | 29 +++++++++++++++ .../SecondLevelCacheOneToManyTest.php | 35 +++++++++++++++++-- 3 files changed, 66 insertions(+), 5 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheAbstractTest.php b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheAbstractTest.php index 2866c146c..e4672b9f2 100644 --- a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheAbstractTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheAbstractTest.php @@ -121,7 +121,7 @@ abstract class SecondLevelCacheAbstractTest extends OrmFunctionalTestCase $this->_em->flush(); } - + protected function loadFixturesTravelersWithProfile() { $t1 = new Traveler("Test traveler 1"); @@ -139,7 +139,7 @@ abstract class SecondLevelCacheAbstractTest extends OrmFunctionalTestCase $this->travelersWithProfile[] = $t1; $this->travelersWithProfile[] = $t2; - + $this->_em->flush(); } @@ -165,6 +165,7 @@ abstract class SecondLevelCacheAbstractTest extends OrmFunctionalTestCase { $t1 = new Travel($this->travelers[0]); $t2 = new Travel($this->travelers[1]); + $t3 = new Travel($this->travelers[1]); $t1->addVisitedCity($this->cities[0]); $t1->addVisitedCity($this->cities[1]); @@ -175,9 +176,11 @@ abstract class SecondLevelCacheAbstractTest extends OrmFunctionalTestCase $this->_em->persist($t1); $this->_em->persist($t2); + $this->_em->persist($t3); $this->travels[] = $t1; $this->travels[] = $t2; + $this->travels[] = $t3; $this->_em->flush(); } diff --git a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheManyToManyTest.php b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheManyToManyTest.php index ac3dfd4fc..490e0cf1a 100644 --- a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheManyToManyTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheManyToManyTest.php @@ -214,4 +214,33 @@ class SecondLevelCacheManyToManyTest extends SecondLevelCacheAbstractTest $this->_em->persist($travel); $this->_em->flush(); } + + public function testManyToManyWithEmptyRelation() + { + $this->loadFixturesCountries(); + $this->loadFixturesStates(); + $this->loadFixturesCities(); + $this->loadFixturesTraveler(); + $this->loadFixturesTravels(); + $this->_em->clear(); + + $this->evictRegions(); + + $queryCount = $this->getCurrentQueryCount(); + + $entitiId = $this->travels[2]->getId(); //empty travel + $entity = $this->_em->find(Travel::CLASSNAME, $entitiId); + + $this->assertEquals(0, $entity->getVisitedCities()->count()); + $this->assertEquals($queryCount+2, $this->getCurrentQueryCount()); + + $this->_em->clear(); + + $entity = $this->_em->find(Travel::CLASSNAME, $entitiId); + + $queryCount = $this->getCurrentQueryCount(); + $this->assertEquals(0, $entity->getVisitedCities()->count()); + $this->assertEquals($queryCount, $this->getCurrentQueryCount()); + + } } \ No newline at end of file diff --git a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheOneToManyTest.php b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheOneToManyTest.php index 6d1fd700c..f8aff3790 100644 --- a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheOneToManyTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheOneToManyTest.php @@ -90,7 +90,7 @@ class SecondLevelCacheOneToManyTest extends SecondLevelCacheAbstractTest $s3 = $this->_em->find(State::CLASSNAME, $this->states[0]->getId()); $s4 = $this->_em->find(State::CLASSNAME, $this->states[1]->getId()); - + //trigger lazy load from cache $this->assertCount(2, $s3->getCities()); $this->assertCount(2, $s4->getCities()); @@ -133,12 +133,12 @@ class SecondLevelCacheOneToManyTest extends SecondLevelCacheAbstractTest //trigger lazy load from database $this->assertCount(2, $this->_em->find(State::CLASSNAME, $this->states[0]->getId())->getCities()); - + $this->assertTrue($this->cache->containsEntity(State::CLASSNAME, $this->states[0]->getId())); $this->assertTrue($this->cache->containsCollection(State::CLASSNAME, 'cities', $this->states[0]->getId())); $this->assertTrue($this->cache->containsEntity(City::CLASSNAME, $this->states[0]->getCities()->get(0)->getId())); $this->assertTrue($this->cache->containsEntity(City::CLASSNAME, $this->states[0]->getCities()->get(1)->getId())); - + $queryCount = $this->getCurrentQueryCount(); $stateId = $this->states[0]->getId(); $state = $this->_em->find(State::CLASSNAME, $stateId); @@ -284,6 +284,35 @@ class SecondLevelCacheOneToManyTest extends SecondLevelCacheAbstractTest $this->assertEquals(0, $this->secondLevelCacheLogger->getRegionHitCount($this->getCollectionRegion(State::CLASSNAME, 'cities'))); } + public function testOneToManyWithEmptyRelation() + { + $this->loadFixturesCountries(); + $this->loadFixturesStates(); + $this->loadFixturesCities(); + + $this->secondLevelCacheLogger->clearStats(); + $this->cache->evictEntityRegion(City::CLASSNAME); + $this->cache->evictEntityRegion(State::CLASSNAME); + $this->cache->evictCollectionRegion(State::CLASSNAME, 'cities'); + $this->_em->clear(); + + $entitiId = $this->states[2]->getId(); // bavaria (cities count = 0) + $queryCount = $this->getCurrentQueryCount(); + $entity = $this->_em->find(State::CLASSNAME, $entitiId); + + $this->assertEquals(0, $entity->getCities()->count()); + $this->assertEquals($queryCount + 2, $this->getCurrentQueryCount()); + + $this->_em->clear(); + + $queryCount = $this->getCurrentQueryCount(); + $entity = $this->_em->find(State::CLASSNAME, $entitiId); + + $this->assertEquals(0, $entity->getCities()->count()); + $this->assertEquals($queryCount, $this->getCurrentQueryCount()); + + } + public function testOneToManyCount() { $this->loadFixturesCountries(); From 57ac3bd4be9e0682fcffd309d482782a6268865c Mon Sep 17 00:00:00 2001 From: Shaun Date: Tue, 11 Feb 2014 17:23:19 -0500 Subject: [PATCH 13/18] Add DB-level onDelete CASCADE example This adds `onDelete: CASCADE` to the `address` 1-1 relationship just to show how you would map a db-level cascade. --- docs/en/reference/yaml-mapping.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/reference/yaml-mapping.rst b/docs/en/reference/yaml-mapping.rst index e929306e0..dea597984 100644 --- a/docs/en/reference/yaml-mapping.rst +++ b/docs/en/reference/yaml-mapping.rst @@ -100,6 +100,7 @@ of several common elements: joinColumn: name: address_id referencedColumnName: id + onDelete: CASCADE oneToMany: phonenumbers: targetEntity: Phonenumber From 94896ce55255dc15f0d15d4ad2d545bcae5441dc Mon Sep 17 00:00:00 2001 From: Asmir Mustafic Date: Wed, 12 Feb 2014 08:18:34 +0100 Subject: [PATCH 14/18] Typo fix on many-to-many assocaition cascade test --- .../Tests/ORM/Functional/SecondLevelCacheManyToManyTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheManyToManyTest.php b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheManyToManyTest.php index 490e0cf1a..0db9e1cbc 100644 --- a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheManyToManyTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheManyToManyTest.php @@ -171,7 +171,7 @@ class SecondLevelCacheManyToManyTest extends SecondLevelCacheAbstractTest $this->_em->flush(); $this->_em->clear(); - $this->assertTrue($this->cache->containsEntity(Traveler::CLASSNAME, $travel->getId())); + $this->assertTrue($this->cache->containsEntity(Travel::CLASSNAME, $travel->getId())); $this->assertTrue($this->cache->containsEntity(Traveler::CLASSNAME, $traveler->getId())); $this->assertTrue($this->cache->containsEntity(City::CLASSNAME, $this->cities[0]->getId())); $this->assertTrue($this->cache->containsEntity(City::CLASSNAME, $this->cities[1]->getId())); From 1f0d4197a96ebe30d4357e186f275a03de4daf01 Mon Sep 17 00:00:00 2001 From: Asmir Mustafic Date: Wed, 12 Feb 2014 23:42:13 +0100 Subject: [PATCH 15/18] Update doc with latest news about extra lazy assoc --- docs/en/tutorials/extra-lazy-associations.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/en/tutorials/extra-lazy-associations.rst b/docs/en/tutorials/extra-lazy-associations.rst index 7ac88d8c4..f640484a5 100644 --- a/docs/en/tutorials/extra-lazy-associations.rst +++ b/docs/en/tutorials/extra-lazy-associations.rst @@ -15,7 +15,9 @@ the first time its accessed. If you mark an association as extra lazy the follow can be called without triggering a full load of the collection: - ``Collection#contains($entity)`` +- ``Collection#containsKey($key)`` (available with Doctrine 2.5) - ``Collection#count()`` +- ``Collection#get($key)`` (available with Doctrine 2.4 - ``Collection#slice($offset, $length = null)`` For each of this three methods the following semantics apply: From e27d963784be4548fb99996ce0d46d0a2f8c0819 Mon Sep 17 00:00:00 2001 From: Asmir Mustafic Date: Wed, 12 Feb 2014 23:42:52 +0100 Subject: [PATCH 16/18] Update extra-lazy-associations.rst --- docs/en/tutorials/extra-lazy-associations.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/tutorials/extra-lazy-associations.rst b/docs/en/tutorials/extra-lazy-associations.rst index f640484a5..2665d4bba 100644 --- a/docs/en/tutorials/extra-lazy-associations.rst +++ b/docs/en/tutorials/extra-lazy-associations.rst @@ -17,7 +17,7 @@ can be called without triggering a full load of the collection: - ``Collection#contains($entity)`` - ``Collection#containsKey($key)`` (available with Doctrine 2.5) - ``Collection#count()`` -- ``Collection#get($key)`` (available with Doctrine 2.4 +- ``Collection#get($key)`` (available with Doctrine 2.4) - ``Collection#slice($offset, $length = null)`` For each of this three methods the following semantics apply: From 0797feeb0f6aa1fdbdd88088df70539cb15b54cb Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Tue, 18 Feb 2014 10:28:13 +0100 Subject: [PATCH 17/18] Travis must use --prefer-source because of Github API limitations --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 88bf7cf63..8a13f9551 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ before_script: - sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'create database doctrine_tests;' -U postgres; fi" - sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'create database doctrine_tests_tmp;' -U postgres; fi" - sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'create database IF NOT EXISTS doctrine_tests_tmp;create database IF NOT EXISTS doctrine_tests;'; fi" - - composer install --prefer-dist --dev + - composer install --prefer-source --dev script: phpunit -v --configuration tests/travis/$DB.travis.xml From dfe7a68053b20b59bd92f83da20943af22519772 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Wed, 19 Feb 2014 22:02:07 +0100 Subject: [PATCH 18/18] Removing notice about public properties support (included since 2.4) see doctrine/doctrine2#406 --- docs/en/reference/best-practices.rst | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/docs/en/reference/best-practices.rst b/docs/en/reference/best-practices.rst index f58291d18..6937e99b1 100644 --- a/docs/en/reference/best-practices.rst +++ b/docs/en/reference/best-practices.rst @@ -6,22 +6,6 @@ design generally refer to best practices when working with Doctrine and do not necessarily reflect best practices for database design in general. - -Don't use public properties on entities ---------------------------------------- - -It is very important that you don't map public properties on -entities, but only protected or private ones. The reason for this -is simple, whenever you access a public property of a proxy object -that hasn't been initialized yet the return value will be null. -Doctrine cannot hook into this process and magically make the -entity lazy load. - -This can create situations where it is very hard to debug the -current failure. We therefore urge you to map only private and -protected properties on entities and use getter methods or magic -\_\_get() to access them. - Constrain relationships as much as possible -------------------------------------------