How to set multi select value from array object in

2019-05-22 12:57发布

问题:

I have table which have multiple reference to ohter tables like

user
id         name         email
categories
id         title
user_categories
user_id    category_id

Here a user will have multiple category associated with him/her

I am able to save these successfully with new records like following

View File:

echo $form->field($package_categories, 'category_id')->dropDownList( ArrayHelper::map(
StudyMaterialCategories::find()->all(), 'id', 'title'), 
['multiple' => true]
);

Save New record:

$model = new Packages();
$package_categories = new PackageCategories();
$request = Yii::$app->request;
if ($request->isPost) {
    $transaction = Yii::$app->db->beginTransaction();
    try {
        $post = $request->post();
        $model->load($post);
        $model->save();
        foreach ($post['PackageCategories']['category_id'] as $key => $value) {
            $package_categories = new PackageCategories();
            $package_categories->category_id = $value;
            $package_categories->package_id = $model->id;
            $package_categories->save();
        }
        $transaction->commit();
        return $this->redirect(['view', 'id' => $model->id]);
    } catch (Exception $ex) {
        $transaction->rolback();
        Yii::$app->session->setFlash("error", $ex->getMessage());
    }
}

Till now It's running successfully.

But I'm stuck when going to update the table. The problem part is dropdown list. How to set multiple selected option as per database if I'm coming with array of object. Have a look on the following code

$package_categories = PackageCategories::find()
->where('package_id=:package_id', ['package_id' => $id])->all();
if (count($package_categories) < 1) {
    $package_categories = new PackageCategories();
}
$request = Yii::$app->request;
if ($request->isPost) {
    $transaction = Yii::$app->db->beginTransaction();
    try {
        $post = $request->post();
        $model->load($post);
        $model->save();
        $package_categories = new PackageCategories();
        $package_categories->deleteAll(
            "package_id=:package_id", 
            [':package_id' => $model->id]
        );
        foreach ($post['PackageCategories']['category_id'] as $key => $value) {
            $package_categories = new PackageCategories();
            $package_categories->category_id = $value;
            $package_categories->package_id = $model->id;
            $package_categories->save();
        }
        $transaction->commit();
        return $this->redirect(['view', 'id' => $model->id]);
    } catch (Exception $ex) {
        $transaction->rolback();
        Yii::$app->session->setFlash("error", $ex->getMessage());
    }
}

if I try to get first object of the array $package_categories of only able to set selected one option

回答1:

This is an example code of a model class Permit which has a many to many relationship with Activity through PermitActivity (pivot table model).

Model Class Activity

public class Permit extends \yii\db\ActiveRecord {
    public $activities_ids;
    ...
    public function rules() {
        return [
            ...
            [['activities_ids'], 'safe'],
            ...
        ];
    }
    ...
    // Method called after record is saved, be it insert or update.
    public function afterSave($insert, $changedAttributes) {
        // If this is not a new record, unlink all records related through relationship 'activities'
        if(!$this->isNewRecord) {
            // We unlink all related records from the 'activities' relationship.
            $this->unlinkAll('activities', true);
            // NOTE: because this is a many to many relationship, we send 'true' as second parameter
            // so the records in the pivot table are deleted. However on a one to many relationship
            // if we send true, this method will delete the records on the related table. Because of this,
            // send false on one to many relationships if you don't want the related records deleted.
        }

        foreach($this->activities_ids as $activity_id) {
            // Find and link every model from the array of ids we got from the user.
            $activity = Activity::findOne($activity_id);
            $this->link('activities', $activity);
        }

        parent::afterSave($insert, $changedAttributes);
    }
    ...
    // Declare relationship with Activity through the pivot table permitActivity
    public function getActivities(){
        return $this->hasMany(Activitiy::className(), ['id' => 'activity_id'])
            ->viaTable('permitActivity',['permit_id' => 'id']);
    }
    ...
    public function afterFind(){
        parent::afterFind();
        $this->activities_id = ArrayHelper::getColumn($this->activities, 'id');
    }
}

This way the model class is the one responsible for creating and updating the relationship using the pivot table.

The most important thing is to have the relationship method declared correctly.

Edit

This is an example of the view using kartikv\widgets\Select2. I don't really know if dropDownList supports multiple select, however Select2 has so many useful features i usually use it over other options.

echo $form->field($model, 'activities')->widget(Select2::classname(), [
    'data' => $data,
    'options' => [
        'placeholder' => '...'
    ],
    'pluginOptions' => [
        'allowClear' => true,
        'multiple' => true,
    ],
]);