mirror of
https://github.com/doctrine/orm.git
synced 2026-03-24 15:02:22 +01:00
Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ebae57eb96 | ||
|
|
30a7c2aa67 | ||
|
|
3a9b8fde9b | ||
|
|
4f864bc178 | ||
|
|
d76cbd755f | ||
|
|
4aece04ae7 | ||
|
|
f31dbf8d4e | ||
|
|
416f35dba9 | ||
|
|
c29370e061 | ||
|
|
4e0f6837d0 | ||
|
|
e45d212f02 | ||
|
|
8f62bd39b5 | ||
|
|
5e11afcdf1 | ||
|
|
f833222017 | ||
|
|
c7f39ebbde | ||
|
|
15f08ed006 | ||
|
|
b6fd4b5ef3 | ||
|
|
5e4dae88f3 | ||
|
|
7312ddeda7 | ||
|
|
9a67b6f699 | ||
|
|
f59a0c349b | ||
|
|
4c8831f716 | ||
|
|
01ca442be7 | ||
|
|
01374ca2ab | ||
|
|
94e8b1d43c | ||
|
|
61d0f96c17 | ||
|
|
41729be80a | ||
|
|
6dbaa39016 | ||
|
|
58c95a92d1 | ||
|
|
4958180b02 | ||
|
|
8312ff0cb5 | ||
|
|
fb9b9b276e | ||
|
|
792a9a9149 | ||
|
|
0f655f9fb6 | ||
|
|
2d7acbd07f | ||
|
|
b06679cc14 | ||
|
|
2693a93aed | ||
|
|
8724589c6e | ||
|
|
424305ef38 | ||
|
|
9d01f6a45c | ||
|
|
7ed487b534 | ||
|
|
40f3925589 | ||
|
|
f92c3dba32 | ||
|
|
bcbd4401b8 | ||
|
|
d6aca8e146 | ||
|
|
8f1911a4fe | ||
|
|
7f30cd3102 | ||
|
|
f01fe3e050 | ||
|
|
210c2ee6a4 | ||
|
|
497dfd1a84 | ||
|
|
d9f0e2a27f | ||
|
|
9a40ac6e2a | ||
|
|
1687d9c479 | ||
|
|
1a46ed8901 | ||
|
|
36d0352c01 | ||
|
|
15eacd787b | ||
|
|
5b3f9bdd7b | ||
|
|
e00dba94f4 | ||
|
|
ab0e4007a5 | ||
|
|
32266c54f9 | ||
|
|
dd2120cd41 | ||
|
|
8991df0785 | ||
|
|
ca31923a39 | ||
|
|
68bc00b6c6 | ||
|
|
5b55b8c6cf | ||
|
|
10f381bc95 | ||
|
|
40aa8fe5db | ||
|
|
5801474ba3 | ||
|
|
9dbd960631 | ||
|
|
544df89055 | ||
|
|
378944dd27 | ||
|
|
8b749642cd | ||
|
|
277b53a970 | ||
|
|
2febb4509a | ||
|
|
21d2c88013 | ||
|
|
e7d33eb1a9 | ||
|
|
cab7a4558d | ||
|
|
35cf4810c1 |
@@ -12,21 +12,27 @@
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "2.8",
|
||||
"branchName": "2.8.x",
|
||||
"slug": "2.8",
|
||||
"name": "2.9",
|
||||
"branchName": "2.9.x",
|
||||
"slug": "2.9",
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "2.7",
|
||||
"branchName": "2.7",
|
||||
"slug": "2.7",
|
||||
"name": "2.8",
|
||||
"branchName": "2.8.x",
|
||||
"slug": "2.8",
|
||||
"current": true,
|
||||
"aliases": [
|
||||
"current",
|
||||
"stable"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "2.7",
|
||||
"branchName": "2.7",
|
||||
"slug": "2.7",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.6",
|
||||
"branchName": "2.6",
|
||||
|
||||
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1,5 +1,6 @@
|
||||
/tests export-ignore
|
||||
/tools export-ignore
|
||||
/docs export-ignore
|
||||
/.github export-ignore
|
||||
.gitattributes export-ignore
|
||||
.gitignore export-ignore
|
||||
|
||||
25
.github/workflows/coding-standard.yml
vendored
25
.github/workflows/coding-standard.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Static Analysis
|
||||
name: "Coding Standards"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
@@ -26,21 +26,18 @@ jobs:
|
||||
php-version: "${{ matrix.php-version }}"
|
||||
tools: "cs2pr"
|
||||
|
||||
- name: "Cache dependencies installed with composer"
|
||||
uses: "actions/cache@v1"
|
||||
with:
|
||||
path: "~/.composer/cache"
|
||||
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
|
||||
restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v1"
|
||||
|
||||
- name: "Install dependencies with composer"
|
||||
run: "composer update --no-interaction --no-progress --no-suggest"
|
||||
|
||||
- name: "Install git-phpcs"
|
||||
run: "wget https://github.com/diff-sniffer/git/releases/download/0.3.2/git-phpcs.phar"
|
||||
- name: "Install diff-sniffer"
|
||||
run: "wget https://github.com/diff-sniffer/diff-sniffer/releases/download/0.5.1/diff-sniffer.phar"
|
||||
|
||||
- name: "Fetch head branch"
|
||||
run: "git remote set-branches --add origin $GITHUB_BASE_REF && git fetch origin $GITHUB_BASE_REF"
|
||||
|
||||
- name: "Run git-phpcs"
|
||||
run: "php git-phpcs.phar origin/$GITHUB_BASE_REF...$GITHUB_SHA --report=checkstyle | cs2pr"
|
||||
- name: "Run diff-sniffer"
|
||||
run: "php diff-sniffer.phar origin/$GITHUB_BASE_REF...$GITHUB_SHA --report=checkstyle | cs2pr"
|
||||
|
||||
- name: "Run phpcbf"
|
||||
run: "vendor/bin/phpcbf"
|
||||
|
||||
|
||||
53
.github/workflows/continuous-integration.yml
vendored
53
.github/workflows/continuous-integration.yml
vendored
@@ -20,9 +20,9 @@ jobs:
|
||||
- "7.4"
|
||||
- "8.0"
|
||||
deps:
|
||||
- "normal"
|
||||
- "highest"
|
||||
include:
|
||||
- deps: "low"
|
||||
- deps: "lowest"
|
||||
php-version: "7.3"
|
||||
|
||||
steps:
|
||||
@@ -39,20 +39,10 @@ jobs:
|
||||
coverage: "pcov"
|
||||
ini-values: "zend.assertions=1"
|
||||
|
||||
- name: "Cache dependencies installed with composer"
|
||||
uses: "actions/cache@v2"
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v1"
|
||||
with:
|
||||
path: "~/.composer/cache"
|
||||
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
|
||||
restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
|
||||
|
||||
- name: "Install dependencies with composer"
|
||||
run: "composer update --no-interaction --no-progress --no-suggest"
|
||||
if: "${{ matrix.deps == 'normal' }}"
|
||||
|
||||
- name: "Install lowest possible dependencies with composer"
|
||||
run: "composer update --no-interaction --no-progress --no-suggest --prefer-dist --prefer-lowest"
|
||||
if: "${{ matrix.deps == 'low' }}"
|
||||
dependency-versions: "${{ matrix.deps }}"
|
||||
|
||||
- name: "Run PHPUnit"
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/sqlite.xml --coverage-clover=coverage-no-cache.xml"
|
||||
@@ -109,15 +99,8 @@ jobs:
|
||||
coverage: "pcov"
|
||||
ini-values: "zend.assertions=1"
|
||||
|
||||
- name: "Cache dependencies installed with composer"
|
||||
uses: "actions/cache@v2"
|
||||
with:
|
||||
path: "~/.composer/cache"
|
||||
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
|
||||
restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
|
||||
|
||||
- name: "Install dependencies with composer"
|
||||
run: "composer update --no-interaction --no-progress --no-suggest"
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v1"
|
||||
|
||||
- name: "Run PHPUnit"
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/pdo_pgsql.xml --coverage-clover=coverage.xml"
|
||||
@@ -171,15 +154,8 @@ jobs:
|
||||
ini-values: "zend.assertions=1"
|
||||
extensions: "${{ matrix.extension }}"
|
||||
|
||||
- name: "Cache dependencies installed with composer"
|
||||
uses: "actions/cache@v2"
|
||||
with:
|
||||
path: "~/.composer/cache"
|
||||
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
|
||||
restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
|
||||
|
||||
- name: "Install dependencies with composer"
|
||||
run: "composer update --no-interaction --no-progress --no-suggest"
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v1"
|
||||
|
||||
- name: "Run PHPUnit"
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --coverage-clover=coverage.xml"
|
||||
@@ -233,15 +209,8 @@ jobs:
|
||||
ini-values: "zend.assertions=1"
|
||||
extensions: "${{ matrix.extension }}"
|
||||
|
||||
- name: "Cache dependencies installed with composer"
|
||||
uses: "actions/cache@v2"
|
||||
with:
|
||||
path: "~/.composer/cache"
|
||||
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
|
||||
restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
|
||||
|
||||
- name: "Install dependencies with composer"
|
||||
run: "composer update --no-interaction --no-progress --no-suggest"
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v1"
|
||||
|
||||
- name: "Run PHPUnit"
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --coverage-clover=coverage-no-cache.xml"
|
||||
|
||||
22
.github/workflows/static-analysis.yml
vendored
22
.github/workflows/static-analysis.yml
vendored
@@ -24,15 +24,8 @@ jobs:
|
||||
php-version: "${{ matrix.php-version }}"
|
||||
tools: cs2pr
|
||||
|
||||
- name: "Cache dependencies installed with composer"
|
||||
uses: "actions/cache@v1"
|
||||
with:
|
||||
path: "~/.composer/cache"
|
||||
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
|
||||
restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
|
||||
|
||||
- name: "Install dependencies with composer"
|
||||
run: "composer update --no-progress --no-suggest --no-interaction --prefer-dist"
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v1"
|
||||
|
||||
- name: "Run a static analysis with phpstan/phpstan"
|
||||
run: "php vendor/bin/phpstan analyse --error-format=checkstyle | cs2pr"
|
||||
@@ -56,15 +49,8 @@ jobs:
|
||||
coverage: "none"
|
||||
php-version: "${{ matrix.php-version }}"
|
||||
|
||||
- name: "Cache dependencies installed with composer"
|
||||
uses: "actions/cache@v1"
|
||||
with:
|
||||
path: "~/.composer/cache"
|
||||
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
|
||||
restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
|
||||
|
||||
- name: "Install dependencies with composer"
|
||||
run: "composer update --no-interaction --no-progress --no-suggest"
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v1"
|
||||
|
||||
- name: "Run a static analysis with vimeo/psalm"
|
||||
run: "vendor/bin/psalm --show-info=false --stats --output-format=github --threads=$(nproc)"
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"doctrine/annotations": "^1.11.1",
|
||||
"doctrine/cache": "^1.9.1",
|
||||
"doctrine/collections": "^1.5",
|
||||
"doctrine/common": "^3.0",
|
||||
"doctrine/common": "^3.0.3",
|
||||
"doctrine/dbal": "^2.10.0",
|
||||
"doctrine/event-manager": "^1.1",
|
||||
"doctrine/inflector": "^1.4|^2.0",
|
||||
|
||||
@@ -483,6 +483,7 @@ classes. We'll store them in ``src/Bug.php`` and ``src/User.php``, respectively.
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="bugs")
|
||||
*/
|
||||
class Bug
|
||||
@@ -661,12 +662,12 @@ domain model to match the requirements:
|
||||
|
||||
Lazy load proxies always contain an instance of
|
||||
Doctrine's EntityManager and all its dependencies. Therefore a
|
||||
var\_dump() will possibly dump a very large recursive structure
|
||||
``var_dump()`` will possibly dump a very large recursive structure
|
||||
which is impossible to render and read. You have to use
|
||||
``Doctrine\Common\Util\Debug::dump()`` to restrict the dumping to a
|
||||
human readable level. Additionally you should be aware that dumping
|
||||
the EntityManager to a Browser may take several minutes, and the
|
||||
Debug::dump() method just ignores any occurrences of it in Proxy
|
||||
``Debug::dump()`` method just ignores any occurrences of it in Proxy
|
||||
instances.
|
||||
|
||||
Because we only work with collections for the references we must be
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -20,14 +21,21 @@
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
use Countable;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\DBAL\Cache\QueryCacheProfile;
|
||||
use Doctrine\ORM\Mapping\MappingException as ORMMappingException;
|
||||
use Doctrine\Persistence\Mapping\MappingException;
|
||||
use Doctrine\ORM\Query\Parameter;
|
||||
use Doctrine\DBAL\Driver\Statement;
|
||||
use Doctrine\ORM\Cache\Logging\CacheLogger;
|
||||
use Doctrine\ORM\Cache\QueryCacheKey;
|
||||
use Doctrine\ORM\Cache\TimestampCacheKey;
|
||||
use Doctrine\ORM\Internal\Hydration\IterableResult;
|
||||
use Doctrine\ORM\Mapping\MappingException as ORMMappingException;
|
||||
use Doctrine\ORM\Query\Parameter;
|
||||
use Doctrine\ORM\Query\QueryException;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\Persistence\Mapping\MappingException;
|
||||
use Traversable;
|
||||
|
||||
use function array_map;
|
||||
use function array_shift;
|
||||
use function count;
|
||||
@@ -42,18 +50,13 @@ use function reset;
|
||||
use function serialize;
|
||||
use function sha1;
|
||||
use function trigger_error;
|
||||
|
||||
use const E_USER_DEPRECATED;
|
||||
|
||||
/**
|
||||
* Base contract for ORM queries. Base class for Query and NativeQuery.
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
*/
|
||||
abstract class AbstractQuery
|
||||
{
|
||||
@@ -62,27 +65,27 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Hydrates an object graph. This is the default behavior.
|
||||
*/
|
||||
const HYDRATE_OBJECT = 1;
|
||||
public const HYDRATE_OBJECT = 1;
|
||||
|
||||
/**
|
||||
* Hydrates an array graph.
|
||||
*/
|
||||
const HYDRATE_ARRAY = 2;
|
||||
public const HYDRATE_ARRAY = 2;
|
||||
|
||||
/**
|
||||
* Hydrates a flat, rectangular result set with scalar values.
|
||||
*/
|
||||
const HYDRATE_SCALAR = 3;
|
||||
public const HYDRATE_SCALAR = 3;
|
||||
|
||||
/**
|
||||
* Hydrates a single scalar value.
|
||||
*/
|
||||
const HYDRATE_SINGLE_SCALAR = 4;
|
||||
public const HYDRATE_SINGLE_SCALAR = 4;
|
||||
|
||||
/**
|
||||
* Very simple object hydrator (optimized for performance).
|
||||
*/
|
||||
const HYDRATE_SIMPLEOBJECT = 5;
|
||||
public const HYDRATE_SIMPLEOBJECT = 5;
|
||||
|
||||
/**
|
||||
* The parameter map of this query.
|
||||
@@ -95,7 +98,7 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* The user-specified ResultSetMapping to use.
|
||||
*
|
||||
* @var \Doctrine\ORM\Query\ResultSetMapping
|
||||
* @var ResultSetMapping
|
||||
*/
|
||||
protected $_resultSetMapping;
|
||||
|
||||
@@ -120,33 +123,27 @@ abstract class AbstractQuery
|
||||
*/
|
||||
protected $_hydrationMode = self::HYDRATE_OBJECT;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\DBAL\Cache\QueryCacheProfile
|
||||
*/
|
||||
/** @var QueryCacheProfile */
|
||||
protected $_queryCacheProfile;
|
||||
|
||||
/**
|
||||
* Whether or not expire the result cache.
|
||||
*
|
||||
* @var boolean
|
||||
* @var bool
|
||||
*/
|
||||
protected $_expireResultCache = false;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\DBAL\Cache\QueryCacheProfile
|
||||
*/
|
||||
/** @var QueryCacheProfile */
|
||||
protected $_hydrationCacheProfile;
|
||||
|
||||
/**
|
||||
* Whether to use second level cache, if available.
|
||||
*
|
||||
* @var boolean
|
||||
* @var bool
|
||||
*/
|
||||
protected $cacheable = false;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
/** @var bool */
|
||||
protected $hasCache = false;
|
||||
|
||||
/**
|
||||
@@ -159,31 +156,25 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Second level query cache mode.
|
||||
*
|
||||
* @var integer|null
|
||||
* @var int|null
|
||||
*/
|
||||
protected $cacheMode;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache\Logging\CacheLogger|null
|
||||
*/
|
||||
/** @var CacheLogger|null */
|
||||
protected $cacheLogger;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
/** @var int */
|
||||
protected $lifetime = 0;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of a class derived from <tt>AbstractQuery</tt>.
|
||||
*
|
||||
* @param \Doctrine\ORM\EntityManagerInterface $em
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->_em = $em;
|
||||
$this->parameters = new ArrayCollection();
|
||||
$this->_hints = $em->getConfiguration()->getDefaultQueryHints();
|
||||
$this->hasCache = $this->_em->getConfiguration()->isSecondLevelCacheEnabled();
|
||||
$this->_em = $em;
|
||||
$this->parameters = new ArrayCollection();
|
||||
$this->_hints = $em->getConfiguration()->getDefaultQueryHints();
|
||||
$this->hasCache = $this->_em->getConfiguration()->isSecondLevelCacheEnabled();
|
||||
|
||||
if ($this->hasCache) {
|
||||
$this->cacheLogger = $em->getConfiguration()
|
||||
@@ -195,19 +186,19 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Enable/disable second level query (result) caching for this query.
|
||||
*
|
||||
* @param boolean $cacheable
|
||||
* @param bool $cacheable
|
||||
*
|
||||
* @return static This query instance.
|
||||
*/
|
||||
public function setCacheable($cacheable)
|
||||
{
|
||||
$this->cacheable = (boolean) $cacheable;
|
||||
$this->cacheable = (bool) $cacheable;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean TRUE if the query results are enable for second level cache, FALSE otherwise.
|
||||
* @return bool TRUE if the query results are enable for second level cache, FALSE otherwise.
|
||||
*/
|
||||
public function isCacheable()
|
||||
{
|
||||
@@ -227,17 +218,17 @@ abstract class AbstractQuery
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the name of the second level query cache region in which query results will be stored
|
||||
*
|
||||
* @return string|null The cache region name; NULL indicates the default region.
|
||||
*/
|
||||
* Obtain the name of the second level query cache region in which query results will be stored
|
||||
*
|
||||
* @return string|null The cache region name; NULL indicates the default region.
|
||||
*/
|
||||
public function getCacheRegion()
|
||||
{
|
||||
return $this->cacheRegion;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean TRUE if the query cache and second level cache are enabled, FALSE otherwise.
|
||||
* @return bool TRUE if the query cache and second level cache are enabled, FALSE otherwise.
|
||||
*/
|
||||
protected function isCacheEnabled()
|
||||
{
|
||||
@@ -245,7 +236,7 @@ abstract class AbstractQuery
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
* @return int
|
||||
*/
|
||||
public function getLifetime()
|
||||
{
|
||||
@@ -255,19 +246,19 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Sets the life-time for this query into second level cache.
|
||||
*
|
||||
* @param integer $lifetime
|
||||
* @param int $lifetime
|
||||
*
|
||||
* @return static This query instance.
|
||||
*/
|
||||
public function setLifetime($lifetime)
|
||||
{
|
||||
$this->lifetime = (integer) $lifetime;
|
||||
$this->lifetime = (int) $lifetime;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
* @return int
|
||||
*/
|
||||
public function getCacheMode()
|
||||
{
|
||||
@@ -275,13 +266,13 @@ abstract class AbstractQuery
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $cacheMode
|
||||
* @param int $cacheMode
|
||||
*
|
||||
* @return static This query instance.
|
||||
*/
|
||||
public function setCacheMode($cacheMode)
|
||||
{
|
||||
$this->cacheMode = (integer) $cacheMode;
|
||||
$this->cacheMode = (int) $cacheMode;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -298,7 +289,7 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Retrieves the associated EntityManager of this Query instance.
|
||||
*
|
||||
* @return \Doctrine\ORM\EntityManager
|
||||
* @return EntityManager
|
||||
*/
|
||||
public function getEntityManager()
|
||||
{
|
||||
@@ -341,7 +332,7 @@ abstract class AbstractQuery
|
||||
$key = Query\Parameter::normalizeName($key);
|
||||
|
||||
$filteredParameters = $this->parameters->filter(
|
||||
function (Query\Parameter $parameter) use ($key) : bool {
|
||||
static function (Query\Parameter $parameter) use ($key): bool {
|
||||
$parameterName = $parameter->getName();
|
||||
|
||||
return $key === $parameterName;
|
||||
@@ -412,7 +403,7 @@ abstract class AbstractQuery
|
||||
*
|
||||
* @return mixed[]|string|int|float|bool
|
||||
*
|
||||
* @throws \Doctrine\ORM\ORMInvalidArgumentException
|
||||
* @throws ORMInvalidArgumentException
|
||||
*
|
||||
* @psalm-return array|scalar
|
||||
*/
|
||||
@@ -446,15 +437,12 @@ abstract class AbstractQuery
|
||||
if ($value === null) {
|
||||
throw ORMInvalidArgumentException::invalidIdentifierBindingEntity();
|
||||
}
|
||||
} catch (ORMMappingException $e) {
|
||||
// Silence any mapping exceptions. These can occur if the object in
|
||||
// question is not a mapped entity, in which case we just don't do
|
||||
// any preparation on the value.
|
||||
|
||||
$value = $this->potentiallyProcessIterable($value);
|
||||
} catch (MappingException $e) {
|
||||
// as previous, but depending on MappingDriver this exception from Persistence
|
||||
// is thrown and not the ORM one.
|
||||
} catch (MappingException | ORMMappingException $e) {
|
||||
/* Silence any mapping exceptions. These can occur if the object in
|
||||
question is not a mapped entity, in which case we just don't do
|
||||
any preparation on the value.
|
||||
Depending on MappingDriver, either MappingException or
|
||||
ORMMappingException is thrown. */
|
||||
|
||||
$value = $this->potentiallyProcessIterable($value);
|
||||
}
|
||||
@@ -499,8 +487,6 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Sets the ResultSetMapping that should be used for hydration.
|
||||
*
|
||||
* @param \Doctrine\ORM\Query\ResultSetMapping $rsm
|
||||
*
|
||||
* @return static This query instance.
|
||||
*/
|
||||
public function setResultSetMapping(Query\ResultSetMapping $rsm)
|
||||
@@ -514,7 +500,7 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Gets the ResultSetMapping used for hydration.
|
||||
*
|
||||
* @return \Doctrine\ORM\Query\ResultSetMapping
|
||||
* @return ResultSetMapping
|
||||
*/
|
||||
protected function getResultSetMapping()
|
||||
{
|
||||
@@ -524,17 +510,15 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Allows to translate entity namespaces to full qualified names.
|
||||
*
|
||||
* @param Query\ResultSetMapping $rsm
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function translateNamespaces(Query\ResultSetMapping $rsm)
|
||||
{
|
||||
$translate = function ($alias) : string {
|
||||
$translate = function ($alias): string {
|
||||
return $this->_em->getClassMetadata($alias)->getName();
|
||||
};
|
||||
|
||||
$rsm->aliasMap = array_map($translate, $rsm->aliasMap);
|
||||
$rsm->aliasMap = array_map($translate, $rsm->aliasMap);
|
||||
$rsm->declaringClasses = array_map($translate, $rsm->declaringClasses);
|
||||
}
|
||||
|
||||
@@ -550,21 +534,19 @@ abstract class AbstractQuery
|
||||
* some form of caching with UnitOfWork registration you should use
|
||||
* {@see AbstractQuery::setResultCacheProfile()}.
|
||||
*
|
||||
* @return static This query instance.
|
||||
*
|
||||
* @example
|
||||
* $lifetime = 100;
|
||||
* $resultKey = "abc";
|
||||
* $query->setHydrationCacheProfile(new QueryCacheProfile());
|
||||
* $query->setHydrationCacheProfile(new QueryCacheProfile($lifetime, $resultKey));
|
||||
*
|
||||
* @param \Doctrine\DBAL\Cache\QueryCacheProfile $profile
|
||||
*
|
||||
* @return static This query instance.
|
||||
*/
|
||||
public function setHydrationCacheProfile(QueryCacheProfile $profile = null)
|
||||
public function setHydrationCacheProfile(?QueryCacheProfile $profile = null)
|
||||
{
|
||||
if ($profile !== null && ! $profile->getResultCacheDriver()) {
|
||||
$resultCacheDriver = $this->_em->getConfiguration()->getHydrationCacheImpl();
|
||||
$profile = $profile->setResultCacheDriver($resultCacheDriver);
|
||||
$profile = $profile->setResultCacheDriver($resultCacheDriver);
|
||||
}
|
||||
|
||||
$this->_hydrationCacheProfile = $profile;
|
||||
@@ -573,7 +555,7 @@ abstract class AbstractQuery
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Doctrine\DBAL\Cache\QueryCacheProfile
|
||||
* @return QueryCacheProfile
|
||||
*/
|
||||
public function getHydrationCacheProfile()
|
||||
{
|
||||
@@ -586,15 +568,13 @@ abstract class AbstractQuery
|
||||
* If no result cache driver is set in the QueryCacheProfile, the default
|
||||
* result cache driver is used from the configuration.
|
||||
*
|
||||
* @param \Doctrine\DBAL\Cache\QueryCacheProfile $profile
|
||||
*
|
||||
* @return static This query instance.
|
||||
*/
|
||||
public function setResultCacheProfile(QueryCacheProfile $profile = null)
|
||||
public function setResultCacheProfile(?QueryCacheProfile $profile = null)
|
||||
{
|
||||
if ($profile !== null && ! $profile->getResultCacheDriver()) {
|
||||
$resultCacheDriver = $this->_em->getConfiguration()->getResultCacheImpl();
|
||||
$profile = $profile->setResultCacheDriver($resultCacheDriver);
|
||||
$profile = $profile->setResultCacheDriver($resultCacheDriver);
|
||||
}
|
||||
|
||||
$this->_queryCacheProfile = $profile;
|
||||
@@ -668,7 +648,7 @@ abstract class AbstractQuery
|
||||
*
|
||||
* @return static This query instance.
|
||||
*/
|
||||
public function enableResultCache(?int $lifetime = null, ?string $resultCacheId = null) : self
|
||||
public function enableResultCache(?int $lifetime = null, ?string $resultCacheId = null): self
|
||||
{
|
||||
$this->setResultCacheLifetime($lifetime);
|
||||
$this->setResultCacheId($resultCacheId);
|
||||
@@ -681,7 +661,7 @@ abstract class AbstractQuery
|
||||
*
|
||||
* @return static This query instance.
|
||||
*/
|
||||
public function disableResultCache() : self
|
||||
public function disableResultCache(): self
|
||||
{
|
||||
$this->_queryCacheProfile = null;
|
||||
|
||||
@@ -697,7 +677,7 @@ abstract class AbstractQuery
|
||||
*/
|
||||
public function setResultCacheLifetime($lifetime)
|
||||
{
|
||||
$lifetime = ($lifetime !== null) ? (int) $lifetime : 0;
|
||||
$lifetime = $lifetime !== null ? (int) $lifetime : 0;
|
||||
|
||||
$this->_queryCacheProfile = $this->_queryCacheProfile
|
||||
? $this->_queryCacheProfile->setLifetime($lifetime)
|
||||
@@ -711,7 +691,7 @@ abstract class AbstractQuery
|
||||
*
|
||||
* @deprecated
|
||||
*
|
||||
* @return integer
|
||||
* @return int
|
||||
*/
|
||||
public function getResultCacheLifetime()
|
||||
{
|
||||
@@ -721,7 +701,7 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Defines if the result cache is active or not.
|
||||
*
|
||||
* @param boolean $expire Whether or not to force resultset cache expiration.
|
||||
* @param bool $expire Whether or not to force resultset cache expiration.
|
||||
*
|
||||
* @return static This query instance.
|
||||
*/
|
||||
@@ -735,7 +715,7 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Retrieves if the resultset cache is active or not.
|
||||
*
|
||||
* @return boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function getExpireResultCache()
|
||||
{
|
||||
@@ -816,7 +796,7 @@ abstract class AbstractQuery
|
||||
*
|
||||
* Alias for execute(null, HYDRATE_ARRAY).
|
||||
*
|
||||
* @return array
|
||||
* @return array<int,mixed>
|
||||
*/
|
||||
public function getArrayResult()
|
||||
{
|
||||
@@ -828,7 +808,7 @@ abstract class AbstractQuery
|
||||
*
|
||||
* Alias for execute(null, HYDRATE_SCALAR).
|
||||
*
|
||||
* @return array
|
||||
* @return array<int,mixed>
|
||||
*/
|
||||
public function getScalarResult()
|
||||
{
|
||||
@@ -852,17 +832,16 @@ abstract class AbstractQuery
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
if ($this->_hydrationMode !== self::HYDRATE_SINGLE_SCALAR && ! $result) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( ! is_array($result)) {
|
||||
if (! is_array($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if (count($result) > 1) {
|
||||
throw new NonUniqueResultException;
|
||||
throw new NonUniqueResultException();
|
||||
}
|
||||
|
||||
return array_shift($result);
|
||||
@@ -888,15 +867,15 @@ abstract class AbstractQuery
|
||||
$result = $this->execute(null, $hydrationMode);
|
||||
|
||||
if ($this->_hydrationMode !== self::HYDRATE_SINGLE_SCALAR && ! $result) {
|
||||
throw new NoResultException;
|
||||
throw new NoResultException();
|
||||
}
|
||||
|
||||
if ( ! is_array($result)) {
|
||||
if (! is_array($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if (count($result) > 1) {
|
||||
throw new NonUniqueResultException;
|
||||
throw new NonUniqueResultException();
|
||||
}
|
||||
|
||||
return array_shift($result);
|
||||
@@ -941,7 +920,7 @@ abstract class AbstractQuery
|
||||
*/
|
||||
public function getHint($name)
|
||||
{
|
||||
return isset($this->_hints[$name]) ? $this->_hints[$name] : false;
|
||||
return $this->_hints[$name] ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -959,7 +938,7 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Return the key value map of query hints that are currently set.
|
||||
*
|
||||
* @return array
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public function getHints()
|
||||
{
|
||||
@@ -972,10 +951,10 @@ abstract class AbstractQuery
|
||||
*
|
||||
* @deprecated
|
||||
*
|
||||
* @param ArrayCollection|array|null $parameters The query parameters.
|
||||
* @param string|int|null $hydrationMode The hydration mode to use.
|
||||
* @param ArrayCollection|mixed[]|null $parameters The query parameters.
|
||||
* @param string|int|null $hydrationMode The hydration mode to use.
|
||||
*
|
||||
* @return \Doctrine\ORM\Internal\Hydration\IterableResult
|
||||
* @return IterableResult
|
||||
*/
|
||||
public function iterate($parameters = null, $hydrationMode = null)
|
||||
{
|
||||
@@ -988,7 +967,7 @@ abstract class AbstractQuery
|
||||
$this->setHydrationMode($hydrationMode);
|
||||
}
|
||||
|
||||
if ( ! empty($parameters)) {
|
||||
if (! empty($parameters)) {
|
||||
$this->setParameters($parameters);
|
||||
}
|
||||
|
||||
@@ -1007,19 +986,25 @@ abstract class AbstractQuery
|
||||
*
|
||||
* @return iterable<mixed>
|
||||
*/
|
||||
public function toIterable(iterable $parameters = [], $hydrationMode = null) : iterable
|
||||
public function toIterable(iterable $parameters = [], $hydrationMode = null): iterable
|
||||
{
|
||||
if ($hydrationMode !== null) {
|
||||
$this->setHydrationMode($hydrationMode);
|
||||
}
|
||||
|
||||
if (($this->isCountable($parameters) && count($parameters) !== 0)
|
||||
if (
|
||||
($this->isCountable($parameters) && count($parameters) !== 0)
|
||||
|| ($parameters instanceof Traversable && iterator_count($parameters) !== 0)
|
||||
) {
|
||||
$this->setParameters($parameters);
|
||||
}
|
||||
|
||||
$rsm = $this->getResultSetMapping();
|
||||
$rsm = $this->getResultSetMapping();
|
||||
|
||||
if ($rsm->isMixed && count($rsm->scalarMappings) > 0) {
|
||||
throw QueryException::iterateWithMixedResultNotAllowed();
|
||||
}
|
||||
|
||||
$stmt = $this->_doExecute();
|
||||
|
||||
return $this->_em->newHydrator($this->_hydrationMode)->toIterable($stmt, $rsm, $this->_hints);
|
||||
@@ -1028,8 +1013,8 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Executes the query.
|
||||
*
|
||||
* @param ArrayCollection|array|null $parameters Query parameters.
|
||||
* @param string|int|null $hydrationMode Processing mode to be used during the hydration process.
|
||||
* @param ArrayCollection|mixed[]|null $parameters Query parameters.
|
||||
* @param string|int|null $hydrationMode Processing mode to be used during the hydration process.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
@@ -1045,8 +1030,8 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Execute query ignoring second level cache.
|
||||
*
|
||||
* @param ArrayCollection|array|null $parameters
|
||||
* @param string|int|null $hydrationMode
|
||||
* @param ArrayCollection|mixed[]|null $parameters
|
||||
* @param string|int|null $hydrationMode
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
@@ -1056,11 +1041,11 @@ abstract class AbstractQuery
|
||||
$this->setHydrationMode($hydrationMode);
|
||||
}
|
||||
|
||||
if ( ! empty($parameters)) {
|
||||
if (! empty($parameters)) {
|
||||
$this->setParameters($parameters);
|
||||
}
|
||||
|
||||
$setCacheEntry = static function () : void {
|
||||
$setCacheEntry = static function (): void {
|
||||
};
|
||||
|
||||
if ($this->_hydrationCacheProfile !== null) {
|
||||
@@ -1074,11 +1059,11 @@ abstract class AbstractQuery
|
||||
return $result[$realCacheKey];
|
||||
}
|
||||
|
||||
if ( ! $result) {
|
||||
if (! $result) {
|
||||
$result = [];
|
||||
}
|
||||
|
||||
$setCacheEntry = static function ($data) use ($cache, $result, $cacheKey, $realCacheKey, $queryCacheProfile) : void {
|
||||
$setCacheEntry = static function ($data) use ($cache, $result, $cacheKey, $realCacheKey, $queryCacheProfile): void {
|
||||
$result[$realCacheKey] = $data;
|
||||
|
||||
$cache->save($cacheKey, $result, $queryCacheProfile->getLifetime());
|
||||
@@ -1104,8 +1089,8 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Load from second level cache or executes the query and put into cache.
|
||||
*
|
||||
* @param ArrayCollection|array|null $parameters
|
||||
* @param string|int|null $hydrationMode
|
||||
* @param ArrayCollection|mixed[]|null $parameters
|
||||
* @param string|int|null $hydrationMode
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
@@ -1120,7 +1105,7 @@ abstract class AbstractQuery
|
||||
$this->getTimestampKey()
|
||||
);
|
||||
|
||||
$result = $queryCache->get($queryKey, $rsm, $this->_hints);
|
||||
$result = $queryCache->get($queryKey, $rsm, $this->_hints);
|
||||
|
||||
if ($result !== null) {
|
||||
if ($this->cacheLogger) {
|
||||
@@ -1145,7 +1130,7 @@ abstract class AbstractQuery
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Doctrine\ORM\Cache\TimestampCacheKey|null
|
||||
* @return TimestampCacheKey|null
|
||||
*/
|
||||
private function getTimestampKey()
|
||||
{
|
||||
@@ -1218,7 +1203,7 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Executes the query and returns a the resulting Statement object.
|
||||
*
|
||||
* @return \Doctrine\DBAL\Driver\Statement The executed database statement that holds the results.
|
||||
* @return Statement The executed database statement that holds the results.
|
||||
*/
|
||||
abstract protected function _doExecute();
|
||||
|
||||
@@ -1244,10 +1229,12 @@ abstract class AbstractQuery
|
||||
{
|
||||
$query = $this->getSQL();
|
||||
$hints = $this->getHints();
|
||||
$params = array_map(function(Parameter $parameter) {
|
||||
$params = array_map(function (Parameter $parameter) {
|
||||
$value = $parameter->getValue();
|
||||
|
||||
// Small optimization
|
||||
// Does not invoke processParameterValue for scalar values
|
||||
if (is_scalar($value = $parameter->getValue())) {
|
||||
// Does not invoke processParameterValue for scalar value
|
||||
if (is_scalar($value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
@@ -1260,7 +1247,7 @@ abstract class AbstractQuery
|
||||
}
|
||||
|
||||
/** @param iterable<mixed> $subject */
|
||||
private function isCountable(iterable $subject) : bool
|
||||
private function isCountable(iterable $subject): bool
|
||||
{
|
||||
return $subject instanceof Countable || is_array($subject);
|
||||
}
|
||||
|
||||
@@ -20,44 +20,44 @@
|
||||
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
use Doctrine\ORM\Cache\QueryCache;
|
||||
use Doctrine\ORM\Cache\Region;
|
||||
|
||||
/**
|
||||
* Provides an API for querying/managing the second level cache regions.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
interface Cache
|
||||
{
|
||||
const DEFAULT_QUERY_REGION_NAME = 'query_cache_region';
|
||||
public const DEFAULT_QUERY_REGION_NAME = 'query_cache_region';
|
||||
|
||||
const DEFAULT_TIMESTAMP_REGION_NAME = 'timestamp_cache_region';
|
||||
public const DEFAULT_TIMESTAMP_REGION_NAME = 'timestamp_cache_region';
|
||||
|
||||
/**
|
||||
* May read items from the cache, but will not add items.
|
||||
*/
|
||||
const MODE_GET = 1;
|
||||
public const MODE_GET = 1;
|
||||
|
||||
/**
|
||||
* Will never read items from the cache,
|
||||
* but will add items to the cache as it reads them from the database.
|
||||
*/
|
||||
const MODE_PUT = 2;
|
||||
public const MODE_PUT = 2;
|
||||
|
||||
/**
|
||||
* May read items from the cache, and add items to the cache.
|
||||
*/
|
||||
const MODE_NORMAL = 3;
|
||||
public const MODE_NORMAL = 3;
|
||||
|
||||
/**
|
||||
* The query will never read items from the cache,
|
||||
* but will refresh items to the cache as it reads them from the database.
|
||||
*/
|
||||
const MODE_REFRESH = 4;
|
||||
public const MODE_REFRESH = 4;
|
||||
|
||||
/**
|
||||
* @param string $className The entity class.
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache\Region|null
|
||||
* @return Region|null
|
||||
*/
|
||||
public function getEntityCacheRegion($className);
|
||||
|
||||
@@ -65,7 +65,7 @@ interface Cache
|
||||
* @param string $className The entity class.
|
||||
* @param string $association The field name that represents the association.
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache\Region|null
|
||||
* @return Region|null
|
||||
*/
|
||||
public function getCollectionCacheRegion($className, $association);
|
||||
|
||||
@@ -75,7 +75,7 @@ interface Cache
|
||||
* @param string $className The entity class.
|
||||
* @param mixed $identifier The entity identifier
|
||||
*
|
||||
* @return boolean true if the underlying cache contains corresponding data; false otherwise.
|
||||
* @return bool true if the underlying cache contains corresponding data; false otherwise.
|
||||
*/
|
||||
public function containsEntity($className, $identifier);
|
||||
|
||||
@@ -112,7 +112,7 @@ interface Cache
|
||||
* @param string $association The field name that represents the association.
|
||||
* @param mixed $ownerIdentifier The identifier of the owning entity.
|
||||
*
|
||||
* @return boolean true if the underlying cache contains corresponding data; false otherwise.
|
||||
* @return bool true if the underlying cache contains corresponding data; false otherwise.
|
||||
*/
|
||||
public function containsCollection($className, $association, $ownerIdentifier);
|
||||
|
||||
@@ -149,7 +149,7 @@ interface Cache
|
||||
*
|
||||
* @param string $regionName The cache name given to the query.
|
||||
*
|
||||
* @return boolean true if the underlying cache contains corresponding data; false otherwise.
|
||||
* @return bool true if the underlying cache contains corresponding data; false otherwise.
|
||||
*/
|
||||
public function containsQuery($regionName);
|
||||
|
||||
@@ -172,7 +172,7 @@ interface Cache
|
||||
*
|
||||
* @param string|null $regionName Query cache region name, or default query cache if the region name is NULL.
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache\QueryCache The Query Cache associated with the region name.
|
||||
* @return QueryCache The Query Cache associated with the region name.
|
||||
*/
|
||||
public function getQueryCache($regionName = null);
|
||||
}
|
||||
|
||||
@@ -22,16 +22,13 @@ namespace Doctrine\ORM\Cache;
|
||||
|
||||
/**
|
||||
* Association cache entry
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class AssociationCacheEntry implements CacheEntry
|
||||
{
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
*
|
||||
* @var array The entity identifier
|
||||
* @var array<string, mixed> The entity identifier
|
||||
*/
|
||||
public $identifier;
|
||||
|
||||
@@ -43,13 +40,13 @@ class AssociationCacheEntry implements CacheEntry
|
||||
public $class;
|
||||
|
||||
/**
|
||||
* @param string $class The entity class.
|
||||
* @param array $identifier The entity identifier.
|
||||
* @param string $class The entity class.
|
||||
* @param array<string, mixed> $identifier The entity identifier.
|
||||
*/
|
||||
public function __construct($class, array $identifier)
|
||||
{
|
||||
$this->class = $class;
|
||||
$this->identifier = $identifier;
|
||||
$this->class = $class;
|
||||
$this->identifier = $identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,7 +54,7 @@ class AssociationCacheEntry implements CacheEntry
|
||||
*
|
||||
* This method allow Doctrine\Common\Cache\PhpFileCache compatibility
|
||||
*
|
||||
* @param array $values array containing property values
|
||||
* @param array<string, mixed> $values array containing property values
|
||||
*
|
||||
* @return AssociationCacheEntry
|
||||
*/
|
||||
|
||||
@@ -24,34 +24,23 @@ use Doctrine\ORM\Cache\Logging\CacheLogger;
|
||||
|
||||
/**
|
||||
* Configuration container for second-level cache.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class CacheConfiguration
|
||||
{
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache\CacheFactory|null
|
||||
*/
|
||||
/** @var CacheFactory|null */
|
||||
private $cacheFactory;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache\RegionsConfiguration|null
|
||||
*/
|
||||
/** @var RegionsConfiguration|null */
|
||||
private $regionsConfig;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache\Logging\CacheLogger|null
|
||||
*/
|
||||
/** @var CacheLogger|null */
|
||||
private $cacheLogger;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache\QueryCacheValidator|null
|
||||
*/
|
||||
/** @var QueryCacheValidator|null */
|
||||
private $queryValidator;
|
||||
|
||||
/**
|
||||
* @return \Doctrine\ORM\Cache\CacheFactory|null
|
||||
* @return CacheFactory|null
|
||||
*/
|
||||
public function getCacheFactory()
|
||||
{
|
||||
@@ -59,8 +48,6 @@ class CacheConfiguration
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\Cache\CacheFactory $factory
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setCacheFactory(CacheFactory $factory)
|
||||
@@ -69,23 +56,20 @@ class CacheConfiguration
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Doctrine\ORM\Cache\Logging\CacheLogger|null
|
||||
* @return CacheLogger|null
|
||||
*/
|
||||
public function getCacheLogger()
|
||||
{
|
||||
return $this->cacheLogger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\Cache\Logging\CacheLogger $logger
|
||||
*/
|
||||
public function setCacheLogger(CacheLogger $logger)
|
||||
{
|
||||
$this->cacheLogger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Doctrine\ORM\Cache\RegionsConfiguration
|
||||
* @return RegionsConfiguration
|
||||
*/
|
||||
public function getRegionsConfiguration()
|
||||
{
|
||||
@@ -96,16 +80,13 @@ class CacheConfiguration
|
||||
return $this->regionsConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\Cache\RegionsConfiguration $regionsConfig
|
||||
*/
|
||||
public function setRegionsConfiguration(RegionsConfiguration $regionsConfig)
|
||||
{
|
||||
$this->regionsConfig = $regionsConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Doctrine\ORM\Cache\QueryCacheValidator
|
||||
* @return QueryCacheValidator
|
||||
*/
|
||||
public function getQueryValidator()
|
||||
{
|
||||
@@ -118,9 +99,6 @@ class CacheConfiguration
|
||||
return $this->queryValidator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\Cache\QueryCacheValidator $validator
|
||||
*/
|
||||
public function setQueryValidator(QueryCacheValidator $validator)
|
||||
{
|
||||
$this->queryValidator = $validator;
|
||||
|
||||
@@ -26,11 +26,7 @@ namespace Doctrine\ORM\Cache;
|
||||
* <b>IMPORTANT NOTE:</b>
|
||||
*
|
||||
* Fields of classes that implement CacheEntry are public for performance reason.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
interface CacheEntry
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -21,11 +22,10 @@ namespace Doctrine\ORM\Cache;
|
||||
|
||||
use Doctrine\ORM\ORMException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Exception for cache.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class CacheException extends ORMException
|
||||
{
|
||||
@@ -33,7 +33,7 @@ class CacheException extends ORMException
|
||||
* @param string $sourceEntity
|
||||
* @param string $fieldName
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache\CacheException
|
||||
* @return CacheException
|
||||
*/
|
||||
public static function updateReadOnlyCollection($sourceEntity, $fieldName)
|
||||
{
|
||||
@@ -43,7 +43,7 @@ class CacheException extends ORMException
|
||||
/**
|
||||
* @param string $entityName
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache\CacheException
|
||||
* @return CacheException
|
||||
*/
|
||||
public static function updateReadOnlyEntity($entityName)
|
||||
{
|
||||
@@ -53,7 +53,7 @@ class CacheException extends ORMException
|
||||
/**
|
||||
* @param string $entityName
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache\CacheException
|
||||
* @return CacheException
|
||||
*/
|
||||
public static function nonCacheableEntity($entityName)
|
||||
{
|
||||
|
||||
@@ -20,93 +20,91 @@
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Cache;
|
||||
use Doctrine\ORM\Cache\Persister\Collection\CachedCollectionPersister;
|
||||
use Doctrine\ORM\Cache\Persister\Entity\CachedEntityPersister;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
|
||||
use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
|
||||
/**
|
||||
* Contract for building second level cache regions components.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
interface CacheFactory
|
||||
{
|
||||
/**
|
||||
* Build an entity persister for the given entity metadata.
|
||||
*
|
||||
* @param \Doctrine\ORM\EntityManagerInterface $em The entity manager.
|
||||
* @param \Doctrine\ORM\Persisters\Entity\EntityPersister $persister The entity persister that will be cached.
|
||||
* @param \Doctrine\ORM\Mapping\ClassMetadata $metadata The entity metadata.
|
||||
* @param EntityManagerInterface $em The entity manager.
|
||||
* @param EntityPersister $persister The entity persister that will be cached.
|
||||
* @param ClassMetadata $metadata The entity metadata.
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache\Persister\Entity\CachedEntityPersister
|
||||
* @return CachedEntityPersister
|
||||
*/
|
||||
public function buildCachedEntityPersister(EntityManagerInterface $em, EntityPersister $persister, ClassMetadata $metadata);
|
||||
|
||||
/**
|
||||
* Build a collection persister for the given relation mapping.
|
||||
*
|
||||
* @param \Doctrine\ORM\EntityManagerInterface $em The entity manager.
|
||||
* @param \Doctrine\ORM\Persisters\Collection\CollectionPersister $persister The collection persister that will be cached.
|
||||
* @param array $mapping The association mapping.
|
||||
* @param EntityManagerInterface $em The entity manager.
|
||||
* @param CollectionPersister $persister The collection persister that will be cached.
|
||||
* @param mixed[] $mapping The association mapping.
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache\Persister\Collection\CachedCollectionPersister
|
||||
* @return CachedCollectionPersister
|
||||
*/
|
||||
public function buildCachedCollectionPersister(EntityManagerInterface $em, CollectionPersister $persister, array $mapping);
|
||||
|
||||
/**
|
||||
* Build a query cache based on the given region name
|
||||
*
|
||||
* @param \Doctrine\ORM\EntityManagerInterface $em The Entity manager.
|
||||
* @param string $regionName The region name.
|
||||
* @param EntityManagerInterface $em The Entity manager.
|
||||
* @param string $regionName The region name.
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache\QueryCache The built query cache.
|
||||
* @return QueryCache The built query cache.
|
||||
*/
|
||||
public function buildQueryCache(EntityManagerInterface $em, $regionName = null);
|
||||
|
||||
/**
|
||||
* Build an entity hydrator
|
||||
*
|
||||
* @param \Doctrine\ORM\EntityManagerInterface $em The Entity manager.
|
||||
* @param \Doctrine\ORM\Mapping\ClassMetadata $metadata The entity metadata.
|
||||
* @param EntityManagerInterface $em The Entity manager.
|
||||
* @param ClassMetadata $metadata The entity metadata.
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache\EntityHydrator The built entity hydrator.
|
||||
* @return EntityHydrator The built entity hydrator.
|
||||
*/
|
||||
public function buildEntityHydrator(EntityManagerInterface $em, ClassMetadata $metadata);
|
||||
|
||||
/**
|
||||
* Build a collection hydrator
|
||||
*
|
||||
* @param \Doctrine\ORM\EntityManagerInterface $em The Entity manager.
|
||||
* @param array $mapping The association mapping.
|
||||
* @param EntityManagerInterface $em The Entity manager.
|
||||
* @param mixed[] $mapping The association mapping.
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache\CollectionHydrator The built collection hydrator.
|
||||
* @return CollectionHydrator The built collection hydrator.
|
||||
*/
|
||||
public function buildCollectionHydrator(EntityManagerInterface $em, array $mapping);
|
||||
|
||||
/**
|
||||
* Build a cache region
|
||||
*
|
||||
* @param array $cache The cache configuration.
|
||||
* @param array<string,mixed> $cache The cache configuration.
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache\Region The cache region.
|
||||
* @return Region The cache region.
|
||||
*/
|
||||
public function getRegion(array $cache);
|
||||
|
||||
/**
|
||||
* Build timestamp cache region
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache\TimestampRegion The timestamp region.
|
||||
* @return TimestampRegion The timestamp region.
|
||||
*/
|
||||
public function getTimestampRegion();
|
||||
|
||||
/**
|
||||
* Build \Doctrine\ORM\Cache
|
||||
*
|
||||
* @param EntityManagerInterface $entityManager
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache
|
||||
* @return Cache
|
||||
*/
|
||||
public function createCache(EntityManagerInterface $entityManager);
|
||||
}
|
||||
|
||||
@@ -23,9 +23,6 @@ namespace Doctrine\ORM\Cache;
|
||||
/**
|
||||
* Defines entity / collection / query key to be stored in the cache region.
|
||||
* Allows multiple roles to be stored in the same cache region.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
abstract class CacheKey
|
||||
{
|
||||
|
||||
@@ -22,9 +22,6 @@ namespace Doctrine\ORM\Cache;
|
||||
|
||||
/**
|
||||
* Collection cache entry
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class CollectionCacheEntry implements CacheEntry
|
||||
{
|
||||
@@ -48,7 +45,7 @@ class CollectionCacheEntry implements CacheEntry
|
||||
*
|
||||
* This method allows for Doctrine\Common\Cache\PhpFileCache compatibility
|
||||
*
|
||||
* @param array $values array containing property values
|
||||
* @param array<string, mixed> $values array containing property values
|
||||
*
|
||||
* @return CollectionCacheEntry
|
||||
*/
|
||||
|
||||
@@ -20,18 +20,20 @@
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
use function implode;
|
||||
use function ksort;
|
||||
use function str_replace;
|
||||
use function strtolower;
|
||||
|
||||
/**
|
||||
* Defines entity collection roles to be stored in the cache region.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class CollectionCacheKey extends CacheKey
|
||||
{
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
*
|
||||
* @var array The owner entity identifier
|
||||
* @var array<string, mixed> The owner entity identifier
|
||||
*/
|
||||
public $ownerIdentifier;
|
||||
|
||||
@@ -50,17 +52,17 @@ class CollectionCacheKey extends CacheKey
|
||||
public $association;
|
||||
|
||||
/**
|
||||
* @param string $entityClass The entity class.
|
||||
* @param string $association The field name that represents the association.
|
||||
* @param array $ownerIdentifier The identifier of the owning entity.
|
||||
* @param string $entityClass The entity class.
|
||||
* @param string $association The field name that represents the association.
|
||||
* @param array<string, mixed> $ownerIdentifier The identifier of the owning entity.
|
||||
*/
|
||||
public function __construct($entityClass, $association, array $ownerIdentifier)
|
||||
{
|
||||
ksort($ownerIdentifier);
|
||||
|
||||
$this->ownerIdentifier = $ownerIdentifier;
|
||||
$this->entityClass = (string) $entityClass;
|
||||
$this->association = (string) $association;
|
||||
$this->hash = str_replace('\\', '.', strtolower($entityClass)) . '_' . implode(' ', $ownerIdentifier) . '__' . $association;
|
||||
$this->ownerIdentifier = $ownerIdentifier;
|
||||
$this->entityClass = (string) $entityClass;
|
||||
$this->association = (string) $association;
|
||||
$this->hash = str_replace('\\', '.', strtolower($entityClass)) . '_' . implode(' ', $ownerIdentifier) . '__' . $association;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,33 +20,31 @@
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
|
||||
/**
|
||||
* Hydrator cache entry for collections
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
interface CollectionHydrator
|
||||
{
|
||||
/**
|
||||
* @param \Doctrine\ORM\Mapping\ClassMetadata $metadata The entity metadata.
|
||||
* @param \Doctrine\ORM\Cache\CollectionCacheKey $key The cached collection key.
|
||||
* @param array|\Doctrine\Common\Collections\Collection $collection The collection.
|
||||
* @param ClassMetadata $metadata The entity metadata.
|
||||
* @param CollectionCacheKey $key The cached collection key.
|
||||
* @param mixed[]|Collection $collection The collection.
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache\CollectionCacheEntry
|
||||
* @return CollectionCacheEntry
|
||||
*/
|
||||
public function buildCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, $collection);
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\Mapping\ClassMetadata $metadata The owning entity metadata.
|
||||
* @param \Doctrine\ORM\Cache\CollectionCacheKey $key The cached collection key.
|
||||
* @param \Doctrine\ORM\Cache\CollectionCacheEntry $entry The cached collection entry.
|
||||
* @param \Doctrine\ORM\PersistentCollection $collection The collection to load the cache into.
|
||||
* @param ClassMetadata $metadata The owning entity metadata.
|
||||
* @param CollectionCacheKey $key The cached collection key.
|
||||
* @param CollectionCacheEntry $entry The cached collection entry.
|
||||
* @param PersistentCollection $collection The collection to load the cache into.
|
||||
*
|
||||
* @return array
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function loadCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, CollectionCacheEntry $entry, PersistentCollection $collection);
|
||||
}
|
||||
|
||||
@@ -26,32 +26,29 @@ namespace Doctrine\ORM\Cache;
|
||||
*
|
||||
* When a entry is locked another process should not be able to read or write the entry.
|
||||
* All evict operation should not consider locks, even though an entry is locked evict should be able to delete the entry and its lock.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
interface ConcurrentRegion extends Region
|
||||
{
|
||||
/**
|
||||
* Attempts to read lock the mapping for the given key.
|
||||
*
|
||||
* @param \Doctrine\ORM\Cache\CacheKey $key The key of the item to lock.
|
||||
* @param CacheKey $key The key of the item to lock.
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache\Lock A lock instance or NULL if the lock already exists.
|
||||
* @return Lock A lock instance or NULL if the lock already exists.
|
||||
*
|
||||
* @throws \Doctrine\ORM\Cache\LockException Indicates a problem accessing the region.
|
||||
* @throws LockException Indicates a problem accessing the region.
|
||||
*/
|
||||
public function lock(CacheKey $key);
|
||||
|
||||
/**
|
||||
* Attempts to read unlock the mapping for the given key.
|
||||
*
|
||||
* @param \Doctrine\ORM\Cache\CacheKey $key The key of the item to unlock.
|
||||
* @param \Doctrine\ORM\Cache\Lock $lock The lock previously obtained from {@link readLock}
|
||||
* @param CacheKey $key The key of the item to unlock.
|
||||
* @param Lock $lock The lock previously obtained from {@link readLock}
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws \Doctrine\ORM\Cache\LockException Indicates a problem accessing the region.
|
||||
* @throws LockException Indicates a problem accessing the region.
|
||||
*/
|
||||
public function unlock(CacheKey $key, Lock $lock);
|
||||
}
|
||||
|
||||
@@ -20,44 +20,35 @@
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
use Doctrine\ORM\Cache;
|
||||
use Doctrine\Common\Util\ClassUtils;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Cache;
|
||||
use Doctrine\ORM\Cache\Persister\CachedPersister;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\ORMInvalidArgumentException;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
|
||||
/**
|
||||
* Provides an API for querying/managing the second level cache regions.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class DefaultCache implements Cache
|
||||
{
|
||||
/**
|
||||
* @var \Doctrine\ORM\EntityManagerInterface
|
||||
*/
|
||||
/** @var EntityManagerInterface */
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\UnitOfWork
|
||||
*/
|
||||
/** @var UnitOfWork */
|
||||
private $uow;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache\CacheFactory
|
||||
*/
|
||||
/** @var CacheFactory */
|
||||
private $cacheFactory;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache\QueryCache[]
|
||||
*/
|
||||
/** @var QueryCache[] */
|
||||
private $queryCaches = [];
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache\QueryCache
|
||||
*/
|
||||
/** @var QueryCache */
|
||||
private $defaultQueryCache;
|
||||
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
@@ -77,7 +68,7 @@ class DefaultCache implements Cache
|
||||
$metadata = $this->em->getClassMetadata($className);
|
||||
$persister = $this->uow->getEntityPersister($metadata->rootEntityName);
|
||||
|
||||
if ( ! ($persister instanceof CachedPersister)) {
|
||||
if (! ($persister instanceof CachedPersister)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -92,7 +83,7 @@ class DefaultCache implements Cache
|
||||
$metadata = $this->em->getClassMetadata($className);
|
||||
$persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association));
|
||||
|
||||
if ( ! ($persister instanceof CachedPersister)) {
|
||||
if (! ($persister instanceof CachedPersister)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -104,10 +95,10 @@ class DefaultCache implements Cache
|
||||
*/
|
||||
public function containsEntity($className, $identifier)
|
||||
{
|
||||
$metadata = $this->em->getClassMetadata($className);
|
||||
$persister = $this->uow->getEntityPersister($metadata->rootEntityName);
|
||||
$metadata = $this->em->getClassMetadata($className);
|
||||
$persister = $this->uow->getEntityPersister($metadata->rootEntityName);
|
||||
|
||||
if ( ! ($persister instanceof CachedPersister)) {
|
||||
if (! ($persister instanceof CachedPersister)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -122,7 +113,7 @@ class DefaultCache implements Cache
|
||||
$metadata = $this->em->getClassMetadata($className);
|
||||
$persister = $this->uow->getEntityPersister($metadata->rootEntityName);
|
||||
|
||||
if ( ! ($persister instanceof CachedPersister)) {
|
||||
if (! ($persister instanceof CachedPersister)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -137,7 +128,7 @@ class DefaultCache implements Cache
|
||||
$metadata = $this->em->getClassMetadata($className);
|
||||
$persister = $this->uow->getEntityPersister($metadata->rootEntityName);
|
||||
|
||||
if ( ! ($persister instanceof CachedPersister)) {
|
||||
if (! ($persister instanceof CachedPersister)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -154,7 +145,7 @@ class DefaultCache implements Cache
|
||||
foreach ($metadatas as $metadata) {
|
||||
$persister = $this->uow->getEntityPersister($metadata->rootEntityName);
|
||||
|
||||
if ( ! ($persister instanceof CachedPersister)) {
|
||||
if (! ($persister instanceof CachedPersister)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -170,7 +161,7 @@ class DefaultCache implements Cache
|
||||
$metadata = $this->em->getClassMetadata($className);
|
||||
$persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association));
|
||||
|
||||
if ( ! ($persister instanceof CachedPersister)) {
|
||||
if (! ($persister instanceof CachedPersister)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -185,7 +176,7 @@ class DefaultCache implements Cache
|
||||
$metadata = $this->em->getClassMetadata($className);
|
||||
$persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association));
|
||||
|
||||
if ( ! ($persister instanceof CachedPersister)) {
|
||||
if (! ($persister instanceof CachedPersister)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -200,7 +191,7 @@ class DefaultCache implements Cache
|
||||
$metadata = $this->em->getClassMetadata($className);
|
||||
$persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association));
|
||||
|
||||
if ( ! ($persister instanceof CachedPersister)) {
|
||||
if (! ($persister instanceof CachedPersister)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -215,16 +206,14 @@ class DefaultCache implements Cache
|
||||
$metadatas = $this->em->getMetadataFactory()->getAllMetadata();
|
||||
|
||||
foreach ($metadatas as $metadata) {
|
||||
|
||||
foreach ($metadata->associationMappings as $association) {
|
||||
|
||||
if ( ! $association['type'] & ClassMetadata::TO_MANY) {
|
||||
if (! $association['type'] & ClassMetadata::TO_MANY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$persister = $this->uow->getCollectionPersister($association);
|
||||
|
||||
if ( ! ($persister instanceof CachedPersister)) {
|
||||
if (! ($persister instanceof CachedPersister)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -279,7 +268,7 @@ class DefaultCache implements Cache
|
||||
$this->defaultQueryCache = $this->cacheFactory->buildQueryCache($this->em);
|
||||
}
|
||||
|
||||
if ( ! isset($this->queryCaches[$regionName])) {
|
||||
if (! isset($this->queryCaches[$regionName])) {
|
||||
$this->queryCaches[$regionName] = $this->cacheFactory->buildQueryCache($this->em, $regionName);
|
||||
}
|
||||
|
||||
@@ -287,14 +276,14 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\Mapping\ClassMetadata $metadata The entity metadata.
|
||||
* @param mixed $identifier The entity identifier.
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache\EntityCacheKey
|
||||
*/
|
||||
* @param ClassMetadata $metadata The entity metadata.
|
||||
* @param mixed $identifier The entity identifier.
|
||||
*
|
||||
* @return EntityCacheKey
|
||||
*/
|
||||
private function buildEntityCacheKey(ClassMetadata $metadata, $identifier)
|
||||
{
|
||||
if ( ! is_array($identifier)) {
|
||||
if (! is_array($identifier)) {
|
||||
$identifier = $this->toIdentifierArray($metadata, $identifier);
|
||||
}
|
||||
|
||||
@@ -302,15 +291,15 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\Mapping\ClassMetadata $metadata The entity metadata.
|
||||
* @param string $association The field name that represents the association.
|
||||
* @param mixed $ownerIdentifier The identifier of the owning entity.
|
||||
* @param ClassMetadata $metadata The entity metadata.
|
||||
* @param string $association The field name that represents the association.
|
||||
* @param mixed $ownerIdentifier The identifier of the owning entity.
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache\CollectionCacheKey
|
||||
* @return CollectionCacheKey
|
||||
*/
|
||||
private function buildCollectionCacheKey(ClassMetadata $metadata, $association, $ownerIdentifier)
|
||||
{
|
||||
if ( ! is_array($ownerIdentifier)) {
|
||||
if (! is_array($ownerIdentifier)) {
|
||||
$ownerIdentifier = $this->toIdentifierArray($metadata, $ownerIdentifier);
|
||||
}
|
||||
|
||||
@@ -318,10 +307,10 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\Mapping\ClassMetadata $metadata The entity metadata.
|
||||
* @param mixed $identifier The entity identifier.
|
||||
* @param ClassMetadata $metadata The entity metadata.
|
||||
* @param mixed $identifier The entity identifier.
|
||||
*
|
||||
* @return array
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function toIdentifierArray(ClassMetadata $metadata, $identifier)
|
||||
{
|
||||
@@ -335,5 +324,4 @@ class DefaultCache implements Cache
|
||||
|
||||
return [$metadata->identifier[0] => $identifier];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -38,42 +38,30 @@ use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
|
||||
use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
|
||||
/**
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class DefaultCacheFactory implements CacheFactory
|
||||
{
|
||||
/**
|
||||
* @var CacheAdapter
|
||||
*/
|
||||
/** @var CacheAdapter */
|
||||
private $cache;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache\RegionsConfiguration
|
||||
*/
|
||||
/** @var RegionsConfiguration */
|
||||
private $regionsConfig;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache\TimestampRegion|null
|
||||
*/
|
||||
/** @var TimestampRegion|null */
|
||||
private $timestampRegion;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache\Region[]
|
||||
*/
|
||||
/** @var Region[] */
|
||||
private $regions = [];
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
/** @var string|null */
|
||||
private $fileLockRegionDirectory;
|
||||
|
||||
/**
|
||||
* @param RegionsConfiguration $cacheConfig
|
||||
* @param CacheAdapter $cache
|
||||
*/
|
||||
public function __construct(RegionsConfiguration $cacheConfig, CacheAdapter $cache)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
@@ -96,17 +84,11 @@ class DefaultCacheFactory implements CacheFactory
|
||||
return $this->fileLockRegionDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\Cache\Region $region
|
||||
*/
|
||||
public function setRegion(Region $region)
|
||||
{
|
||||
$this->regions[$region->getName()] = $region;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\Cache\TimestampRegion $region
|
||||
*/
|
||||
public function setTimestampRegion(TimestampRegion $region)
|
||||
{
|
||||
$this->timestampRegion = $region;
|
||||
@@ -117,8 +99,8 @@ class DefaultCacheFactory implements CacheFactory
|
||||
*/
|
||||
public function buildCachedEntityPersister(EntityManagerInterface $em, EntityPersister $persister, ClassMetadata $metadata)
|
||||
{
|
||||
$region = $this->getRegion($metadata->cache);
|
||||
$usage = $metadata->cache['usage'];
|
||||
$region = $this->getRegion($metadata->cache);
|
||||
$usage = $metadata->cache['usage'];
|
||||
|
||||
if ($usage === ClassMetadata::CACHE_USAGE_READ_ONLY) {
|
||||
return new ReadOnlyCachedEntityPersister($persister, $region, $em, $metadata);
|
||||
@@ -132,7 +114,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
return new ReadWriteCachedEntityPersister($persister, $region, $em, $metadata);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf("Unrecognized access strategy type [%s]", $usage));
|
||||
throw new InvalidArgumentException(sprintf('Unrecognized access strategy type [%s]', $usage));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,8 +122,8 @@ class DefaultCacheFactory implements CacheFactory
|
||||
*/
|
||||
public function buildCachedCollectionPersister(EntityManagerInterface $em, CollectionPersister $persister, array $mapping)
|
||||
{
|
||||
$usage = $mapping['cache']['usage'];
|
||||
$region = $this->getRegion($mapping['cache']);
|
||||
$usage = $mapping['cache']['usage'];
|
||||
$region = $this->getRegion($mapping['cache']);
|
||||
|
||||
if ($usage === ClassMetadata::CACHE_USAGE_READ_ONLY) {
|
||||
return new ReadOnlyCachedCollectionPersister($persister, $region, $em, $mapping);
|
||||
@@ -155,7 +137,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
return new ReadWriteCachedCollectionPersister($persister, $region, $em, $mapping);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf("Unrecognized access strategy type [%s]", $usage));
|
||||
throw new InvalidArgumentException(sprintf('Unrecognized access strategy type [%s]', $usage));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,7 +150,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
$this->getRegion(
|
||||
[
|
||||
'region' => $regionName ?: Cache::DEFAULT_QUERY_REGION_NAME,
|
||||
'usage' => ClassMetadata::CACHE_USAGE_NONSTRICT_READ_WRITE
|
||||
'usage' => ClassMetadata::CACHE_USAGE_NONSTRICT_READ_WRITE,
|
||||
]
|
||||
)
|
||||
);
|
||||
@@ -203,17 +185,16 @@ class DefaultCacheFactory implements CacheFactory
|
||||
$cacheAdapter = $this->createRegionCache($name);
|
||||
$lifetime = $this->regionsConfig->getLifetime($cache['region']);
|
||||
|
||||
$region = ($cacheAdapter instanceof MultiGetCache)
|
||||
$region = $cacheAdapter instanceof MultiGetCache
|
||||
? new DefaultMultiGetRegion($name, $cacheAdapter, $lifetime)
|
||||
: new DefaultRegion($name, $cacheAdapter, $lifetime);
|
||||
|
||||
if ($cache['usage'] === ClassMetadata::CACHE_USAGE_READ_WRITE) {
|
||||
|
||||
if (
|
||||
'' === $this->fileLockRegionDirectory ||
|
||||
null === $this->fileLockRegionDirectory
|
||||
$this->fileLockRegionDirectory === '' ||
|
||||
$this->fileLockRegionDirectory === null
|
||||
) {
|
||||
throw new \LogicException(
|
||||
throw new LogicException(
|
||||
'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 want to use it please provide a valid directory, DefaultCacheFactory#setFileLockRegionDirectory(). '
|
||||
);
|
||||
@@ -235,13 +216,13 @@ class DefaultCacheFactory implements CacheFactory
|
||||
{
|
||||
$cacheAdapter = clone $this->cache;
|
||||
|
||||
if (!$cacheAdapter instanceof CacheProvider) {
|
||||
if (! $cacheAdapter instanceof CacheProvider) {
|
||||
return $cacheAdapter;
|
||||
}
|
||||
|
||||
$namespace = $cacheAdapter->getNamespace();
|
||||
|
||||
if ('' !== $namespace) {
|
||||
if ($namespace !== '') {
|
||||
$namespace .= ':';
|
||||
}
|
||||
|
||||
|
||||
@@ -20,36 +20,32 @@
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Cache\Persister\CachedPersister;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
|
||||
use function array_walk;
|
||||
use function assert;
|
||||
|
||||
/**
|
||||
* Default hydrator cache for collections
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class DefaultCollectionHydrator implements CollectionHydrator
|
||||
{
|
||||
/**
|
||||
* @var \Doctrine\ORM\EntityManagerInterface
|
||||
*/
|
||||
/** @var EntityManagerInterface */
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\UnitOfWork
|
||||
*/
|
||||
/** @var UnitOfWork */
|
||||
private $uow;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var array<string,mixed> */
|
||||
private static $hints = [Query::HINT_CACHE_ENABLED => true];
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\EntityManagerInterface $em The entity manager.
|
||||
* @param EntityManagerInterface $em The entity manager.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
@@ -77,23 +73,23 @@ class DefaultCollectionHydrator implements CollectionHydrator
|
||||
public function loadCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, CollectionCacheEntry $entry, PersistentCollection $collection)
|
||||
{
|
||||
$assoc = $metadata->associationMappings[$key->association];
|
||||
/* @var $targetPersister \Doctrine\ORM\Cache\Persister\CachedPersister */
|
||||
$targetPersister = $this->uow->getEntityPersister($assoc['targetEntity']);
|
||||
$targetRegion = $targetPersister->getCacheRegion();
|
||||
$list = [];
|
||||
assert($targetPersister instanceof CachedPersister);
|
||||
$targetRegion = $targetPersister->getCacheRegion();
|
||||
$list = [];
|
||||
|
||||
/** @var EntityCacheEntry[]|null $entityEntries */
|
||||
$entityEntries = $targetRegion->getMultiple($entry);
|
||||
|
||||
if ($entityEntries === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/* @var $entityEntries \Doctrine\ORM\Cache\EntityCacheEntry[] */
|
||||
foreach ($entityEntries as $index => $entityEntry) {
|
||||
$list[$index] = $this->uow->createEntity($entityEntry->class, $entityEntry->resolveAssociationEntries($this->em), self::$hints);
|
||||
}
|
||||
|
||||
array_walk($list, function($entity, $index) use ($collection) {
|
||||
array_walk($list, static function ($entity, $index) use ($collection) {
|
||||
$collection->hydrateSet($index, $entity);
|
||||
});
|
||||
|
||||
|
||||
@@ -21,49 +21,45 @@
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
use Doctrine\Common\Util\ClassUtils;
|
||||
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
use Doctrine\ORM\Utility\IdentifierFlattener;
|
||||
|
||||
use function array_merge;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function reset;
|
||||
|
||||
/**
|
||||
* Default hydrator cache for entities
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class DefaultEntityHydrator implements EntityHydrator
|
||||
{
|
||||
/**
|
||||
* @var \Doctrine\ORM\EntityManagerInterface
|
||||
*/
|
||||
/** @var EntityManagerInterface */
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\UnitOfWork
|
||||
*/
|
||||
/** @var UnitOfWork */
|
||||
private $uow;
|
||||
|
||||
/**
|
||||
* The IdentifierFlattener used for manipulating identifiers
|
||||
*
|
||||
* @var \Doctrine\ORM\Utility\IdentifierFlattener
|
||||
* @var IdentifierFlattener
|
||||
*/
|
||||
private $identifierFlattener;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var array<string,mixed> */
|
||||
private static $hints = [Query::HINT_CACHE_ENABLED => true];
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\EntityManagerInterface $em The entity manager.
|
||||
* @param EntityManagerInterface $em The entity manager.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $em;
|
||||
$this->uow = $em->getUnitOfWork();
|
||||
$this->em = $em;
|
||||
$this->uow = $em->getUnitOfWork();
|
||||
$this->identifierFlattener = new IdentifierFlattener($em->getUnitOfWork(), $em->getMetadataFactory());
|
||||
}
|
||||
|
||||
@@ -80,19 +76,19 @@ class DefaultEntityHydrator implements EntityHydrator
|
||||
}
|
||||
|
||||
foreach ($metadata->associationMappings as $name => $assoc) {
|
||||
if ( ! isset($data[$name])) {
|
||||
if (! isset($data[$name])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! ($assoc['type'] & ClassMetadata::TO_ONE)) {
|
||||
if (! ($assoc['type'] & ClassMetadata::TO_ONE)) {
|
||||
unset($data[$name]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! isset($assoc['cache'])) {
|
||||
if (! isset($assoc['cache'])) {
|
||||
$targetClassMetadata = $this->em->getClassMetadata($assoc['targetEntity']);
|
||||
$owningAssociation = ( ! $assoc['isOwningSide'])
|
||||
$owningAssociation = ! $assoc['isOwningSide']
|
||||
? $targetClassMetadata->associationMappings[$assoc['mappedBy']]
|
||||
: $assoc;
|
||||
$associationIds = $this->identifierFlattener->flattenIdentifier(
|
||||
@@ -113,7 +109,7 @@ class DefaultEntityHydrator implements EntityHydrator
|
||||
|
||||
$targetAssoc = $targetClassMetadata->associationMappings[$fieldName];
|
||||
|
||||
foreach($assoc['targetToSourceKeyColumns'] as $referencedColumn => $localColumn) {
|
||||
foreach ($assoc['targetToSourceKeyColumns'] as $referencedColumn => $localColumn) {
|
||||
if (isset($targetAssoc['sourceToTargetKeyColumns'][$referencedColumn])) {
|
||||
$data[$localColumn] = $fieldValue;
|
||||
}
|
||||
@@ -123,7 +119,7 @@ class DefaultEntityHydrator implements EntityHydrator
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! isset($assoc['id'])) {
|
||||
if (! isset($assoc['id'])) {
|
||||
$targetClass = ClassUtils::getClass($data[$name]);
|
||||
$targetId = $this->uow->getEntityIdentifier($data[$name]);
|
||||
$data[$name] = new AssociationCacheEntry($targetClass, $targetId);
|
||||
@@ -138,7 +134,7 @@ class DefaultEntityHydrator implements EntityHydrator
|
||||
|
||||
// @TODO - fix it !
|
||||
// handle UnitOfWork#createEntity hash generation
|
||||
if ( ! is_array($targetId)) {
|
||||
if (! is_array($targetId)) {
|
||||
$data[reset($assoc['joinColumnFieldNames'])] = $targetId;
|
||||
|
||||
$targetEntity = $this->em->getClassMetadata($assoc['targetEntity']);
|
||||
@@ -160,20 +156,20 @@ class DefaultEntityHydrator implements EntityHydrator
|
||||
$hints = self::$hints;
|
||||
|
||||
if ($entity !== null) {
|
||||
$hints[Query::HINT_REFRESH] = true;
|
||||
$hints[Query::HINT_REFRESH_ENTITY] = $entity;
|
||||
$hints[Query::HINT_REFRESH] = true;
|
||||
$hints[Query::HINT_REFRESH_ENTITY] = $entity;
|
||||
}
|
||||
|
||||
foreach ($metadata->associationMappings as $name => $assoc) {
|
||||
if ( ! isset($assoc['cache']) || ! isset($data[$name])) {
|
||||
if (! isset($assoc['cache']) || ! isset($data[$name])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$assocClass = $data[$name]->class;
|
||||
$assocId = $data[$name]->identifier;
|
||||
$isEagerLoad = ($assoc['fetch'] === ClassMetadata::FETCH_EAGER || ($assoc['type'] === ClassMetadata::ONE_TO_ONE && ! $assoc['isOwningSide']));
|
||||
$assocClass = $data[$name]->class;
|
||||
$assocId = $data[$name]->identifier;
|
||||
$isEagerLoad = ($assoc['fetch'] === ClassMetadata::FETCH_EAGER || ($assoc['type'] === ClassMetadata::ONE_TO_ONE && ! $assoc['isOwningSide']));
|
||||
|
||||
if ( ! $isEagerLoad) {
|
||||
if (! $isEagerLoad) {
|
||||
$data[$name] = $this->em->getReference($assocClass, $assocId);
|
||||
|
||||
continue;
|
||||
|
||||
@@ -21,68 +21,63 @@
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\ORM\Cache\Persister\CachedPersister;
|
||||
use Doctrine\ORM\Cache\Persister\Entity\CachedEntityPersister;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\Common\Proxy\Proxy;
|
||||
use Doctrine\ORM\Cache;
|
||||
use Doctrine\ORM\Cache\Logging\CacheLogger;
|
||||
use Doctrine\ORM\Cache\Persister\Entity\CachedEntityPersister;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
|
||||
use function array_key_exists;
|
||||
use function array_map;
|
||||
use function array_shift;
|
||||
use function array_unshift;
|
||||
use function assert;
|
||||
use function count;
|
||||
use function is_array;
|
||||
use function key;
|
||||
use function reset;
|
||||
|
||||
/**
|
||||
* Default query cache implementation.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class DefaultQueryCache implements QueryCache
|
||||
{
|
||||
/**
|
||||
* @var \Doctrine\ORM\EntityManagerInterface
|
||||
*/
|
||||
/** @var EntityManagerInterface */
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\UnitOfWork
|
||||
*/
|
||||
/** @var UnitOfWork */
|
||||
private $uow;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache\Region
|
||||
*/
|
||||
/** @var Region */
|
||||
private $region;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache\QueryCacheValidator
|
||||
*/
|
||||
/** @var QueryCacheValidator */
|
||||
private $validator;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache\Logging\CacheLogger
|
||||
*/
|
||||
/** @var CacheLogger */
|
||||
protected $cacheLogger;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var array<string,mixed> */
|
||||
private static $hints = [Query::HINT_CACHE_ENABLED => true];
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\EntityManagerInterface $em The entity manager.
|
||||
* @param \Doctrine\ORM\Cache\Region $region The query region.
|
||||
* @param EntityManagerInterface $em The entity manager.
|
||||
* @param Region $region The query region.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $em, Region $region)
|
||||
{
|
||||
$cacheConfig = $em->getConfiguration()->getSecondLevelCacheConfiguration();
|
||||
|
||||
$this->em = $em;
|
||||
$this->region = $region;
|
||||
$this->uow = $em->getUnitOfWork();
|
||||
$this->cacheLogger = $cacheConfig->getCacheLogger();
|
||||
$this->validator = $cacheConfig->getQueryValidator();
|
||||
$this->em = $em;
|
||||
$this->region = $region;
|
||||
$this->uow = $em->getUnitOfWork();
|
||||
$this->cacheLogger = $cacheConfig->getCacheLogger();
|
||||
$this->validator = $cacheConfig->getQueryValidator();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,17 +85,17 @@ class DefaultQueryCache implements QueryCache
|
||||
*/
|
||||
public function get(QueryCacheKey $key, ResultSetMapping $rsm, array $hints = [])
|
||||
{
|
||||
if ( ! ($key->cacheMode & Cache::MODE_GET)) {
|
||||
if (! ($key->cacheMode & Cache::MODE_GET)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$cacheEntry = $this->region->get($key);
|
||||
|
||||
if ( ! $cacheEntry instanceof QueryCacheEntry) {
|
||||
if (! $cacheEntry instanceof QueryCacheEntry) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( ! $this->validator->isValid($key, $cacheEntry)) {
|
||||
if (! $this->validator->isValid($key, $cacheEntry)) {
|
||||
$this->region->evict($key);
|
||||
|
||||
return null;
|
||||
@@ -117,7 +112,7 @@ class DefaultQueryCache implements QueryCache
|
||||
|
||||
$cm = $this->em->getClassMetadata($entityName);
|
||||
|
||||
$generateKeys = static function (array $entry) use ($cm) : EntityCacheKey {
|
||||
$generateKeys = static function (array $entry) use ($cm): EntityCacheKey {
|
||||
return new EntityCacheKey($cm->rootEntityName, $entry['identifier']);
|
||||
};
|
||||
|
||||
@@ -140,8 +135,8 @@ class DefaultQueryCache implements QueryCache
|
||||
$this->cacheLogger->entityCacheHit($regionName, $cacheKeys->identifiers[$index]);
|
||||
}
|
||||
|
||||
if ( ! $hasRelation) {
|
||||
$result[$index] = $this->uow->createEntity($entityEntry->class, $entityEntry->resolveAssociationEntries($this->em), self::$hints);
|
||||
if (! $hasRelation) {
|
||||
$result[$index] = $this->uow->createEntity($entityEntry->class, $entityEntry->resolveAssociationEntries($this->em), self::$hints);
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -156,9 +151,10 @@ class DefaultQueryCache implements QueryCache
|
||||
$assocMetadata = $this->em->getClassMetadata($assoc['targetEntity']);
|
||||
|
||||
if ($assoc['type'] & ClassMetadata::TO_ONE) {
|
||||
$assocKey = new EntityCacheKey($assocMetadata->rootEntityName, $assoc['identifier']);
|
||||
$assocEntry = $assocRegion->get($assocKey);
|
||||
|
||||
if (($assocEntry = $assocRegion->get($assocKey = new EntityCacheKey($assocMetadata->rootEntityName, $assoc['identifier']))) === null) {
|
||||
|
||||
if ($assocEntry === null) {
|
||||
if ($this->cacheLogger !== null) {
|
||||
$this->cacheLogger->entityCacheMiss($assocRegion->getName(), $assocKey);
|
||||
}
|
||||
@@ -177,11 +173,11 @@ class DefaultQueryCache implements QueryCache
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! isset($assoc['list']) || empty($assoc['list'])) {
|
||||
if (! isset($assoc['list']) || empty($assoc['list'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$generateKeys = function ($id) use ($assocMetadata): EntityCacheKey {
|
||||
$generateKeys = static function ($id) use ($assocMetadata): EntityCacheKey {
|
||||
return new EntityCacheKey($assocMetadata->rootEntityName, $id);
|
||||
};
|
||||
|
||||
@@ -249,29 +245,29 @@ class DefaultQueryCache implements QueryCache
|
||||
public function put(QueryCacheKey $key, ResultSetMapping $rsm, $result, array $hints = [])
|
||||
{
|
||||
if ($rsm->scalarMappings) {
|
||||
throw new CacheException("Second level cache does not support scalar results.");
|
||||
throw new CacheException('Second level cache does not support scalar results.');
|
||||
}
|
||||
|
||||
if (count($rsm->entityMappings) > 1) {
|
||||
throw new CacheException("Second level cache does not support multiple root entities.");
|
||||
throw new CacheException('Second level cache does not support multiple root entities.');
|
||||
}
|
||||
|
||||
if ( ! $rsm->isSelect) {
|
||||
throw new CacheException("Second-level cache query supports only select statements.");
|
||||
if (! $rsm->isSelect) {
|
||||
throw new CacheException('Second-level cache query supports only select statements.');
|
||||
}
|
||||
|
||||
if (($hints[Query\SqlWalker::HINT_PARTIAL] ?? false) === true || ($hints[Query::HINT_FORCE_PARTIAL_LOAD] ?? false) === true) {
|
||||
throw new CacheException("Second level cache does not support partial entities.");
|
||||
throw new CacheException('Second level cache does not support partial entities.');
|
||||
}
|
||||
|
||||
if ( ! ($key->cacheMode & Cache::MODE_PUT)) {
|
||||
if (! ($key->cacheMode & Cache::MODE_PUT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$data = [];
|
||||
$entityName = reset($rsm->aliasMap);
|
||||
$rootAlias = key($rsm->aliasMap);
|
||||
$persister = $this->uow->getEntityPersister($entityName);
|
||||
$data = [];
|
||||
$entityName = reset($rsm->aliasMap);
|
||||
$rootAlias = key($rsm->aliasMap);
|
||||
$persister = $this->uow->getEntityPersister($entityName);
|
||||
|
||||
if (! $persister instanceof CachedEntityPersister) {
|
||||
throw CacheException::nonCacheableEntity($entityName);
|
||||
@@ -288,7 +284,7 @@ class DefaultQueryCache implements QueryCache
|
||||
|
||||
if (($key->cacheMode & Cache::MODE_REFRESH) || ! $region->contains($entityKey)) {
|
||||
// Cancel put result if entity put fail
|
||||
if ( ! $persister->storeEntityCache($entity, $entityKey)) {
|
||||
if (! $persister->storeEntityCache($entity, $entityKey)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -298,11 +294,11 @@ class DefaultQueryCache implements QueryCache
|
||||
|
||||
// @TODO - move to cache hydration components
|
||||
foreach ($rsm->relationMap as $alias => $name) {
|
||||
$parentAlias = $rsm->parentAliasMap[$alias];
|
||||
$parentClass = $rsm->aliasMap[$parentAlias];
|
||||
$metadata = $this->em->getClassMetadata($parentClass);
|
||||
$assoc = $metadata->associationMappings[$name];
|
||||
$assocValue = $this->getAssociationValue($rsm, $alias, $entity);
|
||||
$parentAlias = $rsm->parentAliasMap[$alias];
|
||||
$parentClass = $rsm->aliasMap[$parentAlias];
|
||||
$metadata = $this->em->getClassMetadata($parentClass);
|
||||
$assoc = $metadata->associationMappings[$name];
|
||||
$assocValue = $this->getAssociationValue($rsm, $alias, $entity);
|
||||
|
||||
if ($assocValue === null) {
|
||||
continue;
|
||||
@@ -311,7 +307,8 @@ class DefaultQueryCache implements QueryCache
|
||||
// root entity association
|
||||
if ($rootAlias === $parentAlias) {
|
||||
// Cancel put result if association put fail
|
||||
if ( ($assocInfo = $this->storeAssociationCache($key, $assoc, $assocValue)) === null) {
|
||||
$assocInfo = $this->storeAssociationCache($key, $assoc, $assocValue);
|
||||
if ($assocInfo === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -321,7 +318,7 @@ class DefaultQueryCache implements QueryCache
|
||||
}
|
||||
|
||||
// store single nested association
|
||||
if ( ! is_array($assocValue)) {
|
||||
if (! is_array($assocValue)) {
|
||||
// Cancel put result if association put fail
|
||||
if ($this->storeAssociationCache($key, $assoc, $assocValue) === null) {
|
||||
return false;
|
||||
@@ -344,9 +341,8 @@ class DefaultQueryCache implements QueryCache
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\Cache\QueryCacheKey $key
|
||||
* @param array $assoc
|
||||
* @param mixed $assocValue
|
||||
* @param array<string,mixed> $assoc
|
||||
* @param mixed $assocValue
|
||||
*
|
||||
* @return mixed[]|null
|
||||
*
|
||||
@@ -363,9 +359,9 @@ class DefaultQueryCache implements QueryCache
|
||||
$assocIdentifier = $this->uow->getEntityIdentifier($assocValue);
|
||||
$entityKey = new EntityCacheKey($assocMetadata->rootEntityName, $assocIdentifier);
|
||||
|
||||
if ( ! $assocValue instanceof Proxy && ($key->cacheMode & Cache::MODE_REFRESH) || ! $assocRegion->contains($entityKey)) {
|
||||
if (! $assocValue instanceof Proxy && ($key->cacheMode & Cache::MODE_REFRESH) || ! $assocRegion->contains($entityKey)) {
|
||||
// Entity put fail
|
||||
if ( ! $assocPersister->storeEntityCache($assocValue, $entityKey)) {
|
||||
if (! $assocPersister->storeEntityCache($assocValue, $entityKey)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -373,7 +369,7 @@ class DefaultQueryCache implements QueryCache
|
||||
return [
|
||||
'targetEntity' => $assocMetadata->rootEntityName,
|
||||
'identifier' => $assocIdentifier,
|
||||
'type' => $assoc['type']
|
||||
'type' => $assoc['type'],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -386,7 +382,7 @@ class DefaultQueryCache implements QueryCache
|
||||
|
||||
if (($key->cacheMode & Cache::MODE_REFRESH) || ! $assocRegion->contains($entityKey)) {
|
||||
// Entity put fail
|
||||
if ( ! $assocPersister->storeEntityCache($assocItem, $entityKey)) {
|
||||
if (! $assocPersister->storeEntityCache($assocItem, $entityKey)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -402,11 +398,10 @@ class DefaultQueryCache implements QueryCache
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\Query\ResultSetMapping $rsm
|
||||
* @param string $assocAlias
|
||||
* @param object $entity
|
||||
* @param string $assocAlias
|
||||
* @param object $entity
|
||||
*
|
||||
* @return array|object
|
||||
* @return array<object>|object
|
||||
*/
|
||||
private function getAssociationValue(ResultSetMapping $rsm, $assocAlias, $entity)
|
||||
{
|
||||
@@ -420,9 +415,8 @@ class DefaultQueryCache implements QueryCache
|
||||
|
||||
array_unshift($path, [
|
||||
'field' => $field,
|
||||
'class' => $class
|
||||
]
|
||||
);
|
||||
'class' => $class,
|
||||
]);
|
||||
|
||||
$alias = $parent;
|
||||
}
|
||||
@@ -431,10 +425,10 @@ class DefaultQueryCache implements QueryCache
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
* @param array $path
|
||||
* @param mixed $value
|
||||
* @param array<mixed> $path
|
||||
*
|
||||
* @return array|object|null
|
||||
* @return array<object>|object|null
|
||||
*/
|
||||
private function getAssociationPathValue($value, array $path)
|
||||
{
|
||||
|
||||
@@ -22,18 +22,17 @@ namespace Doctrine\ORM\Cache;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
use function array_map;
|
||||
|
||||
/**
|
||||
* Entity cache entry
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class EntityCacheEntry implements CacheEntry
|
||||
{
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
*
|
||||
* @var array The entity map data
|
||||
* @var array<string,mixed> The entity map data
|
||||
*/
|
||||
public $data;
|
||||
|
||||
@@ -45,8 +44,8 @@ class EntityCacheEntry implements CacheEntry
|
||||
public $class;
|
||||
|
||||
/**
|
||||
* @param string $class The entity class.
|
||||
* @param array $data The entity data.
|
||||
* @param string $class The entity class.
|
||||
* @param array<string,mixed> $data The entity data.
|
||||
*/
|
||||
public function __construct($class, array $data)
|
||||
{
|
||||
@@ -59,7 +58,7 @@ class EntityCacheEntry implements CacheEntry
|
||||
*
|
||||
* This method allow Doctrine\Common\Cache\PhpFileCache compatibility
|
||||
*
|
||||
* @param array $values array containing property values
|
||||
* @param array<string,mixed> $values array containing property values
|
||||
*
|
||||
* @return EntityCacheEntry
|
||||
*/
|
||||
@@ -71,14 +70,12 @@ class EntityCacheEntry implements CacheEntry
|
||||
/**
|
||||
* Retrieves the entity data resolving cache entries
|
||||
*
|
||||
* @param \Doctrine\ORM\EntityManagerInterface $em
|
||||
*
|
||||
* @return array
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function resolveAssociationEntries(EntityManagerInterface $em)
|
||||
{
|
||||
return array_map(function($value) use ($em) {
|
||||
if ( ! ($value instanceof AssociationCacheEntry)) {
|
||||
return array_map(static function ($value) use ($em) {
|
||||
if (! ($value instanceof AssociationCacheEntry)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,18 +20,20 @@
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
use function implode;
|
||||
use function ksort;
|
||||
use function str_replace;
|
||||
use function strtolower;
|
||||
|
||||
/**
|
||||
* Defines entity classes roles to be stored in the cache region.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class EntityCacheKey extends CacheKey
|
||||
{
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
*
|
||||
* @var array The entity identifier
|
||||
* @var array<string, mixed> The entity identifier
|
||||
*/
|
||||
public $identifier;
|
||||
|
||||
@@ -43,8 +45,8 @@ class EntityCacheKey extends CacheKey
|
||||
public $entityClass;
|
||||
|
||||
/**
|
||||
* @param string $entityClass The entity class name. In a inheritance hierarchy it should always be the root entity class.
|
||||
* @param array $identifier The entity identifier
|
||||
* @param string $entityClass The entity class name. In a inheritance hierarchy it should always be the root entity class.
|
||||
* @param array<string, mixed> $identifier The entity identifier
|
||||
*/
|
||||
public function __construct($entityClass, array $identifier)
|
||||
{
|
||||
|
||||
@@ -24,26 +24,23 @@ use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
|
||||
/**
|
||||
* Hydrator cache entry for entities
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
interface EntityHydrator
|
||||
{
|
||||
/**
|
||||
* @param \Doctrine\ORM\Mapping\ClassMetadata $metadata The entity metadata.
|
||||
* @param \Doctrine\ORM\Cache\EntityCacheKey $key The entity cache key.
|
||||
* @param object $entity The entity.
|
||||
* @param ClassMetadata $metadata The entity metadata.
|
||||
* @param EntityCacheKey $key The entity cache key.
|
||||
* @param object $entity The entity.
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache\EntityCacheEntry
|
||||
* @return EntityCacheEntry
|
||||
*/
|
||||
public function buildCacheEntry(ClassMetadata $metadata, EntityCacheKey $key, $entity);
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\Mapping\ClassMetadata $metadata The entity metadata.
|
||||
* @param \Doctrine\ORM\Cache\EntityCacheKey $key The entity cache key.
|
||||
* @param \Doctrine\ORM\Cache\EntityCacheEntry $entry The entity cache entry.
|
||||
* @param object $entity The entity to load the cache into. If not specified, a new entity is created.
|
||||
* @param ClassMetadata $metadata The entity metadata.
|
||||
* @param EntityCacheKey $key The entity cache key.
|
||||
* @param EntityCacheEntry $entry The entity cache entry.
|
||||
* @param object $entity The entity to load the cache into. If not specified, a new entity is created.
|
||||
*/
|
||||
public function loadCacheEntry(ClassMetadata $metadata, EntityCacheKey $key, EntityCacheEntry $entry, $entity = null);
|
||||
}
|
||||
|
||||
@@ -20,27 +20,23 @@
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
use function time;
|
||||
use function uniqid;
|
||||
|
||||
/**
|
||||
* Cache Lock
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class Lock
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
public $value;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
/** @var int */
|
||||
public $time;
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
* @param integer $time
|
||||
* @param string $value
|
||||
* @param int $time
|
||||
*/
|
||||
public function __construct($value, $time = null)
|
||||
{
|
||||
@@ -49,7 +45,7 @@ class Lock
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Doctrine\ORM\Cache\Lock
|
||||
* @return Lock
|
||||
*/
|
||||
public static function createLockRead()
|
||||
{
|
||||
|
||||
@@ -22,11 +22,7 @@ namespace Doctrine\ORM\Cache;
|
||||
|
||||
/**
|
||||
* Lock exception for cache.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class LockException extends CacheException
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -26,81 +26,78 @@ use Doctrine\ORM\Cache\QueryCacheKey;
|
||||
|
||||
/**
|
||||
* Interface for logging.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
interface CacheLogger
|
||||
{
|
||||
/**
|
||||
* Log an entity put into second level cache.
|
||||
*
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param \Doctrine\ORM\Cache\EntityCacheKey $key The cache key of the entity.
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param EntityCacheKey $key The cache key of the entity.
|
||||
*/
|
||||
public function entityCachePut($regionName, EntityCacheKey $key);
|
||||
|
||||
/**
|
||||
* Log an entity get from second level cache resulted in a hit.
|
||||
*
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param \Doctrine\ORM\Cache\EntityCacheKey $key The cache key of the entity.
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param EntityCacheKey $key The cache key of the entity.
|
||||
*/
|
||||
public function entityCacheHit($regionName, EntityCacheKey $key);
|
||||
|
||||
/**
|
||||
* Log an entity get from second level cache resulted in a miss.
|
||||
*
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param \Doctrine\ORM\Cache\EntityCacheKey $key The cache key of the entity.
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param EntityCacheKey $key The cache key of the entity.
|
||||
*/
|
||||
public function entityCacheMiss($regionName, EntityCacheKey $key);
|
||||
|
||||
/**
|
||||
* Log an entity put into second level cache.
|
||||
*
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param \Doctrine\ORM\Cache\CollectionCacheKey $key The cache key of the collection.
|
||||
*/
|
||||
* Log an entity put into second level cache.
|
||||
*
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param CollectionCacheKey $key The cache key of the collection.
|
||||
*/
|
||||
public function collectionCachePut($regionName, CollectionCacheKey $key);
|
||||
|
||||
/**
|
||||
* Log an entity get from second level cache resulted in a hit.
|
||||
*
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param \Doctrine\ORM\Cache\CollectionCacheKey $key The cache key of the collection.
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param CollectionCacheKey $key The cache key of the collection.
|
||||
*/
|
||||
public function collectionCacheHit($regionName, CollectionCacheKey $key);
|
||||
|
||||
/**
|
||||
* Log an entity get from second level cache resulted in a miss.
|
||||
*
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param \Doctrine\ORM\Cache\CollectionCacheKey $key The cache key of the collection.
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param CollectionCacheKey $key The cache key of the collection.
|
||||
*/
|
||||
public function collectionCacheMiss($regionName, CollectionCacheKey $key);
|
||||
|
||||
/**
|
||||
* Log a query put into the query cache.
|
||||
*
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param \Doctrine\ORM\Cache\QueryCacheKey $key The cache key of the query.
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param QueryCacheKey $key The cache key of the query.
|
||||
*/
|
||||
public function queryCachePut($regionName, QueryCacheKey $key);
|
||||
|
||||
/**
|
||||
* Log a query get from the query cache resulted in a hit.
|
||||
*
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param \Doctrine\ORM\Cache\QueryCacheKey $key The cache key of the query.
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param QueryCacheKey $key The cache key of the query.
|
||||
*/
|
||||
public function queryCacheHit($regionName, QueryCacheKey $key);
|
||||
|
||||
/**
|
||||
* Log a query get from the query cache resulted in a miss.
|
||||
*
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param \Doctrine\ORM\Cache\QueryCacheKey $key The cache key of the query.
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param QueryCacheKey $key The cache key of the query.
|
||||
*/
|
||||
public function queryCacheMiss($regionName, QueryCacheKey $key);
|
||||
}
|
||||
|
||||
@@ -26,20 +26,14 @@ use Doctrine\ORM\Cache\QueryCacheKey;
|
||||
|
||||
/**
|
||||
* Cache logger chain
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class CacheLoggerChain implements CacheLogger
|
||||
{
|
||||
/**
|
||||
* @var array<\Doctrine\ORM\Cache\Logging\CacheLogger>
|
||||
*/
|
||||
/** @var array<CacheLogger> */
|
||||
private $loggers = [];
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param \Doctrine\ORM\Cache\Logging\CacheLogger $logger
|
||||
* @param string $name
|
||||
*/
|
||||
public function setLogger($name, CacheLogger $logger)
|
||||
{
|
||||
@@ -49,15 +43,15 @@ class CacheLoggerChain implements CacheLogger
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache\Logging\CacheLogger|null
|
||||
* @return CacheLogger|null
|
||||
*/
|
||||
public function getLogger($name)
|
||||
{
|
||||
return isset($this->loggers[$name]) ? $this->loggers[$name] : null;
|
||||
return $this->loggers[$name] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<\Doctrine\ORM\Cache\Logging\CacheLogger>
|
||||
* @return array<CacheLogger>
|
||||
*/
|
||||
public function getLoggers()
|
||||
{
|
||||
|
||||
@@ -24,27 +24,20 @@ use Doctrine\ORM\Cache\CollectionCacheKey;
|
||||
use Doctrine\ORM\Cache\EntityCacheKey;
|
||||
use Doctrine\ORM\Cache\QueryCacheKey;
|
||||
|
||||
use function array_sum;
|
||||
|
||||
/**
|
||||
* Provide basic second level cache statistics.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class StatisticsCacheLogger implements CacheLogger
|
||||
{
|
||||
/**
|
||||
* @var int[]
|
||||
*/
|
||||
/** @var int[] */
|
||||
private $cacheMissCountMap = [];
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
*/
|
||||
/** @var int[] */
|
||||
private $cacheHitCountMap = [];
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
*/
|
||||
/** @var int[] */
|
||||
private $cachePutCountMap = [];
|
||||
|
||||
/**
|
||||
@@ -146,7 +139,7 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
*/
|
||||
public function getRegionHitCount($regionName)
|
||||
{
|
||||
return isset($this->cacheHitCountMap[$regionName]) ? $this->cacheHitCountMap[$regionName] : 0;
|
||||
return $this->cacheHitCountMap[$regionName] ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,7 +151,7 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
*/
|
||||
public function getRegionMissCount($regionName)
|
||||
{
|
||||
return isset($this->cacheMissCountMap[$regionName]) ? $this->cacheMissCountMap[$regionName] : 0;
|
||||
return $this->cacheMissCountMap[$regionName] ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,11 +163,11 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
*/
|
||||
public function getRegionPutCount($regionName)
|
||||
{
|
||||
return isset($this->cachePutCountMap[$regionName]) ? $this->cachePutCountMap[$regionName] : 0;
|
||||
return $this->cachePutCountMap[$regionName] ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @return array<string, int>
|
||||
*/
|
||||
public function getRegionsMiss()
|
||||
{
|
||||
@@ -182,7 +175,7 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @return array<string, int>
|
||||
*/
|
||||
public function getRegionsHit()
|
||||
{
|
||||
@@ -190,7 +183,7 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @return array<string, int>
|
||||
*/
|
||||
public function getRegionsPut()
|
||||
{
|
||||
|
||||
@@ -24,9 +24,6 @@ namespace Doctrine\ORM\Cache;
|
||||
* Defines a region that supports multi-get reading.
|
||||
*
|
||||
* With one method call we can get multiple items.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Asmir Mustafic
|
||||
*/
|
||||
interface MultiGetRegion
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -19,11 +20,10 @@
|
||||
|
||||
namespace Doctrine\ORM\Cache\Persister;
|
||||
|
||||
use Doctrine\ORM\Cache\Region;
|
||||
|
||||
/**
|
||||
* Interface for persister that support second level cache.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
interface CachedPersister
|
||||
{
|
||||
@@ -40,7 +40,7 @@ interface CachedPersister
|
||||
/**
|
||||
* Gets the The region access.
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache\Region
|
||||
* @return Region
|
||||
*/
|
||||
public function getCacheRegion();
|
||||
}
|
||||
|
||||
@@ -21,99 +21,82 @@
|
||||
namespace Doctrine\ORM\Cache\Persister\Collection;
|
||||
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\ORM\Cache\EntityCacheKey;
|
||||
use Doctrine\ORM\Cache\CollectionCacheKey;
|
||||
use Doctrine\ORM\Cache\Persister\Entity\CachedEntityPersister;
|
||||
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Cache\Region;
|
||||
use Doctrine\Common\Util\ClassUtils;
|
||||
use Doctrine\ORM\Cache\CollectionCacheKey;
|
||||
use Doctrine\ORM\Cache\CollectionHydrator;
|
||||
use Doctrine\ORM\Cache\EntityCacheKey;
|
||||
use Doctrine\ORM\Cache\Logging\CacheLogger;
|
||||
use Doctrine\ORM\Cache\Persister\Entity\CachedEntityPersister;
|
||||
use Doctrine\ORM\Cache\Region;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataFactory;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
|
||||
use function array_values;
|
||||
use function assert;
|
||||
use function count;
|
||||
use function is_array;
|
||||
|
||||
/**
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @since 2.5
|
||||
*/
|
||||
abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
{
|
||||
/**
|
||||
* @var \Doctrine\ORM\UnitOfWork
|
||||
*/
|
||||
/** @var UnitOfWork */
|
||||
protected $uow;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Mapping\ClassMetadataFactory
|
||||
*/
|
||||
/** @var ClassMetadataFactory */
|
||||
protected $metadataFactory;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Persisters\Collection\CollectionPersister
|
||||
*/
|
||||
/** @var CollectionPersister */
|
||||
protected $persister;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Mapping\ClassMetadata
|
||||
*/
|
||||
/** @var ClassMetadata */
|
||||
protected $sourceEntity;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Mapping\ClassMetadata
|
||||
*/
|
||||
/** @var ClassMetadata */
|
||||
protected $targetEntity;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var mixed[] */
|
||||
protected $association;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var mixed[] */
|
||||
protected $queuedCache = [];
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache\Region
|
||||
*/
|
||||
/** @var Region */
|
||||
protected $region;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $regionName;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache\CollectionHydrator
|
||||
*/
|
||||
/** @var CollectionHydrator */
|
||||
protected $hydrator;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache\Logging\CacheLogger
|
||||
*/
|
||||
/** @var CacheLogger */
|
||||
protected $cacheLogger;
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\Persisters\Collection\CollectionPersister $persister The collection persister that will be cached.
|
||||
* @param \Doctrine\ORM\Cache\Region $region The collection region.
|
||||
* @param \Doctrine\ORM\EntityManagerInterface $em The entity manager.
|
||||
* @param array $association The association mapping.
|
||||
* @param CollectionPersister $persister The collection persister that will be cached.
|
||||
* @param Region $region The collection region.
|
||||
* @param EntityManagerInterface $em The entity manager.
|
||||
* @param mixed[] $association The association mapping.
|
||||
*/
|
||||
public function __construct(CollectionPersister $persister, Region $region, EntityManagerInterface $em, array $association)
|
||||
{
|
||||
$configuration = $em->getConfiguration();
|
||||
$cacheConfig = $configuration->getSecondLevelCacheConfiguration();
|
||||
$cacheFactory = $cacheConfig->getCacheFactory();
|
||||
$configuration = $em->getConfiguration();
|
||||
$cacheConfig = $configuration->getSecondLevelCacheConfiguration();
|
||||
$cacheFactory = $cacheConfig->getCacheFactory();
|
||||
|
||||
$this->region = $region;
|
||||
$this->persister = $persister;
|
||||
$this->association = $association;
|
||||
$this->regionName = $region->getName();
|
||||
$this->uow = $em->getUnitOfWork();
|
||||
$this->metadataFactory = $em->getMetadataFactory();
|
||||
$this->cacheLogger = $cacheConfig->getCacheLogger();
|
||||
$this->hydrator = $cacheFactory->buildCollectionHydrator($em, $association);
|
||||
$this->sourceEntity = $em->getClassMetadata($association['sourceEntity']);
|
||||
$this->targetEntity = $em->getClassMetadata($association['targetEntity']);
|
||||
$this->region = $region;
|
||||
$this->persister = $persister;
|
||||
$this->association = $association;
|
||||
$this->regionName = $region->getName();
|
||||
$this->uow = $em->getUnitOfWork();
|
||||
$this->metadataFactory = $em->getMetadataFactory();
|
||||
$this->cacheLogger = $cacheConfig->getCacheLogger();
|
||||
$this->hydrator = $cacheFactory->buildCollectionHydrator($em, $association);
|
||||
$this->sourceEntity = $em->getClassMetadata($association['sourceEntity']);
|
||||
$this->targetEntity = $em->getClassMetadata($association['targetEntity']);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,22 +124,17 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\PersistentCollection $collection
|
||||
* @param \Doctrine\ORM\Cache\CollectionCacheKey $key
|
||||
*
|
||||
* @return object[]|null
|
||||
*/
|
||||
public function loadCollectionCache(PersistentCollection $collection, CollectionCacheKey $key)
|
||||
{
|
||||
if (($cache = $this->region->get($key)) === null) {
|
||||
$cache = $this->region->get($key);
|
||||
|
||||
if ($cache === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (($cache = $this->hydrator->loadCacheEntry($this->sourceEntity, $key, $cache, $collection)) === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $cache;
|
||||
return $this->hydrator->loadCacheEntry($this->sourceEntity, $key, $cache, $collection);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,14 +142,14 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
*/
|
||||
public function storeCollectionCache(CollectionCacheKey $key, $elements)
|
||||
{
|
||||
/* @var $targetPersister CachedEntityPersister */
|
||||
$associationMapping = $this->sourceEntity->associationMappings[$key->association];
|
||||
$targetPersister = $this->uow->getEntityPersister($this->targetEntity->rootEntityName);
|
||||
$targetRegion = $targetPersister->getCacheRegion();
|
||||
$targetHydrator = $targetPersister->getEntityHydrator();
|
||||
assert($targetPersister instanceof CachedEntityPersister);
|
||||
$targetRegion = $targetPersister->getCacheRegion();
|
||||
$targetHydrator = $targetPersister->getEntityHydrator();
|
||||
|
||||
// Only preserve ordering if association configured it
|
||||
if ( ! (isset($associationMapping['indexBy']) && $associationMapping['indexBy'])) {
|
||||
if (! (isset($associationMapping['indexBy']) && $associationMapping['indexBy'])) {
|
||||
// Elements may be an array or a Collection
|
||||
$elements = array_values(is_array($elements) ? $elements : $elements->getValues());
|
||||
}
|
||||
@@ -183,15 +161,15 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
continue;
|
||||
}
|
||||
|
||||
$class = $this->targetEntity;
|
||||
$className = ClassUtils::getClass($elements[$index]);
|
||||
$class = $this->targetEntity;
|
||||
$className = ClassUtils::getClass($elements[$index]);
|
||||
|
||||
if ($className !== $this->targetEntity->name) {
|
||||
$class = $this->metadataFactory->getMetadataFor($className);
|
||||
}
|
||||
|
||||
$entity = $elements[$index];
|
||||
$entityEntry = $targetHydrator->buildCacheEntry($class, $entityKey, $entity);
|
||||
$entity = $elements[$index];
|
||||
$entityEntry = $targetHydrator->buildCacheEntry($class, $entityKey, $entity);
|
||||
|
||||
$targetRegion->put($entityKey, $entityEntry);
|
||||
}
|
||||
@@ -261,8 +239,6 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
|
||||
/**
|
||||
* Clears cache entries related to the current collection
|
||||
*
|
||||
* @param PersistentCollection $collection
|
||||
*/
|
||||
protected function evictCollectionCache(PersistentCollection $collection)
|
||||
{
|
||||
@@ -285,10 +261,10 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
*/
|
||||
protected function evictElementCache($targetEntity, $element)
|
||||
{
|
||||
/* @var $targetPersister CachedEntityPersister */
|
||||
$targetPersister = $this->uow->getEntityPersister($targetEntity);
|
||||
$targetRegion = $targetPersister->getCacheRegion();
|
||||
$key = new EntityCacheKey($targetEntity, $this->uow->getEntityIdentifier($element));
|
||||
assert($targetPersister instanceof CachedEntityPersister);
|
||||
$targetRegion = $targetPersister->getCacheRegion();
|
||||
$key = new EntityCacheKey($targetEntity, $this->uow->getEntityIdentifier($element));
|
||||
|
||||
$targetRegion->evict($key);
|
||||
|
||||
|
||||
@@ -20,44 +20,39 @@
|
||||
|
||||
namespace Doctrine\ORM\Cache\Persister\Collection;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Cache\CollectionCacheKey;
|
||||
use Doctrine\ORM\Cache\Persister\CachedPersister;
|
||||
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
|
||||
|
||||
/**
|
||||
* Interface for second level cache collection persisters.
|
||||
*
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
* @since 2.5
|
||||
*/
|
||||
interface CachedCollectionPersister extends CachedPersister, CollectionPersister
|
||||
{
|
||||
/**
|
||||
* @return \Doctrine\ORM\Mapping\ClassMetadata
|
||||
* @return ClassMetadata
|
||||
*/
|
||||
public function getSourceEntityMetadata();
|
||||
|
||||
/**
|
||||
* @return \Doctrine\ORM\Mapping\ClassMetadata
|
||||
* @return ClassMetadata
|
||||
*/
|
||||
public function getTargetEntityMetadata();
|
||||
|
||||
/**
|
||||
* Loads a collection from cache
|
||||
*
|
||||
* @param \Doctrine\ORM\PersistentCollection $collection
|
||||
* @param \Doctrine\ORM\Cache\CollectionCacheKey $key
|
||||
*
|
||||
* @return \Doctrine\ORM\PersistentCollection|null
|
||||
* @return PersistentCollection|null
|
||||
*/
|
||||
public function loadCollectionCache(PersistentCollection $collection, CollectionCacheKey $key);
|
||||
|
||||
/**
|
||||
* Stores a collection into cache
|
||||
*
|
||||
* @param \Doctrine\ORM\Cache\CollectionCacheKey $key
|
||||
* @param array|\Doctrine\Common\Collections\Collection $elements
|
||||
* @param mixed[]|Collection $elements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
@@ -23,10 +23,8 @@ namespace Doctrine\ORM\Cache\Persister\Collection;
|
||||
use Doctrine\ORM\Cache\CollectionCacheKey;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
|
||||
/**
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
* @since 2.5
|
||||
*/
|
||||
use function spl_object_hash;
|
||||
|
||||
class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
{
|
||||
/**
|
||||
@@ -78,7 +76,7 @@ class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPers
|
||||
$isInitialized = $collection->isInitialized();
|
||||
$isDirty = $collection->isDirty();
|
||||
|
||||
if ( ! $isInitialized && ! $isDirty) {
|
||||
if (! $isInitialized && ! $isDirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -98,7 +96,7 @@ class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPers
|
||||
|
||||
$this->queuedCache['update'][spl_object_hash($collection)] = [
|
||||
'key' => $key,
|
||||
'list' => $collection
|
||||
'list' => $collection,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,19 +20,15 @@
|
||||
|
||||
namespace Doctrine\ORM\Cache\Persister\Collection;
|
||||
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Cache\CacheException;
|
||||
use Doctrine\Common\Util\ClassUtils;
|
||||
use Doctrine\ORM\Cache\CacheException;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
|
||||
/**
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
* @since 2.5
|
||||
*/
|
||||
class ReadOnlyCachedCollectionPersister extends NonStrictReadWriteCachedCollectionPersister
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function update(PersistentCollection $collection)
|
||||
{
|
||||
if ($collection->isDirty() && $collection->getSnapshot()) {
|
||||
|
||||
@@ -20,23 +20,21 @@
|
||||
|
||||
namespace Doctrine\ORM\Cache\Persister\Collection;
|
||||
|
||||
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Cache\CollectionCacheKey;
|
||||
use Doctrine\ORM\Cache\ConcurrentRegion;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
|
||||
|
||||
use function spl_object_hash;
|
||||
|
||||
/**
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
* @since 2.5
|
||||
*/
|
||||
class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
{
|
||||
/**
|
||||
* @param \Doctrine\ORM\Persisters\Collection\CollectionPersister $persister The collection persister that will be cached.
|
||||
* @param \Doctrine\ORM\Cache\ConcurrentRegion $region The collection region.
|
||||
* @param \Doctrine\ORM\EntityManagerInterface $em The entity manager.
|
||||
* @param array $association The association mapping.
|
||||
* @param CollectionPersister $persister The collection persister that will be cached.
|
||||
* @param ConcurrentRegion $region The collection region.
|
||||
* @param EntityManagerInterface $em The entity manager.
|
||||
* @param mixed[] $association The association mapping.
|
||||
*/
|
||||
public function __construct(CollectionPersister $persister, ConcurrentRegion $region, EntityManagerInterface $em, array $association)
|
||||
{
|
||||
@@ -100,7 +98,7 @@ class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
|
||||
$this->queuedCache['delete'][spl_object_hash($collection)] = [
|
||||
'key' => $key,
|
||||
'lock' => $lock
|
||||
'lock' => $lock,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -112,7 +110,7 @@ class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
$isInitialized = $collection->isInitialized();
|
||||
$isDirty = $collection->isDirty();
|
||||
|
||||
if ( ! $isInitialized && ! $isDirty) {
|
||||
if (! $isInitialized && ! $isDirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -128,7 +126,7 @@ class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
|
||||
$this->queuedCache['update'][spl_object_hash($collection)] = [
|
||||
'key' => $key,
|
||||
'lock' => $lock
|
||||
'lock' => $lock,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,117 +20,97 @@
|
||||
|
||||
namespace Doctrine\ORM\Cache\Persister\Entity;
|
||||
|
||||
use Doctrine\ORM\Cache;
|
||||
use Doctrine\ORM\Cache\Region;
|
||||
use Doctrine\ORM\Cache\EntityCacheKey;
|
||||
use Doctrine\ORM\Cache\CollectionCacheKey;
|
||||
use Doctrine\ORM\Cache\TimestampCacheKey;
|
||||
use Doctrine\ORM\Cache\QueryCacheKey;
|
||||
use Doctrine\ORM\Cache\Persister\CachedPersister;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
|
||||
use Doctrine\Common\Util\ClassUtils;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\Common\Util\ClassUtils;
|
||||
use Doctrine\ORM\Cache;
|
||||
use Doctrine\ORM\Cache\CollectionCacheKey;
|
||||
use Doctrine\ORM\Cache\EntityCacheKey;
|
||||
use Doctrine\ORM\Cache\EntityHydrator;
|
||||
use Doctrine\ORM\Cache\Logging\CacheLogger;
|
||||
use Doctrine\ORM\Cache\Persister\CachedPersister;
|
||||
use Doctrine\ORM\Cache\QueryCacheKey;
|
||||
use Doctrine\ORM\Cache\Region;
|
||||
use Doctrine\ORM\Cache\TimestampCacheKey;
|
||||
use Doctrine\ORM\Cache\TimestampRegion;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataFactory;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
|
||||
use function assert;
|
||||
use function serialize;
|
||||
use function sha1;
|
||||
|
||||
/**
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
* @since 2.5
|
||||
*/
|
||||
abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
{
|
||||
/**
|
||||
* @var \Doctrine\ORM\UnitOfWork
|
||||
*/
|
||||
/** @var UnitOfWork */
|
||||
protected $uow;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Mapping\ClassMetadataFactory
|
||||
*/
|
||||
/** @var ClassMetadataFactory */
|
||||
protected $metadataFactory;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Persisters\Entity\EntityPersister
|
||||
*/
|
||||
/** @var EntityPersister */
|
||||
protected $persister;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Mapping\ClassMetadata
|
||||
*/
|
||||
/** @var ClassMetadata */
|
||||
protected $class;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var mixed[] */
|
||||
protected $queuedCache = [];
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache\Region
|
||||
*/
|
||||
/** @var Region */
|
||||
protected $region;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache\TimestampRegion
|
||||
*/
|
||||
/** @var TimestampRegion */
|
||||
protected $timestampRegion;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache\TimestampCacheKey
|
||||
*/
|
||||
/** @var TimestampCacheKey */
|
||||
protected $timestampKey;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache\EntityHydrator
|
||||
*/
|
||||
/** @var EntityHydrator */
|
||||
protected $hydrator;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache
|
||||
*/
|
||||
/** @var Cache */
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache\Logging\CacheLogger
|
||||
*/
|
||||
/** @var CacheLogger */
|
||||
protected $cacheLogger;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $regionName;
|
||||
|
||||
/**
|
||||
* Associations configured as FETCH_EAGER, as well as all inverse one-to-one associations.
|
||||
*
|
||||
* @var array|null
|
||||
* @var array<string>|null
|
||||
*/
|
||||
protected $joinedAssociations;
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\Persisters\Entity\EntityPersister $persister The entity persister to cache.
|
||||
* @param \Doctrine\ORM\Cache\Region $region The entity cache region.
|
||||
* @param \Doctrine\ORM\EntityManagerInterface $em The entity manager.
|
||||
* @param \Doctrine\ORM\Mapping\ClassMetadata $class The entity metadata.
|
||||
* @param EntityPersister $persister The entity persister to cache.
|
||||
* @param Region $region The entity cache region.
|
||||
* @param EntityManagerInterface $em The entity manager.
|
||||
* @param ClassMetadata $class The entity metadata.
|
||||
*/
|
||||
public function __construct(EntityPersister $persister, Region $region, EntityManagerInterface $em, ClassMetadata $class)
|
||||
{
|
||||
$configuration = $em->getConfiguration();
|
||||
$cacheConfig = $configuration->getSecondLevelCacheConfiguration();
|
||||
$cacheFactory = $cacheConfig->getCacheFactory();
|
||||
$configuration = $em->getConfiguration();
|
||||
$cacheConfig = $configuration->getSecondLevelCacheConfiguration();
|
||||
$cacheFactory = $cacheConfig->getCacheFactory();
|
||||
|
||||
$this->class = $class;
|
||||
$this->region = $region;
|
||||
$this->persister = $persister;
|
||||
$this->cache = $em->getCache();
|
||||
$this->regionName = $region->getName();
|
||||
$this->uow = $em->getUnitOfWork();
|
||||
$this->metadataFactory = $em->getMetadataFactory();
|
||||
$this->cacheLogger = $cacheConfig->getCacheLogger();
|
||||
$this->timestampRegion = $cacheFactory->getTimestampRegion();
|
||||
$this->hydrator = $cacheFactory->buildEntityHydrator($em, $class);
|
||||
$this->timestampKey = new TimestampCacheKey($this->class->rootEntityName);
|
||||
$this->class = $class;
|
||||
$this->region = $region;
|
||||
$this->persister = $persister;
|
||||
$this->cache = $em->getCache();
|
||||
$this->regionName = $region->getName();
|
||||
$this->uow = $em->getUnitOfWork();
|
||||
$this->metadataFactory = $em->getMetadataFactory();
|
||||
$this->cacheLogger = $cacheConfig->getCacheLogger();
|
||||
$this->timestampRegion = $cacheFactory->getTimestampRegion();
|
||||
$this->hydrator = $cacheFactory->buildEntityHydrator($em, $class);
|
||||
$this->timestampKey = new TimestampCacheKey($this->class->rootEntityName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,7 +132,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSelectSQL($criteria, $assoc = null, $lockMode = null, $limit = null, $offset = null, array $orderBy = null)
|
||||
public function getSelectSQL($criteria, $assoc = null, $lockMode = null, $limit = null, $offset = null, ?array $orderBy = null)
|
||||
{
|
||||
return $this->persister->getSelectSQL($criteria, $assoc, $lockMode, $limit, $offset, $orderBy);
|
||||
}
|
||||
@@ -192,9 +172,9 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function exists($entity, Criteria $extraConditions = null)
|
||||
public function exists($entity, ?Criteria $extraConditions = null)
|
||||
{
|
||||
if (null === $extraConditions) {
|
||||
if ($extraConditions === null) {
|
||||
$key = new EntityCacheKey($this->class->rootEntityName, $this->class->getIdentifierValues($entity));
|
||||
|
||||
if ($this->region->contains($key)) {
|
||||
@@ -214,7 +194,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Doctrine\ORM\Cache\EntityHydrator
|
||||
* @return EntityHydrator
|
||||
*/
|
||||
public function getEntityHydrator()
|
||||
{
|
||||
@@ -226,8 +206,8 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
*/
|
||||
public function storeEntityCache($entity, EntityCacheKey $key)
|
||||
{
|
||||
$class = $this->class;
|
||||
$className = ClassUtils::getClass($entity);
|
||||
$class = $this->class;
|
||||
$className = ClassUtils::getClass($entity);
|
||||
|
||||
if ($className !== $this->class->name) {
|
||||
$class = $this->metadataFactory->getMetadataFor($className);
|
||||
@@ -252,10 +232,11 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
$associations = [];
|
||||
|
||||
foreach ($this->class->associationMappings as $name => $assoc) {
|
||||
if (isset($assoc['cache']) &&
|
||||
if (
|
||||
isset($assoc['cache']) &&
|
||||
($assoc['type'] & ClassMetadata::TO_ONE) &&
|
||||
($assoc['fetch'] === ClassMetadata::FETCH_EAGER || ! $assoc['isOwningSide'])) {
|
||||
|
||||
($assoc['fetch'] === ClassMetadata::FETCH_EAGER || ! $assoc['isOwningSide'])
|
||||
) {
|
||||
$associations[] = $name;
|
||||
}
|
||||
}
|
||||
@@ -291,7 +272,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getHash($query, $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
protected function getHash($query, $criteria, ?array $orderBy = null, $limit = null, $offset = null)
|
||||
{
|
||||
[$params] = $criteria instanceof Criteria
|
||||
? $this->persister->expandCriteriaParameters($criteria)
|
||||
@@ -361,7 +342,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load(array $criteria, $entity = null, $assoc = null, array $hints = [], $lockMode = null, $limit = null, array $orderBy = null)
|
||||
public function load(array $criteria, $entity = null, $assoc = null, array $hints = [], $lockMode = null, $limit = null, ?array $orderBy = null)
|
||||
{
|
||||
if ($entity !== null || $assoc !== null || ! empty($hints) || $lockMode !== null) {
|
||||
return $this->persister->load($criteria, $entity, $assoc, $hints, $lockMode, $limit, $orderBy);
|
||||
@@ -383,7 +364,9 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
return $result[0];
|
||||
}
|
||||
|
||||
if (($result = $this->persister->load($criteria, $entity, $assoc, $hints, $lockMode, $limit, $orderBy)) === null) {
|
||||
$result = $this->persister->load($criteria, $entity, $assoc, $hints, $lockMode, $limit, $orderBy);
|
||||
|
||||
if ($result === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -405,7 +388,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadAll(array $criteria = [], array $orderBy = null, $limit = null, $offset = null)
|
||||
public function loadAll(array $criteria = [], ?array $orderBy = null, $limit = null, $offset = null)
|
||||
{
|
||||
$query = $this->persister->getSelectSQL($criteria, null, null, $limit, $offset, $orderBy);
|
||||
$hash = $this->getHash($query, $criteria, null, null, null);
|
||||
@@ -469,8 +452,8 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
return null;
|
||||
}
|
||||
|
||||
$class = $this->class;
|
||||
$className = ClassUtils::getClass($entity);
|
||||
$class = $this->class;
|
||||
$className = ClassUtils::getClass($entity);
|
||||
|
||||
if ($className !== $this->class->name) {
|
||||
$class = $this->metadataFactory->getMetadataFor($className);
|
||||
@@ -479,7 +462,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
$cacheEntry = $this->hydrator->buildCacheEntry($class, $cacheKey, $entity);
|
||||
$cached = $this->region->put($cacheKey, $cacheEntry);
|
||||
|
||||
if ($cached && (null === $this->joinedAssociations || $this->joinedAssociations)) {
|
||||
if ($cached && ($this->joinedAssociations === null || $this->joinedAssociations)) {
|
||||
$this->storeJoinedAssociations($entity);
|
||||
}
|
||||
|
||||
@@ -549,7 +532,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
$persister = $this->uow->getCollectionPersister($assoc);
|
||||
$hasCache = ($persister instanceof CachedPersister);
|
||||
|
||||
if ( ! $hasCache) {
|
||||
if (! $hasCache) {
|
||||
return $this->persister->loadManyToManyCollection($assoc, $sourceEntity, $collection);
|
||||
}
|
||||
|
||||
@@ -584,7 +567,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
$persister = $this->uow->getCollectionPersister($assoc);
|
||||
$hasCache = ($persister instanceof CachedPersister);
|
||||
|
||||
if ( ! $hasCache) {
|
||||
if (! $hasCache) {
|
||||
return $this->persister->loadOneToManyCollection($assoc, $sourceEntity, $collection);
|
||||
}
|
||||
|
||||
@@ -636,15 +619,15 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $association
|
||||
* @param array $ownerId
|
||||
* @param array<string, mixed> $association
|
||||
* @param array<string, mixed> $ownerId
|
||||
*
|
||||
* @return CollectionCacheKey
|
||||
*/
|
||||
protected function buildCollectionCacheKey(array $association, $ownerId)
|
||||
{
|
||||
/** @var ClassMetadata $metadata */
|
||||
$metadata = $this->metadataFactory->getMetadataFor($association['sourceEntity']);
|
||||
assert($metadata instanceof ClassMetadata);
|
||||
|
||||
return new CollectionCacheKey($metadata->rootEntityName, $association['fieldName'], $ownerId);
|
||||
}
|
||||
|
||||
@@ -21,27 +21,24 @@
|
||||
namespace Doctrine\ORM\Cache\Persister\Entity;
|
||||
|
||||
use Doctrine\ORM\Cache\EntityCacheKey;
|
||||
use Doctrine\ORM\Cache\EntityHydrator;
|
||||
use Doctrine\ORM\Cache\Persister\CachedPersister;
|
||||
use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
|
||||
/**
|
||||
* Interface for second level cache entity persisters.
|
||||
*
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
* @since 2.5
|
||||
*/
|
||||
interface CachedEntityPersister extends CachedPersister, EntityPersister
|
||||
{
|
||||
/**
|
||||
* @return \Doctrine\ORM\Cache\EntityHydrator
|
||||
* @return EntityHydrator
|
||||
*/
|
||||
public function getEntityHydrator();
|
||||
|
||||
/**
|
||||
* @param object $entity
|
||||
* @param \Doctrine\ORM\Cache\EntityCacheKey $key
|
||||
* @param object $entity
|
||||
*
|
||||
* @return boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function storeEntityCache($entity, EntityCacheKey $key);
|
||||
}
|
||||
|
||||
@@ -22,12 +22,10 @@ namespace Doctrine\ORM\Cache\Persister\Entity;
|
||||
|
||||
use Doctrine\ORM\Cache\EntityCacheKey;
|
||||
|
||||
use function get_class;
|
||||
|
||||
/**
|
||||
* Specific non-strict read/write cached entity persister
|
||||
*
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @since 2.5
|
||||
*/
|
||||
class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
{
|
||||
@@ -108,11 +106,11 @@ class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
*/
|
||||
private function updateCache($entity, $isChanged)
|
||||
{
|
||||
$class = $this->metadataFactory->getMetadataFor(get_class($entity));
|
||||
$key = new EntityCacheKey($class->rootEntityName, $this->uow->getEntityIdentifier($entity));
|
||||
$entry = $this->hydrator->buildCacheEntry($class, $key, $entity);
|
||||
$cached = $this->region->put($key, $entry);
|
||||
$isChanged = $isChanged ?: $cached;
|
||||
$class = $this->metadataFactory->getMetadataFor(get_class($entity));
|
||||
$key = new EntityCacheKey($class->rootEntityName, $this->uow->getEntityIdentifier($entity));
|
||||
$entry = $this->hydrator->buildCacheEntry($class, $key, $entity);
|
||||
$cached = $this->region->put($key, $entry);
|
||||
$isChanged = $isChanged ?: $cached;
|
||||
|
||||
if ($this->cacheLogger && $cached) {
|
||||
$this->cacheLogger->entityCachePut($this->regionName, $key);
|
||||
|
||||
@@ -20,14 +20,11 @@
|
||||
|
||||
namespace Doctrine\ORM\Cache\Persister\Entity;
|
||||
|
||||
use Doctrine\ORM\Cache\CacheException;
|
||||
use Doctrine\Common\Util\ClassUtils;
|
||||
use Doctrine\ORM\Cache\CacheException;
|
||||
|
||||
/**
|
||||
* Specific read-only region entity persister
|
||||
*
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
* @since 2.5
|
||||
*/
|
||||
class ReadOnlyCachedEntityPersister extends NonStrictReadWriteCachedEntityPersister
|
||||
{
|
||||
|
||||
@@ -20,26 +20,22 @@
|
||||
|
||||
namespace Doctrine\ORM\Cache\Persister\Entity;
|
||||
|
||||
use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Cache\ConcurrentRegion;
|
||||
use Doctrine\ORM\Cache\EntityCacheKey;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
|
||||
/**
|
||||
* Specific read-write entity persister
|
||||
*
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @since 2.5
|
||||
*/
|
||||
class ReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
{
|
||||
/**
|
||||
* @param \Doctrine\ORM\Persisters\Entity\EntityPersister $persister The entity persister to cache.
|
||||
* @param \Doctrine\ORM\Cache\ConcurrentRegion $region The entity cache region.
|
||||
* @param \Doctrine\ORM\EntityManagerInterface $em The entity manager.
|
||||
* @param \Doctrine\ORM\Mapping\ClassMetadata $class The entity metadata.
|
||||
* @param EntityPersister $persister The entity persister to cache.
|
||||
* @param ConcurrentRegion $region The entity cache region.
|
||||
* @param EntityManagerInterface $em The entity manager.
|
||||
* @param ClassMetadata $class The entity metadata.
|
||||
*/
|
||||
public function __construct(EntityPersister $persister, ConcurrentRegion $region, EntityManagerInterface $em, ClassMetadata $class)
|
||||
{
|
||||
@@ -115,7 +111,7 @@ class ReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
|
||||
$this->queuedCache['delete'][] = [
|
||||
'lock' => $lock,
|
||||
'key' => $key
|
||||
'key' => $key,
|
||||
];
|
||||
|
||||
return $deleted;
|
||||
@@ -137,7 +133,7 @@ class ReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
|
||||
$this->queuedCache['update'][] = [
|
||||
'lock' => $lock,
|
||||
'key' => $key
|
||||
'key' => $key,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,38 +25,31 @@ use Doctrine\ORM\Query\ResultSetMapping;
|
||||
/**
|
||||
* Defines the contract for caches capable of storing query results.
|
||||
* These caches should only concern themselves with storing the matching result ids.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
interface QueryCache
|
||||
{
|
||||
/**
|
||||
* @return boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function clear();
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\Cache\QueryCacheKey $key
|
||||
* @param \Doctrine\ORM\Query\ResultSetMapping $rsm
|
||||
* @param mixed $result
|
||||
* @param array $hints
|
||||
* @param mixed $result
|
||||
* @param mixed[] $hints
|
||||
*
|
||||
* @return boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function put(QueryCacheKey $key, ResultSetMapping $rsm, $result, array $hints = []);
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\Cache\QueryCacheKey $key
|
||||
* @param \Doctrine\ORM\Query\ResultSetMapping $rsm
|
||||
* @param array $hints
|
||||
* @param mixed[] $hints
|
||||
*
|
||||
* @return array|null
|
||||
* @return mixed[]|null
|
||||
*/
|
||||
public function get(QueryCacheKey $key, ResultSetMapping $rsm, array $hints = []);
|
||||
|
||||
/**
|
||||
* @return \Doctrine\ORM\Cache\Region
|
||||
* @return Region
|
||||
*/
|
||||
public function getRegion();
|
||||
}
|
||||
|
||||
@@ -20,18 +20,17 @@
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
use function microtime;
|
||||
|
||||
/**
|
||||
* Query cache entry
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class QueryCacheEntry implements CacheEntry
|
||||
{
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
*
|
||||
* @var array List of entity identifiers
|
||||
* @var array<string, mixed> List of entity identifiers
|
||||
*/
|
||||
public $result;
|
||||
|
||||
@@ -43,8 +42,8 @@ class QueryCacheEntry implements CacheEntry
|
||||
public $time;
|
||||
|
||||
/**
|
||||
* @param array $result
|
||||
* @param float $time
|
||||
* @param array<string, mixed> $result
|
||||
* @param float $time
|
||||
*/
|
||||
public function __construct($result, $time = null)
|
||||
{
|
||||
@@ -53,7 +52,7 @@ class QueryCacheEntry implements CacheEntry
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $values
|
||||
* @param array<string, mixed> $values
|
||||
*
|
||||
* @return QueryCacheEntry
|
||||
*/
|
||||
|
||||
@@ -24,23 +24,20 @@ use Doctrine\ORM\Cache;
|
||||
|
||||
/**
|
||||
* A cache key that identifies a particular query.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class QueryCacheKey extends CacheKey
|
||||
{
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
*
|
||||
* @var integer Cache key lifetime
|
||||
* @var int Cache key lifetime
|
||||
*/
|
||||
public $lifetime;
|
||||
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
*
|
||||
* @var integer Cache mode (Doctrine\ORM\Cache::MODE_*)
|
||||
* @var int Cache mode (Doctrine\ORM\Cache::MODE_*)
|
||||
*/
|
||||
public $cacheMode;
|
||||
|
||||
@@ -52,16 +49,15 @@ class QueryCacheKey extends CacheKey
|
||||
public $timestampKey;
|
||||
|
||||
/**
|
||||
* @param string $hash Result cache id
|
||||
* @param integer $lifetime Query lifetime
|
||||
* @param int $cacheMode Query cache mode
|
||||
* @param TimestampCacheKey|null $timestampKey
|
||||
* @param string $hash Result cache id
|
||||
* @param int $lifetime Query lifetime
|
||||
* @param int $cacheMode Query cache mode
|
||||
*/
|
||||
public function __construct(
|
||||
$hash,
|
||||
$lifetime = 0,
|
||||
$cacheMode = Cache::MODE_NORMAL,
|
||||
TimestampCacheKey $timestampKey = null
|
||||
?TimestampCacheKey $timestampKey = null
|
||||
) {
|
||||
$this->hash = $hash;
|
||||
$this->lifetime = $lifetime;
|
||||
|
||||
@@ -22,19 +22,13 @@ namespace Doctrine\ORM\Cache;
|
||||
|
||||
/**
|
||||
* Cache query validator interface.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
interface QueryCacheValidator
|
||||
{
|
||||
/**
|
||||
* Checks if the query entry is valid
|
||||
*
|
||||
* @param \Doctrine\ORM\Cache\QueryCacheKey $key
|
||||
* @param \Doctrine\ORM\Cache\QueryCacheEntry $entry
|
||||
*
|
||||
* @return boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid(QueryCacheKey $key, QueryCacheEntry $entry);
|
||||
}
|
||||
|
||||
@@ -22,9 +22,6 @@ namespace Doctrine\ORM\Cache;
|
||||
|
||||
/**
|
||||
* Defines a contract for accessing a particular named region.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
interface Region extends MultiGetRegion
|
||||
{
|
||||
@@ -38,47 +35,47 @@ interface Region extends MultiGetRegion
|
||||
/**
|
||||
* Determine whether this region contains data for the given key.
|
||||
*
|
||||
* @param \Doctrine\ORM\Cache\CacheKey $key The cache key
|
||||
* @param CacheKey $key The cache key
|
||||
*
|
||||
* @return boolean TRUE if the underlying cache contains corresponding data; FALSE otherwise.
|
||||
* @return bool TRUE if the underlying cache contains corresponding data; FALSE otherwise.
|
||||
*/
|
||||
public function contains(CacheKey $key);
|
||||
|
||||
/**
|
||||
* Get an item from the cache.
|
||||
*
|
||||
* @param \Doctrine\ORM\Cache\CacheKey $key The key of the item to be retrieved.
|
||||
* @param CacheKey $key The key of the item to be retrieved.
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache\CacheEntry|null The cached entry or NULL
|
||||
* @return CacheEntry|null The cached entry or NULL
|
||||
*
|
||||
* @throws \Doctrine\ORM\Cache\CacheException Indicates a problem accessing the item or region.
|
||||
* @throws CacheException Indicates a problem accessing the item or region.
|
||||
*/
|
||||
public function get(CacheKey $key);
|
||||
|
||||
/**
|
||||
* Put an item into the cache.
|
||||
*
|
||||
* @param \Doctrine\ORM\Cache\CacheKey $key The key under which to cache the item.
|
||||
* @param \Doctrine\ORM\Cache\CacheEntry $entry The entry to cache.
|
||||
* @param \Doctrine\ORM\Cache\Lock $lock The lock previously obtained.
|
||||
* @param CacheKey $key The key under which to cache the item.
|
||||
* @param CacheEntry $entry The entry to cache.
|
||||
* @param Lock $lock The lock previously obtained.
|
||||
*
|
||||
* @throws \Doctrine\ORM\Cache\CacheException Indicates a problem accessing the region.
|
||||
* @throws CacheException Indicates a problem accessing the region.
|
||||
*/
|
||||
public function put(CacheKey $key, CacheEntry $entry, Lock $lock = null);
|
||||
public function put(CacheKey $key, CacheEntry $entry, ?Lock $lock = null);
|
||||
|
||||
/**
|
||||
* Remove an item from the cache.
|
||||
*
|
||||
* @param \Doctrine\ORM\Cache\CacheKey $key The key under which to cache the item.
|
||||
* @param CacheKey $key The key under which to cache the item.
|
||||
*
|
||||
* @throws \Doctrine\ORM\Cache\CacheException Indicates a problem accessing the region.
|
||||
* @throws CacheException Indicates a problem accessing the region.
|
||||
*/
|
||||
public function evict(CacheKey $key);
|
||||
|
||||
/**
|
||||
* Remove all contents of this particular cache region.
|
||||
*
|
||||
* @throws \Doctrine\ORM\Cache\CacheException Indicates problem accessing the region.
|
||||
* @throws CacheException Indicates problem accessing the region.
|
||||
*/
|
||||
public function evictAll();
|
||||
}
|
||||
|
||||
@@ -20,15 +20,16 @@
|
||||
|
||||
namespace Doctrine\ORM\Cache\Region;
|
||||
|
||||
use Doctrine\Common\Cache\Cache;
|
||||
use Doctrine\Common\Cache\MultiGetCache;
|
||||
use Doctrine\ORM\Cache\CacheEntry;
|
||||
use Doctrine\ORM\Cache\CollectionCacheEntry;
|
||||
|
||||
use function assert;
|
||||
use function count;
|
||||
|
||||
/**
|
||||
* A cache region that enables the retrieval of multiple elements with one call
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Asmir Mustafic <goetas@gmail.com>
|
||||
*/
|
||||
class DefaultMultiGetRegion extends DefaultRegion
|
||||
{
|
||||
@@ -36,7 +37,7 @@ class DefaultMultiGetRegion extends DefaultRegion
|
||||
* Note that the multiple type is due to doctrine/cache not integrating the MultiGetCache interface
|
||||
* in its signature due to BC in 1.x
|
||||
*
|
||||
* @var MultiGetCache|\Doctrine\Common\Cache\Cache
|
||||
* @var MultiGetCache|Cache
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
@@ -47,7 +48,7 @@ class DefaultMultiGetRegion extends DefaultRegion
|
||||
*/
|
||||
public function __construct($name, MultiGetCache $cache, $lifetime = 0)
|
||||
{
|
||||
/* @var $cache \Doctrine\Common\Cache\Cache */
|
||||
assert($cache instanceof Cache);
|
||||
parent::__construct($name, $cache, $lifetime);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
|
||||
namespace Doctrine\ORM\Cache\Region;
|
||||
|
||||
use BadMethodCallException;
|
||||
use Doctrine\Common\Cache\Cache as CacheAdapter;
|
||||
use Doctrine\Common\Cache\CacheProvider;
|
||||
use Doctrine\Common\Cache\ClearableCache;
|
||||
use Doctrine\ORM\Cache\CacheEntry;
|
||||
use Doctrine\ORM\Cache\CacheKey;
|
||||
@@ -28,41 +30,34 @@ use Doctrine\ORM\Cache\CollectionCacheEntry;
|
||||
use Doctrine\ORM\Cache\Lock;
|
||||
use Doctrine\ORM\Cache\Region;
|
||||
|
||||
use function get_class;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* The simplest cache region compatible with all doctrine-cache drivers.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class DefaultRegion implements Region
|
||||
{
|
||||
const REGION_KEY_SEPARATOR = '_';
|
||||
public const REGION_KEY_SEPARATOR = '_';
|
||||
|
||||
/**
|
||||
* @var CacheAdapter
|
||||
*/
|
||||
/** @var CacheAdapter */
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
/** @var int */
|
||||
protected $lifetime = 0;
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param CacheAdapter $cache
|
||||
* @param integer $lifetime
|
||||
* @param string $name
|
||||
* @param int $lifetime
|
||||
*/
|
||||
public function __construct($name, CacheAdapter $cache, $lifetime = 0)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
$this->name = (string) $name;
|
||||
$this->lifetime = (integer) $lifetime;
|
||||
$this->lifetime = (int) $lifetime;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,7 +69,7 @@ class DefaultRegion implements Region
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Doctrine\Common\Cache\CacheProvider
|
||||
* @return CacheProvider
|
||||
*/
|
||||
public function getCache()
|
||||
{
|
||||
@@ -125,7 +120,6 @@ class DefaultRegion implements Region
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CacheKey $key
|
||||
* @return string
|
||||
*/
|
||||
protected function getCacheEntryKey(CacheKey $key)
|
||||
@@ -136,7 +130,7 @@ class DefaultRegion implements Region
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function put(CacheKey $key, CacheEntry $entry, Lock $lock = null)
|
||||
public function put(CacheKey $key, CacheEntry $entry, ?Lock $lock = null)
|
||||
{
|
||||
return $this->cache->save($this->getCacheEntryKey($key), $entry, $this->lifetime);
|
||||
}
|
||||
@@ -155,7 +149,7 @@ class DefaultRegion implements Region
|
||||
public function evictAll()
|
||||
{
|
||||
if (! $this->cache instanceof ClearableCache) {
|
||||
throw new \BadMethodCallException(sprintf(
|
||||
throw new BadMethodCallException(sprintf(
|
||||
'Clearing all cache entries is not supported by the supplied cache adapter of type %s',
|
||||
get_class($this->cache)
|
||||
));
|
||||
|
||||
@@ -20,53 +20,62 @@
|
||||
|
||||
namespace Doctrine\ORM\Cache\Region;
|
||||
|
||||
use Doctrine\ORM\Cache\CacheEntry;
|
||||
use Doctrine\ORM\Cache\CacheKey;
|
||||
use Doctrine\ORM\Cache\CollectionCacheEntry;
|
||||
use Doctrine\ORM\Cache\ConcurrentRegion;
|
||||
use Doctrine\ORM\Cache\Lock;
|
||||
use Doctrine\ORM\Cache\Region;
|
||||
use Doctrine\ORM\Cache\CacheKey;
|
||||
use Doctrine\ORM\Cache\CacheEntry;
|
||||
use Doctrine\ORM\Cache\ConcurrentRegion;
|
||||
use InvalidArgumentException;
|
||||
|
||||
use function array_filter;
|
||||
use function array_map;
|
||||
use function chmod;
|
||||
use function file_get_contents;
|
||||
use function file_put_contents;
|
||||
use function fileatime;
|
||||
use function glob;
|
||||
use function is_dir;
|
||||
use function is_file;
|
||||
use function is_writable;
|
||||
use function mkdir;
|
||||
use function sprintf;
|
||||
use function time;
|
||||
use function unlink;
|
||||
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const LOCK_EX;
|
||||
|
||||
/**
|
||||
* Very naive concurrent region, based on file locks.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silvagmail.com>
|
||||
*/
|
||||
class FileLockRegion implements ConcurrentRegion
|
||||
{
|
||||
const LOCK_EXTENSION = 'lock';
|
||||
public const LOCK_EXTENSION = 'lock';
|
||||
|
||||
/**
|
||||
* var \Doctrine\ORM\Cache\Region
|
||||
*/
|
||||
/** @var Region */
|
||||
private $region;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
private $directory;
|
||||
|
||||
/**
|
||||
* var integer
|
||||
*/
|
||||
/** @var int */
|
||||
private $lockLifetime;
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\Cache\Region $region
|
||||
* @param string $directory
|
||||
* @param string $lockLifetime
|
||||
* @param string $directory
|
||||
* @param string $lockLifetime
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __construct(Region $region, $directory, $lockLifetime)
|
||||
{
|
||||
if ( ! is_dir($directory) && ! @mkdir($directory, 0775, true)) {
|
||||
throw new \InvalidArgumentException(sprintf('The directory "%s" does not exist and could not be created.', $directory));
|
||||
if (! is_dir($directory) && ! @mkdir($directory, 0775, true)) {
|
||||
throw new InvalidArgumentException(sprintf('The directory "%s" does not exist and could not be created.', $directory));
|
||||
}
|
||||
|
||||
if ( ! is_writable($directory)) {
|
||||
throw new \InvalidArgumentException(sprintf('The directory "%s" is not writable.', $directory));
|
||||
if (! is_writable($directory)) {
|
||||
throw new InvalidArgumentException(sprintf('The directory "%s" is not writable.', $directory));
|
||||
}
|
||||
|
||||
$this->region = $region;
|
||||
@@ -75,23 +84,20 @@ class FileLockRegion implements ConcurrentRegion
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\Cache\CacheKey $key
|
||||
* @param \Doctrine\ORM\Cache\Lock $lock
|
||||
*
|
||||
* @return boolean
|
||||
* @return bool
|
||||
*/
|
||||
private function isLocked(CacheKey $key, Lock $lock = null)
|
||||
private function isLocked(CacheKey $key, ?Lock $lock = null)
|
||||
{
|
||||
$filename = $this->getLockFileName($key);
|
||||
|
||||
if ( ! is_file($filename)) {
|
||||
if (! is_file($filename)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$time = $this->getLockTime($filename);
|
||||
$content = $this->getLockContent($filename);
|
||||
$time = $this->getLockTime($filename);
|
||||
$content = $this->getLockContent($filename);
|
||||
|
||||
if ( ! $content || ! $time) {
|
||||
if (! $content || ! $time) {
|
||||
@unlink($filename);
|
||||
|
||||
return false;
|
||||
@@ -102,7 +108,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
}
|
||||
|
||||
// outdated lock
|
||||
if (($time + $this->lockLifetime) <= time()) {
|
||||
if ($time + $this->lockLifetime <= time()) {
|
||||
@unlink($filename);
|
||||
|
||||
return false;
|
||||
@@ -112,8 +118,6 @@ class FileLockRegion implements ConcurrentRegion
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\Cache\CacheKey $key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getLockFileName(CacheKey $key)
|
||||
@@ -134,7 +138,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
/**
|
||||
* @param string $filename
|
||||
*
|
||||
* @return integer
|
||||
* @return int
|
||||
*/
|
||||
private function getLockTime($filename)
|
||||
{
|
||||
@@ -188,7 +192,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function put(CacheKey $key, CacheEntry $entry, Lock $lock = null)
|
||||
public function put(CacheKey $key, CacheEntry $entry, ?Lock $lock = null)
|
||||
{
|
||||
if ($this->isLocked($key, $lock)) {
|
||||
return false;
|
||||
@@ -216,7 +220,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
{
|
||||
// The check below is necessary because on some platforms glob returns false
|
||||
// when nothing matched (even though no errors occurred)
|
||||
$filenames = glob(sprintf("%s/*.%s" , $this->directory, self::LOCK_EXTENSION));
|
||||
$filenames = glob(sprintf('%s/*.%s', $this->directory, self::LOCK_EXTENSION));
|
||||
|
||||
if ($filenames) {
|
||||
foreach ($filenames as $filename) {
|
||||
@@ -239,9 +243,10 @@ class FileLockRegion implements ConcurrentRegion
|
||||
$lock = Lock::createLockRead();
|
||||
$filename = $this->getLockFileName($key);
|
||||
|
||||
if ( ! @file_put_contents($filename, $lock->value, LOCK_EX)) {
|
||||
if (! @file_put_contents($filename, $lock->value, LOCK_EX)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
chmod($filename, 0664);
|
||||
|
||||
return $lock;
|
||||
@@ -258,10 +263,6 @@ class FileLockRegion implements ConcurrentRegion
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! @unlink($this->getLockFileName($key))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return @unlink($this->getLockFileName($key));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,15 +20,12 @@
|
||||
|
||||
namespace Doctrine\ORM\Cache\Region;
|
||||
|
||||
use Doctrine\ORM\Cache\CacheKey;
|
||||
use Doctrine\ORM\Cache\TimestampCacheEntry;
|
||||
use Doctrine\ORM\Cache\TimestampRegion;
|
||||
use Doctrine\ORM\Cache\CacheKey;
|
||||
|
||||
/**
|
||||
* Tracks the timestamps of the most recent updates to particular keys.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class UpdateTimestampCache extends DefaultRegion implements TimestampRegion
|
||||
{
|
||||
@@ -37,6 +34,6 @@ class UpdateTimestampCache extends DefaultRegion implements TimestampRegion
|
||||
*/
|
||||
public function update(CacheKey $key)
|
||||
{
|
||||
$this->put($key, new TimestampCacheEntry);
|
||||
$this->put($key, new TimestampCacheEntry());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,44 +22,33 @@ namespace Doctrine\ORM\Cache;
|
||||
|
||||
/**
|
||||
* Cache regions configuration
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class RegionsConfiguration
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var array<string,int> */
|
||||
private $lifetimes = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var array<string,int> */
|
||||
private $lockLifetimes = [];
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
/** @var int */
|
||||
private $defaultLifetime;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
/** @var int */
|
||||
private $defaultLockLifetime;
|
||||
|
||||
/**
|
||||
* @param integer $defaultLifetime
|
||||
* @param integer $defaultLockLifetime
|
||||
* @param int $defaultLifetime
|
||||
* @param int $defaultLockLifetime
|
||||
*/
|
||||
public function __construct($defaultLifetime = 3600, $defaultLockLifetime = 60)
|
||||
{
|
||||
$this->defaultLifetime = (integer) $defaultLifetime;
|
||||
$this->defaultLockLifetime = (integer) $defaultLockLifetime;
|
||||
$this->defaultLifetime = (int) $defaultLifetime;
|
||||
$this->defaultLockLifetime = (int) $defaultLockLifetime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
* @return int
|
||||
*/
|
||||
public function getDefaultLifetime()
|
||||
{
|
||||
@@ -67,15 +56,15 @@ class RegionsConfiguration
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $defaultLifetime
|
||||
* @param int $defaultLifetime
|
||||
*/
|
||||
public function setDefaultLifetime($defaultLifetime)
|
||||
{
|
||||
$this->defaultLifetime = (integer) $defaultLifetime;
|
||||
$this->defaultLifetime = (int) $defaultLifetime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
* @return int
|
||||
*/
|
||||
public function getDefaultLockLifetime()
|
||||
{
|
||||
@@ -83,52 +72,48 @@ class RegionsConfiguration
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $defaultLockLifetime
|
||||
* @param int $defaultLockLifetime
|
||||
*/
|
||||
public function setDefaultLockLifetime($defaultLockLifetime)
|
||||
{
|
||||
$this->defaultLockLifetime = (integer) $defaultLockLifetime;
|
||||
$this->defaultLockLifetime = (int) $defaultLockLifetime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $regionName
|
||||
*
|
||||
* @return integer
|
||||
* @return int
|
||||
*/
|
||||
public function getLifetime($regionName)
|
||||
{
|
||||
return isset($this->lifetimes[$regionName])
|
||||
? $this->lifetimes[$regionName]
|
||||
: $this->defaultLifetime;
|
||||
return $this->lifetimes[$regionName] ?? $this->defaultLifetime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param integer $lifetime
|
||||
* @param string $name
|
||||
* @param int $lifetime
|
||||
*/
|
||||
public function setLifetime($name, $lifetime)
|
||||
{
|
||||
$this->lifetimes[$name] = (integer) $lifetime;
|
||||
$this->lifetimes[$name] = (int) $lifetime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $regionName
|
||||
*
|
||||
* @return integer
|
||||
* @return int
|
||||
*/
|
||||
public function getLockLifetime($regionName)
|
||||
{
|
||||
return isset($this->lockLifetimes[$regionName])
|
||||
? $this->lockLifetimes[$regionName]
|
||||
: $this->defaultLockLifetime;
|
||||
return $this->lockLifetimes[$regionName] ?? $this->defaultLockLifetime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param integer $lifetime
|
||||
* @param string $name
|
||||
* @param int $lifetime
|
||||
*/
|
||||
public function setLockLifetime($name, $lifetime)
|
||||
{
|
||||
$this->lockLifetimes[$name] = (integer) $lifetime;
|
||||
$this->lockLifetimes[$name] = (int) $lifetime;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,10 @@
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
use function microtime;
|
||||
|
||||
/**
|
||||
* Timestamp cache entry
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class TimestampCacheEntry implements CacheEntry
|
||||
{
|
||||
@@ -48,7 +47,7 @@ class TimestampCacheEntry implements CacheEntry
|
||||
*
|
||||
* This method allow Doctrine\Common\Cache\PhpFileCache compatibility
|
||||
*
|
||||
* @param array $values array containing property values
|
||||
* @param array<string,float> $values array containing property values
|
||||
*
|
||||
* @return TimestampCacheEntry
|
||||
*/
|
||||
|
||||
@@ -22,9 +22,6 @@ namespace Doctrine\ORM\Cache;
|
||||
|
||||
/**
|
||||
* A key that identifies a timestamped space.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class TimestampCacheKey extends CacheKey
|
||||
{
|
||||
|
||||
@@ -20,20 +20,13 @@
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
/**
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
use function microtime;
|
||||
|
||||
class TimestampQueryCacheValidator implements QueryCacheValidator
|
||||
{
|
||||
/**
|
||||
* @var TimestampRegion
|
||||
*/
|
||||
/** @var TimestampRegion */
|
||||
private $timestampRegion;
|
||||
|
||||
/**
|
||||
* @param TimestampRegion $timestampRegion
|
||||
*/
|
||||
public function __construct(TimestampRegion $timestampRegion)
|
||||
{
|
||||
$this->timestampRegion = $timestampRegion;
|
||||
@@ -48,17 +41,14 @@ class TimestampQueryCacheValidator implements QueryCacheValidator
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($key->lifetime == 0) {
|
||||
if ($key->lifetime === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return ($entry->time + $key->lifetime) > microtime(true);
|
||||
return $entry->time + $key->lifetime > microtime(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param QueryCacheKey $key
|
||||
* @param QueryCacheEntry $entry
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function regionUpdated(QueryCacheKey $key, QueryCacheEntry $entry)
|
||||
|
||||
@@ -22,18 +22,15 @@ namespace Doctrine\ORM\Cache;
|
||||
|
||||
/**
|
||||
* Defines the contract for a cache region which will specifically be used to store entity "update timestamps".
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
interface TimestampRegion extends Region
|
||||
{
|
||||
/**
|
||||
* Update an specific key into the cache region.
|
||||
*
|
||||
* @param \Doctrine\ORM\Cache\CacheKey $key The key of the item to update the timestamp.
|
||||
* @param CacheKey $key The key of the item to update the timestamp.
|
||||
*
|
||||
* @throws \Doctrine\ORM\Cache\LockException Indicates a problem accessing the region.
|
||||
* @throws LockException Indicates a problem accessing the region.
|
||||
*/
|
||||
public function update(CacheKey $key);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -39,19 +40,16 @@ use Doctrine\ORM\Repository\DefaultRepositoryFactory;
|
||||
use Doctrine\ORM\Repository\RepositoryFactory;
|
||||
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
use function interface_exists;
|
||||
use ReflectionClass;
|
||||
|
||||
use function strtolower;
|
||||
use function trim;
|
||||
|
||||
/**
|
||||
* Configuration container for all configuration options of Doctrine.
|
||||
* It combines all configuration options from DBAL & ORM.
|
||||
*
|
||||
* Internal note: When adding a new configuration option just write a getter/setter pair.
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class Configuration extends \Doctrine\DBAL\Configuration
|
||||
{
|
||||
@@ -70,38 +68,36 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Gets the directory where Doctrine generates any necessary proxy class files.
|
||||
*
|
||||
* @return string|null
|
||||
*
|
||||
* @deprecated 2.7 We're switch to `ocramius/proxy-manager` and this method isn't applicable any longer
|
||||
*
|
||||
* @see https://github.com/Ocramius/ProxyManager
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getProxyDir()
|
||||
{
|
||||
return isset($this->_attributes['proxyDir'])
|
||||
? $this->_attributes['proxyDir']
|
||||
: null;
|
||||
return $this->_attributes['proxyDir'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the strategy for automatically generating proxy classes.
|
||||
*
|
||||
* @return int Possible values are constants of Doctrine\Common\Proxy\AbstractProxyFactory.
|
||||
*
|
||||
* @deprecated 2.7 We're switch to `ocramius/proxy-manager` and this method isn't applicable any longer
|
||||
*
|
||||
* @see https://github.com/Ocramius/ProxyManager
|
||||
*
|
||||
* @return int Possible values are constants of Doctrine\Common\Proxy\AbstractProxyFactory.
|
||||
*/
|
||||
public function getAutoGenerateProxyClasses()
|
||||
{
|
||||
return isset($this->_attributes['autoGenerateProxyClasses'])
|
||||
? $this->_attributes['autoGenerateProxyClasses']
|
||||
: AbstractProxyFactory::AUTOGENERATE_ALWAYS;
|
||||
return $this->_attributes['autoGenerateProxyClasses'] ?? AbstractProxyFactory::AUTOGENERATE_ALWAYS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the strategy for automatically generating proxy classes.
|
||||
*
|
||||
* @param boolean|int $autoGenerate Possible values are constants of Doctrine\Common\Proxy\AbstractProxyFactory.
|
||||
* True is converted to AUTOGENERATE_ALWAYS, false to AUTOGENERATE_NEVER.
|
||||
* @param bool|int $autoGenerate Possible values are constants of Doctrine\Common\Proxy\AbstractProxyFactory.
|
||||
* True is converted to AUTOGENERATE_ALWAYS, false to AUTOGENERATE_NEVER.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -113,16 +109,15 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Gets the namespace where proxy classes reside.
|
||||
*
|
||||
* @return string|null
|
||||
*
|
||||
* @deprecated 2.7 We're switch to `ocramius/proxy-manager` and this method isn't applicable any longer
|
||||
*
|
||||
* @see https://github.com/Ocramius/ProxyManager
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getProxyNamespace()
|
||||
{
|
||||
return isset($this->_attributes['proxyNamespace'])
|
||||
? $this->_attributes['proxyNamespace']
|
||||
: null;
|
||||
return $this->_attributes['proxyNamespace'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,8 +135,6 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Sets the cache driver implementation that is used for metadata caching.
|
||||
*
|
||||
* @param MappingDriver $driverImpl
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @todo Force parameter to be a Closure to ensure lazy evaluation
|
||||
@@ -204,7 +197,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getEntityNamespace($entityNamespaceAlias)
|
||||
{
|
||||
if ( ! isset($this->_attributes['entityNamespaces'][$entityNamespaceAlias])) {
|
||||
if (! isset($this->_attributes['entityNamespaces'][$entityNamespaceAlias])) {
|
||||
throw ORMException::unknownEntityNamespace($entityNamespaceAlias);
|
||||
}
|
||||
|
||||
@@ -242,28 +235,22 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getMetadataDriverImpl()
|
||||
{
|
||||
return isset($this->_attributes['metadataDriverImpl'])
|
||||
? $this->_attributes['metadataDriverImpl']
|
||||
: null;
|
||||
return $this->_attributes['metadataDriverImpl'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cache driver implementation that is used for the query cache (SQL cache).
|
||||
*
|
||||
* @return \Doctrine\Common\Cache\Cache|null
|
||||
* @return CacheDriver|null
|
||||
*/
|
||||
public function getQueryCacheImpl()
|
||||
{
|
||||
return isset($this->_attributes['queryCacheImpl'])
|
||||
? $this->_attributes['queryCacheImpl']
|
||||
: null;
|
||||
return $this->_attributes['queryCacheImpl'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cache driver implementation that is used for the query cache (SQL cache).
|
||||
*
|
||||
* @param \Doctrine\Common\Cache\Cache $cacheImpl
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setQueryCacheImpl(CacheDriver $cacheImpl)
|
||||
@@ -274,20 +261,16 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Gets the cache driver implementation that is used for the hydration cache (SQL cache).
|
||||
*
|
||||
* @return \Doctrine\Common\Cache\Cache|null
|
||||
* @return CacheDriver|null
|
||||
*/
|
||||
public function getHydrationCacheImpl()
|
||||
{
|
||||
return isset($this->_attributes['hydrationCacheImpl'])
|
||||
? $this->_attributes['hydrationCacheImpl']
|
||||
: null;
|
||||
return $this->_attributes['hydrationCacheImpl'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cache driver implementation that is used for the hydration cache (SQL cache).
|
||||
*
|
||||
* @param \Doctrine\Common\Cache\Cache $cacheImpl
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setHydrationCacheImpl(CacheDriver $cacheImpl)
|
||||
@@ -298,20 +281,16 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Gets the cache driver implementation that is used for metadata caching.
|
||||
*
|
||||
* @return \Doctrine\Common\Cache\Cache|null
|
||||
* @return CacheDriver|null
|
||||
*/
|
||||
public function getMetadataCacheImpl()
|
||||
{
|
||||
return isset($this->_attributes['metadataCacheImpl'])
|
||||
? $this->_attributes['metadataCacheImpl']
|
||||
: null;
|
||||
return $this->_attributes['metadataCacheImpl'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cache driver implementation that is used for metadata caching.
|
||||
*
|
||||
* @param \Doctrine\Common\Cache\Cache $cacheImpl
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setMetadataCacheImpl(CacheDriver $cacheImpl)
|
||||
@@ -343,7 +322,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getNamedQuery($name)
|
||||
{
|
||||
if ( ! isset($this->_attributes['namedQueries'][$name])) {
|
||||
if (! isset($this->_attributes['namedQueries'][$name])) {
|
||||
throw ORMException::namedQueryNotFound($name);
|
||||
}
|
||||
|
||||
@@ -376,7 +355,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getNamedNativeQuery($name)
|
||||
{
|
||||
if ( ! isset($this->_attributes['namedNativeQueries'][$name])) {
|
||||
if (! isset($this->_attributes['namedNativeQueries'][$name])) {
|
||||
throw ORMException::namedNativeQueryNotFound($name);
|
||||
}
|
||||
|
||||
@@ -396,7 +375,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
{
|
||||
$queryCacheImpl = $this->getQueryCacheImpl();
|
||||
|
||||
if ( ! $queryCacheImpl) {
|
||||
if (! $queryCacheImpl) {
|
||||
throw ORMException::queryCacheNotConfigured();
|
||||
}
|
||||
|
||||
@@ -406,7 +385,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
|
||||
$metadataCacheImpl = $this->getMetadataCacheImpl();
|
||||
|
||||
if ( ! $metadataCacheImpl) {
|
||||
if (! $metadataCacheImpl) {
|
||||
throw ORMException::metadataCacheNotConfigured();
|
||||
}
|
||||
|
||||
@@ -442,15 +421,14 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
* @param string $name
|
||||
*
|
||||
* @return string|null
|
||||
*
|
||||
* @psalm-return ?class-string
|
||||
*/
|
||||
public function getCustomStringFunction($name)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
|
||||
return isset($this->_attributes['customStringFunctions'][$name])
|
||||
? $this->_attributes['customStringFunctions'][$name]
|
||||
: null;
|
||||
return $this->_attributes['customStringFunctions'][$name] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -495,15 +473,14 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
* @param string $name
|
||||
*
|
||||
* @return string|null
|
||||
*
|
||||
* @psalm-return ?class-string
|
||||
*/
|
||||
public function getCustomNumericFunction($name)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
|
||||
return isset($this->_attributes['customNumericFunctions'][$name])
|
||||
? $this->_attributes['customNumericFunctions'][$name]
|
||||
: null;
|
||||
return $this->_attributes['customNumericFunctions'][$name] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -557,9 +534,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
{
|
||||
$name = strtolower($name);
|
||||
|
||||
return isset($this->_attributes['customDatetimeFunctions'][$name])
|
||||
? $this->_attributes['customDatetimeFunctions'][$name]
|
||||
: null;
|
||||
return $this->_attributes['customDatetimeFunctions'][$name] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -610,9 +585,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getCustomHydrationMode($modeName)
|
||||
{
|
||||
return isset($this->_attributes['customHydrationModes'][$modeName])
|
||||
? $this->_attributes['customHydrationModes'][$modeName]
|
||||
: null;
|
||||
return $this->_attributes['customHydrationModes'][$modeName] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -649,7 +622,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getClassMetadataFactoryName()
|
||||
{
|
||||
if ( ! isset($this->_attributes['classMetadataFactoryName'])) {
|
||||
if (! isset($this->_attributes['classMetadataFactoryName'])) {
|
||||
$this->_attributes['classMetadataFactoryName'] = ClassMetadataFactory::class;
|
||||
}
|
||||
|
||||
@@ -679,16 +652,12 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function getFilterClassName($name)
|
||||
{
|
||||
return isset($this->_attributes['filters'][$name])
|
||||
? $this->_attributes['filters'][$name]
|
||||
: null;
|
||||
return $this->_attributes['filters'][$name] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets default repository class.
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
* @param string $className
|
||||
*
|
||||
* @return void
|
||||
@@ -697,9 +666,9 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*/
|
||||
public function setDefaultRepositoryClassName($className)
|
||||
{
|
||||
$reflectionClass = new \ReflectionClass($className);
|
||||
$reflectionClass = new ReflectionClass($className);
|
||||
|
||||
if ( ! $reflectionClass->implementsInterface(ObjectRepository::class)) {
|
||||
if (! $reflectionClass->implementsInterface(ObjectRepository::class)) {
|
||||
throw ORMException::invalidEntityRepository($className);
|
||||
}
|
||||
|
||||
@@ -709,26 +678,18 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Get default repository class.
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @psalm-return class-string
|
||||
*/
|
||||
public function getDefaultRepositoryClassName()
|
||||
{
|
||||
return isset($this->_attributes['defaultRepositoryClassName'])
|
||||
? $this->_attributes['defaultRepositoryClassName']
|
||||
: EntityRepository::class;
|
||||
return $this->_attributes['defaultRepositoryClassName'] ?? EntityRepository::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets naming strategy.
|
||||
*
|
||||
* @since 2.3
|
||||
*
|
||||
* @param NamingStrategy $namingStrategy
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setNamingStrategy(NamingStrategy $namingStrategy)
|
||||
@@ -739,13 +700,11 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Gets naming strategy..
|
||||
*
|
||||
* @since 2.3
|
||||
*
|
||||
* @return NamingStrategy
|
||||
*/
|
||||
public function getNamingStrategy()
|
||||
{
|
||||
if ( ! isset($this->_attributes['namingStrategy'])) {
|
||||
if (! isset($this->_attributes['namingStrategy'])) {
|
||||
$this->_attributes['namingStrategy'] = new DefaultNamingStrategy();
|
||||
}
|
||||
|
||||
@@ -755,10 +714,6 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Sets quote strategy.
|
||||
*
|
||||
* @since 2.3
|
||||
*
|
||||
* @param \Doctrine\ORM\Mapping\QuoteStrategy $quoteStrategy
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setQuoteStrategy(QuoteStrategy $quoteStrategy)
|
||||
@@ -769,13 +724,11 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Gets quote strategy.
|
||||
*
|
||||
* @since 2.3
|
||||
*
|
||||
* @return \Doctrine\ORM\Mapping\QuoteStrategy
|
||||
* @return QuoteStrategy
|
||||
*/
|
||||
public function getQuoteStrategy()
|
||||
{
|
||||
if ( ! isset($this->_attributes['quoteStrategy'])) {
|
||||
if (! isset($this->_attributes['quoteStrategy'])) {
|
||||
$this->_attributes['quoteStrategy'] = new DefaultQuoteStrategy();
|
||||
}
|
||||
|
||||
@@ -784,9 +737,6 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
|
||||
/**
|
||||
* Set the entity listener resolver.
|
||||
*
|
||||
* @since 2.4
|
||||
* @param \Doctrine\ORM\Mapping\EntityListenerResolver $resolver
|
||||
*/
|
||||
public function setEntityListenerResolver(EntityListenerResolver $resolver)
|
||||
{
|
||||
@@ -796,12 +746,11 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Get the entity listener resolver.
|
||||
*
|
||||
* @since 2.4
|
||||
* @return \Doctrine\ORM\Mapping\EntityListenerResolver
|
||||
* @return EntityListenerResolver
|
||||
*/
|
||||
public function getEntityListenerResolver()
|
||||
{
|
||||
if ( ! isset($this->_attributes['entityListenerResolver'])) {
|
||||
if (! isset($this->_attributes['entityListenerResolver'])) {
|
||||
$this->_attributes['entityListenerResolver'] = new DefaultEntityListenerResolver();
|
||||
}
|
||||
|
||||
@@ -810,9 +759,6 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
|
||||
/**
|
||||
* Set the entity repository factory.
|
||||
*
|
||||
* @since 2.4
|
||||
* @param \Doctrine\ORM\Repository\RepositoryFactory $repositoryFactory
|
||||
*/
|
||||
public function setRepositoryFactory(RepositoryFactory $repositoryFactory)
|
||||
{
|
||||
@@ -822,45 +768,32 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Get the entity repository factory.
|
||||
*
|
||||
* @since 2.4
|
||||
* @return \Doctrine\ORM\Repository\RepositoryFactory
|
||||
* @return RepositoryFactory
|
||||
*/
|
||||
public function getRepositoryFactory()
|
||||
{
|
||||
return isset($this->_attributes['repositoryFactory'])
|
||||
? $this->_attributes['repositoryFactory']
|
||||
: new DefaultRepositoryFactory();
|
||||
return $this->_attributes['repositoryFactory'] ?? new DefaultRepositoryFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.5
|
||||
*
|
||||
* @return boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function isSecondLevelCacheEnabled()
|
||||
{
|
||||
return isset($this->_attributes['isSecondLevelCacheEnabled'])
|
||||
? $this->_attributes['isSecondLevelCacheEnabled']
|
||||
: false;
|
||||
return $this->_attributes['isSecondLevelCacheEnabled'] ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.5
|
||||
*
|
||||
* @param boolean $flag
|
||||
* @param bool $flag
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setSecondLevelCacheEnabled($flag = true)
|
||||
{
|
||||
$this->_attributes['isSecondLevelCacheEnabled'] = (boolean) $flag;
|
||||
$this->_attributes['isSecondLevelCacheEnabled'] = (bool) $flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.5
|
||||
*
|
||||
* @param \Doctrine\ORM\Cache\CacheConfiguration $cacheConfig
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setSecondLevelCacheConfiguration(CacheConfiguration $cacheConfig)
|
||||
@@ -869,38 +802,30 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.5
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache\CacheConfiguration|null
|
||||
* @return CacheConfiguration|null
|
||||
*/
|
||||
public function getSecondLevelCacheConfiguration()
|
||||
{
|
||||
if ( ! isset($this->_attributes['secondLevelCacheConfiguration']) && $this->isSecondLevelCacheEnabled()) {
|
||||
if (! isset($this->_attributes['secondLevelCacheConfiguration']) && $this->isSecondLevelCacheEnabled()) {
|
||||
$this->_attributes['secondLevelCacheConfiguration'] = new CacheConfiguration();
|
||||
}
|
||||
|
||||
return isset($this->_attributes['secondLevelCacheConfiguration'])
|
||||
? $this->_attributes['secondLevelCacheConfiguration']
|
||||
: null;
|
||||
return $this->_attributes['secondLevelCacheConfiguration'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns query hints, which will be applied to every query in application
|
||||
*
|
||||
* @since 2.5
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDefaultQueryHints()
|
||||
{
|
||||
return isset($this->_attributes['defaultQueryHints']) ? $this->_attributes['defaultQueryHints'] : [];
|
||||
return $this->_attributes['defaultQueryHints'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets array of query hints, which will be applied to every query in application
|
||||
*
|
||||
* @since 2.5
|
||||
*
|
||||
* @param array $defaultQueryHints
|
||||
*/
|
||||
public function setDefaultQueryHints(array $defaultQueryHints)
|
||||
@@ -911,24 +836,18 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Gets the value of a default query hint. If the hint name is not recognized, FALSE is returned.
|
||||
*
|
||||
* @since 2.5
|
||||
*
|
||||
* @param string $name The name of the hint.
|
||||
*
|
||||
* @return mixed The value of the hint or FALSE, if the hint name is not recognized.
|
||||
*/
|
||||
public function getDefaultQueryHint($name)
|
||||
{
|
||||
return isset($this->_attributes['defaultQueryHints'][$name])
|
||||
? $this->_attributes['defaultQueryHints'][$name]
|
||||
: false;
|
||||
return $this->_attributes['defaultQueryHints'][$name] ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a default query hint. If the hint name is not recognized, it is silently ignored.
|
||||
*
|
||||
* @since 2.5
|
||||
*
|
||||
* @param string $name The name of the hint.
|
||||
* @param mixed $value The value of the hint.
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -19,26 +20,18 @@
|
||||
|
||||
namespace Doctrine\ORM\Decorator;
|
||||
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\Persistence\ObjectManagerDecorator;
|
||||
|
||||
/**
|
||||
* Base class for EntityManager decorators
|
||||
*
|
||||
* @since 2.4
|
||||
* @author Lars Strojny <lars@strojny.net
|
||||
*/
|
||||
abstract class EntityManagerDecorator extends ObjectManagerDecorator implements EntityManagerInterface
|
||||
{
|
||||
/**
|
||||
* @var EntityManagerInterface
|
||||
*/
|
||||
/** @var EntityManagerInterface */
|
||||
protected $wrapped;
|
||||
|
||||
/**
|
||||
* @param EntityManagerInterface $wrapped
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $wrapped)
|
||||
{
|
||||
$this->wrapped = $wrapped;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -19,22 +20,38 @@
|
||||
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
use BadMethodCallException;
|
||||
use Doctrine\Common\EventManager;
|
||||
use Doctrine\Common\Util\ClassUtils;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\DriverManager;
|
||||
use Doctrine\DBAL\LockMode;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataFactory;
|
||||
use Doctrine\ORM\Proxy\ProxyFactory;
|
||||
use Doctrine\ORM\Query\Expr;
|
||||
use Doctrine\ORM\Query\FilterCollection;
|
||||
use Doctrine\Common\Util\ClassUtils;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\Repository\RepositoryFactory;
|
||||
use Doctrine\Persistence\Mapping\MappingException;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
use InvalidArgumentException;
|
||||
use Throwable;
|
||||
|
||||
use function array_keys;
|
||||
use function call_user_func;
|
||||
use function get_class;
|
||||
use function gettype;
|
||||
use function is_array;
|
||||
use function is_callable;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function ltrim;
|
||||
use const E_USER_DEPRECATED;
|
||||
use function sprintf;
|
||||
use function trigger_error;
|
||||
|
||||
use const E_USER_DEPRECATED;
|
||||
|
||||
/**
|
||||
* The EntityManager is the central access point to ORM functionality.
|
||||
*
|
||||
@@ -59,68 +76,62 @@ use function trigger_error;
|
||||
* is not a valid extension point for the EntityManager. Instead you
|
||||
* should take a look at the {@see \Doctrine\ORM\Decorator\EntityManagerDecorator}
|
||||
* and wrap your entity manager in a decorator.
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
/* final */class EntityManager implements EntityManagerInterface
|
||||
{
|
||||
/**
|
||||
* The used Configuration.
|
||||
*
|
||||
* @var \Doctrine\ORM\Configuration
|
||||
* @var Configuration
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* The database connection used by the EntityManager.
|
||||
*
|
||||
* @var \Doctrine\DBAL\Connection
|
||||
* @var Connection
|
||||
*/
|
||||
private $conn;
|
||||
|
||||
/**
|
||||
* The metadata factory, used to retrieve the ORM metadata of entity classes.
|
||||
*
|
||||
* @var \Doctrine\ORM\Mapping\ClassMetadataFactory
|
||||
* @var ClassMetadataFactory
|
||||
*/
|
||||
private $metadataFactory;
|
||||
|
||||
/**
|
||||
* The UnitOfWork used to coordinate object-level transactions.
|
||||
*
|
||||
* @var \Doctrine\ORM\UnitOfWork
|
||||
* @var UnitOfWork
|
||||
*/
|
||||
private $unitOfWork;
|
||||
|
||||
/**
|
||||
* The event manager that is the central point of the event system.
|
||||
*
|
||||
* @var \Doctrine\Common\EventManager
|
||||
* @var EventManager
|
||||
*/
|
||||
private $eventManager;
|
||||
|
||||
/**
|
||||
* The proxy factory used to create dynamic proxies.
|
||||
*
|
||||
* @var \Doctrine\ORM\Proxy\ProxyFactory
|
||||
* @var ProxyFactory
|
||||
*/
|
||||
private $proxyFactory;
|
||||
|
||||
/**
|
||||
* The repository factory used to create dynamic repositories.
|
||||
*
|
||||
* @var \Doctrine\ORM\Repository\RepositoryFactory
|
||||
* @var RepositoryFactory
|
||||
*/
|
||||
private $repositoryFactory;
|
||||
|
||||
/**
|
||||
* The expression builder instance used to generate query expressions.
|
||||
*
|
||||
* @var \Doctrine\ORM\Query\Expr
|
||||
* @var Expr
|
||||
*/
|
||||
private $expressionBuilder;
|
||||
|
||||
@@ -134,32 +145,26 @@ use function trigger_error;
|
||||
/**
|
||||
* Collection of query filters.
|
||||
*
|
||||
* @var \Doctrine\ORM\Query\FilterCollection
|
||||
* @var FilterCollection
|
||||
*/
|
||||
private $filterCollection;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Cache The second level cache regions API.
|
||||
*/
|
||||
/** @var Cache The second level cache regions API. */
|
||||
private $cache;
|
||||
|
||||
/**
|
||||
* Creates a new EntityManager that operates on the given database connection
|
||||
* and uses the given Configuration and EventManager implementations.
|
||||
*
|
||||
* @param \Doctrine\DBAL\Connection $conn
|
||||
* @param \Doctrine\ORM\Configuration $config
|
||||
* @param \Doctrine\Common\EventManager $eventManager
|
||||
*/
|
||||
protected function __construct(Connection $conn, Configuration $config, EventManager $eventManager)
|
||||
{
|
||||
$this->conn = $conn;
|
||||
$this->config = $config;
|
||||
$this->eventManager = $eventManager;
|
||||
$this->conn = $conn;
|
||||
$this->config = $config;
|
||||
$this->eventManager = $eventManager;
|
||||
|
||||
$metadataFactoryClassName = $config->getClassMetadataFactoryName();
|
||||
|
||||
$this->metadataFactory = new $metadataFactoryClassName;
|
||||
$this->metadataFactory = new $metadataFactoryClassName();
|
||||
$this->metadataFactory->setEntityManager($this);
|
||||
$this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl());
|
||||
|
||||
@@ -173,9 +178,9 @@ use function trigger_error;
|
||||
);
|
||||
|
||||
if ($config->isSecondLevelCacheEnabled()) {
|
||||
$cacheConfig = $config->getSecondLevelCacheConfiguration();
|
||||
$cacheFactory = $cacheConfig->getCacheFactory();
|
||||
$this->cache = $cacheFactory->createCache($this);
|
||||
$cacheConfig = $config->getSecondLevelCacheConfiguration();
|
||||
$cacheFactory = $cacheConfig->getCacheFactory();
|
||||
$this->cache = $cacheFactory->createCache($this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +195,7 @@ use function trigger_error;
|
||||
/**
|
||||
* Gets the metadata factory used to gather the metadata of classes.
|
||||
*
|
||||
* @return \Doctrine\ORM\Mapping\ClassMetadataFactory
|
||||
* @return ClassMetadataFactory
|
||||
*/
|
||||
public function getMetadataFactory()
|
||||
{
|
||||
@@ -203,7 +208,7 @@ use function trigger_error;
|
||||
public function getExpressionBuilder()
|
||||
{
|
||||
if ($this->expressionBuilder === null) {
|
||||
$this->expressionBuilder = new Query\Expr;
|
||||
$this->expressionBuilder = new Query\Expr();
|
||||
}
|
||||
|
||||
return $this->expressionBuilder;
|
||||
@@ -230,8 +235,8 @@ use function trigger_error;
|
||||
*/
|
||||
public function transactional($func)
|
||||
{
|
||||
if (!is_callable($func)) {
|
||||
throw new \InvalidArgumentException('Expected argument of type "callable", got "' . gettype($func) . '"');
|
||||
if (! is_callable($func)) {
|
||||
throw new InvalidArgumentException('Expected argument of type "callable", got "' . gettype($func) . '"');
|
||||
}
|
||||
|
||||
$this->conn->beginTransaction();
|
||||
@@ -281,7 +286,7 @@ use function trigger_error;
|
||||
*
|
||||
* @param string $className
|
||||
*
|
||||
* @return \Doctrine\ORM\Mapping\ClassMetadata
|
||||
* @return ClassMetadata
|
||||
*/
|
||||
public function getClassMetadata($className)
|
||||
{
|
||||
@@ -295,7 +300,7 @@ use function trigger_error;
|
||||
{
|
||||
$query = new Query($this);
|
||||
|
||||
if ( ! empty($dql)) {
|
||||
if (! empty($dql)) {
|
||||
$query->setDQL($dql);
|
||||
}
|
||||
|
||||
@@ -349,12 +354,12 @@ use function trigger_error;
|
||||
* If an entity is explicitly passed to this method only this entity and
|
||||
* the cascade-persist semantics + scheduled inserts/removals are synchronized.
|
||||
*
|
||||
* @param null|object|array $entity
|
||||
* @param object|mixed[]|null $entity
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws \Doctrine\ORM\OptimisticLockException If a version check on an entity that
|
||||
* makes use of optimistic locking fails.
|
||||
* @throws OptimisticLockException If a version check on an entity that
|
||||
* makes use of optimistic locking fails.
|
||||
* @throws ORMException
|
||||
*/
|
||||
public function flush($entity = null)
|
||||
@@ -374,13 +379,13 @@ use function trigger_error;
|
||||
/**
|
||||
* Finds an Entity by its identifier.
|
||||
*
|
||||
* @param string $className The class name of the entity to find.
|
||||
* @param mixed $id The identity of the entity to find.
|
||||
* @param integer|null $lockMode One of the \Doctrine\DBAL\LockMode::* constants
|
||||
* or NULL if no specific lock mode should be used
|
||||
* during the search.
|
||||
* @param integer|null $lockVersion The version of the entity to find when using
|
||||
* optimistic locking.
|
||||
* @param string $className The class name of the entity to find.
|
||||
* @param mixed $id The identity of the entity to find.
|
||||
* @param int|null $lockMode One of the \Doctrine\DBAL\LockMode::* constants
|
||||
* or NULL if no specific lock mode should be used
|
||||
* during the search.
|
||||
* @param int|null $lockVersion The version of the entity to find when using
|
||||
* optimistic locking.
|
||||
*
|
||||
* @return object|null The entity instance or NULL if the entity can not be found.
|
||||
*
|
||||
@@ -390,7 +395,7 @@ use function trigger_error;
|
||||
* @throws ORMException
|
||||
*
|
||||
* @template T
|
||||
* @psalm-param class-string<T> $entityName
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-return ?T
|
||||
*/
|
||||
public function find($className, $id, $lockMode = null, $lockVersion = null)
|
||||
@@ -401,7 +406,7 @@ use function trigger_error;
|
||||
$this->checkLockRequirements($lockMode, $class);
|
||||
}
|
||||
|
||||
if ( ! is_array($id)) {
|
||||
if (! is_array($id)) {
|
||||
if ($class->isIdentifierComposite) {
|
||||
throw ORMInvalidArgumentException::invalidCompositeIdentifier();
|
||||
}
|
||||
@@ -422,7 +427,7 @@ use function trigger_error;
|
||||
$sortedId = [];
|
||||
|
||||
foreach ($class->identifier as $identifier) {
|
||||
if ( ! isset($id[$identifier])) {
|
||||
if (! isset($id[$identifier])) {
|
||||
throw ORMException::missingIdentifierField($class->name, $identifier);
|
||||
}
|
||||
|
||||
@@ -436,20 +441,22 @@ use function trigger_error;
|
||||
|
||||
$unitOfWork = $this->getUnitOfWork();
|
||||
|
||||
$entity = $unitOfWork->tryGetById($sortedId, $class->rootEntityName);
|
||||
|
||||
// Check identity map first
|
||||
if (($entity = $unitOfWork->tryGetById($sortedId, $class->rootEntityName)) !== false) {
|
||||
if ( ! ($entity instanceof $class->name)) {
|
||||
if ($entity !== false) {
|
||||
if (! ($entity instanceof $class->name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
case LockMode::OPTIMISTIC === $lockMode:
|
||||
case $lockMode === LockMode::OPTIMISTIC:
|
||||
$this->lock($entity, $lockMode, $lockVersion);
|
||||
break;
|
||||
|
||||
case LockMode::NONE === $lockMode:
|
||||
case LockMode::PESSIMISTIC_READ === $lockMode:
|
||||
case LockMode::PESSIMISTIC_WRITE === $lockMode:
|
||||
case $lockMode === LockMode::NONE:
|
||||
case $lockMode === LockMode::PESSIMISTIC_READ:
|
||||
case $lockMode === LockMode::PESSIMISTIC_WRITE:
|
||||
$persister = $unitOfWork->getEntityPersister($class->name);
|
||||
$persister->refresh($sortedId, $entity, $lockMode);
|
||||
break;
|
||||
@@ -461,15 +468,15 @@ use function trigger_error;
|
||||
$persister = $unitOfWork->getEntityPersister($class->name);
|
||||
|
||||
switch (true) {
|
||||
case LockMode::OPTIMISTIC === $lockMode:
|
||||
case $lockMode === LockMode::OPTIMISTIC:
|
||||
$entity = $persister->load($sortedId);
|
||||
|
||||
$unitOfWork->lock($entity, $lockMode, $lockVersion);
|
||||
|
||||
return $entity;
|
||||
|
||||
case LockMode::PESSIMISTIC_READ === $lockMode:
|
||||
case LockMode::PESSIMISTIC_WRITE === $lockMode:
|
||||
case $lockMode === LockMode::PESSIMISTIC_READ:
|
||||
case $lockMode === LockMode::PESSIMISTIC_WRITE:
|
||||
return $persister->load($sortedId, null, null, [], $lockMode);
|
||||
|
||||
default:
|
||||
@@ -484,14 +491,14 @@ use function trigger_error;
|
||||
{
|
||||
$class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
|
||||
|
||||
if ( ! is_array($id)) {
|
||||
if (! is_array($id)) {
|
||||
$id = [$class->identifier[0] => $id];
|
||||
}
|
||||
|
||||
$sortedId = [];
|
||||
|
||||
foreach ($class->identifier as $identifier) {
|
||||
if ( ! isset($id[$identifier])) {
|
||||
if (! isset($id[$identifier])) {
|
||||
throw ORMException::missingIdentifierField($class->name, $identifier);
|
||||
}
|
||||
|
||||
@@ -503,9 +510,11 @@ use function trigger_error;
|
||||
throw ORMException::unrecognizedIdentifierFields($class->name, array_keys($id));
|
||||
}
|
||||
|
||||
$entity = $this->unitOfWork->tryGetById($sortedId, $class->rootEntityName);
|
||||
|
||||
// Check identity map first, if its already in there just return it.
|
||||
if (($entity = $this->unitOfWork->tryGetById($sortedId, $class->rootEntityName)) !== false) {
|
||||
return ($entity instanceof $class->name) ? $entity : null;
|
||||
if ($entity !== false) {
|
||||
return $entity instanceof $class->name ? $entity : null;
|
||||
}
|
||||
|
||||
if ($class->subClasses) {
|
||||
@@ -526,12 +535,14 @@ use function trigger_error;
|
||||
{
|
||||
$class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
|
||||
|
||||
$entity = $this->unitOfWork->tryGetById($identifier, $class->rootEntityName);
|
||||
|
||||
// Check identity map first, if its already in there just return it.
|
||||
if (($entity = $this->unitOfWork->tryGetById($identifier, $class->rootEntityName)) !== false) {
|
||||
return ($entity instanceof $class->name) ? $entity : null;
|
||||
if ($entity !== false) {
|
||||
return $entity instanceof $class->name ? $entity : null;
|
||||
}
|
||||
|
||||
if ( ! is_array($identifier)) {
|
||||
if (! is_array($identifier)) {
|
||||
$identifier = [$class->identifier[0] => $identifier];
|
||||
}
|
||||
|
||||
@@ -559,7 +570,7 @@ use function trigger_error;
|
||||
*/
|
||||
public function clear($entityName = null)
|
||||
{
|
||||
if (null !== $entityName && ! is_string($entityName)) {
|
||||
if ($entityName !== null && ! is_string($entityName)) {
|
||||
throw ORMInvalidArgumentException::invalidEntityName($entityName);
|
||||
}
|
||||
|
||||
@@ -571,7 +582,7 @@ use function trigger_error;
|
||||
}
|
||||
|
||||
$this->unitOfWork->clear(
|
||||
null === $entityName
|
||||
$entityName === null
|
||||
? null
|
||||
: $this->metadataFactory->getMetadataFor($entityName)->getName()
|
||||
);
|
||||
@@ -605,7 +616,7 @@ use function trigger_error;
|
||||
*/
|
||||
public function persist($entity)
|
||||
{
|
||||
if ( ! is_object($entity)) {
|
||||
if (! is_object($entity)) {
|
||||
throw ORMInvalidArgumentException::invalidObject('EntityManager#persist()', $entity);
|
||||
}
|
||||
|
||||
@@ -629,7 +640,7 @@ use function trigger_error;
|
||||
*/
|
||||
public function remove($entity)
|
||||
{
|
||||
if ( ! is_object($entity)) {
|
||||
if (! is_object($entity)) {
|
||||
throw ORMInvalidArgumentException::invalidObject('EntityManager#remove()', $entity);
|
||||
}
|
||||
|
||||
@@ -651,7 +662,7 @@ use function trigger_error;
|
||||
*/
|
||||
public function refresh($entity)
|
||||
{
|
||||
if ( ! is_object($entity)) {
|
||||
if (! is_object($entity)) {
|
||||
throw ORMInvalidArgumentException::invalidObject('EntityManager#refresh()', $entity);
|
||||
}
|
||||
|
||||
@@ -667,19 +678,19 @@ use function trigger_error;
|
||||
* Entities which previously referenced the detached entity will continue to
|
||||
* reference it.
|
||||
*
|
||||
* @deprecated 2.7 This method is being removed from the ORM and won't have any replacement
|
||||
*
|
||||
* @param object $entity The entity to detach.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws ORMInvalidArgumentException
|
||||
*
|
||||
* @deprecated 2.7 This method is being removed from the ORM and won't have any replacement
|
||||
*/
|
||||
public function detach($entity)
|
||||
{
|
||||
@trigger_error('Method ' . __METHOD__ . '() is deprecated and will be removed in Doctrine ORM 3.0.', E_USER_DEPRECATED);
|
||||
|
||||
if ( ! is_object($entity)) {
|
||||
if (! is_object($entity)) {
|
||||
throw ORMInvalidArgumentException::invalidObject('EntityManager#detach()', $entity);
|
||||
}
|
||||
|
||||
@@ -691,20 +702,20 @@ use function trigger_error;
|
||||
* of this EntityManager and returns the managed copy of the entity.
|
||||
* The entity passed to merge will not become associated/managed with this EntityManager.
|
||||
*
|
||||
* @deprecated 2.7 This method is being removed from the ORM and won't have any replacement
|
||||
*
|
||||
* @param object $entity The detached entity to merge into the persistence context.
|
||||
*
|
||||
* @return object The managed copy of the entity.
|
||||
*
|
||||
* @throws ORMInvalidArgumentException
|
||||
* @throws ORMException
|
||||
*
|
||||
* @deprecated 2.7 This method is being removed from the ORM and won't have any replacement
|
||||
*/
|
||||
public function merge($entity)
|
||||
{
|
||||
@trigger_error('Method ' . __METHOD__ . '() is deprecated and will be removed in Doctrine ORM 3.0.', E_USER_DEPRECATED);
|
||||
|
||||
if ( ! is_object($entity)) {
|
||||
if (! is_object($entity)) {
|
||||
throw ORMInvalidArgumentException::invalidObject('EntityManager#merge()', $entity);
|
||||
}
|
||||
|
||||
@@ -720,7 +731,7 @@ use function trigger_error;
|
||||
{
|
||||
@trigger_error('Method ' . __METHOD__ . '() is deprecated and will be removed in Doctrine ORM 3.0.', E_USER_DEPRECATED);
|
||||
|
||||
throw new \BadMethodCallException("Not implemented.");
|
||||
throw new BadMethodCallException('Not implemented.');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -752,7 +763,7 @@ use function trigger_error;
|
||||
*
|
||||
* @param object $entity
|
||||
*
|
||||
* @return boolean TRUE if this EntityManager currently manages the given entity, FALSE otherwise.
|
||||
* @return bool TRUE if this EntityManager currently manages the given entity, FALSE otherwise.
|
||||
*/
|
||||
public function contains($entity)
|
||||
{
|
||||
@@ -796,7 +807,7 @@ use function trigger_error;
|
||||
*/
|
||||
public function isOpen()
|
||||
{
|
||||
return (!$this->closed);
|
||||
return ! $this->closed;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -837,7 +848,9 @@ use function trigger_error;
|
||||
return new Internal\Hydration\SimpleObjectHydrator($this);
|
||||
|
||||
default:
|
||||
if (($class = $this->config->getCustomHydrationMode($hydrationMode)) !== null) {
|
||||
$class = $this->config->getCustomHydrationMode($hydrationMode);
|
||||
|
||||
if ($class !== null) {
|
||||
return new $class($this);
|
||||
}
|
||||
}
|
||||
@@ -864,18 +877,18 @@ use function trigger_error;
|
||||
/**
|
||||
* Factory method to create EntityManager 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.
|
||||
* @param array<string, mixed>|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 EntityManager The created EntityManager.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws InvalidArgumentException
|
||||
* @throws ORMException
|
||||
*/
|
||||
public static function create($connection, Configuration $config, EventManager $eventManager = null)
|
||||
public static function create($connection, Configuration $config, ?EventManager $eventManager = null)
|
||||
{
|
||||
if ( ! $config->getMetadataDriverImpl()) {
|
||||
if (! $config->getMetadataDriverImpl()) {
|
||||
throw ORMException::missingMappingDriverImpl();
|
||||
}
|
||||
|
||||
@@ -887,23 +900,23 @@ use function trigger_error;
|
||||
/**
|
||||
* 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.
|
||||
* @param array<string, mixed>|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 InvalidArgumentException
|
||||
* @throws ORMException
|
||||
*/
|
||||
protected static function createConnection($connection, Configuration $config, EventManager $eventManager = null)
|
||||
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(
|
||||
if (! $connection instanceof Connection) {
|
||||
throw new InvalidArgumentException(
|
||||
sprintf(
|
||||
'Invalid $connection argument of type %s given%s.',
|
||||
is_object($connection) ? get_class($connection) : gettype($connection),
|
||||
@@ -924,7 +937,7 @@ use function trigger_error;
|
||||
*/
|
||||
public function getFilters()
|
||||
{
|
||||
if (null === $this->filterCollection) {
|
||||
if ($this->filterCollection === null) {
|
||||
$this->filterCollection = new FilterCollection($this);
|
||||
}
|
||||
|
||||
@@ -936,7 +949,7 @@ use function trigger_error;
|
||||
*/
|
||||
public function isFiltersStateClean()
|
||||
{
|
||||
return null === $this->filterCollection || $this->filterCollection->isClean();
|
||||
return $this->filterCollection === null || $this->filterCollection->isClean();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -944,12 +957,10 @@ use function trigger_error;
|
||||
*/
|
||||
public function hasFilters()
|
||||
{
|
||||
return null !== $this->filterCollection;
|
||||
return $this->filterCollection !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $lockMode
|
||||
* @param ClassMetadata $class
|
||||
* @throws OptimisticLockException
|
||||
* @throws TransactionRequiredException
|
||||
*/
|
||||
@@ -957,13 +968,14 @@ use function trigger_error;
|
||||
{
|
||||
switch ($lockMode) {
|
||||
case LockMode::OPTIMISTIC:
|
||||
if (!$class->isVersioned) {
|
||||
if (! $class->isVersioned) {
|
||||
throw OptimisticLockException::notVersioned($class->name);
|
||||
}
|
||||
|
||||
break;
|
||||
case LockMode::PESSIMISTIC_READ:
|
||||
case LockMode::PESSIMISTIC_WRITE:
|
||||
if (!$this->getConnection()->isTransactionActive()) {
|
||||
if (! $this->getConnection()->isTransactionActive()) {
|
||||
throw TransactionRequiredException::transactionRequired();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -19,15 +20,19 @@
|
||||
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
use BadMethodCallException;
|
||||
use Doctrine\Common\EventManager;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\ORM\Internal\Hydration\AbstractHydrator;
|
||||
use Doctrine\ORM\Proxy\ProxyFactory;
|
||||
use Doctrine\ORM\Query\Expr;
|
||||
use Doctrine\ORM\Query\FilterCollection;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
|
||||
/**
|
||||
* EntityManager interface
|
||||
*
|
||||
* @since 2.4
|
||||
* @author Lars Strojny <lars@strojny.net>
|
||||
*
|
||||
* @method Mapping\ClassMetadata getClassMetadata($className)
|
||||
*/
|
||||
interface EntityManagerInterface extends ObjectManager
|
||||
@@ -35,14 +40,14 @@ interface EntityManagerInterface extends ObjectManager
|
||||
/**
|
||||
* Returns the cache API for managing the second level cache regions or NULL if the cache is not enabled.
|
||||
*
|
||||
* @return \Doctrine\ORM\Cache|null
|
||||
* @return Cache|null
|
||||
*/
|
||||
public function getCache();
|
||||
|
||||
/**
|
||||
* Gets the database connection object used by the EntityManager.
|
||||
*
|
||||
* @return \Doctrine\DBAL\Connection
|
||||
* @return Connection
|
||||
*/
|
||||
public function getConnection();
|
||||
|
||||
@@ -58,7 +63,7 @@ interface EntityManagerInterface extends ObjectManager
|
||||
* ->where($expr->orX($expr->eq('u.id', 1), $expr->eq('u.id', 2)));
|
||||
* </code>
|
||||
*
|
||||
* @return \Doctrine\ORM\Query\Expr
|
||||
* @return Expr
|
||||
*/
|
||||
public function getExpressionBuilder();
|
||||
|
||||
@@ -196,12 +201,12 @@ interface EntityManagerInterface extends ObjectManager
|
||||
*
|
||||
* @deprecated 2.7 This method is being removed from the ORM and won't have any replacement
|
||||
*
|
||||
* @param object $entity The entity to copy.
|
||||
* @param boolean $deep FALSE for a shallow copy, TRUE for a deep copy.
|
||||
* @param object $entity The entity to copy.
|
||||
* @param bool $deep FALSE for a shallow copy, TRUE for a deep copy.
|
||||
*
|
||||
* @return object The new entity.
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function copy($entity, $deep = false);
|
||||
|
||||
@@ -222,7 +227,7 @@ interface EntityManagerInterface extends ObjectManager
|
||||
/**
|
||||
* Gets the EventManager used by the EntityManager.
|
||||
*
|
||||
* @return \Doctrine\Common\EventManager
|
||||
* @return EventManager
|
||||
*/
|
||||
public function getEventManager();
|
||||
|
||||
@@ -248,17 +253,17 @@ interface EntityManagerInterface extends ObjectManager
|
||||
public function getUnitOfWork();
|
||||
|
||||
/**
|
||||
* Gets a hydrator for the given hydration mode.
|
||||
*
|
||||
* This method caches the hydrator instances which is used for all queries that don't
|
||||
* selectively iterate over the result.
|
||||
*
|
||||
* @deprecated
|
||||
*
|
||||
* @param string|int $hydrationMode
|
||||
*
|
||||
* @return \Doctrine\ORM\Internal\Hydration\AbstractHydrator
|
||||
*/
|
||||
* Gets a hydrator for the given hydration mode.
|
||||
*
|
||||
* This method caches the hydrator instances which is used for all queries that don't
|
||||
* selectively iterate over the result.
|
||||
*
|
||||
* @deprecated
|
||||
*
|
||||
* @param string|int $hydrationMode
|
||||
*
|
||||
* @return AbstractHydrator
|
||||
*/
|
||||
public function getHydrator($hydrationMode);
|
||||
|
||||
/**
|
||||
@@ -266,7 +271,7 @@ interface EntityManagerInterface extends ObjectManager
|
||||
*
|
||||
* @param string|int $hydrationMode
|
||||
*
|
||||
* @return \Doctrine\ORM\Internal\Hydration\AbstractHydrator
|
||||
* @return AbstractHydrator
|
||||
*
|
||||
* @throws ORMException
|
||||
*/
|
||||
@@ -275,28 +280,28 @@ interface EntityManagerInterface extends ObjectManager
|
||||
/**
|
||||
* Gets the proxy factory used by the EntityManager to create entity proxies.
|
||||
*
|
||||
* @return \Doctrine\ORM\Proxy\ProxyFactory
|
||||
* @return ProxyFactory
|
||||
*/
|
||||
public function getProxyFactory();
|
||||
|
||||
/**
|
||||
* Gets the enabled filters.
|
||||
*
|
||||
* @return \Doctrine\ORM\Query\FilterCollection The active filter collection.
|
||||
* @return FilterCollection The active filter collection.
|
||||
*/
|
||||
public function getFilters();
|
||||
|
||||
/**
|
||||
* Checks whether the state of the filter collection is clean.
|
||||
*
|
||||
* @return boolean True, if the filter collection is clean.
|
||||
* @return bool True, if the filter collection is clean.
|
||||
*/
|
||||
public function isFiltersStateClean();
|
||||
|
||||
/**
|
||||
* Checks whether the Entity Manager has filters.
|
||||
*
|
||||
* @return boolean True, if the EM has a filter collection.
|
||||
* @return bool True, if the EM has a filter collection.
|
||||
*/
|
||||
public function hasFilters();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -19,11 +20,10 @@
|
||||
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
use function implode;
|
||||
|
||||
/**
|
||||
* Exception thrown when a Proxy fails to retrieve an Entity result.
|
||||
*
|
||||
* @author robo
|
||||
* @since 2.0
|
||||
*/
|
||||
class EntityNotFoundException extends ORMException
|
||||
{
|
||||
@@ -43,7 +43,6 @@ class EntityNotFoundException extends ORMException
|
||||
$ids[] = $key . '(' . $value . ')';
|
||||
}
|
||||
|
||||
|
||||
return new self(
|
||||
'Entity of type \'' . $className . '\'' . ($ids ? ' for IDs ' . implode(', ', $ids) : '') . ' was not found'
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -19,16 +20,25 @@
|
||||
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
use BadMethodCallException;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\Common\Collections\Selectable;
|
||||
use Doctrine\Inflector\Inflector;
|
||||
use Doctrine\Inflector\InflectorFactory;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Query\ResultSetMappingBuilder;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
use const E_USER_DEPRECATED;
|
||||
|
||||
use function array_slice;
|
||||
use function lcfirst;
|
||||
use function sprintf;
|
||||
use function strpos;
|
||||
use function substr;
|
||||
use function trigger_error;
|
||||
|
||||
use const E_USER_DEPRECATED;
|
||||
|
||||
/**
|
||||
* An EntityRepository serves as a repository for entities with generic as well as
|
||||
* business specific methods for retrieving entities.
|
||||
@@ -36,31 +46,19 @@ use function trigger_error;
|
||||
* This class is designed for inheritance and users can subclass this class to
|
||||
* write their own repositories with business-specific methods to locate entities.
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*
|
||||
* @template T
|
||||
* @template-implements Selectable<int,T>
|
||||
* @template-implements ObjectRepository<T>
|
||||
*/
|
||||
class EntityRepository implements ObjectRepository, Selectable
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
protected $_entityName;
|
||||
|
||||
/**
|
||||
* @var EntityManager
|
||||
*/
|
||||
/** @var EntityManager */
|
||||
protected $_em;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Mapping\ClassMetadata
|
||||
*/
|
||||
/** @var ClassMetadata */
|
||||
protected $_class;
|
||||
|
||||
/** @var Inflector */
|
||||
@@ -69,7 +67,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
/**
|
||||
* Initializes a new <tt>EntityRepository</tt>.
|
||||
*
|
||||
* @psalm-param Mapping\ClassMetadata<T>
|
||||
* @psalm-param Mapping\ClassMetadata $class
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $em, Mapping\ClassMetadata $class)
|
||||
{
|
||||
@@ -131,8 +129,8 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
*/
|
||||
public function createNativeNamedQuery($queryName)
|
||||
{
|
||||
$queryMapping = $this->_class->getNamedNativeQuery($queryName);
|
||||
$rsm = new Query\ResultSetMappingBuilder($this->_em);
|
||||
$queryMapping = $this->_class->getNamedNativeQuery($queryName);
|
||||
$rsm = new Query\ResultSetMappingBuilder($this->_em);
|
||||
$rsm->addNamedNativeQueryMapping($this->_class, $queryMapping);
|
||||
|
||||
return $this->_em->createNativeQuery($queryMapping['query'], $rsm);
|
||||
@@ -141,9 +139,9 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
/**
|
||||
* Clears the repository, causing all managed entities to become detached.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @deprecated 2.8 This method is being removed from the ORM and won't have any replacement
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
@@ -194,7 +192,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
*
|
||||
* @psalm-return list<T>
|
||||
*/
|
||||
public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null)
|
||||
{
|
||||
$persister = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName);
|
||||
|
||||
@@ -211,7 +209,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
*
|
||||
* @psalm-return ?T
|
||||
*/
|
||||
public function findOneBy(array $criteria, array $orderBy = null)
|
||||
public function findOneBy(array $criteria, ?array $orderBy = null)
|
||||
{
|
||||
$persister = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName);
|
||||
|
||||
@@ -221,11 +219,11 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @todo Add this method to `ObjectRepository` interface in the next major release
|
||||
*/
|
||||
public function count(array $criteria)
|
||||
{
|
||||
@@ -241,26 +239,27 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
* @return mixed The returned value from the resolved method.
|
||||
*
|
||||
* @throws ORMException
|
||||
* @throws \BadMethodCallException If the method called is invalid
|
||||
* @throws BadMethodCallException If the method called is invalid.
|
||||
*/
|
||||
public function __call($method, $arguments)
|
||||
{
|
||||
if (0 === strpos($method, 'findBy')) {
|
||||
if (strpos($method, 'findBy') === 0) {
|
||||
return $this->resolveMagicCall('findBy', substr($method, 6), $arguments);
|
||||
}
|
||||
|
||||
if (0 === strpos($method, 'findOneBy')) {
|
||||
if (strpos($method, 'findOneBy') === 0) {
|
||||
return $this->resolveMagicCall('findOneBy', substr($method, 9), $arguments);
|
||||
}
|
||||
|
||||
if (0 === strpos($method, 'countBy')) {
|
||||
if (strpos($method, 'countBy') === 0) {
|
||||
return $this->resolveMagicCall('count', substr($method, 7), $arguments);
|
||||
}
|
||||
|
||||
throw new \BadMethodCallException(
|
||||
"Undefined method '$method'. The method name must start with ".
|
||||
"either findBy, findOneBy or countBy!"
|
||||
);
|
||||
throw new BadMethodCallException(sprintf(
|
||||
'Undefined method "%s". The method name must start with ' .
|
||||
'either findBy, findOneBy or countBy!',
|
||||
$method
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -299,11 +298,9 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
* Select all elements from a selectable that match the expression and
|
||||
* return a new collection containing these elements.
|
||||
*
|
||||
* @param \Doctrine\Common\Collections\Criteria $criteria
|
||||
* @return Collection
|
||||
*
|
||||
* @return \Doctrine\Common\Collections\Collection
|
||||
*
|
||||
* @psalm-return \Doctrine\Common\Collections\Collection<int, T>
|
||||
* @psalm-return Collection<int, T>
|
||||
*/
|
||||
public function matching(Criteria $criteria)
|
||||
{
|
||||
@@ -319,9 +316,9 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
* @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
|
||||
*
|
||||
* @throws ORMException If the method called is invalid or the requested field/association does not exist.
|
||||
*/
|
||||
private function resolveMagicCall($method, $by, array $arguments)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -19,6 +20,7 @@
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\Persistence\Event\LifecycleEventArgs as BaseLifecycleEventArgs;
|
||||
|
||||
/**
|
||||
@@ -26,9 +28,6 @@ use Doctrine\Persistence\Event\LifecycleEventArgs as BaseLifecycleEventArgs;
|
||||
* of entities.
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.de>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class LifecycleEventArgs extends BaseLifecycleEventArgs
|
||||
{
|
||||
@@ -45,7 +44,7 @@ class LifecycleEventArgs extends BaseLifecycleEventArgs
|
||||
/**
|
||||
* Retrieves associated EntityManager.
|
||||
*
|
||||
* @return \Doctrine\ORM\EntityManager
|
||||
* @return EntityManager
|
||||
*/
|
||||
public function getEntityManager()
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -20,38 +21,33 @@
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
use Doctrine\Common\EventArgs;
|
||||
use Doctrine\Common\EventManager;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Mapping\EntityListenerResolver;
|
||||
|
||||
/**
|
||||
* A method invoker based on entity lifecycle.
|
||||
*
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
* @since 2.4
|
||||
*/
|
||||
class ListenersInvoker
|
||||
{
|
||||
const INVOKE_NONE = 0;
|
||||
const INVOKE_LISTENERS = 1;
|
||||
const INVOKE_CALLBACKS = 2;
|
||||
const INVOKE_MANAGER = 4;
|
||||
public const INVOKE_NONE = 0;
|
||||
public const INVOKE_LISTENERS = 1;
|
||||
public const INVOKE_CALLBACKS = 2;
|
||||
public const INVOKE_MANAGER = 4;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Mapping\EntityListenerResolver The Entity listener resolver.
|
||||
*/
|
||||
/** @var EntityListenerResolver The Entity listener resolver. */
|
||||
private $resolver;
|
||||
|
||||
/**
|
||||
* The EventManager used for dispatching events.
|
||||
*
|
||||
* @var \Doctrine\Common\EventManager
|
||||
* @var EventManager
|
||||
*/
|
||||
private $eventManager;
|
||||
|
||||
/**
|
||||
* Initializes a new ListenersInvoker instance.
|
||||
*
|
||||
* @param EntityManagerInterface $em
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
@@ -62,10 +58,10 @@ class ListenersInvoker
|
||||
/**
|
||||
* Get the subscribed event systems
|
||||
*
|
||||
* @param \Doctrine\ORM\Mapping\ClassMetadata $metadata The entity metadata.
|
||||
* @param string $eventName The entity lifecycle event.
|
||||
* @param ClassMetadata $metadata The entity metadata.
|
||||
* @param string $eventName The entity lifecycle event.
|
||||
*
|
||||
* @return integer Bitmask of subscribed event systems.
|
||||
* @return int Bitmask of subscribed event systems.
|
||||
*/
|
||||
public function getSubscribedSystems(ClassMetadata $metadata, $eventName)
|
||||
{
|
||||
@@ -89,11 +85,11 @@ class ListenersInvoker
|
||||
/**
|
||||
* Dispatches the lifecycle event of the given entity.
|
||||
*
|
||||
* @param \Doctrine\ORM\Mapping\ClassMetadata $metadata The entity metadata.
|
||||
* @param string $eventName The entity lifecycle event.
|
||||
* @param object $entity The Entity on which the event occurred.
|
||||
* @param \Doctrine\Common\EventArgs $event The Event args.
|
||||
* @param integer $invoke Bitmask to invoke listeners.
|
||||
* @param ClassMetadata $metadata The entity metadata.
|
||||
* @param string $eventName The entity lifecycle event.
|
||||
* @param object $entity The Entity on which the event occurred.
|
||||
* @param EventArgs $event The Event args.
|
||||
* @param int $invoke Bitmask to invoke listeners.
|
||||
*/
|
||||
public function invoke(ClassMetadata $metadata, $eventName, $entity, EventArgs $event, $invoke)
|
||||
{
|
||||
@@ -105,9 +101,9 @@ class ListenersInvoker
|
||||
|
||||
if ($invoke & self::INVOKE_LISTENERS) {
|
||||
foreach ($metadata->entityListeners[$eventName] as $listener) {
|
||||
$class = $listener['class'];
|
||||
$method = $listener['method'];
|
||||
$instance = $this->resolver->resolve($class);
|
||||
$class = $listener['class'];
|
||||
$method = $listener['method'];
|
||||
$instance = $this->resolver->resolve($class);
|
||||
|
||||
$instance->$method($entity, $event);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -19,25 +20,22 @@
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\Persistence\Event\LoadClassMetadataEventArgs as BaseLoadClassMetadataEventArgs;
|
||||
|
||||
/**
|
||||
* Class that holds event arguments for a loadMetadata event.
|
||||
*
|
||||
* @author Jonathan H. Wage <jonwage@gmail.com>
|
||||
* @since 2.0
|
||||
*
|
||||
* Note: method annotations are used instead of method overrides (due to BC policy)
|
||||
*
|
||||
* @method __construct(\Doctrine\ORM\Mapping\ClassMetadata $classMetadata, \Doctrine\ORM\EntityManager $objectManager)
|
||||
* @method \Doctrine\ORM\Mapping\ClassMetadata getClassMetadata()
|
||||
* @method __construct(ClassMetadata $classMetadata, EntityManager $objectManager)
|
||||
* @method ClassMetadata getClassMetadata()
|
||||
*/
|
||||
class LoadClassMetadataEventArgs extends BaseLoadClassMetadataEventArgs
|
||||
{
|
||||
/**
|
||||
* Retrieve associated EntityManager.
|
||||
*
|
||||
* @return \Doctrine\ORM\EntityManager
|
||||
* @return EntityManager
|
||||
*/
|
||||
public function getEntityManager()
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -22,34 +23,23 @@ namespace Doctrine\ORM\Event;
|
||||
use Doctrine\Persistence\Event\ManagerEventArgs;
|
||||
use Doctrine\Persistence\Mapping\ClassMetadata;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
use function interface_exists;
|
||||
|
||||
/**
|
||||
* Class that holds event arguments for a `onClassMetadataNotFound` event.
|
||||
*
|
||||
* This object is mutable by design, allowing callbacks having access to it to set the
|
||||
* found metadata in it, and therefore "cancelling" a `onClassMetadataNotFound` event
|
||||
*
|
||||
* @author Marco Pivetta <ocramius@gmail.com>
|
||||
* @since 2.5
|
||||
*/
|
||||
class OnClassMetadataNotFoundEventArgs extends ManagerEventArgs
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
private $className;
|
||||
|
||||
/**
|
||||
* @var ClassMetadata|null
|
||||
*/
|
||||
/** @var ClassMetadata|null */
|
||||
private $foundMetadata;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $className
|
||||
* @param ObjectManager $objectManager
|
||||
* @param string $className
|
||||
*/
|
||||
public function __construct($className, ObjectManager $objectManager)
|
||||
{
|
||||
@@ -58,10 +48,7 @@ class OnClassMetadataNotFoundEventArgs extends ManagerEventArgs
|
||||
parent::__construct($objectManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassMetadata|null $classMetadata
|
||||
*/
|
||||
public function setFoundMetadata(ClassMetadata $classMetadata = null)
|
||||
public function setFoundMetadata(?ClassMetadata $classMetadata = null)
|
||||
{
|
||||
$this->foundMetadata = $classMetadata;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -19,34 +20,25 @@
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
use Doctrine\Common\EventArgs;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* Provides event arguments for the onClear event.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.de>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class OnClearEventArgs extends \Doctrine\Common\EventArgs
|
||||
class OnClearEventArgs extends EventArgs
|
||||
{
|
||||
/**
|
||||
* @var EntityManagerInterface
|
||||
*/
|
||||
/** @var EntityManagerInterface */
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
/** @var string|null */
|
||||
private $entityClass;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param EntityManagerInterface $em
|
||||
* @param string|null $entityClass Optional entity class.
|
||||
* @param string|null $entityClass Optional entity class.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $em, $entityClass = null)
|
||||
{
|
||||
@@ -57,7 +49,7 @@ class OnClearEventArgs extends \Doctrine\Common\EventArgs
|
||||
/**
|
||||
* Retrieves associated EntityManager.
|
||||
*
|
||||
* @return \Doctrine\ORM\EntityManager
|
||||
* @return EntityManager
|
||||
*/
|
||||
public function getEntityManager()
|
||||
{
|
||||
@@ -81,6 +73,6 @@ class OnClearEventArgs extends \Doctrine\Common\EventArgs
|
||||
*/
|
||||
public function clearsAllEntities()
|
||||
{
|
||||
return ($this->entityClass === null);
|
||||
return $this->entityClass === null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -20,29 +21,19 @@
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
use Doctrine\Common\EventArgs;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* Provides event arguments for the preFlush event.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.de>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class OnFlushEventArgs extends EventArgs
|
||||
{
|
||||
/**
|
||||
* @var EntityManagerInterface
|
||||
*/
|
||||
/** @var EntityManagerInterface */
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param EntityManagerInterface $em
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $em;
|
||||
@@ -51,11 +42,10 @@ class OnFlushEventArgs extends EventArgs
|
||||
/**
|
||||
* Retrieve associated EntityManager.
|
||||
*
|
||||
* @return \Doctrine\ORM\EntityManager
|
||||
* @return EntityManager
|
||||
*/
|
||||
public function getEntityManager()
|
||||
{
|
||||
return $this->em;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -16,31 +17,23 @@
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
use Doctrine\Common\EventArgs;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* Provides event arguments for the postFlush event.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @author Daniel Freudenberger <df@rebuy.de>
|
||||
*/
|
||||
class PostFlushEventArgs extends EventArgs
|
||||
{
|
||||
/**
|
||||
* @var \Doctrine\ORM\EntityManager
|
||||
*/
|
||||
/** @var EntityManager */
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param EntityManagerInterface $em
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $em;
|
||||
@@ -49,7 +42,7 @@ class PostFlushEventArgs extends EventArgs
|
||||
/**
|
||||
* Retrieves associated EntityManager.
|
||||
*
|
||||
* @return \Doctrine\ORM\EntityManager
|
||||
* @return EntityManager
|
||||
*/
|
||||
public function getEntityManager()
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -20,36 +21,26 @@
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
use Doctrine\Common\EventArgs;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* Provides event arguments for the preFlush event.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT
|
||||
* @link www.doctrine-project.com
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.de>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class PreFlushEventArgs extends EventArgs
|
||||
{
|
||||
/**
|
||||
* @var \Doctrine\ORM\EntityManager
|
||||
*/
|
||||
/** @var EntityManager */
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param EntityManagerInterface $em
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $em;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Doctrine\ORM\EntityManager
|
||||
* @return EntityManager
|
||||
*/
|
||||
public function getEntityManager()
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -20,28 +21,22 @@
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use InvalidArgumentException;
|
||||
|
||||
use function get_class;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Class that holds event arguments for a preInsert/preUpdate event.
|
||||
*
|
||||
* @author Guilherme Blanco <guilehrmeblanco@hotmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @since 2.0
|
||||
*/
|
||||
class PreUpdateEventArgs extends LifecycleEventArgs
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var array<string,array<int,mixed>> */
|
||||
private $entityChangeSet;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param object $entity
|
||||
* @param EntityManagerInterface $em
|
||||
* @param array $changeSet
|
||||
* @param object $entity
|
||||
* @param array<string,array<int,mixed>> $changeSet
|
||||
*/
|
||||
public function __construct($entity, EntityManagerInterface $em, array &$changeSet)
|
||||
{
|
||||
@@ -53,7 +48,7 @@ class PreUpdateEventArgs extends LifecycleEventArgs
|
||||
/**
|
||||
* Retrieves entity changeset.
|
||||
*
|
||||
* @return array
|
||||
* @return array<string,array<int,mixed>>
|
||||
*/
|
||||
public function getEntityChangeSet()
|
||||
{
|
||||
@@ -65,7 +60,7 @@ class PreUpdateEventArgs extends LifecycleEventArgs
|
||||
*
|
||||
* @param string $field
|
||||
*
|
||||
* @return boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function hasChangedField($field)
|
||||
{
|
||||
@@ -122,12 +117,12 @@ class PreUpdateEventArgs extends LifecycleEventArgs
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function assertValidField($field)
|
||||
{
|
||||
if ( ! isset($this->entityChangeSet[$field])) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
if (! isset($this->entityChangeSet[$field])) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Field "%s" is not a valid field of the entity "%s" in PreUpdateEventArgs.',
|
||||
$field,
|
||||
get_class($this->getEntity())
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -23,9 +24,6 @@ namespace Doctrine\ORM;
|
||||
* Container for all ORM events.
|
||||
*
|
||||
* This class cannot be instantiated.
|
||||
*
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @since 2.0
|
||||
*/
|
||||
final class Events
|
||||
{
|
||||
@@ -41,30 +39,24 @@ final class Events
|
||||
* EntityManager remove operation for that entity is executed.
|
||||
*
|
||||
* This is an entity lifecycle event.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const preRemove = 'preRemove';
|
||||
public const preRemove = 'preRemove';
|
||||
|
||||
/**
|
||||
* The postRemove event occurs for an entity after the entity has
|
||||
* been deleted. It will be invoked after the database delete operations.
|
||||
*
|
||||
* This is an entity lifecycle event.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const postRemove = 'postRemove';
|
||||
public const postRemove = 'postRemove';
|
||||
|
||||
/**
|
||||
* The prePersist event occurs for a given entity before the respective
|
||||
* EntityManager persist operation for that entity is executed.
|
||||
*
|
||||
* This is an entity lifecycle event.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const prePersist = 'prePersist';
|
||||
public const prePersist = 'prePersist';
|
||||
|
||||
/**
|
||||
* The postPersist event occurs for an entity after the entity has
|
||||
@@ -72,30 +64,24 @@ final class Events
|
||||
* Generated primary key values are available in the postPersist event.
|
||||
*
|
||||
* This is an entity lifecycle event.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const postPersist = 'postPersist';
|
||||
public const postPersist = 'postPersist';
|
||||
|
||||
/**
|
||||
* The preUpdate event occurs before the database update operations to
|
||||
* entity data.
|
||||
*
|
||||
* This is an entity lifecycle event.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const preUpdate = 'preUpdate';
|
||||
public const preUpdate = 'preUpdate';
|
||||
|
||||
/**
|
||||
* The postUpdate event occurs after the database update operations to
|
||||
* entity data.
|
||||
*
|
||||
* This is an entity lifecycle event.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const postUpdate = 'postUpdate';
|
||||
public const postUpdate = 'postUpdate';
|
||||
|
||||
/**
|
||||
* The postLoad event occurs for an entity after the entity has been loaded
|
||||
@@ -107,33 +93,27 @@ final class Events
|
||||
* or event handler.
|
||||
*
|
||||
* This is an entity lifecycle event.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const postLoad = 'postLoad';
|
||||
public const postLoad = 'postLoad';
|
||||
|
||||
/**
|
||||
* The loadClassMetadata event occurs after the mapping metadata for a class
|
||||
* has been loaded from a mapping source (annotations/xml/yaml).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const loadClassMetadata = 'loadClassMetadata';
|
||||
public const loadClassMetadata = 'loadClassMetadata';
|
||||
|
||||
/**
|
||||
* The onClassMetadataNotFound event occurs whenever loading metadata for a class
|
||||
* failed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const onClassMetadataNotFound = 'onClassMetadataNotFound';
|
||||
public const onClassMetadataNotFound = 'onClassMetadataNotFound';
|
||||
|
||||
/**
|
||||
* The preFlush event occurs when the EntityManager#flush() operation is invoked,
|
||||
* but before any changes to managed entities have been calculated. This event is
|
||||
* always raised right after EntityManager#flush() call.
|
||||
*/
|
||||
const preFlush = 'preFlush';
|
||||
public const preFlush = 'preFlush';
|
||||
|
||||
/**
|
||||
* The onFlush event occurs when the EntityManager#flush() operation is invoked,
|
||||
@@ -141,10 +121,8 @@ final class Events
|
||||
* actual database operations are executed. The event is only raised if there is
|
||||
* actually something to do for the underlying UnitOfWork. If nothing needs to be done,
|
||||
* the onFlush event is not raised.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const onFlush = 'onFlush';
|
||||
public const onFlush = 'onFlush';
|
||||
|
||||
/**
|
||||
* The postFlush event occurs when the EntityManager#flush() operation is invoked and
|
||||
@@ -152,16 +130,12 @@ final class Events
|
||||
* actually something to do for the underlying UnitOfWork. If nothing needs to be done,
|
||||
* the postFlush event is not raised. The event won't be raised if an error occurs during the
|
||||
* flush operation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const postFlush = 'postFlush';
|
||||
public const postFlush = 'postFlush';
|
||||
|
||||
/**
|
||||
* The onClear event occurs when the EntityManager#clear() operation is invoked,
|
||||
* after all references to entities have been removed from the unit of work.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const onClear = 'onClear';
|
||||
public const onClear = 'onClear';
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -26,8 +27,8 @@ abstract class AbstractIdGenerator
|
||||
/**
|
||||
* Generates an identifier for an entity.
|
||||
*
|
||||
* @param EntityManager $em
|
||||
* @param object|null $entity
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function generate(EntityManager $em, $entity);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -22,14 +23,10 @@ namespace Doctrine\ORM\Id;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\ORMException;
|
||||
|
||||
use function get_class;
|
||||
|
||||
/**
|
||||
* Special generator for application-assigned identifiers (doesn't really generate anything).
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class AssignedGenerator extends AbstractIdGenerator
|
||||
{
|
||||
@@ -38,7 +35,7 @@ class AssignedGenerator extends AbstractIdGenerator
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \Doctrine\ORM\ORMException
|
||||
* @throws ORMException
|
||||
*/
|
||||
public function generate(EntityManager $em, $entity)
|
||||
{
|
||||
@@ -49,7 +46,7 @@ class AssignedGenerator extends AbstractIdGenerator
|
||||
foreach ($idFields as $idField) {
|
||||
$value = $class->getFieldValue($entity, $idField);
|
||||
|
||||
if ( ! isset($value)) {
|
||||
if (! isset($value)) {
|
||||
throw ORMException::entityMissingAssignedIdForField($entity, $idField);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -36,8 +37,6 @@ class BigIntegerIdentityGenerator extends AbstractIdGenerator
|
||||
private $sequenceName;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string|null $sequenceName The name of the sequence to pass to lastInsertId()
|
||||
* to obtain the last generated identifier within the current
|
||||
* database session/connection, if any.
|
||||
@@ -63,4 +62,3 @@ class BigIntegerIdentityGenerator extends AbstractIdGenerator
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -36,8 +37,6 @@ class IdentityGenerator extends AbstractIdGenerator
|
||||
private $sequenceName;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string|null $sequenceName The name of the sequence to pass to lastInsertId()
|
||||
* to obtain the last generated identifier within the current
|
||||
* database session/connection, if any.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -22,11 +23,11 @@ namespace Doctrine\ORM\Id;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Serializable;
|
||||
|
||||
use function serialize;
|
||||
use function unserialize;
|
||||
|
||||
/**
|
||||
* Represents an ID generator that uses a database sequence.
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
{
|
||||
@@ -44,25 +45,21 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
*/
|
||||
private $_sequenceName;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
/** @var int */
|
||||
private $_nextValue = 0;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
/** @var int|null */
|
||||
private $_maxValue = null;
|
||||
|
||||
/**
|
||||
* Initializes a new sequence generator.
|
||||
*
|
||||
* @param string $sequenceName The name of the sequence.
|
||||
* @param integer $allocationSize The allocation size of the sequence.
|
||||
* @param string $sequenceName The name of the sequence.
|
||||
* @param int $allocationSize The allocation size of the sequence.
|
||||
*/
|
||||
public function __construct($sequenceName, $allocationSize)
|
||||
{
|
||||
$this->_sequenceName = $sequenceName;
|
||||
$this->_sequenceName = $sequenceName;
|
||||
$this->_allocationSize = $allocationSize;
|
||||
}
|
||||
|
||||
@@ -71,7 +68,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
*/
|
||||
public function generate(EntityManager $em, $entity)
|
||||
{
|
||||
if ($this->_maxValue === null || $this->_nextValue == $this->_maxValue) {
|
||||
if ($this->_maxValue === null || $this->_nextValue === $this->_maxValue) {
|
||||
// Allocate new values
|
||||
$conn = $em->getConnection();
|
||||
$sql = $conn->getDatabasePlatform()->getSequenceNextValSQL($this->_sequenceName);
|
||||
@@ -87,7 +84,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
/**
|
||||
* Gets the maximum value of the currently allocated bag of values.
|
||||
*
|
||||
* @return integer|null
|
||||
* @return int|null
|
||||
*/
|
||||
public function getCurrentMaxValue()
|
||||
{
|
||||
@@ -97,7 +94,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
/**
|
||||
* Gets the next value that will be returned by generate().
|
||||
*
|
||||
* @return integer
|
||||
* @return int
|
||||
*/
|
||||
public function getNextValue()
|
||||
{
|
||||
@@ -111,8 +108,8 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
{
|
||||
return serialize(
|
||||
[
|
||||
'allocationSize' => $this->_allocationSize,
|
||||
'sequenceName' => $this->_sequenceName
|
||||
'allocationSize' => $this->_allocationSize,
|
||||
'sequenceName' => $this->_sequenceName,
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -126,7 +123,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
{
|
||||
$array = unserialize($serialized);
|
||||
|
||||
$this->_sequenceName = $array['sequenceName'];
|
||||
$this->_sequenceName = $array['sequenceName'];
|
||||
$this->_allocationSize = $array['allocationSize'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -23,38 +24,22 @@ use Doctrine\ORM\EntityManager;
|
||||
|
||||
/**
|
||||
* Id generator that uses a single-row database table and a hi/lo algorithm.
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class TableGenerator extends AbstractIdGenerator
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
private $_tableName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
private $_sequenceName;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
/** @var int */
|
||||
private $_allocationSize;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
/** @var int|null */
|
||||
private $_nextValue;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
/** @var int|null */
|
||||
private $_maxValue;
|
||||
|
||||
/**
|
||||
@@ -64,8 +49,8 @@ class TableGenerator extends AbstractIdGenerator
|
||||
*/
|
||||
public function __construct($tableName, $sequenceName = 'default', $allocationSize = 10)
|
||||
{
|
||||
$this->_tableName = $tableName;
|
||||
$this->_sequenceName = $sequenceName;
|
||||
$this->_tableName = $tableName;
|
||||
$this->_sequenceName = $sequenceName;
|
||||
$this->_allocationSize = $allocationSize;
|
||||
}
|
||||
|
||||
@@ -73,9 +58,10 @@ class TableGenerator extends AbstractIdGenerator
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function generate(
|
||||
EntityManager $em, $entity)
|
||||
{
|
||||
if ($this->_maxValue === null || $this->_nextValue == $this->_maxValue) {
|
||||
EntityManager $em,
|
||||
$entity
|
||||
) {
|
||||
if ($this->_maxValue === null || $this->_nextValue === $this->_maxValue) {
|
||||
// Allocate new values
|
||||
$conn = $em->getConnection();
|
||||
|
||||
@@ -84,15 +70,17 @@ class TableGenerator extends AbstractIdGenerator
|
||||
$sql = $conn->getDatabasePlatform()->getTableHiLoCurrentValSql($this->_tableName, $this->_sequenceName);
|
||||
$currentLevel = $conn->fetchColumn($sql);
|
||||
|
||||
if ($currentLevel != null) {
|
||||
if ($currentLevel !== null) {
|
||||
$this->_nextValue = $currentLevel;
|
||||
$this->_maxValue = $this->_nextValue + $this->_allocationSize;
|
||||
$this->_maxValue = $this->_nextValue + $this->_allocationSize;
|
||||
|
||||
$updateSql = $conn->getDatabasePlatform()->getTableHiLoUpdateNextValSql(
|
||||
$this->_tableName, $this->_sequenceName, $this->_allocationSize
|
||||
$this->_tableName,
|
||||
$this->_sequenceName,
|
||||
$this->_allocationSize
|
||||
);
|
||||
|
||||
if ($conn->executeUpdate($updateSql, [1 => $currentLevel, 2 => $currentLevel+1]) !== 1) {
|
||||
if ($conn->executeUpdate($updateSql, [1 => $currentLevel, 2 => $currentLevel + 1]) !== 1) {
|
||||
// no affected rows, concurrency issue, throw exception
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -23,9 +24,6 @@ use Doctrine\ORM\EntityManager;
|
||||
|
||||
/**
|
||||
* Represents an ID generator that uses the database UUID expression
|
||||
*
|
||||
* @since 2.3
|
||||
* @author Maarten de Keizer <m.de.keizer@markei.nl>
|
||||
*/
|
||||
class UuidGenerator extends AbstractIdGenerator
|
||||
{
|
||||
@@ -35,7 +33,7 @@ class UuidGenerator extends AbstractIdGenerator
|
||||
public function generate(EntityManager $em, $entity)
|
||||
{
|
||||
$conn = $em->getConnection();
|
||||
$sql = 'SELECT ' . $conn->getDatabasePlatform()->getGuidExpression();
|
||||
$sql = 'SELECT ' . $conn->getDatabasePlatform()->getGuidExpression();
|
||||
|
||||
return $conn->query($sql)->fetchColumn(0);
|
||||
}
|
||||
|
||||
@@ -20,22 +20,22 @@
|
||||
|
||||
namespace Doctrine\ORM\Internal;
|
||||
|
||||
use stdClass;
|
||||
|
||||
use function array_reverse;
|
||||
|
||||
/**
|
||||
* CommitOrderCalculator implements topological sorting, which is an ordering
|
||||
* algorithm for directed graphs (DG) and/or directed acyclic graphs (DAG) by
|
||||
* using a depth-first searching (DFS) to traverse the graph built in memory.
|
||||
* This algorithm have a linear running time based on nodes (V) and dependency
|
||||
* between the nodes (E), resulting in a computational complexity of O(V + E).
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class CommitOrderCalculator
|
||||
{
|
||||
const NOT_VISITED = 0;
|
||||
const IN_PROGRESS = 1;
|
||||
const VISITED = 2;
|
||||
public const NOT_VISITED = 0;
|
||||
public const IN_PROGRESS = 1;
|
||||
public const VISITED = 2;
|
||||
|
||||
/**
|
||||
* Matrix of nodes (aka. vertex).
|
||||
@@ -52,14 +52,14 @@ class CommitOrderCalculator
|
||||
* - <b>dependencyList</b> (array<string>)
|
||||
* Map of node dependencies defined as hashes.
|
||||
*
|
||||
* @var array<\stdClass>
|
||||
* @var array<stdClass>
|
||||
*/
|
||||
private $nodeList = [];
|
||||
|
||||
/**
|
||||
* Volatile variable holding calculated nodes during sorting process.
|
||||
*
|
||||
* @var array
|
||||
* @psalm-var list<object>
|
||||
*/
|
||||
private $sortedNodeList = [];
|
||||
|
||||
@@ -68,7 +68,7 @@ class CommitOrderCalculator
|
||||
*
|
||||
* @param string $hash
|
||||
*
|
||||
* @return boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function hasNode($hash)
|
||||
{
|
||||
@@ -85,7 +85,7 @@ class CommitOrderCalculator
|
||||
*/
|
||||
public function addNode($hash, $node)
|
||||
{
|
||||
$vertex = new \stdClass();
|
||||
$vertex = new stdClass();
|
||||
|
||||
$vertex->hash = $hash;
|
||||
$vertex->state = self::NOT_VISITED;
|
||||
@@ -98,16 +98,16 @@ class CommitOrderCalculator
|
||||
/**
|
||||
* Adds a new dependency (edge) to the graph using their hashes.
|
||||
*
|
||||
* @param string $fromHash
|
||||
* @param string $toHash
|
||||
* @param integer $weight
|
||||
* @param string $fromHash
|
||||
* @param string $toHash
|
||||
* @param int $weight
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addDependency($fromHash, $toHash, $weight)
|
||||
{
|
||||
$vertex = $this->nodeList[$fromHash];
|
||||
$edge = new \stdClass();
|
||||
$edge = new stdClass();
|
||||
|
||||
$edge->from = $fromHash;
|
||||
$edge->to = $toHash;
|
||||
@@ -122,7 +122,7 @@ class CommitOrderCalculator
|
||||
*
|
||||
* {@internal Highly performance-sensitive method.}
|
||||
*
|
||||
* @return array
|
||||
* @psalm-return list<object>
|
||||
*/
|
||||
public function sort()
|
||||
{
|
||||
@@ -147,7 +147,7 @@ class CommitOrderCalculator
|
||||
*
|
||||
* {@internal Highly performance-sensitive method.}
|
||||
*
|
||||
* @param \stdClass $vertex
|
||||
* @param stdClass $vertex
|
||||
*/
|
||||
private function visit($vertex)
|
||||
{
|
||||
@@ -162,9 +162,10 @@ class CommitOrderCalculator
|
||||
break;
|
||||
|
||||
case self::IN_PROGRESS:
|
||||
if (isset($adjacentVertex->dependencyList[$vertex->hash]) &&
|
||||
$adjacentVertex->dependencyList[$vertex->hash]->weight < $edge->weight) {
|
||||
|
||||
if (
|
||||
isset($adjacentVertex->dependencyList[$vertex->hash]) &&
|
||||
$adjacentVertex->dependencyList[$vertex->hash]->weight < $edge->weight
|
||||
) {
|
||||
// If we have some non-visited dependencies in the in-progress dependency, we
|
||||
// need to visit them before adding the node.
|
||||
foreach ($adjacentVertex->dependencyList as $adjacentEdge) {
|
||||
@@ -179,6 +180,7 @@ class CommitOrderCalculator
|
||||
|
||||
$this->sortedNodeList[] = $adjacentVertex->value;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case self::NOT_VISITED:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -21,34 +22,36 @@ namespace Doctrine\ORM\Internal\Hydration;
|
||||
|
||||
use Doctrine\DBAL\Driver\Statement;
|
||||
use Doctrine\DBAL\FetchMode;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Events;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
use PDO;
|
||||
use const E_USER_DEPRECATED;
|
||||
use ReflectionClass;
|
||||
|
||||
use function array_map;
|
||||
use function array_merge;
|
||||
use function count;
|
||||
use function end;
|
||||
use function in_array;
|
||||
use function trigger_error;
|
||||
|
||||
use const E_USER_DEPRECATED;
|
||||
|
||||
/**
|
||||
* Base class for all hydrators. A hydrator is a class that provides some form
|
||||
* of transformation of an SQL result set into another structure.
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
|
||||
*/
|
||||
abstract class AbstractHydrator
|
||||
{
|
||||
/**
|
||||
* The ResultSetMapping.
|
||||
*
|
||||
* @var \Doctrine\ORM\Query\ResultSetMapping
|
||||
* @var ResultSetMapping
|
||||
*/
|
||||
protected $_rsm;
|
||||
|
||||
@@ -62,14 +65,14 @@ abstract class AbstractHydrator
|
||||
/**
|
||||
* The dbms Platform instance.
|
||||
*
|
||||
* @var \Doctrine\DBAL\Platforms\AbstractPlatform
|
||||
* @var AbstractPlatform
|
||||
*/
|
||||
protected $_platform;
|
||||
|
||||
/**
|
||||
* The UnitOfWork of the associated EntityManager.
|
||||
*
|
||||
* @var \Doctrine\ORM\UnitOfWork
|
||||
* @var UnitOfWork
|
||||
*/
|
||||
protected $_uow;
|
||||
|
||||
@@ -90,7 +93,7 @@ abstract class AbstractHydrator
|
||||
/**
|
||||
* The statement that provides the data to hydrate.
|
||||
*
|
||||
* @var \Doctrine\DBAL\Driver\Statement
|
||||
* @var Statement
|
||||
*/
|
||||
protected $_stmt;
|
||||
|
||||
@@ -151,7 +154,7 @@ abstract class AbstractHydrator
|
||||
*
|
||||
* @return iterable<mixed>
|
||||
*/
|
||||
public function toIterable(Statement $stmt, ResultSetMapping $resultSetMapping, array $hints = []) : iterable
|
||||
public function toIterable(Statement $stmt, ResultSetMapping $resultSetMapping, array $hints = []): iterable
|
||||
{
|
||||
$this->_stmt = $stmt;
|
||||
$this->_rsm = $resultSetMapping;
|
||||
@@ -163,8 +166,6 @@ abstract class AbstractHydrator
|
||||
|
||||
$this->prepare();
|
||||
|
||||
$result = [];
|
||||
|
||||
while (true) {
|
||||
$row = $this->_stmt->fetch(FetchMode::ASSOCIATIVE);
|
||||
|
||||
@@ -174,9 +175,17 @@ abstract class AbstractHydrator
|
||||
break;
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
$this->hydrateRowData($row, $result);
|
||||
|
||||
yield end($result);
|
||||
$this->cleanupAfterRowIteration();
|
||||
|
||||
if (count($result) === 1) {
|
||||
yield end($result);
|
||||
} else {
|
||||
yield $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,6 +281,10 @@ abstract class AbstractHydrator
|
||||
->removeEventListener([Events::onClear], $this);
|
||||
}
|
||||
|
||||
protected function cleanupAfterRowIteration(): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Hydrates a single row from the current statement instance.
|
||||
*
|
||||
@@ -286,13 +299,13 @@ abstract class AbstractHydrator
|
||||
*/
|
||||
protected function hydrateRowData(array $row, array &$result)
|
||||
{
|
||||
throw new HydrationException("hydrateRowData() not implemented by this hydrator.");
|
||||
throw new HydrationException('hydrateRowData() not implemented by this hydrator.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Hydrates all rows from the current statement instance at once.
|
||||
*
|
||||
* @return array
|
||||
* @return mixed[]
|
||||
*/
|
||||
abstract protected function hydrateAllData();
|
||||
|
||||
@@ -305,9 +318,9 @@ abstract class AbstractHydrator
|
||||
* field names during this procedure as well as any necessary conversions on
|
||||
* the values applied. Scalar values are kept in a specific key 'scalars'.
|
||||
*
|
||||
* @param array $data SQL Result Row.
|
||||
* @param array &$id Dql-Alias => ID-Hash.
|
||||
* @param array &$nonemptyComponents Does this DQL-Alias has at least one non NULL value?
|
||||
* @param mixed[] $data SQL Result Row.
|
||||
* @param array &$id Dql-Alias => ID-Hash.
|
||||
* @param array &$nonemptyComponents Does this DQL-Alias has at least one non NULL value?
|
||||
*
|
||||
* @return array<string, array<string, mixed>> An array with all the fields
|
||||
* (name => value) of the data
|
||||
@@ -335,7 +348,7 @@ abstract class AbstractHydrator
|
||||
$fieldName = $cacheKeyInfo['fieldName'];
|
||||
|
||||
switch (true) {
|
||||
case (isset($cacheKeyInfo['isNewObjectParameter'])):
|
||||
case isset($cacheKeyInfo['isNewObjectParameter']):
|
||||
$argIndex = $cacheKeyInfo['argIndex'];
|
||||
$objIndex = $cacheKeyInfo['objIndex'];
|
||||
$type = $cacheKeyInfo['type'];
|
||||
@@ -345,7 +358,7 @@ abstract class AbstractHydrator
|
||||
$rowData['newObjects'][$objIndex]['args'][$argIndex] = $value;
|
||||
break;
|
||||
|
||||
case (isset($cacheKeyInfo['isScalar'])):
|
||||
case isset($cacheKeyInfo['isScalar']):
|
||||
$type = $cacheKeyInfo['type'];
|
||||
$value = $type->convertToPHPValue($value, $this->_platform);
|
||||
|
||||
@@ -359,7 +372,8 @@ abstract class AbstractHydrator
|
||||
|
||||
// If there are field name collisions in the child class, then we need
|
||||
// to only hydrate if we are looking at the correct discriminator value
|
||||
if (isset($cacheKeyInfo['discriminatorColumn'], $data[$cacheKeyInfo['discriminatorColumn']])
|
||||
if (
|
||||
isset($cacheKeyInfo['discriminatorColumn'], $data[$cacheKeyInfo['discriminatorColumn']])
|
||||
&& ! in_array((string) $data[$cacheKeyInfo['discriminatorColumn']], $cacheKeyInfo['discriminatorValues'], true)
|
||||
) {
|
||||
break;
|
||||
@@ -377,9 +391,10 @@ abstract class AbstractHydrator
|
||||
: $value;
|
||||
|
||||
if ($cacheKeyInfo['isIdentifier'] && $value !== null) {
|
||||
$id[$dqlAlias] .= '|' . $value;
|
||||
$id[$dqlAlias] .= '|' . $value;
|
||||
$nonemptyComponents[$dqlAlias] = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -440,13 +455,13 @@ abstract class AbstractHydrator
|
||||
|
||||
switch (true) {
|
||||
// NOTE: Most of the times it's a field mapping, so keep it first!!!
|
||||
case (isset($this->_rsm->fieldMappings[$key])):
|
||||
case isset($this->_rsm->fieldMappings[$key]):
|
||||
$classMetadata = $this->getClassMetadata($this->_rsm->declaringClasses[$key]);
|
||||
$fieldName = $this->_rsm->fieldMappings[$key];
|
||||
$fieldMapping = $classMetadata->fieldMappings[$fieldName];
|
||||
$ownerMap = $this->_rsm->columnOwnerMap[$key];
|
||||
$columnInfo = [
|
||||
'isIdentifier' => \in_array($fieldName, $classMetadata->identifier, true),
|
||||
'isIdentifier' => in_array($fieldName, $classMetadata->identifier, true),
|
||||
'fieldName' => $fieldName,
|
||||
'type' => Type::getType($fieldMapping['type']),
|
||||
'dqlAlias' => $ownerMap,
|
||||
@@ -455,7 +470,7 @@ abstract class AbstractHydrator
|
||||
// the current discriminator value must be saved in order to disambiguate fields hydration,
|
||||
// should there be field name collisions
|
||||
if ($classMetadata->parentClasses && isset($this->_rsm->discriminatorColumns[$ownerMap])) {
|
||||
return $this->_cache[$key] = \array_merge(
|
||||
return $this->_cache[$key] = array_merge(
|
||||
$columnInfo,
|
||||
[
|
||||
'discriminatorColumn' => $this->_rsm->discriminatorColumns[$ownerMap],
|
||||
@@ -467,7 +482,7 @@ abstract class AbstractHydrator
|
||||
|
||||
return $this->_cache[$key] = $columnInfo;
|
||||
|
||||
case (isset($this->_rsm->newObjectMappings[$key])):
|
||||
case isset($this->_rsm->newObjectMappings[$key]):
|
||||
// WARNING: A NEW object is also a scalar, so it must be declared before!
|
||||
$mapping = $this->_rsm->newObjectMappings[$key];
|
||||
|
||||
@@ -478,7 +493,7 @@ abstract class AbstractHydrator
|
||||
'type' => Type::getType($this->_rsm->typeMappings[$key]),
|
||||
'argIndex' => $mapping['argIndex'],
|
||||
'objIndex' => $mapping['objIndex'],
|
||||
'class' => new \ReflectionClass($mapping['className']),
|
||||
'class' => new ReflectionClass($mapping['className']),
|
||||
];
|
||||
|
||||
case isset($this->_rsm->scalarMappings[$key], $this->_hints[LimitSubqueryWalker::FORCE_DBAL_TYPE_CONVERSION]):
|
||||
@@ -487,14 +502,15 @@ abstract class AbstractHydrator
|
||||
'type' => Type::getType($this->_rsm->typeMappings[$key]),
|
||||
'dqlAlias' => '',
|
||||
];
|
||||
case (isset($this->_rsm->scalarMappings[$key])):
|
||||
|
||||
case isset($this->_rsm->scalarMappings[$key]):
|
||||
return $this->_cache[$key] = [
|
||||
'isScalar' => true,
|
||||
'fieldName' => $this->_rsm->scalarMappings[$key],
|
||||
'type' => Type::getType($this->_rsm->typeMappings[$key]),
|
||||
];
|
||||
|
||||
case (isset($this->_rsm->metaMappings[$key])):
|
||||
case isset($this->_rsm->metaMappings[$key]):
|
||||
// Meta column (has meaning in relational schema only, i.e. foreign keys or discriminator columns).
|
||||
$fieldName = $this->_rsm->metaMappings[$key];
|
||||
$dqlAlias = $this->_rsm->columnOwnerMap[$key];
|
||||
@@ -522,10 +538,10 @@ abstract class AbstractHydrator
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function getDiscriminatorValues(ClassMetadata $classMetadata) : array
|
||||
private function getDiscriminatorValues(ClassMetadata $classMetadata): array
|
||||
{
|
||||
$values = array_map(
|
||||
function (string $subClass) : string {
|
||||
function (string $subClass): string {
|
||||
return (string) $this->getClassMetadata($subClass)->discriminatorValue;
|
||||
},
|
||||
$classMetadata->subClasses
|
||||
@@ -541,11 +557,11 @@ abstract class AbstractHydrator
|
||||
*
|
||||
* @param string $className
|
||||
*
|
||||
* @return \Doctrine\ORM\Mapping\ClassMetadata
|
||||
* @return ClassMetadata
|
||||
*/
|
||||
protected function getClassMetadata($className)
|
||||
{
|
||||
if ( ! isset($this->_metadataCache[$className])) {
|
||||
if (! isset($this->_metadataCache[$className])) {
|
||||
$this->_metadataCache[$className] = $this->_em->getClassMetadata($className);
|
||||
}
|
||||
|
||||
@@ -555,9 +571,8 @@ abstract class AbstractHydrator
|
||||
/**
|
||||
* Register entity as managed in UnitOfWork.
|
||||
*
|
||||
* @param ClassMetadata $class
|
||||
* @param object $entity
|
||||
* @param array $data
|
||||
* @param object $entity
|
||||
* @param mixed[] $data
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
@@ -578,7 +593,7 @@ abstract class AbstractHydrator
|
||||
$id = [
|
||||
$fieldName => isset($class->associationMappings[$fieldName])
|
||||
? $data[$class->associationMappings[$fieldName]['joinColumns'][0]['name']]
|
||||
: $data[$fieldName]
|
||||
: $data[$fieldName],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -19,47 +20,37 @@
|
||||
|
||||
namespace Doctrine\ORM\Internal\Hydration;
|
||||
|
||||
use PDO;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use PDO;
|
||||
|
||||
use function count;
|
||||
use function end;
|
||||
use function is_array;
|
||||
use function key;
|
||||
use function reset;
|
||||
|
||||
/**
|
||||
* The ArrayHydrator produces a nested array "graph" that is often (not always)
|
||||
* interchangeable with the corresponding object graph for read-only access.
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
|
||||
*/
|
||||
class ArrayHydrator extends AbstractHydrator
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var array<string,bool> */
|
||||
private $_rootAliases = [];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
/** @var bool */
|
||||
private $_isSimpleQuery = false;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var mixed[] */
|
||||
private $_identifierMap = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var mixed[] */
|
||||
private $_resultPointers = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var array<string,string> */
|
||||
private $_idTemplate = [];
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
/** @var int */
|
||||
private $_resultCounter = 0;
|
||||
|
||||
/**
|
||||
@@ -96,9 +87,9 @@ class ArrayHydrator extends AbstractHydrator
|
||||
protected function hydrateRowData(array $row, array &$result)
|
||||
{
|
||||
// 1) Initialize
|
||||
$id = $this->_idTemplate; // initialize the id-memory
|
||||
$id = $this->_idTemplate; // initialize the id-memory
|
||||
$nonemptyComponents = [];
|
||||
$rowData = $this->gatherRowData($row, $id, $nonemptyComponents);
|
||||
$rowData = $this->gatherRowData($row, $id, $nonemptyComponents);
|
||||
|
||||
// 2) Now hydrate the data found in the current row.
|
||||
foreach ($rowData['data'] as $dqlAlias => $data) {
|
||||
@@ -111,7 +102,7 @@ class ArrayHydrator extends AbstractHydrator
|
||||
$path = $parent . '.' . $dqlAlias;
|
||||
|
||||
// missing parent data, skipping as RIGHT JOIN hydration is not supported.
|
||||
if ( ! isset($nonemptyComponents[$parent]) ) {
|
||||
if (! isset($nonemptyComponents[$parent])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -121,7 +112,7 @@ class ArrayHydrator extends AbstractHydrator
|
||||
$first = reset($this->_resultPointers);
|
||||
// TODO: Exception if $key === null ?
|
||||
$baseElement =& $this->_resultPointers[$parent][key($first)];
|
||||
} else if (isset($this->_resultPointers[$parent])) {
|
||||
} elseif (isset($this->_resultPointers[$parent])) {
|
||||
$baseElement =& $this->_resultPointers[$parent];
|
||||
} else {
|
||||
unset($this->_resultPointers[$dqlAlias]); // Ticket #1228
|
||||
@@ -134,10 +125,10 @@ class ArrayHydrator extends AbstractHydrator
|
||||
$relation = $parentClass->associationMappings[$relationAlias];
|
||||
|
||||
// Check the type of the relation (many or single-valued)
|
||||
if ( ! ($relation['type'] & ClassMetadata::TO_ONE)) {
|
||||
if (! ($relation['type'] & ClassMetadata::TO_ONE)) {
|
||||
$oneToOne = false;
|
||||
|
||||
if ( ! isset($baseElement[$relationAlias])) {
|
||||
if (! isset($baseElement[$relationAlias])) {
|
||||
$baseElement[$relationAlias] = [];
|
||||
}
|
||||
|
||||
@@ -146,7 +137,7 @@ class ArrayHydrator extends AbstractHydrator
|
||||
$index = $indexExists ? $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] : false;
|
||||
$indexIsValid = $index !== false ? isset($baseElement[$relationAlias][$index]) : false;
|
||||
|
||||
if ( ! $indexExists || ! $indexIsValid) {
|
||||
if (! $indexExists || ! $indexIsValid) {
|
||||
$element = $data;
|
||||
|
||||
if (isset($this->_rsm->indexByMap[$dqlAlias])) {
|
||||
@@ -164,11 +155,11 @@ class ArrayHydrator extends AbstractHydrator
|
||||
$oneToOne = true;
|
||||
|
||||
if (
|
||||
( ! isset($nonemptyComponents[$dqlAlias])) &&
|
||||
! isset($nonemptyComponents[$dqlAlias]) &&
|
||||
( ! isset($baseElement[$relationAlias]))
|
||||
) {
|
||||
$baseElement[$relationAlias] = null;
|
||||
} else if ( ! isset($baseElement[$relationAlias])) {
|
||||
} elseif (! isset($baseElement[$relationAlias])) {
|
||||
$baseElement[$relationAlias] = $data;
|
||||
}
|
||||
}
|
||||
@@ -182,10 +173,10 @@ class ArrayHydrator extends AbstractHydrator
|
||||
// It's a root result element
|
||||
|
||||
$this->_rootAliases[$dqlAlias] = true; // Mark as root
|
||||
$entityKey = $this->_rsm->entityMappings[$dqlAlias] ?: 0;
|
||||
$entityKey = $this->_rsm->entityMappings[$dqlAlias] ?: 0;
|
||||
|
||||
// if this row has a NULL value for the root result id then make it a null result.
|
||||
if ( ! isset($nonemptyComponents[$dqlAlias]) ) {
|
||||
if (! isset($nonemptyComponents[$dqlAlias])) {
|
||||
$result[] = $this->_rsm->isMixed
|
||||
? [$entityKey => null]
|
||||
: null;
|
||||
@@ -203,18 +194,18 @@ class ArrayHydrator extends AbstractHydrator
|
||||
: $data;
|
||||
|
||||
if (isset($this->_rsm->indexByMap[$dqlAlias])) {
|
||||
$resultKey = $row[$this->_rsm->indexByMap[$dqlAlias]];
|
||||
$resultKey = $row[$this->_rsm->indexByMap[$dqlAlias]];
|
||||
$result[$resultKey] = $element;
|
||||
} else {
|
||||
$resultKey = $this->_resultCounter;
|
||||
$result[] = $element;
|
||||
$result[] = $element;
|
||||
|
||||
++$this->_resultCounter;
|
||||
}
|
||||
|
||||
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey;
|
||||
} else {
|
||||
$index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]];
|
||||
$index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]];
|
||||
$resultKey = $index;
|
||||
}
|
||||
|
||||
@@ -222,13 +213,13 @@ class ArrayHydrator extends AbstractHydrator
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! isset($resultKey)) {
|
||||
if (! isset($resultKey)) {
|
||||
$this->_resultCounter++;
|
||||
}
|
||||
|
||||
// Append scalar values to mixed result sets
|
||||
if (isset($rowData['scalars'])) {
|
||||
if ( ! isset($resultKey)) {
|
||||
if (! isset($resultKey)) {
|
||||
// this only ever happens when no object is fetched (scalar result only)
|
||||
$resultKey = isset($this->_rsm->indexByMap['scalars'])
|
||||
? $row[$this->_rsm->indexByMap['scalars']]
|
||||
@@ -242,18 +233,18 @@ class ArrayHydrator extends AbstractHydrator
|
||||
|
||||
// Append new object to mixed result sets
|
||||
if (isset($rowData['newObjects'])) {
|
||||
if ( ! isset($resultKey)) {
|
||||
if (! isset($resultKey)) {
|
||||
$resultKey = $this->_resultCounter - 1;
|
||||
}
|
||||
|
||||
$scalarCount = (isset($rowData['scalars'])? count($rowData['scalars']): 0);
|
||||
$scalarCount = (isset($rowData['scalars']) ? count($rowData['scalars']) : 0);
|
||||
|
||||
foreach ($rowData['newObjects'] as $objIndex => $newObject) {
|
||||
$class = $newObject['class'];
|
||||
$args = $newObject['args'];
|
||||
$obj = $class->newInstanceArgs($args);
|
||||
$class = $newObject['class'];
|
||||
$args = $newObject['args'];
|
||||
$obj = $class->newInstanceArgs($args);
|
||||
|
||||
if (count($args) == $scalarCount || ($scalarCount == 0 && count($rowData['newObjects']) == 1)) {
|
||||
if (count($args) === $scalarCount || ($scalarCount === 0 && count($rowData['newObjects']) === 1)) {
|
||||
$result[$resultKey] = $obj;
|
||||
|
||||
continue;
|
||||
@@ -268,10 +259,10 @@ class ArrayHydrator extends AbstractHydrator
|
||||
* Updates the result pointer for an Entity. The result pointers point to the
|
||||
* last seen instance of each Entity type. This is used for graph construction.
|
||||
*
|
||||
* @param array $coll The element.
|
||||
* @param boolean|integer $index Index of the element in the collection.
|
||||
* @param string $dqlAlias
|
||||
* @param boolean $oneToOne Whether it is a single-valued association or not.
|
||||
* @param mixed[] $coll The element.
|
||||
* @param bool|int $index Index of the element in the collection.
|
||||
* @param string $dqlAlias
|
||||
* @param bool $oneToOne Whether it is a single-valued association or not.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -295,7 +286,7 @@ class ArrayHydrator extends AbstractHydrator
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! $coll) {
|
||||
if (! $coll) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -19,14 +20,19 @@
|
||||
|
||||
namespace Doctrine\ORM\Internal\Hydration;
|
||||
|
||||
class HydrationException extends \Doctrine\ORM\ORMException
|
||||
use Doctrine\ORM\ORMException;
|
||||
|
||||
use function implode;
|
||||
use function sprintf;
|
||||
|
||||
class HydrationException extends ORMException
|
||||
{
|
||||
/**
|
||||
* @return HydrationException
|
||||
*/
|
||||
public static function nonUniqueResult()
|
||||
{
|
||||
return new self("The result returned by the query was not unique.");
|
||||
return new self('The result returned by the query was not unique.');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,16 +54,13 @@ class HydrationException extends \Doctrine\ORM\ORMException
|
||||
*/
|
||||
public static function emptyDiscriminatorValue($dqlAlias)
|
||||
{
|
||||
return new self("The DQL alias '" . $dqlAlias . "' contains an entity ".
|
||||
"of an inheritance hierarchy with an empty discriminator value. This means " .
|
||||
"that the database contains inconsistent data with an empty " .
|
||||
"discriminator value in a table row."
|
||||
);
|
||||
return new self("The DQL alias '" . $dqlAlias . "' contains an entity " .
|
||||
'of an inheritance hierarchy with an empty discriminator value. This means ' .
|
||||
'that the database contains inconsistent data with an empty ' .
|
||||
'discriminator value in a table row.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.3
|
||||
*
|
||||
* @param string $entityName
|
||||
* @param string $discrColumnName
|
||||
* @param string $dqlAlias
|
||||
@@ -68,13 +71,13 @@ class HydrationException extends \Doctrine\ORM\ORMException
|
||||
{
|
||||
return new self(sprintf(
|
||||
'The discriminator column "%s" is missing for "%s" using the DQL alias "%s".',
|
||||
$discrColumnName, $entityName, $dqlAlias
|
||||
$discrColumnName,
|
||||
$entityName,
|
||||
$dqlAlias
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.3
|
||||
*
|
||||
* @param string $entityName
|
||||
* @param string $discrColumnName
|
||||
* @param string $dqlAlias
|
||||
@@ -85,7 +88,9 @@ class HydrationException extends \Doctrine\ORM\ORMException
|
||||
{
|
||||
return new self(sprintf(
|
||||
'The meta mapping for the discriminator column "%s" is missing for "%s" using the DQL alias "%s".',
|
||||
$discrColumnName, $entityName, $dqlAlias
|
||||
$discrColumnName,
|
||||
$entityName,
|
||||
$dqlAlias
|
||||
));
|
||||
}
|
||||
|
||||
@@ -99,7 +104,8 @@ class HydrationException extends \Doctrine\ORM\ORMException
|
||||
{
|
||||
return new self(sprintf(
|
||||
'The discriminator value "%s" is invalid. It must be one of "%s".',
|
||||
$discrValue, implode('", "', $discrMap)
|
||||
$discrValue,
|
||||
implode('", "', $discrMap)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -19,36 +20,30 @@
|
||||
|
||||
namespace Doctrine\ORM\Internal\Hydration;
|
||||
|
||||
use Iterator;
|
||||
|
||||
/**
|
||||
* Represents a result structure that can be iterated over, hydrating row-by-row
|
||||
* during the iteration. An IterableResult is obtained by AbstractHydrator#iterate().
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
class IterableResult implements \Iterator
|
||||
class IterableResult implements Iterator
|
||||
{
|
||||
/**
|
||||
* @var \Doctrine\ORM\Internal\Hydration\AbstractHydrator
|
||||
*/
|
||||
/** @var AbstractHydrator */
|
||||
private $_hydrator;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
/** @var bool */
|
||||
private $_rewinded = false;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
/** @var int */
|
||||
private $_key = -1;
|
||||
|
||||
/**
|
||||
* @var object|null
|
||||
*/
|
||||
/** @var object|null */
|
||||
private $_current = null;
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\Internal\Hydration\AbstractHydrator $hydrator
|
||||
* @param AbstractHydrator $hydrator
|
||||
*/
|
||||
public function __construct($hydrator)
|
||||
{
|
||||
@@ -62,10 +57,10 @@ class IterableResult implements \Iterator
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
if ($this->_rewinded == true) {
|
||||
throw new HydrationException("Can only iterate a Result once.");
|
||||
if ($this->_rewinded === true) {
|
||||
throw new HydrationException('Can only iterate a Result once.');
|
||||
} else {
|
||||
$this->_current = $this->next();
|
||||
$this->_current = $this->next();
|
||||
$this->_rewinded = true;
|
||||
}
|
||||
}
|
||||
@@ -104,6 +99,6 @@ class IterableResult implements \Iterator
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return ($this->_current!=false);
|
||||
return $this->_current !== false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -19,59 +20,48 @@
|
||||
|
||||
namespace Doctrine\ORM\Internal\Hydration;
|
||||
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
use PDO;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\ORM\Proxy\Proxy;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
use PDO;
|
||||
|
||||
use function array_fill_keys;
|
||||
use function array_keys;
|
||||
use function count;
|
||||
use function is_array;
|
||||
use function key;
|
||||
use function ltrim;
|
||||
use function spl_object_hash;
|
||||
|
||||
/**
|
||||
* The ObjectHydrator constructs an object graph out of an SQL result set.
|
||||
*
|
||||
* Internal note: Highly performance-sensitive code.
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class ObjectHydrator extends AbstractHydrator
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var mixed[] */
|
||||
private $identifierMap = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var mixed[] */
|
||||
private $resultPointers = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var mixed[] */
|
||||
private $idTemplate = [];
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
/** @var int */
|
||||
private $resultCounter = 0;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var mixed[] */
|
||||
private $rootAliases = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var mixed[] */
|
||||
private $initializedCollections = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var mixed[] */
|
||||
private $existingCollections = [];
|
||||
|
||||
/**
|
||||
@@ -79,7 +69,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
*/
|
||||
protected function prepare()
|
||||
{
|
||||
if ( ! isset($this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD])) {
|
||||
if (! isset($this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD])) {
|
||||
$this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD] = true;
|
||||
}
|
||||
|
||||
@@ -89,13 +79,13 @@ class ObjectHydrator extends AbstractHydrator
|
||||
|
||||
// Remember which associations are "fetch joined", so that we know where to inject
|
||||
// collection stubs or proxies and where not.
|
||||
if ( ! isset($this->_rsm->relationMap[$dqlAlias])) {
|
||||
if (! isset($this->_rsm->relationMap[$dqlAlias])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$parent = $this->_rsm->parentAliasMap[$dqlAlias];
|
||||
|
||||
if ( ! isset($this->_rsm->aliasMap[$parent])) {
|
||||
if (! isset($this->_rsm->aliasMap[$parent])) {
|
||||
throw HydrationException::parentObjectOfRelationNotFound($dqlAlias, $parent);
|
||||
}
|
||||
|
||||
@@ -121,7 +111,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$class = $this->getClassMetadata($className);
|
||||
$inverseAssoc = $class->associationMappings[$assoc['inversedBy']];
|
||||
|
||||
if ( ! ($inverseAssoc['type'] & ClassMetadata::TO_ONE)) {
|
||||
if (! ($inverseAssoc['type'] & ClassMetadata::TO_ONE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -135,14 +125,14 @@ class ObjectHydrator extends AbstractHydrator
|
||||
*/
|
||||
protected function cleanup()
|
||||
{
|
||||
$eagerLoad = (isset($this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD])) && $this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD] == true;
|
||||
$eagerLoad = isset($this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD]) && $this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD] === true;
|
||||
|
||||
parent::cleanup();
|
||||
|
||||
$this->identifierMap =
|
||||
$this->identifierMap =
|
||||
$this->initializedCollections =
|
||||
$this->existingCollections =
|
||||
$this->resultPointers = [];
|
||||
$this->existingCollections =
|
||||
$this->resultPointers = [];
|
||||
|
||||
if ($eagerLoad) {
|
||||
$this->_uow->triggerEagerLoads();
|
||||
@@ -151,6 +141,14 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$this->_uow->hydrationComplete();
|
||||
}
|
||||
|
||||
protected function cleanupAfterRowIteration(): void
|
||||
{
|
||||
$this->identifierMap =
|
||||
$this->initializedCollections =
|
||||
$this->existingCollections =
|
||||
$this->resultPointers = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -178,7 +176,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
* @param string $fieldName The name of the field on the entity that holds the collection.
|
||||
* @param string $parentDqlAlias Alias of the parent fetch joining this collection.
|
||||
*
|
||||
* @return \Doctrine\ORM\PersistentCollection
|
||||
* @return PersistentCollection
|
||||
*/
|
||||
private function initRelatedCollection($entity, $class, $fieldName, $parentDqlAlias)
|
||||
{
|
||||
@@ -190,9 +188,11 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$value = new ArrayCollection((array) $value);
|
||||
}
|
||||
|
||||
if ( ! $value instanceof PersistentCollection) {
|
||||
if (! $value instanceof PersistentCollection) {
|
||||
$value = new PersistentCollection(
|
||||
$this->_em, $this->_metadataCache[$relation['targetEntity']], $value
|
||||
$this->_em,
|
||||
$this->_metadataCache[$relation['targetEntity']],
|
||||
$value
|
||||
);
|
||||
$value->setOwner($entity, $relation);
|
||||
|
||||
@@ -200,7 +200,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$this->_uow->setOriginalEntityProperty($oid, $fieldName, $value);
|
||||
|
||||
$this->initializedCollections[$oid . $fieldName] = $value;
|
||||
} else if (
|
||||
} elseif (
|
||||
isset($this->_hints[Query::HINT_REFRESH]) ||
|
||||
isset($this->_hints['fetched'][$parentDqlAlias][$fieldName]) &&
|
||||
! $value->isInitialized()
|
||||
@@ -236,24 +236,24 @@ class ObjectHydrator extends AbstractHydrator
|
||||
if (isset($this->_rsm->discriminatorColumns[$dqlAlias])) {
|
||||
$fieldName = $this->_rsm->discriminatorColumns[$dqlAlias];
|
||||
|
||||
if ( ! isset($this->_rsm->metaMappings[$fieldName])) {
|
||||
if (! isset($this->_rsm->metaMappings[$fieldName])) {
|
||||
throw HydrationException::missingDiscriminatorMetaMappingColumn($className, $fieldName, $dqlAlias);
|
||||
}
|
||||
|
||||
$discrColumn = $this->_rsm->metaMappings[$fieldName];
|
||||
|
||||
if ( ! isset($data[$discrColumn])) {
|
||||
if (! isset($data[$discrColumn])) {
|
||||
throw HydrationException::missingDiscriminatorColumn($className, $discrColumn, $dqlAlias);
|
||||
}
|
||||
|
||||
if ($data[$discrColumn] === "") {
|
||||
if ($data[$discrColumn] === '') {
|
||||
throw HydrationException::emptyDiscriminatorValue($dqlAlias);
|
||||
}
|
||||
|
||||
$discrMap = $this->_metadataCache[$className]->discriminatorMap;
|
||||
$discrMap = $this->_metadataCache[$className]->discriminatorMap;
|
||||
$discriminatorValue = (string) $data[$discrColumn];
|
||||
|
||||
if ( ! isset($discrMap[$discriminatorValue])) {
|
||||
if (! isset($discrMap[$discriminatorValue])) {
|
||||
throw HydrationException::invalidDiscriminatorValue($discriminatorValue, array_keys($discrMap));
|
||||
}
|
||||
|
||||
@@ -282,7 +282,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
// TODO: Abstract this code and UnitOfWork::createEntity() equivalent?
|
||||
$class = $this->_metadataCache[$className];
|
||||
|
||||
/* @var $class ClassMetadata */
|
||||
/** @var ClassMetadata $class */
|
||||
if ($class->isIdentifierComposite) {
|
||||
$idHash = '';
|
||||
|
||||
@@ -293,7 +293,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
return $this->_uow->tryGetByIdHash(ltrim($idHash), $class->rootEntityName);
|
||||
} else if (isset($class->associationMappings[$class->identifier[0]])) {
|
||||
} elseif (isset($class->associationMappings[$class->identifier[0]])) {
|
||||
return $this->_uow->tryGetByIdHash($data[$class->associationMappings[$class->identifier[0]]['joinColumns'][0]['name']], $class->rootEntityName);
|
||||
}
|
||||
|
||||
@@ -325,7 +325,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
protected function hydrateRowData(array $row, array &$result)
|
||||
{
|
||||
// Initialize
|
||||
$id = $this->idTemplate; // initialize the id-memory
|
||||
$id = $this->idTemplate; // initialize the id-memory
|
||||
$nonemptyComponents = [];
|
||||
// Split the row data into chunks of class data.
|
||||
$rowData = $this->gatherRowData($row, $id, $nonemptyComponents);
|
||||
@@ -346,28 +346,28 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$path = $parentAlias . '.' . $dqlAlias;
|
||||
|
||||
// We have a RIGHT JOIN result here. Doctrine cannot hydrate RIGHT JOIN Object-Graphs
|
||||
if ( ! isset($nonemptyComponents[$parentAlias])) {
|
||||
if (! isset($nonemptyComponents[$parentAlias])) {
|
||||
// TODO: Add special case code where we hydrate the right join objects into identity map at least
|
||||
continue;
|
||||
}
|
||||
|
||||
$parentClass = $this->_metadataCache[$this->_rsm->aliasMap[$parentAlias]];
|
||||
$relationField = $this->_rsm->relationMap[$dqlAlias];
|
||||
$relation = $parentClass->associationMappings[$relationField];
|
||||
$reflField = $parentClass->reflFields[$relationField];
|
||||
$parentClass = $this->_metadataCache[$this->_rsm->aliasMap[$parentAlias]];
|
||||
$relationField = $this->_rsm->relationMap[$dqlAlias];
|
||||
$relation = $parentClass->associationMappings[$relationField];
|
||||
$reflField = $parentClass->reflFields[$relationField];
|
||||
|
||||
// Get a reference to the parent object to which the joined element belongs.
|
||||
if ($this->_rsm->isMixed && isset($this->rootAliases[$parentAlias])) {
|
||||
$objectClass = $this->resultPointers[$parentAlias];
|
||||
$objectClass = $this->resultPointers[$parentAlias];
|
||||
$parentObject = $objectClass[key($objectClass)];
|
||||
} else if (isset($this->resultPointers[$parentAlias])) {
|
||||
} elseif (isset($this->resultPointers[$parentAlias])) {
|
||||
$parentObject = $this->resultPointers[$parentAlias];
|
||||
} else {
|
||||
// Parent object of relation not found, mark as not-fetched again
|
||||
$element = $this->getEntity($data, $dqlAlias);
|
||||
|
||||
// Update result pointer and provide initial fetch data for parent
|
||||
$this->resultPointers[$dqlAlias] = $element;
|
||||
$this->resultPointers[$dqlAlias] = $element;
|
||||
$rowData['data'][$parentAlias][$relationField] = $element;
|
||||
|
||||
// Mark as not-fetched again
|
||||
@@ -378,7 +378,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$oid = spl_object_hash($parentObject);
|
||||
|
||||
// Check the type of the relation (many or single-valued)
|
||||
if ( ! ($relation['type'] & ClassMetadata::TO_ONE)) {
|
||||
if (! ($relation['type'] & ClassMetadata::TO_ONE)) {
|
||||
// PATH A: Collection-valued association
|
||||
$reflFieldValue = $reflField->getValue($parentObject);
|
||||
|
||||
@@ -386,15 +386,15 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$collKey = $oid . $relationField;
|
||||
if (isset($this->initializedCollections[$collKey])) {
|
||||
$reflFieldValue = $this->initializedCollections[$collKey];
|
||||
} else if ( ! isset($this->existingCollections[$collKey])) {
|
||||
} elseif (! isset($this->existingCollections[$collKey])) {
|
||||
$reflFieldValue = $this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
|
||||
}
|
||||
|
||||
$indexExists = isset($this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]]);
|
||||
$index = $indexExists ? $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] : false;
|
||||
$indexIsValid = $index !== false ? isset($reflFieldValue[$index]) : false;
|
||||
$indexExists = isset($this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]]);
|
||||
$index = $indexExists ? $this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] : false;
|
||||
$indexIsValid = $index !== false ? isset($reflFieldValue[$index]) : false;
|
||||
|
||||
if ( ! $indexExists || ! $indexIsValid) {
|
||||
if (! $indexExists || ! $indexIsValid) {
|
||||
if (isset($this->existingCollections[$collKey])) {
|
||||
// Collection exists, only look for the element in the identity map.
|
||||
if ($element = $this->getEntityFromIdentityMap($entityName, $data)) {
|
||||
@@ -414,6 +414,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$reflFieldValue->last();
|
||||
$this->identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $reflFieldValue->key();
|
||||
}
|
||||
|
||||
// Update result pointer
|
||||
$this->resultPointers[$dqlAlias] = $element;
|
||||
}
|
||||
@@ -421,17 +422,16 @@ class ObjectHydrator extends AbstractHydrator
|
||||
// Update result pointer
|
||||
$this->resultPointers[$dqlAlias] = $reflFieldValue[$index];
|
||||
}
|
||||
} else if ( ! $reflFieldValue) {
|
||||
} elseif (! $reflFieldValue) {
|
||||
$this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
|
||||
} else if ($reflFieldValue instanceof PersistentCollection && $reflFieldValue->isInitialized() === false) {
|
||||
} elseif ($reflFieldValue instanceof PersistentCollection && $reflFieldValue->isInitialized() === false) {
|
||||
$reflFieldValue->setInitialized(true);
|
||||
}
|
||||
|
||||
} else {
|
||||
// PATH B: Single-valued association
|
||||
$reflFieldValue = $reflField->getValue($parentObject);
|
||||
|
||||
if ( ! $reflFieldValue || isset($this->_hints[Query::HINT_REFRESH]) || ($reflFieldValue instanceof Proxy && !$reflFieldValue->__isInitialized__)) {
|
||||
if (! $reflFieldValue || isset($this->_hints[Query::HINT_REFRESH]) || ($reflFieldValue instanceof Proxy && ! $reflFieldValue->__isInitialized__)) {
|
||||
// we only need to take action if this value is null,
|
||||
// we refresh the entity or its an uninitialized proxy.
|
||||
if (isset($nonemptyComponents[$dqlAlias])) {
|
||||
@@ -449,7 +449,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$targetClass->reflFields[$inverseAssoc['fieldName']]->setValue($element, $parentObject);
|
||||
$this->_uow->setOriginalEntityProperty(spl_object_hash($element), $inverseAssoc['fieldName'], $parentObject);
|
||||
}
|
||||
} else if ($parentClass === $targetClass && $relation['mappedBy']) {
|
||||
} elseif ($parentClass === $targetClass && $relation['mappedBy']) {
|
||||
// Special case: bi-directional self-referencing one-one on the same class
|
||||
$targetClass->reflFields[$relationField]->setValue($element, $parentObject);
|
||||
}
|
||||
@@ -458,6 +458,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$targetClass->reflFields[$relation['mappedBy']]->setValue($element, $parentObject);
|
||||
$this->_uow->setOriginalEntityProperty(spl_object_hash($element), $relation['mappedBy'], $parentObject);
|
||||
}
|
||||
|
||||
// Update result pointer
|
||||
$this->resultPointers[$dqlAlias] = $element;
|
||||
} else {
|
||||
@@ -473,22 +474,23 @@ class ObjectHydrator extends AbstractHydrator
|
||||
} else {
|
||||
// PATH C: Its a root result element
|
||||
$this->rootAliases[$dqlAlias] = true; // Mark as root alias
|
||||
$entityKey = $this->_rsm->entityMappings[$dqlAlias] ?: 0;
|
||||
$entityKey = $this->_rsm->entityMappings[$dqlAlias] ?: 0;
|
||||
|
||||
// if this row has a NULL value for the root result id then make it a null result.
|
||||
if ( ! isset($nonemptyComponents[$dqlAlias]) ) {
|
||||
if (! isset($nonemptyComponents[$dqlAlias])) {
|
||||
if ($this->_rsm->isMixed) {
|
||||
$result[] = [$entityKey => null];
|
||||
} else {
|
||||
$result[] = null;
|
||||
}
|
||||
|
||||
$resultKey = $this->resultCounter;
|
||||
++$this->resultCounter;
|
||||
continue;
|
||||
}
|
||||
|
||||
// check for existing result from the iterations before
|
||||
if ( ! isset($this->identifierMap[$dqlAlias][$id[$dqlAlias]])) {
|
||||
if (! isset($this->identifierMap[$dqlAlias][$id[$dqlAlias]])) {
|
||||
$element = $this->getEntity($data, $dqlAlias);
|
||||
|
||||
if ($this->_rsm->isMixed) {
|
||||
@@ -518,12 +520,11 @@ class ObjectHydrator extends AbstractHydrator
|
||||
|
||||
// Update result pointer
|
||||
$this->resultPointers[$dqlAlias] = $element;
|
||||
|
||||
} else {
|
||||
// Update result pointer
|
||||
$index = $this->identifierMap[$dqlAlias][$id[$dqlAlias]];
|
||||
$index = $this->identifierMap[$dqlAlias][$id[$dqlAlias]];
|
||||
$this->resultPointers[$dqlAlias] = $result[$index];
|
||||
$resultKey = $index;
|
||||
$resultKey = $index;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,14 +533,14 @@ class ObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! isset($resultKey) ) {
|
||||
if (! isset($resultKey)) {
|
||||
$this->resultCounter++;
|
||||
}
|
||||
|
||||
// Append scalar values to mixed result sets
|
||||
if (isset($rowData['scalars'])) {
|
||||
if ( ! isset($resultKey) ) {
|
||||
$resultKey = (isset($this->_rsm->indexByMap['scalars']))
|
||||
if (! isset($resultKey)) {
|
||||
$resultKey = isset($this->_rsm->indexByMap['scalars'])
|
||||
? $row[$this->_rsm->indexByMap['scalars']]
|
||||
: $this->resultCounter - 1;
|
||||
}
|
||||
@@ -551,19 +552,18 @@ class ObjectHydrator extends AbstractHydrator
|
||||
|
||||
// Append new object to mixed result sets
|
||||
if (isset($rowData['newObjects'])) {
|
||||
if ( ! isset($resultKey) ) {
|
||||
if (! isset($resultKey)) {
|
||||
$resultKey = $this->resultCounter - 1;
|
||||
}
|
||||
|
||||
|
||||
$scalarCount = (isset($rowData['scalars'])? count($rowData['scalars']): 0);
|
||||
$scalarCount = (isset($rowData['scalars']) ? count($rowData['scalars']) : 0);
|
||||
|
||||
foreach ($rowData['newObjects'] as $objIndex => $newObject) {
|
||||
$class = $newObject['class'];
|
||||
$args = $newObject['args'];
|
||||
$obj = $class->newInstanceArgs($args);
|
||||
$class = $newObject['class'];
|
||||
$args = $newObject['args'];
|
||||
$obj = $class->newInstanceArgs($args);
|
||||
|
||||
if ($scalarCount == 0 && count($rowData['newObjects']) == 1 ) {
|
||||
if ($scalarCount === 0 && count($rowData['newObjects']) === 1) {
|
||||
$result[$resultKey] = $obj;
|
||||
|
||||
continue;
|
||||
@@ -586,7 +586,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
{
|
||||
parent::onClear($eventArgs);
|
||||
|
||||
$aliases = array_keys($this->identifierMap);
|
||||
$aliases = array_keys($this->identifierMap);
|
||||
|
||||
$this->identifierMap = array_fill_keys($aliases, []);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -19,14 +20,12 @@
|
||||
|
||||
namespace Doctrine\ORM\Internal\Hydration;
|
||||
|
||||
use PDO;
|
||||
|
||||
/**
|
||||
* Hydrator that produces flat, rectangular results of scalar data.
|
||||
* The created result is almost the same as a regular SQL result set, except
|
||||
* that column names are mapped to field names and data type conversions take place.
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
*/
|
||||
class ScalarHydrator extends AbstractHydrator
|
||||
{
|
||||
@@ -37,7 +36,7 @@ class ScalarHydrator extends AbstractHydrator
|
||||
{
|
||||
$result = [];
|
||||
|
||||
while ($data = $this->_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
while ($data = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$this->hydrateRowData($data, $result);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -19,17 +20,23 @@
|
||||
|
||||
namespace Doctrine\ORM\Internal\Hydration;
|
||||
|
||||
use PDO;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Query;
|
||||
use Exception;
|
||||
use PDO;
|
||||
use RuntimeException;
|
||||
|
||||
use function array_keys;
|
||||
use function array_search;
|
||||
use function count;
|
||||
use function in_array;
|
||||
use function key;
|
||||
use function reset;
|
||||
use function sprintf;
|
||||
|
||||
class SimpleObjectHydrator extends AbstractHydrator
|
||||
{
|
||||
/**
|
||||
* @var ClassMetadata
|
||||
*/
|
||||
/** @var ClassMetadata */
|
||||
private $class;
|
||||
|
||||
/**
|
||||
@@ -38,11 +45,11 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
protected function prepare()
|
||||
{
|
||||
if (count($this->_rsm->aliasMap) !== 1) {
|
||||
throw new \RuntimeException("Cannot use SimpleObjectHydrator with a ResultSetMapping that contains more than one object result.");
|
||||
throw new RuntimeException('Cannot use SimpleObjectHydrator with a ResultSetMapping that contains more than one object result.');
|
||||
}
|
||||
|
||||
if ($this->_rsm->scalarMappings) {
|
||||
throw new \RuntimeException("Cannot use SimpleObjectHydrator with a ResultSetMapping that contains scalar mappings.");
|
||||
throw new RuntimeException('Cannot use SimpleObjectHydrator with a ResultSetMapping that contains scalar mappings.');
|
||||
}
|
||||
|
||||
$this->class = $this->getClassMetadata(reset($this->_rsm->aliasMap));
|
||||
@@ -116,17 +123,17 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
foreach ($row as $column => $value) {
|
||||
// An ObjectHydrator should be used instead of SimpleObjectHydrator
|
||||
if (isset($this->_rsm->relationMap[$column])) {
|
||||
throw new \Exception(sprintf('Unable to retrieve association information for column "%s"', $column));
|
||||
throw new Exception(sprintf('Unable to retrieve association information for column "%s"', $column));
|
||||
}
|
||||
|
||||
$cacheKeyInfo = $this->hydrateColumnInfo($column);
|
||||
|
||||
if ( ! $cacheKeyInfo) {
|
||||
if (! $cacheKeyInfo) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if value is null before conversion (because some types convert null to something else)
|
||||
$valueIsNull = null === $value;
|
||||
$valueIsNull = $value === null;
|
||||
|
||||
// Convert field to a valid PHP value
|
||||
if (isset($cacheKeyInfo['type'])) {
|
||||
@@ -137,7 +144,7 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
$fieldName = $cacheKeyInfo['fieldName'];
|
||||
|
||||
// Prevent overwrite in case of inherit classes using same property name (See AbstractHydrator)
|
||||
if ( ! isset($data[$fieldName]) || ! $valueIsNull) {
|
||||
if (! isset($data[$fieldName]) || ! $valueIsNull) {
|
||||
// If we have inheritance in resultset, make sure the field belongs to the correct class
|
||||
if (isset($cacheKeyInfo['discriminatorValues']) && ! in_array((string) $discrColumnValue, $cacheKeyInfo['discriminatorValues'], true)) {
|
||||
continue;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -19,15 +20,16 @@
|
||||
|
||||
namespace Doctrine\ORM\Internal\Hydration;
|
||||
|
||||
use Doctrine\ORM\NoResultException;
|
||||
use Doctrine\ORM\NonUniqueResultException;
|
||||
use Doctrine\ORM\NoResultException;
|
||||
use PDO;
|
||||
|
||||
use function array_shift;
|
||||
use function count;
|
||||
use function key;
|
||||
|
||||
/**
|
||||
* Hydrator that hydrates a single scalar value from the result set.
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
*/
|
||||
class SingleScalarHydrator extends AbstractHydrator
|
||||
{
|
||||
@@ -36,7 +38,7 @@ class SingleScalarHydrator extends AbstractHydrator
|
||||
*/
|
||||
protected function hydrateAllData()
|
||||
{
|
||||
$data = $this->_stmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||
$data = $this->_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$numRows = count($data);
|
||||
|
||||
if ($numRows === 0) {
|
||||
@@ -46,7 +48,7 @@ class SingleScalarHydrator extends AbstractHydrator
|
||||
if ($numRows > 1) {
|
||||
throw new NonUniqueResultException('The query returned multiple rows. Change the query or use a different result function like getScalarResult().');
|
||||
}
|
||||
|
||||
|
||||
if (count($data[key($data)]) > 1) {
|
||||
throw new NonUniqueResultException('The query returned a row containing multiple columns. Change the query or use a different result function like getScalarResult().');
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -28,32 +29,20 @@ use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
/**
|
||||
* Class, which can handle completion of hydration cycle and produce some of tasks.
|
||||
* In current implementation triggers deferred postLoad event.
|
||||
*
|
||||
* @author Artur Eshenbrener <strate@yandex.ru>
|
||||
* @since 2.5
|
||||
*/
|
||||
final class HydrationCompleteHandler
|
||||
{
|
||||
/**
|
||||
* @var ListenersInvoker
|
||||
*/
|
||||
/** @var ListenersInvoker */
|
||||
private $listenersInvoker;
|
||||
|
||||
/**
|
||||
* @var EntityManagerInterface
|
||||
*/
|
||||
/** @var EntityManagerInterface */
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* @var array[]
|
||||
*/
|
||||
/** @var mixed[][] */
|
||||
private $deferredPostLoadInvocations = [];
|
||||
|
||||
/**
|
||||
* Constructor for this object
|
||||
*
|
||||
* @param ListenersInvoker $listenersInvoker
|
||||
* @param EntityManagerInterface $em
|
||||
*/
|
||||
public function __construct(ListenersInvoker $listenersInvoker, EntityManagerInterface $em)
|
||||
{
|
||||
@@ -64,8 +53,7 @@ final class HydrationCompleteHandler
|
||||
/**
|
||||
* Method schedules invoking of postLoad entity to the very end of current hydration cycle.
|
||||
*
|
||||
* @param ClassMetadata $class
|
||||
* @param object $entity
|
||||
* @param object $entity
|
||||
*/
|
||||
public function deferPostLoadInvoking(ClassMetadata $class, $entity)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -23,7 +24,6 @@ use Doctrine\Common\Collections\AbstractLazyCollection;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\Common\Collections\Selectable;
|
||||
use Doctrine\ORM\Persisters\Entity\BasicEntityPersister;
|
||||
use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
|
||||
/**
|
||||
@@ -31,32 +31,18 @@ use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
* Once count gets executed once without collection being initialized, result
|
||||
* is cached and returned on subsequent calls until collection gets loaded,
|
||||
* then returning the number of loaded results.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Michaël Gallego <mic.gallego@gmail.com>
|
||||
*/
|
||||
class LazyCriteriaCollection extends AbstractLazyCollection implements Selectable
|
||||
{
|
||||
/**
|
||||
* @var BasicEntityPersister
|
||||
*/
|
||||
/** @var EntityPersister */
|
||||
protected $entityPersister;
|
||||
|
||||
/**
|
||||
* @var Criteria
|
||||
*/
|
||||
/** @var Criteria */
|
||||
protected $criteria;
|
||||
|
||||
/**
|
||||
* @var integer|null
|
||||
*/
|
||||
/** @var int|null */
|
||||
private $count;
|
||||
|
||||
/**
|
||||
* @param EntityPersister $entityPersister
|
||||
* @param Criteria $criteria
|
||||
*/
|
||||
public function __construct(EntityPersister $entityPersister, Criteria $criteria)
|
||||
{
|
||||
$this->entityPersister = $entityPersister;
|
||||
@@ -66,7 +52,7 @@ class LazyCriteriaCollection extends AbstractLazyCollection implements Selectabl
|
||||
/**
|
||||
* Do an efficient count on the collection
|
||||
*
|
||||
* @return integer
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
@@ -85,7 +71,7 @@ class LazyCriteriaCollection extends AbstractLazyCollection implements Selectabl
|
||||
/**
|
||||
* check if collection is empty without loading it
|
||||
*
|
||||
* @return boolean TRUE if the collection is empty, FALSE otherwise.
|
||||
* @return bool TRUE if the collection is empty, FALSE otherwise.
|
||||
*/
|
||||
public function isEmpty()
|
||||
{
|
||||
@@ -93,7 +79,7 @@ class LazyCriteriaCollection extends AbstractLazyCollection implements Selectabl
|
||||
return $this->collection->isEmpty();
|
||||
}
|
||||
|
||||
return !$this->count();
|
||||
return ! $this->count();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -24,9 +25,6 @@ use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
/**
|
||||
* ANSI compliant quote strategy, this strategy does not apply any quote.
|
||||
* To use this strategy all mapped tables and columns should be ANSI compliant.
|
||||
*
|
||||
* @since 2.5
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class AnsiQuoteStrategy implements QuoteStrategy
|
||||
{
|
||||
@@ -89,7 +87,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getColumnAlias($columnName, $counter, AbstractPlatform $platform, ClassMetadata $class = null)
|
||||
public function getColumnAlias($columnName, $counter, AbstractPlatform $platform, ?ClassMetadata $class = null)
|
||||
{
|
||||
return $platform->getSQLResultCasing($columnName . '_' . $counter);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -22,9 +23,6 @@ namespace Doctrine\ORM\Mapping;
|
||||
/**
|
||||
* This annotation is used to override association mapping of property for an entity relationship.
|
||||
*
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
* @since 2.3
|
||||
*
|
||||
* @Annotation
|
||||
* @Target("ANNOTATION")
|
||||
*/
|
||||
@@ -32,8 +30,8 @@ final class AssociationOverride implements Annotation
|
||||
{
|
||||
/**
|
||||
* The name of the relationship property whose mapping is being overridden.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
@@ -62,7 +60,6 @@ final class AssociationOverride implements Annotation
|
||||
* The fetching strategy to use for the association.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @Enum({"LAZY", "EAGER", "EXTRA_LAZY"})
|
||||
*/
|
||||
public $fetch;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -22,9 +23,6 @@ namespace Doctrine\ORM\Mapping;
|
||||
/**
|
||||
* This annotation is used to override association mappings of relationship properties.
|
||||
*
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
* @since 2.3
|
||||
*
|
||||
* @Annotation
|
||||
* @Target("CLASS")
|
||||
*/
|
||||
@@ -33,7 +31,7 @@ final class AssociationOverrides implements Annotation
|
||||
/**
|
||||
* Mapping overrides of relationship properties.
|
||||
*
|
||||
* @var array<\Doctrine\ORM\Mapping\AssociationOverride>
|
||||
* @var array<\Doctrine\ORM\Mapping\AssociationOverride>
|
||||
*/
|
||||
public $value;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -22,9 +23,6 @@ namespace Doctrine\ORM\Mapping;
|
||||
/**
|
||||
* This annotation is used to override the mapping of a entity property.
|
||||
*
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
* @since 2.3
|
||||
*
|
||||
* @Annotation
|
||||
* @Target("ANNOTATION")
|
||||
*/
|
||||
@@ -32,8 +30,8 @@ final class AttributeOverride implements Annotation
|
||||
{
|
||||
/**
|
||||
* The name of the property whose mapping is being overridden.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -22,9 +23,6 @@ namespace Doctrine\ORM\Mapping;
|
||||
/**
|
||||
* This annotation is used to override the mapping of a entity property.
|
||||
*
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
* @since 2.3
|
||||
*
|
||||
* @Annotation
|
||||
* @Target("CLASS")
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -20,39 +21,31 @@
|
||||
namespace Doctrine\ORM\Mapping\Builder;
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class AssociationBuilder
|
||||
{
|
||||
/**
|
||||
* @var ClassMetadataBuilder
|
||||
*/
|
||||
/** @var ClassMetadataBuilder */
|
||||
protected $builder;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
/** @var mixed[] */
|
||||
protected $mapping;
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
/** @var mixed[]|null */
|
||||
protected $joinColumns;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
/** @var int */
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* @param ClassMetadataBuilder $builder
|
||||
* @param array $mapping
|
||||
* @param int $type
|
||||
* @param mixed[] $mapping
|
||||
* @param int $type
|
||||
*/
|
||||
public function __construct(ClassMetadataBuilder $builder, array $mapping, $type)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
$this->mapping = $mapping;
|
||||
$this->type = $type;
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,7 +77,7 @@ class AssociationBuilder
|
||||
*/
|
||||
public function cascadeAll()
|
||||
{
|
||||
$this->mapping['cascade'] = ["ALL"];
|
||||
$this->mapping['cascade'] = ['ALL'];
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -94,7 +87,7 @@ class AssociationBuilder
|
||||
*/
|
||||
public function cascadePersist()
|
||||
{
|
||||
$this->mapping['cascade'][] = "persist";
|
||||
$this->mapping['cascade'][] = 'persist';
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -104,7 +97,7 @@ class AssociationBuilder
|
||||
*/
|
||||
public function cascadeRemove()
|
||||
{
|
||||
$this->mapping['cascade'][] = "remove";
|
||||
$this->mapping['cascade'][] = 'remove';
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -114,7 +107,7 @@ class AssociationBuilder
|
||||
*/
|
||||
public function cascadeMerge()
|
||||
{
|
||||
$this->mapping['cascade'][] = "merge";
|
||||
$this->mapping['cascade'][] = 'merge';
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -124,7 +117,7 @@ class AssociationBuilder
|
||||
*/
|
||||
public function cascadeDetach()
|
||||
{
|
||||
$this->mapping['cascade'][] = "detach";
|
||||
$this->mapping['cascade'][] = 'detach';
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -134,7 +127,7 @@ class AssociationBuilder
|
||||
*/
|
||||
public function cascadeRefresh()
|
||||
{
|
||||
$this->mapping['cascade'][] = "refresh";
|
||||
$this->mapping['cascade'][] = 'refresh';
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -222,7 +215,7 @@ class AssociationBuilder
|
||||
/**
|
||||
* @return ClassMetadataBuilder
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
@@ -230,13 +223,14 @@ class AssociationBuilder
|
||||
if ($this->joinColumns) {
|
||||
$mapping['joinColumns'] = $this->joinColumns;
|
||||
}
|
||||
|
||||
$cm = $this->builder->getClassMetadata();
|
||||
if ($this->type == ClassMetadata::MANY_TO_ONE) {
|
||||
if ($this->type === ClassMetadata::MANY_TO_ONE) {
|
||||
$cm->mapManyToOne($mapping);
|
||||
} else if ($this->type == ClassMetadata::ONE_TO_ONE) {
|
||||
} elseif ($this->type === ClassMetadata::ONE_TO_ONE) {
|
||||
$cm->mapOneToOne($mapping);
|
||||
} else {
|
||||
throw new \InvalidArgumentException("Type should be a ToOne Association here");
|
||||
throw new InvalidArgumentException('Type should be a ToOne Association here');
|
||||
}
|
||||
|
||||
return $this->builder;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -25,22 +26,13 @@ use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
/**
|
||||
* Builder Object for ClassMetadata
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT
|
||||
* @link www.doctrine-project.com
|
||||
* @since 2.2
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
*/
|
||||
class ClassMetadataBuilder
|
||||
{
|
||||
/**
|
||||
* @var \Doctrine\ORM\Mapping\ClassMetadataInfo
|
||||
*/
|
||||
/** @var ClassMetadataInfo */
|
||||
private $cm;
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\Mapping\ClassMetadataInfo $cm
|
||||
*/
|
||||
public function __construct(ClassMetadataInfo $cm)
|
||||
{
|
||||
$this->cm = $cm;
|
||||
@@ -62,7 +54,7 @@ class ClassMetadataBuilder
|
||||
public function setMappedSuperClass()
|
||||
{
|
||||
$this->cm->isMappedSuperclass = true;
|
||||
$this->cm->isEmbeddedClass = false;
|
||||
$this->cm->isEmbeddedClass = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -74,7 +66,7 @@ class ClassMetadataBuilder
|
||||
*/
|
||||
public function setEmbeddable()
|
||||
{
|
||||
$this->cm->isEmbeddedClass = true;
|
||||
$this->cm->isEmbeddedClass = true;
|
||||
$this->cm->isMappedSuperclass = false;
|
||||
|
||||
return $this;
|
||||
@@ -95,7 +87,7 @@ class ClassMetadataBuilder
|
||||
[
|
||||
'fieldName' => $fieldName,
|
||||
'class' => $class,
|
||||
'columnPrefix' => $columnPrefix
|
||||
'columnPrefix' => $columnPrefix,
|
||||
]
|
||||
);
|
||||
|
||||
@@ -152,7 +144,7 @@ class ClassMetadataBuilder
|
||||
*/
|
||||
public function addIndex(array $columns, $name)
|
||||
{
|
||||
if (!isset($this->cm->table['indexes'])) {
|
||||
if (! isset($this->cm->table['indexes'])) {
|
||||
$this->cm->table['indexes'] = [];
|
||||
}
|
||||
|
||||
@@ -171,7 +163,7 @@ class ClassMetadataBuilder
|
||||
*/
|
||||
public function addUniqueConstraint(array $columns, $name)
|
||||
{
|
||||
if ( ! isset($this->cm->table['uniqueConstraints'])) {
|
||||
if (! isset($this->cm->table['uniqueConstraints'])) {
|
||||
$this->cm->table['uniqueConstraints'] = [];
|
||||
}
|
||||
|
||||
@@ -312,7 +304,7 @@ class ClassMetadataBuilder
|
||||
public function addField($name, $type, array $mapping = [])
|
||||
{
|
||||
$mapping['fieldName'] = $name;
|
||||
$mapping['type'] = $type;
|
||||
$mapping['type'] = $type;
|
||||
|
||||
$this->cm->mapField($mapping);
|
||||
|
||||
@@ -333,7 +325,7 @@ class ClassMetadataBuilder
|
||||
$this,
|
||||
[
|
||||
'fieldName' => $name,
|
||||
'type' => $type
|
||||
'type' => $type,
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -353,7 +345,7 @@ class ClassMetadataBuilder
|
||||
[
|
||||
'fieldName' => $fieldName,
|
||||
'class' => $class,
|
||||
'columnPrefix' => null
|
||||
'columnPrefix' => null,
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -394,7 +386,7 @@ class ClassMetadataBuilder
|
||||
$this,
|
||||
[
|
||||
'fieldName' => $name,
|
||||
'targetEntity' => $targetEntity
|
||||
'targetEntity' => $targetEntity,
|
||||
],
|
||||
ClassMetadata::MANY_TO_ONE
|
||||
);
|
||||
@@ -414,7 +406,7 @@ class ClassMetadataBuilder
|
||||
$this,
|
||||
[
|
||||
'fieldName' => $name,
|
||||
'targetEntity' => $targetEntity
|
||||
'targetEntity' => $targetEntity,
|
||||
],
|
||||
ClassMetadata::ONE_TO_ONE
|
||||
);
|
||||
@@ -471,7 +463,7 @@ class ClassMetadataBuilder
|
||||
$this,
|
||||
[
|
||||
'fieldName' => $name,
|
||||
'targetEntity' => $targetEntity
|
||||
'targetEntity' => $targetEntity,
|
||||
],
|
||||
ClassMetadata::MANY_TO_MANY
|
||||
);
|
||||
@@ -528,7 +520,7 @@ class ClassMetadataBuilder
|
||||
$this,
|
||||
[
|
||||
'fieldName' => $name,
|
||||
'targetEntity' => $targetEntity
|
||||
'targetEntity' => $targetEntity,
|
||||
],
|
||||
ClassMetadata::ONE_TO_MANY
|
||||
);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user