Browse Source

Merge pull request #4420 from cakephp/issue-4414

Fix broken behavior configuration
José Lorenzo Rodríguez 11 years ago
parent
commit
409f43280c

+ 48 - 8
src/ORM/Behavior.php

@@ -125,10 +125,50 @@ class Behavior implements EventListener {
  * @param array $config The config for this behavior.
  */
 	public function __construct(Table $table, array $config = []) {
+		$config = $this->_resolveMethodAliases(
+			'implementedFinders',
+			$this->_defaultConfig,
+			$config
+		);
+		$config = $this->_resolveMethodAliases(
+			'implementedMethods',
+			$this->_defaultConfig,
+			$config
+		);
 		$this->config($config);
 	}
 
 /**
+ * Removes aliased methods that would otherwise be duplicated by userland configuration.
+ *
+ * @param string $key The key to filter.
+ * @param array $defaults The default method mappings.
+ * @param array $config The customized method mappings.
+ * @return array A de-duped list of config data.
+ */
+	protected function _resolveMethodAliases($key, $defaults, $config) {
+		if (!isset($defaults[$key], $config[$key])) {
+			return $config;
+		}
+		if (isset($config[$key]) && $config[$key] === []) {
+			$this->config($key, [], false);
+			unset($config[$key]);
+			return $config;
+		}
+
+		$indexed = array_flip($defaults[$key]);
+		$indexedCustom = array_flip($config[$key]);
+		foreach ($indexed as $method => $alias) {
+			if (!isset($indexedCustom[$method])) {
+				$indexedCustom[$method] = $alias;
+			}
+		}
+		$this->config($key, array_flip($indexedCustom), false);
+		unset($config[$key]);
+		return $config;
+	}
+
+/**
  * verifyConfig
  *
  * Check that implemented* keys contain values pointing at callable.
@@ -212,12 +252,12 @@ class Behavior implements EventListener {
  * @return array
  */
 	public function implementedFinders() {
-		if (isset($this->_config['implementedFinders'])) {
-			return $this->_config['implementedFinders'];
+		$methods = $this->config('implementedFinders');
+		if (isset($methods)) {
+			return $methods;
 		}
 
-		$reflectionMethods = $this->_reflectionCache();
-		return $reflectionMethods['finders'];
+		return $this->_reflectionCache()['finders'];
 	}
 
 /**
@@ -242,12 +282,12 @@ class Behavior implements EventListener {
  * @return array
  */
 	public function implementedMethods() {
-		if (isset($this->_config['implementedMethods'])) {
-			return $this->_config['implementedMethods'];
+		$methods = $this->config('implementedMethods');
+		if (isset($methods)) {
+			return $methods;
 		}
 
-		$reflectionMethods = $this->_reflectionCache();
-		return $reflectionMethods['methods'];
+		return $this->_reflectionCache()['methods'];
 	}
 
 /**

+ 45 - 0
tests/TestCase/ORM/BehaviorRegistryTest.php

@@ -129,6 +129,51 @@ class BehaviorRegistryTest extends TestCase {
 	}
 
 /**
+ * Test load() duplicate method aliasing
+ *
+ * @return void
+ */
+	public function testLoadDuplicateMethodAliasing() {
+		$this->Behaviors->load('Tree');
+		$this->Behaviors->load('Duplicate', [
+			'implementedFinders' => [
+				'renamed' => 'findChildren',
+			],
+			'implementedMethods' => [
+				'renamed' => 'slugify',
+			]
+		]);
+		$this->assertTrue($this->Behaviors->hasMethod('renamed'));
+	}
+
+/**
+ * Test load() duplicate finder error
+ *
+ * @expectedException \Cake\Error\Exception
+ * @expectedExceptionMessage TestApp\Model\Behavior\DuplicateBehavior contains duplicate finder "children"
+ * @return void
+ */
+	public function testLoadDuplicateFinderError() {
+		$this->Behaviors->load('Tree');
+		$this->Behaviors->load('Duplicate');
+	}
+
+/**
+ * Test load() duplicate finder aliasing
+ *
+ * @return void
+ */
+	public function testLoadDuplicateFinderAliasing() {
+		$this->Behaviors->load('Tree');
+		$this->Behaviors->load('Duplicate', [
+			'implementedFinders' => [
+				'renamed' => 'findChildren',
+			]
+		]);
+		$this->assertTrue($this->Behaviors->hasFinder('renamed'));
+	}
+
+/**
  * test hasMethod()
  *
  * @return void

+ 11 - 3
tests/TestCase/ORM/BehaviorTest.php

@@ -35,6 +35,15 @@ class TestBehavior extends Behavior {
  */
 class Test2Behavior extends Behavior {
 
+	protected $_defaultConfig = [
+		'implementedFinders' => [
+			'foo' => 'findFoo',
+		],
+		'implementedMethods' => [
+			'doSomething' => 'doSomething',
+		]
+	];
+
 /**
  * Test for event bindings.
  */
@@ -239,7 +248,7 @@ class BehaviorTest extends TestCase {
 		$table = $this->getMock('Cake\ORM\Table');
 		$behavior = new Test2Behavior($table);
 		$expected = [
-			'foo' => 'findFoo'
+			'foo' => 'findFoo',
 		];
 		$this->assertEquals($expected, $behavior->implementedFinders());
 	}
@@ -272,8 +281,7 @@ class BehaviorTest extends TestCase {
 		$behavior = new Test2Behavior($table, [
 			'implementedFinders' => []
 		]);
-		$expected = [];
-		$this->assertEquals($expected, $behavior->implementedFinders());
+		$this->assertEquals([], $behavior->implementedFinders());
 	}
 
 /**

+ 12 - 0
tests/test_app/TestApp/Model/Behavior/DuplicateBehavior.php

@@ -21,6 +21,18 @@ use Cake\ORM\Behavior;
  */
 class DuplicateBehavior extends Behavior {
 
+	protected $_defaultConfig = [
+		'implementedFinders' => [
+			'children' => 'findChildren',
+		],
+		'implementedMethods' => [
+			'slugify' => 'slugify',
+		]
+	];
+
+	public function findChildren() {
+	}
+
 	public function slugify() {
 	}