Doctrineに様々なデータ型のカラムをimportしてみる

# 動機・背景

既存のMySQLデータベースから、Doctrineを使ってEntityクラスを生成する機会がありましたが、上手くインポートできなかったり、期待とは異なるデータ型になる事があったため、調査の目的で様々なデータ型のカラムを持つテーブルをインポートしてみました。


# 環境

- php 7.0.2
- symfony 3.0.1
- doctrine/orm 2.5.3
- MySQL 5.5


# Importしたテーブル

```sql
CREATE TABLE `test` (
    `id` int(11) NOT NULL,
    `test_int` int(11) DEFAULT NULL,
    `test_tinyint` tinyint(4) DEFAULT NULL,
    `test_tinyint_unsigned` tinyint(3) unsigned DEFAULT NULL,
    `test_flg` tinyint(1) DEFAULT NULL,
    `test_smallint` smallint(6) DEFAULT NULL,
    `test_mediumint` mediumint(9) DEFAULT NULL,
    `test_bigint` bigint(20) DEFAULT NULL,
    `test_float` float DEFAULT NULL,
    `test_double` double DEFAULT NULL,
    `test_double43` double(4, 3) DEFAULT NULL,
    `test_double_unsigned` double unsigned DEFAULT NULL,
    `test_date` date DEFAULT NULL,
    `test_datetime` datetime DEFAULT NULL,
    `test_timestamp` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
    `test_time` time DEFAULT NULL,
    `test_year` year(4) DEFAULT NULL,
    `test_char` char(10) DEFAULT NULL,
    `test_varchar` varchar(10) DEFAULT NULL,
    `test_binary` binary(10) DEFAULT NULL,
    `test_varbinary` varbinary(10) DEFAULT NULL,
    `test_tinyblob` tinyblob,
    `test_blob` blob,
    `test_mediumblob` mediumblob,
    `test_longblob` longblob,
    `test_tinytext` tinytext,
    `test_text` text,
    `test_mediumtext` mediumtext,
    `test_longtext` longtext,
    `test_set`
    set('abc', 'def', 'ghi') DEFAULT NULL,
        PRIMARY KEY (`id`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8
```


# 既存のテーブルからEntityを作成する

**コマンド**

```
php bin/console doctrine:mapping:convert annotation ./src/AppBundle/Entity --from-database --filter='Test'
```

**生成されたEntityクラス**

```php
<?php
use Doctrine\ORM\Mapping as ORM;

/**
 * Test
 *
 * @ORM\Table(name="test")
 * @ORM\Entity
 */
class Test
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var integer
     *
     * @ORM\Column(name="test_int", type="integer", nullable=true)
     */
    private $testInt;

    /**
     * @var boolean
     *
     * @ORM\Column(name="test_tinyint", type="boolean", nullable=true)
     */
    private $testTinyint;

    /**
     * @var boolean
     *
     * @ORM\Column(name="test_tinyint_unsigned", type="boolean", nullable=true)
     */
    private $testTinyintUnsigned;

    /**
     * @var boolean
     *
     * @ORM\Column(name="test_flg", type="boolean", nullable=true)
     */
    private $testFlg;

    /**
     * @var integer
     *
     * @ORM\Column(name="test_smallint", type="smallint", nullable=true)
     */
    private $testSmallint;

    /**
     * @var integer
     *
     * @ORM\Column(name="test_mediumint", type="integer", nullable=true)
     */
    private $testMediumint;

    /**
     * @var integer
     *
     * @ORM\Column(name="test_bigint", type="bigint", nullable=true)
     */
    private $testBigint;

    /**
     * @var float
     *
     * @ORM\Column(name="test_float", type="float", precision=10, scale=0, nullable=true)
     */
    private $testFloat;

    /**
     * @var float
     *
     * @ORM\Column(name="test_double", type="float", precision=10, scale=0, nullable=true)
     */
    private $testDouble;

    /**
     * @var float
     *
     * @ORM\Column(name="test_double43", type="float", precision=4, scale=3, nullable=true)
     */
    private $testDouble43;

    /**
     * @var float
     *
     * @ORM\Column(name="test_double_unsigned", type="float", precision=10, scale=0, nullable=true)
     */
    private $testDoubleUnsigned;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="test_date", type="date", nullable=true)
     */
    private $testDate;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="test_datetime", type="datetime", nullable=true)
     */
    private $testDatetime;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="test_timestamp", type="datetime", nullable=false)
     */
    private $testTimestamp = '0000-00-00 00:00:00';

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="test_time", type="time", nullable=true)
     */
    private $testTime;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="test_year", type="date", nullable=true)
     */
    private $testYear;

    /**
     * @var string
     *
     * @ORM\Column(name="test_char", type="string", length=10, nullable=true)
     */
    private $testChar;

    /**
     * @var string
     *
     * @ORM\Column(name="test_varchar", type="string", length=10, nullable=true)
     */
    private $testVarchar;

    /**
     * @var binary
     *
     * @ORM\Column(name="test_binary", type="binary", nullable=true)
     */
    private $testBinary;

    /**
     * @var binary
     *
     * @ORM\Column(name="test_varbinary", type="binary", nullable=true)
     */
    private $testVarbinary;

    /**
     * @var string
     *
     * @ORM\Column(name="test_tinyblob", type="blob", length=255, nullable=true)
     */
    private $testTinyblob;

    /**
     * @var string
     *
     * @ORM\Column(name="test_blob", type="blob", length=65535, nullable=true)
     */
    private $testBlob;

    /**
     * @var string
     *
     * @ORM\Column(name="test_mediumblob", type="blob", length=16777215, nullable=true)
     */
    private $testMediumblob;

    /**
     * @var string
     *
     * @ORM\Column(name="test_longblob", type="blob", nullable=true)
     */
    private $testLongblob;

    /**
     * @var string
     *
     * @ORM\Column(name="test_tinytext", type="text", length=255, nullable=true)
     */
    private $testTinytext;

    /**
     * @var string
     *
     * @ORM\Column(name="test_text", type="text", length=65535, nullable=true)
     */
    private $testText;

    /**
     * @var string
     *
     * @ORM\Column(name="test_mediumtext", type="text", length=16777215, nullable=true)
     */
    private $testMediumtext;

    /**
     * @var string
     *
     * @ORM\Column(name="test_longtext", type="text", nullable=true)
     */
    private $testLongtext;

    /**
     * @var array
     *
     * @ORM\Column(name="test_set", type="simple_array", nullable=true)
     */
    private $testSet;
}
```


# 分かったこと

- `tinyint`のカラムはデータ長に関わらず`type="boolean"`になる。
- `Date`, `Time`, `Datetime`, `Timestamp`はすべて`DateTime`になる。
- `CURRENT_TIMESTAMP`が設定されているカラムは、デフォルト値に`String`で`'CURRENT_TIMESTAMP'`が代入される。
- MySQLの場合、コマンドを使ってEntityを自動生成すると`strategy=IDENTITY`になる。
- 複合主キーのテーブルは`strategy=NONE`になる。
- プライマリキーがなければエラーになる。


## Strategyとは何か

項目 | 内容
:--- | :---
AUTO | データベースの種類に応じて、IDENTITY or SEQUENCEを自動的に選択。
SEQUENCE | 自動連番。Oracle, PostgreSQL向け。
IDENTITY | 自動連番。MySQL, SQLite (AUTO_INCREMENT), MSSQL(IDENTITY), PostgreSQL (SERIAL)。
NONE | 上記のような設定をDoctrineが自動的にできなかった場合にNONEになる。重複は自分で何とかする必要がある。

**参照**

http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/basic-mapping.html