Browse Source

Fix behavior method alias management.

When behaviors explicitly defined their finders/methods aliasing and
disabling methods no longer worked. This was due to the underlying
config() method always merging and the values - not the keys - being the
key feature of the data. This new code now uses the values to determine
what the correct config data should be. This results in additional calls
to config when methods are customized, but the code behaves as most
people would expect now.

Refs #4414
mark_story 11 years ago
parent
commit
0cb4ee606c

+ 40 - 0
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.

+ 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

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

@@ -34,6 +34,14 @@ class TestBehavior extends Behavior {
  * Test Stub.
  */
 class Test2Behavior extends Behavior {
+	protected $_defaultConfig = [
+		'implementedFinders' => [
+			'foo' => 'findFoo',
+		],
+		'implementedMethods' => [
+			'doSomething' => 'doSomething',
+		]
+	];
 
 /**
  * Test for event bindings.
@@ -239,7 +247,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 +280,7 @@ class BehaviorTest extends TestCase {
 		$behavior = new Test2Behavior($table, [
 			'implementedFinders' => []
 		]);
-		$expected = [];
-		$this->assertEquals($expected, $behavior->implementedFinders());
+		$this->assertEquals([], $behavior->implementedFinders());
 	}
 
 /**

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

@@ -20,6 +20,17 @@ use Cake\ORM\Behavior;
  * Test class for trigging duplicate method errors.
  */
 class DuplicateBehavior extends Behavior {
+	protected $_defaultConfig = [
+		'implementedFinders' => [
+			'children' => 'findChildren',
+		],
+		'implementedMethods' => [
+			'slugify' => 'slugify',
+		]
+	];
+
+	public function findChildren() {
+	}
 
 	public function slugify() {
 	}