1
0
mirror of synced 2024-12-15 23:56:02 +03:00
doctrine2/docs/en/reference/basic-mapping.rst

494 lines
17 KiB
ReStructuredText

Basic Mapping
=============
This guide explains the basic mapping of entities and properties.
After working through this guide you should know:
- How to create PHP classes that can be saved in the database with Doctrine
- How to configure the mapping between columns on tables and properties on
entities.
- What Doctrine Mapping types are
- Defining primary keys and how identifiers are generated by Doctrine
- How quoting of reserved symbols works in Doctrine
Mapping of associations will be covered in the next chapter on
:doc:`Association Mapping <association-mapping>`.
Guide Assumptions
-----------------
You should have already :doc:`installed and configure <configuration>`
Doctrine.
Creating Classes for the Database
---------------------------------
Every PHP Class that you want to save in the database using Doctrine
need to be marked as "Entity". The term "Entity" describes objects
that have identity over many independent requests. This identity is
usually achieved by assigning a unique identifier to an entity.
In this tutorial the following ``Message`` PHP class will serve as
example Entity:
.. code-block:: php
<?php
class Message
{
private $id;
private $text;
private $postedAt;
}
Because Doctrine is a generic library, it can only know about your
entities when you are describing their existance and structure using
Metadata Mapping, a pattern `described by Martin Fowler in PoEAA
<http://martinfowler.com/eaaCatalog/metadataMapping.html>`_. Because
of this pattern the documentation will often speak of "mapping something",
which means that we use the metadata mapping pattern to use this feature.
Doctrine provides several different ways for specifying object-relational
mapping metadata:
- :doc:`Docblock Annotations <annotations-reference>`
- :doc:`XML <xml-mapping>`
- :doc:`YAML <yml-mapping>`
- PHP code
This manual usually mentions docblock annotations in all the examples that are
spread throughout all chapters, however for many examples alternative YAML and
XML examples are given as well.
.. note::
All metadata drivers perform equally. 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. If you're not using a metadata cache (not
recommended!) then the XML driver is the fastest by using PHP's native XML
support.
Marking our ``Message`` entity for Doctrine is straightforward:
.. configuration-block::
.. code-block:: php
<?php
/** @Entity */
class Message
{
//...
}
.. code-block:: xml
<doctrine-mapping>
<entity name="Message">
<!-- ... -->
</entity>
</doctrine-mapping>
.. code-block:: yaml
Message:
type: entity
# ...
With no additional information given Doctrine expects the entity to be saved
into a table with the same name as the class in our case ``Message``.
You can change this by configuring information about the table:
.. configuration-block::
.. code-block:: php
<?php
/**
* @Entity
* @Table(name="message")
*/
class Message
{
//...
}
.. code-block:: xml
<doctrine-mapping>
<entity name="Message" table="message">
<!-- ... -->
</entity>
</doctrine-mapping>
.. code-block:: yaml
Message:
type: entity
table: message
# ...
Now the class ``Message`` will be saved and fetched from the table ``message``.
Property Mapping
----------------
The next step after defining a PHP class as entity is mapping of properties
to columns in a table.
To configure a property use the ``@Column`` docblock annotation. 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.
.. configuration-block::
.. code-block:: php
<?php
/** @Entity */
class Message
{
/** @Column(type="integer") */
private $id;
/** @Column(length=140) */
private $text;
/** @Column(type="datetime", name="posted_at") */
private $postedAt;
}
.. code-block:: xml
<doctrine-mapping>
<entity name="Message">
<field name="id" type="integer" />
<field name="text" length="140" />
<field name="postedAt" column="posted_at" type="datetime" />
</entity>
</doctrine-mapping>
.. code-block:: yaml
Message:
type: entity
fields:
id:
type: integer
text:
length: 140
postedAt:
type: datetime
name: posted_at
Because we don't explicitly specify a column name, Doctrine assumes the field
name is also the column name. In the example we configured the property ``id`` to map to the column ``id``
using the mapping type ``integer``. The field ``text`` is mapped to the column
``text`` with the default mapping type ``string`` and ``postedAt`` is of the
datetime type, but mapped to a column called ``posted_at``.
The Column annotation has some more attributes. Here is a complete
list:
- ``type``: (optional, defaults to 'string') The mapping type to
use for the column.
- ``name``: (optional, defaults to field name) The name of the
column in the database.
- ``length``: (optional, default 255) The length of the column in
the database. (Applies only if a string-valued column is used).
- ``unique``: (optional, default FALSE) Whether the column is a
unique key.
- ``nullable``: (optional, default FALSE) Whether the database
column is nullable.
- ``precision``: (optional, default 0) The precision for a decimal
(exact numeric) column. (Applies only if a decimal column is used.)
- ``scale``: (optional, default 0) The scale for a decimal (exact
numeric) column. (Applies only if a decimal column is used.)
- ``columnDefinition``: (optional) Allows to define a custom
DDL snippet that is used to create the column. Warning: This normally
confuses the SchemaTool to always detect the column as changed.
- ``options``: (optional) Key-value pairs of options that get passed
to the underlying database platform when generating DDL statements.
Doctrine Mapping Types
----------------------
The ``type`` option used in the ``@Column`` accepts any of the existing
Doctrine types or even your own custom types. A Doctrine type defines
the conversion between PHP and SQL types, indepedant from the database vendor
you are using. All Mapping Types that ship with Doctrine are fully portable
between the supported database systems.
As an example the Doctrine Mapping Type ``string`` defines the
mapping from a PHP string to a SQL VARCHAR (or VARCHAR2 etc.
depending on the RDBMS brand). Here is a quick overview of the
built-in mapping types:
- ``string``: Type that maps a SQL VARCHAR to a PHP string.
- ``integer``: Type that maps a SQL INT to a PHP integer.
- ``smallint``: Type that maps a database SMALLINT to a PHP
integer.
- ``bigint``: Type that maps a database BIGINT to a PHP string.
- ``boolean``: Type that maps a SQL boolean or equivalent (TINYINT) to a PHP boolean.
- ``decimal``: Type that maps a SQL DECIMAL to a PHP string.
- ``date``: Type that maps a SQL DATETIME to a PHP DateTime
object.
- ``time``: Type that maps a SQL TIME to a PHP DateTime object.
- ``datetime``: Type that maps a SQL DATETIME/TIMESTAMP to a PHP
DateTime object.
- ``datetimetz``: Type that maps a SQL DATETIME/TIMESTAMP to a PHP
DateTime object with timezone.
- ``text``: Type that maps a SQL CLOB to a PHP string.
- ``object``: Type that maps a SQL CLOB to a PHP object using
``serialize()`` and ``unserialize()``
- ``array``: Type that maps a SQL CLOB to a PHP array using
``serialize()`` and ``unserialize()``
- ``simple_array``: Type that maps a SQL CLOB to a PHP array using
``implode()`` and ``explode()``, with a comma as delimiter. *IMPORTANT*
Only use this type if you are sure that your values cannot contain a ",".
- ``json_array``: Type that maps a SQL CLOB to a PHP array using
``json_encode()`` and ``json_decode()``
- ``float``: Type that maps a SQL Float (Double Precision) to a
PHP double. *IMPORTANT*: Works only with locale settings that use
decimal points as separator.
- ``guid``: Type that maps a database GUID/UUID to a PHP string. Defaults to
varchar but uses a specific type if the platform supports it.
- ``blob``: Type that maps a SQL BLOB to a PHP resource stream
A cookbook article shows how to define :doc:`your own custom mapping types
<../cookbook/custom-mapping-types>`.
.. note::
DateTime and Object types are compared by reference, not by value. Doctrine
updates this values if the reference changes and therefore behaves as if
these objects are immutable value objects.
.. warning::
All Date types assume that you are exclusively using the default timezone
set by `date_default_timezone_set() <http://docs.php.net/manual/en/function.date-default-timezone-set.php>`_
or by the php.ini configuration ``date.timezone``. Working with
different timezones will cause troubles and unexpected behavior.
If you need specific timezone handling you have to handle this
in your domain, converting all the values back and forth from UTC.
There is also a :doc:`cookbook entry <../cookbook/working-with-datetime>`
on working with datetimes that gives hints for implementing
multi timezone applications.
Identifiers / Primary Keys
--------------------------
Every entity class requires an identifier/primary key. You can select
the field that serves as the identifier with the ``@Id``
annotation.
.. configuration-block::
.. code-block:: php
<?php
class Message
{
/**
* @Id @Column(type="integer")
* @GeneratedValue
*/
private $id;
//...
}
.. code-block:: xml
<doctrine-mapping>
<entity name="Message">
<id name="id" type="integer">
<generator strategy="AUTO" />
</id>
<!-- -->
</entity>
</doctrine-mapping>
.. code-block:: yaml
Message:
type: entity
id:
id:
type: integer
generator:
strategy: AUTO
fields:
# fields here
In most cases using the automatic generator strategy (``@GeneratedValue``) is
what you want. It defaults to the identifier generation mechanism your current
database vendor prefers: AUTO_INCREMENT with MySQL, SERIAL with PostgreSQL,
Sequences with Oracle and so on.
Identifier Generation Strategies
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The previous example showed how to use the default identifier
generation strategy without knowing the underlying database with
the AUTO-detection strategy. It is also possible to specify the
identifier generation strategy more explicitly, which allows to
make use of some additional features.
Here is the list of possible generation strategies:
- ``AUTO`` (default): Tells Doctrine to pick the strategy that is
preferred by the used database platform. The preferred strategies
are IDENTITY for MySQL, SQLite and MsSQL and SEQUENCE for Oracle
and PostgreSQL. This strategy provides full portability.
- ``SEQUENCE``: Tells Doctrine to use a database sequence for ID
generation. This strategy does currently not provide full
portability. Sequences are supported by Oracle and PostgreSql.
- ``IDENTITY``: Tells Doctrine to use special identity columns in
the database that generate a value on insertion of a row. This
strategy does currently not provide full portability and is
supported by the following platforms: MySQL/SQLite
(AUTO\_INCREMENT), MSSQL (IDENTITY) and PostgreSQL (SERIAL).
- ``TABLE``: Tells Doctrine to use a separate table for ID
generation. This strategy provides full portability.
***This strategy is not yet implemented!***
- ``NONE``: Tells Doctrine that the identifiers are assigned (and
thus generated) by your code. The assignment must take place before
a new entity is passed to ``EntityManager#persist``. NONE is the
same as leaving off the @GeneratedValue entirely.
Sequence Generator
^^^^^^^^^^^^^^^^^^
The Sequence Generator can currently be used in conjunction with
Oracle or Postgres and allows some additional configuration options
besides specifying the sequence's name:
.. configuration-block::
.. code-block:: php
<?php
class User
{
/**
* @Id
* @GeneratedValue(strategy="SEQUENCE")
* @SequenceGenerator(sequenceName="tablename_seq", initialValue=1, allocationSize=100)
*/
protected $id = null;
}
.. code-block:: xml
<doctrine-mapping>
<entity name="User">
<id name="id" type="integer">
<generator strategy="SEQUENCE" />
<sequence-generator sequence-name="tablename_seq" allocation-size="100" initial-value="1" />
</id>
</entity>
</doctrine-mapping>
.. code-block:: yaml
MyPersistentClass:
type: entity
id:
id:
type: integer
generator:
strategy: SEQUENCE
sequenceGenerator:
sequenceName: tablename_seq
allocationSize: 100
initialValue: 1
The initial value specifies at which value the sequence should
start.
The allocationSize is a powerful feature to optimize INSERT
performance of Doctrine. The allocationSize specifies by how much
values the sequence is incremented whenever the next value is
retrieved. If this is larger than 1 (one) Doctrine can generate
identifier values for the allocationSizes amount of entities. In
the above example with ``allocationSize=100`` Doctrine 2 would only
need to access the sequence once to generate the identifiers for
100 new entities.
*The default allocationSize for a @SequenceGenerator is currently 10.*
.. 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.
.. 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
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
----------------------
Sometimes it is necessary to quote a column or table name because of reserved
word conflicts. Doctrine does not quote identifiers automatically, because it
leads to more problems then it would solve. Quoting tables and column names
needs to be done explicitly using ticks in the definition.
.. code-block:: php
<?php
/** @Column(name="`number`", type="integer") */
private $number;
Doctrine will then quote this column name in all SQL statements
according to the used database platform.
.. warning::
Identifier Quoting does not work for join column names or discriminator
column names unless you are using a custom ``QuoteStrategy``.
.. _reference-basic-mapping-custom-mapping-types:
.. versionadded: 2.3
For more control over column quoting the ``Doctrine\ORM\Mapping\QuoteStrategy`` interface
was introduced in 2.3. It is invoked for every column, table, alias and other
SQL names. You can implement the QuoteStrategy and set it by calling
``Doctrine\ORM\Configuration#setQuoteStrategy()``.
.. versionadded: 2.4
The ANSI Quote Strategy was added, which assumes quoting is not necessary for any SQL name.
You can use it with the following code:
.. code-block:: php
<?php
use Doctrine\ORM\Mapping\AnsiQuoteStrategy;
$configuration->setQuoteStrategy(new AnsiQuoteStrategy());