<p>I think your problem is that the record is not being populated – the <code>save()</code> method does take an array of attributes, but that would be the <em>second</em> parameter, as per the <a href="http://www.yiiframework.com/doc/api/1.1/CActiveRecord#save-detail" rel="nofollow noreferrer">CActiveRecord docs</a>.</p>

<p>Try this:</p>

<pre><code>$record = new MyPluginRecord();
$record-&gt;setAttributes( $contact-&gt;getAttributes() );
$record-&gt;save();
</code></pre>

<p>EDIT:</p>

<p>The BaseRecord's <code>setAttributes</code> method <a href="https://craftcms.stackexchange.com/questions/2788/plugin-only-saving-one-column-in-database">seems a bit unreliable</a>. If only some values (or none) are saved, you can try multiple calls to <code>$record-&gt;setAttribut()</code> instead:</p>

<pre><code>$attributes = $contact-&gt;getAttributes();
foreach ( $attributes as $key =&gt; $value ) {
   $record-&gt;setAttribute( $key, $value );
}
$record-&gt;save();
</code></pre>

<p>EDIT 2:</p>

<p>I haven't had the time to test this, but if you're having trouble saving all attributes using <code>$record-&gt;setAttributes( $model-&gt;getAttributes() );</code> you could also try flattening the values:</p>

<pre><code>$record-&gt;setAttributes( $model-&gt;getAttributes( null, true ) );
</code></pre>

CC BY-SA 3.0
2015-03-26T21:57:30.813Z
This got me closer! I was only getting the `email` field populated using this method. However, when I logged out what was in the `getAttributes()` all of the data was there. Strange.

Thanks to [this article](http://craftcms.stackexchange.com/questions/2788/plugin-only-saving-one-column-in-database) I Was at least able to follow along with what was happing because of your answer so thank you very much!
Damon
CC BY-SA 3.0
2015-03-27T08:32:19.143Z
@dragonslovetacos Hm, it's really odd how ```$record->saveAttributes()``` seem wonky. I actually tested it myself and experienced the same – need to do multiple calls to ```setAttribute```, rather than one clean ```setAttributes()``` call. I have no idea if this is intended behaviour or a bug.
Mats Mikkel Rummelhoff
CC BY-SA 3.0
2015-03-27T08:39:21.437Z
_Edited my answer to include the above caveat_
Mats Mikkel Rummelhoff
CC BY-SA 3.0
2015-03-27T13:26:48.257Z
Thank you for taking the time to post all of this - I was able to get it to work  and I'm also going to go back and review the comments/articles posted above as well. Really want to develop "good" habits from the git-go.
Damon
CC BY-SA 3.0
2015-03-27T13:28:12.770Z
No worries @dragonslovetacos! Happy to hear you got it singing. Did you have to call ```setAttribute()``` multiple times, or did flattening the model attributes work? **Edit:** Sorry, didn't notice the above answer before :)
Mats Mikkel Rummelhoff
CC BY-SA 3.0
2015-03-27T13:42:10.807Z
I did end up using `setAttribute()` multiple times - and everything is working. I'm going to go back now and review my code to include the comment by Stuart Whitehead.
Damon
CC BY-SA 3.0
2015-03-26T20:50:42.537Z
2015-03-27T08:37:10.710Z
2017-04-13T12:51:00.160Z
Mats Mikkel Rummelhoff
<p>Stripping this back, your basic problem is saving data to the database from an unreliable source. This is a fundamentally insecure operation—we've got no idea if this user is genuine or attempting something malicious. That's why the underlying Yii framework is trying to protect your install of Craft, and which is the reason you're seeing this ‘buggy’ behaviour with <code>setAttributes()</code>.</p>

<p>The Yii framework implements a ‘safe’ validator. A key point made in <a href="http://www.yiiframework.com/wiki/161/understanding-safe-validation-rules/">this helpful article</a> is this: </p>

<blockquote>
  <p>Massive Assignment will <strong>only</strong> be made for fields which have passed
  some explicit validation rule.</p>
</blockquote>

<p>This means that any attributes you define without an explicit validation rule will be considered <em>unsafe</em>. This will be the reason that only your email field was saving—it has an explicit validation rule (i.e. an email pattern).</p>

<p>How can you resolve this, then?</p>

<p><strong>Set attributes explicitly</strong></p>

<p>Firstly, you could explicitly set each attribute like you have been doing. Since this is not a massive assignment, the data is treated as safe and will save OK. Both <code>$record-&gt;setAttribute()</code> and <code>$record-&gt;attribute()</code> will work for this.</p>

<p><strong>Define attributes with explicit validation</strong></p>

<p>Another solution is to define explicit validation rules, and will allow massive assignment on these attributes, but explicit rules only really apply for some data types. What if you want a simple string?</p>

<p><strong>Make existing attributes safe</strong></p>

<p>A solution could be to add the <code>safe</code> rule to your attribute definition. If you follow the definition of attributes down the rabbit hole, you'll find that attribute configs are normalised by <code>ModelHelper::normalizeAttributeConfig()</code> (and subsequently <code>ModelHelper::getRules()</code>) which does not cater for this. Now where does that leave us?</p>

<p>It's possible to override (and extend) the inherited <code>rules()</code> method. Assuming you wanted to make all attributes safe and valid for massive assignment, I reckon something like this would work.</p>

<pre><code>public function rules()
{
    // Are there any existing rules?
    $rules = parent::rules();

    // Make all attributes safe
    $rules[] = array(implode(',', array_keys($this-&gt;getAttributes())), 'safe');

    // Send it on outta here
    return $rules;
}
</code></pre>

<p>You should then be able to massively set attributes with <code>$record-&gt;setAttributes()</code>.</p>

CC BY-SA 3.0
2015-03-27T13:25:45.870Z
Thank you so much for this! It's pretty obvious I'm just starting my Craft/Yii journey, so I appreciate the time you took to post this. Coming from CodeIgniter, Yii is a tad different & is taking some getting used to. I'll get there eventually. Thank you again.
Damon
CC BY-SA 3.0
2015-03-27T18:46:12.963Z
Not a problem :) The Craft and Yii documentation is pretty descriptive, however I've found Larry Ullman's [‘The Yii Book’](https://larry.pub/) to be very informative and a good way to learn the framework.
Stuart Whitehead
CC BY-SA 3.0
2015-03-27T10:35:05.517Z
2015-03-27T10:35:05.517Z
Stuart Whitehead
<p>I have your standard contact form. (Name, email etc.)</p>

<p>When the user clicks "save" I want to capture what was entered via a plugin &amp; have a CP page to show the people who have filled out the form. I'll get there eventually, but for now I am stuck actually inserting the record.</p>

<p>I am able to insert a record, but it's completely empty. So I know I'm getting close, just not passing off the right information to the right spot.</p>

<p><strong>Model:</strong></p>

<pre><code>public function defineAttributes()
{
    return[
        'firstName' =&gt; [
          'type' =&gt; AttributeType::String,
          'required' =&gt; TRUE
        ]
     ....
    ];
}
</code></pre>

<p><strong>Controller:</strong></p>

<pre><code>public function actionSaveContact() {
    $this-&gt;requirePostRequest();

    $model = new Model();

    $model-&gt;firstName = craft()-&gt;request-&gt;getPost('firstName');
    ....

    if ($model-&gt;validate())
    {
        craft-&gt;service-&gt;saveContact($model);
    }
}
</code></pre>

<p><strong>Service:</strong></p>

<pre><code>public function saveContact(Model, $contact) {
    error_log(print_r($contact, true));

   // I know the data is showing, I can see it in the log
   // [_attributes:Craft\BaseModel:private] =&gt; Array(
   //     [firstName] =&gt; Bob   
   // )

   // Here is where I am hung up. I don't know what to do next.
   // $record = new Record();
   // $record-&gt;save($contact); This creates an empty record in my db
}
</code></pre>

<p>I feel really silly asking for help on what seems like such an elementary task. I'm close - just need a little shove in the right direction I think.</p>

<p>Thank you!</p>

<p><strong>EDIT</strong></p>

<p>Thank you to Mats Mikkel Rummelhoff for your suggestion. It pointed me in the right direction. It seems what I am encountering now has been found in the past? Now it seems I am only saving one field? <a href="https://craftcms.stackexchange.com/questions/2788/plugin-only-saving-one-column-in-database">Using this post</a> I was able to "manually" collect all data and save to my DB. I'm not sure why though - all of the data seemed to be available.</p>

<p><strong>Service</strong></p>

<pre><code>....
$attributes = array(
    'firstName' =&gt; $model-&gt;getAttribute( 'firstName' )
    ....
);    

foreach($attributes as $k =&gt; $v) {
    $record-&gt;setAttribute($k,$v);
}

if ( $record-&gt;save() )
{
    error_log('SUCCESS');
}
else
{
    ....
}
</code></pre>

<p><strong>EDIT</strong></p>

<p>Thank you so much for everyone's contribution(s). I'm going to keep updating this in the event that someone else comes across this same problem.</p>

<p>Going along with @Stuart Whitehead comments, right here is proof: 
"AttributeType::String does not apply any validation rules." Which is why that field was not getting populated.</p>

<p>Which is what I was setting as my <code>firstName</code>, <code>lastName</code> and so on.</p>

<p>I have also found this article: <a href="http://straightupcraft.com/articles/the-definitive-guide-to-validation-in-craft" rel="nofollow noreferrer">The Definitive Guide to Validation in Craft</a> Which, is making more and more sense each time I go though it.</p>

<p>The tricky part (for me) is that there isn't a direct corolation between craft and Yii. Meaning that Yii doesn't have a <code>defineAttributes()</code> method where the rules are defined. Craft uses this method, and translates it (for lack of better words) into the Yii equivalent. Pretty cool, just increases the learning curve a bit.</p>

<p>Light bulbs are coming on!</p>

<p><strong>EDIT</strong></p>

<p>This is probably pretty elementry, but I have also discovered that the attribute type that you define in your model, must match the same attribute type in your record. For example:</p>

<p><strong>Record</strong></p>

<pre><code>public function defineAttributes() {
    'firstName' =&gt; AttributeType::Name,
    'lastName' =&gt; AttributeType::Name,
    ....
}
</code></pre>

<p><strong>Model</strong></p>

<pre><code>public function defineAttributes() {
    return [
        'firstName' =&gt; [
             'type' =&gt; AttributeType::Name,
             'required' =&gt; TRUE
         ],
         'lastName' =&gt; [
             'type' =&gt; AttributeType::Name,
             'required' =&gt; TRUE
         ],
         ....
    ];
}
</code></pre>

<p>Now with things starting to get in the correct way of doing things, <em>gasp</em> stuff is working. Now using @Mats Mikkel Rummelhoff's comment (having all fields validate now) I am able to use: </p>

<pre><code>$record-&gt;setAttributes( $model-&gt;getAttributes() );
</code></pre>

<plugin-development>
Save contact form data to database
# Save contact form data to database

(Asked by: username_0 on 2015-03-26)

I have your standard contact form. (Name, email etc.)
When the user clicks "save" I want to capture what was entered via a plugin & have a CP page to show the people who have filled out the form. I'll get there eventually, but for now I am stuck actually inserting the record.
I am able to insert a record, but it's completely empty. So I know I'm getting close, just not passing off the right information to the right spot.
Model:
public function defineAttributes()
{
    return[
        'firstName' => [
          'type' => AttributeType::String,
          'required' => TRUE
        ]
     ....
    ];
}

Controller:
public function actionSaveContact() {
    $this->requirePostRequest();

    $model = new Model();

    $model->firstName = craft()->request->getPost('firstName');
    ....

    if ($model->validate())
    {
        craft->service->saveContact($model);
    }
}

Service:
public function saveContact(Model, $contact) {
    error_log(print_r($contact, true));

   // I know the data is showing, I can see it in the log
   // [_attributes:Craft\BaseModel:private] => Array(
   //     [firstName] => Bob   
   // )

   // Here is where I am hung up. I don't know what to do next.
   // $record = new Record();
   // $record->save($contact); This creates an empty record in my db
}

I feel really silly asking for help on what seems like such an elementary task. I'm close - just need a little shove in the right direction I think.
Thank you!
EDIT
Thank you to username_1 for your suggestion. It pointed me in the right direction. It seems what I am encountering now has been found in the past? Now it seems I am only saving one field? Using this post I was able to "manually" collect all data and save to my DB. I'm not sure why though - all of the data seemed to be available.
Service
....
$attributes = array(
    'firstName' => $model->getAttribute( 'firstName' )
    ....
);    

foreach($attributes as $k => $v) {
    $record->setAttribute($k,$v);
}

if ( $record->save() )
{
    error_log('SUCCESS');
}
else
{
    ....
}

EDIT
Thank you so much for everyone's contribution(s). I'm going to keep updating this in the event that someone else comes across this same problem.
Going along with @username_2 comments, right here is proof: 
"AttributeType::String does not apply any validation rules." Which is why that field was not getting populated.
Which is what I was setting as my firstName, lastName and so on.
I have also found this article: The Definitive Guide to Validation in Craft Which, is making more and more sense each time I go though it.
The tricky part (for me) is that there isn't a direct corolation between craft and Yii. Meaning that Yii doesn't have a defineAttributes() method where the rules are defined. Craft uses this method, and translates it (for lack of better words) into the Yii equivalent. Pretty cool, just increases the learning curve a bit.
Light bulbs are coming on!
EDIT
This is probably pretty elementry, but I have also discovered that the attribute type that you define in your model, must match the same attribute type in your record. For example:
Record
public function defineAttributes() {
    'firstName' => AttributeType::Name,
    'lastName' => AttributeType::Name,
    ....
}

Model
public function defineAttributes() {
    return [
        'firstName' => [
             'type' => AttributeType::Name,
             'required' => TRUE
         ],
         'lastName' => [
             'type' => AttributeType::Name,
             'required' => TRUE
         ],
         ....
    ];
}

Now with things starting to get in the correct way of doing things, gasp stuff is working. Now using @username_1's comment (having all fields validate now) I am able to use: 
$record->setAttributes( $model->getAttributes() );

**Tags:** plugin-development


---

## 2 answers

### Answer by username_2 on 2015-03-27. Score: 7 | Accepted answer

Stripping this back, your basic problem is saving data to the database from an unreliable source. This is a fundamentally insecure operation—we've got no idea if this user is genuine or attempting something malicious. That's why the underlying Yii framework is trying to protect your install of Craft, and which is the reason you're seeing this ‘buggy’ behaviour with setAttributes().
The Yii framework implements a ‘safe’ validator. A key point made in this helpful article is this: 

Massive Assignment will only be made for fields which have passed
  some explicit validation rule.

This means that any attributes you define without an explicit validation rule will be considered unsafe. This will be the reason that only your email field was saving—it has an explicit validation rule (i.e. an email pattern).
How can you resolve this, then?
Set attributes explicitly
Firstly, you could explicitly set each attribute like you have been doing. Since this is not a massive assignment, the data is treated as safe and will save OK. Both $record->setAttribute() and $record->attribute() will work for this.
Define attributes with explicit validation
Another solution is to define explicit validation rules, and will allow massive assignment on these attributes, but explicit rules only really apply for some data types. What if you want a simple string?
Make existing attributes safe
A solution could be to add the safe rule to your attribute definition. If you follow the definition of attributes down the rabbit hole, you'll find that attribute configs are normalised by ModelHelper::normalizeAttributeConfig() (and subsequently ModelHelper::getRules()) which does not cater for this. Now where does that leave us?
It's possible to override (and extend) the inherited rules() method. Assuming you wanted to make all attributes safe and valid for massive assignment, I reckon something like this would work.
public function rules()
{
    // Are there any existing rules?
    $rules = parent::rules();

    // Make all attributes safe
    $rules[] = array(implode(',', array_keys($this->getAttributes())), 'safe');

    // Send it on outta here
    return $rules;
}

You should then be able to massively set attributes with $record->setAttributes().

> **Comments:**
> **username_0**: Thank you so much for this! It's pretty obvious I'm just starting my Craft/Yii journey, so I appreciate the time you took to post this. Coming from CodeIgniter, Yii is a tad different & is taking some getting used to. I'll get there eventually. Thank you again.  
> **username_2**: Not a problem :) The Craft and Yii documentation is pretty descriptive, however I've found Larry Ullman's [‘The Yii Book’](https://larry.pub/) to be very informative and a good way to learn the framework.  

---

### Answer by username_1 on 2015-03-26. Score: 3

I think your problem is that the record is not being populated – the save() method does take an array of attributes, but that would be the second parameter, as per the CActiveRecord docs.
Try this:
$record = new MyPluginRecord();
$record->setAttributes( $contact->getAttributes() );
$record->save();

EDIT:
The BaseRecord's setAttributes method seems a bit unreliable. If only some values (or none) are saved, you can try multiple calls to $record->setAttribut() instead:
$attributes = $contact->getAttributes();
foreach ( $attributes as $key => $value ) {
   $record->setAttribute( $key, $value );
}
$record->save();

EDIT 2:
I haven't had the time to test this, but if you're having trouble saving all attributes using $record->setAttributes( $model->getAttributes() ); you could also try flattening the values:
$record->setAttributes( $model->getAttributes( null, true ) );

> **Comments:**
> **username_0**: This got me closer! I was only getting the `email` field populated using this method. However, when I logged out what was in the `getAttributes()` all of the data was there. Strange.  Thanks to [this article](http://craftcms.stackexchange.com/questions/2788/plugin-only-saving-one-column-in-database) I Was at least able to follow along with what was happing because of your answer so thank you very much!  
> **username_1**: @dragonslovetacos Hm, it's really odd how ```$record->saveAttributes()``` seem wonky. I actually tested it myself and experienced the same – need to do multiple calls to ```setAttribute```, rather than one clean ```setAttributes()``` call. I have no idea if this is intended behaviour or a bug.  
> **username_1**: _Edited my answer to include the above caveat_  
> **username_0**: Thank you for taking the time to post all of this - I was able to get it to work  and I'm also going to go back and review the comments/articles posted above as well. Really want to develop "good" habits from the git-go.  
> **username_1**: No worries @dragonslovetacos! Happy to hear you got it singing. Did you have to call ```setAttribute()``` multiple times, or did flattening the model attributes work? **Edit:** Sorry, didn't notice the above answer before :)  
> **username_0**: I did end up using `setAttribute()` multiple times - and everything is working. I'm going to go back now and review my code to include the comment by username_2.  

---

