Architecture

This chapter gives an overview of the overall architecture, terminology and constraints of Doctrine. It is recommended to read this chapter carefully.

Documents

A document is a lightweight, persistent domain object. A document can be any regular PHP class observing the following restrictions:

  • A document class must not be final or contain final methods.
  • All persistent properties/field of any document class should always be private or protected, otherwise lazy-loading might not work as expected.
  • A document class must not implement __clone or do so safely.
  • A document class must not implement __wakeup or do so safely. Also consider implementing Serializable instead.
  • Any two document classes in a class hierarchy that inherit directly or indirectly from one another must not have a mapped property with the same name. That is, if B inherits from A then B must not have a mapped field with the same name as an already mapped field that is inherited from A.

Documents support inheritance, polymorphic associations, and polymorphic queries. Both abstract and concrete classes can be documents. Documents may extend non-document classes as well as document classes, and non-document classes may extend document classes.

Tip

The constructor of a document is only ever invoked when you construct a new instance with the new keyword. Doctrine never calls document constructors, thus you are free to use them as you wish and even have it require arguments of any type.

Document states

A document instance can be characterized as being NEW, MANAGED, DETACHED or REMOVED.

  • A NEW document instance has no persistent identity, and is not yet associated with a DocumentManager and a UnitOfWork (i.e. those just created with the "new" operator).
  • A MANAGED document instance is an instance with a persistent identity that is associated with a DocumentManager and whose persistence is thus managed.
  • A DETACHED document instance is an instance with a persistent identity that is not (or no longer) associated with a DocumentManager and a UnitOfWork.
  • A REMOVED document instance is an instance with a persistent identity, associated with a DocumentManager, that will be removed from the database upon transaction commit.

Persistent fields

The persistent state of a document is represented by instance variables. An instance variable must be directly accessed only from within the methods of the document by the document instance itself. Instance variables must not be accessed by clients of the document. The state of the document is available to clients only through the document'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 document is made persistent. Once the document becomes managed (or detached), subsequent access must be through the interface type.

Serializing documents

Serializing documents can be problematic and is not really recommended, at least not as long as a document instance still holds references to proxy objects or is still managed by an DocumentManager. If you intend to serialize (and unserialize) document 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 DocumentManager

The DocumentManager class is a central access point to the ODM functionality provided by Doctrine. The DocumentManager API is used to manage the persistence of your objects and to query for persistent objects.

Transactional write-behind

An DocumentManager and the underlying UnitOfWork employ a strategy called "transactional write-behind" that delays the execution of query 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 DocumentManager#flush() to make your changes persistent.

The Unit of Work

Internally an DocumentManager uses a UnitOfWork, which is a typical implementation of the Unit of Work pattern, to keep track of all the things that need to be done the next time flush is invoked. You usually do not directly interact with a UnitOfWork but with the DocumentManager instead.

Fork me on GitHub