YiiFramework Числовые поля в БД

Vano

Новичок
Yii, при апдейте записи, обещает изменять только те столбцы, которые отличаются от старых. Тоесть изменил name, запрос будет типа UPDATE ... set name = "Name". Но что делать, если в таблице есть числовые поля типа tinyint для статусов, ведь если даже не менять запись в форме и отправить на сохранение, в модель за'load'дятся переменные string. И получается пользователь ничего не изменял, а в БД запрос пошел UPDATE ... set status = 1.

Вкратце: Вынимаем из БД ["status"]=> int(1); лоадим в модель ["status"] => string(1) "1" ; Update set stauts = 1.

Что посоветуете?
 

Vano

Новичок
Вариант 1. Сделать нормализацию валидатором "FilterValidator"
Код:
['status', 'filter', 'filter' => 'intval'],
Так, как валидация выполняется по очереди массива rules, отстроченых багов не должно быть, если фильтр поля после валидации этого же поля.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
ты проверял, что запрос действительно делается если вместо "1" записать 1?
 

Vano

Новичок
Да, в дебагере смотрел(в случае если $model->oldAttributes не совпадают по типам с $model->attributes). FilterValidator решает эту задачу.
 

Vano

Новичок
Это кстате незаметный прикол) который может привести, как минимум, к тому, что поле "дата редактирования" будет обновлятся в ненужное время.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
можно открыть багрепорт.
@Sam Dark что думаешь о таком не-приведении типов?
 

Sam Dark

Новичок
Из формы всё-всё приходит строками, поэтому и получается так.

Решается, как уже отметил Vano, фильтром. Штука известная. Описано в доке в двух местах.

Автоматом приводить часто никак потому как число может и не влезть в 32 бита PHP, а вот в базу влезет спокойно.
 

Vano

Новичок
Не все так просто. Во-первых нужно добавить пропуск пустых
Код:
[['status', 'status2', 'status3'], 'filter', 'filter' => 'intval', 'skipOnEmpty' => true], //Если есть поля которые могут быть пустыми
['%поле которое может быть пустым%', 'default', 'value' => '%дифолт значение из бд%']
И это всё нивелируется TimeStampBehavior'ом (всмысле, я себе задачу такую поставил; опишу ниже), так как, он ставит Апдейт Тайм в любом случае.

А моя задача состоит в том, чтобы если пользователь случайно нажал сохранить, но ничего не изменял - Не шел запрос в БД, и не менялся Апдейт Тайм
 

Vano

Новичок
Но все таки и для этой задачи
И это всё нивелируется TimeStampBehavior'ом
есть решение -
Код:
'value' => function ($event) {
                    if ($event->name == "beforeUpdate" && !$event->sender->dirtyAttributes) {
                        return $event->sender->date_update; //где date_update поле даты редактирования
                    }
                    return new \yii\db\Expression('NOW()');
                }
В бехавиоре валуе назначить что-то типа такого.
 

Sam Dark

Новичок
При вытаскивании из базы мы точно знаем, что там за поле, какого оно типа и мапится ли оно на PHP нормально. Поэтому для bit приводится к PHP-шному int-у.

Обратно откуда данные попадают мы особо не знаем. Они могут из формы прилетать, из какого-то API и т.д. То есть могут быть какого угодно типа.
Теоретически, можно было бы также смотреть на тип поля в базе перед сохранением и сравнивать для каждого типа немного по-разному.
 

Sam Dark

Новичок
Такое возможно для типа bit. С типом, например, int это всё ещё такая же проблема.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
да понятно, вы хотите сделать разработку правильнее,
просто этим вы создали непредсказуемое и мало кому нужное поведение ценой лишних циклов процессора и внезапных проблем для всех, кто привык что везде работа идет со строками, и за 20 лет жизнь показала, что Размус в этом вопросе прав,

но считать что все не в ногу, в принципе, совершенно нормально для yii :)
 
  • Like
Реакции: AmdY

Sam Dark

Новичок
Чего сразу наезды? :) Мы готовы меняться. Только дайте нам знать и предложите как.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
никакого наезда, думаю, ты его спасаешь, этот yii :)

я приведения не замечаю потому что у меня основная бизнес-логика в собственных моделях с plain sql или query builder, а ActiveRecord - в основном в роли DbTableGateway
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Что может помочь - это валидация данных через filter_var_array(), он делает приведение типов. Вообще, очень недооцененная штука - каждый фреймворк считает что умеет лучше, но реально все изобретают велосипеды, или не разобравшись, или not invented here, не знаю. Я ее активно юзаю. Задаю простыню массива правил и одним вызовом получаю данные с гарантированной структурой и типами.
Никаких Warning: Array to string conversion.
Правила можно было бы генерить налету из списка правил в AR.
 

Sam Dark

Новичок
Мы её не юзаем из за клиентской валидации. Она должна вести себя 1 в 1 как серверная и настраиваться так же.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
я не нашел какую проверку нельзя сделать через filter, там есть regexp и callback,
приведение правил из формата yii в формат filter - вопрос not invented here,
но в скорости, надежности и памяти filter выигрывает
 
Последнее редактирование:
Сверху