Cactiverecord Saving New Record With Attributes

here’s my code from controller




public function actionAddNote()

{

   $note = new Notes();


   if (Yii::app()->request->isPostRequest && isset($_POST['Notes'])) {//POST

      $note->attributes = $_POST['Notes']; //FAILS

      $note->_attributes = $_POST['Notes']; //SUCCESS

      $note->save();	

   }

}



$_POST[‘Notes’] contains array like [title => some_data] posted via ActiveForm

my question is, is it normal behavior that setting $note->_attributes works but $note->attributes does not (according to manual http://www.yiiframework.com/doc/guide/1.1/en/database.ar )

  1. Nope this is not normal and I am wondering how your code would work. You are accessing a private property!?

  2. rendering your view in the else clause does not fetch the case where validation fails and save() returns false. You should render view even on post request so errors show up in the form when validation is not successfull.

there’s no private properties when __set is used like in its parents. anyway, i’m running code on IIS Win8 x64 + PHP 5.5.7 x64 NTS, maybe it has some impact.

CeBe, are you able to save array of attributes using technique from tutorial?

like


$note->attributes = $_POST['Notes']; //FAILS

$note->save();

'cause it’s weird to have $_attributes and $attributes. I’m new to this framework, and i have some shock so far

p.s.

i cut validation and transaction code to simplify the issue

How exactly does your code "fail"?

nothing is set using $note->attributes

How did you define validation rules? Attributes set via massive assignment need to be declared "safe" or need validation rules.

http://www.yiiframework.com/doc/guide/1.1/en/form.model#securing-attribute-assignments

i didn’t define any. Fine then, i defined rule for model Notes next way




class Notes extends CActiveRecord

{

	public static function model($className=__CLASS__)

	{

		return parent::model($className);

	}

	

	public function scopes()

	{

		return [];

	}

	

	public function rules()

	{

	    return [['title', 'length', 'min' => 4]];

	}

	

}



And yes, now it sets $note->attributes and on save puts error " 0 => string ‘Title is too short (minimum is 4 characters).’" which is fine.

So, this is normal behavior to silently refuse setting atributes if i don’t want to apply any validation rules? If i just want to make a bulk save, what can you suggest? (i expect it makes mysql prepared statements which must fix all sort of injections by default)

reagards

This is what you need then:

http://www.yiiframework.com/doc/api/1.1/CActiveRecord#saveAttributes-detail

Btw: it fails silently because it filters out what comes in post. If someone sends you additional fields or for example the submit button also has a value in POST data you do not want that in the record and you still want your record to save instead of failing when the rest of attributes are valid.

that’s what i get when using


$note->saveAttributes($_POST['Notes']);

my tries to avoid rules were not successful




public function rules()

{

   return [['title']]; //FAIL

   return [['title', '']]; //FAIL

}



About fields, i’m not sure what you mean. This class is supposed to get attributes from table schema (which it does, as i cannot assign non-existing attribute for $note)

this is still question for me for saving new record.

Thank you CeBe for your time and links

another scenario in which i may want to use new record for selection into data provider + grid view


    public function actionGetNotes()

    {

        $dp_notes = new CActiveDataProvider('Notes');

        $filter_note = new Notes();

        

        if (!empty($_GET['Notes'])) {

            $filter_note->attributes = $_GET['Notes']; //silently FAILS to set values for attributes w/o rules() in Notes model

            $dp_notes->setCriteria((new CDbCriteria())

                ->compare('note_id', $filter_note->note_id, false)

                ->compare('title', $filter_note->title, true));

        }

        

        $this->render('list', [

            'dp_notes' => $dp_notes,

            'filter_note' => $filter_note

        ]);

    }

which in fact, ignores all rules, as i can serach for title with only 1 letter, but how can i search for created_date if i don’t need rules for its value as it creates on db server? I got a reply live chat that i can select record, reset values and then fill as it is expected with $note->setAttributes(). But why i have to load db server with 1 useless select?

Try this rules definition:




public function rules()

{

   return [['title,note_id','safe']];

}



if it is works extend with scenario:




public function rules()

{

   return [['title,note_id','safe','on' => 'search']];

}






$filter_note = new Notes('search');



thanks this workaround works nicely.


public function rules()

{

   return [['title,note_id','safe']];

}

after changing code to this


	public function rules()

	{

	    return [

    	    ['title', 'safe', 'on' => 'add,filter,update'],

    	    ['note_id,created_date', 'safe', 'on' => 'add,filter']

        ];

	}



the current realization of ActiveRecord looks clear for me.