diff --git a/framework/base/Component.php b/framework/base/Component.php index 7cee3b0720d..7838f4b1da2 100644 --- a/framework/base/Component.php +++ b/framework/base/Component.php @@ -190,7 +190,9 @@ public function __set($name, $value) $name = trim(substr($name, 3)); if ($value instanceof Behavior) { $this->attachBehavior($name, $value); - } elseif ((isset($value['class']) && is_subclass_of($value['class'], Behavior::class)) || (isset($value['__class']) && is_subclass_of($value['__class'], Behavior::class))) { + } elseif (isset($value['__class']) && is_subclass_of($value['__class'], Behavior::class)) { + $this->attachBehavior($name, Yii::createObject($value)); + } elseif (!isset($value['__class']) && isset($value['class']) && is_subclass_of($value['class'], Behavior::class)) { $this->attachBehavior($name, Yii::createObject($value)); } elseif (is_string($value) && is_subclass_of($value, Behavior::class, true)) { $this->attachBehavior($name, Yii::createObject($value)); diff --git a/tests/framework/base/ComponentTest.php b/tests/framework/base/ComponentTest.php index dca3c37bd91..d16671a5fa1 100644 --- a/tests/framework/base/ComponentTest.php +++ b/tests/framework/base/ComponentTest.php @@ -10,6 +10,8 @@ use yii\base\Behavior; use yii\base\Component; use yii\base\Event; +use yii\base\InvalidConfigException; +use yii\base\UnknownMethodException; use yiiunit\TestCase; function globalEventHandler($event) @@ -331,19 +333,39 @@ public function testAttachBehavior() $this->assertSame($behavior, $component->detachBehavior('a')); $this->assertFalse($component->hasProperty('p')); - $this->expectException('yii\base\UnknownMethodException'); - $component->test(); + try { + $component->test(); + $this->fail('Expected exception ' . UnknownMethodException::class . " wasn't thrown"); + } catch (UnknownMethodException $e) { + // Expected + } - $p = 'as b'; $component = new NewComponent(); - $component->$p = ['class' => 'NewBehavior']; - $this->assertSame($behavior, $component->getBehavior('a')); + $component->{'as b'} = ['class' => NewBehavior::class]; + $this->assertInstanceOf(NewBehavior::class, $component->getBehavior('b')); $this->assertTrue($component->hasProperty('p')); $component->test(); $this->assertTrue($component->behaviorCalled); $component->{'as c'} = ['__class' => NewBehavior::class]; $this->assertNotNull($component->getBehavior('c')); + + $component->{'as d'} = [ + '__class' => NewBehavior2::class, + 'class' => NewBehavior::class, + ]; + $this->assertInstanceOf(NewBehavior2::class, $component->getBehavior('d')); + + // CVE-2024-4990 + try { + $component->{'as e'} = [ + '__class' => 'NotExistsBehavior', + 'class' => NewBehavior::class, + ]; + $this->fail('Expected exception ' . InvalidConfigException::class . " wasn't thrown"); + } catch (InvalidConfigException $e) { + $this->assertSame('Class is not of type yii\base\Behavior or its subclasses', $e->getMessage()); + } } public function testAttachBehaviors() @@ -546,6 +568,10 @@ public function test() } } +class NewBehavior2 extends Behavior +{ +} + class NewComponent2 extends Component { public $a;