1
0
mirror of synced 2025-01-19 15:01:40 +03:00

Merge branch 'master' of github.com:doctrine/doctrine2

This commit is contained in:
Benjamin Eberlei 2014-02-21 16:14:57 +01:00
commit f5897d4b0b
42 changed files with 115 additions and 125 deletions

View File

@ -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;' -U postgres; fi"
- sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'create database doctrine_tests_tmp;' -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" - 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 script: phpunit -v --configuration tests/travis/$DB.travis.xml

View File

@ -6,22 +6,6 @@ design generally refer to best practices when working with Doctrine
and do not necessarily reflect best practices for database design and do not necessarily reflect best practices for database design
in general. 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 Constrain relationships as much as possible
------------------------------------------- -------------------------------------------

View File

@ -100,6 +100,7 @@ of several common elements:
joinColumn: joinColumn:
name: address_id name: address_id
referencedColumnName: id referencedColumnName: id
onDelete: CASCADE
oneToMany: oneToMany:
phonenumbers: phonenumbers:
targetEntity: Phonenumber targetEntity: Phonenumber

View File

@ -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: can be called without triggering a full load of the collection:
- ``Collection#contains($entity)`` - ``Collection#contains($entity)``
- ``Collection#containsKey($key)`` (available with Doctrine 2.5)
- ``Collection#count()`` - ``Collection#count()``
- ``Collection#get($key)`` (available with Doctrine 2.4)
- ``Collection#slice($offset, $length = null)`` - ``Collection#slice($offset, $length = null)``
For each of this three methods the following semantics apply: For each of this three methods the following semantics apply:

View File

@ -29,7 +29,6 @@ use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\ORM\Cache; use Doctrine\ORM\Cache;
use Doctrine\ORM\Query\QueryException; use Doctrine\ORM\Query\QueryException;
use Doctrine\ORM\ORMInvalidArgumentException;
/** /**
* Base contract for ORM queries. Base class for Query and NativeQuery. * Base contract for ORM queries. Base class for Query and NativeQuery.

View File

@ -20,8 +20,6 @@
namespace Doctrine\ORM; namespace Doctrine\ORM;
use Doctrine\ORM\EntityManagerInterface;
/** /**
* Provides an API for querying/managing the second level cache regions. * Provides an API for querying/managing the second level cache regions.
* *

View File

@ -21,10 +21,7 @@
namespace Doctrine\ORM\Cache; namespace Doctrine\ORM\Cache;
use Doctrine\ORM\ORMException; use Doctrine\ORM\ORMException;
use Doctrine\ORM\Cache\CacheFactory;
use Doctrine\ORM\Cache\Logging\CacheLogger; use Doctrine\ORM\Cache\Logging\CacheLogger;
use Doctrine\ORM\Cache\QueryCacheValidator;
use Doctrine\ORM\Cache\TimestampQueryCacheValidator;
/** /**
* Configuration container for second-level cache. * Configuration container for second-level cache.

View File

@ -22,8 +22,6 @@ namespace Doctrine\ORM\Cache;
use Doctrine\ORM\PersistentCollection; use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Cache\CollectionCacheKey;
use Doctrine\ORM\Cache\CollectionCacheEntry;
/** /**
* Hydrator cache entry for collections * Hydrator cache entry for collections

View File

@ -20,8 +20,6 @@
namespace Doctrine\ORM\Cache; namespace Doctrine\ORM\Cache;
use Doctrine\ORM\Cache\Lock;
/** /**
* Defines contract for concurrently managed data region. * Defines contract for concurrently managed data region.
* It should be able to lock an specific cache entry in an atomic operation. * It should be able to lock an specific cache entry in an atomic operation.

View File

@ -24,8 +24,6 @@ use Doctrine\Common\Cache\CacheProvider;
use Doctrine\ORM\Cache; use Doctrine\ORM\Cache;
use Doctrine\ORM\Cache\Region; use Doctrine\ORM\Cache\Region;
use Doctrine\ORM\Cache\TimestampRegion;
use Doctrine\ORM\Cache\RegionsConfiguration;
use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Cache\Region\DefaultRegion; use Doctrine\ORM\Cache\Region\DefaultRegion;

View File

@ -24,8 +24,6 @@ use Doctrine\ORM\Query;
use Doctrine\ORM\PersistentCollection; use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Cache\CollectionCacheKey;
use Doctrine\ORM\Cache\CollectionCacheEntry;
/** /**
* Default hydrator cache for collections * Default hydrator cache for collections

View File

@ -23,10 +23,8 @@ namespace Doctrine\ORM\Cache;
use Doctrine\Common\Util\ClassUtils; use Doctrine\Common\Util\ClassUtils;
use Doctrine\ORM\Query; use Doctrine\ORM\Query;
use Doctrine\ORM\Cache\EntityCacheKey;
use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Cache\EntityCacheEntry;
/** /**
* Default hydrator cache for entities * Default hydrator cache for entities

View File

@ -25,10 +25,7 @@ use Doctrine\ORM\Cache\Persister\CachedPersister;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query\ResultSetMapping; use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Cache\QueryCacheEntry;
use Doctrine\ORM\Cache\EntityCacheKey;
use Doctrine\ORM\PersistentCollection; use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Cache\CacheException;
use Doctrine\Common\Proxy\Proxy; use Doctrine\Common\Proxy\Proxy;
use Doctrine\ORM\Cache; use Doctrine\ORM\Cache;
use Doctrine\ORM\Query; use Doctrine\ORM\Query;

View File

@ -20,9 +20,7 @@
namespace Doctrine\ORM\Cache; namespace Doctrine\ORM\Cache;
use Doctrine\ORM\Cache\EntityCacheKey;
use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Cache\EntityCacheEntry;
/** /**
* Hydrator cache entry for entities * Hydrator cache entry for entities

View File

@ -508,7 +508,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
$list = $this->persister->loadManyToManyCollection($assoc, $sourceEntity, $coll); $list = $this->persister->loadManyToManyCollection($assoc, $sourceEntity, $coll);
if ($hasCache && ! empty($list)) { if ($hasCache) {
$persister->storeCollectionCache($key, $list); $persister->storeCollectionCache($key, $list);
if ($this->cacheLogger) { if ($this->cacheLogger) {
@ -543,7 +543,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
$list = $this->persister->loadOneToManyCollection($assoc, $sourceEntity, $coll); $list = $this->persister->loadOneToManyCollection($assoc, $sourceEntity, $coll);
if ($hasCache && ! empty($list)) { if ($hasCache) {
$persister->storeCollectionCache($key, $list); $persister->storeCollectionCache($key, $list);
if ($this->cacheLogger) { if ($this->cacheLogger) {

View File

@ -20,8 +20,6 @@
namespace Doctrine\ORM\Cache; namespace Doctrine\ORM\Cache;
use Doctrine\ORM\Cache\QueryCacheEntry;
/** /**
* Cache query validator interface. * Cache query validator interface.
* *

View File

@ -20,8 +20,6 @@
namespace Doctrine\ORM\Cache; namespace Doctrine\ORM\Cache;
use Doctrine\ORM\Cache\Lock;
/** /**
* Defines a contract for accessing a particular named region. * Defines a contract for accessing a particular named region.
* *

View File

@ -20,9 +20,6 @@
namespace Doctrine\ORM\Cache; namespace Doctrine\ORM\Cache;
use Doctrine\ORM\Cache\QueryCacheEntry;
use Doctrine\ORM\Cache\QueryCacheKey;
/** /**
* @since 2.5 * @since 2.5
* @author Fabio B. Silva <fabio.bat.silva@gmail.com> * @author Fabio B. Silva <fabio.bat.silva@gmail.com>

View File

@ -19,7 +19,6 @@
namespace Doctrine\ORM\Event; namespace Doctrine\ORM\Event;
use Doctrine\ORM\EntityManager;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs as BaseLifecycleEventArgs; use Doctrine\Common\Persistence\Event\LifecycleEventArgs as BaseLifecycleEventArgs;
/** /**

View File

@ -19,9 +19,6 @@
namespace Doctrine\ORM\Event; 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; use Doctrine\Common\Persistence\Event\LoadClassMetadataEventArgs as BaseLoadClassMetadataEventArgs;
/** /**

View File

@ -19,7 +19,6 @@
namespace Doctrine\ORM\Event; namespace Doctrine\ORM\Event;
use Doctrine\Common\EventArgs;
use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManager;
/** /**

View File

@ -19,7 +19,6 @@
namespace Doctrine\ORM\Mapping; namespace Doctrine\ORM\Mapping;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\AbstractPlatform;
/** /**

View File

@ -2370,7 +2370,7 @@ class ClassMetadataInfo implements ClassMetadata
$queryMapping['isSelfClass'] = false; $queryMapping['isSelfClass'] = false;
if (isset($queryMapping['resultClass'])) { if (isset($queryMapping['resultClass'])) {
if($queryMapping['resultClass'] === '__CLASS__') { if ($queryMapping['resultClass'] === '__CLASS__') {
$queryMapping['isSelfClass'] = true; $queryMapping['isSelfClass'] = true;
$queryMapping['resultClass'] = $this->name; $queryMapping['resultClass'] = $this->name;
@ -2410,7 +2410,7 @@ class ClassMetadataInfo implements ClassMetadata
} }
$entityResult['isSelfClass'] = false; $entityResult['isSelfClass'] = false;
if($entityResult['entityClass'] === '__CLASS__') { if ($entityResult['entityClass'] === '__CLASS__') {
$entityResult['isSelfClass'] = true; $entityResult['isSelfClass'] = true;
$entityResult['entityClass'] = $this->name; $entityResult['entityClass'] = $this->name;
@ -2430,7 +2430,7 @@ class ClassMetadataInfo implements ClassMetadata
if (!isset($field['column'])) { if (!isset($field['column'])) {
$fieldName = $field['name']; $fieldName = $field['name'];
if(strpos($fieldName, '.')){ if (strpos($fieldName, '.')) {
list(, $fieldName) = explode('.', $fieldName); list(, $fieldName) = explode('.', $fieldName);
} }
@ -2583,7 +2583,7 @@ class ClassMetadataInfo implements ClassMetadata
*/ */
public function addLifecycleCallback($callback, $event) 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; return;
} }

View File

@ -19,7 +19,6 @@
namespace Doctrine\ORM\Mapping; namespace Doctrine\ORM\Mapping;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\AbstractPlatform;
/** /**

View File

@ -19,7 +19,6 @@
namespace Doctrine\ORM\Mapping; namespace Doctrine\ORM\Mapping;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\AbstractPlatform;
/** /**

View File

@ -25,7 +25,6 @@ use Doctrine\Common\Proxy\ProxyDefinition;
use Doctrine\Common\Util\ClassUtils; use Doctrine\Common\Util\ClassUtils;
use Doctrine\Common\Proxy\Proxy as BaseProxy; use Doctrine\Common\Proxy\Proxy as BaseProxy;
use Doctrine\Common\Proxy\ProxyGenerator; use Doctrine\Common\Proxy\ProxyGenerator;
use Doctrine\ORM\ORMInvalidArgumentException;
use Doctrine\ORM\Persisters\EntityPersister; use Doctrine\ORM\Persisters\EntityPersister;
use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityNotFoundException; use Doctrine\ORM\EntityNotFoundException;

View File

@ -19,7 +19,6 @@
namespace Doctrine\ORM\Query; namespace Doctrine\ORM\Query;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManager;
/** /**

View File

@ -26,9 +26,6 @@ use Doctrine\Common\Collections\Expr\Comparison;
use Doctrine\Common\Collections\Expr\CompositeExpression; use Doctrine\Common\Collections\Expr\CompositeExpression;
use Doctrine\Common\Collections\Expr\Value; use Doctrine\Common\Collections\Expr\Value;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\Query\Parameter;
/** /**
* Converts Collection expressions to Query expressions. * Converts Collection expressions to Query expressions.
* *

View File

@ -23,7 +23,6 @@ use Doctrine\DBAL\LockMode;
use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query; use Doctrine\ORM\Query;
use Doctrine\ORM\Query\QueryException;
use Doctrine\ORM\OptimisticLockException; use Doctrine\ORM\OptimisticLockException;
use Doctrine\ORM\Mapping\ClassMetadataInfo; use Doctrine\ORM\Mapping\ClassMetadataInfo;
@ -895,6 +894,8 @@ class SqlWalker implements TreeWalker
} }
} }
$targetTableJoin = null;
// This condition is not checking ClassMetadata::MANY_TO_ONE, because by definition it cannot // 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. // 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. // The owning side is necessary at this point because only it contains the JoinColumn information.
@ -929,7 +930,10 @@ class SqlWalker implements TreeWalker
$conditions[] = $filterExpr; $conditions[] = $filterExpr;
} }
$sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ' . implode(' AND ', $conditions); $targetTableJoin = array(
'table' => $targetTableName . ' ' . $targetTableAlias,
'condition' => implode(' AND ', $conditions),
);
break; break;
case ($assoc['type'] == ClassMetadata::MANY_TO_MANY): case ($assoc['type'] == ClassMetadata::MANY_TO_MANY):
@ -981,20 +985,33 @@ class SqlWalker implements TreeWalker
$conditions[] = $filterExpr; $conditions[] = $filterExpr;
} }
$sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ' . implode(' AND ', $conditions); $targetTableJoin = array(
'table' => $targetTableName . ' ' . $targetTableAlias,
'condition' => implode(' AND ', $conditions),
);
break; break;
default:
throw new \BadMethodCallException('Type of association must be one of *_TO_ONE or MANY_TO_MANY');
} }
// Handle WITH clause // Handle WITH clause
if ($condExpr !== null) { $withCondition = (null === $condExpr) ? '' : ('(' . $this->walkConditionalExpression($condExpr) . ')');
// Phase 2 AST optimization: Skip processing of ConditionalExpression
// if only one ConditionalTerm is defined if ($targetClass->isInheritanceTypeJoined()) {
$sql .= ' AND (' . $this->walkConditionalExpression($condExpr) . ')'; $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'];
} else {
$sql .= $targetTableJoin['table'] . ' ON ' . $targetTableJoin['condition'] . $ctiJoins;
}
} else {
$sql .= $targetTableJoin['table'] . ' ON ' . $targetTableJoin['condition'];
} }
// FIXME: these should either be nested or all forced to be left joins (DDC-XXX) if ($withCondition) {
if ($targetClass->isInheritanceTypeJoined()) { $sql .= ' AND ' . $withCondition;
$sql .= $this->_generateClassTableInheritanceJoins($targetClass, $joinedDqlAlias);
} }
// Apply the indexes // Apply the indexes

View File

@ -74,11 +74,11 @@ class GenerateEntitiesCommand extends Command
'Flag to define if generator should only update entity if it exists.', true 'Flag to define if generator should only update entity if it exists.', true
), ),
new InputOption( new InputOption(
'extend', null, InputOption::VALUE_OPTIONAL, 'extend', null, InputOption::VALUE_REQUIRED,
'Defines a base class to be extended by generated entity classes.' 'Defines a base class to be extended by generated entity classes.'
), ),
new InputOption( new InputOption(
'num-spaces', null, InputOption::VALUE_OPTIONAL, 'num-spaces', null, InputOption::VALUE_REQUIRED,
'Defines the number of indentation spaces', 4 'Defines the number of indentation spaces', 4
), ),
new InputOption( new InputOption(

View File

@ -19,7 +19,6 @@
namespace Doctrine\ORM\Tools\Console\Command\SchemaTool; namespace Doctrine\ORM\Tools\Console\Command\SchemaTool;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;

View File

@ -19,7 +19,6 @@
namespace Doctrine\ORM\Tools\Console\Command\SchemaTool; namespace Doctrine\ORM\Tools\Console\Command\SchemaTool;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;

View File

@ -19,7 +19,6 @@
namespace Doctrine\ORM\Tools\Console\Command\SchemaTool; namespace Doctrine\ORM\Tools\Console\Command\SchemaTool;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;

View File

@ -19,8 +19,6 @@
namespace Doctrine\ORM\Tools\Export; namespace Doctrine\ORM\Tools\Export;
use Doctrine\ORM\Tools\Export\ExportException;
/** /**
* Class used for converting your mapping information between the * Class used for converting your mapping information between the
* supported formats: yaml, xml, and php/annotation. * supported formats: yaml, xml, and php/annotation.

View File

@ -16,7 +16,6 @@ namespace Doctrine\ORM\Tools\Pagination;
use Doctrine\ORM\Query\SqlWalker; use Doctrine\ORM\Query\SqlWalker;
use Doctrine\ORM\Query\AST\SelectStatement; use Doctrine\ORM\Query\AST\SelectStatement;
use Doctrine\DBAL\Platforms\PostgreSqlPlatform; use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
use Doctrine\DBAL\Platforms\OraclePlatform;
/** /**
* Wraps the query in order to select root entity IDs for pagination. * Wraps the query in order to select root entity IDs for pagination.
@ -164,11 +163,8 @@ class LimitSubqueryOutputWalker extends SqlWalker
$sql = sprintf('SELECT DISTINCT %s FROM (%s) dctrn_result', $sql = sprintf('SELECT DISTINCT %s FROM (%s) dctrn_result',
implode(', ', $sqlIdentifier), $innerSql); implode(', ', $sqlIdentifier), $innerSql);
if ($this->platform instanceof PostgreSqlPlatform ||
$this->platform instanceof OraclePlatform) {
// http://www.doctrine-project.org/jira/browse/DDC-1958 // http://www.doctrine-project.org/jira/browse/DDC-1958
$this->preserveSqlOrdering($AST, $sqlIdentifier, $innerSql, $sql); $sql = $this->preserveSqlOrdering($AST, $sqlIdentifier, $innerSql, $sql);
}
// Apply the limit and offset. // Apply the limit and offset.
$sql = $this->platform->modifyLimitQuery( $sql = $this->platform->modifyLimitQuery(
@ -196,7 +192,7 @@ class LimitSubqueryOutputWalker extends SqlWalker
* *
* @return void * @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. // For every order by, find out the SQL alias by inspecting the ResultSetMapping.
$sqlOrderColumns = array(); $sqlOrderColumns = array();
@ -219,11 +215,6 @@ class LimitSubqueryOutputWalker extends SqlWalker
$sqlOrderColumns = array_diff($sqlOrderColumns, $sqlIdentifier); $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)) { if (count($orderBy)) {
$sql = sprintf( $sql = sprintf(
'SELECT DISTINCT %s FROM (%s) dctrn_result ORDER BY %s', 'SELECT DISTINCT %s FROM (%s) dctrn_result ORDER BY %s',
@ -232,5 +223,7 @@ class LimitSubqueryOutputWalker extends SqlWalker
implode(', ', $orderBy) implode(', ', $orderBy)
); );
} }
return $sql;
} }
} }

View File

@ -20,7 +20,6 @@
namespace Doctrine\ORM\Tools; namespace Doctrine\ORM\Tools;
use Doctrine\ORM\ORMException; use Doctrine\ORM\ORMException;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Schema\Comparator; use Doctrine\DBAL\Schema\Comparator;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Schema\Table;
@ -28,7 +27,6 @@ use Doctrine\DBAL\Schema\Visitor\DropSchemaSqlCollector;
use Doctrine\DBAL\Schema\Visitor\RemoveNamespacedAssets; use Doctrine\DBAL\Schema\Visitor\RemoveNamespacedAssets;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Internal\CommitOrderCalculator;
use Doctrine\ORM\Tools\Event\GenerateSchemaTableEventArgs; use Doctrine\ORM\Tools\Event\GenerateSchemaTableEventArgs;
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs; use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;

View File

@ -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) { foreach ($class->subClasses as $subClass) {
if (!in_array($class->name, class_parents($subClass))) { if (!in_array($class->name, class_parents($subClass))) {
$ce[] = "According to the discriminator map class '" . $subClass . "' has to be a child ". $ce[] = "According to the discriminator map class '" . $subClass . "' has to be a child ".

View File

@ -38,12 +38,6 @@ class SchemaValidatorTest extends \Doctrine\Tests\OrmFunctionalTestCase
foreach ($classes as $class) { foreach ($classes as $class) {
$ce = $validator->validateClass($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)); $this->assertEquals(0, count($ce), "Invalid Modelset: " . $modelSet . " class " . $class->name . ": ". implode("\n", $ce));
} }
} }

View File

@ -165,6 +165,7 @@ abstract class SecondLevelCacheAbstractTest extends OrmFunctionalTestCase
{ {
$t1 = new Travel($this->travelers[0]); $t1 = new Travel($this->travelers[0]);
$t2 = new Travel($this->travelers[1]); $t2 = new Travel($this->travelers[1]);
$t3 = new Travel($this->travelers[1]);
$t1->addVisitedCity($this->cities[0]); $t1->addVisitedCity($this->cities[0]);
$t1->addVisitedCity($this->cities[1]); $t1->addVisitedCity($this->cities[1]);
@ -175,9 +176,11 @@ abstract class SecondLevelCacheAbstractTest extends OrmFunctionalTestCase
$this->_em->persist($t1); $this->_em->persist($t1);
$this->_em->persist($t2); $this->_em->persist($t2);
$this->_em->persist($t3);
$this->travels[] = $t1; $this->travels[] = $t1;
$this->travels[] = $t2; $this->travels[] = $t2;
$this->travels[] = $t3;
$this->_em->flush(); $this->_em->flush();
} }

View File

@ -171,7 +171,7 @@ class SecondLevelCacheManyToManyTest extends SecondLevelCacheAbstractTest
$this->_em->flush(); $this->_em->flush();
$this->_em->clear(); $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(Traveler::CLASSNAME, $traveler->getId()));
$this->assertTrue($this->cache->containsEntity(City::CLASSNAME, $this->cities[0]->getId())); $this->assertTrue($this->cache->containsEntity(City::CLASSNAME, $this->cities[0]->getId()));
$this->assertTrue($this->cache->containsEntity(City::CLASSNAME, $this->cities[1]->getId())); $this->assertTrue($this->cache->containsEntity(City::CLASSNAME, $this->cities[1]->getId()));
@ -214,4 +214,33 @@ class SecondLevelCacheManyToManyTest extends SecondLevelCacheAbstractTest
$this->_em->persist($travel); $this->_em->persist($travel);
$this->_em->flush(); $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());
}
} }

View File

@ -284,6 +284,35 @@ class SecondLevelCacheOneToManyTest extends SecondLevelCacheAbstractTest
$this->assertEquals(0, $this->secondLevelCacheLogger->getRegionHitCount($this->getCollectionRegion(State::CLASSNAME, 'cities'))); $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() public function testOneToManyCount()
{ {
$this->loadFixturesCountries(); $this->loadFixturesCountries();

View File

@ -2065,7 +2065,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
'SELECT e.id FROM Doctrine\Tests\Models\Company\CompanyOrganization o JOIN o.events e WITH e.id = ?1', '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) array(Query::HINT_FORCE_PARTIAL_LOAD => false)
); );
} }