Donc, après avoir passé près d'une journée à lutter contre ce même problème dans ma propre extension, j'ai pensé partager ma solution ici. Quelque chose à noter est que mes entités n'utilisent pas le système EAV, chaque entité a sa propre table plate avec une colonne pour chaque attribut. Mon entité possède quatre attributs datetime, dont deux sont remplis à partir de l'entrée utilisateur ( open_date
, close_date
) et deux sont remplis automatiquement par le code source ( create_date
, close_date
).
Classe modèle de l'entité
Dans la classe de modèle de l'entité, j'ai inclus les éléments suivants:
- Un moyen de définir et de récupérer les attributs de type datetime et remplis via des données saisies par l'utilisateur fournies dans l'heure locale du magasin.
- Une méthode qui convertit uniquement ces champs de l'heure GMT à l'heure locale du magasin (plus d'informations à ce sujet plus tard).
- Une méthode _beforeSave () qui définit automatiquement pour moi les attributs 'edit_date' et 'create_date' (qui ne sont pas renseignés via les entrées utilisateur) dans GMT.
Le code source:
/**
* 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;
}
L'action saveAction du contrôleur d'administration de l'entité
Dans la méthode saveAction de mon contrôleur, j'ai utilisé la méthode getDateFields () définie dans la classe de modèle pour savoir quels attributs je dois changer de l'heure locale du magasin (qui a été entrée par l'utilisateur) à l'heure GMT avant de l'enregistrer dans la base de données. Notez que ce n'est qu'un extrait partiel de ma méthode de sauvegarde:
....
$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();
....
Le bloc de formulaire d'administration pour modifier l'entité
Contrairement au widget de la grille d'administration de Magento, qui attend que les valeurs datetime des collections soient fournies dans GMT, avec l'intention de convertir ces valeurs en heure locale du magasin avant d'afficher la page, le widget de formulaire d'administration de Magento ne suit pas ce comportement. Au lieu de cela, le widget de formulaire acceptera la valeur datetime telle quelle et l'affichera sans ajuster automatiquement l'heure. Par conséquent, étant donné que les valeurs sont stockées dans la base de données au format GMT, nous devons d'abord convertir les attributs datetime entrés par l'utilisateur en heure locale du magasin avant de fournir ces données au formulaire. C'est là que notre n ° 2 sur la classe modèle de l'entité entre en jeu.
Voici une partie de la méthode _prepareForm () de la classe de bloc de mon formulaire d'administration (qui étend Mage_Adminhtml_Block_Widget_Form). J'ai omis la majorité de ma fonction, essayant d'inclure uniquement le strict minimum qui est pertinent pour cette question, et toujours fournir une méthode de classe valide:
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();
}
La plupart de ceci suit n'importe quel autre widget de formulaire pour Magento. Cependant, la chose clé qu'il est important de noter ici est que plutôt que d'appeler, $form->setValues($model->getData())
nous appelons $form->setValues($model->getAdminFormData())
. Ce qui, si nous examinons mon code du premier segment de cette réponse, cette méthode prend de convertir tous les attributs datetime, qui sont entrés par l'utilisateur, de GMT à l'heure locale du magasin.
Résultat final:
- Toutes les valeurs enregistrées dans DB en temps GMT.
- Les valeurs saisies par l'utilisateur sont converties de GMT en heure locale du magasin, avant de le donner pour modifier le formulaire
- La grille d'administration fonctionne comme elle l'a toujours fait, en prenant les valeurs GMT et en les convertissant à l'heure locale du magasin avant de rendre la grille sur la page.
J'espère que cela s'avérera une ressource précieuse pour aider quelqu'un d'autre un jour. Lorsque vous travaillez sur le développement frontal, n'oubliez pas que les valeurs datetime sont en GMT dans la base de données!