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,