Browse Source

Merge pull request #17704 from cakephp/backport-17703

Backport #17703 to 4.x
othercorey 1 year ago
parent
commit
f2ecd001d0

+ 25 - 0
src/ORM/BehaviorRegistry.php

@@ -204,6 +204,31 @@ class BehaviorRegistry extends ObjectRegistry implements EventDispatcherInterfac
     }
 
     /**
+     * Remove an object from the registry.
+     *
+     * If this registry has an event manager, the object will be detached from any events as well.
+     *
+     * @param string $name The name of the object to remove from the registry.
+     * @return $this
+     */
+    public function unload(string $name)
+    {
+        $instance = $this->get($name);
+        $result = parent::unload($name);
+
+        $methods = $instance->implementedMethods();
+        foreach ($methods as $method) {
+            unset($this->_methodMap[$method]);
+        }
+        $finders = $instance->implementedFinders();
+        foreach ($finders as $finder) {
+            unset($this->_finderMap[$finder]);
+        }
+
+        return $result;
+    }
+
+    /**
      * Check if any loaded behavior implements a method.
      *
      * Will return true if any behavior provides a public non-finder method

+ 10 - 15
tests/TestCase/ORM/BehaviorRegistryTest.php

@@ -23,6 +23,7 @@ use Cake\ORM\Query;
 use Cake\ORM\Table;
 use Cake\TestSuite\TestCase;
 use LogicException;
+use RuntimeException;
 
 /**
  * Test case for BehaviorRegistry.
@@ -257,19 +258,8 @@ class BehaviorRegistryTest extends TestCase
     public function testCall(): void
     {
         $this->Behaviors->load('Sluggable');
-        $mockedBehavior = $this->getMockBuilder('Cake\ORM\Behavior')
-            ->addMethods(['slugify'])
-            ->disableOriginalConstructor()
-            ->getMock();
-        $this->Behaviors->set('Sluggable', $mockedBehavior);
-
-        $mockedBehavior
-            ->expects($this->once())
-            ->method('slugify')
-            ->with(['some value'])
-            ->will($this->returnValue('some-thing'));
-        $return = $this->Behaviors->call('slugify', [['some value']]);
-        $this->assertSame('some-thing', $return);
+        $return = $this->Behaviors->call('slugify', ['some value']);
+        $this->assertSame('some-value', $return);
     }
 
     /**
@@ -327,8 +317,11 @@ class BehaviorRegistryTest extends TestCase
         $this->expectException(BadMethodCallException::class);
         $this->expectExceptionMessage('Cannot call "slugify" it does not belong to any attached behavior.');
         $this->Behaviors->load('Sluggable');
+
+        $this->assertTrue($this->Behaviors->hasMethod('slugify'));
         $this->Behaviors->unload('Sluggable');
 
+        $this->assertFalse($this->Behaviors->hasMethod('slugify'), 'should not have method anymore');
         $this->Behaviors->call('slugify');
     }
 
@@ -340,9 +333,11 @@ class BehaviorRegistryTest extends TestCase
         $this->expectException(BadMethodCallException::class);
         $this->expectExceptionMessage('Cannot call finder "noslug" it does not belong to any attached behavior.');
         $this->Behaviors->load('Sluggable');
+        $this->assertTrue($this->Behaviors->hasFinder('noSlug'));
         $this->Behaviors->unload('Sluggable');
 
         $this->Behaviors->callFinder('noSlug');
+        $this->assertFalse($this->Behaviors->hasFinder('noSlug'));
     }
 
     /**
@@ -377,8 +372,8 @@ class BehaviorRegistryTest extends TestCase
      */
     public function testUnloadUnknown(): void
     {
-        $this->expectException(MissingBehaviorException::class);
-        $this->expectExceptionMessage('Behavior class FooBehavior could not be found.');
+        $this->expectException(RuntimeException::class);
+        $this->expectExceptionMessage('Unknown object "Foo"');
         $this->Behaviors->unload('Foo');
     }
 

+ 14 - 0
tests/TestCase/ORM/TableTest.php

@@ -1790,6 +1790,20 @@ class TableTest extends TestCase
     }
 
     /**
+     * Test removing a behavior from a table clears the method map for the behavior
+     */
+    public function testRemoveBehaviorMethodMapCleared(): void
+    {
+        $table = new Table(['table' => 'articles']);
+        $table->addBehavior('Sluggable');
+        $this->assertTrue($table->behaviors()->hasMethod('slugify'), 'slugify should be mapped');
+        $this->assertSame('foo-bar', $table->slugify('foo bar'));
+
+        $table->removeBehavior('Sluggable');
+        $this->assertFalse($table->behaviors()->hasMethod('slugify'), 'slugify should not be callable');
+    }
+
+    /**
      * Test adding multiple behaviors to a table.
      */
     public function testAddBehaviors(): void