• 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
DataMapper: In-table Foreign Key with non-standard name

#1
[eluser]Genki1[/eluser]
Scenario: I have a one-to-many relationship with an in-table foreign key (ITFK) which has a non-standard name. I have modified the models as explained in Advanced Relationships in the section, "You want to use alternative name for a foreign key column name."

Issue: DataMapper complains that a join table cannot be found:
Quote:Error 1146: table 'accounts_lookups' does't exist". Filename: libraries/datamapper.php. Line Number: 1470.

My tables:

Table "accounts":
Code:
id
account_type_id   // ITFK, related to table "Lookups"

Table "lookups":
Code:
id
field_one

My models:

account.php:

Code:
class Account extends DataMapper {
  // related models that each record in this table can have just one of.
  var $has_one = array(
    'lookup' => array('join_self_as' => 'account_type') //ITFK is account_type_id, not lookup_id
  );
}

lookup.php:

Code:
class Lookup extends DataMapper {
  // related models that each record in this table can have many of.
  var $has_many = array(
    'account' => array('join_other_as' => 'account_type') //ITFK is account_type_id, not lookup_id
  );
}

The documentation for "You want to use alternative name for a foreign key column name" mentions only to use the attributes "join_self_as" and "join_other_as". Since I'm getting an error I guess more is needed, but the solution is not clear to me.

#2
[eluser]WanWizard[/eluser]
The issue here is that you misunderstood the definition of 'self' and 'other'. 'self' must be seen as 'join myself on this column', and 'other' as 'join the other model on this column'. In this case Lookup needs to be joined on Account.account_type_id, so for Lookup, this means 'join_self_as'.

It has no reference to the table/model that contains the column (for example in a one-to-one relation, the column could be in either one).

So you have them the wrong way around. Lookup must have the 'join_self_as', and Account the 'join_other_as'.

Just for reference:

The following rules will be applied for the missing fields of an advanced relationship definition:
- class: will be set to the name of the relation (the key of the array or the name if a string)
- other_field: will be set to the name of the current class (the model)
- join_self_as: will be set the the value of 'other_field'
- join_other_as: will be set to the name of the relation (the key of the array or the name if a string)
- join table: will be left empty (= autodetect the name)
- reciprocal: will be set to FALSE
- auto_populate: will be set to NULL

So in the above case the definition will be expanded to:
Code:
class Account extends DataMapper {
  // related models that each record in this table can have just one of.
  var $has_one = array(
    'lookup' => array(
      'class' => 'lookup',
      'other_field' => 'account',
      'join_self_as' => 'account_type',
      'join_other_as' => 'lookup',
      'join table' => '',
      'reciprocal' => FALSE,
      'auto_populate' => NULL,
    )
  );
}

Code:
class Lookup extends DataMapper {
  // related models that each record in this table can have many of.
  var $has_many = array(
    'account' => array(
      'class' => 'account',
      'other_field' => 'lookup',
      'join_self_as' => 'account',
      'join_other_as' => 'account_type'
      'join table' => '',
      'reciprocal' => FALSE,
      'auto_populate' => NULL,
    )
  );
}

#3
[eluser]Genki1[/eluser]
Yep, that fixed it. Thank you, as always!


#4
[eluser]Genki1[/eluser]
Follow-up question:

Now that my $has_one array includes customized attributes for a relationship, how do I specify other relationships that are to be used with DataMapper's default settings?

In other words, would I specify the 'user' relationship like this...

Code:
// related models that each record in this table can have just one of.
var $has_one = array(
  'user',  
  'lookup' => array(
   'join_other_as' => 'account_type') //ITFK is account_type_id, not lookup_id
);

...or like this?
Code:
// related models that each record in this table can have just one of.
var $has_one = array(
  'user' => array(),  
  'lookup' => array(
   'join_other_as' => 'account_type') //ITFK is account_type_id, not lookup_id
);

#5
[eluser]WanWizard[/eluser]
The first one.

Although it doesn't really matter, if you pass an empty array Datamapper will fill in the defaults for you, same as if you pass a string (it will be converted to an array internally).


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2021 MyBB Group.