mirror of
https://github.com/doctrine/orm.git
synced 2026-04-26 16:08:03 +02:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| de7eee5ed7 | |||
| 4051937fda | |||
| b2e42dc92d | |||
| f219b87870 | |||
| 87fefbac34 | |||
| 853e80ca98 | |||
| d68baef880 | |||
| fdccfbd120 | |||
| 180afa8c8f | |||
| dbbf5c7279 | |||
| 5d9b8f0ea8 | |||
| 174947155d | |||
| 2138cc9383 | |||
| 39a434914d | |||
| 227f60c832 | |||
| f72f6b199b | |||
| 92e63ca4f9 | |||
| 3c98973ab3 | |||
| 3b8692fa4a | |||
| c9efc1cdee | |||
| c5e4e41e05 | |||
| 9431b2ea45 | |||
| 036ea713a5 | |||
| 0852847659 | |||
| 1e2625a82f | |||
| 3010fd1680 | |||
| 85ac2769a9 | |||
| 28e98b3475 | |||
| 99a37d864e | |||
| 27df173971 | |||
| 0aa45dd607 | |||
| f8bf84d1aa | |||
| c825e34f8d | |||
| ff6bad486b | |||
| 30a2680bfd | |||
| a460a4d054 | |||
| 9d5ab4ce76 |
+12
-6
@@ -12,21 +12,27 @@
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "2.14",
|
||||
"branchName": "2.14.x",
|
||||
"slug": "2.14",
|
||||
"name": "2.15",
|
||||
"branchName": "2.15.x",
|
||||
"slug": "2.15",
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "2.13",
|
||||
"branchName": "2.13.x",
|
||||
"slug": "2.13",
|
||||
"name": "2.14",
|
||||
"branchName": "2.14.x",
|
||||
"slug": "2.14",
|
||||
"current": true,
|
||||
"aliases": [
|
||||
"current",
|
||||
"stable"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "2.13",
|
||||
"branchName": "2.13.x",
|
||||
"slug": "2.13",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.12",
|
||||
"branchName": "2.12.x",
|
||||
|
||||
@@ -78,9 +78,6 @@ jobs:
|
||||
run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update"
|
||||
if: "${{ matrix.dbal-version != 'default' }}"
|
||||
|
||||
- name: "Uninstall PHPBench"
|
||||
run: "composer remove --dev --no-update phpbench/phpbench"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
with:
|
||||
@@ -156,9 +153,6 @@ jobs:
|
||||
run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update"
|
||||
if: "${{ matrix.dbal-version != 'default' }}"
|
||||
|
||||
- name: "Uninstall PHPBench"
|
||||
run: "composer remove --dev --no-update phpbench/phpbench"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
with:
|
||||
@@ -220,9 +214,6 @@ jobs:
|
||||
run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update"
|
||||
if: "${{ matrix.dbal-version != 'default' }}"
|
||||
|
||||
- name: "Uninstall PHPBench"
|
||||
run: "composer remove --dev --no-update phpbench/phpbench"
|
||||
|
||||
- name: "Install PHP"
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
with:
|
||||
@@ -300,9 +291,6 @@ jobs:
|
||||
run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update"
|
||||
if: "${{ matrix.dbal-version != 'default' }}"
|
||||
|
||||
- name: "Uninstall PHPBench"
|
||||
run: "composer remove --dev --no-update phpbench/phpbench"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
with:
|
||||
|
||||
@@ -57,9 +57,6 @@ jobs:
|
||||
- name: "Require specific persistence version"
|
||||
run: "composer require doctrine/persistence ^$([ ${{ matrix.persistence-version }} = default ] && echo '3.1' || echo ${{ matrix.persistence-version }}) --no-update"
|
||||
|
||||
- name: "Uninstall PHPBench"
|
||||
run: "composer remove --dev --no-update phpbench/phpbench"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
with:
|
||||
@@ -97,9 +94,6 @@ jobs:
|
||||
- name: "Require specific persistence version"
|
||||
run: "composer require doctrine/persistence ^3.1 --no-update"
|
||||
|
||||
- name: "Uninstall PHPBench"
|
||||
run: "composer remove --dev --no-update phpbench/phpbench"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
with:
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Upgrade to 2.14
|
||||
|
||||
## Deprecated `Doctrine\ORM\Persisters\Exception\UnrecognizedField::byName($field)` method.
|
||||
|
||||
Use `Doctrine\ORM\Persisters\Exception\UnrecognizedField::byFullyQualifiedName($className, $field)` instead.
|
||||
|
||||
## Deprecated constants of `Doctrine\ORM\Internal\CommitOrderCalculator`
|
||||
|
||||
The following public constants have been deprecated:
|
||||
|
||||
+2
-2
@@ -42,14 +42,14 @@
|
||||
"doctrine/annotations": "^1.13 || ^2",
|
||||
"doctrine/coding-standard": "^9.0.2 || ^11.0",
|
||||
"phpbench/phpbench": "^0.16.10 || ^1.0",
|
||||
"phpstan/phpstan": "~1.4.10 || 1.9.4",
|
||||
"phpstan/phpstan": "~1.4.10 || 1.9.8",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
|
||||
"psr/log": "^1 || ^2 || ^3",
|
||||
"squizlabs/php_codesniffer": "3.7.1",
|
||||
"symfony/cache": "^4.4 || ^5.4 || ^6.0",
|
||||
"symfony/var-exporter": "^4.4 || ^5.4 || ^6.2",
|
||||
"symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0",
|
||||
"vimeo/psalm": "4.30.0 || 5.3.0"
|
||||
"vimeo/psalm": "4.30.0 || 5.4.0"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/annotations": "<1.13 || >= 3.0"
|
||||
|
||||
@@ -94,6 +94,25 @@ classes, and non-entity classes may extend entity classes.
|
||||
never calls entity constructors, thus you are free to use them as
|
||||
you wish and even have it require arguments of any type.
|
||||
|
||||
Mapped Superclasses
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A mapped superclass is an abstract or concrete class that provides
|
||||
persistent entity state and mapping information for its subclasses,
|
||||
but which is not itself an entity.
|
||||
|
||||
Mapped superclasses are explained in greater detail in the chapter
|
||||
on :doc:`inheritance mapping <reference/inheritance-mapping>`.
|
||||
|
||||
Transient Classes
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
The term "transient class" appears in some places in the mapping
|
||||
drivers as well as the code dealing with metadata handling.
|
||||
|
||||
A transient class is a class that is neither an entity nor a mapped
|
||||
superclass. From the ORM's point of view, these classes can be
|
||||
completely ignored, and no class metadata is loaded for them at all.
|
||||
|
||||
Entity states
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
@@ -28,10 +28,11 @@ table alias of the SQL table of the entity.
|
||||
In the case of joined or single table inheritance, you always get passed the ClassMetadata of the
|
||||
inheritance root. This is necessary to avoid edge cases that would break the SQL when applying the filters.
|
||||
|
||||
Parameters for the query should be set on the filter object by
|
||||
``SQLFilter#setParameter()``. Only parameters set via this function can be used
|
||||
in filters. The ``SQLFilter#getParameter()`` function takes care of the
|
||||
proper quoting of parameters.
|
||||
For the filter to correctly function, the following rules must be followed. Failure to do so will lead to unexpected results from the query cache.
|
||||
1. Parameters for the query should be set on the filter object by ``SQLFilter#setParameter()`` before the filter is used by the ORM ( i.e. do not set parameters inside ``SQLFilter#addFilterConstraint()`` function ).
|
||||
2. The filter must be deterministic. Don't change the values base on external inputs.
|
||||
|
||||
The ``SQLFilter#getParameter()`` function takes care of the proper quoting of parameters.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
|
||||
@@ -45,8 +45,7 @@ in scenarios where data is loaded for read-only purposes.
|
||||
Read-Only Entities
|
||||
------------------
|
||||
|
||||
You can mark entities as read only (See metadata mapping
|
||||
references for details).
|
||||
You can mark entities as read only. For details, see :ref:`attrref_entity`
|
||||
|
||||
This means that the entity marked as read only is never considered for updates.
|
||||
During flush on the EntityManager these entities are skipped even if properties
|
||||
@@ -55,8 +54,6 @@ changed.
|
||||
Read-Only allows to persist new entities of a kind and remove existing ones,
|
||||
they are just not considered for updates.
|
||||
|
||||
See :ref:`annref_entity`
|
||||
|
||||
You can also explicitly mark individual entities read only directly on the
|
||||
UnitOfWork via a call to ``markReadOnly()``:
|
||||
|
||||
|
||||
@@ -25,6 +25,12 @@ appear in the middle of an otherwise mapped inheritance hierarchy
|
||||
For further support of inheritance, the single or
|
||||
joined table inheritance features have to be used.
|
||||
|
||||
.. note::
|
||||
|
||||
You may be tempted to use traits to mix mapped fields or relationships
|
||||
into your entity classes to circumvent some of the limitations of
|
||||
mapped superclasses. Before doing that, please read the section on traits
|
||||
in the :doc:`Limitations and Known Issues <reference/limitations-and-known-issues>` chapter.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -77,7 +83,7 @@ like this (this is for SQLite):
|
||||
|
||||
.. code-block:: sql
|
||||
|
||||
CREATE TABLE EntitySubClass (mapped1 INTEGER NOT NULL, mapped2 TEXT NOT NULL, id INTEGER NOT NULL, name TEXT NOT NULL, related1_id INTEGER DEFAULT NULL, PRIMARY KEY(id))
|
||||
CREATE TABLE Employee (mapped1 INTEGER NOT NULL, mapped2 TEXT NOT NULL, id INTEGER NOT NULL, name TEXT NOT NULL, toothbrush_id INTEGER DEFAULT NULL, PRIMARY KEY(id))
|
||||
|
||||
As you can see from this DDL snippet, there is only a single table
|
||||
for the entity subclass. All the mappings from the mapped
|
||||
|
||||
@@ -130,10 +130,51 @@ included in the core of Doctrine ORM. However there are already two
|
||||
extensions out there that offer support for Nested Set with
|
||||
ORM:
|
||||
|
||||
|
||||
- `Doctrine2 Hierarchical-Structural Behavior <https://github.com/guilhermeblanco/Doctrine2-Hierarchical-Structural-Behavior>`_
|
||||
- `Doctrine2 NestedSet <https://github.com/blt04/doctrine2-nestedset>`_
|
||||
|
||||
Using Traits in Entity Classes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The use of traits in entity or mapped superclasses, at least when they
|
||||
include mapping configuration or mapped fields, is currently not
|
||||
endorsed by the Doctrine project. The reasons for this are as follows.
|
||||
|
||||
Traits were added in PHP 5.4 more than 10 years ago, but at the same time
|
||||
more than two years after the initial Doctrine 2 release and the time where
|
||||
core components were designed.
|
||||
|
||||
In fact, this documentation mentions traits only in the context of
|
||||
:doc:`overriding field association mappings in subclasses <tutorials/override-field-association-mappings-in-subclasses>`.
|
||||
Coverage of traits in test cases is practically nonexistent.
|
||||
|
||||
Thus, you should at least be aware that when using traits in your entity and
|
||||
mapped superclasses, you will be in uncharted terrain.
|
||||
|
||||
.. warning::
|
||||
|
||||
There be dragons.
|
||||
|
||||
From a more technical point of view, traits basically work at the language level
|
||||
as if the code contained in them had been copied into the class where the trait
|
||||
is used, and even private fields are accessible by the using class. In addition to
|
||||
that, some precedence and conflict resolution rules apply.
|
||||
|
||||
When it comes to loading mapping configuration, the annotation and attribute drivers
|
||||
rely on PHP reflection to inspect class properties including their docblocks.
|
||||
As long as the results are consistent with what a solution _without_ traits would
|
||||
have produced, this is probably fine.
|
||||
|
||||
However, to mention known limitations, it is currently not possible to use "class"
|
||||
level `annotations <https://github.com/doctrine/orm/pull/1517>` or
|
||||
`attributes <https://github.com/doctrine/orm/issues/8868>` on traits, and attempts to
|
||||
improve parser support for traits as `here <https://github.com/doctrine/annotations/pull/102>`
|
||||
or `there <https://github.com/doctrine/annotations/pull/63>` have been abandoned
|
||||
due to complexity.
|
||||
|
||||
XML mapping configuration probably needs to completely re-configure or otherwise
|
||||
copy-and-paste configuration for fields used from traits.
|
||||
|
||||
Known Issues
|
||||
------------
|
||||
|
||||
|
||||
@@ -3,13 +3,12 @@ Implementing a TypedFieldMapper
|
||||
|
||||
.. versionadded:: 2.14
|
||||
|
||||
You can specify custom typed field mapping between PHP type and DBAL type using ``Configuration``
|
||||
You can specify custom typed field mapping between PHP type and DBAL type using ``Doctrine\ORM\Configuration``
|
||||
and a custom ``Doctrine\ORM\Mapping\TypedFieldMapper`` implementation.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
$configuration->setTypedFieldMapper(new CustomTypedFieldMapper());
|
||||
|
||||
|
||||
@@ -24,6 +23,7 @@ PHP type => DBAL type mappings into its constructor to override the default beha
|
||||
<?php
|
||||
use App\CustomIds\CustomIdObject;
|
||||
use App\DBAL\Type\CustomIdObjectType;
|
||||
use Doctrine\ORM\Mapping\DefaultTypedFieldMapper;
|
||||
|
||||
$configuration->setTypedFieldMapper(new DefaultTypedFieldMapper([
|
||||
CustomIdObject::class => CustomIdObjectType::class,
|
||||
@@ -84,6 +84,7 @@ It is perfectly valid to override even the "automatic" mapping rules mentioned a
|
||||
|
||||
<?php
|
||||
use App\DBAL\Type\CustomIntType;
|
||||
use Doctrine\ORM\Mapping\DefaultTypedFieldMapper;
|
||||
|
||||
$configuration->setTypedFieldMapper(new DefaultTypedFieldMapper([
|
||||
'int' => CustomIntType::class,
|
||||
@@ -126,10 +127,12 @@ the instances were supplied to the ``ChainTypedFieldMapper`` constructor.
|
||||
|
||||
<?php
|
||||
use App\DBAL\Type\CustomIntType;
|
||||
use Doctrine\ORM\Mapping\ChainTypedFieldMapper;
|
||||
use Doctrine\ORM\Mapping\DefaultTypedFieldMapper;
|
||||
|
||||
$configuration->setTypedFieldMapper(
|
||||
new ChainTypedFieldMapper(
|
||||
DefaultTypedFieldMapper(['int' => CustomIntType::class,]),
|
||||
new DefaultTypedFieldMapper(['int' => CustomIntType::class,]),
|
||||
new CustomTypedFieldMapper()
|
||||
)
|
||||
);
|
||||
@@ -173,4 +176,4 @@ You need to create a class which implements ``Doctrine\ORM\Mapping\TypedFieldMap
|
||||
|
||||
Note that this case checks whether the mapping is already assigned, and if yes, it skips it. This is up to your
|
||||
implementation. You can make a "greedy" mapper which will always override the mapping with its own type, or one
|
||||
that behaves like ``DefaultTypedFieldMapper`` and does not modify the type once its set prior in the chain.
|
||||
that behaves like the ``DefaultTypedFieldMapper`` and does not modify the type once its set prior in the chain.
|
||||
@@ -32,9 +32,9 @@ and year of production as primary keys:
|
||||
class Car
|
||||
{
|
||||
public function __construct(
|
||||
#[Id, Column(type: 'string')]
|
||||
#[Id, Column]
|
||||
private string $name,
|
||||
#[Id, Column(type: 'integer')]
|
||||
#[Id, Column]
|
||||
private int $year,
|
||||
) {
|
||||
}
|
||||
@@ -82,27 +82,6 @@ and year of production as primary keys:
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class User
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
private int|null $id = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class Address
|
||||
{
|
||||
/** @Id @OneToOne(targetEntity="User") */
|
||||
private User|null $user = null;
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
@@ -152,7 +131,7 @@ And for querying you can use arrays to both DQL and EntityRepositories:
|
||||
|
||||
$dql = "SELECT c FROM VehicleCatalogue\Model\Car c WHERE c.id = ?1";
|
||||
$audi = $em->createQuery($dql)
|
||||
->setParameter(1, array("name" => "Audi A8", "year" => 2010))
|
||||
->setParameter(1, ["name" => "Audi A8", "year" => 2010])
|
||||
->getSingleResult();
|
||||
|
||||
You can also use this entity in associations. Doctrine will then generate two foreign keys one for ``name``
|
||||
@@ -190,7 +169,52 @@ We keep up the example of an Article with arbitrary attributes, the mapping look
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
.. code-block:: php
|
||||
.. code-block:: attribute
|
||||
|
||||
<?php
|
||||
namespace Application\Model;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
|
||||
#[Entity]
|
||||
class Article
|
||||
{
|
||||
#[Id, Column, GeneratedValue]
|
||||
private int|null $id = null;
|
||||
#[Column]
|
||||
private string $title;
|
||||
|
||||
/** @var ArrayCollection<string, ArticleAttribute> */
|
||||
#[OneToMany(targetEntity: ArticleAttribute::class, mappedBy: 'article', cascade: ['ALL'], indexBy: 'attribute')]
|
||||
private Collection $attributes;
|
||||
|
||||
public function addAttribute(string $name, ArticleAttribute $value): void
|
||||
{
|
||||
$this->attributes[$name] = new ArticleAttribute($name, $value, $this);
|
||||
}
|
||||
}
|
||||
|
||||
#[Entity]
|
||||
class ArticleAttribute
|
||||
{
|
||||
#[Id, ManyToOne(targetEntity: Article::class, inversedBy: 'attributes')]
|
||||
private Article $article;
|
||||
|
||||
#[Id, Column]
|
||||
private string $attribute;
|
||||
|
||||
#[Column]
|
||||
private string $value;
|
||||
|
||||
public function __construct(string $name, string $value, Article $article)
|
||||
{
|
||||
$this->attribute = $name;
|
||||
$this->value = $value;
|
||||
$this->article = $article;
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
namespace Application\Model;
|
||||
@@ -241,51 +265,6 @@ We keep up the example of an Article with arbitrary attributes, the mapping look
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: attribute
|
||||
|
||||
<?php
|
||||
namespace Application\Model;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
|
||||
#[Entity]
|
||||
class Article
|
||||
{
|
||||
#[Id, Column(type: 'integer'), GeneratedValue]
|
||||
private int|null $id = null;
|
||||
#[Column(type: 'string')]
|
||||
private string $title;
|
||||
|
||||
/** @var ArrayCollection<string, ArticleAttribute> */
|
||||
#[OneToMany(targetEntity: ArticleAttribute::class, mappedBy: 'article', cascade: ['ALL'], indexBy: 'attribute')]
|
||||
private Collection $attributes;
|
||||
|
||||
public function addAttribute(string $name, ArticleAttribute $value): void
|
||||
{
|
||||
$this->attributes[$name] = new ArticleAttribute($name, $value, $this);
|
||||
}
|
||||
}
|
||||
|
||||
#[Entity]
|
||||
class ArticleAttribute
|
||||
{
|
||||
#[Id, ManyToOne(targetEntity: Article::class, inversedBy: 'attributes')]
|
||||
private Article $article;
|
||||
|
||||
#[Id, Column(type: 'string')]
|
||||
private string $attribute;
|
||||
|
||||
#[Column(type: 'string')]
|
||||
private string $value;
|
||||
|
||||
public function __construct(string $name, string $value, Article $article)
|
||||
{
|
||||
$this->attribute = $name;
|
||||
$this->value = $value;
|
||||
$this->article = $article;
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
@@ -338,7 +317,7 @@ One good example for this is a user-address relationship:
|
||||
#[Entity]
|
||||
class User
|
||||
{
|
||||
#[Id, Column(type: 'integer'), GeneratedValue]
|
||||
#[Id, Column, GeneratedValue]
|
||||
private int|null $id = null;
|
||||
}
|
||||
|
||||
@@ -386,18 +365,18 @@ of products purchased and maybe even the current price.
|
||||
#[Entity]
|
||||
class Order
|
||||
{
|
||||
#[Id, Column(type: 'integer'), GeneratedValue]
|
||||
#[Id, Column, GeneratedValue]
|
||||
private int|null $id = null;
|
||||
|
||||
/** @var ArrayCollection<int, OrderItem> */
|
||||
#[OneToMany(targetEntity: OrderItem::class, mappedBy: 'order')]
|
||||
private Collection $items;
|
||||
|
||||
#[Column(type: 'boolean')]
|
||||
#[Column]
|
||||
private bool $paid = false;
|
||||
#[Column(type: 'boolean')]
|
||||
#[Column]
|
||||
private bool $shipped = false;
|
||||
#[Column(type: 'datetime')]
|
||||
#[Column]
|
||||
private DateTime $created;
|
||||
|
||||
public function __construct(
|
||||
@@ -412,16 +391,16 @@ of products purchased and maybe even the current price.
|
||||
#[Entity]
|
||||
class Product
|
||||
{
|
||||
#[Id, Column(type: 'integer'), GeneratedValue]
|
||||
#[Id, Column, GeneratedValue]
|
||||
private int|null $id = null;
|
||||
|
||||
#[Column(type: 'string')]
|
||||
#[Column]
|
||||
private string $name;
|
||||
|
||||
#[Column(type: 'decimal')]
|
||||
private float $currentPrice;
|
||||
#[Column]
|
||||
private int $currentPrice;
|
||||
|
||||
public function getCurrentPrice(): float
|
||||
public function getCurrentPrice(): int
|
||||
{
|
||||
return $this->currentPrice;
|
||||
}
|
||||
@@ -436,11 +415,11 @@ of products purchased and maybe even the current price.
|
||||
#[Id, ManyToOne(targetEntity: Product::class)]
|
||||
private Product|null $product = null;
|
||||
|
||||
#[Column(type: 'integer')]
|
||||
#[Column]
|
||||
private int $amount = 1;
|
||||
|
||||
#[Column(type: 'decimal')]
|
||||
private float $offeredPrice;
|
||||
#[Column]
|
||||
private int $offeredPrice;
|
||||
|
||||
public function __construct(Order $order, Product $product, int $amount = 1)
|
||||
{
|
||||
|
||||
@@ -1321,9 +1321,11 @@ abstract class AbstractQuery
|
||||
protected function getHydrationCacheId()
|
||||
{
|
||||
$parameters = [];
|
||||
$types = [];
|
||||
|
||||
foreach ($this->getParameters() as $parameter) {
|
||||
$parameters[$parameter->getName()] = $this->processParameterValue($parameter->getValue());
|
||||
$types[$parameter->getName()] = $parameter->getType();
|
||||
}
|
||||
|
||||
$sql = $this->getSQL();
|
||||
@@ -1335,7 +1337,7 @@ abstract class AbstractQuery
|
||||
ksort($hints);
|
||||
assert($queryCacheProfile !== null);
|
||||
|
||||
return $queryCacheProfile->generateCacheKeys($sql, $parameters, $hints);
|
||||
return $queryCacheProfile->generateCacheKeys($sql, $parameters, $types, $hints);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -73,7 +73,7 @@ final class Events
|
||||
* has been applied to it.
|
||||
*
|
||||
* Note that the postLoad event occurs for an entity before any associations have been
|
||||
* initialized. Therefore it is not safe to access associations in a postLoad callback
|
||||
* initialized. Therefore, it is not safe to access associations in a postLoad callback
|
||||
* or event handler.
|
||||
*
|
||||
* This is an entity lifecycle event.
|
||||
|
||||
@@ -698,7 +698,7 @@ abstract class AbstractHydrator
|
||||
*
|
||||
* @return BackedEnum|array<BackedEnum>
|
||||
*/
|
||||
private function buildEnum($value, string $enumType)
|
||||
final protected function buildEnum($value, string $enumType)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
return array_map(static function ($value) use ($enumType): BackedEnum {
|
||||
|
||||
@@ -6,9 +6,11 @@ namespace Doctrine\ORM\Internal\Hydration;
|
||||
|
||||
use Doctrine\ORM\Internal\SQLResultCasing;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Mapping\MappingException;
|
||||
use Doctrine\ORM\Query;
|
||||
use Exception;
|
||||
use RuntimeException;
|
||||
use ValueError;
|
||||
|
||||
use function array_keys;
|
||||
use function array_search;
|
||||
@@ -140,6 +142,21 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
$value = $type->convertToPHPValue($value, $this->_platform);
|
||||
}
|
||||
|
||||
if ($value !== null && isset($cacheKeyInfo['enumType'])) {
|
||||
$originalValue = $value;
|
||||
try {
|
||||
$value = $this->buildEnum($originalValue, $cacheKeyInfo['enumType']);
|
||||
} catch (ValueError $e) {
|
||||
throw MappingException::invalidEnumValue(
|
||||
$entityName,
|
||||
$cacheKeyInfo['fieldName'],
|
||||
(string) $originalValue,
|
||||
$cacheKeyInfo['enumType'],
|
||||
$e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$fieldName = $cacheKeyInfo['fieldName'];
|
||||
|
||||
// Prevent overwrite in case of inherit classes using same property name (See AbstractHydrator)
|
||||
@@ -148,6 +165,10 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->_hints[Query::HINT_REFRESH_ENTITY])) {
|
||||
$this->registerManaged($this->class, $this->_hints[Query::HINT_REFRESH_ENTITY], $data);
|
||||
}
|
||||
|
||||
$uow = $this->_em->getUnitOfWork();
|
||||
$entity = $uow->createEntity($entityName, $data, $this->_hints);
|
||||
|
||||
|
||||
@@ -392,7 +392,6 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
$mapping['sourceEntity'] = $subClass->name;
|
||||
}
|
||||
|
||||
//$subclassMapping = $mapping;
|
||||
if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
|
||||
$mapping['inherited'] = $parentClass->name;
|
||||
}
|
||||
|
||||
@@ -406,6 +406,22 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
/**
|
||||
* READ-ONLY: The names of all embedded classes based on properties.
|
||||
*
|
||||
* The value (definition) array may contain, among others, the following values:
|
||||
*
|
||||
* - <b>'inherited'</b> (string, optional)
|
||||
* This is set when this embedded-class field is inherited by this class from another (inheritance) parent
|
||||
* <em>entity</em> class. The value is the FQCN of the topmost entity class that contains
|
||||
* mapping information for this field. (If there are transient classes in the
|
||||
* class hierarchy, these are ignored, so the class property may in fact come
|
||||
* from a class further up in the PHP class hierarchy.)
|
||||
* Fields initially declared in mapped superclasses are
|
||||
* <em>not</em> considered 'inherited' in the nearest entity subclasses.
|
||||
*
|
||||
* - <b>'declared'</b> (string, optional)
|
||||
* This is set when the embedded-class field does not appear for the first time in this class, but is originally
|
||||
* declared in another parent <em>entity or mapped superclass</em>. The value is the FQCN
|
||||
* of the topmost non-transient class that contains mapping information for this field.
|
||||
*
|
||||
* @psalm-var array<string, mixed[]>
|
||||
*/
|
||||
public $embeddedClasses = [];
|
||||
@@ -523,6 +539,20 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* - <b>'unique'</b> (string, optional, schema-only)
|
||||
* Whether a unique constraint should be generated for the column.
|
||||
*
|
||||
* - <b>'inherited'</b> (string, optional)
|
||||
* This is set when the field is inherited by this class from another (inheritance) parent
|
||||
* <em>entity</em> class. The value is the FQCN of the topmost entity class that contains
|
||||
* mapping information for this field. (If there are transient classes in the
|
||||
* class hierarchy, these are ignored, so the class property may in fact come
|
||||
* from a class further up in the PHP class hierarchy.)
|
||||
* Fields initially declared in mapped superclasses are
|
||||
* <em>not</em> considered 'inherited' in the nearest entity subclasses.
|
||||
*
|
||||
* - <b>'declared'</b> (string, optional)
|
||||
* This is set when the field does not appear for the first time in this class, but is originally
|
||||
* declared in another parent <em>entity or mapped superclass</em>. The value is the FQCN
|
||||
* of the topmost non-transient class that contains mapping information for this field.
|
||||
*
|
||||
* @var mixed[]
|
||||
* @psalm-var array<string, FieldMapping>
|
||||
*/
|
||||
@@ -625,6 +655,11 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* - <b>fieldName</b> (string)
|
||||
* The name of the field in the entity the association is mapped to.
|
||||
*
|
||||
* - <b>sourceEntity</b> (string)
|
||||
* The class name of the source entity. In the case of to-many associations initially
|
||||
* present in mapped superclasses, the nearest <em>entity</em> subclasses will be
|
||||
* considered the respective source entities.
|
||||
*
|
||||
* - <b>targetEntity</b> (string)
|
||||
* The class name of the target entity. If it is fully-qualified it is used as is.
|
||||
* If it is a simple, unqualified class name the namespace is assumed to be the same
|
||||
@@ -661,6 +696,20 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* This field HAS to be either the primary key or a unique column. Otherwise the collection
|
||||
* does not contain all the entities that are actually related.
|
||||
*
|
||||
* - <b>'inherited'</b> (string, optional)
|
||||
* This is set when the association is inherited by this class from another (inheritance) parent
|
||||
* <em>entity</em> class. The value is the FQCN of the topmost entity class that contains
|
||||
* this association. (If there are transient classes in the
|
||||
* class hierarchy, these are ignored, so the class property may in fact come
|
||||
* from a class further up in the PHP class hierarchy.)
|
||||
* To-many associations initially declared in mapped superclasses are
|
||||
* <em>not</em> considered 'inherited' in the nearest entity subclasses.
|
||||
*
|
||||
* - <b>'declared'</b> (string, optional)
|
||||
* This is set when the association does not appear in the current class for the first time, but
|
||||
* is initially declared in another parent <em>entity or mapped superclass</em>. The value is the FQCN
|
||||
* of the topmost non-transient class that contains association information for this relationship.
|
||||
*
|
||||
* A join table definition has the following structure:
|
||||
* <pre>
|
||||
* array(
|
||||
|
||||
@@ -696,8 +696,8 @@ class AnnotationDriver extends CompatibilityAnnotationDriver
|
||||
/**
|
||||
* Parses the given method.
|
||||
*
|
||||
* @return callable[]
|
||||
* @psalm-return list<callable-array>
|
||||
* @return list<array{string, string}>
|
||||
* @psalm-return list<array{string, (Events::*)}>
|
||||
*/
|
||||
private function getMethodCallbacks(ReflectionMethod $method): array
|
||||
{
|
||||
|
||||
@@ -615,7 +615,8 @@ class AttributeDriver extends CompatibilityAnnotationDriver
|
||||
/**
|
||||
* Parses the given method.
|
||||
*
|
||||
* @return callable[]
|
||||
* @return list<array{string, string}>
|
||||
* @psalm-return list<array{string, (Events::*)}>
|
||||
*/
|
||||
private function getMethodCallbacks(ReflectionMethod $method): array
|
||||
{
|
||||
|
||||
@@ -13,12 +13,12 @@ use Doctrine\ORM\Exception\ORMException;
|
||||
*/
|
||||
class OptimisticLockException extends ORMException
|
||||
{
|
||||
/** @var object|null */
|
||||
/** @var object|string|null */
|
||||
private $entity;
|
||||
|
||||
/**
|
||||
* @param string $msg
|
||||
* @param object|null $entity
|
||||
* @param string $msg
|
||||
* @param object|string|null $entity
|
||||
*/
|
||||
public function __construct($msg, $entity)
|
||||
{
|
||||
@@ -30,7 +30,7 @@ class OptimisticLockException extends ORMException
|
||||
/**
|
||||
* Gets the entity that caused the exception.
|
||||
*
|
||||
* @return object|null
|
||||
* @return object|string|null
|
||||
*/
|
||||
public function getEntity()
|
||||
{
|
||||
@@ -38,7 +38,7 @@ class OptimisticLockException extends ORMException
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $entity
|
||||
* @param object|class-string $entity
|
||||
*
|
||||
* @return OptimisticLockException
|
||||
*/
|
||||
@@ -48,9 +48,9 @@ class OptimisticLockException extends ORMException
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $entity
|
||||
* @param int|DateTimeInterface $expectedLockVersion
|
||||
* @param int|DateTimeInterface $actualLockVersion
|
||||
* @param object $entity
|
||||
* @param int|string|DateTimeInterface $expectedLockVersion
|
||||
* @param int|string|DateTimeInterface $actualLockVersion
|
||||
*
|
||||
* @return OptimisticLockException
|
||||
*/
|
||||
|
||||
@@ -487,7 +487,7 @@ class BasicEntityPersister implements EntityPersister
|
||||
$targetType = PersisterHelper::getTypeOfField($targetMapping->identifier[0], $targetMapping, $this->em);
|
||||
|
||||
if ($targetType === []) {
|
||||
throw UnrecognizedField::byName($targetMapping->identifier[0]);
|
||||
throw UnrecognizedField::byFullyQualifiedName($this->class->name, $targetMapping->identifier[0]);
|
||||
}
|
||||
|
||||
$types[] = reset($targetType);
|
||||
@@ -1199,7 +1199,7 @@ class BasicEntityPersister implements EntityPersister
|
||||
continue;
|
||||
}
|
||||
|
||||
throw UnrecognizedField::byName($fieldName);
|
||||
throw UnrecognizedField::byFullyQualifiedName($this->class->name, $fieldName);
|
||||
}
|
||||
|
||||
return ' ORDER BY ' . implode(', ', $orderByList);
|
||||
@@ -1506,6 +1506,9 @@ class BasicEntityPersister implements EntityPersister
|
||||
$columnAlias = $this->getSQLColumnAlias($fieldMapping['columnName']);
|
||||
|
||||
$this->currentPersisterContext->rsm->addFieldResult($alias, $columnAlias, $field);
|
||||
if (! empty($fieldMapping['enumType'])) {
|
||||
$this->currentPersisterContext->rsm->addEnumResult($columnAlias, $fieldMapping['enumType']);
|
||||
}
|
||||
|
||||
if (isset($fieldMapping['requireSQLConversion'])) {
|
||||
$type = Type::getType($fieldMapping['type']);
|
||||
@@ -1754,7 +1757,7 @@ class BasicEntityPersister implements EntityPersister
|
||||
return [$field];
|
||||
}
|
||||
|
||||
throw UnrecognizedField::byName($field);
|
||||
throw UnrecognizedField::byFullyQualifiedName($this->class->name, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,8 +10,15 @@ use function sprintf;
|
||||
|
||||
final class UnrecognizedField extends PersisterException
|
||||
{
|
||||
/** @deprecated Use {@see byFullyQualifiedName()} instead. */
|
||||
public static function byName(string $field): self
|
||||
{
|
||||
return new self(sprintf('Unrecognized field: %s', $field));
|
||||
}
|
||||
|
||||
/** @param class-string $className */
|
||||
public static function byFullyQualifiedName(string $className, string $field): self
|
||||
{
|
||||
return new self(sprintf('Unrecognized field: %s::$%s', $className, $field));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ use Doctrine\ORM\UnitOfWork;
|
||||
use Doctrine\ORM\Utility\IdentifierFlattener;
|
||||
use Doctrine\Persistence\Mapping\ClassMetadata;
|
||||
use Doctrine\Persistence\Proxy;
|
||||
use ReflectionProperty;
|
||||
use Symfony\Component\VarExporter\ProxyHelper;
|
||||
use Symfony\Component\VarExporter\VarExporter;
|
||||
|
||||
@@ -313,17 +314,24 @@ EOPHP;
|
||||
{
|
||||
$skippedProperties = ['__isCloning' => true];
|
||||
$identifiers = array_flip($class->getIdentifierFieldNames());
|
||||
$filter = ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED | ReflectionProperty::IS_PRIVATE;
|
||||
$reflector = $class->getReflectionClass();
|
||||
|
||||
foreach ($class->getReflectionClass()->getProperties() as $property) {
|
||||
$name = $property->getName();
|
||||
while ($reflector) {
|
||||
foreach ($reflector->getProperties($filter) as $property) {
|
||||
$name = $property->getName();
|
||||
|
||||
if ($property->isStatic() || (($class->hasField($name) || $class->hasAssociation($name)) && ! isset($identifiers[$name]))) {
|
||||
continue;
|
||||
if ($property->isStatic() || (($class->hasField($name) || $class->hasAssociation($name)) && ! isset($identifiers[$name]))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$prefix = $property->isPrivate() ? "\0" . $property->getDeclaringClass()->getName() . "\0" : ($property->isProtected() ? "\0*\0" : '');
|
||||
|
||||
$skippedProperties[$prefix . $name] = true;
|
||||
}
|
||||
|
||||
$prefix = $property->isPrivate() ? "\0" . $property->getDeclaringClass()->getName() . "\0" : ($property->isProtected() ? "\0*\0" : '');
|
||||
|
||||
$skippedProperties[$prefix . $name] = true;
|
||||
$filter = ReflectionProperty::IS_PRIVATE;
|
||||
$reflector = $reflector->getParentClass();
|
||||
}
|
||||
|
||||
uksort($skippedProperties, 'strnatcmp');
|
||||
|
||||
+5
-85
@@ -270,11 +270,6 @@ parameters:
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Persisters/Entity/CachedPersisterContext.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property Doctrine\\\\Persistence\\\\Proxy::\\$__isCloning\\.$#"
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\:\\:\\$isEmbeddedClass\\.$#"
|
||||
count: 1
|
||||
@@ -285,6 +280,11 @@ parameters:
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property Doctrine\\\\Persistence\\\\Proxy\\:\\:\\$__isCloning\\.$#"
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method Doctrine\\\\Common\\\\Proxy\\\\Proxy\\:\\:__wakeup\\(\\)\\.$#"
|
||||
count: 1
|
||||
@@ -305,81 +305,11 @@ parameters:
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$days of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateAddDaysExpression\\(\\) expects int\\|numeric\\-string, string given\\.$#"
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$hours of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateAddHourExpression\\(\\) expects int\\|numeric\\-string, string given\\.$#"
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$minutes of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateAddMinutesExpression\\(\\) expects int\\|numeric\\-string, string given\\.$#"
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$months of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateAddMonthExpression\\(\\) expects int\\|numeric\\-string, string given\\.$#"
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$seconds of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateAddSecondsExpression\\(\\) expects int\\|numeric\\-string, string given\\.$#"
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$weeks of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateAddWeeksExpression\\(\\) expects int\\|numeric\\-string, string given\\.$#"
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$years of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateAddYearsExpression\\(\\) expects int\\|numeric\\-string, string given\\.$#"
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property Doctrine\\\\ORM\\\\Query\\\\AST\\\\Node\\:\\:\\$value\\.$#"
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$days of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateSubDaysExpression\\(\\) expects int\\|numeric\\-string, string given\\.$#"
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$hours of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateSubHourExpression\\(\\) expects int\\|numeric\\-string, string given\\.$#"
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$minutes of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateSubMinutesExpression\\(\\) expects int\\|numeric\\-string, string given\\.$#"
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$months of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateSubMonthExpression\\(\\) expects int\\|numeric\\-string, string given\\.$#"
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$seconds of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateSubSecondsExpression\\(\\) expects int\\|numeric\\-string, string given\\.$#"
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$weeks of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateSubWeeksExpression\\(\\) expects int\\|numeric\\-string, string given\\.$#"
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$years of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getDateSubYearsExpression\\(\\) expects int\\|numeric\\-string, string given\\.$#"
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$simpleArithmeticExpr of method Doctrine\\\\ORM\\\\Query\\\\SqlWalker\\:\\:walkSimpleArithmeticExpression\\(\\) expects Doctrine\\\\ORM\\\\Query\\\\AST\\\\SimpleArithmeticExpression, Doctrine\\\\ORM\\\\Query\\\\AST\\\\Node given\\.$#"
|
||||
count: 1
|
||||
@@ -510,11 +440,6 @@ parameters:
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Query/SqlWalker.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$entity of static method Doctrine\\\\ORM\\\\OptimisticLockException\\:\\:lockFailed\\(\\) expects object, class\\-string\\<object\\> given\\.$#"
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Query/SqlWalker.php
|
||||
|
||||
-
|
||||
message: "#^Result of && is always false\\.$#"
|
||||
count: 1
|
||||
@@ -705,11 +630,6 @@ parameters:
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/UnitOfWork.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#3 \\$collection of class Doctrine\\\\ORM\\\\PersistentCollection constructor expects Doctrine\\\\Common\\\\Collections\\\\Collection\\<\\(int\\|string\\), mixed\\>&Doctrine\\\\Common\\\\Collections\\\\Selectable\\<\\(int\\|string\\), mixed\\>, Doctrine\\\\Common\\\\Collections\\\\Collection given\\.$#"
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/UnitOfWork.php
|
||||
|
||||
-
|
||||
message: "#^Access to an undefined property Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\:\\:\\$name\\.$#"
|
||||
count: 1
|
||||
|
||||
@@ -41,8 +41,3 @@ parameters:
|
||||
|
||||
# Symfony cache supports passing a key prefix to the clear method.
|
||||
- '/^Method Psr\\Cache\\CacheItemPoolInterface\:\:clear\(\) invoked with 1 parameter, 0 required\.$/'
|
||||
|
||||
# Cache 1 compatibility
|
||||
-
|
||||
message: '~^Parameter #2 \$cache of class Doctrine\\Common\\Annotations\\CachedReader constructor expects Doctrine\\Common\\Cache\\Cache, Doctrine\\Common\\Cache\\ArrayCache given\.~'
|
||||
path: lib/Doctrine/ORM/Configuration.php
|
||||
|
||||
+5
-28
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<files psalm-version="5.3.0@b6faa3e96b8eb50ec71384c53799b8a107236bb6">
|
||||
<files psalm-version="5.4.0@62db5d4f6a7ae0a20f7cc5a4952d730272fc0863">
|
||||
<file src="lib/Doctrine/ORM/AbstractQuery.php">
|
||||
<DeprecatedClass occurrences="1">
|
||||
<code>IterableResult</code>
|
||||
@@ -19,17 +19,11 @@
|
||||
<InvalidNullableReturnType occurrences="1">
|
||||
<code>\Doctrine\Common\Cache\Cache</code>
|
||||
</InvalidNullableReturnType>
|
||||
<LessSpecificReturnStatement occurrences="1">
|
||||
<code>$queryCacheProfile->generateCacheKeys($sql, $parameters, $hints)</code>
|
||||
</LessSpecificReturnStatement>
|
||||
<MissingClosureParamType occurrences="3">
|
||||
<code>$alias</code>
|
||||
<code>$data</code>
|
||||
<code>$data</code>
|
||||
</MissingClosureParamType>
|
||||
<MoreSpecificReturnType occurrences="1">
|
||||
<code>array{string, string}</code>
|
||||
</MoreSpecificReturnType>
|
||||
<NullableReturnStatement occurrences="2">
|
||||
<code>$this->_em->getConfiguration()->getResultCacheImpl()</code>
|
||||
<code>$this->_queryCacheProfile->getResultCacheDriver()</code>
|
||||
@@ -244,10 +238,6 @@
|
||||
<ArgumentTypeCoercion occurrences="1">
|
||||
<code>$className</code>
|
||||
</ArgumentTypeCoercion>
|
||||
<DeprecatedClass occurrences="2">
|
||||
<code>new CachedReader($reader, new ArrayCache())</code>
|
||||
<code>new SimpleAnnotationReader()</code>
|
||||
</DeprecatedClass>
|
||||
<DeprecatedMethod occurrences="2">
|
||||
<code>getMetadataCacheImpl</code>
|
||||
<code>getQueryCacheImpl</code>
|
||||
@@ -809,12 +799,6 @@
|
||||
</file>
|
||||
<file src="lib/Doctrine/ORM/Mapping/Driver/AttributeDriver.php">
|
||||
<InvalidArgument occurrences="2"/>
|
||||
<InvalidArrayAccess occurrences="4">
|
||||
<code>$value[0]</code>
|
||||
<code>$value[0]</code>
|
||||
<code>$value[1]</code>
|
||||
<code>$value[1]</code>
|
||||
</InvalidArrayAccess>
|
||||
<LessSpecificReturnStatement occurrences="1">
|
||||
<code>$mapping</code>
|
||||
</LessSpecificReturnStatement>
|
||||
@@ -1110,9 +1094,10 @@
|
||||
</PossiblyInvalidArgument>
|
||||
</file>
|
||||
<file src="lib/Doctrine/ORM/PersistentCollection.php">
|
||||
<ImplementedReturnTypeMismatch occurrences="2">
|
||||
<ImplementedReturnTypeMismatch occurrences="3">
|
||||
<code>Collection<TKey, T></code>
|
||||
<code>object|null</code>
|
||||
<code>object|null</code>
|
||||
</ImplementedReturnTypeMismatch>
|
||||
<InvalidReturnStatement occurrences="2">
|
||||
<code>$this->em->find($this->typeClass->name, $key)</code>
|
||||
@@ -2231,12 +2216,11 @@
|
||||
<ImplicitToStringCast occurrences="1">
|
||||
<code>$expr</code>
|
||||
</ImplicitToStringCast>
|
||||
<InvalidArgument occurrences="5">
|
||||
<InvalidArgument occurrences="4">
|
||||
<code>$assoc</code>
|
||||
<code>$condExpr</code>
|
||||
<code>$condTerm</code>
|
||||
<code>$factor</code>
|
||||
<code>$selectedClass['class']->name</code>
|
||||
</InvalidArgument>
|
||||
<InvalidNullableReturnType occurrences="1">
|
||||
<code>string</code>
|
||||
@@ -2626,17 +2610,13 @@
|
||||
<PossiblyNullArgument occurrences="1">
|
||||
<code>$variableType</code>
|
||||
</PossiblyNullArgument>
|
||||
<PossiblyNullReference occurrences="1">
|
||||
<code>getTraits</code>
|
||||
</PossiblyNullReference>
|
||||
<PropertyNotSetInConstructor occurrences="1">
|
||||
<code>$classToExtend</code>
|
||||
</PropertyNotSetInConstructor>
|
||||
<RedundantCastGivenDocblockType occurrences="1">
|
||||
<code>(bool) $embeddablesImmutable</code>
|
||||
</RedundantCastGivenDocblockType>
|
||||
<RedundantConditionGivenDocblockType occurrences="2">
|
||||
<code>$reflClass !== false</code>
|
||||
<RedundantConditionGivenDocblockType occurrences="1">
|
||||
<code>isset($metadata->lifecycleCallbacks)</code>
|
||||
</RedundantConditionGivenDocblockType>
|
||||
</file>
|
||||
@@ -2899,9 +2879,6 @@
|
||||
<code>$collectionToUpdate</code>
|
||||
<code>$em->getMetadataFactory()</code>
|
||||
</InvalidArgument>
|
||||
<InvalidArrayOffset occurrences="1">
|
||||
<code>$commitOrder[$i]</code>
|
||||
</InvalidArrayOffset>
|
||||
<InvalidNullableReturnType occurrences="1">
|
||||
<code>object</code>
|
||||
</InvalidNullableReturnType>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\Models\GH10336;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="gh10336_entities")
|
||||
*/
|
||||
class GH10336Entity
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue
|
||||
*/
|
||||
public ?int $id = null;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="GH10336Relation")
|
||||
* @ORM\JoinColumn(name="relation_id", referencedColumnName="id", nullable=true)
|
||||
*/
|
||||
public ?GH10336Relation $relation = null;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\Models\GH10336;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="gh10336_relations")
|
||||
*/
|
||||
class GH10336Relation
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue
|
||||
*/
|
||||
public ?int $id = null;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string")
|
||||
*/
|
||||
public string $value;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Tests\Models\GH10336\GH10336Entity;
|
||||
use Doctrine\Tests\Models\GH10336\GH10336Relation;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
/**
|
||||
* @requires PHP 7.4
|
||||
*/
|
||||
final class GH10336Test extends OrmFunctionalTestCase
|
||||
{
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->createSchemaForModels(
|
||||
GH10336Entity::class,
|
||||
GH10336Relation::class
|
||||
);
|
||||
}
|
||||
|
||||
public function testCanAccessRelationPropertyAfterClear(): void
|
||||
{
|
||||
$relation = new GH10336Relation();
|
||||
$relation->value = 'foo';
|
||||
$entity = new GH10336Entity();
|
||||
$entity->relation = $relation;
|
||||
|
||||
$this->_em->persist($entity);
|
||||
$this->_em->persist($relation);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$entity = $this->_em->find(GH10336Entity::class, 1);
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$this->assertSame('foo', $entity->relation->value);
|
||||
}
|
||||
}
|
||||
@@ -18,12 +18,12 @@ final class GH6682Test extends OrmFunctionalTestCase
|
||||
'initialValue' => '',
|
||||
];
|
||||
|
||||
$classMetadataInfo = new ClassMetadata('test_entity');
|
||||
$classMetadataInfo->setSequenceGeneratorDefinition($parsedDefinition);
|
||||
$classMetadata = new ClassMetadata('test_entity');
|
||||
$classMetadata->setSequenceGeneratorDefinition($parsedDefinition);
|
||||
|
||||
self::assertSame(
|
||||
['sequenceName' => 'test_sequence', 'allocationSize' => '1', 'initialValue' => '1'],
|
||||
$classMetadataInfo->sequenceGeneratorDefinition
|
||||
$classMetadata->sequenceGeneratorDefinition
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Persisters\Exception;
|
||||
|
||||
use Doctrine\ORM\Persisters\Exception\UnrecognizedField;
|
||||
use Doctrine\Tests\Models\Taxi\Car;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class UnrecognizedFieldTest extends TestCase
|
||||
{
|
||||
public function testByFullyQualifiedName(): void
|
||||
{
|
||||
static::expectException(UnrecognizedField::class);
|
||||
static::expectExceptionMessage('Unrecognized field: Doctrine\Tests\Models\Taxi\Car::$color');
|
||||
|
||||
throw UnrecognizedField::byFullyQualifiedName(Car::class, 'color');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user