Form validation errors with transactions and multiple models

Hi all,

I’m having problems getting my validation errors to appear in my forms and wondering if anyone could share some insights.

I’ve constructed a multi-page form, where each page writes to one or more different related models. I’ve wrapped a transaction around the model->saves() to make sure nothing gets left out of the save.

The problem I’m having is that when the validation fails, it’s not properly sending errors to the form, and in some cases, I can’t find out what the error is at all.

Everything is handled through actionUpdate() in the controller:




$model=$this->loadModel();

		if ($_POST) :

			$transaction = $model->dbConnection->beginTransaction();

			$action = 'redirect';

			try { // THIS RUNS THROUGH THE VARIOUS MODELS THAT ARE USED

				if (isset($_POST['Application'])) {

					$model->attributes=$_POST['Application'];

					$model->save(false);

				}


				//THE MODELS/RELATIONS ARE PULLED FROM FUNCTION "singleModels" IN THE MAIN MODEL

				foreach ($model->singleModels as $relationName => $modelName) :

					if (isset($_POST[$modelName])) :

						$myModel = $model->$relationName;

						$myModel->attributes = $_POST[$modelName];

						if ($myModel->validate()) {

							$myModel->save(false);

						} else { // TRYING TO GET SOME RESPONSE TO ERRORS

							$this->addErrors();

							print_r($myModel->getErrors());

							exit;

						}

					endif;

				endforeach;


				$transaction->commit();

			}

			catch (Exception $e) {

				$transaction->rollback();

			}

		else :

			$action = 'render';

		endif;




		if (isset($_POST['Nav']))

			foreach ($_POST['Nav'] as $section => $name)

				$model->section = $section;


		if ($action == 'redirect') //REDIRECTING KEEPS THE NEXT PAGE FROM TRYING TO RESUBMIT ON RELOAD

			$this->redirect(array(

				'update',

				'id'		=> $model->id,

				'section'	=> $model->section,

			));

		else

			$this->render('update',array(

				'model'=>$model,

			));



The View pages are sub-pages ("_viewName.php") called by update.php. They use a standard ActiveForm schema, but each have their own model IDs assigned:

From update.php:




<?php $form = $this->beginWidget('CActiveForm', array(

	'id'=>'application-form',

	'enableAjaxValidation'=>false,

      )); ?>


<h2><?php echo Yii::t('app',$model->navSections->current['name']) ?></h2>

<?php echo Yii::t('app',$model->navSections->current['description']) ?>


<?php echo $this->renderPartial($template, array('model'=>$model,'form'=>$form)); ?>


...



From the sub template:




<?php $faModel = $model->assistance; ?>


	<p class="note">Fields with <span class="required">*</span> are required.</p>


	<?php echo $form->errorSummary($faModel); ?>


	<div class="row">

		<?php echo $form->labelEx($faModel,'household_annual_income'); ?>

		<?php echo $form->textField($faModel,'household_annual_income',array('size'=>10,'maxlength'=>10,'class'=>'currency')); ?>&nbsp;<?php echo $model->program->currency->code ?>

		<?php echo $form->error($faModel,'household_annual_income'); ?>

	</div>


...



What do I need to do to get the Error Messages to show up properly?

Many thanks in advance!

Let me try my question a different way.

When you’re updating multiple models using a transaction, it’s recommend you validate all the models first using the format, and then save them. But this doesn’t send feedback to the user. If the validation fails, is there a way to send the error back to ActiveForm so the error summary and offending input can be highlighted for the user?




$valid = true;

foreach ($models as $model) {

  $model->attributes = get_the_attributes();

  $valid = $model->validate() && $valid;

}


if ($valid) :

  foreach ($models as $model) {

    $model->attributes = get_the_attributes(); // and there must be a better way than repeating this...

    $model->save;

  }

else :

  //can we do something here to send back the error summary and error detail to CActiveForm?

endif;



I think this is not related to transactions at all… try without them to see…

The problem IMO are the multiple pages… how to display errors on them…

Yes, and this could also solve your problems.

All changes that you are making in your models in the first loop are being discarded (thus you need to assign the attributes again). Among the discarded changes are the validation errors.

All you need to solve your problems with the validation errors and to eliminate the need for assigning the attributes again is to get the models as reference in the first loop.

Read the documentation at http://php.net/foreach and use “unset” (there’s a documented gotcha in that page).