mirror of
https://github.com/doctrine/orm.git
synced 2026-03-24 15:02:22 +01:00
Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ed6c2234a | ||
|
|
ff612b9678 | ||
|
|
ee0d7197dd | ||
|
|
39d2136f46 | ||
|
|
bea454eefc | ||
|
|
14f2572e4e | ||
|
|
c2c500077b | ||
|
|
6281c2b79f | ||
|
|
bac1c17eab | ||
|
|
b6137c8911 | ||
|
|
51be1b1d52 | ||
|
|
488a5dd3bf | ||
|
|
896c65504d | ||
|
|
16a8f10fd2 | ||
|
|
d80a831157 | ||
|
|
52660297ab | ||
|
|
58287bb731 | ||
|
|
8a25b264f7 | ||
|
|
0e48b19cd3 | ||
|
|
109042e5af | ||
|
|
08328adc6c | ||
|
|
65806884b0 | ||
|
|
ad80e8281a | ||
|
|
2245149588 | ||
|
|
91709c1275 | ||
|
|
74ef28295a | ||
|
|
7d01f19667 | ||
|
|
d0e9177121 | ||
|
|
83851a9716 | ||
|
|
066ec1ac81 | ||
|
|
68744489f0 | ||
|
|
bf3e082c00 | ||
|
|
eb49f66926 | ||
|
|
8b6a58fa0e | ||
|
|
b725908c83 | ||
|
|
be307edba8 | ||
|
|
083f642cfa | ||
|
|
716da7e538 | ||
|
|
bcdc5bdaf4 | ||
|
|
a3e3a3bbf3 |
4
.github/workflows/continuous-integration.yml
vendored
4
.github/workflows/continuous-integration.yml
vendored
@@ -40,6 +40,7 @@ jobs:
|
||||
- "8.1"
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
dbal-version:
|
||||
- "default"
|
||||
extension:
|
||||
@@ -113,6 +114,7 @@ jobs:
|
||||
php-version:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3@dev"
|
||||
@@ -186,6 +188,7 @@ jobs:
|
||||
php-version:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3@dev"
|
||||
@@ -256,6 +259,7 @@ jobs:
|
||||
php-version:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3@dev"
|
||||
|
||||
36
UPGRADE.md
36
UPGRADE.md
@@ -1,3 +1,39 @@
|
||||
# Upgrade to 2.20
|
||||
|
||||
## Add `Doctrine\ORM\Query\OutputWalker` interface, deprecate `Doctrine\ORM\Query\SqlWalker::getExecutor()`
|
||||
|
||||
Output walkers should implement the new `\Doctrine\ORM\Query\OutputWalker` interface and create
|
||||
`Doctrine\ORM\Query\Exec\SqlFinalizer` instances instead of `Doctrine\ORM\Query\Exec\AbstractSqlExecutor`s.
|
||||
The output walker must not base its workings on the query `firstResult`/`maxResult` values, so that the
|
||||
`SqlFinalizer` can be kept in the query cache and used regardless of the actual `firstResult`/`maxResult` values.
|
||||
Any operation dependent on `firstResult`/`maxResult` should take place within the `SqlFinalizer::createExecutor()`
|
||||
method. Details can be found at https://github.com/doctrine/orm/pull/11188.
|
||||
|
||||
## Explictly forbid property hooks
|
||||
|
||||
Property hooks are not supported yet by Doctrine ORM. Until support is added,
|
||||
they are explicitly forbidden because the support would result in a breaking
|
||||
change in behavior.
|
||||
|
||||
Progress on this is tracked at https://github.com/doctrine/orm/issues/11624 .
|
||||
|
||||
## PARTIAL DQL syntax is undeprecated
|
||||
|
||||
Use of the PARTIAL keyword is not deprecated anymore in DQL, because we will be
|
||||
able to support PARTIAL objects with PHP 8.4 Lazy Objects and
|
||||
Symfony/VarExporter in a better way. When we decided to remove this feature
|
||||
these two abstractions did not exist yet.
|
||||
|
||||
WARNING: If you want to upgrade to 3.x and still use PARTIAL keyword in DQL
|
||||
with array or object hydrators, then you have to directly migrate to ORM 3.3.x or higher.
|
||||
PARTIAL keyword in DQL is not available in 3.0, 3.1 and 3.2 of ORM.
|
||||
|
||||
## Deprecate `\Doctrine\ORM\Query\Parser::setCustomOutputTreeWalker()`
|
||||
|
||||
Use the `\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER` query hint to set the output walker
|
||||
class instead of setting it through the `\Doctrine\ORM\Query\Parser::setCustomOutputTreeWalker()` method
|
||||
on the parser instance.
|
||||
|
||||
# Upgrade to 2.19
|
||||
|
||||
## Deprecate calling `ClassMetadata::getAssociationMappedByTargetField()` with the owning side of an association
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"composer/package-versions-deprecated": true,
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true,
|
||||
"phpstan/extension-installer": true
|
||||
},
|
||||
"sort-packages": true
|
||||
},
|
||||
@@ -42,7 +43,9 @@
|
||||
"doctrine/annotations": "^1.13 || ^2",
|
||||
"doctrine/coding-standard": "^9.0.2 || ^12.0",
|
||||
"phpbench/phpbench": "^0.16.10 || ^1.0",
|
||||
"phpstan/extension-installer": "~1.1.0 || ^1.4",
|
||||
"phpstan/phpstan": "~1.4.10 || 1.12.6",
|
||||
"phpstan/phpstan-deprecation-rules": "^1",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6",
|
||||
"psr/log": "^1 || ^2 || ^3",
|
||||
"squizlabs/php_codesniffer": "3.7.2",
|
||||
|
||||
Submodule docs/en/_theme deleted from 6f1bc8bead
@@ -81,8 +81,8 @@ implements the ``MappingDriver`` interface:
|
||||
/**
|
||||
* Loads the metadata for the specified class into the provided container.
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-param ClassMetadata<T> $metadata
|
||||
* @param class-string<T> $className
|
||||
* @param ClassMetadata<T> $metadata
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
@@ -93,8 +93,7 @@ implements the ``MappingDriver`` interface:
|
||||
/**
|
||||
* Gets the names of all mapped classes known to this driver.
|
||||
*
|
||||
* @return array<int, string> The names of all mapped classes known to this driver.
|
||||
* @psalm-return list<class-string>
|
||||
* @return list<class-string> The names of all mapped classes known to this driver.
|
||||
*/
|
||||
public function getAllClassNames();
|
||||
|
||||
@@ -102,7 +101,7 @@ implements the ``MappingDriver`` interface:
|
||||
* Returns whether the class with the specified name should have its metadata loaded.
|
||||
* This is only the case if it is either mapped as an Entity or a MappedSuperclass.
|
||||
*
|
||||
* @psalm-param class-string $className
|
||||
* @param class-string $className
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
@@ -165,6 +165,11 @@ parameters:
|
||||
count: 2
|
||||
path: src/Mapping/ClassMetadataFactory.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method ReflectionProperty\\:\\:getHooks\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: src/Mapping/ClassMetadataInfo.php
|
||||
|
||||
-
|
||||
message: "#^Method Doctrine\\\\ORM\\\\Mapping\\\\NamingStrategy\\:\\:joinColumnName\\(\\) invoked with 2 parameters, 1 required\\.$#"
|
||||
count: 2
|
||||
|
||||
@@ -61,6 +61,11 @@ parameters:
|
||||
count: 2
|
||||
path: src/Mapping/ClassMetadataFactory.php
|
||||
|
||||
- '~^Call to deprecated method getSQLResultCasing\(\) of class Doctrine\\DBAL\\Platforms\\AbstractPlatform\.$~'
|
||||
-
|
||||
message: '~deprecated class Doctrine\\DBAL\\Tools\\Console\\Command\\ImportCommand\:~'
|
||||
path: src/Tools/Console/ConsoleRunner.php
|
||||
|
||||
# Symfony cache supports passing a key prefix to the clear method.
|
||||
- '/^Method Psr\\Cache\\CacheItemPoolInterface\:\:clear\(\) invoked with 1 parameter, 0 required\.$/'
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ includes:
|
||||
- phpstan-params.neon
|
||||
|
||||
parameters:
|
||||
reportUnmatchedIgnoredErrors: false
|
||||
|
||||
ignoreErrors:
|
||||
# deprecations from doctrine/dbal:3.x
|
||||
- '/^Call to an undefined method Doctrine\\DBAL\\Platforms\\AbstractPlatform::getGuidExpression\(\).$/'
|
||||
@@ -70,3 +72,13 @@ parameters:
|
||||
paths:
|
||||
- src/Mapping/Driver/XmlDriver.php
|
||||
- src/Mapping/Driver/YamlDriver.php
|
||||
|
||||
# Extending a deprecated class conditionally to maintain BC
|
||||
-
|
||||
message: '~deprecated class Doctrine\\Persistence\\Mapping\\Driver\\AnnotationDriver\:~'
|
||||
path: src/Mapping/Driver/CompatibilityAnnotationDriver.php
|
||||
|
||||
# We're sniffing for this deprecated class in order to detect Persistence 2
|
||||
-
|
||||
message: '~deprecated class Doctrine\\Common\\Persistence\\PersistentObject\:~'
|
||||
path: src/EntityManager.php
|
||||
|
||||
@@ -305,7 +305,7 @@
|
||||
<code><![CDATA[$persister->loadById($sortedId)]]></code>
|
||||
</InvalidReturnStatement>
|
||||
<InvalidReturnType>
|
||||
<code><![CDATA[?T]]></code>
|
||||
<code><![CDATA[T|null]]></code>
|
||||
</InvalidReturnType>
|
||||
<MissingReturnType>
|
||||
<code><![CDATA[wrapInTransaction]]></code>
|
||||
@@ -713,6 +713,9 @@
|
||||
<code><![CDATA[joinColumnName]]></code>
|
||||
<code><![CDATA[joinColumnName]]></code>
|
||||
</TooManyArguments>
|
||||
<UndefinedMethod>
|
||||
<code><![CDATA[getHooks]]></code>
|
||||
</UndefinedMethod>
|
||||
</file>
|
||||
<file src="src/Mapping/ColumnResult.php">
|
||||
<MissingConstructor>
|
||||
@@ -1865,6 +1868,12 @@
|
||||
<code><![CDATA[$this->_sqlStatements = &$this->sqlStatements]]></code>
|
||||
</UnsupportedPropertyReferenceUsage>
|
||||
</file>
|
||||
<file src="src/Query/Exec/FinalizedSelectExecutor.php">
|
||||
<PropertyNotSetInConstructor>
|
||||
<code><![CDATA[FinalizedSelectExecutor]]></code>
|
||||
<code><![CDATA[FinalizedSelectExecutor]]></code>
|
||||
</PropertyNotSetInConstructor>
|
||||
</file>
|
||||
<file src="src/Query/Exec/MultiTableDeleteExecutor.php">
|
||||
<InvalidReturnStatement>
|
||||
<code><![CDATA[$numDeleted]]></code>
|
||||
@@ -1993,6 +2002,9 @@
|
||||
<ArgumentTypeCoercion>
|
||||
<code><![CDATA[$stringPattern]]></code>
|
||||
</ArgumentTypeCoercion>
|
||||
<DeprecatedMethod>
|
||||
<code><![CDATA[setSqlExecutor]]></code>
|
||||
</DeprecatedMethod>
|
||||
<InvalidNullableReturnType>
|
||||
<code><![CDATA[AST\SelectStatement|AST\UpdateStatement|AST\DeleteStatement]]></code>
|
||||
</InvalidNullableReturnType>
|
||||
@@ -2054,11 +2066,6 @@
|
||||
<code><![CDATA[$token === TokenType::T_IDENTIFIER]]></code>
|
||||
</RedundantConditionGivenDocblockType>
|
||||
</file>
|
||||
<file src="src/Query/ParserResult.php">
|
||||
<PropertyNotSetInConstructor>
|
||||
<code><![CDATA[$sqlExecutor]]></code>
|
||||
</PropertyNotSetInConstructor>
|
||||
</file>
|
||||
<file src="src/Query/QueryExpressionVisitor.php">
|
||||
<InvalidReturnStatement>
|
||||
<code><![CDATA[new ArrayCollection($this->parameters)]]></code>
|
||||
|
||||
@@ -558,9 +558,11 @@ abstract class AbstractQuery
|
||||
|
||||
// DBAL 2
|
||||
if (! method_exists(QueryCacheProfile::class, 'setResultCache')) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
if (! $profile->getResultCacheDriver()) {
|
||||
$defaultHydrationCacheImpl = $this->_em->getConfiguration()->getHydrationCache();
|
||||
if ($defaultHydrationCacheImpl) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
$profile = $profile->setResultCacheDriver(DoctrineProvider::wrap($defaultHydrationCacheImpl));
|
||||
}
|
||||
}
|
||||
@@ -609,9 +611,11 @@ abstract class AbstractQuery
|
||||
|
||||
// DBAL 2
|
||||
if (! method_exists(QueryCacheProfile::class, 'setResultCache')) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
if (! $profile->getResultCacheDriver()) {
|
||||
$defaultResultCacheDriver = $this->_em->getConfiguration()->getResultCache();
|
||||
if ($defaultResultCacheDriver) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
$profile = $profile->setResultCacheDriver(DoctrineProvider::wrap($defaultResultCacheDriver));
|
||||
}
|
||||
}
|
||||
@@ -677,6 +681,7 @@ abstract class AbstractQuery
|
||||
$resultCacheDriver = DoctrineProvider::wrap($resultCache);
|
||||
|
||||
$this->_queryCacheProfile = $this->_queryCacheProfile
|
||||
// @phpstan-ignore method.deprecated
|
||||
? $this->_queryCacheProfile->setResultCacheDriver($resultCacheDriver)
|
||||
: new QueryCacheProfile(0, null, $resultCacheDriver);
|
||||
|
||||
@@ -780,6 +785,7 @@ abstract class AbstractQuery
|
||||
|
||||
// Compatibility for DBAL 2
|
||||
if (! method_exists($this->_queryCacheProfile, 'setResultCache')) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
$this->_queryCacheProfile = $this->_queryCacheProfile->setResultCacheDriver(DoctrineProvider::wrap($cache));
|
||||
|
||||
return $this;
|
||||
@@ -1235,6 +1241,7 @@ abstract class AbstractQuery
|
||||
|
||||
// Support for DBAL 2
|
||||
if (! method_exists($this->_hydrationCacheProfile, 'getResultCache')) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
$cacheDriver = $this->_hydrationCacheProfile->getResultCacheDriver();
|
||||
assert($cacheDriver !== null);
|
||||
|
||||
|
||||
@@ -21,15 +21,13 @@ class AssociationCacheEntry implements CacheEntry
|
||||
* The entity class name
|
||||
*
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var string
|
||||
* @psalm-var class-string
|
||||
* @var class-string
|
||||
*/
|
||||
public $class;
|
||||
|
||||
/**
|
||||
* @param string $class The entity class.
|
||||
* @param class-string $class The entity class.
|
||||
* @param array<string, mixed> $identifier The entity identifier.
|
||||
* @psalm-param class-string $class
|
||||
*/
|
||||
public function __construct($class, array $identifier)
|
||||
{
|
||||
|
||||
@@ -26,8 +26,7 @@ class CollectionCacheKey extends CacheKey
|
||||
* The owner entity class
|
||||
*
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var string
|
||||
* @psalm-var class-string
|
||||
* @var class-string
|
||||
*/
|
||||
public $entityClass;
|
||||
|
||||
@@ -40,10 +39,9 @@ class CollectionCacheKey extends CacheKey
|
||||
public $association;
|
||||
|
||||
/**
|
||||
* @param string $entityClass The entity class.
|
||||
* @param class-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.
|
||||
* @psalm-param class-string $entityClass
|
||||
*/
|
||||
public function __construct($entityClass, $association, array $ownerIdentifier)
|
||||
{
|
||||
|
||||
@@ -25,15 +25,13 @@ class EntityCacheEntry implements CacheEntry
|
||||
* The entity class name
|
||||
*
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var string
|
||||
* @psalm-var class-string
|
||||
* @var class-string
|
||||
*/
|
||||
public $class;
|
||||
|
||||
/**
|
||||
* @param string $class The entity class.
|
||||
* @param class-string $class The entity class.
|
||||
* @param array<string,mixed> $data The entity data.
|
||||
* @psalm-param class-string $class
|
||||
*/
|
||||
public function __construct($class, array $data)
|
||||
{
|
||||
|
||||
@@ -26,15 +26,13 @@ class EntityCacheKey extends CacheKey
|
||||
* The entity class name
|
||||
*
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var string
|
||||
* @psalm-var class-string
|
||||
* @var class-string
|
||||
*/
|
||||
public $entityClass;
|
||||
|
||||
/**
|
||||
* @param string $entityClass The entity class name. In a inheritance hierarchy it should always be the root entity class.
|
||||
* @param class-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
|
||||
* @psalm-param class-string $entityClass
|
||||
*/
|
||||
public function __construct($entityClass, array $identifier)
|
||||
{
|
||||
|
||||
@@ -254,9 +254,8 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
/**
|
||||
* @deprecated This method is not used anymore.
|
||||
*
|
||||
* @param string $targetEntity
|
||||
* @param object $element
|
||||
* @psalm-param class-string $targetEntity
|
||||
* @param class-string $targetEntity
|
||||
* @param object $element
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
@@ -8,6 +8,8 @@ use Doctrine\ORM\Cache\Exception\CacheException;
|
||||
|
||||
/**
|
||||
* Defines a contract for accessing a particular named region.
|
||||
*
|
||||
* @phpstan-ignore interface.extendsDeprecatedInterface
|
||||
*/
|
||||
interface Region extends MultiGetRegion
|
||||
{
|
||||
|
||||
@@ -72,6 +72,7 @@ class DefaultRegion implements Region
|
||||
CacheItemPoolInterface::class
|
||||
);
|
||||
|
||||
// @phpstan-ignore property.deprecated
|
||||
$this->cache = $cacheItemPool;
|
||||
$this->cacheItemPool = CacheAdapter::wrap($cacheItemPool);
|
||||
} elseif (! $cacheItemPool instanceof CacheItemPoolInterface) {
|
||||
@@ -82,6 +83,7 @@ class DefaultRegion implements Region
|
||||
get_debug_type($cacheItemPool)
|
||||
));
|
||||
} else {
|
||||
// @phpstan-ignore property.deprecated
|
||||
$this->cache = DoctrineProvider::wrap($cacheItemPool);
|
||||
$this->cacheItemPool = $cacheItemPool;
|
||||
}
|
||||
|
||||
@@ -269,6 +269,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
);
|
||||
|
||||
if (! isset($this->_attributes['entityNamespaces'][$entityNamespaceAlias])) {
|
||||
// @phpstan-ignore staticMethod.deprecatedClass
|
||||
throw UnknownEntityNamespace::fromNamespaceAlias($entityNamespaceAlias);
|
||||
}
|
||||
|
||||
@@ -314,6 +315,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
{
|
||||
// Compatibility with DBAL 2
|
||||
if (! method_exists(parent::class, 'getResultCache')) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
$cacheImpl = $this->getResultCacheImpl();
|
||||
|
||||
return $cacheImpl ? CacheAdapter::wrap($cacheImpl) : null;
|
||||
@@ -329,6 +331,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
{
|
||||
// Compatibility with DBAL 2
|
||||
if (! method_exists(parent::class, 'setResultCache')) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
$this->setResultCacheImpl(DoctrineProvider::wrap($cache));
|
||||
|
||||
return;
|
||||
@@ -684,8 +687,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string|callable|null
|
||||
* @psalm-return class-string|callable|null
|
||||
* @return class-string|callable|null
|
||||
*/
|
||||
public function getCustomNumericFunction($name)
|
||||
{
|
||||
@@ -702,7 +704,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*
|
||||
* Any previously added numeric functions are discarded.
|
||||
*
|
||||
* @psalm-param array<string, class-string> $functions The map of custom
|
||||
* @param array<string, class-string> $functions The map of custom
|
||||
* DQL numeric functions.
|
||||
*
|
||||
* @return void
|
||||
@@ -737,8 +739,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string|callable|null
|
||||
* @psalm-return class-string|callable|null
|
||||
* @return class-string|callable|null
|
||||
*/
|
||||
public function getCustomDatetimeFunction($name)
|
||||
{
|
||||
@@ -804,8 +805,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*
|
||||
* @param string $modeName The hydration mode name.
|
||||
*
|
||||
* @return string|null The hydrator class name.
|
||||
* @psalm-return class-string<AbstractHydrator>|null
|
||||
* @return class-string<AbstractHydrator>|null The hydrator class name.
|
||||
*/
|
||||
public function getCustomHydrationMode($modeName)
|
||||
{
|
||||
@@ -815,9 +815,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Adds a custom hydration mode.
|
||||
*
|
||||
* @param string $modeName The hydration mode name.
|
||||
* @param string $hydrator The hydrator class name.
|
||||
* @psalm-param class-string<AbstractHydrator> $hydrator
|
||||
* @param string $modeName The hydration mode name.
|
||||
* @param class-string<AbstractHydrator> $hydrator The hydrator class name.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -829,8 +828,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Sets a class metadata factory.
|
||||
*
|
||||
* @param string $cmfName
|
||||
* @psalm-param class-string $cmfName
|
||||
* @param class-string $cmfName
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -839,10 +837,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
$this->_attributes['classMetadataFactoryName'] = $cmfName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @psalm-return class-string
|
||||
*/
|
||||
/** @return class-string */
|
||||
public function getClassMetadataFactoryName()
|
||||
{
|
||||
if (! isset($this->_attributes['classMetadataFactoryName'])) {
|
||||
@@ -855,9 +850,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Adds a filter to the list of possible filters.
|
||||
*
|
||||
* @param string $name The name of the filter.
|
||||
* @param string $className The class name of the filter.
|
||||
* @psalm-param class-string<SQLFilter> $className
|
||||
* @param string $name The name of the filter.
|
||||
* @param class-string<SQLFilter> $className The class name of the filter.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -871,9 +865,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*
|
||||
* @param string $name The name of the filter.
|
||||
*
|
||||
* @return string|null The class name of the filter, or null if it is not
|
||||
* defined.
|
||||
* @psalm-return class-string<SQLFilter>|null
|
||||
* @return class-string<SQLFilter>|null The class name of the filter,
|
||||
* or null if it is not defined.
|
||||
*/
|
||||
public function getFilterClassName($name)
|
||||
{
|
||||
@@ -883,8 +876,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Sets default repository class.
|
||||
*
|
||||
* @param string $className
|
||||
* @psalm-param class-string<EntityRepository> $className
|
||||
* @param class-string<EntityRepository> $className
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
@@ -912,8 +904,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Get default repository class.
|
||||
*
|
||||
* @return string
|
||||
* @psalm-return class-string<EntityRepository>
|
||||
* @return class-string<EntityRepository>
|
||||
*/
|
||||
public function getDefaultRepositoryClassName()
|
||||
{
|
||||
|
||||
@@ -50,7 +50,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @param class-string<T> $className
|
||||
*
|
||||
* @psalm-return EntityRepository<T>
|
||||
*
|
||||
@@ -96,6 +96,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
E_USER_NOTICE
|
||||
);
|
||||
|
||||
// @phpstan-ignore method.deprecated
|
||||
return $this->wrapped->transactional($func);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,9 +30,7 @@ use Doctrine\ORM\Query\FilterCollection;
|
||||
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 class_exists;
|
||||
@@ -162,8 +160,9 @@ class EntityManager implements EntityManagerInterface
|
||||
throw MissingMappingDriverImplementation::create();
|
||||
}
|
||||
|
||||
$this->conn = $conn;
|
||||
$this->config = $config;
|
||||
$this->conn = $conn;
|
||||
$this->config = $config;
|
||||
// @phpstan-ignore method.deprecated
|
||||
$this->eventManager = $eventManager ?? $conn->getEventManager();
|
||||
|
||||
$metadataFactoryClassName = $config->getClassMetadataFactoryName();
|
||||
@@ -246,18 +245,24 @@ class EntityManager implements EntityManagerInterface
|
||||
|
||||
$this->conn->beginTransaction();
|
||||
|
||||
$successful = false;
|
||||
|
||||
try {
|
||||
$return = $func($this);
|
||||
|
||||
$this->flush();
|
||||
$this->conn->commit();
|
||||
|
||||
return $return ?: true;
|
||||
} catch (Throwable $e) {
|
||||
$this->close();
|
||||
$this->conn->rollBack();
|
||||
$successful = true;
|
||||
|
||||
throw $e;
|
||||
return $return ?: true;
|
||||
} finally {
|
||||
if (! $successful) {
|
||||
$this->close();
|
||||
if ($this->conn->isTransactionActive()) {
|
||||
$this->conn->rollBack();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,18 +273,24 @@ class EntityManager implements EntityManagerInterface
|
||||
{
|
||||
$this->conn->beginTransaction();
|
||||
|
||||
$successful = false;
|
||||
|
||||
try {
|
||||
$return = $func($this);
|
||||
|
||||
$this->flush();
|
||||
$this->conn->commit();
|
||||
|
||||
return $return;
|
||||
} catch (Throwable $e) {
|
||||
$this->close();
|
||||
$this->conn->rollBack();
|
||||
$successful = true;
|
||||
|
||||
throw $e;
|
||||
return $return;
|
||||
} finally {
|
||||
if (! $successful) {
|
||||
$this->close();
|
||||
if ($this->conn->isTransactionActive()) {
|
||||
$this->conn->rollBack();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,25 +417,23 @@ class EntityManager implements EntityManagerInterface
|
||||
/**
|
||||
* 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 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.
|
||||
* @psalm-param class-string<T> $className
|
||||
* @param class-string<T> $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.
|
||||
* @psalm-param LockMode::*|null $lockMode
|
||||
*
|
||||
* @return object|null The entity instance or NULL if the entity can not be found.
|
||||
* @psalm-return ?T
|
||||
* @return T|null The entity instance or NULL if the entity can not be found.
|
||||
*
|
||||
* @throws OptimisticLockException
|
||||
* @throws ORMInvalidArgumentException
|
||||
* @throws TransactionRequiredException
|
||||
* @throws ORMException
|
||||
*
|
||||
* @template T
|
||||
* @template T of object
|
||||
*/
|
||||
public function find($className, $id, $lockMode = null, $lockVersion = null)
|
||||
{
|
||||
@@ -615,6 +624,7 @@ class EntityManager implements EntityManagerInterface
|
||||
public function clear($entityName = null)
|
||||
{
|
||||
if ($entityName !== null && ! is_string($entityName)) {
|
||||
// @phpstan-ignore staticMethod.deprecated
|
||||
throw ORMInvalidArgumentException::invalidEntityName($entityName);
|
||||
}
|
||||
|
||||
@@ -801,11 +811,9 @@ class EntityManager implements EntityManagerInterface
|
||||
/**
|
||||
* Gets the repository for an entity class.
|
||||
*
|
||||
* @param string $entityName The name of the entity.
|
||||
* @psalm-param class-string<T> $entityName
|
||||
* @param class-string<T> $entityName The name of the entity.
|
||||
*
|
||||
* @return ObjectRepository|EntityRepository The repository class.
|
||||
* @psalm-return EntityRepository<T>
|
||||
* @return EntityRepository<T> The repository class.
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
@@ -1109,6 +1117,7 @@ class EntityManager implements EntityManagerInterface
|
||||
|
||||
private function configureLegacyMetadataCache(): void
|
||||
{
|
||||
// @phpstan-ignore method.deprecated
|
||||
$metadataCache = $this->config->getMetadataCacheImpl();
|
||||
if (! $metadataCache) {
|
||||
return;
|
||||
|
||||
@@ -29,9 +29,9 @@ interface EntityManagerInterface extends ObjectManager
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @param class-string<T> $className
|
||||
*
|
||||
* @psalm-return EntityRepository<T>
|
||||
* @return EntityRepository<T>
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
@@ -172,12 +172,10 @@ interface EntityManagerInterface extends ObjectManager
|
||||
* Gets a reference to the entity identified by the given type and identifier
|
||||
* without actually loading it, if the entity is not yet loaded.
|
||||
*
|
||||
* @param string $entityName The name of the entity type.
|
||||
* @param mixed $id The entity identifier.
|
||||
* @psalm-param class-string<T> $entityName
|
||||
* @param class-string<T> $entityName The name of the entity type.
|
||||
* @param mixed $id The entity identifier.
|
||||
*
|
||||
* @return object|null The entity reference.
|
||||
* @psalm-return T|null
|
||||
* @return T|null The entity reference.
|
||||
*
|
||||
* @throws ORMException
|
||||
*
|
||||
@@ -202,12 +200,10 @@ interface EntityManagerInterface extends ObjectManager
|
||||
*
|
||||
* @deprecated 2.7 This method is being removed from the ORM and won't have any replacement
|
||||
*
|
||||
* @param string $entityName The name of the entity type.
|
||||
* @param mixed $identifier The entity identifier.
|
||||
* @psalm-param class-string<T> $entityName
|
||||
* @param class-string<T> $entityName The name of the entity type.
|
||||
* @param mixed $identifier The entity identifier.
|
||||
*
|
||||
* @return object|null The (partial) entity reference
|
||||
* @psalm-return T|null
|
||||
* @return T|null The (partial) entity reference
|
||||
*
|
||||
* @template T
|
||||
*/
|
||||
@@ -337,7 +333,7 @@ interface EntityManagerInterface extends ObjectManager
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param string|class-string<T> $className
|
||||
* @param string|class-string<T> $className
|
||||
*
|
||||
* @return Mapping\ClassMetadata
|
||||
* @psalm-return ($className is class-string<T> ? Mapping\ClassMetadata<T> : Mapping\ClassMetadata<object>)
|
||||
|
||||
@@ -42,8 +42,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
/**
|
||||
* @internal This property will be private in 3.0, call {@see getEntityName()} instead.
|
||||
*
|
||||
* @var string
|
||||
* @psalm-var class-string<T>
|
||||
* @var class-string<T>
|
||||
*/
|
||||
protected $_entityName;
|
||||
|
||||
@@ -287,10 +286,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @psalm-return class-string<T>
|
||||
*/
|
||||
/** @return class-string<T> */
|
||||
protected function getEntityName()
|
||||
{
|
||||
return $this->_entityName;
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
/** @phpstan-ignore class.extendsDeprecatedClass */
|
||||
final class PostLoadEventArgs extends LifecycleEventArgs
|
||||
{
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
/** @phpstan-ignore class.extendsDeprecatedClass */
|
||||
final class PostPersistEventArgs extends LifecycleEventArgs
|
||||
{
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
/** @phpstan-ignore class.extendsDeprecatedClass */
|
||||
final class PostRemoveEventArgs extends LifecycleEventArgs
|
||||
{
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
/** @phpstan-ignore class.extendsDeprecatedClass */
|
||||
final class PostUpdateEventArgs extends LifecycleEventArgs
|
||||
{
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
/** @phpstan-ignore class.extendsDeprecatedClass */
|
||||
final class PrePersistEventArgs extends LifecycleEventArgs
|
||||
{
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
/** @phpstan-ignore class.extendsDeprecatedClass */
|
||||
final class PreRemoveEventArgs extends LifecycleEventArgs
|
||||
{
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ use function sprintf;
|
||||
|
||||
/**
|
||||
* Class that holds event arguments for a preUpdate event.
|
||||
*
|
||||
* @phpstan-ignore class.extendsDeprecatedClass
|
||||
*/
|
||||
class PreUpdateEventArgs extends LifecycleEventArgs
|
||||
{
|
||||
@@ -26,6 +28,7 @@ class PreUpdateEventArgs extends LifecycleEventArgs
|
||||
*/
|
||||
public function __construct($entity, EntityManagerInterface $em, array &$changeSet)
|
||||
{
|
||||
// @phpstan-ignore staticMethod.deprecatedClass
|
||||
parent::__construct($entity, $em);
|
||||
|
||||
$this->entityChangeSet = &$changeSet;
|
||||
|
||||
@@ -8,6 +8,8 @@ use Doctrine\ORM\ORMException as BaseORMException;
|
||||
|
||||
/**
|
||||
* Should become an interface in 3.0
|
||||
*
|
||||
* @phpstan-ignore class.extendsDeprecatedClass
|
||||
*/
|
||||
class ORMException extends BaseORMException
|
||||
{
|
||||
|
||||
@@ -73,6 +73,7 @@ abstract class AbstractIdGenerator
|
||||
throw new InvalidArgumentException('Unsupported entity manager implementation.');
|
||||
}
|
||||
|
||||
// @phpstan-ignore method.deprecated
|
||||
return $this->generate($em, $entity);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ trait CriteriaOrderings
|
||||
private static function getCriteriaOrderings(Criteria $criteria): array
|
||||
{
|
||||
if (! method_exists(Criteria::class, 'orderings')) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
return $criteria->getOrderings();
|
||||
}
|
||||
|
||||
|
||||
@@ -273,7 +273,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-param class-string $className
|
||||
* @param class-string $className
|
||||
* @psalm-param array<string, mixed> $data
|
||||
*
|
||||
* @return mixed
|
||||
|
||||
@@ -172,6 +172,8 @@ class ClassMetadataBuilder
|
||||
/**
|
||||
* Adds named query.
|
||||
*
|
||||
* @deprecated
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $dqlQuery
|
||||
*
|
||||
@@ -216,11 +218,11 @@ class ClassMetadataBuilder
|
||||
/**
|
||||
* Sets the discriminator column details.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $type
|
||||
* @param int $length
|
||||
* @psalm-param class-string<BackedEnum>|null $enumType
|
||||
* @psalm-param array<string, mixed> $options
|
||||
* @param string $name
|
||||
* @param string $type
|
||||
* @param int $length
|
||||
* @param class-string<BackedEnum>|null $enumType
|
||||
* @param array<string, mixed> $options
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
||||
@@ -420,7 +420,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
/**
|
||||
* Gets the lower-case short name of a class.
|
||||
*
|
||||
* @psalm-param class-string $className
|
||||
* @param class-string $className
|
||||
*/
|
||||
private function getShortName(string $className): string
|
||||
{
|
||||
@@ -558,6 +558,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
{
|
||||
foreach ($parentClass->namedQueries as $name => $query) {
|
||||
if (! isset($subClass->namedQueries[$name])) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
$subClass->addNamedQuery(
|
||||
[
|
||||
'name' => $query['name'],
|
||||
@@ -575,6 +576,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
{
|
||||
foreach ($parentClass->namedNativeQueries as $name => $query) {
|
||||
if (! isset($subClass->namedNativeQueries[$name])) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
$subClass->addNamedNativeQuery(
|
||||
[
|
||||
'name' => $query['name'],
|
||||
@@ -637,7 +639,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
$platform = $this->getTargetPlatform();
|
||||
|
||||
// Platforms that do not have native IDENTITY support need a sequence to emulate this behaviour.
|
||||
/** @psalm-suppress UndefinedClass, InvalidClass */
|
||||
/** @psalm-suppress UndefinedClass, InvalidClass */ // @phpstan-ignore method.deprecated
|
||||
if (! $platform instanceof MySQLPlatform && ! $platform instanceof SqlitePlatform && ! $platform instanceof SQLServerPlatform && $platform->usesSequenceEmulatedIdentityColumns()) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
@@ -654,8 +656,9 @@ DEPRECATION
|
||||
$columnName = $class->getSingleIdentifierColumnName();
|
||||
$quoted = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']);
|
||||
$sequencePrefix = $class->getSequencePrefix($this->getTargetPlatform());
|
||||
$sequenceName = $this->getTargetPlatform()->getIdentitySequenceName($sequencePrefix, $columnName);
|
||||
$definition = [
|
||||
// @phpstan-ignore method.deprecated
|
||||
$sequenceName = $this->getTargetPlatform()->getIdentitySequenceName($sequencePrefix, $columnName);
|
||||
$definition = [
|
||||
'sequenceName' => $this->truncateSequenceName($sequenceName),
|
||||
];
|
||||
|
||||
@@ -711,6 +714,7 @@ DEPRECATION
|
||||
$class->setIdGenerator(new AssignedGenerator());
|
||||
break;
|
||||
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
case ClassMetadata::GENERATOR_TYPE_UUID:
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
@@ -718,6 +722,7 @@ DEPRECATION
|
||||
'Mapping for %s: the "UUID" id generator strategy is deprecated with no replacement',
|
||||
$class->name
|
||||
);
|
||||
// @phpstan-ignore new.deprecated
|
||||
$class->setIdGenerator(new UuidGenerator());
|
||||
break;
|
||||
|
||||
@@ -845,8 +850,10 @@ DEPRECATION
|
||||
*/
|
||||
protected function getFqcnFromAlias($namespaceAlias, $simpleClassName)
|
||||
{
|
||||
/** @psalm-var class-string */
|
||||
return $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;
|
||||
/** @var class-string $classString */
|
||||
$classString = $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;
|
||||
|
||||
return $classString;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -257,8 +257,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
/**
|
||||
* READ-ONLY: The name of the entity class.
|
||||
*
|
||||
* @var string
|
||||
* @psalm-var class-string<T>
|
||||
* @var class-string<T>
|
||||
*/
|
||||
public $name;
|
||||
|
||||
@@ -275,8 +274,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* hierarchy. If the entity is not part of a mapped inheritance hierarchy this is the same
|
||||
* as {@link $name}.
|
||||
*
|
||||
* @var string
|
||||
* @psalm-var class-string
|
||||
* @var class-string
|
||||
*/
|
||||
public $rootEntityName;
|
||||
|
||||
@@ -300,8 +298,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* The name of the custom repository class used for the entity class.
|
||||
* (Optional).
|
||||
*
|
||||
* @var string|null
|
||||
* @psalm-var ?class-string<EntityRepository>
|
||||
* @var class-string<EntityRepository>|null
|
||||
*/
|
||||
public $customRepositoryClassName;
|
||||
|
||||
@@ -323,7 +320,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* READ-ONLY: The names of the parent <em>entity</em> classes (ancestors), starting with the
|
||||
* nearest one and ending with the root entity class.
|
||||
*
|
||||
* @psalm-var list<class-string>
|
||||
* @var list<class-string>
|
||||
*/
|
||||
public $parentClasses = [];
|
||||
|
||||
@@ -350,7 +347,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* For subclasses of such root entities, the list can be reused/passed downwards, it only needs to
|
||||
* be filtered accordingly (only keep remaining subclasses)
|
||||
*
|
||||
* @psalm-var list<class-string>
|
||||
* @var list<class-string>
|
||||
*/
|
||||
public $subClasses = [];
|
||||
|
||||
@@ -548,9 +545,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*
|
||||
* @see discriminatorColumn
|
||||
*
|
||||
* @var array<int|string, string>
|
||||
*
|
||||
* @psalm-var array<int|string, class-string>
|
||||
* @var array<int|string, class-string>
|
||||
*/
|
||||
public $discriminatorMap = [];
|
||||
|
||||
@@ -811,8 +806,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* Initializes a new ClassMetadata instance that will hold the object-relational mapping
|
||||
* metadata of the class with the given name.
|
||||
*
|
||||
* @param string $entityName The name of the entity class the new instance is used for.
|
||||
* @psalm-param class-string<T> $entityName
|
||||
* @param class-string<T> $entityName The name of the entity class the new instance is used for.
|
||||
*/
|
||||
public function __construct($entityName, ?NamingStrategy $namingStrategy = null, ?TypedFieldMapper $typedFieldMapper = null)
|
||||
{
|
||||
@@ -1405,6 +1399,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*/
|
||||
public function getColumnName($fieldName)
|
||||
{
|
||||
// @phpstan-ignore property.deprecated
|
||||
return $this->columnNames[$fieldName] ?? $fieldName;
|
||||
}
|
||||
|
||||
@@ -1659,6 +1654,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
$mapping['quoted'] = true;
|
||||
}
|
||||
|
||||
// @phpstan-ignore property.deprecated
|
||||
$this->columnNames[$mapping['fieldName']] = $mapping['columnName'];
|
||||
|
||||
if (isset($this->fieldNames[$mapping['columnName']]) || ($this->discriminatorColumn && $this->discriminatorColumn['name'] === $mapping['columnName'])) {
|
||||
@@ -1683,6 +1679,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
}
|
||||
}
|
||||
|
||||
// @phpstan-ignore method.deprecated
|
||||
if (Type::hasType($mapping['type']) && Type::getType($mapping['type'])->canRequireSQLConversion()) {
|
||||
if (isset($mapping['id']) && $mapping['id'] === true) {
|
||||
throw MappingException::sqlConversionNotAllowedForIdentifiers($this->name, $mapping['fieldName'], $mapping['type']);
|
||||
@@ -2423,7 +2420,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* Assumes that the class names in the passed array are in the order:
|
||||
* directParent -> directParentParent -> directParentParentParent ... -> root.
|
||||
*
|
||||
* @psalm-param list<class-string> $classNames
|
||||
* @param list<class-string> $classNames
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -2576,6 +2573,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
|
||||
unset($this->fieldMappings[$fieldName]);
|
||||
unset($this->fieldNames[$mapping['columnName']]);
|
||||
// @phpstan-ignore property.deprecated
|
||||
unset($this->columnNames[$mapping['fieldName']]);
|
||||
|
||||
$overrideMapping = $this->validateAndCompleteFieldMapping($overrideMapping);
|
||||
@@ -2699,6 +2697,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*/
|
||||
private function isInheritanceType(int $type): bool
|
||||
{
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
if ($type === self::INHERITANCE_TYPE_TABLE_PER_CLASS) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
@@ -2710,6 +2709,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
return $type === self::INHERITANCE_TYPE_NONE ||
|
||||
$type === self::INHERITANCE_TYPE_SINGLE_TABLE ||
|
||||
$type === self::INHERITANCE_TYPE_JOINED ||
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
$type === self::INHERITANCE_TYPE_TABLE_PER_CLASS;
|
||||
}
|
||||
|
||||
@@ -2766,8 +2766,9 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
public function addInheritedFieldMapping(array $fieldMapping)
|
||||
{
|
||||
$this->fieldMappings[$fieldMapping['fieldName']] = $fieldMapping;
|
||||
$this->columnNames[$fieldMapping['fieldName']] = $fieldMapping['columnName'];
|
||||
$this->fieldNames[$fieldMapping['columnName']] = $fieldMapping['fieldName'];
|
||||
// @phpstan-ignore property.deprecated
|
||||
$this->columnNames[$fieldMapping['fieldName']] = $fieldMapping['columnName'];
|
||||
$this->fieldNames[$fieldMapping['columnName']] = $fieldMapping['fieldName'];
|
||||
|
||||
if (isset($fieldMapping['generated'])) {
|
||||
$this->requiresFetchAfterChange = true;
|
||||
@@ -3017,8 +3018,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
/**
|
||||
* Registers a custom repository class for the entity class.
|
||||
*
|
||||
* @param string|null $repositoryClassName The class name of the custom mapper.
|
||||
* @psalm-param class-string<EntityRepository>|null $repositoryClassName
|
||||
* @param class-string<EntityRepository>|null $repositoryClassName The class name of the custom mapper.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -3555,8 +3555,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*
|
||||
* @param string $assocName
|
||||
*
|
||||
* @return string
|
||||
* @psalm-return class-string
|
||||
* @return class-string
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
@@ -3859,6 +3858,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
if ($schemaName) {
|
||||
$sequencePrefix = $schemaName . '.' . $tableName;
|
||||
|
||||
// @phpstan-ignore method.deprecated
|
||||
if (! $platform->supportsSchemas() && $platform->canEmulateSchemas()) {
|
||||
$sequencePrefix = $schemaName . '__' . $tableName;
|
||||
}
|
||||
@@ -3875,7 +3875,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
}
|
||||
}
|
||||
|
||||
/** @psalm-param class-string $class */
|
||||
/** @param class-string $class */
|
||||
private function getAccessibleProperty(ReflectionService $reflService, string $class, string $field): ?ReflectionProperty
|
||||
{
|
||||
$reflectionProperty = $reflService->getAccessibleProperty($class, $field);
|
||||
@@ -3890,6 +3890,10 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
}
|
||||
}
|
||||
|
||||
if (PHP_VERSION_ID >= 80400 && $reflectionProperty !== null && count($reflectionProperty->getHooks()) > 0) {
|
||||
throw new LogicException('Doctrine ORM does not support property hooks in this version. Check https://github.com/doctrine/orm/issues/11624 for details of versions that support property hooks.');
|
||||
}
|
||||
|
||||
return $reflectionProperty;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ use function trim;
|
||||
*/
|
||||
class DefaultEntityListenerResolver implements EntityListenerResolver
|
||||
{
|
||||
/** @psalm-var array<class-string, object> Map to store entity listener instances. */
|
||||
/** @var array<class-string, object> Map to store entity listener instances. */
|
||||
private $instances = [];
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,6 +42,7 @@ class DefaultQuoteStrategy implements QuoteStrategy
|
||||
if (! empty($class->table['schema'])) {
|
||||
$tableName = $class->table['schema'] . '.' . $class->table['name'];
|
||||
|
||||
// @phpstan-ignore method.deprecated
|
||||
if (! $platform->supportsSchemas() && $platform->canEmulateSchemas()) {
|
||||
$tableName = $class->table['schema'] . '__' . $class->table['name'];
|
||||
}
|
||||
@@ -90,7 +91,8 @@ class DefaultQuoteStrategy implements QuoteStrategy
|
||||
$schema = '';
|
||||
|
||||
if (isset($association['joinTable']['schema'])) {
|
||||
$schema = $association['joinTable']['schema'];
|
||||
$schema = $association['joinTable']['schema'];
|
||||
// @phpstan-ignore method.deprecated
|
||||
$schema .= ! $platform->supportsSchemas() && $platform->canEmulateSchemas() ? '__' : '.';
|
||||
}
|
||||
|
||||
|
||||
@@ -47,10 +47,7 @@ class AnnotationDriver extends CompatibilityAnnotationDriver
|
||||
*/
|
||||
protected $reader;
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
* @psalm-var array<class-string, int>
|
||||
*/
|
||||
/** @var array<class-string, int> */
|
||||
protected $entityAnnotationClasses = [
|
||||
Mapping\Entity::class => 1,
|
||||
Mapping\MappedSuperclass::class => 2,
|
||||
@@ -89,8 +86,8 @@ class AnnotationDriver extends CompatibilityAnnotationDriver
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-param ClassMetadata<T> $metadata
|
||||
* @param class-string<T> $className
|
||||
* @param ClassMetadata<T> $metadata
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
|
||||
@@ -65,6 +65,7 @@ class AttributeDriver extends CompatibilityAnnotationDriver
|
||||
$this->reader = new AttributeReader();
|
||||
$this->addPaths($paths);
|
||||
|
||||
// @phpstan-ignore property.deprecated
|
||||
if ($this->entityAnnotationClasses !== self::ENTITY_ATTRIBUTE_CLASSES) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
@@ -114,6 +115,7 @@ class AttributeDriver extends CompatibilityAnnotationDriver
|
||||
|
||||
foreach ($classAttributes as $a) {
|
||||
$attr = $a instanceof RepeatableAttributeCollection ? $a[0] : $a;
|
||||
// @phpstan-ignore property.deprecated
|
||||
if (isset($this->entityAnnotationClasses[get_class($attr)])) {
|
||||
return false;
|
||||
}
|
||||
@@ -125,8 +127,8 @@ class AttributeDriver extends CompatibilityAnnotationDriver
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-param ClassMetadata<T> $metadata
|
||||
* @param class-string<T> $className
|
||||
* @param ClassMetadata<T> $metadata
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
|
||||
@@ -185,8 +185,8 @@ class DatabaseDriver implements MappingDriver
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-param ClassMetadata<T> $metadata
|
||||
* @param class-string<T> $className
|
||||
* @param ClassMetadata<T> $metadata
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
@@ -533,7 +533,7 @@ class DatabaseDriver implements MappingDriver
|
||||
/**
|
||||
* Returns the mapped class name for a table if it exists. Otherwise return "classified" version.
|
||||
*
|
||||
* @psalm-return class-string
|
||||
* @return class-string
|
||||
*/
|
||||
private function getClassNameForTable(string $tableName): string
|
||||
{
|
||||
|
||||
@@ -10,6 +10,8 @@ use Doctrine\Persistence\Mapping\Driver\SymfonyFileLocator;
|
||||
* YamlDriver that additionally looks for mapping information in a global file.
|
||||
*
|
||||
* @deprecated This class is being removed from the ORM and won't have any replacement
|
||||
*
|
||||
* @phpstan-ignore class.extendsDeprecatedClass
|
||||
*/
|
||||
class SimplifiedYamlDriver extends YamlDriver
|
||||
{
|
||||
|
||||
@@ -73,8 +73,8 @@ class XmlDriver extends FileDriver
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-param ClassMetadata<T> $metadata
|
||||
* @param class-string<T> $className
|
||||
* @param ClassMetadata<T> $metadata
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
@@ -122,6 +122,7 @@ class XmlDriver extends FileDriver
|
||||
// Evaluate named queries
|
||||
if (isset($xmlRoot->{'named-queries'})) {
|
||||
foreach ($xmlRoot->{'named-queries'}->{'named-query'} ?? [] as $namedQueryElement) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
$metadata->addNamedQuery(
|
||||
[
|
||||
'name' => (string) $namedQueryElement['name'],
|
||||
@@ -134,6 +135,7 @@ class XmlDriver extends FileDriver
|
||||
// Evaluate native named queries
|
||||
if (isset($xmlRoot->{'named-native-queries'})) {
|
||||
foreach ($xmlRoot->{'named-native-queries'}->{'named-native-query'} ?? [] as $nativeQueryElement) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
$metadata->addNamedNativeQuery(
|
||||
[
|
||||
'name' => isset($nativeQueryElement['name']) ? (string) $nativeQueryElement['name'] : null,
|
||||
@@ -489,6 +491,7 @@ class XmlDriver extends FileDriver
|
||||
/** @psalm-suppress DeprecatedConstant */
|
||||
$orderBy[(string) $orderByField['name']] = isset($orderByField['direction'])
|
||||
? (string) $orderByField['direction']
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
: (class_exists(Order::class) ? (Order::Ascending)->value : Criteria::ASC);
|
||||
}
|
||||
|
||||
@@ -618,6 +621,7 @@ class XmlDriver extends FileDriver
|
||||
/** @psalm-suppress DeprecatedConstant */
|
||||
$orderBy[(string) $orderByField['name']] = isset($orderByField['direction'])
|
||||
? (string) $orderByField['direction']
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
: (class_exists(Order::class) ? (Order::Ascending)->value : Criteria::ASC);
|
||||
}
|
||||
|
||||
@@ -967,19 +971,19 @@ class XmlDriver extends FileDriver
|
||||
|
||||
if (isset($xmlElement->entity)) {
|
||||
foreach ($xmlElement->entity as $entityElement) {
|
||||
/** @psalm-var class-string $entityName */
|
||||
/** @var class-string $entityName */
|
||||
$entityName = (string) $entityElement['name'];
|
||||
$result[$entityName] = $entityElement;
|
||||
}
|
||||
} elseif (isset($xmlElement->{'mapped-superclass'})) {
|
||||
foreach ($xmlElement->{'mapped-superclass'} as $mappedSuperClass) {
|
||||
/** @psalm-var class-string $className */
|
||||
/** @var class-string $className */
|
||||
$className = (string) $mappedSuperClass['name'];
|
||||
$result[$className] = $mappedSuperClass;
|
||||
}
|
||||
} elseif (isset($xmlElement->embeddable)) {
|
||||
foreach ($xmlElement->embeddable as $embeddableElement) {
|
||||
/** @psalm-var class-string $embeddableName */
|
||||
/** @var class-string $embeddableName */
|
||||
$embeddableName = (string) $embeddableElement['name'];
|
||||
$result[$embeddableName] = $embeddableElement;
|
||||
}
|
||||
|
||||
@@ -63,8 +63,8 @@ class YamlDriver extends FileDriver
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-param ClassMetadata<T> $metadata
|
||||
* @param class-string<T> $className
|
||||
* @param ClassMetadata<T> $metadata
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
|
||||
@@ -18,8 +18,7 @@ use Doctrine\ORM\EntityRepository;
|
||||
final class Entity implements MappingAttribute
|
||||
{
|
||||
/**
|
||||
* @var string|null
|
||||
* @psalm-var class-string<EntityRepository<T>>|null
|
||||
* @var class-string<EntityRepository<T>>|null
|
||||
* @readonly
|
||||
*/
|
||||
public $repositoryClass;
|
||||
|
||||
@@ -17,13 +17,12 @@ use Doctrine\ORM\EntityRepository;
|
||||
final class MappedSuperclass implements MappingAttribute
|
||||
{
|
||||
/**
|
||||
* @var string|null
|
||||
* @psalm-var class-string<EntityRepository>|null
|
||||
* @var class-string<EntityRepository>|null
|
||||
* @readonly
|
||||
*/
|
||||
public $repositoryClass;
|
||||
|
||||
/** @psalm-param class-string<EntityRepository>|null $repositoryClass */
|
||||
/** @param class-string<EntityRepository>|null $repositoryClass */
|
||||
public function __construct(?string $repositoryClass = null)
|
||||
{
|
||||
$this->repositoryClass = $repositoryClass;
|
||||
|
||||
@@ -4,7 +4,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Mapping;
|
||||
|
||||
/** A marker interface for mapping attributes. */
|
||||
/**
|
||||
* A marker interface for mapping attributes.
|
||||
*
|
||||
* @phpstan-ignore interface.extendsDeprecatedInterface
|
||||
*/
|
||||
interface MappingAttribute extends Annotation
|
||||
{
|
||||
}
|
||||
|
||||
@@ -33,8 +33,7 @@ final class ReflectionPropertiesGetter
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
* @psalm-param class-string $className
|
||||
* @param class-string $className
|
||||
*
|
||||
* @return ReflectionProperty[] indexed by property internal name
|
||||
*/
|
||||
@@ -57,7 +56,7 @@ final class ReflectionPropertiesGetter
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-param class-string $className
|
||||
* @param class-string $className
|
||||
*
|
||||
* @return ReflectionClass[]
|
||||
* @psalm-return list<ReflectionClass<object>>
|
||||
|
||||
@@ -250,6 +250,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
|
||||
// If the database platform supports FKs, just
|
||||
// delete the row from the root table. Cascades do the rest.
|
||||
// @phpstan-ignore method.deprecated
|
||||
if ($this->platform->supportsForeignKeyConstraints()) {
|
||||
$rootClass = $this->em->getClassMetadata($this->class->rootEntityName);
|
||||
$rootTable = $this->quoteStrategy->getTableName($rootClass, $this->platform);
|
||||
|
||||
@@ -173,6 +173,7 @@ EOPHP;
|
||||
$this->isLazyGhostObjectEnabled = false;
|
||||
|
||||
$proxyGenerator = new ProxyGenerator($proxyDir, $proxyNs);
|
||||
// @phpstan-ignore classConstant.deprecatedInterface
|
||||
$proxyGenerator->setPlaceholder('baseProxyInterface', LegacyProxy::class);
|
||||
|
||||
parent::__construct($proxyGenerator, $em->getMetadataFactory(), $autoGenerate);
|
||||
|
||||
@@ -18,6 +18,8 @@ use Doctrine\ORM\Query\AST\DeleteStatement;
|
||||
use Doctrine\ORM\Query\AST\SelectStatement;
|
||||
use Doctrine\ORM\Query\AST\UpdateStatement;
|
||||
use Doctrine\ORM\Query\Exec\AbstractSqlExecutor;
|
||||
use Doctrine\ORM\Query\Exec\SqlFinalizer;
|
||||
use Doctrine\ORM\Query\OutputWalker;
|
||||
use Doctrine\ORM\Query\Parameter;
|
||||
use Doctrine\ORM\Query\ParameterTypeInferer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
@@ -33,6 +35,7 @@ use function assert;
|
||||
use function count;
|
||||
use function get_debug_type;
|
||||
use function in_array;
|
||||
use function is_a;
|
||||
use function is_int;
|
||||
use function ksort;
|
||||
use function md5;
|
||||
@@ -196,7 +199,7 @@ class Query extends AbstractQuery
|
||||
*/
|
||||
public function getSQL()
|
||||
{
|
||||
return $this->parse()->getSqlExecutor()->getSqlStatements();
|
||||
return $this->getSqlExecutor()->getSqlStatements();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -285,7 +288,7 @@ class Query extends AbstractQuery
|
||||
*/
|
||||
protected function _doExecute()
|
||||
{
|
||||
$executor = $this->parse()->getSqlExecutor();
|
||||
$executor = $this->getSqlExecutor();
|
||||
|
||||
if ($this->_queryCacheProfile) {
|
||||
$executor->setQueryCacheProfile($this->_queryCacheProfile);
|
||||
@@ -344,6 +347,7 @@ class Query extends AbstractQuery
|
||||
|
||||
$cache = method_exists(QueryCacheProfile::class, 'getResultCache')
|
||||
? $this->_queryCacheProfile->getResultCache()
|
||||
// @phpstan-ignore method.deprecated
|
||||
: $this->_queryCacheProfile->getResultCacheDriver();
|
||||
|
||||
assert($cache !== null);
|
||||
@@ -812,11 +816,31 @@ class Query extends AbstractQuery
|
||||
{
|
||||
ksort($this->_hints);
|
||||
|
||||
if (! $this->hasHint(self::HINT_CUSTOM_OUTPUT_WALKER)) {
|
||||
// Assume Parser will create the SqlOutputWalker; save is_a call, which might trigger a class load
|
||||
$firstAndMaxResult = '';
|
||||
} else {
|
||||
$outputWalkerClass = $this->getHint(self::HINT_CUSTOM_OUTPUT_WALKER);
|
||||
if (is_a($outputWalkerClass, OutputWalker::class, true)) {
|
||||
$firstAndMaxResult = '';
|
||||
} else {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/11188/',
|
||||
'Your output walker class %s should implement %s in order to provide a %s. This also means the output walker should not use the query firstResult/maxResult values, which should be read from the query by the SqlFinalizer only.',
|
||||
$outputWalkerClass,
|
||||
OutputWalker::class,
|
||||
SqlFinalizer::class
|
||||
);
|
||||
$firstAndMaxResult = '&firstResult=' . $this->firstResult . '&maxResult=' . $this->maxResults;
|
||||
}
|
||||
}
|
||||
|
||||
return md5(
|
||||
$this->getDQL() . serialize($this->_hints) .
|
||||
'&platform=' . get_debug_type($this->getEntityManager()->getConnection()->getDatabasePlatform()) .
|
||||
($this->_em->hasFilters() ? $this->_em->getFilters()->getHash() : '') .
|
||||
'&firstResult=' . $this->firstResult . '&maxResult=' . $this->maxResults .
|
||||
$firstAndMaxResult .
|
||||
'&hydrationMode=' . $this->_hydrationMode . '&types=' . serialize($this->parsedTypes) . 'DOCTRINE_QUERY_CACHE_SALT'
|
||||
);
|
||||
}
|
||||
@@ -835,4 +859,9 @@ class Query extends AbstractQuery
|
||||
|
||||
$this->state = self::STATE_DIRTY;
|
||||
}
|
||||
|
||||
private function getSqlExecutor(): AbstractSqlExecutor
|
||||
{
|
||||
return $this->parse()->prepareSqlExecutor($this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/** @phpstan-ignore class.extendsDeprecatedClass */
|
||||
class InListExpression extends InExpression
|
||||
{
|
||||
/** @var non-empty-list<mixed> */
|
||||
@@ -15,6 +16,7 @@ class InListExpression extends InExpression
|
||||
$this->literals = $literals;
|
||||
$this->not = $not;
|
||||
|
||||
// @phpstan-ignore staticMethod.deprecatedClass
|
||||
parent::__construct($expression);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/** @phpstan-ignore class.extendsDeprecatedClass */
|
||||
class InSubselectExpression extends InExpression
|
||||
{
|
||||
/** @var Subselect */
|
||||
@@ -14,6 +15,7 @@ class InSubselectExpression extends InExpression
|
||||
$this->subselect = $subselect;
|
||||
$this->not = $not;
|
||||
|
||||
// @phpstan-ignore staticMethod.deprecatedClass
|
||||
parent::__construct($expression);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ class IndexBy extends Node
|
||||
|
||||
public function __construct(PathExpression $singleValuedPathExpression)
|
||||
{
|
||||
// @phpstan-ignore property.deprecated
|
||||
$this->singleValuedPathExpression = $this->simpleStateFieldPathExpression = $singleValuedPathExpression;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ abstract class AbstractSqlExecutor
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
// @phpstan-ignore property.deprecated
|
||||
$this->_sqlStatements = &$this->sqlStatements;
|
||||
}
|
||||
|
||||
@@ -93,10 +94,13 @@ abstract class AbstractSqlExecutor
|
||||
|
||||
public function __wakeup(): void
|
||||
{
|
||||
// @phpstan-ignore property.deprecated
|
||||
if ($this->_sqlStatements !== null && $this->sqlStatements === null) {
|
||||
// @phpstan-ignore property.deprecated
|
||||
$this->sqlStatements = $this->_sqlStatements;
|
||||
}
|
||||
|
||||
// @phpstan-ignore property.deprecated
|
||||
$this->_sqlStatements = &$this->sqlStatements;
|
||||
}
|
||||
}
|
||||
|
||||
33
src/Query/Exec/FinalizedSelectExecutor.php
Normal file
33
src/Query/Exec/FinalizedSelectExecutor.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\Exec;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Result;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
|
||||
/**
|
||||
* SQL executor for a given, final, single SELECT SQL query
|
||||
*
|
||||
* @method string getSqlStatements()
|
||||
*/
|
||||
class FinalizedSelectExecutor extends AbstractSqlExecutor
|
||||
{
|
||||
public function __construct(string $sql)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->sqlStatements = $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<mixed>|array<string, mixed> $params
|
||||
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types
|
||||
*/
|
||||
public function execute(Connection $conn, array $params, array $types): Result
|
||||
{
|
||||
return $conn->executeQuery($this->getSqlStatements(), $params, $types, $this->queryCacheProfile);
|
||||
}
|
||||
}
|
||||
28
src/Query/Exec/PreparedExecutorFinalizer.php
Normal file
28
src/Query/Exec/PreparedExecutorFinalizer.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\Exec;
|
||||
|
||||
use Doctrine\ORM\Query;
|
||||
|
||||
/**
|
||||
* PreparedExecutorFinalizer is a wrapper for the SQL finalization
|
||||
* phase that does nothing - it is constructed with the sql executor
|
||||
* already.
|
||||
*/
|
||||
final class PreparedExecutorFinalizer implements SqlFinalizer
|
||||
{
|
||||
/** @var AbstractSqlExecutor */
|
||||
private $executor;
|
||||
|
||||
public function __construct(AbstractSqlExecutor $exeutor)
|
||||
{
|
||||
$this->executor = $exeutor;
|
||||
}
|
||||
|
||||
public function createExecutor(Query $query): AbstractSqlExecutor
|
||||
{
|
||||
return $this->executor;
|
||||
}
|
||||
}
|
||||
64
src/Query/Exec/SingleSelectSqlFinalizer.php
Normal file
64
src/Query/Exec/SingleSelectSqlFinalizer.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\Exec;
|
||||
|
||||
use Doctrine\DBAL\LockMode;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Query\QueryException;
|
||||
use Doctrine\ORM\Utility\LockSqlHelper;
|
||||
|
||||
/**
|
||||
* SingleSelectSqlFinalizer finalizes a given SQL query by applying
|
||||
* the query's firstResult/maxResult values as well as extra read lock/write lock
|
||||
* statements, both through the platform-specific methods.
|
||||
*
|
||||
* The resulting, "finalized" SQL is passed to a FinalizedSelectExecutor.
|
||||
*/
|
||||
class SingleSelectSqlFinalizer implements SqlFinalizer
|
||||
{
|
||||
use LockSqlHelper;
|
||||
|
||||
/** @var string */
|
||||
private $sql;
|
||||
|
||||
public function __construct(string $sql)
|
||||
{
|
||||
$this->sql = $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method exists temporarily to support old SqlWalker interfaces.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @psalm-internal Doctrine\ORM
|
||||
*/
|
||||
public function finalizeSql(Query $query): string
|
||||
{
|
||||
$platform = $query->getEntityManager()->getConnection()->getDatabasePlatform();
|
||||
|
||||
$sql = $platform->modifyLimitQuery($this->sql, $query->getMaxResults(), $query->getFirstResult());
|
||||
|
||||
$lockMode = $query->getHint(Query::HINT_LOCK_MODE) ?: LockMode::NONE;
|
||||
|
||||
if ($lockMode !== LockMode::NONE && $lockMode !== LockMode::OPTIMISTIC && $lockMode !== LockMode::PESSIMISTIC_READ && $lockMode !== LockMode::PESSIMISTIC_WRITE) {
|
||||
throw QueryException::invalidLockMode();
|
||||
}
|
||||
|
||||
if ($lockMode === LockMode::PESSIMISTIC_READ) {
|
||||
$sql .= ' ' . $this->getReadLockSQL($platform);
|
||||
} elseif ($lockMode === LockMode::PESSIMISTIC_WRITE) {
|
||||
$sql .= ' ' . $this->getWriteLockSQL($platform);
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/** @return FinalizedSelectExecutor */
|
||||
public function createExecutor(Query $query): AbstractSqlExecutor
|
||||
{
|
||||
return new FinalizedSelectExecutor($this->finalizeSql($query));
|
||||
}
|
||||
}
|
||||
@@ -14,8 +14,6 @@ use Doctrine\ORM\Query\SqlWalker;
|
||||
* that are mapped to a single table.
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*
|
||||
* @todo This is exactly the same as SingleSelectExecutor. Unify in SingleStatementExecutor.
|
||||
*/
|
||||
class SingleTableDeleteUpdateExecutor extends AbstractSqlExecutor
|
||||
{
|
||||
|
||||
26
src/Query/Exec/SqlFinalizer.php
Normal file
26
src/Query/Exec/SqlFinalizer.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\Exec;
|
||||
|
||||
use Doctrine\ORM\Query;
|
||||
|
||||
/**
|
||||
* SqlFinalizers are created by OutputWalkers that traversed the DQL AST.
|
||||
* The SqlFinalizer instance can be kept in the query cache and re-used
|
||||
* at a later time.
|
||||
*
|
||||
* Once the SqlFinalizer has been created or retrieved from the query cache,
|
||||
* it receives the Query object again in order to yield the AbstractSqlExecutor
|
||||
* that will then be used to execute the query.
|
||||
*
|
||||
* The SqlFinalizer may assume that the DQL that was used to build the AST
|
||||
* and run the OutputWalker (which created the SqlFinalizer) is equivalent to
|
||||
* the query that will be passed to the createExecutor() method. Potential differences
|
||||
* are the parameter values or firstResult/maxResult settings.
|
||||
*/
|
||||
interface SqlFinalizer
|
||||
{
|
||||
public function createExecutor(Query $query): AbstractSqlExecutor;
|
||||
}
|
||||
@@ -84,7 +84,11 @@ class Lexer extends AbstractLexer
|
||||
public const T_CLOSE_CURLY_BRACE = TokenType::T_CLOSE_CURLY_BRACE;
|
||||
|
||||
// All tokens that are identifiers or keywords that could be considered as identifiers should be >= 100
|
||||
/** @deprecated No Replacement planned. */
|
||||
/**
|
||||
* @deprecated No Replacement planned.
|
||||
*
|
||||
* @phpstan-ignore classConstant.deprecated
|
||||
*/
|
||||
public const T_ALIASED_NAME = TokenType::T_ALIASED_NAME;
|
||||
|
||||
/** @deprecated use {@see TokenType::T_FULLY_QUALIFIED_NAME} */
|
||||
@@ -341,6 +345,7 @@ class Lexer extends AbstractLexer
|
||||
$value
|
||||
);
|
||||
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
return TokenType::T_ALIASED_NAME;
|
||||
}
|
||||
|
||||
|
||||
28
src/Query/OutputWalker.php
Normal file
28
src/Query/OutputWalker.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query;
|
||||
|
||||
use Doctrine\ORM\Query\Exec\SqlFinalizer;
|
||||
|
||||
/**
|
||||
* Interface for output walkers
|
||||
*
|
||||
* Output walkers, like tree walkers, can traverse the DQL AST to perform
|
||||
* their purpose.
|
||||
*
|
||||
* The goal of an OutputWalker is to ultimately provide the SqlFinalizer
|
||||
* which produces the final, executable SQL statement in a "finalization" phase.
|
||||
*
|
||||
* It must be possible to use the same SqlFinalizer for Queries with different
|
||||
* firstResult/maxResult values. In other words, SQL produced by the
|
||||
* output walker should not depend on those values, and any SQL generation/modification
|
||||
* specific to them should happen in the finalizer's `\Doctrine\ORM\Query\Exec\SqlFinalizer::createExecutor()`
|
||||
* method instead.
|
||||
*/
|
||||
interface OutputWalker
|
||||
{
|
||||
/** @param AST\DeleteStatement|AST\UpdateStatement|AST\SelectStatement $AST */
|
||||
public function getFinalizer($AST): SqlFinalizer;
|
||||
}
|
||||
@@ -8,10 +8,12 @@ use BackedEnum;
|
||||
use DateInterval;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use Doctrine\DBAL\ArrayParameterType;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\ParameterType;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
|
||||
use function class_exists;
|
||||
use function current;
|
||||
use function is_array;
|
||||
use function is_bool;
|
||||
@@ -67,9 +69,17 @@ class ParameterTypeInferer
|
||||
$firstValue = $firstValue->value;
|
||||
}
|
||||
|
||||
if (! class_exists(ArrayParameterType::class)) {
|
||||
return is_int($firstValue)
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
? Connection::PARAM_INT_ARRAY
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
: Connection::PARAM_STR_ARRAY;
|
||||
}
|
||||
|
||||
return is_int($firstValue)
|
||||
? Connection::PARAM_INT_ARRAY
|
||||
: Connection::PARAM_STR_ARRAY;
|
||||
? ArrayParameterType::INTEGER
|
||||
: ArrayParameterType::STRING;
|
||||
}
|
||||
|
||||
return ParameterType::STRING;
|
||||
|
||||
@@ -10,6 +10,7 @@ use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Query\AST\Functions;
|
||||
use Doctrine\ORM\Query\Exec\SqlFinalizer;
|
||||
use LogicException;
|
||||
use ReflectionClass;
|
||||
|
||||
@@ -51,7 +52,7 @@ class Parser
|
||||
{
|
||||
/**
|
||||
* @readonly Maps BUILT-IN string function names to AST class names.
|
||||
* @psalm-var array<string, class-string<Functions\FunctionNode>>
|
||||
* @var array<string, class-string<Functions\FunctionNode>>
|
||||
*/
|
||||
private static $stringFunctions = [
|
||||
'concat' => Functions\ConcatFunction::class,
|
||||
@@ -64,7 +65,7 @@ class Parser
|
||||
|
||||
/**
|
||||
* @readonly Maps BUILT-IN numeric function names to AST class names.
|
||||
* @psalm-var array<string, class-string<Functions\FunctionNode>>
|
||||
* @var array<string, class-string<Functions\FunctionNode>>
|
||||
*/
|
||||
private static $numericFunctions = [
|
||||
'length' => Functions\LengthFunction::class,
|
||||
@@ -87,7 +88,7 @@ class Parser
|
||||
|
||||
/**
|
||||
* @readonly Maps BUILT-IN datetime function names to AST class names.
|
||||
* @psalm-var array<string, class-string<Functions\FunctionNode>>
|
||||
* @var array<string, class-string<Functions\FunctionNode>>
|
||||
*/
|
||||
private static $datetimeFunctions = [
|
||||
'current_date' => Functions\CurrentDateFunction::class,
|
||||
@@ -162,7 +163,7 @@ class Parser
|
||||
/**
|
||||
* Any additional custom tree walkers that modify the AST.
|
||||
*
|
||||
* @psalm-var list<class-string<TreeWalker>>
|
||||
* @var list<class-string<TreeWalker>>
|
||||
*/
|
||||
private $customTreeWalkers = [];
|
||||
|
||||
@@ -193,21 +194,26 @@ class Parser
|
||||
* Sets a custom tree walker that produces output.
|
||||
* This tree walker will be run last over the AST, after any other walkers.
|
||||
*
|
||||
* @param string $className
|
||||
* @psalm-param class-string<SqlWalker> $className
|
||||
* @param class-string<SqlWalker> $className
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setCustomOutputTreeWalker($className)
|
||||
{
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/11641',
|
||||
'%s is deprecated, set the output walker class with the \Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER query hint instead',
|
||||
__METHOD__
|
||||
);
|
||||
|
||||
$this->customOutputWalker = $className;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a custom tree walker for modifying the AST.
|
||||
*
|
||||
* @param string $className
|
||||
* @psalm-param class-string<TreeWalker> $className
|
||||
* @param class-string<TreeWalker> $className
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -391,11 +397,26 @@ class Parser
|
||||
$this->queryComponents = $treeWalkerChain->getQueryComponents();
|
||||
}
|
||||
|
||||
$outputWalkerClass = $this->customOutputWalker ?: SqlWalker::class;
|
||||
$outputWalkerClass = $this->customOutputWalker ?: SqlOutputWalker::class;
|
||||
$outputWalker = new $outputWalkerClass($this->query, $this->parserResult, $this->queryComponents);
|
||||
|
||||
// Assign an SQL executor to the parser result
|
||||
$this->parserResult->setSqlExecutor($outputWalker->getExecutor($AST));
|
||||
if ($outputWalker instanceof OutputWalker) {
|
||||
$finalizer = $outputWalker->getFinalizer($AST);
|
||||
$this->parserResult->setSqlFinalizer($finalizer);
|
||||
} else {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/11188/',
|
||||
'Your output walker class %s should implement %s in order to provide a %s. This also means the output walker should not use the query firstResult/maxResult values, which should be read from the query by the SqlFinalizer only.',
|
||||
$outputWalkerClass,
|
||||
OutputWalker::class,
|
||||
SqlFinalizer::class
|
||||
);
|
||||
// @phpstan-ignore method.deprecated
|
||||
$executor = $outputWalker->getExecutor($AST);
|
||||
// @phpstan-ignore method.deprecated
|
||||
$this->parserResult->setSqlExecutor($executor);
|
||||
}
|
||||
|
||||
return $this->parserResult;
|
||||
}
|
||||
@@ -981,6 +1002,7 @@ class Parser
|
||||
return $this->lexer->token->value;
|
||||
}
|
||||
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
$this->match(TokenType::T_ALIASED_NAME);
|
||||
|
||||
assert($this->lexer->token !== null);
|
||||
@@ -1844,12 +1866,6 @@ class Parser
|
||||
*/
|
||||
public function PartialObjectExpression()
|
||||
{
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/issues/8471',
|
||||
'PARTIAL syntax in DQL is deprecated.'
|
||||
);
|
||||
|
||||
$this->match(TokenType::T_PARTIAL);
|
||||
|
||||
$partialFieldSet = [];
|
||||
@@ -2575,6 +2591,8 @@ class Parser
|
||||
* AST\InstanceOfExpression|
|
||||
* AST\LikeExpression|
|
||||
* AST\NullComparisonExpression)
|
||||
*
|
||||
* @phpstan-ignore return.deprecatedClass
|
||||
*/
|
||||
public function SimpleConditionalExpression()
|
||||
{
|
||||
|
||||
@@ -4,7 +4,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query;
|
||||
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Query\Exec\AbstractSqlExecutor;
|
||||
use Doctrine\ORM\Query\Exec\SqlFinalizer;
|
||||
use LogicException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
@@ -20,15 +23,23 @@ class ParserResult
|
||||
'sqlExecutor' => '_sqlExecutor',
|
||||
'resultSetMapping' => '_resultSetMapping',
|
||||
'parameterMappings' => '_parameterMappings',
|
||||
'sqlFinalizer' => 'sqlFinalizer',
|
||||
];
|
||||
|
||||
/**
|
||||
* The SQL executor used for executing the SQL.
|
||||
*
|
||||
* @var AbstractSqlExecutor
|
||||
* @var ?AbstractSqlExecutor
|
||||
*/
|
||||
private $sqlExecutor;
|
||||
|
||||
/**
|
||||
* The SQL executor used for executing the SQL.
|
||||
*
|
||||
* @var ?SqlFinalizer
|
||||
*/
|
||||
private $sqlFinalizer;
|
||||
|
||||
/**
|
||||
* The ResultSetMapping that describes how to map the SQL result set.
|
||||
*
|
||||
@@ -75,6 +86,8 @@ class ParserResult
|
||||
/**
|
||||
* Sets the SQL executor that should be used for this ParserResult.
|
||||
*
|
||||
* @deprecated
|
||||
*
|
||||
* @param AbstractSqlExecutor $executor
|
||||
*
|
||||
* @return void
|
||||
@@ -87,13 +100,33 @@ class ParserResult
|
||||
/**
|
||||
* Gets the SQL executor used by this ParserResult.
|
||||
*
|
||||
* @return AbstractSqlExecutor
|
||||
* @deprecated
|
||||
*
|
||||
* @return ?AbstractSqlExecutor
|
||||
*/
|
||||
public function getSqlExecutor()
|
||||
{
|
||||
return $this->sqlExecutor;
|
||||
}
|
||||
|
||||
public function setSqlFinalizer(SqlFinalizer $finalizer): void
|
||||
{
|
||||
$this->sqlFinalizer = $finalizer;
|
||||
}
|
||||
|
||||
public function prepareSqlExecutor(Query $query): AbstractSqlExecutor
|
||||
{
|
||||
if ($this->sqlFinalizer !== null) {
|
||||
return $this->sqlFinalizer->createExecutor($query);
|
||||
}
|
||||
|
||||
if ($this->sqlExecutor !== null) {
|
||||
return $this->sqlExecutor;
|
||||
}
|
||||
|
||||
throw new LogicException('This ParserResult lacks both the SqlFinalizer as well as the (legacy) SqlExecutor');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a DQL to SQL parameter mapping. One DQL parameter name/position can map to
|
||||
* several SQL parameter positions.
|
||||
|
||||
@@ -41,7 +41,7 @@ class ResultSetMapping
|
||||
* Maps alias names to class names.
|
||||
*
|
||||
* @ignore
|
||||
* @psalm-var array<string, class-string>
|
||||
* @var array<string, class-string>
|
||||
*/
|
||||
public $aliasMap = [];
|
||||
|
||||
@@ -137,7 +137,7 @@ class ResultSetMapping
|
||||
* Map from column names to class names that declare the field the column is mapped to.
|
||||
*
|
||||
* @ignore
|
||||
* @psalm-var array<string, class-string>
|
||||
* @var array<string, class-string>
|
||||
*/
|
||||
public $declaringClasses = [];
|
||||
|
||||
@@ -172,12 +172,11 @@ class ResultSetMapping
|
||||
/**
|
||||
* Adds an entity result to this ResultSetMapping.
|
||||
*
|
||||
* @param string $class The class name of the entity.
|
||||
* @param string $alias The alias for the class. The alias must be unique among all entity
|
||||
* results or joined entity results within this ResultSetMapping.
|
||||
* @param string|null $resultAlias The result alias with which the entity result should be
|
||||
* placed in the result structure.
|
||||
* @psalm-param class-string $class
|
||||
* @param class-string $class The class name of the entity.
|
||||
* @param string $alias The alias for the class. The alias must be unique among all entity
|
||||
* results or joined entity results within this ResultSetMapping.
|
||||
* @param string|null $resultAlias The result alias with which the entity result should be
|
||||
* placed in the result structure.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
@@ -316,15 +315,14 @@ class ResultSetMapping
|
||||
/**
|
||||
* Adds a field to the result that belongs to an entity or joined entity.
|
||||
*
|
||||
* @param string $alias The alias of the root entity or joined entity to which the field belongs.
|
||||
* @param string $columnName The name of the column in the SQL result set.
|
||||
* @param string $fieldName The name of the field on the declaring class.
|
||||
* @param string|null $declaringClass The name of the class that declares/owns the specified field.
|
||||
* When $alias refers to a superclass in a mapped hierarchy but
|
||||
* the field $fieldName is defined on a subclass, specify that here.
|
||||
* If not specified, the field is assumed to belong to the class
|
||||
* designated by $alias.
|
||||
* @psalm-param class-string|null $declaringClass
|
||||
* @param string $alias The alias of the root entity or joined entity to which the field belongs.
|
||||
* @param string $columnName The name of the column in the SQL result set.
|
||||
* @param string $fieldName The name of the field on the declaring class.
|
||||
* @param class-string|null $declaringClass The name of the class that declares/owns the specified field.
|
||||
* When $alias refers to a superclass in a mapped hierarchy but
|
||||
* the field $fieldName is defined on a subclass, specify that here.
|
||||
* If not specified, the field is assumed to belong to the class
|
||||
* designated by $alias.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
@@ -349,12 +347,11 @@ class ResultSetMapping
|
||||
/**
|
||||
* Adds a joined entity result.
|
||||
*
|
||||
* @param string $class The class name of the joined entity.
|
||||
* @param string $alias The unique alias to use for the joined entity.
|
||||
* @param string $parentAlias The alias of the entity result that is the parent of this joined result.
|
||||
* @param string $relation The association field that connects the parent entity result
|
||||
* with the joined entity result.
|
||||
* @psalm-param class-string $class
|
||||
* @param class-string $class The class name of the joined entity.
|
||||
* @param string $alias The unique alias to use for the joined entity.
|
||||
* @param string $parentAlias The alias of the entity result that is the parent of this joined result.
|
||||
* @param string $relation The association field that connects the parent entity result
|
||||
* with the joined entity result.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
@@ -539,7 +536,7 @@ class ResultSetMapping
|
||||
return $this->fieldMappings[$columnName];
|
||||
}
|
||||
|
||||
/** @psalm-return array<string, class-string> */
|
||||
/** @return array<string, class-string> */
|
||||
public function getAliasMap()
|
||||
{
|
||||
return $this->aliasMap;
|
||||
|
||||
@@ -77,12 +77,10 @@ class ResultSetMappingBuilder extends ResultSetMapping
|
||||
/**
|
||||
* Adds a root entity and all of its fields to the result set.
|
||||
*
|
||||
* @param string $class The class name of the root entity.
|
||||
* @param string $alias The unique alias to use for the root entity.
|
||||
* @param string[] $renamedColumns Columns that have been renamed (tableColumnName => queryColumnName).
|
||||
* @param int|null $renameMode One of the COLUMN_RENAMING_* constants or array for BC reasons (CUSTOM).
|
||||
* @psalm-param class-string $class
|
||||
* @psalm-param array<string, string> $renamedColumns
|
||||
* @param class-string $class The class name of the root entity.
|
||||
* @param string $alias The unique alias to use for the root entity.
|
||||
* @param array<string, string> $renamedColumns Columns that have been renamed (tableColumnName => queryColumnName).
|
||||
* @param int|null $renameMode One of the COLUMN_RENAMING_* constants or array for BC reasons (CUSTOM).
|
||||
* @psalm-param self::COLUMN_RENAMING_*|null $renameMode
|
||||
*
|
||||
* @return void
|
||||
@@ -99,15 +97,13 @@ class ResultSetMappingBuilder extends ResultSetMapping
|
||||
/**
|
||||
* Adds a joined entity and all of its fields to the result set.
|
||||
*
|
||||
* @param string $class The class name of the joined entity.
|
||||
* @param string $alias The unique alias to use for the joined entity.
|
||||
* @param string $parentAlias The alias of the entity result that is the parent of this joined result.
|
||||
* @param string $relation The association field that connects the parent entity result
|
||||
* with the joined entity result.
|
||||
* @param string[] $renamedColumns Columns that have been renamed (tableColumnName => queryColumnName).
|
||||
* @param int|null $renameMode One of the COLUMN_RENAMING_* constants or array for BC reasons (CUSTOM).
|
||||
* @psalm-param class-string $class
|
||||
* @psalm-param array<string, string> $renamedColumns
|
||||
* @param class-string $class The class name of the joined entity.
|
||||
* @param string $alias The unique alias to use for the joined entity.
|
||||
* @param string $parentAlias The alias of the entity result that is the parent of this joined result.
|
||||
* @param string $relation The association field that connects the parent entity result
|
||||
* with the joined entity result.
|
||||
* @param array<string, string> $renamedColumns Columns that have been renamed (tableColumnName => queryColumnName).
|
||||
* @param int|null $renameMode One of the COLUMN_RENAMING_* constants or array for BC reasons (CUSTOM).
|
||||
* @psalm-param self::COLUMN_RENAMING_*|null $renameMode
|
||||
*
|
||||
* @return void
|
||||
@@ -228,12 +224,11 @@ class ResultSetMappingBuilder extends ResultSetMapping
|
||||
*
|
||||
* This depends on the renaming mode selected by the user.
|
||||
*
|
||||
* @psalm-param class-string $className
|
||||
* @param class-string $className
|
||||
* @psalm-param self::COLUMN_RENAMING_* $mode
|
||||
* @psalm-param array<string, string> $customRenameColumns
|
||||
*
|
||||
* @return string[]
|
||||
* @psalm-return array<array-key, string>
|
||||
*/
|
||||
private function getColumnAliasMap(
|
||||
string $className,
|
||||
|
||||
29
src/Query/SqlOutputWalker.php
Normal file
29
src/Query/SqlOutputWalker.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query;
|
||||
|
||||
use Doctrine\ORM\Query\Exec\PreparedExecutorFinalizer;
|
||||
use Doctrine\ORM\Query\Exec\SingleSelectSqlFinalizer;
|
||||
use Doctrine\ORM\Query\Exec\SqlFinalizer;
|
||||
use LogicException;
|
||||
|
||||
class SqlOutputWalker extends SqlWalker implements OutputWalker
|
||||
{
|
||||
public function getFinalizer($AST): SqlFinalizer
|
||||
{
|
||||
switch (true) {
|
||||
case $AST instanceof AST\SelectStatement:
|
||||
return new SingleSelectSqlFinalizer($this->createSqlForFinalizer($AST));
|
||||
|
||||
case $AST instanceof AST\UpdateStatement:
|
||||
return new PreparedExecutorFinalizer($this->createUpdateStatementExecutor($AST));
|
||||
|
||||
case $AST instanceof AST\DeleteStatement:
|
||||
return new PreparedExecutorFinalizer($this->createDeleteStatementExecutor($AST));
|
||||
}
|
||||
|
||||
throw new LogicException('Unexpected AST node type');
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@ use Doctrine\ORM\Mapping\QuoteStrategy;
|
||||
use Doctrine\ORM\OptimisticLockException;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Utility\HierarchyDiscriminatorResolver;
|
||||
use Doctrine\ORM\Utility\LockSqlHelper;
|
||||
use Doctrine\ORM\Utility\PersisterHelper;
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
@@ -49,8 +48,6 @@ use function trim;
|
||||
*/
|
||||
class SqlWalker implements TreeWalker
|
||||
{
|
||||
use LockSqlHelper;
|
||||
|
||||
public const HINT_DISTINCT = 'doctrine.distinct';
|
||||
|
||||
/**
|
||||
@@ -278,34 +275,48 @@ class SqlWalker implements TreeWalker
|
||||
/**
|
||||
* Gets an executor that can be used to execute the result of this walker.
|
||||
*
|
||||
* @deprecated Output walkers should no longer create the executor directly, but instead provide
|
||||
* a SqlFinalizer by implementing the `OutputWalker` interface. Thus, this method is
|
||||
* no longer needed and will be removed in 4.0.
|
||||
*
|
||||
* @param AST\DeleteStatement|AST\UpdateStatement|AST\SelectStatement $AST
|
||||
*
|
||||
* @return Exec\AbstractSqlExecutor
|
||||
*
|
||||
* @not-deprecated
|
||||
*/
|
||||
public function getExecutor($AST)
|
||||
{
|
||||
switch (true) {
|
||||
case $AST instanceof AST\DeleteStatement:
|
||||
$primaryClass = $this->em->getClassMetadata($AST->deleteClause->abstractSchemaName);
|
||||
|
||||
return $primaryClass->isInheritanceTypeJoined()
|
||||
? new Exec\MultiTableDeleteExecutor($AST, $this)
|
||||
: new Exec\SingleTableDeleteUpdateExecutor($AST, $this);
|
||||
return $this->createDeleteStatementExecutor($AST);
|
||||
|
||||
case $AST instanceof AST\UpdateStatement:
|
||||
$primaryClass = $this->em->getClassMetadata($AST->updateClause->abstractSchemaName);
|
||||
|
||||
return $primaryClass->isInheritanceTypeJoined()
|
||||
? new Exec\MultiTableUpdateExecutor($AST, $this)
|
||||
: new Exec\SingleTableDeleteUpdateExecutor($AST, $this);
|
||||
return $this->createUpdateStatementExecutor($AST);
|
||||
|
||||
default:
|
||||
return new Exec\SingleSelectExecutor($AST, $this);
|
||||
}
|
||||
}
|
||||
|
||||
/** @psalm-internal Doctrine\ORM */
|
||||
protected function createUpdateStatementExecutor(AST\UpdateStatement $AST): Exec\AbstractSqlExecutor
|
||||
{
|
||||
$primaryClass = $this->em->getClassMetadata($AST->updateClause->abstractSchemaName);
|
||||
|
||||
return $primaryClass->isInheritanceTypeJoined()
|
||||
? new Exec\MultiTableUpdateExecutor($AST, $this)
|
||||
: new Exec\SingleTableDeleteUpdateExecutor($AST, $this);
|
||||
}
|
||||
|
||||
/** @psalm-internal Doctrine\ORM */
|
||||
protected function createDeleteStatementExecutor(AST\DeleteStatement $AST): Exec\AbstractSqlExecutor
|
||||
{
|
||||
$primaryClass = $this->em->getClassMetadata($AST->deleteClause->abstractSchemaName);
|
||||
|
||||
return $primaryClass->isInheritanceTypeJoined()
|
||||
? new Exec\MultiTableDeleteExecutor($AST, $this)
|
||||
: new Exec\SingleTableDeleteUpdateExecutor($AST, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a unique, short SQL table alias.
|
||||
*
|
||||
@@ -561,10 +572,15 @@ class SqlWalker implements TreeWalker
|
||||
*/
|
||||
public function walkSelectStatement(AST\SelectStatement $AST)
|
||||
{
|
||||
$limit = $this->query->getMaxResults();
|
||||
$offset = $this->query->getFirstResult();
|
||||
$lockMode = $this->query->getHint(Query::HINT_LOCK_MODE) ?: LockMode::NONE;
|
||||
$sql = $this->walkSelectClause($AST->selectClause)
|
||||
$sql = $this->createSqlForFinalizer($AST);
|
||||
$finalizer = new Exec\SingleSelectSqlFinalizer($sql);
|
||||
|
||||
return $finalizer->finalizeSql($this->query);
|
||||
}
|
||||
|
||||
protected function createSqlForFinalizer(AST\SelectStatement $AST): string
|
||||
{
|
||||
$sql = $this->walkSelectClause($AST->selectClause)
|
||||
. $this->walkFromClause($AST->fromClause)
|
||||
. $this->walkWhereClause($AST->whereClause);
|
||||
|
||||
@@ -585,33 +601,24 @@ class SqlWalker implements TreeWalker
|
||||
$sql .= ' ORDER BY ' . $orderBySql;
|
||||
}
|
||||
|
||||
$sql = $this->platform->modifyLimitQuery($sql, $limit, $offset);
|
||||
|
||||
if ($lockMode === LockMode::NONE) {
|
||||
return $sql;
|
||||
}
|
||||
|
||||
if ($lockMode === LockMode::PESSIMISTIC_READ) {
|
||||
return $sql . ' ' . $this->getReadLockSQL($this->platform);
|
||||
}
|
||||
|
||||
if ($lockMode === LockMode::PESSIMISTIC_WRITE) {
|
||||
return $sql . ' ' . $this->getWriteLockSQL($this->platform);
|
||||
}
|
||||
|
||||
if ($lockMode !== LockMode::OPTIMISTIC) {
|
||||
throw QueryException::invalidLockMode();
|
||||
}
|
||||
|
||||
foreach ($this->selectedClasses as $selectedClass) {
|
||||
if (! $selectedClass['class']->isVersioned) {
|
||||
throw OptimisticLockException::lockFailed($selectedClass['class']->name);
|
||||
}
|
||||
}
|
||||
$this->assertOptimisticLockingHasAllClassesVersioned();
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
private function assertOptimisticLockingHasAllClassesVersioned(): void
|
||||
{
|
||||
$lockMode = $this->query->getHint(Query::HINT_LOCK_MODE) ?: LockMode::NONE;
|
||||
|
||||
if ($lockMode === LockMode::OPTIMISTIC) {
|
||||
foreach ($this->selectedClasses as $selectedClass) {
|
||||
if (! $selectedClass['class']->isVersioned) {
|
||||
throw OptimisticLockException::lockFailed($selectedClass['class']->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks down an UpdateStatement AST node, thereby generating the appropriate SQL.
|
||||
*
|
||||
|
||||
@@ -806,6 +806,7 @@ abstract class TreeWalkerAdapter implements TreeWalker
|
||||
|
||||
final protected function getMetadataForDqlAlias(string $dqlAlias): ClassMetadata
|
||||
{
|
||||
// @phpstan-ignore method.deprecated
|
||||
$metadata = $this->_getQueryComponents()[$dqlAlias]['metadata'] ?? null;
|
||||
|
||||
if ($metadata === null) {
|
||||
|
||||
@@ -23,8 +23,7 @@ class TreeWalkerChain implements TreeWalker
|
||||
/**
|
||||
* The tree walkers.
|
||||
*
|
||||
* @var string[]
|
||||
* @psalm-var list<class-string<TreeWalker>>
|
||||
* @var list<class-string<TreeWalker>>
|
||||
*/
|
||||
private $walkers = [];
|
||||
|
||||
@@ -81,8 +80,7 @@ class TreeWalkerChain implements TreeWalker
|
||||
/**
|
||||
* Adds a tree walker to the chain.
|
||||
*
|
||||
* @param string $walkerClass The class of the walker to instantiate.
|
||||
* @psalm-param class-string<TreeWalker> $walkerClass
|
||||
* @param class-string<TreeWalker> $walkerClass The class of the walker to instantiate.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
@@ -49,10 +49,7 @@ class TreeWalkerChainIterator implements Iterator, ArrayAccess
|
||||
$this->parserResult = $parserResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|false
|
||||
* @psalm-return class-string<TreeWalker>|false
|
||||
*/
|
||||
/** @return class-string<TreeWalker>|false */
|
||||
#[ReturnTypeWillChange]
|
||||
public function rewind()
|
||||
{
|
||||
|
||||
@@ -86,6 +86,7 @@ class QueryBuilder
|
||||
*
|
||||
* @var int
|
||||
* @psalm-var self::SELECT|self::DELETE|self::UPDATE
|
||||
* @phpstan-ignore classConstant.deprecated
|
||||
*/
|
||||
private $type = self::SELECT;
|
||||
|
||||
@@ -94,6 +95,7 @@ class QueryBuilder
|
||||
*
|
||||
* @var int
|
||||
* @psalm-var self::STATE_*
|
||||
* @phpstan-ignore classConstant.deprecated
|
||||
*/
|
||||
private $state = self::STATE_CLEAN;
|
||||
|
||||
@@ -342,25 +344,30 @@ class QueryBuilder
|
||||
*/
|
||||
public function getDQL()
|
||||
{
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
if ($this->dql !== null && $this->state === self::STATE_CLEAN) {
|
||||
return $this->dql;
|
||||
}
|
||||
|
||||
switch ($this->type) {
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
case self::DELETE:
|
||||
$dql = $this->getDQLForDelete();
|
||||
break;
|
||||
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
case self::UPDATE:
|
||||
$dql = $this->getDQLForUpdate();
|
||||
break;
|
||||
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
case self::SELECT:
|
||||
default:
|
||||
$dql = $this->getDQLForSelect();
|
||||
break;
|
||||
}
|
||||
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
$this->state = self::STATE_CLEAN;
|
||||
$this->dql = $dql;
|
||||
|
||||
@@ -422,6 +429,7 @@ class QueryBuilder
|
||||
} else {
|
||||
// Should never happen with correct joining order. Might be
|
||||
// thoughtful to throw exception instead.
|
||||
// @phpstan-ignore method.deprecated
|
||||
$rootAlias = $this->getRootAlias();
|
||||
}
|
||||
|
||||
@@ -743,6 +751,7 @@ class QueryBuilder
|
||||
$newDqlPart = [];
|
||||
|
||||
foreach ($dqlPart as $k => $v) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
$k = is_numeric($k) ? $this->getRootAlias() : $k;
|
||||
|
||||
$newDqlPart[$k] = $v;
|
||||
@@ -763,6 +772,7 @@ class QueryBuilder
|
||||
$this->dqlParts[$dqlPartName] = $isMultiple ? [$dqlPart] : $dqlPart;
|
||||
}
|
||||
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
$this->state = self::STATE_DIRTY;
|
||||
|
||||
return $this;
|
||||
@@ -785,6 +795,7 @@ class QueryBuilder
|
||||
*/
|
||||
public function select($select = null)
|
||||
{
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
$this->type = self::SELECT;
|
||||
|
||||
if (empty($select)) {
|
||||
@@ -816,7 +827,8 @@ class QueryBuilder
|
||||
|
||||
if ($this->dqlParts['distinct'] !== $flag) {
|
||||
$this->dqlParts['distinct'] = $flag;
|
||||
$this->state = self::STATE_DIRTY;
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
$this->state = self::STATE_DIRTY;
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -839,6 +851,7 @@ class QueryBuilder
|
||||
*/
|
||||
public function addSelect($select = null)
|
||||
{
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
$this->type = self::SELECT;
|
||||
|
||||
if (empty($select)) {
|
||||
@@ -868,6 +881,7 @@ class QueryBuilder
|
||||
*/
|
||||
public function delete($delete = null, $alias = null)
|
||||
{
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
$this->type = self::DELETE;
|
||||
|
||||
if (! $delete) {
|
||||
@@ -903,6 +917,7 @@ class QueryBuilder
|
||||
*/
|
||||
public function update($update = null, $alias = null)
|
||||
{
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
$this->type = self::UPDATE;
|
||||
|
||||
if (! $update) {
|
||||
@@ -1528,7 +1543,8 @@ class QueryBuilder
|
||||
public function resetDQLPart($part)
|
||||
{
|
||||
$this->dqlParts[$part] = is_array($this->dqlParts[$part]) ? [] : null;
|
||||
$this->state = self::STATE_DIRTY;
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
$this->state = self::STATE_DIRTY;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ EOT
|
||||
|
||||
$cacheDriver = null;
|
||||
if (! $cache) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
$cacheDriver = $em->getConfiguration()->getQueryCacheImpl();
|
||||
|
||||
if (! $cacheDriver) {
|
||||
|
||||
@@ -63,8 +63,9 @@ EOT
|
||||
{
|
||||
$ui = (new SymfonyStyle($input, $output))->getErrorStyle();
|
||||
|
||||
$em = $this->getEntityManager($input);
|
||||
$cache = $em->getConfiguration()->getResultCache();
|
||||
$em = $this->getEntityManager($input);
|
||||
$cache = $em->getConfiguration()->getResultCache();
|
||||
// @phpstan-ignore method.deprecated
|
||||
$cacheDriver = method_exists(Configuration::class, 'getResultCacheImpl') ? $em->getConfiguration()->getResultCacheImpl() : null;
|
||||
|
||||
if (! $cacheDriver && ! $cache) {
|
||||
|
||||
@@ -131,8 +131,7 @@ EOT
|
||||
/**
|
||||
* Return all mapped entity class names
|
||||
*
|
||||
* @return string[]
|
||||
* @psalm-return class-string[]
|
||||
* @return class-string[]
|
||||
*/
|
||||
private function getMappedEntities(EntityManagerInterface $entityManager): array
|
||||
{
|
||||
|
||||
@@ -71,6 +71,7 @@ final class ConsoleRunner
|
||||
if ($helperSetOrProvider instanceof HelperSet) {
|
||||
$cli->setHelperSet($helperSetOrProvider);
|
||||
|
||||
// @phpstan-ignore new.deprecated
|
||||
$helperSetOrProvider = new HelperSetManagerProvider($helperSetOrProvider);
|
||||
}
|
||||
|
||||
@@ -83,6 +84,7 @@ final class ConsoleRunner
|
||||
public static function addCommands(Application $cli, ?EntityManagerProvider $entityManagerProvider = null): void
|
||||
{
|
||||
if ($entityManagerProvider === null) {
|
||||
// @phpstan-ignore new.deprecated
|
||||
$entityManagerProvider = new HelperSetManagerProvider($cli->getHelperSet());
|
||||
}
|
||||
|
||||
@@ -95,6 +97,7 @@ final class ConsoleRunner
|
||||
$cli->addCommands(
|
||||
[
|
||||
// DBAL Commands
|
||||
// @phpstan-ignore new.deprecated
|
||||
new DBALConsole\Command\ReservedWordsCommand($connectionProvider),
|
||||
new DBALConsole\Command\RunSqlCommand($connectionProvider),
|
||||
|
||||
@@ -108,11 +111,16 @@ final class ConsoleRunner
|
||||
new Command\SchemaTool\CreateCommand($entityManagerProvider),
|
||||
new Command\SchemaTool\UpdateCommand($entityManagerProvider),
|
||||
new Command\SchemaTool\DropCommand($entityManagerProvider),
|
||||
// @phpstan-ignore new.deprecated
|
||||
new Command\EnsureProductionSettingsCommand($entityManagerProvider),
|
||||
// @phpstan-ignore new.deprecated
|
||||
new Command\ConvertDoctrine1SchemaCommand(),
|
||||
// @phpstan-ignore new.deprecated
|
||||
new Command\GenerateRepositoriesCommand($entityManagerProvider),
|
||||
// @phpstan-ignore new.deprecated
|
||||
new Command\GenerateEntitiesCommand($entityManagerProvider),
|
||||
new Command\GenerateProxiesCommand($entityManagerProvider),
|
||||
// @phpstan-ignore new.deprecated
|
||||
new Command\ConvertMappingCommand($entityManagerProvider),
|
||||
new Command\RunDqlCommand($entityManagerProvider),
|
||||
new Command\ValidateSchemaCommand($entityManagerProvider),
|
||||
|
||||
@@ -91,8 +91,8 @@ class ConvertDoctrine1Schema
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $mappingInformation
|
||||
* @psalm-param class-string $className
|
||||
* @param class-string $className
|
||||
* @param mixed[] $mappingInformation
|
||||
*/
|
||||
private function convertToClassMetadataInfo(
|
||||
string $className,
|
||||
|
||||
@@ -1278,12 +1278,25 @@ public function __construct(<params>)
|
||||
|
||||
$methods = [];
|
||||
|
||||
foreach ($metadata->lifecycleCallbacks as $name => $callbacks) {
|
||||
$lifecycleEventsByCallback = [];
|
||||
foreach ($metadata->lifecycleCallbacks as $event => $callbacks) {
|
||||
foreach ($callbacks as $callback) {
|
||||
$methods[] = $this->generateLifecycleCallbackMethod($name, $callback, $metadata);
|
||||
$callbackCaseInsensitive = $callback;
|
||||
foreach (array_keys($lifecycleEventsByCallback) as $key) {
|
||||
if (strtolower($key) === strtolower($callback)) {
|
||||
$callbackCaseInsensitive = $key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$lifecycleEventsByCallback[$callbackCaseInsensitive][] = $event;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($lifecycleEventsByCallback as $callback => $events) {
|
||||
$methods[] = $this->generateLifecycleCallbackMethod($events, $callback, $metadata);
|
||||
}
|
||||
|
||||
return implode("\n\n", array_filter($methods));
|
||||
}
|
||||
|
||||
@@ -1414,8 +1427,8 @@ public function __construct(<params>)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $methodName
|
||||
* @param string|string[] $name
|
||||
* @param string $methodName
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
@@ -1425,10 +1438,16 @@ public function __construct(<params>)
|
||||
return '';
|
||||
}
|
||||
|
||||
$this->staticReflection[$metadata->name]['methods'][] = $methodName;
|
||||
$this->staticReflection[$metadata->name]['methods'][] = strtolower($methodName);
|
||||
|
||||
$replacements = [
|
||||
'<name>' => $this->annotationsPrefix . ucfirst($name),
|
||||
$eventAnnotations = array_map(
|
||||
function ($event) {
|
||||
return $this->annotationsPrefix . ucfirst($event);
|
||||
},
|
||||
is_array($name) ? $name : [$name]
|
||||
);
|
||||
$replacements = [
|
||||
'<name>' => implode("\n * @", $eventAnnotations),
|
||||
'<methodName>' => $methodName,
|
||||
];
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ use const DIRECTORY_SEPARATOR;
|
||||
*/
|
||||
class EntityRepositoryGenerator
|
||||
{
|
||||
/** @psalm-var class-string|null */
|
||||
/** @var class-string|null */
|
||||
private $repositoryName;
|
||||
|
||||
/** @var string */
|
||||
@@ -80,7 +80,7 @@ class <className> extends <repositoryName>
|
||||
/**
|
||||
* Generates the namespace, if class do not have namespace, return empty string instead.
|
||||
*
|
||||
* @psalm-param class-string $fullClassName
|
||||
* @param class-string $fullClassName
|
||||
*/
|
||||
private function getClassNamespace(string $fullClassName): string
|
||||
{
|
||||
@@ -90,7 +90,7 @@ class <className> extends <repositoryName>
|
||||
/**
|
||||
* Generates the class name
|
||||
*
|
||||
* @psalm-param class-string $fullClassName
|
||||
* @param class-string $fullClassName
|
||||
*/
|
||||
private function generateClassName(string $fullClassName): string
|
||||
{
|
||||
@@ -108,7 +108,7 @@ class <className> extends <repositoryName>
|
||||
/**
|
||||
* Generates the namespace statement, if class do not have namespace, return empty string instead.
|
||||
*
|
||||
* @psalm-param class-string $fullClassName The full repository class name.
|
||||
* @param class-string $fullClassName The full repository class name.
|
||||
*/
|
||||
private function generateEntityRepositoryNamespace(string $fullClassName): string
|
||||
{
|
||||
|
||||
@@ -16,6 +16,8 @@ use function str_replace;
|
||||
* @deprecated 2.7 This class is being removed from the ORM and won't have any replacement
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*
|
||||
* @phpstan-ignore class.extendsDeprecatedClass
|
||||
*/
|
||||
class AnnotationExporter extends AbstractExporter
|
||||
{
|
||||
|
||||
@@ -23,6 +23,8 @@ use const PHP_EOL;
|
||||
* @deprecated 2.7 This class is being removed from the ORM and won't have any replacement
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*
|
||||
* @phpstan-ignore class.extendsDeprecatedClass
|
||||
*/
|
||||
class PhpExporter extends AbstractExporter
|
||||
{
|
||||
|
||||
@@ -21,6 +21,8 @@ use function uasort;
|
||||
* @deprecated 2.7 This class is being removed from the ORM and won't have any replacement
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*
|
||||
* @phpstan-ignore class.extendsDeprecatedClass
|
||||
*/
|
||||
class XmlExporter extends AbstractExporter
|
||||
{
|
||||
|
||||
@@ -16,6 +16,8 @@ use function count;
|
||||
* @deprecated 2.7 This class is being removed from the ORM and won't have any replacement
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*
|
||||
* @phpstan-ignore class.extendsDeprecatedClass
|
||||
*/
|
||||
class YamlExporter extends AbstractExporter
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ use Doctrine\ORM\Query\AST\SelectStatement;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\ParserResult;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
use Doctrine\ORM\Query\SqlOutputWalker;
|
||||
use RuntimeException;
|
||||
|
||||
use function array_diff;
|
||||
@@ -36,7 +36,7 @@ use function sprintf;
|
||||
*
|
||||
* @psalm-import-type QueryComponent from Parser
|
||||
*/
|
||||
class CountOutputWalker extends SqlWalker
|
||||
class CountOutputWalker extends SqlOutputWalker
|
||||
{
|
||||
/** @var AbstractPlatform */
|
||||
private $platform;
|
||||
@@ -62,16 +62,13 @@ class CountOutputWalker extends SqlWalker
|
||||
parent::__construct($query, $parserResult, $queryComponents);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function walkSelectStatement(SelectStatement $AST)
|
||||
protected function createSqlForFinalizer(SelectStatement $AST): string
|
||||
{
|
||||
if ($this->platform instanceof SQLServerPlatform) {
|
||||
$AST->orderByClause = null;
|
||||
}
|
||||
|
||||
$sql = parent::walkSelectStatement($AST);
|
||||
$sql = parent::createSqlForFinalizer($AST);
|
||||
|
||||
if ($AST->groupByClause) {
|
||||
return sprintf(
|
||||
|
||||
@@ -14,15 +14,20 @@ use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\QuoteStrategy;
|
||||
use Doctrine\ORM\OptimisticLockException;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Query\AST\DeleteStatement;
|
||||
use Doctrine\ORM\Query\AST\OrderByClause;
|
||||
use Doctrine\ORM\Query\AST\PathExpression;
|
||||
use Doctrine\ORM\Query\AST\SelectExpression;
|
||||
use Doctrine\ORM\Query\AST\SelectStatement;
|
||||
use Doctrine\ORM\Query\AST\UpdateStatement;
|
||||
use Doctrine\ORM\Query\Exec\SingleSelectSqlFinalizer;
|
||||
use Doctrine\ORM\Query\Exec\SqlFinalizer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\ParserResult;
|
||||
use Doctrine\ORM\Query\QueryException;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
use Doctrine\ORM\Query\SqlOutputWalker;
|
||||
use LogicException;
|
||||
use RuntimeException;
|
||||
|
||||
use function array_diff;
|
||||
@@ -50,7 +55,7 @@ use function substr;
|
||||
*
|
||||
* @psalm-import-type QueryComponent from Parser
|
||||
*/
|
||||
class LimitSubqueryOutputWalker extends SqlWalker
|
||||
class LimitSubqueryOutputWalker extends SqlOutputWalker
|
||||
{
|
||||
private const ORDER_BY_PATH_EXPRESSION = '/(?<![a-z0-9_])%s\.%s(?![a-z0-9_])/i';
|
||||
|
||||
@@ -100,6 +105,8 @@ class LimitSubqueryOutputWalker extends SqlWalker
|
||||
$this->platform = $query->getEntityManager()->getConnection()->getDatabasePlatform();
|
||||
$this->rsm = $parserResult->getResultSetMapping();
|
||||
|
||||
$query = clone $query;
|
||||
|
||||
// Reset limit and offset
|
||||
$this->firstResult = $query->getFirstResult();
|
||||
$this->maxResults = $query->getMaxResults();
|
||||
@@ -158,11 +165,33 @@ class LimitSubqueryOutputWalker extends SqlWalker
|
||||
*/
|
||||
public function walkSelectStatement(SelectStatement $AST)
|
||||
{
|
||||
if ($this->platformSupportsRowNumber()) {
|
||||
return $this->walkSelectStatementWithRowNumber($AST);
|
||||
$sqlFinalizer = $this->getFinalizer($AST);
|
||||
|
||||
$query = $this->getQuery();
|
||||
|
||||
$abstractSqlExecutor = $sqlFinalizer->createExecutor($query);
|
||||
|
||||
return $abstractSqlExecutor->getSqlStatements();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DeleteStatement|UpdateStatement|SelectStatement $AST
|
||||
*
|
||||
* @return SingleSelectSqlFinalizer
|
||||
*/
|
||||
public function getFinalizer($AST): SqlFinalizer
|
||||
{
|
||||
if (! $AST instanceof SelectStatement) {
|
||||
throw new LogicException(self::class . ' is to be used on SelectStatements only');
|
||||
}
|
||||
|
||||
return $this->walkSelectStatementWithoutRowNumber($AST);
|
||||
if ($this->platformSupportsRowNumber()) {
|
||||
$sql = $this->createSqlWithRowNumber($AST);
|
||||
} else {
|
||||
$sql = $this->createSqlWithoutRowNumber($AST);
|
||||
}
|
||||
|
||||
return new SingleSelectSqlFinalizer($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -174,6 +203,16 @@ class LimitSubqueryOutputWalker extends SqlWalker
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function walkSelectStatementWithRowNumber(SelectStatement $AST)
|
||||
{
|
||||
// Apply the limit and offset.
|
||||
return $this->platform->modifyLimitQuery(
|
||||
$this->createSqlWithRowNumber($AST),
|
||||
$this->maxResults,
|
||||
$this->firstResult
|
||||
);
|
||||
}
|
||||
|
||||
private function createSqlWithRowNumber(SelectStatement $AST): string
|
||||
{
|
||||
$hasOrderBy = false;
|
||||
$outerOrderBy = ' ORDER BY dctrn_minrownum ASC';
|
||||
@@ -203,13 +242,6 @@ class LimitSubqueryOutputWalker extends SqlWalker
|
||||
$sql .= $orderGroupBy . $outerOrderBy;
|
||||
}
|
||||
|
||||
// Apply the limit and offset.
|
||||
$sql = $this->platform->modifyLimitQuery(
|
||||
$sql,
|
||||
$this->maxResults,
|
||||
$this->firstResult
|
||||
);
|
||||
|
||||
// Add the columns to the ResultSetMapping. It's not really nice but
|
||||
// it works. Preferably I'd clear the RSM or simply create a new one
|
||||
// but that is not possible from inside the output walker, so we dirty
|
||||
@@ -232,6 +264,16 @@ class LimitSubqueryOutputWalker extends SqlWalker
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function walkSelectStatementWithoutRowNumber(SelectStatement $AST, $addMissingItemsFromOrderByToSelect = true)
|
||||
{
|
||||
// Apply the limit and offset.
|
||||
return $this->platform->modifyLimitQuery(
|
||||
$this->createSqlWithoutRowNumber($AST, $addMissingItemsFromOrderByToSelect),
|
||||
$this->maxResults,
|
||||
$this->firstResult
|
||||
);
|
||||
}
|
||||
|
||||
private function createSqlWithoutRowNumber(SelectStatement $AST, bool $addMissingItemsFromOrderByToSelect = true): string
|
||||
{
|
||||
// We don't want to call this recursively!
|
||||
if ($AST->orderByClause instanceof OrderByClause && $addMissingItemsFromOrderByToSelect) {
|
||||
@@ -260,13 +302,6 @@ class LimitSubqueryOutputWalker extends SqlWalker
|
||||
// https://github.com/doctrine/orm/issues/2630
|
||||
$sql = $this->preserveSqlOrdering($sqlIdentifier, $innerSql, $sql, $orderByClause);
|
||||
|
||||
// Apply the limit and offset.
|
||||
$sql = $this->platform->modifyLimitQuery(
|
||||
$sql,
|
||||
$this->maxResults,
|
||||
$this->firstResult
|
||||
);
|
||||
|
||||
// Add the columns to the ResultSetMapping. It's not really nice but
|
||||
// it works. Preferably I'd clear the RSM or simply create a new one
|
||||
// but that is not possible from inside the output walker, so we dirty
|
||||
|
||||
@@ -74,6 +74,7 @@ class LimitSubqueryWalker extends TreeWalkerAdapter
|
||||
return;
|
||||
}
|
||||
|
||||
// @phpstan-ignore method.deprecated
|
||||
$queryComponents = $this->_getQueryComponents();
|
||||
foreach ($AST->orderByClause->orderByItems as $item) {
|
||||
if ($item->expression instanceof PathExpression) {
|
||||
|
||||
@@ -209,7 +209,7 @@ class Paginator implements Countable, IteratorAggregate
|
||||
/**
|
||||
* Appends a custom tree walker to the tree walkers hint.
|
||||
*
|
||||
* @psalm-param class-string $walkerClass
|
||||
* @param class-string $walkerClass
|
||||
*/
|
||||
private function appendTreeWalker(Query $query, string $walkerClass): void
|
||||
{
|
||||
|
||||
@@ -5,7 +5,10 @@ declare(strict_types=1);
|
||||
namespace Doctrine\ORM\Tools\Pagination;
|
||||
|
||||
use Doctrine\ORM\Query\AST;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
use Doctrine\ORM\Query\Exec\FinalizedSelectExecutor;
|
||||
use Doctrine\ORM\Query\Exec\PreparedExecutorFinalizer;
|
||||
use Doctrine\ORM\Query\Exec\SqlFinalizer;
|
||||
use Doctrine\ORM\Query\SqlOutputWalker;
|
||||
use Doctrine\ORM\Utility\PersisterHelper;
|
||||
use RuntimeException;
|
||||
|
||||
@@ -22,7 +25,7 @@ use function reset;
|
||||
* Returning the type instead of a "real" SQL statement is a slight hack. However, it has the
|
||||
* benefit that the DQL -> root entity id type resolution can be cached in the query cache.
|
||||
*/
|
||||
final class RootTypeWalker extends SqlWalker
|
||||
final class RootTypeWalker extends SqlOutputWalker
|
||||
{
|
||||
public function walkSelectStatement(AST\SelectStatement $AST): string
|
||||
{
|
||||
@@ -45,4 +48,13 @@ final class RootTypeWalker extends SqlWalker
|
||||
->getEntityManager()
|
||||
)[0];
|
||||
}
|
||||
|
||||
public function getFinalizer($AST): SqlFinalizer
|
||||
{
|
||||
if (! $AST instanceof AST\SelectStatement) {
|
||||
throw new RuntimeException(self::class . ' is to be used on SelectStatements only');
|
||||
}
|
||||
|
||||
return new PreparedExecutorFinalizer(new FinalizedSelectExecutor($this->walkSelectStatement($AST)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +84,7 @@ class SchemaTool
|
||||
$this->quoteStrategy = $em->getConfiguration()->getQuoteStrategy();
|
||||
$this->schemaManager = method_exists(Connection::class, 'createSchemaManager')
|
||||
? $em->getConnection()->createSchemaManager()
|
||||
// @phpstan-ignore method.deprecated
|
||||
: $em->getConnection()->getSchemaManager();
|
||||
}
|
||||
|
||||
@@ -311,6 +312,7 @@ class SchemaTool
|
||||
$table->setPrimaryKey($pkColumns);
|
||||
}
|
||||
}
|
||||
// @phpstan-ignore method.deprecated
|
||||
} elseif ($class->isInheritanceTypeTablePerClass()) {
|
||||
throw NotSupported::create();
|
||||
} else {
|
||||
@@ -412,7 +414,9 @@ class SchemaTool
|
||||
return ! $asset->isInDefaultNamespace($schema->getName());
|
||||
};
|
||||
|
||||
// @phpstan-ignore method.deprecated
|
||||
if (array_filter($schema->getSequences() + $schema->getTables(), $filter) && ! $this->platform->canEmulateSchemas()) {
|
||||
// @phpstan-ignore method.deprecated, new.deprecated
|
||||
$schema->visit(new RemoveNamespacedAssets());
|
||||
}
|
||||
}
|
||||
@@ -989,10 +993,12 @@ class SchemaTool
|
||||
$schemaDiff = $comparator->compareSchemas($fromSchema, $toSchema);
|
||||
|
||||
if ($saveMode) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
return $schemaDiff->toSaveSql($this->platform);
|
||||
}
|
||||
|
||||
if (! method_exists(AbstractPlatform::class, 'getAlterSchemaSQL')) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
return $schemaDiff->toSql($this->platform);
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,6 @@ use Doctrine\Persistence\PropertyChangedListener;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use Throwable;
|
||||
use UnexpectedValueException;
|
||||
|
||||
use function array_chunk;
|
||||
@@ -126,8 +125,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
* Since all classes in a hierarchy must share the same identifier set,
|
||||
* we always take the root class name of the hierarchy.
|
||||
*
|
||||
* @var mixed[]
|
||||
* @psalm-var array<class-string, array<string, object>>
|
||||
* @var array<class-string, array<string, object>>
|
||||
*/
|
||||
private $identityMap = [];
|
||||
|
||||
@@ -174,7 +172,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
* This is only used for entities with a change tracking policy of DEFERRED_EXPLICIT.
|
||||
* Keys are object ids (spl_object_id).
|
||||
*
|
||||
* @psalm-var array<class-string, array<int, mixed>>
|
||||
* @var array<class-string, array<int, mixed>>
|
||||
*/
|
||||
private $scheduledForSynchronization = [];
|
||||
|
||||
@@ -312,7 +310,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
/**
|
||||
* Map of Entity Class-Names and corresponding IDs that should eager loaded when requested.
|
||||
*
|
||||
* @psalm-var array<class-string, array<string, mixed>>
|
||||
* @var array<class-string, array<string, mixed>>
|
||||
*/
|
||||
private $eagerLoadingEntities = [];
|
||||
|
||||
@@ -427,6 +425,8 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$conn = $this->em->getConnection();
|
||||
$conn->beginTransaction();
|
||||
|
||||
$successful = false;
|
||||
|
||||
try {
|
||||
// Collection deletions (deletions of complete collections)
|
||||
foreach ($this->collectionDeletions as $collectionToDelete) {
|
||||
@@ -478,16 +478,18 @@ class UnitOfWork implements PropertyChangedListener
|
||||
|
||||
throw new OptimisticLockException('Commit failed', $object);
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
$this->em->close();
|
||||
|
||||
if ($conn->isTransactionActive()) {
|
||||
$conn->rollBack();
|
||||
$successful = true;
|
||||
} finally {
|
||||
if (! $successful) {
|
||||
$this->em->close();
|
||||
|
||||
if ($conn->isTransactionActive()) {
|
||||
$conn->rollBack();
|
||||
}
|
||||
|
||||
$this->afterTransactionRolledBack();
|
||||
}
|
||||
|
||||
$this->afterTransactionRolledBack();
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$this->afterTransactionComplete();
|
||||
@@ -2906,11 +2908,9 @@ EXCEPTION
|
||||
*
|
||||
* Internal note: Highly performance-sensitive method.
|
||||
*
|
||||
* @param string $className The name of the entity class.
|
||||
* @param mixed[] $data The data for the entity.
|
||||
* @param mixed[] $hints Any hints to account for during reconstitution/lookup of the entity.
|
||||
* @psalm-param class-string $className
|
||||
* @psalm-param array<string, mixed> $hints
|
||||
* @param class-string $className The name of the entity class.
|
||||
* @param mixed[] $data The data for the entity.
|
||||
* @param array<string, mixed> $hints Any hints to account for during reconstitution/lookup of the entity.
|
||||
*
|
||||
* @return object The managed entity instance.
|
||||
*
|
||||
@@ -3339,7 +3339,7 @@ EXCEPTION
|
||||
/**
|
||||
* Gets the identity map of the UnitOfWork.
|
||||
*
|
||||
* @psalm-return array<class-string, array<string, object>>
|
||||
* @return array<class-string, array<string, object>>
|
||||
*/
|
||||
public function getIdentityMap()
|
||||
{
|
||||
@@ -3439,9 +3439,8 @@ EXCEPTION
|
||||
* Tries to find an entity with the given identifier in the identity map of
|
||||
* this UnitOfWork.
|
||||
*
|
||||
* @param mixed $id The entity identifier to look for.
|
||||
* @param string $rootClassName The name of the root class of the mapped entity hierarchy.
|
||||
* @psalm-param class-string $rootClassName
|
||||
* @param mixed $id The entity identifier to look for.
|
||||
* @param class-string $rootClassName The name of the root class of the mapped entity hierarchy.
|
||||
*
|
||||
* @return object|false Returns the entity with the specified identifier if it exists in
|
||||
* this UnitOfWork, FALSE otherwise.
|
||||
@@ -3493,8 +3492,7 @@ EXCEPTION
|
||||
/**
|
||||
* Gets the EntityPersister for an Entity.
|
||||
*
|
||||
* @param string $entityName The name of the Entity.
|
||||
* @psalm-param class-string $entityName
|
||||
* @param class-string $entityName The name of the Entity.
|
||||
*
|
||||
* @return EntityPersister
|
||||
*/
|
||||
|
||||
@@ -10,9 +10,9 @@ use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
class MetadataGenerator
|
||||
{
|
||||
/**
|
||||
* @psalm-param class-string<T> $entityName
|
||||
* @param class-string<T> $entityName
|
||||
*
|
||||
* @psalm-return ClassMetadata<T>
|
||||
* @return ClassMetadata<T>
|
||||
*/
|
||||
public function createMetadata(string $entityName): ClassMetadata
|
||||
{
|
||||
|
||||
@@ -15,18 +15,15 @@ use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
*/
|
||||
abstract class GetMetadata
|
||||
{
|
||||
/**
|
||||
* @param string|object $class
|
||||
* @psalm-param class-string|object $class
|
||||
*/
|
||||
/** @param class-string|object $class */
|
||||
abstract public function getEntityManager($class): EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* @psalm-param class-string<TObject> $class
|
||||
* @param class-string<TObject> $class
|
||||
*
|
||||
* @psalm-return ClassMetadata<TObject>
|
||||
* @return ClassMetadata<TObject>
|
||||
*
|
||||
* @psalm-template TObject of object
|
||||
* @template TObject of object
|
||||
*/
|
||||
public function __invoke(string $class): ClassMetadata
|
||||
{
|
||||
|
||||
@@ -7,12 +7,14 @@ namespace Doctrine\Tests\Mocks;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\ORM\Query\AST;
|
||||
use Doctrine\ORM\Query\Exec\AbstractSqlExecutor;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
use Doctrine\ORM\Query\Exec\PreparedExecutorFinalizer;
|
||||
use Doctrine\ORM\Query\Exec\SqlFinalizer;
|
||||
use Doctrine\ORM\Query\SqlOutputWalker;
|
||||
|
||||
/**
|
||||
* SqlWalker implementation that does not produce SQL.
|
||||
*/
|
||||
class NullSqlWalker extends SqlWalker
|
||||
class NullSqlWalker extends SqlOutputWalker
|
||||
{
|
||||
public function walkSelectStatement(AST\SelectStatement $AST): string
|
||||
{
|
||||
@@ -29,13 +31,15 @@ class NullSqlWalker extends SqlWalker
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getExecutor($AST): AbstractSqlExecutor
|
||||
public function getFinalizer($AST): SqlFinalizer
|
||||
{
|
||||
return new class extends AbstractSqlExecutor {
|
||||
public function execute(Connection $conn, array $params, array $types): int
|
||||
{
|
||||
return 0;
|
||||
return new PreparedExecutorFinalizer(
|
||||
new class extends AbstractSqlExecutor {
|
||||
public function execute(Connection $conn, array $params, array $types): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,16 +21,21 @@ use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
|
||||
use Doctrine\Persistence\Mapping\MappingException;
|
||||
use Doctrine\Tests\Mocks\ConnectionMock;
|
||||
use Doctrine\Tests\Mocks\EntityManagerMock;
|
||||
use Doctrine\Tests\Models\CMS\CmsUser;
|
||||
use Doctrine\Tests\Models\GeoNames\Country;
|
||||
use Doctrine\Tests\OrmTestCase;
|
||||
use Exception;
|
||||
use Generator;
|
||||
use InvalidArgumentException;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use stdClass;
|
||||
use TypeError;
|
||||
|
||||
use function get_class;
|
||||
use function random_int;
|
||||
use function sprintf;
|
||||
use function sys_get_temp_dir;
|
||||
use function uniqid;
|
||||
|
||||
@@ -382,4 +387,61 @@ class EntityManagerTest extends OrmTestCase
|
||||
|
||||
$this->entityManager->flush($entity);
|
||||
}
|
||||
|
||||
/** @dataProvider entityManagerMethodNames */
|
||||
public function testItPreservesTheOriginalExceptionOnRollbackFailure(string $methodName): void
|
||||
{
|
||||
$entityManager = new EntityManagerMock(new class extends ConnectionMock {
|
||||
public function rollBack(): bool
|
||||
{
|
||||
throw new Exception('Rollback exception');
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
$entityManager->$methodName(static function (): void {
|
||||
throw new Exception('Original exception');
|
||||
});
|
||||
self::fail('Exception expected');
|
||||
} catch (Exception $e) {
|
||||
self::assertSame('Rollback exception', $e->getMessage());
|
||||
self::assertNotNull($e->getPrevious());
|
||||
self::assertSame('Original exception', $e->getPrevious()->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/** @dataProvider entityManagerMethodNames */
|
||||
public function testItDoesNotAttemptToRollbackIfNoTransactionIsActive(string $methodName): void
|
||||
{
|
||||
$entityManager = new EntityManagerMock(
|
||||
new class extends ConnectionMock {
|
||||
public function commit(): bool
|
||||
{
|
||||
throw new Exception('Commit exception that happens after doing the actual commit');
|
||||
}
|
||||
|
||||
public function rollBack(): bool
|
||||
{
|
||||
Assert::fail('Should not attempt to rollback if no transaction is active');
|
||||
}
|
||||
|
||||
public function isTransactionActive(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
$this->expectExceptionMessage('Commit exception');
|
||||
$entityManager->$methodName(static function (): void {
|
||||
});
|
||||
}
|
||||
|
||||
/** @return Generator<string, array{string}> */
|
||||
public function entityManagerMethodNames(): Generator
|
||||
{
|
||||
foreach (['transactional', 'wrapInTransaction'] as $methodName) {
|
||||
yield sprintf('%s()', $methodName) => [$methodName];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ abstract class DatabaseDriverTestCase extends OrmFunctionalTestCase
|
||||
/**
|
||||
* @param string[] $classNames
|
||||
*
|
||||
* @psalm-return array<class-string, ClassMetadata>
|
||||
* @return array<class-string, ClassMetadata>
|
||||
*/
|
||||
protected function extractClassMetadata(array $classNames): array
|
||||
{
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Closure;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Query\Exec\FinalizedSelectExecutor;
|
||||
use Doctrine\ORM\Query\Exec\PreparedExecutorFinalizer;
|
||||
use Doctrine\ORM\Query\Exec\SingleSelectExecutor;
|
||||
use Doctrine\ORM\Query\ParserResult;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
@@ -35,7 +37,29 @@ class ParserResultSerializationTest extends OrmFunctionalTestCase
|
||||
*
|
||||
* @dataProvider provideToSerializedAndBack
|
||||
*/
|
||||
public function testSerializeParserResult(Closure $toSerializedAndBack): void
|
||||
public function testSerializeParserResultForQueryWithSqlWalker(Closure $toSerializedAndBack): void
|
||||
{
|
||||
$query = $this->_em
|
||||
->createQuery('SELECT u FROM Doctrine\Tests\Models\Company\CompanyEmployee u WHERE u.name = :name');
|
||||
|
||||
// Use the (legacy) SqlWalker which directly puts an SqlExecutor instance into the parser result
|
||||
$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, Query\SqlWalker::class);
|
||||
|
||||
$parserResult = self::parseQuery($query);
|
||||
$unserialized = $toSerializedAndBack($parserResult);
|
||||
|
||||
$this->assertInstanceOf(ParserResult::class, $unserialized);
|
||||
$this->assertInstanceOf(ResultSetMapping::class, $unserialized->getResultSetMapping());
|
||||
$this->assertEquals(['name' => [0]], $unserialized->getParameterMappings());
|
||||
$this->assertNotNull($unserialized->prepareSqlExecutor($query));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Closure(ParserResult): ParserResult $toSerializedAndBack
|
||||
*
|
||||
* @dataProvider provideToSerializedAndBack
|
||||
*/
|
||||
public function testSerializeParserResultForQueryWithSqlOutputWalker(Closure $toSerializedAndBack): void
|
||||
{
|
||||
$query = $this->_em
|
||||
->createQuery('SELECT u FROM Doctrine\Tests\Models\Company\CompanyEmployee u WHERE u.name = :name');
|
||||
@@ -46,7 +70,7 @@ class ParserResultSerializationTest extends OrmFunctionalTestCase
|
||||
$this->assertInstanceOf(ParserResult::class, $unserialized);
|
||||
$this->assertInstanceOf(ResultSetMapping::class, $unserialized->getResultSetMapping());
|
||||
$this->assertEquals(['name' => [0]], $unserialized->getParameterMappings());
|
||||
$this->assertInstanceOf(SingleSelectExecutor::class, $unserialized->getSqlExecutor());
|
||||
$this->assertNotNull($unserialized->prepareSqlExecutor($query));
|
||||
}
|
||||
|
||||
/** @return Generator<string, array{Closure(ParserResult): ParserResult}> */
|
||||
@@ -75,6 +99,9 @@ class ParserResultSerializationTest extends OrmFunctionalTestCase
|
||||
$query = $this->_em
|
||||
->createQuery('SELECT u FROM Doctrine\Tests\Models\Company\CompanyEmployee u WHERE u.name = :name');
|
||||
|
||||
// Use the (legacy) SqlWalker which directly puts an SqlExecutor instance into the parser result
|
||||
$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, Query\SqlWalker::class);
|
||||
|
||||
$parserResult = self::parseQuery($query);
|
||||
$serialized = serialize($parserResult);
|
||||
$this->assertStringNotContainsString(
|
||||
@@ -118,11 +145,12 @@ class ParserResultSerializationTest extends OrmFunctionalTestCase
|
||||
|
||||
public function testSymfony44ProvidedData(): void
|
||||
{
|
||||
$sqlExecutor = $this->createMock(SingleSelectExecutor::class);
|
||||
$sqlExecutor = new FinalizedSelectExecutor('test');
|
||||
$sqlFinalizer = new PreparedExecutorFinalizer($sqlExecutor);
|
||||
$resultSetMapping = $this->createMock(ResultSetMapping::class);
|
||||
|
||||
$parserResult = new ParserResult();
|
||||
$parserResult->setSqlExecutor($sqlExecutor);
|
||||
$parserResult->setSqlFinalizer($sqlFinalizer);
|
||||
$parserResult->setResultSetMapping($resultSetMapping);
|
||||
$parserResult->addParameterMapping('name', 0);
|
||||
|
||||
@@ -132,7 +160,7 @@ class ParserResultSerializationTest extends OrmFunctionalTestCase
|
||||
$this->assertInstanceOf(ParserResult::class, $unserialized);
|
||||
$this->assertInstanceOf(ResultSetMapping::class, $unserialized->getResultSetMapping());
|
||||
$this->assertEquals(['name' => [0]], $unserialized->getParameterMappings());
|
||||
$this->assertInstanceOf(SingleSelectExecutor::class, $unserialized->getSqlExecutor());
|
||||
$this->assertEquals($sqlExecutor, $unserialized->prepareSqlExecutor($this->createMock(Query::class)));
|
||||
}
|
||||
|
||||
private static function parseQuery(Query $query): ParserResult
|
||||
|
||||
@@ -296,7 +296,7 @@ class PostLoadListenerCheckAssociationsArePopulated
|
||||
|
||||
class PostLoadListenerLoadEntityInEventHandler
|
||||
{
|
||||
/** @psalm-var array<class-string, int> */
|
||||
/** @var array<class-string, int> */
|
||||
private $firedByClasses = [];
|
||||
|
||||
public function postLoad(PostLoadEventArgs $event): void
|
||||
|
||||
@@ -43,7 +43,7 @@ class QueryCacheTest extends OrmFunctionalTestCase
|
||||
}
|
||||
|
||||
/** @depends testQueryCacheDependsOnHints */
|
||||
public function testQueryCacheDependsOnFirstResult(array $previous): void
|
||||
public function testQueryCacheDoesNotDependOnFirstResultForDefaultOutputWalker(array $previous): void
|
||||
{
|
||||
[$query, $cache] = $previous;
|
||||
assert($query instanceof Query);
|
||||
@@ -55,11 +55,11 @@ class QueryCacheTest extends OrmFunctionalTestCase
|
||||
$query->setMaxResults(9999);
|
||||
|
||||
$query->getResult();
|
||||
self::assertCount($cacheCount + 1, $cache->getValues());
|
||||
self::assertCount($cacheCount, $cache->getValues());
|
||||
}
|
||||
|
||||
/** @depends testQueryCacheDependsOnHints */
|
||||
public function testQueryCacheDependsOnMaxResults(array $previous): void
|
||||
public function testQueryCacheDoesNotDependOnMaxResultsForDefaultOutputWalker(array $previous): void
|
||||
{
|
||||
[$query, $cache] = $previous;
|
||||
assert($query instanceof Query);
|
||||
@@ -70,7 +70,7 @@ class QueryCacheTest extends OrmFunctionalTestCase
|
||||
$query->setMaxResults(10);
|
||||
|
||||
$query->getResult();
|
||||
self::assertCount($cacheCount + 1, $cache->getValues());
|
||||
self::assertCount($cacheCount, $cache->getValues());
|
||||
}
|
||||
|
||||
/** @depends testQueryCacheDependsOnHints */
|
||||
|
||||
@@ -56,7 +56,7 @@ class DDC1884Test extends OrmFunctionalTestCase
|
||||
/**
|
||||
* @psalm-return array{Car, Car, Car, Car}
|
||||
*
|
||||
* @psalm-var class-string<Car> $class
|
||||
* @var class-string<Car> $class
|
||||
*/
|
||||
private function createCars(string $class): array
|
||||
{
|
||||
@@ -87,7 +87,7 @@ class DDC1884Test extends OrmFunctionalTestCase
|
||||
/**
|
||||
* @psalm-return array{Driver, Driver}
|
||||
*
|
||||
* @psalm-var class-string<Driver> $class
|
||||
* @var class-string<Driver> $class
|
||||
*/
|
||||
private function createDrivers(string $class): array
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user