1

I have a template variable thus

public function twitterAccounts()
{
  return craft()->myPlugin->getAllAccounts();
  //Craft::dd(craft()->myPlugin->getAllAccounts());
}

it calls the following service method

public function getAllAccounts()
{
  return MyPlugin_TwitterAccountRecord::model()->findAll(array('order'=>'oauth_token'));
}

the record is set up like this:

class MyPlugin_TwitterAccountRecord extends BaseRecord
{
    public function getTableName()
    {
        return 'myPlugin_twitter_accounts';
    }

    protected function defineAttributes()
    {
        return array(
            'screen_name' => AttributeType::String,
            'id_str'      => AttributeType::String,
            'password'    => AttributeType::String,
            'oauth_token' => AttributeType::String, // this is a reference to the oauth_tokens table ID, not the actual token.
            'last_tweet'  => AttributeType::DateTime,
            'is_company'  => AttributeType::Bool,

            //array(AttributeType::Enum, 'values' => "alcohol,mixer,other"),
        );
    }
}

I have three records in that table 2 have values for the oauth_token field and one is NULL.

Before the NULL value row the following worked fine in a template...

{% set twitterAccounts = craft.myPlugin.twitterAccounts %}
{% for thisAccount in twitterAccounts %}
  {% if thisAccount.oauth_token is defined and thisAccount.oauth_token is not null %}
    {{ thisAccount.screen_name }} is oauthed
  {% else %}
    {{ thisAccount.screen_name }} is not oauthed
  {% endif %}
{% endfor %}

but now I'm getting (devmode)

Craft\MyPlugin_TwitterAccountRecord and its behaviors do not have a method or closure named "oauth_token".

The annoying thing is when I comment out the return in the template variable method and use the Craft::dd() I see all three rows with their proper attributes, including the null value.

If I change the conditional to

{% if false and thisAccount.oauth_token is defined and thisAccount.oauth_token is not null %}

...in order to always be false and skip into the else, it lists all three accounts in there!

Can someone point me in the right direction here please? Is there a bug in templating with a NULL value in an activerecord collection? (this happens whether or not I have that orderBy oauth_token in the findAll())

Cheers.

4

You don't want to expose a Record to the template level for many reasons, including inadvertently letting a template call record.save() causing unexpected updates to the database, but you also don't want to expose any unnecessary data to the template (like "password", in your example). A bit more info on that here.

This is where Models come in. They don't have the database overhead and you can limit what gets exposed to the template as well as combine data from multiple records into one model for easy consumption.

Create a MyPlugin_TwitterAccountModel class like so:

class MyPlugin_TwitterAccountModel extends BaseModel
{
    protected function defineAttributes()
    {
        return array(
            'oauth_token' => AttributeType::String,
            'screenname'  => AttributeType::String,
        );
    }
}

(include any other attributes your template might access)

Then change your getAllAccounts() method in your service to:

public function getAllAccounts()
{
    $records = MyPlugin_TwitterAccountRecord::model()->findAll(array('order'=>'oauth_token'));
    return MyPlugin_TwitterAccountModel::populateModels($records);
}

Now your template will only have access to your plugin's model.

Having typed all of that, I literally have no idea if it will solve your original issue.

It might be some odd bug with Twig's interactions with Records that you're the first to run into since we highly discourage exposing Records to templates.

  • Thanks Brad that totally fixed the problem and I learned a good lesson on populating models from records. The template now works as I'd expected, so I think this is a freak bug in Twig but only instigated when there are pebkac issues... ;oD – billythekid Feb 5 '15 at 8:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.