1
0
mirror of synced 2025-01-18 22:41:43 +03:00

Move Custom Mapping Types into cookbook, restructure the chapter more.

This commit is contained in:
Benjamin Eberlei 2013-09-10 22:08:54 +02:00
parent caf6ba65e8
commit 546c817f64
2 changed files with 131 additions and 176 deletions

View File

@ -0,0 +1,97 @@
Custom Mapping Types
====================
Doctrine allows you to create new mapping types. This can come in
handy when you're missing a specific mapping type or when you want
to replace the existing implementation of a mapping type.
In order to create a new mapping type you need to subclass
``Doctrine\DBAL\Types\Type`` and implement/override the methods as
you wish. Here is an example skeleton of such a custom type class:
.. code-block:: php
<?php
namespace My\Project\Types;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
/**
* My custom datatype.
*/
class MyType extends Type
{
const MYTYPE = 'mytype'; // modify to match your type name
public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
// return the SQL used to create your column type. To create a portable column type, use the $platform.
}
public function convertToPHPValue($value, AbstractPlatform $platform)
{
// This is executed when the value is read from the database. Make your conversions here, optionally using the $platform.
}
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
// This is executed when the value is written to the database. Make your conversions here, optionally using the $platform.
}
public function getName()
{
return self::MYTYPE; // modify to match your constant name
}
}
The following assumptions are applied to mapping types by the ORM:
- If the value of the field is *NULL* the method
``convertToDatabaseValue()`` is not called.
- The ``UnitOfWork`` never passes values to the database convert
method that did not change in the request.
When you have implemented the type you still need to let Doctrine
know about it. This can be achieved through the
``Doctrine\DBAL\Types\Type#addType($name, $className)``
method. See the following example:
.. code-block:: php
<?php
// in bootstrapping code
// ...
use Doctrine\DBAL\Types\Type;
// ...
// Register my type
Type::addType('mytype', 'My\Project\Types\MyType');
To convert the underlying database type of your
new "mytype" directly into an instance of ``MyType`` when performing
schema operations, the type has to be registered with the database
platform as well:
.. code-block:: php
<?php
$conn = $em->getConnection();
$conn->getDatabasePlatform()->registerDoctrineTypeMapping('db_mytype', 'mytype');
When registering the custom types in the configuration you specify a unique
name for the mapping type and map that to the corresponding fully qualified
class name. Now the new type can be used when mapping columns:
.. code-block:: php
<?php
class MyPersistentClass
{
/** @Column(type="mytype") */
private $field;
}

View File

@ -7,8 +7,9 @@ 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
- What Doctrine types are
- How quoting of reserved symbols works in Doctrine
Mapping of associations will be covered in the next chapter on
:doc:`Association Mapping <association-mapping>`.
@ -41,7 +42,10 @@ example Entity:
Because Doctrine is a generic library, it can only know about your
entities when you are describing their existance and structure using
Metadata Configuration.
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:
@ -207,10 +211,11 @@ list:
Doctrine Mapping Types
----------------------
A Doctrine Mapping Type defines the conversion the type of a PHP variable and
an SQL type. All Mapping Types that ship with Doctrine are fully portable
between the supported database systems. You can add your own custom mapping
types to add more conversions.
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.
@ -222,7 +227,7 @@ built-in mapping types:
- ``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 to a PHP boolean.
- ``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.
@ -248,10 +253,14 @@ built-in mapping types:
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.
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::
@ -266,22 +275,24 @@ built-in mapping types:
on working with datetimes that gives hints for implementing
multi timezone applications.
Identifiers / Primary Keys
--------------------------
Every entity class needs an identifier/primary key. You designate
Every entity class requires an identifier/primary key. You can select
the field that serves as the identifier with the ``@Id``
annotation:
annotation.
.. configuration-block::
.. code-block:: php
<?php
class MyPersistentClass
class Message
{
/** @Id @Column(type="integer") */
/**
* @Id @Column(type="integer")
* @GeneratedValue
*/
private $id;
//...
}
@ -289,58 +300,17 @@ annotation:
.. code-block:: xml
<doctrine-mapping>
<entity name="MyPersistentClass">
<id name="id" type="integer" />
<field name="name" length="50" />
</entity>
</doctrine-mapping>
.. code-block:: yaml
MyPersistentClass:
type: entity
id:
id:
type: integer
fields:
name:
length: 50
This definition is missing an ID generation strategy, which means that your code needs to assign
the identifier manually before passing a new entity to
``EntityManager#persist($entity)``.
Doctrine can alternatively generate identifiers for entities using generation strategies,
using database sequences or auto incrementing numbers.
.. configuration-block::
.. code-block:: php
<?php
class MyPersistentClass
{
/**
* @Id @Column(type="integer")
* @GeneratedValue
*/
private $id;
}
.. code-block:: xml
<doctrine-mapping>
<entity name="MyPersistentClass">
<entity name="Message">
<id name="id" type="integer">
<generator strategy="AUTO" />
</id>
<field name="name" length="50" />
<!-- -->
</entity>
</doctrine-mapping>
.. code-block:: yaml
MyPersistentClass:
Message:
type: entity
id:
id:
@ -348,15 +318,12 @@ using database sequences or auto incrementing numbers.
generator:
strategy: AUTO
fields:
name:
length: 50
# fields here
This tells Doctrine to automatically generate a value for the
identifier. How this value is generated is specified by the
``strategy`` attribute, which is optional and defaults to 'AUTO'. A
value of ``AUTO`` tells Doctrine to use the generation strategy
that is preferred by the currently used database platform. See
below for details.
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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -524,112 +491,3 @@ You can use it with the following code:
use Doctrine\ORM\Mapping\AnsiQuoteStrategy;
$configuration->setQuoteStrategy(new AnsiQuoteStrategy());
Custom Mapping Types
--------------------
Doctrine allows you to create new mapping types. This can come in
handy when you're missing a specific mapping type or when you want
to replace the existing implementation of a mapping type.
In order to create a new mapping type you need to subclass
``Doctrine\DBAL\Types\Type`` and implement/override the methods as
you wish. Here is an example skeleton of such a custom type class:
.. code-block:: php
<?php
namespace My\Project\Types;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
/**
* My custom datatype.
*/
class MyType extends Type
{
const MYTYPE = 'mytype'; // modify to match your type name
public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
// return the SQL used to create your column type. To create a portable column type, use the $platform.
}
public function convertToPHPValue($value, AbstractPlatform $platform)
{
// This is executed when the value is read from the database. Make your conversions here, optionally using the $platform.
}
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
// This is executed when the value is written to the database. Make your conversions here, optionally using the $platform.
}
public function getName()
{
return self::MYTYPE; // modify to match your constant name
}
}
The following assumptions are applied to mapping types by the ORM:
- If the value of the field is *NULL* the method
``convertToDatabaseValue()`` is not called.
- The ``UnitOfWork`` never passes values to the database convert
method that did not change in the request.
When you have implemented the type you still need to let Doctrine
know about it. This can be achieved through the
``Doctrine\DBAL\Types\Type#addType($name, $className)``
method. See the following example:
.. code-block:: php
<?php
// in bootstrapping code
// ...
use Doctrine\DBAL\Types\Type;
// ...
// Register my type
Type::addType('mytype', 'My\Project\Types\MyType');
To convert the underlying database type of your
new "mytype" directly into an instance of ``MyType`` when performing
schema operations, the type has to be registered with the database
platform as well:
.. code-block:: php
<?php
$conn = $em->getConnection();
$conn->getDatabasePlatform()->registerDoctrineTypeMapping('db_mytype', 'mytype');
When registering the custom types in the configuration you specify a unique
name for the mapping type and map that to the corresponding fully qualified
class name. Now the new type can be used when mapping columns:
.. code-block:: php
<?php
class MyPersistentClass
{
/** @Column(type="mytype") */
private $field;
}
Custom ColumnDefinition
-----------------------
You can define a custom definition for each column using the "columnDefinition"
attribute of ``@Column``. You have to define all the definitions that follow
the name of a column here.
.. note::
Using columnDefinition will break change-detection in SchemaTool.