Skip to content

Commit

Permalink
Fixes #16247: Cloning components will now clone their behaviors as well
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonkelly authored and samdark committed Jun 22, 2018
1 parent f903fb2 commit e1a49cf
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 3 deletions.
1 change: 1 addition & 0 deletions framework/CHANGELOG.md
Expand Up @@ -53,6 +53,7 @@ Yii Framework 2 Change Log
- Enh #16054: Callback execution with mutex synchronization (zhuravljov)
- Enh #16126: Allows to configure `Connection::dsn` by config array (leandrogehlen)
- Chg #11397: `yii\i18n\MessageFormatter` polyfills and `yii\i18n\MessageFormatter::parse()` method were removed resulting in performance boost. See UPGRADE for compatibility notes (samdark)
- Chg #16247: Cloning components will now clone their behaviors as well (brandonkelly)

2.0.14.2 under development
------------------------
Expand Down
11 changes: 9 additions & 2 deletions framework/base/Component.php
Expand Up @@ -302,13 +302,20 @@ public function __call($name, $params)

/**
* This method is called after the object is created by cloning an existing one.
* It removes all behaviors because they are attached to the old object.
* It clones all behaviors as well, and attaches them to the new object.
*/
public function __clone()
{
$this->_events = [];
$this->_eventWildcards = [];
$this->_behaviors = null;

if ($this->_behaviors !== null) {
$behaviors = $this->_behaviors;
$this->_behaviors = null;
foreach ($behaviors as $name => $behavior) {
$this->attachBehavior($name, clone $behavior);
}
}
}

/**
Expand Down
3 changes: 2 additions & 1 deletion tests/framework/base/ComponentTest.php
Expand Up @@ -61,7 +61,8 @@ public function testClone()

$clone = clone $component;
$this->assertNotSame($component, $clone);
$this->assertNull($clone->getBehavior('a'));
$this->assertNotNull($clone->getBehavior('a'));
$this->assertNotSame($behavior, $clone->getBehavior('a'));
$this->assertFalse($clone->hasEventHandlers('test'));
$this->assertFalse($clone->hasEventHandlers('foo'));
$this->assertFalse($clone->hasEventHandlers('*'));
Expand Down
57 changes: 57 additions & 0 deletions tests/framework/behaviors/CloningBehaviorTest.php
@@ -0,0 +1,57 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/

namespace yiiunit\framework\behaviors;

use yii\base\Behavior;
use yii\base\Model;
use yiiunit\TestCase;

/**
* Unit test for cloning behaviors when objects are cloned.
*
* @group behaviors
*/
class CloningBehaviorTest extends TestCase
{
public function testCloningObjectsClonesBehaviors()
{
$model1 = new ModelWithBehavior();
$model1->myBehaviorProperty = 'foo';
$model2 = clone $model1;

$this->assertEquals($model1->myBehaviorProperty, $model2->myBehaviorProperty);
}
}

/**
* Test Model class with a behavior attached.
*
* @mixin BehaviorWithProperty
*/
class ModelWithBehavior extends Model
{
/**
* {@inheritdoc}
*/
public function behaviors()
{
return [
'myBehavior' => BehaviorWithProperty::class
];
}
}

/**
* Test Behavior class with property.
*
*/
class BehaviorWithProperty extends Behavior
{
public $myBehaviorProperty;
}

0 comments on commit e1a49cf

Please sign in to comment.