diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 5620d0ac5e..6471fb80b9 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -1,10 +1,10 @@ Yii Framework 2 Change Log ========================== -2.0.12 under development +2.0.11.2 under development -------------------------- -- no changes in this release. +- Bug #13508: Fixed duplicate attachment of behavior BC break (cebe) 2.0.11.1 February 02, 2017 diff --git a/framework/base/Component.php b/framework/base/Component.php index 4c73e9fab3..21880846fc 100644 --- a/framework/base/Component.php +++ b/framework/base/Component.php @@ -669,14 +669,14 @@ class Component extends Object if (is_int($name)) { $behavior->attach($this); $this->_behaviors[] = $behavior; + } else { + if (isset($this->_behaviors[$name])) { + $this->_behaviors[$name]->detach(); + } + $behavior->attach($this); + $this->_behaviors[$name] = $behavior; } - if (isset($this->_behaviors[$name])) { - $this->_behaviors[$name]->detach(); - } - $behavior->attach($this); - $this->_behaviors[$name] = $behavior; - return $behavior; } } diff --git a/tests/framework/base/BehaviorTest.php b/tests/framework/base/BehaviorTest.php index 9a950f6990..c5ec181b13 100644 --- a/tests/framework/base/BehaviorTest.php +++ b/tests/framework/base/BehaviorTest.php @@ -22,6 +22,9 @@ class FooClass extends Component class BarBehavior extends Behavior { + public static $attachCount = 0; + public static $detachCount = 0; + public $behaviorProperty = 'behavior property'; public function behaviorMethod() @@ -46,6 +49,18 @@ class BarBehavior extends Behavior return parent::hasMethod($name); } + + public function attach($owner) + { + self::$attachCount++; + parent::attach($owner); + } + + public function detach() + { + self::$detachCount++; + parent::detach(); + } } /** @@ -59,11 +74,16 @@ class BehaviorTest extends TestCase $this->mockApplication(); } - public function testAttachAndAccessing() + public function testAttachAndAccessingWithName() { + BarBehavior::$attachCount = 0; + BarBehavior::$detachCount = 0; + $bar = new BarClass(); $behavior = new BarBehavior(); $bar->attachBehavior('bar', $behavior); + $this->assertEquals(1, BarBehavior::$attachCount); + $this->assertEquals(0, BarBehavior::$detachCount); $this->assertEquals('behavior property', $bar->behaviorProperty); $this->assertEquals('behavior method', $bar->behaviorMethod()); $this->assertEquals('behavior property', $bar->getBehavior('bar')->behaviorProperty); @@ -71,14 +91,37 @@ class BehaviorTest extends TestCase $behavior = new BarBehavior(['behaviorProperty' => 'reattached']); $bar->attachBehavior('bar', $behavior); + $this->assertEquals(2, BarBehavior::$attachCount); + $this->assertEquals(1, BarBehavior::$detachCount); $this->assertEquals('reattached', $bar->behaviorProperty); } + public function testAttachAndAccessingAnonymous() + { + BarBehavior::$attachCount = 0; + BarBehavior::$detachCount = 0; + + $bar = new BarClass(); + $behavior = new BarBehavior(); + $bar->attachBehaviors([$behavior]); + $this->assertEquals(1, BarBehavior::$attachCount); + $this->assertEquals(0, BarBehavior::$detachCount); + $this->assertEquals('behavior property', $bar->behaviorProperty); + $this->assertEquals('behavior method', $bar->behaviorMethod()); + } + public function testAutomaticAttach() { + BarBehavior::$attachCount = 0; + BarBehavior::$detachCount = 0; + $foo = new FooClass(); + $this->assertEquals(0, BarBehavior::$attachCount); + $this->assertEquals(0, BarBehavior::$detachCount); $this->assertEquals('behavior property', $foo->behaviorProperty); $this->assertEquals('behavior method', $foo->behaviorMethod()); + $this->assertEquals(1, BarBehavior::$attachCount); + $this->assertEquals(0, BarBehavior::$detachCount); } public function testMagicMethods()