This file is indexed.

/usr/share/doc/php-doctrine-orm/html/_sources/cookbook/mysql-enums.txt is in doctrine-orm-doc 2.4.6-1+deb8u1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
Mysql Enums
===========

The type system of Doctrine 2 consists of flyweights, which means there is only
one instance of any given type. Additionally types do not contain state. Both
assumptions make it rather complicated to work with the Enum Type of MySQL that
is used quite a lot by developers.

When using Enums with a non-tweaked Doctrine 2 application you will get
errors from the Schema-Tool commands due to the unknown database type "enum".
By default Doctrine does not map the MySQL enum type to a Doctrine type.
This is because Enums contain state (their allowed values) and Doctrine
types don't.

This cookbook entry shows two possible solutions to work with MySQL enums.
But first a word of warning. The MySQL Enum type has considerable downsides:

-  Adding new values requires to rebuild the whole table, which can take hours
   depending on the size.
-  Enums are ordered in the way the values are specified, not in their "natural" order.
-  Enums validation mechanism for allowed values is not necessarily good,
   specifying invalid values leads to an empty enum for the default MySQL error
   settings. You can easily replicate the "allow only some values" requirement
   in your Doctrine entities.

Solution 1: Mapping to Varchars
-------------------------------

You can map ENUMs to varchars. You can register MySQL ENUMs to map to Doctrine
varchars. This way Doctrine always resolves ENUMs to Doctrine varchars. It
will even detect this match correctly when using SchemaTool update commands.

.. code-block:: php

    <?php
    $conn = $em->getConnection();
    $conn->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');

In this case you have to ensure that each varchar field that is an enum in the
database only gets passed the allowed values. You can easily enforce this in your
entities:

.. code-block:: php

    <?php
    /** @Entity */
    class Article
    {
        const STATUS_VISIBLE = 'visible';
        const STATUS_INVISIBLE = 'invisible';

        /** @Column(type="string") */
        private $status;

        public function setStatus($status)
        {
            if (!in_array($status, array(self::STATUS_VISIBLE, self::STATUS_INVISIBLE))) {
                throw new \InvalidArgumentException("Invalid status");
            }
            $this->status = $status;
        }
    }

If you want to actively create enums through the Doctrine Schema-Tool by using
the **columnDefinition** attribute.

.. code-block:: php

    <?php
    /** @Entity */
    class Article
    {
        /** @Column(type="string", columnDefinition="ENUM('visible', 'invisible')") */
        private $status;
    }

In this case however Schema-Tool update will have a hard time not to request changes for this column on each call.

Solution 2: Defining a Type
---------------------------

You can make a stateless ENUM type by creating a type class for each unique set of ENUM values.
For example for the previous enum type:

.. code-block:: php

    <?php
    namespace MyProject\DBAL;

    use Doctrine\DBAL\Types\Type;
    use Doctrine\DBAL\Platforms\AbstractPlatform;

    class EnumVisibilityType extends Type
    {
        const ENUM_VISIBILITY = 'enumvisibility';
        const STATUS_VISIBLE = 'visible';
        const STATUS_INVISIBLE = 'invisible';

        public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
        {
            return "ENUM('visible', 'invisible') COMMENT '(DC2Type:enumvisibility)'";
        }

        public function convertToPHPValue($value, AbstractPlatform $platform)
        {
            return $value;
        }

        public function convertToDatabaseValue($value, AbstractPlatform $platform)
        {
            if (!in_array($value, array(self::STATUS_VISIBLE, self::STATUS_INVISIBLE))) {
                throw new \InvalidArgumentException("Invalid status");
            }
            return $value;
        }

        public function getName()
        {
            return self::ENUM_VISIBILITY;
        }
    }

You can register this type with ``Type::addType('enumvisibility', 'MyProject\DBAL\EnumVisibilityType');``.
Then in your entity you can just use this type:

.. code-block:: php

    <?php
    /** @Entity */
    class Article
    {
        /** @Column(type="enumvisibility") */
        private $status;
    }

You can generalize this approach easily to create a base class for enums:

.. code-block:: php

    <?php
    namespace MyProject\DBAL;

    use Doctrine\DBAL\Types\Type;
    use Doctrine\DBAL\Platforms\AbstractPlatform;

    abstract class EnumType extends Type
    {
        protected $name;
        protected $values = array();

        public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
        {
            $values = array_map(function($val) { return "'".$val."'"; }, $this->values);

            return "ENUM(".implode(", ", $values).") COMMENT '(DC2Type:".$this->name.")'";
        }

        public function convertToPHPValue($value, AbstractPlatform $platform)
        {
            return $value;
        }

        public function convertToDatabaseValue($value, AbstractPlatform $platform)
        {
            if (!in_array($value, $this->values)) {
                throw new \InvalidArgumentException("Invalid '".$this->name."' value.");
            }
            return $value;
        }

        public function getName()
        {
            return $this->name;
        }
    }

With this base class you can define an enum as easily as:

.. code-block:: php

    <?php
    namespace MyProject\DBAL;

    class EnumVisibilityType extends EnumType
    {
        protected $name = 'enumvisibility';
        protected $values = array('visible', 'invisible');
    }