Sabe quando a solução parece simples, mas ficamos agarrados sem conseguir resolver… pois é. Segue abaixo o meu problema:
Cenário:
Estou trabalhando com MySQL, com os campos no formato Date.
Tenho um cadastro de Vendas, com 3 Models (cabeçalho, Itens e Pagamentos)
Utilizo a extension i18n-datetime-behavior
Na actionUpdate (por exemplo), após o $model_cabecalho passar pelo método ->save(), se houver algum erro encontrado nos dois outros Models, preciso emitir uma mensagem de erro, fazer um rollback() e voltar ao formulário para o usuário arrumar o problema.
Erro:
O $model_cabecalho volta com a data no formato do MySQL (yyyy-MM-dd).
Analisando o behavior, entendo que isso foi feito pelo evento: "public function beforeSave($event){"
Tentei executar o comando abaixo, logo antes do render da actionUpdate… para devolver o formato para i18n, mas agora ele força a data atual no campo, ao invés de mostrar o conteúdo do que estava no model.
Quando trabalho com transação eu chamo primeiro os métodos validate() de cada modelo, se todos passarem pela validação eu chamo o save(), nesse caso a data nem chega a ir para o formato yyyy-MM-dd, pois o validador da data utiliza o padrão dd/MM/yyyy.
Eu fiz uma função para facilitar diversos casos que terei.
Mas existe uma melhor forma de descobrir em qual formato ( yyyy-mm-dd ou dd/mm/yyyy ) a data está ?
Acredito que essa função possa melhorar para ficar mais "estável".
public function getDate_i18n_format($sdate) {
if ($sdate =='') return $sdate;
// Verificando se a data está no formato yyyy-mm-dd
if (strpos($sdate, '-')) {
list($y, $m, $d) = explode('-', $sdate);
if(checkdate($m, $d, $y))
// Se estiver no formato, faz a conversão
return date('d/m/Y', CDateTimeParser::parse($sdate, 'yyyy-MM-dd'));
else
return $sdate; // senão, devolve o que estava na variável
} else
return $sdate;
}
Neste caso a dúvida é mais de PHP do que Yii. Mas se puder ajudar!?!
Gustavo, não depurei este método, mas se está quebrando teu galho é oq vale. São muitas as maneiras pra vc fazer isso. A forma que utilizo muito é com com expressão regular.
Eu tb utilizo essa extensão (i18n-datetime-behavior), mas quando os valores não passam pela validação as datas retornam como inseridas no "_form.php", ou seja, eu não preciso fazer essa conversão q vc faz.
Passa como está em seu controlador, vou dar uma olhada, as vezes tú nem precisa esquentar com essa conversão.
Eu faço um validate() antes do save(). Mas como é um Master-Detail, o save() do cabeçalho acontece antes de gravar os registros "detalhes" (itens e pagamentos). Segue o código para você verificar. Agraço as críticas !! Valeu !
Até pensei em passar o save do cabeçalho, depois que houver sucesso na gravação dos detalhes (depois de todas as validações). Talvez assim, não precise de fazer a conversão da data.
/**
* Updates a particular model.
* If update is successful, the browser will be redirected to the 'view' page.
* @param integer $id the ID of the model to be updated
*/
public function actionUpdate($id)
{
$model_cabec=$this->loadModel($id);
$model_itens=new Vendas02;
$model_pgtos=new Contasreceber;
$dp_itens=$this->loadModel_itens($id);
$dp_pgtos=$this->loadModel_pgtos($id);
$readonly = FALSE;
// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);
if(isset($_POST['Vendas01']))
{
$model_cabec->attributes=$_POST['Vendas01'];
// Montando o array com os campos da View
$gridItens = $this->itens_from_post();
$gridPgtos = $this->pgtos_from_post();
$dp_itens = $this->cria_dataprovider_itens($gridItens);
$dp_pgtos = $this->cria_dataprovider_pgtos($gridPgtos);
$success1 = false;
$success2 = false;
$success3 = false;
if ($model_cabec->validate()) {
$transaction = Yii::app()->db->beginTransaction();
$success1 = $model_cabec->save(false);
//Pré-Validações
$form_validado = $this->f_valida_form($model_cabec, $model_itens, $model_pgtos, $gridItens, $gridPgtos);
if ($form_validado) {
// Exclui todos os itens e pagamentos existentes
$this->delete_Itens($model_cabec->id);
$this->delete_Pgtos($model_cabec->id);
// Grava os novos registros
$success2 = true;
foreach($gridItens as $i=>$item) {
$model_itens_save=new Vendas02;
$model_itens_save->unsetAttributes();
$model_itens_save->id_venda = $model_cabec->id;
$model_itens_save->id_item = $item["id_item"];
$model_itens_save->id_produto = $item["id_produto"];
$model_itens_save->qtde = $item["qtde"];
$model_itens_save->desconto = $item["desconto"];
$model_itens_save->valor = $item["valor"];
// Salva e Valida os submodels
if ($model_itens_save->validate())
$model_itens_save->save(false);
else
$success2 = false;
}
// Grava os novos registros
$success3 = true;
foreach($gridPgtos as $i=>$pgto) {
$model_pgtos_save=new Contasreceber;
$model_pgtos_save->unsetAttributes();
$model_pgtos_save->id_venda = $model_cabec->id;
$model_pgtos_save->id_parcela = $pgto["id_parcela"];
$model_pgtos_save->id_tipopgto = $pgto["id_tipopgto"];
$model_pgtos_save->id_cartaocred = $pgto["id_cartaocred"];
$model_pgtos_save->id_operatef = $pgto["id_operatef"];
$model_pgtos_save->numdoc = $pgto["numdoc"];
$model_pgtos_save->parc_data = $pgto["parc_data"];
$model_pgtos_save->parc_valor = str_replace(',', '.', $pgto["parc_valor"]);
// Valida e Salva os submodels
if ($model_pgtos_save->validate())
$model_pgtos_save->save(false);
else
$success3 = false;
}
}
// Verificando o resultado das validações
$success = $success1 && $success2 && $success3;
if ($success) {
$transaction->commit();
// redireciona para visualização
$this->redirect(array('view','id'=>$model_cabec->id));
}
else
$transaction->rollBack();
}
}
// Convertendo o formato da data, pois pode chegar com formato y-m-d
$model_cabec->data = $this->getDate_i18n_format($model_cabec->data);
$this->render('update',array(
'model_cabec'=>$model_cabec,
'model_itens'=>$model_itens,
'model_pgtos'=>$model_pgtos,
'dp_itens'=>$dp_itens,
'dp_pgtos'=>$dp_pgtos,
'readonly'=>$readonly,
));
}
Li o código. Acredito tb que se vc fizer isso q pensou não haverá necessidade de converter a data, já que o método save do $model_cabec não será executado caso a gravação dos detalhes não ocorra.
Pelo fato da extensão interpretar os modelos individualmente, e converter a(s) data(s) antes de salvar, se, e somente se, a validação for bem sucedida ou quando não há validação ($model->save(false)), ocorrerá isso msm.