8

Here's my record (model is nearly identical):

namespace Craft;

class Recurly_PlanRecord extends BaseRecord
{

  public function getTableName()
  {
    return 'recurly_plans';
  }

  protected function defineAttributes()
  {
    return array(
      'sortOrder'      => AttributeType::SortOrder,
      'code'           => AttributeType::String,
      'max'            => AttributeType::Number,
      'min'            => AttributeType::Number,
      'annual'         => AttributeType::Bool,
      'base_endpoints' => AttributeType::Number,
      'endpoint_code'  => AttributeType::String,
      'base_cost'      => array(
        'type'     => AttributeType::Number,
        'decimals' => 2,
      ),
      'endpoint_cost'  => array(
        'type'     => AttributeType::Number,
        'decimals' => 2,
      ),
    );
  }
}

In the DB, the column types seem to be set correctly based on this. What I can't figure out how to do, is actually get data back in the specified types, not just strings.

Here's me using it in a service:

$record = Recurly_PlanRecord::model()->find();
var_dump($record->attributes); // all strings :(
var_dump($record->base_cost); // string '1402.50' (length=7)

$model  = Recurly_PlanModel::populateModel($record);
var_dump($model->attributes); // all strings :(

What I want is float 1402.50. What I get is a string.

I'm having the same problem with AttributeType::Bool.

What am I doing wrong?

  • 1
    Not sure if you are aware, but P&T recently added Craft::dd($variableName) as an option and has been very helpful when troubleshooting issues like this. – Jason McCallister Nov 15 '14 at 4:51
  • Thanks @JasonMcCallister, didn't know about that. Getting the same results from Craft::dd, however. Showing strings for everything. – Tim Kelty Nov 17 '14 at 17:17
3

Currently the only thing Craft does in BaseModel->setAttribute() and BaseRecord->prepAttributesForUse() is some normalization when the attribute in either case happens to be AttributeType::DateTime or AttributeType::Mixed.

All other attribute types will be returned directly as the database returned them (as a string).

However, I agree with you that we probably should be doing more to return the exact type as the attribute specifies. Since that's potentially a big breaking change, though, it'll have to wait until Craft 3.0.

The good news is, thanks to PHP's loose typing system, you can still workaround most cases.

For example a bool will come back as either the string '1' or '0'.

Using that in a PHP conditional if ($myModel->boolAttribute) will evaluate to true or false.

Using your float example: '1402.50' + 100.00, PHP will properly cast that to 1502.50.

| improve this answer | |
  • Thanks for the answer Brad. The way this came up is I had a controller just dumping models to json: $this->returnJson($arrayOfModels);, but noticed everything was strings when I really wanted to retain things that were floats, bool, etc. – Tim Kelty Nov 17 '14 at 23:53
  • Ahh... in that case, you might just need to do some casting yourself. – Brad Bell Nov 17 '14 at 23:54
  • I'm thinking I'll override the model constructor and do my casting there, if that makes sense. But +1 for getting this on the books for Craft 3! – Tim Kelty Nov 17 '14 at 23:56
  • I'd like to point out that this is a Yii issue. The justification by the Yii development Team was that using strings to represent integers avoids integer overflow on 32-bit machines. Personally I still think it's a bit of a silly decision. – Jay May 1 '15 at 14:18
3

I ended up overriding BaseModel->setAttribute() and BaseRecord->prepAttributesForUse() in my plugin.

Works well! Right now I'm just handling Bool and Number types.

Posted this solution here: http://craftcookbook.net/recipes/324

| improve this answer | |

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.