1
0
mirror of synced 2025-01-25 01:31:40 +03:00

Merge pull request #1 from doctrine/master

Update from original
This commit is contained in:
Simon Harris 2014-07-31 16:24:31 +01:00
commit bf91d03adf
45 changed files with 747 additions and 133 deletions

View File

@ -38,3 +38,5 @@ matrix:
env: DB=pgsql # driver currently unsupported by HHVM
- php: hhvm-nightly
env: DB=mysqli # driver currently unsupported by HHVM
allow_failures:
- php: hhvm-nightly # hhvm-nightly currently chokes on composer installation

View File

@ -2,17 +2,17 @@
## Minor BC BREAK: Custom Hydrators API change
As of 2.5, `AbstractHydrator` does not enforce the usage of cache as part of
As of 2.5, `AbstractHydrator` does not enforce the usage of cache as part of
API, and now provides you a clean API for column information through the method
`hydrateColumnInfo($column)`.
Cache variable being passed around by reference is no longer needed since
Cache variable being passed around by reference is no longer needed since
Hydrators are per query instantiated since Doctrine 2.4.
## Minor BC BREAK: Entity based ``EntityManager#clear()`` calls follow cascade detach
Whenever ``EntityManager#clear()`` method gets called with a given entity class
name, until 2.4, it was only detaching the specific requested entity.
As of 2.5, ``EntityManager`` will follow configured cascades, providing a better
Whenever ``EntityManager#clear()`` method gets called with a given entity class
name, until 2.4, it was only detaching the specific requested entity.
As of 2.5, ``EntityManager`` will follow configured cascades, providing a better
memory management since associations will be garbage collected, optimizing
resources consumption on long running jobs.

View File

@ -20,7 +20,14 @@
use Symfony\Component\Console\Helper\HelperSet;
use Doctrine\ORM\Tools\Console\ConsoleRunner;
(@include_once __DIR__ . '/../vendor/autoload.php') || @include_once __DIR__ . '/../../../autoload.php';
$autoloadFiles = array(__DIR__ . '/../vendor/autoload.php',
__DIR__ . '/../../../autoload.php');
foreach ($autoloadFiles as $autoloadFile) {
if (file_exists($autoloadFile)) {
require_once $autoloadFile;
}
}
$directories = array(getcwd(), getcwd() . DIRECTORY_SEPARATOR . 'config');

View File

@ -232,7 +232,7 @@ Example usage
// Setup custom mapping type
use Doctrine\DBAL\Types\Type;
Type::addType('point', 'Geo\Types\Point');
Type::addType('point', 'Geo\Types\PointType');
$em->getConnection()->getDatabasePlatform()->registerDoctrineTypeMapping('point', 'point');
// Store a Location object

View File

@ -3,7 +3,7 @@ Keeping your Modules independent
.. versionadded:: 2.2
One of the goals of using modules is to create discreet units of functionality
One of the goals of using modules is to create discrete units of functionality
that do not have many (if any) dependencies, allowing you to use that
functionality in other applications without including unnecessary items.

View File

@ -109,6 +109,26 @@ Optional attributes:
- **nullable**: Determines if NULL values allowed for this column.
- **options**: Array of additional options:
- ``default``: The default value to set for the column if no value
is supplied.
- ``unsigned``: Boolean value to determine if the column should
be capable of representing only non-negative integers
(applies only for integer column and might not be supported by
all vendors).
- ``fixed``: Boolean value to determine if the specified length of
a string column should be fixed or varying (applies only for
string/binary column and might not be supported by all vendors).
- ``comment``: The comment of the column in the schema (might not
be supported by all vendors).
- ``customSchemaOptions``: Array of additional schema options
which are mostly vendor specific.
- **columnDefinition**: DDL SQL snippet that starts after the column
name and specifies the complete (non-portable!) column definition.
This attribute allows to make use of advanced RMDBS features.
@ -120,7 +140,12 @@ Optional attributes:
attribute still handles the conversion between PHP and Database
values. If you use this attribute on a column that is used for
joins between tables you should also take a look at
:ref:`@JoinColumn <annref_joincolumn>`.
:ref:`@JoinColumn <annref_joincolumn>`.
.. note::
For more detailed information on each attribute, please refer to
the DBAL ``Schema-Representation`` documentation.
Examples:
@ -131,17 +156,27 @@ Examples:
* @Column(type="string", length=32, unique=true, nullable=false)
*/
protected $username;
/**
* @Column(type="string", columnDefinition="CHAR(2) NOT NULL")
*/
protected $country;
/**
* @Column(type="decimal", precision=2, scale=1)
*/
protected $height;
/**
* @Column(type="string", length=2, options={"fixed":true, "comment":"Initial letters of first and last name"})
*/
protected $initials;
/**
* @Column(type="integer", name="login_count" nullable=false, options={"unsigned":true, "default":0})
*/
protected $loginCount;
.. _annref_column_result:
@ColumnResult
@ -222,7 +257,7 @@ Optional attributes:
~~~~~~~~~~~~~~~~~~~~~
The discriminator map is a required annotation on the
topmost/super class in an inheritance hierarchy. Its only argument is an
topmost/super class in an inheritance hierarchy. Its only argument is an
array which defines which class should be saved under
which name in the database. Keys are the database value and values
are the classes, either as fully- or as unqualified class names
@ -447,7 +482,7 @@ Examples:
{
// ...
}
/**
* @Entity
* @InheritanceType("JOINED")
@ -612,7 +647,7 @@ Optional attributes:
- **mappedBy**: This option specifies the property name on the
targetEntity that is the owning side of this relation. It is a
required attribute for the inverse side of a relationship.
- **inversedBy**: The inversedBy attribute designates the eld in the
- **inversedBy**: The inversedBy attribute designates the field in the
entity that is the inverse side of the relationship.
- **cascade**: Cascade Option
- **fetch**: One of LAZY, EXTRA_LAZY or EAGER
@ -640,7 +675,7 @@ Example:
* )
*/
private $groups;
/**
* Inverse Side
*
@ -786,7 +821,7 @@ Optional attributes:
- **orphanRemoval**: Boolean that specifies if orphans, inverse
OneToOne entities that are not connected to any owning instance,
should be removed by Doctrine. Defaults to false.
- **inversedBy**: The inversedBy attribute designates the eld in the
- **inversedBy**: The inversedBy attribute designates the field in the
entity that is the inverse side of the relationship.
Example:

View File

@ -42,6 +42,8 @@ internally but also mean more work during ``flush``.
$em->clear(); // Detaches all objects from Doctrine!
}
}
$em->flush(); //Persist objects that did not make up an entire batch
$em->clear();
Bulk Updates
------------

View File

@ -302,6 +302,14 @@ With Arithmetic Expression in WHERE clause:
$query = $em->createQuery('SELECT u FROM CmsUser u WHERE ((u.id + 5000) * u.id + 3) < 10000000');
$users = $query->getResult(); // array of ForumUser objects
Retrieve user entities with Arithmetic Expression in ORDER close, using the ``HIDDEN`` keyword:
.. code-block:: php
<?php
$query = $em->createQuery('SELECT u, u.posts_count + u.likes_count AS HIDDEN score FROM CmsUser u ORDER BY score');
$users = $query->getResult(); // array of User objects
Using a LEFT JOIN to hydrate all user-ids and optionally associated
article-ids:

View File

@ -191,6 +191,12 @@ the life-time of their registered entities.
safe to access associations in a postLoad callback or event
handler.
.. warning::
Note that the postRemove event or any events triggered after an entity removal
can receive an uninitializable proxy in case you have configured an entity to
cascade remove relations. In this case, you should load yourself the proxy in
the associated pre event.
You can access the Event constants from the ``Events`` class in the
ORM package.

View File

@ -109,19 +109,19 @@ Example:
.. code-block:: yaml
MyProject\Model\Person:
type: entity
inheritanceType: SINGLE_TABLE
discriminatorColumn:
MyProject\Model\Person:
type: entity
inheritanceType: SINGLE_TABLE
discriminatorColumn:
name: discr
type: string
discriminatorMap:
discriminatorMap:
person: Person
employee: Employee
MyProject\Model\Employee:
type: entity
MyProject\Model\Employee:
type: entity
Things to note:

View File

@ -65,18 +65,6 @@ Where the ``attribute_name`` column contains the key and
The feature request for persistence of primitive value arrays
`is described in the DDC-298 ticket <http://www.doctrine-project.org/jira/browse/DDC-298>`_.
Value Objects
~~~~~~~~~~~~~
There is currently no native support value objects in Doctrine
other than for ``DateTime`` instances or if you serialize the
objects using ``serialize()/deserialize()`` which the DBAL Type
"object" supports.
The feature request for full value-object support
`is described in the DDC-93 ticket <http://www.doctrine-project.org/jira/browse/DDC-93>`_.
Cascade Merge with Bi-directional Associations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -27,7 +27,7 @@ to write a mapping file for it using the above configured
<?php
namespace Entities;
class User
{
private $id;
@ -42,16 +42,30 @@ named ``Entities.User.php`` inside of the
<?php
// /path/to/php/mapping/files/Entities.User.php
$metadata->mapField(array(
'id' => true,
'fieldName' => 'id',
'type' => 'integer'
));
$metadata->mapField(array(
'fieldName' => 'username',
'type' => 'string'
'type' => 'string',
'options' => array(
'fixed' => true,
'comment' => "User's login name"
)
));
$metadata->mapField(array(
'fieldName' => 'login_count',
'type' => 'integer',
'nullable' => false,
'options' => array(
'unsigned' => true,
'default' => 0
)
));
Now we can easily retrieve the populated ``ClassMetadata`` instance
@ -87,13 +101,13 @@ Now you just need to define a static function named
<?php
namespace Entities;
use Doctrine\ORM\Mapping\ClassMetadata;
class User
{
// ...
public static function loadMetadata(ClassMetadata $metadata)
{
$metadata->mapField(array(
@ -101,7 +115,7 @@ Now you just need to define a static function named
'fieldName' => 'id',
'type' => 'integer'
));
$metadata->mapField(array(
'fieldName' => 'username',
'type' => 'string'

View File

@ -22,9 +22,9 @@ setup for the latest code in trunk.
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
https://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd">
...
</doctrine-mapping>
The XML mapping document of a class is loaded on-demand the first
@ -108,37 +108,37 @@ of several common elements:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd">
<entity name="Doctrine\Tests\ORM\Mapping\User" table="cms_users">
<indexes>
<index name="name_idx" columns="name"/>
<index columns="user_email"/>
</indexes>
<unique-constraints>
<unique-constraint columns="name,user_email" name="search_idx" />
</unique-constraints>
<lifecycle-callbacks>
<lifecycle-callback type="prePersist" method="doStuffOnPrePersist"/>
<lifecycle-callback type="prePersist" method="doOtherStuffOnPrePersistToo"/>
<lifecycle-callback type="postPersist" method="doStuffOnPostPersist"/>
</lifecycle-callbacks>
<id name="id" type="integer" column="id">
<generator strategy="AUTO"/>
<sequence-generator sequence-name="tablename_seq" allocation-size="100" initial-value="1" />
</id>
<field name="name" column="name" type="string" length="50" nullable="true" unique="true" />
<field name="email" column="user_email" type="string" column-definition="CHAR(32) NOT NULL" />
<one-to-one field="address" target-entity="Address" inversed-by="user">
<cascade><cascade-remove /></cascade>
<join-column name="address_id" referenced-column-name="id" on-delete="CASCADE" on-update="CASCADE"/>
</one-to-one>
<one-to-many field="phonenumbers" target-entity="Phonenumber" mapped-by="user">
<cascade>
<cascade-persist/>
@ -147,7 +147,7 @@ of several common elements:
<order-by-field name="number" direction="ASC" />
</order-by>
</one-to-many>
<many-to-many field="groups" target-entity="Group">
<cascade>
<cascade-all/>
@ -161,9 +161,9 @@ of several common elements:
</inverse-join-columns>
</join-table>
</many-to-many>
</entity>
</doctrine-mapping>
Be aware that class-names specified in the XML files should be
@ -224,12 +224,18 @@ entity. For the ID mapping you have to use the ``<id />`` element.
.. code-block:: xml
<entity name="MyProject\User">
<field name="name" type="string" length="50" />
<field name="username" type="string" unique="true" />
<field name="age" type="integer" nullable="true" />
<field name="isActive" column="is_active" type="boolean" />
<field name="weight" type="decimal" scale="5" precision="2" />
<field name="login_count" type="integer" nullable="false">
<options>
<option name="comment">The number of times the user has logged in.</option>
<option name="default">0</option>
</options>
</field>
</entity>
Required attributes:
@ -255,12 +261,32 @@ Optional attributes:
works on fields with type integer or datetime.
- scale - Scale of a decimal type.
- precision - Precision of a decimal type.
- options - Array of additional options:
- default - The default value to set for the column if no value
is supplied.
- unsigned - Boolean value to determine if the column should
be capable of representing only non-negative integers
(applies only for integer column and might not be supported by
all vendors).
- fixed - Boolean value to determine if the specified length of
a string column should be fixed or varying (applies only for
string/binary column and might not be supported by all vendors).
- comment - The comment of the column in the schema (might not
be supported by all vendors).
- customSchemaOptions - Array of additional schema options
which are mostly vendor specific.
- column-definition - Optional alternative SQL representation for
this column. This definition begin after the field-name and has to
specify the complete column definition. Using this feature will
turn this field dirty for Schema-Tool update commands at all
times.
.. note::
For more detailed information on each attribute, please refer to
the DBAL ``Schema-Representation`` documentation.
Defining Identity and Generator Strategies
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -423,7 +449,7 @@ using the ``<lifecycle-callbacks />`` element:
.. code-block:: xml
<entity name="Doctrine\Tests\ORM\Mapping\User" table="cms_users">
<lifecycle-callbacks>
<lifecycle-callback type="prePersist" method="onPrePersist" />
</lifecycle-callbacks>
@ -716,12 +742,12 @@ table you can use the ``<indexes />`` and
.. code-block:: xml
<entity name="Doctrine\Tests\ORM\Mapping\User" table="cms_users">
<indexes>
<index name="name_idx" columns="name"/>
<index columns="user_email"/>
</indexes>
<unique-constraints>
<unique-constraint columns="name,user_email" name="search_idx" />
</unique-constraints>

View File

@ -94,6 +94,14 @@ of several common elements:
unique: true
options:
fixed: true
comment: User's email address
loginCount:
type: integer
column: login_count
nullable: false
options:
unsigned: true
default: 0
oneToOne:
address:
targetEntity: Address

View File

@ -429,7 +429,6 @@
<xs:attribute name="unique" type="xs:boolean" default="false" />
<xs:attribute name="nullable" type="xs:boolean" default="true" />
<xs:attribute name="on-delete" type="orm:fk-action" />
<xs:attribute name="on-update" type="orm:fk-action" />
<xs:attribute name="column-definition" type="xs:string" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>

View File

@ -191,9 +191,9 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* {@inheritdoc}
*/
public function exists($entity, array $extraConditions = array())
public function exists($entity, Criteria $extraConditions = null)
{
if (empty($extraConditions)) {
if (null === $extraConditions) {
$key = new EntityCacheKey($this->class->rootEntityName, $this->class->getIdentifierValues($entity));
if ($this->region->contains($key)) {

View File

@ -425,7 +425,7 @@ use Doctrine\Common\Util\ClassUtils;
break;
case LockMode::NONE === $lockMode:
case LockMode::PESSIMISTIC_READ === $lockMode;
case LockMode::PESSIMISTIC_READ === $lockMode:
case LockMode::PESSIMISTIC_WRITE === $lockMode:
$persister = $unitOfWork->getEntityPersister($class->name);
$persister->refresh($sortedId, $entity, $lockMode);

View File

@ -75,6 +75,11 @@ class SimpleObjectHydrator extends AbstractHydrator
if ($this->class->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) {
$discrColumnName = $this->_platform->getSQLResultCasing($this->class->discriminatorColumn['name']);
// Find mapped discriminator column from the result set.
if ($metaMappingDiscrColumnName = array_search($discrColumnName, $this->_rsm->metaMappings)) {
$discrColumnName = $metaMappingDiscrColumnName;
}
if ( ! isset($sqlResult[$discrColumnName])) {
throw HydrationException::missingDiscriminatorColumn($entityName, $discrColumnName, key($this->_rsm->aliasMap));
}

View File

@ -30,7 +30,7 @@ use Doctrine\ORM\Persisters\EntityPersister;
* A lazy collection that allow a fast count when using criteria object
* Once count gets executed once without collection being initialized, result
* is cached and returned on subsequent calls until collection gets loaded,
* then returning the number of loaded results.
* then returning the number of loaded results.
*
* @since 2.5
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
@ -82,6 +82,21 @@ class LazyCriteriaCollection extends AbstractLazyCollection implements Selectabl
return $this->count = $this->entityPersister->count($this->criteria);
}
/**
* Do an optimized search of an element
*
* @param object $element
* @return bool
*/
public function contains($element)
{
if ($this->isInitialized()) {
return $this->collection->contains($element);
}
return $this->entityPersister->exists($element, $this->criteria);
}
/**
* {@inheritDoc}
*/

View File

@ -908,7 +908,7 @@ class ClassMetadataInfo implements ClassMetadata
public function newInstance()
{
if ($this->_prototype === null) {
if (PHP_VERSION_ID === 50428 || PHP_VERSION_ID === 50513) {
if (PHP_VERSION_ID === 50429 || PHP_VERSION_ID === 50513) {
$this->_prototype = $this->reflClass->newInstanceWithoutConstructor();
} else {
$this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));

View File

@ -655,7 +655,7 @@ class MappingException extends \Doctrine\ORM\ORMException
*/
public static function noInheritanceOnMappedSuperClass($className)
{
return new self("Its not supported to define inheritance information on a mapped superclass '" . $className . "'.");
return new self("It is not supported to define inheritance information on a mapped superclass '" . $className . "'.");
}
/**

View File

@ -65,7 +65,7 @@ class ORMInvalidArgumentException extends \InvalidArgumentException
static public function entityWithoutIdentity($className, $entity)
{
return new self(
"The given entity of type '" . $className . "' (".self::objToStr($entity).") has no identity/no " .
"The given entity of type '" . $className . "' (".self::objToStr($entity).") has no identity/no " .
"id values set. It cannot be added to the identity map."
);
}
@ -154,7 +154,7 @@ class ORMInvalidArgumentException extends \InvalidArgumentException
*/
static public function detachedEntityCannot($entity, $operation)
{
return new self("A detached entity was found during " . $operation . " " . self::objToStr($entity));
return new self("Detached entity " . self::objToStr($entity) . " cannot be " . $operation);
}
/**

View File

@ -1835,7 +1835,7 @@ class BasicEntityPersister implements EntityPersister
/**
* {@inheritdoc}
*/
public function exists($entity, array $extraConditions = array())
public function exists($entity, Criteria $extraConditions = null)
{
$criteria = $this->class->getIdentifierValues($entity);
@ -1843,22 +1843,25 @@ class BasicEntityPersister implements EntityPersister
return false;
}
if ($extraConditions) {
$criteria = array_merge($criteria, $extraConditions);
}
$alias = $this->getSQLTableAlias($this->class->name);
$sql = 'SELECT 1 '
. $this->getLockTablesSql(null)
. ' WHERE ' . $this->getSelectConditionSQL($criteria);
list($params) = $this->expandParameters($criteria);
if (null !== $extraConditions) {
$sql .= ' AND ' . $this->getSelectConditionCriteriaSQL($extraConditions);
list($criteriaParams, $values) = $this->expandCriteriaParameters($extraConditions);
$params = array_merge($params, $criteriaParams);
}
if ($filterSql = $this->generateFilterConditionSQL($this->class, $alias)) {
$sql .= ' AND ' . $filterSql;
}
list($params) = $this->expandParameters($criteria);
return (bool) $this->conn->fetchColumn($sql, $params);
}

View File

@ -319,10 +319,10 @@ interface EntityPersister
/**
* Checks whether the given managed entity exists in the database.
*
* @param object $entity
* @param array $extraConditions
* @param object $entity
* @param Criteria|null $extraConditions
*
* @return boolean TRUE if the entity exists in the database, FALSE otherwise.
*/
public function exists($entity, array $extraConditions = array());
public function exists($entity, Criteria $extraConditions = null);
}

View File

@ -19,6 +19,7 @@
namespace Doctrine\ORM\Persisters;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\UnitOfWork;
@ -168,7 +169,7 @@ class OneToManyPersister extends AbstractCollectionPersister
return (bool) $this->conn->fetchColumn($sql, $params);
}
private function getJoinTableRestrictions(PersistentCollection $coll, $addFilters)
{
$mapping = $coll->getMapping();
@ -227,9 +228,9 @@ class OneToManyPersister extends AbstractCollectionPersister
// only works with single id identifier entities. Will throw an
// exception in Entity Persisters if that is not the case for the
// 'mappedBy' field.
$id = current($uow->getEntityIdentifier($coll->getOwner()));
$criteria = new Criteria(Criteria::expr()->eq($mapping['mappedBy'], $coll->getOwner()));
return $persister->exists($element, array($mapping['mappedBy'] => $id));
return $persister->exists($element, $criteria);
}
/**

View File

@ -287,9 +287,13 @@ final class Query extends AbstractQuery
// Prepare parameters
$paramMappings = $this->_parserResult->getParameterMappings();
$paramCount = count($this->parameters);
$mappingCount = count($paramMappings);
if (count($paramMappings) != count($this->parameters)) {
throw QueryException::invalidParameterNumber();
if ($paramCount > $mappingCount) {
throw QueryException::tooManyParameters($mappingCount, $paramCount);
} elseif ($paramCount < $mappingCount) {
throw QueryException::tooFewParameters($mappingCount, $paramCount);
}
// evict all cache for the entity region
@ -682,8 +686,14 @@ final class Query extends AbstractQuery
{
ksort($this->_hints);
$platform = $this->getEntityManager()
->getConnection()
->getDatabasePlatform()
->getName();
return md5(
$this->getDql() . serialize($this->_hints) .
'&platform=' . $platform .
($this->_em->hasFilters() ? $this->_em->getFilters()->getHash() : '') .
'&firstResult=' . $this->_firstResult . '&maxResult=' . $this->_maxResults .
'&hydrationMode='.$this->_hydrationMode.'DOCTRINE_QUERY_CACHE_SALT'

View File

@ -93,11 +93,25 @@ class QueryException extends \Doctrine\ORM\ORMException
}
/**
* @param integer $expected
* @param integer $received
*
* @return QueryException
*/
public static function invalidParameterNumber()
public static function tooManyParameters($expected, $received)
{
return new self("Invalid parameter number: number of bound variables does not match number of tokens");
return new self('Too many parameters: the query defines ' . $expected . ' parameters and you bound ' . $received);
}
/**
* @param integer $expected
* @param integer $received
*
* @return QueryException
*/
public static function tooFewParameters($expected, $received)
{
return new self('Too few parameters: the query defines ' . $expected . ' parameters but you only bound ' . $received);
}
/**

View File

@ -753,12 +753,20 @@ class SqlWalker implements TreeWalker
$owningClass = (isset($assoc['inherited'])) ? $this->em->getClassMetadata($assoc['inherited']) : $class;
$sqlTableAlias = $this->getSQLTableAlias($owningClass->getTableName(), $dqlAlias);
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
$targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
foreach ($assoc['targetToSourceKeyColumns'] as $targetColumn => $srcColumn) {
$columnAlias = $this->getSQLColumnAlias($srcColumn);
$type = null;
$isIdentifier = (isset($assoc['id']) && $assoc['id'] === true);
$sqlSelectExpressions[] = $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias;
$this->rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn, (isset($assoc['id']) && $assoc['id'] === true));
if (isset($targetClass->fieldNames[$targetColumn])) {
$type = $targetClass->fieldMappings[$targetClass->fieldNames[$targetColumn]]['type'];
}
$this->rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn, $isIdentifier, $type);
}
}
@ -1968,7 +1976,7 @@ class SqlWalker implements TreeWalker
$this->parserResult->addParameterMapping($dqlParamKey, $this->sqlParamIndex++);
}
$sqlParts[] = $targetTableAlias . '.' . $targetColumnName . ' = ' . $entitySql;
$sqlParts[] = $targetTableAlias . '.' . $targetColumnName . ' IN (' . $entitySql . ')';
}
$sql .= implode(' AND ', $sqlParts);

View File

@ -134,7 +134,7 @@ class EntityGenerator
/**
* Visibility of the field
*
*
* @var string
*/
protected $fieldVisibility = 'private';
@ -570,7 +570,7 @@ public function __construct()
return 'namespace ' . $this->getNamespace($metadata) .';';
}
}
protected function generateEntityUse()
{
if ($this->generateAnnotations) {
@ -696,9 +696,9 @@ public function __construct()
$inClass = true;
} elseif ($token[0] == T_FUNCTION) {
if ($tokens[$i+2][0] == T_STRING) {
$this->staticReflection[$lastSeenClass]['methods'][] = $tokens[$i+2][1];
$this->staticReflection[$lastSeenClass]['methods'][] = strtolower($tokens[$i+2][1]);
} elseif ($tokens[$i+2] == "&" && $tokens[$i+3][0] == T_STRING) {
$this->staticReflection[$lastSeenClass]['methods'][] = $tokens[$i+3][1];
$this->staticReflection[$lastSeenClass]['methods'][] = strtolower($tokens[$i+3][1]);
}
} elseif (in_array($token[0], array(T_VAR, T_PUBLIC, T_PRIVATE, T_PROTECTED)) && $tokens[$i+2][0] != T_FUNCTION) {
$this->staticReflection[$lastSeenClass]['properties'][] = substr($tokens[$i+2][1], 1);
@ -761,7 +761,7 @@ public function __construct()
return (
isset($this->staticReflection[$metadata->name]) &&
in_array($method, $this->staticReflection[$metadata->name]['methods'])
in_array(strtolower($method), $this->staticReflection[$metadata->name]['methods'])
);
}
@ -1149,14 +1149,16 @@ public function __construct()
protected function generateEntityStubMethod(ClassMetadataInfo $metadata, $type, $fieldName, $typeHint = null, $defaultValue = null)
{
$methodName = $type . Inflector::classify($fieldName);
$variableName = Inflector::camelize($fieldName);
if (in_array($type, array("add", "remove"))) {
$methodName = Inflector::singularize($methodName);
$variableName = Inflector::singularize($variableName);
}
if ($this->hasMethod($methodName, $metadata)) {
return '';
}
$this->staticReflection[$metadata->name]['methods'][] = $methodName;
$this->staticReflection[$metadata->name]['methods'][] = strtolower($methodName);
$var = sprintf('%sMethodTemplate', $type);
$template = static::$$var;
@ -1171,10 +1173,10 @@ public function __construct()
}
$replacements = array(
'<description>' => ucfirst($type) . ' ' . $fieldName,
'<description>' => ucfirst($type) . ' ' . $variableName . ".\n",
'<methodTypeHint>' => $methodTypeHint,
'<variableType>' => $variableType,
'<variableName>' => Inflector::camelize($fieldName),
'<variableName>' => $variableName,
'<methodName>' => $methodName,
'<fieldName>' => $fieldName,
'<variableDefault>' => ($defaultValue !== null ) ? (' = '.$defaultValue) : '',
@ -1445,11 +1447,11 @@ public function __construct()
if (isset($fieldMapping['nullable'])) {
$column[] = 'nullable=' . var_export($fieldMapping['nullable'], true);
}
if (isset($fieldMapping['unsigned']) && $fieldMapping['unsigned']) {
$column[] = 'options={"unsigned"=true}';
}
if (isset($fieldMapping['columnDefinition'])) {
$column[] = 'columnDefinition="' . $fieldMapping['columnDefinition'] . '"';
}
@ -1571,15 +1573,15 @@ public function __construct()
private function exportTableOptions(array $options)
{
$optionsStr = array();
foreach($options as $name => $option) {
if (is_array($option)) {
$optionsStr[] = '"' . $name . '"={' . $this->exportTableOptions($option) . '}';
} else {
$optionsStr[] = '"' . $name . '"="' . (string) $option . '"';
}
}
}
return implode(',', $optionsStr);
}
}

View File

@ -21,6 +21,7 @@ namespace Doctrine\ORM\Tools;
use Doctrine\Common\ClassLoader;
use Doctrine\Common\Cache\Cache;
use Doctrine\Common\Cache\CacheProvider;
use Doctrine\Common\Cache\ArrayCache;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\Mapping\Driver\XmlDriver;
@ -144,7 +145,9 @@ class Setup
$cache = new ArrayCache();
}
$cache->setNamespace("dc2_" . md5($proxyDir) . "_"); // to avoid collisions
if ($cache instanceof CacheProvider) {
$cache->setNamespace("dc2_" . md5($proxyDir) . "_"); // to avoid collisions
}
$config = new Configuration();
$config->setMetadataCacheImpl($cache);

View File

@ -943,12 +943,13 @@ class UnitOfWork implements PropertyChangedListener
}
if ($changeSet) {
$this->entityChangeSets[$oid] = (isset($this->entityChangeSets[$oid]))
? array_merge($this->entityChangeSets[$oid], $changeSet)
: $changeSet;
if (isset($this->entityChangeSets[$oid])) {
$this->entityChangeSets[$oid] = array_merge($this->entityChangeSets[$oid], $changeSet);
} else if ( ! isset($this->entityInsertions[$oid])) {
$this->entityChangeSets[$oid] = $changeSet;
$this->entityUpdates[$oid] = $entity;
}
$this->originalEntityData[$oid] = $actualData;
$this->entityUpdates[$oid] = $entity;
}
}
@ -2405,12 +2406,12 @@ class UnitOfWork implements PropertyChangedListener
}
} else {
$visited = array();
foreach ($this->identityMap as $className => $entities) {
if ($className !== $entityName) {
continue;
}
foreach ($entities as $entity) {
$this->doDetach($entity, $visited, false);
}
@ -2522,7 +2523,7 @@ class UnitOfWork implements PropertyChangedListener
$id = array($class->identifier[0] => $id);
}
$idHash = implode(' ', $id);
if (isset($this->identityMap[$class->rootEntityName][$idHash])) {

View File

@ -86,13 +86,13 @@ class EntityManagerMock extends \Doctrine\ORM\EntityManager
public static function create($conn, \Doctrine\ORM\Configuration $config = null,
\Doctrine\Common\EventManager $eventManager = null)
{
if (is_null($config)) {
if (null === $config) {
$config = new \Doctrine\ORM\Configuration();
$config->setProxyDir(__DIR__ . '/../Proxies');
$config->setProxyNamespace('Doctrine\Tests\Proxies');
$config->setMetadataDriverImpl($config->newDefaultAnnotationDriver(array(), true));
}
if (is_null($eventManager)) {
if (null === $eventManager) {
$eventManager = new \Doctrine\Common\EventManager();
}

View File

@ -1,6 +1,7 @@
<?php
namespace Doctrine\Tests\Mocks;
use Doctrine\Common\Collections\Criteria;
/**
* EntityPersister implementation used for mocking during tests.
@ -88,7 +89,7 @@ class EntityPersisterMock extends \Doctrine\ORM\Persisters\BasicEntityPersister
/**
* {@inheritdoc}
*/
public function exists($entity, array $extraConditions = array())
public function exists($entity, Criteria $extraConditions = null)
{
$this->existsCalled = true;
}

View File

@ -433,8 +433,8 @@ abstract class AbstractEntityPersisterTest extends OrmTestCase
$this->entityPersister->expects($this->once())
->method('exists')
->with($this->equalTo($entity), $this->equalTo(array()));
->with($this->equalTo($entity), $this->equalTo(null));
$this->assertNull($persister->exists($entity, array()));
$this->assertNull($persister->exists($entity));
}
}

View File

@ -21,6 +21,8 @@ namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Tests\Models\Generic\DateTimeModel;
use Doctrine\Common\Collections\Criteria;
use Doctrine\Tests\Models\Tweet\Tweet;
use Doctrine\Tests\Models\Tweet\User;
/**
* @author Josiah <josiah@jjs.id.au>
@ -30,6 +32,7 @@ class EntityRepositoryCriteriaTest extends \Doctrine\Tests\OrmFunctionalTestCase
protected function setUp()
{
$this->useModelSet('generic');
$this->useModelSet('tweet');
parent::setUp();
}
@ -165,4 +168,34 @@ class EntityRepositoryCriteriaTest extends \Doctrine\Tests\OrmFunctionalTestCase
$date = $dates[0];
$this->assertTrue($dates->isInitialized());
}
public function testCanContainsWithoutLoadingCollection()
{
$user = new User();
$user->name = 'Marco';
$this->_em->persist($user);
$this->_em->flush();
$tweet = new Tweet();
$tweet->author = $user;
$tweet->content = 'Criteria is awesome';
$this->_em->persist($tweet);
$this->_em->flush();
$this->_em->clear();
$criteria = new Criteria();
$criteria->andWhere($criteria->expr()->contains('content', 'Criteria'));
$user = $this->_em->find('Doctrine\Tests\Models\Tweet\User', $user->id);
$tweets = $user->tweets->matching($criteria);
$this->assertInstanceOf('Doctrine\ORM\LazyCriteriaCollection', $tweets);
$this->assertFalse($tweets->isInitialized());
$tweets->contains($tweet);
$this->assertTrue($tweets->contains($tweet));
$this->assertFalse($tweets->isInitialized());
}
}

View File

@ -127,11 +127,11 @@ class QueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$user = $q->getSingleResult();
}
public function testMismatchingParamExpectedParamCount()
public function testTooManyParametersShouldThrowException()
{
$this->setExpectedException(
"Doctrine\ORM\Query\QueryException",
"Invalid parameter number: number of bound variables does not match number of tokens"
"Too many parameters: the query defines 1 parameters and you bound 2"
);
$q = $this->_em->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = ?1');
@ -141,6 +141,18 @@ class QueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$user = $q->getSingleResult();
}
public function testTooFewParametersShouldThrowException()
{
$this->setExpectedException(
"Doctrine\ORM\Query\QueryException",
"Too few parameters: the query defines 1 parameters but you only bound 0"
);
$q = $this->_em->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = ?1');
$user = $q->getSingleResult();
}
public function testInvalidInputParameterThrowsException()
{
$this->setExpectedException("Doctrine\ORM\Query\QueryException");

View File

@ -0,0 +1,70 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Tests\Models\CMS\CmsUser;
use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\Events;
use Doctrine\Tests\OrmFunctionalTestCase;
/**
* FlushEventTest
*
* @author robo
*/
class DDC3160Test extends OrmFunctionalTestCase
{
protected function setUp() {
$this->useModelSet('cms');
parent::setUp();
}
/**
* @group DDC-3160
*/
public function testNoUpdateOnInsert()
{
$listener = new DDC3160OnFlushListener();
$this->_em->getEventManager()->addEventListener(Events::onFlush, $listener);
$user = new CmsUser;
$user->username = 'romanb';
$user->name = 'Roman';
$user->status = 'Dev';
$this->_em->persist($user);
$this->_em->flush();
$this->_em->refresh($user);
$this->assertEquals('romanc', $user->username);
$this->assertEquals(1, $listener->inserts);
$this->assertEquals(0, $listener->updates);
}
}
class DDC3160OnFlushListener
{
public $inserts = 0;
public $updates = 0;
public function onFlush(OnFlushEventArgs $args)
{
$em = $args->getEntityManager();
$uow = $em->getUnitOfWork();
foreach ($uow->getScheduledEntityInsertions() as $entity) {
$this->inserts++;
if ($entity instanceof CmsUser) {
$entity->username = 'romanc';
$cm = $em->getClassMetadata(get_class($entity));
$uow->recomputeSingleEntityChangeSet($cm, $entity);
}
}
foreach ($uow->getScheduledEntityUpdates() as $entity) {
$this->updates++;
}
}
}

View File

@ -0,0 +1,110 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\Internal\Hydration\HydrationException;
/**
* @group DDC-2306
*/
class DDC3170Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
/**
* {@inheritDoc}
*/
protected function setup()
{
parent::setup();
$this->_schemaTool->createSchema(
array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC3170AbstractEntityJoined'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC3170ProductJoined'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC3170AbstractEntitySingleTable'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC3170ProductSingleTable'),
)
);
}
/**
* Tests that the discriminator column is correctly read from the meta mappings when fetching a
* child from an inheritance mapped class.
*
* The simple object hydration maps the type field to a field alias like type2. This mapping needs
* to be considered when loading the discriminator column's value from the SQL result.
*
* {@see \Doctrine\ORM\Internal\Hydration\SimpleObjectHydrator::hydrateRowData()}
*/
public function testIssue()
{
// $this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger);
$productJoined = new DDC3170ProductJoined();
$productSingleTable = new DDC3170ProductSingleTable();
$this->_em->persist($productJoined);
$this->_em->persist($productSingleTable);
$this->_em->flush();
$this->_em->clear();
try {
$this->_em->createQueryBuilder()
->select('p')
->from(__NAMESPACE__ . '\\DDC3170ProductJoined', 'p')
->getQuery()
->getResult(AbstractQuery::HYDRATE_SIMPLEOBJECT);
} catch (HydrationException $e) // Thrown by SimpleObjectHydrator
{
$this->fail('Failed correct mapping of discriminator column when using simple object hydration and class table inheritance');
}
try {
$this->_em->createQueryBuilder()
->select('p')
->from(__NAMESPACE__ . '\\DDC3170ProductSingleTable', 'p')
->getQuery()
->getResult(AbstractQuery::HYDRATE_SIMPLEOBJECT);
} catch (HydrationException $e) // Thrown by SimpleObjectHydrator
{
$this->fail('Failed correct mapping of discriminator column when using simple object hydration and single table inheritance');
}
}
}
/**
* @Entity
* @InheritanceType("JOINED")
* @DiscriminatorColumn(name="type", type="string")
* @DiscriminatorMap({"product" = "DDC3170ProductJoined"})
*/
abstract class DDC3170AbstractEntityJoined
{
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
}
/**
* @Entity
*/
class DDC3170ProductJoined extends DDC3170AbstractEntityJoined
{
}
/**
* @Entity
* @InheritanceType("SINGLE_TABLE")
* @DiscriminatorColumn(name="type", type="string")
* @DiscriminatorMap({"product" = "DDC3170ProductSingleTable"})
*/
abstract class DDC3170AbstractEntitySingleTable
{
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
}
/**
* @Entity
*/
class DDC3170ProductSingleTable extends DDC3170AbstractEntitySingleTable
{
}

View File

@ -0,0 +1,168 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\ORM\Query;
/**
* @group DDC-2494
* @group non-cacheable
*/
class DDC3192Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
protected function setUp()
{
parent::setUp();
if (Type::hasType('ddc3192_currency_code')) {
$this->fail(
'Type ddc3192_currency_code exists for testing DDC-3192 only, ' .
'but it has already been registered for some reason'
);
}
Type::addType('ddc3192_currency_code', __NAMESPACE__ . '\DDC3192CurrencyCode');
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(DDC3192Currency::CLASSNAME),
$this->_em->getClassMetadata(DDC3192Transaction::CLASSNAME),
));
}
public function testIssue()
{
$currency = new DDC3192Currency('BYR');
$this->_em->persist($currency);
$this->_em->flush();
$amount = 50;
$transaction = new DDC3192Transaction($amount, $currency);
$this->_em->persist($transaction);
$this->_em->flush();
$this->_em->close();
$resultByPersister = $this->_em->find(DDC3192Transaction::CLASSNAME, $transaction->id);
// This works: DDC2494 makes persister set type mapping info to ResultSetMapping
$this->assertEquals('BYR', $resultByPersister->currency->code);
$this->_em->close();
$query = $this->_em->createQuery();
$query->setDQL('SELECT t FROM ' . DDC3192Transaction::CLASSNAME . ' t WHERE t.id = ?1');
$query->setParameter(1, $transaction->id);
$resultByQuery = $query->getSingleResult();
// This is fixed here: before the fix it used to return 974.
// because unlike the BasicEntityPersister, SQLWalker doesn't set type info
$this->assertEquals('BYR', $resultByQuery->currency->code);
}
}
/**
* @Table(name="ddc3192_currency")
* @Entity
*/
class DDC3192Currency
{
const CLASSNAME = __CLASS__;
/**
* @Id
* @Column(type="ddc3192_currency_code")
*/
public $code;
/**
* @var \Doctrine\Common\Collections\Collection
*
* @OneToMany(targetEntity="DDC3192Transaction", mappedBy="currency")
*/
public $transactions;
public function __construct($code)
{
$this->code = $code;
}
}
/**
* @Table(name="ddc3192_transaction")
* @Entity
*/
class DDC3192Transaction
{
const CLASSNAME = __CLASS__;
/**
* @Id
* @GeneratedValue
* @Column(type="integer")
*/
public $id;
/**
* @var int
*
* @Column(type="integer")
*/
public $amount;
/**
* @var \Doctrine\Tests\ORM\Functional\Ticket\DDC3192Currency
*
* @ManyToOne(targetEntity="DDC3192Currency", inversedBy="transactions")
* @JoinColumn(name="currency_id", referencedColumnName="code", nullable=false)
*/
public $currency;
public function __construct($amount, DDC3192Currency $currency)
{
$this->amount = $amount;
$this->currency = $currency;
}
}
class DDC3192CurrencyCode extends Type
{
private static $map = array(
'BYR' => 974,
);
/**
* {@inheritdoc}
*/
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
return $platform->getSmallIntTypeDeclarationSQL($fieldDeclaration);
}
/**
* {@inheritdoc}
*/
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
return self::$map[$value];
}
/**
* {@inheritdoc}
*/
public function convertToPHPValue($value, AbstractPlatform $platform)
{
return array_search($value, self::$map);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'ddc3192_currency_code';
}
}

View File

@ -160,7 +160,7 @@ class AnnotationDriverTest extends AbstractMappingDriverTest
$factory->setEntityManager($em);
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException',
"Its not supported to define inheritance information on a mapped ".
"It is not supported to define inheritance information on a mapped ".
"superclass 'Doctrine\Tests\ORM\Mapping\MappedSuperClassInheritence'.");
$usingInvalidMsc = $factory->getMetadataFor('Doctrine\Tests\ORM\Mapping\MappedSuperClassInheritence');
}

View File

@ -2,10 +2,9 @@
namespace Doctrine\Tests\ORM\Mapping;
use Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\Mapping\ClassMetadataFactory,
Doctrine\ORM\Mapping\Driver\XmlDriver,
Doctrine\ORM\Mapping\Driver\YamlDriver;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ClassMetadataFactory;
use Doctrine\ORM\Mapping\Driver\XmlDriver;
class XmlMappingDriverTest extends AbstractMappingDriverTest
{
@ -24,9 +23,9 @@ class XmlMappingDriverTest extends AbstractMappingDriverTest
$mappingDriver->loadMetadataForClass($className, $class);
$expectedMap = array(
"foo" => "Doctrine\Tests\ORM\Mapping\CTIFoo",
"bar" => "Doctrine\Tests\ORM\Mapping\CTIBar",
"baz" => "Doctrine\Tests\ORM\Mapping\CTIBaz",
'foo' => 'Doctrine\Tests\ORM\Mapping\CTIFoo',
'bar' => 'Doctrine\Tests\ORM\Mapping\CTIBar',
'baz' => 'Doctrine\Tests\ORM\Mapping\CTIBaz',
);
$this->assertEquals(3, count($class->discriminatorMap));
@ -117,7 +116,7 @@ class XmlMappingDriverTest extends AbstractMappingDriverTest
/**
* @group DDC-889
* @expectedException Doctrine\Common\Persistence\Mapping\MappingException
* @expectedException \Doctrine\Common\Persistence\Mapping\MappingException
* @expectedExceptionMessage Invalid mapping file 'Doctrine.Tests.Models.DDC889.DDC889Class.dcm.xml' for class 'Doctrine\Tests\Models\DDC889\DDC889Class'.
*/
public function testinvalidEntityOrMappedSuperClassShouldMentionParentClasses()

View File

@ -54,7 +54,7 @@
<one-to-one field="address" target-entity="Address" inversed-by="user">
<cascade><cascade-remove /></cascade>
<join-column name="address_id" referenced-column-name="id" on-delete="CASCADE" on-update="CASCADE"/>
<join-column name="address_id" referenced-column-name="id" on-delete="CASCADE" />
</one-to-one>
<one-to-many field="phonenumbers" target-entity="Phonenumber" mapped-by="user" index-by="number" orphan-removal="true">

View File

@ -623,7 +623,24 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
$q->setParameter('param', $group);
$this->assertEquals(
'SELECT c0_.id AS id_0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_users_groups c1_ INNER JOIN cms_groups c2_ ON c1_.group_id = c2_.id WHERE c1_.user_id = c0_.id AND c2_.id = ?)',
'SELECT c0_.id AS id_0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_users_groups c1_ INNER JOIN cms_groups c2_ ON c1_.group_id = c2_.id WHERE c1_.user_id = c0_.id AND c2_.id IN (?))',
$q->getSql()
);
}
public function testSupportsMemberOfExpressionManyToManyParameterArray()
{
$q = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :param MEMBER OF u.groups');
$q->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
$group = new \Doctrine\Tests\Models\CMS\CmsGroup;
$group->id = 101;
$group2 = new \Doctrine\Tests\Models\CMS\CmsGroup;
$group2->id = 105;
$q->setParameter('param', array($group, $group2));
$this->assertEquals(
'SELECT c0_.id AS id_0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_users_groups c1_ INNER JOIN cms_groups c2_ ON c1_.group_id = c2_.id WHERE c1_.user_id = c0_.id AND c2_.id IN (?))',
$q->getSql()
);
}
@ -637,7 +654,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
$this->_em->getClassMetadata(get_class($person))->setIdentifierValues($person, array('id' => 101));
$q->setParameter('param', $person);
$this->assertEquals(
'SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.title AS title_2, c2_.salary AS salary_3, c2_.department AS department_4, c2_.startDate AS startDate_5, c0_.discr AS discr_6, c0_.spouse_id AS spouse_id_7, c1_.car_id AS car_id_8 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id WHERE EXISTS (SELECT 1 FROM company_persons_friends c3_ INNER JOIN company_persons c4_ ON c3_.friend_id = c4_.id WHERE c3_.person_id = c0_.id AND c4_.id = ?)',
'SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.title AS title_2, c2_.salary AS salary_3, c2_.department AS department_4, c2_.startDate AS startDate_5, c0_.discr AS discr_6, c0_.spouse_id AS spouse_id_7, c1_.car_id AS car_id_8 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id WHERE EXISTS (SELECT 1 FROM company_persons_friends c3_ INNER JOIN company_persons c4_ ON c3_.friend_id = c4_.id WHERE c3_.person_id = c0_.id AND c4_.id IN (?))',
$q->getSql()
);
}
@ -648,7 +665,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
$q = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.email MEMBER OF u.groups');
$this->assertEquals(
'SELECT c0_.id AS id_0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_users_groups c1_ INNER JOIN cms_groups c2_ ON c1_.group_id = c2_.id WHERE c1_.user_id = c0_.id AND c2_.id = c0_.email_id)',
'SELECT c0_.id AS id_0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_users_groups c1_ INNER JOIN cms_groups c2_ ON c1_.group_id = c2_.id WHERE c1_.user_id = c0_.id AND c2_.id IN (c0_.email_id))',
$q->getSql()
);
}
@ -659,7 +676,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
$q = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u MEMBER OF u.groups');
$this->assertEquals(
'SELECT c0_.id AS id_0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_users_groups c1_ INNER JOIN cms_groups c2_ ON c1_.group_id = c2_.id WHERE c1_.user_id = c0_.id AND c2_.id = c0_.id)',
'SELECT c0_.id AS id_0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_users_groups c1_ INNER JOIN cms_groups c2_ ON c1_.group_id = c2_.id WHERE c1_.user_id = c0_.id AND c2_.id IN (c0_.id))',
$q->getSql()
);
}

View File

@ -133,6 +133,14 @@ class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase
$book->setName('Jonathan H. Wage');
$this->assertEquals('Jonathan H. Wage', $book->getName());
$reflMethod = new \ReflectionMethod($metadata->name, 'addComment');
$addCommentParameters = $reflMethod->getParameters();
$this->assertEquals('comment', $addCommentParameters[0]->getName());
$reflMethod = new \ReflectionMethod($metadata->name, 'removeComment');
$removeCommentParameters = $reflMethod->getParameters();
$this->assertEquals('comment', $removeCommentParameters[0]->getName());
$author = new EntityGeneratorAuthor();
$book->setAuthor($author);
$this->assertEquals($author, $book->getAuthor());
@ -169,6 +177,30 @@ class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase
$this->assertTrue($reflClass->getMethod('getTest')->isPublic(), "Check for public visibility of method 'getTest' failed.");
}
/**
* @group DDC-3152
*/
public function testDoesNotRegenerateExistingMethodsWithDifferentCase()
{
$metadata = $this->generateBookEntityFixture();
// Workaround to change existing fields case (just to simulate the use case)
$metadata->fieldMappings['status']['fieldName'] = 'STATUS';
// Should not throw a PHP fatal error
$this->_generator->writeEntityClass($metadata, $this->_tmpDir);
$this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/EntityGeneratorBook.php~");
$this->newInstance($metadata);
$reflClass = new \ReflectionClass($metadata->name);
$this->assertTrue($reflClass->hasProperty('status'));
$this->assertTrue($reflClass->hasProperty('STATUS'));
$this->assertTrue($reflClass->hasMethod('getStatus'));
$this->assertTrue($reflClass->hasMethod('setStatus'));
}
/**
* @group DDC-2121
*/

View File

@ -89,4 +89,19 @@ class SetupTest extends \Doctrine\Tests\OrmTestCase
$this->assertSame($cache, $config->getMetadataCacheImpl());
$this->assertSame($cache, $config->getQueryCacheImpl());
}
/**
* @group DDC-3190
*/
public function testConfigureCacheCustomInstance()
{
$cache = $this->getMock('Doctrine\Common\Cache\Cache');
$cache->expects($this->never())->method('setNamespace');
$config = Setup::createConfiguration(array(), true, $cache);
$this->assertSame($cache, $config->getResultCacheImpl());
$this->assertSame($cache, $config->getMetadataCacheImpl());
$this->assertSame($cache, $config->getQueryCacheImpl());
}
}