Validation of related model

Hello everyone,

I am kind of lost on how to achieve a functionality in Yii 2.0.

I have a model which have related model in a one to many relationship. The thing is that the related model has a property to mark one of the related models as main. I am not sure how can I achieve the following validation in the parent model: if no related model or if more than one related model is marked as main this should throw a validation error. Only one is allowed and required.

Can anyone give me some lights on how to achieve this?

Regards,

you could fire an Event

$this->trigger(MyModel::EVENT_AFTER_VALIDATE,, $event){

}

or write your own FormModel (https://www.yiiframework.com/doc/guide/2.0/en/input-forms)

class CustomerForm extends Model
{
    private $customer;
    private $contact;

    public function rules()
    {
        return [
            [['Customer'], 'required'],
            [['Contact'], 'safe'],
        ];
    }

    public function afterValidate()
    {
        $error = false;
        if (!$this->customer->validate()) {
            $error = true;
        }
        if (!$this->contact->validate()) {
            $error = true;
        }
        parent::afterValidate();
    }

It’s only for example, because you haven’t show some code

Hi demonking,

Thanks for your quick reply.

Ok here are the model classes. I removed the code pieces (other properties, constants, validation rules, labels, model methods and events - beforeSave and afterSave -) that are not needed to understand what I am trying to achieve. Also the code was translated from spanish to english so please ignore if I left any spanish word in the process.

/**
 * This is the model class for table "production_order".
 *
 * @property integer $production_order_id
 * @property integer $production_order_type_id
 *
 * @property ProductionOrderType $productionOrderTypeId
 * @property ProductionOrderDie[] $productionOrderDies
 * @property ProductionOrderDie $mainProductionOrderDieId
 */
class ProductionOrder extends \yii\db\ActiveRecord
{
	const MAX_DIES = 3;
	
    /**
     * @return \yii\db\ActiveQuery
     */
    public function getProductionOrderDies()
    {
        return $this->hasMany(ProductionOrderDie::className(), ['production_order_id' =>     'production_order_id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getDies()
    {
        return $this->hasMany(Die::className(), ['die_id' => 'die_id'])-    >viaTable('production_order_die', ['production_order_id' => 'production_order_id']);
    }

    public function getMainProductionOrderDieId()
    {
    	if (($model = ProductionOrderDie::findOne(['production_order_id' => $this->production_order_id, 'main_die' => 1])) !== null) {
    		return $model;
    	} else {
    		return null;
    	}
    }
}

/**
 * This is the model class for table "production_order_die".
 *
 * @property integer $production_order_die_id
 * @property integer $production_order_id
 * @property integer $die_id
 * @property integer $main_die
 *
 * @property ProductionOrder $productionOrderId
 * @property Die $dieId
  */
class ProductionOrderDie extends \yii\db\ActiveRecord
{
    /**
     * @return \yii\db\ActiveQuery
     */
    public function getProductionOrderId()
    {
        return $this->hasOne(ProductionOrder::className(), ['production_order_id' => 'production_order_id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getDieId()
    {
        return $this->hasOne(Die::className(), ['die_id' => 'die_id']);
    }
}

/**
 * This is the model class for table "die".
 *
 * @property integer $die_id
 *
 * @property ProductionOrderDie[] $productionOrderDies
 * @property ProductionOrder[] $productionOrders
 */
class Die extends \yii\db\ActiveRecord
{
    /**
     * @return \yii\db\ActiveQuery
     */
    public function getProductionOrderDies()
    {
        return $this->hasMany(ProductionOrderDie::className(), ['die_id' => 'die_id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getProductionOrders()
    {
        return $this->hasMany(ProductionOrder::className(), ['production_order_id' =>     'production_order_id'])->viaTable('production_order_die', ['die_id' => 'die_id']);
    }
}

What I want to do is: The production order can allow from one to three dies. The dies can be marked as the main die for the production order. Conditions:

  • Every order must have at least one die: so I need to validate that if no dies are entered there should be a validation message.
  • Only one die can be the main die: so I need to validate that if more than one die is marked as main there should be a validation message.
  • A main die is required: so I need to validate that if no die is marked as main there should be a validation message (even though if just one die is entered it is obvious that it is the main one I need to ensure the user marks it and not the system decides for him that the only die in the order is the main one).

I hope you can give me some lights with this extra information.

Best regards,

Any response or comments?

Basically what I need to validate from the ProductionOrder model is:

  • That the count of order dies is greater that zero and less than or equal to 3.
  • That the count of order dies marked as main is equal to 1.

Regards,

Hi @Oscar_Ibarra,

It’s a bit complicated for me. So I have to make sure what I understand is right.

  • ProductionOrder can have many ProductionOrderDies
  • ProductionOrder must have at least one ProductionOrderDies
  • ProductionOrder can not have more than 3 ProductionOrderDies
  • ProductionOrder must have one (and only one) main ProductionOrderDie

Correct?

The challenge would be rather constructing a form for input than validating the input, because you have to supply some UI to select the dies for the order.

I think it’s better to create a model for the input form that is extended from ProductionOrder. Something like:

class ProductionOrderForm extends ProductionOrder
{
    public  $die_ids = [0, 0, 0];
    public  $is_main = [false, false, false];
    ...
}

And in the form:

<?php
    for ($i = 0; $i < 3; $i++) {
        echo $form->field($model, "[$i]die_ids");
        echo $form->field($model, "[$i]is_main")->checkbox();
    }
?>

And you will be able to write some method in the form model to validate $die_ids and $is_main somehow.

Hi @softark,

Yes your understanding is ok.

I am not using a form model class but the ProductionOrder class (ActiveRecord). In the form view I actually have a loop to write the 3 selectList widgets to select the dies and the dropdown for marking the main one (the user wanted a 3 stated dropdown instead of a checkbox which is only two states). The form is working and it is saving fine. The only thing pending are the two validations I said:

  • At least one die has to be selected (the max three limit is controlled by the rendering of only three set of controls).
  • One and only one die has to be marked as main.

Below is the code I sent at the beginning but expanded a little more to show that the corresponding parts are done and working in the controller as well as in the view.

Controller

/**
 * ProductionOrderController implements the CRUD actions for ProductionOrder model.
 */
class ProductionOrderController extends Controller
{
	/**
	 * Creates a new ProductionOrder model.
	 * If creation is successful, the browser will be redirected to the 'view' page.
	 * @return mixed
	 */
	public function actionCreate()
	{
		if (Yii::$app->user->can(AuthItem::ROLE_ADMINISTRATOR) || 
				Yii::$app->user->can(AuthItem::ROLE_SALESPERSON) || 
				Yii::$app->user->can(AuthItem::ROLE_DESIGNER)) {
				
			$model = new ProductionOrder();
			$modelDetailsDies = [];
				
			$formDetailsDies = Yii::$app->request->post('ProductionOrderDie', []);
			foreach ($formDetailsDies as $formDetailsDie) {
				$modelDetailDie = new ProductionOrderDie(['scenario' => ProductionOrderDie::SCENARIO_BATCH_UPDATE]);
				$modelDetailDie->setAttributes($formDetailsDie);
				$modelDetailsDies[] = $modelDetailDie;
			}
			
			if ($model->load(Yii::$app->request->post())) {
				if (Model::validateMultiple($modelDetailsDies) && $model->validate(null, false)) {
				
					$model->save();
					foreach($modelDetailsDies as $modelDetailsDie) {
						if (isset($modelDetailsDie->die_id) && $modelDetailsDie->die_id != '') {
							$modelDetailsDie->production_order_id = $model->production_order_id;
							$modelDetailsDie->save();
						}
					}
					 
					return $this->redirect(['view', 'id' => $model->production_order_id]);
				}
			}
			
			while(count($modelDetailsDies) < ProductionOrder::MAX_DIES) {
				$modelDetailsDies[] = new ProductionOrderDie(['scenario' => ProductionOrderDie::SCENARIO_BATCH_UPDATE]);
			}
			return $this->render('create', [
				'model' => $model,
				'modelDetailsDies' => $modelDetailsDies,
			]);
		} else {
			throw new ForbiddenHttpException('Access denied for user '.Yii::$app->user->identity->id);
		}
	}

	/**
	 * Updates an existing ProductionOrder model.
	 * If update is successful, the browser will be redirected to the 'view' page.
	 * @param string $id
	 * @return mixed
	 */
	public function actionUpdate($id)
	{
		if (Yii::$app->user->can(AuthItem::ROLE_ADMINISTRATOR) || 
				Yii::$app->user->can(AuthItem::ROLE_SUPERVISOR) || 
				Yii::$app->user->can(AuthItem::ROLE_SALESPERSON) || 
				Yii::$app->user->can(AuthItem::ROLE_DESIGNER) ||
				Yii::$app->user->can(AuthItem::ROLE_PRESS_OPERATOR) ||
				Yii::$app->user->can(AuthItem::ROLE_WINDING_OPERATOR)) {

			$model = $this->findModel($id);
			$modelDetailsDies = $model->productionOrderDies;
			
			$modelDetailsDies = $this->loadModelDetailDies(Yii::$app->request->post('ProductionOrderDie', []), $modelDetailsDies);
			
			if ($model->load(Yii::$app->request->post())) {
				if (Model::validateMultiple($modelDetailsDies) && $model->validate()) {
					$model->save();

					$model->saveDies($modelDetailsDies);
					
					return $this->redirect(['view', 'id' => $model->production_order_id]);
				}
			}

			while(count($modelDetailsDies) < ProductionOrder::MAX_DIES) {
				$modelDetailsDies[] = new ProductionOrderDie(['scenario' => ProductionOrderDie::SCENARIO_BATCH_UPDATE]);
			}
			return $this->render('update', [
				'model' => $model,
				'modelDetailsDies' => $modelDetailsDies
			]);
		} else {
			throw new ForbiddenHttpException('Access denied for user '.Yii::$app->user->identity->id);
		}
	}

	/**
	 * Finds the ProductionOrder model based on its primary key value.
	 * If the model is not found, a 404 HTTP exception will be thrown.
	 * @param string $id
	 * @return ProductionOrder the loaded model
	 * @throws NotFoundHttpException if the model cannot be found
	 */
	protected function findModel($id)
	{
		if (($model = ProductionOrder::findOne($id)) !== null) {
			return $model;
		} else {
			throw new NotFoundHttpException('The requested page does not exist.');
		}
	}
	
	private function loadModelDetailDies($formDetailArray, $modelDetailArray) 
	{
		foreach ($formDetailArray as $i => $formDetail) 
		{
			if (isset($formDetail['production_order_die_id']) && isset($formDetail['updateType']) && $formDetail['updateType'] != ProductionOrderDie::UPDATE_TYPE_CREATE) 
			{
				$modelDetail = ProductionOrderDie::findOne(['production_order_die_id' => $formDetail['production_order_die_id']]);
				$modelDetail->setScenario(ProductionOrderDie::SCENARIO_BATCH_UPDATE);
				$modelDetail->setAttributes($formDetail);
				$modelDetailArray[$i] = $modelDetail;
				if (!isset($modelDetail->die_id) || $modelDetail->die_id == '') 
				{
					$modelDetail->updateType = ProductionOrderDie::UPDATE_TYPE_DELETE;
				}
			}
			else if (isset($formDetail['die_id']) && $formDetail['die_id'] != '')
			{
				$modelDetail = new ProductionOrderDie(['scenario' => ProductionOrderDie::SCENARIO_BATCH_UPDATE]);
				$modelDetail->setAttributes($formDetail);
				$modelDetailArray[] = $modelDetail;
			}
			while(count($modelDetailArray) < ProductionOrderDie::MAX_DIES) 
			{
				$modelDetailArray[] = new ProductionOrderDie(['scenario' => ProductionOrderDie::SCENARIO_BATCH_UPDATE]);
			}
		}
		 
		return $modelDetailArray;
	}
}

Models

/**
 * This is the model class for table "auth_item".
 *
 */
class AuthItem extends \yii\db\ActiveRecord
{
	const ROLE_ADMINISTRATOR = 'Administrator';
	const ROLE_SUPERVISOR = 'Supervisor';
	const ROLE_SALESPERSON = 'Salesperson';
	const ROLE_DESIGNER = 'Designer';
	const ROLE_PRESS_OPERATOR = 'Press_Operator';
	const ROLE_WINDING_OPERATOR = 'Winding_Operator';
	const ROLE_INVOICING = 'Invoicing';
	const ROLE_RECEPTION = 'Reception';
	const ROLE_REPORTS = 'Reports';
}

/**
 * This is the model class for table "production_order".
 *
 * @property integer $production_order_id
 * @property integer $production_order_type_id
 *
 * @property ProductionOrderType $productionOrderTypeId
 * @property ProductionOrderDie[] $productionOrderDies
 * @property ProductionOrderDie $mainProductionOrderDieId
 */
class ProductionOrder extends \yii\db\ActiveRecord
{
	const MAX_DIES = 3;
	
	/**
	 * @return \yii\db\ActiveQuery
	 */
	public function getProductionOrderDies()
	{
		return $this->hasMany(ProductionOrderDie::className(), ['production_order_id' =>     'production_order_id']);
	}

	/**
	 * @return \yii\db\ActiveQuery
	 */
	public function getDies()
	{
		return $this->hasMany(Die::className(), ['die_id' => 'die_id'])-    >viaTable('production_order_die', ['production_order_id' => 'production_order_id']);
	}

	public function getMainProductionOrderDieId()
	{
		if (($model = ProductionOrderDie::findOne(['production_order_id' => $this->production_order_id, 'main_die' => 1])) !== null) {
			return $model;
		} else {
			return null;
		}
	}

	public function saveDies($modelDetailArray)
	{
		foreach($modelDetailArray as $modelDetail)
		{
			if ($modelDetail->updateType == ProductionOrderDie::UPDATE_TYPE_DELETE)
			{
				$modelDetail->delete();
			}
			else
			{
				if (isset($modelDetail->die_id) && $modelDetail->die_id != '')
				{
					$modelDetail->production_order_id = $this->production_order_id;
					$modelDetail->save();
				}
			}
		}
	}
}

/**
 * This is the model class for table "production_order_die".
 *
 * @property integer $production_order_die_id
 * @property integer $production_order_id
 * @property integer $die_id
 * @property integer $main_die
 *
 * @property ProductionOrder $productionOrderId
 * @property Die $dieId
  */
class ProductionOrderDie extends \yii\db\ActiveRecord
{
	const UPDATE_TYPE_CREATE = 'create';
	const UPDATE_TYPE_UPDATE = 'update';
	const UPDATE_TYPE_DELETE = 'delete';

	const SCENARIO_BATCH_UPDATE = 'batchUpdate';

	/**
	 * @return \yii\db\ActiveQuery
	 */
	public function getProductionOrderId()
	{
		return $this->hasOne(ProductionOrder::className(), ['production_order_id' => 'production_order_id']);
	}

	/**
	 * @return \yii\db\ActiveQuery
	 */
	public function getDieId()
	{
		return $this->hasOne(Die::className(), ['die_id' => 'die_id']);
	}
}

/**
 * This is the model class for table "die".
 *
 * @property integer $die_id
 *
 * @property ProductionOrderDie[] $productionOrderDies
 * @property ProductionOrder[] $productionOrders
 */
class Die extends \yii\db\ActiveRecord
{
	/**
	 * @return \yii\db\ActiveQuery
	 */
	public function getProductionOrderDies()
	{
		return $this->hasMany(ProductionOrderDie::className(), ['die_id' => 'die_id']);
	}

	/**
	 * @return \yii\db\ActiveQuery
	 */
	public function getProductionOrders()
	{
		return $this->hasMany(ProductionOrder::className(), ['production_order_id' => 'production_order_id'])->viaTable('production_order_die', ['die_id' => 'die_id']);
	}
}

View production_order/create.php

<?php

use yii\helpers\Html;


/* @var $this yii\web\View */
/* @var $model app\models\ProductionOrder */
/* @var $modelDetailsDies app\models\ProductionOrderDie[] */

$this->title = 'Create Production Order';
$this->params['breadcrumbs'][] = ['label' => 'Production Orders', 'url' => ['index']];
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="production-order-create">

	<h1><?= Html::encode($this->title) ?></h1>

	<?= $this->render('_form', [
		'model' => $model,
		'modelDetailsDies' => $modelDetailsDies
	]) ?>

</div>

View production_order/_form.php

<?php
/* @var $this yii\web\View */
/* @var $model app\models\ProductionOrder */
/* @var $form yii\widgets\ActiveForm */
/* @var $modelDetailsDies app\models\ProductionOrderDie[] */

?>
<div class="production-order-form">

	<?php $form = ActiveForm::begin([
		'enableClientValidation' => false,
	]); ?>
	
	<?= $form->errorSummary($model); ?>
	<?= $form->errorSummary($modelDetailsDies); ?>
	
	<table class="table table-striped table-bordered detail-view">
		<tr><td colspan="4"><strong>Dies</strong></td>	</tr>
		<tr>
	
	<?php if ($model->isNewRecord || 
		(Yii::$app->user->can(AuthItem::ROLE_SALESPERSON) && $model->id_estado_orden == OrdenProduccion::STATUS_NEW) || 
		(Yii::$app->user->can(AuthItem::ROLE_DESIGNER) && ($model->id_estado_orden == OrdenProduccion::STATUS_INITIAL_DESIGN || $model->id_estado_orden == OrdenProduccion::STATUS_DESIGN_APPROVED)) || 
		(Yii::$app->user->can(AuthItem::ROLE_SUPERVISOR) && $model->id_estado_orden == OrdenProduccion::STATUS_PENDING_REVIEW)): ?>

		<?php foreach ($modelDetailsDies as $i => $modelDetailDie) : ?>
			<td>
				<div class="row production-order-die production-order-die-<?= $i ?>">
					<div class="col-md-10">
			<?= Html::activeHiddenInput($modelDetailDie, "[$i]production_order_die_id") ?>
			<?= Html::activeHiddenInput($modelDetailDie, "[$i]updateType", ['class' => 'update-type']) ?>
			<?= $form->field($modelDetailDie, "[$i]die_id")->widget(Select2::classname(), [
					'data' => ArrayHelper::map(Die::find()->all(),'die_id', 'name'),
					'language' => 'es',
					'options' => [
						'placeholder' => '--CHOOSE--',
					],
					'pluginOptions' => [
							'allowClear' => true
					],
				])->label(false); ?>

			Is Main Die?
			
			<?php if ($modelDetailDie->die_id) : ?>
			
				<?= $form->field($modelDetailDie, "[$i]main_die")->dropDownList(
						[ '1' => 'Yes', '0' => 'No' ],
						[
							'prompt'=>'--CHOOSE--',
						])->label(false); ?>

			<?php else : ?>
			
				<?= $form->field($modelDetailDie, "[$i]main_die")->dropDownList(
						[ '1' => 'Yes', '0' => 'No' ],
						[
							'prompt'=>'--CHOOSE--',
							'disabled' => 'disabled',
						])->label(false); ?>

				<?= $form->field($modelDetailDie, "[$i]main_die")->hiddenInput()->label(false) ?>
				
			<?php endif; ?>
			
						<div id="die-data-<?= $i ?>">
			<?php if ($modelDetailDie->die_id) : ?>
					
							<div><strong>Die data</strong></div>
							<table class="table">
								...
							</table>
			<?php endif; ?>
						</div>
					</div>
				</div>
			</td>
		<?php endforeach; ?>

	<?php else: ?>

		<?php foreach ($modelDetailsDies as $i => $modelDetailDie) : ?>
			<td>
				<div class="row production-order-die production-order-die-<?= $i ?>">
					<div class="col-md-10">
				<?= Html::activeHiddenInput($modelDetailDie, "[$i]production_order_die_id") ?>
				<?= Html::activeHiddenInput($modelDetailDie, "[$i]updateType", ['class' => 'update-type']) ?>
				<?= $form->field($modelDetailDie, "[$i]die_id")->hiddenInput()->label(false); ?>
				<?= $form->field($modelDetailDie, "[$i]main_die")->hiddenInput()->label(false); ?>
				
						<div id="die-data-<?= $i ?>">
				
			<?php if ($modelDetailDie->die_id) : ?>
				
							<div><strong>Die data</strong></div>
							<table class="table">
								<tr><th>Die name</th><td><?= $modelDetailDie->dieId->name ?></td></tr>
							</table>
				
			<?php endif; ?>
						</div>
					</div>
				</div>
			</td>
	<?php endforeach; ?>

	<?php endif; ?>
	
			<td>	
			</td>
		</tr>
	</table>
	

	<div class="form-group">
		<?= Html::submitButton($model->isNewRecord ? 'Create' : (($model->scenario == ProductionOrder::SCENARIO_SEND_TO_INITIAL_DESIGN || $model->scenario == ProductionOrder::SCENARIO_SEND_TO_REVIEW || $model->scenario == ProductionOrder::SCENARIO_SEND_TO_INVOICE) ? 'Save and Send' : 'Save'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
	</div>

	<?php ActiveForm::end(); ?>

</div>

Best Regards,

Because input validation is performed per model, it’s difficult to implement your business logic regarding the dies, as long as you handle them with an array of models. You want to see other dies when you validate one die, but you can’t see them because they are in other models.

So, you want to include all the information of related dies in a single model in order to validate them as a set.

class ProductionOrderForm extends ProductionOrder
{
    public  $die_ids = [0, 0, 0];
    public  $is_main = [false, false, false];
    ...

    public function rules()
    {
        return [
            ...
            ['die_ids', 'each', 'rule' => ['exist', 'targetClass' => Die::class, 'targetAttribute' => 'die_id']],
            ['is_main', 'validateDies'],
        ];
    }

    public function validateDies($attribute, $params, $validator)
    {
        $die_count = 0;
        $main_count = 0;
        for ($i = 0; $i < 3; $i++) {
            if ($this->die_ids[$i] != 0) {
                $die_count++;
                if ($is_main[$i]) {
                    $main_count++;
                }
            } else {
                $this->is_main[$i] = false;
            }
        }
        if ($die_count == 0) {
            $this->addError('die_ids', "You have to select at least one die.");
        } elseif ($die_count == 1) {
            if ($main_count != 1) {
                for ($i = 0; $i < 3; $i++) {
                    if ($this->die_ids[$i] != 0) {
                        $this->is_main[$i] = true;
                    }
                }
            }
        } else {
            if ($main_count != 1) {
                $this->addError('is_main', "You can select only 1 main die.");
            }
        }
    }
}

You can convert $die_ids and $is_main to an array of ProductionOrderDie before you save.

public function actionCreate()
{
    $model = new ProductionOrderForm();
    if ($model->load(Yii::$app->request->post())) {
        if ($model->validate()) {
            $model->save(false);
            for ($i = 0; $i < 3; $i++) {
                if ($model->die_ids[$i] != 0) {
                    $model2 = new ProductionOrderDie();
                    $model2->production_order_id = $model->production_order_id;
                    $model2->die_id = $model->die_ids[$i];
                    $model2->is_main = $model->is_main[$i];
                    $model2->save(false);
                }
            }
            return $this->redirect(['view', 'id' => $model->production_order_id]);
        }
    }
    return $this->render('create', [
        'model' => $model,
    ]);
}

This may not be exactly what you wanted and may not work as expected. But I hope you’ve got some idea.

Thanks @softark,

I will try adding this on the ProductionOrder ActiveRecord class

public function afterValidate()
{
    $dies_count = 0;
    $main_dies_count = 0;
    foreach ($this->productionOrderDies as $productionOrderDie) {
        if ($productionOrderDie->die_id != "") {
            $dies_count++;
            if ($productionOrderDie->main_die) {
                $main_dies_count++;
            }
        } else {
            $productionOrderDie->main_die = false;
        }
    }
    if ($dies_count == 0) {
        $this->addError(null, "At least one die is required.");
    } elseif ($dies_count == 1) {
        if ($main_dies_count != 1) {
            $this->productionOrderDies[0]->main_die = true;
        }
    } else {
        if ($main_dies_count == 0) {
            $this->addError(null, "You must select one of the dies as main die.");
        }
        else
        {
            $this->addError(null, "You cannot select more than one main die.");
        }
    }
    
    parent::afterValidate();
} 

Will let you know if this works.

Regards,

Looks nice. I didn’t think of afterValidate at all. :+1:

This might be dangerous, though. Isn’t there any possibility that the user selects the 2nd or the 3rd die as the only one die?

You are right @softark I will change that because the average user will select it in order starting from left to right (from index 0 to index 2) but nothing avoids that he can select the die at index 1 or 2 instead of the one at index 0.

After I write this though I realized that maybe $this->productionOrderDies will not bring me the POST data but either the database data or no data at all. Either way I will try with afterValidate to see what happens.

If it does not work I will try with the following function which I included in the ProductionOrder class which I could call from the controller sending the POST values. The drawback is that I cannot autoselect the main die if the user just include one die in the order. But the validation will force the user to do it.

public function checkDies($productionOrderDieArray)
{
    $error_count = 0;
    $dies_count = 0;
    $main_dies_count = 0;

    foreach ($productionOrderDieArray as $productionOrderDie) {
        if ($productionOrderDie->die_id != "") {
            $dies_count++;
            if ($productionOrderDie->main_die) {
                $main_dies_count++;
            }
        }
    }
    if ($dies_count == 0) {
        $this->addError(null, "At least one die is required.");
        $error_count++;
    } else {
        if ($main_dies_count == 0) {
            $this->addError(null, "You must select one of the dies as main die.");
            $error_count++;
        } else if ($main_dies_count > 1) {
            $this->addError(null, "You cannot select more than one main die.");
            $error_count++;
        }
    }
    
    return ($error_count == 0);
}

Regards,

At the end the afterValidate didn’t worked as expected.

I ended up using

public function checkDies($productionOrderDieArray)
{
    $error_count = 0;
    $dies_count = 0;
    $main_dies_count = 0;

    foreach ($productionOrderDieArray as $productionOrderDie) {
        if ($productionOrderDie->die_id != "") {
            $dies_count++;
            if ($productionOrderDie->main_die) {
                $main_dies_count++;
            }
        }
    }
    if ($dies_count == 0) {
        $this->addError(null, "At least one die is required.");
        $error_count++;
    } else {
        if ($main_dies_count == 0) {
            $this->addError(null, "You must select one of the dies as main die.");
            $error_count++;
        } else if ($main_dies_count > 1) {
            $this->addError(null, "You cannot select more than one main die.");
            $error_count++;
        }
    }
    
    return ($error_count == 0);
}

And calling it from the controller at

				if (Model::validateMultiple($modelDetailsDies) && checkDies($modelDetailsDies) $model->validate(null, false)) {

Thanks for all your help @softark and @demonking

Best regards,

1 Like