Compare commits

...

16 Commits
2.9.0 ... 2.9.2

Author SHA1 Message Date
Yup
75b4b88c5b Add automatic type detection for Embedded. (#8724)
* Add automatic type detection for Embedded.

* Inline statement.

Co-authored-by: Benjamin Eberlei <kontakt@beberlei.de>
2021-05-31 11:53:14 +02:00
Benjamin Eberlei
d9e59d6862 [GH-8723] Remove use of nullability to automatically detect nullable status (#8732)
* [GH-8723] Remove use of nullability to automatically detect nullable status.

* [GH-8723] Make Column::$nullable default to false again, fix tests.
2021-05-31 10:19:16 +02:00
Yup
5fa94969de Adapt flush($argument) in documentation as it's deprecated. (#8728) 2021-05-29 22:22:19 +02:00
Juan Iglesias
f2c3ddac97 Add note about performance and inheritance mapping (#8704)
Co-authored-by: Claudio Zizza <859964+SenseException@users.noreply.github.com>
2021-05-27 08:27:55 +02:00
Grégoire Paris
46f0da9ffa Merge pull request #8710 from franmomu/recompute
Handle generic parameters in UnitOfWork
2021-05-25 13:29:21 +02:00
Fran Moreno
1e832a6782 Add generics to parameters 2021-05-25 13:01:47 +02:00
Grégoire Paris
56bdb44efd Merge pull request #8722 from alcaeus/fix-metadata-cache-clear 2021-05-25 12:55:00 +02:00
Andreas Braun
fffac44991 Bump doctrine/cache patch dependency to fix build with lowest deps 2021-05-25 11:58:11 +02:00
Andreas Braun
e42b3d6584 Fix metadata cache compatibility layer 2021-05-25 10:38:00 +02:00
Grégoire Paris
7ab2c3abbd Merge pull request #8708 from VincentLanglet/patch-2
Fix ClassMetadaInfo template inference
2021-05-25 08:49:50 +02:00
Grégoire Paris
498c816b65 Merge pull request #8717 from greg0ire/update-branch-metadata
Mark 2.8.x as unmaintained, and 2.9.x as current
2021-05-25 00:01:21 +02:00
Vincent Langlet
eec740079d Fix ClassMetadataInfo template inference 2021-05-24 21:52:40 +02:00
Grégoire Paris
c359715a97 Mark 2.8.x as unmaintained, and 2.9.x as current 2021-05-24 21:32:26 +02:00
Benjamin Eberlei
f3e55fae9f Update .doctrine-project.json to include 2.9 stable and 2.10 upcoming 2021-05-24 17:54:12 +02:00
Michael Babker
91c3bd4121 Fix links to attribute sections (#8714) 2021-05-24 17:52:30 +02:00
Peter Gribanov
e6cf12c66f remove usage Webmozart (#8713) 2021-05-24 17:50:15 +02:00
29 changed files with 199 additions and 163 deletions

View File

@@ -12,21 +12,27 @@
"upcoming": true
},
{
"name": "2.9",
"branchName": "2.9.x",
"slug": "2.9",
"name": "2.10",
"branchName": "2.10.x",
"slug": "2.10",
"upcoming": true
},
{
"name": "2.8",
"branchName": "2.8.x",
"slug": "2.8",
"name": "2.9",
"branchName": "2.9.x",
"slug": "2.9",
"current": true,
"aliases": [
"current",
"stable"
]
},
{
"name": "2.8",
"branchName": "2.8.x",
"slug": "2.8",
"maintained": false
},
{
"name": "2.7",
"branchName": "2.7",

View File

@@ -20,7 +20,7 @@
"ext-pdo": "*",
"composer/package-versions-deprecated": "^1.8",
"doctrine/annotations": "^1.13",
"doctrine/cache": "^1.11|^2.0",
"doctrine/cache": "^1.11.3|^2.0.3",
"doctrine/collections": "^1.5",
"doctrine/common": "^3.0.3",
"doctrine/dbal": "^2.13.0",

View File

@@ -10,7 +10,7 @@ code should look like. We will implement it on a
`Layer Supertype <http://martinfowler.com/eaaCatalog/layerSupertype.html>`_
for all our domain objects.
.. warning::
.. note::
The notify change tracking policy is deprecated and will be removed in ORM 3.0.
(`Details <https://github.com/doctrine/orm/issues/8383>`_)

View File

@@ -113,7 +113,7 @@ Optional attributes:
- **unique**: Boolean value to determine if the value of the column
should be unique across all rows of the underlying entities table.
- **nullable**: Determines if NULL values allowed for this column. If not specified, default value is false. When using typed properties on entity class defaults to true when property is nullable.
- **nullable**: Determines if NULL values allowed for this column. If not specified, default value is false.
- **options**: Array of additional options:
@@ -350,7 +350,7 @@ in order to specify that it is an embedded class.
Required attributes:
- **class**: The embeddable class
- **class**: The embeddable class. You can omit this value if you use a PHP property type instead.
.. code-block:: php
@@ -649,8 +649,6 @@ Optional attributes:
constraint level. Defaults to false.
- **nullable**: Determine whether the related entity is required, or if
null is an allowed state for the relation. Defaults to true.
When using typed properties on entity class defaults to false when
property is not nullable.
- **onDelete**: Cascade Action (Database-level)
- **columnDefinition**: DDL SQL snippet that starts after the column
name and specifies the complete (non-portable!) column definition.

View File

@@ -10,46 +10,46 @@ annotation metadata supported since the first version 2.0.
Index
-----
- :ref:`#[Column] <annref_column>`
- :ref:`#[Cache] <annref_cache>`
- :ref:`#[ChangeTrackingPolicy <annref_changetrackingpolicy>`
- :ref:`#[CustomIdGenerator] <annref_customidgenerator>`
- :ref:`#[DiscriminatorColumn] <annref_discriminatorcolumn>`
- :ref:`#[DiscriminatorMap] <annref_discriminatormap>`
- :ref:`#[Embeddable] <annref_embeddable>`
- :ref:`#[Embedded] <annref_embedded>`
- :ref:`#[Entity] <annref_entity>`
- :ref:`#[GeneratedValue] <annref_generatedvalue>`
- :ref:`#[HasLifecycleCallbacks] <annref_haslifecyclecallbacks>`
- :ref:`#[Index] <annref_index>`
- :ref:`#[Id] <annref_id>`
- :ref:`#[InheritanceType] <annref_inheritancetype>`
- :ref:`#[JoinColumn] <annref_joincolumn>`
- :ref:`#[JoinColumns] <annref_joincolumns>`
- :ref:`#[JoinTable] <annref_jointable>`
- :ref:`#[ManyToOne] <annref_manytoone>`
- :ref:`#[ManyToMany] <annref_manytomany>`
- :ref:`#[MappedSuperclass] <annref_mappedsuperclass>`
- :ref:`#[OneToOne] <annref_onetoone>`
- :ref:`#[OneToMany] <annref_onetomany>`
- :ref:`#[OrderBy] <annref_orderby>`
- :ref:`#[PostLoad] <annref_postload>`
- :ref:`#[PostPersist] <annref_postpersist>`
- :ref:`#[PostRemove] <annref_postremove>`
- :ref:`#[PostUpdate] <annref_postupdate>`
- :ref:`#[PrePersist] <annref_prepersist>`
- :ref:`#[PreRemove] <annref_preremove>`
- :ref:`#[PreUpdate] <annref_preupdate>`
- :ref:`#[SequenceGenerator] <annref_sequencegenerator>`
- :ref:`#[Table] <annref_table>`
- :ref:`#[UniqueConstraint] <annref_uniqueconstraint>`
- :ref:`#[Version] <annref_version>`
- :ref:`#[Column] <attrref_column>`
- :ref:`#[Cache] <attrref_cache>`
- :ref:`#[ChangeTrackingPolicy <attrref_changetrackingpolicy>`
- :ref:`#[CustomIdGenerator] <attrref_customidgenerator>`
- :ref:`#[DiscriminatorColumn] <attrref_discriminatorcolumn>`
- :ref:`#[DiscriminatorMap] <attrref_discriminatormap>`
- :ref:`#[Embeddable] <attrref_embeddable>`
- :ref:`#[Embedded] <attrref_embedded>`
- :ref:`#[Entity] <attrref_entity>`
- :ref:`#[GeneratedValue] <attrref_generatedvalue>`
- :ref:`#[HasLifecycleCallbacks] <attrref_haslifecyclecallbacks>`
- :ref:`#[Index] <attrref_index>`
- :ref:`#[Id] <attrref_id>`
- :ref:`#[InheritanceType] <attrref_inheritancetype>`
- :ref:`#[JoinColumn] <attrref_joincolumn>`
- :ref:`#[JoinColumns] <attrref_joincolumns>`
- :ref:`#[JoinTable] <attrref_jointable>`
- :ref:`#[ManyToOne] <attrref_manytoone>`
- :ref:`#[ManyToMany] <attrref_manytomany>`
- :ref:`#[MappedSuperclass] <attrref_mappedsuperclass>`
- :ref:`#[OneToOne] <attrref_onetoone>`
- :ref:`#[OneToMany] <attrref_onetomany>`
- :ref:`#[OrderBy] <attrref_orderby>`
- :ref:`#[PostLoad] <attrref_postload>`
- :ref:`#[PostPersist] <attrref_postpersist>`
- :ref:`#[PostRemove] <attrref_postremove>`
- :ref:`#[PostUpdate] <attrref_postupdate>`
- :ref:`#[PrePersist] <attrref_prepersist>`
- :ref:`#[PreRemove] <attrref_preremove>`
- :ref:`#[PreUpdate] <attrref_preupdate>`
- :ref:`#[SequenceGenerator] <attrref_sequencegenerator>`
- :ref:`#[Table] <attrref_table>`
- :ref:`#[UniqueConstraint] <attrref_uniqueconstraint>`
- :ref:`#[Version] <attrref_version>`
Reference
---------
.. _annref_column:
.. _attrref_column:
#[Column]
~~~~~~~~~
@@ -122,7 +122,7 @@ Optional attributes:
attribute still handles the conversion between PHP and Database
values. If you use this attribute on a column that is used for
joins between tables you should also take a look at
:ref:`#[JoinColumn] <annref_joincolumn>`.
:ref:`#[JoinColumn] <attrref_joincolumn>`.
.. note::
@@ -159,7 +159,7 @@ Examples:
)]
protected $loginCount;
.. _annref_cache:
.. _attrref_cache:
#[Cache]
~~~~~~~~
@@ -170,7 +170,7 @@ Optional attributes:
- **usage**: One of ``READ_ONLY``, ``READ_WRITE`` or ``NONSTRICT_READ_WRITE``, By default this is ``READ_ONLY``.
- **region**: An specific region name
.. _annref_changetrackingpolicy:
.. _attrref_changetrackingpolicy:
#[ChangeTrackingPolicy]
~~~~~~~~~~~~~~~~~~~~~~~
@@ -203,12 +203,12 @@ Example:
]
class User {}
.. _annref_customidgenerator:
.. _attrref_customidgenerator:
#[CustomIdGenerator]
~~~~~~~~~~~~~~~~~~~~
This attribute allows you to specify a user-provided class to generate identifiers. This attribute only works when both :ref:`#[Id] <annref_id>` and :ref:`#[GeneratedValue(strategy: "CUSTOM")] <annref_generatedvalue>` are specified.
This attribute allows you to specify a user-provided class to generate identifiers. This attribute only works when both :ref:`#[Id] <attrref_id>` and :ref:`#[GeneratedValue(strategy: "CUSTOM")] <attrref_generatedvalue>` are specified.
Required attributes:
@@ -231,7 +231,7 @@ Example:
#[CustomIdGenerator(class: MyIdGenerator::class)]
public $id;
.. _annref_discriminatorcolumn:
.. _attrref_discriminatorcolumn:
#[DiscriminatorColumn]
~~~~~~~~~~~~~~~~~~~~~~
@@ -256,7 +256,7 @@ Optional attributes:
- **type**: By default this is string.
- **length**: By default this is 255.
.. _annref_discriminatormap:
.. _attrref_discriminatormap:
#[DiscriminatorMap]
~~~~~~~~~~~~~~~~~~~
@@ -286,13 +286,13 @@ depending on whether the classes are in the namespace or not.
}
.. _annref_embeddable:
.. _attrref_embeddable:
#[Embeddable]
~~~~~~~~~~~~~
The embeddable attribute is required on a class, in order to make it
embeddable inside an entity. It works together with the :ref:`#[Embedded] <annref_embedded>`
embeddable inside an entity. It works together with the :ref:`#[Embedded] <attrref_embedded>`
attribute to establish the relationship between the two classes.
.. code-block:: php
@@ -311,7 +311,7 @@ attribute to establish the relationship between the two classes.
private $address;
.. _annref_embedded:
.. _attrref_embedded:
#[Embedded]
~~~~~~~~~~~
@@ -323,7 +323,7 @@ Required attributes:
- **class**: The embeddable class
.. _annref_entity:
.. _attrref_entity:
#[Entity]
~~~~~~~~~
@@ -355,13 +355,13 @@ Example:
//...
}
.. _annref_entity_result:
.. _attrref_entity_result:
#[GeneratedValue]
~~~~~~~~~~~~~~~~~
Specifies which strategy is used for identifier generation for an
instance variable which is annotated by :ref:`#[Id] <annref_id>`. This
instance variable which is annotated by :ref:`#[Id] <attrref_id>`. This
attribute is optional and only has meaning when used in
conjunction with #[Id].
@@ -387,7 +387,7 @@ Example:
#[Id, Column(type: "integer"), GeneratedValue(strategy="IDENTITY")]
protected $id = null;
.. _annref_haslifecyclecallbacks:
.. _attrref_haslifecyclecallbacks:
#[HasLifecycleCallbacks]
~~~~~~~~~~~~~~~~~~~~~~~~
@@ -415,7 +415,7 @@ Example:
public function sendOptinMail() {}
}
.. _annref_index:
.. _attrref_index:
#[Index]
~~~~~~~~
@@ -466,7 +466,7 @@ Example with partial indexes:
{
}
.. _annref_id:
.. _attrref_id:
#[Id]
~~~~~
@@ -488,7 +488,7 @@ Example:
#[Id, Column(type="integer")]
protected $id = null;
.. _annref_inheritancetype:
.. _attrref_inheritancetype:
#[InheritanceType]
~~~~~~~~~~~~~~~~~~
@@ -499,8 +499,8 @@ inheritance. Currently Single Table and Class Table Inheritance are
supported.
This attribute has always been used in conjunction with the
:ref:`#[DiscriminatorMap] <annref_discriminatormap>` and
:ref:`#[DiscriminatorColumn] <annref_discriminatorcolumn>` attributes.
:ref:`#[DiscriminatorMap] <attrref_discriminatormap>` and
:ref:`#[DiscriminatorColumn] <attrref_discriminatorcolumn>` attributes.
Examples:
@@ -530,14 +530,14 @@ Examples:
// ...
}
.. _annref_joincolumn:
.. _attrref_joincolumn:
#[JoinColumn], #[InverseJoinColumn]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This attribute is used in the context of relations in
:ref:`#[ManyToOne] <annref_manytoone>`, :ref:`#[OneToOne] <annref_onetoone>` fields
and in the Context of a :ref:`#[ManyToMany] <annref_manytomany>`. If this attribute or both *name* and *referencedColumnName*
:ref:`#[ManyToOne] <attrref_manytoone>`, :ref:`#[OneToOne] <attrref_onetoone>` fields
and in the Context of a :ref:`#[ManyToMany] <attrref_manytomany>`. If this attribute or both *name* and *referencedColumnName*
are missing they will be computed considering the field's name and the current
:doc:`naming strategy <namingstrategy>`.
@@ -564,7 +564,7 @@ Optional attributes:
this attribute on ``#[JoinColumn]`` is necessary if you need slightly
different column definitions for joining columns, for example
regarding NULL/NOT NULL defaults. However by default a
"columnDefinition" attribute on :ref:`#[Column] <annref_column>` also sets
"columnDefinition" attribute on :ref:`#[Column] <attrref_column>` also sets
the related ``#[JoinColumn]``'s columnDefinition. This is necessary to
make foreign keys work.
@@ -580,13 +580,13 @@ Example:
#[JoinColumn(name: "customer_id", referencedColumnName: "id")]
private $customer;
.. _annref_jointable:
.. _attrref_jointable:
#[JoinTable]
~~~~~~~~~~~~
Using
:ref:`#[ManytoMany] <annref_manytomany>` on the owning side of the relation
:ref:`#[ManytoMany] <attrref_manytomany>` on the owning side of the relation
requires to specify the #[JoinTable] attribute which describes the
details of the database join table. If you do not specify
``#[JoinTable]`` on these relations reasonable mapping defaults apply
@@ -612,7 +612,7 @@ Example:
#[JoinTable(name: "users_phonenumbers")]
public $phonenumbers;
.. _annref_manytoone:
.. _attrref_manytoone:
#[ManyToOne]
~~~~~~~~~~~~
@@ -645,13 +645,13 @@ Example:
#[ManyToOne(targetEntity: "Cart", cascade: ["all"], fetch: "EAGER")]
private $cart;
.. _annref_manytomany:
.. _attrref_manytomany:
#[ManyToMany]
~~~~~~~~~~~~~
Defines that the annotated instance variable holds a many-to-many relationship
between two entities. :ref:`#[JoinTable] <annref_jointable>` is an
between two entities. :ref:`#[JoinTable] <attrref_jointable>` is an
additional, optional attribute that has reasonable default
configuration values using the table and names of the two related
entities.
@@ -703,7 +703,7 @@ Example:
#[ManyToMany(targetEntity: "User", mappedBy: "groups")]
private $features;
.. _annref_mappedsuperclass:
.. _attrref_mappedsuperclass:
#[MappedSuperclass]
~~~~~~~~~~~~~~~~~~~
@@ -742,15 +742,15 @@ Example:
// ... fields and methods
}
.. _annref_onetoone:
.. _attrref_onetoone:
#[OneToOne]
~~~~~~~~~~~
The ``#[OneToOne]`` attribute works almost exactly as the
:ref:`#[ManyToOne] <annref_manytoone>` with one additional option which can
:ref:`#[ManyToOne] <attrref_manytoone>` with one additional option which can
be specified. When no
:ref:`#[JoinColumn] <annref_joincolumn>` is specified it defaults to using the target entity table and
:ref:`#[JoinColumn] <attrref_joincolumn>` is specified it defaults to using the target entity table and
primary key column names and the current naming strategy to determine a name for the join column.
Required attributes:
@@ -778,7 +778,7 @@ Example:
#[JoinColumn(name: "customer_id", referencedColumnName: "id")]
private $customer;
.. _annref_onetomany:
.. _attrref_onetomany:
#[OneToMany]
~~~~~~~~~~~~
@@ -816,13 +816,13 @@ Example:
]
public $phonenumbers;
.. _annref_orderby:
.. _attrref_orderby:
#[OrderBy]
~~~~~~~~~~
Optional attribute that can be specified with a
:ref:`#[ManyToMany] <annref_manytomany>` or :ref:`#[OneToMany] <annref_onetomany>`
:ref:`#[ManyToMany] <attrref_manytomany>` or :ref:`#[OneToMany] <attrref_onetomany>`
attribute to specify by which criteria the collection should be
retrieved from the database by using an ORDER BY clause.
@@ -841,7 +841,7 @@ positional statement. Multiple Fields are separated by a comma (,).
The referenced field names have to exist on the ``targetEntity``
class of the ``#[ManyToMany]`` or ``#[OneToMany]`` attribute.
.. _annref_postload:
.. _attrref_postload:
#[PostLoad]
~~~~~~~~~~~~~~
@@ -850,7 +850,7 @@ Marks a method on the entity to be called as a ``#[PostLoad]`` event.
Only works with ``#[HasLifecycleCallbacks]`` in the entity class PHP
level.
.. _annref_postpersist:
.. _attrref_postpersist:
#[PostPersist]
~~~~~~~~~~~~~~
@@ -859,7 +859,7 @@ Marks a method on the entity to be called as a ``#[PostPersist]`` event.
Only works with ``#[HasLifecycleCallbacks]`` in the entity class PHP
level.
.. _annref_postremove:
.. _attrref_postremove:
#[PostRemove]
~~~~~~~~~~~~~~
@@ -868,7 +868,7 @@ Marks a method on the entity to be called as a ``#[PostRemove]`` event.
Only works with ``#[HasLifecycleCallbacks]`` in the entity class PHP
level.
.. _annref_postupdate:
.. _attrref_postupdate:
#[PostUpdate]
~~~~~~~~~~~~~~
@@ -877,7 +877,7 @@ Marks a method on the entity to be called as a ``#[PostUpdate]`` event.
Only works with ``#[HasLifecycleCallbacks]`` in the entity class PHP
level.
.. _annref_prepersist:
.. _attrref_prepersist:
#[PrePersist]
~~~~~~~~~~~~~~
@@ -886,7 +886,7 @@ Marks a method on the entity to be called as a ``#[PrePersist]`` event.
Only works with ``#[HasLifecycleCallbacks]`` in the entity class PHP
level.
.. _annref_preremove:
.. _attrref_preremove:
#[PreRemove]
~~~~~~~~~~~~~~
@@ -895,7 +895,7 @@ Marks a method on the entity to be called as a #``[PreRemove]`` event.
Only works with ``#[HasLifecycleCallbacks]`` in the entity class PHP
level.
.. _annref_preupdate:
.. _attrref_preupdate:
#[PreUpdate]
~~~~~~~~~~~~~~
@@ -904,7 +904,7 @@ Marks a method on the entity to be called as a ``#[PreUpdate]`` event.
Only works with ``#[HasLifecycleCallbacks]`` in the entity class PHP
level.
.. _annref_sequencegenerator:
.. _attrref_sequencegenerator:
#[SequenceGenerator]
~~~~~~~~~~~~~~~~~~~~~
@@ -941,7 +941,7 @@ Example:
#[SequenceGenerator(sequenceName: "tablename_seq", initialValue: 1, allocationSize: 100)]
protected $id = null;
.. _annref_table:
.. _attrref_table:
#[Table]
~~~~~~~~
@@ -971,7 +971,7 @@ Example:
#[Table(name: "user", schema: "schema_name")]
class User { }
.. _annref_uniqueconstraint:
.. _attrref_uniqueconstraint:
#[UniqueConstraint]
~~~~~~~~~~~~~~~~~~~
@@ -1008,16 +1008,16 @@ Basic example:
{
}
.. _annref_version:
.. _attrref_version:
#[Version]
~~~~~~~~~~
Marker attribute that defines a specified column as version attribute used in
an :ref:`optimistic locking <transactions-and-concurrency_optimistic-locking>`
scenario. It only works on :ref:`#[Column] <annref_column>` attributes that have
scenario. It only works on :ref:`#[Column] <attrref_column>` attributes that have
the type ``integer`` or ``datetime``. Setting ``#[Version]`` on a property with
:ref:`#[Id <annref_id>` is not supported.
:ref:`#[Id <attrref_id>` is not supported.
Example:

View File

@@ -61,7 +61,7 @@ This policy can be configured as follows:
Notify
~~~~~~
.. warning::
.. note::
The notify change tracking policy is deprecated and will be removed in ORM 3.0.
(`Details <https://github.com/doctrine/orm/issues/8383>`_)

View File

@@ -274,6 +274,9 @@ be a leaf entity in the inheritance hierarchy, (ie. have no subclasses).
Otherwise Doctrine *CANNOT* create proxy instances
of this entity and will *ALWAYS* load the entity eagerly.
There is also another important performance consideration that it is *NOT POSSIBLE*
to query for the base entity without any LEFT JOINs to the sub-types.
SQL Schema considerations
~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -2,7 +2,7 @@ Partial Objects
===============
.. warning::
.. note::
Creating Partial Objects through DQL is deprecated and
will be removed in the future, use data transfer object

View File

@@ -134,6 +134,10 @@ optimize the performance of the Flush Operation:
explicit strategies of notifying the UnitOfWork what objects/properties
changed.
.. note::
Flush only a single entity with ``$entityManager->flush($entity)`` is deprecated and will be removed in ORM 3.0.
(`Details <https://github.com/doctrine/orm/issues/8459>`_)
Query Internals
---------------

View File

@@ -309,7 +309,7 @@
<xs:complexType name="embedded">
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="class" type="orm:fqcn" use="required" />
<xs:attribute name="class" type="orm:fqcn" use="optional" />
<xs:attribute name="column-prefix" type="xs:string" use="optional" />
<xs:attribute name="use-column-prefix" type="xs:boolean" default="true" use="optional" />
</xs:complexType>

View File

@@ -26,6 +26,7 @@ use Doctrine\Common\Annotations\CachedReader;
use Doctrine\Common\Annotations\SimpleAnnotationReader;
use Doctrine\Common\Cache\ArrayCache;
use Doctrine\Common\Cache\Cache as CacheDriver;
use Doctrine\Common\Cache\Psr6\CacheAdapter;
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
use Doctrine\Common\Proxy\AbstractProxyFactory;
use Doctrine\Deprecations\Deprecation;
@@ -326,6 +327,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
);
$this->_attributes['metadataCacheImpl'] = $cacheImpl;
$this->_attributes['metadataCache'] = CacheAdapter::wrap($cacheImpl);
}
public function getMetadataCache(): ?CacheItemPoolInterface
@@ -335,7 +337,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
public function setMetadataCache(CacheItemPoolInterface $cache): void
{
$this->_attributes['metadataCache'] = $cache;
$this->_attributes['metadataCache'] = $cache;
$this->_attributes['metadataCacheImpl'] = DoctrineProvider::wrap($cache);
}
/**
@@ -430,16 +433,12 @@ class Configuration extends \Doctrine\DBAL\Configuration
throw ORMException::proxyClassesAlwaysRegenerating();
}
if ($this->getMetadataCache()) {
return;
if (! $this->getMetadataCache()) {
throw ORMException::metadataCacheNotConfigured();
}
$metadataCacheImpl = $this->getMetadataCacheImpl();
if (! $metadataCacheImpl) {
throw ORMException::metadataCacheNotConfigured();
}
if ($metadataCacheImpl instanceof ArrayCache) {
throw ORMException::metadataCacheUsesNonPersistentCache($metadataCacheImpl);
}

View File

@@ -710,6 +710,7 @@ class ClassMetadataInfo implements ClassMetadata
* metadata of the class with the given name.
*
* @param string $entityName The name of the entity class the new instance is used for.
* @psalm-param class-string<T> $entityName
*/
public function __construct($entityName, ?NamingStrategy $namingStrategy = null)
{
@@ -1467,10 +1468,6 @@ class ClassMetadataInfo implements ClassMetadata
$type = $this->reflClass->getProperty($mapping['fieldName'])->getType();
if ($type) {
if (! isset($mapping['nullable'])) {
$mapping['nullable'] = $type->allowsNull();
}
if (
! isset($mapping['type'])
&& ($type instanceof ReflectionNamedType)
@@ -1526,14 +1523,6 @@ class ClassMetadataInfo implements ClassMetadata
$mapping['targetEntity'] = $type->getName();
}
if (isset($mapping['joinColumns'])) {
foreach ($mapping['joinColumns'] as &$joinColumn) {
if ($type->allowsNull() === false) {
$joinColumn['nullable'] = false;
}
}
}
return $mapping;
}
@@ -3604,9 +3593,16 @@ class ClassMetadataInfo implements ClassMetadata
{
$this->assertFieldNotMapped($mapping['fieldName']);
if (! isset($mapping['class']) && $this->isTypedProperty($mapping['fieldName'])) {
$type = $this->reflClass->getProperty($mapping['fieldName'])->getType();
if ($type instanceof ReflectionNamedType) {
$mapping['class'] = $type->getName();
}
}
$this->embeddedClasses[$mapping['fieldName']] = [
'class' => $this->fullyQualifiedClassName($mapping['class']),
'columnPrefix' => $mapping['columnPrefix'],
'columnPrefix' => $mapping['columnPrefix'] ?? null,
'declaredField' => $mapping['declaredField'] ?? null,
'originalField' => $mapping['originalField'] ?? null,
];

View File

@@ -57,8 +57,8 @@ final class Column implements Annotation
/** @var bool */
public $unique = false;
/** @var bool|null */
public $nullable;
/** @var bool */
public $nullable = false;
/** @var array<string,mixed> */
public $options = [];
@@ -76,7 +76,7 @@ final class Column implements Annotation
?int $precision = null,
?int $scale = null,
bool $unique = false,
?bool $nullable = null,
bool $nullable = false,
array $options = [],
?string $columnDefinition = null
) {

View File

@@ -324,7 +324,7 @@ class XmlDriver extends FileDriver
$mapping = [
'fieldName' => (string) $embeddedMapping['name'],
'class' => (string) $embeddedMapping['class'],
'class' => isset($embeddedMapping['class']) ? (string) $embeddedMapping['class'] : null,
'columnPrefix' => $useColumnPrefix ? $columnPrefix : false,
];

View File

@@ -408,7 +408,7 @@ class YamlDriver extends FileDriver
foreach ($element['embedded'] as $name => $embeddedMapping) {
$mapping = [
'fieldName' => $name,
'class' => $embeddedMapping['class'],
'class' => $embeddedMapping['class'] ?? null,
'columnPrefix' => $embeddedMapping['columnPrefix'] ?? null,
];
$metadata->mapEmbedded($mapping);

View File

@@ -31,16 +31,13 @@ use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
#[Attribute(Attribute::TARGET_PROPERTY)]
final class Embedded implements Annotation
{
/**
* @Required
* @var string
*/
/** @var string|null */
public $class;
/** @var string|bool|null */
public $columnPrefix;
public function __construct(string $class, $columnPrefix = null)
public function __construct(?string $class = null, $columnPrefix = null)
{
$this->class = $class;
$this->columnPrefix = $columnPrefix;

View File

@@ -78,7 +78,6 @@ use Doctrine\ORM\Query\AST\UpdateStatement;
use Doctrine\ORM\Query\AST\WhenClause;
use Doctrine\ORM\Query\AST\WhereClause;
use ReflectionClass;
use Webmozart\Assert\Assert;
use function array_intersect;
use function array_search;
@@ -3543,7 +3542,7 @@ class Parser
$functionName = strtolower($this->lexer->lookahead['value']);
$functionClass = $this->em->getConfiguration()->getCustomNumericFunction($functionName);
Assert::notNull($functionClass);
assert($functionClass !== null);
$function = is_string($functionClass)
? new $functionClass($functionName)
@@ -3584,7 +3583,7 @@ class Parser
$functionName = $this->lexer->lookahead['value'];
$functionClass = $this->em->getConfiguration()->getCustomDatetimeFunction($functionName);
Assert::notNull($functionClass);
assert($functionClass !== null);
$function = is_string($functionClass)
? new $functionClass($functionName)
@@ -3626,7 +3625,7 @@ class Parser
$functionName = $this->lexer->lookahead['value'];
$functionClass = $this->em->getConfiguration()->getCustomStringFunction($functionName);
Assert::notNull($functionClass);
assert($functionClass !== null);
$function = is_string($functionClass)
? new $functionClass($functionName)

View File

@@ -105,6 +105,7 @@ class ConvertDoctrine1Schema
/**
* @param mixed[] $mappingInformation
* @psalm-param class-string $className
*/
private function convertToClassMetadataInfo(
string $className,

View File

@@ -630,9 +630,13 @@ class UnitOfWork implements PropertyChangedListener
*
* @param ClassMetadata $class The class descriptor of the entity.
* @param object $entity The entity for which to compute the changes.
* @psalm-param ClassMetadata<T> $class
* @psalm-param T $entity
*
* @return void
*
* @template T of object
*
* @ignore
*/
public function computeChangeSet(ClassMetadata $class, $entity)
@@ -959,6 +963,10 @@ class UnitOfWork implements PropertyChangedListener
/**
* @param object $entity
* @psalm-param ClassMetadata<T> $class
* @psalm-param T $entity
*
* @template T of object
*/
private function persistNew(ClassMetadata $class, $entity): void
{
@@ -1017,11 +1025,14 @@ class UnitOfWork implements PropertyChangedListener
*
* @param ClassMetadata $class The class descriptor of the entity.
* @param object $entity The entity for which to (re)calculate the change set.
* @psalm-param ClassMetadata<T> $class
* @psalm-param T $entity
*
* @return void
*
* @throws ORMInvalidArgumentException If the passed entity is not MANAGED.
*
* @template T of object
* @ignore
*/
public function recomputeSingleEntityChangeSet(ClassMetadata $class, $entity)
@@ -1144,6 +1155,10 @@ class UnitOfWork implements PropertyChangedListener
/**
* @param object $entity
* @psalm-param ClassMetadata<T> $class
* @psalm-param T $entity
*
* @template T of object
*/
private function addToEntityIdentifiersAndEntityMap(
ClassMetadata $class,
@@ -2020,8 +2035,13 @@ class UnitOfWork implements PropertyChangedListener
/**
* @param object $entity
* @param object $managedCopy
* @psalm-param ClassMetadata<T> $class
* @psalm-param T $entity
* @psalm-param T $managedCopy
*
* @throws OptimisticLockException
*
* @template T of object
*/
private function ensureVersionMatch(
ClassMetadata $class,

View File

@@ -557,7 +557,7 @@ parameters:
-
message: "#^Call to an undefined method ReflectionProperty\\:\\:getType\\(\\)\\.$#"
count: 2
count: 3
path: lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
-
@@ -1457,7 +1457,7 @@ parameters:
path: lib/Doctrine/ORM/Query/Parser.php
-
message: "#^Parameter \\#1 \\$function of function call_user_func expects callable\\(\\)\\: mixed, null given\\.$#"
message: "#^Else branch is unreachable because ternary operator condition is always true\\.$#"
count: 3
path: lib/Doctrine/ORM/Query/Parser.php

View File

@@ -1125,9 +1125,7 @@
<code>$table</code>
<code>$tableGeneratorDefinition</code>
</PropertyNotSetInConstructor>
<PropertyTypeCoercion occurrences="13">
<code>$entityName</code>
<code>$entityName</code>
<PropertyTypeCoercion occurrences="11">
<code>$this-&gt;entityListeners</code>
<code>$this-&gt;fieldMappings</code>
<code>$this-&gt;fullyQualifiedClassName($repositoryClassName)</code>

View File

@@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\Models\TypedProperties;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Embeddable()
*/
#[ORM\Embeddable]
class Contact
{
/** @Column() */
#[ORM\Column]
public ?string $email = null;
}

View File

@@ -24,6 +24,7 @@ class UserTyped
*/
#[ORM\Id, ORM\Column, ORM\GeneratedValue]
public int $id;
/** @Column(length=50) */
#[ORM\Column(length: 50)]
public ?string $status;
@@ -67,6 +68,10 @@ class UserTyped
#[ORM\ManyToOne]
public ?CmsEmail $mainEmail;
/** @Embedded */
#[ORM\Embedded]
public ?Contact $contact = null;
public static function loadMetadata(ClassMetadataInfo $metadata): void
{
$metadata->setInheritanceType(ClassMetadataInfo::INHERITANCE_TYPE_NONE);
@@ -131,5 +136,7 @@ class UserTyped
$metadata->mapManyToOne(
['fieldName' => 'mainEmail']
);
$metadata->mapEmbedded(['fieldName' => 'contact']);
}
}

View File

@@ -133,6 +133,7 @@ class ConfigurationTest extends DoctrineTestCase
$queryCacheImpl = $this->createMock(Cache::class);
$this->configuration->setMetadataCacheImpl($queryCacheImpl);
$this->assertSame($queryCacheImpl, $this->configuration->getMetadataCacheImpl());
$this->assertNotNull($this->configuration->getMetadataCache());
}
public function testSetGetMetadataCache(): void
@@ -141,6 +142,7 @@ class ConfigurationTest extends DoctrineTestCase
$cache = $this->createStub(CacheItemPoolInterface::class);
$this->configuration->setMetadataCache($cache);
$this->assertSame($cache, $this->configuration->getMetadataCache());
$this->assertNotNull($this->configuration->getMetadataCacheImpl());
}
public function testAddGetNamedQuery(): void

View File

@@ -42,6 +42,7 @@ use Doctrine\Tests\Models\DDC889\DDC889Class;
use Doctrine\Tests\Models\DDC889\DDC889Entity;
use Doctrine\Tests\Models\DDC964\DDC964Admin;
use Doctrine\Tests\Models\DDC964\DDC964Guest;
use Doctrine\Tests\Models\TypedProperties\Contact;
use Doctrine\Tests\Models\TypedProperties\UserTyped;
use Doctrine\Tests\OrmTestCase;
@@ -265,24 +266,6 @@ abstract class AbstractMappingDriverTest extends OrmTestCase
return $class;
}
public function testFieldIsNullableByType(): void
{
if (PHP_VERSION_ID < 70400) {
$this->markTestSkipped('requies PHP 7.4');
}
$class = $this->createClassMetadata(UserTyped::class);
// Explicit Nullable
$this->assertTrue($class->isNullable('status'));
// Explicit Not Nullable
$this->assertFalse($class->isNullable('username'));
$this->assertEquals(CmsEmail::class, $class->getAssociationMapping('email')['targetEntity']);
$this->assertEquals(CmsEmail::class, $class->getAssociationMapping('mainEmail')['targetEntity']);
}
public function testFieldTypeFromReflection(): void
{
if (PHP_VERSION_ID < 70400) {
@@ -299,6 +282,10 @@ abstract class AbstractMappingDriverTest extends OrmTestCase
$this->assertEquals('json', $class->getTypeOfField('array'));
$this->assertEquals('boolean', $class->getTypeOfField('boolean'));
$this->assertEquals('float', $class->getTypeOfField('float'));
$this->assertEquals(CmsEmail::class, $class->getAssociationMapping('email')['targetEntity']);
$this->assertEquals(CmsEmail::class, $class->getAssociationMapping('mainEmail')['targetEntity']);
$this->assertEquals(Contact::class, $class->embeddedClasses['contact']['class']);
}
/**

View File

@@ -120,19 +120,14 @@ class ClassMetadataTest extends OrmTestCase
$cm = new ClassMetadata(TypedProperties\UserTyped::class);
$cm->initializeReflection(new RuntimeReflectionService());
// Explicit Nullable
$cm->mapField(['fieldName' => 'status', 'length' => 50]);
$this->assertTrue($cm->isNullable('status'));
// Explicit Not Nullable
$cm->mapField(['fieldName' => 'username', 'length' => 50]);
$this->assertFalse($cm->isNullable('username'));
$cm->mapOneToOne(['fieldName' => 'email', 'joinColumns' => [[]]]);
$this->assertEquals(CmsEmail::class, $cm->getAssociationMapping('email')['targetEntity']);
$cm->mapManyToOne(['fieldName' => 'mainEmail']);
$this->assertEquals(CmsEmail::class, $cm->getAssociationMapping('mainEmail')['targetEntity']);
$cm->mapEmbedded(['fieldName' => 'contact']);
$this->assertEquals(TypedProperties\Contact::class, $cm->embeddedClasses['contact']['class']);
}
public function testFieldTypeFromReflection(): void

View File

@@ -61,3 +61,5 @@ $metadata->mapOneToOne(
$metadata->mapManyToOne(
['fieldName' => 'mainEmail']
);
$metadata->mapEmbedded(['fieldName' => 'contact']);

View File

@@ -25,5 +25,7 @@
</one-to-one>
<many-to-one field="mainEmail"/>
<embedded name="contact" />
</entity>
</doctrine-mapping>

View File

@@ -24,3 +24,5 @@ Doctrine\Tests\Models\TypedProperties\UserTyped:
joinColumn: []
manyToOne:
mainEmail: []
embedded:
contact: ~