mirror of
https://github.com/doctrine/orm.git
synced 2026-03-24 06:52:09 +01:00
Compare commits
54 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37946d3a21 | ||
|
|
baf96cdad4 | ||
|
|
ce09c96427 | ||
|
|
ae659fe650 | ||
|
|
0a177d5074 | ||
|
|
dbfe47b07b | ||
|
|
d31aabb40c | ||
|
|
22b1f52c1c | ||
|
|
d66884403f | ||
|
|
a90ee5c495 | ||
|
|
11270425e5 | ||
|
|
552eae37a3 | ||
|
|
ee4b03aa78 | ||
|
|
f1246d57c2 | ||
|
|
a14ef7c279 | ||
|
|
54c29140fa | ||
|
|
daa99f197b | ||
|
|
2b04cc2e3f | ||
|
|
3d9af3187f | ||
|
|
e83d8a80ba | ||
|
|
c5291b4de8 | ||
|
|
029ca611f0 | ||
|
|
831d86548c | ||
|
|
f26b3b9cf9 | ||
|
|
9e7715f678 | ||
|
|
9ab84f7478 | ||
|
|
e6bb4ef20e | ||
|
|
0e26e3ed50 | ||
|
|
63315c8e4a | ||
|
|
8ca99fdfdc | ||
|
|
2d8e466636 | ||
|
|
94986af284 | ||
|
|
ad5c8e4bdc | ||
|
|
c363f55ad1 | ||
|
|
c973a62272 | ||
|
|
8d3446015a | ||
|
|
4e335f4044 | ||
|
|
bb36d49b38 | ||
|
|
2b81a8e260 | ||
|
|
7d3b3f28e9 | ||
|
|
cbec236e8b | ||
|
|
306963fe79 | ||
|
|
fb4578406f | ||
|
|
bdc41e2b5e | ||
|
|
90376a6431 | ||
|
|
97634ae6a1 | ||
|
|
4672d284ff | ||
|
|
69f51cc794 | ||
|
|
f9331ee2b9 | ||
|
|
cb05f1aadf | ||
|
|
ab616f1a1d | ||
|
|
7d1444e5b6 | ||
|
|
25d5936337 | ||
|
|
68f9bf5dfa |
9
.github/dependabot.yml
vendored
Normal file
9
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
labels:
|
||||
- "CI"
|
||||
target-branch: "2.19.x"
|
||||
2
.github/workflows/coding-standards.yml
vendored
2
.github/workflows/coding-standards.yml
vendored
@@ -24,4 +24,4 @@ on:
|
||||
|
||||
jobs:
|
||||
coding-standards:
|
||||
uses: "doctrine/.github/.github/workflows/coding-standards.yml@3.0.0"
|
||||
uses: "doctrine/.github/.github/workflows/coding-standards.yml@5.0.1"
|
||||
|
||||
12
.github/workflows/continuous-integration.yml
vendored
12
.github/workflows/continuous-integration.yml
vendored
@@ -75,7 +75,7 @@ jobs:
|
||||
if: "${{ matrix.dbal-version != 'default' }}"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
composer-options: "--ignore-platform-req=php+"
|
||||
dependency-versions: "${{ matrix.deps }}"
|
||||
@@ -156,7 +156,7 @@ jobs:
|
||||
if: "${{ matrix.dbal-version != 'default' }}"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
composer-options: "--ignore-platform-req=php+"
|
||||
|
||||
@@ -222,7 +222,7 @@ jobs:
|
||||
extensions: "${{ matrix.extension }}"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
composer-options: "--ignore-platform-req=php+"
|
||||
|
||||
@@ -296,7 +296,7 @@ jobs:
|
||||
if: "${{ matrix.dbal-version != 'default' }}"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
composer-options: "--ignore-platform-req=php+"
|
||||
|
||||
@@ -337,6 +337,8 @@ jobs:
|
||||
path: "reports"
|
||||
|
||||
- name: "Upload to Codecov"
|
||||
uses: "codecov/codecov-action@v3"
|
||||
uses: "codecov/codecov-action@v4"
|
||||
with:
|
||||
directory: reports
|
||||
env:
|
||||
CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}"
|
||||
|
||||
2
.github/workflows/documentation.yml
vendored
2
.github/workflows/documentation.yml
vendored
@@ -36,7 +36,7 @@ jobs:
|
||||
run: "composer require --dev phpdocumentor/guides-cli --no-update"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
dependency-versions: "highest"
|
||||
|
||||
|
||||
11
.github/workflows/phpbench.yml
vendored
11
.github/workflows/phpbench.yml
vendored
@@ -47,15 +47,8 @@ jobs:
|
||||
coverage: "pcov"
|
||||
ini-values: "zend.assertions=1, apc.enable_cli=1"
|
||||
|
||||
- name: "Cache dependencies installed with composer"
|
||||
uses: "actions/cache@v3"
|
||||
with:
|
||||
path: "~/.composer/cache"
|
||||
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
|
||||
restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
|
||||
|
||||
- name: "Install dependencies with composer"
|
||||
run: "composer update --no-interaction --no-progress"
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
|
||||
- name: "Run PHPBench"
|
||||
run: "vendor/bin/phpbench run --report=default"
|
||||
|
||||
@@ -7,7 +7,7 @@ on:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@4.0.0"
|
||||
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@5.0.1"
|
||||
secrets:
|
||||
GIT_AUTHOR_EMAIL: ${{ secrets.GIT_AUTHOR_EMAIL }}
|
||||
GIT_AUTHOR_NAME: ${{ secrets.GIT_AUTHOR_NAME }}
|
||||
|
||||
2
.github/workflows/static-analysis.yml
vendored
2
.github/workflows/static-analysis.yml
vendored
@@ -83,7 +83,7 @@ jobs:
|
||||
if: "${{ matrix.dbal-version != 'default' }}"
|
||||
|
||||
- name: Install dependencies with Composer
|
||||
uses: ramsey/composer-install@v2
|
||||
uses: ramsey/composer-install@v3
|
||||
|
||||
- name: Run static analysis with Vimeo Psalm
|
||||
run: vendor/bin/psalm --shepherd
|
||||
|
||||
26
UPGRADE.md
26
UPGRADE.md
@@ -1,3 +1,29 @@
|
||||
# Upgrade to 3.2
|
||||
|
||||
## Deprecate the `NotSupported` exception
|
||||
|
||||
The class `Doctrine\ORM\Exception\NotSupported` is deprecated without replacement.
|
||||
|
||||
## Deprecate remaining `Serializable` implementation
|
||||
|
||||
Relying on `SequenceGenerator` implementing the `Serializable` is deprecated
|
||||
because that interface won't be implemented in ORM 4 anymore.
|
||||
|
||||
The following methods are deprecated:
|
||||
|
||||
* `SequenceGenerator::serialize()`
|
||||
* `SequenceGenerator::unserialize()`
|
||||
|
||||
## `orm:schema-tool:update` option `--complete` is deprecated
|
||||
|
||||
That option behaves as a no-op, and is deprecated. It will be removed in 4.0.
|
||||
|
||||
## Deprecate properties `$indexes` and `$uniqueConstraints` of `Doctrine\ORM\Mapping\Table`
|
||||
|
||||
The properties `$indexes` and `$uniqueConstraints` have been deprecated since they had no effect at all.
|
||||
The preferred way of defining indices and unique constraints is by
|
||||
using the `\Doctrine\ORM\Mapping\UniqueConstraint` and `\Doctrine\ORM\Mapping\Index` attributes.
|
||||
|
||||
# Upgrade to 3.1
|
||||
|
||||
## Deprecate `Doctrine\ORM\Mapping\ReflectionEnumProperty`
|
||||
|
||||
@@ -38,12 +38,12 @@
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^12.0",
|
||||
"phpbench/phpbench": "^1.0",
|
||||
"phpstan/phpstan": "1.10.59",
|
||||
"phpstan/phpstan": "1.11.1",
|
||||
"phpunit/phpunit": "^10.4.0",
|
||||
"psr/log": "^1 || ^2 || ^3",
|
||||
"squizlabs/php_codesniffer": "3.7.2",
|
||||
"symfony/cache": "^5.4 || ^6.2 || ^7.0",
|
||||
"vimeo/psalm": "5.22.2"
|
||||
"vimeo/psalm": "5.24.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "Provides support for XSD validation for XML mapping files",
|
||||
|
||||
@@ -11,7 +11,7 @@ What we offer are hooks to execute any kind of validation.
|
||||
.. note::
|
||||
|
||||
You don't need to validate your entities in the lifecycle
|
||||
events. Its only one of many options. Of course you can also
|
||||
events. It is only one of many options. Of course you can also
|
||||
perform validations in value setters or any other method of your
|
||||
entities that are used in your code.
|
||||
|
||||
|
||||
@@ -870,8 +870,8 @@ This is essentially the same as the following, more verbose, mapping:
|
||||
* @var Collection<int, Group>
|
||||
*/
|
||||
#[JoinTable(name: 'User_Group')]
|
||||
#[JoinColumn(name: 'User_id', referencedColumnName: 'id')]
|
||||
#[InverseJoinColumn(name: 'Group_id', referencedColumnName: 'id')]
|
||||
#[JoinColumn(name: 'user_id', referencedColumnName: 'id')]
|
||||
#[InverseJoinColumn(name: 'group_id', referencedColumnName: 'id')]
|
||||
#[ManyToMany(targetEntity: Group::class)]
|
||||
private Collection $groups;
|
||||
// ...
|
||||
@@ -884,10 +884,10 @@ This is essentially the same as the following, more verbose, mapping:
|
||||
<many-to-many field="groups" target-entity="Group">
|
||||
<join-table name="User_Group">
|
||||
<join-columns>
|
||||
<join-column id="User_id" referenced-column-name="id" />
|
||||
<join-column id="user_id" referenced-column-name="id" />
|
||||
</join-columns>
|
||||
<inverse-join-columns>
|
||||
<join-column id="Group_id" referenced-column-name="id" />
|
||||
<join-column id="group_id" referenced-column-name="id" />
|
||||
</inverse-join-columns>
|
||||
</join-table>
|
||||
</many-to-many>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<files psalm-version="5.22.2@d768d914152dbbf3486c36398802f74e80cfde48">
|
||||
<files psalm-version="5.24.0@462c80e31c34e58cc4f750c656be3927e80e550e">
|
||||
<file src="src/AbstractQuery.php">
|
||||
<FalsableReturnStatement>
|
||||
<code><![CDATA[! $filteredParameters->isEmpty() ? $filteredParameters->first() : null]]></code>
|
||||
@@ -206,6 +206,11 @@
|
||||
<code><![CDATA[$entity]]></code>
|
||||
</PossiblyNullArgument>
|
||||
</file>
|
||||
<file src="src/Id/SequenceGenerator.php">
|
||||
<ParamNameMismatch>
|
||||
<code><![CDATA[$serialized]]></code>
|
||||
</ParamNameMismatch>
|
||||
</file>
|
||||
<file src="src/Internal/Hydration/AbstractHydrator.php">
|
||||
<ReferenceConstraintViolation>
|
||||
<code><![CDATA[return $rowData;]]></code>
|
||||
|
||||
@@ -63,27 +63,27 @@ class EntityManager implements EntityManagerInterface
|
||||
/**
|
||||
* The metadata factory, used to retrieve the ORM metadata of entity classes.
|
||||
*/
|
||||
private readonly ClassMetadataFactory $metadataFactory;
|
||||
private ClassMetadataFactory $metadataFactory;
|
||||
|
||||
/**
|
||||
* The UnitOfWork used to coordinate object-level transactions.
|
||||
*/
|
||||
private readonly UnitOfWork $unitOfWork;
|
||||
private UnitOfWork $unitOfWork;
|
||||
|
||||
/**
|
||||
* The event manager that is the central point of the event system.
|
||||
*/
|
||||
private readonly EventManager $eventManager;
|
||||
private EventManager $eventManager;
|
||||
|
||||
/**
|
||||
* The proxy factory used to create dynamic proxies.
|
||||
*/
|
||||
private readonly ProxyFactory $proxyFactory;
|
||||
private ProxyFactory $proxyFactory;
|
||||
|
||||
/**
|
||||
* The repository factory used to create dynamic repositories.
|
||||
*/
|
||||
private readonly RepositoryFactory $repositoryFactory;
|
||||
private RepositoryFactory $repositoryFactory;
|
||||
|
||||
/**
|
||||
* The expression builder instance used to generate query expressions.
|
||||
@@ -112,8 +112,8 @@ class EntityManager implements EntityManagerInterface
|
||||
* @param Connection $conn The database connection used by the EntityManager.
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly Connection $conn,
|
||||
private readonly Configuration $config,
|
||||
private Connection $conn,
|
||||
private Configuration $config,
|
||||
EventManager|null $eventManager = null,
|
||||
) {
|
||||
if (! $config->getMetadataDriverImpl()) {
|
||||
|
||||
@@ -8,6 +8,7 @@ use LogicException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
/** @deprecated */
|
||||
final class NotSupported extends LogicException implements ORMException
|
||||
{
|
||||
public static function create(): self
|
||||
|
||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace Doctrine\ORM\Id;
|
||||
|
||||
use Doctrine\DBAL\Connections\PrimaryReadReplicaConnection;
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Serializable;
|
||||
|
||||
@@ -65,8 +66,17 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
return $this->nextValue;
|
||||
}
|
||||
|
||||
/** @deprecated without replacement. */
|
||||
final public function serialize(): string
|
||||
{
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/11468',
|
||||
'%s() is deprecated, use __serialize() instead. %s won\'t implement the Serializable interface anymore in ORM 4.',
|
||||
__METHOD__,
|
||||
self::class,
|
||||
);
|
||||
|
||||
return serialize($this->__serialize());
|
||||
}
|
||||
|
||||
@@ -79,8 +89,17 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
];
|
||||
}
|
||||
|
||||
/** @deprecated without replacement. */
|
||||
final public function unserialize(string $serialized): void
|
||||
{
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/11468',
|
||||
'%s() is deprecated, use __unserialize() instead. %s won\'t implement the Serializable interface anymore in ORM 4.',
|
||||
__METHOD__,
|
||||
self::class,
|
||||
);
|
||||
|
||||
$this->__unserialize(unserialize($serialized));
|
||||
}
|
||||
|
||||
|
||||
@@ -104,29 +104,31 @@ abstract class AbstractHydrator
|
||||
|
||||
$this->prepare();
|
||||
|
||||
while (true) {
|
||||
$row = $this->statement()->fetchAssociative();
|
||||
try {
|
||||
while (true) {
|
||||
$row = $this->statement()->fetchAssociative();
|
||||
|
||||
if ($row === false) {
|
||||
$this->cleanup();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
$this->hydrateRowData($row, $result);
|
||||
|
||||
$this->cleanupAfterRowIteration();
|
||||
if (count($result) === 1) {
|
||||
if (count($resultSetMapping->indexByMap) === 0) {
|
||||
yield end($result);
|
||||
} else {
|
||||
yield from $result;
|
||||
if ($row === false) {
|
||||
break;
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
$this->hydrateRowData($row, $result);
|
||||
|
||||
$this->cleanupAfterRowIteration();
|
||||
if (count($result) === 1) {
|
||||
if (count($resultSetMapping->indexByMap) === 0) {
|
||||
yield end($result);
|
||||
} else {
|
||||
yield from $result;
|
||||
}
|
||||
} else {
|
||||
yield $result;
|
||||
}
|
||||
} else {
|
||||
yield $result;
|
||||
}
|
||||
} finally {
|
||||
$this->cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace Doctrine\ORM\Mapping;
|
||||
|
||||
use Attribute;
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
|
||||
#[Attribute(Attribute::TARGET_CLASS)]
|
||||
final class Table implements MappingAttribute
|
||||
@@ -21,5 +22,24 @@ final class Table implements MappingAttribute
|
||||
public readonly array|null $uniqueConstraints = null,
|
||||
public readonly array $options = [],
|
||||
) {
|
||||
if ($this->indexes !== null) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/11357',
|
||||
'Providing the property $indexes on %s does not have any effect and will be removed in Doctrine ORM 4.0. Please use the %s attribute instead.',
|
||||
self::class,
|
||||
Index::class,
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->uniqueConstraints !== null) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/11357',
|
||||
'Providing the property $uniqueConstraints on %s does not have any effect and will be removed in Doctrine ORM 4.0. Please use the %s attribute instead.',
|
||||
self::class,
|
||||
UniqueConstraint::class,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -635,9 +635,10 @@ class Query extends AbstractQuery
|
||||
/**
|
||||
* Get the current lock mode for this query.
|
||||
*
|
||||
* @return int|null The current lock mode of this query or NULL if no specific lock mode is set.
|
||||
* @return LockMode|int|null The current lock mode of this query or NULL if no specific lock mode is set.
|
||||
* @psalm-return LockMode::*|null
|
||||
*/
|
||||
public function getLockMode(): int|null
|
||||
public function getLockMode(): LockMode|int|null
|
||||
{
|
||||
$lockMode = $this->getHint(self::HINT_LOCK_MODE);
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ use function count;
|
||||
use function implode;
|
||||
use function is_array;
|
||||
use function is_float;
|
||||
use function is_int;
|
||||
use function is_numeric;
|
||||
use function is_string;
|
||||
use function preg_match;
|
||||
@@ -384,7 +385,9 @@ class SqlWalker
|
||||
$values = [];
|
||||
|
||||
if ($class->discriminatorValue !== null) { // discriminators can be 0
|
||||
$values[] = $conn->quote($class->discriminatorValue);
|
||||
$values[] = $class->getDiscriminatorColumn()->type === 'integer' && is_int($class->discriminatorValue)
|
||||
? $class->discriminatorValue
|
||||
: $conn->quote((string) $class->discriminatorValue);
|
||||
}
|
||||
|
||||
foreach ($class->subClasses as $subclassName) {
|
||||
@@ -396,7 +399,9 @@ class SqlWalker
|
||||
continue;
|
||||
}
|
||||
|
||||
$values[] = $conn->quote((string) $subclassMetadata->discriminatorValue);
|
||||
$values[] = $subclassMetadata->getDiscriminatorColumn()->type === 'integer' && is_int($subclassMetadata->discriminatorValue)
|
||||
? $subclassMetadata->discriminatorValue
|
||||
: $conn->quote((string) $subclassMetadata->discriminatorValue);
|
||||
}
|
||||
|
||||
if ($values !== []) {
|
||||
@@ -2246,8 +2251,10 @@ class SqlWalker
|
||||
$discriminators += HierarchyDiscriminatorResolver::resolveDiscriminatorsForClass($metadata, $this->em);
|
||||
}
|
||||
|
||||
foreach (array_keys($discriminators) as $dis) {
|
||||
$sqlParameterList[] = $this->conn->quote($dis);
|
||||
foreach (array_keys($discriminators) as $discriminatorValue) {
|
||||
$sqlParameterList[] = $rootClass->getDiscriminatorColumn()->type === 'integer' && is_int($discriminatorValue)
|
||||
? $discriminatorValue
|
||||
: $this->conn->quote((string) $discriminatorValue);
|
||||
}
|
||||
|
||||
return '(' . implode(', ', $sqlParameterList) . ')';
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Tools\Console\Command\SchemaTool;
|
||||
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\Tools\SchemaTool;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
@@ -28,7 +29,7 @@ class UpdateCommand extends AbstractCommand
|
||||
$this->setName($this->name)
|
||||
->setDescription('Executes (or dumps) the SQL needed to update the database schema to match the current mapping metadata')
|
||||
->addOption('em', null, InputOption::VALUE_REQUIRED, 'Name of the entity manager to operate on')
|
||||
->addOption('complete', null, InputOption::VALUE_NONE, 'This option is a no-op and will be removed in 4.0')
|
||||
->addOption('complete', null, InputOption::VALUE_NONE, 'This option is a no-op, is deprecated and will be removed in 4.0')
|
||||
->addOption('dump-sql', null, InputOption::VALUE_NONE, 'Dumps the generated SQL statements to the screen (does not execute them).')
|
||||
->addOption('force', 'f', InputOption::VALUE_NONE, 'Causes the generated SQL statements to be physically executed against your database.')
|
||||
->setHelp(<<<'EOT'
|
||||
@@ -75,6 +76,15 @@ EOT);
|
||||
{
|
||||
$notificationUi = $ui->getErrorStyle();
|
||||
|
||||
if ($input->getOption('complete') === true) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/11354',
|
||||
'The --complete option is a no-op, is deprecated and will be removed in Doctrine ORM 4.0.',
|
||||
);
|
||||
$notificationUi->warning('The --complete option is a no-op, is deprecated and will be removed in Doctrine ORM 4.0.');
|
||||
}
|
||||
|
||||
$sqls = $schemaTool->getUpdateSchemaSql($metadatas);
|
||||
|
||||
if (empty($sqls)) {
|
||||
|
||||
@@ -1143,6 +1143,8 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$eventsToDispatch = [];
|
||||
|
||||
foreach ($entities as $entity) {
|
||||
$this->removeFromIdentityMap($entity);
|
||||
|
||||
$oid = spl_object_id($entity);
|
||||
$class = $this->em->getClassMetadata($entity::class);
|
||||
$persister = $this->getEntityPersister($class->name);
|
||||
@@ -1484,8 +1486,6 @@ class UnitOfWork implements PropertyChangedListener
|
||||
return;
|
||||
}
|
||||
|
||||
$this->removeFromIdentityMap($entity);
|
||||
|
||||
unset($this->entityUpdates[$oid]);
|
||||
|
||||
if (! isset($this->entityDeletions[$oid])) {
|
||||
@@ -2653,7 +2653,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$entities[] = $collection->getOwner();
|
||||
}
|
||||
|
||||
$found = $this->getEntityPersister($targetEntity)->loadAll([$mappedBy => $entities]);
|
||||
$found = $this->getEntityPersister($targetEntity)->loadAll([$mappedBy => $entities], $mapping->orderBy);
|
||||
|
||||
$targetClass = $this->em->getClassMetadata($targetEntity);
|
||||
$targetProperty = $targetClass->getReflectionProperty($mappedBy);
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace Doctrine\Tests\ORM\Cache\Persister\Entity;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\DBAL\LockMode;
|
||||
use Doctrine\ORM\Cache\Persister\CachedPersister;
|
||||
use Doctrine\ORM\Cache\Persister\Entity\AbstractEntityPersister;
|
||||
use Doctrine\ORM\Cache\Persister\Entity\CachedEntityPersister;
|
||||
@@ -97,7 +98,7 @@ abstract class EntityPersisterTestCase extends OrmTestCase
|
||||
->with(
|
||||
self::identicalTo(['name' => 'Foo']),
|
||||
self::identicalTo($associationMapping),
|
||||
self::identicalTo(1),
|
||||
self::identicalTo(LockMode::OPTIMISTIC),
|
||||
self::identicalTo(2),
|
||||
self::identicalTo(3),
|
||||
self::identicalTo([4]),
|
||||
@@ -107,7 +108,7 @@ abstract class EntityPersisterTestCase extends OrmTestCase
|
||||
self::assertSame('SELECT * FROM foo WERE name = ?', $persister->getSelectSQL(
|
||||
['name' => 'Foo'],
|
||||
$associationMapping,
|
||||
1,
|
||||
LockMode::OPTIMISTIC,
|
||||
2,
|
||||
3,
|
||||
[4],
|
||||
@@ -233,13 +234,21 @@ abstract class EntityPersisterTestCase extends OrmTestCase
|
||||
self::identicalTo($entity),
|
||||
self::identicalTo($associationMapping),
|
||||
self::identicalTo([1]),
|
||||
self::identicalTo(2),
|
||||
self::identicalTo(LockMode::PESSIMISTIC_READ),
|
||||
self::identicalTo(3),
|
||||
self::identicalTo([4]),
|
||||
)
|
||||
->willReturn($entity);
|
||||
|
||||
self::assertSame($entity, $persister->load(['id' => 1], $entity, $associationMapping, [1], 2, 3, [4]));
|
||||
self::assertSame($entity, $persister->load(
|
||||
['id' => 1],
|
||||
$entity,
|
||||
$associationMapping,
|
||||
[1],
|
||||
LockMode::PESSIMISTIC_READ,
|
||||
3,
|
||||
[4],
|
||||
));
|
||||
}
|
||||
|
||||
public function testInvokeLoadAll(): void
|
||||
@@ -402,9 +411,9 @@ abstract class EntityPersisterTestCase extends OrmTestCase
|
||||
|
||||
$this->entityPersister->expects(self::once())
|
||||
->method('lock')
|
||||
->with(self::identicalTo($identifier), self::identicalTo(1));
|
||||
->with(self::identicalTo($identifier), self::identicalTo(LockMode::OPTIMISTIC));
|
||||
|
||||
$persister->lock($identifier, 1);
|
||||
$persister->lock($identifier, LockMode::OPTIMISTIC);
|
||||
}
|
||||
|
||||
public function testInvokeExists(): void
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace Doctrine\Tests\ORM;
|
||||
use Doctrine\Common\EventManager;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\ORM\Configuration;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Exception\EntityManagerClosed;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataFactory;
|
||||
@@ -21,7 +22,9 @@ use Doctrine\Tests\OrmTestCase;
|
||||
use Generator;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use ReflectionProperty;
|
||||
use stdClass;
|
||||
use Symfony\Component\VarExporter\LazyGhostTrait;
|
||||
use TypeError;
|
||||
|
||||
class EntityManagerTest extends OrmTestCase
|
||||
@@ -172,4 +175,36 @@ class EntityManagerTest extends OrmTestCase
|
||||
self::assertFalse($this->entityManager->isOpen());
|
||||
}
|
||||
}
|
||||
|
||||
/** Resetting the EntityManager relies on lazy objects until https://github.com/doctrine/orm/issues/5933 is resolved */
|
||||
public function testLazyGhostEntityManager(): void
|
||||
{
|
||||
$em = new class () extends EntityManager {
|
||||
use LazyGhostTrait;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
$em = $em::createLazyGhost(static function ($em): void {
|
||||
$r = new ReflectionProperty(EntityManager::class, 'unitOfWork');
|
||||
$r->setValue($em, new class () extends UnitOfWork {
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function clear(): void
|
||||
{
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$this->assertTrue($em->isOpen());
|
||||
$em->close();
|
||||
$this->assertFalse($em->isOpen());
|
||||
|
||||
$em->resetLazyObject();
|
||||
$this->assertTrue($em->isOpen());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,7 +252,6 @@ class QueryDqlFunctionTest extends OrmFunctionalTestCase
|
||||
self::assertEquals(1_600_000, $result[3]['op']);
|
||||
}
|
||||
|
||||
#[Group('test')]
|
||||
public function testOperatorDiv(): void
|
||||
{
|
||||
$result = $this->_em->createQuery('SELECT m, (m.salary/0.5) AS op FROM Doctrine\Tests\Models\Company\CompanyManager m ORDER BY m.salary ASC')
|
||||
|
||||
112
tests/Tests/ORM/Functional/Ticket/GH11163Test.php
Normal file
112
tests/Tests/ORM/Functional/Ticket/GH11163Test.php
Normal file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
class GH11163Test extends OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->setUpEntitySchema([
|
||||
GH11163Bucket::class,
|
||||
GH11163BucketItem::class,
|
||||
]);
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
parent::tearDown();
|
||||
|
||||
$conn = static::$sharedConn;
|
||||
$conn->executeStatement('DELETE FROM GH11163BucketItem');
|
||||
$conn->executeStatement('DELETE FROM GH11163Bucket');
|
||||
}
|
||||
|
||||
public function testFetchEagerModeWithOrderBy(): void
|
||||
{
|
||||
// Load entities into database
|
||||
$this->_em->persist($bucket = new GH11163Bucket(11163));
|
||||
$this->_em->persist(new GH11163BucketItem(1, $bucket, 2));
|
||||
$this->_em->persist(new GH11163BucketItem(2, $bucket, 3));
|
||||
$this->_em->persist(new GH11163BucketItem(3, $bucket, 1));
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
// Fetch entity from database
|
||||
$dql = 'SELECT bucket FROM ' . GH11163Bucket::class . ' bucket WHERE bucket.id = :id';
|
||||
$bucket = $this->_em->createQuery($dql)
|
||||
->setParameter('id', 11163)
|
||||
->getSingleResult();
|
||||
|
||||
// Assert associated entity is loaded eagerly
|
||||
static::assertInstanceOf(GH11163Bucket::class, $bucket);
|
||||
static::assertInstanceOf(PersistentCollection::class, $bucket->items);
|
||||
static::assertTrue($bucket->items->isInitialized());
|
||||
|
||||
static::assertCount(3, $bucket->items);
|
||||
|
||||
// Assert order of entities
|
||||
static::assertSame(1, $bucket->items[0]->position);
|
||||
static::assertSame(3, $bucket->items[0]->id);
|
||||
|
||||
static::assertSame(2, $bucket->items[1]->position);
|
||||
static::assertSame(1, $bucket->items[1]->id);
|
||||
|
||||
static::assertSame(3, $bucket->items[2]->position);
|
||||
static::assertSame(2, $bucket->items[2]->id);
|
||||
}
|
||||
}
|
||||
|
||||
#[ORM\Entity]
|
||||
class GH11163Bucket
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private int $id;
|
||||
|
||||
/** @var Collection<int, GH11163BucketItem> */
|
||||
#[ORM\OneToMany(
|
||||
targetEntity: GH11163BucketItem::class,
|
||||
mappedBy: 'bucket',
|
||||
fetch: 'EAGER',
|
||||
)]
|
||||
#[ORM\OrderBy(['position' => 'ASC'])]
|
||||
public Collection $items;
|
||||
|
||||
public function __construct(int $id)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->items = new ArrayCollection();
|
||||
}
|
||||
}
|
||||
|
||||
#[ORM\Entity]
|
||||
class GH11163BucketItem
|
||||
{
|
||||
#[ORM\ManyToOne(targetEntity: GH11163Bucket::class, inversedBy: 'items')]
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
private GH11163Bucket $bucket;
|
||||
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
public int $id;
|
||||
|
||||
#[ORM\Column(type: 'integer')]
|
||||
public int $position;
|
||||
|
||||
public function __construct(int $id, GH11163Bucket $bucket, int $position)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->bucket = $bucket;
|
||||
$this->position = $position;
|
||||
}
|
||||
}
|
||||
157
tests/Tests/ORM/Functional/Ticket/GH11341Test.php
Normal file
157
tests/Tests/ORM/Functional/Ticket/GH11341Test.php
Normal file
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
use Generator;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class GH11341Test extends OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->setUpEntitySchema([
|
||||
IntegerBaseClass::class,
|
||||
IntegerFooEntity::class,
|
||||
IntegerBarEntity::class,
|
||||
StringAsIntBaseClass::class,
|
||||
StringAsIntFooEntity::class,
|
||||
StringAsIntBarEntity::class,
|
||||
StringBaseClass::class,
|
||||
StringFooEntity::class,
|
||||
StringBarEntity::class,
|
||||
]);
|
||||
}
|
||||
|
||||
public static function dqlStatements(): Generator
|
||||
{
|
||||
yield ['SELECT e FROM ' . IntegerBaseClass::class . ' e', '/WHERE [a-z]0_.type IN \(1, 2\)$/'];
|
||||
yield ['SELECT e FROM ' . IntegerFooEntity::class . ' e', '/WHERE [a-z]0_.type IN \(1\)$/'];
|
||||
yield ['SELECT e FROM ' . IntegerBarEntity::class . ' e', '/WHERE [a-z]0_.type IN \(2\)$/'];
|
||||
yield ['SELECT e FROM ' . StringAsIntBaseClass::class . ' e', '/WHERE [a-z]0_.type IN \(\'1\', \'2\'\)$/'];
|
||||
yield ['SELECT e FROM ' . StringAsIntFooEntity::class . ' e', '/WHERE [a-z]0_.type IN \(\'1\'\)$/'];
|
||||
yield ['SELECT e FROM ' . StringAsIntBarEntity::class . ' e', '/WHERE [a-z]0_.type IN \(\'2\'\)$/'];
|
||||
yield ['SELECT e FROM ' . StringBaseClass::class . ' e', '/WHERE [a-z]0_.type IN \(\'1\', \'2\'\)$/'];
|
||||
yield ['SELECT e FROM ' . StringFooEntity::class . ' e', '/WHERE [a-z]0_.type IN \(\'1\'\)$/'];
|
||||
yield ['SELECT e FROM ' . StringBarEntity::class . ' e', '/WHERE [a-z]0_.type IN \(\'2\'\)$/'];
|
||||
}
|
||||
|
||||
#[DataProvider('dqlStatements')]
|
||||
public function testDiscriminatorValue(string $dql, string $expectedDiscriminatorValues): void
|
||||
{
|
||||
$query = $this->_em->createQuery($dql);
|
||||
$sql = $query->getSQL();
|
||||
|
||||
self::assertMatchesRegularExpression($expectedDiscriminatorValues, $sql);
|
||||
}
|
||||
|
||||
public static function dqlStatementsForInstanceOf(): Generator
|
||||
{
|
||||
yield [IntegerBaseClass::class, IntegerFooEntity::class];
|
||||
yield [StringBaseClass::class, StringFooEntity::class];
|
||||
yield [StringAsIntBaseClass::class, StringAsIntFooEntity::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-param class-string $baseClass
|
||||
* @psalm-param class-string $inheritedClass
|
||||
*/
|
||||
#[DataProvider('dqlStatementsForInstanceOf')]
|
||||
public function testInstanceOf(string $baseClass, string $inheritedClass): void
|
||||
{
|
||||
$this->_em->persist(new $inheritedClass());
|
||||
$this->_em->flush();
|
||||
|
||||
$dql = 'SELECT p FROM ' . $baseClass . ' p WHERE p INSTANCE OF ' . $baseClass;
|
||||
|
||||
$query = $this->_em->createQuery($dql);
|
||||
$result = $query->getResult();
|
||||
|
||||
self::assertCount(1, $result);
|
||||
self::assertContainsOnlyInstancesOf($baseClass, $result);
|
||||
}
|
||||
}
|
||||
|
||||
#[ORM\Entity]
|
||||
#[ORM\Table(name: 'integer_discriminator')]
|
||||
#[ORM\InheritanceType('SINGLE_TABLE')]
|
||||
#[ORM\DiscriminatorColumn(name: 'type', type: 'integer')]
|
||||
#[ORM\DiscriminatorMap([
|
||||
1 => IntegerFooEntity::class,
|
||||
2 => IntegerBarEntity::class,
|
||||
])]
|
||||
class IntegerBaseClass
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: 'IDENTITY')]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private int|null $id = null;
|
||||
}
|
||||
|
||||
#[ORM\Entity]
|
||||
class IntegerFooEntity extends IntegerBaseClass
|
||||
{
|
||||
}
|
||||
|
||||
#[ORM\Entity]
|
||||
class IntegerBarEntity extends IntegerBaseClass
|
||||
{
|
||||
}
|
||||
|
||||
#[ORM\Entity]
|
||||
#[ORM\Table(name: 'string_as_int_discriminator')]
|
||||
#[ORM\InheritanceType('SINGLE_TABLE')]
|
||||
#[ORM\DiscriminatorColumn(name: 'type', type: 'string')]
|
||||
#[ORM\DiscriminatorMap([
|
||||
1 => StringAsIntFooEntity::class,
|
||||
2 => StringAsIntBarEntity::class,
|
||||
])]
|
||||
class StringAsIntBaseClass
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: 'IDENTITY')]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private int|null $id = null;
|
||||
}
|
||||
|
||||
#[ORM\Entity]
|
||||
class StringAsIntFooEntity extends StringAsIntBaseClass
|
||||
{
|
||||
}
|
||||
|
||||
#[ORM\Entity]
|
||||
class StringAsIntBarEntity extends StringAsIntBaseClass
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#[ORM\Entity]
|
||||
#[ORM\Table(name: 'string_discriminator')]
|
||||
#[ORM\InheritanceType('SINGLE_TABLE')]
|
||||
#[ORM\DiscriminatorColumn(name: 'type', type: 'string')]
|
||||
#[ORM\DiscriminatorMap([
|
||||
'1' => StringFooEntity::class,
|
||||
'2' => StringBarEntity::class,
|
||||
])]
|
||||
class StringBaseClass
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: 'IDENTITY')]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private int|null $id = null;
|
||||
}
|
||||
|
||||
#[ORM\Entity]
|
||||
class StringFooEntity extends StringBaseClass
|
||||
{
|
||||
}
|
||||
|
||||
#[ORM\Entity]
|
||||
class StringBarEntity extends StringBaseClass
|
||||
{
|
||||
}
|
||||
79
tests/Tests/ORM/Functional/Ticket/GH6123Test.php
Normal file
79
tests/Tests/ORM/Functional/Ticket/GH6123Test.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
class GH6123Test extends OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->createSchemaForModels(
|
||||
GH6123Entity::class,
|
||||
);
|
||||
}
|
||||
|
||||
public function testLoadingRemovedEntityFromDatabaseDoesNotCreateNewManagedEntityInstance(): void
|
||||
{
|
||||
$entity = new GH6123Entity();
|
||||
$this->_em->persist($entity);
|
||||
$this->_em->flush();
|
||||
|
||||
self::assertSame(UnitOfWork::STATE_MANAGED, $this->_em->getUnitOfWork()->getEntityState($entity));
|
||||
self::assertFalse($this->_em->getUnitOfWork()->isScheduledForDelete($entity));
|
||||
|
||||
$this->_em->remove($entity);
|
||||
|
||||
$freshEntity = $this->loadEntityFromDatabase($entity->id);
|
||||
self::assertSame($entity, $freshEntity);
|
||||
|
||||
self::assertSame(UnitOfWork::STATE_REMOVED, $this->_em->getUnitOfWork()->getEntityState($freshEntity));
|
||||
self::assertTrue($this->_em->getUnitOfWork()->isScheduledForDelete($freshEntity));
|
||||
}
|
||||
|
||||
public function testRemovedEntityCanBePersistedAgain(): void
|
||||
{
|
||||
$entity = new GH6123Entity();
|
||||
$this->_em->persist($entity);
|
||||
$this->_em->flush();
|
||||
|
||||
$this->_em->remove($entity);
|
||||
self::assertSame(UnitOfWork::STATE_REMOVED, $this->_em->getUnitOfWork()->getEntityState($entity));
|
||||
self::assertTrue($this->_em->getUnitOfWork()->isScheduledForDelete($entity));
|
||||
|
||||
$this->loadEntityFromDatabase($entity->id);
|
||||
|
||||
$this->_em->persist($entity);
|
||||
self::assertSame(UnitOfWork::STATE_MANAGED, $this->_em->getUnitOfWork()->getEntityState($entity));
|
||||
self::assertFalse($this->_em->getUnitOfWork()->isScheduledForDelete($entity));
|
||||
|
||||
$this->_em->flush();
|
||||
}
|
||||
|
||||
private function loadEntityFromDatabase(int $id): GH6123Entity|null
|
||||
{
|
||||
return $this->_em->createQueryBuilder()
|
||||
->select('e')
|
||||
->from(GH6123Entity::class, 'e')
|
||||
->where('e.id = :id')
|
||||
->setParameter('id', $id)
|
||||
->getQuery()
|
||||
->getOneOrNullResult();
|
||||
}
|
||||
}
|
||||
|
||||
#[ORM\Entity]
|
||||
class GH6123Entity
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column(type: Types::INTEGER)]
|
||||
public int $id;
|
||||
}
|
||||
@@ -13,6 +13,7 @@ use Doctrine\ORM\Events;
|
||||
use Doctrine\ORM\Exception\ORMException;
|
||||
use Doctrine\ORM\Internal\Hydration\AbstractHydrator;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\Tests\Models\Hydration\SimpleEntity;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
@@ -149,4 +150,33 @@ class AbstractHydratorTest extends OrmFunctionalTestCase
|
||||
$this->expectException(ORMException::class);
|
||||
$this->hydrator->hydrateAll($this->mockResult, $this->mockResultMapping);
|
||||
}
|
||||
|
||||
public function testToIterableIfYieldAndBreakBeforeFinishAlwaysCleansUp(): void
|
||||
{
|
||||
$this->setUpEntitySchema([SimpleEntity::class]);
|
||||
|
||||
$entity1 = new SimpleEntity();
|
||||
$this->_em->persist($entity1);
|
||||
$entity2 = new SimpleEntity();
|
||||
$this->_em->persist($entity2);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$evm = $this->_em->getEventManager();
|
||||
|
||||
$q = $this->_em->createQuery('SELECT e.id FROM ' . SimpleEntity::class . ' e');
|
||||
|
||||
// select two entities, but do no iterate
|
||||
$q->toIterable();
|
||||
self::assertCount(0, $evm->getListeners(Events::onClear));
|
||||
|
||||
// select two entities, but abort after first record
|
||||
foreach ($q->toIterable() as $result) {
|
||||
self::assertCount(1, $evm->getListeners(Events::onClear));
|
||||
break;
|
||||
}
|
||||
|
||||
self::assertCount(0, $evm->getListeners(Events::onClear));
|
||||
}
|
||||
}
|
||||
|
||||
28
tests/Tests/ORM/Mapping/TableMappingTest.php
Normal file
28
tests/Tests/ORM/Mapping/TableMappingTest.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Mapping;
|
||||
|
||||
use Doctrine\Deprecations\PHPUnit\VerifyDeprecations;
|
||||
use Doctrine\ORM\Mapping\Table;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class TableMappingTest extends TestCase
|
||||
{
|
||||
use VerifyDeprecations;
|
||||
|
||||
public function testDeprecationOnIndexesPropertyIsTriggered(): void
|
||||
{
|
||||
$this->expectDeprecationWithIdentifier('https://github.com/doctrine/orm/pull/11357');
|
||||
|
||||
new Table(indexes: []);
|
||||
}
|
||||
|
||||
public function testDeprecationOnUniqueConstraintsPropertyIsTriggered(): void
|
||||
{
|
||||
$this->expectDeprecationWithIdentifier('https://github.com/doctrine/orm/pull/11357');
|
||||
|
||||
new Table(uniqueConstraints: []);
|
||||
}
|
||||
}
|
||||
@@ -12,9 +12,12 @@ use Doctrine\DBAL\Cache\ArrayResult;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Driver;
|
||||
use Doctrine\DBAL\Driver\Result;
|
||||
use Doctrine\DBAL\LockMode;
|
||||
use Doctrine\DBAL\ParameterType;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Query\Parameter;
|
||||
use Doctrine\ORM\Query\QueryException;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
@@ -39,8 +42,7 @@ use function array_map;
|
||||
|
||||
class QueryTest extends OrmTestCase
|
||||
{
|
||||
/** @var EntityManagerMock */
|
||||
protected $entityManager;
|
||||
private EntityManagerMock $entityManager;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
@@ -80,6 +82,30 @@ class QueryTest extends OrmTestCase
|
||||
self::assertEquals($parameters, $query->getParameters());
|
||||
}
|
||||
|
||||
/** @psalm-param LockMode::* $lockMode */
|
||||
#[DataProvider('provideLockModes')]
|
||||
public function testSetLockMode(LockMode|int $lockMode): void
|
||||
{
|
||||
$query = $this->entityManager->wrapInTransaction(static function (EntityManagerInterface $em) use ($lockMode): Query {
|
||||
$query = $em->createQuery('select u from Doctrine\Tests\Models\CMS\CmsUser u where u.username = ?1');
|
||||
$query->setLockMode($lockMode);
|
||||
|
||||
return $query;
|
||||
});
|
||||
|
||||
self::assertSame($lockMode, $query->getLockMode());
|
||||
self::assertSame($lockMode, $query->getHint(Query::HINT_LOCK_MODE));
|
||||
}
|
||||
|
||||
/** @psalm-return list<array{LockMode::*}> */
|
||||
public static function provideLockModes(): array
|
||||
{
|
||||
return [
|
||||
[LockMode::PESSIMISTIC_READ],
|
||||
[LockMode::PESSIMISTIC_WRITE],
|
||||
];
|
||||
}
|
||||
|
||||
public function testFree(): void
|
||||
{
|
||||
$query = $this->entityManager->createQuery('select u from Doctrine\Tests\Models\CMS\CmsUser u where u.username = ?1');
|
||||
|
||||
@@ -288,12 +288,18 @@ class UnitOfWorkTest extends OrmTestCase
|
||||
$entity->id = 123;
|
||||
|
||||
$this->_unitOfWork->registerManaged($entity, ['id' => 123], []);
|
||||
self::assertSame(UnitOfWork::STATE_MANAGED, $this->_unitOfWork->getEntityState($entity));
|
||||
self::assertFalse($this->_unitOfWork->isScheduledForDelete($entity));
|
||||
self::assertTrue($this->_unitOfWork->isInIdentityMap($entity));
|
||||
|
||||
$this->_unitOfWork->remove($entity);
|
||||
self::assertFalse($this->_unitOfWork->isInIdentityMap($entity));
|
||||
self::assertSame(UnitOfWork::STATE_REMOVED, $this->_unitOfWork->getEntityState($entity));
|
||||
self::assertTrue($this->_unitOfWork->isScheduledForDelete($entity));
|
||||
self::assertTrue($this->_unitOfWork->isInIdentityMap($entity));
|
||||
|
||||
$this->_unitOfWork->persist($entity);
|
||||
self::assertSame(UnitOfWork::STATE_MANAGED, $this->_unitOfWork->getEntityState($entity));
|
||||
self::assertFalse($this->_unitOfWork->isScheduledForDelete($entity));
|
||||
self::assertTrue($this->_unitOfWork->isInIdentityMap($entity));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user