Поэтому, потратив почти день на борьбу с этой же проблемой в своем собственном дополнении, я решил поделиться своим решением здесь. Следует отметить, что мои объекты не используют систему EAV, у каждого объекта есть своя собственная плоская таблица со столбцом для каждого атрибута. Моя сущность имеет четыре атрибута datetime - два из которых заполняются из пользовательского ввода ( open_date
, close_date
), а два из них автоматически заполняются исходным кодом ( create_date
, close_date
).
Модель класса сущности
В класс модели объекта я включил следующее:
- Способ определить и выбрать, какие атрибуты относятся к типу datetime и заполняются с помощью введенных пользователем данных, предоставляемых по местному времени магазина.
- Метод, который преобразует только эти поля из времени по Гринвичу в местное время магазина (подробнее об этом позже).
- Метод _beforeSave (), который устанавливает для меня атрибуты 'edit_date' и 'create_date' (которые не заполняются через пользовательский ввод) в GMT автоматически при сохранении.
Исходный код:
/**
* Model's datetime attributes that are populated with user data supplied
* in the store's local time.
*
* @var array
*/
protected $_dateFields = array(
'open_date',
'close_date',
);
/**
* Return the model's datetime attributes that are populated with user
* data supplied in the store's local time.
*
* @return array
*/
public function getDateFields()
{
return $this->_dateFields;
}
/**
* (non-PHPdoc)
* @see Mage_Core_Model_Abstract::_beforeSave()
*/
protected function _beforeSave()
{
parent::_beforeSave();
$date = Mage::getModel('core/date')->gmtDate();
if (!$this->getId()) {
$this->setData('create_date', $date);
}
$this->setData('edit_date', $date);
return $this;
}
SaveAction административного контроллера сущности
В методе saveAction моего контроллера я использовал метод getDateFields (), определенный в классе модели, чтобы узнать, какие атрибуты мне нужно изменить с локального времени магазина (которое было введено пользователем) на время по Гринвичу до сохранения в базе данных. Обратите внимание, что это только частичный фрагмент моего метода сохранения:
....
$data = $this->getRequest()->getPost()
// Convert user input time from the store's local time to GMT time
$dateFields = $model->getDateFields();
if (is_array($dateFields) && count($dateFields)) {
$data = $this->_filterDateTime($data, $dateFields);
$store_timezone = new DateTimeZone(Mage::getStoreConfig('general/locale/timezone'));
$gmt_timezone = new DateTimeZone('Europe/London');
foreach ($dateFields as $key) if (isset($data[$key])) {
$dateTime = new DateTime($data[$key], $store_timezone);
$dateTime->setTimezone($gmt_timezone);
$data[$key] = $dateTime->format('Y-m-d H:i:s');
}
}
$model->addData($data);
try {
$model->save();
....
Блок административной формы для редактирования сущности
В отличие от виджета сетки администратора Magento, который ожидает, что значения времени и даты из коллекций будут предоставлены в GMT, с намерением преобразовать эти значения в местное время магазина до отображения страницы, виджет формы администратора Magento не соответствует этому поведению. Вместо этого виджет формы будет принимать значение даты и времени как есть и отображать его без автоматической настройки времени. Поэтому, поскольку значения хранятся в базе данных в GMT, мы должны сначала преобразовать введенные пользователем атрибуты datetime в местное время магазина, прежде чем предоставлять эти данные в форму. Вот тут-то и вступает в игру наш второй номер в классе моделей Entity .
Вот часть метода _prepareForm () класса блока моей формы администратора (который расширяет Mage_Adminhtml_Block_Widget_Form). Я опустил большую часть своей функции, пытаясь включить только тот минимум, который имеет отношение к этому вопросу, и по-прежнему предоставлять правильный метод класса:
protected function _prepareForm()
{
$form = new Varien_Data_Form();
$model = Mage::registry('YOUR_MODEL_CLASS');
$date_format = Mage::app()->getLocale()->getDateTimeFormat(Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM);
$time_zone = $this->__('Time Zone: %s', Mage::getStoreConfig('general/locale/timezone'));
$calendar_img = $this->getSkinUrl('images/grid-cal.gif');
$fieldset = $form->addFieldset('base_fieldset', array('legend'=> $this->__('General Information')));
$fieldset->addField('open_date', 'datetime', array(
'name' => 'open_date',
'label' => $this->__('Open Date'),
'title' => $this->__('Open Date'),
'time' => 'true',
'image' => $calendar_img,
'format' => $date_format,
'style' => 'width:160px',
'required' => true,
'note' => $time_zone
));
$fieldset->addField('close_date', 'datetime', array(
'name' => 'close_date',
'label' => $this->__('Close Date'),
'title' => $this->__('Close Date'),
'time' => 'true',
'image' => $calendar_img,
'format' => $date_format,
'style' => 'width:160px',
'required' => true,
'note' => $time_zone
));
if ($model->getId()) {
$form->setValues($model->getAdminFormData());
}
$this->setForm($form);
return parent::_prepareForm();
}
Большая часть этого следует за любым другим виджетом формы для Magento. Однако, одна ключевая вещь, которую важно здесь отметить, это то, что вместо того, чтобы звонить, $form->setValues($model->getData())
мы звоним $form->setValues($model->getAdminFormData())
. Что, если мы рассмотрим мой код из первого сегмента этого ответа, этот метод берет преобразование всех атрибутов даты и времени, которые вводятся пользователем, из GMT в местное время магазина.
Конечный результат:
- Все значения сохраняются в БД по времени GMT.
- Введенные пользователем значения преобразуются из GMT в местное время магазина, прежде чем дать его для редактирования формы
- Сетка администратора работает как всегда, принимая значения по Гринвичу и конвертируя в местное время магазина до отображения сетки на странице.
Надеюсь, что это окажется ценным ресурсом, чтобы помочь кому-то еще там когда-нибудь. Настало время, когда вы работаете над интерфейсной разработкой, имейте в виду, что значения datetime находятся в GMT в БД!