在 yii2 中实现多选下拉时出现违反完整性约束的错误

Integrity constraint violation error while implementing multiselect dropdown in yii2

我正在尝试使用 "cornernote/yii2-linkall " 和 "kartik-v/yii2-widget-select2" 实现多 select 下拉列表。我有 followed this guide 并且它适用于单个 multi-select 下拉菜单,所以现在我正在尝试以单一形式实现两个 multi-select 下拉菜单但我被卡住了. 当我重复执行更新功能时,它给出了 Integrity constraint violated 错误。

Integrity constraint violation – yii\db\IntegrityException
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '34-1' for key 'PRIMARY'
The SQL being executed was: INSERT INTO `supplier_to_industry` (`supplier_id`, `industry_id`) VALUES (34, 1)

Error Info: Array
(
    [0] => 23000
    [1] => 1062
    [2] => Duplicate entry '34-1' for key 'PRIMARY'
)

↵
Caused by: PDOException
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '34-1' for key 'PRIMARY'

in /var/www/html/final/vendor/yiisoft/yii2/db/Command.php at line 846

数据库 tables 如下所示: 部分(ID,名称) 行业(编号,名称)

supplier_to_part(supplier_id, part_id) supplier_to_industry(supplier_id, industry_id)

主要 table 是:- 供应商 (id,......)

SupplierController.php

  


<?php

namespace frontend\controllers;

use Yii;
use frontend\models\Supplier;
use frontend\models\SupplierSearch;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use yii\helpers\ArrayHelper;
use frontend\models\SupManpower;
use frontend\models\User;
use frontend\models\Industry;



use frontend\models\SupManpowerSearch;
use frontend\controllers\SupManpowerController;
use frontend\models\Model;

/**
 * SupplierController implements the CRUD actions for Supplier model.
 */
class SupplierController extends Controller
{
    /**
     * @inheritdoc
     */
    public function behaviors()
    {
        return [
            'verbs' => [
                'class' => VerbFilter::className(),
                'actions' => [
                    'delete' => ['POST'],
                ],
            ],
        ];
    }

    /**
     * Lists all Supplier models.
     * @return mixed
     */
    public function actionIndex()
    {
        $searchModel = new SupplierSearch();
        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);

        return $this->render('index', [
            'searchModel' => $searchModel,
            'dataProvider' => $dataProvider,
        ]);
    }

    /**
     * Displays a single Supplier model.
     * @param integer $id
     * @return mixed
     */
    public function actionView($id)
    {
        return $this->render('view', [
            'model' => $this->findModel($id),
        ]);
    }

    /**
     * Creates a new Supplier model.
     * If creation is successful, the browser will be redirected to the 'view' page.
     * @return mixed
    
     */
    
  public function actionCreate()
    {
        $model = new Supplier();
         $modelsSupManpower = [new SupManpower];
    $user = new User();

        if ($model->load(Yii::$app->request->post()) ) {
         $model->user_id = Yii::$app->user->getId();
           $model->save(); 
           $user = $this->findUserModel($model->user_id);
        $user->pin = $model->pin;
        $user->country = $model->country;
        $user->state = $model->state;
        $user->city = $model->city;
        $user->save();
         
            $modelsSupManpower = Model::createMultiple(SupManpower::classname());
            Model::loadMultiple($modelsSupManpower, Yii::$app->request->post());

           

            // validate all models
            $valid = $model->validate();
            $valid = Model::validateMultiple($modelsSupManpower) && $valid;

            if ($valid) {
                $transaction = \Yii::$app->db->beginTransaction();
                try {
                    if ($flag = $model->save(false)) {
                        foreach ($modelsSupManpower as $modelSupManpower) {
                            $modelSupManpower->supplier_id = $model->id;
                            if (! ($flag = $modelSupManpower->save(false))) {
                                $transaction->rollBack();
                                break;
                            }
                        }
                    }
                    if ($flag) {
                        $transaction->commit();
                        return $this->redirect(['view', 'id' => $model->id]);
                    }
                } catch (Exception $e) {
                    $transaction->rollBack();
                }
            }
         
            
        } elseif (!\Yii::$app->request->isPost) {
            $model->load(Yii::$app->request->get());
            $model->part_ids = ArrayHelper::map($model->parts, 'name', 'name');
             $model->industry_ids = ArrayHelper::map($model->industries, 'name', 'name');
        
            return $this->render('create', [
                'model' => $model,
                'modelsSupManpower' => (empty($modelsSupManpower)) ? [new SupManpower] : $modelsSupManpower
            ]);
        }
    }


protected function findUserModel($id)
{
    if (($model = User::findOne($id)) !== null) {
        return $model;
    } else {
        throw new NotFoundHttpException('The requested page does not exist.');
    }
}

    /**
     * Updates an existing Supplier model.
     * If update is successful, the browser will be redirected to the 'view' page.
     * @param integer $id
     * @return mixed
      
     */
   public function actionUpdate($id)
    {
        $model = $this->findModel($id);
        $modelsSupManpower = $model->supManpowers;

        if ($model->load(Yii::$app->request->post())) {
         $user = $this->findUserModel($model->user_id);
        $user->pin = $model->pin;
        $user->country = $model->country;
        $user->state = $model->state;
        $user->city = $model->city;
        $user->save();

            $oldIDs = ArrayHelper::map($modelsSupManpower, 'id', 'id');
            $modelsSupManpower = Model::createMultiple(SupManpower::classname(), $modelsSupManpower);
            Model::loadMultiple($modelsSupManpower, Yii::$app->request->post());
            $deletedIDs = array_diff($oldIDs, array_filter(ArrayHelper::map($modelsSupManpower, 'id', 'id')));

            // ajax validation
            if (Yii::$app->request->isAjax) {
                Yii::$app->response->format = Response::FORMAT_JSON;
                return ArrayHelper::merge(
                    ActiveForm::validateMultiple($modelsSupManpower),
                    ActiveForm::validate($model)
                );
            }

            // validate all models
            $valid = $model->validate();
            $valid = Model::validateMultiple($modelsSupManpower) && $valid;

            if ($valid) {
                $transaction = \Yii::$app->db->beginTransaction();
                try {
                    if ($flag = $model->save(false)) {
                        if (! empty($deletedIDs)) {
                            SupManpower::deleteAll(['id' => $deletedIDs]);
                        }
                        foreach ($modelsSupManpower as $modelSupManpower) {
                            $modelSupManpower->supplier_id = $model->id;
                            if (! ($flag = $modelSupManpower->save(false))) {
                                $transaction->rollBack();
                                break;
                            }
                        }
                    }
                    if ($flag) {
                        $transaction->commit();
                        return $this->redirect(['view', 'id' => $model->id]);
                    }
                } catch (Exception $e) {
                    $transaction->rollBack();
                }
            }
        }
   elseif (!\Yii::$app->request->isPost) {
            $model->load(Yii::$app->request->get());
            $model->part_ids = ArrayHelper::map($model->parts, 'name', 'name');
            $model->industry_ids = ArrayHelper::map($model->industries, 'name', 'name');
            return $this->render('update', [
            'model' => $model,
            'modelsSupManpower' => (empty($modelsSupManpower)) ? [new SupManpower] : $modelsSupManpower
        ]);
        }
        
    }  
    

    /**
     * Deletes an existing Supplier model.
     * If deletion is successful, the browser will be redirected to the 'index' page.
     * @param integer $id
     * @return mixed
     */
    public function actionDelete($id)
    {
        $this->findModel($id)->delete();

        return $this->redirect(['index']);
    }

    /**
     * Finds the Supplier model based on its primary key value.
     * If the model is not found, a 404 HTTP exception will be thrown.
     * @param integer $id
     * @return Supplier the loaded model
     * @throws NotFoundHttpException if the model cannot be found
     */
    protected function findModel($id)
    {
        if (($model = Supplier::findOne($id)) !== null) {
            return $model;
        } else {
            throw new NotFoundHttpException('The requested page does not exist.');
        }
    }
}


 
   _form.php


<?php

use yii\helpers\Html;
use yii\widgets\ActiveForm;
use frontend\models\Part;
use frontend\models\Industry;
use kartik\select2\Select2;
use yii\helpers\ArrayHelper;

use frontend\models\Manpower;
use wbraganca\dynamicform\DynamicFormWidget;


/* @var $this yii\web\View */
/* @var $model frontend\models\Supplier */
/* @var $form yii\widgets\ActiveForm */
?>

<div class="supplier-form">

   <?php $form = ActiveForm::begin(['id' => 'dynamic-form']); ?>

    <?= $form->field($model, 'company_constitution')->textInput(['maxlength' => true]) ?>

    <?= $form->field($model, 'yoe')->textInput() ?>

    <?= $form->field($model, 'door_no')->textInput() ?>

    <?= $form->field($model, 'street')->textInput(['maxlength' => true]) ?>

    <?= $form->field($model, 'locality')->textInput(['maxlength' => true]) ?>

    <?= $form->field($model, 'iarea_name')->textInput(['maxlength' => true]) ?>

    <?= $form->field($model, 'state')->textInput(['maxlength' => true]) ?>

    <?= $form->field($model, 'city')->textInput(['maxlength' => true]) ?>

    <?= $form->field($model, 'country')->textInput(['maxlength' => true]) ?>

    <?= $form->field($model, 'pin')->textInput() ?>

    <?= $form->field($model, 'total_facility_area')->textInput(['maxlength' => true]) ?>

    <?= $form->field($model, 'power_load_capacity')->textInput(['maxlength' => true]) ?>

    <?= $form->field($model, 'type')->textInput(['maxlength' => true]) ?>

    <?= $form->field($model, 'total_ton_capacity')->textInput() ?>

    <?= $form->field($model, 'total_numbers')->textInput() ?>

    <?= $form->field($model, 'total_direct_employees')->textInput() ?>

    <?= $form->field($model, 'total_indirect_employees')->textInput() ?>

    <?= $form->field($model, 'unionised')->textInput(['maxlength' => true]) ?>

    <?= $form->field($model, 'turnover_year')->textInput(['maxlength' => true]) ?>

    <?= $form->field($model, 'turnover')->textInput(['maxlength' => true]) ?>

   

 <?= $form->field($model, 'part_ids')->widget(Select2::className(), [
            'model' => $model,
            'attribute' => 'part_ids',
            'data' => ArrayHelper::map(Part::find()->all(), 'name', 'name'),
            'options' => [
                'multiple' => true,
            ],
            'pluginOptions' => [
                'parts' => true,
            ],
        ]); ?>
        
         <?= $form->field($model, 'industry_ids')->widget(Select2::className(), [
            'model' => $model,
            'attribute' => 'industry_ids',
            'data' => ArrayHelper::map(Industry::find()->all(), 'name', 'name'),
            'options' => [
                'multiple' => true,
            ],
            'pluginOptions' => [
                'industrys' => true,
            ],
        ]); ?>
        
        
        <div class="panel panel-default">
        <div class="panel-heading"><h4><i class="glyphicon glyphicon-envelope"></i> SupManpower</h4></div>
        <div class="panel-body">
             <?php DynamicFormWidget::begin([
                'widgetContainer' => 'dynamicform_wrapper', // required: only alphanumeric characters plus "_" [A-Za-z0-9_]
                'widgetBody' => '.container-items', // required: css class selector
                'widgetItem' => '.item', // required: css class
                'limit' => 4, // the maximum times, an element can be cloned (default 999)
                'min' => 1, // 0 or 1 (default 1)
                'insertButton' => '.add-item', // css class
                'deleteButton' => '.remove-item', // css class
                'model' => $modelsSupManpower[0],
                'formId' => 'dynamic-form',
                'formFields' => [
                    'role',
                    'role_total',
                  
                ],
            ]); ?>

            <div class="container-items"><!-- widgetContainer -->
            <?php foreach ($modelsSupManpower as $i => $modelSupManpower): ?>
                <div class="item panel panel-default"><!-- widgetBody -->
                    <div class="panel-heading">
                        <h3 class="panel-title pull-left">Sup Manpower</h3>
                        <div class="pull-right">
                            <button type="button" class="add-item btn btn-success btn-xs"><i class="glyphicon glyphicon-plus"></i></button>
                            <button type="button" class="remove-item btn btn-danger btn-xs"><i class="glyphicon glyphicon-minus"></i></button>
                        </div>
                        <div class="clearfix"></div>
                    </div>
                    <div class="panel-body">
                        <?php
                            // necessary for update action.
                            if (! $modelSupManpower->isNewRecord) {
                                echo Html::activeHiddenInput($modelSupManpower, "[{$i}]id");
                            }
                        ?>
                       
                        <div class="row">
                            <div class="col-sm-6">
                                <?= $form->field($modelSupManpower, "[{$i}]role")->dropDownList(
                      ArrayHelper::map(Manpower::find()->all(),'manpower_name','manpower_name'),
                      [
                
          'prompt'=>'select manpower category',                
                 
                    ]); ?>
                            </div>
                            <div class="col-sm-6">
                                <?= $form->field($modelSupManpower, "[{$i}]role_total")->textInput(['maxlength' => true]) ?>
                            </div>
                        </div><!-- .row -->
                    
                    </div>
                </div>
            <?php endforeach; ?>
            </div>
            <?php DynamicFormWidget::end(); ?>
        </div>
    </div>

    
    <div class="form-group">
        <?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
    </div>

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

</div>



 
   Supplier.php

<?php

namespace frontend\models;

use Yii;
use yii\web\UploadedFile;
use yii\db\ActiveRecord;
use yii\behaviors\TimestampBehavior;
use common\models\MasterAdmin;
use cornernote\linkall\LinkAllBehavior;
use frontend\models\Industry;
/**
 * This is the model class for table "supplier".
 *
 * @property integer $id
 * @property string $company_constitution
 * @property integer $yoe
 * @property integer $door_no
 * @property string $street
 * @property string $locality
 * @property string $iarea_name
 * @property string $state
 * @property string $city
 * @property string $country
 * @property integer $pin
 * @property string $total_facility_area
 * @property string $power_load_capacity
 * @property string $type
 * @property integer $total_ton_capacity
 * @property integer $total_numbers
 * @property integer $total_direct_employees
 * @property integer $total_indirect_employees
 * @property string $unionised
 * @property string $turnover_year
 * @property string $turnover
 * @property integer $user_id
 * @property string $created_at
 * @property string $updated_at
 *
 * @property User $user
 * @property SupplierToPart[] $supplierToParts
 * @property Part[] $parts
 */
class Supplier extends MasterAdmin
{
    /**
     * @inheritdoc
     */
      public $part_ids;
      public $industry_ids;
     public function behaviors()
    {
        return [
            \cornernote\linkall\LinkAllBehavior::className(),
        ];
    }
    public static function tableName()
    {
        return 'supplier';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['company_constitution', 'yoe', 'door_no', 'street', 'locality', 'iarea_name', 'state', 'city', 'country', 'pin', 'total_facility_area', 'power_load_capacity', 'type', 'total_ton_capacity', 'total_numbers', 'total_direct_employees', 'total_indirect_employees', 'unionised', 'turnover_year', 'turnover',  'part_ids', 'industry_ids'], 'required'],
            [['yoe', 'door_no', 'pin', 'total_ton_capacity', 'total_numbers', 'total_direct_employees', 'total_indirect_employees'], 'integer'],
            [['company_constitution', 'state', 'city', 'country'], 'string', 'max' => 50],
            [['street', 'locality', 'total_facility_area', 'power_load_capacity', 'type', 'turnover'], 'string', 'max' => 100],
            [['iarea_name'], 'string', 'max' => 200],
            [['unionised'], 'string', 'max' => 5],
            [['turnover_year'], 'string', 'max' => 10],
           
           [['user_id'], 'unique'],
            [['user_id'], 'exist', 'skipOnError' => true, 'targetClass' => User::className(), 'targetAttribute' => ['user_id' => 'id']],
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'company_constitution' => 'Company Constitution',
            'yoe' => 'Yoe',
            'door_no' => 'Door No',
            'street' => 'Street',
            'locality' => 'Locality',
            'iarea_name' => 'Iarea Name',
            'state' => 'State',
            'city' => 'City',
            'country' => 'Country',
            'pin' => 'Pin',
            'total_facility_area' => 'Total Facility Area',
            'power_load_capacity' => 'Power Load Capacity',
            'type' => 'Type',
            'total_ton_capacity' => 'Total Ton Capacity',
            'total_numbers' => 'Total Numbers',
            'total_direct_employees' => 'Total Direct Employees',
            'total_indirect_employees' => 'Total Indirect Employees',
            'unionised' => 'Unionised',
            'turnover_year' => 'Turnover Year',
            'turnover' => 'Turnover',
          
            
        ];
    }

public function afterSave($insert, $changedAttributes)
    {
        $parts = [];
        $industries = [];
     
       // foreach (array_merge($this->part_ids,$this->industry_ids) as $part_name ) {
           foreach ($this->part_ids  as $part_name ){ 
             foreach ($this->industry_ids as $industry_name ){ 
            $part = Part::getPartByName($part_name);
             $industry = Industry::getIndustryByName($industry_name);
            if ($part ||$industry ) {
                $parts[] = $part;
           
                $industries[] = $industry;
            }
        } 
        }
       
       
        $this->linkAll('industries', $industries );
       
        $this->linkAll('parts', $parts );
        parent::afterSave($insert, $changedAttributes);
    }
 
  /**
     * @return \yii\db\ActiveQuery
     */
    public function getSupManpowers()
    {
        return $this->hasMany(SupManpower::className(), ['supplier_id' => 'id']);
    }


    /**
     * @return \yii\db\ActiveQuery
     */
    public function getUser()
    {
        return $this->hasOne(User::className(), ['id' => 'user_id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getSupplierToParts()
    {
        return $this->hasMany(SupplierToPart::className(), ['supplier_id' => 'id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getParts()
    {
        return $this->hasMany(Part::className(), ['id' => 'part_id'])->viaTable('supplier_to_part', ['supplier_id' => 'id']);
    }
     /**
     * @return \yii\db\ActiveQuery
     */
    /**
     * @return \yii\db\ActiveQuery
     */
    public function getSupplierToIndustries()
    {
        return $this->hasMany(SupplierToIndustry::className(), ['supplier_id' => 'id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getIndustries()
    {
        return $this->hasMany(Industry::className(), ['id' => 'industry_id'])->viaTable('supplier_to_industry', ['supplier_id' => 'id']);
    } 
}

afterSave()有什么问题吗??任何帮助

在所需的表单字段上使用 $model 变量调用模型名称。例如:

 <?= $form->field($model->industry,'industry_ids')->widget(Select2::className(),['model' => $model->industry, ...

问题出在 foreach 上。

而不是

              foreach ($this->part_ids  as $part_name ){ 
                foreach ($this->industry_ids as $industry_name ){ 
                      $part = Part::getPartByName($part_name);
                     $industry = Industry::getIndustryByName($industry_name);
                   if ($part ||$industry ) {
                    $parts[] = $part;
                    $industries[] = $industry;
                   }
               }
          }

需要使用:

       foreach ($this->production_scope as $part_name ){ 
                $part = Part::getPartByName($part_name);
                if ($part) {
                    $parts[] = $part;
                }
            }
        foreach ($this->target_industry as $industry_name ){ 
                $industry = Industry::getIndustryByName($industry_name);
                if ($industry) {
                    $industries[] = $industry;
                }
            }