128 lines
4.2 KiB
ReStructuredText
128 lines
4.2 KiB
ReStructuredText
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
|
|
---------------------------------------
|
|
|
|
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:
|
|
|
|
.. code-block:: php
|
|
|
|
<?php
|
|
namespace MyProject\Model;
|
|
use Doctrine\Common\Collections\ArrayCollection;
|
|
|
|
class User {
|
|
private $addresses;
|
|
private $articles;
|
|
|
|
public function __construct() {
|
|
$this->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.
|
|
|
|
|