したがって、自分の拡張機能でこの同じ問題との戦いにほぼ1日費やした後、私は自分の解決策をここで共有したいと思いました。注目すべきことは、私のエンティティはEAVシステムを利用していないことです。各エンティティには、各属性の列を持つ独自のフラットテーブルがあります。私のエンティティには4つの日時属性があります。そのうち2つはユーザー入力から入力され(open_date
、close_date
)、2つはソースコードによって自動的に入力されます(create_date
、close_date
)。
エンティティのモデルクラス
エンティティのモデルクラスに、以下を含めました。
- どの属性がタイプ日時であり、ストアのローカル時間で提供されるユーザー入力データを介して入力されるかを定義およびフェッチする方法。
- これらのフィールドのみをGMT時間からストアのローカル時間に変換するメソッド(これについては後で詳しく説明します)。
- 保存時に自動的にGMTで'edit_date'および 'create_date'属性(ユーザー入力を介して入力されない)を設定する_beforeSave()メソッド。
ソースコード:
/**
* 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()メソッドを利用して、ストアのローカル時間(ユーザーが入力したもの)からGMT時間に変更してからデータベースに保存する必要がある属性を確認しました。これは私の保存メソッドの一部にすぎないことに注意してください。
....
$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で格納されるため、ユーザーが入力した日時属性をストアのローカル時間に変換してから、そのデータをフォームに提供する必要があります。これが、エンティティのモデルクラスの#2の出番です。
以下は、私の管理フォームのブロッククラス(Mage_Adminhtml_Block_Widget_Formを拡張)の_prepareForm()メソッドの一部です。私は関数の大部分を省略し、この質問に関連する最小限の要素のみを含め、有効なクラスメソッドを提供しようとしています。
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の他のフォームウィジェットに従います。ただし、ここで注意すべき重要な点の1つは、を呼び出すので$form->setValues($model->getData())
はなく、を呼び出すこと$form->setValues($model->getAdminFormData())
です。この回答の最初のセグメントからコードを確認すると、このメソッドは、ユーザー入力のすべての日時属性をGMTからストアのローカル時間に変換します。
最終結果:
- GMT時間でDBに保存されたすべての値。
- ユーザーが入力した値は、編集フォームに渡す前に、GMTから店舗の現地時間に変換されます。
- 管理グリッドは従来どおり機能し、ページにグリッドをレンダリングする前にGMT値を取り込み、ストアのローカル時間に変換します。
これがいつか他の誰かを助けるための貴重なリソースとして証明されることを願っています。フロントエンドの開発に取り掛かるときは、日時の値がDBのGMTであることを覚えておいてください。