From 91b2c82c58bae2051df4e8c8b227c033df525143 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Wed, 13 Jul 2011 20:31:01 +0200 Subject: [PATCH] Brought most of the documentation up to date on 2.1 --- en/reference/annotations-reference.rst | 10 +- en/reference/dql-doctrine-query-language.rst | 26 +++++ en/reference/faq.rst | 25 +++- en/reference/improving-performance.rst | 13 +++ en/reference/native-sql.rst | 25 +++- en/reference/working-with-objects.rst | 20 +++- en/reference/xml-mapping.rst | 32 +++++- en/tutorials/composite-primary-keys.rst | 115 ++++++++++++------- en/tutorials/extra-lazy-associations.rst | 4 - 9 files changed, 213 insertions(+), 57 deletions(-) diff --git a/en/reference/annotations-reference.rst b/en/reference/annotations-reference.rst index e444ca7b9..3f739800d 100644 --- a/en/reference/annotations-reference.rst +++ b/en/reference/annotations-reference.rst @@ -528,14 +528,16 @@ Optional attributes: - **inversedBy**: The inversedBy attribute designates the field in the entity that is the inverse side of the relationship. - **cascade**: Cascade Option -- **fetch**: One of LAZY or EAGER +- **fetch**: One of LAZY, EXTRA_LAZY or EAGER +- **indexBy**: Index the collection by a field on the target entity. - **NOTE** For ManyToMany bidirectional relationships either side may +.. note:: + + For ManyToMany bidirectional relationships either side may be the owning side (the side that defines the @JoinTable and/or does not make use of the mappedBy attribute, thus using a default join table). - Example: .. code-block:: php @@ -635,6 +637,8 @@ Optional attributes: - **mappedBy**: This option specifies the property name on the targetEntity that is the owning side of this relation. Its a required attribute for the inverse side of a relationship. +- **fetch**: One of LAZY, EXTRA_LAZY or EAGER. +- **indexBy**: Index the collection by a field on the target entity. Example: diff --git a/en/reference/dql-doctrine-query-language.rst b/en/reference/dql-doctrine-query-language.rst index de26eda9a..bd32720d1 100644 --- a/en/reference/dql-doctrine-query-language.rst +++ b/en/reference/dql-doctrine-query-language.rst @@ -557,6 +557,9 @@ clauses: - TRIM([LEADING \| TRAILING \| BOTH] ['trchar' FROM] str) - Trim the string by the given trim char, defaults to whitespaces. - UPPER(str) - Return the upper-case of the given string. +- DATE_ADD(date, days) - Add the number of days to a given date. +- DATE_SUB(date, days) - Substract the number of days from a given date. +- DATE_DIFF(date1, date2) - Calculate the difference in days between date1-date2. Arithmetic operators ~~~~~~~~~~~~~~~~~~~~ @@ -1263,6 +1266,29 @@ number of results: entity might appear in many rows, effectively hydrating less than the specified number of results. +.. _dql-temporarily-change-fetch-mode: + +Temporarily change fetch mode in DQL +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +While normally all your associations are marked as lazy or extra lazy you will have cases where you are using DQL and don't want to +fetch join a second, third or fourth level of entities into your result, because of the increased cost of the SQL JOIN. You +can mark a many-to-one or one-to-one association as fetched temporarily to batch fetch these entities using a WHERE .. IN query. + +.. code-block:: php + + createQuery("SELECT u FROM MyProject\User u"); + $query->setFetchMode("MyProject\User", "address", "EAGER"); + $query->execute(); + +Given that there are 10 users and corresponding addresses in the database the executed queries will look something like: + +.. code-block:: sql + + SELECT * FROM users; + SELECT * FROM address WHERE id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + EBNF ---- diff --git a/en/reference/faq.rst b/en/reference/faq.rst index 4e0ae7537..91d39a291 100644 --- a/en/reference/faq.rst +++ b/en/reference/faq.rst @@ -7,6 +7,17 @@ Frequently Asked Questions what is often asked. If you stumble accross an unanswerd question please write a mail to the mailing-list or join the #doctrine channel on Freenode IRC. +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. + Entity Classes -------------- @@ -23,7 +34,7 @@ Doctrine does not support to set the default values in columns through the "DEFA This is not necessary however, you can just use your class properties as default values. These are then used upon insert: -.. code-block:: +.. code-block:: php class User { @@ -47,7 +58,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 `Symfony 2`_ for example there is a Unique Entity Validator +In `Symfony 2 `_ 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 @@ -128,7 +139,7 @@ Can I use Inheritance with Doctrine 2? Yes, you can use Single- or Joined-Table Inheritance in Doctrine 2. -See the documentation chapter on :doc:`inheritance mapping `_ for +See the documentation chapter on :doc:`inheritance mapping ` for the details. Why does Doctrine not create proxy objects for my inheritance hierachy? @@ -144,12 +155,16 @@ EntityGenerator Why does the EntityGenerator not do X? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -. +The EntityGenerator is not a full fledged code-generator that solves all tasks. Code-Generation +is not a first-class priority in Doctrine 2 anymore (compared to Doctrine 1). The EntityGenerator +is supposed to kick-start you, but not towards 100%. Why does the EntityGenerator not generate inheritance correctly? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -. +Just from the details of the discriminator map the EntityGenerator cannot guess the inheritance hierachy. +This is why the generation of inherited entities does not fully work. You have to adjust some additional +code to get this one working correctly. Performance ----------- diff --git a/en/reference/improving-performance.rst b/en/reference/improving-performance.rst index c5b99a189..9bc4c8632 100644 --- a/en/reference/improving-performance.rst +++ b/en/reference/improving-performance.rst @@ -42,6 +42,19 @@ for updates, which means when you call flush on the EntityManager these entities even if properties changed. Read-Only allows to persist new entities of a kind and remove existing ones, they are just not considered for updates. +Extra-Lazy Collections +---------------------- + +If entities hold references to large collections you will get performance and memory problems initializing them. +To solve this issue you can use the EXTRA_LAZY fetch-mode feature for collections. See the :doc:`tutorial <../tutorials/extra-lazy-associations>` +for more information on how this fetch mode works. + +Temporarily change fetch mode in DQL +------------------------------------ + +See :ref:`Doctrine Query Language chapter ` + + Apply Best Practices -------------------- diff --git a/en/reference/native-sql.rst b/en/reference/native-sql.rst index dfec36ff8..01b837d4a 100644 --- a/en/reference/native-sql.rst +++ b/en/reference/native-sql.rst @@ -229,7 +229,6 @@ which meta-column is the discriminator column of this tree. * @param string $alias The alias of the entity result or joined entity result the discriminator * column should be used for. * @param string $discrColumn The name of the discriminator column in the SQL result set. - * @todo Rename: addDiscriminatorColumn */ public function setDiscriminatorColumn($alias, $discrColumn) @@ -363,4 +362,28 @@ are actually a subtype of User. When using DQL, Doctrine automatically includes the necessary joins for this mapping strategy but with native SQL it is your responsibility. +ResultSetMappingBuilder +----------------------- +There are some downsides with Native SQL queries. The primary one is that you have to adjust all result set mapping +definitions if names of columns change. In DQL this is detected dynamically when the Query is regenerated with +the current metadata. + +To avoid this hassle you can use the ``ResultSetMappingBuilder`` class. It allows to add all columns of an entity +to a result set mapping. To avoid clashes you can optionally rename specific columns when you are doing the same +in your sQL statement: + +.. code-block:: php + + addRootEntityFromClassMetadata('MyProject\User', 'u'); + $rsm->addJoinedEntityFromClassMetadata('MyProject\Address', 'a', array('id' => 'address_id')); + +For entites with more columns the builder is very convenient to use. It extends the ``ResultSetMapping`` class +and as such has all the functionality of it as well. Currently the ``ResultSetMappingBuilder`` does not support +entities with inheritance. diff --git a/en/reference/working-with-objects.rst b/en/reference/working-with-objects.rst index a47b13ef4..c235828ae 100644 --- a/en/reference/working-with-objects.rst +++ b/en/reference/working-with-objects.rst @@ -692,10 +692,28 @@ methods on a repository as follows: You can also load by owning side associations through the repository: +.. code-block:: php + + find('MyProject\Domain\Phonenumber', 1234); $user = $em->getRepository('MyProject\Domain\User')->findOneBy(array('phone' => $number->getId())); -Take not that this only works by passing the ID of the associated entity, not yet by passing the associated entity itself. +Be careful that this only works by passing the ID of the associated entity, not yet by passing the associated entity itself. + +The ``EntityRepository#findBy()`` method additionally accepts orderings, limit and offset as second to fourth parameters: + +.. code-block:: php + + getRepository('MyProject\Domain\User')-findBy(array('age' => 20), array('name' => 'ASC'), 10, 0); + +If you pass an array of values Doctrine will convert the query into a WHERE field IN (..) query automatically: + +.. code-block:: php + + getRepository('MyProject\Domain\User')-findBy(array('age' => array(20, 30, 40))); + // translates roughly to: SELECT * FROM users WHERE age IN (20, 30, 40) An EntityRepository also provides a mechanism for more concise calls through its use of ``__call``. Thus, the following two diff --git a/en/reference/xml-mapping.rst b/en/reference/xml-mapping.rst index ef351da2d..758ff5b7c 100644 --- a/en/reference/xml-mapping.rst +++ b/en/reference/xml-mapping.rst @@ -448,7 +448,7 @@ Optional attributes for owning One-to-One: field on the inverse entity that contains the back-reference. - orphan-removal - If true, the inverse side entity is always deleted when the owning side entity is. Defaults to false. -- fetch - Either LAZY or FETCH, defaults to LAZY. This attribute +- fetch - Either LAZY or EAGER, defaults to LAZY. This attribute makes only sense on the owning side, the inverse side *ALWAYS* has to use the ``FETCH`` strategy. @@ -501,7 +501,7 @@ Optional attributes: always deleted when the owning side entity is and it is not connected to any other owning side entity anymore. Defaults to false. -- fetch - Either LAZY or FETCH, defaults to LAZY. +- fetch - Either LAZY or EAGER, defaults to LAZY. This definition relies on a bunch of mapping defaults with regards to the naming of the join-column/foreign key. The explicitly @@ -547,7 +547,8 @@ Required attributes: Optional attributes: -- fetch - Either LAZY or FETCH, defaults to LAZY. +- fetch - Either LAZY, EXTRA_LAZY or EAGER, defaults to LAZY. +- index-by: Index the collection by a field on the target entity. Defining Many-To-Many Associations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -579,7 +580,8 @@ Optional attributes: - inversed-by - If the association is bidirectional the inversed-by attribute has to be specified with the name of the field on the inverse entity that contains the back-reference. -- fetch - Either LAZY or FETCH, defaults to LAZY. +- fetch - Either LAZY, EXTRA_LAZY or EAGER, defaults to LAZY. +- index-by: Index the collection by a field on the target entity. The mapping defaults would lead to a join-table with the name "User\_Group" being created that contains two columns "user\_id" @@ -698,4 +700,26 @@ table you can use the ```` and You have to specify the column and not the entity-class field names in the index and unique-constraint definitions. +Derived Entities ID syntax +~~~~~~~~~~~~~~~~~~~~~~~~~~ +If the primary key of an entity contains a foreign key to another entity we speak of a derived +entity relationship. You can define this in XML with the "association-key" attribute in the ```` tag. + +.. code-block:: xml + + + + + + + + + + + + + diff --git a/en/tutorials/composite-primary-keys.rst b/en/tutorials/composite-primary-keys.rst index 83ccd73ac..a091f573b 100644 --- a/en/tutorials/composite-primary-keys.rst +++ b/en/tutorials/composite-primary-keys.rst @@ -144,55 +144,92 @@ Use-Case 1: Dynamic Attributes We keep up the example of an Article with arbitrary attributes, the mapping looks like this: -.. code-block:: php +.. configuration-block:: - attributes[$name] = new ArticleAttribute($name, $value, $this); + /** @Id @Column(type="integer") @GeneratedValue */ + private $id; + /** @Column(type="string") */ + private $title; + + /** + * @OneToMany(targetEntity="ArticleAttribute", mappedBy="article", cascade={"ALL"}, indexBy="attribute") + */ + private $attributes; + + public function addAttribute($name, $value) + { + $this->attributes[$name] = new ArticleAttribute($name, $value, $this); + } } - } - /** - * @Entity - */ - class ArticleAttribute - { - /** @Id @ManyToOne(targetEntity="Article", inversedBy="attributes") */ - private $article; - - /** @Id @Column(type="string") */ - private $attribute; - - /** @Column(type="string") */ - private $value; - - public function __construct($name, $value, $article) + /** + * @Entity + */ + class ArticleAttribute { - $this->attribute = $name; - $this->value = $value; - $this->article = $article; + /** @Id @ManyToOne(targetEntity="Article", inversedBy="attributes") */ + private $article; + + /** @Id @Column(type="string") */ + private $attribute; + + /** @Column(type="string") */ + private $value; + + public function __construct($name, $value, $article) + { + $this->attribute = $name; + $this->value = $value; + $this->article = $article; + } } - } + + .. code-block:: xml + + + + + + + + + + + + + + + .. code-block:: yaml + + Application\Model\ArticleAttribute: + type: entity + id: + article: + associationKey: true + attribute: + type: string + fields: + value: + type: string + manyToOne: + article: + targetEntity: Article + inversedBy: attributes Use-Case 2: Simple Derived Identity @@ -311,4 +348,4 @@ a simple surrogate key. This performance impact is mostly due to additional PHP necessary to handle this kind of keys, most notably when using derived identifiers. On the SQL side there is not much overhead as no additional or unexpected queries have to be -executed to manage entities with derived foreign keys. \ No newline at end of file +executed to manage entities with derived foreign keys. diff --git a/en/tutorials/extra-lazy-associations.rst b/en/tutorials/extra-lazy-associations.rst index b854f72c1..ae58eb23c 100644 --- a/en/tutorials/extra-lazy-associations.rst +++ b/en/tutorials/extra-lazy-associations.rst @@ -1,10 +1,6 @@ Extra Lazy Associations ======================= -.. note:: - - This feature is scheduled for version 2.1 of Doctrine and not included in the 2.0.x series. - In many cases associations between entities can get pretty large. Even in a simple scenario like a blog. where posts can be commented, you always have to assume that a post draws hundrets of comments. In Doctrine 2.0 if you accessed an association it would always get loaded completly into memory. This