Answers.Body: <p>I’m seeing a few issues with this:</p>
  
  <ul>
  <li><p>Service classes aren’t created with any arguments*, so the <code>$traceRecord</code> argument in your <code>__construct()</code> method is pointless.</p></li>
  <li><p>Setting <code>$this-&gt;traceRecord</code> to <code>Trackr_TraceRecord::model()</code> is really weird. When you call <code>::model()</code> you’re getting a “meta” version of your record class, which should only be used to call things like <code>find()</code>, and those functions will return the actual record instances. (It’s basically just an awkward workaround for the fact that Yii 1 didn’t require PHP 5.3+, so they couldn’t rely on Late Static Bindings support, which would have made it possible to do things like <code>MyServiceClass::find()</code> directly - as you can in Yii 2.) Point is, you shouldn’t be storing a reference to the meta record returned by <code>::model()</code>.</p></li>
  <li><p><code>$trace-&gt;getAttribute('id')</code> implies that your Trackr_TraceModel class has an <code>id</code> attribute, but it doesn’t, unless you didn’t post all of your model attributes code.</p></li>
  <li><p>Calling <code>if ($this-&gt;traceRecord-&gt;findByPk($id) === NULL)</code> works as a conditional statement, but it looks like your logic is assuming that if a record was actually found, that <code>$this-&gt;traceRecord</code> would be set to that new record. That won’t actually be the case unless you write <code>$this-&gt;traceRecord = ...</code>.</p></li>
  <li><p>Records don’t have a <code>create()</code> method. I’m not sure why that’s not throwing a PHP error for you. Did you add that method yourself? If you want to create a new record instance, you should be typing <code>$this-&gt;traceRecord = new Trackr_TraceRecord();</code></p></li>
  </ul>
  
  <p>I’d suggest you remove your service’s <code>__construct()</code> method, and also its protected <code>$traceRecord</code> property. Then update its <code>saveTrace()</code> method to the following:</p>
  
  <p>
  
  <pre><code>public function saveTrace(Trackr_TraceModel &amp;$trace)
  {
  
      if ($id = $trace-&gt;getAttribute('id'))
      {
          $traceRecord = Trackr_TraceRecord::model()-&gt;findById($id);
  
          if (!$traceRecord)
          {
              throw new Exception(Craft::t('Can\'t find trace with ID "{id}"', array('id' =&gt; $id)));
          }
      }
      else
      {
          $traceRecord = new Trackr_TraceRecord();
      }
  
      if ($trace-&gt;validate())
      {
          $dt = DateTimeHelper::currentTimeForDb();
          $attributes = array(
              'entry_id' =&gt; $trace-&gt;entry_id,
              'sess_id' =&gt; $trace-&gt;sess_id,
              'dateCreated' =&gt; $dt,
              'dateUpdated' =&gt;$dt,
              'uid' =&gt; StringHelper::UUID(),
              'id' =&gt; 0
          );
  
          foreach($attributes as $k =&gt; $v)
          {
              $traceRecord-&gt;setAttribute($k,$v);
          }
  
          if ($traceRecord-&gt;save())
          {
              // update id on model (for new records)
              $trace-&gt;setAttribute('id', $traceRecord-&gt;getAttribute('id'));
              return true;
          }
          else
          {
              $model-&gt;addErrors($traceRecord-&gt;getErrors());
              return false;
          }
      }
  }
  </code></pre>
  
  <hr>
  
  <p>* Unless you’re creating an instance of your class in some other way besides calling <code>craft()-&gt;trackr_trace</code>, but you shouldn’t be.</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-08-18T12:48:11.413Z
Answers.Text: Brandon, you are a Gentleman and a Scholar! This worked perfectly. Reading through your explanation makes perfect sense. I'm still a noob to Yii coming from Laravel I'm still learning the nuances. Thank you again!
Answers.UserDisplayName: Dan Lake
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-08-18T12:15:21.380Z
Answers.LastActivityDate: 2015-08-18T12:15:21.380Z
Answers.UserDisplayName: Brandon Kelly
Body: <p>I am tearing my hair out with this!</p>
  
  <p>So, I have a variable file setup as follows</p>
  
  <pre><code> &lt;?php
  namespace Craft;
  
  class TrackrVariable
  {
      public function startTrace()
      {
          if(!isset($_COOKIE['trackr_sess'])):
              $sess = StringHelper::randomString(40, TRUE);
              $expire = time()+60*60*24*120; // 120 days
              setcookie('trackr_sess', $sess, $expire);
              $_COOKIE['trackr_sess'] = $sess;
          else:
              $sess = $_COOKIE['trackr_sess'];
          endif;
  
          $trace = new Trackr_TraceModel();
          $trace-&gt;entry_id = 1;
          $trace-&gt;sess_id = $sess;
          craft()-&gt;trackr_trace-&gt;saveTrace($trace);
      }
  }
  </code></pre>
  
  <p>...and I am calling the function in my template using:</p>
  
  <pre><code>{{ craft.trackr.startTrace() }}
  </code></pre>
  
  <p>I create the model and set the attributes and hand off to a service. The model looks like this:</p>
  
  <pre><code>&lt;?php
  namespace Craft;
  
  class Trackr_TraceModel extends BaseModel
  {
     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;
      }
  
      protected function defineAttributes()
      {
          return [
              'entry_id' =&gt; [
                   'type' =&gt; AttributeType::Number,
                   'required' =&gt; TRUE
               ],
               'sess_id' =&gt; [
                   'type' =&gt; AttributeType::String,
                   'required' =&gt; TRUE
               ]
          ];
      }
  }
  </code></pre>
  
  <p>and the service looks like:</p>
  
  <pre><code>&lt;?php
  namespace Craft;
  
  class Trackr_TraceService extends BaseApplicationComponent
  {
  
      protected $traceRecord;
  
      public function __construct($traceRecord = null)
      {
          $this-&gt;traceRecord = $traceRecord;
          if(is_null($this-&gt;traceRecord))
          {
              $this-&gt;traceRecord = Trackr_TraceRecord::model();
          }   
      }
  
      public function saveTrace(Trackr_TraceModel &amp;$trace)
      {
  
          if ($id = $trace-&gt;getAttribute('id')) :
              if ($this-&gt;traceRecord-&gt;findByPk($id) === NULL):
                  throw new Exception(Craft::t('Can\'t find trace with ID "{id}"', array('id' =&gt; $id)));
              endif;
          else:
              $this-&gt;traceRecord-&gt;create();
          endif;
  
          if ($trace-&gt;validate()):
  
              $dt = DateTimeHelper::currentTimeForDb();
              $attributes = array(
                  'entry_id' =&gt; $trace-&gt;entry_id,
                  'sess_id' =&gt; $trace-&gt;sess_id,
                  'dateCreated' =&gt; $dt,
                  'dateUpdated' =&gt;$dt,
                  'uid' =&gt; StringHelper::UUID(),
                  'id' =&gt; 0
              );    
              foreach($attributes as $k =&gt; $v) $this-&gt;traceRecord-&gt;setAttribute($k,$v);
  
              if($this-&gt;traceRecord-&gt;save()):
                  // update id on model (for new records)
                  $trace-&gt;setAttribute('id', $this-&gt;traceRecord-&gt;getAttribute('id'));
                  return TRUE;
              else:
                  $model-&gt;addErrors($this-&gt;traceRecord-&gt;getErrors());
                  return FALSE;
              endif;
  
          endif;
      }
  }
  </code></pre>
  
  <p>In my mind, the service should be accepting the model, assigning it's attributes to the record and saving the record to the database. Currently, $record->save() is returning TRUE and therefore passing the conditional but no record is created in the dataset, no errors, no trace of any issues whatsoever!</p>
  
  <p>At first I though it might be a 'safe validation' issue as outlined in <a href="https://craftcms.stackexchange.com/a/8895/3968">this answer</a> but, as far as I am aware, I am following all of the advice there.</p>
  
  <p>All I want to be able to do is create a random string, store it in a cookie, as use that cookie to track resources that users view by storing the entry IDs in a table.</p>
  
  <p>If I print out the record and the model separately, the data is being assigned to the attributes just fine, and the cookie bit works.</p>
  
  <p>Please help!
  Dan</p>
  
  <p><strong>EDIT</strong></p>
  
  <p>The Record file looks like this:</p>
  
  <pre><code>&lt;?php
  namespace Craft;
  
  class Trackr_TraceRecord extends BaseRecord
  {
      public function getTableName()
      {
          return 'trackr_trace';
      }
  
      protected function defineAttributes()
      {
          return array(
              'entry_id' =&gt; AttributeType::Number,
              'sess_id' =&gt; AttributeType::String
          );
      }
      public function defineIndexes()
      {
          return array(
              array('columns' =&gt; array('sess_id'), 'unique' =&gt; TRUE),
          );
      }
  
      /**
       * Create a new instance of the current class.
       *
       * @return BaseRecord
       */
      public function create()
      {
          $class = get_class($this);
          $record = new $class();
          return $record;
      }
  }
  </code></pre>
  
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2015-08-14T17:16:02.597Z
Comments.Text: I think the issue is `$record = $this->traceRecord;`.  Try doing all of your record related operations on `$this->traceRecord` directly instead of copying it to `$record`.
Comments.UserDisplayName: Brad Bell
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2015-08-17T09:16:25.863Z
Comments.Text: Thanks Brad but unfortunately this didn't make any difference, I have updated the example code in this post to reflect the changes.
Comments.UserDisplayName: Dan Lake
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2015-08-18T10:29:44.023Z
Comments.Text: Are you able to share your record code at all?
Comments.UserDisplayName: Alec Ritson
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2015-08-18T12:38:16.197Z
Comments.Text: Added the record into the original question
Comments.UserDisplayName: Dan Lake
Tags: <plugin-development><database><records>
Title: Craft CMS Plugin Save Record to DB from Variable
ThreadText: # Craft CMS Plugin Save Record to DB from Variable
  
  (Asked by: username_0 on 2015-08-14)
  
  I am tearing my hair out with this!
  
  So, I have a variable file setup as follows
  
  ```
   <?php
  namespace Craft;
  
  class TrackrVariable
  {
      public function startTrace()
      {
          if(!isset($_COOKIE['trackr_sess'])):
              $sess = StringHelper::randomString(40, TRUE);
              $expire = time()+60*60*24*120; // 120 days
              setcookie('trackr_sess', $sess, $expire);
              $_COOKIE['trackr_sess'] = $sess;
          else:
              $sess = $_COOKIE['trackr_sess'];
          endif;
  
          $trace = new Trackr_TraceModel();
          $trace->entry_id = 1;
          $trace->sess_id = $sess;
          craft()->trackr_trace->saveTrace($trace);
      }
  }
  
  ```
  
  ...and I am calling the function in my template using:
  
  ```
  {{ craft.trackr.startTrace() }}
  
  ```
  
  I create the model and set the attributes and hand off to a service. The model looks like this:
  
  ```
  <?php
  namespace Craft;
  
  class Trackr_TraceModel extends BaseModel
  {
     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;
      }
  
      protected function defineAttributes()
      {
          return [
              'entry_id' => [
                   'type' => AttributeType::Number,
                   'required' => TRUE
               ],
               'sess_id' => [
                   'type' => AttributeType::String,
                   'required' => TRUE
               ]
          ];
      }
  }
  
  ```
  
  and the service looks like:
  
  ```
  <?php
  namespace Craft;
  
  class Trackr_TraceService extends BaseApplicationComponent
  {
  
      protected $traceRecord;
  
      public function __construct($traceRecord = null)
      {
          $this->traceRecord = $traceRecord;
          if(is_null($this->traceRecord))
          {
              $this->traceRecord = Trackr_TraceRecord::model();
          }   
      }
  
      public function saveTrace(Trackr_TraceModel &$trace)
      {
  
          if ($id = $trace->getAttribute('id')) :
              if ($this->traceRecord->findByPk($id) === NULL):
                  throw new Exception(Craft::t('Can\'t find trace with ID "{id}"', array('id' => $id)));
              endif;
          else:
              $this->traceRecord->create();
          endif;
  
          if ($trace->validate()):
  
              $dt = DateTimeHelper::currentTimeForDb();
              $attributes = array(
                  'entry_id' => $trace->entry_id,
                  'sess_id' => $trace->sess_id,
                  'dateCreated' => $dt,
                  'dateUpdated' =>$dt,
                  'uid' => StringHelper::UUID(),
                  'id' => 0
              );    
              foreach($attributes as $k => $v) $this->traceRecord->setAttribute($k,$v);
  
              if($this->traceRecord->save()):
                  // update id on model (for new records)
                  $trace->setAttribute('id', $this->traceRecord->getAttribute('id'));
                  return TRUE;
              else:
                  $model->addErrors($this->traceRecord->getErrors());
                  return FALSE;
              endif;
  
          endif;
      }
  }
  
  ```
  
  In my mind, the service should be accepting the model, assigning it's attributes to the record and saving the record to the database. Currently, $record->save() is returning TRUE and therefore passing the conditional but no record is created in the dataset, no errors, no trace of any issues whatsoever!
  
  At first I though it might be a 'safe validation' issue as outlined in [this answer](https://craftcms.stackexchange.com/a/8895/3968) but, as far as I am aware, I am following all of the advice there.
  
  All I want to be able to do is create a random string, store it in a cookie, as use that cookie to track resources that users view by storing the entry IDs in a table.
  
  If I print out the record and the model separately, the data is being assigned to the attributes just fine, and the cookie bit works.
  
  Please help!
  Dan
  
  **EDIT**
  
  The Record file looks like this:
  
  ```
  <?php
  namespace Craft;
  
  class Trackr_TraceRecord extends BaseRecord
  {
      public function getTableName()
      {
          return 'trackr_trace';
      }
  
      protected function defineAttributes()
      {
          return array(
              'entry_id' => AttributeType::Number,
              'sess_id' => AttributeType::String
          );
      }
      public function defineIndexes()
      {
          return array(
              array('columns' => array('sess_id'), 'unique' => TRUE),
          );
      }
  
      /**
       * Create a new instance of the current class.
       *
       * @return BaseRecord
       */
      public function create()
      {
          $class = get_class($this);
          $record = new $class();
          return $record;
      }
  }
  
  ```
  
  **Tags:** plugin-development, database, records
  
  > **Comments:**
  > **username_1**: I think the issue is `$record = $this->traceRecord;`.  Try doing all of your record related operations on `$this->traceRecord` directly instead of copying it to `$record`.  
  > **username_0**: Thanks username_1 but unfortunately this didn't make any difference, I have updated the example code in this post to reflect the changes.  
  > **username_2**: Are you able to share your record code at all?  
  > **username_0**: Added the record into the original question  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_3 on 2015-08-18. Score: 2 | Accepted answer
  
  I’m seeing a few issues with this:
  
  * Service classes aren’t created with any arguments\*, so the `$traceRecord` argument in your `__construct()` method is pointless.
  * Setting `$this->traceRecord` to `Trackr_TraceRecord::model()` is really weird. When you call `::model()` you’re getting a “meta” version of your record class, which should only be used to call things like `find()`, and those functions will return the actual record instances. (It’s basically just an awkward workaround for the fact that Yii 1 didn’t require PHP 5.3+, so they couldn’t rely on Late Static Bindings support, which would have made it possible to do things like `MyServiceClass::find()` directly - as you can in Yii 2.) Point is, you shouldn’t be storing a reference to the meta record returned by `::model()`.
  * `$trace->getAttribute('id')` implies that your Trackr\_TraceModel class has an `id` attribute, but it doesn’t, unless you didn’t post all of your model attributes code.
  * Calling `if ($this->traceRecord->findByPk($id) === NULL)` works as a conditional statement, but it looks like your logic is assuming that if a record was actually found, that `$this->traceRecord` would be set to that new record. That won’t actually be the case unless you write `$this->traceRecord = ...`.
  * Records don’t have a `create()` method. I’m not sure why that’s not throwing a PHP error for you. Did you add that method yourself? If you want to create a new record instance, you should be typing `$this->traceRecord = new Trackr_TraceRecord();`
  
  I’d suggest you remove your service’s `__construct()` method, and also its protected `$traceRecord` property. Then update its `saveTrace()` method to the following:
  
  ```
  public function saveTrace(Trackr_TraceModel &$trace)
  {
  
      if ($id = $trace->getAttribute('id'))
      {
          $traceRecord = Trackr_TraceRecord::model()->findById($id);
  
          if (!$traceRecord)
          {
              throw new Exception(Craft::t('Can\'t find trace with ID "{id}"', array('id' => $id)));
          }
      }
      else
      {
          $traceRecord = new Trackr_TraceRecord();
      }
  
      if ($trace->validate())
      {
          $dt = DateTimeHelper::currentTimeForDb();
          $attributes = array(
              'entry_id' => $trace->entry_id,
              'sess_id' => $trace->sess_id,
              'dateCreated' => $dt,
              'dateUpdated' =>$dt,
              'uid' => StringHelper::UUID(),
              'id' => 0
          );
  
          foreach($attributes as $k => $v)
          {
              $traceRecord->setAttribute($k,$v);
          }
  
          if ($traceRecord->save())
          {
              // update id on model (for new records)
              $trace->setAttribute('id', $traceRecord->getAttribute('id'));
              return true;
          }
          else
          {
              $model->addErrors($traceRecord->getErrors());
              return false;
          }
      }
  }
  
  ```
  
  ---
  
  \* Unless you’re creating an instance of your class in some other way besides calling `craft()->trackr_trace`, but you shouldn’t be.
  
  > **Comments:**
  > **username_0**: username_3, you are a Gentleman and a Scholar! This worked perfectly. Reading through your explanation makes perfect sense. I'm still a noob to Yii coming from Laravel I'm still learning the nuances. Thank you again!  
  
  ---
  
  