Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Making HasOne able to work with multi column primary keys

  • Loading branch information...
commit cf9ee7ba22d9e3c7836f1bec58df48200bedf6e5 1 parent 386394c
@lorenzo lorenzo authored
View
2  Cake/ORM/Association/BelongsTo.php
@@ -145,7 +145,7 @@ protected function _joinCondition(array $options) {
$tAlias = $this->target()->alias();
$sAlias = $this->_sourceTable->alias();
$foreignKey = (array)$options['foreignKey'];
- $primaryKey = $this->_targetTable->primaryKey();
+ $primaryKey = (array)$this->_targetTable->primaryKey();
if (count($foreignKey) !== count($primaryKey)) {
$msg = 'Cannot match provided foreignKey, got %d columns expected %d';
View
2  Cake/ORM/Association/DependentDeleteTrait.php
@@ -40,7 +40,7 @@ public function cascadeDelete(Entity $entity, $options = []) {
}
$table = $this->target();
$foreignKey = (array)$this->foreignKey();
- $primaryKey = $this->source()->primaryKey();
+ $primaryKey = (array)$this->source()->primaryKey();
$conditions = array_combine($foreignKey, $entity->extract($primaryKey));
if ($this->_cascadeCallbacks) {
View
28 Cake/ORM/Association/HasOne.php
@@ -134,16 +134,28 @@ public function save(Entity $entity, $options = []) {
*
* @param array $options list of options passed to attachTo method
* @return array
+ * @throws \RuntimeException if the number of columns in the foreignKey do not
+ * match the number of columns in the source table primaryKey
*/
protected function _joinCondition(array $options) {
- $field = sprintf('%s.%s',
- $this->_sourceTable->alias(),
- $this->_sourceTable->primaryKey()
- );
- $value = new IdentifierExpression(sprintf(
- '%s.%s', $this->_targetTable->alias(), $options['foreignKey']
- ));
- return [$field => $value];
+ $conditions = [];
+ $tAlias = $this->target()->alias();
+ $sAlias = $this->_sourceTable->alias();
+ $foreignKey = (array)$options['foreignKey'];
+ $primaryKey = $this->_sourceTable->primaryKey();
+
+ if (count($foreignKey) !== count($primaryKey)) {
+ $msg = 'Cannot match provided foreignKey, got %d columns expected %d';
+ throw new \RuntimeException(sprintf($msg, count($foreignKey), count($primaryKey)));
+ }
+
+ foreach ($foreignKey as $k => $f) {
+ $field = sprintf('%s.%s', $sAlias, $primaryKey[$k]);
+ $value = new IdentifierExpression(sprintf('%s.%s', $tAlias, $f));
+ $conditions[$field] = $value;
+ }
+
+ return $conditions;
}
}
View
2  Cake/ORM/Query.php
@@ -1042,7 +1042,7 @@ protected function _collectKeys($statement) {
if ($meta['instance']->requiresKeys($meta['config'])) {
$alias = $source->alias();
$pkFields = [];
- foreach($source->primaryKey() as $key) {
+ foreach ((array)$source->primaryKey() as $key) {
$pkFields[] = key($this->aliasField($key, $alias));
}
$collectKeys[] = [$alias, $pkFields, count($pkFields) === 1];
View
2  Cake/ORM/Table.php
@@ -829,7 +829,7 @@ public function findThreaded(Query $query, array $options = []) {
*/
public function get($primaryKey, $options = []) {
$key = (array)$this->primaryKey();
- $conditions = array_combine($key, (array)$primaryKey);
+ $conditions = array_combine($key, $primaryKey);
$entity = $this->find('all', $options)->where($conditions)->first();
if (!$entity) {
View
52 Test/TestCase/ORM/Association/HasOneTest.php
@@ -213,6 +213,58 @@ public function testAttachToWithQueryBuilder() {
}
/**
+ * Tests that using hasOne with a table having a multi column primary
+ * key will work if the foreign key is passed
+ *
+ * @return void
+ */
+ public function testAttachToMultiPrimaryKey() {
+ $query = $this->getMock('\Cake\ORM\Query', ['join', 'select'], [null, null]);
+ $config = [
+ 'sourceTable' => $this->user,
+ 'targetTable' => $this->profile,
+ 'conditions' => ['Profiles.is_active' => true],
+ 'foreignKey' => ['user_id', 'user_site_id']
+ ];
+ $this->user->primaryKey(['id', 'site_id']);
+ $association = new HasOne('Profiles', $config);
+ $field1 = new IdentifierExpression('Profiles.user_id');
+ $field2 = new IdentifierExpression('Profiles.user_site_id');
+ $query->expects($this->once())->method('join')->with([
+ 'Profiles' => [
+ 'conditions' => new QueryExpression([
+ 'Profiles.is_active' => true,
+ ['Users.id' => $field1, 'Users.site_id' => $field2],
+ ]),
+ 'type' => 'INNER',
+ 'table' => 'profiles'
+ ]
+ ]);
+ $query->expects($this->never())->method('select');
+ $association->attachTo($query, ['includeFields' => false]);
+ }
+
+/**
+ * Tests that using hasOne with a table having a multi column primary
+ * key will work if the foreign key is passed
+ *
+ * @expectedException \RuntimeException
+ * @expectedExceptionMessage Cannot match provided foreignKey, got 1 columns expected 2
+ * @return void
+ */
+ public function testAttachToMultiPrimaryKeyMistmatch() {
+ $query = $this->getMock('\Cake\ORM\Query', ['join', 'select'], [null, null]);
+ $config = [
+ 'sourceTable' => $this->user,
+ 'targetTable' => $this->profile,
+ 'conditions' => ['Profiles.is_active' => true],
+ ];
+ $this->user->primaryKey(['id', 'site_id']);
+ $association = new HasOne('Profiles', $config);
+ $association->attachTo($query, ['includeFields' => false]);
+ }
+
+/**
* Test that save() ignores non entity values.
*
* @return void
Please sign in to comment.
Something went wrong with that request. Please try again.