3

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

Ahmad Asjad
  • 825
  • 1
  • 8
  • 29
  • to show multiple items selected inside a multi-select you just need to set the values as array to the model field that is used to show the multiple select. – Muhammad Omer Aslam Feb 03 '18 at 21:12

1 Answers1

3

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,
    ],
]);
marche
  • 1,756
  • 1
  • 14
  • 24
  • My question is how do I will set multiple item selected in view – Ahmad Asjad Jan 28 '17 at 09:53
  • In my example, the multiple items field is `activities_ids` – marche Jan 28 '17 at 15:52
  • Give me an example to show on view like $form->field($modal_obj, 'attribute_name')->dropdownlist($items, ['multiple'=>true]) – Ahmad Asjad Jan 28 '17 at 17:57
  • Added example with Select2 widget by Krajee – marche Jan 28 '17 at 22:44
  • I think $data variable in the widget is array, but my question is how do I will set two options as selected when we are in update form? – Ahmad Asjad Jan 28 '17 at 22:56
  • yea, `$data` is an associative array, with `'value' => 'Option Name'`. Just by setting `'multiple' => true,` the widget will allow to choose many options, which will be sent through post as an array with the values selected. In the model in the `afterSave` method the model takes these values and links them to the model, creating the relationship with the elements from the other table. – marche Jan 29 '17 at 02:26
  • If you see my question seriously, you'll get there that it's already being used, and I'm capable to select multiple. My question how to set selected multiple when rendering form when I click on edit button. – Ahmad Asjad Jan 29 '17 at 09:48
  • Oh, sorry. Added `afterFind` code. There you find the ids of the related records and save them on the attribute that you use for the form. – marche Jan 29 '17 at 14:19