Стоит ли использовать типы данных ENUM & SET в БД MySQL?

Здравствуйте, в недавнее время я занялся разработкой одного проекта (личного), где нужно создать функционал управления пользователями, и всё что с ними связано. Проект делается на Symfony 2 со всеми его стандартными компонентами (включая DoctrineORM). У каждого пользователя должен быть свой профиль, который он может редактировать. С помощью DoctrineORM в SF2 я создал две сущности между которыми установлена связь 1:1 - Account и Profile. В account хранятся все данные необходимые для аутентификации и авторизации, а в profile как раз и будет хранится вся информация, с которой пользователь будет манипулировать. Например, в сущности profile надо сохранить пол пользователя и его семейное положение, и ещё к примеру его знание иностранных языков. В первом случае на первый взгляд не плохо бы подошёл тип данных ENUM, где нужно выбрать среди всех вариантов только один, а во втором тип данных SET, где можно выбрать несколько вариантом, так как пользователь может знать несколько иностранных языков - это логично, но...
Разумеется я задался вопросом, а будет ли это решением правильным?! Например в самой DoctrineORM нет такого встроенного типа, и его нужно самому делать Cookbook - Mysql Enums. Не в этом даже беда, а в том, что его использование считается плохой практикой, об этом даже пишется "в самой ссылке". Я очень много прочёл статей, где знающее люди перечисляют недостатки и все проблемы, с которыми придётся столкнутся. А про тип данных SET я вообще молчу, ибо не нашёл дельной информации, поэтому надеюсь услышать от вас разумных ответов. Так вот, стоит ли их использовать в моём случае? Или может быть есть какой то альтернативный вариант, хотелось бы услышать как это реализовать на самой DoctrineORM, например сохранять как то через типы данных (array, simple array, json_array, object), а затем извлекая фильтровать???
  • Вопрос задан
  • 4393 просмотра
Пригласить эксперта
Ответы на вопрос 2
lexxpavlov
@lexxpavlov
Программист, преподаватель
Set я не использовал, а вот Enum использую успешно. Используется он очень просто. Причём я создаю отдельный класс для каждого enum-а в проекте, что даёт некоторые преимущества, например, простой доступ к массиву допустимых значений.

Я создаю в проекте папку DBAL, и там создаю такие классы:
<?php

namespace AppBundle\DBAL;

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

abstract class EnumType extends Type
{
    protected $name;

    public static $VALUES = array();

    public static function getValues()
    {
        return array_combine(static::$VALUES, static::$VALUES);
    }

    public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
    {
        $values = array_map(function($val) { return "'".$val."'"; }, static::$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, static::$VALUES)) {
            throw new \InvalidArgumentException("Invalid value '$value' for enum '$this->name'.");
        }
        return $value;
    }

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

Этот класс является базовым для кастомных классов Enum-ов, вот пример одного такого:
<?php

namespace AppBundle\DBAL;

class GenderType extends EnumType
{
    protected $name = 'gender';
    public static $VALUES = array('male', 'female');
}

Теперь нужно научить доктрину их использовать:
doctrine:
    dbal:
        # ...
        types:
            gender: AppBundle\DBAL\GenderType
        mapping_types:
            enum: string
            gender: gender

Теперь можно использовать в описаниях сущностей:
<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;

/**
 * @ORM\Entity
 */
class Person
{
    // other fields

    /**
     * @var string
     *
     * @ORM\Column(type="gender")
     */
    protected $gender;

    // setters & getters
}

И в любом месте кода можно получить список доступных значений:
foreach (GenderType::$VALUES as $gender) {
    echo $gender;
}


Насчёт типа SET - думаю, нужно написать подобный класс, умеющий переводить из значения php в формат sql, который корректно сохранит в поле. Но по мне, для языков лучше использовать simple_array, и не мучаться с ними.
Ответ написан
Quber
@Quber
PHP Team lead
Пользуюсь этим решением, очень отличное https://github.com/fre5h/DoctrineEnumBundle
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы