diff --git a/generate-docs.sh b/generate-docs.sh
index 14fdb721b..07aaf048f 100755
--- a/generate-docs.sh
+++ b/generate-docs.sh
@@ -1,2 +1,2 @@
#!/bin/bash
-sphinx-build reference/en /var/www/docs
\ No newline at end of file
+sphinx-build manual/en /var/www/docs
diff --git a/manual/en/annotations-reference.rst b/manual/en/annotations-reference.rst
index d7515c38a..3b5cefddd 100644
--- a/manual/en/annotations-reference.rst
+++ b/manual/en/annotations-reference.rst
@@ -1,3 +1,6 @@
+Annotations Reference
+=====================
+
In this chapter a reference of every Doctrine 2 Annotation is given
with short explanations on their context and usage.
@@ -38,7 +41,8 @@ Index
Reference
---------
-### @Column
+@Column
+~~~~~~~
Marks an annotated instance variable as "persistent". It has to be
inside the instance variables PHP DocBlock comment. Any value hold
@@ -97,7 +101,8 @@ Examples:
*/
protected $height;
-### @ChangeTrackingPolicy
+@ChangeTrackingPolicy
+~~~~~~~~~~~~~~~~~~~~~
The Change Tracking Policy annotation allows to specify how the
Doctrine 2 UnitOfWork should detect changes in properties of
@@ -125,7 +130,8 @@ Example:
*/
class User {}
-### @DiscrimnatorColumn
+@DiscrimnatorColumn
+~~~~~~~~~~~~~~~~~~~~~
This annotation is a required annotation for the topmost/super
class of an inheritance hierarchy. It specifies the details of the
@@ -144,7 +150,8 @@ Optional attributes:
- type - By default this is string.
- length - By default this is 255.
-### @DiscriminatorMap
+@DiscriminatorMap
+~~~~~~~~~~~~~~~~~~~~~
The discriminator map is a required annotation on the
top-most/super class in an inheritance hierarchy. It takes an array
@@ -167,7 +174,8 @@ depending if the classes are in the namespace or not.
// ...
}
-### @Entity
+@Entity
+~~~~~~~
Required annotation to mark a PHP class as Entity. Doctrine manages
the persistence of all classes marked as entity.
@@ -193,7 +201,8 @@ Example:
//...
}
-### @GeneratedValue
+@GeneratedValue
+~~~~~~~~~~~~~~~~~~~~~
Specifies which strategy is used for identifier generation for an
instance variable which is annotated by `@Id <#ann_id>`_. This
@@ -221,7 +230,8 @@ Example:
*/
protected $id = null;
-### @HasLifecycleCallbacks
+@HasLifecycleCallbacks
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Annotation which has to be set on the entity-class PHP DocBlock to
notify Doctrine that this entity has entity life-cycle callback
@@ -247,7 +257,8 @@ Example:
public function sendOptinMail() {}
}
-### @Index
+@Index
+~~~~~~~
Annotation is used inside the `@Table <#ann_table>`_ annotation on
the entity-class level. It allows to hint the SchemaTool to
@@ -273,7 +284,8 @@ Example:
{
}
-### @Id
+@Id
+~~~~~~~
The annotated instance variable will be marked as entity
identifier, the primary key in the database. This annotation is a
@@ -292,7 +304,8 @@ Example:
*/
protected $id = null;
-### @InheritanceType
+@InheritanceType
+~~~~~~~~~~~~~~~~~~~~~
In an inheritance hierarchy you have to use this annotation on the
topmost/super class to define which strategy should be used for
@@ -330,7 +343,8 @@ Examples:
// ...
}
-### @JoinColumn
+@JoinColumn
+~~~~~~~~~~~~~~
This annotation is used in the context of relations in
`@ManyToOne <#ann_manytoone>`_, `@OneToOne <#ann_onetoone>`_ fields
@@ -379,13 +393,15 @@ Example:
*/
private $customer;
-### @JoinColumns
+@JoinColumns
+~~~~~~~~~~~~~~
An array of @JoinColumn annotations for a
`@ManyToOne <#ann_manytoone>`_ or `@OneToOne <#ann_onetoone>`_
relation with an entity that has multiple identifiers.
-### @JoinTable
+@JoinTable
+~~~~~~~~~~~~~~
Using `@OneToMany <#ann_onetomany>`_ or
`@ManyToMany <#ann_manytomany>`_ on the owning side of the relation
@@ -423,7 +439,8 @@ Example:
*/
public $phonenumbers;
-### @ManyToOne
+@ManyToOne
+~~~~~~~~~~~~~~
Defines that the annotated instance variable holds a reference that
describes a many-to-one relationship between two entities.
@@ -453,7 +470,8 @@ Example:
*/
private $cart;
-### @ManyToMany
+@ManyToMany
+~~~~~~~~~~~~~~
Defines an instance variable holds a many-to-many relationship
between two entities. `@JoinTable <#ann_jointable>`_ is an
@@ -508,7 +526,8 @@ Example:
*/
private $features;
-### @MappedSuperclass
+@MappedSuperclass
+~~~~~~~~~~~~~~~~~~~~~
An mapped superclass is an abstract or concrete class that provides
persistent entity state and mapping information for its subclasses,
@@ -519,7 +538,8 @@ The @MappedSuperclass annotation cannot be used in conjunction with
@Entity. See the Inheritance Mapping section for
`more details on the restrictions of mapped superclasses `_.
-### @OneToOne
+@OneToOne
+~~~~~~~~~~~~~~
The @OneToOne annotation works almost exactly as the
`@ManyToOne <#ann_manytoone>`_ with one additional option that can
@@ -556,7 +576,8 @@ Example:
*/
private $customer;
-### @OneToMany
+@OneToMany
+~~~~~~~~~~~~~~
Required attributes:
@@ -586,7 +607,8 @@ Example:
*/
public $phonenumbers;
-### @OrderBy
+@OrderBy
+~~~~~~~~~~~~~~
Optional annotation that can be specified with a
`@ManyToMany <#ann_manytomany>`_ or `@OneToMany <#ann_onetomany>`_
@@ -613,49 +635,57 @@ 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.
-### @PostLoad
+@PostLoad
+~~~~~~~~~~~~~~
Marks a method on the entity to be called as a @PostLoad event.
Only works with @HasLifecycleCallbacks in the entity class PHP
DocBlock.
-### @PostPersist
+@PostPersist
+~~~~~~~~~~~~~~
Marks a method on the entity to be called as a @PostPersist event.
Only works with @HasLifecycleCallbacks in the entity class PHP
DocBlock.
-### @PostRemove
+@PostRemove
+~~~~~~~~~~~~~~
Marks a method on the entity to be called as a @PostRemove event.
Only works with @HasLifecycleCallbacks in the entity class PHP
DocBlock.
-### @PostUpdate
+@PostUpdate
+~~~~~~~~~~~~~~
Marks a method on the entity to be called as a @PostUpdate event.
Only works with @HasLifecycleCallbacks in the entity class PHP
DocBlock.
-### @PrePersist
+@PrePersist
+~~~~~~~~~~~~~~
Marks a method on the entity to be called as a @PrePersist event.
Only works with @HasLifecycleCallbacks in the entity class PHP
DocBlock.
-### @PreRemove
+@PreRemove
+~~~~~~~~~~~~~~
Marks a method on the entity to be called as a @PreRemove event.
Only works with @HasLifecycleCallbacks in the entity class PHP
DocBlock.
-### @PreUpdate
+@PreUpdate
+~~~~~~~~~~~~~~
Marks a method on the entity to be called as a @PreUpdate event.
Only works with @HasLifecycleCallbacks in the entity class PHP
DocBlock.
-### @SequenceGenerator
+@SequenceGenerator
+~~~~~~~~~~~~~~~~~~~~~
For the use with @generatedValue(strategy="SEQUENCE") this
annotation allows to specify details about the sequence, such as
@@ -688,7 +718,8 @@ Example:
*/
protected $id = null;
-### @Table
+@Table
+~~~~~~~
Annotation describes the table an entity is persisted in. It is
placed on the entity-class PHP DocBlock and is optional. If it is
@@ -721,7 +752,8 @@ Example:
*/
class User { }
-### @UniqueConstraint
+@UniqueConstraint
+~~~~~~~~~~~~~~~~~~~~~
Annotation is used inside the `@Table <#ann_table>`_ annotation on
the entity-class level. It allows to hint the SchemaTool to
@@ -748,7 +780,8 @@ Example:
{
}
-### @Version
+@Version
+~~~~~~~~~~~~~~
Marker annotation that defines a specified column as version
attribute used in an optimistic locking scenario. It only works on
diff --git a/manual/en/annotations-reference.txt b/manual/en/annotations-reference.txt
deleted file mode 100644
index a95362e9e..000000000
--- a/manual/en/annotations-reference.txt
+++ /dev/null
@@ -1,611 +0,0 @@
-In this chapter a reference of every Doctrine 2 Annotation is given with short explanations on their context and usage.
-
-## Index
-
-* [@Column](#ann_column)
-* [@ChangeTrackingPolicy](#ann_changetrackingpolicy)
-* [@DiscriminatorColumn](#ann_discriminatorcolumn)
-* [@DiscriminatorMap](#ann_discriminatormap)
-* [@Entity](#ann_entity)
-* [@GeneratedValue](#ann_generatedvalue)
-* [@HasLifecycleCallbacks](#ann_haslifecyclecallbacks)
-* [@Index](#ann_indexes)
-* [@Id](#ann_id)
-* [@InheritanceType](#ann_inheritancetype)
-* [@JoinColumn](#ann_joincolumn)
-* [@JoinTable](#ann_jointable)
-* [@ManyToOne](#ann_manytoone)
-* [@ManyToMany](#ann_manytomany)
-* [@MappedSuperclass](#ann_mappedsuperclass)
-* [@OneToOne](#ann_onetoone)
-* [@OneToMany](#ann_onetomany)
-* [@OrderBy](#ann_orderby)
-* [@PostLoad](#ann_postload)
-* [@PostPersist](#ann_postpersist)
-* [@PostRemove](#ann_postremove)
-* [@PostUpdate](#ann_postupdate)
-* [@PrePersist](#ann_prepersist)
-* [@PreRemove](#ann_preremove)
-* [@PreUpdate](#ann_preupdate)
-* [@SequenceGenerator](#ann_sequencegenerator)
-* [@Table](#ann_table)
-* [@UniqueConstraint](#ann_uniqueconstraint)
-* [@Version](#ann_version)
-
-## Reference
-
-
-### @Column
-
-Marks an annotated instance variable as "persistent". It has to be inside the instance variables PHP DocBlock comment.
-Any value hold inside this variable will be saved to and loaded from the database as part of the lifecycle of the instance variables entity-class.
-
-Required attributes:
-
-* type - Name of the Doctrine Type which is converted between PHP and Database representation.
-
-Optional attributes:
-
-* name - By default the property name is used for the database column name also, however the 'name' attribute allows you to determine the column name.
-* length - Used by the "string" type to determine its maximum length in the database. Doctrine does not validate the length of a string values for you.
-* precision - The precision for a decimal (exact numeric) column (Applies only for decimal column)
-* scale - The scale for a decimal (exact numeric) column (Applies only for decimal column)
-* 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.
-* columnDefinition - DDL SQL snippet that starts after the column name and specifies the complete (non-portable!) column definition. This attribute allows to make use of advanced RMDBS features. However you should make careful use of this feature and the consequences. Additionally you should remember that the "type" 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 [@JoinColumn](#ann_joincolumn).
-
-Examples:
-
-
-### @ChangeTrackingPolicy
-
-The Change Tracking Policy annotation allows to specify how the Doctrine 2 UnitOfWork should detect changes
-in properties of entities during flush. By default each entity is checked according to a deferred implicit
-strategy, which means upon flush UnitOfWork compares all the properties of an entity to a previously stored
-snapshot. This works out of the box, however you might want to tweak the flush performance where using
-another change tracking policy is an interesting option.
-
-The [details on all the available change tracking policies](/../configuration#change-tracking-policies)
-can be found in the configuration section.
-
-Example:
-
-
-### @DiscrimnatorColumn
-
-This annotation is a required annotation for the topmost/super class of an inheritance hierarchy. It specifies
-the details of the column which saves the name of the class, which the entity is actually instantiated as.
-
-Required attributes:
-
-* name - The column name of the discriminator. This name is also used during Array hydration as key to specify the class-name.
-
-Optional attributes:
-
-* type - By default this is string.
-* length - By default this is 255.
-
-
-### @DiscriminatorMap
-
-The discriminator map is a required annotation on the top-most/super class in an inheritance hierarchy. It takes
-an array as only argument which defines which class should be saved under which name in the database. Keys
-are the database value and values are the classes, either as fully- or as unqualified class names depending
-if the classes are in the namespace or not.
-
-
-### @Entity
-
-Required annotation to mark a PHP class as Entity. Doctrine manages the persistence of all classes marked as entity.
-
-Optional attributes:
-
-* repositoryClass - Specifies the FQCN of a subclass of the Doctrine\ORM\EntityRepository. Use of repositories for entities is encouraged to keep specialized DQL and SQL operations separated from the Model/Domain Layer.
-
-Example:
-
-
-### @GeneratedValue
-
-Specifies which strategy is used for identifier generation for an instance variable which is annotated by [@Id](#ann_id).
-This annotation is optional and only has meaning when used in conjunction with @Id.
-
-If this annotation is not specified with @Id the NONE strategy is used as default.
-
-Required attributes:
-
-* strategy - Set the name of the identifier generation strategy. Valid values are AUTO, SEQUENCE, TABLE, IDENTITY and NONE.
-
-Example:
-
-
-### @HasLifecycleCallbacks
-
-Annotation which has to be set on the entity-class PHP DocBlock to notify Doctrine that this entity has entity life-cycle
-callback annotations set on at least one of its methods. Using @PostLoad, @PrePersist, @PostPersist, @PreRemove, @PostRemove,
-@PreUpdate or @PostUpdate without this marker annotation will make Doctrine ignore the callbacks.
-
-Example:
-
-
-### @Index
-
-Annotation is used inside the [@Table](#ann_table) annotation on the entity-class level. It allows to hint the
-SchemaTool to generate a database index on the specified table columns. It only has meaning in the SchemaTool
-schema generation context.
-
-Required attributes:
-
-* name - Name of the Index
-* columns - Array of columns.
-
-Example:
-
-
-### @Id
-
-The annotated instance variable will be marked as entity identifier, the primary key in the database.
-This annotation is a marker only and has no required or optional attributes. For entities that have multiple
-identifier columns each column has to be marked with @Id.
-
-Example:
-
-
-### @InheritanceType
-
-In an inheritance hierarchy you have to use this annotation on the topmost/super class to define which
-strategy should be used for inheritance. Currently Single Table and Class Table Inheritance are supported.
-
-This annotation has always been used in conjunction with the [@DiscriminatorMap](#ann_discriminatormap) and
-[@DiscriminatorColumn](#ann_discriminatorcolumn) annotations.
-
-Examples:
-
-
-### @JoinColumn
-
-This annotation is used in the context of relations in [@ManyToOne](#ann_manytoone), [@OneToOne](#ann_onetoone) fields
-and in the Context of [@JoinTable](#ann_jointable) nested inside a @ManyToMany. This annotation is not required.
-If its not specified the attributes *name* and *referencedColumnName* are inferred from the table and primary key names.
-
-Required attributes:
-
-* name - Column name that holds the foreign key identifier for this relation. In the context of @JoinTable it specifies the column name in the join table.
-* referencedColumnName - Name of the primary key identifier that is used for joining of this relation.
-
-Optional attributes:
-
-* unique - Determines if this relation exclusive between the affected entities and should be enforced so on the database constraint level. Defaults to false.
-* nullable - Determine if the related entity is required, or if null is an allowed state for the relation. Defaults to true.
-* onDelete - Cascade Action (Database-level)
-* onUpdate - Cascade Action (Database-level)
-* columnDefinition - DDL SQL snippet that starts after the column name and specifies the complete (non-portable!) column definition. This attribute allows to make use of advanced RMDBS features. Using 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 [@Column](#ann_column) also sets the related @JoinColumn's columnDefinition. This is necessary to make foreign keys work.
-
-Example:
-
-
-### @JoinColumns
-
-An array of @JoinColumn annotations for a [@ManyToOne](#ann_manytoone) or [@OneToOne](#ann_onetoone) relation
-with an entity that has multiple identifiers.
-
-
-### @JoinTable
-
-Using [@OneToMany](#ann_onetomany) or [@ManyToMany](#ann_manytomany) on the owning side of the relation requires to specify
-the @JoinTable annotation which describes the details of the database join table. If you do not specify @JoinTable on
-these relations reasonable mapping defaults apply using the affected table and the column names.
-
-Required attributes:
-
-* name - Database name of the join-table
-* joinColumns - An array of @JoinColumn annotations describing the join-relation between the owning entities table and the join table.
-* inverseJoinColumns - An array of @JoinColumn annotations describing the join-relation between the inverse entities table and the join table.
-
-Optional attributes:
-
-* schema - Database schema name of this table.
-
-Example:
-
-
-### @ManyToOne
-
-Defines that the annotated instance variable holds a reference that describes a many-to-one relationship between two entities.
-
-Required attributes:
-
-* targetEntity - FQCN of the referenced target entity. Can be the unqualified class name if both classes are in the same namespace. *IMPORTANT:* No leading backslash!
-
-Optional attributes:
-
-* cascade - Cascade Option
-* fetch - One of LAZY or EAGER
-* inversedBy - The inversedBy attribute designates the field in the entity that is the inverse side of the relationship.
-
-Example:
-
-
-### @ManyToMany
-
-Defines an instance variable holds a many-to-many relationship between two entities. [@JoinTable](#ann_jointable)
-is an additional, optional annotation that has reasonable default configuration values using the table
-and names of the two related entities.
-
-Required attributes:
-
-* targetEntity - FQCN of the referenced target entity. Can be the unqualified class name if both classes are in the same namespace. *IMPORTANT:* No leading backslash!
-
-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.
-* 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
-
-> **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:
-
-
-### @MappedSuperclass
-
-An mapped superclass is an abstract or concrete class that provides persistent entity state and mapping information
-for its subclasses, but which is not itself an entity. This annotation is specified on the Class docblock
-and has no additional attributes.
-
-The @MappedSuperclass annotation cannot be used in conjunction with @Entity. See the Inheritance Mapping
-section for [more details on the restrictions of mapped superclasses](/../inheritance-mapping#mapped-superclasses).
-
-
-### @OneToOne
-
-The @OneToOne annotation works almost exactly as the [@ManyToOne](#ann_manytoone) with one additional option
-that can be specified. The configuration defaults for [@JoinColumn](#ann_joincolumn) using the target entity table and primary key column names
-apply here too.
-
-Required attributes:
-
-* targetEntity - FQCN of the referenced target entity. Can be the unqualified class name if both classes are in the same namespace. *IMPORTANT:* No leading backslash!
-
-Optional attributes:
-
-* cascade - Cascade Option
-* fetch - One of LAZY or EAGER
-* orphanRemoval - Boolean that specifies if orphans, inverse OneToOne entities that are not connected to any
-owning instance, should be removed by Doctrine. Defaults to false.
-* inversedBy - The inversedBy attribute designates the field in the entity that is the inverse side of the relationship.
-
-Example:
-
-
-### @OneToMany
-
-Required attributes:
-
-* targetEntity - FQCN of the referenced target entity. Can be the unqualified class name if both classes are in the same namespace. *IMPORTANT:* No leading backslash!
-
-Optional attributes:
-
-* cascade - Cascade Option
-* orphanRemoval - Boolean that specifies if orphans, inverse OneToOne entities that are not connected to any
-owning instance, should be removed by Doctrine. Defaults to false.
-* 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.
-
-Example:
-
-
-### @OrderBy
-
-Optional annotation that can be specified with a [@ManyToMany](#ann_manytomany) or [@OneToMany](#ann_onetomany)
-annotation to specify by which criteria the collection should be retrieved from the database by using an ORDER BY
-clause.
-
-This annotation requires a single non-attributed value with an DQL snippet:
-
-Example:
-
-
-### @PostLoad
-
-Marks a method on the entity to be called as a @PostLoad event. Only works with @HasLifecycleCallbacks in the entity class PHP DocBlock.
-
-
-### @PostPersist
-
-Marks a method on the entity to be called as a @PostPersist event. Only works with @HasLifecycleCallbacks in the entity class PHP DocBlock.
-
-
-### @PostRemove
-
-Marks a method on the entity to be called as a @PostRemove event. Only works with @HasLifecycleCallbacks in the entity class PHP DocBlock.
-
-
-### @PostUpdate
-
-Marks a method on the entity to be called as a @PostUpdate event. Only works with @HasLifecycleCallbacks in the entity class PHP DocBlock.
-
-
-### @PrePersist
-
-Marks a method on the entity to be called as a @PrePersist event. Only works with @HasLifecycleCallbacks in the entity class PHP DocBlock.
-
-
-### @PreRemove
-
-Marks a method on the entity to be called as a @PreRemove event. Only works with @HasLifecycleCallbacks in the entity class PHP DocBlock.
-
-
-### @PreUpdate
-
-Marks a method on the entity to be called as a @PreUpdate event. Only works with @HasLifecycleCallbacks in the entity class PHP DocBlock.
-
-
-### @SequenceGenerator
-
-For the use with @generatedValue(strategy="SEQUENCE") this annotation allows to specify details about the sequence,
-such as the increment size and initial values of the sequence.
-
-Required attributes:
-
-* sequenceName - Name of the sequence
-
-Optional attributes:
-
-* allocationSize - Increment the sequence by the allocation size when its fetched. A value larger than 1 allows to optimize for scenarios where you create more than one new entity per request. Defaults to 10
-* initialValue - Where does the sequence start, defaults to 1.
-
-Example:
-
-
-### @Table
-
-Annotation describes the table an entity is persisted in. It is placed on the entity-class PHP DocBlock and is optional.
-If it is not specified the table name will default to the entities unqualified classname.
-
-Required attributes:
-
-* name - Name of the table
-
-Optional attributes:
-
-* schema - Database schema name of this table.
-* indexes - Array of @Index annotations
-* uniqueConstraints - Array of @UniqueConstraint annotations.
-
-Example:
-
-
-### @UniqueConstraint
-
-Annotation is used inside the [@Table](#ann_table) annotation on the entity-class level. It allows to hint the
-SchemaTool to generate a database unique constraint on the specified table columns. It only has meaning in the SchemaTool
-schema generation context.
-
-Required attributes:
-
-* name - Name of the Index
-* columns - Array of columns.
-
-Example:
-
-
-### @Version
-
-Marker annotation that defines a specified column as version attribute used in an optimistic locking scenario.
-It only works on [@Column](#ann_column) annotations that have the type integer or datetime.
-
-Example:
-
- **TIP**
-> The constructor of an entity is only ever invoked when *you* construct a new instance
-> with the *new* keyword. Doctrine never calls entity constructors, thus you are free to use
-> them as you wish and even have it require arguments of any type.
-
-### Entity states
-
-An entity instance can be characterized as being NEW, MANAGED, DETACHED or REMOVED.
-
-* A NEW entity instance has no persistent identity, and is not yet associated with an EntityManager and a UnitOfWork (i.e. those just created with the "new" operator).
-* A MANAGED entity instance is an instance with a persistent identity that is associated with an EntityManager and whose persistence is thus managed.
-* A DETACHED entity instance is an instance with a persistent identity that is not (or no longer) associated with an EntityManager and a UnitOfWork.
-* A REMOVED entity instance is an instance with a persistent identity, associated with an EntityManager, that will be removed from the database upon transaction commit.
-
-### Persistent fields
-
-The persistent state of an entity is represented by instance variables. An
-instance variable must be directly accessed only from within the methods of the
-entity by the entity instance itself. Instance variables must not be accessed by
-clients of the entity. The state of the entity is available to clients only through
-the entity’s methods, i.e. accessor methods (getter/setter methods) or other
-business methods.
-
-Collection-valued persistent fields and properties must be defined in terms of
-the `Doctrine\Common\Collections\Collection` interface. The collection
-implementation type may be used by the application to initialize fields or
-properties before the entity is made persistent. Once the entity becomes
-managed (or detached), subsequent access must be through the interface type.
-
-### Serializing entities
-
-Serializing entities can be problematic and is not really recommended, at least not as long as an
-entity instance still holds references to proxy objects or is still managed by an EntityManager.
-If you intend to serialize (and unserialize) entity instances that still hold references to proxy objects
-you may run into problems with private properties because of technical limitations.
-Proxy objects implement `__sleep` and it is not possible for `__sleep` to return names of
-private properties in parent classes. On the other hand it is not a solution for proxy objects
-to implement `Serializable` because Serializable does not work well with any potential cyclic
-object references (at least we did not find a way yet, if you did, please contact us).
-
-## The EntityManager
-
-The `EntityManager` class is a central access point to the ORM functionality
-provided by Doctrine 2. The `EntityManager` API is used to manage the persistence
-of your objects and to query for persistent objects.
-
-### Transactional write-behind
-
-An `EntityManager` and the underlying `UnitOfWork` employ a strategy called
-"transactional write-behind" that delays the execution of SQL statements in
-order to execute them in the most efficient way and to execute them at the end
-of a transaction so that all write locks are quickly released. You should see
-Doctrine as a tool to synchronize your in-memory objects with the database in
-well defined units of work. Work with your objects and modify them as usual and
-when you're done call `EntityManager#flush()` to make your changes persistent.
-
-### The Unit of Work
-
-Internally an `EntityManager` uses a `UnitOfWork`, which is a typical
-implementation of the [Unit of Work pattern](http://martinfowler.com/eaaCatalog/unitOfWork.html), 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.
\ No newline at end of file
diff --git a/manual/en/association-mapping.rst b/manual/en/association-mapping.rst
index de7b72790..6b1631905 100644
--- a/manual/en/association-mapping.rst
+++ b/manual/en/association-mapping.rst
@@ -1,3 +1,6 @@
+Association Mapping
+===================
+
This chapter explains how associations between entities are mapped
with Doctrine. We start out with an explanation of the concept of
owning and inverse sides which is important to understand when
@@ -65,7 +68,9 @@ The owning side of a bidirectional association is the side Doctrine
consequently whether there is anything to do to update the
association in the database.
- **NOTE** "Owning side" and "inverse side" are technical concepts of
+.. note::
+
+ "Owning side" and "inverse side" are technical concepts of
the ORM technology, not concepts of your domain model. What you
consider as the owning side in your domain model can be different
from what the owning side is for Doctrine. These are unrelated.
@@ -96,7 +101,9 @@ and more importantly because you can not pass this collection to
all the useful PHP array functions, which makes it very hard to
work with.
- **CAUTION** The Collection interface and ArrayCollection class,
+.. warning::
+
+ The Collection interface and ArrayCollection class,
like everything else in the Doctrine namespace, are neither part of
the ORM, nor the DBAL, it is a plain PHP class that has no outside
dependencies apart from dependencies on PHP itself (and the SPL).
@@ -280,7 +287,7 @@ Or you can trigger the validation manually:
If the mapping is invalid the errors array contains a positive
number of elements with error messages.
- **NOTE**
+.. note::
One common error is to use a backlash in front of the
fully-qualified class-name. Whenever a FQCN is represented inside a
@@ -325,9 +332,8 @@ as the defaults would be the same.
Generated MySQL Schema:
-::
+.. code-block:: sql
- [sql]
CREATE TABLE Product (
id INT AUTO_INCREMENT NOT NULL,
shipping_id INT DEFAULT NULL,
@@ -381,9 +387,8 @@ as the defaults would be the same.
Generated MySQL Schema:
-::
+.. code-block:: sql
- [sql]
CREATE TABLE Cart (
id INT AUTO_INCREMENT NOT NULL,
customer_id INT DEFAULT NULL,
@@ -426,9 +431,8 @@ as the defaults would be the same.
With the generated MySQL Schema:
-::
+.. code-block:: sql
- [sql]
CREATE TABLE Student (
id INT AUTO_INCREMENT NOT NULL,
mentor_id INT DEFAULT NULL,
@@ -476,15 +480,16 @@ association:
// ...
}
- **NOTE** One-To-Many uni-directional relations with join-table only
+.. note::
+
+ One-To-Many uni-directional relations with join-table only
work using the @ManyToMany annotation and a unique-constraint.
Generates the following MySQL Schema:
-::
+.. code-block:: sql
- [sql]
CREATE TABLE User (
id INT AUTO_INCREMENT NOT NULL,
PRIMARY KEY(id)
@@ -532,16 +537,17 @@ with the following:
// ...
}
- **TIP** The above ``@JoinColumn`` is optional as it would default
+.. note::
+
+ 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.
Generated MySQL Schema:
-::
+.. code-block:: sql
- [sql]
CREATE TABLE User (
id INT AUTO_INCREMENT NOT NULL,
address_id INT DEFAULT NULL,
@@ -597,9 +603,8 @@ as the defaults would be the same.
Generated MySQL Schema:
-::
+.. code-block:: sql
- [sql]
CREATE TABLE Product (
id INT AUTO_INCREMENT NOT NULL,
PRIMARY KEY(id)
@@ -649,9 +654,8 @@ as the defaults would be the same.
Generated MySQL Schema:
-::
+.. code-block:: sql
- [sql]
CREATE TABLE Category (
id INT AUTO_INCREMENT NOT NULL,
parent_id INT DEFAULT NULL,
@@ -706,9 +710,8 @@ entities:
Generated MySQL Schema:
-::
+.. code-block:: sql
- [sql]
CREATE TABLE User (
id INT AUTO_INCREMENT NOT NULL,
PRIMARY KEY(id)
@@ -868,9 +871,8 @@ field named ``$friendsWithMe`` and ``$myFriends``.
Generated MySQL Schema:
-::
+.. code-block:: sql
- [sql]
CREATE TABLE User (
id INT AUTO_INCREMENT NOT NULL,
PRIMARY KEY(id)
@@ -940,30 +942,26 @@ ORDER BY, since g is not fetch joined:
However the following:
-::
+.. code-block:: sql
- [sql]
SELECT u, g FROM User u JOIN u.groups g WHERE u.id = 10
...would internally be rewritten to:
-::
+.. code-block:: sql
- [sql]
SELECT u, g FROM User u JOIN u.groups g WHERE u.id = 10 ORDER BY g.name ASC
You can't reverse the order with an explicit DQL ORDER BY:
-::
+.. code-block:: sql
- [sql]
SELECT u, g FROM User u JOIN u.groups g WHERE u.id = 10 ORDER BY g.name DESC
...is internally rewritten to:
-::
+.. code-block:: sql
- [sql]
SELECT u, g FROM User u JOIN u.groups g WHERE u.id = 10 ORDER BY g.name DESC, g.name ASC
diff --git a/manual/en/association-mapping.txt b/manual/en/association-mapping.txt
deleted file mode 100644
index fb22869f2..000000000
--- a/manual/en/association-mapping.txt
+++ /dev/null
@@ -1,756 +0,0 @@
-This chapter explains how associations between entities are mapped with Doctrine. We start out with an explanation of the concept of owning and inverse sides which is important to understand when working with bidirectional associations. Please read these explanations carefully.
-
-## Owning Side and Inverse Side
-
-When mapping bidirectional associations it is important to understand the concept of the owning and inverse sides. The following general rules apply:
-
-* Relationships may be bidirectional or unidirectional.
-* A bidirectional relationship has both an owning side and an inverse side.
-* A unidirectional relationship only has an owning side.
-* The owning side of a relationship determines the updates to the relationship in the database.
-
-The following rules apply to *bidirectional* associations:
-
-* The inverse side of a bidirectional relationship must refer to its owning side by use of the mappedBy attribute of the OneToOne, OneToMany, or ManyToMany mapping declaration. The mappedBy attribute designates the field in the entity that is the owner of the relationship.
-* The owning side of a bidirectional relationship must refer to its inverse side by use of the inversedBy attribute of the OneToOne, ManyToOne, or ManyToMany mapping declaration. The inversedBy attribute designates the field in the entity that is the inverse side of the relationship.
-* The many side of OneToMany/ManyToOne bidirectional relationships *must* be the owning side, hence the mappedBy element can not be specified on the ManyToOne side.
-* For OneToOne bidirectional relationships, the owning side corresponds to the side that contains the corresponding foreign key (@JoinColumn(s)).
-* 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).
-
-Especially important is the following:
-
-**The owning side of a relationship determines the updates to the relationship in the database**.
-
-To fully understand this, remember how bidirectional associations are maintained
-in the object world. There are 2 references on each side of the association
-and these 2 references both represent the same association but can change
-independently of one another. Of course, in a correct application the semantics
-of the bidirectional association are properly maintained by the application
-developer (that's his responsibility). Doctrine needs to know which of
-these two in-memory references is the one that should be persisted and which
-not. This is what the owning/inverse concept is mainly used for.
-
-**Changes made only to the inverse side of an association are ignored. Make sure to update both sides of a bidirectional association (or at least the owning side, from Doctrine's point of view)**
-
-The owning side of a bidirectional association is the side Doctrine "looks at" when determining
-the state of the association, and consequently whether there is anything to do to update the association
-in the database.
-
-> **NOTE**
-> "Owning side" and "inverse side" are technical concepts of the ORM technology, not concepts
-> of your domain model. What you consider as the owning side in your domain model can be different
-> from what the owning side is for Doctrine. These are unrelated.
-
-## Collections
-
-In all the examples of many-valued associations in this manual we will make use of a `Collection` interface and a corresponding default implementation `ArrayCollection` that are defined in the `Doctrine\Common\Collections` namespace. Why do we need that? Doesn't that couple my domain model to Doctrine? Unfortunately, PHP arrays, while being great for many things, do not make up for good collections of business objects, especially not in the context of an ORM. The reason is that plain PHP arrays can not be transparently extended / instrumented in PHP code, which is necessary for a lot of advanced ORM features. The classes / interfaces that come closest to an OO collection are ArrayAccess and ArrayObject but until instances of these types can be used in all places where a plain array can be used (something that may happen in PHP6) their usability is fairly limited. You "can" type-hint on `ArrayAccess` instead of `Collection`, since the Collection interface extends `ArrayAccess`, but this will severely limit you in the way you can work with the collection, because the `ArrayAccess` API is (intentionally) very primitive and more importantly because you can not pass this collection to all the useful PHP array functions, which makes it very hard to work with.
-
-> **CAUTION**
-> The Collection interface and ArrayCollection class, like everything else in the
-> Doctrine\Common namespace, are neither part of the ORM, nor the DBAL, it is a plain PHP
-> class that has no outside dependencies apart from dependencies on PHP itself (and the
-> SPL). Therefore using this class in your domain classes and elsewhere does not introduce
-> a coupling to the persistence layer. The Collection class, like everything else in the
-> Common namespace, is not part of the persistence layer. You could even copy that class
-> over to your project if you want to remove Doctrine from your project and all your
-> domain classes will work the same as before.
-
-## Mapping Defaults
-
-Before we introduce all the association mappings in detail, you should note that the @JoinColumn and @JoinTable
-definitions are usually optional and have sensible default values.
-The defaults for a join column in a one-to-one/many-to-one association is as follows:
-
- name: "_id"
- referencedColumnName: "id"
-
-As an example, consider this mapping:
-
- groups;
- }
- }
-
-With this code alone the `$groups` field only contains an instance of `Doctrine\Common\Collections\Collection` if the user is retrieved from
-Doctrine, however not after you instantiated a fresh instance of the User. When your user entity is still new `$groups` will obviously be null.
-
-This is why we recommend to initialize all collection fields to an empty `ArrayCollection` in your entities constructor:
-
- groups = new ArrayCollection();
- }
-
- public function getGroups()
- {
- return $this->groups;
- }
- }
-
-Now the following code will be working even if the Entity hasn't been associated with an EntityManager yet:
-
- find('Group', $groupId);
- $user = new User();
- $user->getGroups()->add($group);
-
-## Runtime vs Development Mapping Validation
-
-For performance reasons Doctrine 2 has to skip some of the necessary validation of association mappings.
-You have to execute this validation in your development workflow to verify the associations are correctly
-defined.
-
-You can either use the Doctrine Command Line Tool:
-
- doctrine orm:validate-schema
-
-Or you can trigger the validation manually:
-
- use Doctrine\ORM\Tools\SchemaValidator;
-
- $validator = new SchemaValidator($entityManager);
- $errors = $validator->validateMapping();
-
- if (count($errors) > 0) {
- // Lots of errors!
- echo implode("\n\n", $errors);
- }
-
-If the mapping is invalid the errors array contains a positive number of elements with error messages.
-
-> **NOTE**
->
-> One common error is to use a backlash in front of the fully-qualified class-name. Whenever a FQCN is represented
-> inside a string (such as in your mapping definitions) you have to drop the prefix backslash. PHP does this with
-> `get_class()` or Reflection methods for backwards compatibility reasons.
-
-## One-To-One, Unidirectional
-
-A unidirectional one-to-one association is very common. Here is an example of a `Product` that has one `Shipping` object associated to it. The `Shipping` side does not reference back to the `Product` so it is unidirectional.
-
- phonenumbers = new \Doctrine\Common\Collections\ArrayCollection();
- }
-
- // ...
- }
-
- /** @Entity */
- class Phonenumber
- {
- // ...
- }
-
-> **NOTE**
-> One-To-Many uni-directional relations with join-table only work using the @ManyToMany annotation and a unique-constraint.
-
-Generates the following MySQL Schema:
-
- [sql]
- CREATE TABLE User (
- id INT AUTO_INCREMENT NOT NULL,
- PRIMARY KEY(id)
- ) ENGINE = InnoDB;
-
- CREATE TABLE users_phonenumbers (
- user_id INT NOT NULL,
- phonenumber_id INT NOT NULL,
- UNIQUE INDEX users_phonenumbers_phonenumber_id_uniq (phonenumber_id),
- PRIMARY KEY(user_id, phonenumber_id)
- ) ENGINE = InnoDB;
-
- CREATE TABLE Phonenumber (
- id INT AUTO_INCREMENT NOT NULL,
- PRIMARY KEY(id)
- ) ENGINE = InnoDB;
-
- ALTER TABLE users_phonenumbers ADD FOREIGN KEY (user_id) REFERENCES User(id);
- ALTER TABLE users_phonenumbers ADD FOREIGN KEY (phonenumber_id) REFERENCES Phonenumber(id);
-
-## Many-To-One, Unidirectional
-
-You can easily implement a many-to-one unidirectional association with the following:
-
- **TIP**
-> 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.
-
-Generated MySQL Schema:
-
- [sql]
- CREATE TABLE User (
- id INT AUTO_INCREMENT NOT NULL,
- address_id INT DEFAULT NULL,
- PRIMARY KEY(id)
- ) ENGINE = InnoDB;
-
- CREATE TABLE Address (
- id INT AUTO_INCREMENT NOT NULL,
- PRIMARY KEY(id)
- ) ENGINE = InnoDB;
-
- ALTER TABLE User ADD FOREIGN KEY (address_id) REFERENCES Address(id);
-
-## One-To-Many, Bidirectional
-
-Bidirectional one-to-many associations are very common. The following code shows an example with a Product and a Feature class:
-
- features = new \Doctrine\Common\Collections\ArrayCollection();
- }
- }
-
- /** @Entity */
- class Feature
- {
- // ...
- /**
- * @ManyToOne(targetEntity="Product", inversedBy="features")
- * @JoinColumn(name="product_id", referencedColumnName="id")
- */
- private $product;
- // ...
- }
-
-Note that the @JoinColumn is not really necessary in this example, as the defaults would be the same.
-
-Generated MySQL Schema:
-
- [sql]
- CREATE TABLE Product (
- id INT AUTO_INCREMENT NOT NULL,
- PRIMARY KEY(id)
- ) ENGINE = InnoDB;
- CREATE TABLE Feature (
- id INT AUTO_INCREMENT NOT NULL,
- product_id INT DEFAULT NULL,
- PRIMARY KEY(id)
- ) ENGINE = InnoDB;
- ALTER TABLE Feature ADD FOREIGN KEY (product_id) REFERENCES Product(id);
-
-## One-To-Many, Self-referencing
-
-You can also setup a one-to-many association that is self-referencing. In this example we
-setup a hierarchy of `Category` objects by creating a self referencing relationship.
-This effectively models a hierarchy of categories and from the database perspective is known as an adjacency list approach.
-
- children = new \Doctrine\Common\Collections\ArrayCollection();
- }
- }
-
-Note that the @JoinColumn is not really necessary in this example, as the defaults would be the same.
-
-Generated MySQL Schema:
-
- [sql]
- CREATE TABLE Category (
- id INT AUTO_INCREMENT NOT NULL,
- parent_id INT DEFAULT NULL,
- PRIMARY KEY(id)
- ) ENGINE = InnoDB;
- ALTER TABLE Category ADD FOREIGN KEY (parent_id) REFERENCES Category(id);
-
-## Many-To-Many, Unidirectional
-
-Real many-to-many associations are less common. The following example shows a unidirectional association between User and Group entities:
-
- groups = new \Doctrine\Common\Collections\ArrayCollection();
- }
- }
-
- /** @Entity */
- class Group
- {
- // ...
- }
-
-> **NOTE**
-> Why are many-to-many associations less common? Because frequently you want to associate
-> additional attributes with an association, in which case you introduce an association
-> class. Consequently, the direct many-to-many association disappears and is replaced
-> by one-to-many/many-to-one associations between the 3 participating classes.
-
-Generated MySQL Schema:
-
- [sql]
- CREATE TABLE User (
- id INT AUTO_INCREMENT NOT NULL,
- PRIMARY KEY(id)
- ) ENGINE = InnoDB;
- CREATE TABLE users_groups (
- user_id INT NOT NULL,
- group_id INT NOT NULL,
- PRIMARY KEY(user_id, group_id)
- ) ENGINE = InnoDB;
- CREATE TABLE Group (
- id INT AUTO_INCREMENT NOT NULL,
- PRIMARY KEY(id)
- ) ENGINE = InnoDB;
- ALTER TABLE users_groups ADD FOREIGN KEY (user_id) REFERENCES User(id);
- ALTER TABLE users_groups ADD FOREIGN KEY (group_id) REFERENCES Group(id);
-
-## Many-To-Many, Bidirectional
-
-Here is a similar many-to-many relationship as above except this one is bidirectional.
-
- groups = new \Doctrine\Common\Collections\ArrayCollection();
- }
-
- // ...
- }
-
- /** @Entity */
- class Group
- {
- // ...
- /**
- * @ManyToMany(targetEntity="User", mappedBy="groups")
- */
- private $users;
-
- public function __construct() {
- $this->users = new \Doctrine\Common\Collections\ArrayCollection();
- }
-
- // ...
- }
-
-The MySQL schema is exactly the same as for the Many-To-Many uni-directional case above.
-
-### Picking Owning and Inverse Side
-
-For Many-To-Many associations you can chose which entity is the owning and which the inverse side. There is
-a very simple semantic rule to decide which side is more suitable to be the owning side from a developers perspective.
-You only have to ask yourself, which entity is responsible for the connection management and pick that as the owning side.
-
-Take an example of two entities `Article` and `Tag`. Whenever you want to connect an Article to a Tag and vice-versa, it is mostly
-the Article that is responsible for this relation. Whenever you add a new article, you want to connect it with existing or new tags.
-Your create Article form will probably support this notion and allow to specify the tags directly. This is why you should
-pick the Article as owning side, as it makes the code more understandable:
-
- addArticle($this); // synchronously updating inverse side
- $this->tags[] = $tag;
- }
- }
-
- class Tag
- {
- private $articles;
-
- public function addArticle(Article $article)
- {
- $this->articles[] = $article;
- }
- }
-
-This allows to group the tag adding on the `Article` side of the association:
-
- addTag($tagA);
- $article->addTag($tagB);
-
-## Many-To-Many, Self-referencing
-
-You can even have a self-referencing many-to-many association. A common scenario is where a `User` has friends and the target entity of that relationship is a `User` so it is self referencing. In this example it is bidirectional so `User` has a field named `$friendsWithMe` and `$myFriends`.
-
- friendsWithMe = new \Doctrine\Common\Collections\ArrayCollection();
- $this->myFriends = new \Doctrine\Common\Collections\ArrayCollection();
- }
-
- // ...
- }
-
-Generated MySQL Schema:
-
- [sql]
- CREATE TABLE User (
- id INT AUTO_INCREMENT NOT NULL,
- PRIMARY KEY(id)
- ) ENGINE = InnoDB;
- CREATE TABLE friends (
- user_id INT NOT NULL,
- friend_user_id INT NOT NULL,
- PRIMARY KEY(user_id, friend_user_id)
- ) ENGINE = InnoDB;
- ALTER TABLE friends ADD FOREIGN KEY (user_id) REFERENCES User(id);
- ALTER TABLE friends ADD FOREIGN KEY (friend_user_id) REFERENCES User(id);
-
-## Ordering To-Many Collections
-
-In many use-cases you will want to sort collections when they are retrieved from the database.
-In userland you do this as long as you haven't initially saved an entity with its associations
-into the database. To retrieve a sorted collection from the database you can use the
-`@OrderBy` annotation with an collection that specifies an DQL snippet that is appended
-to all queries with this collection.
-
-Additional to any `@OneToMany` or `@ManyToMany` annotation you can specify the `@OrderBy`
-in the following way:
-
- 10
-
-However the following:
-
- [sql]
- SELECT u, g FROM User u JOIN u.groups g WHERE u.id = 10
-
-...would internally be rewritten to:
-
- [sql]
- SELECT u, g FROM User u JOIN u.groups g WHERE u.id = 10 ORDER BY g.name ASC
-
-You can't reverse the order with an explicit DQL ORDER BY:
-
- [sql]
- SELECT u, g FROM User u JOIN u.groups g WHERE u.id = 10 ORDER BY g.name DESC
-
-...is internally rewritten to:
-
- [sql]
- SELECT u, g FROM User u JOIN u.groups g WHERE u.id = 10 ORDER BY g.name DESC, g.name ASC
\ No newline at end of file
diff --git a/manual/en/basic-mapping.rst b/manual/en/basic-mapping.rst
index 7d8378f4e..506337092 100644
--- a/manual/en/basic-mapping.rst
+++ b/manual/en/basic-mapping.rst
@@ -1,3 +1,6 @@
+Basic Mapping
+=============
+
This chapter explains the basic mapping of objects and properties.
Mapping of associations will be covered in the next chapter
"Association Mapping".
@@ -17,7 +20,9 @@ This manual usually uses docblock annotations in all the examples
that are spread throughout all chapters. There are dedicated
chapters for XML and YAML mapping, respectively.
- **NOTE** If you're wondering which mapping driver gives the best
+.. note::
+
+ If you're wondering which mapping driver gives the best
performance, the answer is: None. Once the metadata of a class has
been read from the source (annotations, xml or yaml) it is stored
in an instance of the ``Doctrine\ORM\Mapping\ClassMetadata`` class
@@ -127,11 +132,14 @@ built-in mapping types:
PHP double. *IMPORTANT*: Works only with locale settings that use
decimal points as separator.
- **NOTE** Doctrine Mapping Types are NOT SQL types and NOT PHP
+.. note::
+
+ Doctrine Mapping Types are NOT SQL types and NOT PHP
types! They are mapping types between 2 types.
+.. warning::
- **CAUTION** Mapping types are *case-sensitive*. For example, using
+ Mapping types are *case-sensitive*. For example, using
a DateTime column will NOT match the datetime type that ships with
Doctrine 2!
@@ -259,7 +267,9 @@ know about it. This can be achieved through the
``Doctrine\DBAL\Configuration#setCustomTypes(array $types)``
method.
- **NOTE** ``Doctrine\ORM\Configuration`` is a subclass of
+.. note::
+
+ ``Doctrine\ORM\Configuration`` is a subclass of
``Doctrine\DBAL\Configuration``, so the methods are available on
your ORM Configuration instance as well.
@@ -428,7 +438,9 @@ need to access the sequence once to generate the identifiers for
INCREMENT BY value, otherwise you may get duplicate keys.
- **TIP** It is possible to use strategy="AUTO" and at the same time
+.. note::
+
+ It is possible to use strategy="AUTO" and at the same time
specifying a @SequenceGenerator. In such a case, your custom
sequence settings are used in the case where the preferred strategy
of the underlying platform is SEQUENCE, such as for Oracle and
@@ -467,11 +479,14 @@ backticks. Here is an example:
Doctrine will then quote this column name in all SQL statements
according to the used database platform.
- **CAUTION** Identifier Quoting is not supported for join column
+.. warning::
+
+ Identifier Quoting is not supported for join column
names or discriminator column names.
+.. warning::
- **CAUTION** Identifier Quoting is a feature that is mainly intended
+ Identifier Quoting is a feature that is mainly intended
to support legacy database schemas. The use of reserved words and
identifier quoting is generally discouraged. Identifier quoting
should not be used to enable the use non-standard-characters such
diff --git a/manual/en/basic-mapping.txt b/manual/en/basic-mapping.txt
deleted file mode 100644
index 15eeb81dc..000000000
--- a/manual/en/basic-mapping.txt
+++ /dev/null
@@ -1,321 +0,0 @@
-This chapter explains the basic mapping of objects and properties. Mapping of associations will be covered in the next chapter "Association Mapping".
-
-## Mapping Drivers
-
-Doctrine provides several different ways for specifying object-relational mapping metadata:
-
-* Docblock Annotations
-* XML
-* YAML
-
-This manual usually uses docblock annotations in all the examples that are spread throughout all chapters. There are dedicated chapters for XML and YAML mapping, respectively.
-
-> **NOTE**
-> If you're wondering which mapping driver gives the best performance, the answer is:
-> None. Once the metadata of a class has been read from the source (annotations, xml or
-> yaml) it is stored in an instance of the `Doctrine\ORM\Mapping\ClassMetadata` class
-> and these instances are stored in the metadata cache. Therefore at the end of the day
-> all drivers perform equally well. If you're not using a metadata cache (not
-> recommended!) then the XML driver might have a slight edge in performance due to the
-> powerful native XML support in PHP.
-
-## Introduction to Docblock Annotations
-
-You've probably used docblock annotations in some form already, most likely to provide documentation metadata for a tool like `PHPDocumentor` (@author, @link, ...). Docblock annotations are a tool to embed metadata inside the documentation section which can then be processed by some tool. Doctrine 2 generalizes the concept of docblock annotations so that they can be used for any kind of metadata and so that it is easy to define new docblock annotations. In order to allow more involved annotation values and to reduce the chances of clashes with other docblock annotations, the Doctrine 2 docblock annotations feature an alternative syntax that is heavily inspired by the Annotation syntax introduced in Java 5.
-
-The implementation of these enhanced docblock annotations is located in the `Doctrine\Common\Annotations` namespace and therefore part of the Common package. Doctrine 2 docblock annotations support namespaces and nested annotations among other things. The Doctrine 2 ORM defines its own set of docblock annotations for supplying object-relational mapping metadata.
-
-> **NOTE**
-> If you're not comfortable with the concept of docblock annotations, don't worry, as
-> mentioned earlier Doctrine 2 provides XML and YAML alternatives and you could easily
-> implement your own favourite mechanism for defining ORM metadata.
-
-## Persistent classes
-
-In order to mark a class for object-relational persistence it needs to be designated as an entity. This can be done through the `@Entity` marker annotation.
-
- **NOTE**
-> Doctrine Mapping Types are NOT SQL types and NOT PHP types! They are mapping types
-> between 2 types.
-
-> **CAUTION**
-> Mapping types are *case-sensitive*. For example, using a DateTime column will NOT match the datetime type
-> that ships with Doctrine 2!
-
-## Property Mapping
-
-After a class has been marked as an entity it can specify mappings for its instance fields. Here we will only look at simple fields that hold scalar values like strings, numbers, etc. Associations to other objects are covered in the chapter "Association Mapping".
-
-To mark a property for relational persistence the `@Column` docblock annotation is used. This annotation usually requires at least 1 attribute to be set, the `type`. The `type` attribute specifies the Doctrine Mapping Type to use for the field. If the type is not specified, 'string' is used as the default mapping type since it is the most flexible.
-
-Example:
-
- **NOTE**
-> `Doctrine\ORM\Configuration` is a subclass of `Doctrine\DBAL\Configuration`, so the
-> methods are available on your ORM Configuration instance as well.
-
-Here is an example:
-
- getConnection();
- $conn->getDatabasePlatform()->registerDoctrineTypeMapping('db_mytype', 'mytype');
-
-Now using Schema-Tool, whenever it detects a column having the `db_mytype` it will convert it into a `mytype`
-Doctrine Type instance for Schema representation. Keep in mind that you can easily produce clashes this way,
-each database type can only map to exactly one Doctrine mapping type.
-
-## Identifiers / Primary Keys
-
-Every entity class needs an identifier/primary key. You designate the field that serves as the identifier with the `@Id` marker annotation. Here is an example:
-
- **CAUTION**
-> The allocationSize is detected by SchemaTool and transformed into an "INCREMENT BY " clause
-> in the CREATE SEQUENCE statement. For a database schema created manually (and not SchemaTool) you have to
-> make sure that the allocationSize configuration option is never larger than the actual sequences INCREMENT BY value,
-> otherwise you may get duplicate keys.
-
-> **TIP**
-> It is possible to use strategy="AUTO" and at the same time specifying a @SequenceGenerator.
-> In such a case, your custom sequence settings are used in the case where the preferred
-> strategy of the underlying platform is SEQUENCE, such as for Oracle and PostgreSQL.
-
-
-### Composite Keys
-
-Doctrine 2 allows to use composite primary keys. There are however some restrictions opposed to using a single identifier.
-The use of the `@GeneratedValue` annotation is only supported for simple (not composite) primary keys, which means
-you can only use composite keys if you generate the primary key values yourself before calling `EntityManager#persist()`
-on the entity.
-
-To designate a composite primary key / identifier, simply put the @Id marker annotation on all fields that make up the primary key.
-
-## Quoting Reserved Words
-
-It may sometimes be necessary to quote a column or table name because it conflicts with a reserved word of the particular RDBMS in use. This is often referred to as "Identifier Quoting". To let Doctrine know that you would like a table or column name to be quoted in all SQL statements, enclose the table or column name in backticks. Here is an example:
-
- **CAUTION**
-> Identifier Quoting is not supported for join column names or discriminator column names.
-
-> **CAUTION**
-> Identifier Quoting is a feature that is mainly intended to support legacy database
-> schemas. The use of reserved words and identifier quoting is generally discouraged.
-> Identifier quoting should not be used to enable the use non-standard-characters such
-> as a dash in a hypothetical column `test-name`. Also Schema-Tool will likely have
-> troubles when quoting is used for case-sensitivity reasons (in Oracle for example).
\ No newline at end of file
diff --git a/manual/en/batch-processing.rst b/manual/en/batch-processing.rst
index 5e04e435b..b47906d6a 100644
--- a/manual/en/batch-processing.rst
+++ b/manual/en/batch-processing.rst
@@ -1,9 +1,14 @@
+Batch Processing
+================
+
This chapter shows you how to accomplish bulk inserts, updates and
deletes with Doctrine in an efficient way. The main problem with
bulk operations is usually not to run out of memory and this is
especially what the strategies presented here provide help with.
- **CAUTION** An ORM tool is not primarily well-suited for mass
+.. warning::
+
+ An ORM tool is not primarily well-suited for mass
inserts, updates or deletions. Every RDBMS has its own, most
effective way of dealing with such operations and if the options
outlined below are not sufficient for your purposes we recommend
diff --git a/manual/en/batch-processing.txt b/manual/en/batch-processing.txt
deleted file mode 100644
index fdc44bd45..000000000
--- a/manual/en/batch-processing.txt
+++ /dev/null
@@ -1,122 +0,0 @@
-This chapter shows you how to accomplish bulk inserts, updates and deletes with Doctrine in an efficient way. The main problem with bulk operations is usually not to run out of memory and this is especially what the strategies presented here provide help with.
-
-> **CAUTION**
-> An ORM tool is not primarily well-suited for mass inserts, updates or deletions.
-> Every RDBMS has its own, most effective way of dealing with such operations and if
-> the options outlined below are not sufficient for your purposes we recommend you
-> use the tools for your particular RDBMS for these bulk operations.
-
-## Bulk Inserts
-
-Bulk inserts in Doctrine are best performed in batches, taking advantage of the transactional write-behind behavior of an `EntityManager`. The following code shows an example for inserting 10000 objects with a batch size of 20. You may need to experiment with the batch size to find the size that works best for you. Larger batch sizes mean more prepared statement reuse internally but also mean more work during `flush`.
-
- setStatus('user');
- $user->setUsername('user' . $i);
- $user->setName('Mr.Smith-' . $i);
- $em->persist($user);
- if (($i % $batchSize) == 0) {
- $em->flush();
- $em->clear(); // Detaches all objects from Doctrine!
- }
- }
-
-## Bulk Updates
-
-There are 2 possibilities for bulk updates with Doctrine.
-
-### DQL UPDATE
-
-The by far most efficient way for bulk updates is to use a DQL UPDATE query. Example:
-
- createQuery('update MyProject\Model\Manager m set m.salary = m.salary * 0.9');
- $numUpdated = $q->execute();
-
-### Iterating results
-
-An alternative solution for bulk updates is to use the `Query#iterate()` facility to iterate over the query results step by step instead of loading the whole result into memory at once. The following example shows how to do this, combining the iteration with the batching strategy that was already used for bulk inserts:
-
- createQuery('select u from MyProject\Model\User u');
- $iterableResult = $q->iterate();
- foreach($iterableResult AS $row) {
- $user = $row[0];
- $user->increaseCredit();
- $user->calculateNewBonuses();
- if (($i % $batchSize) == 0) {
- $em->flush(); // Executes all updates.
- $em->clear(); // Detaches all objects from Doctrine!
- }
- ++$i;
- }
-
-> **NOTE**
-> Iterating results is not possible with queries that fetch-join a collection-valued
-> association. The nature of such SQL result sets is not suitable for incremental
-> hydration.
-
-## Bulk Deletes
-
-There are two possibilities for bulk deletes with Doctrine. You can either issue
-a single DQL DELETE query or you can iterate over results removing them one at a time.
-
-### DQL DELETE
-
-The by far most efficient way for bulk deletes is to use a DQL DELETE query.
-
-Example:
-
- createQuery('delete from MyProject\Model\Manager m where m.salary > 100000');
- $numDeleted = $q->execute();
-
-### Iterating results
-
-An alternative solution for bulk deletes is to use the `Query#iterate()` facility to iterate over the query results step by step instead of loading the whole result into memory at once. The following example shows how to do this:
-
- createQuery('select u from MyProject\Model\User u');
- $iterableResult = $q->iterate();
- while (($row = $iterableResult->next()) !== false) {
- $em->remove($row[0]);
- if (($i % $batchSize) == 0) {
- $em->flush(); // Executes all deletions.
- $em->clear(); // Detaches all objects from Doctrine!
- }
- ++$i;
- }
-
-> **NOTE**
-> Iterating results is not possible with queries that fetch-join a collection-valued
-> association. The nature of such SQL result sets is not suitable for incremental
-> hydration.
-
-## Iterating Large Results for Data-Processing
-
-You can use the `iterate()` method just to iterate over a large result and no UPDATE or DELETE
-intention. The `IterableResult` instance returned from `$query->iterate()` implements the
-Iterator interface so you can process a large result without memory problems using the
-following approach:
-
- _em->createQuery('select u from MyProject\Model\User u');
- $iterableResult = $q->iterate();
- foreach ($iterableResult AS $row) {
- // do stuff with the data in the row, $row[0] is always the object
-
- // detach from Doctrine, so that it can be Garbage-Collected immediately
- $this->_em->detach($row[0]);
- }
-
-> **NOTE**
-> Iterating results is not possible with queries that fetch-join a collection-valued
-> association. The nature of such SQL result sets is not suitable for incremental
-> hydration.
\ No newline at end of file
diff --git a/manual/en/best-practices.rst b/manual/en/best-practices.rst
index 48a8771c7..28709666f 100644
--- a/manual/en/best-practices.rst
+++ b/manual/en/best-practices.rst
@@ -1,7 +1,10 @@
- **NOTE** The best practices mentioned here that affect database
- design generally refer to best practices when working with Doctrine
- and do not necessarily reflect best practices for database design
- in general.
+Best Practices
+==============
+
+The best practices mentioned here that affect database
+design generally refer to best practices when working with Doctrine
+and do not necessarily reflect best practices for database design
+in general.
Don't use public properties on entities
diff --git a/manual/en/best-practices.txt b/manual/en/best-practices.txt
deleted file mode 100644
index 1d4cee690..000000000
--- a/manual/en/best-practices.txt
+++ /dev/null
@@ -1,77 +0,0 @@
-
-> **NOTE**
-> The best practices mentioned here that affect database design generally refer to best
-> practices when working with Doctrine and do not necessarily reflect best practices for
-> database design in general.
-
-## Don't use public properties on entities
-
-It is very important that you don't map public properties on entities, but only protected or private ones.
-The reason for this is simple, whenever you access a public property of a proxy object that hasn't been initialized
-yet the return value will be null. Doctrine cannot hook into this process and magically make the entity lazy load.
-
-This can create situations where it is very hard to debug the current failure. We therefore urge you to map only
-private and protected properties on entities and use getter methods or magic __get() to access them.
-
-## Constrain relationships as much as possible
-
-It is important to constrain relationships as much as possible. This means:
-
-* Impose a traversal direction (avoid bidirectional associations if possible)
-* Eliminate nonessential associations
-
-This has several benefits:
-
-* Reduced coupling in your domain model
-* Simpler code in your domain model (no need to maintain bidirectionality properly)
-* Less work for Doctrine
-
-## Avoid composite keys
-
-Even though Doctrine fully supports composite keys it is best not to use them if possible. Composite keys require additional work by Doctrine and thus have a higher probability of errors.
-
-## Use events judiciously
-
-The event system of Doctrine is great and fast. Even though making heavy use of events, especially lifecycle events, can have a negative impact on the performance of your application. Thus you should use events judiciously.
-
-## Use cascades judiciously
-
-Automatic cascades of the persist/remove/merge/etc. operations are very handy but should be used wisely. Do NOT simply add all cascades to all associations. Think about which cascades actually do make sense for you for a particular association, given the scenarios it is most likely used in.
-
-## Don't use special characters
-
-Avoid using any non-ASCII characters in class, field, table or column names. Doctrine itself is not unicode-safe in many places and will not be until PHP itself is fully unicode-aware (PHP6).
-
-## Don't use identifier quoting
-
-Identifier quoting is a workaround for using reserved words that often causes problems in edge cases. Do not use identifier quoting and avoid using reserved words as table or column names.
-
-## Initialize collections in the constructor
-
-It is recommended best practice to initialize any business collections in entities in the constructor. Example:
-
- addresses = new ArrayCollection;
- $this->articles = new ArrayCollection;
- }
- }
-
-## Don't map foreign keys to fields in an entity
-
-Foreign keys have no meaning whatsoever in an object model. Foreign keys are how a relational database establishes relationships. Your object model establishes relationships through object references. Thus mapping foreign keys to object fields heavily leaks details of the relational model into the object model, something you really should not do.
-
-## Use explicit transaction demarcation
-
-While Doctrine will automatically wrap all DML operations in a transaction on flush(), it is considered best practice to explicitly set the transaction boundaries yourself.
-Otherwise every single query is wrapped in a small transaction (Yes, SELECT queries, too) since you can not talk to your database outside of a transaction.
-While such short transactions for read-only (SELECT) queries generally don't have any noticeable performance impact, it is still preferable to use fewer, well-defined transactions
-that are established through explicit transaction boundaries.
-
diff --git a/manual/en/caching.rst b/manual/en/caching.rst
index 8c4ee7a4d..62601af86 100644
--- a/manual/en/caching.rst
+++ b/manual/en/caching.rst
@@ -1,3 +1,6 @@
+Caching
+=======
+
Doctrine provides cache drivers in the ``Common`` package for some
of the most popular caching implementations such as APC, Memcache
and Xcache. We also provide an ``ArrayCache`` driver which stores
diff --git a/manual/en/caching.txt b/manual/en/caching.txt
deleted file mode 100644
index 7a2909ac1..000000000
--- a/manual/en/caching.txt
+++ /dev/null
@@ -1,350 +0,0 @@
-Doctrine provides cache drivers in the `Common` package for some of the most
-popular caching implementations such as APC, Memcache and Xcache. We also provide
-an `ArrayCache` driver which stores the data in a PHP array. Obviously, the cache
-does not live between requests but this is useful for testing in a development
-environment.
-
-## Cache Drivers
-
-The cache drivers follow a simple interface that is defined in `Doctrine\Common\Cache\Cache`.
-All the cache drivers extend a base class `Doctrine\Common\Cache\AbstractCache`
-which implements the before mentioned interface.
-
-The interface defines the following methods for you to publicly use.
-
- * fetch($id) - Fetches an entry from the cache.
- * contains($id) - Test if an entry exists in the cache.
- * save($id, $data, $lifeTime = false) - Puts data into the cache.
- * delete($id) - Deletes a cache entry.
-
-Each driver extends the `AbstractCache` class which defines a few abstract
-protected methods that each of the drivers must implement.
-
- * _doFetch($id)
- * _doContains($id)
- * _doSave($id, $data, $lifeTime = false)
- * _doDelete($id)
-
-The public methods `fetch()`, `contains()`, etc. utilize the above protected methods
-that are implemented by the drivers. The code is organized this way so that the
-protected methods in the drivers do the raw interaction with the cache implementation
-and the `AbstractCache` can build custom functionality on top of these methods.
-
-### APC
-
-In order to use the APC cache driver you must have it compiled and enabled in
-your php.ini. You can read about APC [here](http://us2.php.net/apc) 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.
-
-Below is a simple example of how you could use the APC cache driver by itself.
-
- save('cache_id', 'my_data');
-
-### 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 [here](http://us2.php.net/memcache) 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.
-
-Below is a simple example of how you could use the Memcache cache driver by itself.
-
- connect('memcache_host', 11211);
-
- $cacheDriver = new \Doctrine\Common\Cache\MemcacheCache();
- $cacheDriver->setMemcache()
- $cacheDriver->save('cache_id', 'my_data');
-
-### Xcache
-
-In order to use the Xcache cache driver you must have it compiled and enabled in
-your php.ini. You can read about Xcache [here](http://xcache.lighttpd.net/). 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.
-
-Below is a simple example of how you could use the Xcache cache driver by itself.
-
- save('cache_id', 'my_data');
-
-## Using Cache Drivers
-
-In this section we'll describe how you can fully utilize the API of the cache
-drivers to save cache, check if some cache exists, fetch the cached data and
-delete the cached data. We'll use the `ArrayCache` implementation as our
-example here.
-
- save('cache_id', 'my_data');
-
-The `save()` method accepts three arguments which are described below.
-
- * `$id` - The cache id
- * `$data` - The cache entry/data.
- * `$lifeTime` - The lifetime. If != false, sets a specific lifetime for this cache entry (null => infinite lifeTime).
-
-You can save any type of data whether it be a string, array, object, etc.
-
- 'value1',
- 'key2' => 'value2'
- );
- $cacheDriver->save('my_array', $array);
-
-### Checking
-
-Checking whether some cache exists is very simple, just use the `contains()` method.
-It accepts a single argument which is the ID of the cache entry.
-
- contains('cache_id')) {
- echo 'cache exists';
- } else {
- echo 'cache does not exist';
- }
-
-### Fetching
-
-Now if you want to retrieve some cache entry you can use the `fetch()` method. It
-also accepts a single argument just like `contains()` which is the ID of the cache entry.
-
- fetch('my_array');
-
-### Deleting
-
-As you might guess, deleting is just as easy as saving, checking and fetching.
-We have a few ways to delete cache entries. You can delete by an individual ID,
-regular expression, prefix, suffix or you can delete all entries.
-
-#### By Cache ID
-
- delete('my_array');
-
-You can also pass wild cards to the `delete()` method and it will return an array
-of IDs that were matched and deleted.
-
- delete('users_*');
-
-#### By Regular Expression
-
-If you need a little more control than wild cards you can use a PHP regular
-expression to delete cache entries.
-
- deleteByRegex('/users_.*/');
-
-#### By Prefix
-
-Because regular expressions are kind of slow, if simply deleting by a prefix or
-suffix is sufficient, it is recommended that you do that instead of using a regular
-expression because it will be much faster if you have many cache entries.
-
- deleteByPrefix('users_');
-
-#### By Suffix
-
-Just like we did above with the prefix you can do the same with a suffix.
-
- deleteBySuffix('_my_account');
-
-#### All
-
-If you simply want to delete all cache entries you can do so with the `deleteAll()`
-method.
-
- deleteAll();
-
-### Counting
-
-If you want to count how many entries are stored in the cache driver instance
-you can use the `count()` method.
-
- count();
-
-> **NOTE**
-> In order to use `deleteByRegex()`, `deleteByPrefix()`, `deleteBySuffix()`,
-> `deleteAll()`, `count()` or `getIds()` you must enable an option for the cache
-> driver to manage your cache IDs internally. This is necessary because APC,
-> Memcache, etc. don't have any advanced functionality for fetching and deleting.
-> We add some functionality on top of the cache drivers to maintain an index of
-> all the IDs stored in the cache driver so that we can allow more granular deleting
-> operations.
->
-> $cacheDriver->setManageCacheIds(true);
-
-### Namespaces
-
-If you heavily use caching in your application and utilize it in multiple parts
-of your application, or use it in different applications on the same server you
-may have issues with cache naming collisions. This can be worked around by using
-namespaces. You can set the namespace a cache driver should use by using the
-`setNamespace()` method.
-
- setNamespace('my_namespace_');
-
-## Integrating with the ORM
-
-The Doctrine ORM package is tightly integrated with the cache drivers to allow
-you to improve performance of various aspects of Doctrine by just simply making
-some additional configurations and method calls.
-
-### Query Cache
-
-It is highly recommended that in a production environment you cache the
-transformation of a DQL query to its SQL counterpart. It doesn't make sense to
-do this parsing multiple times as it doesn't change unless you alter the DQL
-query.
-
-This can be done by configuring the query cache implementation to use on your ORM
-configuration.
-
- setQueryCacheImpl(new \Doctrine\Common\Cache\ApcCache());
-
-### Result Cache
-
-The result cache can be used to cache the results of your queries so that we
-don't have to query the database or hydrate the data again after the first time.
-You just need to configure the result cache implementation.
-
- setResultCacheImpl(new \Doctrine\Common\Cache\ApcCache());
-
-Now when you're executing DQL queries you can configure them to use the result cache.
-
- createQuery('select u from \Entities\User u');
- $query->useResultCache(true);
-
-You can also configure an individual query to use a different result cache driver.
-
- setResultCacheDriver(new \Doctrine\Common\Cache\ApcCache());
-
-> **NOTE**
-> Setting the result cache driver on the query will automatically enable the
-> result cache for the query. If you want to disable it pass false to
-> `useResultCache()`.
->
-> $query->useResultCache(false);
-
-If you want to set the time the cache has to live you can use the `setResultCacheLifetime()`
-method.
-
- setResultCacheLifetime(3600);
-
-The ID used to store the result set cache is a hash which is automatically generated
-for you if you don't set a custom ID yourself with the `setResultCacheId()` method.
-
- setResultCacheId('my_custom_id');
-
-You can also set the lifetime and cache ID by passing the values as the second
-and third argument to `useResultCache()`.
-
- useResultCache(true, 3600, 'my_custom_id');
-
-### 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.
-
-Just like the query and result cache we need to configure it first.
-
- setMetadataCacheImpl(new \Doctrine\Common\Cache\ApcCache());
-
-Now the metadata information will only be parsed once and stored in the cache
-driver.
-
-## Clearing the Cache
-
-We've already shown you previously how you can use the API of the cache drivers
-to manually delete cache entries. For your convenience we offer a command line task
-for you to help you with clearing the query, result and metadata cache.
-
-From the Doctrine command line you can run the following command.
-
- $ ./doctrine clear-cache
-
-Running this task with no arguments will clear all the cache for all the configured
-drivers. If you want to be more specific about what you clear you can use the
-following options.
-
-To clear the query cache use the `--query` option.
-
- $ ./doctrine clear-cache --query
-
-To clear the metadata cache use the `--metadata` option.
-
- $ ./doctrine clear-cache --metadata
-
-To clear the result cache use the `--result` option.
-
- $ ./doctrine clear-cache --result
-
-When you use the `--result` option you can use some other options to be more
-specific about what queries result sets you want to clear.
-
-Just like the API of the cache drivers you can clear based on an ID, regular
-expression, prefix or suffix.
-
- $ ./doctrine clear-cache --result --id=cache_id
-
-Or if you want to clear based on a regular expressions.
-
- $ ./doctrine clear-cache --result --regex=users_.*
-
-Or with a prefix.
-
- $ ./doctrine clear-cache --result --prefix=users_
-
-And finally with a suffix.
-
- $ ./doctrine clear-cache --result --suffix=_my_account
-
-> **NOTE**
-> Using the `--id`, `--regex`, etc. options with the `--query` and `--metadata`
-> are not allowed as it is not necessary to be specific about what you clear.
-> You only ever need to completely clear the cache to remove stale entries.
-
-## Cache Slams
-
-Something to be careful of when utilizing the cache drivers is cache slams. If
-you have a heavily trafficked website with some code that checks for the existence
-of a cache record and if it does not exist it generates the information and saves
-it to the cache. Now if 100 requests were issued all at the same time and each one
-sees the cache does not exist and they all try and insert the same cache entry
-it could lock up APC, Xcache, etc. and cause problems. Ways exist to work around
-this, like pre-populating your cache and not letting your users requests populate
-the cache.
-
-You can read more about cache slams [here](http://t3.dotgnu.info/blog/php/user-cache-timebomb).
\ No newline at end of file
diff --git a/manual/en/change-tracking-policies.rst b/manual/en/change-tracking-policies.rst
index 97b3508fb..25f32d051 100644
--- a/manual/en/change-tracking-policies.rst
+++ b/manual/en/change-tracking-policies.rst
@@ -1,5 +1,5 @@
Change Tracking Policies
-------------------------
+========================
Change tracking is the process of determining what has changed in
managed entities since the last time they were synchronized with
diff --git a/manual/en/change-tracking-policies.txt b/manual/en/change-tracking-policies.txt
deleted file mode 100644
index 11fec2e4d..000000000
--- a/manual/en/change-tracking-policies.txt
+++ /dev/null
@@ -1,128 +0,0 @@
-## Change Tracking Policies
-
-Change tracking is the process of determining what has changed in managed
-entities since the last time they were synchronized with the database.
-
-Doctrine provides 3 different change tracking policies, each having its
-particular advantages and disadvantages. The change tracking policy can
-be defined on a per-class basis (or more precisely, per-hierarchy).
-
-### Deferred Implicit
-
-The deferred implicit policy is the default change tracking policy and the most
-convenient one. With this policy, Doctrine detects the changes by a
-property-by-property comparison at commit time and also detects changes
-to entities or new entities that are referenced by other managed entities
-("persistence by reachability"). Although the most convenient policy, it can
-have negative effects on performance if you are dealing with large units of
-work (see "Understanding the Unit of Work"). Since Doctrine can't know what
-has changed, it needs to check all managed entities for changes every time you
-invoke EntityManager#flush(), making this operation rather costly.
-
-### Deferred Explicit
-
-The deferred explicit policy is similar to the deferred implicit policy in that
-it detects changes through a property-by-property comparison at commit time. The
-difference is that only entities are considered that have been explicitly marked
-for change detection through a call to EntityManager#persist(entity) or through
-a save cascade. All other entities are skipped. This policy therefore gives
-improved performance for larger units of work while sacrificing the behavior
-of "automatic dirty checking".
-
-Therefore, flush() operations are potentially cheaper with this policy. The
-negative aspect this has is that if you have a rather large application and
-you pass your objects through several layers for processing purposes and
-business tasks you may need to track yourself which entities have changed
-on the way so you can pass them to EntityManager#persist().
-
-This policy can be configured as follows:
-
- _listeners[] = $listener;
- }
- }
-
-Then, in each property setter of this class or derived classes, you need to
-notify all the `PropertyChangedListener` instances. As an example we
-add a convenience method on `MyEntity` that shows this behaviour:
-
- _listeners) {
- foreach ($this->_listeners as $listener) {
- $listener->propertyChanged($this, $propName, $oldValue, $newValue);
- }
- }
- }
-
- public function setData($data)
- {
- if ($data != $this->data) {
- $this->_onPropertyChanged('data', $this->data, $data);
- $this->data = $data;
- }
- }
- }
-
-You have to invoke `_onPropertyChanged` inside every method that changes the
-persistent state of `MyEntity`.
-
-The check whether the new value is different from the old one is not mandatory
-but recommended. That way you also have full control over when you consider a
-property changed.
-
-The negative point of this policy is obvious: You need implement an interface
-and write some plumbing code. But also note that we tried hard to keep this
-notification functionality abstract. Strictly speaking, it has nothing to do
-with the persistence layer and the Doctrine ORM or DBAL. You may find that
-property notification events come in handy in many other scenarios as well.
-As mentioned earlier, the `Doctrine\Common` namespace is not that evil and
-consists solely of very small classes and interfaces that have almost no
-external dependencies (none to the DBAL and none to the ORM) and that you
-can easily take with you should you want to swap out the persistence layer.
-This change tracking policy does not introduce a dependency on the Doctrine
-DBAL/ORM or the persistence layer.
-
-The positive point and main advantage of this policy is its effectiveness. It
-has the best performance characteristics of the 3 policies with larger units of
-work and a flush() operation is very cheap when nothing has changed.
\ No newline at end of file
diff --git a/manual/en/configuration.rst b/manual/en/configuration.rst
index 585108f6e..a3a3a3987 100644
--- a/manual/en/configuration.rst
+++ b/manual/en/configuration.rst
@@ -1,3 +1,6 @@
+Configuration
+=============
+
Bootstrapping
-------------
@@ -32,7 +35,9 @@ namespace and where there is a common root namespace.
The following example shows the setup of a ``ClassLoader`` for the
different types of Doctrine Installations:
- **NOTE** This assumes you've created some kind of script to test
+.. note::
+
+ This assumes you've created some kind of script to test
the following code in. Something like a ``test.php`` file.
@@ -370,7 +375,8 @@ lazy-loading capabilities to them. Doctrine can then give you an
instance of such a proxy class whenever you request an object of
the class being proxied. This happens in two situations:
-**Reference Proxies**
+Reference Proxies
+~~~~~~~~~~~~~~~~~
The method ``EntityManager#getReference($entityName, $identifier)``
lets you obtain a reference to an entity for which the identifier
@@ -395,7 +401,8 @@ for the Item class but your code does not need to care. In fact it
**should not care**. Proxy objects should be transparent to your
code.
-**Association proxies**
+Association proxies
+~~~~~~~~~~~~~~~~~~~
The second most important situation where Doctrine uses proxy
objects is when querying for objects. Whenever you query for an
@@ -405,7 +412,9 @@ query, Doctrine puts proxy objects in place where normally the
associated object would be. Just like other proxies it will
transparently initialize itself on first access.
- **NOTE** Joining an association in a DQL or native query
+.. note::
+
+ Joining an association in a DQL or native query
essentially means eager loading of that association in that query.
This will override the 'fetch' option specified in the mapping for
that association, but only for that query.
diff --git a/manual/en/configuration.txt b/manual/en/configuration.txt
deleted file mode 100644
index 717032b0a..000000000
--- a/manual/en/configuration.txt
+++ /dev/null
@@ -1,307 +0,0 @@
-## Bootstrapping
-
-Bootstrapping Doctrine is a relatively simple procedure that roughly exists of
-just 2 steps:
-
-* Making sure Doctrine class files can be loaded on demand.
-* Obtaining an EntityManager instance.
-
-### Class loading
-
-Lets start with the class loading setup. We need to set up some class loaders
-(often called "autoloader") so that Doctrine class files are loaded on demand.
-The Doctrine\Common namespace contains a very fast and minimalistic class loader
-that can be used for Doctrine and any other libraries where the coding standards
-ensure that a class's location in the directory tree is reflected by its name
-and namespace and where there is a common root namespace.
-
-> **NOTE**
-> You are not forced to use the Doctrine class loader to load Doctrine
-> classes. Doctrine does not care how the classes are loaded, if you want to use a
-> different class loader or your own to load Doctrine classes, just do that.
-> Along the same lines, the class loader in the Doctrine\Common namespace is not
-> meant to be only used for Doctrine classes, too. It is a generic class loader that can
-> be used for any classes that follow some basic naming standards as described above.
-
-The following example shows the setup of a `ClassLoader` for the different types
-of Doctrine Installations:
-
-> **NOTE**
-> This assumes you've created some kind of script to test the following code in.
-> Something like a `test.php` file.
-
-#### PEAR or Tarball Download
-
- register(); // register on SPL autoload stack
-
-#### Git
-
-The Git bootstrap assumes that you have fetched the related packages through `git submodule update --init`
-
- register();
-
- $classLoader = new \Doctrine\Common\ClassLoader('Doctrine\DBAL', $lib . 'vendor/doctrine-dbal/lib');
- $classLoader->register();
-
- $classLoader = new \Doctrine\Common\ClassLoader('Doctrine\ORM', $lib);
- $classLoader->register();
-
-#### Additional Symfony Components
-
-If you don't use Doctrine2 in combination with Symfony2 you have to register an additional namespace to be able to use
-the Doctrine-CLI Tool or the YAML Mapping driver:
-
- register();
-
- // Git Setup
- $classloader = new \Doctrine\Common\ClassLoader('Symfony', $lib . 'vendor/');
- $classloader->register();
-
-For best class loading performance it is recommended that you keep your include_path short, ideally it should only contain the path to the PEAR libraries, and any other class libraries should be registered with their full base path.
-
-### Obtaining an EntityManager
-
-Once you have prepared the class loading, you acquire an *EntityManager* instance.
-The EntityManager class is the primary access point to ORM functionality provided by Doctrine.
-
-A simple configuration of the EntityManager requires a `Doctrine\ORM\Configuration`
-instance as well as some database connection parameters:
-
- setMetadataCacheImpl($cache);
- $driverImpl = $config->newDefaultAnnotationDriver('/path/to/lib/MyProject/Entities');
- $config->setMetadataDriverImpl($driverImpl);
- $config->setQueryCacheImpl($cache);
- $config->setProxyDir('/path/to/myproject/lib/MyProject/Proxies');
- $config->setProxyNamespace('MyProject\Proxies');
-
- if ($applicationMode == "development") {
- $config->setAutoGenerateProxyClasses(true);
- } else {
- $config->setAutoGenerateProxyClasses(false);
- }
-
- $connectionOptions = array(
- 'driver' => 'pdo_sqlite',
- 'path' => 'database.sqlite'
- );
-
- $em = EntityManager::create($connectionOptions, $config);
-
-> **CAUTION**
-> Do not use Doctrine without a metadata and query cache! Doctrine is highly
-> optimized for working with caches. The main parts in Doctrine that are optimized
-> for caching are the metadata mapping information with the metadata cache and the
-> DQL to SQL 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](http://www.php.net/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.
-
-## Configuration Options
-
-The following sections describe all the configuration options available on a `Doctrine\ORM\Configuration` instance.
-
-### Proxy Directory (***REQUIRED***)
-
- setProxyDir($dir);
- $config->getProxyDir();
-
-Gets or sets the directory where Doctrine generates any proxy classes. For a detailed explanation on proxy classes and how they are used in Doctrine, refer to the "Proxy Objects" section further down.
-
-### Proxy Namespace (***REQUIRED***)
-
- setProxyNamespace($namespace);
- $config->getProxyNamespace();
-
-Gets or sets the namespace to use for generated proxy classes. For a detailed explanation on proxy classes and how they are used in Doctrine, refer to the "Proxy Objects" section further down.
-
-### Metadata Driver (***REQUIRED***)
-
- setMetadataDriverImpl($driver);
- $config->getMetadataDriverImpl();
-
-Gets or sets the metadata driver implementation that is used by Doctrine to acquire the object-relational metadata for your classes.
-
-There are currently 4 available implementations:
-
- * `Doctrine\ORM\Mapping\Driver\AnnotationDriver`
- * `Doctrine\ORM\Mapping\Driver\XmlDriver`
- * `Doctrine\ORM\Mapping\Driver\YamlDriver`
- * `Doctrine\ORM\Mapping\Driver\DriverChain`
-
-Throughout the most part of this manual the AnnotationDriver is used in the examples. For information on the usage of the XmlDriver or YamlDriver please refer to the dedicated chapters `XML Mapping` and `YAML Mapping`.
-
-The annotation driver can be configured with a factory method on the `Doctrine\ORM\Configuration`:
-
- newDefaultAnnotationDriver('/path/to/lib/MyProject/Entities');
- $config->setMetadataDriverImpl($driverImpl);
-
-The path information to the entities is required for the annotation 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 directories. With this feature a
-single driver can support multiple directories of Entities.
-
-### Metadata Cache (***RECOMMENDED***)
-
- setMetadataCacheImpl($cache);
- $config->getMetadataCacheImpl();
-
-Gets or sets the cache implementation to use for caching metadata information, that is, all the information you supply via 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 `Doctrine\Common\Cache\Cache` interface.
-
-Usage of a metadata cache is highly recommended.
-
-The recommended implementations for production are:
-
- * `Doctrine\Common\Cache\ApcCache`
- * `Doctrine\Common\Cache\MemcacheCache`
- * `Doctrine\Common\Cache\XcacheCache`
-
-For development you should use the `Doctrine\Common\Cache\ArrayCache` which only caches data on a per-request basis.
-
-### Query Cache (***RECOMMENDED***)
-
- setQueryCacheImpl($cache);
- $config->getQueryCacheImpl();
-
-Gets or sets the cache implementation to use for caching DQL queries, that is, the result of a DQL parsing process that includes the final SQL as well as meta information about how to process the SQL result set of a query. Note that the query cache does not affect query results. You do not get stale data. This is a pure optimization cache without any negative side-effects (except some minimal memory usage in your cache).
-
-Usage of a query cache is highly recommended.
-
-The recommended implementations for production are:
-
- * `Doctrine\Common\Cache\ApcCache`
- * `Doctrine\Common\Cache\MemcacheCache`
- * `Doctrine\Common\Cache\XcacheCache`
-
-For development you should use the `Doctrine\Common\Cache\ArrayCache` which only caches data on a per-request basis.
-
-### SQL Logger (***Optional***)
-
- setSQLLogger($logger);
- $config->getSQLLogger();
-
-Gets or sets the logger to use for logging all SQL statements executed by Doctrine. The logger class must implement the `Doctrine\DBAL\Logging\SqlLogger` interface. A simple default implementation that logs to the standard output using `echo` and `var_dump` can be found at `Doctrine\DBAL\Logging\EchoSqlLogger`.
-
-### Auto-generating Proxy Classes (***OPTIONAL***)
-
- setAutoGenerateProxyClasses($bool);
- $config->getAutoGenerateProxyClasses();
-
-Gets or sets whether proxy classes should be generated automatically at runtime by Doctrine. If set to `FALSE`, proxy classes must be generated manually through the doctrine command line task `generate-proxies`. The strongly recommended value for a production environment is `FALSE`.
-
-## Development vs Production Configuration
-
-You should code your Doctrine2 bootstrapping with two different runtime models in mind. There are some serious
-benefits of using APC or Memcache in production. In development however this will frequently give you fatal
-errors, when you change your entities and the cache still keeps the outdated metadata. That is why we recommend
-the `ArrayCache` for development.
-
-Furthermore you should have the Auto-generating Proxy Classes option to true in development and to false
-in production. If this option is set to `TRUE` it can seriously hurt your script performance if several proxy
-classes are re-generated during script execution. Filesystem calls of that magnitude can even slower than all
-the database queries Doctrine issues. Additionally writing a proxy sets an exclusive file lock which can cause
-serious performance bottlenecks in systems with regular concurrent requests.
-
-## Connection Options
-
-The `$connectionOptions` passed as the first argument to `EntityManager::create()` has to be either an array
-or an instance of `Doctrine\DBAL\Connection`. If an array is passed it is directly passed along to the
-DBAL Factory `Doctrine\DBAL\DriverManager::getConnection()`. The DBAL configuration is explained
-in the [DBAL section](./../../../../../dbal/2.0/docs/reference/configuration/en).
-
-## Proxy Objects
-
-A proxy object is an object that is put in place or used instead of the "real" object. A proxy object can add behavior to the object being proxied without that object being aware of it. In Doctrine 2, proxy objects are used to realize several features but mainly for transparent lazy-loading.
-
-Proxy objects with their lazy-loading facilities help to keep the subset of objects that are already in memory connected to the rest of the objects. This is an essential property as without it there would always be fragile partial objects at the outer edges of your object graph.
-
-Doctrine 2 implements a variant of the proxy pattern where it generates classes that extend your entity classes and adds lazy-loading capabilities to them. Doctrine can then give you an instance of such a proxy class whenever you request an object of the class being proxied. This happens in two situations:
-
-**Reference Proxies**
-
-The method `EntityManager#getReference($entityName, $identifier)` lets you obtain a reference to an entity for which the identifier is known, without loading that entity from the database. This is useful, for example, as a performance enhancement, when you want to establish an association to an entity for which you have the identifier. You could simply do this:
-
- getReference('MyProject\Model\Item', $itemId);
- $cart->addItem($item);
-
-Here, we added an Item to a Cart without loading the Item from the database. If you invoke any method on the Item instance, it would fully initialize its state transparently from the database. Here $item is actually an instance of the proxy class that was generated for the Item class but your code does not need to care. In fact it **should not care**. Proxy objects should be transparent to your code.
-
-**Association proxies**
-
-The second most important situation where Doctrine uses proxy objects is when querying for objects. Whenever you query for an object that has a single-valued association to another object that is configured LAZY, without joining that association in the same query, Doctrine puts proxy objects in place where normally the associated object would be.
-Just like other proxies it will transparently initialize itself on first access.
-
-> **NOTE**
-> Joining an association in a DQL or native query essentially means eager loading of that
-> association in that query. This will override the 'fetch' option specified in
-> the mapping for that association, but only for that query.
-
-### Generating Proxy classes
-
-Proxy classes can either be generated manually through the Doctrine Console or automatically by Doctrine. The configuration option that controls this behavior is:
-
- setAutoGenerateProxyClasses($bool);
- $config->getAutoGenerateProxyClasses();
-
-The default value is `TRUE` for convenient development. However, this setting is not optimal for performance and therefore not recommended for a production environment.
-To eliminate the overhead of proxy class generation during runtime, set this configuration option to `FALSE`. When you do this in a development environment, note that you may get class/file not found errors if certain proxy classes are not available or failing lazy-loads if new methods were added to the entity class that are not yet in the proxy class. In such a case, simply use the Doctrine Console to (re)generate the proxy classes like so:
-
- $ ./doctrine orm:generate-proxies
-
-## Multiple Metadata Sources
-
-When using different components using Doctrine 2 you may end up with them using two different metadata drivers,
-for example XML and YAML. You can use the DriverChain Metadata implementations to aggregate these drivers
-based on namespaces:
-
- addDriver($xmlDriver, 'Doctrine\Tests\Models\Company');
- $chain->addDriver($yamlDriver, 'Doctrine\Tests\ORM\Mapping');
-
-Based on the namespace of the entity the loading of entities is delegated to the appropriate driver. The chain
-semantics come from the fact that the driver loops through all namespaces and matches the entity class name
-against the namespace using a `strpos() === 0` call. This means you need to order the drivers correctly if
-sub-namespaces use different metadata driver implementations.
diff --git a/manual/en/dql-doctrine-query-language.rst b/manual/en/dql-doctrine-query-language.rst
index 2ec388c59..e99916d2c 100644
--- a/manual/en/dql-doctrine-query-language.rst
+++ b/manual/en/dql-doctrine-query-language.rst
@@ -1,5 +1,5 @@
-DQL Explained
--------------
+Doctrine Query Language
+===========================
DQL stands for **D**octrine **Q**uery **L**anguage and is an Object
Query Language derivate that is very similar to the **H**ibernate
@@ -433,9 +433,8 @@ starting with 0. However with INDEX BY you can specify any other
column to be the key of your result, it really only makes sense
with primary or unique fields though:
-::
+.. code-block:: sql
- [sql]
SELECT u.id, u.status, upper(u.name) nameUpper FROM User u INDEX BY u.id
JOIN u.phonenumbers p INDEX BY p.phonenumber
@@ -470,15 +469,17 @@ can also execute bulk updates on a set of entities using an
DQL-UPDATE query. The Syntax of an UPDATE query works as expected,
as the following example shows:
-::
+.. code-block:: sql
UPDATE MyProject\Model\User u SET u.password = 'new' WHERE u.id IN (1, 2, 3)
References to related entities are only possible in the WHERE
clause and using sub-selects.
- **CAUTION** DQL UPDATE statements are ported directly into a
- Database UPDATE statement and therefore bypass any locking scheme
+.. warning::
+
+ DQL UPDATE statements are ported directly into a
+ Database UPDATE statement and therefore bypass any locking scheme, events
and do not increment the version column. Entities that are already
loaded into the persistence context will *NOT* be synced with the
updated database state. It is recommended to call
@@ -492,14 +493,16 @@ DELETE queries
DELETE queries can also be specified using DQL and their syntax is
as simple as the UPDATE syntax:
-::
+.. code-block:: sql
DELETE MyProject\Model\User u WHERE u.id = 4
The same restrictions apply for the reference of related entities.
- **CAUTION** DQL DELETE statements are ported directly into a
- Database DELETE statement and therefore bypass any checks for the
+.. warning::
+
+ DQL DELETE statements are ported directly into a
+ Database DELETE statement and therefore bypass any events and checks for the
version column if they are not explicitly added to the WHERE clause
of the query. Additionally Deletes of specifies entities are *NOT*
cascaded to related entities even if specified in the metadata.
@@ -540,7 +543,7 @@ Arithmetic operators
You can do math in DQL using numeric values, for example:
-::
+.. warning::
SELECT person.salary * 1.5 FROM CompanyPerson person WHERE person.salary < 100000
@@ -694,9 +697,8 @@ scenario it is a generic Person and Employee example:
First notice that the generated SQL to create the tables for these
entities looks like the following:
-::
+.. code-block:: sql
- [sql]
CREATE TABLE Person (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name VARCHAR(50) NOT NULL, discr VARCHAR(255) NOT NULL, department VARCHAR(50) NOT NULL)
Now when persist a new ``Employee`` instance it will set the
@@ -714,18 +716,16 @@ discriminator value for us automatically:
Now lets run a simple query to retrieve the ``Employee`` we just
created:
-::
+.. code-block:: sql
- [sql]
SELECT e FROM Entities\Employee e WHERE e.name = 'test'
If we check the generated SQL you will notice it has some special
conditions added to ensure that we will only get back ``Employee``
entities:
-::
+.. code-block:: sql
- [sql]
SELECT p0_.id AS id0, p0_.name AS name1, p0_.department AS department2, p0_.discr AS discr3 FROM Person p0_ WHERE (p0_.name = ?) AND p0_.discr IN ('employee')
Class Table Inheritance
@@ -761,9 +761,8 @@ table, you just need to change the inheritance type from
Now take a look at the SQL which is generated to create the table,
you'll notice some differences:
-::
+.. code-block:: sql
- [sql]
CREATE TABLE Person (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(50) NOT NULL, discr VARCHAR(255) NOT NULL, PRIMARY KEY(id)) ENGINE = InnoDB;
CREATE TABLE Employee (id INT NOT NULL, department VARCHAR(50) NOT NULL, PRIMARY KEY(id)) ENGINE = InnoDB;
ALTER TABLE Employee ADD FOREIGN KEY (id) REFERENCES Person(id) ON DELETE CASCADE
@@ -777,9 +776,8 @@ Now if were to insert the same ``Employee`` as we did in the
generate different SQL joining the ``Person`` information
automatically for you:
-::
+.. code-block:: sql
- [sql]
SELECT p0_.id AS id0, p0_.name AS name1, e1_.department AS department2, p0_.discr AS discr3 FROM Employee e1_ INNER JOIN Person p0_ ON e1_.id = p0_.id WHERE p0_.name = ?
The Query class
@@ -892,9 +890,8 @@ structure:
To better understand mixed results, consider the following DQL
query:
-::
+.. code-block:: sql
- [sql]
SELECT u, UPPER(u.name) nameUpper FROM MyProject\Model\User u
This query makes use of the ``UPPER`` DQL function that returns a
@@ -1186,7 +1183,9 @@ number of results:
- ``Query::setMaxResults($maxResults)``
- ``Query::setFirstResult($offset)``
- **NOTE** If your query contains a fetch-joined collection
+.. note::
+
+ If your query contains a fetch-joined collection
specifying the result limit methods are not working as you would
expect. Set Max Results restricts the number of database result
rows, however in the case of fetch-joined collections one root
diff --git a/manual/en/dql-doctrine-query-language.txt b/manual/en/dql-doctrine-query-language.txt
deleted file mode 100644
index 1a3f6ab6c..000000000
--- a/manual/en/dql-doctrine-query-language.txt
+++ /dev/null
@@ -1,1096 +0,0 @@
-## DQL Explained
-
-DQL stands for **D**octrine **Q**uery **L**anguage and is an Object Query Language derivate that is very similar to the **H**ibernate **Q**uery **L**anguage (HQL) or the **J**ava **P**ersistence **Q**uery **L**anguage (JPQL).
-
-In essence, DQL provides powerful querying capabilities over your object model. Imagine all your objects lying around in some storage (like an object database). When writing DQL queries, think about querying that storage to pick a certain subset of your objects.
-
-> **CAUTION**
-> A common mistake for beginners is to mistake DQL for being just some form of SQL
-> and therefore trying to use table names and column names or join arbitrary tables
-> together in a query. You need to think about DQL as a query language for your object
-> model, not for your relational schema.
-
-DQL is case in-sensitive, except for namespace, class and field names, which are case sensitive.
-
-## Types of DQL queries
-
-DQL as a query language has SELECT, UPDATE and DELETE constructs that map to their corresponding
-SQL statement types. INSERT statements are not allowed in DQL, because entities and their relations
-have to be introduced into the persistence context through `EntityManager#persist()` to ensure
-consistency of your object model.
-
-DQL SELECT statements are a very powerful way of retrieving parts of your domain model that are
-not accessible via associations. Additionally they allow to retrieve entities and their associations
-in one single sql select statement which can make a huge difference in performance in contrast
-to using several queries.
-
-DQL UPDATE and DELETE statements offer a way to execute bulk changes on the entities of your
-domain model. This is often necessary when you cannot load all the affected entities of a bulk
-update into memory.
-
-## SELECT queries
-
-### DQL SELECT clause
-
-The select clause of a DQL query specifies what appears in the query result. The composition of all the expressions in the select clause also influences the nature of the query result.
-
-Here is an example that selects all users with an age > 20:
-
- createQuery('SELECT u FROM MyProject\Model\User u WHERE u.age > 20');
- $users = $query->getResult();
-
-Lets examine the query:
-
-* `u` is a so called identification variable or alias that refers to the `MyProject\Model\User` class. By placing this alias in the SELECT clause we specify that we want all instances of the User class that are matched by this query appear in the query result.
-* The FROM keyword is always followed by a fully-qualified class name which in turn is followed by an identification variable or alias for that class name. This class designates a root of our query from which we can navigate further via joins (explained later) and path expressions.
-* The expression `u.age` in the WHERE clause is a path expression. Path expressions in DQL are easily identified by the use of the '.' operator that is used for constructing paths. The path expression `u.age` refers to the `age` field on the User class.
-
-The result of this query would be a list of User objects where all users are older than 20.
-
-The SELECT clause allows to specify both class identification variables that signal the hydration
-of a complete entity class or just fields of the entity using the syntax `u.name`.
-Combinations of both are also allowed and it is possible to wrap both fields and
-identification values into aggregation and DQL functions. Numerical fields can
-be part of computations using mathematical operations. See the sub-section on [DQL Functions, Aggregates and Operations](#dqlfn)
-on more information.
-
-### Joins
-
-A SELECT query can contain joins. There are 2 types of JOINs: "Regular" Joins and "Fetch" Joins.
-
-**Regular Joins**: Used to limit the results and/or compute aggregate values.
-
-**Fetch Joins**: In addition to the uses of regular joins: Used to fetch related entities and include them in the hydrated result of a query.
-
-There is no special DQL keyword that distinguishes a regular join from a fetch join. A join (be it an inner or outer join) becomes a "fetch join" as soon as fields of the joined entity appear in the SELECT part of the DQL query outside of an aggregate function. Otherwise its a "regular join".
-
-Example:
-
-Regular join of the address:
-
- createQuery("SELECT u FROM User u JOIN u.address a WHERE a.city = 'Berlin'");
- $users = $query->getResult();
-
-Fetch join of the address:
-
- createQuery("SELECT u, a FROM User u JOIN u.address a WHERE a.city = 'Berlin'");
- $users = $query->getResult();
-
-When Doctrine hydrates a query with fetch-join it returns the class in the FROM clause on the
-root level of the result array. In the previous example an array of User instances is returned
-and the address of each user is fetched and hydrated into the `User#address` variable. If you access
-the address Doctrine does not need to lazy load the association with another query.
-
-> **NOTE**
-> Doctrine allows you to walk all the associations between all the objects in your domain model.
-> Objects that were not already loaded from the database are replaced with lazy load proxy instances.
-> Non-loaded Collections are also replaced by lazy-load instances that fetch all the contained objects upon
-> first access. However relying on the lazy-load mechanism leads to many small queries executed
-> against the database, which can significantly affect the performance of your application.
-> **Fetch Joins** are the solution to hydrate most or all of the entities that you
-> need in a single SELECT query.
-
-### Named and Positional Parameters
-
-DQL supports both named and positional parameters, however in contrast to many SQL dialects
-positional parameters are specified with numbers, for example "?1", "?2" and so on.
-Named parameters are specified with ":name1", ":name2" and so on.
-
-### DQL SELECT Examples
-
-This section contains a large set of DQL queries and some explanations of what is happening.
-The actual result also depends on the hydration mode.
-
-Hydrate all User entities:
-
- createQuery('SELECT u FROM MyProject\Model\User u');
- $users = $query->getResult(); // array of User objects
-
-Retrieve the IDs of all CmsUsers:
-
- createQuery('SELECT u.id FROM CmsUser u');
- $ids = $query->getResult(); // array of CmsUser ids
-
-Retrieve the IDs of all users that have written an article:
-
- createQuery('SELECT DISTINCT u.id FROM CmsArticle a JOIN a.user u');
- $ids = $query->getResult(); // array of CmsUser ids
-
-Retrieve all articles and sort them by the name of the articles users instance:
-
- createQuery('SELECT a FROM CmsArticle a JOIN a.user u ORDER BY u.name ASC');
- $articles = $query->getResult(); // array of CmsArticle objects
-
-Retrieve the Username and Name of a CmsUser:
-
- createQuery('SELECT u.username, u.name FROM CmsUser u');
- $users = $query->getResults(); // array of CmsUser username and id values
- echo $users[0]['username'];
-
-Retrieve a ForumUser and his single associated entity:
-
- createQuery('SELECT u, a FROM ForumUser u JOIN u.avatar a');
- $users = $query->getResult(); // array of ForumUser objects with the avatar association loaded
- echo get_class($users[0]->getAvatar());
-
-Retrieve a CmsUser and fetch join all the phonenumbers he has:
-
- createQuery('SELECT u, p FROM CmsUser u JOIN u.phonenumbers p');
- $users = $query->getResult(); // array of CmsUser objects with the phonenumbers association loaded
- $phonenumbers = $users[0]->getPhonenumbers();
-
-Hydrate a result in Ascending:
-
- createQuery('SELECT u FROM ForumUser u ORDER BY u.id ASC');
- $users = $query->getResult(); // array of ForumUser objects
-
-Or in Descending Order:
-
- createQuery('SELECT u FROM ForumUser u ORDER BY u.id DESC');
- $users = $query->getResult(); // array of ForumUser objects
-
-Using Aggregate Functions:
-
- createQuery('SELECT COUNT(u.id) FROM Entities\User u');
- $count = $query->getSingleScalarResult();
-
-With WHERE Clause and Positional Parameter:
-
- createQuery('SELECT u FROM ForumUser u WHERE u.id = ?1');
- $users = $query->getResult(); // array of ForumUser objects
-
-With WHERE Clause and Named Parameter:
-
- createQuery('SELECT u FROM ForumUser u WHERE u.username = :name');
- $users = $query->getResult(); // array of ForumUser objects
-
-With Nested Conditions in WHERE Clause:
-
- createQuery('SELECT u from ForumUser u WHERE (u.username = :name OR u.username = :name2) AND u.id = :id');
- $users = $query->getResult(); // array of ForumUser objects
-
-With COUNT DISTINCT:
-
- createQuery('SELECT COUNT(DISTINCT u.name) FROM CmsUser');
- $users = $query->getResult(); // array of ForumUser objects
-
-With Arithmetic Expression in WHERE clause:
-
- createQuery('SELECT u FROM CmsUser u WHERE ((u.id + 5000) * u.id + 3) < 10000000');
- $users = $query->getResult(); // array of ForumUser objects
-
-Using a LEFT JOIN to hydrate all user-ids and optionally associated article-ids:
-
- createQuery('SELECT u.id, a.id as article_id FROM CmsUser u LEFT JOIN u.articles a');
- $results = $query->getResult(); // array of user ids and every article_id for each user
-
-Restricting a JOIN clause by additional conditions:
-
- createQuery("SELECT u FROM CmsUser u LEFT JOIN u.articles a WITH a.topic LIKE '%foo%'");
- $users = $query->getResult();
-
-Using several Fetch JOINs:
-
- createQuery('SELECT u, a, p, c FROM CmsUser u JOIN u.articles a JOIN u.phonenumbers p JOIN a.comments c');
- $users = $query->getResult();
-
-BETWEEN in WHERE clause:
-
- createQuery('SELECT u.name FROM CmsUser u WHERE u.id BETWEEN ?1 AND ?2');
- $usernames = $query->getResult();
-
-DQL Functions in WHERE clause:
-
- createQuery("SELECT u.name FROM CmsUser u WHERE TRIM(u.name) = 'someone'");
- $usernames = $query->getResult();
-
-IN() Expression:
-
- createQuery('SELECT u.name FROM CmsUser u WHERE u.id IN(46)');
- $usernames = $query->getResult();
-
- $query = $em->createQuery('SELECT u FROM CmsUser u WHERE u.id IN (1, 2)');
- $users = $query->getResult();
-
- $query = $em->createQuery('SELECT u FROM CmsUser u WHERE u.id NOT IN (1)');
- $users = $query->getResult();
-
-CONCAT() DQL Function:
-
- createQuery("SELECT u.id FROM CmsUser u WHERE CONCAT(u.name, 's') = ?1");
- $ids = $query->getResult();
-
- $query = $em->createQuery('SELECT CONCAT(u.id, u.name) FROM CmsUser u WHERE u.id = ?1');
- $idUsernames = $query->getResult();
-
-EXISTS in WHERE clause with correlated Subquery
-
- createQuery('SELECT u.id FROM CmsUser u WHERE EXISTS (SELECT p.phonenumber FROM CmsPhonenumber p WHERE p.user = u.id)');
- $ids = $query->getResult();
-
-Get all users who are members of $group.
-
- createQuery('SELECT u.id FROM CmsUser u WHERE :groupId MEMBER OF u.groups');
- $query->setParameter(':groupId', $group);
- $ids = $query->getResult();
-
-Get all users that have more than 1 phonenumber
-
- createQuery('SELECT u FROM CmsUser u WHERE SIZE(u.phonenumbers) > 1');
- $users = $query->getResult();
-
-Get all users that have no phonenumber
-
- createQuery('SELECT u FROM CmsUser u WHERE u.phonenumbers IS EMPTY');
- $users = $query->getResult();
-
-Get all instances of a specific type, for use with inheritance hierarchies:
-
- createQuery('SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF Doctrine\Tests\Models\Company\CompanyEmployee');
- $query = $em->createQuery('SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF ?1');
- $query = $em->createQuery('SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u NOT INSTANCE OF ?1');
-
-#### Partial Object Syntax
-
-By default when you run a DQL query in Doctrine and select only a subset of the
-fields for a given entity, you do not receive objects back. Instead, you receive
-only arrays as a flat rectangular result set, similar to how you would if you
-were just using SQL directly and joining some data.
-
-If you want to select partial objects you can use the `partial` DQL keyword:
-
- createQuery('SELECT partial u.{id, username} FROM CmsUser u');
- $users = $query->getResult(); // array of partially loaded CmsUser objects
-
-You use the partial syntax when joining as well:
-
- createQuery('SELECT partial u.{id, username}, partial a.{id, name} FROM CmsUser u JOIN u.articles a');
- $users = $query->getResult(); // array of partially loaded CmsUser objects
-
-### Using INDEX BY
-
-The INDEX BY construct is nothing that directly translates into SQL but that affects
-object and array hydration. After each FROM and JOIN clause you specify by which field
-this class should be indexed in the result. By default a result is incremented
-by numerical keys starting with 0. However with INDEX BY you can specify any
-other column to be the key of your result, it really only makes sense with primary
-or unique fields though:
-
- [sql]
- SELECT u.id, u.status, upper(u.name) nameUpper FROM User u INDEX BY u.id
- JOIN u.phonenumbers p INDEX BY p.phonenumber
-
-Returns an array of the following kind, indexed by both user-id then phonenumber-id:
-
- array
- 0 =>
- array
- 1 =>
- object(stdClass)[299]
- public '__CLASS__' => string 'Doctrine\Tests\Models\CMS\CmsUser' (length=33)
- public 'id' => int 1
- ..
- 'nameUpper' => string 'ROMANB' (length=6)
- 1 =>
- array
- 2 =>
- object(stdClass)[298]
- public '__CLASS__' => string 'Doctrine\Tests\Models\CMS\CmsUser' (length=33)
- public 'id' => int 2
- ...
- 'nameUpper' => string 'JWAGE' (length=5)
-
-## UPDATE queries
-
-DQL not only allows to select your Entities using field names, you can also execute bulk updates on a set
-of entities using an DQL-UPDATE query. The Syntax of an UPDATE query works as expected, as the following
-example shows:
-
- UPDATE MyProject\Model\User u SET u.password = 'new' WHERE u.id IN (1, 2, 3)
-
-References to related entities are only possible in the WHERE clause and using sub-selects.
-
-> **CAUTION**
-> DQL UPDATE statements are ported directly into a Database UPDATE statement and therefore bypass
-> any locking scheme and do not increment the version column. Entities that are already
-> loaded into the persistence context will *NOT* be synced with the updated database state. It
-> is recommended to call `EntityManager#clear()` and retrieve new instances of any affected entity.
-
-## DELETE queries
-
-DELETE queries can also be specified using DQL and their syntax is as simple as the UPDATE syntax:
-
- DELETE MyProject\Model\User u WHERE u.id = 4
-
-The same restrictions apply for the reference of related entities.
-
-> **CAUTION**
-> DQL DELETE statements are ported directly into a Database DELETE statement and therefore
-> bypass any checks for the version column if they are not explicitly added to the WHERE
-> clause of the query. Additionally Deletes of specifies entities are *NOT* cascaded
-> to related entities even if specified in the metadata.
-
-## Functions, Operators, Aggregates
-
-
-### DQL Functions
-
-The following functions are supported in SELECT, WHERE and HAVING clauses:
-
-* ABS(arithmetic_expression)
-* CONCAT(str1, str2)
-* CURRENT_DATE() - Return the current date
-* CURRENT_TIME() - Returns the current time
-* CURRENT_TIMESTAMP() - Returns a timestamp of the current date and time.
-* LENGTH(str) - Returns the length of the given string
-* LOCATE(needle, haystack [, offset]) - Locate the first occurrence of the substring in the string.
-* LOWER(str) - returns the string lowercased.
-* MOD(a, b) - Return a MOD b.
-* SIZE(collection) - Return the number of elements in the specified collection
-* SQRT(q) - Return the square-root of q.
-* SUBSTRING(str, start [, length]) - Return substring of given string.
-* 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.
-
-### Arithmetic operators
-
-You can do math in DQL using numeric values, for example:
-
- SELECT person.salary * 1.5 FROM CompanyPerson person WHERE person.salary < 100000
-
-### Aggregate Functions
-
-The following aggregate functions are allowed in SELECT and GROUP BY clauses: AVG, COUNT, MIN, MAX, SUM
-
-### Other Expressions
-
-DQL offers a wide-range of additional expressions that are known from SQL, here is a list of
-all the supported constructs:
-
-* `ALL/ANY/SOME` - Used in a WHERE clause followed by a sub-select this works like the equivalent constructs in SQL.
-* `BETWEEN a AND b` and `NOT BETWEEN a AND b` can be used to match ranges of arithmetic values.
-* `IN (x1, x2, ...)` and `NOT IN (x1, x2, ..)` can be used to match a set of given values.
-* `LIKE ..` and `NOT LIKE ..` match parts of a string or text using % as a wildcard.
-* `IS NULL` and `IS NOT NULL` to check for null values
-* `EXISTS` and `NOT EXISTS` in combination with a sub-select
-
-### Adding your own functions to the DQL language
-
-By default DQL comes with functions that are part of a large basis of underlying databases. However you will most likely
-choose a database platform at the beginning of your project and most likely never change it. For this cases you can
-easily extend the DQL parser with own specialized platform functions.
-
-You can register custom DQL functions in your ORM Configuration:
-
- addCustomStringFunction($name, $class);
- $config->addCustomNumericFunction($name, $class);
- $config->addCustomDatetimeFunction($name, $class);
-
- $em = EntityManager::create($dbParams, $config);
-
-The functions have to return either a string, numeric or datetime value depending on the registered function type. As an example
-we will add a MySQL specific FLOOR() functionality. All the given classes have to implement the base class
-\Doctrine\ORM\Query\AST\Functions\FunctionNode:
-
- walkSimpleArithmeticExpression(
- $this->simpleArithmeticExpression
- ) . ')';
- }
-
- public function parse(\Doctrine\ORM\Query\Parser $parser)
- {
- $lexer = $parser->getLexer();
-
- $parser->match(Lexer::T_ABS);
- $parser->match(Lexer::T_OPEN_PARENTHESIS);
-
- $this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression();
-
- $parser->match(Lexer::T_CLOSE_PARENTHESIS);
- }
- }
-
-We will register the function by calling and can then use it:
-
- setName('test');
- $employee->setDepartment('testing');
- $em->persist($employee);
- $em->flush();
-
-Now lets run a simple query to retrieve the `Employee` we just created:
-
- [sql]
- SELECT e FROM Entities\Employee e WHERE e.name = 'test'
-
-If we check the generated SQL you will notice it has some special conditions added to
-ensure that we will only get back `Employee` entities:
-
- [sql]
- SELECT p0_.id AS id0, p0_.name AS name1, p0_.department AS department2, p0_.discr AS discr3 FROM Person p0_ WHERE (p0_.name = ?) AND p0_.discr IN ('employee')
-
-### Class Table Inheritance
-
-[Class Table Inheritance](http://martinfowler.com/eaaCatalog/classTableInheritance.html) 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 of a parent class through a foreign key constraint.
-Doctrine 2 implements this strategy through the use of a discriminator column in the topmost table of the hierarchy because this is the easiest way to achieve polymorphic queries with Class Table Inheritance.
-
-The example for class table inheritance is the same as single table, you just need to
-change the inheritance type from `SINGLE_TABLE` to `JOINED`:
-
- createQuery('select u from MyProject\Model\User u');
-
- // example2: using setDql
- $q = $em->createQuery();
- $q->setDql('select u from MyProject\Model\User u');
-
-### Query Result Formats
-
-The format in which the result of a DQL SELECT query is returned can be influenced by a so-called `hydration mode`. A hydration mode specifies a particular way in which an SQL result set is transformed. Each hydration mode has its own dedicated method on the Query class. Here they are:
-
-* `Query#getResult()`: Retrieves a collection of objects. The result is either a plain collection of objects (pure) or an array where the objects are nested in the result rows (mixed).
-* `Query#getSingleResult()`: Retrieves a single object. If the result contains more than one object, an exception is thrown. The pure/mixed distinction does not apply.
-* `Query#getArrayResult()`: Retrieves an array graph (a nested array) that is largely interchangeable with the object graph generated by `Query#getResultList()` for read-only purposes.
-
-> **NOTE**
-> An array graph can differ from the corresponding object graph in
-> certain scenarios due to the difference of the identity semantics between arrays and
-> objects.
-
-* `Query#getScalarResult()`: Retrieves a flat/rectangular result set of scalar values that can contain duplicate data. The pure/mixed distinction does not apply.
-* `Query#getSingleScalarResult()`: Retrieves a single scalar value from the result returned by the dbms. If the result contains more than a single scalar value, an exception is thrown. The pure/mixed distinction does not apply.
-
-Instead of using these methods, you can alternatively use the general-purpose method `Query#execute(array $params = array(), $hydrationMode = Query::HYDRATE_OBJECT)`. Using this method you can directly supply the hydration mode as the second parameter via one of the Query constants. In fact, the methods mentioned earlier are just convenient shortcuts for the execute method. For example, the method `Query#getResultList()` internally invokes execute, passing in `Query::HYDRATE_OBJECT` as the hydration mode.
-
-The use of the methods mentioned earlier is generally preferred as it leads to more concise code.
-
-### Pure and Mixed Results
-
-The nature of a result returned by a DQL SELECT query retrieved through `Query#getResult()` or `Query#getArrayResult()` can be of 2 forms: **pure** and **mixed**. In the previous simple examples, you already saw a "pure" query result, with only objects. By default, the result type is **pure** but **as soon as scalar values, such as aggregate values or other scalar values that do not belong to an entity, appear in the SELECT part of the DQL query, the result becomes mixed**. A mixed result has a different structure than a pure result in order to accommodate for the scalar values.
-
-A pure result usually looks like this:
-
- array
- [0] => Object
- [1] => Object
- [2] => Object
- ...
-
-A mixed result on the other hand has the following general structure:
-
- array
- array
- [0] => Object
- [1] => "some scalar string"
- ['count'] => 42
- // ... more scalar values, either indexed numerically or with a name
- array
- [0] => Object
- [1] => "some scalar string"
- ['count'] => 42
- // ... more scalar values, either indexed numerically or with a name
-
-To better understand mixed results, consider the following DQL query:
-
- [sql]
- SELECT u, UPPER(u.name) nameUpper FROM MyProject\Model\User u
-
-This query makes use of the `UPPER` DQL function that returns a scalar value and because there is now a scalar value in the SELECT clause, we get a mixed result.
-
-Here is how the result could look like:
-
- array
- array
- [0] => User (Object)
- ['nameUpper'] => "Roman"
- array
- [0] => User (Object)
- ['nameUpper'] => "Jonathan"
- ...
-
-And here is how you would access it in PHP code:
-
- getName();
- echo "Name UPPER: " . $row['nameUpper'];
- }
-
-You may have observed that in a mixed result, the object always ends up on index 0 of a result row.
-
-### Hydration Modes
-
-Each of the Hydration Modes makes assumptions about how the result is returned to user land. You should
-know about all the details to make best use of the different result formats:
-
-The constants for the different hydration modes are:
-
-* Query::HYDRATE_OBJECT
-* Query::HYDRATE_ARRAY
-* Query::HYDRATE_SCALAR
-* Query::HYDRATE_SINGLE_SCALAR
-
-#### Object Hydration
-
-Object hydration hydrates the result set into the object graph:
-
- createQuery('SELECT u FROM CmsUser u');
- $users = $query->getResult(Query::HYDRATE_OBJECT);
-
-#### Array Hydration
-
-You can run the same query with array hydration and the result set is hydrated into
-an array that represents the object graph:
-
- createQuery('SELECT u FROM CmsUser u');
- $users = $query->getResult(Query::HYDRATE_ARRAY);
-
-You can use the `getArrayResult()` shortcut as well:
-
- getArrayResult();
-
-#### Scalar Hydration
-
-If you want to return a flat rectangular result set instead of an object graph
-you can use scalar hydration:
-
- createQuery('SELECT u FROM CmsUser u');
- $users = $query->getResult(Query::HYDRATE_SCALAR);
- echo $users[0]['u_id'];
-
-The following assumptions are made about selected fields using Scalar Hydration:
-
-1. Fields from classes are prefixed by the DQL alias in the result. A query of the kind 'SELECT u.name ..' returns a key 'u_name' in the result rows.
-
-#### Single Scalar Hydration
-
-If you a query which returns just a single scalar value you can use single scalar
-hydration:
-
- createQuery('SELECT COUNT(a.id) FROM CmsUser u LEFT JOIN u.articles a WHERE u.username = ?1 GROUP BY u.id');
- $query->setParameter(1, 'jwage');
- $numArticles = $query->getResult(Query::HYDRATE_SINGLE_SCALAR);
-
-You can use the `getSingleScalarResult()` shortcut as well:
-
- getSingleScalarResult();
-
-#### Custom Hydration Modes
-
-You can easily add your own custom hydration modes by first creating a class which extends `AbstractHydrator`:
-
- _stmt->fetchAll(PDO::FETCH_ASSOC);
- }
- }
-
-Next you just need to add the class to the ORM configuration:
-
- getConfiguration()->addCustomHydrationMode('CustomHydrator', 'MyProject\Hydrators\CustomHydrator');
-
-Now the hydrator is ready to be used in your queries:
-
- createQuery('SELECT u FROM CmsUser u');
- $results = $query->getResult('CustomHydrator');
-
-### Iterating Large Result Sets
-
-There are situations when a query you want to execute returns a very large result-set that needs
-to be processed. All the previously described hydration modes completely load a result-set into
-memory which might not be feasible with large result sets. See the [Batch Processing](batch-processing)
-section on details how to iterate large result sets.
-
-### Functions
-
-The following methods exist on the `AbstractQuery` which both `Query` and `NativeQuery` extend from.
-
-#### Parameters
-
-Prepared Statements that use numerical or named wildcards require additional parameters to be executable
-against the database. To pass parameters to the query the following methods can be used:
-
-* `AbstractQuery::setParameter($param, $value)` - Set the numerical or named wildcard to the given value.
-* `AbstractQuery::setParameters(array $params)` - Set an array of parameter key-value pairs.
-* `AbstractQuery::getParameter($param)`
-* `AbstractQuery::getParameters()`
-
-#### Cache related API
-
-You can cache query results based either on all variables that define the result (SQL, Hydration Mode, Parameters and Hints)
-or on user-defined cache keys. However by default query results are not cached at all. You have to enable
-the result cache on a per query basis. The following example shows a complete workflow using the Result Cache
-API:
-
- createQuery('SELECT u FROM MyProject\Model\User u WHERE u.id = ?1');
- $query->setParameter(1, 12);
-
- $query->setResultCacheDriver(new ApcCache());
-
- $query->useResultCache(true)
- ->setResultCacheLifeTime($seconds = 3600);
-
- $result = $query->getResult(); // cache miss
-
- $query->expireResultCache(true);
- $result = $query->getResult(); // forced expire, cache miss
-
- $query->setResultCacheId('my_query_result');
- $result = $query->getResult(); // saved in given result cache id.
-
- // or call useResultCache() with all parameters:
- $query->useResultCache(true, $seconds = 3600, 'my_query_result');
- $result = $query->getResult(); // cache hit!
-
-> **TIP!**
-> You can set the Result Cache Driver globally on the `Doctrine\ORM\Configuration` instance
-> so that it is passed to every `Query` and `NativeQuery` instance.
-
-#### Query Hints
-
-You can pass hints to the query parser and hydrators by using the `AbstractQuery::setHint($name, $value)` method.
-Currently there exist mostly internal query hints that are not be consumed in userland. However the following few hints
-are to be used in userland:
-
-* Query::HINT_FORCE_PARTIAL_LOAD - Allows to hydrate objects although not all their columns are fetched. This query
-hint can be used to handle memory consumption problems with large result-sets that contain char or binary data.
-Doctrine has no way of implicitly reloading this data. Partially loaded objects have to be passed to
-`EntityManager::refresh()` if they are to be reloaded fully from the database.
-* Query::HINT_REFRESH - This query is used internally by `EntityManager::refresh()` and can be used in userland as well.
-If you specify this hint and a query returns the data for an entity that is already managed by the UnitOfWork, the
-fields of the existing entity will be refreshed. In normal operation a result-set that loads data of an already existing
-entity is discarded in favor of the already existing entity.
-* Query::HINT_CUSTOM_TREE_WALKERS - An array of additional `Doctrine\ORM\Query\TreeWalker` instances that are attached
-to the DQL query parsing process.
-
-#### Query Cache (DQL Query Only)
-
-Parsing a DQL query and converting it into an SQL query against the underlying database platform obviously has some overhead
-in contrast to directly executing Native SQL queries. That is why there is a dedicated Query Cache for caching the
-DQL parser results. In combination with the use of wildcards you can reduce the number of parsed queries in production
-to zero.
-
-The Query Cache Driver is passed from the `Doctrine\ORM\Configuration` instance to each `Doctrine\ORM\Query` instance
-by default and is also enabled by default. This also means you don't regularly need to fiddle with the parameters
-of the Query Cache, however if you do there are several methods to interact with it:
-
-* `Query::setQueryCacheDriver($driver)` - Allows to set a Cache instance
-* `Query::setQueryCacheLifeTime($seconds = 3600)` - Set lifetime of the query caching.
-* `Query::expireQueryCache($bool)` - Enforce the expiring of the query cache if set to true.
-* `Query::getExpireQueryCache()`
-* `Query::getQueryCacheDriver()`
-* `Query::getQueryCacheLifeTime()`
-
-#### First and Max Result Items (DQL Query Only)
-
-You can limit the number of results returned from a DQL query as well as specify the starting offset, Doctrine
-then uses a strategy of manipulating the select query to return only the requested number of results:
-
-* `Query::setMaxResults($maxResults)`
-* `Query::setFirstResult($offset)`
-
-> **NOTE**
-> If your query contains a fetch-joined collection specifying the result limit methods are not working
-> as you would expect. Set Max Results restricts the number of database result rows, however in the
-> case of fetch-joined collections one root entity might appear in many rows, effectively hydrating
-> less than the specified number of results.
-
-## EBNF
-
-The following context-free grammar, written in an EBNF variant, describes the Doctrine Query Language. You can consult this grammar whenever you are unsure about what is possible with DQL or what the correct syntax for a particular query should be.
-
-### Document syntax:
-
-* non-terminals begin with an upper case character
-* terminals begin with a lower case character
-* parentheses (...) are used for grouping
-* square brackets [...] are used for defining an optional part, e.g. zero or one time
-* curly brackets {...} are used for repetition, e.g. zero or more times
-* double quotation marks "..." define a terminal string a vertical bar | represents an alternative
-
-### Terminals
-
-* identifier (name, email, ...)
-* string ('foo', 'bar''s house', '%ninja%', ...)
-* char ('/', '\\', ' ', ...)
-* integer (-1, 0, 1, 34, ...)
-* float (-0.23, 0.007, 1.245342E+8, ...)
-* boolean (false, true)
-
-### Query Language
-
- QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatement
-
-### Statements
-
- SelectStatement ::= SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
- UpdateStatement ::= UpdateClause [WhereClause]
- DeleteStatement ::= DeleteClause [WhereClause]
-
-### Identifiers
-
- /* Alias Identification usage (the "u" of "u.name") */
- IdentificationVariable ::= identifier
-
- /* Alias Identification declaration (the "u" of "FROM User u") */
- AliasIdentificationVariable :: = identifier
-
- /* identifier that must be a class name (the "User" of "FROM User u") */
- AbstractSchemaName ::= identifier
-
- /* identifier that must be a field (the "name" of "u.name") */
- /* This is responsible to know if the field exists in Object, no matter if it's a relation or a simple field */
- FieldIdentificationVariable ::= identifier
-
- /* identifier that must be a collection-valued association field (to-many) (the "Phonenumbers" of "u.Phonenumbers") */
- CollectionValuedAssociationField ::= FieldIdentificationVariable
-
- /* identifier that must be a single-valued association field (to-one) (the "Group" of "u.Group") */
- SingleValuedAssociationField ::= FieldIdentificationVariable
-
- /* identifier that must be an embedded class state field (for the future) */
- EmbeddedClassStateField ::= FieldIdentificationVariable
-
- /* identifier that must be a simple state field (name, email, ...) (the "name" of "u.name") */
- /* The difference between this and FieldIdentificationVariable is only semantical, because it points to a single field (not mapping to a relation) */
- SimpleStateField ::= FieldIdentificationVariable
-
- /* Alias ResultVariable declaration (the "total" of "COUNT(*) AS total") */
- AliasResultVariable = identifier
-
- /* ResultVariable identifier usage of mapped field aliases (the "total" of "COUNT(*) AS total") */
- ResultVariable = identifier
-
-### Path Expressions
-
- /* "u.Group" or "u.Phonenumbers" declarations */
- JoinAssociationPathExpression ::= IdentificationVariable "." (CollectionValuedAssociationField | SingleValuedAssociationField)
-
- /* "u.Group" or "u.Phonenumbers" usages */
- AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression
-
- /* "u.name" or "u.Group" */
- SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression
-
- /* "u.name" or "u.Group.name" */
- StateFieldPathExpression ::= IdentificationVariable "." StateField | SingleValuedAssociationPathExpression "." StateField
-
- /* "u.Group" */
- SingleValuedAssociationPathExpression ::= IdentificationVariable "." {SingleValuedAssociationField "."}* SingleValuedAssociationField
-
- /* "u.Group.Permissions" */
- CollectionValuedPathExpression ::= IdentificationVariable "." {SingleValuedAssociationField "."}* CollectionValuedAssociationField
-
- /* "name" */
- StateField ::= {EmbeddedClassStateField "."}* SimpleStateField
-
- /* "u.name" or "u.address.zip" (address = EmbeddedClassStateField) */
- SimpleStateFieldPathExpression ::= IdentificationVariable "." StateField
-
-
-### Clauses
-
- SelectClause ::= "SELECT" ["DISTINCT"] SelectExpression {"," SelectExpression}*
- SimpleSelectClause ::= "SELECT" ["DISTINCT"] SimpleSelectExpression
- UpdateClause ::= "UPDATE" AbstractSchemaName ["AS"] AliasIdentificationVariable "SET" UpdateItem {"," UpdateItem}*
- DeleteClause ::= "DELETE" ["FROM"] AbstractSchemaName ["AS"] AliasIdentificationVariable
- FromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}*
- SubselectFromClause ::= "FROM" SubselectIdentificationVariableDeclaration {"," SubselectIdentificationVariableDeclaration}*
- WhereClause ::= "WHERE" ConditionalExpression
- HavingClause ::= "HAVING" ConditionalExpression
- GroupByClause ::= "GROUP" "BY" GroupByItem {"," GroupByItem}*
- OrderByClause ::= "ORDER" "BY" OrderByItem {"," OrderByItem}*
- Subselect ::= SimpleSelectClause SubselectFromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
-
-
-### Items
-
- UpdateItem ::= IdentificationVariable "." (StateField | SingleValuedAssociationField) "=" NewValue
- OrderByItem ::= (ResultVariable | StateFieldPathExpression) ["ASC" | "DESC"]
- GroupByItem ::= IdentificationVariable | SingleValuedPathExpression
- NewValue ::= ScalarExpression | SimpleEntityExpression | "NULL"
-
-
-### From, Join and Index by
-
- IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {JoinVariableDeclaration}*
- SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration | (AssociationPathExpression ["AS"] AliasIdentificationVariable)
- JoinVariableDeclaration ::= Join [IndexBy]
- RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable
- Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" JoinAssociationPathExpression
- ["AS"] AliasIdentificationVariable ["WITH" ConditionalExpression]
- IndexBy ::= "INDEX" "BY" SimpleStateFieldPathExpression
-
-
-### Select Expressions
-
- SelectExpression ::= IdentificationVariable | PartialObjectExpression | (AggregateExpression | "(" Subselect ")" | FunctionDeclaration | ScalarExpression) [["AS"] AliasResultVariable]
- SimpleSelectExpression ::= ScalarExpression | IdentificationVariable |
- (AggregateExpression [["AS"] AliasResultVariable])
- PartialObjectExpression ::= "PARTIAL" IdentificationVariable "." PartialFieldSet
- PartialFieldSet ::= "{" SimpleStateField {"," SimpleStateField}* "}"
-
-
-### Conditional Expressions
-
- ConditionalExpression ::= ConditionalTerm {"OR" ConditionalTerm}*
- ConditionalTerm ::= ConditionalFactor {"AND" ConditionalFactor}*
- ConditionalFactor ::= ["NOT"] ConditionalPrimary
- ConditionalPrimary ::= SimpleConditionalExpression | "(" ConditionalExpression ")"
- SimpleConditionalExpression ::= ComparisonExpression | BetweenExpression | LikeExpression |
- InExpression | NullComparisonExpression | ExistsExpression |
- EmptyCollectionComparisonExpression | CollectionMemberExpression
-
-
-### Collection Expressions
-
- EmptyCollectionComparisonExpression ::= CollectionValuedPathExpression "IS" ["NOT"] "EMPTY"
- CollectionMemberExpression ::= EntityExpression ["NOT"] "MEMBER" ["OF"] CollectionValuedPathExpression
-
-### Literal Values
-
- Literal ::= string | char | integer | float | boolean
- InParameter ::= Literal | InputParameter
-
-### Input Parameter
-
- InputParameter ::= PositionalParameter | NamedParameter
- PositionalParameter ::= "?" integer
- NamedParameter ::= ":" string
-
-
-### Arithmetic Expressions
-
- ArithmeticExpression ::= SimpleArithmeticExpression | "(" Subselect ")"
- SimpleArithmeticExpression ::= ArithmeticTerm {("+" | "-") ArithmeticTerm}*
- ArithmeticTerm ::= ArithmeticFactor {("*" | "/") ArithmeticFactor}*
- ArithmeticFactor ::= [("+" | "-")] ArithmeticPrimary
- ArithmeticPrimary ::= SingleValuedPathExpression | Literal | "(" SimpleArithmeticExpression ")"
- | FunctionsReturningNumerics | AggregateExpression | FunctionsReturningStrings
- | FunctionsReturningDatetime | IdentificationVariable | InputParameter
-
-
-### Scalar and Type Expressions
-
- ScalarExpression ::= SimpleArithmeticExpression | StringPrimary | DateTimePrimary | StateFieldPathExpression
- BooleanPrimary | CaseExpression | EntityTypeExpression
- CaseExpression ::= GeneralCaseExpression | SimpleCaseExpression |
- CoalesceExpression | NullifExpression
- GeneralCaseExpression ::= "CASE" WhenClause {WhenClause}* "ELSE" ScalarExpression
- "END"
- WhenClause ::= "WHEN" ConditionalExpression "THEN" ScalarExpression
- SimpleCaseExpression ::= "CASE" CaseOperand SimpleWhenClause {SimpleWhenClause}*
- "ELSE" ScalarExpression "END"
- CaseOperand ::= StateFieldPathExpression | TypeDiscriminator
- SimpleWhenClause ::= "WHEN" ScalarExpression "THEN" ScalarExpression
- CoalesceExpression ::= "COALESCE" "(" ScalarExpression {"," ScalarExpression}* ")"
- NullifExpression ::= "NULLIF" "(" ScalarExpression "," ScalarExpression ")"
- StringExpression ::= StringPrimary | "(" Subselect ")"
- StringPrimary ::= StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression
- BooleanExpression ::= BooleanPrimary | "(" Subselect ")"
- BooleanPrimary ::= StateFieldPathExpression | boolean | InputParameter
- EntityExpression ::= SingleValuedAssociationPathExpression | SimpleEntityExpression
- SimpleEntityExpression ::= IdentificationVariable | InputParameter
- DatetimeExpression ::= DatetimePrimary | "(" Subselect ")"
- DatetimePrimary ::= StateFieldPathExpression | InputParameter | FunctionsReturningDatetime | AggregateExpression
-
-
-### Aggregate Expressions
-
- AggregateExpression ::= ("AVG" | "MAX" | "MIN" | "SUM") "(" ["DISTINCT"] StateFieldPathExpression ")" |
- "COUNT" "(" ["DISTINCT"] (IdentificationVariable | SingleValuedPathExpression) ")"
-
-### Other Expressions
-
-QUANTIFIED/BETWEEN/COMPARISON/LIKE/NULL/EXISTS
-
- QuantifiedExpression ::= ("ALL" | "ANY" | "SOME") "(" Subselect ")"
- BetweenExpression ::= ArithmeticExpression ["NOT"] "BETWEEN" ArithmeticExpression "AND" ArithmeticExpression
- ComparisonExpression ::= ArithmeticExpression ComparisonOperator ( QuantifiedExpression | ArithmeticExpression )
- InExpression ::= StateFieldPathExpression ["NOT"] "IN" "(" (InParameter {"," InParameter}* | Subselect) ")"
- LikeExpression ::= StringExpression ["NOT"] "LIKE" string ["ESCAPE" char]
- NullComparisonExpression ::= (SingleValuedPathExpression | InputParameter) "IS" ["NOT"] "NULL"
- ExistsExpression ::= ["NOT"] "EXISTS" "(" Subselect ")"
- ComparisonOperator ::= "=" | "<" | "<=" | "<>" | ">" | ">=" | "!="
-
-### Functions
-
- FunctionDeclaration ::= FunctionsReturningStrings | FunctionsReturningNumerics | FunctionsReturningDateTime
-
- FunctionsReturningNumerics ::=
- "LENGTH" "(" StringPrimary ")" |
- "LOCATE" "(" StringPrimary "," StringPrimary ["," SimpleArithmeticExpression]")" |
- "ABS" "(" SimpleArithmeticExpression ")" | "SQRT" "(" SimpleArithmeticExpression ")" |
- "MOD" "(" SimpleArithmeticExpression "," SimpleArithmeticExpression ")" |
- "SIZE" "(" CollectionValuedPathExpression ")"
-
- FunctionsReturningDateTime ::= "CURRENT_DATE" | "CURRENT_TIME" | "CURRENT_TIMESTAMP"
-
- FunctionsReturningStrings ::=
- "CONCAT" "(" StringPrimary "," StringPrimary ")" |
- "SUBSTRING" "(" StringPrimary "," SimpleArithmeticExpression "," SimpleArithmeticExpression ")" |
- "TRIM" "(" [["LEADING" | "TRAILING" | "BOTH"] [char] "FROM"] StringPrimary ")" |
- "LOWER" "(" StringPrimary ")" |
- "UPPER" "(" StringPrimary ")"
\ No newline at end of file
diff --git a/manual/en/events.rst b/manual/en/events.rst
index e899e3121..ebdeee81b 100644
--- a/manual/en/events.rst
+++ b/manual/en/events.rst
@@ -1,3 +1,6 @@
+Events
+======
+
Doctrine 2 features a lightweight event system that is part of the
Common package.
@@ -139,10 +142,10 @@ the life-time of their registered entities.
- preRemove - The preRemove event occurs for a given entity before
the respective EntityManager remove operation for that entity is
- executed.
+ executed. It is not called for a DQL DELETE statement.
- postRemove - The postRemove event occurs for an entity after the
entity has been deleted. It will be invoked after the database
- delete operations.
+ delete operations. It is not called for a DQL DELETE statement.
- prePersist - The prePersist event occurs for a given entity
before the respective EntityManager persist operation for that
entity is executed.
@@ -151,9 +154,9 @@ the life-time of their registered entities.
database insert operations. Generated primary key values are
available in the postPersist event.
- preUpdate - The preUpdate event occurs before the database
- update operations to entity data.
+ update operations to entity data. It is not called for a DQL UPDATE statement.
- postUpdate - The postUpdate event occurs after the database
- update operations to entity data.
+ update operations to entity data. It is not called for a DQL UPDATE statement.
- postLoad - The postLoad event occurs for an entity after the
entity has been loaded into the current EntityManager from the
database or after the refresh operation has been applied to it.
@@ -164,7 +167,9 @@ the life-time of their registered entities.
managed entities are computed. This event is not a lifecycle
callback.
- **CAUTION** Note that the postLoad event occurs for an entity
+.. warning::
+
+ Note that the postLoad event occurs for an entity
before any associations have been initialized. Therefore it is not
safe to access associations in a postLoad callback or event
handler.
@@ -191,7 +196,9 @@ listeners:
methods that receives some kind of ``EventArgs`` instance which
give access to the entity, EntityManager or other relevant data.
- **NOTE** All Lifecycle events that happen during the ``flush()`` of
+.. note::
+
+ All Lifecycle events that happen during the ``flush()`` of
an EntityManager have very specific constraints on the allowed
operations that can be executed. Please read the
*Implementing Event Listeners* section very carefully to understand
diff --git a/manual/en/events.txt b/manual/en/events.txt
deleted file mode 100644
index a83340f39..000000000
--- a/manual/en/events.txt
+++ /dev/null
@@ -1,467 +0,0 @@
-Doctrine 2 features a lightweight event system that is part of the Common package.
-
-## The Event System
-
-The event system is controlled by the `EventManager`. It is the central point
-of Doctrine's event listener system. Listeners are registered on the manager
-and events are dispatched through the manager.
-
- addEventListener(array(self::preFoo, self::postFoo), $this);
- }
-
- public function preFoo(EventArgs $e)
- {
- $this->preFooInvoked = true;
- }
-
- public function postFoo(EventArgs $e)
- {
- $this->postFooInvoked = true;
- }
- }
-
- // Create a new instance
- $test = new EventTest($evm);
-
-Events can be dispatched by using the `dispatchEvent()` method.
-
- dispatchEvent(EventTest::preFoo);
- $evm->dispatchEvent(EventTest::postFoo);
-
-You can easily remove a listener with the `removeEventListener()` method.
-
- removeEventListener(array(self::preFoo, self::postFoo), $this);
-
-The Doctrine 2 event system also has a simple concept of event subscribers. We
-can define a simple `TestEventSubscriber` class which implements the
-`\Doctrine\Common\EventSubscriber` interface and implements a `getSubscribedEvents()`
-method which returns an array of events it should be subscribed to.
-
- preFooInvoked = true;
- }
-
- public function getSubscribedEvents()
- {
- return array(TestEvent::preFoo);
- }
- }
-
- $eventSubscriber = new TestEventSubscriber();
- $evm->addEventSubscriber($eventSubscriber);
-
-Now when you dispatch an event any event subscribers will be notified for that event.
-
- dispatchEvent(TestEvent::preFoo);
-
-Now you can test the `$eventSubscriber` instance to see if the `preFoo()` method was invoked.
-
- preFooInvoked) {
- echo 'pre foo invoked!';
- }
-
-### Naming convention
-
-Events being used with the Doctrine 2 EventManager are best named with camelcase and the value of the corresponding constant should be the name of the constant itself, even with spelling. This has several reasons:
-
-* It is easy to read.
-* Simplicity.
-* Each method within an EventSubscriber is named after the corresponding constant. If constant name and constant value differ, you MUST use the new value and thus, your code might be subject to codechanges when the value changes. This contradicts the intention of a constant.
-
-An example for a correct notation can be found in the example `EventTest` above.
-
-## Lifecycle Events
-
-The EntityManager and UnitOfWork trigger a bunch of events during the life-time of their registered entities.
-
-* preRemove - The preRemove event occurs for a given entity before the respective EntityManager remove operation for that entity is executed.
-* postRemove - The postRemove event occurs for an entity after the entity has been deleted. It will be invoked after the database delete operations.
-* prePersist - The prePersist event occurs for a given entity before the respective EntityManager persist operation for that entity is executed.
-* postPersist - The postPersist event occurs for an entity after the entity has been made persistent. It will be invoked after the database insert operations. Generated primary key values are available in the postPersist event.
-* preUpdate - The preUpdate event occurs before the database update operations to entity data.
-* postUpdate - The postUpdate event occurs after the database update operations to entity data.
-* postLoad - The postLoad event occurs for an entity after the entity has been loaded into the current EntityManager from the database or after the refresh operation has been applied to it.
-* loadClassMetadata - The loadClassMetadata event occurs after the mapping metadata for a class has been loaded from a mapping source (annotations/xml/yaml).
-* onFlush - The onFlush event occurs after the change-sets of all managed entities are computed. This event is not a lifecycle callback.
-
-> **CAUTION**
-> Note that the postLoad event occurs for an entity before any associations have been
-> initialized. Therefore it is not safe to access associations in a postLoad callback
-> or event handler.
-
-You can access the Event constants from the `Events` class in the ORM package.
-
- **NOTE**
-> All Lifecycle events that happen during the `flush()` of an EntityManager have very specific constraints on the allowed
-> operations that can be executed. Please read the *Implementing Event Listeners* section very carefully to understand
-> which operations are allowed in which lifecycle event.
-
-## Lifecycle Callbacks
-
-A lifecycle event is a regular event with the additional feature of providing
-a mechanism to register direct callbacks inside the corresponding entity classes
-that are executed when the lifecycle event occurs.
-
- createdAt = date('Y-m-d H:m:s');
- }
-
- /** @PrePersist */
- public function doOtherStuffOnPrePersist()
- {
- $this->value = 'changed from prePersist callback!';
- }
-
- /** @PostPersist */
- public function doStuffOnPostPersist()
- {
- $this->value = 'changed from postPersist callback!';
- }
-
- /** @PostLoad */
- public function doStuffOnPostLoad()
- {
- $this->value = 'changed from postLoad callback!';
- }
-
- /** @PreUpdate */
- public function doStuffOnPreUpdate()
- {
- $this->value = 'changed from preUpdate callback!';
- }
- }
-
-Note that when using annotations you have to apply the @HasLifecycleCallbacks marker annotation on the entity class.
-
-If you want to register lifecycle callbacks from YAML or XML you can do it with
-the following.
-
- [yml]
- User:
- type: entity
- fields:
- # ...
- name:
- type: string(50)
- lifecycleCallbacks:
- doStuffOnPrePersist: prePersist
- doStuffOnPostPersist: postPersist
-
-XML would look something like this:
-
- [xml]
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-You just need to make sure a public `doStuffOnPrePersist()` and `doStuffOnPostPersist()` method is defined on your `User` model.
-
- addEventListener(array(Events::preUpdate), MyEventListener());
- $eventManager->addEventSubscriber(new MyEventSubscriber());
-
- $entityManager = EntityManager::create($dbOpts, $config, $eventManager);
-
-You can also retrieve the event manager instance after the EntityManager was created:
-
- getEventManager()->addEventListener(array(Events::preUpdate), MyEventListener());
- $entityManager->getEventManager()->addEventSubscriber(new MyEventSubscriber());
-
-## Implementing Event Listeners
-
-This section explains what is and what is not allowed during specific lifecycle events of the UnitOfWork.
-Although you get passed the EntityManager in all of these events, you have to follow this restrictions very
-carefully since operations in the wrong event may produce lots of different errors, such as inconsistent data and
-lost updates/persists/removes.
-
-For the described events that are also lifecycle callback events the restrictions
-apply as well, with the additional restriction that you do not have access to the EntityManager
-or UnitOfWork APIs inside these events.
-
-### prePersist
-
-There are two ways for the `prePersist` event to be triggered. One is obviously
-when you call `EntityManager#persist()`. The event is also called for all
-cascaded associations.
-
-There is another way for `prePersist` to be called, inside the `flush()`
-method when changes to associations are computed and this association
-is marked as cascade persist. Any new entity found during this operation
-is also persisted and `prePersist` called on it. This is called "persistence by reachability".
-
-In both cases you get passed a `LifecycleEventArgs`
-instance which has access to the entity and the entity manager.
-
-The following restrictions apply to `prePersist`:
-
-* If you are using a PrePersist Identity Generator such as sequences the ID value
- will *NOT* be available within any PrePersist events.
-* Doctrine will not recognize changes made to relations in a pre persist event
- called by "reachability" through a cascade persist unless you use the internal
- `UnitOfWork` API. We do not recommend such operations in the persistence by
- reachability context, so do this at your own risk and possibly supported by unit-tests.
-
-### preRemove
-
-The `preRemove` event is called on every entity when its passed to
-the `EntityManager#remove()` method. It is cascaded for all
-associations that are marked as cascade delete.
-
-There are no restrictions to what methods can be called inside
-the `preRemove` event, except when the remove method itself was
-called during a flush operation.
-
-### onFlush
-
-OnFlush is a very powerful event. It is called inside `EntityManager#flush()`
-after the changes to all the managed entities and their associations have
-been computed. This means, the `onFlush` event has access to the sets of:
-
-* Entities scheduled for insert
-* Entities scheduled for update
-* Entities scheduled for removal
-* Collections scheduled for update
-* Collections scheduled for removal
-
-To make use of the onFlush event you have to be familiar with the internal UnitOfWork API,
-which grants you access to the previously mentioned sets. See this example:
-
- getEntityManager();
- $uow = $em->getUnitOfWork();
-
- foreach ($uow->getScheduledEntityInsertions() AS $entity) {
-
- }
-
- foreach ($uow->getScheduledEntityUpdates() AS $entity) {
-
- }
-
- foreach ($uow->getScheduledEntityDeletions() AS $entity) {
-
- }
-
- foreach ($uow->getScheduledCollectionDeletions() AS $col) {
-
- }
-
- foreach ($uow->getScheduledCollectionUpdates() AS $col) {
-
- }
- }
- }
-
-The following restrictions apply to the onFlush event:
-
-* Calling `EntityManager#persist()` does not suffice to trigger a persist on an entity.
- You have to execute an additional call to `$unitOfWork->computeChangeSet($classMetadata, $entity)`.
-* Changing primitive fields or associations requires you to explicitly trigger
- a re-computation of the changeset of the affected entity. This can be done
- by either calling `$unitOfWork->computeChangeSet($classMetadata, $entity)`
- or `$unitOfWork->recomputeSingleEntityChangeSet($classMetadata, $entity)`. The second
- method has lower overhead, but only re-computes primitive fields, never associations.
-
-### preUpdate
-
-PreUpdate is the most restrictive to use event, since it is called right before
-an update statement is called for an entity inside the `EntityManager#flush()`
-method.
-
-Changes to associations of the updated entity are never allowed in this event, since Doctrine cannot guarantee to
-correctly handle referential integrity at this point of the flush operation. This
-event has a powerful feature however, it is executed with a `PreUpdateEventArgs`
-instance, which contains a reference to the computed change-set of this entity.
-
-This means you have access to all the fields that have changed for this entity
-with their old and new value. The following methods are available on the `PreUpdateEventArgs`:
-
-* `getEntity()` to get access to the actual entity.
-* `getEntityChangeSet()` to get a copy of the changeset array. Changes to this returned array do not affect updating.
-* `hasChangedField($fieldName)` to check if the given field name of the current entity changed.
-* `getOldValue($fieldName)` and `getNewValue($fieldName)` to access the values of a field.
-* `setNewValue($fieldName, $value)` to change the value of a field to be updated.
-
-A simple example for this event looks like:
-
- getEntity() instanceof User) {
- if ($eventArgs->hasChangedField('name') && $eventArgs->getNewValue('name') == 'Alice') {
- $eventArgs->setNewValue('name', 'Bob');
- }
- }
- }
- }
-
-You could also use this listener to implement validation of all the fields that have changed.
-This is more efficient than using a lifecycle callback when there are expensive validations
-to call:
-
- getEntity() instanceof Account) {
- if ($eventArgs->hasChangedField('creditCard')) {
- $this->validateCreditCard($eventArgs->getNewValue('creditCard'));
- }
- }
- }
-
- private function validateCreditCard($no)
- {
- // throw an exception to interrupt flush event. Transaction will be rolled back.
- }
- }
-
-Restrictions for this event:
-
-* Changes to associations of the passed entities are not recognized by the flush operation anymore.
-* Changes to fields of the passed entities are not recognized by the flush operation anymore, use the computed change-set passed to the event to modify primitive field values.
-* Any calls to `EntityManager#persist()` or `EntityManager#remove()`, even in combination with the UnitOfWork API are strongly discouraged and don't work as expected outside the flush operation.
-
-### postUpdate, postRemove, postPersist
-
-The three post events are called inside `EntityManager#flush()`. Changes in here
-are not relevant to the persistence in the database, but you can use this events
-to
-
-### postLoad
-
-This event is called after an entity is constructed by the EntityManager.
-
-## Load ClassMetadata Event
-
-When the mapping information for an entity is read, it is populated in to a
-`ClassMetadataInfo` instance. You can hook in to this process and manipulate
-the instance.
-
- getMetadataFactory();
- $evm = $em->getEventManager();
- $evm->addEventListener(Events::loadClassMetadata, $test);
-
- class EventTest
- {
- public function loadClassMetadata(\Doctrine\ORM\Event\LoadClassMetadataEventArgs $eventArgs)
- {
- $classMetadata = $eventArgs->getClassMetadata();
- $fieldMapping = array(
- 'fieldName' => 'about',
- 'type' => 'string',
- 'length' => 255
- );
- $classMetadata->mapField($fieldMapping);
- }
- }
diff --git a/manual/en/improving-performance.rst b/manual/en/improving-performance.rst
index 2d9ffb57f..eee5b4b9b 100644
--- a/manual/en/improving-performance.rst
+++ b/manual/en/improving-performance.rst
@@ -1,3 +1,6 @@
+Improving Performance
+=====================
+
Bytecode Cache
--------------
@@ -5,7 +8,9 @@ It is highly recommended to make use of a bytecode cache like APC.
A bytecode cache removes the need for parsing PHP code on every
request and can greatly improve performance.
- **NOTE** "If you care about performance and don't use a bytecode
+.. note::
+
+ "If you care about performance and don't use a bytecode
cache then you don't really care about performance. Please get one
and start using it." (Stas Malyshev, Core Contributor to PHP and
Zend Employee).
diff --git a/manual/en/improving-performance.txt b/manual/en/improving-performance.txt
deleted file mode 100644
index 01509bb81..000000000
--- a/manual/en/improving-performance.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-
-## Bytecode Cache
-
-It is highly recommended to make use of a bytecode cache like APC. A bytecode cache removes the need for parsing PHP code on every request and can greatly improve performance.
-
-> **NOTE**
-> "If you care about performance and don't use a bytecode cache then you don't really care
-> about performance. Please get one and start using it." (Stas Malyshev, Core Contributor
-> to PHP and Zend Employee).
-
-
-## Metadata and Query caches
-
-As already mentioned earlier in the chapter about configuring Doctrine, it is strongly discouraged to use Doctrine without a Metadata and Query cache (preferably with APC or Memcache as the cache driver). Operating Doctrine without these caches means Doctrine will need to load your mapping information on every single request and has to parse each DQL query on every single request. This is a waste of resources.
-
-## Alternative Query Result Formats
-
-Make effective use of the available alternative query result formats like nested array graphs or pure scalar results, especially in scenarios where data is loaded for read-only purposes.
-
-## Apply Best Practices
-
-A lot of the points mentioned in the Best Practices chapter will also positively affect the performance of Doctrine.
-
-
-
diff --git a/manual/en/index.rst b/manual/en/index.rst
index af4ddee9a..91eb8f6b6 100644
--- a/manual/en/index.rst
+++ b/manual/en/index.rst
@@ -11,6 +11,33 @@ Contents:
.. toctree::
:maxdepth: 2
+ introduction
+ architecture
+ configuration
+ basic-mapping
+ association-mapping
+ inheritance-mapping
+ working-with-objects
+ working-with-associations
+ transactions-and-concurrency
+ events
+ batch-processing
+ dql-doctrine-query-language
+ query-builder
+ native-sql
+ change-tracking-policies
+ partial-objects
+ xml-mapping
+ yaml-mapping
+ annotations-reference
+ php-mapping
+ caching
+ improving-performance
+ tools
+ metadata-drivers
+ best-practices
+ limitations-and-Known-issues
+
Indices and tables
==================
diff --git a/manual/en/inheritance-mapping.rst b/manual/en/inheritance-mapping.rst
index f950577c5..3b226aad4 100644
--- a/manual/en/inheritance-mapping.rst
+++ b/manual/en/inheritance-mapping.rst
@@ -1,3 +1,6 @@
+Inheritance Mapping
+===================
+
Mapped Superclasses
-------------------
@@ -11,7 +14,7 @@ Mapped superclasses, just as regular, non-mapped classes, can
appear in the middle of an otherwise mapped inheritance hierarchy
(through Single Table Inheritance or Class Table Inheritance).
- **NOTE**
+.. note::
A mapped superclass cannot be an entity, it is not query-able and
persistent relationships defined by a mapped superclass must be
@@ -54,9 +57,8 @@ Example:
The DDL for the corresponding database schema would look something
like this (this is for SQLite):
-::
+.. code-block:: sql
- [sql]
CREATE TABLE EntitySubClass (mapped1 INTEGER NOT NULL, mapped2 TEXT NOT NULL, id INTEGER NOT NULL, name TEXT NOT NULL, related1_id INTEGER DEFAULT NULL, PRIMARY KEY(id))
As you can see from this DDL snippet, there is only a single table
@@ -202,7 +204,9 @@ Things to note:
namespace as the entity class on which the discriminator map is
applied.
- **NOTE** When you do not use the SchemaTool to generate the
+.. note::
+
+ When you do not use the SchemaTool to generate the
required SQL you should know that deleting a class table
inheritance makes use of the foreign key property
``ON DELETE CASCADE`` in all database implementations. A failure to
diff --git a/manual/en/inheritance-mapping.txt b/manual/en/inheritance-mapping.txt
deleted file mode 100644
index b1ed480c4..000000000
--- a/manual/en/inheritance-mapping.txt
+++ /dev/null
@@ -1,159 +0,0 @@
-## Mapped Superclasses
-
-An mapped superclass is an abstract or concrete class that provides persistent entity state and mapping information
-for its subclasses, but which is not itself an entity. Typically, the purpose of such a mapped superclass is to define
-state and mapping information that is common to multiple entity classes.
-
-Mapped superclasses, just as regular, non-mapped classes, can appear in the middle of an otherwise
-mapped inheritance hierarchy (through Single Table Inheritance or Class Table Inheritance).
-
-> **NOTE**
->
-> A mapped superclass cannot be an entity, it is not query-able and persistent relationships defined by a mapped
-> superclass must be unidirectional. For further support of inheritance, the single or joined table inheritance
-> features have to be used.
-
-Example:
-
- **NOTE**
-> When you do not use the SchemaTool to generate the required SQL you should know that deleting a class table inheritance
-> makes use of the foreign key property `ON DELETE CASCADE` in all database implementations. A failure to implement this
-> yourself will lead to dead rows in the database.
-
-### Design-time considerations
-
-Introducing a new type to the hierarchy, at any level, simply involves interjecting a new table into the schema. Subtypes of that type will automatically join with that new type at runtime. Similarly, modifying any entity type in the hierarchy by adding, modifying or removing fields affects only the immediate table mapped to that type. This mapping strategy provides the greatest flexibility at design time, since changes to any type are always limited to that type's dedicated table.
-
-### Performance impact
-
-This strategy inherently requires multiple JOIN operations to perform just about any query which can have a negative impact on performance, especially with large tables and/or large hierarchies. When partial objects are allowed, either globally or on the specific query, then querying for any type will not cause the tables of subtypes to be OUTER JOINed which can increase performance but the resulting partial objects will not fully load themselves on access of any subtype fields, so accessing fields of subtypes after such a query is not safe.
-
-There is a general performance consideration with Class Table Inheritance: If you use a CTI entity as a many-to-one or one-to-one entity you should never use one of the classes at the upper levels of the inheritance hierachy as "targetEntity", only those that have no subclasses. Otherwise Doctrine *CANNOT* create proxy instances of this entity and will *ALWAYS* load the entity eagerly.
-
-### SQL Schema considerations
-
-For each entity in the Class-Table Inheritance hierarchy all the mapped fields have to be columns on the
-table of this entity. Additionally each child table has to have an id column that matches the id column
-definition on the root table (except for any sequence or auto-increment details). Furthermore each child table has
-to have a foreign key pointing from the id column to the root table id column and cascading on delete.
diff --git a/manual/en/introduction.txt b/manual/en/introduction.txt
deleted file mode 100644
index 4515ead00..000000000
--- a/manual/en/introduction.txt
+++ /dev/null
@@ -1,309 +0,0 @@
-## Welcome
-
-Doctrine 2 is an object-relational mapper (ORM) for PHP 5.3.0+ that provides
-transparent persistence for PHP objects. It sits on top of a powerful database
-abstraction layer (DBAL). Object-Relational Mappers primary task is the transparent
-translation between (PHP) objects and relational database rows.
-
-One of Doctrines key features is the option to write database queries in a
-proprietary object oriented SQL dialect called Doctrine
-Query Language (DQL), inspired by Hibernates HQL. Besides DQLs slight
-differences to SQL it abstracts the mapping between database rows and
-objects considerably, allowing developers to write powerful queries
-in a simple and flexible fashion.
-
-## Disclaimer
-
-This is the Doctrine 2 reference documentation. Introductory guides and tutorials
-that you can follow along from start to finish, like the "Guide to Doctrine" book
-known from the Doctrine 1.x series, will be available at a later date.
-
-## Using an Object-Relational Mapper
-
-As the term ORM already hints at, Doctrine 2 aims to simplify the translation
-between database rows and the PHP object model. The primary use case for Doctrine
-are therefore applications that utilize the Object-Oriented Programming Paradigm.
-For applications that not primarily work with objects Doctrine 2 is not suited very well.
-
-## Requirements
-
-Doctrine 2 requires a minimum of PHP 5.3.0. For greatly improved performance it
-is also recommended that you use APC with PHP.
-
-## Doctrine 2 Packages
-
-Doctrine 2 is divided into three main packages.
-
-* Common
-* DBAL (includes Common)
-* ORM (includes DBAL+Common)
-
-This manual mainly covers the ORM package, sometimes touching parts of the
-underlying DBAL and Common packages. The Doctrine code base is split in to these
-packages for a few reasons and they are to...
-
-* ...make things more maintainable and decoupled
-* ...allow you to use the code in Doctrine Common without the ORM or DBAL
-* ...allow you to use the DBAL without the ORM
-
-### The Common Package
-
-The Common package contains highly reusable components that have no dependencies
-beyond the package itself (and PHP, of course). The root namespace of the
-Common package is `Doctrine\Common`.
-
-### The DBAL Package
-
-The DBAL package contains an enhanced database abstraction layer on top of
-PDO but is not strongly bound to PDO. The purpose of this layer is to provide a
-single API that bridges most of the differences between the different RDBMS vendors.
-The root namespace of the DBAL package is `Doctrine\DBAL`.
-
-### The ORM Package
-
-The ORM package contains the object-relational mapping toolkit that provides
-transparent relational persistence for plain PHP objects. The root namespace of
-the ORM package is `Doctrine\ORM`.
-
-## Installing
-
-Doctrine can be installed many different ways. We will describe all the different
-ways and you can choose which one suits you best.
-
-### PEAR
-
-You can easily install any of the three Doctrine packages from the PEAR command
-line installation utility.
-
-To install just the `Common` package you can run the following command:
-
- $ sudo pear install pear.doctrine-project.org/DoctrineCommon-
-
-If you want to use the Doctrine Database Abstraction Layer you can install it
-with the following command.
-
- $ sudo pear install pear.doctrine-project.org/DoctrineDBAL-
-
-Or, if you want to get the works and go for the ORM you can install it with the
-following command.
-
- $ sudo pear install pear.doctrine-project.org/DoctrineORM-
-
-> **NOTE**
-> The `` tag above represents the version you want to install. For example the
-> current version at the time of writing this is `2.0.0BETA3` for the ORM, so you could
-> install it like the following:
->
-> $ sudo pear install pear.doctrine-project.org/DoctrineORM-2.0.0BETA3
-
-When you have a package installed via PEAR you can require and load the
-`ClassLoader` with the following code.
-
- **NOTE**
->
-> You should not combine the Doctrine-Common, Doctrine-DBAL and Doctrine-ORM master commits
-> with each other in combination. The ORM may not work with the current Common or DBAL master versions.
-> Instead the ORM ships with the Git Submodules that are required.
-
-### Subversion
-
-> **NOTE**
->
-> Using the SVN Mirror is not recommended. It only allows access to the latest master commit
-> and does not automatically fetch the submodules.
-
-If you prefer subversion you can also checkout the code from GitHub.com through
-the subversion protocol:
-
- $ svn co http://svn.github.com/doctrine/doctrine2.git doctrine2
-
-However this only allows you to check out the current master of Doctrine 2, without
-the Common and DBAL dependencies. You have to grab them yourself, but might run
-into version incompatibilities between the different master branches of Common, DBAL
-and ORM.
-
-## Sandbox Quickstart
-
-> **NOTE**
-> The sandbox is only available via the Doctrine2 Github Repository or soon as a separate download on the downloads
-> page. You will find it in the $root/tools/sandbox folder.
-
-The sandbox is a pre-configured environment for evaluating and playing
-with Doctrine 2.
-
-### Overview
-
-After navigating to the sandbox directory, you should see the following structure:
-
- sandbox/
- Entities/
- Address.php
- User.php
- xml/
- Entities.Address.dcm.xml
- Entities.User.dcm.xml
- yaml/
- Entities.Address.dcm.yml
- Entities.User.dcm.yml
- cli-config.php
- doctrine
- doctrine.php
- index.php
-
-Here is a short overview of the purpose of these folders and files:
-
- * The `Entities` folder is where any model classes are created. Two example entities are already there.
- * The `xml` folder is where any XML mapping files are created (if you want to use XML mapping). Two example mapping documents for the 2 example entities are already there.
- * The `yaml` folder is where any YAML mapping files are created (if you want to use YAML mapping). Two example mapping documents for the 2 example entities are already there.
- * The `cli-config.php` contains bootstrap code for a configuration that is used by the Console tool `doctrine` whenever you execute a task.
- * `doctrine`/`doctrine.php` is a command-line tool.
- * `index.php` is a basic classical bootstrap file of a php application that uses Doctrine 2.
-
-### Mini-tutorial
-
-1) From within the tools/sandbox folder, run the following command and you should
-see the same output.
-
- $ php doctrine orm:schema-tool:create
- Creating database schema...
- Database schema created successfully!
-
-2) Take another look into the tools/sandbox folder. A SQLite database should
-have been created with the name `database.sqlite`.
-
-3) Open `index.php` and at the bottom edit it so it looks like the following:
-
- setName('Garfield');
- $em->persist($user);
- $em->flush();
-
- echo "User saved!";
-
-Open index.php in your browser or execute it on the command line. You should see
-the output "User saved!".
-
-4) Inspect the SQLite database. Again from within the tools/sandbox folder,
-execute the following command:
-
- $ php doctrine dbal:run-sql "select * from users"
-
-You should get the following output:
-
- array(1) {
- [0]=>
- array(2) {
- ["id"]=>
- string(1) "1"
- ["name"]=>
- string(8) "Garfield"
- }
- }
-
-You just saved your first entity with a generated ID in an SQLite database.
-
-5) Replace the contents of index.php with the following:
-
- createQuery('select u from Entities\User u where u.name = ?1');
- $q->setParameter(1, 'Garfield');
- $garfield = $q->getSingleResult();
-
- echo "Hello " . $garfield->getName() . "!";
-
-You just created your first DQL query to retrieve the user with the name
-'Garfield' from an SQLite database (Yes, there is an easier way to do it,
-but we wanted to introduce you to DQL at this point. Can you **find** the easier way?).
-
-> **TIP**
-> When you create new model classes or alter existing ones you can recreate the database
-> schema with the command `doctrine orm:schema-tool --drop` followed by
-> `doctrine orm:schema-tool --create`.
-
-6) Explore Doctrine 2!
-
-See the following links if you want to start with more complex tutorials rather than reading the manual:
-
-* Doctrine2 Cookbook: [Getting Started XML Edition](http://www.doctrine-project.org/projects/orm/2.0/docs/cookbook/getting-started-xml-edition/en)
diff --git a/manual/en/limitations-and-known-issues.rst b/manual/en/limitations-and-known-issues.rst
index 78072272c..8631c2d7d 100644
--- a/manual/en/limitations-and-known-issues.rst
+++ b/manual/en/limitations-and-known-issues.rst
@@ -1,3 +1,6 @@
+Limitations and Known Issues
+============================
+
We try to make using Doctrine2 a very pleasant experience.
Therefore we think it is very important to be honest about the
current limitations to our users. Much like every other piece of
@@ -21,9 +24,8 @@ There are many use-cases where you would want to use an
Entity-Attribute-Value approach to modelling and define a
table-schema like the following:
-::
+.. code-block:: sql
- [sql]
CREATE TABLE product (
id INTEGER,
name VARCHAR,
@@ -41,9 +43,8 @@ This is currently *NOT* possible with Doctrine2. You have to define
a surrogate key on the ``product_attributes`` table and use a
unique-constraint for the ``product_id`` and ``attribute_name``.
-::
+.. code-block:: sql
- [sql]
CREATE TABLE product_attributes (
attribute_id, INTEGER,
product_id INTEGER,
@@ -109,9 +110,8 @@ Identifier" you might be interested in mapping the same table
structure as given above to an array. However this is not yet
possible either. See the following example:
-::
+.. code-block:: sql
- [sql]
CREATE TABLE product (
id INTEGER,
name VARCHAR,
diff --git a/manual/en/limitations-and-known-issues.txt b/manual/en/limitations-and-known-issues.txt
deleted file mode 100644
index d65a8516d..000000000
--- a/manual/en/limitations-and-known-issues.txt
+++ /dev/null
@@ -1,203 +0,0 @@
-We try to make using Doctrine2 a very pleasant experience. Therefore we think it is very important
-to be honest about the current limitations to our users.
-Much like every other piece of software Doctrine2 is not perfect and far from feature complete.
-This section should give you an overview of current limitations of Doctrine 2 as well as critical known issues that
-you should know about.
-
-## Current Limitations
-
-There is a set of limitations that exist currently which might be solved in the future. Any of this
-limitations now stated has at least one ticket in the Tracker and is discussed for future releases.
-
-### Foreign Keys as Identifiers
-
-There are many use-cases where you would want to use an Entity-Attribute-Value approach to modelling and
-define a table-schema like the following:
-
- [sql]
- CREATE TABLE product (
- id INTEGER,
- name VARCHAR,
- PRIMARY KEY(id)
- );
-
- CREATE TABLE product_attributes (
- product_id INTEGER,
- attribute_name VARCHAR,
- attribute_value VARCHAR,
- PRIMARY KEY (product_id, attribute_name)
- );
-
-This is currently *NOT* possible with Doctrine2. You have to define a surrogate key on the `product_attributes`
-table and use a unique-constraint for the `product_id` and `attribute_name`.
-
- [sql]
- CREATE TABLE product_attributes (
- attribute_id, INTEGER,
- product_id INTEGER,
- attribute_name VARCHAR,
- attribute_value VARCHAR,
- PRIMARY KEY (attribute_id),
- UNIQUE (product_id, attribute_name)
- );
-
-Although we state that we support composite primary keys that does not currently include foreign keys as primary key
-columns. To see the fundamental difference between the two different `product_attributes` tables you should see
-how they translate into a Doctrine Mapping (Using Annotations):
-
- **TIP**
-> The populated `ClassMetadata` instances are also cached so in a production
-> environment the parsing and populating only ever happens once. You can configure
-> the metadata cache implementation using the `setMetadataCacheImpl()` method on
-> the `Doctrine\ORM\Configuration` class:
->
-> $em->getConfiguration()->setMetadataCacheImpl(new ApcCache());
-
-If you want to use one of the included core metadata drivers you just need to
-configure it. All the drivers are in the `Doctrine\ORM\Mapping\Driver` namespace:
-
- getConfiguration()->setMetadataDriverImpl($driver);
-
-## Implementing Metadata Drivers
-
-In addition to the included metadata drivers you can very easily implement
-your own. All you need to do is define a class which implements the `Driver`
-interface:
-
- _loadMappingFile($file);
-
- // populate ClassMetadataInfo instance from $data
- }
-
- /**
- * {@inheritdoc}
- */
- protected function _loadMappingFile($file)
- {
- // parse contents of $file and return php data structure
- }
- }
-
-> **NOTE**
-> When using the `AbstractFileDriver` it requires that you only have one entity
-> defined per file and the file named after the class described inside where
-> namespace separators are replaced by periods. So if you have an entity named
-> `Entities\User` and you wanted to write a mapping file for your driver above
-> you would need to name the file `Entities.User.dcm.ext` for it to be recognized.
-
-Now you can use your `MyMetadataDriver` implementation by setting it with the
-`setMetadataDriverImpl()` method:
-
- getConfiguration()->setMetadataDriverImpl($driver);
-
-## ClassMetadata
-
-The last piece you need to know and understand about metadata in Doctrine 2 is
-the API of the `ClassMetadata` classes. You need to be familiar with them in order
-to implement your own drivers but more importantly to retrieve mapping information
-for a certain entity when needed.
-
-You have all the methods you need to manually specify the mapping information
-instead of using some mapping file to populate it from. The base `ClassMetadataInfo`
-class is responsible for only data storage and is not meant for runtime use. It
-does not require that the class actually exists yet so it is useful for describing some
-entity before it exists and using that information to generate for example the
-entities themselves. The class `ClassMetadata` extends `ClassMetadataInfo` and
-adds some functionality required for runtime usage and requires that the PHP
-class is present and can be autoloaded.
-
-You can read more about the API of the `ClassMetadata` classes in the PHP Mapping
-chapter.
-
-## Getting ClassMetadata Instances
-
-If you want to get the `ClassMetadata` instance for an entity in your project
-to programatically use some mapping information to generate some HTML or something
-similar you can retrieve it through the `ClassMetadataFactory`:
-
- getMetadataFactory();
- $class = $cmf->getMetadataFor('MyEntityName');
-
-Now you can learn about the entity and use the data stored in the `ClassMetadata`
-instance to get all mapped fields for example and iterate over them:
-
- fieldMappings as $fieldMapping) {
- echo $fieldMapping['fieldName'] . "\n";
- }
\ No newline at end of file
diff --git a/manual/en/native-sql.rst b/manual/en/native-sql.rst
index 059168713..992eefc06 100644
--- a/manual/en/native-sql.rst
+++ b/manual/en/native-sql.rst
@@ -1,3 +1,6 @@
+Native SQL
+==========
+
A ``NativeQuery`` lets you execute native SQL, mapping the results
according to your specifications. Such a specification that
describes how an SQL result set is mapped to a Doctrine result is
@@ -44,7 +47,9 @@ components:
root entities or joined entities must be present in the SQL query
and mapped accordingly using ``ResultSetMapping#addMetaResult``.
- **TIP** It might not surprise you that Doctrine uses
+.. note::
+
+ It might not surprise you that Doctrine uses
``ResultSetMapping``s internally when you create DQL queries. As
the query gets parsed and transformed to SQL, Doctrine fills a
``ResultSetMapping`` that describes how the results should be
diff --git a/manual/en/native-sql.txt b/manual/en/native-sql.txt
deleted file mode 100644
index 867bc523c..000000000
--- a/manual/en/native-sql.txt
+++ /dev/null
@@ -1,242 +0,0 @@
-A `NativeQuery` lets you execute native SQL, mapping the results according to your specifications.
-Such a specification that describes how an SQL result set is mapped to a Doctrine result is
-represented by a `ResultSetMapping`. It describes how each column of the database result should
-be mapped by Doctrine in terms of the object graph. This allows you to map arbitrary SQL code to objects, such as
-highly vendor-optimized SQL or stored-procedures.
-
-## The NativeQuery class
-
-To create a `NativeQuery` you use the method `EntityManager#createNativeQuery($sql, $resultSetMapping)`. As you can see in the signature of this method, it expects 2 ingredients: The SQL you want to execute and the `ResultSetMapping` that describes how the results will be mapped.
-
-Once you obtained an instance of a `NativeQuery`, you can bind parameters to it and finally execute it.
-
-## The ResultSetMapping
-
-Understanding the `ResultSetMapping` is the key to using a `NativeQuery`.
-A Doctrine result can contain the following components:
-
- * Entity results. These represent root result elements.
- * Joined entity results. These represent joined entities in associations of root entity results.
- * Field results. These represent a column in the result set that maps to a field of an entity. A field result always belongs to an entity result or joined entity result.
- * Scalar results. These represent scalar values in the result set that will appear in each result row. Adding scalar results to a ResultSetMapping can also cause the overall result to become **mixed** (see DQL - Doctrine Query Language) if the same ResultSetMapping also contains entity results.
- * Meta results. These represent columns that contain meta-information, such as foreign keys and discriminator columns.
- When querying for objects (`getResult()`), all meta columns of root entities or joined entities must be present in the SQL query
- and mapped accordingly using `ResultSetMapping#addMetaResult`.
-
-> **TIP**
-> It might not surprise you that Doctrine uses `ResultSetMapping`s internally when you
-> create DQL queries. As the query gets parsed and transformed to SQL, Doctrine fills
-> a `ResultSetMapping` that describes how the results should be processed by the hydration
-> routines.
-
-We will now look at each of the result types that can appear in a ResultSetMapping in detail.
-
-### Entity results
-
-An entity result describes an entity type that appears as a root element in the transformed result. You add an entity result through `ResultSetMapping#addEntityResult()`.
-Let's take a look at the method signature in detail:
-
- addEntityResult('User', 'u');
- $rsm->addFieldResult('u', 'id', 'id');
- $rsm->addFieldResult('u', 'name', 'name');
-
- $query = $this->_em->createNativeQuery('SELECT id, name FROM users WHERE name = ?', $rsm);
- $query->setParameter(1, 'romanb');
-
- $users = $query->getResult();
-
-The result would look like this:
-
- array(
- [0] => User (Object)
- )
-
-Note that this would be a partial object if the entity has more fields than just id and name. In the example above the column and field names are identical but that is not necessary, of course. Also note that the query string passed to createNativeQuery is **real native SQL**. Doctrine does not touch this SQL in any way.
-
-In the previous basic example, a User had no relations and the table the class is mapped to owns no foreign keys.
-The next example assumes User has a unidirectional or bidirectional one-to-one association to a CmsAddress,
-where the User is the owning side and thus owns the foreign key.
-
- addEntityResult('User', 'u');
- $rsm->addFieldResult('u', 'id', 'id');
- $rsm->addFieldResult('u', 'name', 'name');
- $rsm->addMetaResult('u', 'address_id', 'address_id');
-
- $query = $this->_em->createNativeQuery('SELECT id, name, address_id FROM users WHERE name = ?', $rsm);
- $query->setParameter(1, 'romanb');
-
- $users = $query->getResult();
-
-Foreign keys are used by Doctrine for lazy-loading purposes when querying for objects.
-In the previous example, each user object in the result will have a proxy (a "ghost") in place
-of the address that contains the address_id. When the ghost proxy is accessed, it loads itself
-based on this key.
-
-Consequently, associations that are *fetch-joined* do not require the foreign keys to be present
-in the SQL result set, only associations that are lazy.
-
- addEntityResult('User', 'u');
- $rsm->addFieldResult('u', 'id', 'id');
- $rsm->addFieldResult('u', 'name', 'name');
- $rsm->addJoinedEntityResult('Address' , 'a', 'u', 'address');
- $rsm->addFieldResult('a', 'address_id', 'id');
- $rsm->addFieldResult('a', 'street', 'street');
- $rsm->addFieldResult('a', 'city', 'city');
-
- $sql = 'SELECT u.id, u.name, a.id AS address_id, a.street, a.city FROM users u ' .
- 'INNER JOIN address a ON u.address_id = a.id WHERE u.name = ?';
- $query = $this->_em->createNativeQuery($sql, $rsm);
- $query->setParameter(1, 'romanb');
-
- $users = $query->getResult();
-
-In this case the nested entity `Address` is registered with the `ResultSetMapping#addJoinedEntityResult`
-method, which notifies Doctrine that this entity is not hydrated at the root level, but as a joined entity
-somewhere inside the object graph. In this case we specify the alias 'u' as third parameter and `address`
-as fourth parameter, which means the `Address` is hydrated into the `User::$address` property.
-
-If a fetched entity is part of a mapped hierarchy that requires a discriminator column, this
-column must be present in the result set as a meta column so that Doctrine can create the
-appropriate concrete type. This is shown in the following example where we assume that there
-are one or more subclasses that extend User and either Class Table Inheritance or Single Table Inheritance
-is used to map the hierarchy (both use a discriminator column).
-
- addEntityResult('User', 'u');
- $rsm->addFieldResult('u', 'id', 'id');
- $rsm->addFieldResult('u', 'name', 'name');
- $rsm->addMetaResult('u', 'discr', 'discr'); // discriminator column
- $rsm->setDiscriminatorColumn('u', 'discr');
-
- $query = $this->_em->createNativeQuery('SELECT id, name, discr FROM users WHERE name = ?', $rsm);
- $query->setParameter(1, 'romanb');
-
- $users = $query->getResult();
-
-Note that in the case of Class Table Inheritance, an example as above would result in partial objects
-if any objects in the result 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.
\ No newline at end of file
diff --git a/manual/en/partial-objects.rst b/manual/en/partial-objects.rst
index e2d353af2..f6a6a17c0 100644
--- a/manual/en/partial-objects.rst
+++ b/manual/en/partial-objects.rst
@@ -1,10 +1,15 @@
+Partial Objects
+===============
+
A partial object is an object whose state is not fully initialized
after being reconstituted from the database and that is
disconnected from the rest of its data. The following section will
describe why partial objects are problematic and what the approach
of Doctrine2 to this problem is.
- **NOTE** The partial object problem in general does not apply to
+.. note::
+
+ The partial object problem in general does not apply to
methods or queries where you do not retrieve the query result as
objects. Examples are: ``Query#getArrayResult()``,
``Query#getScalarResult()``, ``Query#getSingleScalarResult()``,
diff --git a/manual/en/partial-objects.txt b/manual/en/partial-objects.txt
deleted file mode 100644
index 83e89b233..000000000
--- a/manual/en/partial-objects.txt
+++ /dev/null
@@ -1,49 +0,0 @@
-A partial object is an object whose state is not fully initialized after being
-reconstituted from the database and that is disconnected from the rest of its data.
-The following section will describe why partial objects are problematic and what the approach of Doctrine2 to this problem is.
-
-> **NOTE**
-> The partial object problem in general does not apply to methods or
-> queries where you do not retrieve the query result as objects. Examples are:
-> `Query#getArrayResult()`, `Query#getScalarResult()`, `Query#getSingleScalarResult()`,
-> etc.
-
-## What is the problem?
-
-In short, partial objects are problematic because they are usually objects with
-broken invariants. As such, code that uses these partial objects tends to be
-very fragile and either needs to "know" which fields or methods can be safely
-accessed or add checks around every field access or method invocation. The same
-holds true for the internals, i.e. the method implementations, of such objects.
-You usually simply assume the state you need in the method is available, after
-all you properly constructed this object before you pushed it into the database,
-right? These blind assumptions can quickly lead to null reference errors when
-working with such partial objects.
-
-It gets worse with the scenario of an optional association (0..1 to 1). When
-the associated field is NULL, you don't know whether this object does not have
-an associated object or whether it was simply not loaded when the owning object
-was loaded from the database.
-
-These are reasons why many ORMs do not allow partial objects at all and instead
-you always have to load an object with all its fields (associations being proxied).
-One secure way to allow partial objects is if the programming language/platform
-allows the ORM tool to hook deeply into the object and instrument it in such a
-way that individual fields (not only associations) can be loaded lazily on first
-access. This is possible in Java, for example, through bytecode instrumentation.
-In PHP though this is not possible, so there is no way to have "secure" partial
-objects in an ORM with transparent persistence.
-
-Doctrine, by default, does not allow partial objects. That means, any query that
-only selects partial object data and wants to retrieve the result as objects
-(i.e. `Query#getResult()`) will raise an exception telling you that
-partial objects are dangerous. If you want to force a query to return you partial
-objects, possibly as a performance tweak, you can use the `partial` keyword as follows:
-
- createQuery("select partial u.{id,name} from MyApp\Domain\User u");
-
-## When should I force partial objects?
-
-Mainly for optimization purposes, but be careful of premature optimization as partial objects
-lead to potentially more fragile code.
\ No newline at end of file
diff --git a/manual/en/php-mapping.rst b/manual/en/php-mapping.rst
index 4a0326524..21fb33fec 100644
--- a/manual/en/php-mapping.rst
+++ b/manual/en/php-mapping.rst
@@ -1,3 +1,6 @@
+PHP Mapping
+===========
+
Doctrine 2 also allows you to provide the ORM metadata in the form
of plain PHP code using the ``ClassMetadata`` API. You can write
the code in PHP files or inside of a static function named
diff --git a/manual/en/php-mapping.txt b/manual/en/php-mapping.txt
deleted file mode 100644
index 05ea41ca3..000000000
--- a/manual/en/php-mapping.txt
+++ /dev/null
@@ -1,199 +0,0 @@
-Doctrine 2 also allows you to provide the ORM metadata in the form of plain
-PHP code using the `ClassMetadata` API. You can write the code in PHP files or
-inside of a static function named `loadMetadata($class)` on the entity class itself.
-
-## PHP Files
-
-If you wish to write your mapping information inside PHP files that are named
-after the entity and included to populate the metadata for an entity you can do
-so by using the `PHPDriver`:
-
- getConfiguration()->setMetadataDriverImpl($driver);
-
-Now imagine we had an entity named `Entities\User` and we wanted to write a mapping
-file for it using the above configured `PHPDriver` instance:
-
- mapField(array(
- 'id' => true,
- 'fieldName' => 'id',
- 'type' => 'integer'
- ));
-
- $metadata->mapField(array(
- 'fieldName' => 'username',
- 'type' => 'string'
- ));
-
-Now we can easily retrieve the populated `ClassMetadata` instance where the `PHPDriver`
-includes the file and the `ClassMetadataFactory` caches it for later retrieval:
-
- getMetadataFor('Entities\User');
-
-## 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`:
-
- getConfiguration()->setMetadataDriverImpl($driver);
-
-Now you just need to define a static function named `loadMetadata($metadata)` on your entity:
-
- mapField(array(
- 'id' => true,
- 'fieldName' => 'id',
- 'type' => 'integer'
- ));
-
- $metadata->mapField(array(
- 'fieldName' => 'username',
- 'type' => 'string'
- ));
- }
- }
-
-## ClassMetadataInfo API
-
-The `ClassMetadataInfo` class is the base data object for storing the mapping
-metadata for a single entity. It contains all the getters and setters you need
-populate and retrieve information for an entity.
-
-### General Setters
-
- * `setTableName($tableName)`
- * `setPrimaryTable(array $primaryTableDefinition)`
- * `setCustomRepositoryClass($repositoryClassName)`
- * `setIdGeneratorType($generatorType)`
- * `setIdGenerator($generator)`
- * `setSequenceGeneratorDefinition(array $definition)`
- * `setChangeTrackingPolicy($policy)`
- * `setIdentifier(array $identifier)`
-
-### Inheritance Setters
-
- * `setInheritanceType($type)`
- * `setSubclasses(array $subclasses)`
- * `setParentClasses(array $classNames)`
- * `setDiscriminatorColumn($columnDef)`
- * `setDiscriminatorMap(array $map)`
-
-### Field Mapping Setters
-
- * `mapField(array $mapping)`
- * `mapOneToOne(array $mapping)`
- * `mapOneToMany(array $mapping)`
- * `mapManyToOne(array $mapping)`
- * `mapManyToMany(array $mapping)`
-
-### Lifecycle Callback Setters
-
- * `addLifecycleCallback($callback, $event)`
- * `setLifecycleCallbacks(array $callbacks)`
-
-### Versioning Setters
-
- * `setVersionMapping(array &$mapping)`
- * `setVersioned($bool)`
- * `setVersionField()`
-
-### General Getters
-
- * `getTableName()`
- * `getTemporaryIdTableName()`
-
-### Identifier Getters
-
- * `getIdentifierColumnNames()`
- * `usesIdGenerator()`
- * `isIdentifier($fieldName)`
- * `isIdGeneratorIdentity()`
- * `isIdGeneratorSequence()`
- * `isIdGeneratorTable()`
- * `isIdentifierNatural()`
- * `getIdentifierFieldNames()`
- * `getSingleIdentifierFieldName()`
- * `getSingleIdentifierColumnName()`
-
-### Inheritance Getters
-
- * `isInheritanceTypeNone()`
- * `isInheritanceTypeJoined()`
- * `isInheritanceTypeSingleTable()`
- * `isInheritanceTypeTablePerClass()`
- * `isInheritedField($fieldName)`
- * `isInheritedAssociation($fieldName)`
-
-### Change Tracking Getters
-
- * `isChangeTrackingDeferredExplicit()`
- * `isChangeTrackingDeferredImplicit()`
- * `isChangeTrackingNotify()`
-
-### Field & Association Getters
-
- * `isUniqueField($fieldName)`
- * `isNullable($fieldName)`
- * `getColumnName($fieldName)`
- * `getFieldMapping($fieldName)`
- * `getAssociationMapping($fieldName)`
- * `getAssociationMappings()`
- * `getFieldName($columnName)`
- * `hasField($fieldName)`
- * `getColumnNames(array $fieldNames = null)`
- * `getTypeOfField($fieldName)`
- * `getTypeOfColumn($columnName)`
- * `hasAssociation($fieldName)`
- * `isSingleValuedAssociation($fieldName)`
- * `isCollectionValuedAssociation($fieldName)`
-
-### Lifecycle Callback Getters
-
- * `hasLifecycleCallbacks($lifecycleEvent)`
- * `getLifecycleCallbacks($event)`
-
-## ClassMetadata API
-
-The `ClassMetadata` class extends `ClassMetadataInfo` and adds the runtime functionality
-required by Doctrine. It adds a few extra methods related to runtime reflection
-for working with the entities themselves.
-
- * `getReflectionClass()`
- * `getReflectionProperties()`
- * `getReflectionProperty($name)`
- * `getSingleIdReflectionProperty()`
- * `getIdentifierValues($entity)`
- * `setIdentifierValues($entity, $id)`
- * `setFieldValue($entity, $field, $value)`
- * `getFieldValue($entity, $field)`
\ No newline at end of file
diff --git a/manual/en/query-builder.rst b/manual/en/query-builder.rst
index 5b883ae39..240cf6113 100644
--- a/manual/en/query-builder.rst
+++ b/manual/en/query-builder.rst
@@ -1,5 +1,5 @@
The QueryBuilder
-----------------
+================
A ``QueryBuilder`` provides an API that is designed for
conditionally constructing a DQL query in several steps.
diff --git a/manual/en/query-builder.txt b/manual/en/query-builder.txt
deleted file mode 100644
index 5f15bed7a..000000000
--- a/manual/en/query-builder.txt
+++ /dev/null
@@ -1,408 +0,0 @@
-
-## The QueryBuilder
-
-A `QueryBuilder` provides an API that is designed for conditionally constructing a DQL query in several steps.
-
-It provides a set of classes and methods that is able to programmatically build queries, and also provides a fluent API.
-This means that you can change between one methodology to the other as you want, and also pick one if you prefer.
-
-### Constructing a new QueryBuilder object
-
-The same way you build a normal Query, you build a `QueryBuilder` object, just providing the correct method name.
-Here is an example how to build a `QueryBuilder` object:
-
- createQueryBuilder();
-
-Once you have created an instance of QueryBuilder, it provides a set of useful informative functions that you can use.
-One good example is to inspect what type of object the `QueryBuilder` is.
-
- getType(); // Prints: 0
-
-There're currently 3 possible return values for `getType()`:
-
-* `QueryBuilder::SELECT`, which returns value 0
-* `QueryBuilder::DELETE`, returning value 1
-* `QueryBuilder::UPDATE`, which returns value 2
-
-It is possible to retrieve the associated `EntityManager` of the current `QueryBuilder`, its DQL and also a `Query` object when you finish building your DQL.
-
- getEntityManager();
-
- // example4: retrieve the DQL string of what was defined in QueryBuilder
- $dql = $qb->getDql();
-
- // example5: retrieve the associated Query object with the processed DQL
- $q = $qb->getQuery();
-
-Internally, `QueryBuilder` works with a DQL cache to increase performance. Any changes that may affect the generated DQL actually modifies the state of `QueryBuilder` to a stage we call STATE_DIRTY.
-One `QueryBuilder` can be in two different states:
-
-* `QueryBuilder::STATE_CLEAN`, which means DQL haven't been altered since last retrieval or nothing were added since its instantiation
-* `QueryBuilder::STATE_DIRTY`, means DQL query must (and will) be processed on next retrieval
-
-### Working with QueryBuilder
-
-All helper methods in `QueryBuilder` actually rely on a single one: `add()`.
-This method is responsible of building every piece of DQL. It takes 3 parameters: `$dqlPartName`, `$dqlPart` and `$append` (default=false)
-
-* `$dqlPartName`: Where the `$dqlPart` should be placed. Possible values: select, from, where, groupBy, having, orderBy
-* `$dqlPart`: What should be placed in `$dqlPartName`. Accepts a string or any instance of `Doctrine\ORM\Query\Expr\*`
-* `$append`: Optional flag (default=false) if the `$dqlPart` should override all previously defined items in `$dqlPartName` or not
-
--
-
- add('select', 'u')
- ->add('from', 'User u')
- ->add('where', 'u.id = ?1')
- ->add('orderBy', 'u.name ASC');
-
-#### Binding parameters to your query
-
-Doctrine supports dynamic binding of parameters to your query, similar to preparing queries. You can use both strings and numbers as placeholders, although both have a slightly different syntax. Additionally, you must make your choice: Mixing both styles is not allowed. Binding parameters can simply be achieved as follows:
-
- add('select', 'u')
- ->add('from', 'User u')
- ->add('where', 'u.id = ?1')
- ->add('orderBy', 'u.name ASC');
- ->setParameter(1, 100); // Sets ?1 to 100, and thus we will fetch a user with u.id = 100
-
-You are not forced to enumerate your placeholders as the alternative syntax is available:
-
-
- add('select', 'u')
- ->add('from', 'User u')
- ->add('where', 'u.id = :identifier')
- ->add('orderBy', 'u.name ASC');
- ->setParameter('identifier', 100); // Sets :identifier to 100, and thus we will fetch a user with u.id = 100
-
-Note that numeric placeholders start with a ? followed by a number while the named placeholders start with a : followed by a string.
-
-If you've got several parameters to bind to your query, you can also use setParameters() instead of setParameter() with the following syntax:
-
- setParameters(array(1 => 'value for ?1', 2 => 'value for ?2'));
-
-
-Getting already bound parameters is easy - simply use the above mentioned syntax with "getParameter()" or "getParameters()":
-
- getParameters(array(1, 2));
- // Equivalent to
- $param = array($qb->getParameter(1), $qb->getParameter(2));
-
-Note: If you try to get a parameter that was not bound yet, getParameter() simply returns NULL.
-
-#### Expr\* classes
-
-When you call `add()` with string, it internally evaluates to an instance of `Doctrine\ORM\Query\Expr\Expr\*` class.
-Here is the same query of example 6 written using `Doctrine\ORM\Query\Expr\Expr\*` classes:
-
- add('select', new Expr\Select(array('u')))
- ->add('from', new Expr\From('User', 'u'))
- ->add('where', new Expr\Comparison('u.id', '=', '?1'))
- ->add('orderBy', new Expr\OrderBy('u.name', 'ASC'));
-
-Of course this is the hardest way to build a DQL query in Doctrine. To simplify some of these efforts, we introduce what we call as `Expr` helper class.
-
-#### The Expr class
-
-To workaround most of the issues that `add()` method may cause, Doctrine created a class that can be considered as a helper for building queries.
-This class is called `Expr`, which provides a set of useful static methods to help building queries:
-
- add('select', $qb->expr()->select('u'))
- ->add('from', $qb->expr()->from('User', 'u'))
- ->add('where', $qb->expr()->orx(
- $qb->expr()->eq('u.id', '?1'),
- $qb->expr()->like('u.nickname', '?2')
- ))
- ->add('orderBy', $qb->expr()->orderBy('u.surname', 'ASC'));
-
-Although it still sounds complex, the ability to programmatically create conditions are the main feature of `Expr`.
-Here it is a complete list of supported helper methods available:
-
- expr()->select('u')
- public function select($select = null); // Returns Expr\Select instance
-
- // Example - $qb->expr()->from('User', 'u')
- public function from($from, $alias); // Returns Expr\From instance
-
- // Example - $qb->expr()->leftJoin('u.Phonenumbers', 'p', Expr\Join::ON, 'p.user_id = u.id AND p.country_code = 55');
- // Example - $qb->expr()->leftJoin('u. Phonenumbers', 'p', 'ON', $qb->expr()->andx($qb->expr()->eq('p.user_id', 'u.id'), $qb->expr()->eq('p.country_code', '55'));
- public function leftJoin($join, $alias, $conditionType = null, $condition = null); // Returns Expr\Join instance
-
- // Example - $qb->expr()->innerJoin('u.Group', 'g', Expr\Join::WITH, 'g.manager_level = 100');
- // Example - $qb->expr()->innerJoin('u.Group', 'g', 'WITH', $qb->expr()->eq('g.manager_level', '100'));
- public function innerJoin($join, $alias, $conditionType = null, $condition = null); // Returns Expr\Join instance
-
- // Example - $qb->expr()->orderBy('u.surname', 'ASC')->add('u.firstname', 'ASC')->...
- public function orderBy($sort = null, $order = null); // Returns Expr\OrderBy instance
-
- // Example - $qb->expr()->groupBy()->add('u.id')->...
- public function groupBy($groupBy = null); // Returns Expr\GroupBy instance
-
-
- /** Conditional objects **/
-
- // Example - $qb->expr()->andx($cond1 [, $condN])->add(...)->...
- public function andx($x = null); // Returns Expr\Andx instance
-
- // Example - $qb->expr()->orx($cond1 [, $condN])->add(...)->...
- public function orx($x = null); // Returns Expr\Orx instance
-
-
- /** Comparison objects **/
-
- // Example - $qb->expr()->eq('u.id', '?1') => u.id = ?1
- public function eq($x, $y); // Returns Expr\Comparison instance
-
- // Example - $qb->expr()->neq('u.id', '?1') => u.id <> ?1
- public function neq($x, $y); // Returns Expr\Comparison instance
-
- // Example - $qb->expr()->lt('u.id', '?1') => u.id < ?1
- public function lt($x, $y); // Returns Expr\Comparison instance
-
- // Example - $qb->expr()->lte('u.id', '?1') => u.id <= ?1
- public function lte($x, $y); // Returns Expr\Comparison instance
-
- // Example - $qb->expr()->gt('u.id', '?1') => u.id > ?1
- public function gt($x, $y); // Returns Expr\Comparison instance
-
- // Example - $qb->expr()->gte('u.id', '?1') => u.id >= ?1
- public function gte($x, $y); // Returns Expr\Comparison instance
-
-
- /** Arithmetic objects **/
-
- // Example - $qb->expr()->prod('u.id', '2') => u.id * 2
- public function prod($x, $y); // Returns Expr\Math instance
-
- // Example - $qb->expr()->diff('u.id', '2') => u.id - 2
- public function diff($x, $y); // Returns Expr\Math instance
-
- // Example - $qb->expr()->sum('u.id', '2') => u.id + 2
- public function sum($x, $y); // Returns Expr\Math instance
-
- // Example - $qb->expr()->quot('u.id', '2') => u.id / 2
- public function quot($x, $y); // Returns Expr\Math instance
-
-
- /** Pseudo-function objects **/
-
- // Example - $qb->expr()->exists($qb2->getDql())
- public function exists($subquery); // Returns Expr\Func instance
-
- // Example - $qb->expr()->all($qb2->getDql())
- public function all($subquery); // Returns Expr\Func instance
-
- // Example - $qb->expr()->some($qb2->getDql())
- public function some($subquery); // Returns Expr\Func instance
-
- // Example - $qb->expr()->any($qb2->getDql())
- public function any($subquery); // Returns Expr\Func instance
-
- // Example - $qb->expr()->not($qb->expr()->eq('u.id', '?1'))
- public function not($restriction); // Returns Expr\Func instance
-
- // Example - $qb->expr()->in('u.id', array(1, 2, 3))
- // Make sure that you do NOT use something similar to $qb->expr()->in('value', array('stringvalue')) as this will cause Doctrine to throw an Exception.
- // Instead, use $qb->expr()->in('value', array('?1')) and bind your parameter to ?1 (see section above)
- public function in($x, $y); // Returns Expr\Func instance
-
- // Example - $qb->expr()->notIn('u.id', '2')
- public function notIn($x, $y); // Returns Expr\Func instance
-
- // Example - $qb->expr()->like('u.firstname', $qb->expr()->literal('Gui%'))
- public function like($x, $y); // Returns Expr\Comparison instance
-
- // Example - $qb->expr()->between('u.id', '1', '10')
- public function between($val, $x, $y); // Returns Expr\Func
-
-
- /** Function objects **/
-
- // Example - $qb->expr()->trim('u.firstname')
- public function trim($x); // Returns Expr\Func
-
- // Example - $qb->expr()->concat('u.firstname', $qb->expr()->concat(' ', 'u.lastname'))
- public function concat($x, $y); // Returns Expr\Func
-
- // Example - $qb->expr()->substr('u.firstname', 0, 1)
- public function substr($x, $from, $len); // Returns Expr\Func
-
- // Example - $qb->expr()->lower('u.firstname')
- public function lower($x); // Returns Expr\Func
-
- // Example - $qb->expr()->upper('u.firstname')
- public function upper($x); // Returns Expr\Func
-
- // Example - $qb->expr()->length('u.firstname')
- public function length($x); // Returns Expr\Func
-
- // Example - $qb->expr()->avg('u.age')
- public function avg($x); // Returns Expr\Func
-
- // Example - $qb->expr()->max('u.age')
- public function max($x); // Returns Expr\Func
-
- // Example - $qb->expr()->min('u.age')
- public function min($x); // Returns Expr\Func
-
- // Example - $qb->expr()->abs('u.currentBalance')
- public function abs($x); // Returns Expr\Func
-
- // Example - $qb->expr()->sqrt('u.currentBalance')
- public function sqrt($x); // Returns Expr\Func
-
- // Example - $qb->expr()->count('u.firstname')
- public function count($x); // Returns Expr\Func
-
- // Example - $qb->expr()->countDistinct('u.surname')
- public function countDistinct($x); // Returns Expr\Func
- }
-
-#### Helper methods
-
-Until now we have described the lowest level (thought of as the hardcore method) of creating queries. It may be useful to work at this level for optimization purposes, but most of the time it is preferred to work at a higher level of abstraction.
-To simplify even more the way you build a query in Doctrine, we can take advantage of what we call Helper methods. For all base code, there is a set of useful methods to simplify a programmer's life.
-To illustrate how to work with them, here is the same example 6 re-written using `QueryBuilder` helper methods:
-
- select('u')
- ->from('User', 'u')
- ->where('u.id = ?1')
- ->orderBy('u.name ASC');
-
-`QueryBuilder` helper methods are considered the standard way to build DQL queries. Although it is supported, it should be avoided to use string based queries and greatly encouraged to use `$qb->expr()->*` methods.
-Here is a converted example 8 to suggested standard way to build queries:
-
- select(array('u')) // string 'u' is converted to array internally
- ->from('User', 'u')
- ->where($qb->expr()->orx(
- $qb->expr()->eq('u.id', '?1'),
- $qb->expr()->like('u.nickname', '?2')
- ))
- ->orderBy('u.surname', 'ASC'));
-
-Here is a complete list of helper methods available in `QueryBuilder`:
-
- select('u')
- // Example - $qb->select(array('u', 'p'))
- // Example - $qb->select($qb->expr()->select('u', 'p'))
- public function select($select = null);
-
- // Example - $qb->delete('User', 'u')
- public function delete($delete = null, $alias = null);
-
- // Example - $qb->update('Group', 'g')
- public function update($update = null, $alias = null);
-
- // Example - $qb->set('u.firstName', $qb->expr()->literal('Arnold'))
- // Example - $qb->set('u.numChilds', 'u.numChilds + ?1')
- // Example - $qb->set('u.numChilds', $qb->expr()->sum('u.numChilds', '?1'))
- public function set($key, $value);
-
- // Example - $qb->from('Phonenumber', 'p')
- public function from($from, $alias = null);
-
- // Example - $qb->innerJoin('u.Group', 'g', Expr\Join::ON, $qb->expr()->and($qb->expr()->eq('u.group_id', 'g.id'), 'g.name = ?1'))
- // Example - $qb->innerJoin('u.Group', 'g', 'ON', 'u.group_id = g.id AND g.name = ?1')
- public function innerJoin($join, $alias = null, $conditionType = null, $condition = null);
-
- // Example - $qb->leftJoin('u.Phonenumbers', 'p', Expr\Join::WITH, $qb->expr()->eq('p.area_code', 55))
- // Example - $qb->leftJoin('u.Phonenumbers', 'p', 'WITH', 'p.area_code = 55')
- public function leftJoin($join, $alias = null, $conditionType = null, $condition = null);
-
- // NOTE: ->where() overrides all previously set conditions
- //
- // Example - $qb->where('u.firstName = ?1', $qb->expr()->eq('u.surname', '?2'))
- // Example - $qb->where($qb->expr()->andx($qb->expr()->eq('u.firstName', '?1'), $qb->expr()->eq('u.surname', '?2')))
- // Example - $qb->where('u.firstName = ?1 AND u.surname = ?2')
- public function where($where);
-
- // Example - $qb->andWhere($qb->expr()->orx($qb->expr()->lte('u.age', 40), 'u.numChild = 0'))
- public function andWhere($where);
-
- // Example - $qb->orWhere($qb->expr()->between('u.id', 1, 10));
- public function orWhere($where);
-
- // NOTE: -> groupBy() overrides all previously set grouping conditions
- //
- // Example - $qb->groupBy('u.id')
- public function groupBy($groupBy);
-
- // Example - $qb->addGroupBy('g.name')
- public function addGroupBy($groupBy);
-
- // NOTE: -> having() overrides all previously set having conditions
- //
- // Example - $qb->having('u.salary >= ?1')
- // Example - $qb->having($qb->expr()->gte('u.salary', '?1'))
- public function having($having);
-
- // Example - $qb->andHaving($qb->expr()->gt($qb->expr()->count('u.numChild'), 0))
- public function andHaving($having);
-
- // Example - $qb->orHaving($qb->expr()->lte('g.managerLevel', '100'))
- public function orHaving($having);
-
- // NOTE: -> orderBy() overrides all previously set ordering conditions
- //
- // Example - $qb->orderBy('u.surname', 'DESC')
- public function orderBy($sort, $order = null);
-
- // Example - $qb->addOrderBy('u.firstName')
- public function addOrderBy($sort, $order = null); // Default $order = 'ASC'
- }
diff --git a/manual/en/tools.rst b/manual/en/tools.rst
index 79941ea1d..2274b38d1 100644
--- a/manual/en/tools.rst
+++ b/manual/en/tools.rst
@@ -1,5 +1,8 @@
-The Doctrine Console
---------------------
+Tools
+=====
+
+Doctrine Console
+----------------
The Doctrine Console is a Command Line Interface tool for
simplifying common tasks during the development of a project that
@@ -170,7 +173,7 @@ The following Commands are currently available:
Database Schema Generation
--------------------------
- **Note**
+.. note::
SchemaTool can do harm to your database. It will drop or alter
tables, indexes, sequences and such. Please use this tool with
@@ -274,7 +277,7 @@ will output the SQL for the ran operation.
Before using the orm:schema-tool commands, remember to configure
your cli-config.php properly.
- **NOTE**
+.. note::
When using the Annotation Mapping Driver you have to either setup
your autoloader in the cli-config.php correctly to find all the
@@ -364,7 +367,9 @@ You can also reverse engineer a database using the
$ php doctrine orm:convert-mapping --from-database yml /path/to/mapping-path-converted-to-yml
- **CAUTION** Reverse Engineering is not always working perfectly
+.. warning::
+
+ Reverse Engineering is not always working perfectly
depending on special cases. It will only detect Many-To-One
relations (even if they are One-To-One) and will try to create
entities from Many-To-Many tables. It also has problems with naming
diff --git a/manual/en/tools.txt b/manual/en/tools.txt
deleted file mode 100644
index 221ce89ce..000000000
--- a/manual/en/tools.txt
+++ /dev/null
@@ -1,254 +0,0 @@
-## The Doctrine Console
-
-The Doctrine Console is a Command Line Interface tool for simplifying common tasks during the development of a project that uses Doctrine 2.
-
-### Installation
-
-If you installed Doctrine 2 through PEAR, the `doctrine` command line tool should already be available to you.
-
-If you use Doctrine through SVN or a release package you need to copy the `doctrine` and `doctrine.php` files from the `tools/sandbox` or `bin` folder, respectively, to a location of your choice, for example a `tools` folder of your project.
-You probably need to edit `doctrine.php` to adjust some paths to the new environment, most importantly the first line that includes the `Doctrine\Common\ClassLoader`.
-
-### Getting Help
-
-Type `doctrine` on the command line and you should see an overview of the available commands or use the --help flag to get information on the available commands. If you want to know more about the use of generate entities for example, you can call:
-
- doctrine orm:generate-entities --help
-
-### Configuration
-
-Whenever the `doctrine` command line tool is invoked, it can access alls Commands that were registered by developer.
-There is no auto-detection mechanism at work. The `bin\doctrine.php` file already registers all the commands that
-currently ship with Doctrine DBAL and ORM. If you want to use additional commands you have to register them yourself.
-
-All the commands of the Doctrine Console require either the `db` or the `em` helpers to be defined in order to work correctly. Doctrine Console requires the definition of a HelperSet that is the DI tool to be injected in the Console.
-In case of a project that is dealing exclusively with DBAL, the ConnectionHelper is required:
-
- new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($conn)
- ));
- $cli->setHelperSet($helperSet);
-
-When dealing with the ORM package, the EntityManagerHelper is required:
-
- new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em)
- ));
- $cli->setHelperSet($helperSet);
-
-The HelperSet instance has to be generated in a separate file (i.e. `cli-config.php`) that contains typical Doctrine
-bootstrap code and predefines the needed HelperSet attributes mentioned above. A typical `cli-config.php` file looks as follows:
-
- register();
-
- $classLoader = new \Doctrine\Common\ClassLoader('Proxies', __DIR__);
- $classLoader->register();
-
- $config = new \Doctrine\ORM\Configuration();
- $config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache);
- $config->setProxyDir(__DIR__ . '/Proxies');
- $config->setProxyNamespace('Proxies');
-
- $connectionOptions = array(
- 'driver' => 'pdo_sqlite',
- 'path' => 'database.sqlite'
- );
-
- $em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config);
-
- $helperSet = new \Symfony\Components\Console\Helper\HelperSet(array(
- 'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($em->getConnection()),
- 'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em)
- ));
-
-It is important to define a correct HelperSet that doctrine.php script will ultimately use. The Doctrine Binary
-will automatically find the first instance of HelperSet in the global variable namespace and use this.
-
-You can also add your own commands on-top of the Doctrine supported tools.
-To include a new command on Doctrine Console, you need to do:
-
- addCommand(new \MyProject\Tools\Console\Commands\MyCustomCommand());
-
-Additionally, include multiple commands (and overriding previously defined ones) is possible through the command:
-
- addCommands(array(
- new \MyProject\Tools\Console\Commands\MyCustomCommand(),
- new \MyProject\Tools\Console\Commands\SomethingCommand(),
- new \MyProject\Tools\Console\Commands\AnotherCommand(),
- new \MyProject\Tools\Console\Commands\OneMoreCommand(),
- ));
-
-### Command Overview
-
-The following Commands are currently available:
-
- * `help` Displays help for a command (?)
- * `list` Lists commands
- * `dbal:import` Import SQL file(s) directly to Database.
- * `dbal:run-sql` Executes arbitrary SQL directly from the command line.
- * `orm:clear-cache:metadata` Clear all metadata cache of the various cache drivers.
- * `orm:clear-cache:query` Clear all query cache of the various cache drivers.
- * `orm:clear-cache:result` Clear result cache of the various cache drivers.
- * `orm:convert-d1-schema` Converts Doctrine 1.X schema into a Doctrine 2.X schema.
- * `orm:convert-mapping` Convert mapping information between supported formats.
- * `orm:ensure-production-settings` Verify that Doctrine is properly configured for a production environment.
- * `orm:generate-entities` Generate entity classes and method stubs from your mapping information.
- * `orm:generate-proxies` Generates proxy classes for entity classes.
- * `orm:generate-repositories` Generate repository classes from your mapping information.
- * `orm:run-dql` Executes arbitrary DQL directly from the command line.
- * `orm:schema-tool:create` Processes the schema and either create it directly on EntityManager Storage Connection or generate the SQL output.
- * `orm:schema-tool:drop` Processes the schema and either drop the database schema of EntityManager Storage Connection or generate the SQL output.
- * `orm:schema-tool:update` Processes the schema and either update the database schema of EntityManager Storage Connection or generate the SQL output.
-
-## Database Schema Generation
-
-> **Note**
->
-> SchemaTool can do harm to your database. It will drop or alter tables, indexes, sequences and such. Please use
-> this tool with caution in development and not on a production server. It is meant for helping you develop your
-> Database Schema, but NOT with migrating schema from A to B in production. A safe approach would be generating
-> the SQL on development server and saving it into SQL Migration files that are executed manually on the production
-> server.
->
-> SchemaTool assumes your Doctrine Project uses the given database on its own. Update and Drop commands will
-> mess with other tables if they are not related to the current project that is using Doctrine. Please be careful!
-
-To generate your database schema from your Doctrine mapping files you can use the
-`SchemaTool` class or the `schema-tool` Console Command.
-
-When using the SchemaTool class directly, create your schema using the `createSchema()` method. First create an instance of the `SchemaTool` and pass it an instance of the `EntityManager` that you want to use to create the schema. This method receives an array of `ClassMetadataInfo` instances.
-
- getClassMetadata('Entities\User'),
- $em->getClassMetadata('Entities\Profile')
- );
- $tool->createSchema($classes);
-
-To drop the schema you can use the `dropSchema()` method.
-
- dropSchema($classes);
-
-This drops all the tables that are currently used by your metadata model.
-When you are changing your metadata a lot during development you might want
-to drop the complete database instead of only the tables of the current model
-to clean up with orphaned tables.
-
- dropSchema($classes, \Doctrine\ORM\Tools\SchemaTool::DROP_DATABASE);
-
-You can also use database introspection to update your schema easily with the
-`updateSchema()` method. It will compare your existing database schema to the
-passed array of `ClassMetdataInfo` instances.
-
- updateSchema($classes);
-
-If you want to use this functionality from the command line you can use the
-`schema-tool` command.
-
-To create the schema use the `create` command:
-
- $ php doctrine orm:schema-tool:create
-
-To drop the schema use the `drop` command:
-
- $ php doctrine orm:schema-tool:drop
-
-If you want to drop and then recreate the schema then use both options:
-
- $ php doctrine orm:schema-tool:drop
- $ php doctrine orm:schema-tool:create
-
-As you would think, if you want to update your schema use the `update` command:
-
- $ php doctrine orm:schema-tool:update
-
-All of the above commands also accept a `--dump-sql` option that will output the SQL
-for the ran operation.
-
- $ php doctrine orm:schema-tool:create --dump-sql
-
-Before using the orm:schema-tool commands, remember to configure your cli-config.php properly.
-
-> **NOTE**
->
-> When using the Annotation Mapping Driver you have to either setup your autoloader in the cli-config.php
-> correctly to find all the entities, or you can use the second argument of the `EntityManagerHelper` to
-> specify all the paths of your entities (or mapping files), i.e.
-> `new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em, $mappingPaths);`
-
-## Convert Mapping Information
-
-To convert some mapping information between the various supported formats you can
-use the `ClassMetadataExporter` to get exporter instances for the different formats:
-
- getExporter('yml', '/path/to/export/yml');
-
-Now you can export some `ClassMetadata` instances:
-
- getClassMetadata('Entities\User'),
- $em->getClassMetadata('Entities\Profile')
- );
- $exporter->setMetadata($classes);
- $exporter->export();
-
-This functionality is also available from the command line to convert your
-loaded mapping information to another format. The `orm:convert-mapping` command
-accepts two arguments, the type to convert to and the path to generate it:
-
- $ php doctrine orm:convert-mapping xml /path/to/mapping-path-converted-to-xml
-
-## Reverse Engineering
-
-You can use the `DatabaseDriver` to reverse engineer a database to an array of
-`ClassMetadataInfo` instances and generate YAML, XML, etc. from them.
-
-First you need to retrieve the metadata instances with the `DatabaseDriver`:
-
- getConfiguration()->setMetadataDriverImpl(
- new \Doctrine\ORM\Mapping\Driver\DatabaseDriver(
- $em->getConnection()->getSchemaManager()
- )
- );
-
- $cmf = new DisconnectedClassMetadataFactory($em);
- $metadata = $cmf->getAllMetadata();
-
-Now you can get an exporter instance and export the loaded metadata to yml:
-
- getExporter('yml', '/path/to/export/yml');
- $exporter->setMetadata($metadata);
- $exporter->export();
-
-You can also reverse engineer a database using the `orm:convert-mapping` command:
-
- $ php doctrine orm:convert-mapping --from-database yml /path/to/mapping-path-converted-to-yml
-
-> **CAUTION**
-> Reverse Engineering is not always working perfectly depending on special cases.
-> It will only detect Many-To-One relations (even if they are One-To-One) and
-> will try to create entities from Many-To-Many tables. It also has problems
-> with naming of foreign keys that have multiple column names. Any Reverse Engineered
-> Database-Schema needs considerable manual work to become a useful domain model.
\ No newline at end of file
diff --git a/manual/en/transactions-and-concurrency.rst b/manual/en/transactions-and-concurrency.rst
index 19692f1ac..717783340 100644
--- a/manual/en/transactions-and-concurrency.rst
+++ b/manual/en/transactions-and-concurrency.rst
@@ -1,3 +1,6 @@
+Transactions and Concurrency
+============================
+
Transaction Demarcation
-----------------------
diff --git a/manual/en/transactions-and-concurrency.txt b/manual/en/transactions-and-concurrency.txt
deleted file mode 100644
index 550f8e52e..000000000
--- a/manual/en/transactions-and-concurrency.txt
+++ /dev/null
@@ -1,249 +0,0 @@
-## Transaction Demarcation
-
-Transaction demarcation is the task of defining your transaction boundaries. Proper transaction demarcation is very
-important because if not done properly it can negatively affect the performance of your application.
-Many databases and database abstraction layers like PDO by default operate in auto-commit mode,
-which means that every single SQL statement is wrapped in a small transaction. Without any explicit
-transaction demarcation from your side, this quickly results in poor performance because transactions are not cheap.
-
-For the most part, Doctrine 2 already takes care of proper transaction demarcation for you: All the write
-operations (INSERT/UPDATE/DELETE) are queued until `EntityManager#flush()` is invoked which wraps all
-of these changes in a single transaction.
-
-However, Doctrine 2 also allows (and encourages) you to take over and control transaction demarcation yourself.
-
-These are two ways to deal with transactions when using the Doctrine ORM and are now described in more detail.
-
-### Approach 1: Implicitly
-
-The first approach is to use the implicit transaction handling provided by the Doctrine ORM
-EntityManager. Given the following code snippet, without any explicit transaction demarcation:
-
- setName('George');
- $em->persist($user);
- $em->flush();
-
-Since we do not do any custom transaction demarcation in the above code, `EntityManager#flush()` will begin
-and commit/rollback a transaction. This behavior is made possible by the aggregation of the DML operations
-by the Doctrine ORM and is sufficient if all the data manipulation that is part of a unit of work happens
-through the domain model and thus the ORM.
-
-
-### Approach 2: Explicitly
-
-The explicit alternative is to use the `Doctrine\DBAL\Connection` API
-directly to control the transaction boundaries. The code then looks like this:
-
- getConnection()->beginTransaction(); // suspend auto-commit
- try {
- //... do some work
- $user = new User;
- $user->setName('George');
- $em->persist($user);
- $em->flush();
- $em->getConnection()->commit();
- } catch (Exception $e) {
- $em->getConnection()->rollback();
- $em->close();
- throw $e;
- }
-
-Explicit transaction demarcation is required when you want to include custom DBAL operations in a unit of work
-or when you want to make use of some methods of the `EntityManager` API that require an active transaction.
-Such methods will throw a `TransactionRequiredException` to inform you of that requirement.
-
-A more convenient alternative for explicit transaction demarcation is the use of provided control
-abstractions in the form of `Connection#transactional($func)` and `EntityManager#transactional($func)`.
-When used, these control abstractions ensure that you never forget to rollback the transaction or
-close the `EntityManager`, apart from the obvious code reduction. An example that is functionally
-equivalent to the previously shown code looks as follows:
-
- transactional(function($em) {
- //... do some work
- $user = new User;
- $user->setName('George');
- $em->persist($user);
- });
-
-The difference between `Connection#transactional($func)` and `EntityManager#transactional($func)` is
-that the latter abstraction flushes the `EntityManager` prior to transaction commit and also closes
-the `EntityManager` properly when an exception occurs (in addition to rolling back the transaction).
-
-
-### Exception Handling
-
-When using implicit transaction demarcation and an exception occurs during `EntityManager#flush()`, the transaction
-is automatically rolled back and the `EntityManager` closed.
-
-When using explicit transaction demarcation and an exception occurs, the transaction should be rolled back immediately
-and the `EntityManager` closed by invoking `EntityManager#close()` and subsequently discarded, as demonstrated in
-the example above. This can be handled elegantly by the control abstractions shown earlier.
-Note that when catching `Exception` you should generally re-throw the exception. If you intend to
-recover from some exceptions, catch them explicitly in earlier catch blocks (but do not forget to rollback the
-transaction and close the `EntityManager` there as well). All other best practices of exception handling apply
-similarly (i.e. either log or re-throw, not both, etc.).
-
-As a result of this procedure, all previously managed or removed instances of the `EntityManager` become detached.
-The state of the detached objects will be the state at the point at which the transaction was rolled back.
-The state of the objects is in no way rolled back and thus the objects are now out of synch with the database.
-The application can continue to use the detached objects, knowing that their state is potentially no longer
-accurate.
-
-If you intend to start another unit of work after an exception has occurred you should do that with a new `EntityManager`.
-
-## Locking Support
-
-Doctrine 2 offers support for Pessimistic- and Optimistic-locking strategies natively. This allows to take
-very fine-grained control over what kind of locking is required for your Entities in your application.
-
-### Optimistic Locking
-
-Database transactions are fine for concurrency control during a single request. However, a database transaction
-should not span across requests, the so-called "user think time". Therefore a long-running "business transaction"
-that spans multiple requests needs to involve several database transactions. Thus, database transactions alone
-can no longer control concurrency during such a long-running business transaction. Concurrency control becomes
-the partial responsibility of the application itself.
-
-Doctrine has integrated support for automatic optimistic locking via a version field. In this approach any entity
-that should be protected against concurrent modifications during long-running business transactions gets a version
-field that is either a simple number (mapping type: integer) or a timestamp (mapping type: datetime). When changes
-to such an entity are persisted at the end of a long-running conversation the version of the entity is compared to
-the version in the database and if they don't match, an `OptimisticLockException` is thrown, indicating that the
-entity has been modified by someone else already.
-
-You designate a version field in an entity as follows. In this example we'll use an integer.
-
- find('User', $theEntityId, LockMode::OPTIMISTIC, $expectedVersion);
-
- // do the work
-
- $em->flush();
- } catch(OptimisticLockException $e) {
- echo "Sorry, but someone else has already changed this entity. Please apply the changes again!";
- }
-
-Or you can use `EntityManager#lock()` to find out:
-
- find('User', $theEntityId);
-
- try {
- // assert version
- $em->lock($entity, LockMode::OPTIMISTIC, $expectedVersion);
-
- } catch(OptimisticLockException $e) {
- echo "Sorry, but someone else has already changed this entity. Please apply the changes again!";
- }
-
-#### Important Implementation Notes
-
-You can easily get the optimistic locking workflow wrong if you compare the wrong versions.
-Say you have Alice and Bob accessing a hypothetical bank account:
-
-* Alice reads the headline of the blog post being "Foo", at optimistic lock version 1 (GET Request)
-* Bob reads the headline of the blog post being "Foo", at optimistic lock version 1 (GET Request)
-* Bob updates the headline to "Bar", upgrading the optimistic lock version to 2 (POST Request of a Form)
-* Alice updates the headline to "Baz", ... (POST Request of a Form)
-
-Now at the last stage of this scenario the blog post has to be read again from the database before
-Alice's headline can be applied. At this point you will want to check if the blog post is still at version 1
-(which it is not in this scenario).
-
-Using optimistic locking correctly, you *have* to add the version as an additional hidden field
-(or into the SESSION for more safety). Otherwise you cannot verify the version is still the one being originally read from
-the database when Alice performed her GET request for the blog post. If this happens you might
-see lost updates you wanted to prevent with Optimistic Locking.
-
-See the example code, The form (GET Request):
-
- find('BlogPost', 123456);
-
- echo '';
- echo '';
-
-And the change headline action (POST Request):
-
- find('BlogPost', $postId, \Doctrine\DBAL\LockMode::OPTIMISTIC, $postVersion);
-
-### Pessimistic Locking
-
-Doctrine 2 supports Pessimistic Locking at the database level. No attempt is being made to implement pessimistic locking
-inside Doctrine, rather vendor-specific and ANSI-SQL commands are used to acquire row-level locks. Every Entity can
-be part of a pessimistic lock, there is no special metadata required to use this feature.
-
-However for Pessimistic Locking to work you have to disable the Auto-Commit Mode of your Database and start a
-transaction around your pessimistic lock use-case using the "Approach 2: Explicit Transaction Demarcation" described
-above. Doctrine 2 will throw an Exception if you attempt to acquire an pessimistic lock and no transaction is running.
-
-Doctrine 2 currently supports two pessimistic lock modes:
-
-* Pessimistic Write (`Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE`), locks the underlying database rows for concurrent Read and Write Operations.
-* Pessimistic Read (`Doctrine\DBAL\LockMode::PESSIMISTIC_READ`), locks other concurrent requests that attempt to update or lock rows in write mode.
-
-You can use pessimistic locks in three different scenarios:
-
-1. Using `EntityManager#find($className, $id, \Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE)` or `EntityManager#find($className, $id, \Doctrine\DBAL\LockMode::PESSIMISTIC_READ)`
-2. Using `EntityManager#lock($entity, \Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE)` or `EntityManager#lock($entity, \Doctrine\DBAL\LockMode::PESSIMISTIC_READ)`
-3. Using `Query#setLockMode(\Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE)` or `Query#setLockMode(\Doctrine\DBAL\LockMode::PESSIMISTIC_READ)`
-
diff --git a/manual/en/working-with-associations.rst b/manual/en/working-with-associations.rst
index 12d2f10a6..784b0d836 100644
--- a/manual/en/working-with-associations.rst
+++ b/manual/en/working-with-associations.rst
@@ -1,3 +1,6 @@
+Working with Associations
+=========================
+
Associations between entities are represented just like in regular
object-oriented PHP, with references to other objects or
collections of objects. When it comes to persistence, it is
@@ -101,9 +104,8 @@ information about its type and if its the owning or inverse side.
This two entities generate the following MySQL Schema (Foreign Key
definitions omitted):
-::
+.. code-block:: sql
- [sql]
CREATE TABLE User (
id VARCHAR(255) NOT NULL,
firstComment_id VARCHAR(255) DEFAULT NULL,
@@ -262,7 +264,7 @@ essentially an ordered map (just like a PHP array). That is why the
separate method that has O(n) complexity using ``array_search``,
where n is the size of the map.
- **NOTE**
+.. note::
Since Doctrine always only looks at the owning side of a
bidirectional association for updates, it is not necessary for
@@ -350,7 +352,7 @@ is needed. As you can see, proper bidirectional association
management in plain OOP is a non-trivial task and encapsulating all
the details inside the classes can be challenging.
- **NOTE**
+.. note::
If you want to make sure that your collections are perfectly
encapsulated you should not return them from a
diff --git a/manual/en/working-with-associations.txt b/manual/en/working-with-associations.txt
deleted file mode 100644
index 8da311188..000000000
--- a/manual/en/working-with-associations.txt
+++ /dev/null
@@ -1,417 +0,0 @@
-Associations between entities are represented just like in regular object-oriented PHP, with references to other objects
-or collections of objects. When it comes to persistence, it is important to understand three main things:
-
- * The concept of owning and inverse sides in bidirectional associations as described [here](http://www.doctrine-project.org/documentation/manual/2_0/en/association-mapping#owning-side-and-inverse-side).
- * If an entity is removed from a collection, the association is removed, not the entity itself. A collection of entities always only represents the association to the containing entities, not the entity itself.
- * Collection-valued persistent fields have to be instances of the `Doctrine\Common\Collections\Collection` interface. [See here](http://www.doctrine-project.org/documentation/manual/2_0/en/architecture#entities:persistent-fields) for more details.
-
-Changes to associations in your code are not synchronized to the database directly, but upon calling `EntityManager#flush()`.
-
-To describe all the concepts of working with associations we introduce a specific set of example entities that show
-all the different flavors of association management in Doctrine.
-
-## Association Example Entities
-
-We will use a simple comment system with Users and Comments as entities to show examples of association management.
-See the PHP docblocks of each association in the following example for information about its type and if its the owning or inverse side.
-
- commentsRead;
- }
-
- public function setFirstComment(Comment $c) {
- $this->firstComment = $c;
- }
- }
-
-The interaction code would then look like in the following snippet (`$em` here is an instance of the EntityManager):
-
- find('User', $userId);
-
- // unidirectional many to many
- $comment = $em->find('Comment', $readCommentId);
- $user->getReadComments()->add($comment);
-
- $em->flush();
-
- // unidirectional many to one
- $myFirstComment = new Comment();
- $user->setFirstComment($myFirstComment);
-
- $em->persist($myFirstComment);
- $em->flush();
-
-In the case of bi-directional associations you have to update the fields on both sides:
-
- commentsAuthored;
- }
-
- public function getFavoriteComments() {
- return $this->favorites;
- }
- }
-
- class Comment
- {
- // ...
-
- public function getUserFavorites() {
- return $this->userFavorites;
- }
-
- public function setAuthor(User $author = null) {
- $this->author = $author;
- }
- }
-
- // Many-to-Many
- $user->getFavorites()->add($favoriteComment);
- $favoriteComment->getUserFavorites()->add($user);
-
- $em->flush();
-
- // Many-To-One / One-To-Many Bidirectional
- $newComment = new Comment();
- $user->getAuthoredComments()->add($newComment);
- $newComment->setAuthor($user);
-
- $em->persist($newComment);
- $em->flush();
-
-
-Notice how always both sides of the bidirectional association are updated. The previous unidirectional associations were simpler to handle.
-
-## Removing Associations
-
-Removing an association between two entities is similarly straight-forward. There are two strategies
-to do so, by key and by element. Here are some examples:
-
- getComments()->removeElement($comment);
- $comment->setAuthor(null);
-
- $user->getFavorites()->removeElement($comment);
- $comment->getUserFavorites()->removeElement($user);
-
- // Remove by Key
- $user->getComments()->removeElement($ithComment);
- $comment->setAuthor(null);
-
-You need to call `$em->flush()` to make persist these changes in the database permanently.
-
-Notice how both sides of the bidirectional association are always updated. Unidirectional associations are consequently
-simpler to handle. Also note that if you type-hint your methods, i.e. `setAddress(Address $address)`, then PHP does only
-allows null values if `null` is set as default value. Otherwise setAddress(null) will fail for removing the association.
-If you insist on type-hinting a typical way to deal with this is to provide a special method, like `removeAddress()`.
-This can also provide better encapsulation as it hides the internal meaning of not having an address.
-
-When working with collections, keep in mind that a Collection is essentially an ordered map (just like a PHP array).
-That is why the `remove` operation accepts an index/key. `removeElement` is a separate method
-that has O(n) complexity using `array_search`, where n is the size of the map.
-
-> **NOTE**
->
-> Since Doctrine always only looks at the owning side of a bidirectional association for updates, it is not necessary
-> for write operations that an inverse collection of a bidirectional one-to-many or many-to-many association is updated.
-> This knowledge can often be used to improve performance by avoiding the loading of the inverse collection.
-
-You can also clear the contents of a whole collection using the `Collections::clear()` method. You
-should be aware that using this method can lead to a straight and optimized database delete or update call
-during the flush operation that is not aware of entities that have been re-added to the collection.
-
-Say you clear a collection of tags by calling `$post->getTags()->clear();` and then call
-`$post->getTags()->add($tag)`. This will not recognize tag being already added before and issue
-two database calls.
-
-## Association Management Methods
-
-It is generally a good idea to encapsulate proper association management inside the entity classes. This makes it easier to use the class correctly and can encapsulate details about how the association is maintained.
-
-The following code shows updates to the previous User and Comment example that encapsulate much of
-the association management code:
-
- commentsRead[] = $comment;
- }
-
- public function addComment(Comment $comment) {
- if (count($this->commentsAuthored) == 0) {
- $this->setFirstComment($comment);
- }
- $this->comments[] = $comment;
- $comment->setAuthor($this);
- }
-
- private function setFirstComment(Comment $c) {
- $this->firstComment = $c;
- }
-
- public function addFavorite(Comment $comment) {
- $this->favorites->add($comment);
- $comment->addUserFavorite($this);
- }
-
- public function removeFavorite(Comment $comment) {
- $this->favorites->removeElement($comment);
- $comment->removeUserFavorite($this);
- }
- }
-
- class Comment
- {
- // ..
-
- public function addUserFavorite(User $user) {
- $this->userFavorites[] = $user;
- }
-
- public function removeUserFavorite(User $user) {
- $this->userFavorites->removeElement($user);
- }
- }
-
-You will notice that `addUserFavorite` and `removeUserFavorite` do not call `addFavorite` and `removeFavorite`,
-thus the bidirectional association is strictly-speaking still incomplete. However if you would naively add the
-`addFavorite` in `addUserFavorite`, you end up with an infinite loop, so more work is needed.
-As you can see, proper bidirectional association management in plain OOP is a non-trivial task
-and encapsulating all the details inside the classes can be challenging.
-
-> **NOTE**
->
-> If you want to make sure that your collections are perfectly encapsulated you should not return
-> them from a `getCollectionName()` method directly, but call `$collection->toArray()`. This way a client programmer
-> for the entity cannot circumvent the logic you implement on your entity for association management. For example:
-
- commentsRead->toArray();
- }
- }
-
-This will however always initialize the collection, with all the performance penalties given the size. In
-some scenarios of large collections it might even be a good idea to completely hide the read access behind
-methods on the EntityRepository.
-
-There is no single, best way for association management. It greatly depends on the requirements of your concrete
-domain model as well as your preferences.
-
-## Synchronizing Bidirectional Collections
-
-In the case of Many-To-Many associations you as the developer are responsible to keep the collections on the
-owning and inverse side up in sync, when you apply changes to them. Doctrine can only guarantee a consistent
-state for the hydration, not for your client code.
-
-Using the User-Comment entities from above, a very simple example can show the possible caveats you can encounter:
-
- getFavorites()->add($favoriteComment);
- // not calling $favoriteComment->getUserFavorites()->add($user);
-
- $user->getFavorites()->contains($favoriteComment); // TRUE
- $favoriteComment->getUserFavorites()->contains($user); // FALSE
-
-There are to approaches to handle this problem in your code:
-
-1. Ignore updating the inverse side of bidirectional collections, BUT never read from them in requests that changed
- their state. In the next Request Doctrine hydrates the consistent collection state again.
-2. Always keep the bidirectional collections in sync through association management methods. Reads of
- the Collections directly after changes are consistent then.
-
-## Transitive persistence / Cascade Operations
-
-Persisting, removing, detaching and merging individual entities can become pretty
-cumbersome, especially when a larger object graph with collections is involved.
-Therefore Doctrine 2 provides a mechanism for transitive persistence through
-cascading of these operations. Each association to another entity or a collection
-of entities can be configured to automatically cascade certain operations. By
-default, no operations are cascaded.
-
-The following cascade options exist:
-
- * persist : Cascades persist operations to the associated entities.
- * remove : Cascades remove operations to the associated entities.
- * merge : Cascades merge operations to the associated entities.
- * detach : Cascades detach operations to the associated entities.
- * all : Cascades persist, remove, merge and detach operations to associated entities.
-
-The following example is an extension to the User-Comment example of this chapter.
-Suppose in our application a user is created whenever he writes his first comment.
-In this case we would use the following code:
-
- addComment($myFirstComment);
-
- $em->persist($user);
- $em->persist($myFirstComment);
- $em->flush();
-
-Even if you *persist* a new User that contains our new Comment this code would fail
-if you removed the call to `EntityManager#persist($myFirstComment)`. Doctrine 2 does
-not cascade the persist operation to all nested entities that are new as well.
-
-More complicated is the deletion of all a users comments when he is removed from the system:
-
- $user = $em->find('User', $deleteUserId);
-
- foreach ($user->getAuthoredComments() AS $comment) {
- $em->remove($comment);
- }
- $em->remove($user);
- $em->flush();
-
-Without the loop over all the authored comments Doctrine would use an UPDATE statement only
-to set the foreign key to NULL and only the User would be deleted from the database
-during the flush()-Operation.
-
-To have Doctrine handle both cases automatically we can change the `User#commentsAuthored`
-property to cascade both the "persist" and the "remove" operation.
-
- persist($user);
$em->flush();
- **CAUTION** Generated entity identifiers / primary keys are
+.. warning::
+
+ Generated entity identifiers / primary keys are
guaranteed to be available after the next successful flush
operation that involves the entity in question. You can not rely on
a generated identifier to be available directly after invoking
@@ -244,7 +251,9 @@ the ``EntityManager#remove($entity)`` method. By applying the
which means that its persistent state will be deleted once
``EntityManager#flush()`` is invoked.
- **CAUTION** Just like ``persist``, invoking ``remove`` on an entity
+.. warning::
+
+ Just like ``persist``, invoking ``remove`` on an entity
does NOT cause an immediate SQL DELETE to be issued on the
database. The entity will be deleted on the next invocation of
``EntityManager#flush()`` that involves that entity.
@@ -423,7 +432,9 @@ the ``merge`` operation is to reattach entities to an EntityManager
that come from some cache (and are therefore detached) and you want
to modify and persist such an entity.
- **NOTE** If you load some detached entities from a cache and you do
+.. note::
+
+ If you load some detached entities from a cache and you do
not need to persist or delete them or otherwise make use of them
without the need for persistence services there is no need to use
``merge``. I.e. you can simply pass detached objects from a cache
@@ -516,7 +527,9 @@ to change tracking (see "Change Tracking Policies") and, of course,
memory consumption, so you may want to check it from time to time
during development.
- **CAUTION** Do not invoke ``flush`` after every change to an entity
+.. warning::
+
+ Do not invoke ``flush`` after every change to an entity
or every single invocation of persist/remove/merge/... This is an
anti-pattern and unnecessarily reduces the performance of your
application. Instead, form units of work that operate on your
diff --git a/manual/en/working-with-objects.txt b/manual/en/working-with-objects.txt
deleted file mode 100644
index ad0a943ec..000000000
--- a/manual/en/working-with-objects.txt
+++ /dev/null
@@ -1,549 +0,0 @@
-
-In this chapter we will help you understand the `EntityManager` and the `UnitOfWork`.
-A Unit of Work is similar to an object-level transaction. A new Unit of Work is
-implicitly started when an EntityManager is initially created or after
-`EntityManager#flush()` has been invoked. A Unit of Work is committed
-(and a new one started) by invoking `EntityManager#flush()`.
-
-A Unit of Work can be manually closed by calling EntityManager#close(). Any
-changes to objects within this Unit of Work that have not yet been persisted
-are lost.
-
-> **NOTE**
->
-> It is very important to understand that only `EntityManager#flush()` ever causes
-> write operations against the database to be executed. Any other methods such
-> as `EntityManager#persist($entity)` or `EntityManager#remove($entity)` only
-> notify the UnitOfWork to perform these operations during flush.
->
-> Not calling `EntityManager#flush()` will lead to all changes during that request being lost.
-
-## Entities and the Identity Map
-
-Entities are objects with identity. Their identity has a conceptual meaning inside your domain.
-In a CMS application each article has a unique id. You can uniquely identify each article
-by that id.
-
-Take the following example, where you find an article with the headline "Hello World"
-with the ID 1234:
-
- find('CMS\Article', 1234);
- $article->setHeadline('Hello World dude!');
-
- $article2 = $entityManager->find('CMS\Article', 1234);
- echo $article2->getHeadline();
-
-In this case the Article is accessed from the entity manager twice, but modified in between.
-Doctrine 2 realizes this and will only ever give you access to one instance of the Article
-with ID 1234, no matter how often do you retrieve it from the EntityManager and even no
-matter what kind of Query method you are using (find, Repository Finder or DQL).
-This is called "Identity Map" pattern, which means Doctrine keeps a map of each entity
-and ids that have been retrieved per PHP request and keeps returning you the same instances.
-
-In the previous example the echo prints "Hello World dude!" to the screen. You can
-even verify that `$article` and `$article2` are indeed pointing to the same instance
-by running the following code:
-
- comments = new ArrayCollection();
- }
-
- public function getAuthor() { return $this->author; }
- public function getComments() { return $this->comments; }
- }
-
- $article = $em->find('Article', 1);
-
-This code only retrieves the `User` instance with id 1 executing a single SELECT statement
-against the user table in the database. You can still access the associated properties author
-and comments and the associated objects they contain.
-
-This works by utilizing the lazy loading pattern. Instead of passing you back a real
-Author instance and a collection of comments Doctrine will create proxy instances for you.
-Only if you access these proxies for the first time they will go through the EntityManager
-and load their state from the database.
-
-This lazy-loading process happens behind the scenes, hidden from your code. See the following code:
-
- find('Article', 1);
-
- // accessing a method of the user instance triggers the lazy-load
- echo "Author: " . $article->getAuthor()->getName() . "\n";
-
- // Lazy Loading Proxies pass instanceof tests:
- if ($article->getAuthor() instanceof User) {
- // a User Proxy is a generated "UserProxy" class
- }
-
- // accessing the comments as an iterator triggers the lazy-load
- // retrieving ALL the comments of this article from the database
- // using a single SELECT statement
- foreach ($article->getComments() AS $comment) {
- echo $comment->getText() . "\n\n";
- }
-
- // Article::$comments passes instanceof tests for the Collection interface
- // But it will NOT pass for the ArrayCollection interface
- if ($article->getComments() instanceof \Doctrine\Common\Collections\Collection) {
- echo "This will always be true!";
- }
-
-A slice of the generated proxy classes code looks like the following piece of code. A real proxy
-class override ALL public methods along the lines of the `getName()` method shown below:
-
- _load();
- return parent::getName();
- }
- // .. other public methods of User
- }
-
-> **Warning**
->
-> Traversing the object graph for parts that are lazy-loaded will easily trigger lots
-> of SQL queries and will perform badly if used to heavily. Make sure to use DQL
-> to fetch-join all the parts of the object-graph that you need as efficiently as possible.
-
-## Persisting entities
-
-An entity can be made persistent by passing it to the `EntityManager#persist($entity)`
-method. By applying the persist operation on some entity, that entity becomes MANAGED,
-which means that its persistence is from now on managed by an EntityManager. As a
-result the persistent state of such an entity will subsequently be properly
-synchronized with the database when `EntityManager#flush()` is invoked.
-
-> **CAUTION**
-> Invoking the `persist` method on an entity does NOT cause an immediate SQL INSERT to be
-> issued on the database. Doctrine applies a strategy called "transactional write-behind",
-> which means that it will delay most SQL commands until `EntityManager#flush()` is
-> invoked which will then issue all necessary SQL statements to synchronize your objects
-> with the database in the most efficient way and a single, short transaction,
-> taking care of maintaining referential integrity.
-
-Example:
-
- setName('Mr.Right');
- $em->persist($user);
- $em->flush();
-
-> **CAUTION**
-> Generated entity identifiers / primary keys are guaranteed to be available after the
-> next successful flush operation that involves the entity in question.
-> You can not rely on a generated identifier to be available directly after invoking `persist`.
-> The inverse is also true. You can not rely on a generated identifier being not available
-> after a failed flush operation.
-
-The semantics of the persist operation, applied on an entity X, are as follows:
-
-* If X is a new entity, it becomes managed. The entity X will be entered into the database as a result of the flush operation.
-* If X is a preexisting managed entity, it is ignored by the persist operation. However, the persist operation is cascaded to entities referenced by X, if the relationships from X to these other entities are mapped with cascade=PERSIST or cascade=ALL (see "Transitive Persistence").
-* If X is a removed entity, it becomes managed.
-* If X is a detached entity, an exception will be thrown on flush.
-
-
-## Removing entities
-
-An entity can be removed from persistent storage by passing it to the `EntityManager#remove($entity)` method. By applying the `remove` operation on some entity, that entity becomes REMOVED, which means that its persistent state will be deleted once `EntityManager#flush()` is invoked.
-
-> **CAUTION**
-> Just like `persist`, invoking `remove` on an entity does NOT cause an immediate SQL
-> DELETE to be issued on the database. The entity will be deleted on the next invocation
-> of `EntityManager#flush()` that involves that entity.
-
-Example:
-
- remove($user);
- $em->flush();
-
-The semantics of the remove operation, applied to an entity X are as follows:
-
-* If X is a new entity, it is ignored by the remove operation. However, the remove operation is cascaded to entities referenced by X, if the relationship from X to these other entities is mapped with cascade=REMOVE or cascade=ALL (see "Transitive Persistence").
-* If X is a managed entity, the remove operation causes it to become removed. The remove operation is cascaded to entities referenced by X, if the relationships from X to these other entities is mapped with cascade=REMOVE or cascade=ALL (see "Transitive Persistence").
-* If X is a detached entity, an InvalidArgumentException will be thrown.
-* If X is a removed entity, it is ignored by the remove operation.
-* A removed entity X will be removed from the database as a result of the flush operation.
-
-After an entity has been removed its in-memory state is the same as before the removal, except for generated identifiers.
-
-Removing an entity will also automatically delete any existing records in many-to-many
-join tables that link this entity. The action taken depends on the value of the `@joinColumn`
-mapping attribute "onDelete". Either Doctrine issues a dedicated `DELETE` statement
-for records of each join table or it depends on the foreign key semantics of
-onDelete="CASCADE".
-
-Deleting an object with all its associated objects can be achieved in multiple
-ways with very different performance impacts.
-
-1. If an association is marked as `CASCADE=REMOVE` Doctrine 2 will fetch this
- association. If its a Single association it will pass this entity to
- ´EntityManager#remove()`. If the association is a collection, Doctrine will loop over all
- its elements and pass them to `EntityManager#remove()`. In both cases the
- cascade remove semantics are applied recursively. For large object graphs
- this removal strategy can be very costly.
-2. Using a DQL `DELETE` statement allows you to delete multiple entities of a
- type with a single command and without hydrating these entities. This
- can be very efficient to delete large object graphs from the database.
-3. Using foreign key semantics `onDelete="CASCADE"` can force the database
- to remove all associated objects internally. This strategy is a bit
- tricky to get right but can be very powerful and fast. You should be aware
- however that using strategy 1 (`CASCADE=REMOVE`) completely by-passes
- any foreign key `onDelete=CASCADE` option, because Doctrine will fetch and remove
- all associated entities explicitly nevertheless.
-
-## Detaching entities
-
-An entity is detached from an EntityManager and thus no longer managed by
-invoking the `EntityManager#detach($entity)` method on it or by cascading
-the detach operation to it. Changes made to the detached entity, if any
-(including removal of the entity), will not be synchronized to the database
-after the entity has been detached.
-
-Doctrine will not hold on to any references to a detached entity.
-
-Example:
-
- detach($entity);
-
-The semantics of the detach operation, applied to an entity X are as follows:
-
-* If X is a managed entity, the detach operation causes it to become detached. The detach operation is cascaded to entities referenced by X, if the relationships from X to these other entities is mapped with cascade=DETACH or cascade=ALL (see "Transitive Persistence"). Entities which previously referenced X will continue to reference X.
-* If X is a new or detached entity, it is ignored by the detach operation.
-* If X is a removed entity, the detach operation is cascaded to entities referenced by X, if the relationships from X to these other entities is mapped with cascade=DETACH or cascade=ALL (see "Transitive Persistence"). Entities which previously referenced X will continue to reference X.
-
-There are several situations in which an entity is detached automatically without invoking the `detach` method:
-
-* When `EntityManager#clear()` is invoked, all entities that are currently managed by the EntityManager instance become detached.
-* When serializing an entity. The entity retrieved upon subsequent unserialization will be detached (This is the case for all entities that are serialized and stored in some cache, i.e. when using the Query Result Cache).
-
-The `detach` operation is usually not as frequently needed and used as `persist` and `remove`.
-
-
-## Merging entities
-
-Merging entities refers to the merging of (usually detached) entities into the
-context of an EntityManager so that they become managed again. To merge the
-state of an entity into an EntityManager use the `EntityManager#merge($entity)`
-method. The state of the passed entity will be merged into a managed copy of
-this entity and this copy will subsequently be returned.
-
-Example:
-
- merge($detachedEntity);
- // $entity now refers to the fully managed copy returned by the merge operation.
- // The EntityManager $em now manages the persistence of $entity as usual.
-
-> **CAUTION**
-> When you want to serialize/unserialize entities you have to make all entity properties
-> protected, never private. The reason for this is, if you serialize a class that was a proxy
-> instance before, the private variables won't be serialized and a PHP Notice is thrown.
-
-The semantics of the merge operation, applied to an entity X, are as follows:
-
-* If X is a detached entity, the state of X is copied onto a pre-existing managed entity instance X' of the same identity.
-* If X is a new entity instance, a new managed copy X' will be created and the state of X is copied onto this managed instance.
-* If X is a removed entity instance, an InvalidArgumentException will be thrown.
-* If X is a managed entity, it is ignored by the merge operation, however, the merge operation is cascaded to entities referenced by relationships from X if these relationships have been mapped with the cascade element value MERGE or ALL (see "Transitive Persistence").
-* For all entities Y referenced by relationships from X having the cascade element value
-MERGE or ALL, Y is merged recursively as Y'. For all such Y referenced by X, X' is set to reference Y'. (Note that if X is managed then X is the same object as X'.)
-* If X is an entity merged to X', with a reference to another entity Y, where cascade=MERGE or cascade=ALL is not specified, then navigation of the same association from X' yields a reference to a managed object Y' with the same persistent identity as Y.
-
-The `merge` operation will throw an `OptimisticLockException` if the entity
-being merged uses optimistic locking through a version field and the versions
-of the entity being merged and the managed copy don't match. This usually means
-that the entity has been modified while being detached.
-
-The `merge` operation is usually not as frequently needed and used as `persist`
-and `remove`. The most common scenario for the `merge` operation is to reattach
-entities to an EntityManager that come from some cache (and are therefore detached)
-and you want to modify and persist such an entity.
-
-> **NOTE**
-> If you load some detached entities from a cache and you do not need to persist or
-> delete them or otherwise make use of them without the need for persistence services
-> there is no need to use `merge`. I.e. you can simply pass detached objects from a cache
-> directly to the view.
-
-## Synchronization with the Database
-
-The state of persistent entities is synchronized with the database on flush of an `EntityManager`
-which commits the underlying `UnitOfWork`. The synchronization involves writing any updates to
-persistent entities and their relationships to the database. Thereby bidirectional relationships
-are persisted based on the references held by the owning side of the relationship as explained
-in the Association Mapping chapter.
-
-When `EntityManager#flush()` is called, Doctrine inspects all managed, new and removed entities
-and will perform the following operations.
-
-### Synchronizing New and Managed Entities
-
-The flush operation applies to a managed entity with the following semantics:
-
-* The entity itself is synchronized to the database using a SQL UPDATE statement, only if at least one persistent field has changed.
-* No SQL updates are executed if the entity did not change.
-
-The flush operation applies to a new entity with the following semantics:
-
-* The entity itself is synchronized to the database using a SQL INSERT statement.
-
-For all (initialized) relationships of the new or managed entity the following semantics apply to each
-associated entity X:
-
-* If X is new and persist operations are configured to cascade on the relationship,
- X will be persisted.
-* If X is new and no persist operations are configured to cascade on the relationship,
- an exception will be thrown as this indicates a programming error.
-* If X is removed and persist operations are configured to cascade on the relationship,
- an exception will be thrown as this indicates a programming error (X would be re-persisted by the cascade).
-* If X is detached and persist operations are configured to cascade on the relationship,
- an exception will be thrown (This is semantically the same as passing X to persist()).
-
-### Synchronizing Removed Entities
-
-The flush operation applies to a removed entity by deleting its persistent state from the database.
-No cascade options are relevant for removed entities on flush, the cascade remove option is already
-executed during `EntityManager#remove($entity)`.
-
-### The size of a Unit of Work
-
-The size of a Unit of Work mainly refers to the number of managed entities at
-a particular point in time.
-
-### The cost of flushing
-
-How costly a flush operation is, mainly depends on two factors:
-
-* The size of the EntityManager's current UnitOfWork.
-* The configured change tracking policies
-
-You can get the size of a UnitOfWork as follows:
-
- getUnitOfWork()->size();
-
-The size represents the number of managed entities in the Unit of Work. This
-size affects the performance of flush() operations due to change tracking
-(see "Change Tracking Policies") and, of course, memory consumption, so you
-may want to check it from time to time during development.
-
-> **CAUTION**
-> Do not invoke `flush` after every change to an entity or every single invocation of
-> persist/remove/merge/... This is an anti-pattern and unnecessarily reduces the
-> performance of your application. Instead, form units of work that operate on your objects
-> and call `flush` when you are done. While serving a single HTTP request there should
-> be usually no need for invoking `flush` more than 0-2 times.
-
-### Direct access to a Unit of Work
-
-You can get direct access to the Unit of Work by calling `EntityManager#getUnitOfWork()`.
-This will return the UnitOfWork instance the EntityManager is currently using.
-
- getUnitOfWork();
-
-> **NOTE**
-> Directly manipulating a UnitOfWork is not recommended. When working directly with the
-> UnitOfWork API, respect methods marked as INTERNAL by not using them and carefully read
-> the API documentation.
-
-### Entity State
-
-As outlined in the architecture overview an entity can be in one of four possible states:
-NEW, MANAGED, REMOVED, DETACHED. If you explicitly need to find out what the current state
-of an entity is in the context of a certain `EntityManager` you can ask the underlying
-`UnitOfWork`:
-
- getUnitOfWork()->getEntityState($entity)) {
- case UnitOfWork::MANAGED:
- ...
- case UnitOfWork::REMOVED:
- ...
- case UnitOfWork::DETACHED:
- ...
- case UnitOfWork::NEW:
- ...
- }
-
-An entity is in MANAGED state if it is associated with an `EntityManager` and it is not REMOVED.
-
-An entity is in REMOVED state after it has been passed to `EntityManager#remove()` until the
-next flush operation of the same EntityManager. A REMOVED entity is still associated with an
-`EntityManager` until the next flush operation.
-
-An entity is in DETACHED state if it has persistent state and identity but is currently not
-associated with an `EntityManager`.
-
-An entity is in NEW state if has no persistent state and identity and is not associated with an
-`EntityManager` (for example those just created via the "new" operator).
-
-
-## Querying
-
-Doctrine 2 provides the following ways, in increasing level of power and flexibility, to query for persistent objects. You should always start with the simplest one that suits your needs.
-
-### By Primary Key
-
-The most basic way to query for a persistent object is by its identifier / primary key using the `EntityManager#find($entityName, $id)` method. Here is an example:
-
- find('MyProject\Domain\User', $id);
-
-The return value is either the found entity instance or null if no instance could be found with the given identifier.
-
-Essentially, `EntityManager#find()` is just a shortcut for the following:
-
- getRepository('MyProject\Domain\User')->find($id);
-
-`EntityManager#getRepository($entityName)` returns a repository object which provides many ways to retrieve entities of the specified type. By default, the repository instance is of type `Doctrine\ORM\EntityRepository`. You can also use custom repository classes as shown later.
-
-### By Simple Conditions
-
-To query for one or more entities based on several conditions that form a logical conjunction, use the `findBy` and `findOneBy` methods on a repository as follows:
-
- getRepository('MyProject\Domain\User')->findBy(array('age' => 20));
-
- // All users that are 20 years old and have a surname of 'Miller'
- $users = $em->getRepository('MyProject\Domain\User')->findBy(array('age' => 20, 'surname' => 'Miller'));
-
- // A single user by its nickname
- $user = $em->getRepository('MyProject\Domain\User')->findOneBy(array('nickname' => 'romanb'));
-
-An EntityRepository also provides a mechanism for more concise calls through its use of `__call`. Thus, the following two examples are equivalent:
-
- getRepository('MyProject\Domain\User')->findOneBy(array('nickname' => 'romanb'));
-
- // A single user by its nickname (__call magic)
- $user = $em->getRepository('MyProject\Domain\User')->findOneByNickname('romanb');
-
-
-### By Eager Loading
-
-Whenever you query for an entity that has persistent associations and these associations are mapped as EAGER, they will automatically be loaded together with the entity being queried and is thus immediately available to your application.
-
-
-### By Lazy Loading
-
-Whenever you have a managed entity instance at hand, you can traverse and use any associations of that entity that are configured LAZY as if they were in-memory already. Doctrine will automatically load the associated objects on demand through the concept of lazy-loading.
-
-
-### By DQL
-
-The most powerful and flexible method to query for persistent objects is the Doctrine Query Language, an object query language. DQL enables you to query for persistent objects in the language of objects. DQL understands classes, fields, inheritance and associations.
-DQL is syntactically very similar to the familiar SQL but *it is not SQL*.
-
-A DQL query is represented by an instance of the `Doctrine\ORM\Query` class. You create a query using `EntityManager#createQuery($dql)`. Here is a simple example:
-
- createQuery("select u from MyDomain\Model\User u where u.age >= 20 and u.age <= 30");
- $users = $q->getResult();
-
-Note that this query contains no knowledge about the relational schema, only about the object model. DQL supports positional as well as named parameters, many functions, (fetch) joins, aggregates, subqueries and much more. Detailed information about DQL and its syntax as well as the Doctrine\ORM\Query class can be found in [the dedicated chapter](http://www.doctrine-project.org/documentation/manual/2_0/en/dql-doctrine-query-language). For programmatically building up queries based on conditions that are only known at runtime, Doctrine provides the special `Doctrine\ORM\QueryBuilder` class. More information on constructing queries with a QueryBuilder can be found [in the dedicated chapter](http://www.doctrine-project.org/documentation/manual/2_0/en/query-builder).
-
-
-### By Native Queries
-
-As an alternative to DQL or as a fallback for special SQL statements native queries can be used.
-Native queries are built by using a hand-crafted SQL query and a ResultSetMapping that describes
-how the SQL result set should be transformed by Doctrine. More information about native queries
-can be found in [the dedicated chapter](http://www.doctrine-project.org/documentation/manual/2_0/en/native-sql).
-
-### Custom Repositories
-
-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 applications that require lots of specialized DQL queries using a custom repository is
-one recommended way of grouping these queries in a central location.
-
- _em->createQuery('SELECT u FROM MyDomain\Model\User u WHERE u.status = "admin"')
- ->getResult();
- }
- }
-
-You can access your repository now by calling:
-
- getRepository('MyDomain\Model\User')->getAllAdminUsers();
-
diff --git a/manual/en/xml-mapping.rst b/manual/en/xml-mapping.rst
index b384dd638..e93ded5a1 100644
--- a/manual/en/xml-mapping.rst
+++ b/manual/en/xml-mapping.rst
@@ -1,3 +1,6 @@
+XML Mapping
+===========
+
The XML mapping driver enables you to provide the ORM metadata in
form of XML documents.
@@ -13,9 +16,8 @@ code-completion based on such an XML Schema document. The following
is an outline of a XML mapping document with the proper xmlns/xsi
setup for the latest code in trunk.
-::
+.. code-block:: xml
- [xml]
`` element as a direct child of the
```` element:
-::
+.. code-block:: xml
- [xml]
@@ -188,9 +188,8 @@ element as a children to the ```` element. The field
element is only used for primitive types that are not the ID of the
entity. For the ID mapping you have to use the ```` element.
-::
+.. code-block:: xml
- [xml]
@@ -238,9 +237,8 @@ surrogate keys are recommended for use with Doctrine 2. The Id
field allows to define properties of the identifier and allows a
subset of the ```` element attributes:
-::
+.. code-block:: xml
- [xml]
@@ -270,9 +268,8 @@ to nest a ```` element inside the id-element. This of
course only works for surrogate keys. For composite keys you always
have to use the ``ASSIGNED`` strategy.
-::
+.. code-block:: xml
- [xml]
@@ -333,9 +330,8 @@ from, which itself is not an entity however. The chapter on
*Inheritance Mapping* describes a Mapped Superclass in detail. You
can define it in XML using the ```` tag.
-::
+.. code-block:: xml
- [xml]
@@ -366,9 +362,8 @@ You can specify the inheritance type in the ```` element
and then use the ```` and
```` attributes.
-::
+.. code-block:: xml
- [xml]
@@ -381,7 +376,7 @@ and then use the ```` and
The allowed values for inheritance-type attribute are ``JOINED`` or
``SINGLE_TABLE``.
- **NOTE**
+.. note::
All inheritance related definitions have to be defined on the root
entity of the hierarchy.
@@ -393,9 +388,8 @@ Defining Lifecycle Callbacks
You can define the lifecycle callback methods on your entities
using the ```` element:
-::
+.. code-block:: xml
- [xml]
@@ -412,9 +406,8 @@ depend on the associations being on the inverse or owning side.
For the inverse side the mapping is as simple as:
-::
+.. code-block:: xml
- [xml]
@@ -431,9 +424,8 @@ Required attributes for inverse One-To-One:
For the owning side this mapping would look like:
-::
+.. code-block:: xml
- [xml]
@@ -467,9 +459,8 @@ association, which means it contains the foreign key.
The completed explicitly defined mapping is:
-::
+.. code-block:: xml
- [xml]
@@ -484,9 +475,8 @@ bidirectional association. This simplifies the mapping compared to
the one-to-one case. The minimal mapping for this association looks
like:
-::
+.. code-block:: xml
- [xml]
@@ -516,9 +506,8 @@ to the naming of the join-column/foreign key. The explicitly
defined mapping includes a ```` tag nested inside
the many-to-one association tag:
-::
+.. code-block:: xml
- [xml]
@@ -537,9 +526,8 @@ association. There exists no such thing as a uni-directional
one-to-many association, which means this association only ever
exists for bi-directional associations.
-::
+.. code-block:: xml
- [xml]
@@ -566,9 +554,8 @@ From all the associations the many-to-many has the most complex
definition. When you rely on the mapping defaults you can omit many
definitions and rely on their implicit values.
-::
+.. code-block:: xml
- [xml]
@@ -596,9 +583,8 @@ The mapping defaults would lead to a join-table with the name
"User\_Group" being created that contains two columns "user\_id"
and "group\_id". The explicit definition of this mapping would be:
-::
+.. code-block:: xml
- [xml]
@@ -626,9 +612,8 @@ related entities. You can specify the cascade operations in the
```` element inside any of the association mapping
tags.
-::
+.. code-block:: xml
- [xml]
@@ -677,9 +662,8 @@ Defining Order of To-Many Associations
You can require one-to-many or many-to-many associations to be
retrieved using an additional ``ORDER BY``.
-::
+.. code-block:: xml
- [xml]
@@ -695,9 +679,8 @@ To define additional indexes or unique constraints on the entities
table you can use the ```` and
```` elements:
-::
+.. code-block:: xml
- [xml]
diff --git a/manual/en/xml-mapping.txt b/manual/en/xml-mapping.txt
deleted file mode 100644
index 2dd1806b7..000000000
--- a/manual/en/xml-mapping.txt
+++ /dev/null
@@ -1,509 +0,0 @@
-The XML mapping driver enables you to provide the ORM metadata in form of XML documents.
-
-The XML driver is backed by an XML Schema document that describes the structure of a mapping document. The most recent version of the XML Schema document is available online at [http://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd](http://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd). In order to point to the latest version of the document of a particular stable release branch, just append the release number, i.e.: doctrine-mapping-2.0.xsd The most convenient way to work with XML mapping files is to use an IDE/editor that can provide code-completion based on such an XML Schema document. The following is an outline of a XML mapping document with the proper xmlns/xsi setup for the latest code in trunk.
-
- [xml]
-
-
- ...
-
-
-
-The XML mapping document of a class is loaded on-demand the first time it is requested and subsequently stored in the metadata cache. In order to work, this requires certain conventions:
-
- * Each entity/mapped superclass must get its own dedicated XML mapping document.
- * The name of the mapping document must consist of the fully qualified name of the class, where namespace
- separators are replaced by dots (.). For example an Entity with the fully qualified class-name "MyProject\Entities\User"
- would require a mapping file "MyProject.Entities.User.dcm.xml" unless the extension is changed.
- * All mapping documents should get the extension ".dcm.xml" to identify it as a Doctrine mapping file. This is more of
- a convention and you are not forced to do this. You can change the file extension easily enough.
-
--
-
- setFileExtension('.xml');
-
-It is recommended to put all XML mapping documents in a single folder but you can spread the documents over several folders if you want to. In order to tell the XmlDriver where to look for your mapping documents, supply an array of paths as the first argument of the constructor, like this:
-
- setMetadataDriverImpl($driver);
-
-
-## Example
-
-As a quick start, here is a small example document that makes use of several common elements:
-
- [xml]
- // Doctrine.Tests.ORM.Mapping.User.dcm.xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Be aware that class-names specified in the XML files should be fully qualified.
-
-## XML-Element Reference
-
-The XML-Element reference explains all the tags and attributes that the Doctrine Mapping XSD Schema defines.
-You should read the Basic-, Association- and Inheritance Mapping chapters to understand what each of this
-definitions means in detail.
-
-### Defining an Entity
-
-Each XML Mapping File contains the definition of one entity, specified as the `` element
-as a direct child of the `` element:
-
- [xml]
-
-
-
-
-
-
-Required attributes:
-
-* name - The fully qualified class-name of the entity.
-
-Optional attributes:
-
-* table - The Table-Name to be used for this entity. Otherwise the Unqualified Class-Name is used by default.
-* repository-class - The fully qualified class-name of an alternative `Doctrine\ORM\EntityRepository` implementation to be used with this entity.
-* inheritance-type - The type of inheritance, defaults to none. A more detailed description follows in the *Defining Inheritance Mappings* section.
-
-### Defining Fields
-
-Each entity class can contain zero to infinite fields that are managed by Doctrine. You can define
-them using the `` element as a children to the `` element. The field element is only
-used for primitive types that are not the ID of the entity. For the ID mapping you have to use the `` element.
-
- [xml]
-
-
-
-
-
-
-
-
-
-Required attributes:
-
-* name - The name of the Property/Field on the given Entity PHP class.
-
-Optional attributes:
-
-* type - The `Doctrine\DBAL\Types\Type` name, defaults to "string"
-* column - Name of the column in the database, defaults to the field name.
-* length - The length of the given type, for use with strings only.
-* unique - Should this field contain a unique value across the table? Defaults to false.
-* nullable - Should this field allow NULL as a value? Defaults to false.
-* version - Should this field be used for optimistic locking? Only works on fields with type integer or datetime.
-* scale - Scale of a decimal type.
-* precision - Precision of a decimal type.
-* column-definition - Optional alternative SQL representation for this column. This definition begin after the
- field-name and has to specify the complete column definition. Using this feature will turn this field dirty
- for Schema-Tool update commands at all times.
-
-### Defining Identity and Generator Strategies
-
-An entity has to have at least one `` element. For composite keys you can specify more than one id-element,
-however surrogate keys are recommended for use with Doctrine 2. The Id field allows to define properties of
-the identifier and allows a subset of the `` element attributes:
-
- [xml]
-
-
-
-
-Required attributes:
-
-* name - The name of the Property/Field on the given Entity PHP class.
-* type - The `Doctrine\DBAL\Types\Type` name, preferably "string" or "integer".
-
-Optional attributes:
-
-* column - Name of the column in the database, defaults to the field name.
-
-Using the simplified definition above Doctrine will use no identifier strategy for this entity. That means
-you have to manually set the identifier before calling `EntityManager#persist($entity)`. This is the
-so called `ASSIGNED` strategy.
-
-If you want to switch the identifier generation strategy you have to nest a `` element inside
-the id-element. This of course only works for surrogate keys. For composite keys you always have to use
-the `ASSIGNED` strategy.
-
- [xml]
-
-
-
-
-
-
-The following values are allowed for the `` strategy attribute:
-
-* AUTO - Automatic detection of the identifier strategy based on the preferred solution of the database vendor.
-* IDENTITY - Use of a IDENTIFY strategy such as Auto-Increment IDs available to Doctrine AFTER the INSERT statement has been executed.
-* SEQUENCE - Use of a database sequence to retrieve the entity-ids. This is possible before the INSERT statement is executed.
-
-If you are using the SEQUENCE strategy you can define an additional element to describe the sequence:
-
- [xml]
-
-
-
-
-
-
-
-Required attributes for ``:
-
-* sequence-name - The name of the sequence
-
-Optional attributes for ``:
-
-* allocation-size - By how much steps should the sequence be incremented when a value is retrieved. Defaults to 1
-* initial-value - What should the initial value of the sequence be.
-
-> **NOTE**
->
-> If you want to implement a cross-vendor compatible application you have to specify and
-> additionally define the element, if Doctrine chooses the sequence strategy for a platform.
-
-### Defining a Mapped Superclass
-
-Sometimes you want to define a class that multiple entities inherit from, which itself is not an entity however.
-The chapter on *Inheritance Mapping* describes a Mapped Superclass in detail. You can define it in XML using
-the `` tag.
-
- [xml]
-
-
-
-
-
-
-
-Required attributes:
-
-* name - Class name of the mapped superclass.
-
-You can nest any number of `` and unidirectional `` or `` associations inside
-a mapped superclass.
-
-### Defining Inheritance Mappings
-
-There are currently two inheritance persistence strategies that you can choose from when defining entities that
-inherit from each other. Single Table inheritance saves the fields of the complete inheritance hierarchy in a single table,
-joined table inheritance creates a table for each entity combining the fields using join conditions.
-
-You can specify the inheritance type in the `` element and then use the `` and
-`` attributes.
-
- [xml]
-
-
-
-
-
-
-
-
-
-The allowed values for inheritance-type attribute are `JOINED` or `SINGLE_TABLE`.
-
-> **NOTE**
->
-> All inheritance related definitions have to be defined on the root entity of the hierarchy.
-
-### Defining Lifecycle Callbacks
-
-You can define the lifecycle callback methods on your entities using the `` element:
-
- [xml]
-
-
-
-
-
-
-
-### Defining One-To-One Relations
-
-You can define One-To-One Relations/Associations using the `` element. The required
-and optional attributes depend on the associations being on the inverse or owning side.
-
-For the inverse side the mapping is as simple as:
-
- [xml]
-
-
-
-
-Required attributes for inverse One-To-One:
-
-* field - Name of the property/field on the entity's PHP class.
-* target-entity - Name of the entity associated entity class. If this is not qualified the namespace of the current class is prepended. *IMPORTANT:* No leading backslash!
-* mapped-by - Name of the field on the owning side (here Address entity) that contains the owning side association.
-
-For the owning side this mapping would look like:
-
- [xml]
-
-
-
-
-Required attributes for owning One-to-One:
-
-* field - Name of the property/field on the entity's PHP class.
-* target-entity - Name of the entity associated entity class. If this is not qualified the namespace of the current class is prepended. *IMPORTANT:* No leading backslash!
-
-Optional attributes for owning One-to-One:
-
-* 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.
-* 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 makes only sense on the owning side, the inverse side *ALWAYS* has to use the `FETCH` strategy.
-
-The definition for the owning side relies on a bunch of mapping defaults for the join column names.
-Without the nested `` element Doctrine assumes to foreign key to be called `user_id` on the Address
-Entities table. This is because the `MyProject\Address` entity is the owning side of this association, which means
-it contains the foreign key.
-
-The completed explicitly defined mapping is:
-
- [xml]
-
-
-
-
-
-
-### Defining Many-To-One Associations
-
-The many-to-one association is *ALWAYS* the owning side of any bidirectional association. This simplifies the mapping
-compared to the one-to-one case. The minimal mapping for this association looks like:
-
- [xml]
-
-
-
-
-Required attributes:
-
-* field - Name of the property/field on the entity's PHP class.
-* target-entity - Name of the entity associated entity class. If this is not qualified the namespace of the current class is prepended. *IMPORTANT:* No leading backslash!
-
-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.
-* orphan-removal - If true the entity on the inverse side is 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.
-
-This definition relies on a bunch of mapping defaults with regards to the naming of the join-column/foreign key. The
-explicitly defined mapping includes a `` tag nested inside the many-to-one association tag:
-
- [xml]
-
-
-
-
-
-
-The join-column attribute `name` specifies the column name of the foreign key and
-the `referenced-column-name` attribute specifies the name of the primary key column
-on the User entity.
-
-### Defining One-To-Many Associations
-
-The one-to-many association is *ALWAYS* the inverse side of any association. There exists no such thing as a
-uni-directional one-to-many association, which means this association only ever exists for bi-directional associations.
-
- [xml]
-
-
-
-
-Required attributes:
-
-* field - Name of the property/field on the entity's PHP class.
-* target-entity - Name of the entity associated entity class. If this is not qualified the namespace of the current class is prepended. *IMPORTANT:* No leading backslash!
-* mapped-by - Name of the field on the owning side (here Phonenumber entity) that contains the owning side association.
-
-Optional attributes:
-
-* fetch - Either LAZY or FETCH, defaults to LAZY.
-
-### Defining Many-To-Many Associations
-
-From all the associations the many-to-many has the most complex definition. When you rely on the mapping defaults
-you can omit many definitions and rely on their implicit values.
-
- [xml]
-
-
-
-
-Required attributes:
-
-* field - Name of the property/field on the entity's PHP class.
-* target-entity - Name of the entity associated entity class. If this is not qualified the namespace of the current class is prepended. *IMPORTANT:* No leading backslash!
-
-Optional attributes:
-
-* mapped-by - Name of the field on the owning side that contains the owning side association if the defined many-to-many association is on the inverse side.
-* 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.
-
-The mapping defaults would lead to a join-table with the name "User_Group" being created that contains two columns
-"user_id" and "group_id". The explicit definition of this mapping would be:
-
- [xml]
-
-
-
-
-
-
-
-
-
-
-
-
-
-Here both the `` and `` tags are necessary to tell Doctrine for which side the
-specified join-columns apply. These are nested inside a `` attribute which allows to specify
-the table name of the many-to-many join-table.
-
-### Cascade Element
-
-Doctrine allows cascading of several UnitOfWork operations to related entities. You can specify the cascade
-operations in the `` element inside any of the association mapping tags.
-
- [xml]
-
-
-
-
-
-
-
-
-Besides `` the following operations can be specified by their respective tags:
-
-* ``
-* ``
-* ``
-* ``
-
-### Join Column Element
-
-In any explicitly defined association mapping you will need the `` tag. It defines how the
-foreign key and primary key names are called that are used for joining two entities.
-
-Required attributes:
-
-* name - The column name of the foreign key.
-* referenced-column-name - The column name of the associated entities primary key
-
-Optional attributes:
-
-* unique - If the join column should contain a UNIQUE constraint. This makes sense for Many-To-Many join-columns only to simulate a one-to-many unidirectional using a join-table.
-* nullable - should the join column be nullable, defaults to true.
-* on-delete - Foreign Key Cascade action to perform when entity is deleted, defaults to NO ACTION/RESTRICT but can be set to "CASCADE".
-
-### Defining Order of To-Many Associations
-
-You can require one-to-many or many-to-many associations to be retrieved using an additional `ORDER BY`.
-
- [xml]
-
-
-
-
-
-
-
-
-### Defining Indexes or Unique Constraints
-
-To define additional indexes or unique constraints on the entities table you can use the
-`` and `` elements:
-
- [xml]
-
-
-
-
-
-
-
-
-
-
-
-
-You have to specify the column and not the entity-class field names in the index and unique-constraint
-definitions.
\ No newline at end of file
diff --git a/manual/en/yaml-mapping.rst b/manual/en/yaml-mapping.rst
index 54245c5c2..9f62eea8d 100644
--- a/manual/en/yaml-mapping.rst
+++ b/manual/en/yaml-mapping.rst
@@ -1,3 +1,6 @@
+YAML Mapping
+============
+
The YAML mapping driver enables you to provide the ORM metadata in
form of YAML documents.
@@ -42,9 +45,8 @@ Example
As a quick start, here is a small example document that makes use
of several common elements:
-::
+.. code-block:: yaml
- [yml]
# Doctrine.Tests.ORM.Mapping.User.dcm.yml
Doctrine\Tests\ORM\Mapping\User:
type: entity
diff --git a/manual/en/yaml-mapping.txt b/manual/en/yaml-mapping.txt
deleted file mode 100644
index e043eb121..000000000
--- a/manual/en/yaml-mapping.txt
+++ /dev/null
@@ -1,66 +0,0 @@
-The YAML mapping driver enables you to provide the ORM metadata in form of YAML documents.
-
-The YAML mapping document of a class is loaded on-demand the first time it is requested and subsequently stored in the metadata cache. In order to work, this requires certain conventions:
-
- * Each entity/mapped superclass must get its own dedicated YAML mapping document.
- * The name of the mapping document must consist of the fully qualified name of the class, where namespace separators are replaced by dots (.).
- * All mapping documents should get the extension ".dcm.yml" to identify it as a Doctrine mapping file. This is more of a convention and you are not forced to do this. You can change the file extension easily enough.
-
--
-
- setFileExtension('.yml');
-
-It is recommended to put all YAML mapping documents in a single folder but you can spread the documents over several folders if you want to. In order to tell the YamlDriver where to look for your mapping documents, supply an array of paths as the first argument of the constructor, like this:
-
- setMetadataDriverImpl($driver);
-
-
-## Example
-
-As a quick start, here is a small example document that makes use of several common elements:
-
- [yml]
- # Doctrine.Tests.ORM.Mapping.User.dcm.yml
- Doctrine\Tests\ORM\Mapping\User:
- type: entity
- table: cms_users
- id:
- id:
- type: integer
- generator:
- strategy: AUTO
- fields:
- name:
- type: string
- length: 50
- oneToOne:
- address:
- targetEntity: Address
- joinColumn:
- name: address_id
- referencedColumnName: id
- oneToMany:
- phonenumbers:
- targetEntity: Phonenumber
- mappedBy: user
- cascade: cascadePersist
- manyToMany:
- groups:
- targetEntity: Group
- joinTable:
- name: cms_users_groups
- joinColumns:
- user_id:
- referencedColumnName: id
- inverseJoinColumns:
- group_id:
- referencedColumnName: id
- lifecycleCallbacks:
- prePersist: [ doStuffOnPrePersist, doOtherStuffOnPrePersistToo ]
- postPersist: [ doStuffOnPostPersist ]
-
- Be aware that class-names specified in the YAML files should be fully qualified.
\ No newline at end of file