1
0
mirror of synced 2025-02-10 01:09:26 +03:00

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

This commit is contained in:
mike 2016-11-03 20:42:59 +01:00
commit b8b5c2d686
391 changed files with 3035 additions and 2414 deletions

View File

@ -1,4 +0,0 @@
# for php-coveralls
service_name: travis-ci
src_dir: lib
coverage_clover: build/logs/clover*.xml

View File

@ -1,10 +1,9 @@
language: php language: php
php: php:
- 5.4
- 5.5
- 5.6 - 5.6
- 7.0 - 7.0
- nightly
- hhvm - hhvm
env: env:
@ -28,14 +27,6 @@ after_script:
matrix: matrix:
include: include:
- php: 5.4
env: DB=mariadb
addons:
mariadb: 5.5
- php: 5.5
env: DB=mariadb
addons:
mariadb: 5.5
- php: 5.6 - php: 5.6
env: DB=mariadb env: DB=mariadb
addons: addons:
@ -49,14 +40,6 @@ matrix:
addons: addons:
mariadb: 5.5 mariadb: 5.5
- php: 5.4
env: DB=mariadb
addons:
mariadb: 10.1
- php: 5.5
env: DB=mariadb
addons:
mariadb: 10.1
- php: 5.6 - php: 5.6
env: DB=mariadb env: DB=mariadb
addons: addons:
@ -72,6 +55,8 @@ matrix:
exclude: exclude:
- php: hhvm - php: hhvm
env: DB=pgsql # driver for PostgreSQL currently unsupported by HHVM, requires 3rd party dependency env: DB=pgsql # driver for PostgreSQL currently unsupported by HHVM, requires 3rd party dependency
allow_failures:
- php: nightly
sudo: false sudo: false

View File

@ -3,7 +3,7 @@
| [![Build status][Master image]][Master] | [![Build status][2.5 image]][2.5] | | [![Build status][Master image]][Master] | [![Build status][2.5 image]][2.5] |
| [![Coverage Status][Master coverage image]][Master coverage] | [![Coverage Status][2.5 coverage image]][2.5 coverage] | | [![Coverage Status][Master coverage image]][Master coverage] | [![Coverage Status][2.5 coverage image]][2.5 coverage] |
Doctrine 2 is an object-relational mapper (ORM) for PHP 5.4+ that provides transparent persistence Doctrine 2 is an object-relational mapper (ORM) for PHP 5.6+ that provides transparent persistence
for PHP objects. It sits on top of a powerful database abstraction layer (DBAL). One of its key features for PHP objects. It sits on top of a powerful database abstraction layer (DBAL). One of its key features
is the option to write database queries in a proprietary object oriented SQL dialect called Doctrine Query Language (DQL), is the option to write database queries in a proprietary object oriented SQL dialect called Doctrine Query Language (DQL),
inspired by Hibernate's HQL. This provides developers with a powerful alternative to SQL that maintains flexibility inspired by Hibernate's HQL. This provides developers with a powerful alternative to SQL that maintains flexibility
@ -18,9 +18,9 @@ without requiring unnecessary code duplication.
[Master image]: https://img.shields.io/travis/doctrine/doctrine2/master.svg?style=flat-square [Master image]: https://img.shields.io/travis/doctrine/doctrine2/master.svg?style=flat-square
[Master]: https://travis-ci.org/doctrine/doctrine2 [Master]: https://travis-ci.org/doctrine/doctrine2
[Master coverage image]: https://img.shields.io/coveralls/doctrine/doctrine2/master.svg?style=flat-square [Master coverage image]: https://img.shields.io/scrutinizer/coverage/g/doctrine/doctrine2/master.svg?style=flat-square
[Master coverage]: https://coveralls.io/r/doctrine/doctrine2?branch=master [Master coverage]: https://scrutinizer-ci.com/g/doctrine/doctrine2/?branch=master
[2.5 image]: https://img.shields.io/travis/doctrine/doctrine2/2.5.svg?style=flat-square [2.5 image]: https://img.shields.io/travis/doctrine/doctrine2/2.5.svg?style=flat-square
[2.5]: https://github.com/doctrine/doctrine2/tree/2.5 [2.5]: https://github.com/doctrine/doctrine2/tree/2.5
[2.5 coverage image]: https://img.shields.io/coveralls/doctrine/doctrine2/2.5.svg?style=flat-square [2.5 coverage image]: https://img.shields.io/scrutinizer/coverage/g/doctrine/doctrine2/2.5.svg?style=flat-square
[2.5 coverage]: https://coveralls.io/r/doctrine/doctrine2?branch=2.5 [2.5 coverage]: https://scrutinizer-ci.com/g/doctrine/doctrine2/?branch=2.5

View File

@ -1,5 +1,11 @@
# Upgrade to 2.5 # Upgrade to 2.5
## Minor BC BREAK: query cache key time is now a float
As of 2.5.5, the `QueryCacheEntry#time` property will contain a float value
instead of an integer in order to have more precision and also to be consistent
with the `TimestampCacheEntry#time`.
## Minor BC BREAK: discriminator map must now include all non-transient classes ## Minor BC BREAK: discriminator map must now include all non-transient classes
It is now required that you declare the root of an inheritance in the It is now required that you declare the root of an inheritance in the

View File

@ -31,7 +31,7 @@ $helperSet = null;
if (file_exists($configFile)) { if (file_exists($configFile)) {
if ( ! is_readable($configFile)) { if ( ! is_readable($configFile)) {
trigger_error( trigger_error(
'Configuration file [' . $configFile . '] does not have read permission.', E_ERROR 'Configuration file [' . $configFile . '] does not have read permission.', E_USER_ERROR
); );
} }

View File

@ -14,7 +14,7 @@
], ],
"minimum-stability": "dev", "minimum-stability": "dev",
"require": { "require": {
"php": ">=5.4", "php": "^5.6 || ^7.0",
"ext-pdo": "*", "ext-pdo": "*",
"doctrine/collections": "~1.2", "doctrine/collections": "~1.2",
"doctrine/dbal": ">=2.5-dev,<2.7-dev", "doctrine/dbal": ">=2.5-dev,<2.7-dev",
@ -25,7 +25,7 @@
}, },
"require-dev": { "require-dev": {
"symfony/yaml": "~2.3|~3.0", "symfony/yaml": "~2.3|~3.0",
"phpunit/phpunit": "~4.0" "phpunit/phpunit": "^5.4"
}, },
"suggest": { "suggest": {
"symfony/yaml": "If you want to use YAML Metadata Mapping Driver" "symfony/yaml": "If you want to use YAML Metadata Mapping Driver"
@ -43,6 +43,6 @@
} }
}, },
"archive": { "archive": {
"exclude": ["!vendor", "tests", "*phpunit.xml", ".travis.yml", "build.xml", "build.properties", "composer.phar", "vendor/satooshi", "lib/vendor", "*.swp", "*coveralls.yml"] "exclude": ["!vendor", "tests", "*phpunit.xml", ".travis.yml", "build.xml", "build.properties", "composer.phar", "vendor/satooshi", "lib/vendor", "*.swp"]
} }
} }

View File

@ -98,7 +98,7 @@ For example for the previous enum type:
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{ {
return "ENUM('visible', 'invisible') COMMENT '(DC2Type:enumvisibility)'"; return "ENUM('visible', 'invisible')";
} }
public function convertToPHPValue($value, AbstractPlatform $platform) public function convertToPHPValue($value, AbstractPlatform $platform)
@ -118,6 +118,11 @@ For example for the previous enum type:
{ {
return self::ENUM_VISIBILITY; return self::ENUM_VISIBILITY;
} }
public function requiresSQLCommentHint(AbstractPlatform $platform)
{
return true;
}
} }
You can register this type with ``Type::addType('enumvisibility', 'MyProject\DBAL\EnumVisibilityType');``. You can register this type with ``Type::addType('enumvisibility', 'MyProject\DBAL\EnumVisibilityType');``.
@ -152,7 +157,7 @@ You can generalize this approach easily to create a base class for enums:
{ {
$values = array_map(function($val) { return "'".$val."'"; }, $this->values); $values = array_map(function($val) { return "'".$val."'"; }, $this->values);
return "ENUM(".implode(", ", $values).") COMMENT '(DC2Type:".$this->name.")'"; return "ENUM(".implode(", ", $values).")";
} }
public function convertToPHPValue($value, AbstractPlatform $platform) public function convertToPHPValue($value, AbstractPlatform $platform)
@ -172,6 +177,11 @@ You can generalize this approach easily to create a base class for enums:
{ {
return $this->name; return $this->name;
} }
public function requiresSQLCommentHint(AbstractPlatform $platform)
{
return true;
}
} }
With this base class you can define an enum as easily as: With this base class you can define an enum as easily as:

View File

@ -49,7 +49,7 @@ By default Doctrine assumes that you are working with a default timezone. Each D
is created by Doctrine will be assigned the timezone that is currently the default, either through is created by Doctrine will be assigned the timezone that is currently the default, either through
the ``date.timezone`` ini setting or by calling ``date_default_timezone_set()``. the ``date.timezone`` ini setting or by calling ``date_default_timezone_set()``.
This is very important to handle correctly if your application runs on different serves or is moved from one to another server This is very important to handle correctly if your application runs on different servers or is moved from one to another server
(with different timezone settings). You have to make sure that the timezone is the correct one (with different timezone settings). You have to make sure that the timezone is the correct one
on all this systems. on all this systems.

View File

@ -394,7 +394,7 @@ means that you have to register a special autoloader for these classes:
.. code-block:: php .. code-block:: php
<?php <?php
use Doctrine\ORM\Proxy\Autoloader; use Doctrine\Common\Proxy\Autoloader;
$proxyDir = "/path/to/proxies"; $proxyDir = "/path/to/proxies";
$proxyNamespace = "MyProxies"; $proxyNamespace = "MyProxies";

View File

@ -37,8 +37,11 @@ Index
- :ref:`@ColumnResult <annref_column_result>` - :ref:`@ColumnResult <annref_column_result>`
- :ref:`@Cache <annref_cache>` - :ref:`@Cache <annref_cache>`
- :ref:`@ChangeTrackingPolicy <annref_changetrackingpolicy>` - :ref:`@ChangeTrackingPolicy <annref_changetrackingpolicy>`
- :ref:`@CustomIdGenerator <annref_customidgenerator>`
- :ref:`@DiscriminatorColumn <annref_discriminatorcolumn>` - :ref:`@DiscriminatorColumn <annref_discriminatorcolumn>`
- :ref:`@DiscriminatorMap <annref_discriminatormap>` - :ref:`@DiscriminatorMap <annref_discriminatormap>`
- :ref:`@Embeddable <annref_embeddable>`
- :ref:`@Embedded <annref_embedded>`
- :ref:`@Entity <annref_entity>` - :ref:`@Entity <annref_entity>`
- :ref:`@EntityResult <annref_entity_result>` - :ref:`@EntityResult <annref_entity_result>`
- :ref:`@FieldResult <annref_field_result>` - :ref:`@FieldResult <annref_field_result>`
@ -231,6 +234,30 @@ Example:
*/ */
class User {} class User {}
.. _annref_customidgenerator:
@CustomIdGenerator
~~~~~~~~~~~~~~~~~~~~~
This annotations allows you to specify a user-provided class to generate identifiers. This annotation only works when both :ref:`@Id <annref_id>` and :ref:`@GeneratedValue(strategy="CUSTOM") <annref_generatedvalue>` are specified.
Required attributes:
- **class**: name of the class which should extend Doctrine\ORM\Id\AbstractIdGenerator
Example:
.. code-block:: php
<?php
/**
* @Id
* @Column(type="integer")
* @GeneratedValue(strategy="CUSTOM")
* @CustomIdGenerator(class="My\Namespace\MyIdGenerator")
*/
public $id;
.. _annref_discriminatorcolumn: .. _annref_discriminatorcolumn:
@DiscriminatorColumn @DiscriminatorColumn
@ -282,6 +309,67 @@ depending on whether the classes are in the namespace or not.
// ... // ...
} }
.. _annref_embeddable:
@Embeddable
~~~~~~~~~~~~~~~~~~~~~
The embeddable is required on an entity targeted to be embeddable inside
another. It works together with the :ref:`@Embedded <annref_embedded>`
annotation to establish the relationship between two entities.
.. code-block:: php
<?php
/**
* @Embeddable
*/
class Address
{
// ...
class User
{
/**
* @Embedded(class = "Address")
*/
private $address;
.. _annref_embedded:
@Embedded
~~~~~~~~~~~~~~~~~~~~~
The embedded annotation is required on a member class varible targed to
embed it's class argument inside it's own class.
Required attributes:
- **class**: The embeddable class
.. code-block:: php
<?php
// ...
class User
{
/**
* @Embedded(class = "Address")
*/
private $address;
/**
* @Embeddable
*/
class Address
{
// ...
.. _annref_entity: .. _annref_entity:
@Entity @Entity

View File

@ -909,7 +909,7 @@ An instance of the ``Doctrine\ORM\Query`` class represents a DQL
query. You create a Query instance be calling query. You create a Query instance be calling
``EntityManager#createQuery($dql)``, passing the DQL query string. ``EntityManager#createQuery($dql)``, passing the DQL query string.
Alternatively you can create an empty ``Query`` instance and invoke Alternatively you can create an empty ``Query`` instance and invoke
``Query#setDql($dql)`` afterwards. Here are some examples: ``Query#setDQL($dql)`` afterwards. Here are some examples:
.. code-block:: php .. code-block:: php
@ -919,9 +919,9 @@ Alternatively you can create an empty ``Query`` instance and invoke
// example1: passing a DQL string // example1: passing a DQL string
$q = $em->createQuery('select u from MyProject\Model\User u'); $q = $em->createQuery('select u from MyProject\Model\User u');
// example2: using setDql // example2: using setDQL
$q = $em->createQuery(); $q = $em->createQuery();
$q->setDql('select u from MyProject\Model\User u'); $q->setDQL('select u from MyProject\Model\User u');
Query Result Formats Query Result Formats
~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~

View File

@ -179,7 +179,7 @@ the life-time of their registered entities.
allows providing fallback metadata even when no actual metadata exists allows providing fallback metadata even when no actual metadata exists
or could be found. This event is not a lifecycle callback. or could be found. This event is not a lifecycle callback.
- preFlush - The preFlush event occurs at the very beginning of a flush - preFlush - The preFlush event occurs at the very beginning of a flush
operation. This event is not a lifecycle callback. operation.
- onFlush - The onFlush event occurs after the change-sets of all - onFlush - The onFlush event occurs after the change-sets of all
managed entities are computed. This event is not a lifecycle managed entities are computed. This event is not a lifecycle
callback. callback.
@ -406,8 +406,8 @@ behaviors across different entity classes.
Note that they require much more detailed knowledge about the inner Note that they require much more detailed knowledge about the inner
workings of the EntityManager and UnitOfWork. Please read the workings of the EntityManager and UnitOfWork. Please read the
*Implementing Event Listeners* section carefully if you are trying :ref:`reference-events-implementing-listeners` section carefully if you
to write your own listener. are trying to write your own listener.
For event subscribers, there are no surprises. They declare the For event subscribers, there are no surprises. They declare the
lifecycle events in their ``getSubscribedEvents`` method and provide lifecycle events in their ``getSubscribedEvents`` method and provide
@ -434,7 +434,7 @@ A lifecycle event listener looks like the following:
} }
} }
A lifecycle event subscriber may looks like this: A lifecycle event subscriber may look like this:
.. code-block:: php .. code-block:: php

View File

@ -113,7 +113,7 @@ suggested standard way to build queries:
$qb->expr()->eq('u.id', '?1'), $qb->expr()->eq('u.id', '?1'),
$qb->expr()->like('u.nickname', '?2') $qb->expr()->like('u.nickname', '?2')
)) ))
->orderBy('u.surname', 'ASC')); ->orderBy('u.surname', 'ASC');
Here is a complete list of helper methods available in ``QueryBuilder``: Here is a complete list of helper methods available in ``QueryBuilder``:

View File

@ -153,21 +153,21 @@ Built-in cached persisters
Cached persisters are responsible to access cache regions. Cached persisters are responsible to access cache regions.
+-----------------------+-------------------------------------------------------------------------------+ +-----------------------+-------------------------------------------------------------------------------------------+
| Cache Usage | Persister | | Cache Usage | Persister |
+=======================+===============================================================================+ +=======================+===========================================================================================+
| READ_ONLY | Doctrine\\ORM\\Cache\\Persister\\ReadOnlyCachedEntityPersister | | READ_ONLY | Doctrine\\ORM\\Cache\\Persister\\Entity\\ReadOnlyCachedEntityPersister |
+-----------------------+-------------------------------------------------------------------------------+ +-----------------------+-------------------------------------------------------------------------------------------+
| READ_WRITE | Doctrine\\ORM\\Cache\\Persister\\ReadWriteCachedEntityPersister | | READ_WRITE | Doctrine\\ORM\\Cache\\Persister\\Entity\\ReadWriteCachedEntityPersister |
+-----------------------+-------------------------------------------------------------------------------+ +-----------------------+-------------------------------------------------------------------------------------------+
| NONSTRICT_READ_WRITE | Doctrine\\ORM\\Cache\\Persister\\NonStrictReadWriteCachedEntityPersister | | NONSTRICT_READ_WRITE | Doctrine\\ORM\\Cache\\Persister\\Entity\\NonStrictReadWriteCachedEntityPersister |
+-----------------------+-------------------------------------------------------------------------------+ +-----------------------+-------------------------------------------------------------------------------------------+
| READ_ONLY | Doctrine\\ORM\\Cache\\Persister\\ReadOnlyCachedCollectionPersister | | READ_ONLY | Doctrine\\ORM\\Cache\\Persister\\Collection\\ReadOnlyCachedCollectionPersister |
+-----------------------+-------------------------------------------------------------------------------+ +-----------------------+-------------------------------------------------------------------------------------------+
| READ_WRITE | Doctrine\\ORM\\Cache\\Persister\\ReadWriteCachedCollectionPersister | | READ_WRITE | Doctrine\\ORM\\Cache\\Persister\\Collection\\ReadWriteCachedCollectionPersister |
+-----------------------+-------------------------------------------------------------------------------+ +-----------------------+-------------------------------------------------------------------------------------------+
| NONSTRICT_READ_WRITE | Doctrine\\ORM\\Cache\\Persister\\NonStrictReadWriteCacheCollectionPersister | | NONSTRICT_READ_WRITE | Doctrine\\ORM\\Cache\\Persister\\Collection\\NonStrictReadWriteCachedCollectionPersister |
+-----------------------+-------------------------------------------------------------------------------+ +-----------------------+-------------------------------------------------------------------------------------------+
Configuration Configuration
------------- -------------

View File

@ -32,7 +32,7 @@ You can consider the following APIs to be safe from SQL injection:
- Queries through the Criteria API on ``Doctrine\ORM\PersistentCollection`` and - Queries through the Criteria API on ``Doctrine\ORM\PersistentCollection`` and
``Doctrine\ORM\EntityRepository``. ``Doctrine\ORM\EntityRepository``.
You are **NOT** save from SQL injection when using user input with: You are **NOT** safe from SQL injection when using user input with:
- Expression API of ``Doctrine\ORM\QueryBuilder`` - Expression API of ``Doctrine\ORM\QueryBuilder``
- Concatenating user input into DQL SELECT, UPDATE or DELETE statements or - Concatenating user input into DQL SELECT, UPDATE or DELETE statements or

View File

@ -699,8 +699,6 @@ You can also load by owning side associations through the repository:
$number = $em->find('MyProject\Domain\Phonenumber', 1234); $number = $em->find('MyProject\Domain\Phonenumber', 1234);
$user = $em->getRepository('MyProject\Domain\User')->findOneBy(array('phone' => $number->getId())); $user = $em->getRepository('MyProject\Domain\User')->findOneBy(array('phone' => $number->getId()));
Be careful that this only works by passing the ID of the associated entity, not yet by passing the associated entity itself.
The ``EntityRepository#findBy()`` method additionally accepts orderings, limit and offset as second to fourth parameters: The ``EntityRepository#findBy()`` method additionally accepts orderings, limit and offset as second to fourth parameters:
.. code-block:: php .. code-block:: php
@ -729,6 +727,14 @@ examples are equivalent:
// A single user by its nickname (__call magic) // A single user by its nickname (__call magic)
$user = $em->getRepository('MyProject\Domain\User')->findOneByNickname('romanb'); $user = $em->getRepository('MyProject\Domain\User')->findOneByNickname('romanb');
Additionally, you can just count the result of the provided conditions when you don't really need the data:
.. code-block:: php
<?php
// Check there is no user with nickname
$availableNickname = 0 === $em->getRepository('MyProject\Domain\User')->count(['nickname' => 'nonexistent']);
By Criteria By Criteria
~~~~~~~~~~~ ~~~~~~~~~~~

View File

@ -1,7 +1,7 @@
Separating Concerns using Embeddables Separating Concerns using Embeddables
------------------------------------- -------------------------------------
Embeddables are classes which are not entities themself, but are embedded Embeddables are classes which are not entities themselves, but are embedded
in entities and can also be queried in DQL. You'll mostly want to use them in entities and can also be queried in DQL. You'll mostly want to use them
to reduce duplication or separating concerns. Value objects such as date range to reduce duplication or separating concerns. Value objects such as date range
or address are the primary use case for this feature. Embeddables can only or address are the primary use case for this feature. Embeddables can only

View File

@ -17,7 +17,7 @@ This guide is designed for beginners that haven't worked with Doctrine ORM
before. There are some prerequesites for the tutorial that have to be before. There are some prerequesites for the tutorial that have to be
installed: installed:
- PHP 5.4 or above - PHP (latest stable version)
- Composer Package Manager (`Install Composer - Composer Package Manager (`Install Composer
<http://getcomposer.org/doc/00-intro.md>`_) <http://getcomposer.org/doc/00-intro.md>`_)
@ -344,7 +344,7 @@ Now that we have defined our first entity, let's update the database:
$ vendor/bin/doctrine orm:schema-tool:update --force --dump-sql $ vendor/bin/doctrine orm:schema-tool:update --force --dump-sql
Specifying both flags ``--force`` and ``-dump-sql`` prints and executes the DDL Specifying both flags ``--force`` and ``--dump-sql`` prints and executes the DDL
statements. statements.
Now create a new script that will insert products into the database: Now create a new script that will insert products into the database:
@ -616,12 +616,12 @@ domain model to match the requirements:
} }
} }
Whenever an entity is recreated from the database, an Collection You use Doctrine's ArrayCollections in your Doctrine models, rather
implementation of the type Doctrine is injected into your entity than plain PHP arrays, so that Doctrine can watch what happens with
instead of an array. Compared to the ArrayCollection this them and act appropriately. Note that if you dump your entities,
implementation helps the Doctrine ORM understand the changes that you'll see a "PersistentCollection" in place of your ArrayCollection,
have happened to the collection which are noteworthy for which is just an
persistence. internal Doctrine class with the same interface.
.. warning:: .. warning::
@ -1535,6 +1535,16 @@ As an example here is the code of the first use case "List of Bugs":
Using EntityRepositories you can avoid coupling your model with specific query logic. Using EntityRepositories you can avoid coupling your model with specific query logic.
You can also re-use query logic easily throughout your application. You can also re-use query logic easily throughout your application.
The method ``count()`` takes an array of fields or association keys and the values to match against.
This provides you with a convenient and lightweight way to count a resultset when you don't need to
deal with it:
.. code-block:: php
<?php
$productCount = $entityManager->getRepository(Product::class)
->count(['name' => $productName]);
Conclusion Conclusion
---------- ----------

View File

@ -28,7 +28,7 @@ use Doctrine\ORM\Cache\QueryCacheKey;
use Doctrine\DBAL\Cache\QueryCacheProfile; use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\ORM\Cache; use Doctrine\ORM\Cache;
use Doctrine\ORM\Query\QueryException; use Doctrine\ORM\Query\ResultSetMapping;
/** /**
* Base contract for ORM queries. Base class for Query and NativeQuery. * Base contract for ORM queries. Base class for Query and NativeQuery.
@ -719,7 +719,7 @@ abstract class AbstractQuery
* *
* @param int $hydrationMode * @param int $hydrationMode
* *
* @return array * @return mixed
*/ */
public function getResult($hydrationMode = self::HYDRATE_OBJECT) public function getResult($hydrationMode = self::HYDRATE_OBJECT)
{ {
@ -992,32 +992,54 @@ abstract class AbstractQuery
private function executeUsingQueryCache($parameters = null, $hydrationMode = null) private function executeUsingQueryCache($parameters = null, $hydrationMode = null)
{ {
$rsm = $this->getResultSetMapping(); $rsm = $this->getResultSetMapping();
$querykey = new QueryCacheKey($this->getHash(), $this->lifetime, $this->cacheMode ?: Cache::MODE_NORMAL);
$queryCache = $this->_em->getCache()->getQueryCache($this->cacheRegion); $queryCache = $this->_em->getCache()->getQueryCache($this->cacheRegion);
$result = $queryCache->get($querykey, $rsm, $this->_hints); $queryKey = new QueryCacheKey(
$this->getHash(),
$this->lifetime,
$this->cacheMode ?: Cache::MODE_NORMAL,
$this->getTimestampKey()
);
$result = $queryCache->get($queryKey, $rsm, $this->_hints);
if ($result !== null) { if ($result !== null) {
if ($this->cacheLogger) { if ($this->cacheLogger) {
$this->cacheLogger->queryCacheHit($queryCache->getRegion()->getName(), $querykey); $this->cacheLogger->queryCacheHit($queryCache->getRegion()->getName(), $queryKey);
} }
return $result; return $result;
} }
$result = $this->executeIgnoreQueryCache($parameters, $hydrationMode); $result = $this->executeIgnoreQueryCache($parameters, $hydrationMode);
$cached = $queryCache->put($querykey, $rsm, $result, $this->_hints); $cached = $queryCache->put($queryKey, $rsm, $result, $this->_hints);
if ($this->cacheLogger) { if ($this->cacheLogger) {
$this->cacheLogger->queryCacheMiss($queryCache->getRegion()->getName(), $querykey); $this->cacheLogger->queryCacheMiss($queryCache->getRegion()->getName(), $queryKey);
if ($cached) { if ($cached) {
$this->cacheLogger->queryCachePut($queryCache->getRegion()->getName(), $querykey); $this->cacheLogger->queryCachePut($queryCache->getRegion()->getName(), $queryKey);
} }
} }
return $result; return $result;
} }
/**
* @return \Doctrine\ORM\Cache\TimestampCacheKey|null
*/
private function getTimestampKey()
{
$entityName = reset($this->_resultSetMapping->aliasMap);
if (empty($entityName)) {
return null;
}
$metadata = $this->_em->getClassMetadata($entityName);
return new Cache\TimestampCacheKey($metadata->getTableName());
}
/** /**
* Get the result cache id to use to store the result set cache entry. * Get the result cache id to use to store the result set cache entry.
* Will return the configured id if it exists otherwise a hash will be * Will return the configured id if it exists otherwise a hash will be

View File

@ -110,7 +110,9 @@ class CacheConfiguration
public function getQueryValidator() public function getQueryValidator()
{ {
if ($this->queryValidator === null) { if ($this->queryValidator === null) {
$this->queryValidator = new TimestampQueryCacheValidator(); $this->queryValidator = new TimestampQueryCacheValidator(
$this->cacheFactory->getTimestampRegion()
);
} }
return $this->queryValidator; return $this->queryValidator;

View File

@ -217,8 +217,8 @@ class DefaultCacheFactory implements CacheFactory
if ( ! $this->fileLockRegionDirectory) { if ( ! $this->fileLockRegionDirectory) {
throw new \LogicException( throw new \LogicException(
'If you what to use a "READ_WRITE" cache an implementation of "Doctrine\ORM\Cache\ConcurrentRegion" is required, ' . 'If you want to use a "READ_WRITE" cache an implementation of "Doctrine\ORM\Cache\ConcurrentRegion" is required, ' .
'The default implementation provided by doctrine is "Doctrine\ORM\Cache\Region\FileLockRegion" if you what to use it please provide a valid directory, DefaultCacheFactory#setFileLockRegionDirectory(). ' 'The default implementation provided by doctrine is "Doctrine\ORM\Cache\Region\FileLockRegion" if you want to use it please provide a valid directory, DefaultCacheFactory#setFileLockRegionDirectory(). '
); );
} }

View File

@ -233,8 +233,8 @@ class DefaultQueryCache implements QueryCache
$data = array(); $data = array();
$entityName = reset($rsm->aliasMap); $entityName = reset($rsm->aliasMap);
$rootAlias = key($rsm->aliasMap);
$hasRelation = ( ! empty($rsm->relationMap)); $hasRelation = ( ! empty($rsm->relationMap));
$metadata = $this->em->getClassMetadata($entityName);
$persister = $this->uow->getEntityPersister($entityName); $persister = $this->uow->getEntityPersister($entityName);
if ( ! ($persister instanceof CachedPersister)) { if ( ! ($persister instanceof CachedPersister)) {
@ -245,10 +245,11 @@ class DefaultQueryCache implements QueryCache
foreach ($result as $index => $entity) { foreach ($result as $index => $entity) {
$identifier = $this->uow->getEntityIdentifier($entity); $identifier = $this->uow->getEntityIdentifier($entity);
$entityKey = new EntityCacheKey($entityName, $identifier);
$data[$index]['identifier'] = $identifier; $data[$index]['identifier'] = $identifier;
$data[$index]['associations'] = array(); $data[$index]['associations'] = array();
if (($key->cacheMode & Cache::MODE_REFRESH) || ! $region->contains($entityKey = new EntityCacheKey($entityName, $identifier))) { if (($key->cacheMode & Cache::MODE_REFRESH) || ! $region->contains($entityKey)) {
// Cancel put result if entity put fail // Cancel put result if entity put fail
if ( ! $persister->storeEntityCache($entity, $entityKey)) { if ( ! $persister->storeEntityCache($entity, $entityKey)) {
return false; return false;
@ -261,37 +262,81 @@ class DefaultQueryCache implements QueryCache
// @TODO - move to cache hydration components // @TODO - move to cache hydration components
foreach ($rsm->relationMap as $alias => $name) { foreach ($rsm->relationMap as $alias => $name) {
$metadata = $this->em->getClassMetadata($rsm->aliasMap[$rsm->parentAliasMap[$alias]]); $parentAlias = $rsm->parentAliasMap[$alias];
$parentClass = $rsm->aliasMap[$parentAlias];
$metadata = $this->em->getClassMetadata($parentClass);
$assoc = $metadata->associationMappings[$name]; $assoc = $metadata->associationMappings[$name];
$assocValue = $this->getAssociationValue($rsm, $alias, $entity);
if (($assocValue = $metadata->getFieldValue($entity, $name)) === null || $assocValue instanceof Proxy) { if ($assocValue === null) {
continue; continue;
} }
$assocPersister = $this->uow->getEntityPersister($assoc['targetEntity']); // root entity association
$assocRegion = $assocPersister->getCacheRegion(); if ($rootAlias === $parentAlias) {
$assocMetadata = $assocPersister->getClassMetadata(); // Cancel put result if association put fail
if ( ($assocInfo = $this->storeAssociationCache($key, $assoc, $assocValue)) === null) {
return false;
}
// Handle *-to-one associations $data[$index]['associations'][$name] = $assocInfo;
if ($assoc['type'] & ClassMetadata::TO_ONE) {
$assocIdentifier = $this->uow->getEntityIdentifier($assocValue); continue;
}
if (($key->cacheMode & Cache::MODE_REFRESH) || ! $assocRegion->contains($entityKey = new EntityCacheKey($assocMetadata->rootEntityName, $assocIdentifier))) { // store single nested association
if ( ! is_array($assocValue)) {
// Cancel put result if association put fail
if ($this->storeAssociationCache($key, $assoc, $assocValue) === null) {
return false;
}
// Cancel put result if association entity put fail continue;
if ( ! $assocPersister->storeEntityCache($assocValue, $entityKey)) { }
// store array of nested association
foreach ($assocValue as $aVal) {
// Cancel put result if association put fail
if ($this->storeAssociationCache($key, $assoc, $aVal) === null) {
return false; return false;
} }
} }
}
}
$data[$index]['associations'][$name] = array( return $this->region->put($key, new QueryCacheEntry($data));
}
/**
* @param \Doctrine\ORM\Cache\QueryCacheKey $key
* @param array $assoc
* @param mixed $assocValue
*
* @return array|null
*/
private function storeAssociationCache(QueryCacheKey $key, array $assoc, $assocValue)
{
$assocPersister = $this->uow->getEntityPersister($assoc['targetEntity']);
$assocMetadata = $assocPersister->getClassMetadata();
$assocRegion = $assocPersister->getCacheRegion();
// Handle *-to-one associations
if ($assoc['type'] & ClassMetadata::TO_ONE) {
$assocIdentifier = $this->uow->getEntityIdentifier($assocValue);
$entityKey = new EntityCacheKey($assocMetadata->rootEntityName, $assocIdentifier);
if ( ! $assocValue instanceof Proxy && ($key->cacheMode & Cache::MODE_REFRESH) || ! $assocRegion->contains($entityKey)) {
// Entity put fail
if ( ! $assocPersister->storeEntityCache($assocValue, $entityKey)) {
return null;
}
}
return array(
'targetEntity' => $assocMetadata->rootEntityName, 'targetEntity' => $assocMetadata->rootEntityName,
'identifier' => $assocIdentifier, 'identifier' => $assocIdentifier,
'type' => $assoc['type'] 'type' => $assoc['type']
); );
continue;
} }
// Handle *-to-many associations // Handle *-to-many associations
@ -299,27 +344,86 @@ class DefaultQueryCache implements QueryCache
foreach ($assocValue as $assocItemIndex => $assocItem) { foreach ($assocValue as $assocItemIndex => $assocItem) {
$assocIdentifier = $this->uow->getEntityIdentifier($assocItem); $assocIdentifier = $this->uow->getEntityIdentifier($assocItem);
$entityKey = new EntityCacheKey($assocMetadata->rootEntityName, $assocIdentifier);
if (($key->cacheMode & Cache::MODE_REFRESH) || ! $assocRegion->contains($entityKey = new EntityCacheKey($assocMetadata->rootEntityName, $assocIdentifier))) { if (($key->cacheMode & Cache::MODE_REFRESH) || ! $assocRegion->contains($entityKey)) {
// Entity put fail
// Cancel put result if entity put fail
if ( ! $assocPersister->storeEntityCache($assocItem, $entityKey)) { if ( ! $assocPersister->storeEntityCache($assocItem, $entityKey)) {
return false; return null;
} }
} }
$list[$assocItemIndex] = $assocIdentifier; $list[$assocItemIndex] = $assocIdentifier;
} }
$data[$index]['associations'][$name] = array( return array(
'targetEntity' => $assocMetadata->rootEntityName, 'targetEntity' => $assocMetadata->rootEntityName,
'type' => $assoc['type'], 'type' => $assoc['type'],
'list' => $list, 'list' => $list,
); );
} }
/**
* @param \Doctrine\ORM\Query\ResultSetMapping $rsm
* @param string $assocAlias
* @param object $entity
*
* @return array|object
*/
private function getAssociationValue(ResultSetMapping $rsm, $assocAlias, $entity)
{
$path = array();
$alias = $assocAlias;
while (isset($rsm->parentAliasMap[$alias])) {
$parent = $rsm->parentAliasMap[$alias];
$field = $rsm->relationMap[$alias];
$class = $rsm->aliasMap[$parent];
array_unshift($path, array(
'field' => $field,
'class' => $class
));
$alias = $parent;
} }
return $this->region->put($key, new QueryCacheEntry($data)); return $this->getAssociationPathValue($entity, $path);
}
/**
* @param mixed $value
* @param array $path
*
* @return array|object|null
*/
private function getAssociationPathValue($value, array $path)
{
$mapping = array_shift($path);
$metadata = $this->em->getClassMetadata($mapping['class']);
$assoc = $metadata->associationMappings[$mapping['field']];
$value = $metadata->getFieldValue($value, $mapping['field']);
if ($value === null) {
return null;
}
if (empty($path)) {
return $value;
}
// Handle *-to-one associations
if ($assoc['type'] & ClassMetadata::TO_ONE) {
return $this->getAssociationPathValue($value, $path);
}
$values = array();
foreach ($value as $item) {
$values[] = $this->getAssociationPathValue($item, $path);
}
return $values;
} }
/** /**

View File

@ -71,7 +71,7 @@ class EntityCacheEntry implements CacheEntry
/** /**
* Retrieves the entity data resolving cache entries * Retrieves the entity data resolving cache entries
* *
* @param \Doctrine\ORM\EntityManagerInterfac $em * @param \Doctrine\ORM\EntityManagerInterface $em
* *
* @return array * @return array
*/ */

View File

@ -287,17 +287,16 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
* @param array $orderBy * @param array $orderBy
* @param integer $limit * @param integer $limit
* @param integer $offset * @param integer $offset
* @param integer $timestamp
* *
* @return string * @return string
*/ */
protected function getHash($query, $criteria, array $orderBy = null, $limit = null, $offset = null, $timestamp = null) protected function getHash($query, $criteria, array $orderBy = null, $limit = null, $offset = null)
{ {
list($params) = ($criteria instanceof Criteria) list($params) = ($criteria instanceof Criteria)
? $this->persister->expandCriteriaParameters($criteria) ? $this->persister->expandCriteriaParameters($criteria)
: $this->persister->expandParameters($criteria); : $this->persister->expandParameters($criteria);
return sha1($query . serialize($params) . serialize($orderBy) . $limit . $offset . $timestamp); return sha1($query . serialize($params) . serialize($orderBy) . $limit . $offset);
} }
/** /**
@ -368,17 +367,16 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
} }
//handle only EntityRepository#findOneBy //handle only EntityRepository#findOneBy
$timestamp = $this->timestampRegion->get($this->timestampKey);
$query = $this->persister->getSelectSQL($criteria, null, null, $limit, null, $orderBy); $query = $this->persister->getSelectSQL($criteria, null, null, $limit, null, $orderBy);
$hash = $this->getHash($query, $criteria, null, null, null, $timestamp ? $timestamp->time : null); $hash = $this->getHash($query, $criteria, null, null, null);
$rsm = $this->getResultSetMapping(); $rsm = $this->getResultSetMapping();
$querykey = new QueryCacheKey($hash, 0, Cache::MODE_NORMAL); $queryKey = new QueryCacheKey($hash, 0, Cache::MODE_NORMAL, $this->timestampKey);
$queryCache = $this->cache->getQueryCache($this->regionName); $queryCache = $this->cache->getQueryCache($this->regionName);
$result = $queryCache->get($querykey, $rsm); $result = $queryCache->get($queryKey, $rsm);
if ($result !== null) { if ($result !== null) {
if ($this->cacheLogger) { if ($this->cacheLogger) {
$this->cacheLogger->queryCacheHit($this->regionName, $querykey); $this->cacheLogger->queryCacheHit($this->regionName, $queryKey);
} }
return $result[0]; return $result[0];
@ -388,15 +386,15 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
return null; return null;
} }
$cached = $queryCache->put($querykey, $rsm, array($result)); $cached = $queryCache->put($queryKey, $rsm, array($result));
if ($this->cacheLogger) { if ($this->cacheLogger) {
if ($result) { if ($result) {
$this->cacheLogger->queryCacheMiss($this->regionName, $querykey); $this->cacheLogger->queryCacheMiss($this->regionName, $queryKey);
} }
if ($cached) { if ($cached) {
$this->cacheLogger->queryCachePut($this->regionName, $querykey); $this->cacheLogger->queryCachePut($this->regionName, $queryKey);
} }
} }
@ -408,32 +406,31 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
*/ */
public function loadAll(array $criteria = array(), array $orderBy = null, $limit = null, $offset = null) public function loadAll(array $criteria = array(), array $orderBy = null, $limit = null, $offset = null)
{ {
$timestamp = $this->timestampRegion->get($this->timestampKey);
$query = $this->persister->getSelectSQL($criteria, null, null, $limit, $offset, $orderBy); $query = $this->persister->getSelectSQL($criteria, null, null, $limit, $offset, $orderBy);
$hash = $this->getHash($query, $criteria, null, null, null, $timestamp ? $timestamp->time : null); $hash = $this->getHash($query, $criteria, null, null, null);
$rsm = $this->getResultSetMapping(); $rsm = $this->getResultSetMapping();
$querykey = new QueryCacheKey($hash, 0, Cache::MODE_NORMAL); $queryKey = new QueryCacheKey($hash, 0, Cache::MODE_NORMAL, $this->timestampKey);
$queryCache = $this->cache->getQueryCache($this->regionName); $queryCache = $this->cache->getQueryCache($this->regionName);
$result = $queryCache->get($querykey, $rsm); $result = $queryCache->get($queryKey, $rsm);
if ($result !== null) { if ($result !== null) {
if ($this->cacheLogger) { if ($this->cacheLogger) {
$this->cacheLogger->queryCacheHit($this->regionName, $querykey); $this->cacheLogger->queryCacheHit($this->regionName, $queryKey);
} }
return $result; return $result;
} }
$result = $this->persister->loadAll($criteria, $orderBy, $limit, $offset); $result = $this->persister->loadAll($criteria, $orderBy, $limit, $offset);
$cached = $queryCache->put($querykey, $rsm, $result); $cached = $queryCache->put($queryKey, $rsm, $result);
if ($this->cacheLogger) { if ($this->cacheLogger) {
if ($result) { if ($result) {
$this->cacheLogger->queryCacheMiss($this->regionName, $querykey); $this->cacheLogger->queryCacheMiss($this->regionName, $queryKey);
} }
if ($cached) { if ($cached) {
$this->cacheLogger->queryCachePut($this->regionName, $querykey); $this->cacheLogger->queryCachePut($this->regionName, $queryKey);
} }
} }
@ -511,31 +508,30 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
$limit = $criteria->getMaxResults(); $limit = $criteria->getMaxResults();
$offset = $criteria->getFirstResult(); $offset = $criteria->getFirstResult();
$query = $this->persister->getSelectSQL($criteria); $query = $this->persister->getSelectSQL($criteria);
$timestamp = $this->timestampRegion->get($this->timestampKey); $hash = $this->getHash($query, $criteria, $orderBy, $limit, $offset);
$hash = $this->getHash($query, $criteria, $orderBy, $limit, $offset, $timestamp ? $timestamp->time : null);
$rsm = $this->getResultSetMapping(); $rsm = $this->getResultSetMapping();
$querykey = new QueryCacheKey($hash, 0, Cache::MODE_NORMAL); $queryKey = new QueryCacheKey($hash, 0, Cache::MODE_NORMAL, $this->timestampKey);
$queryCache = $this->cache->getQueryCache($this->regionName); $queryCache = $this->cache->getQueryCache($this->regionName);
$cacheResult = $queryCache->get($querykey, $rsm); $cacheResult = $queryCache->get($queryKey, $rsm);
if ($cacheResult !== null) { if ($cacheResult !== null) {
if ($this->cacheLogger) { if ($this->cacheLogger) {
$this->cacheLogger->queryCacheHit($this->regionName, $querykey); $this->cacheLogger->queryCacheHit($this->regionName, $queryKey);
} }
return $cacheResult; return $cacheResult;
} }
$result = $this->persister->loadCriteria($criteria); $result = $this->persister->loadCriteria($criteria);
$cached = $queryCache->put($querykey, $rsm, $result); $cached = $queryCache->put($queryKey, $rsm, $result);
if ($this->cacheLogger) { if ($this->cacheLogger) {
if ($result) { if ($result) {
$this->cacheLogger->queryCacheMiss($this->regionName, $querykey); $this->cacheLogger->queryCacheMiss($this->regionName, $queryKey);
} }
if ($cached) { if ($cached) {
$this->cacheLogger->queryCachePut($this->regionName, $querykey); $this->cacheLogger->queryCachePut($this->regionName, $queryKey);
} }
} }

View File

@ -38,18 +38,18 @@ class QueryCacheEntry implements CacheEntry
/** /**
* READ-ONLY: Public only for performance reasons, it should be considered immutable. * READ-ONLY: Public only for performance reasons, it should be considered immutable.
* *
* @var integer Time creation of this cache entry * @var float Time creation of this cache entry
*/ */
public $time; public $time;
/** /**
* @param array $result * @param array $result
* @param integer $time * @param float $time
*/ */
public function __construct($result, $time = null) public function __construct($result, $time = null)
{ {
$this->result = $result; $this->result = $result;
$this->time = $time ?: time(); $this->time = $time ?: microtime(true);
} }
/** /**

View File

@ -44,15 +44,28 @@ class QueryCacheKey extends CacheKey
*/ */
public $cacheMode; public $cacheMode;
/**
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
*
* @var TimestampCacheKey|null
*/
public $timestampKey;
/** /**
* @param string $hash Result cache id * @param string $hash Result cache id
* @param integer $lifetime Query lifetime * @param integer $lifetime Query lifetime
* @param integer $cacheMode Query cache mode * @param int $cacheMode Query cache mode
* @param TimestampCacheKey|null $timestampKey
*/ */
public function __construct($hash, $lifetime = 0, $cacheMode = Cache::MODE_NORMAL) public function __construct(
{ $hash,
$lifetime = 0,
$cacheMode = Cache::MODE_NORMAL,
TimestampCacheKey $timestampKey = null
) {
$this->hash = $hash; $this->hash = $hash;
$this->lifetime = $lifetime; $this->lifetime = $lifetime;
$this->cacheMode = $cacheMode; $this->cacheMode = $cacheMode;
$this->timestampKey = $timestampKey;
} }
} }

View File

@ -26,15 +26,49 @@ namespace Doctrine\ORM\Cache;
*/ */
class TimestampQueryCacheValidator implements QueryCacheValidator class TimestampQueryCacheValidator implements QueryCacheValidator
{ {
/**
* @var TimestampRegion
*/
private $timestampRegion;
/**
* @param TimestampRegion $timestampRegion
*/
public function __construct(TimestampRegion $timestampRegion)
{
$this->timestampRegion = $timestampRegion;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function isValid(QueryCacheKey $key, QueryCacheEntry $entry) public function isValid(QueryCacheKey $key, QueryCacheEntry $entry)
{ {
if ($this->regionUpdated($key, $entry)) {
return false;
}
if ($key->lifetime == 0) { if ($key->lifetime == 0) {
return true; return true;
} }
return ($entry->time + $key->lifetime) > time(); return ($entry->time + $key->lifetime) > microtime(true);
}
/**
* @param QueryCacheKey $key
* @param QueryCacheEntry $entry
*
* @return bool
*/
private function regionUpdated(QueryCacheKey $key, QueryCacheEntry $entry)
{
if ($key->timestampKey === null) {
return false;
}
$timestamp = $this->timestampRegion->get($key->timestampKey);
return $timestamp && $timestamp->time > $entry->time;
} }
} }

View File

@ -22,6 +22,7 @@ namespace Doctrine\ORM;
use Exception; use Exception;
use Doctrine\Common\EventManager; use Doctrine\Common\EventManager;
use Doctrine\DBAL\Connection; use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\LockMode; use Doctrine\DBAL\LockMode;
use Doctrine\ORM\Query\ResultSetMapping; use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\Proxy\ProxyFactory; use Doctrine\ORM\Proxy\ProxyFactory;
@ -289,7 +290,7 @@ use Doctrine\Common\Util\ClassUtils;
$query = new Query($this); $query = new Query($this);
if ( ! empty($dql)) { if ( ! empty($dql)) {
$query->setDql($dql); $query->setDQL($dql);
} }
return $query; return $query;
@ -310,7 +311,7 @@ use Doctrine\Common\Util\ClassUtils;
{ {
$query = new NativeQuery($this); $query = new NativeQuery($this);
$query->setSql($sql); $query->setSQL($sql);
$query->setResultSetMapping($rsm); $query->setResultSetMapping($rsm);
return $query; return $query;
@ -820,7 +821,7 @@ use Doctrine\Common\Util\ClassUtils;
/** /**
* Factory method to create EntityManager instances. * Factory method to create EntityManager instances.
* *
* @param mixed $conn An array with the connection parameters or an existing Connection instance. * @param array|Connection $connection An array with the connection parameters or an existing Connection instance.
* @param Configuration $config The Configuration instance to use. * @param Configuration $config The Configuration instance to use.
* @param EventManager $eventManager The EventManager instance to use. * @param EventManager $eventManager The EventManager instance to use.
* *
@ -829,30 +830,44 @@ use Doctrine\Common\Util\ClassUtils;
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
* @throws ORMException * @throws ORMException
*/ */
public static function create($conn, Configuration $config, EventManager $eventManager = null) public static function create($connection, Configuration $config, EventManager $eventManager = null)
{ {
if ( ! $config->getMetadataDriverImpl()) { if ( ! $config->getMetadataDriverImpl()) {
throw ORMException::missingMappingDriverImpl(); throw ORMException::missingMappingDriverImpl();
} }
switch (true) { $connection = static::createConnection($connection, $config, $eventManager);
case (is_array($conn)):
$conn = \Doctrine\DBAL\DriverManager::getConnection(
$conn, $config, ($eventManager ?: new EventManager())
);
break;
case ($conn instanceof Connection): return new EntityManager($connection, $config, $connection->getEventManager());
if ($eventManager !== null && $conn->getEventManager() !== $eventManager) { }
/**
* Factory method to create Connection instances.
*
* @param array|Connection $connection An array with the connection parameters or an existing Connection instance.
* @param Configuration $config The Configuration instance to use.
* @param EventManager $eventManager The EventManager instance to use.
*
* @return Connection
*
* @throws \InvalidArgumentException
* @throws ORMException
*/
protected static function createConnection($connection, Configuration $config, EventManager $eventManager = null)
{
if (is_array($connection)) {
return DriverManager::getConnection($connection, $config, $eventManager ?: new EventManager());
}
if ( ! $connection instanceof Connection) {
throw new \InvalidArgumentException("Invalid argument: " . $connection);
}
if ($eventManager !== null && $connection->getEventManager() !== $eventManager) {
throw ORMException::mismatchedEventManager(); throw ORMException::mismatchedEventManager();
} }
break;
default: return $connection;
throw new \InvalidArgumentException("Invalid argument: " . $conn);
}
return new EntityManager($conn, $config, $conn->getEventManager());
} }
/** /**

View File

@ -7,9 +7,9 @@
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION); HOWEVER CAUSED AND ON ANY * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE); ARISING IN ANY WAY OUT OF THE USE * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals

View File

@ -19,7 +19,7 @@
namespace Doctrine\ORM; namespace Doctrine\ORM;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\Common\Util\Inflector;
use Doctrine\ORM\Query\ResultSetMappingBuilder; use Doctrine\ORM\Query\ResultSetMappingBuilder;
use Doctrine\Common\Persistence\ObjectRepository; use Doctrine\Common\Persistence\ObjectRepository;
use Doctrine\Common\Collections\Selectable; use Doctrine\Common\Collections\Selectable;
@ -197,66 +197,50 @@ class EntityRepository implements ObjectRepository, Selectable
} }
/** /**
* Adds support for magic finders. * Counts entities by a set of criteria.
*
* @todo Add this method to `ObjectRepository` interface in the next major release
*
* @param array $criteria
*
* @return int The cardinality of the objects that match the given criteria.
*/
public function count(array $criteria)
{
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->count($criteria);
}
/**
* Adds support for magic method calls.
* *
* @param string $method * @param string $method
* @param array $arguments * @param array $arguments
* *
* @return array|object The found entity/entities. * @return mixed The returned value from the resolved method.
* *
* @throws ORMException * @throws ORMException
* @throws \BadMethodCallException If the method called is an invalid find* method * @throws \BadMethodCallException If the method called is invalid
* or no find* method at all and therefore an invalid
* method call.
*/ */
public function __call($method, $arguments) public function __call($method, $arguments)
{ {
switch (true) { if (0 === strpos($method, 'findBy')) {
case (0 === strpos($method, 'findBy')): return $this->resolveMagicCall('findBy', substr($method, 6), $arguments);
$by = substr($method, 6); }
$method = 'findBy';
break;
case (0 === strpos($method, 'findOneBy')): if (0 === strpos($method, 'findOneBy')) {
$by = substr($method, 9); return $this->resolveMagicCall('findOneBy', substr($method, 9), $arguments);
$method = 'findOneBy'; }
break;
if (0 === strpos($method, 'countBy')) {
return $this->resolveMagicCall('count', substr($method, 7), $arguments);
}
default:
throw new \BadMethodCallException( throw new \BadMethodCallException(
"Undefined method '$method'. The method name must start with ". "Undefined method '$method'. The method name must start with ".
"either findBy or findOneBy!" "either findBy, findOneBy or countBy!"
); );
} }
if (empty($arguments)) {
throw ORMException::findByRequiresParameter($method . $by);
}
$fieldName = lcfirst(\Doctrine\Common\Util\Inflector::classify($by));
if ($this->_class->hasField($fieldName) || $this->_class->hasAssociation($fieldName)) {
switch (count($arguments)) {
case 1:
return $this->$method(array($fieldName => $arguments[0]));
case 2:
return $this->$method(array($fieldName => $arguments[0]), $arguments[1]);
case 3:
return $this->$method(array($fieldName => $arguments[0]), $arguments[1], $arguments[2]);
case 4:
return $this->$method(array($fieldName => $arguments[0]), $arguments[1], $arguments[2], $arguments[3]);
default:
// Do nothing
}
}
throw ORMException::invalidFindByCall($this->_entityName, $fieldName, $method.$by);
}
/** /**
* @return string * @return string
*/ */
@ -303,4 +287,30 @@ class EntityRepository implements ObjectRepository, Selectable
return new LazyCriteriaCollection($persister, $criteria); return new LazyCriteriaCollection($persister, $criteria);
} }
/**
* Resolves a magic method call to the proper existent method at `EntityRepository`.
*
* @param string $method The method to call
* @param string $by The property name used as condition
* @param array $arguments The arguments to pass at method call
*
* @throws ORMException If the method called is invalid or the requested field/association does not exist
*
* @return mixed
*/
private function resolveMagicCall($method, $by, array $arguments)
{
if (! $arguments) {
throw ORMException::findByRequiresParameter($method . $by);
}
$fieldName = lcfirst(Inflector::classify($by));
if (! ($this->_class->hasField($fieldName) || $this->_class->hasAssociation($fieldName))) {
throw ORMException::invalidMagicCall($this->_entityName, $fieldName, $method . $by);
}
return $this->$method([$fieldName => $arguments[0]], ...array_slice($arguments, 1));
}
} }

View File

@ -15,7 +15,7 @@
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see * and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Event; namespace Doctrine\ORM\Event;

View File

@ -24,9 +24,6 @@ use PDO;
use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\PersistentCollection; use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Query; use Doctrine\ORM\Query;
use Doctrine\ORM\Events;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Event\PostLoadEventDispatcher;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Proxy\Proxy; use Doctrine\ORM\Proxy\Proxy;
@ -332,6 +329,9 @@ class ObjectHydrator extends AbstractHydrator
// Split the row data into chunks of class data. // Split the row data into chunks of class data.
$rowData = $this->gatherRowData($row, $id, $nonemptyComponents); $rowData = $this->gatherRowData($row, $id, $nonemptyComponents);
// reset result pointers for each data row
$this->resultPointers = [];
// Hydrate the data chunks // Hydrate the data chunks
foreach ($rowData['data'] as $dqlAlias => $data) { foreach ($rowData['data'] as $dqlAlias => $data) {
$entityName = $this->_rsm->aliasMap[$dqlAlias]; $entityName = $this->_rsm->aliasMap[$dqlAlias];
@ -586,10 +586,7 @@ class ObjectHydrator extends AbstractHydrator
parent::onClear($eventArgs); parent::onClear($eventArgs);
$aliases = array_keys($this->identifierMap); $aliases = array_keys($this->identifierMap);
$this->identifierMap = array();
foreach ($aliases as $alias) { $this->identifierMap = array_fill_keys($aliases, []);
$this->identifierMap[$alias] = array();
}
} }
} }

View File

@ -20,7 +20,6 @@
namespace Doctrine\ORM\Internal\Hydration; namespace Doctrine\ORM\Internal\Hydration;
use PDO; use PDO;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query; use Doctrine\ORM\Query;
@ -122,6 +121,9 @@ class SimpleObjectHydrator extends AbstractHydrator
continue; continue;
} }
// Check if value is null before conversion (because some types convert null to something else)
$valueIsNull = null === $value;
// Convert field to a valid PHP value // Convert field to a valid PHP value
if (isset($cacheKeyInfo['type'])) { if (isset($cacheKeyInfo['type'])) {
$type = $cacheKeyInfo['type']; $type = $cacheKeyInfo['type'];
@ -131,7 +133,7 @@ class SimpleObjectHydrator extends AbstractHydrator
$fieldName = $cacheKeyInfo['fieldName']; $fieldName = $cacheKeyInfo['fieldName'];
// Prevent overwrite in case of inherit classes using same property name (See AbstractHydrator) // Prevent overwrite in case of inherit classes using same property name (See AbstractHydrator)
if ( ! isset($data[$fieldName]) || $value !== null) { if ( ! isset($data[$fieldName]) || ! $valueIsNull) {
$data[$fieldName] = $value; $data[$fieldName] = $value;
} }
} }

View File

@ -941,8 +941,13 @@ class ClassMetadataInfo implements ClassMetadata
continue; continue;
} }
$parentReflFields[$property] = $reflService->getAccessibleProperty($this->name, $property); $fieldRefl = $reflService->getAccessibleProperty(
$this->reflFields[$property] = $reflService->getAccessibleProperty($this->name, $property); isset($embeddedClass['declared']) ? $embeddedClass['declared'] : $this->name,
$property
);
$parentReflFields[$property] = $fieldRefl;
$this->reflFields[$property] = $fieldRefl;
} }
foreach ($this->fieldMappings as $field => $mapping) { foreach ($this->fieldMappings as $field => $mapping) {
@ -1460,8 +1465,7 @@ class ClassMetadataInfo implements ClassMetadata
$mapping['isOwningSide'] = true; // assume owning side until we hit mappedBy $mapping['isOwningSide'] = true; // assume owning side until we hit mappedBy
// unset optional indexBy attribute if its empty if (empty($mapping['indexBy'])) {
if ( ! isset($mapping['indexBy']) || !$mapping['indexBy']) {
unset($mapping['indexBy']); unset($mapping['indexBy']);
} }
@ -1539,13 +1543,12 @@ class ClassMetadataInfo implements ClassMetadata
// Cascades // Cascades
$cascades = isset($mapping['cascade']) ? array_map('strtolower', $mapping['cascade']) : array(); $cascades = isset($mapping['cascade']) ? array_map('strtolower', $mapping['cascade']) : array();
$allCascades = array('remove', 'persist', 'refresh', 'merge', 'detach');
if (in_array('all', $cascades)) { if (in_array('all', $cascades)) {
$cascades = array('remove', 'persist', 'refresh', 'merge', 'detach'); $cascades = $allCascades;
} } elseif (count($cascades) !== count(array_intersect($cascades, $allCascades))) {
if (count($cascades) !== count(array_intersect($cascades, array('remove', 'persist', 'refresh', 'merge', 'detach')))) {
throw MappingException::invalidCascadeOption( throw MappingException::invalidCascadeOption(
array_diff($cascades, array_intersect($cascades, array('remove', 'persist', 'refresh', 'merge', 'detach'))), array_diff($cascades, $allCascades),
$this->name, $this->name,
$mapping['fieldName'] $mapping['fieldName']
); );
@ -1580,7 +1583,7 @@ class ClassMetadataInfo implements ClassMetadata
} }
if ($mapping['isOwningSide']) { if ($mapping['isOwningSide']) {
if ( ! isset($mapping['joinColumns']) || ! $mapping['joinColumns']) { if (empty($mapping['joinColumns'])) {
// Apply default join column // Apply default join column
$mapping['joinColumns'] = array( $mapping['joinColumns'] = array(
array( array(
@ -1594,8 +1597,8 @@ class ClassMetadataInfo implements ClassMetadata
foreach ($mapping['joinColumns'] as &$joinColumn) { foreach ($mapping['joinColumns'] as &$joinColumn) {
if ($mapping['type'] === self::ONE_TO_ONE && ! $this->isInheritanceTypeSingleTable()) { if ($mapping['type'] === self::ONE_TO_ONE && ! $this->isInheritanceTypeSingleTable()) {
if (count($mapping['joinColumns']) == 1) { if (count($mapping['joinColumns']) === 1) {
if ( ! isset($mapping['id']) || ! $mapping['id']) { if (empty($mapping['id'])) {
$joinColumn['unique'] = true; $joinColumn['unique'] = true;
} }
} else { } else {
@ -1640,8 +1643,8 @@ class ClassMetadataInfo implements ClassMetadata
$mapping['targetToSourceKeyColumns'] = array_flip($mapping['sourceToTargetKeyColumns']); $mapping['targetToSourceKeyColumns'] = array_flip($mapping['sourceToTargetKeyColumns']);
} }
$mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false; $mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) && $mapping['orphanRemoval'];
$mapping['isCascadeRemove'] = $mapping['orphanRemoval'] ? true : $mapping['isCascadeRemove']; $mapping['isCascadeRemove'] = $mapping['orphanRemoval'] || $mapping['isCascadeRemove'];
if ($mapping['orphanRemoval']) { if ($mapping['orphanRemoval']) {
unset($mapping['unique']); unset($mapping['unique']);
@ -1673,14 +1676,10 @@ class ClassMetadataInfo implements ClassMetadata
throw MappingException::oneToManyRequiresMappedBy($mapping['fieldName']); throw MappingException::oneToManyRequiresMappedBy($mapping['fieldName']);
} }
$mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false; $mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) && $mapping['orphanRemoval'];
$mapping['isCascadeRemove'] = $mapping['orphanRemoval'] ? true : $mapping['isCascadeRemove']; $mapping['isCascadeRemove'] = $mapping['orphanRemoval'] || $mapping['isCascadeRemove'];
if (isset($mapping['orderBy'])) { $this->assertMappingOrderBy($mapping);
if ( ! is_array($mapping['orderBy'])) {
throw new InvalidArgumentException("'orderBy' is expected to be an array, not ".gettype($mapping['orderBy']));
}
}
return $mapping; return $mapping;
} }
@ -1784,13 +1783,9 @@ class ClassMetadataInfo implements ClassMetadata
} }
} }
$mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false; $mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) && $mapping['orphanRemoval'];
if (isset($mapping['orderBy'])) { $this->assertMappingOrderBy($mapping);
if ( ! is_array($mapping['orderBy'])) {
throw new InvalidArgumentException("'orderBy' is expected to be an array, not ".gettype($mapping['orderBy']));
}
}
return $mapping; return $mapping;
} }
@ -2208,11 +2203,11 @@ class ClassMetadataInfo implements ClassMetadata
$overrideMapping['id'] = $mapping['id']; $overrideMapping['id'] = $mapping['id'];
} }
if ( ! isset($overrideMapping['type']) || $overrideMapping['type'] === null) { if ( ! isset($overrideMapping['type'])) {
$overrideMapping['type'] = $mapping['type']; $overrideMapping['type'] = $mapping['type'];
} }
if ( ! isset($overrideMapping['fieldName']) || $overrideMapping['fieldName'] === null) { if ( ! isset($overrideMapping['fieldName'])) {
$overrideMapping['fieldName'] = $mapping['fieldName']; $overrideMapping['fieldName'] = $mapping['fieldName'];
} }
@ -2948,7 +2943,8 @@ class ClassMetadataInfo implements ClassMetadata
{ {
if (isset($this->fieldNames[$columnName])) { if (isset($this->fieldNames[$columnName])) {
return $this->fieldNames[$columnName]; return $this->fieldNames[$columnName];
} else { }
foreach ($this->associationMappings as $assocName => $mapping) { foreach ($this->associationMappings as $assocName => $mapping) {
if ($this->isAssociationWithSingleJoinColumn($assocName) && if ($this->isAssociationWithSingleJoinColumn($assocName) &&
$this->associationMappings[$assocName]['joinColumns'][0]['name'] == $columnName) { $this->associationMappings[$assocName]['joinColumns'][0]['name'] == $columnName) {
@ -2959,7 +2955,6 @@ class ClassMetadataInfo implements ClassMetadata
throw MappingException::noFieldNameFoundForColumn($this->name, $columnName); throw MappingException::noFieldNameFoundForColumn($this->name, $columnName);
} }
}
/** /**
* Sets the ID generator used to generate IDs for instances of this class. * Sets the ID generator used to generate IDs for instances of this class.
@ -3385,4 +3380,14 @@ class ClassMetadataInfo implements ClassMetadata
return $sequencePrefix; return $sequencePrefix;
} }
/**
* @param array $mapping
*/
private function assertMappingOrderBy(array $mapping)
{
if (isset($mapping['orderBy']) && !is_array($mapping['orderBy'])) {
throw new InvalidArgumentException("'orderBy' is expected to be an array, not " . gettype($mapping['orderBy']));
}
}
} }

View File

@ -15,7 +15,7 @@
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see * and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Mapping\Driver; namespace Doctrine\ORM\Mapping\Driver;

View File

@ -15,7 +15,7 @@
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see * and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Mapping\Driver; namespace Doctrine\ORM\Mapping\Driver;

View File

@ -14,7 +14,7 @@
* *
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see * and is licensed under the MIT license. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Mapping; namespace Doctrine\ORM\Mapping;

View File

@ -187,6 +187,21 @@ class ORMException extends Exception
); );
} }
/**
* @param string $entityName
* @param string $fieldName
* @param string $method
*
* @return ORMException
*/
public static function invalidMagicCall($entityName, $fieldName, $method)
{
return new self(
"Entity '".$entityName."' has no field '".$fieldName."'. ".
"You can therefore not call '".$method."' on the entities' repository"
);
}
/** /**
* @param string $entityName * @param string $entityName
* @param string $associationFieldName * @param string $associationFieldName

View File

@ -21,7 +21,6 @@ namespace Doctrine\ORM\Persisters\Collection;
use Doctrine\Common\Collections\Criteria; use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Persisters\SqlExpressionVisitor;
use Doctrine\ORM\Persisters\SqlValueVisitor; use Doctrine\ORM\Persisters\SqlValueVisitor;
use Doctrine\ORM\PersistentCollection; use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Query; use Doctrine\ORM\Query;
@ -740,7 +739,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
$valueVisitor->dispatch($expression); $valueVisitor->dispatch($expression);
list($values, $types) = $valueVisitor->getParamsAndTypes(); list(, $types) = $valueVisitor->getParamsAndTypes();
return $types; return $types;
} }

View File

@ -20,7 +20,6 @@
namespace Doctrine\ORM\Persisters\Collection; namespace Doctrine\ORM\Persisters\Collection;
use Doctrine\Common\Collections\Criteria; use Doctrine\Common\Collections\Criteria;
use Doctrine\Common\Proxy\Proxy;
use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\PersistentCollection; use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Utility\PersisterHelper; use Doctrine\ORM\Utility\PersisterHelper;

View File

@ -822,7 +822,7 @@ class BasicEntityPersister implements EntityPersister
? $this->expandCriteriaParameters($criteria) ? $this->expandCriteriaParameters($criteria)
: $this->expandParameters($criteria); : $this->expandParameters($criteria);
return $this->conn->executeQuery($sql, $params, $types)->fetchColumn(); return (int) $this->conn->executeQuery($sql, $params, $types)->fetchColumn();
} }
/** /**
@ -1442,7 +1442,7 @@ class BasicEntityPersister implements EntityPersister
continue; continue;
} }
if ($this->class->generatorType != ClassMetadata::GENERATOR_TYPE_IDENTITY || $this->class->identifier[0] != $name) { if (! $this->class->isIdGeneratorIdentity() || $this->class->identifier[0] != $name) {
$columns[] = $this->quoteStrategy->getColumnName($name, $this->class, $this->platform); $columns[] = $this->quoteStrategy->getColumnName($name, $this->class, $this->platform);
$this->columnTypes[$name] = $this->class->fieldMappings[$name]['type']; $this->columnTypes[$name] = $this->class->fieldMappings[$name]['type'];
} }

View File

@ -20,7 +20,6 @@
namespace Doctrine\ORM\Persisters\Entity; namespace Doctrine\ORM\Persisters\Entity;
use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\DBAL\LockMode; use Doctrine\DBAL\LockMode;
use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Type;

View File

@ -196,7 +196,7 @@ class ProxyFactory extends AbstractProxyFactory
); );
} }
foreach ($class->getReflectionClass()->getProperties() as $property) { foreach ($class->getReflectionProperties() as $property) {
if ( ! $class->hasField($property->name) && ! $class->hasAssociation($property->name)) { if ( ! $class->hasField($property->name) && ! $class->hasAssociation($property->name)) {
continue; continue;
} }

View File

@ -13,7 +13,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT. For more information, see * and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>. * <http://www.doctrine-project.org>.
*/ */

View File

@ -118,8 +118,6 @@ class MultiTableDeleteExecutor extends AbstractSqlExecutor
*/ */
public function execute(Connection $conn, array $params, array $types) public function execute(Connection $conn, array $params, array $types)
{ {
$numDeleted = 0;
// Create temporary id table // Create temporary id table
$conn->executeUpdate($this->_createTempTableSql); $conn->executeUpdate($this->_createTempTableSql);

View File

@ -163,8 +163,6 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor
*/ */
public function execute(Connection $conn, array $params, array $types) public function execute(Connection $conn, array $params, array $types)
{ {
$numUpdated = 0;
// Create temporary id table // Create temporary id table
$conn->executeUpdate($this->_createTempTableSql); $conn->executeUpdate($this->_createTempTableSql);

View File

@ -827,18 +827,14 @@ class Parser
return; return;
} }
$foundRootEntity = false;
foreach ($this->identVariableExpressions as $dqlAlias => $expr) { foreach ($this->identVariableExpressions as $dqlAlias => $expr) {
if (isset($this->queryComponents[$dqlAlias]) && $this->queryComponents[$dqlAlias]['parent'] === null) { if (isset($this->queryComponents[$dqlAlias]) && $this->queryComponents[$dqlAlias]['parent'] === null) {
$foundRootEntity = true; return;
} }
} }
if ( ! $foundRootEntity) {
$this->semanticalError('Cannot select entity through identification variables without choosing at least one root entity alias.'); $this->semanticalError('Cannot select entity through identification variables without choosing at least one root entity alias.');
} }
}
/** /**
* QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatement * QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatement
@ -2953,7 +2949,7 @@ class Parser
/** /**
* EntityExpression ::= SingleValuedAssociationPathExpression | SimpleEntityExpression * EntityExpression ::= SingleValuedAssociationPathExpression | SimpleEntityExpression
* *
* @return \Doctrine\ORM\Query\AST\SingleValuedAssociationPathExpression | * @return \Doctrine\ORM\Query\AST\PathExpression |
* \Doctrine\ORM\Query\AST\SimpleEntityExpression * \Doctrine\ORM\Query\AST\SimpleEntityExpression
*/ */
public function EntityExpression() public function EntityExpression()

View File

@ -19,7 +19,6 @@
namespace Doctrine\ORM\Query; namespace Doctrine\ORM\Query;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadataInfo; use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\Mapping\MappingException; use Doctrine\ORM\Mapping\MappingException;

View File

@ -469,14 +469,15 @@ class QueryBuilder
* $qb = $em->createQueryBuilder() * $qb = $em->createQueryBuilder()
* ->select('u') * ->select('u')
* ->from('User', 'u') * ->from('User', 'u')
* ->join('u.articles','a'; * ->join('u.articles','a');
* *
* $qb->getAllAliases(); // array('u','a') * $qb->getAllAliases(); // array('u','a')
* </code> * </code>
* @return array * @return array
*/ */
public function getAllAliases() { public function getAllAliases()
return array_merge($this->getRootAliases(),array_keys($this->joinRootAliases)); {
return array_merge($this->getRootAliases(), array_keys($this->joinRootAliases));
} }
/** /**

View File

@ -117,7 +117,7 @@ class PhpExporter extends AbstractExporter
$oneToOneMappingArray = array( $oneToOneMappingArray = array(
'mappedBy' => $associationMapping['mappedBy'], 'mappedBy' => $associationMapping['mappedBy'],
'inversedBy' => $associationMapping['inversedBy'], 'inversedBy' => $associationMapping['inversedBy'],
'joinColumns' => $associationMapping['joinColumns'], 'joinColumns' => $associationMapping['isOwningSide'] ? $associationMapping['joinColumns'] : [],
'orphanRemoval' => $associationMapping['orphanRemoval'], 'orphanRemoval' => $associationMapping['orphanRemoval'],
); );

View File

@ -163,7 +163,7 @@ class YamlExporter extends AbstractExporter
} }
if ($associationMapping['type'] & ClassMetadataInfo::TO_ONE) { if ($associationMapping['type'] & ClassMetadataInfo::TO_ONE) {
$joinColumns = $associationMapping['joinColumns']; $joinColumns = $associationMapping['isOwningSide'] ? $associationMapping['joinColumns'] : [];
$newJoinColumns = array(); $newJoinColumns = array();
foreach ($joinColumns as $joinColumn) { foreach ($joinColumns as $joinColumn) {

View File

@ -1,4 +1,21 @@
<?php <?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Tools\Export; namespace Doctrine\ORM\Tools\Export;

View File

@ -1,14 +1,20 @@
<?php <?php
/** /*
* Doctrine ORM * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* LICENSE * This software consists of voluntary contributions made by many individuals
* * and is licensed under the MIT license. For more information, see
* This source file is subject to the new BSD license that is bundled * <http://www.doctrine-project.org>.
* with this package in the file LICENSE.txt.
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to kontakt@beberlei.de so I can send you a copy immediately.
*/ */
namespace Doctrine\ORM\Tools\Pagination; namespace Doctrine\ORM\Tools\Pagination;

View File

@ -1,14 +1,20 @@
<?php <?php
/** /*
* Doctrine ORM * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* LICENSE * This software consists of voluntary contributions made by many individuals
* * and is licensed under the MIT license. For more information, see
* This source file is subject to the new BSD license that is bundled * <http://www.doctrine-project.org>.
* with this package in the file LICENSE.txt.
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to kontakt@beberlei.de so I can send you a copy immediately.
*/ */
namespace Doctrine\ORM\Tools\Pagination; namespace Doctrine\ORM\Tools\Pagination;

View File

@ -1,14 +1,20 @@
<?php <?php
/** /*
* Doctrine ORM * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* LICENSE * This software consists of voluntary contributions made by many individuals
* * and is licensed under the MIT license. For more information, see
* This source file is subject to the new BSD license that is bundled * <http://www.doctrine-project.org>.
* with this package in the file LICENSE.txt.
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to kontakt@beberlei.de so I can send you a copy immediately.
*/ */
namespace Doctrine\ORM\Tools\Pagination; namespace Doctrine\ORM\Tools\Pagination;
@ -18,18 +24,9 @@ use Doctrine\DBAL\Platforms\OraclePlatform;
use Doctrine\DBAL\Platforms\PostgreSqlPlatform; use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
use Doctrine\DBAL\Platforms\SQLAnywherePlatform; use Doctrine\DBAL\Platforms\SQLAnywherePlatform;
use Doctrine\DBAL\Platforms\SQLServerPlatform; use Doctrine\DBAL\Platforms\SQLServerPlatform;
use Doctrine\ORM\Query\AST\ArithmeticExpression;
use Doctrine\ORM\Query\AST\ArithmeticFactor;
use Doctrine\ORM\Query\AST\ArithmeticTerm;
use Doctrine\ORM\Query\AST\Literal;
use Doctrine\ORM\Query\AST\OrderByClause; use Doctrine\ORM\Query\AST\OrderByClause;
use Doctrine\ORM\Query\AST\OrderByItem;
use Doctrine\ORM\Query\AST\PartialObjectExpression; use Doctrine\ORM\Query\AST\PartialObjectExpression;
use Doctrine\ORM\Query\AST\PathExpression;
use Doctrine\ORM\Query\AST\SelectExpression; use Doctrine\ORM\Query\AST\SelectExpression;
use Doctrine\ORM\Query\AST\SimpleArithmeticExpression;
use Doctrine\ORM\Query\Expr\OrderBy;
use Doctrine\ORM\Query\Expr\Select;
use Doctrine\ORM\Query\SqlWalker; use Doctrine\ORM\Query\SqlWalker;
use Doctrine\ORM\Query\AST\SelectStatement; use Doctrine\ORM\Query\AST\SelectStatement;

View File

@ -1,26 +1,26 @@
<?php <?php
/*
/** * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* Doctrine ORM * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* LICENSE * This software consists of voluntary contributions made by many individuals
* * and is licensed under the MIT license. For more information, see
* This source file is subject to the new BSD license that is bundled * <http://www.doctrine-project.org>.
* with this package in the file LICENSE. This license can also be viewed
* at http://hobodave.com/license.txt
*
* @category DoctrineExtensions
* @package DoctrineExtensions\Paginate
* @author David Abdemoulaie <dave@hobodave.com>
* @copyright Copyright (c) 2010 David Abdemoulaie (http://hobodave.com/)
* @license http://hobodave.com/license.txt New BSD License
*/ */
namespace Doctrine\ORM\Tools\Pagination; namespace Doctrine\ORM\Tools\Pagination;
use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Mapping\ClassMetadataInfo; use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\ORMException;
use Doctrine\ORM\Query; use Doctrine\ORM\Query;
use Doctrine\ORM\Query\TreeWalkerAdapter; use Doctrine\ORM\Query\TreeWalkerAdapter;
use Doctrine\ORM\Query\AST\Functions\IdentityFunction; use Doctrine\ORM\Query\AST\Functions\IdentityFunction;

View File

@ -1,18 +1,20 @@
<?php <?php
/** /*
* Doctrine ORM * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* LICENSE * This software consists of voluntary contributions made by many individuals
* * and is licensed under the MIT license. For more information, see
* This source file is subject to the new BSD license that is bundled * <http://www.doctrine-project.org>.
* with this package in the file LICENSE. This license can also be viewed
* at http://hobodave.com/license.txt
*
* @category DoctrineExtensions
* @package DoctrineExtensions\Paginate
* @author David Abdemoulaie <dave@hobodave.com>
* @copyright Copyright (c) 2010 David Abdemoulaie (http://hobodave.com/)
* @license http://hobodave.com/license.txt New BSD License
*/ */
namespace Doctrine\ORM\Tools\Pagination; namespace Doctrine\ORM\Tools\Pagination;

View File

@ -15,7 +15,7 @@
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see * and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Tools; namespace Doctrine\ORM\Tools;

View File

@ -15,7 +15,7 @@
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see * and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Tools; namespace Doctrine\ORM\Tools;

View File

@ -49,7 +49,6 @@ use Doctrine\ORM\Persisters\Entity\JoinedSubclassPersister;
use Doctrine\ORM\Persisters\Collection\OneToManyPersister; use Doctrine\ORM\Persisters\Collection\OneToManyPersister;
use Doctrine\ORM\Persisters\Collection\ManyToManyPersister; use Doctrine\ORM\Persisters\Collection\ManyToManyPersister;
use Doctrine\ORM\Utility\IdentifierFlattener; use Doctrine\ORM\Utility\IdentifierFlattener;
use Doctrine\ORM\Cache\AssociationCacheEntry;
/** /**
* The UnitOfWork is responsible for tracking changes to objects during an * The UnitOfWork is responsible for tracking changes to objects during an
@ -1156,9 +1155,8 @@ class UnitOfWork implements PropertyChangedListener
} }
$joinColumns = reset($assoc['joinColumns']); $joinColumns = reset($assoc['joinColumns']);
$isNullable = isset($joinColumns['nullable']) ? $joinColumns['nullable'] : false;
$calc->addDependency($targetClass->name, $class->name, $isNullable ? 0 : 1); $calc->addDependency($targetClass->name, $class->name, (int)empty($joinColumns['nullable']));
// If the target class has mapped subclasses, these share the same dependency. // If the target class has mapped subclasses, these share the same dependency.
if ( ! $targetClass->subClasses) { if ( ! $targetClass->subClasses) {
@ -1281,7 +1279,7 @@ class UnitOfWork implements PropertyChangedListener
$extraUpdate = array($entity, $changeset); $extraUpdate = array($entity, $changeset);
if (isset($this->extraUpdates[$oid])) { if (isset($this->extraUpdates[$oid])) {
list($ignored, $changeset2) = $this->extraUpdates[$oid]; list(, $changeset2) = $this->extraUpdates[$oid];
$extraUpdate = array($entity, $changeset + $changeset2); $extraUpdate = array($entity, $changeset + $changeset2);
} }
@ -1345,9 +1343,7 @@ class UnitOfWork implements PropertyChangedListener
$this->removeFromIdentityMap($entity); $this->removeFromIdentityMap($entity);
if (isset($this->entityUpdates[$oid])) {
unset($this->entityUpdates[$oid]); unset($this->entityUpdates[$oid]);
}
if ( ! isset($this->entityDeletions[$oid])) { if ( ! isset($this->entityDeletions[$oid])) {
$this->entityDeletions[$oid] = $entity; $this->entityDeletions[$oid] = $entity;
@ -1402,12 +1398,13 @@ class UnitOfWork implements PropertyChangedListener
public function addToIdentityMap($entity) public function addToIdentityMap($entity)
{ {
$classMetadata = $this->em->getClassMetadata(get_class($entity)); $classMetadata = $this->em->getClassMetadata(get_class($entity));
$idHash = implode(' ', $this->entityIdentifiers[spl_object_hash($entity)]); $identifier = $this->entityIdentifiers[spl_object_hash($entity)];
if ($idHash === '') { if (empty($identifier) || in_array(null, $identifier, true)) {
throw ORMInvalidArgumentException::entityWithoutIdentity($classMetadata->name, $entity); throw ORMInvalidArgumentException::entityWithoutIdentity($classMetadata->name, $entity);
} }
$idHash = implode(' ', $identifier);
$className = $classMetadata->rootEntityName; $className = $classMetadata->rootEntityName;
if (isset($this->identityMap[$className][$idHash])) { if (isset($this->identityMap[$className][$idHash])) {
@ -1569,11 +1566,9 @@ class UnitOfWork implements PropertyChangedListener
{ {
$stringIdHash = (string) $idHash; $stringIdHash = (string) $idHash;
if (isset($this->identityMap[$rootClassName][$stringIdHash])) { return isset($this->identityMap[$rootClassName][$stringIdHash])
return $this->identityMap[$rootClassName][$stringIdHash]; ? $this->identityMap[$rootClassName][$stringIdHash]
} : false;
return false;
} }
/** /**
@ -1797,7 +1792,7 @@ class UnitOfWork implements PropertyChangedListener
* @throws ORMInvalidArgumentException If the entity instance is NEW. * @throws ORMInvalidArgumentException If the entity instance is NEW.
* @throws EntityNotFoundException * @throws EntityNotFoundException
*/ */
private function doMerge($entity, array &$visited, $prevManagedCopy = null, $assoc = null) private function doMerge($entity, array &$visited, $prevManagedCopy = null, array $assoc = [])
{ {
$oid = spl_object_hash($entity); $oid = spl_object_hash($entity);
@ -2391,17 +2386,8 @@ class UnitOfWork implements PropertyChangedListener
$this->visitedCollections = $this->visitedCollections =
$this->orphanRemovals = array(); $this->orphanRemovals = array();
} else { } else {
$visited = array(); $this->clearIdentityMapForEntityName($entityName);
$this->clearEntityInsertionsForEntityName($entityName);
foreach ($this->identityMap as $className => $entities) {
if ($className !== $entityName) {
continue;
}
foreach ($entities as $entity) {
$this->doDetach($entity, $visited, false);
}
}
} }
if ($this->evm->hasListeners(Events::onClear)) { if ($this->evm->hasListeners(Events::onClear)) {
@ -2455,9 +2441,7 @@ class UnitOfWork implements PropertyChangedListener
// TODO: if $coll is already scheduled for recreation ... what to do? // TODO: if $coll is already scheduled for recreation ... what to do?
// Just remove $coll from the scheduled recreations? // Just remove $coll from the scheduled recreations?
if (isset($this->collectionUpdates[$coid])) {
unset($this->collectionUpdates[$coid]); unset($this->collectionUpdates[$coid]);
}
$this->collectionDeletions[$coid] = $coll; $this->collectionDeletions[$coid] = $coll;
} }
@ -2864,11 +2848,9 @@ class UnitOfWork implements PropertyChangedListener
{ {
$oid = spl_object_hash($entity); $oid = spl_object_hash($entity);
if (isset($this->originalEntityData[$oid])) { return isset($this->originalEntityData[$oid])
return $this->originalEntityData[$oid]; ? $this->originalEntityData[$oid]
} : [];
return array();
} }
/** /**
@ -2954,11 +2936,9 @@ class UnitOfWork implements PropertyChangedListener
{ {
$idHash = implode(' ', (array) $id); $idHash = implode(' ', (array) $id);
if (isset($this->identityMap[$rootClassName][$idHash])) { return isset($this->identityMap[$rootClassName][$idHash])
return $this->identityMap[$rootClassName][$idHash]; ? $this->identityMap[$rootClassName][$idHash]
} : false;
return false;
} }
/** /**
@ -2995,7 +2975,7 @@ class UnitOfWork implements PropertyChangedListener
*/ */
public function size() public function size()
{ {
$countArray = array_map(function ($item) { return count($item); }, $this->identityMap); $countArray = array_map('count', $this->identityMap);
return array_sum($countArray); return array_sum($countArray);
} }
@ -3424,8 +3404,6 @@ class UnitOfWork implements PropertyChangedListener
); );
$managedCol->setOwner($managedCopy, $assoc2); $managedCol->setOwner($managedCopy, $assoc2);
$prop->setValue($managedCopy, $managedCol); $prop->setValue($managedCopy, $managedCol);
$this->originalEntityData[spl_object_hash($entity)][$name] = $managedCol;
} }
if ($assoc2['isCascadeMerge']) { if ($assoc2['isCascadeMerge']) {
@ -3464,4 +3442,33 @@ class UnitOfWork implements PropertyChangedListener
{ {
$this->hydrationCompleteHandler->hydrationComplete(); $this->hydrationCompleteHandler->hydrationComplete();
} }
/**
* @param string $entityName
*/
private function clearIdentityMapForEntityName($entityName)
{
if (! isset($this->identityMap[$entityName])) {
return;
}
$visited = [];
foreach ($this->identityMap[$entityName] as $entity) {
$this->doDetach($entity, $visited, false);
}
}
/**
* @param string $entityName
*/
private function clearEntityInsertionsForEntityName($entityName)
{
foreach ($this->entityInsertions as $hash => $entity) {
// note: performance optimization - `instanceof` is much faster than a function call
if ($entity instanceof $entityName && get_class($entity) === $entityName) {
unset($this->entityInsertions[$hash]);
}
}
}
} }

View File

@ -1,21 +1,4 @@
<?php <?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Tests\DbalTypes; namespace Doctrine\Tests\DbalTypes;

View File

@ -1,21 +1,4 @@
<?php <?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Tests\DbalTypes; namespace Doctrine\Tests\DbalTypes;

View File

@ -40,7 +40,7 @@ class CacheMetadataListener
* *
* @return bool * @return bool
*/ */
private function isVisited(ClassMetaData $metadata) private function isVisited(ClassMetadata $metadata)
{ {
return isset($this->enabledItems[$metadata->getName()]); return isset($this->enabledItems[$metadata->getName()]);
} }
@ -48,7 +48,7 @@ class CacheMetadataListener
/** /**
* @param ClassMetadata $metadata * @param ClassMetadata $metadata
*/ */
private function recordVisit(ClassMetaData $metadata) private function recordVisit(ClassMetadata $metadata)
{ {
$this->enabledItems[$metadata->getName()] = true; $this->enabledItems[$metadata->getName()] = true;
} }

View File

@ -2,10 +2,12 @@
namespace Doctrine\Tests\Mocks; namespace Doctrine\Tests\Mocks;
use Doctrine\ORM\Mapping\ClassMetadata;
/** /**
* Mock class for ClassMetadata. * Mock class for ClassMetadata.
*/ */
class ClassMetadataMock extends \Doctrine\ORM\Mapping\ClassMetadata class ClassMetadataMock extends ClassMetadata
{ {
/* Mock API */ /* Mock API */

View File

@ -1,11 +1,12 @@
<?php <?php
namespace Doctrine\Tests\Mocks; namespace Doctrine\Tests\Mocks;
use Doctrine\DBAL\Connection;
/** /**
* Mock class for Connection. * Mock class for Connection.
*/ */
class ConnectionMock extends \Doctrine\DBAL\Connection class ConnectionMock extends Connection
{ {
/** /**
* @var mixed * @var mixed

View File

@ -2,10 +2,12 @@
namespace Doctrine\Tests\Mocks; namespace Doctrine\Tests\Mocks;
use Doctrine\DBAL\Platforms\AbstractPlatform;
/** /**
* Mock class for DatabasePlatform. * Mock class for DatabasePlatform.
*/ */
class DatabasePlatformMock extends \Doctrine\DBAL\Platforms\AbstractPlatform class DatabasePlatformMock extends AbstractPlatform
{ {
/** /**
* @var string * @var string

View File

@ -2,10 +2,12 @@
namespace Doctrine\Tests\Mocks; namespace Doctrine\Tests\Mocks;
use Doctrine\DBAL\Driver\Connection;
/** /**
* Mock class for DriverConnection. * Mock class for DriverConnection.
*/ */
class DriverConnectionMock implements \Doctrine\DBAL\Driver\Connection class DriverConnectionMock implements Connection
{ {
/** /**
* @var \Doctrine\DBAL\Driver\Statement * @var \Doctrine\DBAL\Driver\Statement

View File

@ -2,10 +2,15 @@
namespace Doctrine\Tests\Mocks; namespace Doctrine\Tests\Mocks;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
/** /**
* Mock class for Driver. * Mock class for Driver.
*/ */
class DriverMock implements \Doctrine\DBAL\Driver class DriverMock implements Driver
{ {
/** /**
* @var \Doctrine\DBAL\Platforms\AbstractPlatform|null * @var \Doctrine\DBAL\Platforms\AbstractPlatform|null
@ -39,7 +44,7 @@ class DriverMock implements \Doctrine\DBAL\Driver
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getSchemaManager(\Doctrine\DBAL\Connection $conn) public function getSchemaManager(Connection $conn)
{ {
if ($this->_schemaManagerMock == null) { if ($this->_schemaManagerMock == null) {
return new SchemaManagerMock($conn); return new SchemaManagerMock($conn);
@ -55,7 +60,7 @@ class DriverMock implements \Doctrine\DBAL\Driver
* *
* @return void * @return void
*/ */
public function setDatabasePlatform(\Doctrine\DBAL\Platforms\AbstractPlatform $platform) public function setDatabasePlatform(AbstractPlatform $platform)
{ {
$this->_platformMock = $platform; $this->_platformMock = $platform;
} }
@ -65,7 +70,7 @@ class DriverMock implements \Doctrine\DBAL\Driver
* *
* @return void * @return void
*/ */
public function setSchemaManager(\Doctrine\DBAL\Schema\AbstractSchemaManager $sm) public function setSchemaManager(AbstractSchemaManager $sm)
{ {
$this->_schemaManagerMock = $sm; $this->_schemaManagerMock = $sm;
} }
@ -81,7 +86,7 @@ class DriverMock implements \Doctrine\DBAL\Driver
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getDatabase(\Doctrine\DBAL\Connection $conn) public function getDatabase(Connection $conn)
{ {
return; return;
} }

View File

@ -1,32 +1,15 @@
<?php <?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Tests\Mocks; namespace Doctrine\Tests\Mocks;
use Doctrine\ORM\Proxy\ProxyFactory; use Doctrine\Common\EventManager;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\EntityManager;
/** /**
* Special EntityManager mock used for testing purposes. * Special EntityManager mock used for testing purposes.
*/ */
class EntityManagerMock extends \Doctrine\ORM\EntityManager class EntityManagerMock extends EntityManager
{ {
/** /**
* @var \Doctrine\ORM\UnitOfWork|null * @var \Doctrine\ORM\UnitOfWork|null
@ -83,17 +66,16 @@ class EntityManagerMock extends \Doctrine\ORM\EntityManager
* *
* {@inheritdoc} * {@inheritdoc}
*/ */
public static function create($conn, \Doctrine\ORM\Configuration $config = null, public static function create($conn, Configuration $config = null, EventManager $eventManager = null)
\Doctrine\Common\EventManager $eventManager = null)
{ {
if (null === $config) { if (null === $config) {
$config = new \Doctrine\ORM\Configuration(); $config = new Configuration();
$config->setProxyDir(__DIR__ . '/../Proxies'); $config->setProxyDir(__DIR__ . '/../Proxies');
$config->setProxyNamespace('Doctrine\Tests\Proxies'); $config->setProxyNamespace('Doctrine\Tests\Proxies');
$config->setMetadataDriverImpl($config->newDefaultAnnotationDriver(array(), true)); $config->setMetadataDriverImpl($config->newDefaultAnnotationDriver(array(), true));
} }
if (null === $eventManager) { if (null === $eventManager) {
$eventManager = new \Doctrine\Common\EventManager(); $eventManager = new EventManager();
} }
return new EntityManagerMock($conn, $config, $eventManager); return new EntityManagerMock($conn, $config, $eventManager);

View File

@ -3,11 +3,13 @@
namespace Doctrine\Tests\Mocks; namespace Doctrine\Tests\Mocks;
use Doctrine\Common\Collections\Criteria; use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Persisters\Entity\BasicEntityPersister;
/** /**
* EntityPersister implementation used for mocking during tests. * EntityPersister implementation used for mocking during tests.
*/ */
class EntityPersisterMock extends \Doctrine\ORM\Persisters\Entity\BasicEntityPersister class EntityPersisterMock extends BasicEntityPersister
{ {
/** /**
* @var array * @var array
@ -52,7 +54,7 @@ class EntityPersisterMock extends \Doctrine\ORM\Persisters\Entity\BasicEntityPer
public function addInsert($entity) public function addInsert($entity)
{ {
$this->inserts[] = $entity; $this->inserts[] = $entity;
if ( ! is_null($this->mockIdGeneratorType) && $this->mockIdGeneratorType == \Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_IDENTITY if ( ! is_null($this->mockIdGeneratorType) && $this->mockIdGeneratorType == ClassMetadata::GENERATOR_TYPE_IDENTITY
|| $this->class->isIdGeneratorIdentity()) { || $this->class->isIdGeneratorIdentity()) {
$id = $this->identityColumnValueCounter++; $id = $this->identityColumnValueCounter++;
$this->postInsertIds[] = array( $this->postInsertIds[] = array(

View File

@ -2,13 +2,15 @@
namespace Doctrine\Tests\Mocks; namespace Doctrine\Tests\Mocks;
use Doctrine\DBAL\Driver\Statement;
/** /**
* This class is a mock of the Statement interface that can be passed in to the Hydrator * This class is a mock of the Statement interface that can be passed in to the Hydrator
* to test the hydration standalone with faked result sets. * to test the hydration standalone with faked result sets.
* *
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
*/ */
class HydratorMockStatement implements \IteratorAggregate, \Doctrine\DBAL\Driver\Statement class HydratorMockStatement implements \IteratorAggregate, Statement
{ {
/** /**
* @var array * @var array

View File

@ -2,15 +2,18 @@
namespace Doctrine\Tests\Mocks; namespace Doctrine\Tests\Mocks;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
/** /**
* Mock class for MappingDriver. * Mock class for MappingDriver.
*/ */
class MetadataDriverMock implements \Doctrine\Common\Persistence\Mapping\Driver\MappingDriver class MetadataDriverMock implements MappingDriver
{ {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function loadMetadataForClass($className, \Doctrine\Common\Persistence\Mapping\ClassMetadata $metadata) public function loadMetadataForClass($className, ClassMetadata $metadata)
{ {
} }

View File

@ -2,10 +2,12 @@
namespace Doctrine\Tests\Mocks; namespace Doctrine\Tests\Mocks;
use Doctrine\ORM\Query\TreeWalkerAdapter;
/** /**
* Mock class for TreeWalker. * Mock class for TreeWalker.
*/ */
class MockTreeWalker extends \Doctrine\ORM\Query\TreeWalkerAdapter class MockTreeWalker extends TreeWalkerAdapter
{ {
/** /**
* {@inheritdoc} * {@inheritdoc}

View File

@ -2,15 +2,18 @@
namespace Doctrine\Tests\Mocks; namespace Doctrine\Tests\Mocks;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
/** /**
* Mock class for AbstractSchemaManager. * Mock class for AbstractSchemaManager.
*/ */
class SchemaManagerMock extends \Doctrine\DBAL\Schema\AbstractSchemaManager class SchemaManagerMock extends AbstractSchemaManager
{ {
/** /**
* @param \Doctrine\DBAL\Connection $conn * @param \Doctrine\DBAL\Connection $conn
*/ */
public function __construct(\Doctrine\DBAL\Connection $conn) public function __construct(Connection $conn)
{ {
parent::__construct($conn); parent::__construct($conn);
} }

View File

@ -3,11 +3,12 @@
namespace Doctrine\Tests\Mocks; namespace Doctrine\Tests\Mocks;
use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Id\SequenceGenerator;
/** /**
* Mock class for SequenceGenerator. * Mock class for SequenceGenerator.
*/ */
class SequenceMock extends \Doctrine\ORM\Id\SequenceGenerator class SequenceMock extends SequenceGenerator
{ {
/** /**
* @var int * @var int

View File

@ -1,10 +1,4 @@
<?php <?php
/**
* Created by PhpStorm.
* User: avasilenko
* Date: 24/04/15
* Time: 19:01
*/
namespace Doctrine\Tests\Mocks; namespace Doctrine\Tests\Mocks;

View File

@ -2,12 +2,14 @@
namespace Doctrine\Tests\Mocks; namespace Doctrine\Tests\Mocks;
use Doctrine\DBAL\Driver\Statement;
/** /**
* This class is a mock of the Statement interface. * This class is a mock of the Statement interface.
* *
* @author Alexander <iam.asm89@gmail.com> * @author Alexander <iam.asm89@gmail.com>
*/ */
class StatementMock implements \IteratorAggregate, \Doctrine\DBAL\Driver\Statement class StatementMock implements \IteratorAggregate, Statement
{ {
/** /**
* {@inheritdoc} * {@inheritdoc}

View File

@ -1,23 +1,4 @@
<?php <?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Tests\Mocks; namespace Doctrine\Tests\Mocks;

View File

@ -2,10 +2,12 @@
namespace Doctrine\Tests\Mocks; namespace Doctrine\Tests\Mocks;
use Doctrine\ORM\UnitOfWork;
/** /**
* Mock class for UnitOfWork. * Mock class for UnitOfWork.
*/ */
class UnitOfWorkMock extends \Doctrine\ORM\UnitOfWork class UnitOfWorkMock extends UnitOfWork
{ {
/** /**
* @var array * @var array

View File

@ -1,8 +1,4 @@
<?php <?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
namespace Doctrine\Tests\Models\CMS; namespace Doctrine\Tests\Models\CMS;

View File

@ -1,8 +1,4 @@
<?php <?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
namespace Doctrine\Tests\Models\CMS; namespace Doctrine\Tests\Models\CMS;

View File

@ -14,13 +14,8 @@ class Action
/** /**
* @Id * @Id
* @GeneratedValue * @Column(type="string")
* @Column(type="integer") * @GeneratedValue(strategy="NONE")
*/
public $id;
/**
* @Column
*/ */
public $name; public $name;

View File

@ -20,14 +20,14 @@ class ComplexAction
/** /**
* @Id * @Id
* @OneToOne(targetEntity="Action", cascade={"persist", "remove"}) * @OneToOne(targetEntity="Action", cascade={"persist", "remove"})
* @JoinColumn(name="action1_id", referencedColumnName="id") * @JoinColumn(name="action1_name", referencedColumnName="name")
*/ */
public $action1; public $action1;
/** /**
* @Id * @Id
* @OneToOne(targetEntity="Action", cascade={"persist", "remove"}) * @OneToOne(targetEntity="Action", cascade={"persist", "remove"})
* @JoinColumn(name="action2_id", referencedColumnName="id") * @JoinColumn(name="action2_name", referencedColumnName="name")
*/ */
public $action2; public $action2;

View File

@ -36,7 +36,7 @@ class Token
/** /**
* @ManyToOne(targetEntity="Action", cascade={"persist", "remove"}, inversedBy="tokens") * @ManyToOne(targetEntity="Action", cascade={"persist", "remove"}, inversedBy="tokens")
* @JoinColumn(name="action_id", referencedColumnName="id") * @JoinColumn(name="action_name", referencedColumnName="name")
* @var array * @var array
*/ */
public $action; public $action;
@ -44,8 +44,8 @@ class Token
/** /**
* @ManyToOne(targetEntity="ComplexAction", cascade={"persist", "remove"}, inversedBy="tokens") * @ManyToOne(targetEntity="ComplexAction", cascade={"persist", "remove"}, inversedBy="tokens")
* @JoinColumns({ * @JoinColumns({
* @JoinColumn(name="complex_action1_id", referencedColumnName="action1_id"), * @JoinColumn(name="complex_action1_name", referencedColumnName="action1_name"),
* @JoinColumn(name="complex_action2_id", referencedColumnName="action2_id") * @JoinColumn(name="complex_action2_name", referencedColumnName="action2_name")
* }) * })
* @var ComplexAction * @var ComplexAction
*/ */

View File

@ -1,21 +1,4 @@
<?php <?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Tests\Models\CustomType; namespace Doctrine\Tests\Models\CustomType;

View File

@ -1,21 +1,4 @@
<?php <?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Tests\Models\CustomType; namespace Doctrine\Tests\Models\CustomType;

View File

@ -1,23 +1,5 @@
<?php <?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Tests\Models\DDC1476; namespace Doctrine\Tests\Models\DDC1476;
/** /**

View File

@ -20,7 +20,7 @@ class DDC2504RootClass
public $id; public $id;
/** /**
* @var Doctrine\Tests\Models\DDC\DDC2504OtherClass * @var \Doctrine\Tests\Models\DDC2504\DDC2504OtherClass
* *
* @ManyToOne(targetEntity="DDC2504OtherClass", inversedBy="childClasses") * @ManyToOne(targetEntity="DDC2504OtherClass", inversedBy="childClasses")
*/ */

View File

@ -10,7 +10,7 @@ class DDC3293User
protected $id; protected $id;
/** /**
* @var Doctrine\Tests\Models\DDC3293\DDC3293Address * @var \Doctrine\Tests\Models\DDC3293\DDC3293Address
*/ */
protected $address; protected $address;
} }

View File

@ -10,7 +10,7 @@ class DDC3293UserPrefixed
protected $id; protected $id;
/** /**
* @var Doctrine\Tests\Models\DDC3293\DDC3293Address * @var \Doctrine\Tests\Models\DDC3293\DDC3293Address
*/ */
protected $address; protected $address;
} }

View File

@ -2,8 +2,6 @@
namespace Doctrine\Tests\Models\DDC3579; namespace Doctrine\Tests\Models\DDC3579;
use Doctrine\Common\Collections\ArrayCollection;
/** /**
* @Entity * @Entity
* @AssociationOverrides({ * @AssociationOverrides({

View File

@ -1,12 +1,13 @@
<?php <?php
/**
* @author Marc Pantel <pantel.m@gmail.com>
*/
namespace Doctrine\Tests\Models\DDC3711; namespace Doctrine\Tests\Models\DDC3711;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
/**
* @author Marc Pantel <pantel.m@gmail.com>
*/
class DDC3711EntityA class DDC3711EntityA
{ {
/** /**

View File

@ -1,12 +1,13 @@
<?php <?php
/**
* @author Marc Pantel <pantel.m@gmail.com>
*/
namespace Doctrine\Tests\Models\DDC3711; namespace Doctrine\Tests\Models\DDC3711;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
/**
* @author Marc Pantel <pantel.m@gmail.com>
*/
class DDC3711EntityB class DDC3711EntityB
{ {
/** /**

View File

@ -1,23 +1,5 @@
<?php <?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Tests\Models\DDC753; namespace Doctrine\Tests\Models\DDC753;
use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityRepository;

View File

@ -1,23 +1,5 @@
<?php <?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Tests\Models\DDC753; namespace Doctrine\Tests\Models\DDC753;
use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityRepository;

View File

@ -1,23 +1,5 @@
<?php <?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Tests\Models\DDC753; namespace Doctrine\Tests\Models\DDC753;
/** /**

View File

@ -1,23 +1,5 @@
<?php <?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Tests\Models\DDC753; namespace Doctrine\Tests\Models\DDC753;
/** /**

View File

@ -1,23 +1,5 @@
<?php <?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Tests\Models\DDC753; namespace Doctrine\Tests\Models\DDC753;
/** /**

View File

@ -1,27 +1,7 @@
<?php <?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Tests\Models\DDC753; namespace Doctrine\Tests\Models\DDC753;
use Doctrine\ORM\EntityRepository;
class DDC753InvalidRepository class DDC753InvalidRepository
{ {

View File

@ -1,23 +1,5 @@
<?php <?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Tests\Models\DDC869; namespace Doctrine\Tests\Models\DDC869;
/** /**

Some files were not shown because too many files have changed in this diff Show More