From 7fa3e6ec7c75e1b4f14ab7e6a1dd80badc4e0fac Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Wed, 14 Feb 2018 07:57:14 -0200 Subject: [PATCH 1/5] Use HTTPS instead of HTTP --- docs/LICENSE.md | 5 ++-- ...-conversion-using-custom-mapping-types.rst | 2 +- docs/en/cookbook/decorator-pattern.rst | 2 +- docs/en/cookbook/dql-custom-walkers.rst | 2 +- .../cookbook/dql-user-defined-functions.rst | 4 +-- ...menting-arrayaccess-for-domain-objects.rst | 2 +- ...nting-the-notify-changetracking-policy.rst | 2 +- .../cookbook/implementing-wakeup-or-clone.rst | 2 +- docs/en/cookbook/working-with-datetime.rst | 2 +- docs/en/reference/advanced-configuration.rst | 2 +- docs/en/reference/architecture.rst | 4 +-- docs/en/reference/basic-mapping.rst | 2 +- docs/en/reference/caching.rst | 6 ++-- docs/en/reference/configuration.rst | 2 +- .../reference/dql-doctrine-query-language.rst | 4 +-- docs/en/reference/events.rst | 6 ++-- docs/en/reference/faq.rst | 6 ++-- docs/en/reference/inheritance-mapping.rst | 4 +-- .../limitations-and-known-issues.rst | 12 ++++---- docs/en/reference/second-level-cache.rst | 10 +++---- docs/en/reference/security.rst | 2 +- docs/en/reference/xml-mapping.rst | 18 +++++------ docs/en/tutorials/composite-primary-keys.rst | 12 ++++---- docs/en/tutorials/extra-lazy-associations.rst | 6 ++-- docs/en/tutorials/getting-started.rst | 30 +++++++++---------- .../working-with-indexed-associations.rst | 12 ++++---- .../Entity/JoinedSubclassPersister.php | 2 +- .../Entity/SingleTablePersister.php | 2 +- 28 files changed, 82 insertions(+), 83 deletions(-) diff --git a/docs/LICENSE.md b/docs/LICENSE.md index 2956e90afe3..94200cb3128 100644 --- a/docs/LICENSE.md +++ b/docs/LICENSE.md @@ -1,4 +1,4 @@ -The Doctrine ORM documentation is licensed under [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US) +The Doctrine ORM documentation is licensed under [CC BY-NC-SA 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US) Creative Commons Legal Code @@ -359,5 +359,4 @@ Creative Commons Notice available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of this License. - Creative Commons may be contacted at http://creativecommons.org/. - + Creative Commons may be contacted at https://creativecommons.org/. 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 f735d99f46b..e1bf77cd302 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 @@ -193,7 +193,7 @@ object into a string representation before saving to the database (in the value from the database (in the ``convertToPHPValue`` method). The format of the string representation format is called -`Well-known text (WKT) `_. +`Well-known text (WKT) `_. The advantage of this format is, that it is both human readable and parsable by MySQL. Internally, MySQL stores geometry values in a binary format that is not diff --git a/docs/en/cookbook/decorator-pattern.rst b/docs/en/cookbook/decorator-pattern.rst index 8918b5536c9..cffc45867ab 100644 --- a/docs/en/cookbook/decorator-pattern.rst +++ b/docs/en/cookbook/decorator-pattern.rst @@ -5,7 +5,7 @@ Persisting the Decorator Pattern This recipe will show you a simple example of how you can use Doctrine ORM to persist an implementation of the -`Decorator Pattern `_ +`Decorator Pattern `_ Component --------- diff --git a/docs/en/cookbook/dql-custom-walkers.rst b/docs/en/cookbook/dql-custom-walkers.rst index 240e60ebf05..356b4ba868e 100644 --- a/docs/en/cookbook/dql-custom-walkers.rst +++ b/docs/en/cookbook/dql-custom-walkers.rst @@ -14,7 +14,7 @@ In Doctrine 1 the DQL language was not implemented using a real parser. This made modifications of the DQL by the user impossible. Doctrine ORM in contrast has a real parser for the DQL language, which transforms the DQL statement into an -`Abstract Syntax Tree `_ +`Abstract Syntax Tree `_ and generates the appropriate SQL statement for it. Since this process is deterministic Doctrine heavily caches the SQL that is generated from any given DQL query, which reduces the performance diff --git a/docs/en/cookbook/dql-user-defined-functions.rst b/docs/en/cookbook/dql-user-defined-functions.rst index 04a0d65b005..c7505164c9b 100644 --- a/docs/en/cookbook/dql-user-defined-functions.rst +++ b/docs/en/cookbook/dql-user-defined-functions.rst @@ -132,7 +132,7 @@ dql statement. The ``ArithmeticPrimary`` method call is the most common denominator of valid EBNF tokens taken from the -`DQL EBNF grammar `_ +`DQL EBNF grammar `_ that matches our requirements for valid input into the DateDiff Dql function. Picking the right tokens for your methods is a tricky business, but the EBNF grammar is pretty helpful finding it, as is @@ -246,6 +246,6 @@ vendor sql functions and extend the DQL languages scope. Code for this Extension to DQL and other Doctrine Extensions can be found -`in the GitHub DoctrineExtensions repository `_. +`in the GitHub DoctrineExtensions repository `_. diff --git a/docs/en/cookbook/implementing-arrayaccess-for-domain-objects.rst b/docs/en/cookbook/implementing-arrayaccess-for-domain-objects.rst index 4eb2b717bf5..363d1ad8ba1 100644 --- a/docs/en/cookbook/implementing-arrayaccess-for-domain-objects.rst +++ b/docs/en/cookbook/implementing-arrayaccess-for-domain-objects.rst @@ -6,7 +6,7 @@ Implementing ArrayAccess for Domain Objects This recipe will show you how to implement ArrayAccess for your domain objects in order to allow more uniform access, for example in templates. In these examples we will implement ArrayAccess on a -`Layer Supertype `_ +`Layer Supertype `_ for all our domain objects. Option 1 diff --git a/docs/en/cookbook/implementing-the-notify-changetracking-policy.rst b/docs/en/cookbook/implementing-the-notify-changetracking-policy.rst index d640c9e2178..f2a8f19c196 100644 --- a/docs/en/cookbook/implementing-the-notify-changetracking-policy.rst +++ b/docs/en/cookbook/implementing-the-notify-changetracking-policy.rst @@ -7,7 +7,7 @@ The NOTIFY change-tracking policy is the most effective change-tracking policy provided by Doctrine but it requires some boilerplate code. This recipe will show you how this boilerplate code should look like. We will implement it on a -`Layer Supertype `_ +`Layer Supertype `_ for all our domain objects. .. note:: diff --git a/docs/en/cookbook/implementing-wakeup-or-clone.rst b/docs/en/cookbook/implementing-wakeup-or-clone.rst index d5f0f7026a5..adf57d1b27c 100644 --- a/docs/en/cookbook/implementing-wakeup-or-clone.rst +++ b/docs/en/cookbook/implementing-wakeup-or-clone.rst @@ -4,7 +4,7 @@ Implementing Wakeup or Clone .. sectionauthor:: Roman Borschel (roman@code-factory.org) As explained in the -`restrictions for entity classes in the manual `_, +`restrictions for entity classes in the manual `_, it is usually not allowed for an entity to implement ``__wakeup`` or ``__clone``, because Doctrine makes special use of them. However, it is quite easy to make use of these methods in a safe diff --git a/docs/en/cookbook/working-with-datetime.rst b/docs/en/cookbook/working-with-datetime.rst index c8745d8ad2b..95e0687fa41 100644 --- a/docs/en/cookbook/working-with-datetime.rst +++ b/docs/en/cookbook/working-with-datetime.rst @@ -61,7 +61,7 @@ to manage this mess, however let me crush your expectations fast. There is not a single database out there (supported by Doctrine ORM) that supports timezones correctly. Correctly here means that you can cover all the use-cases that can come up with timezones. If you don't believe me you should read up on `Storing DateTime -in Databases `_. +in Databases `_. The problem is simple. Not a single database vendor saves the timezone, only the differences to UTC. However with frequent daylight saving and political timezone changes you can have a UTC offset that moves diff --git a/docs/en/reference/advanced-configuration.rst b/docs/en/reference/advanced-configuration.rst index ed971669404..1a75ad5b563 100644 --- a/docs/en/reference/advanced-configuration.rst +++ b/docs/en/reference/advanced-configuration.rst @@ -50,7 +50,7 @@ steps of configuration. conversions with the query cache. These 2 caches require only an absolute minimum of memory yet they heavily improve the runtime performance of Doctrine. The recommended cache driver to use with - Doctrine is `APC `_. APC provides you with + Doctrine is `APC `_. APC provides you with an opcode-cache (which is highly recommended anyway) and a very fast in-memory cache storage that you can use for the metadata and query caches as seen in the previous code snippet. diff --git a/docs/en/reference/architecture.rst b/docs/en/reference/architecture.rst index fefbdf4a697..6558c3ee8e7 100644 --- a/docs/en/reference/architecture.rst +++ b/docs/en/reference/architecture.rst @@ -83,7 +83,7 @@ be any regular PHP class observing the following restrictions: - An entity class must not implement ``__wakeup`` or :doc:`do so safely <../cookbook/implementing-wakeup-or-clone>`. Also consider implementing - `Serializable `_ + `Serializable `_ instead. - Any two entity classes in a class hierarchy that inherit directly or indirectly from one another must not have a mapped @@ -189,7 +189,7 @@ The Unit of Work Internally an ``EntityManager`` uses a ``UnitOfWork``, which is a typical implementation of the -`Unit of Work pattern `_, +`Unit of Work pattern `_, to keep track of all the things that need to be done the next time ``flush`` is invoked. You usually do not directly interact with a ``UnitOfWork`` but with the ``EntityManager`` instead. diff --git a/docs/en/reference/basic-mapping.rst b/docs/en/reference/basic-mapping.rst index c42e2c917ea..11a154070fa 100644 --- a/docs/en/reference/basic-mapping.rst +++ b/docs/en/reference/basic-mapping.rst @@ -289,7 +289,7 @@ A cookbook article shows how to define :doc:`your own custom mapping types .. warning:: All Date types assume that you are exclusively using the default timezone - set by `date_default_timezone_set() `_ + set by `date_default_timezone_set() `_ or by the php.ini configuration ``date.timezone``. Working with different timezones will cause troubles and unexpected behavior. diff --git a/docs/en/reference/caching.rst b/docs/en/reference/caching.rst index 647c1e71485..e069bcedaa1 100644 --- a/docs/en/reference/caching.rst +++ b/docs/en/reference/caching.rst @@ -74,7 +74,7 @@ Memcache In order to use the Memcache cache driver you must have it compiled and enabled in your php.ini. You can read about Memcache -`on the PHP website `_. It will +`on the PHP website `_. It will give you a little background information about what it is and how you can use it as well as how to install it. @@ -99,7 +99,7 @@ Memcache. In order to use the Memcached cache driver you must have it compiled and enabled in your php.ini. You can read about Memcached -`on the PHP website `_. It will +`on the PHP website `_. It will give you a little background information about what it is and how you can use it as well as how to install it. @@ -121,7 +121,7 @@ Redis In order to use the Redis cache driver you must have it compiled and enabled in your php.ini. You can read about what Redis is -`from here `_. Also check +`from here `_. Also check `A PHP extension for Redis `_ for how you can use and install the Redis PHP extension. diff --git a/docs/en/reference/configuration.rst b/docs/en/reference/configuration.rst index 17e04471cf5..a7478a78627 100644 --- a/docs/en/reference/configuration.rst +++ b/docs/en/reference/configuration.rst @@ -95,7 +95,7 @@ If you want to configure Doctrine in more detail, take a look at the :doc:`Advan .. note:: You can learn more about the database connection configuration in the - `Doctrine DBAL connection configuration reference `_. + `Doctrine DBAL connection configuration reference `_. Setting up the Commandline Tool ------------------------------- diff --git a/docs/en/reference/dql-doctrine-query-language.rst b/docs/en/reference/dql-doctrine-query-language.rst index f77403166dc..0acf42f5a6c 100644 --- a/docs/en/reference/dql-doctrine-query-language.rst +++ b/docs/en/reference/dql-doctrine-query-language.rst @@ -838,7 +838,7 @@ what type of results to expect. Single Table ~~~~~~~~~~~~ -`Single Table Inheritance `_ +`Single Table Inheritance `_ is an inheritance mapping strategy where all classes of a hierarchy are mapped to a single database table. In order to distinguish which row represents which type in the hierarchy a so-called @@ -931,7 +931,7 @@ entities: Class Table Inheritance ~~~~~~~~~~~~~~~~~~~~~~~ -`Class Table Inheritance `_ +`Class Table Inheritance `_ is an inheritance mapping strategy where each class in a hierarchy is mapped to several tables: its own table and the tables of all parent classes. The table of a child class is linked to the table diff --git a/docs/en/reference/events.rst b/docs/en/reference/events.rst index 0dfd17b6a52..24ceb0df434 100644 --- a/docs/en/reference/events.rst +++ b/docs/en/reference/events.rst @@ -329,9 +329,9 @@ XML would look something like this: - diff --git a/docs/en/reference/faq.rst b/docs/en/reference/faq.rst index 03a578ffc8a..d5e86863a76 100644 --- a/docs/en/reference/faq.rst +++ b/docs/en/reference/faq.rst @@ -52,7 +52,7 @@ or adding entities to a collection twice. You have to check for both conditions in the code before calling ``$em->flush()`` if you know that unique constraint failures can occur. -In `Symfony2 `_ for example there is a Unique Entity Validator +In `Symfony2 `_ for example there is a Unique Entity Validator to achieve this task. For collections you can check with ``$collection->contains($entity)`` if an entity is already @@ -112,8 +112,8 @@ over this collection using a LIMIT statement (or vendor equivalent). Doctrine does not offer a solution for this out of the box but there are several extensions that do: -* `DoctrineExtensions `_ -* `Pagerfanta `_ +* `DoctrineExtensions `_ +* `Pagerfanta `_ Why does pagination not work correctly with fetch joins? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/en/reference/inheritance-mapping.rst b/docs/en/reference/inheritance-mapping.rst index 120afb33ab8..856ce3435ed 100644 --- a/docs/en/reference/inheritance-mapping.rst +++ b/docs/en/reference/inheritance-mapping.rst @@ -73,7 +73,7 @@ defined on that class directly. Single Table Inheritance ------------------------ -`Single Table Inheritance `_ +`Single Table Inheritance `_ is an inheritance mapping strategy where all classes of a hierarchy are mapped to a single database table. In order to distinguish which row represents which type in the hierarchy a so-called @@ -181,7 +181,7 @@ the root entity of the single-table inheritance hierarchy. Class Table Inheritance ----------------------- -`Class Table Inheritance `_ +`Class Table Inheritance `_ is an inheritance mapping strategy where each class in a hierarchy is mapped to several tables: its own table and the tables of all parent classes. The table of a child class is linked to the table diff --git a/docs/en/reference/limitations-and-known-issues.rst b/docs/en/reference/limitations-and-known-issues.rst index 61c3568500d..61c1e06bb8c 100644 --- a/docs/en/reference/limitations-and-known-issues.rst +++ b/docs/en/reference/limitations-and-known-issues.rst @@ -112,10 +112,10 @@ in the core library. We don't think behaviors add more value than they cost pain and debugging hell. Please see the many different blog posts we have written on this topics: -- `Doctrine2 "Behaviors" in a Nutshell `_ -- `A re-usable Versionable behavior for Doctrine2 `_ -- `Write your own ORM on top of Doctrine2 `_ -- `Doctrine ORM Behavioral Extensions `_ +- `Doctrine2 "Behaviors" in a Nutshell `_ +- `A re-usable Versionable behavior for Doctrine2 `_ +- `Write your own ORM on top of Doctrine2 `_ +- `Doctrine ORM Behavioral Extensions `_ Doctrine ORM has enough hooks and extension points so that **you** can add whatever you want on top of it. None of this will ever become @@ -131,8 +131,8 @@ extensions out there that offer support for Nested Set with ORM: -- `Doctrine2 Hierarchical-Structural Behavior `_ -- `Doctrine2 NestedSet `_ +- `Doctrine2 Hierarchical-Structural Behavior `_ +- `Doctrine2 NestedSet `_ Known Issues ------------ diff --git a/docs/en/reference/second-level-cache.rst b/docs/en/reference/second-level-cache.rst index 49f54930f35..d84d742e631 100644 --- a/docs/en/reference/second-level-cache.rst +++ b/docs/en/reference/second-level-cache.rst @@ -114,7 +114,7 @@ Timestamp region Tracks the timestamps of the most recent updates to particular entity. -`See API Doc `_. +`See API Doc `_. .. _reference-second-level-cache-mode: @@ -209,7 +209,7 @@ It allows you to provide a specific implementation of the following components : ``CollectionHydrator`` transforms collections into cache entries and cache entries into collections -`See API Doc `_. +`See API Doc `_. Region Lifetime ~~~~~~~~~~~~~~~ @@ -272,7 +272,7 @@ If you want to get more information you should implement ``\Doctrine\ORM\Cache\Logging\CacheLogger`` and collect all the information you want. -`See API Doc `_. +`See API Doc `_. Entity cache definition @@ -315,7 +315,7 @@ level cache region. .. code-block:: xml - + @@ -391,7 +391,7 @@ It caches the primary keys of association and cache each element will be cached .. code-block:: xml - + diff --git a/docs/en/reference/security.rst b/docs/en/reference/security.rst index 0101e860f8f..83d64dda871 100644 --- a/docs/en/reference/security.rst +++ b/docs/en/reference/security.rst @@ -10,7 +10,7 @@ we cannot protect you from SQL injection. Please also read the documentation chapter on Security in Doctrine DBAL. This page only handles Security issues in the ORM. -- `DBAL Security Page ` +- `DBAL Security Page ` If you find a Security bug in Doctrine, please report it on Jira and change the Security Level to "Security Issues". It will be visible to Doctrine Core diff --git a/docs/en/reference/xml-mapping.rst b/docs/en/reference/xml-mapping.rst index a2dd8d21dac..35856e6fd56 100644 --- a/docs/en/reference/xml-mapping.rst +++ b/docs/en/reference/xml-mapping.rst @@ -16,9 +16,9 @@ setup for the latest code in trunk. .. code-block:: xml - ... @@ -102,9 +102,9 @@ of several common elements: // Doctrine.Tests.ORM.Mapping.User.dcm.xml - @@ -763,9 +763,9 @@ entity relationship. You can define this in XML with the "association-key" attri .. code-block:: xml - diff --git a/docs/en/tutorials/composite-primary-keys.rst b/docs/en/tutorials/composite-primary-keys.rst index 32603f8f7f4..9898c851c9b 100644 --- a/docs/en/tutorials/composite-primary-keys.rst +++ b/docs/en/tutorials/composite-primary-keys.rst @@ -58,9 +58,9 @@ and year of production as primary keys: .. code-block:: xml - @@ -194,9 +194,9 @@ We keep up the example of an Article with arbitrary attributes, the mapping look .. code-block:: xml - diff --git a/docs/en/tutorials/extra-lazy-associations.rst b/docs/en/tutorials/extra-lazy-associations.rst index 696002cd311..28fb479609c 100644 --- a/docs/en/tutorials/extra-lazy-associations.rst +++ b/docs/en/tutorials/extra-lazy-associations.rst @@ -71,9 +71,9 @@ switch to extra lazy as shown in these examples: .. code-block:: xml - diff --git a/docs/en/tutorials/getting-started.rst b/docs/en/tutorials/getting-started.rst index f7de43bca0a..850afa98d27 100644 --- a/docs/en/tutorials/getting-started.rst +++ b/docs/en/tutorials/getting-started.rst @@ -311,9 +311,9 @@ but you only need to choose one. .. code-block:: xml - @@ -876,9 +876,9 @@ the ``Product`` before: .. code-block:: xml - @@ -1002,9 +1002,9 @@ Finally, we'll add metadata mappings for the ``User`` entity. .. code-block:: xml - @@ -1188,9 +1188,9 @@ The console output of this script is then: use-case. Don't we use an ORM to get rid of all the endless hand-writing of SQL? Doctrine introduces DQL which is best described as **object-query-language** and is a dialect of - `OQL `_ and + `OQL `_ and similar to `HQL `_ or - `JPQL `_. + `JPQL `_. It does not know the concept of columns and tables, but only those of Entity-Class and property. Using the Metadata we defined before it allows for very short distinctive and powerful queries. @@ -1444,7 +1444,7 @@ Entity Repositories For now we have not discussed how to separate the Doctrine query logic from your model. In Doctrine 1 there was the concept of ``Doctrine_Table`` instances for this separation. The similar concept in Doctrine2 is called Entity Repositories, integrating -the `repository pattern `_ at the heart of Doctrine. +the `repository pattern `_ at the heart of Doctrine. Every Entity uses a default repository by default and offers a bunch of convenience methods that you can use to query for instances of that Entity. Take for example @@ -1545,9 +1545,9 @@ we have to adjust the metadata slightly. .. code-block:: xml - diff --git a/docs/en/tutorials/working-with-indexed-associations.rst b/docs/en/tutorials/working-with-indexed-associations.rst index 3ab37f6e78e..c38b8c5cae6 100644 --- a/docs/en/tutorials/working-with-indexed-associations.rst +++ b/docs/en/tutorials/working-with-indexed-associations.rst @@ -100,9 +100,9 @@ The code and mappings for the Market entity looks like this: .. code-block:: xml - @@ -186,9 +186,9 @@ here are the code and mappings for it: .. code-block:: xml - diff --git a/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php b/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php index 1f5026bb669..de3b1e0e5f2 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php @@ -34,7 +34,7 @@ * The joined subclass persister maps a single entity instance to several tables in the * database as it is defined by the Class Table Inheritance strategy. * - * @see http://martinfowler.com/eaaCatalog/classTableInheritance.html + * @see https://martinfowler.com/eaaCatalog/classTableInheritance.html */ class JoinedSubclassPersister extends AbstractEntityInheritancePersister { diff --git a/lib/Doctrine/ORM/Persisters/Entity/SingleTablePersister.php b/lib/Doctrine/ORM/Persisters/Entity/SingleTablePersister.php index 33104882c95..7f992a41990 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/SingleTablePersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/SingleTablePersister.php @@ -31,7 +31,7 @@ * Persister for entities that participate in a hierarchy mapped with the * SINGLE_TABLE strategy. * - * @link http://martinfowler.com/eaaCatalog/singleTableInheritance.html + * @link https://martinfowler.com/eaaCatalog/singleTableInheritance.html */ class SingleTablePersister extends AbstractEntityInheritancePersister { From 774b5cbdd4a876b5c5416a7e9a77f49bf4919046 Mon Sep 17 00:00:00 2001 From: Alex Rock Ancelet Date: Mon, 18 Dec 2017 20:35:39 +0100 Subject: [PATCH 2/5] document using DTOs and entities as Value Objects --- docs/en/tutorials/getting-started.rst | 302 +++++++++++++++++++++----- 1 file changed, 250 insertions(+), 52 deletions(-) diff --git a/docs/en/tutorials/getting-started.rst b/docs/en/tutorials/getting-started.rst index 850afa98d27..0ed1928b85f 100644 --- a/docs/en/tutorials/getting-started.rst +++ b/docs/en/tutorials/getting-started.rst @@ -235,44 +235,242 @@ entity definition: /** * @var int */ - protected $id; + private $id; /** * @var string */ - protected $name; + private $name; + } - public function getId() - { - return $this->id; - } +When creating entity classes, all of the fields should be ``private``. - public function getName() - { - return $this->name; - } +Use ``protected`` when strictly needed and very rarely if not ever ``public``. - public function setName($name) - { - $this->name = $name; - } - } +Adding behavior to Entities +~~~~~~~~~~~~~~~~~~~~~~~~~~~ -When creating entity classes, all of the fields should be ``protected`` or ``private`` -(not ``public``), with getter and setter methods for each one (except ``$id``). -The use of mutators allows Doctrine to hook into calls which -manipulate the entities in ways that it could not if you just -directly set the values with ``entity#field = foo;`` +There are two options to define methods in entities: +**getters/setters**, or **mutators and DTOs**, +respectively for **anemic entities** or **rich entities**. + +**Anemic entities: Getters and setters** + +The most popular method is to create two kinds of methods to +**read** (getter) and **update** (setter) the object's properties. The id field has no setter since, generally speaking, your code should not set this value since it represents a database id value. (Note that Doctrine itself can still set the value using the Reflection API instead of a defined setter function.) -The next step for persistence with Doctrine is to describe the -structure of 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. +.. note:: + + Doctrine ORM does not use any of the methods you defined: it uses + reflection to read and write values to your objects, and will never + call methods, not even ``__construct``. + +This approach is mostly used when you want to focus on behavior-less +entities, and when you want to have all your business logic in your +services rather than in the objects themselves. + +Getters and setters are a common convention which makes it possible to +expose each field of your entity to the external world, while allowing +you to keep some type safety in place. + +Such an approach is a good choice for RAD (rapid application development), +but may lead to problems later down the road, because providing such an +easy way to modify any field in your entity means that the entity itself +cannot guarantee validity of its internal state. Having any object in +invalid state is dangerous: + +- An invalid state can bring bugs in your business logic. +- The state can be implicitly saved in the database: any forgotten ``flush`` + can persist the broken state. +- If persisted, the corrupted data will be retrieved later in your application + when the data is loaded again, thereby leading to bugs in your business logic. +- When bugs occur after corrupted data is persisted, troubleshooting will + become much harder, and you might be aware of the bug too late to fix it in a + proper manner. + +implicitly saved in database, thereby leading to corrupted or inconsistent +data in your storage, and later in your application when the data is loaded again. + +.. note:: + + This method, although very common, is inappropriate for Domain Driven + Design (`DDD `) + where methods should represent real business operations and not simple + property change, And business invariants should be maintained both in the + application state (entities in this case) and in the database, with no + space for data corruption. + +Here is an example of a simple **anemic entity**: + +.. configuration-block:: + + .. code-block:: php + + username; + } + + public function setUsername(string $username): void + { + $this->username = $username; + } + + public function getPasswordHash(): string + { + return $this->passwordHash; + } + + public function setPasswordHash(string $passwordHash): void + { + $this->passwordHash = $passwordHash; + } + + public function getBans(): array + { + return $this->bans; + } + + public function addBan(Ban $ban): void + { + $this->bans[] = $ban; + } + } + +In the example above, we avoid all possible logic in the entity and only care +about putting and retrieving data into it without validation (except the one +provided by type-hints) nor consideration about the object's state. + +As Doctrine ORM is a persistence tool for your domain, the state of an object is +really important. This is why we strongly recommend using rich entities. + +**Rich entities: Mutators and DTOs** + +We recommend using a rich entity design and rely on more complex mutators, +and if needed based on DTOs. +In this design, you should **not** use getters nor setters, and instead, +implement methods that represent the **behavior** of your domain. + +For example, when having a ``User`` entity, we could foresee +the following kind of optimization. + +Example of a rich entity with proper accessors and mutators: + +.. configuration-block:: + + .. code-block:: php + username; + } + + public function authenticate(string $password, callable $checkHash): bool + { + return $checkHash($password, $this->passwordHash) && ! $this->hasActiveBans(); + } + + public function changePassword(string $password, callable $hash): void + { + $this->passwordHash = $hash($password); + } + + public function ban(\DateInterval $duration): void + { + assert($duration->invert !== 1); + + $this->bans[] = new Ban($this); + } + } + +.. note:: + + Please note that this example is only a stub. When going further in the + documentation, we will update this object with more behavior and maybe + update some methods. + +The entities should only mutate state after checking that all business logic +invariants are being respected. +Additionally, our entities should never see their state change without +validation. For example, creating a ``new Product()`` object without any data +makes it an **invalid object**. +Rich entities should represent **behavior**, not **data**, therefore +they should be valid even after a ``__construct()`` call. + +To help creating such objects, we can rely on ``DTOs``, and/or make +our entities always up-to-date. This can be performed with static constructors, +or rich mutators that accept ``DTOs`` as parameters. + +The role of the ``DTO`` is to maintain the entity's state and to help us rely +upon objects that correctly represent the data that is used to mutate the +entity. + +.. note:: + + A `DTO ` is an object + that only carries data without any logic. Its only goal is to be transferred + from one service to another. + A ``DTO`` often represents data sent by a client and that has to be validated, + but can also be used as simple data carrier for other cases. + +By using ``DTOs``, if we take our previous ``User`` example, we could create +a ``ProfileEditingForm`` DTO that will be a plain model, totally unrelated to +our database, that will be populated via a form and validated. +Then we can add a new mutator to our ``User``: + +.. configuration-block:: + + .. code-block:: php + Date: Tue, 23 Jan 2018 14:15:39 +0100 Subject: [PATCH 3/5] Fix the link to the 'Change Tracking Policies' documentation --- docs/en/reference/improving-performance.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/reference/improving-performance.rst b/docs/en/reference/improving-performance.rst index a8c51223dd2..4eeb526f0b5 100644 --- a/docs/en/reference/improving-performance.rst +++ b/docs/en/reference/improving-performance.rst @@ -97,4 +97,4 @@ See :doc:`Best Practices ` Change Tracking policies ------------------------ -See: :doc:`Change Tracking Policies ` +See: :doc:`Change Tracking Policies ` From 53ba6b9732e288406e24123db6b233562489fb4b Mon Sep 17 00:00:00 2001 From: Catalin Ciobanu Date: Thu, 18 Jan 2018 12:05:17 +0200 Subject: [PATCH 4/5] Updated docblock --- lib/Doctrine/ORM/AbstractQuery.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Doctrine/ORM/AbstractQuery.php b/lib/Doctrine/ORM/AbstractQuery.php index 7010d58e745..61a3d443698 100644 --- a/lib/Doctrine/ORM/AbstractQuery.php +++ b/lib/Doctrine/ORM/AbstractQuery.php @@ -856,7 +856,7 @@ public function getOneOrNullResult($hydrationMode = null) * @return mixed * * @throws NonUniqueResultException If the query result is not unique. - * @throws NoResultException If the query returned no result and hydration mode is not HYDRATE_SINGLE_SCALAR. + * @throws NoResultException If the query returned no result. */ public function getSingleResult($hydrationMode = null) { @@ -886,6 +886,7 @@ public function getSingleResult($hydrationMode = null) * * @throws NoResultException If the query returned no result. * @throws NonUniqueResultException If the query result is not unique. + * @throws NoResultException If the query returned no result. */ public function getSingleScalarResult() { From f3e87d2c2f116166f105b0cd47550a0bad241408 Mon Sep 17 00:00:00 2001 From: Igor Pellegrini Date: Thu, 31 Oct 2019 14:30:36 +0100 Subject: [PATCH 5/5] Fix bullet list not rendering correctly on Github As *rst*, if reading the tutorial on the Github repository, the items are not seen as elements of a bullet list, hence they are not rendered and they are collapsed in a single line of text. Fix won't affect how it renders on [doctrine-project.org](https://www.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/getting-started.html). --- docs/en/tutorials/getting-started.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/tutorials/getting-started.rst b/docs/en/tutorials/getting-started.rst index 0ed1928b85f..043055f7bf3 100644 --- a/docs/en/tutorials/getting-started.rst +++ b/docs/en/tutorials/getting-started.rst @@ -457,12 +457,16 @@ There are several advantages to using such a model: * **Entity state is always valid.** Since no setters exist, this means that we only update portions of the entity that should already be valid. + * Instead of having plain getters and setters, our entity now has **real behavior**: it is much easier to determine the logic in the domain. + * DTOs can be reused in other components, for example deserializing mixed content, using forms... + * Classic and static constructors can be used to manage different ways to create our objects, and they can also use DTOs. + * Anemic entities tend to isolate the entity from logic, whereas rich entities allow putting the logic in the object itself, including data validation.