Как реализовать такую архитектуру на Eloquent laravel?

Недавно я задавал похожий вопрос, но общего характера и больше про RBAC. С тем вопросом относительно разобрался, но другой остался, его и задаю.

Напоминаю вводную.

Есть проект, в нем такие роли - админ, врач, клиент. У клиента своя анкета, у врача своя.
Главный вопрос - если мы врачей и клиентов храним в одной таблице, как лучше хранить их анкеты?

Ведь у врача есть обязательное поле - специализация, например. У клиента его нет, зато есть свое специальное поле, к примеру, это хронические болезни.

Какие варианты вижу я:

1. Все затолкать в одну таблицу (users), нужное подтягивать в зависимости от ситуации. Минус в том, что это бардак в чистом виде - одна таблица двоих еще вместит, а что если там 3-4-5 ролей? Там уже будет хлам.

2. Сделать поле анкета json-ом. Тут тебе и компактность, и нет смешения, но json достаточно недавно в sql для меня, не знаю точно, где его юзать. Да и поиск становится чуть замороченнее.

3. Просто сделать users как базовая модель, а от нее наследовать другие модели - clients и doctors. Тут надо разобраться - как такое сделать и как решать вопрос с авторизацией и как внутри связи устроены? Если этот вариант годный, буду его копать.

4. Увести профили в отдельные таблицы, например, client_profiles и doctor_profiles. Но как тогда корректно прокинуть связь так, чтобы у докторов не было client_profiles (пусть и null'евого), а у клиентов doctor_profiles?..

5. Вышеописанное еще можно сделать так - сделать таблицу profile_attributes, и построчно выставлять соответствие между атрибутом профайла и значением для каждого конкретного юзера - клиента или доктора, не важно.

Короче, понимаю, что варианты есть разные, есть мною не описанные, но хотелось бы понять, какие в этом вопросе best practics?
  • Вопрос задан
  • 1120 просмотров
Пригласить эксперта
Ответы на вопрос 7
Alex_Wells
@Alex_Wells
PHP/TS/Kotlin developer
Подписался на вопрос, но точно скажу что:

1. null'и ненужные поля, они не занимают много места. Будет хлам в таблице, но если в коде разбить одну таблицу на несколько моделек - будет уже лучше и спокойней.
2. json - не очень вариант, только если как-то это абстрагируешь и будешь все из json'а пихать назад в аттрибуты, что бы с этим было удобно работать в коде. Но это тоже так себе вариант.
3. если использовать uuid и морф связи без foreign ключей - да, как вариант
4. не создавать профили кому не нужно и все)
5. нет, хрень. Даже хуже чем второй вариант.

В этом конкретном случае я бы выбирал между вариантами 1 и 3, ибо привязывать примитивку "специализация" к какому-то отдельному энтити - такое себе удовольствие. 1-ый не такой плохой как кажется, а с третим теоретически сложнее работать, хотя это неплохая идея.
Ответ написан
Комментировать
@jazzus
Я за 4. Связь hasOne и поле user_id в каждой таблице. При регистрации юзер выбирает, что он врач и ты создаешь запись в doctor_profile. Подтягивать через with. Удобно тем что просто и наглядно)
Ответ написан
Комментировать
@gian_tiaga
4 вариант из предложенных больше всех напрашивается.
Но есть ещё 6 вариант более интересный, но более сложный, создать 2 таблицы
Таблица attributes
id
name
role_id

Таблица attribute_values
attribute_id
user_id
value
Ответ написан
@larfeus
Таблицы:

# users
- id
- login
- password
- role

# doctors
- id
- user_id
- specialism

# pacients
- id
- user_id
- complaint

Модель пользователя:

class User extends Eloquent
{
    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
     */
    public function profile()
    {
        if ($this->role == 'doctor') {
            return $this->hasOne('App\Doctor', 'user_id', 'id')
                ->withDefault();
        }
        
        if ($this->role == 'pacient') {
            return $this->hasOne('App\Pacient', 'user_id', 'id')
                ->withDefault();
        }
        
        return null;
    }
}
Ответ написан
solotony
@solotony
покоряю пик Балмера
я склоняюсь к варианту 4.

а как организовать связь варианты:

1)
user.doc_profile_id -> doc_profile.id
user.pat_profile_id -> pat_profile.id

2)

user.type=doc user.profile_id -> doc_profile.id
user.type=pat user.profile_id -> pat_profile.id

3)

doc_profile.user_id -> user.id
pat_profile.user_id -> user.id
Ответ написан
@Nc_Soft
Вам надо не только анкеты вынести в отдельные таблицы, но и типы юзеров.
Итого таблицы
users
doctors
clients
admins

Таблицы докторов и клиентов ссылаются на users. В users общая инфа, в doctors ид из юзера и все необходимые поля для анкеты. С клиентами также. Админы могут быть не завязаны на юзеров, это как требования организованы.
Ответ написан
Комментировать
@mayken
Работаю с 3 вариантом, очень удобно, каждая модель-класс удобно хранит необходимые методы для роли пользователя. Никаких лишних таблиц, только users, user_data, валидация в formrequest - можно разделить в зависимости от роли, а также набор принимаемых полей. По-моему - идеальный вариант.)
Ответ написан
Ваш ответ на вопрос

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

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