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 create PHP classes that can be saved in the database with Doctrine
- How to configure the mapping between columns on tables and properties on - How to configure the mapping between columns on tables and properties on
entities. entities.
- What Doctrine Mapping types are
- Defining primary keys and how identifiers are generated by Doctrine - 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 Mapping of associations will be covered in the next chapter on
:doc:`Association Mapping <association-mapping>`. :doc:`Association Mapping <association-mapping>`.
@ -41,7 +42,10 @@ example Entity:
Because Doctrine is a generic library, it can only know about your Because Doctrine is a generic library, it can only know about your
entities when you are describing their existance and structure using 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 Doctrine provides several different ways for specifying object-relational
mapping metadata: mapping metadata:
@ -207,10 +211,11 @@ list:
Doctrine Mapping Types Doctrine Mapping Types
---------------------- ----------------------
A Doctrine Mapping Type defines the conversion the type of a PHP variable and The ``type`` option used in the ``@Column`` accepts any of the existing
an SQL type. All Mapping Types that ship with Doctrine are fully portable Doctrine types or even your own custom types. A Doctrine type defines
between the supported database systems. You can add your own custom mapping the conversion between PHP and SQL types, indepedant from the database vendor
types to add more conversions. 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 As an example the Doctrine Mapping Type ``string`` defines the
mapping from a PHP string to a SQL VARCHAR (or VARCHAR2 etc. 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 - ``smallint``: Type that maps a database SMALLINT to a PHP
integer. integer.
- ``bigint``: Type that maps a database BIGINT to a PHP string. - ``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. - ``decimal``: Type that maps a SQL DECIMAL to a PHP string.
- ``date``: Type that maps a SQL DATETIME to a PHP DateTime - ``date``: Type that maps a SQL DATETIME to a PHP DateTime
object. object.
@ -248,10 +253,14 @@ built-in mapping types:
varchar but uses a specific type if the platform supports it. varchar but uses a specific type if the platform supports it.
- ``blob``: Type that maps a SQL BLOB to a PHP resource stream - ``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:: .. note::
DateTime and Object types are compared by reference, not by value. Doctrine updates this values DateTime and Object types are compared by reference, not by value. Doctrine
if the reference changes and therefore behaves as if these objects are immutable value objects. updates this values if the reference changes and therefore behaves as if
these objects are immutable value objects.
.. warning:: .. warning::
@ -266,22 +275,24 @@ built-in mapping types:
on working with datetimes that gives hints for implementing on working with datetimes that gives hints for implementing
multi timezone applications. multi timezone applications.
Identifiers / Primary Keys 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`` the field that serves as the identifier with the ``@Id``
annotation: annotation.
.. configuration-block:: .. configuration-block::
.. code-block:: php .. code-block:: php
<?php <?php
class MyPersistentClass class Message
{ {
/** @Id @Column(type="integer") */ /**
* @Id @Column(type="integer")
* @GeneratedValue
*/
private $id; private $id;
//... //...
} }
@ -289,58 +300,17 @@ annotation:
.. code-block:: xml .. code-block:: xml
<doctrine-mapping> <doctrine-mapping>
<entity name="MyPersistentClass"> <entity name="Message">
<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">
<id name="id" type="integer"> <id name="id" type="integer">
<generator strategy="AUTO" /> <generator strategy="AUTO" />
</id> </id>
<field name="name" length="50" /> <!-- -->
</entity> </entity>
</doctrine-mapping> </doctrine-mapping>
.. code-block:: yaml .. code-block:: yaml
MyPersistentClass: Message:
type: entity type: entity
id: id:
id: id:
@ -348,15 +318,12 @@ using database sequences or auto incrementing numbers.
generator: generator:
strategy: AUTO strategy: AUTO
fields: fields:
name: # fields here
length: 50
This tells Doctrine to automatically generate a value for the In most cases using the automatic generator strategy (``@GeneratedValue``) is
identifier. How this value is generated is specified by the what you want. It defaults to the identifier generation mechanism your current
``strategy`` attribute, which is optional and defaults to 'AUTO'. A database vendor prefers: AUTO_INCREMENT with MySQL, SERIAL with PostgreSQL,
value of ``AUTO`` tells Doctrine to use the generation strategy Sequences with Oracle and so on.
that is preferred by the currently used database platform. See
below for details.
Identifier Generation Strategies Identifier Generation Strategies
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -524,112 +491,3 @@ You can use it with the following code:
use Doctrine\ORM\Mapping\AnsiQuoteStrategy; use Doctrine\ORM\Mapping\AnsiQuoteStrategy;
$configuration->setQuoteStrategy(new 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.