yii1tech/model-typecast

Allows typecast for Model and ActiveRecord attributes in Yii1

1.0.0 2023-12-22 15:58 UTC

This package is auto-updated.

Last update: 2024-11-22 17:50:43 UTC


README

Model Attributes Typecast Extension for Yii 1


This extension provides support for Yii1 Model and ActiveRecord attributes typecast.

For license information check the LICENSE-file.

Latest Stable Version Total Downloads Build Status

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist yii1tech/model-typecast

or add

"yii1tech/model-typecast": "*"

to the "require" section of your composer.json.

Usage

This extension provides support for Yii1 Model and ActiveRecord automatic attributes typecast. It is performed via usage of \yii1tech\model\typecast\TypecastBehavior behavior. It should be attached to \CModel or \CActiveRecord descendant. For example:

<?php

use yii1tech\model\typecast\TypecastBehavior;

class Item extends CActiveRecord
{
    public function behaviors()
    {
        return [
            'typecastBehavior' => [
                'class' => TypecastBehavior::class,
                'attributeTypes' => [
                    'id' => TypecastBehavior::TYPE_INTEGER,
                    'amount' => TypecastBehavior::TYPE_INTEGER,
                    'price' => TypecastBehavior::TYPE_FLOAT,
                    'is_active' => TypecastBehavior::TYPE_BOOLEAN,
                    'created_at' => TypecastBehavior::TYPE_DATETIME,
                    'json_data' => TypecastBehavior::TYPE_ARRAY_OBJECT,
                ],
                'typecastAfterValidate' => true,
                'typecastBeforeSave' => false,
                'typecastAfterSave' => true,
                'typecastAfterFind' => true,
            ],
        ];
    }

    // ...
}

Tip: you may leave \yii1tech\model\typecast\TypecastBehavior::$attributeTypes blank - in this case its value will be detected automatically: for ActiveRecord - based on owner DB table schema, for regular model - based validation rules.

In the above example attribute typecasting will be automatically performed in following cases:

  • after model successful validation
  • after model successful saving
  • after model retrieval from Database

For example:

<?php

$model = new Item();
$model->setAttributes([
    'name' => 'item name',
    'price' => '10.50',
    'amount' => '14',
    'is_active' => '1',
]);

if ($model->validate()) {
    var_dump($model->id); // outputs: int(123456)
    var_dump($model->price); // outputs: float(10.5)
    var_dump($model->amount); // outputs: int(14)
    var_dump($model->is_active); // outputs: bool(true)
}

$model = Item::model()->findByPk($id);
var_dump($model->id); // outputs: int(12345)
var_dump($model->amount); // outputs: int(18)
var_dump($model->is_active); // outputs: bool(true)

You can manually trigger attribute typecasting anytime invoking \yii1tech\model\typecast\TypecastBehavior::typecastAttributes() method:

<?php

$model = new Item();
$model->price = '38.5';
$model->is_active = 1;
$model->typecastAttributes();

var_dump($model->price); // outputs: float(38.5)
var_dump($model->is_active); // outputs: bool(true)

JSON Typecasting

This behavior allows automatic conversion of array or traversable objects into JSON string on model saving. For example:

<?php

$model = new Item();
$model->json_data = [ // will be saved in DB as '{foo: "bar"}'
    'foo' => 'bar',
];
$model->save();

Note: such conversion will take place even, if there is no direct attribute type specification.

You can typecast JSON column value either to plain array or \ArrayObject instance. Plain arrays consume less memory, but writing of its particular internal keys will not work. \ArrayObject allows free operation over internal keys, but you should note that its value always passed by reference.

<?php

// in case mapping in `attributeTypes` is set to `TypecastBehavior::TYPE_ARRAY`
use yii1tech\model\typecast\TypecastBehavior;

class Item extends CActiveRecord
{
    public function behaviors()
    {
        return [
            'typecastBehavior' => [
                'class' => TypecastBehavior::class,
                'attributeTypes' => [
                    'json_data' => TypecastBehavior::TYPE_ARRAY,
                ],
            ],
        ];
    }

    // ...
}

$model = Item::model()->findByPk($id);
var_dump($model->json_data); // outputs: array(1) {...}
var_dump($model->json_data['foo']); // outputs: string(bar)
$model->json_data['foo'] = 'new value'; // PHP E_NOTICE: Indirect modification of overloaded property Item::$json_data has no effect!
$model->json_data = [ // no problem
    'foo' => 'new value',
];
$model->save();

// in case mapping in `attributeTypes` is set to `TypecastBehavior::TYPE_ARRAY_OBJECT`
use yii1tech\model\typecast\TypecastBehavior;

class Item extends CActiveRecord
{
    public function behaviors()
    {
        return [
            'typecastBehavior' => [
                'class' => TypecastBehavior::class,
                'attributeTypes' => [
                    'json_data' => TypecastBehavior::TYPE_ARRAY_OBJECT,
                ],
            ],
        ];
    }

    // ...
}

$model = Item::model()->findByPk($id);
var_dump($model->json_data); // outputs: object(ArrayObject) {...}
var_dump($model->json_data['foo']); // outputs: string(bar)
$model->json_data['foo'] = 'new value'; // no problem
$jsonDataCopy = $model->json_data; // new variable holds the reference to `\ArrayObject` instance!
$jsonDataCopy['foo'] = 'value from copy'; // changes value of `$model->json_data`!
var_dump($model->json_data['foo']); // outputs: string(value from copy)
$model->save();

DateTime Typecasting

This behavior allows automatic conversion of \DateTime instances into ISO datetime string on model saving. For example:

<?php

use yii1tech\model\typecast\TypecastBehavior;

class Item extends CActiveRecord
{
    public function behaviors()
    {
        return [
            'typecastBehavior' => [
                'class' => TypecastBehavior::class,
                'attributeTypes' => [
                    'created_at' => TypecastBehavior::TYPE_DATETIME,
                ],
            ],
        ];
    }

    // ...
}

$model = new Item();
$model->created_at = new DateTime('now'); // will be saved in DB as '2023-12-22 10:14:17'
$model->save();

$model = Item::model()->findByPk($id);
var_dump($model->created_at); // outputs: object(DateTime)

In case you store the dates using integer Unix timestamp, you can use \yii1tech\model\typecast\TypecastBehavior::TYPE_TIMESTAMP for correct conversion. For example:

<?php

use yii1tech\model\typecast\TypecastBehavior;

class Item extends CActiveRecord
{
    public function behaviors()
    {
        return [
            'typecastBehavior' => [
                'class' => TypecastBehavior::class,
                'attributeTypes' => [
                    'created_at' => TypecastBehavior::TYPE_TIMESTAMP,
                ],
            ],
        ];
    }

    // ...
}

$model = new Item();
$model->created_at = new DateTime('now'); // will be saved in DB as '1703257478'
$model->save();

$model = Item::model()->findByPk($id);
var_dump($model->created_at); // outputs: object(DateTime)

This extension also supports nesbot/carbon package. In order to convert dates to \Carbon\Carbon you should use following types:

  • \yii1tech\model\typecast\TypecastBehavior::TYPE_DATETIME_CARBON
  • \yii1tech\model\typecast\TypecastBehavior::TYPE_TIMESTAMP_CARBON

Custom Typecasting

You may specify any custom typecasting for the attribute using a callable as a type specification at \yii1tech\model\typecast\TypecastBehavior::$attributeTypes. For example:

<?php

use yii1tech\model\typecast\TypecastBehavior;

class Item extends CActiveRecord
{
    public function behaviors()
    {
        return [
            'typecastBehavior' => [
                'class' => TypecastBehavior::class,
                'attributeTypes' => [
                    'heap_data' => function ($value) {
                        if (is_object($value)) {
                            return $value;
                        }
                        
                        $heap = new \SplMaxHeap();
                        foreach (json_decode($value) as $element) {
                            $heap->insert($element);
                        }
                        
                        return $heap;
                    },
                ],
            ],
        ];
    }

    // ...
}

$model = Item::model()->findByPk($id);
var_dump($model->heap_data); // outputs: object(SplMaxHeap)