Skip to content

Commit

Permalink
Allow for unloading, then reloading a behavior (or loading a differen…
Browse files Browse the repository at this point in the history
…t behavior) without causing method/finder map exceptions.

This also takes into account unloading of a behavior and then trying to call one of the removed behavior's methods.
  • Loading branch information
Walther Lalk committed May 15, 2014
1 parent 9f59802 commit 0c76ab6
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 4 deletions.
8 changes: 4 additions & 4 deletions src/ORM/BehaviorRegistry.php
Expand Up @@ -137,7 +137,7 @@ protected function _getMethods(Behavior $instance, $class, $alias) {
$methods = array_change_key_case($instance->implementedMethods());

foreach ($finders as $finder => $methodName) {
if (isset($this->_finderMap[$finder])) {
if (isset($this->_finderMap[$finder]) && $this->loaded($this->_finderMap[$finder][0])) {
$duplicate = $this->_finderMap[$finder];
$error = sprintf(
'%s contains duplicate finder "%s" which is already provided by "%s"',
Expand All @@ -151,7 +151,7 @@ protected function _getMethods(Behavior $instance, $class, $alias) {
}

foreach ($methods as $method => $methodName) {
if (isset($this->_methodMap[$method])) {
if (isset($this->_methodMap[$method]) && $this->loaded($this->_methodMap[$method][0])) {
$duplicate = $this->_methodMap[$method];
$error = sprintf(
'%s contains duplicate method "%s" which is already provided by "%s"',
Expand Down Expand Up @@ -205,7 +205,7 @@ public function hasFinder($method) {
*/
public function call($method, array $args = []) {
$method = strtolower($method);
if ($this->hasMethod($method)) {
if ($this->hasMethod($method) && $this->loaded($this->_methodMap[$method][0])) {
list($behavior, $callMethod) = $this->_methodMap[$method];
return call_user_func_array([$this->_loaded[$behavior], $callMethod], $args);
}
Expand All @@ -224,7 +224,7 @@ public function call($method, array $args = []) {
public function callFinder($type, array $args = []) {
$type = strtolower($type);

if ($this->hasFinder($type)) {
if ($this->hasFinder($type) && $this->loaded($this->_finderMap[$type][0])) {
list($behavior, $callMethod) = $this->_finderMap[$type];
return call_user_func_array([$this->_loaded[$behavior], $callMethod], $args);
}
Expand Down
42 changes: 42 additions & 0 deletions tests/TestCase/ORM/BehaviorRegistryTest.php
Expand Up @@ -243,4 +243,46 @@ public function testCallFinderError() {
$this->Behaviors->callFinder('nope');
}

/**
* Test errors on unloaded behavior methods.
*
* @expectedException \Cake\Error\Exception
* @expectedExceptionMessage Cannot call "slugify" it does not belong to any attached behavior.
*/
public function testUnloadBehaviorThenCall() {
$this->Behaviors->load('Sluggable');
$this->Behaviors->unload('Sluggable');

$this->Behaviors->call('slugify');
}

/**
* Test errors on unloaded behavior finders.
*
* @expectedException \Cake\Error\Exception
* @expectedExceptionMessage Cannot call finder "noslug" it does not belong to any attached behavior.
*/
public function testUnloadBehaviorThenCallFinder() {
$this->Behaviors->load('Sluggable');
$this->Behaviors->unload('Sluggable');

$this->Behaviors->callFinder('noSlug');
}

/**
* Test that unloading then reloading a behavior does not throw any errors.
*
* @return void
*/
public function testUnloadBehaviorThenReload() {
$this->Behaviors->load('Sluggable');
$this->Behaviors->unload('Sluggable');

$this->assertEmpty($this->Behaviors->loaded());

$this->Behaviors->load('Sluggable');

$this->assertEquals(['Sluggable'], $this->Behaviors->loaded());
}

}

0 comments on commit 0c76ab6

Please sign in to comment.