types.rst 5.43 KB
Newer Older
1 2 3 4 5 6 7
Types
=====

Besides abstraction of SQL one needs a translation between database
and PHP data-types to implement database independent applications.
Doctrine 2 has a type translation system baked in that supports the
conversion from and to PHP values from any database platform,
8
as well as platform independent SQL generation for any Doctrine
9 10 11
Type.

Using the ORM you generally don't need to know about the Type
Andreas Fischer's avatar
Andreas Fischer committed
12
system. This is unless you want to make use of database vendor
13 14 15 16 17 18 19 20 21 22
specific database types not included in Doctrine 2. The following
PHP Types are abstracted across all the supported database
vendors:


-  Integer
-  SmallInt
-  BigInt
-  String (string with maximum length, for example 255)
-  Text (strings without maximum length)
Steve Müller's avatar
Steve Müller committed
23
-  Binary (binary string with maximum length, for example 255)
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
-  Decimal (restricted floats, *NOTE* Only works with a setlocale()
   configuration that uses decimal points!)
-  Boolean
-  DateTime
-  Date (DateTime instance where only Y-m-d get persisted)
-  Time (DateTime instance where only H:i:s get persisted)
-  Array (serialized into a text field for all vendors by default)
-  Object (serialized into a text field for all vendors by default)
-  Float (*NOTE* Only works with a setlocale() configuration that
   uses decimal points!)

Types are flyweights. This means there is only ever one instance of
a type and it is not allowed to contain any state. Creation of type
instances is abstracted through a static get method
``Doctrine\DBAL\Types\Type::getType()``.

Benjamin Eberlei's avatar
Benjamin Eberlei committed
40
.. note::
41

42
    See the `Known Vendor Issue <./known-vendor-issues>`_ section
43 44 45
    for details about the different handling of microseconds and
    timezones across all the different vendors.

46 47 48 49 50 51 52 53
.. 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``.

    If you need specific timezone handling you have to handle this
    in your domain, converting all the values back and forth from UTC.
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74

Detection of Database Types
---------------------------

When calling table inspection methods on your connections
``SchemaManager`` instance the retrieved database column types are
translated into Doctrine mapping types. Translation is necessary to
allow database abstraction and metadata comparisons for example for
Migrations or the ORM SchemaTool.

Each database platform has a default mapping of database types to
Doctrine types. You can inspect this mapping for platform of your
choice looking at the
``AbstractPlatform::initializeDoctrineTypeMappings()``
implementation.

If you want to change how Doctrine maps a database type to a
``Doctrine\DBAL\Types\Type`` instance you can use the
``AbstractPlatform::registerDoctrineTypeMapping($dbType, $doctrineType)``
method to add new database types or overwrite existing ones.

Benjamin Eberlei's avatar
Benjamin Eberlei committed
75
.. note::
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103

    You can only map a database type to exactly one Doctrine type.
    Database vendors that allow to define custom types like PostgreSql
    can help to overcome this issue.


Custom Mapping Types
--------------------

Just redefining how database types are mapped to all the existing
Doctrine types is not at all that useful. You can define your own
Doctrine Mapping Types by extending ``Doctrine\DBAL\Types\Type``.
You are required to implement 4 different methods to get this
working.

See this example of how to implement a Money object in PostgreSQL.
For this we create the type in PostgreSQL as:

.. code-block:: sql

    CREATE DOMAIN MyMoney AS DECIMAL(18,3);

Now we implement our ``Doctrine\DBAL\Types\Type`` instance:

::

    <?php
    namespace My\Project\Types;
104

105 106
    use Doctrine\DBAL\Types\Type;
    use Doctrine\DBAL\Platforms\AbstractPlatform;
107

108 109 110 111 112 113
    /**
     * My custom datatype.
     */
    class MoneyType extends Type
    {
        const MONEY = 'money'; // modify to match your type name
114

115 116 117 118
        public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
        {
            return 'MyMoney';
        }
119

120 121 122 123
        public function convertToPHPValue($value, AbstractPlatform $platform)
        {
            return new Money($value);
        }
124

125 126 127 128
        public function convertToDatabaseValue($value, AbstractPlatform $platform)
        {
            return $value->toDecimal();
        }
129

130 131 132 133 134 135
        public function getName()
        {
            return self::MONEY;
        }
    }

136
The job of Doctrine-DBAL is to transform your type into SQL declaration. You can modify the SQL declaration Doctrine will produce. At first, you must to enable this feature by overriding the canRequireSQLConversion method:
137 138 139 140 141 142 143 144 145

::

    <?php
    public function canRequireSQLConversion()
    {
        return true;
    }

146
Then you override the methods convertToPhpValueSQL and convertToDatabaseValueSQL :
147 148 149 150 151 152

::

    <?php
    public function convertToPHPValueSQL($sqlExpr, $platform)
    {
Julien Fastré's avatar
Julien Fastré committed
153
        return 'MyMoneyFunction(\''.$sqlExpr.'\') ';
154
    }
155

156 157 158 159 160 161
    public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform)
    {
        return 'MyFunction('.$sqlExpr.')';
    }


162 163 164 165 166 167 168 169 170 171 172 173 174 175
Now we have to register this type with the Doctrine Type system and
hook it into the database platform:

::

    <?php
    Type::addType('money', 'My\Project\Types\MoneyType');
    $conn->getDatabasePlatform()->registerDoctrineTypeMapping('MyMoney', 'money');

This would allow to use a money type in the ORM for example and
have Doctrine automatically convert it back and forth to the
database.