diff --git a/docs/en/cookbook/advanced-field-value-conversion-using-custom-mapping-types.rst b/docs/en/cookbook/advanced-field-value-conversion-using-custom-mapping-types.rst index ab9ae72c391..040b0c078ff 100644 --- a/docs/en/cookbook/advanced-field-value-conversion-using-custom-mapping-types.rst +++ b/docs/en/cookbook/advanced-field-value-conversion-using-custom-mapping-types.rst @@ -32,59 +32,39 @@ The entity class: namespace Geo\Entity; - /** - * @Entity - */ + use Geo\ValueObject\Point; + + #[Entity] class Location { - /** - * @Column(type="point") - * - * @var \Geo\ValueObject\Point - */ - private $point; - - /** - * @Column(type="string") - * - * @var string - */ - private $address; - - /** - * @param \Geo\ValueObject\Point $point - */ - public function setPoint(\Geo\ValueObject\Point $point) + #[Column(type: 'point')] + private Point $point; + + #[Column] + private string $address; + + public function setPoint(Point $point): void { $this->point = $point; } - /** - * @return \Geo\ValueObject\Point - */ - public function getPoint() + public function getPoint(): Point { return $this->point; } - /** - * @param string $address - */ - public function setAddress($address) + public function setAddress(string $address): void { $this->address = $address; } - /** - * @return string - */ - public function getAddress() + public function getAddress(): string { return $this->address; } } -We use the custom type ``point`` in the ``@Column`` docblock annotation of the +We use the custom type ``point`` in the ``#[Column]`` attribute of the ``$point`` field. We will create this custom mapping type in the next chapter. The point class: @@ -97,29 +77,18 @@ The point class: class Point { - - /** - * @param float $latitude - * @param float $longitude - */ - public function __construct($latitude, $longitude) - { - $this->latitude = $latitude; - $this->longitude = $longitude; + public function __construct( + private float $latitude, + private float $longitude, + ) { } - /** - * @return float - */ - public function getLatitude() + public function getLatitude(): float { return $this->latitude; } - /** - * @return float - */ - public function getLongitude() + public function getLongitude(): float { return $this->longitude; } diff --git a/docs/en/cookbook/implementing-the-notify-changetracking-policy.rst b/docs/en/cookbook/implementing-the-notify-changetracking-policy.rst index f2a8f19c196..0fa27372b9e 100644 --- a/docs/en/cookbook/implementing-the-notify-changetracking-policy.rst +++ b/docs/en/cookbook/implementing-the-notify-changetracking-policy.rst @@ -29,15 +29,15 @@ implement the ``NotifyPropertyChanged`` interface from the listeners[] = $listener; } - + /** Notifies listeners of a change. */ protected function onPropertyChanged($propName, $oldValue, $newValue) { if ($this->listeners) { @@ -55,12 +55,12 @@ listeners: .. code-block:: php data) { // check: is it actually modified? $this->onPropertyChanged('data', $this->data, $data); @@ -73,5 +73,3 @@ The check whether the new value is different from the old one is not mandatory but recommended. That way you can avoid unnecessary updates and also have full control over when you consider a property changed. - - diff --git a/docs/en/cookbook/strategy-cookbook-introduction.rst b/docs/en/cookbook/strategy-cookbook-introduction.rst index 600feb1abac..b7614a38715 100644 --- a/docs/en/cookbook/strategy-cookbook-introduction.rst +++ b/docs/en/cookbook/strategy-cookbook-introduction.rst @@ -154,8 +154,8 @@ As you can see, we have a method "setBlockEntity" which ties a potential strateg * This var contains the classname of the strategy * that is used for this blockitem. (This string (!) value will be persisted by Doctrine ORM) * - * This is a doctrine field, so make sure that you use an @column annotation or setup your - * yaml or xml files correctly + * This is a doctrine field, so make sure that you use a + #[Column] attribute or setup your yaml or xml files correctly * @var string */ protected $strategyClassName; @@ -251,5 +251,3 @@ This might look like this: In this example, even some variables are set - like a view object or a specific configuration object. - - diff --git a/docs/en/cookbook/validation-of-entities.rst b/docs/en/cookbook/validation-of-entities.rst index aa053908519..4f286490a70 100644 --- a/docs/en/cookbook/validation-of-entities.rst +++ b/docs/en/cookbook/validation-of-entities.rst @@ -36,12 +36,12 @@ are allowed to: public function assertCustomerAllowedBuying() { $orderLimit = $this->customer->getOrderLimit(); - + $amount = 0; foreach ($this->orderLines as $line) { $amount += $line->getAmount(); } - + if ($amount > $orderLimit) { throw new CustomerOrderLimitExceededException(); } @@ -53,7 +53,21 @@ code, enforcing it at any time is important so that customers with a unknown reputation don't owe your business too much money. We can enforce this constraint in any of the metadata drivers. -First Annotations: +First Attributes: + +.. code-block:: php + + -YAML needs some little change yet, to allow multiple lifecycle -events for one method, this will happen before Beta 1 though. - Now validation is performed whenever you call ``EntityManager#persist($order)`` or when you call ``EntityManager#flush()`` and an order is about to be updated. Any @@ -101,19 +112,17 @@ validation callbacks. plannedShipDate instanceof DateTime)) { throw new ValidateException(); } - + if ($this->plannedShipDate->format('U') < time()) { throw new ValidateException(); } - + if ($this->customer == null) { throw new OrderRequiresCustomerException(); } diff --git a/docs/en/reference/advanced-configuration.rst b/docs/en/reference/advanced-configuration.rst index e3a76f7e303..943046995fd 100644 --- a/docs/en/reference/advanced-configuration.rst +++ b/docs/en/reference/advanced-configuration.rst @@ -12,6 +12,7 @@ steps of configuration. use Doctrine\ORM\Configuration; use Doctrine\ORM\EntityManager; + use Doctrine\ORM\Mapping\Driver\AttributeDriver; use Doctrine\ORM\ORMSetup; use Symfony\Component\Cache\Adapter\ArrayAdapter; use Symfony\Component\Cache\Adapter\PhpFilesAdapter; @@ -28,7 +29,7 @@ steps of configuration. $config = new Configuration; $config->setMetadataCache($metadataCache); - $driverImpl = ORMSetup::createDefaultAnnotationDriver('/path/to/lib/MyProject/Entities'); + $driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities']); $config->setMetadataDriverImpl($driverImpl); $config->setQueryCache($queryCache); $config->setProxyDir('/path/to/myproject/lib/MyProject/Proxies'); @@ -124,18 +125,17 @@ used in the examples. For information on the usage of the AnnotationDriver, XmlDriver or YamlDriver please refer to the dedicated chapters ``Annotation Reference``, ``XML Mapping`` and ``YAML Mapping``. -The annotation driver can be configured with a factory method on -the ``Doctrine\ORM\Configuration``: +The attribute driver can be injected in the ``Doctrine\ORM\Configuration``: .. code-block:: php setMetadataDriverImpl($driverImpl); -The path information to the entities is required for the annotation +The path information to the entities is required for the attribute driver, because otherwise mass-operations on all entities through the console could not work correctly. All of metadata drivers accept either a single directory as a string or an array of @@ -152,7 +152,7 @@ Metadata Cache (***RECOMMENDED***) $config->getMetadataCache(); Gets or sets the cache adapter to use for caching metadata -information, that is, all the information you supply via +information, that is, all the information you supply via attributes, annotations, xml or yaml, so that they do not need to be parsed and loaded from scratch on every single request which is a waste of resources. The cache implementation must implement the PSR-6 diff --git a/docs/en/reference/association-mapping.rst b/docs/en/reference/association-mapping.rst index 8d4b06762e5..0f323de21d7 100644 --- a/docs/en/reference/association-mapping.rst +++ b/docs/en/reference/association-mapping.rst @@ -37,7 +37,7 @@ A many-to-one association is the most common association between objects. Exampl .. configuration-block:: - .. code-block:: php + .. code-block:: attribute @@ -83,8 +104,8 @@ A many-to-one association is the most common association between objects. Exampl The above ``#[JoinColumn]`` is optional as it would default to ``address_id`` and ``id`` anyways. You can omit it and let it use the defaults. - Likewise, inside the ``#[ManyToOne]`` annotation you can omit the - ``targetEntity`` attribute and it will default to ``Address``. + Likewise, inside the ``#[ManyToOne]`` attribute you can omit the + ``targetEntity`` argument and it will default to ``Address``. Generated MySQL Schema: @@ -111,7 +132,7 @@ references one ``Shipment`` entity. .. configuration-block:: - .. code-block:: php + .. code-block:: attribute @@ -186,7 +231,7 @@ object. .. configuration-block:: - .. code-block:: php + .. code-block:: attribute @@ -318,7 +395,7 @@ bidirectional many-to-one. .. configuration-block:: - .. code-block:: php + .. code-block:: attribute + * @OneToMany(targetEntity="Feature", mappedBy="product") + */ + private Collection $features; + // ... + + public function __construct() { + $this->features = new ArrayCollection(); + } + } + + /** @Entity */ + class Feature + { + // ... + /** + * Many features have one product. This is the owning side. + * @ManyToOne(targetEntity="Product", inversedBy="features") + * @JoinColumn(name="product_id", referencedColumnName="id") + */ + private Product|null $product = null; + // ... + } + .. code-block:: xml @@ -412,7 +524,7 @@ The following example sets up such a unidirectional one-to-many association: .. configuration-block:: - .. code-block:: php + .. code-block:: attribute + */ + private Collection $phonenumbers; + + public function __construct() + { + $this->phonenumbers = new \Doctrine\Common\Collections\ArrayCollection(); + } + + // ... + } + + /** @Entity */ + class Phonenumber + { + // ... + } + .. code-block:: xml @@ -514,7 +659,7 @@ database perspective is known as an adjacency list approach. .. configuration-block:: - .. code-block:: php + .. code-block:: attribute + */ + private Collection $children; + + /** + * Many Categories have One Category. + * @ManyToOne(targetEntity="Category", inversedBy="children") + * @JoinColumn(name="parent_id", referencedColumnName="id") + */ + private Category|null $parent = null; + // ... + + public function __construct() { + $this->children = new \Doctrine\Common\Collections\ArrayCollection(); + } + } + .. code-block:: xml @@ -584,7 +756,7 @@ entities: .. configuration-block:: - .. code-block:: php + .. code-block:: attribute + */ + private Collection $groups; + + // ... + + public function __construct() { + $this->groups = new \Doctrine\Common\Collections\ArrayCollection(); + } + } + + /** @Entity */ + class Group + { + // ... + } + .. code-block:: xml @@ -685,7 +889,7 @@ one is bidirectional. .. configuration-block:: - .. code-block:: php + .. code-block:: attribute + */ + private Collection $groups; + + public function __construct() { + $this->groups = new \Doctrine\Common\Collections\ArrayCollection(); + } + + // ... + } + + /** @Entity */ + class Group + { + // ... + /** + * Many Groups have Many Users. + * @ManyToMany(targetEntity="User", mappedBy="groups") + * @var Collection + */ + private Collection $users; + + public function __construct() { + $this->users = new \Doctrine\Common\Collections\ArrayCollection(); + } + + // ... + } + .. code-block:: xml @@ -903,12 +1148,18 @@ As an example, consider this mapping: .. configuration-block:: - .. code-block:: php + .. code-block:: attribute @@ -930,7 +1181,7 @@ mapping: .. configuration-block:: - .. code-block:: php + .. code-block:: attribute @@ -964,17 +1225,32 @@ similar defaults. As an example, consider this mapping: .. configuration-block:: - .. code-block:: php + .. code-block:: attribute */ #[ManyToMany(targetEntity: Group::class)] private Collection $groups; // ... } + .. code-block:: annotation + + + */ + private Collection $groups; + // ... + } + .. code-block:: xml @@ -995,7 +1271,7 @@ This is essentially the same as the following, more verbose, mapping: .. configuration-block:: - .. code-block:: php + .. code-block:: attribute + */ + private Collection $groups; + // ... + } + .. code-block:: xml @@ -1060,12 +1355,18 @@ attribute on ``JoinColumn`` will be inherited from PHP type. So that: .. configuration-block:: - .. code-block:: php + .. code-block:: attribute @@ -1085,7 +1386,17 @@ Is essentially the same as following: .. configuration-block:: - .. code-block:: php + .. code-block:: annotation + + ` - :doc:`YAML ` (deprecated and will be removed in ``doctrine/orm`` 3.0.) -This manual will usually show mapping metadata via docblock annotations, though -many examples also show the equivalent configuration in YAML and XML. +This manual will usually show mapping metadata via attributes, though +many examples also show the equivalent configuration in annotations, +YAML and XML. .. note:: @@ -157,10 +158,10 @@ Property Mapping The next step is mapping its properties to columns in the table. -To configure a property use the ``Column`` docblock annotation. The ``type`` -attribute specifies the :ref:`Doctrine Mapping Type ` -to use for the field. If the type is not specified, ``string`` is used as the -default. +To configure a property use the ``Column`` attribute. The ``type`` +argument specifies the :ref:`Doctrine Mapping Type +` to use for the field. If the type is not +specified, ``string`` is used as the default. .. configuration-block:: @@ -360,8 +361,7 @@ Identifiers / Primary Keys -------------------------- Every entity class must have an identifier/primary key. You can select -the field that serves as the identifier with the ``@Id`` -annotation. +the field that serves as the identifier with the ``#[Id]`` attribute. .. configuration-block:: @@ -377,6 +377,20 @@ annotation. // ... } + .. code-block:: annotation + + @@ -400,7 +414,7 @@ annotation. fields: # fields here -In most cases using the automatic generator strategy (``@GeneratedValue``) is +In most cases using the automatic generator strategy (``#[GeneratedValue]``) is what you want. It defaults to the identifier generation mechanism your current database vendor prefers: AUTO_INCREMENT with MySQL, sequences with PostgreSQL and Oracle and so on. @@ -436,8 +450,8 @@ Here is the list of possible generation strategies: - ``NONE``: Tells Doctrine that the identifiers are assigned (and thus generated) by your code. The assignment must take place before a new entity is passed to ``EntityManager#persist``. NONE is the - same as leaving off the @GeneratedValue entirely. -- ``CUSTOM``: With this option, you can use the ``@CustomIdGenerator`` annotation. + same as leaving off the ``#[GeneratedValue]`` entirely. +- ``CUSTOM``: With this option, you can use the ``#[CustomIdGenerator]`` attribute. It will allow you to pass a :doc:`class of your own to generate the identifiers.<_annref_customidgenerator>` Sequence Generator @@ -461,6 +475,20 @@ besides specifying the sequence's name: // ... } + .. code-block:: annotation + + @@ -522,11 +550,12 @@ need to access the sequence once to generate the identifiers for Composite Keys ~~~~~~~~~~~~~~ -With Doctrine ORM you can use composite primary keys, using ``@Id`` on more then -one column. Some restrictions exist opposed to using a single identifier in -this case: The use of the ``@GeneratedValue`` annotation is not supported, -which means you can only use composite keys if you generate the primary key -values yourself before calling ``EntityManager#persist()`` on the entity. +With Doctrine ORM you can use composite primary keys, using ``#[Id]`` on +more than one column. Some restrictions exist opposed to using a single +identifier in this case: The use of the ``#[GeneratedValue]`` attribute +is not supported, which means you can only use composite keys if you +generate the primary key values yourself before calling +``EntityManager#persist()`` on the entity. More details on composite primary keys are discussed in a :doc:`dedicated tutorial <../tutorials/composite-primary-keys>`. diff --git a/docs/en/reference/caching.rst b/docs/en/reference/caching.rst index ed13e1029cc..19b30b3d837 100644 --- a/docs/en/reference/caching.rst +++ b/docs/en/reference/caching.rst @@ -109,8 +109,9 @@ Metadata Cache ~~~~~~~~~~~~~~ Your class metadata can be parsed from a few different sources like -YAML, XML, Annotations, etc. Instead of parsing this information on -each request we should cache it using one of the cache drivers. +YAML, XML, Attributes, Annotations etc. Instead of parsing this +information on each request we should cache it using one of the cache +drivers. Just like the query and result cache we need to configure it first. @@ -199,5 +200,3 @@ not letting your users' requests populate the cache. You can read more about cache slams `in this blog post `_. - - diff --git a/docs/en/reference/configuration.rst b/docs/en/reference/configuration.rst index 47b0366a963..57bfd154924 100644 --- a/docs/en/reference/configuration.rst +++ b/docs/en/reference/configuration.rst @@ -55,7 +55,7 @@ access point to ORM functionality provided by Doctrine. 'dbname' => 'foo', ); - $config = ORMSetup::createAnnotationMetadataConfiguration($paths, $isDevMode); + $config = ORMSetup::createAttributeMetadataConfiguration($paths, $isDevMode); $entityManager = EntityManager::create($dbParams, $config); .. note:: @@ -83,9 +83,9 @@ Or if you prefer YAML: .. note:: If you want to use yml mapping you should add yaml dependency to your `composer.json`: - + :: - + "symfony/yaml": "*" Inside the ``ORMSetup`` methods several assumptions are made: diff --git a/docs/en/reference/events.rst b/docs/en/reference/events.rst index 77511d053dc..9958766e777 100644 --- a/docs/en/reference/events.rst +++ b/docs/en/reference/events.rst @@ -827,7 +827,41 @@ you need to map the listener method using the event type mapping: .. configuration-block:: - .. code-block:: php + .. code-block:: attribute + + @@ -980,7 +1015,7 @@ Load ClassMetadata Event ``loadClassMetadata`` - The ``loadClassMetadata`` event occurs after the mapping metadata for a class has been loaded from a mapping source -(annotations/xml/yaml) in to a ``Doctrine\ORM\Mapping\ClassMetadata`` instance. +(attributes/annotations/xml/yaml) in to a ``Doctrine\ORM\Mapping\ClassMetadata`` instance. You can hook in to this process and manipulate the instance. This event is not a lifecycle callback. diff --git a/docs/en/reference/faq.rst b/docs/en/reference/faq.rst index 06edf9458b9..249761f400a 100644 --- a/docs/en/reference/faq.rst +++ b/docs/en/reference/faq.rst @@ -13,10 +13,11 @@ Database Schema How do I set the charset and collation for MySQL tables? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can't set these values inside the annotations, yml or xml mapping files. To make a database -work with the default charset and collation you should configure MySQL to use it as default charset, -or create the database with charset and collation details. This way they get inherited to all newly -created database tables and columns. +You can't set these values with attributes, annotations or inside yml or +xml mapping files. To make a database work with the default charset and +collation you should configure MySQL to use it as default charset, or +create the database with charset and collation details. This way they +get inherited to all newly created database tables and columns. Entity Classes -------------- diff --git a/docs/en/reference/inheritance-mapping.rst b/docs/en/reference/inheritance-mapping.rst index 183769a9b02..e19229320ad 100644 --- a/docs/en/reference/inheritance-mapping.rst +++ b/docs/en/reference/inheritance-mapping.rst @@ -97,7 +97,7 @@ Example: .. configuration-block:: - .. code-block:: php + .. code-block:: attribute + */ + protected Collection $groups; + + /** + * @ManyToOne(targetEntity="Address") + * @JoinColumn(name="address_id", referencedColumnName="id") + */ + protected Address|null $address = null; + } + + // admin mapping + namespace MyProject\Model; + /** + * @Entity + * @AssociationOverrides({ + * @AssociationOverride(name="groups", + * joinTable=@JoinTable( + * name="users_admingroups", + * joinColumns=@JoinColumn(name="adminuser_id"), + * inverseJoinColumns=@JoinColumn(name="admingroup_id") + * ) + * ), + * @AssociationOverride(name="address", + * joinColumns=@JoinColumn( + * name="adminaddress_id", referencedColumnName="id" + * ) + * ) + * }) + */ + class Admin extends User + { + } + .. code-block:: xml @@ -477,7 +553,7 @@ Could be used by an entity that extends a mapped superclass to override a field .. configuration-block:: - .. code-block:: php + .. code-block:: attribute diff --git a/docs/en/reference/namingstrategy.rst b/docs/en/reference/namingstrategy.rst index c48f84f443d..53d75465c2b 100644 --- a/docs/en/reference/namingstrategy.rst +++ b/docs/en/reference/namingstrategy.rst @@ -7,7 +7,7 @@ reduce the verbosity of the mapping document, eliminating repetitive noise (eg: .. warning - The naming strategy is always overridden by entity mapping such as the `Table` annotation. + The naming strategy is always overridden by entity mapping such as the `Table` attribute. Configuring a naming strategy ----------------------------- diff --git a/docs/en/reference/php-mapping.rst b/docs/en/reference/php-mapping.rst index 2c9e425f073..2721d6103d0 100644 --- a/docs/en/reference/php-mapping.rst +++ b/docs/en/reference/php-mapping.rst @@ -90,8 +90,8 @@ Static Function In addition to the PHP files you can also specify your mapping information inside of a static function defined on the entity class itself. This is useful for cases where you want to keep your entity -and mapping information together but don't want to use annotations. -For this you just need to use the ``StaticPHPDriver``: +and mapping information together but don't want to use attributes or +annotations. For this you just need to use the ``StaticPHPDriver``: .. code-block:: php @@ -325,5 +325,3 @@ entities themselves. - ``setIdentifierValues($entity, $id)`` - ``setFieldValue($entity, $field, $value)`` - ``getFieldValue($entity, $field)`` - - diff --git a/docs/en/reference/second-level-cache.rst b/docs/en/reference/second-level-cache.rst index a589fec7958..e5bb2c2b610 100644 --- a/docs/en/reference/second-level-cache.rst +++ b/docs/en/reference/second-level-cache.rst @@ -277,7 +277,7 @@ level cache region. .. configuration-block:: - .. code-block:: php + .. code-block:: attribute @@ -334,7 +358,7 @@ It caches the primary keys of association and cache each element will be cached .. configuration-block:: - .. code-block:: php + .. code-block:: attribute + */ + protected Collection $cities; + + // other properties and methods + } + .. code-block:: xml diff --git a/docs/en/reference/transactions-and-concurrency.rst b/docs/en/reference/transactions-and-concurrency.rst index e57d3d84842..ccd91db6c3f 100644 --- a/docs/en/reference/transactions-and-concurrency.rst +++ b/docs/en/reference/transactions-and-concurrency.rst @@ -189,7 +189,7 @@ example we'll use an integer. .. configuration-block:: - .. code-block:: php + .. code-block:: attribute @@ -222,7 +233,7 @@ timestamp or datetime): .. configuration-block:: - .. code-block:: php + .. code-block:: attribute diff --git a/docs/en/reference/working-with-associations.rst b/docs/en/reference/working-with-associations.rst index fb1b465b2ac..b765419b1e8 100644 --- a/docs/en/reference/working-with-associations.rst +++ b/docs/en/reference/working-with-associations.rst @@ -137,7 +137,6 @@ relations of the ``User``: return $this->commentsRead; } - /** @param Collection $c */ public function setFirstComment(Comment $c): void { $this->firstComment = $c; } diff --git a/docs/en/reference/working-with-objects.rst b/docs/en/reference/working-with-objects.rst index ec3e52e7683..5bc272f4664 100644 --- a/docs/en/reference/working-with-objects.rst +++ b/docs/en/reference/working-with-objects.rst @@ -834,7 +834,7 @@ By default the EntityManager returns a default implementation of ``Doctrine\ORM\EntityRepository`` when you call ``EntityManager#getRepository($entityClass)``. You can overwrite this behaviour by specifying the class name of your own Entity -Repository in the Annotation, XML or YAML metadata. In large +Repository in the Attribute, Annotation, XML or YAML metadata. In large applications that require lots of specialized DQL queries using a custom repository is one recommended way of grouping these queries in a central location. diff --git a/docs/en/tutorials/composite-primary-keys.rst b/docs/en/tutorials/composite-primary-keys.rst index c2b48e290d8..cc9a98130fd 100644 --- a/docs/en/tutorials/composite-primary-keys.rst +++ b/docs/en/tutorials/composite-primary-keys.rst @@ -50,6 +50,59 @@ and year of production as primary keys: } } + .. code-block:: annotation + + name = $name; + $this->year = $year; + } + + public function getModelName(): string + { + return $this->name; + } + + public function getYearOfProduction(): int + { + return $this->year; + } + } + + .. code-block:: annotation + + @@ -126,7 +179,7 @@ of one or many parent entities. The semantics of mapping identity through foreign entities are easy: - Only allowed on Many-To-One or One-To-One associations. -- Plug an ``@Id`` annotation onto every association. +- Plug an ``#[Id]`` attribute onto every association. - Set an attribute ``association-key`` with the field name of the association in XML. - Set a key ``associationKey:`` with the field name of the association in YAML. @@ -144,6 +197,57 @@ We keep up the example of an Article with arbitrary attributes, the mapping look use Doctrine\Common\Collections\ArrayCollection; + /** + * @Entity + */ + class Article + { + /** @Id @Column(type="integer") @GeneratedValue */ + private int|null $id = null; + /** @Column(type="string") */ + private string $title; + + /** + * @OneToMany(targetEntity="ArticleAttribute", mappedBy="article", cascade={"ALL"}, indexBy="attribute") + * @var Collection + */ + private Collection $attributes; + + public function addAttribute($name, $value): void + { + $this->attributes[$name] = new ArticleAttribute($name, $value, $this); + } + } + + /** + * @Entity + */ + class ArticleAttribute + { + /** @Id @ManyToOne(targetEntity="Article", inversedBy="attributes") */ + private Article|null $article; + + /** @Id @Column(type="string") */ + private string $attribute; + + /** @Column(type="string") */ + private string $value; + + public function __construct($name, $value, $article) + { + $this->attribute = $name; + $this->value = $value; + $this->article = $article; + } + } + + .. code-block:: attribute + + @@ -109,7 +136,7 @@ The following example shows you how to set your prefix to ``myPrefix_``: .. configuration-block:: - .. code-block:: php + .. code-block:: attribute @@ -140,7 +178,7 @@ directly, set ``columnPrefix=false`` (``use-column-prefix="false"`` for XML): .. configuration-block:: - .. code-block:: php + .. code-block:: attribute + */ + public Collection $users; + } + .. code-block:: xml diff --git a/docs/en/tutorials/getting-started.rst b/docs/en/tutorials/getting-started.rst index 5a317337c5d..94849afccf3 100644 --- a/docs/en/tutorials/getting-started.rst +++ b/docs/en/tutorials/getting-started.rst @@ -83,7 +83,6 @@ that directory with the following contents: "require": { "doctrine/orm": "^2.11.0", "doctrine/dbal": "^3.2", - "doctrine/annotations": "1.13.2", "symfony/yaml": "^5.4", "symfony/cache": "^5.4" }, @@ -143,14 +142,23 @@ step: require_once "vendor/autoload.php"; // Create a simple "default" Doctrine ORM configuration for Annotations - $isDevMode = true; - $proxyDir = null; - $cache = null; - $useSimpleAnnotationReader = false; - $config = ORMSetup::createAnnotationMetadataConfiguration(array(__DIR__."/src"), $isDevMode, $proxyDir, $cache, $useSimpleAnnotationReader); - // or if you prefer YAML or XML - // $config = ORMSetup::createXMLMetadataConfiguration(array(__DIR__."/config/xml"), $isDevMode); - // $config = ORMSetup::createYAMLMetadataConfiguration(array(__DIR__."/config/yaml"), $isDevMode); + $config = ORMSetup::createAttributeMetadataConfiguration( + paths: array(__DIR__."/src"), + isDevMode: true, + ); + // or if you prefer annotation, YAML or XML + // $config = ORMSetup::createAnnotationMetadataConfiguration( + // paths: array(__DIR__."/src"), + // isDevMode: true, + // ); + // $config = ORMSetup::createXMLMetadataConfiguration( + // paths: array(__DIR__."/config/xml"), + // isDevMode: true, + //); + // $config = ORMSetup::createYAMLMetadataConfiguration( + // paths: array(__DIR__."/config/yaml"), + // isDevMode: true, + // ); // database configuration parameters $conn = array( @@ -165,10 +173,6 @@ step: The YAML driver is deprecated and will be removed in version 3.0. It is strongly recommended to switch to one of the other mappings. -.. note:: - It is recommended not to use the SimpleAnnotationReader because its - usage will be removed for version 3.0. - The ``require_once`` statement sets up the class autoloading for Doctrine and its dependencies using Composer's autoloader. @@ -494,14 +498,14 @@ the ``Product`` entity to Doctrine using a metadata language. The metadata language describes how entities, their properties and references should be persisted and what constraints should be applied to them. -Metadata for an Entity can be configured using DocBlock annotations directly -in the Entity class itself, or in an external XML or YAML file. This Getting -Started guide will demonstrate metadata mappings using all three methods, -but you only need to choose one. +Metadata for an Entity can be configured using attributes directly in +the Entity class itself, or in an external XML or YAML file. This +Getting Started guide will demonstrate metadata mappings using all three +methods, but you only need to choose one. .. configuration-block:: - .. code-block:: php + .. code-block:: attribute @@ -1023,7 +1054,7 @@ Lets add metadata mappings for the ``Bug`` entity, as we did for the ``Product`` before: .. configuration-block:: - .. code-block:: php + .. code-block:: attribute @@ -1146,7 +1230,7 @@ Finally, we'll add metadata mappings for the ``User`` entity. .. configuration-block:: - .. code-block:: php + .. code-block:: attribute An ArrayCollection of Bug objects. + */ + private Collection $reportedBugs; + + /** + * @ORM\OneToMany(targetEntity="Bug", mappedBy="engineer") + * @var Collection An ArrayCollection of Bug objects. + */ + private Collection $assignedBugs; + + // .. (other code) + } .. code-block:: xml @@ -1705,7 +1830,20 @@ we have to adjust the metadata slightly. .. configuration-block:: - .. code-block:: php + .. code-block:: attribute + + + */ + private Collection $groups; + } + .. code-block:: xml @@ -60,7 +76,7 @@ The DQL Snippet in OrderBy is only allowed to consist of unqualified, unquoted field names and of an optional ASC/DESC 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`` annotation. +class of the ``#[ManyToMany]`` or ``#[OneToMany]`` annotation. The semantics of this feature can be described as follows: diff --git a/docs/en/tutorials/override-field-association-mappings-in-subclasses.rst b/docs/en/tutorials/override-field-association-mappings-in-subclasses.rst index 5a2edc866e1..0488c25e464 100644 --- a/docs/en/tutorials/override-field-association-mappings-in-subclasses.rst +++ b/docs/en/tutorials/override-field-association-mappings-in-subclasses.rst @@ -50,7 +50,7 @@ Suppose we have a class ExampleEntityWithOverride. This class uses trait Example The docblock is showing metadata override of the attribute and association type. It basically changes the names of the columns mapped for a property ``foo`` and for the association ``bar`` which relates to Bar class shown above. Here is the trait -which has mapping metadata that is overridden by the annotation above: +which has mapping metadata that is overridden by the attribute above: .. code-block:: php diff --git a/docs/en/tutorials/working-with-indexed-associations.rst b/docs/en/tutorials/working-with-indexed-associations.rst index e41738737b3..b09da398249 100644 --- a/docs/en/tutorials/working-with-indexed-associations.rst +++ b/docs/en/tutorials/working-with-indexed-associations.rst @@ -23,6 +23,7 @@ Mapping Indexed Associations You can map indexed associations by adding: + * ``indexBy`` argument to any ``#[OneToMany]`` or ``#[ManyToMany]`` attribute. * ``indexBy`` attribute to any ``@OneToMany`` or ``@ManyToMany`` annotation. * ``index-by`` attribute to any ```` or ```` xml element. * ``indexBy:`` key-value pair to any association defined in ``manyToMany:`` or ``oneToMany:`` YAML mapping files. @@ -30,7 +31,7 @@ You can map indexed associations by adding: The code and mappings for the Market entity looks like this: .. configuration-block:: - .. code-block:: php + .. code-block:: attribute + */ + private Collection $stocks; + + public function __construct($name) + { + $this->name = $name; + $this->stocks = new ArrayCollection(); + } + + public function getId(): int|null + { + return $this->id; + } + + public function getName(): string + { + return $this->name; + } + + public function addStock(Stock $stock): void + { + $this->stocks[$stock->getSymbol()] = $stock; + } + + public function getStock($symbol): Stock + { + if (!isset($this->stocks[$symbol])) { + throw new \InvalidArgumentException("Symbol is not traded on this market."); + } + + return $this->stocks[$symbol]; + } + + /** @return array */ + public function getStocks(): array + { + return $this->stocks->toArray(); + } + } + .. code-block:: xml @@ -134,7 +203,7 @@ The ``Stock`` entity doesn't contain any special instructions that are new, but here are the code and mappings for it: .. configuration-block:: - .. code-block:: php + .. code-block:: attribute symbol = $symbol; + $this->market = $market; + $market->addStock($this); + } + + public function getSymbol(): string + { + return $this->symbol; + } + } + .. code-block:: xml