views:

60

answers:

1

In my tennis application, my 'match' table has two players (obviously). I've used player1_id and player2_id as a way to track the user ids. I haven't included a user_id foreign key though.

There is also a 'user' table where I want to pull player's names from.

Because 'match' has more than one user and users have more than one model, I'm wondering if the following model configuration will work:

I've setup the user model like this:

var $name = 'User';
var $hasMany = array(
'Match' => array(
'className' => 'Match',
'foreignKey' => array( 'player1_id', 'player2_id'),
'dependent' => true,
)

and the match model like this:

var $name = 'Match';
var $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' =>  'user_id',
'conditions' => '',
)

I need to display the user first/last name for each player where user_id = player1_id or player2_id. Will this work? Can a foreign key use an array? And can a model operation use an 'or' when searching?

Or is there a better way to structure a table (like a match, or could be a group meeting) with more than one user?

Cheers, Paul

+1  A: 

I don't think an array as a foreign key on the User > Match relationship would work, but then again I have never tried. The single Match > User relationship with user_id as the foreign won't work though, since, as you said, that foreign id does not exist.

Conceptually the cleanest way would be a proper hasAndBelongsToMany relationship. After all, a match has many players, and players have many matches. So you're really looking at a many-to-many relationship.

To fake it with a belongsTo/hasMany relationship, you would need to do this:

// user model
var $hasMany = array(
   'MatchAsPlayer1' => array(
       'className'  => 'Match',
       'foreignKey' => 'player1_id',
   ),
   'MatchAsPlayer2' => array(
       'className'  => 'Match',
       'foreignKey' => 'player2_id',
   )
);

// match model
var $belongsTo = array(
    'Player1' => array(
        'className'  => 'User',
        'foreignKey' =>  'player1_id'
    ),
    'Player2' => array(
        'className'  => 'User',
        'foreignKey' =>  'player2_id'
    )
);

The ugly part is in the User model, where you'd receive related matches split into ['MatchAsPlayer1'] and ['MatchAsPlayer2']. You could do some trickery in the afterFind callback to merge those, but it's not a nice solution overall. Just go for the hasAndBelongsToMany. :)

deceze
Thanks. The HASBTM did strike me as the way to go, but wasn't sure. I thought there might be tried approach since you might have similar situations, like a table with three/four or more players. Would each user/match HASBTM model also take an array like the above, since each match has two players?
Paul
@Paul Sorry, I don't understand the question. For your reference though, the usual acronym is "HABTM".
deceze
Thanks deceze for your help. HABTM, noted.What I wanted to understand is if both player1_id and player2_id should be referenced in the user model? Like it is above.Since the match table has two player IDs, does each ID need to be referenced in the HABTM relationship? If this was compared to say, a blog with a Tags and Posts HABTM, each would only have one foreign key for the other.Hope that makes more sense. Much appreciated.
Paul
@Paul If you want to use Cake's automated fetching of related results with the "fake" belongsTo/hasMany relationship above then yes, both relationships will need to be declared separately. You could write your own SQL query instead of relying on the one Cake generates if you want to go the hasMany route without the drawbacks. If you use a HABTM relationship though these problems go away completely, you just have one User hasAndBelongsToMany Match relationship.
deceze