Checkboxlist not saving to the DB

Im new to yii2 and im working on an already build website and im trying to add new fields to the form, its all working upon 1 field, this field is a checkbox list, which wont save anything to the DB.

view.php


$form->field($model, 'sort_abc')->checkBoxLIst( ['a' => 'Item A', 'b' => 'Item B', 'c' => 'Item C'])->label($model->getAttributeLabel('sort_abc'));



models/filter.php





<?php


namespace common\models;


use Yii;

use yii\db\Query;

use common\components\ActiveStateBehavior;

use yii\behaviors\TimestampBehavior;


/**

 * This is the model class for table "{{%filter}}".

 *

 * @property integer $id

 * @property integer $is_enabled

 * @property integer $is_deleted

 * @property string $description

 * @property integer $created_at

 * @property integer $update_at

 */

class Filter extends \yii\db\ActiveRecord

{

    const STATUS_ACTIVE = 1;

    const STATUS_INACTIVE = 0;


    /**

     * @inheritdoc

     */

    public static function tableName()

    {

        return '{{%filter}}';

    }


    /**

     * @inheritdoc

     */

    public function behaviors()

    {

        return [

            ActiveStateBehavior::className(),

            [

                'class' => 'nzz\translations\ActiveTranslationBehavior',

                'attributes' => ['name'],

                'languages' => Yii::$app->params['languages'],

                'relation' => 'translations',

            ],

            TimestampBehavior::className(),

       ];

    }


    /**

     * @inheritdoc

     */

    public function rules()

    {

        return [

            [['name', 'description'], 'required'],

            [['is_enabled', 'is_deleted', 'created_at', 'updated_at', 'visible_on_portal', 'is_blocked'], 'integer'],

            [['global_name' ], 'string'],

            [['sort_abc' ], 'string'],

            [['sort_index'], 'safe'],

        ];

    }


    /**

     * @inheritdoc

     */

    public function attributeLabels()

    {

        return [

            'id' => Yii::t('app', 'ID'),

            'name' => Yii::t('app', 'Name'),

            'description' => Yii::t('app', 'Description'),

            'is_enabled' => Yii::t('app', 'Active'),

            'is_deleted' => Yii::t('app', 'Deleted'),

            'visible_on_portal' => Yii::t('app', 'visibleOnPortal'),

            'is_blocked' => Yii::t('app', 'Blocked'),

            'global_name' => Yii::t('app', 'filterGlobalName'),

            'sort_index' => Yii::t('app', 'sortIndex'),

            'sort_abc' => Yii::t('app', 'sortAbc'),

        ];

    }

}


}

controllers/filtercontroller.php


<?php

namespace backend\controllers;

use Yii;

use yii\web\Controller;

use backend\models\FilterSearch;

use common\models\Filter;


class FilterController extends Controller{

    public function behaviors()

    {

        return [

            'access' => [

                'class' => \yii\filters\AccessControl::className(),

                'rules' => [

                    [

                        'allow' => true,

                        'actions' => ['index'],

                        'roles' => ['filterRead'],

                    ],

                    [

                        'allow' => true,

                        'actions' => ['view'],

                        'roles' => ['filterWrite'],

                    ],

                    [

                        'allow' => true,

                        'actions' => ['delete'],

                        'roles' => ['filterDelete'],

                    ],

                ]

            ],

        ];

    }


    public function actionIndex(){

        $searchModel = new FilterSearch;

        $searchModel->load($_GET);

        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);


        return $this->render('index', [

            'searchModel' => $searchModel,

            'dataProvider' => $dataProvider,

        ]);

    }

    public function actionView($id = null){

        $model = new Filter();

        if(!empty($id)){

            $model = Filter::findOne(['id'=>$id]);

        }

        if(Yii::$app->request->isPost){

            $post = Yii::$app->request->post();

            if($model->load($post) && $model->save()){

                if(isset($post['redirect']) && !empty($post['redirect'])){

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

                }

                Yii::$app->end();

            }

        }

        return $this->renderAjax('view',['model'=>$model]);

    }


}

?>



Add sort_abc to model rules.

I already did(forgotten to add it in the demo above), still not working, it only saves 1 value instead of multiple selected values.

/* moved to yii2 section */

Check validation in the controller, add errorsummary in the view.

And/or try with ->save(false) to skip validation and usually you get a db error for example duplicate key or fk index wong/missing. You can also check db query in the log to see if the field is in update query

Hello. I have the same need : i have a text field that is a SET and want to update it with checkboxes.

(i’ll adapt my case to be like the first post)
In the DB, i have the field sort_abc as SET(‘a’,‘b’,‘c’) and thus data in it is for example “a,b”.

The first problem is that the view code (same as first post) expect my content to be an array, not a string.
The second pb is that on save in the controller (also same as first post), load() + save() don’t save it, again it can’t know that the received array from the form should be imploded.

At first, the code was using arrays all the time in the model, there was also this rule:
[‘sort_abc’, ‘each’, ‘rule’ => [‘in’, ‘range’ => $list]];
And it was doing implode and explodes like this:

       public function beforeSave($insert): bool
       {
               $this->sort_abc = implode(",", $this->sort_abc);
               return parent::beforeSave($insert);
       }
       public function afterFind(): void
       {
               $this->sort_abc = explode(",", $this->sort_abc);
       }

But it feels like bad code and I wanted to remove them.

In conclusion: is there a way to handle a array-like field, in array form or string form (doesn’t matter to me) that pleases load() and checkBoxList() ?

With help, i found the solution:

// in model
    public function behaviors(): array
    {
        return array_merge(
            parent::behaviors(),
            [MyBehavior::class]
        );
    }

// and
class MyBehavior extends Behavior
{
    /**
     * @return assoc-array Actions to impact and their related function in this very class.
     */
    public function events(): array
    {
        return [
            ActiveRecord::EVENT_AFTER_FIND => 'afterFindAfterSave',
            ActiveRecord::EVENT_BEFORE_INSERT => 'beforeSave',
            ActiveRecord::EVENT_BEFORE_UPDATE => 'beforeSave',
            ActiveRecord::EVENT_AFTER_INSERT => 'afterFindAfterSave',
            ActiveRecord::EVENT_AFTER_UPDATE => 'afterFindAfterSave',
            ActiveRecord::EVENT_INIT => 'afterFindAfterSave', // If making new Model(); without sort_abc data, it's null, and I want [] instead.
        ];
    }

    /**
     * When afterFind: Change DB string to usable array.
     * When afterSave: Reverse the beforeSave()
     */
    public function afterFindAfterSave(): void
    {
        if (empty($this->owner->sort_abc)) {
                $this->owner->sort_abc = [];
        } else {
                $this->owner->sort_abc = explode(',', $this->owner->sort_abc);
        }
    }

    /**
     * Change array to string for DB.
     */
    public function beforeSave(): void
    {
        $this->owner->sort_abc = implode(',', $this->owner->sort_abc);
    }
}