ソースを参照

linkable fixes

euromark 12 年 前
コミット
54ee7b02ff

+ 30 - 5
Model/Behavior/LinkableBehavior.php

@@ -68,14 +68,39 @@ class LinkableBehavior extends ModelBehavior {
 					if (empty($options['alias'])) {
 						throw new InvalidArgumentException(sprintf('%s::%s must receive aliased links', get_class($this), __FUNCTION__));
 					}
+
+					// try to find the class name - important for aliased relations
+					foreach ($Model->belongsTo as $relationAlias => $relation) {
+						if (empty($relation['className']) || $relationAlias !== $options['alias']) {
+							continue;
+						}
+						$options['class'] = $relation['className'];
+						break;
+					}
+					foreach ($Model->hasOne as $relationAlias => $relation) {
+						if (empty($relation['className']) || $relationAlias !== $options['alias']) {
+							continue;
+						}
+						$options['class'] = $relation['className'];
+						break;
+					}
+					foreach ($Model->hasMany as $relationAlias => $relation) {
+						if (empty($relation['className']) || $relationAlias !== $options['alias']) {
+							continue;
+						}
+						$options['class'] = $relation['className'];
+						break;
+					}
+
+					// guess it then
 					if (empty($options['table']) && empty($options['class'])) {
 						$options['class'] = $options['alias'];
 					} elseif (!empty($options['table']) && empty($options['class'])) {
 						$options['class'] = Inflector::classify($options['table']);
 					}
 
-					// the incoming model to be linked in query
-					$_Model = ClassRegistry::init($options['class']);
+					// the incoming model to be linked in query using class and alias
+					$_Model = ClassRegistry::init(array('class' => $options['class'], 'alias' => $options['alias']));
 					// the already in query model that links to $_Model
 					$Reference = ClassRegistry::init($options['reference']);
 					$db = $_Model->getDataSource();
@@ -139,17 +164,17 @@ class LinkableBehavior extends ModelBehavior {
 							}
 							// fallback to defaults otherwise
 							if (empty($modelLink)) {
-								$modelLink = $Link->escapeField(Inflector::underscore($_Model->alias) . '_id');
+								$modelLink = $Link->escapeField($association['foreignKey']);
 							}
 							if (empty($referenceLink)) {
-								$referenceLink = $Link->escapeField(Inflector::underscore($Reference->alias) . '_id');
+								$referenceLink = $Link->escapeField($association['associationForeignKey']);
 							}
 							$referenceKey = $Reference->escapeField();
 							$query['joins'][] = array(
 								'alias' => $Link->alias,
 								'table' => $Link->table, //$Link->getDataSource()->fullTableName($Link),
 								'conditions' => "{$referenceLink} = {$referenceKey}",
-								'type' => 'LEFT'
+								'type' => 'LEFT',
 							);
 							$modelKey = $_Model->escapeField();
 							$modelKey = str_replace($_Model->alias, $options['alias'], $modelKey);

+ 79 - 10
Test/Case/Model/Behavior/LinkableBehaviorTest.php

@@ -17,6 +17,9 @@ class LinkableBehaviorTest extends CakeTestCase {
 		'plugin.tools.legacy_company',
 		'plugin.tools.shipment',
 		'plugin.tools.order_item',
+		'plugin.tools.news_article',
+		'plugin.tools.news_category',
+		'plugin.tools.news_articles_news_category',
 	);
 
 	public $User;
@@ -136,8 +139,12 @@ class LinkableBehaviorTest extends CakeTestCase {
 		$this->assertEquals($arrayExpectedTmp, $arrayResult, 'On-the-fly belongsTo association via Linkable, with order: %s');
 	}
 
+	/**
+	 * hasMany association via Containable. Should still work when Linkable is loaded.
+	 *
+	 * @return void
+	 */
 	public function testHasMany() {
-		// hasMany association via Containable. Should still work when Linkable is loaded
 		$arrayExpected = array(
 			'LinkableUser' => array('id' => 1, 'username' => 'CakePHP'),
 			'LinkableComment' => array(
@@ -270,8 +277,8 @@ class LinkableBehaviorTest extends CakeTestCase {
 		$this->assertEquals($arrayExpectedTmp, $arrayResult, 'Linkable and Containable combined: %s');
 	}
 
-	public function _testPagination() {
-		$objController = new Controller(new CakeRequest('/'), new CakeResponse());
+	public function testPagination() {
+		$objController = new Controller(new CakeRequest(), new CakeResponse());
 		$objController->layout = 'ajax';
 		$objController->uses = array('LinkableUser');
 		$objController->constructClasses();
@@ -310,7 +317,7 @@ class LinkableBehaviorTest extends CakeTestCase {
 				)
 			),
 			'limit' => 2,
-			'order' => 'Profile.user_id DESC'
+			'order' => 'LinkableProfile.user_id DESC'
 		);
 
 		$arrayResult = $objController->paginate('LinkableUser');
@@ -339,7 +346,7 @@ class LinkableBehaviorTest extends CakeTestCase {
 				'LinkableProfile'
 			),
 			'limit' => 2,
-			'order' => 'Profile.user_id DESC'
+			'order' => 'LinkableProfile.user_id DESC'
 		);
 
 		$arrayResult = $objController->paginate('LinkableUser');
@@ -347,10 +354,12 @@ class LinkableBehaviorTest extends CakeTestCase {
 	}
 
 	/**
-	 *	Series of tests that assert if Linkable can adapt to assocations that
-	 *	have aliases different from their standard model names
+	 * Series of tests that assert if Linkable can adapt to assocations that
+	 * have aliases different from their standard model names.
+	 *
+	 * @return void
 	 */
-	public function _testNonstandardAssociationNames() {
+	public function testNonstandardAssociationNames() {
 		$this->LinkableTag = ClassRegistry::init('LinkableTag');
 
 		$arrayExpected = array(
@@ -446,7 +455,7 @@ class LinkableBehaviorTest extends CakeTestCase {
 		$this->assertEquals($arrayExpected, $arrayResult, 'hasMany association with custom foreignKey: %s');
 	}
 
-	public function _testAliasedBelongsToWithSameModelAsHasMany() {
+	public function testAliasedBelongsToWithSameModelAsHasMany() {
 		$this->OrderItem = ClassRegistry::init('OrderItem');
 
 		$arrayExpected = array(
@@ -474,8 +483,40 @@ class LinkableBehaviorTest extends CakeTestCase {
 		$this->assertEquals($arrayExpected, $arrayResult, 'belongsTo association with alias (requested), with hasMany to the same model without alias: %s');
 	}
 
-}
+	/**
+	 * Ensure that the correct habtm keys are read from the relationship in the models
+	 *
+	 * @author David Yell <neon1024@gmail.com>
+	 * @return void
+	 */
+	public function testHasAndBelongsToManyNonConvention() {
+		$this->NewsArticle = ClassRegistry::init('NewsArticle');
+
+		$expected = array(
+			array(
+				'NewsArticle' => array(
+					'id' => '1',
+					'title' => 'CakePHP the best framework'
+				),
+				'NewsCategory' => array(
+					'id' => '1',
+					'name' => 'Development'
+				)
+			)
+		);
 
+		$result = $this->NewsArticle->find('all', array(
+			'link' => array(
+				'NewsCategory'
+			),
+			'conditions' => array(
+				'NewsCategory.id' => 1
+			)
+		));
+
+		$this->assertEqual($result, $expected);
+	}
+}
 
 class LinkableTestModel extends CakeTestModel {
 
@@ -607,3 +648,31 @@ class OrderItem extends LinkableTestModel {
 	);
 
 }
+
+class NewsArticle extends LinkableTestModel {
+
+	public $hasAndBelongsToMany = array(
+		'NewsCategory' => array(
+			'className' => 'NewsCategory',
+			'joinTable' => 'news_articles_news_categories',
+			'foreignKey' => 'article_id',
+			'associationForeignKey' => 'category_id',
+			'unique' => 'keepExisting',
+		)
+	);
+
+}
+
+class NewsCategory extends LinkableTestModel {
+
+	public $hasAndBelongsToMany = array(
+		'NewsArticle' => array(
+			'className' => 'NewsArticle',
+			'joinTable' => 'news_articles_news_categories',
+			'foreignKey' => 'category_id',
+			'associationForeignKey' => 'article_id',
+			'unique' => 'keepExisting',
+		)
+	);
+
+}