Merge remote-tracking branch 'upstream/master' into avoid-update-on-delete
This commit is contained in:
commit
ffd858b238
@ -1,6 +1,7 @@
|
||||
# Doctrine 2 ORM
|
||||
|
||||
Master: [![Build Status](https://secure.travis-ci.org/doctrine/doctrine2.png?branch=master)](http://travis-ci.org/doctrine/doctrine2)
|
||||
2.4: [![Build Status](https://secure.travis-ci.org/doctrine/doctrine2.png?branch=2.4)](http://travis-ci.org/doctrine/doctrine2)
|
||||
2.3: [![Build Status](https://secure.travis-ci.org/doctrine/doctrine2.png?branch=2.3)](http://travis-ci.org/doctrine/doctrine2)
|
||||
2.2: [![Build Status](https://secure.travis-ci.org/doctrine/doctrine2.png?branch=2.2)](http://travis-ci.org/doctrine/doctrine2)
|
||||
2.1: [![Build Status](https://secure.travis-ci.org/doctrine/doctrine2.png?branch=2.1.x)](http://travis-ci.org/doctrine/doctrine2)
|
||||
|
@ -67,7 +67,7 @@ Advanced Topics
|
||||
|
||||
* :doc:`Architecture <reference/architecture>`
|
||||
* :doc:`Advanced Configuration <reference/advanced-configuration>`
|
||||
* :doc:`Limitations and knowns issues <reference/limitations-and-known-issues>`
|
||||
* :doc:`Limitations and known issues <reference/limitations-and-known-issues>`
|
||||
* :doc:`Commandline Tools <reference/tools>`
|
||||
* :doc:`Transactions and Concurrency <reference/transactions-and-concurrency>`
|
||||
* :doc:`Filters <reference/filters>`
|
||||
@ -78,6 +78,7 @@ Advanced Topics
|
||||
* :doc:`Change Tracking Policies <reference/change-tracking-policies>`
|
||||
* :doc:`Best Practices <reference/best-practices>`
|
||||
* :doc:`Metadata Drivers <reference/metadata-drivers>`
|
||||
* :doc:`Batch Processing <reference/batch-processing>`
|
||||
|
||||
Tutorials
|
||||
---------
|
||||
|
@ -519,7 +519,7 @@ details of the database join table. If you do not specify
|
||||
@JoinTable on these relations reasonable mapping defaults apply
|
||||
using the affected table and the column names.
|
||||
|
||||
Required attributes:
|
||||
Optional attributes:
|
||||
|
||||
|
||||
- **name**: Database name of the join-table
|
||||
|
@ -70,7 +70,6 @@ looks like this:
|
||||
$em->getConnection()->commit();
|
||||
} catch (Exception $e) {
|
||||
$em->getConnection()->rollback();
|
||||
$em->close();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
@ -81,14 +80,12 @@ require an active transaction. Such methods will throw a
|
||||
``TransactionRequiredException`` to inform you of that
|
||||
requirement.
|
||||
|
||||
A more convenient alternative for explicit transaction demarcation
|
||||
is the use of provided control abstractions in the form of
|
||||
``Connection#transactional($func)`` and
|
||||
``EntityManager#transactional($func)``. When used, these control
|
||||
abstractions ensure that you never forget to rollback the
|
||||
transaction or close the ``EntityManager``, apart from the obvious
|
||||
code reduction. An example that is functionally equivalent to the
|
||||
previously shown code looks as follows:
|
||||
A more convenient alternative for explicit transaction demarcation is the use
|
||||
of provided control abstractions in the form of
|
||||
``Connection#transactional($func)`` and ``EntityManager#transactional($func)``.
|
||||
When used, these control abstractions ensure that you never forget to rollback
|
||||
the transaction, in addition to the obvious code reduction. An example that is
|
||||
functionally equivalent to the previously shown code looks as follows:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@ -104,8 +101,8 @@ previously shown code looks as follows:
|
||||
The difference between ``Connection#transactional($func)`` and
|
||||
``EntityManager#transactional($func)`` is that the latter
|
||||
abstraction flushes the ``EntityManager`` prior to transaction
|
||||
commit and also closes the ``EntityManager`` properly when an
|
||||
exception occurs (in addition to rolling back the transaction).
|
||||
commit and rolls back the transaction when an
|
||||
exception occurs.
|
||||
|
||||
Exception Handling
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
@ -157,7 +157,7 @@ wishes to be hydrated. Default result-types include:
|
||||
- SQL to a single result variable
|
||||
|
||||
Hydration to entities and arrays is one of most complex parts of Doctrine
|
||||
algorithm-wise. It can built results with for example:
|
||||
algorithm-wise. It can build results with for example:
|
||||
|
||||
- Single table selects
|
||||
- Joins with n:1 or 1:n cardinality, grouping belonging to the same parent.
|
||||
|
@ -72,6 +72,7 @@ of several common elements:
|
||||
# Doctrine.Tests.ORM.Mapping.User.dcm.yml
|
||||
Doctrine\Tests\ORM\Mapping\User:
|
||||
type: entity
|
||||
repositoryClass: Doctrine\Tests\ORM\Mapping\UserRepository
|
||||
table: cms_users
|
||||
indexes:
|
||||
name_index:
|
||||
|
@ -381,7 +381,7 @@ better than in a scenario where updates are done for each entity in isolation.
|
||||
|
||||
Doctrine follows the UnitOfWork pattern which additionally detects all entities
|
||||
that were fetched and have changed during the request. You don't have to keep track of
|
||||
entities yourself, when Doctrine already knowns about them.
|
||||
entities yourself, when Doctrine already knows about them.
|
||||
|
||||
As a next step we want to fetch a list of all the products. Let's create a
|
||||
new script for this:
|
||||
|
@ -190,17 +190,14 @@ class ArrayHydrator extends AbstractHydrator
|
||||
( ! isset($baseElement[$relationAlias]))
|
||||
) {
|
||||
$baseElement[$relationAlias] = null;
|
||||
} else if (
|
||||
( ! isset($baseElement[$relationAlias])) ||
|
||||
( ! isset($this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]]))
|
||||
) {
|
||||
} else if ( ! isset($baseElement[$relationAlias])) {
|
||||
$baseElement[$relationAlias] = $data;
|
||||
}
|
||||
}
|
||||
|
||||
$coll =& $baseElement[$relationAlias];
|
||||
|
||||
if ($coll !== null) {
|
||||
if (is_array($coll)) {
|
||||
$this->updateResultPointer($coll, $index, $dqlAlias, $oneToOne);
|
||||
}
|
||||
} else {
|
||||
|
@ -477,7 +477,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$targetClass = $this->ce[$relation['targetEntity']];
|
||||
|
||||
if ($relation['isOwningSide']) {
|
||||
//TODO: Just check hints['fetched'] here?
|
||||
// TODO: Just check hints['fetched'] here?
|
||||
// If there is an inverse mapping on the target class its bidirectional
|
||||
if ($relation['inversedBy']) {
|
||||
$inverseAssoc = $targetClass->associationMappings[$relation['inversedBy']];
|
||||
|
@ -328,7 +328,7 @@ class BasicEntityPersister
|
||||
$identifier = $this->quoteStrategy->getIdentifierColumnNames($versionedClass, $this->platform);
|
||||
$columnName = $this->quoteStrategy->getColumnName($versionField, $versionedClass, $this->platform);
|
||||
|
||||
//FIXME: Order with composite keys might not be correct
|
||||
// FIXME: Order with composite keys might not be correct
|
||||
$sql = 'SELECT ' . $columnName
|
||||
. ' FROM ' . $tableName
|
||||
. ' WHERE ' . implode(' = ? AND ', $identifier) . ' = ?';
|
||||
@ -1976,4 +1976,4 @@ class BasicEntityPersister
|
||||
$sql = implode(' AND ', $filterClauses);
|
||||
return $sql ? "(" . $sql . ")" : ""; // Wrap again to avoid "X or Y and FilterConditionSQL"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ class IdentityFunction extends FunctionNode
|
||||
}
|
||||
}
|
||||
|
||||
//The table with the relation may be a subclass, so get the table name from the association definition
|
||||
// The table with the relation may be a subclass, so get the table name from the association definition
|
||||
$tableName = $sqlWalker->getEntityManager()->getClassMetadata($assoc['sourceEntity'])->getTableName();
|
||||
|
||||
$tableAlias = $sqlWalker->getSQLTableAlias($tableName, $dqlAlias);
|
||||
|
@ -1878,7 +1878,7 @@ class Parser
|
||||
case ($lookahead === Lexer::T_OPEN_PARENTHESIS):
|
||||
return $this->SimpleArithmeticExpression();
|
||||
|
||||
//this check must be done before checking for a filed path expression
|
||||
// this check must be done before checking for a filed path expression
|
||||
case ($this->isFunction()):
|
||||
$this->lexer->peek(); // "("
|
||||
|
||||
@ -1896,7 +1896,7 @@ class Parser
|
||||
}
|
||||
|
||||
break;
|
||||
//it is no function, so it must be a field path
|
||||
// it is no function, so it must be a field path
|
||||
case ($lookahead === Lexer::T_IDENTIFIER):
|
||||
$this->lexer->peek(); // lookahead => '.'
|
||||
$this->lexer->peek(); // lookahead => token after '.'
|
||||
@ -2431,7 +2431,7 @@ class Parser
|
||||
|
||||
switch ($peek['value']) {
|
||||
case '(':
|
||||
//Peeks beyond the matched closing parenthesis.
|
||||
// Peeks beyond the matched closing parenthesis.
|
||||
$token = $this->peekBeyondClosingParenthesis(false);
|
||||
|
||||
if ($token['type'] === Lexer::T_NOT) {
|
||||
|
@ -134,7 +134,7 @@ abstract class AbstractExporter
|
||||
}
|
||||
|
||||
foreach ($this->_metadata as $metadata) {
|
||||
//In case output is returned, write it to a file, skip otherwise
|
||||
// In case output is returned, write it to a file, skip otherwise
|
||||
if($output = $this->exportClassMetadata($metadata)){
|
||||
$path = $this->_generateOutputPath($metadata);
|
||||
$dir = dirname($path);
|
||||
|
@ -166,7 +166,7 @@ class LimitSubqueryOutputWalker extends SqlWalker
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -215,7 +215,7 @@ class LimitSubqueryOutputWalker extends SqlWalker
|
||||
}
|
||||
}
|
||||
}
|
||||
//remove identifier aliases
|
||||
// remove identifier aliases
|
||||
$sqlOrderColumns = array_diff($sqlOrderColumns, $sqlIdentifier);
|
||||
}
|
||||
|
||||
|
@ -2406,7 +2406,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
{
|
||||
$coid = spl_object_hash($coll);
|
||||
|
||||
//TODO: if $coll is already scheduled for recreation ... what to do?
|
||||
// TODO: if $coll is already scheduled for recreation ... what to do?
|
||||
// Just remove $coll from the scheduled recreations?
|
||||
if (isset($this->collectionUpdates[$coid])) {
|
||||
unset($this->collectionUpdates[$coid]);
|
||||
|
@ -85,4 +85,9 @@ class DriverMock implements \Doctrine\DBAL\Driver
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public function convertExceptionCode(\Exception $exception)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
121
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2759Test.php
Normal file
121
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2759Test.php
Normal file
@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
/**
|
||||
* @group DDC-2759
|
||||
*/
|
||||
class DDC2759Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function setup()
|
||||
{
|
||||
parent::setup();
|
||||
|
||||
try {
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2759Qualification'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2759Category'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2759QualificationMetadata'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2759MetadataCategory'),
|
||||
));
|
||||
} catch(\Exception $e) {
|
||||
return;
|
||||
}
|
||||
|
||||
$qualification = new DDC2759Qualification();
|
||||
$qualificationMetadata = new DDC2759QualificationMetadata($qualification);
|
||||
|
||||
$category1 = new DDC2759Category();
|
||||
$category2 = new DDC2759Category();
|
||||
|
||||
$metadataCategory1 = new DDC2759MetadataCategory($qualificationMetadata, $category1);
|
||||
$metadataCategory2 = new DDC2759MetadataCategory($qualificationMetadata, $category2);
|
||||
|
||||
$this->_em->persist($qualification);
|
||||
$this->_em->persist($qualificationMetadata);
|
||||
|
||||
$this->_em->persist($category1);
|
||||
$this->_em->persist($category2);
|
||||
|
||||
$this->_em->persist($metadataCategory1);
|
||||
$this->_em->persist($metadataCategory2);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
}
|
||||
|
||||
public function testCorrectNumberOfAssociationsIsReturned()
|
||||
{
|
||||
$repository = $this->_em->getRepository(__NAMESPACE__ . '\DDC2759Qualification');
|
||||
|
||||
$builder = $repository->createQueryBuilder('q')
|
||||
->select('q, qm, qmc')
|
||||
->innerJoin('q.metadata', 'qm')
|
||||
->innerJoin('qm.metadataCategories', 'qmc');
|
||||
|
||||
$result = $builder->getQuery()
|
||||
->getArrayResult();
|
||||
|
||||
$this->assertCount(2, $result[0]['metadata']['metadataCategories']);
|
||||
}
|
||||
}
|
||||
|
||||
/** @Entity @Table(name="ddc_2759_qualification") */
|
||||
class DDC2759Qualification
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
|
||||
/** @OneToOne(targetEntity="DDC2759QualificationMetadata", mappedBy="content") */
|
||||
public $metadata;
|
||||
}
|
||||
|
||||
/** @Entity @Table(name="ddc_2759_category") */
|
||||
class DDC2759Category
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
|
||||
/** @OneToMany(targetEntity="DDC2759MetadataCategory", mappedBy="category") */
|
||||
public $metadataCategories;
|
||||
}
|
||||
|
||||
/** @Entity @Table(name="ddc_2759_qualification_metadata") */
|
||||
class DDC2759QualificationMetadata
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
|
||||
/** @OneToOne(targetEntity="DDC2759Qualification", inversedBy="metadata") */
|
||||
public $content;
|
||||
|
||||
/** @OneToMany(targetEntity="DDC2759MetadataCategory", mappedBy="metadata") */
|
||||
protected $metadataCategories;
|
||||
|
||||
public function __construct(DDC2759Qualification $content)
|
||||
{
|
||||
$this->content = $content;
|
||||
}
|
||||
}
|
||||
|
||||
/** @Entity @Table(name="ddc_2759_metadata_category") */
|
||||
class DDC2759MetadataCategory
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
|
||||
/** @ManyToOne(targetEntity="DDC2759QualificationMetadata", inversedBy="metadataCategories") */
|
||||
public $metadata;
|
||||
|
||||
/** @ManyToOne(targetEntity="DDC2759Category", inversedBy="metadataCategories") */
|
||||
public $category;
|
||||
|
||||
public function __construct(DDC2759QualificationMetadata $metadata, DDC2759Category $category)
|
||||
{
|
||||
$this->metadata = $metadata;
|
||||
$this->category = $category;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user