kimono
@kimono
Web developer

"Кошерна" ли такая логика модели в Yii2?

Есть модель пользователя, дата рождения в которой в базе MySQL хранится в поле DATE в формате «Y-m-d» (типичная ситуация). Для пользовательского ввода предусмотрен другой формат даты «d.m.Y» (частый случай). Тогда логика такая:
public function afterFind()
{
    parent::afterFind();
    $this->birthdate = \Yii::$app->formatter->asDate(\DateTime::createFromFormat('Y-m-d', $this->birthdate), 'php:d.m.Y');
}

public function beforeSave($insert)
{
    if (parent::beforeSave($insert)) {
        $this->birthdate = \Yii::$app->formatter->asDate(\DateTime::createFromFormat('d.m.Y', $this->birthdate), 'php:Y-m-d');
        return true;
    }
    return false;
}

Допустим пользователь ввёл «01.12.1980», мы проверяем что дата корректая, сохраняем модель, модель сохраняет дату как «1980-12-01», далее мы отправляем модель на клиент и получаем дату в "непотребном" для пользователя формате. Логично было бы снова превратить сохраненную дату в "нормальный формат", или еще логичнее дёрнуть тригер, где у нас это уже происходит:
public function afterSave($insert, $changedAttributes)
{
    parent::afterSave($insert, $changedAttributes);
    $this->trigger(self::EVENT_AFTER_FIND);
}

Насколько это правильно и "кошерно"? Или предложите другую логику?
  • Вопрос задан
  • 595 просмотров
Пригласить эксперта
Ответы на вопрос 5
slo_nik
@slo_nik Куратор тега Yii
Добрый день.
Я думаю, что это лишнее.
Храните дату в timestamp, а при выводе пользователю форматируйте дату как Вам будет угодно.
В базе "data_birthday INT(11)". При выводе Вы будете получать что-то подобное "1497301200".
При выводе даты пользователю форматировать как обычно, при помощи Yii::$app->formatter->asDate(****).
Если это в админке, то в GridView, например, достаточно указать формат даты:
'columns' => [
    'date_birthday:date'
]

Или
'columns' => [
   'attribute' =>  'date_birthday',
   'format' => 'date',
]

При таком варианте Вам надо подправить правила валидации в модели.
Ответ написан
qonand
@qonand
Software Engineer
Не кошерна. Модель должна отвечать за логику а не за преобразование данных для пользователя. За формат отображения должно отвечать представление и соответственно оно должно преобразовать формат Y-m-d в d.m.Y и обратно. Кроме того таким подходом Вы размазываете логику форматирования по всему приложению (а когда необходимо будет поменять формат придется лопатить все приложение...)
Ответ написан
@vism
А в yii нет сеттеров гетеров для атрибутов или мутаторов?
Вобще оптимально преобразовывать в Carbon при получении и парсить Карботом при установке атрибута и готовить для сервера.
Эта логика Кошерна и очень верна(но желательно сетерами и гетерами)
Вы в 1 месте данные готовите для получения и установки.
Ответ написан
Комментировать
VaNnOrus
@VaNnOrus
Имхо, форматировать вывод в моделе - это вообще не по феншую и смысла в этом никакого не наблюдается. За форматирование данных в MVC по концепции должно отвечать представление "V". Во всех остальных местах данные должны быть в том формате, в каком они хранятся.
А обработка пользовательского ввода должна проходить в превалидации. Если вы перед сохранием данных преобразование делаете, то как проходит валидация? В валидации в том числе предполагается проверка соответствия формату.
Ответ написан
Комментировать
@yiiworld
Сам вопрос задан не "кошерно" ))
Вар.1) логика вашего AfterFind (для отображения) действительно должна быть только в представлении. Т.е. работать с данными в модели удобнее в едином формате(например в том формате в котором вы их получаете из БД) (кроме случаев когда это невозможно).
Вар.2) нахождение логики подготовки данных в BeforeSave немного не кошерно т.к. данные до отображения и после получения будут иметь разный формат. Поэтому предпочтительно эту логику выполнить там где данные были получены(например входящий POST в контроллере)
Вар.3) А для вашего "Хочется "целостности"" - тут "плясать" надо от формата данных с которым вы работаете в модели(опорный формат). В таком случае:
- перед сохранением(для проверки соответствия и преобразования) используете валидацию (см.Автономные валидаторы) или [не так кошерно]beforeSave()
- после получения из БД выполняете преобразование в afterFind()
- для отображения выполняете преобразование в представлениях
- для получения из запроса выполняете преобразование в контроллере
и все эти 4 функции(static) приспокойненько располагаете в базовой модели(или основной, если нет базовой) и дергаете их по мере необходимости.
PS: ответы про сеттеры и геттеры это конечно хорошо, но они как таковые просто инструмент а не решение (для Вар3 можно сделать геттеры(и по необходимости сеттеры) для каждого случая(и соответственно 4 виртуальных атрибута), а можно использовать функции преобразования напрямую)
PPS: товарищ Максим Федоров, который за форматирование на JS, пишет уж совсем глупые вещи(читайте комментарии про js и общую архитектуру), (ИМХО). Но тут и диссонанс - в других ответах на тостере он вполне себе здраво рассуждает.
Ответ написан
Ваш ответ на вопрос

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

Похожие вопросы