Q:

How do I get model/record attributes in their proper types, and not just strings?

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?

A:

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.

A:

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

