mirror of
https://github.com/doctrine/orm.git
synced 2026-03-24 15:02:22 +01:00
Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
418587bc25 | ||
|
|
3d46e07887 | ||
|
|
51bc596502 | ||
|
|
95f1b48422 | ||
|
|
f7d8b155db | ||
|
|
539ffea390 | ||
|
|
4bfc84f035 | ||
|
|
53dc5b2ac3 | ||
|
|
f1219f1418 | ||
|
|
072066f746 | ||
|
|
f1365b78d5 | ||
|
|
60cd524443 | ||
|
|
045d1f3bf2 | ||
|
|
1ae6f18fe9 | ||
|
|
91b9dd90f4 | ||
|
|
505d658e3d | ||
|
|
bee8decd18 | ||
|
|
6bce7e9cab | ||
|
|
4d8418fe6f | ||
|
|
850d57e791 | ||
|
|
c3dd71704b | ||
|
|
0b305e5bd3 | ||
|
|
061207861b | ||
|
|
3c91792dd8 | ||
|
|
431d0a3c5e | ||
|
|
1da002ca2f | ||
|
|
ef639d4de6 | ||
|
|
31f4dd671a | ||
|
|
60c4867ed3 | ||
|
|
0ee1716b26 | ||
|
|
a236a83fa8 | ||
|
|
37f1bd7606 | ||
|
|
af4cb282ba | ||
|
|
ce4914ba0e | ||
|
|
bdfd6c1677 | ||
|
|
8e0157d97d | ||
|
|
1767f4b8e7 | ||
|
|
ca95b0ee13 | ||
|
|
4aa09861dd | ||
|
|
24e9a7caaf | ||
|
|
d90df59118 | ||
|
|
f9103a7b41 | ||
|
|
9891477094 | ||
|
|
59e3a55110 |
1
.github/workflows/continuous-integration.yml
vendored
1
.github/workflows/continuous-integration.yml
vendored
@@ -18,6 +18,7 @@ jobs:
|
||||
- "7.2"
|
||||
- "7.3"
|
||||
- "7.4"
|
||||
- "8.0"
|
||||
deps:
|
||||
- "normal"
|
||||
include:
|
||||
|
||||
16
README.md
16
README.md
@@ -1,7 +1,7 @@
|
||||
| [Master][Master] | [2.7][2.7] |
|
||||
| [Master][Master] | [2.8.x][2.8] |
|
||||
|:----------------:|:----------:|
|
||||
| [![Build status][Master image]][Master] | [![Build status][2.7 image]][2.7] |
|
||||
| [![Coverage Status][Master coverage image]][Master coverage] | [![Coverage Status][2.7 coverage image]][2.7 coverage] |
|
||||
| [![Build status][Master image]][Master] | [![Build status][2.8 image]][2.8] |
|
||||
| [![Coverage Status][Master coverage image]][Master coverage] | [![Coverage Status][2.8 coverage image]][2.8 coverage] |
|
||||
|
||||
Doctrine 2 is an object-relational mapper (ORM) for PHP 7.1+ that provides transparent persistence
|
||||
for PHP objects. It sits on top of a powerful database abstraction layer (DBAL). One of its key features
|
||||
@@ -13,14 +13,14 @@ without requiring unnecessary code duplication.
|
||||
## More resources:
|
||||
|
||||
* [Website](http://www.doctrine-project.org)
|
||||
* [Documentation](http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/index.html)
|
||||
* [Documentation](https://www.doctrine-project.org/projects/doctrine-orm/en/latest/index.html)
|
||||
|
||||
|
||||
[Master image]: https://img.shields.io/travis/doctrine/orm/master.svg?style=flat-square
|
||||
[Master]: https://travis-ci.org/doctrine/orm
|
||||
[Master coverage image]: https://codecov.io/gh/doctrine/orm/branch/master/graph/badge.svg
|
||||
[Master coverage]: https://codecov.io/gh/doctrine/orm/branch/master
|
||||
[2.7 image]: https://img.shields.io/travis/doctrine/orm/2.7.svg?style=flat-square
|
||||
[2.7]: https://github.com/doctrine/orm/tree/2.7
|
||||
[2.7 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.7/graph/badge.svg
|
||||
[2.7 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.7
|
||||
[2.8 image]: https://img.shields.io/travis/doctrine/orm/2.8.svg?style=flat-square
|
||||
[2.8]: https://github.com/doctrine/orm/tree/2.8
|
||||
[2.8 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.8/graph/badge.svg
|
||||
[2.8 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.8
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
# Upgrade to 2.8
|
||||
|
||||
## Minor BC BREAK: Failed commit now throw OptimisticLockException
|
||||
|
||||
Method `Doctrine\ORM\UnitOfWork#commit()` can throw an OptimisticLockException when a commit silently fails and returns false
|
||||
since `Doctrine\DBAL\Connection#commit()` signature changed from returning void to boolean
|
||||
|
||||
# Upgrade to 2.7
|
||||
|
||||
## Added `Doctrine\ORM\AbstractQuery#enableResultCache()` and `Doctrine\ORM\AbstractQuery#disableResultCache()` methods
|
||||
@@ -30,7 +37,7 @@ Method `Doctrine\ORM\AbstractQuery#useResultCache()` is deprecated because it is
|
||||
and `disableResultCache()`. It will be removed in 3.0.
|
||||
|
||||
## Deprecated code generators and related console commands
|
||||
|
||||
|
||||
These console commands have been deprecated:
|
||||
|
||||
* `orm:convert-mapping`
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
beStrictAboutTodoAnnotatedTests="true"
|
||||
failOnRisky="true"
|
||||
failOnWarning="true"
|
||||
>
|
||||
<php>
|
||||
<var name="db_driver" value="mysqli"/>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
beStrictAboutTodoAnnotatedTests="true"
|
||||
failOnRisky="true"
|
||||
failOnWarning="true"
|
||||
>
|
||||
<php>
|
||||
<var name="db_driver" value="pdo_mysql"/>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
beStrictAboutTodoAnnotatedTests="true"
|
||||
failOnRisky="true"
|
||||
failOnWarning="true"
|
||||
>
|
||||
<php>
|
||||
<var name="db_driver" value="pdo_pgsql"/>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
beStrictAboutTodoAnnotatedTests="true"
|
||||
failOnRisky="true"
|
||||
failOnWarning="true"
|
||||
>
|
||||
<php>
|
||||
<!-- necessary change for some CLI/console output test assertions -->
|
||||
|
||||
@@ -16,27 +16,27 @@
|
||||
"sort-packages": true
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1",
|
||||
"php": "^7.2|^8.0",
|
||||
"ext-pdo": "*",
|
||||
"composer/package-versions-deprecated": "^1.8",
|
||||
"doctrine/annotations": "^1.11.1",
|
||||
"doctrine/cache": "^1.9.1",
|
||||
"doctrine/collections": "^1.5",
|
||||
"doctrine/common": "^2.11 || ^3.0",
|
||||
"doctrine/dbal": "^2.9.3",
|
||||
"doctrine/common": "^3.0",
|
||||
"doctrine/dbal": "^2.10.0",
|
||||
"doctrine/event-manager": "^1.1",
|
||||
"doctrine/inflector": "^1.0",
|
||||
"doctrine/inflector": "^1.4|^2.0",
|
||||
"doctrine/instantiator": "^1.3",
|
||||
"doctrine/lexer": "^1.0",
|
||||
"doctrine/persistence": "^1.3.3 || ^2.0",
|
||||
"doctrine/persistence": "^2.0",
|
||||
"symfony/console": "^3.0|^4.0|^5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^6.0",
|
||||
"doctrine/coding-standard": "^8.0",
|
||||
"phpstan/phpstan": "^0.12.18",
|
||||
"phpunit/phpunit": "^8.0",
|
||||
"phpunit/phpunit": "^8.5|^9.4",
|
||||
"symfony/yaml": "^3.4|^4.0|^5.0",
|
||||
"vimeo/psalm": "^3.11"
|
||||
"vimeo/psalm": "4.1.1"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/yaml": "If you want to use YAML Metadata Mapping Driver"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
The Doctrine2 documentation is licensed under [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US)
|
||||
The Doctrine ORM documentation is licensed under [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US)
|
||||
|
||||
Creative Commons Legal Code
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Aggregate Fields
|
||||
You will often come across the requirement to display aggregate
|
||||
values of data that can be computed by using the MIN, MAX, COUNT or
|
||||
SUM SQL functions. For any ORM this is a tricky issue
|
||||
traditionally. Doctrine 2 offers several ways to get access to
|
||||
traditionally. Doctrine ORM offers several ways to get access to
|
||||
these values and this article will describe all of them from
|
||||
different perspectives.
|
||||
|
||||
|
||||
@@ -3,45 +3,45 @@ Persisting the Decorator Pattern
|
||||
|
||||
.. sectionauthor:: Chris Woodford <chris.woodford@gmail.com>
|
||||
|
||||
This recipe will show you a simple example of how you can use
|
||||
Doctrine 2 to persist an implementation of the
|
||||
This recipe will show you a simple example of how you can use
|
||||
Doctrine ORM to persist an implementation of the
|
||||
`Decorator Pattern <http://en.wikipedia.org/wiki/Decorator_pattern>`_
|
||||
|
||||
Component
|
||||
---------
|
||||
|
||||
The ``Component`` class needs to be persisted, so it's going to
|
||||
be an ``Entity``. As the top of the inheritance hierarchy, it's going
|
||||
to have to define the persistent inheritance. For this example, we
|
||||
will use Single Table Inheritance, but Class Table Inheritance
|
||||
would work as well. In the discriminator map, we will define two
|
||||
concrete subclasses, ``ConcreteComponent`` and ``ConcreteDecorator``.
|
||||
The ``Component`` class needs to be persisted, so it's going to
|
||||
be an ``Entity``. As the top of the inheritance hierarchy, it's going
|
||||
to have to define the persistent inheritance. For this example, we
|
||||
will use Single Table Inheritance, but Class Table Inheritance
|
||||
would work as well. In the discriminator map, we will define two
|
||||
concrete subclasses, ``ConcreteComponent`` and ``ConcreteDecorator``.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
|
||||
namespace Test;
|
||||
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @InheritanceType("SINGLE_TABLE")
|
||||
* @DiscriminatorColumn(name="discr", type="string")
|
||||
* @DiscriminatorMap({"cc" = "Test\Component\ConcreteComponent",
|
||||
* @DiscriminatorMap({"cc" = "Test\Component\ConcreteComponent",
|
||||
"cd" = "Test\Decorator\ConcreteDecorator"})
|
||||
*/
|
||||
abstract class Component
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @Id @Column(type="integer")
|
||||
* @GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
|
||||
/** @Column(type="string", nullable=true) */
|
||||
protected $name;
|
||||
|
||||
|
||||
/**
|
||||
* Get id
|
||||
* @return integer $id
|
||||
@@ -50,7 +50,7 @@ concrete subclasses, ``ConcreteComponent`` and ``ConcreteDecorator``.
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set name
|
||||
* @param string $name
|
||||
@@ -59,7 +59,7 @@ concrete subclasses, ``ConcreteComponent`` and ``ConcreteDecorator``.
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get name
|
||||
* @return string $name
|
||||
@@ -68,33 +68,33 @@ concrete subclasses, ``ConcreteComponent`` and ``ConcreteDecorator``.
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
ConcreteComponent
|
||||
-----------------
|
||||
|
||||
The ``ConcreteComponent`` class is pretty simple and doesn't do much
|
||||
more than extend the abstract ``Component`` class (only for the
|
||||
The ``ConcreteComponent`` class is pretty simple and doesn't do much
|
||||
more than extend the abstract ``Component`` class (only for the
|
||||
purpose of keeping this example simple).
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
|
||||
namespace Test\Component;
|
||||
|
||||
|
||||
use Test\Component;
|
||||
|
||||
|
||||
/** @Entity */
|
||||
class ConcreteComponent extends Component
|
||||
{}
|
||||
|
||||
|
||||
Decorator
|
||||
---------
|
||||
|
||||
The ``Decorator`` class doesn't need to be persisted, but it does
|
||||
need to define an association with a persisted ``Entity``. We can
|
||||
The ``Decorator`` class doesn't need to be persisted, but it does
|
||||
need to define an association with a persisted ``Entity``. We can
|
||||
use a ``MappedSuperclass`` for this.
|
||||
|
||||
.. code-block:: php
|
||||
@@ -102,17 +102,17 @@ use a ``MappedSuperclass`` for this.
|
||||
<?php
|
||||
|
||||
namespace Test;
|
||||
|
||||
|
||||
/** @MappedSuperclass */
|
||||
abstract class Decorator extends Component
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @OneToOne(targetEntity="Test\Component", cascade={"all"})
|
||||
* @JoinColumn(name="decorates", referencedColumnName="id")
|
||||
*/
|
||||
protected $decorates;
|
||||
|
||||
|
||||
/**
|
||||
* initialize the decorator
|
||||
* @param Component $c
|
||||
@@ -121,7 +121,7 @@ use a ``MappedSuperclass`` for this.
|
||||
{
|
||||
$this->setDecorates($c);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* (non-PHPdoc)
|
||||
* @see Test.Component::getName()
|
||||
@@ -130,7 +130,7 @@ use a ``MappedSuperclass`` for this.
|
||||
{
|
||||
return 'Decorated ' . $this->getDecorates()->getName();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* the component being decorated
|
||||
* @return Component
|
||||
@@ -139,7 +139,7 @@ use a ``MappedSuperclass`` for this.
|
||||
{
|
||||
return $this->decorates;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* sets the component being decorated
|
||||
* @param Component $c
|
||||
@@ -148,52 +148,52 @@ use a ``MappedSuperclass`` for this.
|
||||
{
|
||||
$this->decorates = $c;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
All operations on the ``Decorator`` (i.e. persist, remove, etc) will
|
||||
cascade from the ``Decorator`` to the ``Component``. This means that
|
||||
when we persist a ``Decorator``, Doctrine will take care of
|
||||
persisting the chain of decorated objects for us. A ``Decorator`` can
|
||||
be treated exactly as a ``Component`` when it comes time to
|
||||
All operations on the ``Decorator`` (i.e. persist, remove, etc) will
|
||||
cascade from the ``Decorator`` to the ``Component``. This means that
|
||||
when we persist a ``Decorator``, Doctrine will take care of
|
||||
persisting the chain of decorated objects for us. A ``Decorator`` can
|
||||
be treated exactly as a ``Component`` when it comes time to
|
||||
persisting it.
|
||||
|
||||
The ``Decorator's`` constructor accepts an instance of a
|
||||
``Component``, as defined by the ``Decorator`` pattern. The
|
||||
setDecorates/getDecorates methods have been defined as protected to
|
||||
hide the fact that a ``Decorator`` is decorating a ``Component`` and
|
||||
keeps the ``Component`` interface and the ``Decorator`` interface
|
||||
|
||||
The ``Decorator's`` constructor accepts an instance of a
|
||||
``Component``, as defined by the ``Decorator`` pattern. The
|
||||
setDecorates/getDecorates methods have been defined as protected to
|
||||
hide the fact that a ``Decorator`` is decorating a ``Component`` and
|
||||
keeps the ``Component`` interface and the ``Decorator`` interface
|
||||
identical.
|
||||
|
||||
To illustrate the intended result of the ``Decorator`` pattern, the
|
||||
getName() method has been overridden to append a string to the
|
||||
To illustrate the intended result of the ``Decorator`` pattern, the
|
||||
getName() method has been overridden to append a string to the
|
||||
``Component's`` getName() method.
|
||||
|
||||
ConcreteDecorator
|
||||
-----------------
|
||||
|
||||
The final class required to complete a simple implementation of the
|
||||
Decorator pattern is the ``ConcreteDecorator``. In order to further
|
||||
illustrate how the ``Decorator`` can alter data as it moves through
|
||||
the chain of decoration, a new field, "special", has been added to
|
||||
this class. The getName() has been overridden and appends the value
|
||||
of the getSpecial() method to its return value.
|
||||
The final class required to complete a simple implementation of the
|
||||
Decorator pattern is the ``ConcreteDecorator``. In order to further
|
||||
illustrate how the ``Decorator`` can alter data as it moves through
|
||||
the chain of decoration, a new field, "special", has been added to
|
||||
this class. The getName() has been overridden and appends the value
|
||||
of the getSpecial() method to its return value.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
|
||||
namespace Test\Decorator;
|
||||
|
||||
|
||||
use Test\Decorator;
|
||||
|
||||
|
||||
/** @Entity */
|
||||
class ConcreteDecorator extends Decorator
|
||||
{
|
||||
|
||||
|
||||
/** @Column(type="string", nullable=true) */
|
||||
protected $special;
|
||||
|
||||
|
||||
/**
|
||||
* Set special
|
||||
* @param string $special
|
||||
@@ -202,7 +202,7 @@ of the getSpecial() method to its return value.
|
||||
{
|
||||
$this->special = $special;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get special
|
||||
* @return string $special
|
||||
@@ -211,7 +211,7 @@ of the getSpecial() method to its return value.
|
||||
{
|
||||
return $this->special;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* (non-PHPdoc)
|
||||
* @see Test.Component::getName()
|
||||
@@ -219,55 +219,55 @@ of the getSpecial() method to its return value.
|
||||
public function getName()
|
||||
{
|
||||
return '[' . $this->getSpecial()
|
||||
. '] ' . parent::getName();
|
||||
. '] ' . parent::getName();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Here is an example of how to persist and retrieve your decorated
|
||||
Here is an example of how to persist and retrieve your decorated
|
||||
objects
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
|
||||
use Test\Component\ConcreteComponent,
|
||||
Test\Decorator\ConcreteDecorator;
|
||||
|
||||
// assumes Doctrine 2 is configured and an instance of
|
||||
|
||||
// assumes Doctrine ORM is configured and an instance of
|
||||
// an EntityManager is available as $em
|
||||
|
||||
|
||||
// create a new concrete component
|
||||
$c = new ConcreteComponent();
|
||||
$c->setName('Test Component 1');
|
||||
$em->persist($c); // assigned unique ID = 1
|
||||
|
||||
|
||||
// create a new concrete decorator
|
||||
$c = new ConcreteComponent();
|
||||
$c->setName('Test Component 2');
|
||||
|
||||
|
||||
$d = new ConcreteDecorator($c);
|
||||
$d->setSpecial('Really');
|
||||
$em->persist($d);
|
||||
$em->persist($d);
|
||||
// assigns c as unique ID = 2, and d as unique ID = 3
|
||||
|
||||
|
||||
$em->flush();
|
||||
|
||||
$c = $em->find('Test\Component', 1);
|
||||
$d = $em->find('Test\Component', 3);
|
||||
|
||||
|
||||
echo get_class($c);
|
||||
// prints: Test\Component\ConcreteComponent
|
||||
|
||||
|
||||
echo $c->getName();
|
||||
// prints: Test Component 1
|
||||
|
||||
echo get_class($d)
|
||||
// prints: Test Component 1
|
||||
|
||||
echo get_class($d)
|
||||
// prints: Test\Component\ConcreteDecorator
|
||||
|
||||
|
||||
echo $d->getName();
|
||||
// prints: [Really] Decorated Test Component 2
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Extending DQL in Doctrine 2: Custom AST Walkers
|
||||
Extending DQL in Doctrine ORM: Custom AST Walkers
|
||||
===============================================
|
||||
|
||||
.. sectionauthor:: Benjamin Eberlei <kontakt@beberlei.de>
|
||||
@@ -12,7 +12,7 @@ the Doctrine ORM.
|
||||
|
||||
In Doctrine 1 the DQL language was not implemented using a real
|
||||
parser. This made modifications of the DQL by the user impossible.
|
||||
Doctrine 2 in contrast has a real parser for the DQL language,
|
||||
Doctrine ORM in contrast has a real parser for the DQL language,
|
||||
which transforms the DQL statement into an
|
||||
`Abstract Syntax Tree <http://en.wikipedia.org/wiki/Abstract_syntax_tree>`_
|
||||
and generates the appropriate SQL statement for it. Since this
|
||||
|
||||
@@ -10,7 +10,7 @@ change it during the life of your project. This decision for a
|
||||
specific vendor potentially allows you to make use of powerful SQL
|
||||
features that are unique to the vendor.
|
||||
|
||||
It is worth to mention that Doctrine 2 also allows you to handwrite
|
||||
It is worth to mention that Doctrine ORM also allows you to handwrite
|
||||
your SQL instead of extending the DQL parser. Extending DQL is sort of an
|
||||
advanced extension point. You can map arbitrary SQL to your objects
|
||||
and gain access to vendor specific functionalities using the
|
||||
@@ -240,7 +240,7 @@ functionalities in DQL, we would be excited to see user extensions
|
||||
that add vendor specific function packages, for example more math
|
||||
functions, XML + GIS Support, Hashing functions and so on.
|
||||
|
||||
For 2.0 we will come with the current set of functions, however for
|
||||
For ORM we will come with the current set of functions, however for
|
||||
a future version we will re-evaluate if we can abstract even more
|
||||
vendor sql functions and extend the DQL languages scope.
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Mysql Enums
|
||||
===========
|
||||
|
||||
The type system of Doctrine 2 consists of flyweights, which means there is only
|
||||
The type system of Doctrine ORM consists of flyweights, which means there is only
|
||||
one instance of any given type. Additionally types do not contain state. Both
|
||||
assumptions make it rather complicated to work with the Enum Type of MySQL that
|
||||
is used quite a lot by developers.
|
||||
|
||||
When using Enums with a non-tweaked Doctrine 2 application you will get
|
||||
When using Enums with a non-tweaked Doctrine ORM application you will get
|
||||
errors from the Schema-Tool commands due to the unknown database type "enum".
|
||||
By default Doctrine does not map the MySQL enum type to a Doctrine type.
|
||||
This is because Enums contain state (their allowed values) and Doctrine
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
Keeping your Modules independent
|
||||
=================================
|
||||
|
||||
.. versionadded:: 2.2
|
||||
|
||||
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.
|
||||
|
||||
Doctrine 2.2 includes a new utility called the ``ResolveTargetEntityListener``,
|
||||
Doctrine ORM includes a new utility called the ``ResolveTargetEntityListener``,
|
||||
that functions by intercepting certain calls inside Doctrine and rewrite
|
||||
targetEntity parameters in your metadata mapping at runtime. It means that
|
||||
in your bundle you are able to use an interface or abstract class in your
|
||||
|
||||
@@ -30,7 +30,7 @@ highly uncomfortable because of the following:
|
||||
every panel-type? This wouldn't be flexible. You might be tempted
|
||||
to add an AbstractPanelEntity and an AbstractBlockEntity that use
|
||||
class inheritance. Your page could then only confer to the
|
||||
AbstractPanelType and Doctrine 2 would do the rest for you, i.e.
|
||||
AbstractPanelType and Doctrine ORM would do the rest for you, i.e.
|
||||
load the right entities. But - you'll for sure have lots of panels
|
||||
and blocks, and even worse, you'd have to edit the discriminator
|
||||
map *manually* every time you or another developer implements a new
|
||||
@@ -152,7 +152,7 @@ As you can see, we have a method "setBlockEntity" which ties a potential strateg
|
||||
|
||||
/**
|
||||
* This var contains the classname of the strategy
|
||||
* that is used for this blockitem. (This string (!) value will be persisted by Doctrine 2)
|
||||
* that is used for this blockitem. (This string (!) value will be persisted by Doctrine ORM)
|
||||
*
|
||||
* This is a doctrine field, so make sure that you use an @column annotation or setup your
|
||||
* yaml or xml files correctly
|
||||
@@ -161,7 +161,7 @@ As you can see, we have a method "setBlockEntity" which ties a potential strateg
|
||||
protected $strategyClassName;
|
||||
|
||||
/**
|
||||
* This var contains an instance of $this->blockStrategy. Will not be persisted by Doctrine 2.
|
||||
* This var contains an instance of $this->blockStrategy. Will not be persisted by Doctrine ORM.
|
||||
*
|
||||
* @var BlockStrategyInterface
|
||||
*/
|
||||
@@ -199,7 +199,7 @@ As you can see, we have a method "setBlockEntity" which ties a potential strateg
|
||||
$strategy->setBlockEntity($this);
|
||||
}
|
||||
|
||||
Now, the important point is that $strategyClassName is a Doctrine 2
|
||||
Now, the important point is that $strategyClassName is a Doctrine ORM
|
||||
field, i.e. Doctrine will persist this value. This is only the
|
||||
class name of your strategy and not an instance!
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ Validation of Entities
|
||||
|
||||
.. sectionauthor:: Benjamin Eberlei <kontakt@beberlei.de>
|
||||
|
||||
Doctrine 2 does not ship with any internal validators, the reason
|
||||
Doctrine ORM does not ship with any internal validators, the reason
|
||||
being that we think all the frameworks out there already ship with
|
||||
quite decent ones that can be integrated into your Domain easily.
|
||||
What we offer are hooks to execute any kind of validation.
|
||||
|
||||
@@ -3,7 +3,7 @@ Working with DateTime Instances
|
||||
|
||||
There are many nitty gritty details when working with PHPs DateTime instances. You have to know their inner
|
||||
workings pretty well not to make mistakes with date handling. This cookbook entry holds several
|
||||
interesting pieces of information on how to work with PHP DateTime instances in Doctrine 2.
|
||||
interesting pieces of information on how to work with PHP DateTime instances in ORM.
|
||||
|
||||
DateTime changes are detected by Reference
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -58,7 +58,7 @@ Handling different Timezones with the DateTime Type
|
||||
|
||||
If you first come across the requirement to save different timezones you may be still optimistic about how
|
||||
to manage this mess,
|
||||
however let me crush your expectations fast. There is not a single database out there (supported by Doctrine 2)
|
||||
however let me crush your expectations fast. There is not a single database out there (supported by Doctrine ORM)
|
||||
that supports timezones correctly. Correctly here means that you can cover all the use-cases that
|
||||
can come up with timezones. If you don't believe me you should read up on `Storing DateTime
|
||||
in Databases <http://derickrethans.nl/storing-date-time-in-database.html>`_.
|
||||
@@ -67,7 +67,7 @@ The problem is simple. Not a single database vendor saves the timezone, only the
|
||||
However with frequent daylight saving and political timezone changes you can have a UTC offset that moves
|
||||
in different offset directions depending on the real location.
|
||||
|
||||
The solution for this dilemma is simple. Don't use timezones with DateTime and Doctrine 2. However there is a workaround
|
||||
The solution for this dilemma is simple. Don't use timezones with DateTime and Doctrine ORM. However there is a workaround
|
||||
that even allows correct date-time handling with timezones:
|
||||
|
||||
1. Always convert any DateTime instance to UTC.
|
||||
|
||||
@@ -11,15 +11,15 @@ steps of configuration.
|
||||
<?php
|
||||
use Doctrine\ORM\EntityManager,
|
||||
Doctrine\ORM\Configuration;
|
||||
|
||||
|
||||
// ...
|
||||
|
||||
|
||||
if ($applicationMode == "development") {
|
||||
$cache = new \Doctrine\Common\Cache\ArrayCache;
|
||||
} else {
|
||||
$cache = new \Doctrine\Common\Cache\ApcCache;
|
||||
}
|
||||
|
||||
|
||||
$config = new Configuration;
|
||||
$config->setMetadataCacheImpl($cache);
|
||||
$driverImpl = $config->newDefaultAnnotationDriver('/path/to/lib/MyProject/Entities');
|
||||
@@ -27,18 +27,18 @@ steps of configuration.
|
||||
$config->setQueryCacheImpl($cache);
|
||||
$config->setProxyDir('/path/to/myproject/lib/MyProject/Proxies');
|
||||
$config->setProxyNamespace('MyProject\Proxies');
|
||||
|
||||
|
||||
if ($applicationMode == "development") {
|
||||
$config->setAutoGenerateProxyClasses(true);
|
||||
} else {
|
||||
$config->setAutoGenerateProxyClasses(false);
|
||||
}
|
||||
|
||||
|
||||
$connectionOptions = array(
|
||||
'driver' => 'pdo_sqlite',
|
||||
'path' => 'database.sqlite'
|
||||
);
|
||||
|
||||
|
||||
$em = EntityManager::create($connectionOptions, $config);
|
||||
|
||||
.. note::
|
||||
@@ -259,7 +259,7 @@ In a production environment, it is highly recommended to use
|
||||
AUTOGENERATE_NEVER to allow for optimal performances. The other
|
||||
options are interesting in development environment.
|
||||
|
||||
Before v2.4, ``setAutoGenerateProxyClasses`` would accept a boolean
|
||||
``setAutoGenerateProxyClasses`` can accept a boolean
|
||||
value. This is still possible, ``FALSE`` being equivalent to
|
||||
AUTOGENERATE_NEVER and ``TRUE`` to AUTOGENERATE_ALWAYS.
|
||||
|
||||
@@ -299,7 +299,7 @@ Proxy Objects
|
||||
|
||||
A proxy object is an object that is put in place or used instead of
|
||||
the "real" object. A proxy object can add behavior to the object
|
||||
being proxied without that object being aware of it. In Doctrine 2,
|
||||
being proxied without that object being aware of it. In ORM,
|
||||
proxy objects are used to realize several features but mainly for
|
||||
transparent lazy-loading.
|
||||
|
||||
@@ -309,7 +309,7 @@ of the objects. This is an essential property as without it there
|
||||
would always be fragile partial objects at the outer edges of your
|
||||
object graph.
|
||||
|
||||
Doctrine 2 implements a variant of the proxy pattern where it
|
||||
Doctrine ORM implements a variant of the proxy pattern where it
|
||||
generates classes that extend your entity classes and adds
|
||||
lazy-loading capabilities to them. Doctrine can then give you an
|
||||
instance of such a proxy class whenever you request an object of
|
||||
@@ -411,7 +411,7 @@ be found.
|
||||
Multiple Metadata Sources
|
||||
-------------------------
|
||||
|
||||
When using different components using Doctrine 2 you may end up
|
||||
When using different components using Doctrine ORM you may end up
|
||||
with them using two different metadata drivers, for example XML and
|
||||
YAML. You can use the DriverChain Metadata implementations to
|
||||
aggregate these drivers based on namespaces:
|
||||
|
||||
@@ -5,29 +5,29 @@ You've probably used docblock annotations in some form already,
|
||||
most likely to provide documentation metadata for a tool like
|
||||
``PHPDocumentor`` (@author, @link, ...). Docblock annotations are a
|
||||
tool to embed metadata inside the documentation section which can
|
||||
then be processed by some tool. Doctrine 2 generalizes the concept
|
||||
then be processed by some tool. Doctrine ORM generalizes the concept
|
||||
of docblock annotations so that they can be used for any kind of
|
||||
metadata and so that it is easy to define new docblock annotations.
|
||||
In order to allow more involved annotation values and to reduce the
|
||||
chances of clashes with other docblock annotations, the Doctrine 2
|
||||
chances of clashes with other docblock annotations, the Doctrine ORM
|
||||
docblock annotations feature an alternative syntax that is heavily
|
||||
inspired by the Annotation syntax introduced in Java 5.
|
||||
|
||||
The implementation of these enhanced docblock annotations is
|
||||
located in the ``Doctrine\Common\Annotations`` namespace and
|
||||
therefore part of the Common package. Doctrine 2 docblock
|
||||
therefore part of the Common package. Doctrine ORM docblock
|
||||
annotations support namespaces and nested annotations among other
|
||||
things. The Doctrine 2 ORM defines its own set of docblock
|
||||
things. The Doctrine ORM ORM defines its own set of docblock
|
||||
annotations for supplying object-relational mapping metadata.
|
||||
|
||||
.. note::
|
||||
|
||||
If you're not comfortable with the concept of docblock
|
||||
annotations, don't worry, as mentioned earlier Doctrine 2 provides
|
||||
annotations, don't worry, as mentioned earlier Doctrine ORM provides
|
||||
XML and YAML alternatives and you could easily implement your own
|
||||
favourite mechanism for defining ORM metadata.
|
||||
|
||||
In this chapter a reference of every Doctrine 2 Annotation is given
|
||||
In this chapter a reference of every Doctrine ORM Annotation is given
|
||||
with short explanations on their context and usage.
|
||||
|
||||
Index
|
||||
@@ -213,7 +213,7 @@ Optional attributes:
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The Change Tracking Policy annotation allows to specify how the
|
||||
Doctrine 2 UnitOfWork should detect changes in properties of
|
||||
Doctrine ORM UnitOfWork should detect changes in properties of
|
||||
entities during flush. By default each entity is checked according
|
||||
to a deferred implicit strategy, which means upon flush UnitOfWork
|
||||
compares all the properties of an entity to a previously stored
|
||||
@@ -254,7 +254,7 @@ Example:
|
||||
|
||||
<?php
|
||||
/**
|
||||
* @Id
|
||||
* @Id
|
||||
* @Column(type="integer")
|
||||
* @GeneratedValue(strategy="CUSTOM")
|
||||
* @CustomIdGenerator(class="My\Namespace\MyIdGenerator")
|
||||
@@ -388,7 +388,7 @@ Optional attributes:
|
||||
EntityRepository. Use of repositories for entities is encouraged to keep
|
||||
specialized DQL and SQL operations separated from the Model/Domain
|
||||
Layer.
|
||||
- **readOnly**: (>= 2.1) Specifies that this entity is marked as read only and not
|
||||
- **readOnly**: Specifies that this entity is marked as read only and not
|
||||
considered for change-tracking. Entities of this type can be persisted
|
||||
and removed though.
|
||||
|
||||
@@ -812,7 +812,7 @@ The @MappedSuperclass annotation cannot be used in conjunction with
|
||||
Optional attributes:
|
||||
|
||||
|
||||
- **repositoryClass**: (>= 2.2) Specifies the FQCN of a subclass of the EntityRepository.
|
||||
- **repositoryClass**: Specifies the FQCN of a subclass of the EntityRepository.
|
||||
That will be inherited for all subclasses of that Mapped Superclass.
|
||||
|
||||
Example:
|
||||
@@ -1231,7 +1231,7 @@ Optional attributes:
|
||||
|
||||
- **indexes**: Array of @Index annotations
|
||||
- **uniqueConstraints**: Array of @UniqueConstraint annotations.
|
||||
- **schema**: (>= 2.5) Name of the schema the table lies in.
|
||||
- **schema**: Name of the schema the table lies in.
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
@@ -2,29 +2,29 @@ Architecture
|
||||
============
|
||||
|
||||
This chapter gives an overview of the overall architecture,
|
||||
terminology and constraints of Doctrine 2. It is recommended to
|
||||
terminology and constraints of Doctrine ORM. It is recommended to
|
||||
read this chapter carefully.
|
||||
|
||||
Using an Object-Relational Mapper
|
||||
---------------------------------
|
||||
|
||||
As the term ORM already hints at, Doctrine 2 aims to simplify the
|
||||
As the term ORM already hints at, Doctrine ORM aims to simplify the
|
||||
translation between database rows and the PHP object model. The
|
||||
primary use case for Doctrine are therefore applications that
|
||||
utilize the Object-Oriented Programming Paradigm. For applications
|
||||
that do not primarily work with objects Doctrine 2 is not suited very
|
||||
that do not primarily work with objects Doctrine ORM is not suited very
|
||||
well.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
Doctrine 2 requires a minimum of PHP 7.1. For greatly improved
|
||||
Doctrine ORM requires a minimum of PHP 7.1. For greatly improved
|
||||
performance it is also recommended that you use APC with PHP.
|
||||
|
||||
Doctrine 2 Packages
|
||||
Doctrine ORM Packages
|
||||
-------------------
|
||||
|
||||
Doctrine 2 is divided into three main packages.
|
||||
Doctrine ORM is divided into three main packages.
|
||||
|
||||
- Common
|
||||
- DBAL (includes Common)
|
||||
@@ -166,8 +166,8 @@ did not find a way yet, if you did, please contact us).
|
||||
The EntityManager
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
The ``EntityManager`` class is a central access point to the ORM
|
||||
functionality provided by Doctrine 2. The ``EntityManager`` API is
|
||||
The ``EntityManager`` class is a central access point to the
|
||||
functionality provided by Doctrine ORM. The ``EntityManager`` API is
|
||||
used to manage the persistence of your objects and to query for
|
||||
persistent objects.
|
||||
|
||||
|
||||
@@ -423,7 +423,7 @@ performance of Doctrine. The allocationSize specifies by how much
|
||||
values the sequence is incremented whenever the next value is
|
||||
retrieved. If this is larger than 1 (one) Doctrine can generate
|
||||
identifier values for the allocationSizes amount of entities. In
|
||||
the above example with ``allocationSize=100`` Doctrine 2 would only
|
||||
the above example with ``allocationSize=100`` Doctrine ORM would only
|
||||
need to access the sequence once to generate the identifiers for
|
||||
100 new entities.
|
||||
|
||||
@@ -451,7 +451,7 @@ need to access the sequence once to generate the identifiers for
|
||||
Composite Keys
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
With Doctrine 2 you can use composite primary keys, using ``@Id`` on more then
|
||||
With Doctrine ORM you can use composite primary keys, using ``@Id`` on more then
|
||||
one column. Some restrictions exist opposed to using a single identifier in
|
||||
this case: The use of the ``@GeneratedValue`` annotation is not supported,
|
||||
which means you can only use composite keys if you generate the primary key
|
||||
@@ -484,15 +484,11 @@ according to the used database platform.
|
||||
|
||||
.. _reference-basic-mapping-custom-mapping-types:
|
||||
|
||||
.. versionadded: 2.3
|
||||
|
||||
For more control over column quoting the ``Doctrine\ORM\Mapping\QuoteStrategy`` interface
|
||||
was introduced in 2.3. It is invoked for every column, table, alias and other
|
||||
was introduced in ORM. It is invoked for every column, table, alias and other
|
||||
SQL names. You can implement the QuoteStrategy and set it by calling
|
||||
``Doctrine\ORM\Configuration#setQuoteStrategy()``.
|
||||
|
||||
.. versionadded: 2.4
|
||||
|
||||
The ANSI Quote Strategy was added, which assumes quoting is not necessary for any SQL name.
|
||||
You can use it with the following code:
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ Iterating results
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
An alternative solution for bulk updates is to use the
|
||||
``Query#iterate()`` facility to iterate over the query results step
|
||||
``Query#toIterable()`` facility to iterate over the query results step
|
||||
by step instead of loading the whole result into memory at once.
|
||||
The following example shows how to do this, combining the iteration
|
||||
with the batching strategy that was already used for bulk inserts:
|
||||
@@ -86,9 +86,7 @@ with the batching strategy that was already used for bulk inserts:
|
||||
$batchSize = 20;
|
||||
$i = 1;
|
||||
$q = $em->createQuery('select u from MyProject\Model\User u');
|
||||
$iterableResult = $q->iterate();
|
||||
foreach ($iterableResult as $row) {
|
||||
$user = $row[0];
|
||||
foreach ($q->toIterable() as $user) {
|
||||
$user->increaseCredit();
|
||||
$user->calculateNewBonuses();
|
||||
if (($i % $batchSize) === 0) {
|
||||
@@ -137,7 +135,7 @@ Iterating results
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
An alternative solution for bulk deletes is to use the
|
||||
``Query#iterate()`` facility to iterate over the query results step
|
||||
``Query#toIterable()`` facility to iterate over the query results step
|
||||
by step instead of loading the whole result into memory at once.
|
||||
The following example shows how to do this:
|
||||
|
||||
@@ -147,9 +145,8 @@ The following example shows how to do this:
|
||||
$batchSize = 20;
|
||||
$i = 1;
|
||||
$q = $em->createQuery('select u from MyProject\Model\User u');
|
||||
$iterableResult = $q->iterate();
|
||||
while (($row = $iterableResult->next()) !== false) {
|
||||
$em->remove($row[0]);
|
||||
foreach($q->toIterable() as $row) {
|
||||
$em->remove($row);
|
||||
if (($i % $batchSize) === 0) {
|
||||
$em->flush(); // Executes all deletions.
|
||||
$em->clear(); // Detaches all objects from Doctrine!
|
||||
@@ -168,20 +165,18 @@ The following example shows how to do this:
|
||||
Iterating Large Results for Data-Processing
|
||||
-------------------------------------------
|
||||
|
||||
You can use the ``iterate()`` method just to iterate over a large
|
||||
result and no UPDATE or DELETE intention. The ``IterableResult``
|
||||
instance returned from ``$query->iterate()`` implements the
|
||||
Iterator interface so you can process a large result without memory
|
||||
You can use the ``toIterable()`` method just to iterate over a large
|
||||
result and no UPDATE or DELETE intention. ``$query->toIterable()`` returns ``iterable``
|
||||
so you can process a large result without memory
|
||||
problems using the following approach:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$q = $this->_em->createQuery('select u from MyProject\Model\User u');
|
||||
$iterableResult = $q->iterate();
|
||||
foreach ($iterableResult as $row) {
|
||||
// do stuff with the data in the row, $row[0] is always the object
|
||||
|
||||
foreach ($q->toIterable() as $row) {
|
||||
// do stuff with the data in the row
|
||||
|
||||
// detach from Doctrine, so that it can be Garbage-Collected immediately
|
||||
$this->_em->detach($row[0]);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ Deferred Explicit
|
||||
|
||||
The deferred explicit policy is similar to the deferred implicit
|
||||
policy in that it detects changes through a property-by-property
|
||||
comparison at commit time. The difference is that Doctrine 2 only
|
||||
comparison at commit time. The difference is that Doctrine ORM only
|
||||
considers entities that have been explicitly marked for change detection
|
||||
through a call to EntityManager#persist(entity) or through a save
|
||||
cascade. All other entities are skipped. This policy therefore
|
||||
|
||||
@@ -112,8 +112,6 @@ You need to register your applications EntityManager to the console tool
|
||||
to make use of the tasks by creating a ``cli-config.php`` file with the
|
||||
following content:
|
||||
|
||||
On Doctrine 2.4 and above:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
@@ -126,19 +124,3 @@ On Doctrine 2.4 and above:
|
||||
$entityManager = GetEntityManager();
|
||||
|
||||
return ConsoleRunner::createHelperSet($entityManager);
|
||||
|
||||
On Doctrine 2.3 and below:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// cli-config.php
|
||||
require_once 'my_bootstrap.php';
|
||||
|
||||
// Any way to access the EntityManager from your application
|
||||
$em = GetMyEntityManager();
|
||||
|
||||
$helperSet = new \Symfony\Component\Console\Helper\HelperSet(array(
|
||||
'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($em->getConnection()),
|
||||
'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em)
|
||||
));
|
||||
|
||||
@@ -458,8 +458,6 @@ Get all users that have no phonenumber
|
||||
Get all instances of a specific type, for use with inheritance
|
||||
hierarchies:
|
||||
|
||||
.. versionadded:: 2.1
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
@@ -469,24 +467,20 @@ hierarchies:
|
||||
|
||||
Get all users visible on a given website that have chosen certain gender:
|
||||
|
||||
.. versionadded:: 2.2
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT u FROM User u WHERE u.gender IN (SELECT IDENTITY(agl.gender) FROM Site s JOIN s.activeGenderList agl WHERE s.id = ?1)');
|
||||
|
||||
.. versionadded:: 2.4
|
||||
|
||||
Starting with 2.4, the IDENTITY() DQL function also works for composite primary keys:
|
||||
The IDENTITY() DQL function also works for composite primary keys
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery("SELECT IDENTITY(c.location, 'latitude') AS latitude, IDENTITY(c.location, 'longitude') AS longitude FROM Checkpoint c WHERE c.user = ?1");
|
||||
|
||||
Joins between entities without associations were not possible until version
|
||||
2.4, where you can generate an arbitrary join with the following syntax:
|
||||
Joins between entities without associations are available,
|
||||
where you can generate an arbitrary join with the following syntax:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -534,8 +528,6 @@ You use the partial syntax when joining as well:
|
||||
"NEW" Operator Syntax
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. versionadded:: 2.4
|
||||
|
||||
Using the ``NEW`` operator you can construct Data Transfer Objects (DTOs) directly from DQL queries.
|
||||
|
||||
- When using ``SELECT NEW`` you don't need to specify a mapped entity.
|
||||
@@ -657,6 +649,16 @@ The same restrictions apply for the reference of related entities.
|
||||
of the query. Additionally Deletes of specified entities are *NOT*
|
||||
cascaded to related entities even if specified in the metadata.
|
||||
|
||||
Comments in queries
|
||||
-------------------
|
||||
|
||||
We can use comments with the SQL syntax of comments.
|
||||
|
||||
.. code-block:: sql
|
||||
|
||||
SELECT u FROM MyProject\Model\User u
|
||||
-- my comment
|
||||
WHERE u.age > 20 -- comment at the end of a line
|
||||
|
||||
Functions, Operators, Aggregates
|
||||
--------------------------------
|
||||
@@ -900,7 +902,7 @@ Class Table Inheritance
|
||||
is an inheritance mapping strategy where each class in a hierarchy
|
||||
is mapped to several tables: its own table and the tables of all
|
||||
parent classes. The table of a child class is linked to the table
|
||||
of a parent class through a foreign key constraint. Doctrine 2
|
||||
of a parent class through a foreign key constraint. Doctrine ORM
|
||||
implements this strategy through the use of a discriminator column
|
||||
in the topmost table of the hierarchy because this is the easiest
|
||||
way to achieve polymorphic queries with Class Table Inheritance.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Events
|
||||
======
|
||||
|
||||
Doctrine 2 features a lightweight event system that is part of the
|
||||
Doctrine ORM features a lightweight event system that is part of the
|
||||
Common package. Doctrine uses it to dispatch system events, mainly
|
||||
:ref:`lifecycle events <reference-events-lifecycle-events>`.
|
||||
You can also use it for your own custom events.
|
||||
@@ -70,7 +70,7 @@ method.
|
||||
<?php
|
||||
$evm->removeEventListener(array(self::preFoo, self::postFoo), $this);
|
||||
|
||||
The Doctrine 2 event system also has a simple concept of event
|
||||
The Doctrine ORM event system also has a simple concept of event
|
||||
subscribers. We can define a simple ``TestEventSubscriber`` class
|
||||
which implements the ``\Doctrine\Common\EventSubscriber`` interface
|
||||
and implements a ``getSubscribedEvents()`` method which returns an
|
||||
@@ -124,7 +124,7 @@ Now you can test the ``$eventSubscriber`` instance to see if the
|
||||
Naming convention
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Events being used with the Doctrine 2 EventManager are best named
|
||||
Events being used with the Doctrine ORM EventManager are best named
|
||||
with camelcase and the value of the corresponding constant should
|
||||
be the name of the constant itself, even with spelling. This has
|
||||
several reasons:
|
||||
@@ -195,10 +195,10 @@ events during the life-time of their registered entities.
|
||||
|
||||
.. warning::
|
||||
|
||||
Note that, when using ``Doctrine\ORM\AbstractQuery#iterate()``, ``postLoad``
|
||||
Note that, when using ``Doctrine\ORM\AbstractQuery#toIterable()``, ``postLoad``
|
||||
events will be executed immediately after objects are being hydrated, and therefore
|
||||
associations are not guaranteed to be initialized. It is not safe to combine
|
||||
usage of ``Doctrine\ORM\AbstractQuery#iterate()`` and ``postLoad`` event
|
||||
usage of ``Doctrine\ORM\AbstractQuery#toIterable()`` and ``postLoad`` event
|
||||
handlers.
|
||||
|
||||
.. warning::
|
||||
@@ -221,7 +221,7 @@ These can be hooked into by two different types of event
|
||||
listeners:
|
||||
|
||||
- Lifecycle Callbacks are methods on the entity classes that are
|
||||
called when the event is triggered. As of v2.4 they receive some kind
|
||||
called when the event is triggered. They receive some kind
|
||||
of ``EventArgs`` instance.
|
||||
- Lifecycle Event Listeners and Subscribers are classes with specific callback
|
||||
methods that receives some kind of ``EventArgs`` instance.
|
||||
@@ -383,9 +383,7 @@ defined on your ``User`` model.
|
||||
Lifecycle Callbacks Event Argument
|
||||
-----------------------------------
|
||||
|
||||
.. versionadded:: 2.4
|
||||
|
||||
Since 2.4 the triggered event is given to the lifecycle-callback.
|
||||
The triggered event is also given to the lifecycle-callback.
|
||||
|
||||
With the additional argument you have access to the
|
||||
``EntityManager`` and ``UnitOfWork`` APIs inside these callback methods.
|
||||
@@ -761,8 +759,6 @@ EntityManager.
|
||||
Entity listeners
|
||||
----------------
|
||||
|
||||
.. versionadded:: 2.4
|
||||
|
||||
An entity listener is a lifecycle listener class used for an entity.
|
||||
|
||||
- The entity listener's mapping may be applied to an entity class or mapped superclass.
|
||||
|
||||
@@ -80,7 +80,7 @@ You can solve this exception by:
|
||||
How can I filter an association?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Natively you can't filter associations in 2.0 and 2.1. You should use DQL queries to query for the filtered set of entities.
|
||||
You should use DQL queries to query for the filtered set of entities.
|
||||
|
||||
I call clear() on a One-To-Many collection but the entities are not deleted
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -98,7 +98,7 @@ How can I add columns to a many-to-many table?
|
||||
|
||||
The many-to-many association is only supporting foreign keys in the table definition
|
||||
To work with many-to-many tables containing extra columns you have to use the
|
||||
foreign keys as primary keys feature of Doctrine introduced in version 2.1.
|
||||
foreign keys as primary keys feature of Doctrine ORM.
|
||||
|
||||
See :doc:`the tutorial on composite primary keys for more information<../tutorials/composite-primary-keys>`.
|
||||
|
||||
@@ -128,10 +128,10 @@ See the previous question for a solution to this task.
|
||||
Inheritance
|
||||
-----------
|
||||
|
||||
Can I use Inheritance with Doctrine 2?
|
||||
Can I use Inheritance with Doctrine ORM?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Yes, you can use Single- or Joined-Table Inheritance in Doctrine 2.
|
||||
|
||||
Yes, you can use Single- or Joined-Table Inheritance in ORM.
|
||||
|
||||
See the documentation chapter on :doc:`inheritance mapping <inheritance-mapping>` for
|
||||
the details.
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
Filters
|
||||
=======
|
||||
|
||||
.. versionadded:: 2.2
|
||||
|
||||
Doctrine 2.2 features a filter system that allows the developer to add SQL to
|
||||
Doctrine ORM features a filter system that allows the developer to add SQL to
|
||||
the conditional clauses of queries, regardless the place where the SQL is
|
||||
generated (e.g. from a DQL query, or by loading associated entities).
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ in scenarios where data is loaded for read-only purposes.
|
||||
Read-Only Entities
|
||||
------------------
|
||||
|
||||
Starting with Doctrine 2.1 you can mark entities as read only (See metadata mapping
|
||||
You can mark entities as read only (See metadata mapping
|
||||
references for details). This means that the entity marked as read only is never considered
|
||||
for updates, which means when you call flush on the EntityManager these entities are skipped
|
||||
even if properties changed. Read-Only allows to persist new entities of a kind and remove existing
|
||||
|
||||
@@ -185,7 +185,7 @@ Class Table Inheritance
|
||||
is an inheritance mapping strategy where each class in a hierarchy
|
||||
is mapped to several tables: its own table and the tables of all
|
||||
parent classes. The table of a child class is linked to the table
|
||||
of a parent class through a foreign key constraint. Doctrine 2
|
||||
of a parent class through a foreign key constraint. Doctrine ORM
|
||||
implements this strategy through the use of a discriminator column
|
||||
in the topmost table of the hierarchy because this is the easiest
|
||||
way to achieve polymorphic queries with Class Table Inheritance.
|
||||
|
||||
@@ -6,7 +6,7 @@ Therefore we think it is very important to be honest about the
|
||||
current limitations to our users. Much like every other piece of
|
||||
software Doctrine2 is not perfect and far from feature complete.
|
||||
This section should give you an overview of current limitations of
|
||||
Doctrine 2 as well as critical known issues that you should know
|
||||
Doctrine ORM as well as critical known issues that you should know
|
||||
about.
|
||||
|
||||
Current Limitations
|
||||
@@ -107,7 +107,7 @@ to the same entity.
|
||||
Behaviors
|
||||
~~~~~~~~~
|
||||
|
||||
Doctrine 2 will **never** include a behavior system like Doctrine 1
|
||||
Doctrine ORM will **never** include a behavior system like Doctrine 1
|
||||
in the core library. We don't think behaviors add more value than
|
||||
they cost pain and debugging hell. Please see the many different
|
||||
blog posts we have written on this topics:
|
||||
@@ -115,9 +115,9 @@ blog posts we have written on this topics:
|
||||
- `Doctrine2 "Behaviors" in a Nutshell <http://www.doctrine-project.org/2010/02/17/doctrine2-behaviours-nutshell.html>`_
|
||||
- `A re-usable Versionable behavior for Doctrine2 <http://www.doctrine-project.org/2010/02/24/doctrine2-versionable.html>`_
|
||||
- `Write your own ORM on top of Doctrine2 <http://www.doctrine-project.org/2010/07/19/your-own-orm-doctrine2.html>`_
|
||||
- `Doctrine 2 Behavioral Extensions <http://www.doctrine-project.org/2010/11/18/doctrine2-behavioral-extensions.html>`_
|
||||
- `Doctrine ORM Behavioral Extensions <http://www.doctrine-project.org/2010/11/18/doctrine2-behavioral-extensions.html>`_
|
||||
|
||||
Doctrine 2 has enough hooks and extension points so that **you** can
|
||||
Doctrine ORM has enough hooks and extension points so that **you** can
|
||||
add whatever you want on top of it. None of this will ever become
|
||||
core functionality of Doctrine2 however, you will have to rely on
|
||||
third party extensions for magical behaviors.
|
||||
@@ -126,9 +126,9 @@ Nested Set
|
||||
~~~~~~~~~~
|
||||
|
||||
NestedSet was offered as a behavior in Doctrine 1 and will not be
|
||||
included in the core of Doctrine 2. However there are already two
|
||||
included in the core of Doctrine ORM. However there are already two
|
||||
extensions out there that offer support for Nested Set with
|
||||
Doctrine 2:
|
||||
ORM:
|
||||
|
||||
|
||||
- `Doctrine2 Hierarchical-Structural Behavior <http://github.com/guilhermeblanco/Doctrine2-Hierarchical-Structural-Behavior>`_
|
||||
@@ -149,9 +149,9 @@ Identifier Quoting and Legacy Databases
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
For compatibility reasons between all the supported vendors and
|
||||
edge case problems Doctrine 2 does **NOT** do automatic identifier
|
||||
edge case problems Doctrine ORM does **NOT** do automatic identifier
|
||||
quoting. This can lead to problems when trying to get
|
||||
legacy-databases to work with Doctrine 2.
|
||||
legacy-databases to work with Doctrine ORM.
|
||||
|
||||
|
||||
- You can quote column-names as described in the
|
||||
|
||||
@@ -147,7 +147,7 @@ ClassMetadata
|
||||
-------------
|
||||
|
||||
The last piece you need to know and understand about metadata in
|
||||
Doctrine 2 is the API of the ``ClassMetadata`` classes. You need to
|
||||
Doctrine ORM is the API of the ``ClassMetadata`` classes. You need to
|
||||
be familiar with them in order to implement your own drivers but
|
||||
more importantly to retrieve mapping information for a certain
|
||||
entity when needed.
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
Implementing a NamingStrategy
|
||||
==============================
|
||||
|
||||
.. versionadded:: 2.3
|
||||
|
||||
Using a naming strategy you can provide rules for generating database identifiers,
|
||||
column or table names. This feature helps
|
||||
reduce the verbosity of the mapping document, eliminating repetitive noise (eg: ``TABLE_``).
|
||||
|
||||
@@ -80,9 +80,7 @@ with inheritance hierarchies.
|
||||
|
||||
The builder extends the ``ResultSetMapping`` class and as such has all the functionality of it as well.
|
||||
|
||||
.. versionadded:: 2.4
|
||||
|
||||
Starting with Doctrine ORM 2.4 you can generate the ``SELECT`` clause
|
||||
The ``SELECT`` clause can be generated
|
||||
from a ``ResultSetMappingBuilder``. You can either cast the builder
|
||||
object to ``(string)`` and the DQL aliases are used as SQL table aliases
|
||||
or use the ``generateSelectClause($tableAliases)`` method and pass
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
PHP Mapping
|
||||
===========
|
||||
|
||||
Doctrine 2 also allows you to provide the ORM metadata in the form
|
||||
Doctrine ORM also allows you to provide the ORM metadata in the form
|
||||
of plain PHP code using the ``ClassMetadata`` API. You can write
|
||||
the code in PHP files or inside of a static function named
|
||||
``loadMetadata($class)`` on the entity class itself.
|
||||
|
||||
@@ -354,6 +354,7 @@ a querybuilder instance into a Query object:
|
||||
|
||||
// Execute Query
|
||||
$result = $query->getResult();
|
||||
$iterableResult = $query->toIterable();
|
||||
$single = $query->getSingleResult();
|
||||
$array = $query->getArrayResult();
|
||||
$scalar = $query->getScalarResult();
|
||||
|
||||
@@ -5,7 +5,7 @@ Doctrine Console
|
||||
----------------
|
||||
|
||||
The Doctrine Console is a Command Line Interface tool for simplifying common
|
||||
administration tasks during the development of a project that uses Doctrine 2.
|
||||
administration tasks during the development of a project that uses ORM.
|
||||
|
||||
Take a look at the :doc:`Installation and Configuration <configuration>`
|
||||
chapter for more information how to setup the console command.
|
||||
@@ -27,64 +27,34 @@ Configuration
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Whenever the ``doctrine`` command line tool is invoked, it can
|
||||
access all Commands that were registered by developer. There is no
|
||||
access all Commands that were registered by a developer. There is no
|
||||
auto-detection mechanism at work. The Doctrine binary
|
||||
already registers all the commands that currently ship with
|
||||
Doctrine DBAL and ORM. If you want to use additional commands you
|
||||
have to register them yourself.
|
||||
|
||||
All the commands of the Doctrine Console require access to the ``EntityManager``
|
||||
or ``DBAL`` Connection. You have to inject them into the console application
|
||||
using so called Helper-Sets. This requires either the ``db``
|
||||
or the ``em`` helpers to be defined in order to work correctly.
|
||||
All the commands of the Doctrine Console require access to the
|
||||
``EntityManager``. You have to inject it into the console application with
|
||||
``ConsoleRunner::createHelperSet``. Whenever you invoke the Doctrine
|
||||
binary, it searches the current directory for the file ``cli-config.php``.
|
||||
This file contains the project-specific configuration.
|
||||
|
||||
Whenever you invoke the Doctrine binary the current folder is searched for a
|
||||
``cli-config.php`` file. This file contains the project specific configuration:
|
||||
Here is an example of a the project-specific ``cli-config.php``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$helperSet = new \Symfony\Component\Console\Helper\HelperSet(array(
|
||||
'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($conn)
|
||||
));
|
||||
$cli->setHelperSet($helperSet);
|
||||
use Doctrine\ORM\Tools\Console\ConsoleRunner;
|
||||
|
||||
When dealing with the ORM package, the EntityManagerHelper is
|
||||
required:
|
||||
// replace this with the path to your own project bootstrap file.
|
||||
require_once 'bootstrap.php';
|
||||
|
||||
.. code-block:: php
|
||||
// replace with mechanism to retrieve EntityManager in your app
|
||||
$entityManager = GetEntityManager();
|
||||
|
||||
<?php
|
||||
$helperSet = new \Symfony\Component\Console\Helper\HelperSet(array(
|
||||
'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em)
|
||||
));
|
||||
$cli->setHelperSet($helperSet);
|
||||
return ConsoleRunner::createHelperSet($entityManager);
|
||||
|
||||
The HelperSet instance has to be generated in a separate file (i.e.
|
||||
``cli-config.php``) that contains typical Doctrine bootstrap code
|
||||
and predefines the needed HelperSet attributes mentioned above. A
|
||||
sample ``cli-config.php`` file looks as follows:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// cli-config.php
|
||||
require_once 'my_bootstrap.php';
|
||||
|
||||
// Any way to access the EntityManager from your application
|
||||
$em = GetMyEntityManager();
|
||||
|
||||
$helperSet = new \Symfony\Component\Console\Helper\HelperSet(array(
|
||||
'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($em->getConnection()),
|
||||
'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em)
|
||||
));
|
||||
|
||||
It is important to define a correct HelperSet that Doctrine binary
|
||||
script will ultimately use. The Doctrine Binary will automatically
|
||||
find the first instance of HelperSet in the global variable
|
||||
namespace and use this.
|
||||
|
||||
.. note::
|
||||
.. note::
|
||||
|
||||
You have to adjust this snippet for your specific application or framework
|
||||
and use their facilities to access the Doctrine EntityManager and
|
||||
@@ -375,7 +345,7 @@ First you need to retrieve the metadata instances with the
|
||||
$em->getConnection()->getSchemaManager()
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
$cmf = new \Doctrine\ORM\Tools\DisconnectedClassMetadataFactory();
|
||||
$cmf->setEntityManager($em);
|
||||
$metadata = $cmf->getAllMetadata();
|
||||
@@ -412,7 +382,7 @@ You can also reverse engineer a database using the
|
||||
Runtime vs Development Mapping Validation
|
||||
-----------------------------------------
|
||||
|
||||
For performance reasons Doctrine 2 has to skip some of the
|
||||
For performance reasons Doctrine ORM has to skip some of the
|
||||
necessary validation of metadata mappings. You have to execute
|
||||
this validation in your development workflow to verify the
|
||||
associations are correctly defined.
|
||||
@@ -517,4 +487,3 @@ HelperSet, like it is described in the configuration section.
|
||||
|
||||
// Runs console application
|
||||
$cli->run();
|
||||
|
||||
|
||||
@@ -16,13 +16,13 @@ transaction. Without any explicit transaction demarcation from your
|
||||
side, this quickly results in poor performance because transactions
|
||||
are not cheap.
|
||||
|
||||
For the most part, Doctrine 2 already takes care of proper
|
||||
For the most part, Doctrine ORM already takes care of proper
|
||||
transaction demarcation for you: All the write operations
|
||||
(INSERT/UPDATE/DELETE) are queued until ``EntityManager#flush()``
|
||||
is invoked which wraps all of these changes in a single
|
||||
transaction.
|
||||
|
||||
However, Doctrine 2 also allows (and encourages) you to take over
|
||||
However, Doctrine ORM also allows (and encourages) you to take over
|
||||
and control transaction demarcation yourself.
|
||||
|
||||
These are two ways to deal with transactions when using the
|
||||
@@ -154,7 +154,7 @@ occurred you should do that with a new ``EntityManager``.
|
||||
Locking Support
|
||||
---------------
|
||||
|
||||
Doctrine 2 offers support for Pessimistic- and Optimistic-locking
|
||||
Doctrine ORM offers support for Pessimistic- and Optimistic-locking
|
||||
strategies natively. This allows to take very fine-grained control
|
||||
over what kind of locking is required for your Entities in your
|
||||
application.
|
||||
@@ -367,7 +367,7 @@ And the change headline action (POST Request):
|
||||
Pessimistic Locking
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Doctrine 2 supports Pessimistic Locking at the database level. No
|
||||
Doctrine ORM supports Pessimistic Locking at the database level. No
|
||||
attempt is being made to implement pessimistic locking inside
|
||||
Doctrine, rather vendor-specific and ANSI-SQL commands are used to
|
||||
acquire row-level locks. Every Entity can be part of a pessimistic
|
||||
@@ -376,11 +376,11 @@ lock, there is no special metadata required to use this feature.
|
||||
However for Pessimistic Locking to work you have to disable the
|
||||
Auto-Commit Mode of your Database and start a transaction around
|
||||
your pessimistic lock use-case using the "Approach 2: Explicit
|
||||
Transaction Demarcation" described above. Doctrine 2 will throw an
|
||||
Transaction Demarcation" described above. Doctrine ORM will throw an
|
||||
Exception if you attempt to acquire an pessimistic lock and no
|
||||
transaction is running.
|
||||
|
||||
Doctrine 2 currently supports two pessimistic lock modes:
|
||||
Doctrine ORM currently supports two pessimistic lock modes:
|
||||
|
||||
|
||||
- Pessimistic Write
|
||||
|
||||
@@ -407,7 +407,7 @@ There are two approaches to handle this problem in your code:
|
||||
Transitive persistence / Cascade Operations
|
||||
-------------------------------------------
|
||||
|
||||
Doctrine 2 provides a mechanism for transitive persistence through cascading of certain operations.
|
||||
Doctrine ORM provides a mechanism for transitive persistence through cascading of certain operations.
|
||||
Each association to another entity or a collection of
|
||||
entities can be configured to automatically cascade the following operations to the associated entities:
|
||||
``persist``, ``remove``, ``merge``, ``detach``, ``refresh`` or ``all``.
|
||||
|
||||
@@ -27,7 +27,7 @@ Work that have not yet been persisted are lost.
|
||||
|
||||
.. note::
|
||||
|
||||
Doctrine does NEVER touch the public API of methods in your entity
|
||||
Doctrine does NEVER touch the public API of methods in your entity
|
||||
classes (like getters and setters) nor the constructor method.
|
||||
Instead, it uses reflection to get/set data from/to your entity objects.
|
||||
When Doctrine fetches data from DB and saves it back,
|
||||
@@ -48,12 +48,12 @@ headline "Hello World" with the ID 1234:
|
||||
<?php
|
||||
$article = $entityManager->find('CMS\Article', 1234);
|
||||
$article->setHeadline('Hello World dude!');
|
||||
|
||||
|
||||
$article2 = $entityManager->find('CMS\Article', 1234);
|
||||
echo $article2->getHeadline();
|
||||
|
||||
In this case the Article is accessed from the entity manager twice,
|
||||
but modified in between. Doctrine 2 realizes this and will only
|
||||
but modified in between. Doctrine ORM realizes this and will only
|
||||
ever give you access to one instance of the Article with ID 1234,
|
||||
no matter how often do you retrieve it from the EntityManager and
|
||||
even no matter what kind of Query method you are using (find,
|
||||
@@ -100,25 +100,25 @@ from newly opened EntityManager.
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
private $id;
|
||||
|
||||
|
||||
/** @Column(type="string") */
|
||||
private $headline;
|
||||
|
||||
|
||||
/** @ManyToOne(targetEntity="User") */
|
||||
private $author;
|
||||
|
||||
|
||||
/** @OneToMany(targetEntity="Comment", mappedBy="article") */
|
||||
private $comments;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->comments = new ArrayCollection();
|
||||
}
|
||||
|
||||
|
||||
public function getAuthor() { return $this->author; }
|
||||
public function getComments() { return $this->comments; }
|
||||
}
|
||||
|
||||
|
||||
$article = $em->find('Article', 1);
|
||||
|
||||
This code only retrieves the ``Article`` instance with id 1 executing
|
||||
@@ -139,22 +139,22 @@ your code. See the following code:
|
||||
|
||||
<?php
|
||||
$article = $em->find('Article', 1);
|
||||
|
||||
|
||||
// accessing a method of the user instance triggers the lazy-load
|
||||
echo "Author: " . $article->getAuthor()->getName() . "\n";
|
||||
|
||||
|
||||
// Lazy Loading Proxies pass instanceof tests:
|
||||
if ($article->getAuthor() instanceof User) {
|
||||
// a User Proxy is a generated "UserProxy" class
|
||||
}
|
||||
|
||||
|
||||
// accessing the comments as an iterator triggers the lazy-load
|
||||
// retrieving ALL the comments of this article from the database
|
||||
// using a single SELECT statement
|
||||
foreach ($article->getComments() as $comment) {
|
||||
echo $comment->getText() . "\n\n";
|
||||
}
|
||||
|
||||
|
||||
// Article::$comments passes instanceof tests for the Collection interface
|
||||
// But it will NOT pass for the ArrayCollection interface
|
||||
if ($article->getComments() instanceof \Doctrine\Common\Collections\Collection) {
|
||||
@@ -174,7 +174,7 @@ methods along the lines of the ``getName()`` method shown below:
|
||||
{
|
||||
// lazy loading code
|
||||
}
|
||||
|
||||
|
||||
public function getName()
|
||||
{
|
||||
$this->_load();
|
||||
@@ -275,7 +275,7 @@ which means that its persistent state will be deleted once
|
||||
for and appear in query and collection results. See
|
||||
the section on :ref:`Database and UnitOfWork Out-Of-Sync <workingobjects_database_uow_outofsync>`
|
||||
for more information.
|
||||
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
@@ -318,7 +318,7 @@ Deleting an object with all its associated objects can be achieved
|
||||
in multiple ways with very different performance impacts.
|
||||
|
||||
|
||||
1. If an association is marked as ``CASCADE=REMOVE`` Doctrine 2
|
||||
1. If an association is marked as ``CASCADE=REMOVE`` Doctrine ORM
|
||||
will fetch this association. If its a Single association it will
|
||||
pass this entity to
|
||||
``EntityManager#remove()``. If the association is a collection, Doctrine will loop over all its elements and pass them to``EntityManager#remove()``.
|
||||
@@ -653,7 +653,7 @@ just created via the "new" operator).
|
||||
Querying
|
||||
--------
|
||||
|
||||
Doctrine 2 provides the following ways, in increasing level of
|
||||
Doctrine ORM provides the following ways, in increasing level of
|
||||
power and flexibility, to query for persistent objects. You should
|
||||
always start with the simplest one that suits your needs.
|
||||
|
||||
@@ -700,13 +700,13 @@ methods on a repository as follows:
|
||||
|
||||
<?php
|
||||
// $em instanceof EntityManager
|
||||
|
||||
|
||||
// All users that are 20 years old
|
||||
$users = $em->getRepository('MyProject\Domain\User')->findBy(array('age' => 20));
|
||||
|
||||
|
||||
// All users that are 20 years old and have a surname of 'Miller'
|
||||
$users = $em->getRepository('MyProject\Domain\User')->findBy(array('age' => 20, 'surname' => 'Miller'));
|
||||
|
||||
|
||||
// A single user by its nickname
|
||||
$user = $em->getRepository('MyProject\Domain\User')->findOneBy(array('nickname' => 'romanb'));
|
||||
|
||||
@@ -742,7 +742,7 @@ examples are equivalent:
|
||||
<?php
|
||||
// A single user by its nickname
|
||||
$user = $em->getRepository('MyProject\Domain\User')->findOneBy(array('nickname' => 'romanb'));
|
||||
|
||||
|
||||
// A single user by its nickname (__call magic)
|
||||
$user = $em->getRepository('MyProject\Domain\User')->findOneByNickname('romanb');
|
||||
|
||||
@@ -757,8 +757,6 @@ Additionally, you can just count the result of the provided conditions when you
|
||||
By Criteria
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. versionadded:: 2.3
|
||||
|
||||
The Repository implement the ``Doctrine\Common\Collections\Selectable``
|
||||
interface. That means you can build ``Doctrine\Common\Collections\Criteria``
|
||||
and pass them to the ``matching($criteria)`` method.
|
||||
@@ -800,7 +798,7 @@ A DQL query is represented by an instance of the
|
||||
|
||||
<?php
|
||||
// $em instanceof EntityManager
|
||||
|
||||
|
||||
// All users with an age between 20 and 30 (inclusive).
|
||||
$q = $em->createQuery("select u from MyDomain\Model\User u where u.age >= 20 and u.age <= 30");
|
||||
$users = $q->getResult();
|
||||
@@ -845,18 +843,18 @@ in a central location.
|
||||
|
||||
<?php
|
||||
namespace MyDomain\Model;
|
||||
|
||||
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass="MyDomain\Model\UserRepository")
|
||||
*/
|
||||
class User
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
class UserRepository extends EntityRepository
|
||||
{
|
||||
public function getAllAdminUsers()
|
||||
@@ -872,7 +870,7 @@ You can access your repository now by calling:
|
||||
|
||||
<?php
|
||||
// $em instanceof EntityManager
|
||||
|
||||
|
||||
$admins = $em->getRepository('MyDomain\Model\User')->getAllAdminUsers();
|
||||
|
||||
|
||||
|
||||
@@ -8,9 +8,7 @@ The XML driver is backed by an XML Schema document that describes
|
||||
the structure of a mapping document. The most recent version of the
|
||||
XML Schema document is available online at
|
||||
`https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd <https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd>`_.
|
||||
In order to point to the latest version of the document of a
|
||||
particular stable release branch, just append the release number,
|
||||
i.e.: doctrine-mapping-2.0.xsd The most convenient way to work with
|
||||
The most convenient way to work with
|
||||
XML mapping files is to use an IDE/editor that can provide
|
||||
code-completion based on such an XML Schema document. The following
|
||||
is an outline of a XML mapping document with the proper xmlns/xsi
|
||||
@@ -208,10 +206,10 @@ Optional attributes:
|
||||
- **inheritance-type** - The type of inheritance, defaults to none. A
|
||||
more detailed description follows in the
|
||||
*Defining Inheritance Mappings* section.
|
||||
- **read-only** - (>= 2.1) Specifies that this entity is marked as read only and not
|
||||
- **read-only** - Specifies that this entity is marked as read only and not
|
||||
considered for change-tracking. Entities of this type can be persisted
|
||||
and removed though.
|
||||
- **schema** - (>= 2.5) The schema the table lies in, for platforms that support schemas
|
||||
- **schema** - The schema the table lies in, for platforms that support schemas
|
||||
|
||||
Defining Fields
|
||||
~~~~~~~~~~~~~~~
|
||||
@@ -293,7 +291,7 @@ Defining Identity and Generator Strategies
|
||||
|
||||
An entity has to have at least one ``<id />`` element. For
|
||||
composite keys you can specify more than one id-element, however
|
||||
surrogate keys are recommended for use with Doctrine 2. The Id
|
||||
surrogate keys are recommended for use with Doctrine ORM. The Id
|
||||
field allows to define properties of the identifier and allows a
|
||||
subset of the ``<field />`` element attributes:
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
Composite and Foreign Keys as Primary Key
|
||||
=========================================
|
||||
|
||||
.. versionadded:: 2.1
|
||||
|
||||
Doctrine 2 supports composite primary keys natively. Composite keys are a very powerful relational database concept
|
||||
and we took good care to make sure Doctrine 2 supports as many of the composite primary key use-cases.
|
||||
For Doctrine 2.0 composite keys of primitive data-types are supported, for Doctrine 2.1 even foreign keys as
|
||||
Doctrine ORM supports composite primary keys natively. Composite keys are a very powerful relational database concept
|
||||
and we took good care to make sure Doctrine ORM supports as many of the composite primary key use-cases.
|
||||
For Doctrine ORM composite keys of primitive data-types are supported, even foreign keys as
|
||||
primary keys are supported.
|
||||
|
||||
This tutorial shows how the semantics of composite primary keys work and how they map to the database.
|
||||
@@ -19,7 +17,7 @@ the ID fields have to have their values set before you call ``EntityManager#pers
|
||||
Primitive Types only
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Even in version 2.0 you can have composite keys as long as they only consist of the primitive types
|
||||
You can have composite keys as long as they only consist of the primitive types
|
||||
``integer`` and ``string``. Suppose you want to create a database of cars and use the model-name
|
||||
and year of production as primary keys:
|
||||
|
||||
@@ -120,10 +118,6 @@ and to ``year`` to the related entities.
|
||||
Identity through foreign Entities
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. note::
|
||||
|
||||
Identity through foreign entities is only supported with Doctrine 2.1
|
||||
|
||||
There are tons of use-cases where the identity of an Entity should be determined by the entity
|
||||
of one or many parent entities.
|
||||
|
||||
|
||||
@@ -3,21 +3,21 @@ Extra Lazy Associations
|
||||
|
||||
.. versionadded:: 2.1
|
||||
|
||||
In many cases associations between entities can get pretty large. Even in a simple scenario like a blog
|
||||
In many cases associations between entities can get pretty large. Even in a simple scenario like a blog.
|
||||
where posts can be commented, you always have to assume that a post draws hundreds of comments.
|
||||
In Doctrine 2.0 if you accessed an association it would always get loaded completely into memory. This
|
||||
In Doctrine ORM if you accessed an association it would always get loaded completely into memory. This
|
||||
can lead to pretty serious performance problems, if your associations contain several hundreds or thousands
|
||||
of entities.
|
||||
|
||||
With Doctrine 2.1 a feature called **Extra Lazy** is introduced for associations. Associations
|
||||
Doctrine ORM includes a feature called **Extra Lazy** for associations. Associations
|
||||
are marked as **Lazy** by default, which means the whole collection object for an association is populated
|
||||
the first time its accessed. If you mark an association as extra lazy the following methods on collections
|
||||
can be called without triggering a full load of the collection:
|
||||
|
||||
- ``Collection#contains($entity)``
|
||||
- ``Collection#containsKey($key)`` (available with Doctrine 2.5)
|
||||
- ``Collection#containsKey($key)``
|
||||
- ``Collection#count()``
|
||||
- ``Collection#get($key)`` (available with Doctrine 2.4)
|
||||
- ``Collection#get($key)``
|
||||
- ``Collection#slice($offset, $length = null)``
|
||||
|
||||
For each of the above methods the following semantics apply:
|
||||
@@ -25,7 +25,7 @@ For each of the above methods the following semantics apply:
|
||||
- For each call, if the Collection is not yet loaded, issue a straight SELECT statement against the database.
|
||||
- For each call, if the collection is already loaded, fallback to the default functionality for lazy collections. No additional SELECT statements are executed.
|
||||
|
||||
Additionally even with Doctrine 2.0 the following methods do not trigger the collection load:
|
||||
Additionally even with Doctrine ORM the following methods do not trigger the collection load:
|
||||
|
||||
- ``Collection#add($entity)``
|
||||
- ``Collection#offsetSet($key, $entity)`` - ArrayAccess with no specific key ``$coll[] = $entity``, it does
|
||||
|
||||
@@ -20,8 +20,7 @@ development is said to use the *Database First* approach to Doctrine.
|
||||
|
||||
In this workflow you would modify the database schema first and then
|
||||
regenerate the PHP code to use with this schema. You need a flexible
|
||||
code-generator for this task and up to Doctrine 2.2, the code generator hasn't
|
||||
been flexible enough to achieve this.
|
||||
code-generator for this task.
|
||||
|
||||
We spinned off a subproject, Doctrine CodeGenerator, that will fill this gap and
|
||||
allow you to do *Database First* development.
|
||||
|
||||
@@ -23,15 +23,10 @@ installed:
|
||||
|
||||
The code of this tutorial is `available on Github <https://github.com/doctrine/doctrine2-orm-tutorial>`_.
|
||||
|
||||
.. note::
|
||||
|
||||
This tutorial assumes you work with **Doctrine 2.6** and above.
|
||||
Some of the code will not work with lower versions.
|
||||
|
||||
What is Doctrine?
|
||||
-----------------
|
||||
|
||||
Doctrine 2 is an `object-relational mapper (ORM) <https://en.wikipedia.org/wiki/Object-relational_mapping>`_
|
||||
Doctrine ORM is an `object-relational mapper (ORM) <https://en.wikipedia.org/wiki/Object-relational_mapping>`_
|
||||
for PHP 7.1+ that provides transparent persistence for PHP objects. It uses the Data Mapper
|
||||
pattern at the heart, aiming for a complete separation of your domain/business
|
||||
logic from the persistence in a relational database management system.
|
||||
@@ -123,7 +118,7 @@ Obtaining the EntityManager
|
||||
Doctrine's public interface is through the ``EntityManager``. This class
|
||||
provides access points to the complete lifecycle management for your entities,
|
||||
and transforms entities from and back to persistence. You have to
|
||||
configure and create it to use your entities with Doctrine 2. I
|
||||
configure and create it to use your entities with Doctrine ORM. I
|
||||
will show the configuration steps and then discuss them step by
|
||||
step:
|
||||
|
||||
@@ -133,9 +128,9 @@ step:
|
||||
// bootstrap.php
|
||||
use Doctrine\ORM\Tools\Setup;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
|
||||
|
||||
require_once "vendor/autoload.php";
|
||||
|
||||
|
||||
// Create a simple "default" Doctrine ORM configuration for Annotations
|
||||
$isDevMode = true;
|
||||
$proxyDir = null;
|
||||
@@ -145,13 +140,13 @@ step:
|
||||
// or if you prefer yaml or XML
|
||||
//$config = Setup::createXMLMetadataConfiguration(array(__DIR__."/config/xml"), $isDevMode);
|
||||
//$config = Setup::createYAMLMetadataConfiguration(array(__DIR__."/config/yaml"), $isDevMode);
|
||||
|
||||
|
||||
// database configuration parameters
|
||||
$conn = array(
|
||||
'driver' => 'pdo_sqlite',
|
||||
'path' => __DIR__ . '/db.sqlite',
|
||||
);
|
||||
|
||||
|
||||
// obtaining the entity manager
|
||||
$entityManager = EntityManager::create($conn, $config);
|
||||
|
||||
@@ -193,7 +188,7 @@ defined entity classes and their metadata. For this tool to work, a
|
||||
<?php
|
||||
// cli-config.php
|
||||
require_once "bootstrap.php";
|
||||
|
||||
|
||||
return \Doctrine\ORM\Tools\Console\ConsoleRunner::createHelperSet($entityManager);
|
||||
|
||||
Now call the Doctrine command-line tool:
|
||||
@@ -299,14 +294,14 @@ but you only need to choose one.
|
||||
*/
|
||||
class Product
|
||||
{
|
||||
/**
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue
|
||||
*/
|
||||
protected $id;
|
||||
/**
|
||||
* @ORM\Column(type="string")
|
||||
/**
|
||||
* @ORM\Column(type="string")
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
@@ -562,7 +557,7 @@ classes. We'll store them in ``src/Bug.php`` and ``src/User.php``, respectively.
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="users")
|
||||
*/
|
||||
class User
|
||||
@@ -610,7 +605,7 @@ foreign keys through their own identities.
|
||||
For every foreign key you either have a Doctrine ManyToOne or OneToOne
|
||||
association. On the inverse sides of these foreign keys you can have
|
||||
OneToMany associations. Obviously you can have ManyToMany associations
|
||||
that connect two tables with each other through a join table with
|
||||
that connect two tables with each other through a join table with
|
||||
two foreign keys.
|
||||
|
||||
Now that you know the basics about references in Doctrine, we can extend the
|
||||
@@ -679,8 +674,8 @@ careful to implement a bidirectional reference in the domain model.
|
||||
The concept of owning or inverse side of a relation is central to
|
||||
this notion and should always be kept in mind. The following
|
||||
assumptions are made about relations and have to be followed to be
|
||||
able to work with Doctrine 2. These assumptions are not unique to
|
||||
Doctrine 2 but are best practices in handling database relations
|
||||
able to work with Doctrine ORM. These assumptions are not unique to
|
||||
Doctrine ORM but are best practices in handling database relations
|
||||
and Object-Relational Mapping.
|
||||
|
||||
- In a one-to-one relation, the entity holding the foreign key of
|
||||
@@ -832,14 +827,14 @@ the ``Product`` before:
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="bugs")
|
||||
*/
|
||||
class Bug
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue
|
||||
*/
|
||||
protected $id;
|
||||
@@ -936,8 +931,8 @@ the ``Product`` before:
|
||||
|
||||
|
||||
Here we have the entity, id and primitive type definitions.
|
||||
For the "created" field we have used the ``datetime`` type,
|
||||
which translates the YYYY-mm-dd HH:mm:ss database format
|
||||
For the "created" field we have used the ``datetime`` type,
|
||||
which translates the YYYY-mm-dd HH:mm:ss database format
|
||||
into a PHP DateTime instance and back.
|
||||
|
||||
After the field definitions, the two qualified references to the
|
||||
@@ -975,8 +970,8 @@ Finally, we'll add metadata mappings for the ``User`` entity.
|
||||
class User
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
* @var int
|
||||
*/
|
||||
@@ -1215,10 +1210,10 @@ The console output of this script is then:
|
||||
|
||||
|
||||
As a last resort you can still use Native SQL and a description of the
|
||||
result set to retrieve entities from the database. DQL boils down to a
|
||||
Native SQL statement and a ``ResultSetMapping`` instance itself. Using
|
||||
Native SQL you could even use stored procedures for data retrieval, or
|
||||
make use of advanced non-portable database queries like PostgreSql's
|
||||
result set to retrieve entities from the database. DQL boils down to a
|
||||
Native SQL statement and a ``ResultSetMapping`` instance itself. Using
|
||||
Native SQL you could even use stored procedures for data retrieval, or
|
||||
make use of advanced non-portable database queries like PostgreSql's
|
||||
recursive queries.
|
||||
|
||||
|
||||
@@ -1231,7 +1226,7 @@ objects only from Doctrine however. For a simple list view like the
|
||||
previous one we only need read access to our entities and can
|
||||
switch the hydration from objects to simple PHP arrays instead.
|
||||
|
||||
Hydration can be an expensive process so only retrieving what you need can
|
||||
Hydration can be an expensive process so only retrieving what you need can
|
||||
yield considerable performance benefits for read-only requests.
|
||||
|
||||
Implementing the same list view as before using array hydration we
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
Pagination
|
||||
==========
|
||||
|
||||
.. versionadded:: 2.2
|
||||
|
||||
Starting with version 2.2 Doctrine ships with a Paginator for DQL queries. It
|
||||
Doctrine ORM ships with a Paginator for DQL queries. It
|
||||
has a very simple API and implements the SPL interfaces ``Countable`` and
|
||||
``IteratorAggregate``.
|
||||
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
Working with Indexed Associations
|
||||
=================================
|
||||
|
||||
.. note::
|
||||
|
||||
This feature is available from version 2.1 of Doctrine.
|
||||
|
||||
Doctrine 2 collections are modelled after PHPs native arrays. PHP arrays are an ordered hashmap, but in
|
||||
Doctrine ORM collections are modelled after PHPs native arrays. PHP arrays are an ordered hashmap, but in
|
||||
the first version of Doctrine keys retrieved from the database were always numerical unless ``INDEX BY``
|
||||
was used. Starting with Doctrine 2.1 you can index your collections by a value in the related entity.
|
||||
was used. You can index your collections by a value in the related entity.
|
||||
This is a first step towards full ordered hashmap support through the Doctrine ORM.
|
||||
The feature works like an implicit ``INDEX BY`` for the selected association but has several
|
||||
downsides also:
|
||||
|
||||
@@ -19,14 +19,28 @@
|
||||
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
use Doctrine\Common\Util\ClassUtils;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Countable;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\DBAL\Cache\QueryCacheProfile;
|
||||
use Doctrine\ORM\Mapping\MappingException as ORMMappingException;
|
||||
use Doctrine\ORM\Query\Parameter;
|
||||
use Doctrine\ORM\Cache\QueryCacheKey;
|
||||
use Doctrine\Persistence\Mapping\MappingException;
|
||||
use Traversable;
|
||||
use function array_map;
|
||||
use function array_shift;
|
||||
use function count;
|
||||
use function is_array;
|
||||
use function is_numeric;
|
||||
use function is_object;
|
||||
use function is_scalar;
|
||||
use function iterator_count;
|
||||
use function iterator_to_array;
|
||||
use function ksort;
|
||||
use function reset;
|
||||
use function serialize;
|
||||
use function sha1;
|
||||
use function trigger_error;
|
||||
use const E_USER_DEPRECATED;
|
||||
|
||||
/**
|
||||
* Base contract for ORM queries. Base class for Query and NativeQuery.
|
||||
@@ -406,8 +420,8 @@ abstract class AbstractQuery
|
||||
return $value;
|
||||
}
|
||||
|
||||
if ($value instanceof Collection) {
|
||||
$value = $value->toArray();
|
||||
if ($value instanceof Traversable) {
|
||||
$value = iterator_to_array($value);
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
@@ -433,7 +447,7 @@ abstract class AbstractQuery
|
||||
if ($value === null) {
|
||||
throw ORMInvalidArgumentException::invalidIdentifierBindingEntity();
|
||||
}
|
||||
} catch (MappingException | ORMMappingException $e) {
|
||||
} catch (ORMMappingException $e) {
|
||||
// Silence any mapping exceptions. These can occur if the object in
|
||||
// question is not a mapped entity, in which case we just don't do
|
||||
// any preparation on the value.
|
||||
@@ -916,6 +930,8 @@ abstract class AbstractQuery
|
||||
* Executes the query and returns an IterableResult that can be used to incrementally
|
||||
* iterate over the result.
|
||||
*
|
||||
* @deprecated
|
||||
*
|
||||
* @param ArrayCollection|array|null $parameters The query parameters.
|
||||
* @param string|int|null $hydrationMode The hydration mode to use.
|
||||
*
|
||||
@@ -923,6 +939,11 @@ abstract class AbstractQuery
|
||||
*/
|
||||
public function iterate($parameters = null, $hydrationMode = null)
|
||||
{
|
||||
@trigger_error(
|
||||
'Method ' . __METHOD__ . '() is deprecated and will be removed in Doctrine ORM 3.0. Use toIterable() instead.',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
|
||||
if ($hydrationMode !== null) {
|
||||
$this->setHydrationMode($hydrationMode);
|
||||
}
|
||||
@@ -937,6 +958,33 @@ abstract class AbstractQuery
|
||||
return $this->_em->newHydrator($this->_hydrationMode)->iterate($stmt, $rsm, $this->_hints);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the query and returns an iterable that can be used to incrementally
|
||||
* iterate over the result.
|
||||
*
|
||||
* @param ArrayCollection|mixed[] $parameters The query parameters.
|
||||
* @param string|int|null $hydrationMode The hydration mode to use.
|
||||
*
|
||||
* @return iterable<mixed>
|
||||
*/
|
||||
public function toIterable(iterable $parameters = [], $hydrationMode = null) : iterable
|
||||
{
|
||||
if ($hydrationMode !== null) {
|
||||
$this->setHydrationMode($hydrationMode);
|
||||
}
|
||||
|
||||
if (($this->isCountable($parameters) && count($parameters) !== 0)
|
||||
|| ($parameters instanceof Traversable && iterator_count($parameters) !== 0)
|
||||
) {
|
||||
$this->setParameters($parameters);
|
||||
}
|
||||
|
||||
$rsm = $this->getResultSetMapping();
|
||||
$stmt = $this->_doExecute();
|
||||
|
||||
return $this->_em->newHydrator($this->_hydrationMode)->toIterable($stmt, $rsm, $this->_hints);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the query.
|
||||
*
|
||||
@@ -1170,4 +1218,10 @@ abstract class AbstractQuery
|
||||
|
||||
return sha1($query . '-' . serialize($params) . '-' . serialize($hints));
|
||||
}
|
||||
|
||||
/** @param iterable<mixed> $subject */
|
||||
private function isCountable(iterable $subject) : bool
|
||||
{
|
||||
return $subject instanceof Countable || is_array($subject);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -937,5 +937,3 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
$this->_attributes['defaultQueryHints'][$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
interface_exists(MappingDriver::class);
|
||||
|
||||
@@ -388,6 +388,10 @@ use function trigger_error;
|
||||
* @throws ORMInvalidArgumentException
|
||||
* @throws TransactionRequiredException
|
||||
* @throws ORMException
|
||||
*
|
||||
* @template T
|
||||
* @psalm-param class-string<T> $entityName
|
||||
* @psalm-return ?T
|
||||
*/
|
||||
public function find($className, $id, $lockMode = null, $lockVersion = null)
|
||||
{
|
||||
@@ -733,6 +737,10 @@ use function trigger_error;
|
||||
* @param string $entityName The name of the entity.
|
||||
*
|
||||
* @return ObjectRepository|EntityRepository The repository class.
|
||||
*
|
||||
* @template T
|
||||
* @psalm-param class-string<T> $entityName
|
||||
* @psalm-return EntityRepository<T>
|
||||
*/
|
||||
public function getRepository($entityName)
|
||||
{
|
||||
|
||||
@@ -153,6 +153,10 @@ interface EntityManagerInterface extends ObjectManager
|
||||
* @return object|null The entity reference.
|
||||
*
|
||||
* @throws ORMException
|
||||
*
|
||||
* @template T
|
||||
* @psalm-param class-string<T> $entityName
|
||||
* @psalm-return ?T
|
||||
*/
|
||||
public function getReference($entityName, $id);
|
||||
|
||||
|
||||
@@ -21,9 +21,13 @@ namespace Doctrine\ORM;
|
||||
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\Common\Collections\Selectable;
|
||||
use Doctrine\Common\Inflector\Inflector;
|
||||
use Doctrine\Inflector\Inflector;
|
||||
use Doctrine\Inflector\InflectorFactory;
|
||||
use Doctrine\ORM\Query\ResultSetMappingBuilder;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
use const E_USER_DEPRECATED;
|
||||
use function lcfirst;
|
||||
use function trigger_error;
|
||||
|
||||
/**
|
||||
* An EntityRepository serves as a repository for entities with generic as well as
|
||||
@@ -37,6 +41,10 @@ use Doctrine\Persistence\ObjectRepository;
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*
|
||||
* @template T
|
||||
* @template-implements Selectable<int,T>
|
||||
* @template-implements ObjectRepository<T>
|
||||
*/
|
||||
class EntityRepository implements ObjectRepository, Selectable
|
||||
{
|
||||
@@ -55,8 +63,13 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
*/
|
||||
protected $_class;
|
||||
|
||||
/** @var Inflector */
|
||||
private static $inflector;
|
||||
|
||||
/**
|
||||
* Initializes a new <tt>EntityRepository</tt>.
|
||||
*
|
||||
* @psalm-param Mapping\ClassMetadata<T>
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $em, Mapping\ClassMetadata $class)
|
||||
{
|
||||
@@ -129,9 +142,13 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
* Clears the repository, causing all managed entities to become detached.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @deprecated 2.8 This method is being removed from the ORM and won't have any replacement
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
@trigger_error('Method ' . __METHOD__ . '() is deprecated and will be removed in Doctrine ORM 3.0.', E_USER_DEPRECATED);
|
||||
|
||||
$this->_em->clear($this->_class->rootEntityName);
|
||||
}
|
||||
|
||||
@@ -145,6 +162,8 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
* @param int|null $lockVersion The lock version.
|
||||
*
|
||||
* @return object|null The entity instance or NULL if the entity can not be found.
|
||||
*
|
||||
* @psalm-return ?T
|
||||
*/
|
||||
public function find($id, $lockMode = null, $lockVersion = null)
|
||||
{
|
||||
@@ -155,6 +174,8 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
* Finds all entities in the repository.
|
||||
*
|
||||
* @return array The entities.
|
||||
*
|
||||
* @psalm-return list<T>
|
||||
*/
|
||||
public function findAll()
|
||||
{
|
||||
@@ -170,6 +191,8 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
* @param int|null $offset
|
||||
*
|
||||
* @return array The objects.
|
||||
*
|
||||
* @psalm-return list<T>
|
||||
*/
|
||||
public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
{
|
||||
@@ -185,6 +208,8 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
* @param array|null $orderBy
|
||||
*
|
||||
* @return object|null The entity instance or NULL if the entity can not be found.
|
||||
*
|
||||
* @psalm-return ?T
|
||||
*/
|
||||
public function findOneBy(array $criteria, array $orderBy = null)
|
||||
{
|
||||
@@ -277,6 +302,8 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
* @param \Doctrine\Common\Collections\Criteria $criteria
|
||||
*
|
||||
* @return \Doctrine\Common\Collections\Collection
|
||||
*
|
||||
* @psalm-return \Doctrine\Common\Collections\Collection<int, T>
|
||||
*/
|
||||
public function matching(Criteria $criteria)
|
||||
{
|
||||
@@ -302,7 +329,11 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
throw ORMException::findByRequiresParameter($method . $by);
|
||||
}
|
||||
|
||||
$fieldName = lcfirst(Inflector::classify($by));
|
||||
if (self::$inflector === null) {
|
||||
self::$inflector = InflectorFactory::create()->build();
|
||||
}
|
||||
|
||||
$fieldName = lcfirst(self::$inflector->classify($by));
|
||||
|
||||
if (! ($this->_class->hasField($fieldName) || $this->_class->hasAssociation($fieldName))) {
|
||||
throw ORMException::invalidMagicCall($this->_entityName, $fieldName, $method . $by);
|
||||
|
||||
@@ -84,5 +84,3 @@ class OnClassMetadataNotFoundEventArgs extends ManagerEventArgs
|
||||
return $this->className;
|
||||
}
|
||||
}
|
||||
|
||||
interface_exists(ClassMetadata::class);
|
||||
|
||||
@@ -19,14 +19,20 @@
|
||||
|
||||
namespace Doctrine\ORM\Internal\Hydration;
|
||||
|
||||
use Doctrine\DBAL\Driver\Statement;
|
||||
use Doctrine\DBAL\FetchMode;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Events;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker;
|
||||
use PDO;
|
||||
use const E_USER_DEPRECATED;
|
||||
use function array_map;
|
||||
use function end;
|
||||
use function in_array;
|
||||
use function trigger_error;
|
||||
|
||||
/**
|
||||
* Base class for all hydrators. A hydrator is a class that provides some form
|
||||
@@ -110,6 +116,8 @@ abstract class AbstractHydrator
|
||||
/**
|
||||
* Initiates a row-by-row hydration.
|
||||
*
|
||||
* @deprecated
|
||||
*
|
||||
* @param object $stmt
|
||||
* @param object $resultSetMapping
|
||||
* @param array $hints
|
||||
@@ -118,6 +126,11 @@ abstract class AbstractHydrator
|
||||
*/
|
||||
public function iterate($stmt, $resultSetMapping, array $hints = [])
|
||||
{
|
||||
@trigger_error(
|
||||
'Method ' . __METHOD__ . '() is deprecated and will be removed in Doctrine ORM 3.0. Use toIterable() instead.',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
|
||||
$this->_stmt = $stmt;
|
||||
$this->_rsm = $resultSetMapping;
|
||||
$this->_hints = $hints;
|
||||
@@ -131,6 +144,42 @@ abstract class AbstractHydrator
|
||||
return new IterableResult($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates a row-by-row hydration.
|
||||
*
|
||||
* @param mixed[] $hints
|
||||
*
|
||||
* @return iterable<mixed>
|
||||
*/
|
||||
public function toIterable(Statement $stmt, ResultSetMapping $resultSetMapping, array $hints = []) : iterable
|
||||
{
|
||||
$this->_stmt = $stmt;
|
||||
$this->_rsm = $resultSetMapping;
|
||||
$this->_hints = $hints;
|
||||
|
||||
$evm = $this->_em->getEventManager();
|
||||
|
||||
$evm->addEventListener([Events::onClear], $this);
|
||||
|
||||
$this->prepare();
|
||||
|
||||
$result = [];
|
||||
|
||||
while (true) {
|
||||
$row = $this->_stmt->fetch(FetchMode::ASSOCIATIVE);
|
||||
|
||||
if ($row === false || $row === null) {
|
||||
$this->cleanup();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$this->hydrateRowData($row, $result);
|
||||
|
||||
yield end($result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hydrates all rows returned by the passed statement instance at once.
|
||||
*
|
||||
@@ -159,7 +208,7 @@ abstract class AbstractHydrator
|
||||
|
||||
/**
|
||||
* Hydrates a single row returned by the current statement instance during
|
||||
* row-by-row hydration with {@link iterate()}.
|
||||
* row-by-row hydration with {@link iterate()} or {@link toIterable()}.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
@@ -167,7 +216,7 @@ abstract class AbstractHydrator
|
||||
{
|
||||
$row = $this->_stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ( ! $row) {
|
||||
if ($row === false || $row === null) {
|
||||
$this->cleanup();
|
||||
|
||||
return false;
|
||||
|
||||
@@ -23,8 +23,7 @@ namespace Doctrine\ORM\Internal\Hydration;
|
||||
* Represents a result structure that can be iterated over, hydrating row-by-row
|
||||
* during the iteration. An IterableResult is obtained by AbstractHydrator#iterate().
|
||||
*
|
||||
* @author robo
|
||||
* @since 2.0
|
||||
* @deprecated
|
||||
*/
|
||||
class IterableResult implements \Iterator
|
||||
{
|
||||
|
||||
@@ -33,7 +33,6 @@ use Doctrine\Persistence\Mapping\Driver\MappingDriver;
|
||||
use Doctrine\Persistence\Mapping\ReflectionService;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
use function assert;
|
||||
use function interface_exists;
|
||||
|
||||
/**
|
||||
@@ -804,6 +803,3 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
return $this->targetPlatform;
|
||||
}
|
||||
}
|
||||
|
||||
interface_exists(ClassMetadataInterface::class);
|
||||
interface_exists(ReflectionService::class);
|
||||
|
||||
@@ -693,5 +693,3 @@ class AnnotationDriver extends AbstractAnnotationDriver
|
||||
return new self($reader, $paths);
|
||||
}
|
||||
}
|
||||
|
||||
interface_exists(ClassMetadata::class);
|
||||
|
||||
@@ -19,19 +19,21 @@
|
||||
|
||||
namespace Doctrine\ORM\Mapping\Driver;
|
||||
|
||||
use Doctrine\Common\Inflector\Inflector;
|
||||
use Doctrine\DBAL\Schema\AbstractSchemaManager;
|
||||
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
|
||||
use Doctrine\DBAL\Schema\SchemaException;
|
||||
use Doctrine\DBAL\Schema\Table;
|
||||
use Doctrine\DBAL\Schema\Column;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\Inflector\Inflector;
|
||||
use Doctrine\Inflector\InflectorFactory;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
use Doctrine\ORM\Mapping\MappingException;
|
||||
use Doctrine\Persistence\Mapping\ClassMetadata;
|
||||
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
|
||||
use function interface_exists;
|
||||
use function preg_replace;
|
||||
use function strtolower;
|
||||
|
||||
/**
|
||||
* The DatabaseDriver reverse engineers the mapping metadata from a database.
|
||||
@@ -81,12 +83,16 @@ class DatabaseDriver implements MappingDriver
|
||||
*/
|
||||
private $namespace;
|
||||
|
||||
/** @var Inflector */
|
||||
private $inflector;
|
||||
|
||||
/**
|
||||
* @param AbstractSchemaManager $schemaManager
|
||||
*/
|
||||
public function __construct(AbstractSchemaManager $schemaManager)
|
||||
{
|
||||
$this->_sm = $schemaManager;
|
||||
$this->inflector = InflectorFactory::create()->build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,6 +176,11 @@ class DatabaseDriver implements MappingDriver
|
||||
}
|
||||
}
|
||||
|
||||
public function setInflector(Inflector $inflector) : void
|
||||
{
|
||||
$this->inflector = $inflector;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@@ -547,7 +558,7 @@ class DatabaseDriver implements MappingDriver
|
||||
return $this->namespace . $this->classNamesForTables[$tableName];
|
||||
}
|
||||
|
||||
return $this->namespace . Inflector::classify(strtolower($tableName));
|
||||
return $this->namespace . $this->inflector->classify(strtolower($tableName));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -572,8 +583,6 @@ class DatabaseDriver implements MappingDriver
|
||||
$columnName = preg_replace('/_id$/', '', $columnName);
|
||||
}
|
||||
|
||||
return Inflector::camelize($columnName);
|
||||
return $this->inflector->camelize($columnName);
|
||||
}
|
||||
}
|
||||
|
||||
interface_exists(ClassMetadata::class);
|
||||
|
||||
@@ -903,5 +903,3 @@ class XmlDriver extends FileDriver
|
||||
return ($flag == "true" || $flag == "1");
|
||||
}
|
||||
}
|
||||
|
||||
interface_exists(ClassMetadata::class);
|
||||
|
||||
@@ -845,5 +845,3 @@ class YamlDriver extends FileDriver
|
||||
return Yaml::parse(file_get_contents($file));
|
||||
}
|
||||
}
|
||||
|
||||
interface_exists(ClassMetadata::class);
|
||||
|
||||
@@ -210,5 +210,3 @@ class ProxyFactory extends AbstractProxyFactory
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
interface_exists(ClassMetadata::class);
|
||||
|
||||
@@ -694,6 +694,14 @@ final class Query extends AbstractQuery
|
||||
return parent::iterate($parameters, $hydrationMode);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public function toIterable(iterable $parameters = [], $hydrationMode = self::HYDRATE_OBJECT) : iterable
|
||||
{
|
||||
$this->setHint(self::HINT_INTERNAL_ITERATION, true);
|
||||
|
||||
return parent::toIterable($parameters, $hydrationMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
@@ -24,7 +24,7 @@ use Doctrine\ORM\Query\Lexer;
|
||||
/**
|
||||
* "ABS" "(" SimpleArithmeticExpression ")"
|
||||
*
|
||||
*
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\ORM\Query\AST\TypedExpression;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
use Doctrine\ORM\Query\AST\AggregateExpression;
|
||||
@@ -29,7 +31,7 @@ use Doctrine\ORM\Query\AST\AggregateExpression;
|
||||
* @since 2.6
|
||||
* @author Mathew Davies <thepixeldeveloper@icloud.com>
|
||||
*/
|
||||
final class CountFunction extends FunctionNode
|
||||
final class CountFunction extends FunctionNode implements TypedExpression
|
||||
{
|
||||
/**
|
||||
* @var AggregateExpression
|
||||
@@ -51,4 +53,9 @@ final class CountFunction extends FunctionNode
|
||||
{
|
||||
$this->aggregateExpression = $parser->AggregateExpression();
|
||||
}
|
||||
|
||||
public function getReturnType() : Type
|
||||
{
|
||||
return Type::getType(Type::INTEGER);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ use Doctrine\ORM\Query\AST\Node;
|
||||
/**
|
||||
* Abstract Function Node.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\ORM\Query\AST\TypedExpression;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
|
||||
/**
|
||||
@@ -32,7 +34,7 @@ use Doctrine\ORM\Query\Lexer;
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class LengthFunction extends FunctionNode
|
||||
class LengthFunction extends FunctionNode implements TypedExpression
|
||||
{
|
||||
public $stringPrimary;
|
||||
|
||||
@@ -60,4 +62,9 @@ class LengthFunction extends FunctionNode
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
|
||||
public function getReturnType() : Type
|
||||
{
|
||||
return Type::getType(Type::INTEGER);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ use Doctrine\ORM\Query\Lexer;
|
||||
/**
|
||||
* "SQRT" "(" SimpleArithmeticExpression ")"
|
||||
*
|
||||
*
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
|
||||
15
lib/Doctrine/ORM/Query/AST/TypedExpression.php
Normal file
15
lib/Doctrine/ORM/Query/AST/TypedExpression.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
|
||||
/**
|
||||
* Provides an API for resolving the type of a Node
|
||||
*/
|
||||
interface TypedExpression
|
||||
{
|
||||
public function getReturnType() : Type;
|
||||
}
|
||||
@@ -19,6 +19,10 @@
|
||||
|
||||
namespace Doctrine\ORM\Query;
|
||||
|
||||
use Traversable;
|
||||
use function is_iterable;
|
||||
use function iterator_to_array;
|
||||
|
||||
/**
|
||||
* This class is used to generate DQL expressions via a set of PHP static functions.
|
||||
*
|
||||
@@ -442,7 +446,11 @@ class Expr
|
||||
*/
|
||||
public function in($x, $y)
|
||||
{
|
||||
if (is_array($y)) {
|
||||
if (is_iterable($y)) {
|
||||
if ($y instanceof Traversable) {
|
||||
$y = iterator_to_array($y);
|
||||
}
|
||||
|
||||
foreach ($y as &$literal) {
|
||||
if ( ! ($literal instanceof Expr\Literal)) {
|
||||
$literal = $this->_quoteLiteral($literal);
|
||||
@@ -463,7 +471,11 @@ class Expr
|
||||
*/
|
||||
public function notIn($x, $y)
|
||||
{
|
||||
if (is_array($y)) {
|
||||
if (is_iterable($y)) {
|
||||
if ($y instanceof Traversable) {
|
||||
$y = iterator_to_array($y);
|
||||
}
|
||||
|
||||
foreach ($y as &$literal) {
|
||||
if ( ! ($literal instanceof Expr\Literal)) {
|
||||
$literal = $this->_quoteLiteral($literal);
|
||||
|
||||
@@ -145,7 +145,7 @@ class Lexer extends AbstractLexer
|
||||
*/
|
||||
protected function getNonCatchablePatterns()
|
||||
{
|
||||
return ['\s+', '(.)'];
|
||||
return ['\s+', '--.*', '(.)'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1495,7 +1495,7 @@ class Parser
|
||||
|
||||
/**
|
||||
* OrderByItem ::= (
|
||||
* SimpleArithmeticExpression | SingleValuedPathExpression |
|
||||
* SimpleArithmeticExpression | SingleValuedPathExpression | CaseExpression |
|
||||
* ScalarExpression | ResultVariable | FunctionDeclaration
|
||||
* ) ["ASC" | "DESC"]
|
||||
*
|
||||
@@ -1525,6 +1525,10 @@ class Parser
|
||||
$expr = $this->ScalarExpression();
|
||||
break;
|
||||
|
||||
case $this->lexer->lookahead['type'] === Lexer::T_CASE:
|
||||
$expr = $this->CaseExpression();
|
||||
break;
|
||||
|
||||
case $this->isFunction():
|
||||
$expr = $this->FunctionDeclaration();
|
||||
break;
|
||||
|
||||
@@ -1349,10 +1349,20 @@ class SqlWalker implements TreeWalker
|
||||
|
||||
$this->scalarResultAliasMap[$resultAlias] = $columnAlias;
|
||||
|
||||
if ( ! $hidden) {
|
||||
// We cannot resolve field type here; assume 'string'.
|
||||
$this->rsm->addScalarResult($columnAlias, $resultAlias, 'string');
|
||||
if ($hidden) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (! $expr instanceof Query\AST\TypedExpression) {
|
||||
// Conceptually we could resolve field type here by traverse through AST to retrieve field type,
|
||||
// but this is not a feasible solution; assume 'string'.
|
||||
$this->rsm->addScalarResult($columnAlias, $resultAlias, 'string');
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$this->rsm->addScalarResult($columnAlias, $resultAlias, $expr->getReturnType()->getName());
|
||||
|
||||
break;
|
||||
|
||||
case ($expr instanceof AST\Subselect):
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
namespace Doctrine\ORM\Tools;
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
use Doctrine\Common\Inflector\Inflector;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\Inflector\InflectorFactory;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
/**
|
||||
@@ -293,6 +293,8 @@ class ConvertDoctrine1Schema
|
||||
return;
|
||||
}
|
||||
|
||||
$inflector = InflectorFactory::create()->build();
|
||||
|
||||
foreach ($model['relations'] as $name => $relation) {
|
||||
if ( ! isset($relation['alias'])) {
|
||||
$relation['alias'] = $name;
|
||||
@@ -301,7 +303,7 @@ class ConvertDoctrine1Schema
|
||||
$relation['class'] = $name;
|
||||
}
|
||||
if ( ! isset($relation['local'])) {
|
||||
$relation['local'] = Inflector::tableize($relation['class']);
|
||||
$relation['local'] = $inflector->tableize($relation['class']);
|
||||
}
|
||||
if ( ! isset($relation['foreign'])) {
|
||||
$relation['foreign'] = 'id';
|
||||
|
||||
@@ -20,11 +20,13 @@
|
||||
namespace Doctrine\ORM\Tools;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\Common\Inflector\Inflector;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\Inflector\Inflector;
|
||||
use Doctrine\Inflector\InflectorFactory;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
use ReflectionClass;
|
||||
use const E_USER_DEPRECATED;
|
||||
use const PHP_VERSION_ID;
|
||||
use function str_replace;
|
||||
use function trigger_error;
|
||||
use function var_export;
|
||||
@@ -336,6 +338,9 @@ public function __construct(<params>)
|
||||
}
|
||||
';
|
||||
|
||||
/** @var Inflector */
|
||||
protected $inflector;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
@@ -344,6 +349,7 @@ public function __construct(<params>)
|
||||
@trigger_error(self::class . ' is deprecated and will be removed in Doctrine ORM 3.0', E_USER_DEPRECATED);
|
||||
|
||||
$this->annotationsPrefix = 'ORM\\';
|
||||
$this->inflector = InflectorFactory::create()->build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -593,6 +599,11 @@ public function __construct(<params>)
|
||||
$this->backupExisting = $bool;
|
||||
}
|
||||
|
||||
public function setInflector(Inflector $inflector) : void
|
||||
{
|
||||
$this->inflector = $inflector;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*
|
||||
@@ -809,6 +820,8 @@ public function __construct(<params>)
|
||||
/**
|
||||
* @todo this won't work if there is a namespace in brackets and a class outside of it.
|
||||
*
|
||||
* @psalm-suppress UndefinedConstant
|
||||
*
|
||||
* @param string $src
|
||||
*
|
||||
* @return void
|
||||
@@ -832,6 +845,8 @@ public function __construct(<params>)
|
||||
if ($inNamespace) {
|
||||
if (in_array($token[0], [T_NS_SEPARATOR, T_STRING], true)) {
|
||||
$lastSeenNamespace .= $token[1];
|
||||
} elseif (PHP_VERSION_ID >= 80000 && ($token[0] === T_NAME_QUALIFIED || $token[0] === T_NAME_FULLY_QUALIFIED)) {
|
||||
$lastSeenNamespace .= $token[1];
|
||||
} elseif (is_string($token) && in_array($token, [';', '{'], true)) {
|
||||
$inNamespace = false;
|
||||
}
|
||||
@@ -1380,11 +1395,12 @@ public function __construct(<params>)
|
||||
*/
|
||||
protected function generateEntityStubMethod(ClassMetadataInfo $metadata, $type, $fieldName, $typeHint = null, $defaultValue = null)
|
||||
{
|
||||
$methodName = $type . Inflector::classify($fieldName);
|
||||
$variableName = Inflector::camelize($fieldName);
|
||||
$methodName = $type . $this->inflector->classify($fieldName);
|
||||
$variableName = $this->inflector->camelize($fieldName);
|
||||
|
||||
if (in_array($type, ["add", "remove"])) {
|
||||
$methodName = Inflector::singularize($methodName);
|
||||
$variableName = Inflector::singularize($variableName);
|
||||
$methodName = $this->inflector->singularize($methodName);
|
||||
$variableName = $this->inflector->singularize($variableName);
|
||||
}
|
||||
|
||||
if ($this->hasMethod($methodName, $metadata)) {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
namespace Doctrine\ORM\Tools\Pagination;
|
||||
|
||||
use ArrayIterator;
|
||||
use Doctrine\ORM\NoResultException;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
@@ -33,6 +34,8 @@ use function array_sum;
|
||||
* @author Pablo Díez <pablodip@gmail.com>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @license New BSD
|
||||
*
|
||||
* @template T
|
||||
*/
|
||||
class Paginator implements \Countable, \IteratorAggregate
|
||||
{
|
||||
@@ -134,6 +137,8 @@ class Paginator implements \Countable, \IteratorAggregate
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ArrayIterator<mixed, T>
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
@@ -156,7 +161,7 @@ class Paginator implements \Countable, \IteratorAggregate
|
||||
|
||||
// don't do this for an empty id array
|
||||
if ($foundIdRows === []) {
|
||||
return new \ArrayIterator([]);
|
||||
return new ArrayIterator([]);
|
||||
}
|
||||
|
||||
$whereInQuery = $this->cloneQuery($this->query);
|
||||
@@ -179,7 +184,7 @@ class Paginator implements \Countable, \IteratorAggregate
|
||||
;
|
||||
}
|
||||
|
||||
return new \ArrayIterator($result);
|
||||
return new ArrayIterator($result);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace Doctrine\ORM\Tools;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use function count;
|
||||
|
||||
/**
|
||||
* Performs strict validation of the mapping schema
|
||||
@@ -96,6 +97,12 @@ class SchemaValidator
|
||||
}
|
||||
}
|
||||
|
||||
if ($class->isEmbeddedClass && count($class->associationMappings) > 0) {
|
||||
$ce[] = "Embeddable '" . $class->name . "' does not support associations";
|
||||
|
||||
return $ce;
|
||||
}
|
||||
|
||||
foreach ($class->associationMappings as $fieldName => $assoc) {
|
||||
if (!class_exists($assoc['targetEntity']) || $cmf->isTransient($assoc['targetEntity'])) {
|
||||
$ce[] = "The target entity '" . $assoc['targetEntity'] . "' specified on " . $class->name . '#' . $fieldName . ' is unknown or not an entity.';
|
||||
|
||||
@@ -47,6 +47,7 @@ use InvalidArgumentException;
|
||||
use Throwable;
|
||||
use UnexpectedValueException;
|
||||
use function get_class;
|
||||
use function is_object;
|
||||
use function spl_object_hash;
|
||||
|
||||
/**
|
||||
@@ -425,10 +426,18 @@ class UnitOfWork implements PropertyChangedListener
|
||||
}
|
||||
}
|
||||
|
||||
$conn->commit();
|
||||
// Commit failed silently
|
||||
if ($conn->commit() === false) {
|
||||
$object = is_object($entity) ? $entity : null;
|
||||
|
||||
throw new OptimisticLockException('Commit failed', $object);
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
$this->em->close();
|
||||
$conn->rollBack();
|
||||
|
||||
if ($conn->isTransactionActive()) {
|
||||
$conn->rollBack();
|
||||
}
|
||||
|
||||
$this->afterTransactionRolledBack();
|
||||
|
||||
|
||||
@@ -44,5 +44,3 @@ final class HierarchyDiscriminatorResolver
|
||||
return $discriminators;
|
||||
}
|
||||
}
|
||||
|
||||
interface_exists(ClassMetadata::class);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<exclude-pattern>*/tests/Doctrine/Tests/Proxies/__CG__/*</exclude-pattern>
|
||||
|
||||
<rule ref="Doctrine">
|
||||
<exclude name="SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingParameterTypeHint"/>
|
||||
<exclude name="SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingAnyTypeHint" />
|
||||
<exclude name="SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingReturnTypeHint"/>
|
||||
<exclude name="SlevomatCodingStandard.Exceptions.ReferenceThrowableOnly.ReferencedGeneralException"/>
|
||||
<exclude name="SlevomatCodingStandard.ControlStructures.EarlyExit"/>
|
||||
@@ -37,10 +37,14 @@
|
||||
<exclude-pattern>lib/Doctrine/ORM/Tools/ToolEvents.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingTraversablePropertyTypeHintSpecification">
|
||||
<rule ref="SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingTraversableTypeHintSpecification">
|
||||
<exclude-pattern>lib/Doctrine/ORM/Annotation/*</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.Operators.DisallowEqualOperators.DisallowedNotEqualOperator">
|
||||
<exclude-pattern>lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="PSR1.Methods.CamelCapsMethodName.NotCamelCaps">
|
||||
<exclude-pattern>lib/Doctrine/ORM/Query/Parser.php</exclude-pattern>
|
||||
</rule>
|
||||
@@ -105,7 +109,7 @@
|
||||
<exclude-pattern>lib/Doctrine/ORM/EntityManagerInterface.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingPropertyTypeHint">
|
||||
<rule name="SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingAnyTypeHint">
|
||||
<exclude-pattern>*/tests/*</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
@@ -113,7 +117,7 @@
|
||||
<exclude-pattern>*/tests/*</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingTraversableParameterTypeHintSpecification">
|
||||
<rule ref="SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingTraversableTypeHintSpecification">
|
||||
<exclude-pattern>*/tests/*</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
@@ -121,11 +125,11 @@
|
||||
<exclude-pattern>*/tests/*</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingTraversablePropertyTypeHintSpecification">
|
||||
<rule ref="SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingTraversableTypeHintSpecification">
|
||||
<exclude-pattern>*/tests/*</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingTraversableReturnTypeHintSpecification">
|
||||
<rule ref="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingTraversableTypeHintSpecification">
|
||||
<exclude-pattern>*/tests/*</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
|
||||
37
tests/Doctrine/Tests/IterableTester.php
Normal file
37
tests/Doctrine/Tests/IterableTester.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests;
|
||||
|
||||
use Doctrine\ORM\AbstractQuery;
|
||||
use Doctrine\ORM\Query;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use function is_array;
|
||||
use function iterator_to_array;
|
||||
|
||||
final class IterableTester
|
||||
{
|
||||
public static function assertResultsAreTheSame(Query $query) : void
|
||||
{
|
||||
$result = $query->getResult();
|
||||
$iterable = $query->toIterable();
|
||||
|
||||
Assert::assertSame($result, self::iterableToArray($iterable));
|
||||
|
||||
$result = $query->getResult(AbstractQuery::HYDRATE_ARRAY);
|
||||
$iterable = $query->toIterable([], AbstractQuery::HYDRATE_ARRAY);
|
||||
|
||||
Assert::assertSame($result, self::iterableToArray($iterable));
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the iterable into an array. If the iterable is already an array, return it.
|
||||
*
|
||||
* @return mixed[]
|
||||
*/
|
||||
public static function iterableToArray(iterable $iterable) : array
|
||||
{
|
||||
return is_array($iterable) ? $iterable : iterator_to_array($iterable, true);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\Tests\IterableTester;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
/**
|
||||
@@ -73,6 +74,10 @@ class AdvancedAssociationTest extends OrmFunctionalTestCase
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
IterableTester::assertResultsAreTheSame($query);
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
// test2 - eager load in DQL query with double-join back and forth
|
||||
$query = $this->_em->createQuery("SELECT p,t,pp FROM Doctrine\Tests\ORM\Functional\Phrase p JOIN p.type t JOIN t.phrases pp");
|
||||
$res = $query->getResult();
|
||||
@@ -100,6 +105,10 @@ class AdvancedAssociationTest extends OrmFunctionalTestCase
|
||||
|
||||
$this->assertInstanceOf(Definition::class, $definitions[0]);
|
||||
$this->assertEquals(2, $definitions->count());
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
IterableTester::assertResultsAreTheSame($query);
|
||||
}
|
||||
|
||||
public function testManyToMany()
|
||||
@@ -123,6 +132,10 @@ class AdvancedAssociationTest extends OrmFunctionalTestCase
|
||||
$types = $res[0]->getTypes();
|
||||
|
||||
$this->assertInstanceOf(Type::class, $types[0]);
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
IterableTester::assertResultsAreTheSame($query);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\Tests\IterableTester;
|
||||
use Doctrine\Tests\Models\Company\CompanyEmployee,
|
||||
Doctrine\Tests\Models\Company\CompanyManager,
|
||||
Doctrine\Tests\Models\Company\CompanyCar;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
use function count;
|
||||
|
||||
/**
|
||||
* Functional Query tests.
|
||||
@@ -37,6 +39,24 @@ class AdvancedDqlQueryTest extends OrmFunctionalTestCase
|
||||
$this->assertEquals(600000, $result[1]['avgSalary']);
|
||||
}
|
||||
|
||||
public function testCommentsInDQL()
|
||||
{
|
||||
//same test than testAggregateWithHavingClause but with comments into the DQL
|
||||
$dql = "SELECT p.department, AVG(p.salary) AS avgSalary -- comment end of line
|
||||
-- comment with 'strange chars', & $
|
||||
FROM Doctrine\\Tests\\Models\\Company\\CompanyEmployee p
|
||||
-- comment beginning of line GROUP BY
|
||||
GROUP BY p.department HAVING SUM(p.salary) > 200000 ORDER BY p.department -- comment end of line";
|
||||
|
||||
$result = $this->_em->createQuery($dql)->getScalarResult();
|
||||
|
||||
$this->assertEquals(2, count($result));
|
||||
$this->assertEquals('IT', $result[0]['department']);
|
||||
$this->assertEquals(150000, $result[0]['avgSalary']);
|
||||
$this->assertEquals('IT2', $result[1]['department']);
|
||||
$this->assertEquals(600000, $result[1]['avgSalary']);
|
||||
}
|
||||
|
||||
public function testUnnamedScalarResultsAreOneBased()
|
||||
{
|
||||
$dql = 'SELECT p.department, AVG(p.salary) '.
|
||||
@@ -74,11 +94,58 @@ class AdvancedDqlQueryTest extends OrmFunctionalTestCase
|
||||
$this->assertEquals(1, $result[3]['friends']);
|
||||
}
|
||||
|
||||
public function testOrderBySimpleCaseExpression() : void
|
||||
{
|
||||
$dql = <<<'DQL'
|
||||
SELECT p.name
|
||||
FROM Doctrine\Tests\Models\Company\CompanyEmployee p
|
||||
ORDER BY CASE p.name
|
||||
WHEN 'Jonathan W.' THEN 1
|
||||
WHEN 'Roman B.' THEN 2
|
||||
WHEN 'Guilherme B.' THEN 3
|
||||
ELSE 4
|
||||
END DESC
|
||||
DQL;
|
||||
|
||||
$result = $this->_em->createQuery($dql)->getScalarResult();
|
||||
|
||||
self::assertCount(4, $result);
|
||||
|
||||
self::assertEquals('Benjamin E.', $result[0]['name']);
|
||||
self::assertEquals('Guilherme B.', $result[1]['name']);
|
||||
self::assertEquals('Roman B.', $result[2]['name']);
|
||||
self::assertEquals('Jonathan W.', $result[3]['name']);
|
||||
}
|
||||
|
||||
public function testOrderByGeneralCaseExpression() : void
|
||||
{
|
||||
$dql = <<<'DQL'
|
||||
SELECT p.name
|
||||
FROM Doctrine\Tests\Models\Company\CompanyEmployee p
|
||||
ORDER BY CASE
|
||||
WHEN p.name='Jonathan W.' THEN 1
|
||||
WHEN p.name='Roman B.' THEN 2
|
||||
WHEN p.name='Guilherme B.' THEN 3
|
||||
ELSE 4
|
||||
END DESC
|
||||
DQL;
|
||||
|
||||
$result = $this->_em->createQuery($dql)->getScalarResult();
|
||||
|
||||
self::assertCount(4, $result);
|
||||
|
||||
self::assertEquals('Benjamin E.', $result[0]['name']);
|
||||
self::assertEquals('Guilherme B.', $result[1]['name']);
|
||||
self::assertEquals('Roman B.', $result[2]['name']);
|
||||
self::assertEquals('Jonathan W.', $result[3]['name']);
|
||||
}
|
||||
|
||||
public function testIsNullAssociation()
|
||||
{
|
||||
$dql = 'SELECT p FROM Doctrine\Tests\Models\Company\CompanyPerson p '.
|
||||
$dql = 'SELECT p FROM Doctrine\Tests\Models\Company\CompanyPerson p ' .
|
||||
'WHERE p.spouse IS NULL';
|
||||
$result = $this->_em->createQuery($dql)->getResult();
|
||||
$query = $this->_em->createQuery($dql);
|
||||
$result = $query->getResult();
|
||||
|
||||
$this->assertEquals(2, count($result));
|
||||
$this->assertTrue($result[0]->getId() > 0);
|
||||
@@ -86,35 +153,56 @@ class AdvancedDqlQueryTest extends OrmFunctionalTestCase
|
||||
|
||||
$this->assertTrue($result[1]->getId() > 0);
|
||||
$this->assertNull($result[1]->getSpouse());
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
IterableTester::assertResultsAreTheSame($query);
|
||||
}
|
||||
|
||||
public function testSelectSubselect()
|
||||
{
|
||||
$dql = 'SELECT p, (SELECT c.brand FROM Doctrine\Tests\Models\Company\CompanyCar c WHERE p.car = c) brandName '.
|
||||
$dql = 'SELECT p, (SELECT c.brand FROM Doctrine\Tests\Models\Company\CompanyCar c WHERE p.car = c) brandName ' .
|
||||
'FROM Doctrine\Tests\Models\Company\CompanyManager p';
|
||||
$result = $this->_em->createQuery($dql)->getArrayResult();
|
||||
$query = $this->_em->createQuery($dql);
|
||||
$result = $query->getArrayResult();
|
||||
|
||||
$this->assertEquals(1, count($result));
|
||||
$this->assertEquals("Caramba", $result[0]['brandName']);
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
IterableTester::assertResultsAreTheSame($query);
|
||||
}
|
||||
|
||||
public function testInSubselect()
|
||||
{
|
||||
$dql = "SELECT p.name FROM Doctrine\Tests\Models\Company\CompanyPerson p ".
|
||||
"WHERE p.name IN (SELECT n.name FROM Doctrine\Tests\Models\Company\CompanyPerson n WHERE n.name = 'Roman B.')";
|
||||
$result = $this->_em->createQuery($dql)->getScalarResult();
|
||||
$dql = <<<DQL
|
||||
SELECT p.name FROM Doctrine\Tests\Models\Company\CompanyPerson p
|
||||
WHERE p.name IN (SELECT n.name FROM Doctrine\Tests\Models\Company\CompanyPerson n WHERE n.name = 'Roman B.')
|
||||
DQL;
|
||||
$query = $this->_em->createQuery($dql);
|
||||
$result = $query->getScalarResult();
|
||||
|
||||
$this->assertEquals(1, count($result));
|
||||
$this->assertEquals('Roman B.', $result[0]['name']);
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
IterableTester::assertResultsAreTheSame($query);
|
||||
}
|
||||
|
||||
public function testGroupByMultipleFields()
|
||||
{
|
||||
$dql = 'SELECT p.department, p.name, count(p.id) FROM Doctrine\Tests\Models\Company\CompanyEmployee p '.
|
||||
$dql = 'SELECT p.department, p.name, count(p.id) FROM Doctrine\Tests\Models\Company\CompanyEmployee p ' .
|
||||
'GROUP BY p.department, p.name';
|
||||
$result = $this->_em->createQuery($dql)->getResult();
|
||||
$query = $this->_em->createQuery($dql);
|
||||
$result = $query->getResult();
|
||||
|
||||
$this->assertEquals(4, count($result));
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
IterableTester::assertResultsAreTheSame($query);
|
||||
}
|
||||
|
||||
public function testUpdateAs()
|
||||
@@ -122,8 +210,14 @@ class AdvancedDqlQueryTest extends OrmFunctionalTestCase
|
||||
$dql = 'UPDATE Doctrine\Tests\Models\Company\CompanyEmployee AS p SET p.salary = 1';
|
||||
$this->_em->createQuery($dql)->execute();
|
||||
|
||||
$this->assertTrue(count($this->_em->createQuery(
|
||||
'SELECT count(p.id) FROM Doctrine\Tests\Models\Company\CompanyEmployee p WHERE p.salary = 1')->getResult()) > 0);
|
||||
$query = $this->_em->createQuery(
|
||||
'SELECT count(p.id) FROM Doctrine\Tests\Models\Company\CompanyEmployee p WHERE p.salary = 1'
|
||||
);
|
||||
self::assertGreaterThan(0, $query->getResult());
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
IterableTester::assertResultsAreTheSame($query);
|
||||
}
|
||||
|
||||
public function testDeleteAs()
|
||||
|
||||
@@ -10,6 +10,7 @@ use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Proxy\Proxy;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
use Doctrine\Tests\IterableTester;
|
||||
use Doctrine\Tests\Models\CMS\CmsAddress;
|
||||
use Doctrine\Tests\Models\CMS\CmsArticle;
|
||||
use Doctrine\Tests\Models\CMS\CmsComment;
|
||||
@@ -230,6 +231,10 @@ class BasicFunctionalTest extends OrmFunctionalTestCase
|
||||
//$this->assertNull($users[0]->phonenumbers);
|
||||
//$this->assertNull($users[0]->articles);
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
IterableTester::assertResultsAreTheSame($query);
|
||||
|
||||
$usersArray = $query->getArrayResult();
|
||||
|
||||
$this->assertTrue(is_array($usersArray));
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace Doctrine\Tests\ORM\Functional;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Proxy\Proxy;
|
||||
use Doctrine\Tests\IterableTester;
|
||||
use Doctrine\Tests\Models\Company\CompanyAuction;
|
||||
use Doctrine\Tests\Models\Company\CompanyEmployee;
|
||||
use Doctrine\Tests\Models\Company\CompanyEvent;
|
||||
@@ -62,15 +63,23 @@ class ClassTableInheritanceTest extends OrmFunctionalTestCase
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
IterableTester::assertResultsAreTheSame($query);
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$query = $this->_em->createQuery('select p from ' . CompanyEmployee::class . ' p');
|
||||
|
||||
$entities = $query->getResult();
|
||||
|
||||
$this->assertCount(1, $entities);
|
||||
$this->assertInstanceOf(CompanyEmployee::class, $entities[0]);
|
||||
self::assertCount(1, $entities);
|
||||
self::assertInstanceOf(CompanyEmployee::class, $entities[0]);
|
||||
$this->assertTrue(is_numeric($entities[0]->getId()));
|
||||
$this->assertEquals('Guilherme Blanco', $entities[0]->getName());
|
||||
$this->assertEquals(100000, $entities[0]->getSalary());
|
||||
self::assertEquals('Guilherme Blanco', $entities[0]->getName());
|
||||
self::assertEquals(100000, $entities[0]->getSalary());
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
IterableTester::assertResultsAreTheSame($query);
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
@@ -170,6 +179,10 @@ class ClassTableInheritanceTest extends OrmFunctionalTestCase
|
||||
$this->assertInstanceOf(CompanyEmployee::class, $result[0]->getSpouse());
|
||||
$this->assertEquals('John Smith', $result[0]->getSpouse()->getName());
|
||||
$this->assertSame($result[0], $result[0]->getSpouse()->getSpouse());
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
IterableTester::assertResultsAreTheSame($query);
|
||||
}
|
||||
|
||||
public function testSelfReferencingManyToMany()
|
||||
@@ -242,6 +255,10 @@ class ClassTableInheritanceTest extends OrmFunctionalTestCase
|
||||
$this->assertInstanceOf(CompanyRaffle::class, $events[0]);
|
||||
$this->assertInstanceOf(CompanyAuction::class, $events[1]);
|
||||
}
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
IterableTester::assertResultsAreTheSame($q);
|
||||
}
|
||||
|
||||
public function testLazyLoading2()
|
||||
@@ -264,6 +281,10 @@ class ClassTableInheritanceTest extends OrmFunctionalTestCase
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
IterableTester::assertResultsAreTheSame($q);
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$q = $this->_em->createQuery('select a from ' . CompanyOrganization::class . ' a where a.id = ?1');
|
||||
$q->setParameter(1, $org->getId());
|
||||
|
||||
@@ -276,6 +297,10 @@ class ClassTableInheritanceTest extends OrmFunctionalTestCase
|
||||
// mainEvent should have been loaded because it can't be lazy
|
||||
$this->assertInstanceOf(CompanyAuction::class, $mainEvent);
|
||||
$this->assertNotInstanceOf(Proxy::class, $mainEvent);
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
IterableTester::assertResultsAreTheSame($q);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -286,10 +311,14 @@ class ClassTableInheritanceTest extends OrmFunctionalTestCase
|
||||
$this->_em->createQuery('UPDATE ' . CompanyEmployee::class . ' AS p SET p.salary = 1')
|
||||
->execute();
|
||||
|
||||
$result = $this->_em->createQuery('SELECT count(p.id) FROM ' . CompanyEmployee::class . ' p WHERE p.salary = 1')
|
||||
->getResult();
|
||||
$query = $this->_em->createQuery('SELECT count(p.id) FROM ' . CompanyEmployee::class . ' p WHERE p.salary = 1');
|
||||
$result = $query->getResult();
|
||||
|
||||
$this->assertGreaterThan(0, count($result));
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
IterableTester::assertResultsAreTheSame($query);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
use Doctrine\ORM\ORMException;
|
||||
use Doctrine\ORM\Query\QueryException;
|
||||
use Doctrine\Tests\IterableTester;
|
||||
use Doctrine\Tests\Models\Navigation\NavCountry;
|
||||
use Doctrine\Tests\Models\Navigation\NavPointOfInterest;
|
||||
use Doctrine\Tests\Models\Navigation\NavTour;
|
||||
@@ -86,11 +87,16 @@ class CompositePrimaryKeyTest extends OrmFunctionalTestCase
|
||||
$this->_em->clear();
|
||||
|
||||
$dql = "SELECT IDENTITY(p.poi, 'long') AS long, IDENTITY(p.poi, 'lat') AS lat FROM Doctrine\Tests\Models\Navigation\NavPhotos p";
|
||||
$result = $this->_em->createQuery($dql)->getResult();
|
||||
$query = $this->_em->createQuery($dql);
|
||||
$result = $query->getResult();
|
||||
|
||||
$this->assertCount(1, $result);
|
||||
$this->assertEquals(200, $result[0]['long']);
|
||||
$this->assertEquals(100, $result[0]['lat']);
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
IterableTester::assertResultsAreTheSame($query);
|
||||
}
|
||||
|
||||
public function testManyToManyCompositeRelation()
|
||||
@@ -112,7 +118,10 @@ class CompositePrimaryKeyTest extends OrmFunctionalTestCase
|
||||
'INNER JOIN t.pois p INNER JOIN p.country c';
|
||||
$tours = $this->_em->createQuery($dql)->getResult();
|
||||
|
||||
$this->assertEquals(1, count($tours));
|
||||
$query = $this->_em->createQuery($dql);
|
||||
$tours = $query->getResult();
|
||||
|
||||
self::assertCount(1, $tours);
|
||||
|
||||
$pois = $tours[0]->getPointOfInterests();
|
||||
|
||||
@@ -133,6 +142,10 @@ class CompositePrimaryKeyTest extends OrmFunctionalTestCase
|
||||
->getResult();
|
||||
|
||||
$this->assertEquals(1, count($tours));
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
IterableTester::assertResultsAreTheSame($query);
|
||||
}
|
||||
|
||||
public function testSpecifyUnknownIdentifierPrimaryKeyFails()
|
||||
|
||||
@@ -1118,5 +1118,18 @@ class EntityRepositoryTest extends OrmFunctionalTestCase
|
||||
$this->assertTrue(in_array($user, [$user1, $user2]));
|
||||
}
|
||||
}
|
||||
|
||||
public function testDeprecatedClear() : void
|
||||
{
|
||||
$repository = $this->_em->getRepository(CmsAddress::class);
|
||||
|
||||
$this->expectDeprecationMessageSame(
|
||||
'Method Doctrine\ORM\EntityRepository::clear() is deprecated and will be removed in Doctrine ORM 3.0.'
|
||||
);
|
||||
$this->expectDeprecationMessageSame(
|
||||
'Calling Doctrine\ORM\EntityManager::clear() with any arguments to clear specific entities is deprecated and will not be supported in Doctrine ORM 3.0.'
|
||||
);
|
||||
$repository->clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use Doctrine\ORM\Event\PreFlushEventArgs;
|
||||
use Doctrine\ORM\Event\PreUpdateEventArgs;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
use function sprintf;
|
||||
|
||||
class LifecycleCallbackTest extends OrmFunctionalTestCase
|
||||
{
|
||||
@@ -232,10 +233,9 @@ WHERE
|
||||
e.id IN (%s, %s)
|
||||
DQL;
|
||||
|
||||
$result = $this
|
||||
->_em
|
||||
->createQuery(sprintf($dql, $e1->getId(), $e2->getId()))
|
||||
->iterate();
|
||||
$query = $this->_em->createQuery(sprintf($dql, $e1->getId(), $e2->getId()));
|
||||
|
||||
$result = $query->iterate();
|
||||
|
||||
foreach ($result as $entity) {
|
||||
$this->assertTrue($entity[0]->postLoadCallbackInvoked);
|
||||
@@ -243,6 +243,15 @@ DQL;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$iterableResult = $query->toIterable();
|
||||
|
||||
foreach ($iterableResult as $entity) {
|
||||
self::assertTrue($entity->postLoadCallbackInvoked);
|
||||
self::assertFalse($entity->postLoadCascaderNotNull);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @group DDC-54
|
||||
@@ -256,10 +265,11 @@ DQL;
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$result = $this
|
||||
->_em
|
||||
->createQuery('SELECT e FROM Doctrine\Tests\ORM\Functional\LifecycleCallbackTestEntity AS e')
|
||||
->iterate(null, Query::HYDRATE_SIMPLEOBJECT);
|
||||
$query = $this->_em->createQuery(
|
||||
'SELECT e FROM Doctrine\Tests\ORM\Functional\LifecycleCallbackTestEntity AS e'
|
||||
);
|
||||
|
||||
$result = $query->iterate(null, Query::HYDRATE_SIMPLEOBJECT);
|
||||
|
||||
foreach ($result as $entity) {
|
||||
$this->assertTrue($entity[0]->postLoadCallbackInvoked);
|
||||
@@ -267,6 +277,15 @@ DQL;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$result = $query->toIterable([], Query::HYDRATE_SIMPLEOBJECT);
|
||||
|
||||
foreach ($result as $entity) {
|
||||
self::assertTrue($entity->postLoadCallbackInvoked);
|
||||
self::assertFalse($entity->postLoadCascaderNotNull);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,7 +26,7 @@ class OneToOneInverseSideLoadAfterDqlQueryTest extends OrmFunctionalTestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @group 6759
|
||||
* @group GH-6759
|
||||
*/
|
||||
public function testInverseSideOneToOneLoadedAfterDqlQuery(): void
|
||||
{
|
||||
|
||||
@@ -312,8 +312,7 @@ class QueryDqlFunctionTest extends OrmFunctionalTestCase
|
||||
self::assertEqualsWithDelta(
|
||||
(new \DateTimeImmutable($result['now']))->modify(sprintf('+%d %s', $amount, $unit)),
|
||||
new \DateTimeImmutable($result['add']),
|
||||
$delta,
|
||||
''
|
||||
$delta
|
||||
);
|
||||
}
|
||||
|
||||
@@ -342,8 +341,7 @@ class QueryDqlFunctionTest extends OrmFunctionalTestCase
|
||||
self::assertEqualsWithDelta(
|
||||
(new \DateTimeImmutable($result['now']))->modify(sprintf('-%d %s', $amount, $unit)),
|
||||
new \DateTimeImmutable($result['sub']),
|
||||
$delta,
|
||||
''
|
||||
$delta
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
67
tests/Doctrine/Tests/ORM/Functional/QueryIterableTest.php
Normal file
67
tests/Doctrine/Tests/ORM/Functional/QueryIterableTest.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\Tests\IterableTester;
|
||||
use Doctrine\Tests\Models\CMS\CmsAddress;
|
||||
use Doctrine\Tests\Models\CMS\CmsUser;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
final class QueryIterableTest extends OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp() : void
|
||||
{
|
||||
$this->useModelSet('cms');
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function testAlias() : void
|
||||
{
|
||||
$user = new CmsUser();
|
||||
$user->name = 'Guilherme';
|
||||
$user->username = 'gblanco';
|
||||
$user->status = 'developer';
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
|
||||
$query = $this->_em->createQuery('SELECT u AS user FROM Doctrine\Tests\Models\CMS\CmsUser u');
|
||||
|
||||
$users = $query->getResult();
|
||||
self::assertCount(1, $users);
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
IterableTester::assertResultsAreTheSame($query);
|
||||
}
|
||||
|
||||
public function testAliasInnerJoin() : void
|
||||
{
|
||||
$user = new CmsUser();
|
||||
$user->name = 'Guilherme';
|
||||
$user->username = 'gblanco';
|
||||
$user->status = 'developer';
|
||||
|
||||
$address = new CmsAddress();
|
||||
$address->country = 'Germany';
|
||||
$address->city = 'Berlin';
|
||||
$address->zip = '12345';
|
||||
|
||||
$address->user = $user;
|
||||
$user->address = $address;
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
|
||||
$query = $this->_em->createQuery('SELECT u AS user, a AS address FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.address a');
|
||||
|
||||
$users = $query->getResult();
|
||||
self::assertCount(1, $users);
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
IterableTester::assertResultsAreTheSame($query);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ use Doctrine\ORM\NonUniqueResultException;
|
||||
use Doctrine\ORM\Proxy\Proxy;
|
||||
use Doctrine\ORM\Query\QueryException;
|
||||
use Doctrine\ORM\UnexpectedResultException;
|
||||
use Doctrine\Tests\IterableTester;
|
||||
use Doctrine\Tests\Models\CMS\CmsUser,
|
||||
Doctrine\Tests\Models\CMS\CmsArticle,
|
||||
Doctrine\Tests\Models\CMS\CmsPhonenumber;
|
||||
@@ -15,6 +16,8 @@ use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Query\Parameter;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
use function count;
|
||||
use function iterator_to_array;
|
||||
|
||||
/**
|
||||
* Functional Query tests.
|
||||
@@ -217,26 +220,27 @@ class QueryTest extends OrmFunctionalTestCase
|
||||
$query = $this->_em->createQuery('select a from ' . CmsArticle::class . ' a WHERE a.topic = ?1');
|
||||
$articles = $query->iterate(new ArrayCollection([new Parameter(1, 'Doctrine 2')]), Query::HYDRATE_ARRAY);
|
||||
|
||||
$found = [];
|
||||
$expectedArticle = [
|
||||
'id' => $articleId,
|
||||
'topic' => 'Doctrine 2',
|
||||
'text' => 'This is an introduction to Doctrine 2.',
|
||||
'version' => 1,
|
||||
];
|
||||
|
||||
foreach ($articles AS $article) {
|
||||
$found[] = $article;
|
||||
}
|
||||
$articles = iterator_to_array($articles, false);
|
||||
|
||||
$this->assertEquals(1, count($found));
|
||||
$this->assertSame(
|
||||
[
|
||||
[
|
||||
[
|
||||
'id' => $articleId,
|
||||
'topic' => 'Doctrine 2',
|
||||
'text' => 'This is an introduction to Doctrine 2.',
|
||||
'version' => 1,
|
||||
],
|
||||
],
|
||||
],
|
||||
$found
|
||||
self::assertCount(1, $articles);
|
||||
self::assertEquals([[$expectedArticle]], $articles);
|
||||
|
||||
$articles = $query->toIterable(
|
||||
new ArrayCollection([new Parameter(1, 'Doctrine 2')]),
|
||||
Query::HYDRATE_ARRAY
|
||||
);
|
||||
|
||||
$articles = IterableTester::iterableToArray($articles);
|
||||
|
||||
self::assertCount(1, $articles);
|
||||
self::assertEquals([$expectedArticle], $articles);
|
||||
}
|
||||
|
||||
public function testIterateResult_IterativelyBuildUpUnitOfWork()
|
||||
@@ -275,8 +279,23 @@ class QueryTest extends OrmFunctionalTestCase
|
||||
$this->assertSame(["Doctrine 2", "Symfony 2"], $topics);
|
||||
$this->assertSame(2, $iteratedCount);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
$articles = $query->toIterable();
|
||||
|
||||
$iteratedCount = 0;
|
||||
$topics = [];
|
||||
|
||||
foreach ($articles as $article) {
|
||||
$topics[] = $article->topic;
|
||||
|
||||
$identityMap = $this->_em->getUnitOfWork()->getIdentityMap();
|
||||
$identityMapCount = count($identityMap[CmsArticle::class]);
|
||||
self::assertGreaterThan($iteratedCount, $identityMapCount);
|
||||
|
||||
$iteratedCount++;
|
||||
}
|
||||
|
||||
self::assertSame(['Doctrine 2', 'Symfony 2'], $topics);
|
||||
self::assertSame(2, $iteratedCount);
|
||||
}
|
||||
|
||||
public function testIterateResultClearEveryCycle()
|
||||
@@ -295,9 +314,9 @@ class QueryTest extends OrmFunctionalTestCase
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$query = $this->_em->createQuery("select a from Doctrine\Tests\Models\CMS\CmsArticle a");
|
||||
$articles = $query->iterate();
|
||||
$query = $this->_em->createQuery('select a from Doctrine\Tests\Models\CMS\CmsArticle a');
|
||||
|
||||
$articles = $query->iterate();
|
||||
$iteratedCount = 0;
|
||||
$topics = [];
|
||||
foreach($articles AS $row) {
|
||||
@@ -309,6 +328,20 @@ class QueryTest extends OrmFunctionalTestCase
|
||||
$iteratedCount++;
|
||||
}
|
||||
|
||||
self::assertSame(['Doctrine 2', 'Symfony 2'], $topics);
|
||||
self::assertSame(2, $iteratedCount);
|
||||
|
||||
$articles = $query->toIterable();
|
||||
$iteratedCount = 0;
|
||||
$topics = [];
|
||||
foreach ($articles as $article) {
|
||||
$topics[] = $article->topic;
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$iteratedCount++;
|
||||
}
|
||||
|
||||
$this->assertSame(["Doctrine 2", "Symfony 2"], $topics);
|
||||
$this->assertSame(2, $iteratedCount);
|
||||
|
||||
@@ -317,9 +350,17 @@ class QueryTest extends OrmFunctionalTestCase
|
||||
|
||||
public function testIterateResult_FetchJoinedCollection_ThrowsException()
|
||||
{
|
||||
$this->expectException('Doctrine\ORM\Query\QueryException');
|
||||
$this->expectException(QueryException::class);
|
||||
$query = $this->_em->createQuery("SELECT u, a FROM ' . CmsUser::class . ' u JOIN u.articles a");
|
||||
$articles = $query->iterate();
|
||||
$query->iterate();
|
||||
}
|
||||
|
||||
public function testToIterableResultFetchJoinedCollectionThrowsException() : void
|
||||
{
|
||||
$this->expectException(QueryException::class);
|
||||
|
||||
$query = $this->_em->createQuery("SELECT u, a FROM ' . CmsUser::class . ' u JOIN u.articles a");
|
||||
$query->toIterable();
|
||||
}
|
||||
|
||||
public function testGetSingleResultThrowsExceptionOnNoResult()
|
||||
|
||||
@@ -16,7 +16,6 @@ class DDC144Test extends OrmFunctionalTestCase
|
||||
$this->_em->getClassMetadata(DDC144Operand::class),
|
||||
]
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
use Doctrine\ORM\Events;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
use Doctrine\Tests\Models\CMS\CmsUser;
|
||||
use ReflectionClass;
|
||||
use ReflectionObject;
|
||||
|
||||
/**
|
||||
* @group DDC-3123
|
||||
@@ -38,8 +38,9 @@ class DDC3123Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
->expects($this->once())
|
||||
->method(Events::postFlush)
|
||||
->will($this->returnCallback(function () use ($uow, $test) {
|
||||
$class = new ReflectionClass(UnitOfWork::class);
|
||||
$property = $class->getProperty('extraUpdates');
|
||||
$reflection = new ReflectionObject($uow);
|
||||
$property = $reflection->getProperty('extraUpdates');
|
||||
|
||||
$property->setAccessible(true);
|
||||
$test->assertEmpty(
|
||||
$property->getValue($uow),
|
||||
|
||||
@@ -13,9 +13,9 @@ class DDC3303Test extends OrmFunctionalTestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @group 4097
|
||||
* @group 4277
|
||||
* @group 5867
|
||||
* @group GH-4097
|
||||
* @group GH-4277
|
||||
* @group GH-5867
|
||||
*
|
||||
* When using an embedded field in an inheritance, private properties should also be inherited.
|
||||
*/
|
||||
|
||||
@@ -27,7 +27,8 @@ class DDC3597Test extends OrmFunctionalTestCase
|
||||
/**
|
||||
* @group DDC-3597
|
||||
*/
|
||||
public function testSaveImageEntity() {
|
||||
public function testSaveImageEntity(): void
|
||||
{
|
||||
$imageEntity = new DDC3597Image('foobar');
|
||||
$imageEntity->setFormat('JPG');
|
||||
$imageEntity->setSize(123);
|
||||
|
||||
@@ -6,7 +6,7 @@ use Doctrine\Common\Cache\ArrayCache;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
/**
|
||||
* @group 2947
|
||||
* @group GH-2947
|
||||
*/
|
||||
class GH2947Test extends OrmFunctionalTestCase
|
||||
{
|
||||
|
||||
@@ -25,7 +25,7 @@ final class GH5562Test extends OrmFunctionalTestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @group 5562
|
||||
* @group GH-5562
|
||||
*/
|
||||
public function testCacheShouldBeUpdatedWhenAssociationChanges()
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ use Doctrine\ORM\Id\AbstractIdGenerator;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
/**
|
||||
* @group 5804
|
||||
* @group GH-5804
|
||||
*/
|
||||
final class GH5804Test extends OrmFunctionalTestCase
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@ use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
/**
|
||||
* @group 5887
|
||||
* @group GH-5887
|
||||
*/
|
||||
class GH5887Test extends OrmFunctionalTestCase
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user