Skip to content

Commit

Permalink
Support BackedEnum attribute typecast behaviour.
Browse files Browse the repository at this point in the history
  • Loading branch information
Mārtiņš Briedis authored and briedis committed Dec 4, 2024
1 parent 1a54384 commit a4ecd76
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 2 deletions.
11 changes: 9 additions & 2 deletions framework/behaviors/AttributeTypecastBehavior.php
Original file line number Diff line number Diff line change
Expand Up @@ -267,9 +267,16 @@ protected function typecastValue($value, $type)
return StringHelper::floatToString($value);
}
return (string) $value;
default:
throw new InvalidArgumentException("Unsupported type '{$type}'");
}

if (PHP_VERSION_ID >= 80100 && is_subclass_of($type, \BackedEnum::class)) {
if ($value instanceof $type) {
return $value;

Check warning on line 274 in framework/behaviors/AttributeTypecastBehavior.php

View check run for this annotation

Codecov / codecov/patch

framework/behaviors/AttributeTypecastBehavior.php#L272-L274

Added lines #L272 - L274 were not covered by tests
}
return $type::from($value);

Check warning on line 276 in framework/behaviors/AttributeTypecastBehavior.php

View check run for this annotation

Codecov / codecov/patch

framework/behaviors/AttributeTypecastBehavior.php#L276

Added line #L276 was not covered by tests
}

throw new InvalidArgumentException("Unsupported type '{$type}'");

Check warning on line 279 in framework/behaviors/AttributeTypecastBehavior.php

View check run for this annotation

Codecov / codecov/patch

framework/behaviors/AttributeTypecastBehavior.php#L279

Added line #L279 was not covered by tests
}

return call_user_func($type, $value);
Expand Down
86 changes: 86 additions & 0 deletions tests/framework/behaviors/AttributeTypecastBehaviorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@

namespace yiiunit\framework\behaviors;

use ValueError;
use Yii;
use yii\base\DynamicModel;
use yii\base\Event;
use yii\behaviors\AttributeTypecastBehavior;
use yii\db\ActiveRecord;
use yiiunit\framework\db\enums\StatusTypeString;
use yiiunit\TestCase;

/**
Expand Down Expand Up @@ -47,6 +49,7 @@ protected function setUp(): void
'price' => 'float',
'isActive' => 'boolean',
'callback' => 'string',
'status' => 'string',
];
Yii::$app->getDb()->createCommand()->createTable('test_attribute_typecast', $columns)->execute();
}
Expand Down Expand Up @@ -80,6 +83,55 @@ public function testTypecast()
$this->assertSame('callback: foo', $model->callback);
}

public function testTypecastEnum()
{
if (PHP_VERSION_ID < 80100) {
$this->markTestSkipped('Can not be tested on PHP < 8.1');
}

$model = new ActiveRecordAttributeTypecastWithEnum();

$model->status = StatusTypeString::ACTIVE;

$model->getAttributeTypecastBehavior()->typecastAttributes();

$this->assertSame(StatusTypeString::ACTIVE, $model->status);
}

/**
* @depends testTypecastEnum
*/
public function testTypecastEnumFromString()
{
if (PHP_VERSION_ID < 80100) {
$this->markTestSkipped('Can not be tested on PHP < 8.1');
}

$model = new ActiveRecordAttributeTypecastWithEnum();
$model->status = 'active'; // Same as StatusTypeString::ACTIVE->value;

$model->getAttributeTypecastBehavior()->typecastAttributes();

$this->assertSame(StatusTypeString::ACTIVE, $model->status);
}

/**
* @depends testTypecastEnum
*/
public function testTypecastEnumFailWithInvalidValue()
{
if (PHP_VERSION_ID < 80100) {
$this->markTestSkipped('Can not be tested on PHP < 8.1');
}

$model = new ActiveRecordAttributeTypecastWithEnum();
$model->status = 'invalid';

self::expectException(ValueError::class);

$model->getAttributeTypecastBehavior()->typecastAttributes();
}

/**
* @depends testTypecast
*/
Expand Down Expand Up @@ -339,3 +391,37 @@ public function getAttributeTypecastBehavior()
return $this->getBehavior('attributeTypecast');
}
}

/**
* Test Active Record class with [[AttributeTypecastBehavior]] behavior attached with an enum field.
*
* @property StatusTypeString $status
*/
class ActiveRecordAttributeTypecastWithEnum extends ActiveRecord
{
public function behaviors()
{
return [
'attributeTypecast' => [
'class' => AttributeTypecastBehavior::className(),
'attributeTypes' => [
'status' => StatusTypeString::class,
],
'typecastBeforeSave' => true,
],
];
}

public static function tableName()
{
return 'test_attribute_typecast';
}

/**
* @return AttributeTypecastBehavior
*/
public function getAttributeTypecastBehavior()
{
return $this->getBehavior('attributeTypecast');
}
}

0 comments on commit a4ecd76

Please sign in to comment.