8

I am using cakePHP version 3.x.

When i query the MessagesTable i want to get the Users data for the the sender and the receiver of the message. I have done this many times in cakePHP 2 but i cant figure out why it isn't working in version 3.x.

i have a UsersTable and a MessagesTable.

UsersTable

$this->hasMany('Messages');

MessagesTable

$this->belongsTo('Users', [
    'foreignKey' => 'sender_id',
    'propertyName' => 'Sender',
]);
$this->belongsTo('Users', [
    'foreignKey' => 'user_id',
    'propertyName' => 'Receiver'
]);

This is the query i am using

$messages = $this->Messages->find()
        ->where(['Messages.user_id' => $this->Auth->user('id')])
        ->orwhere(['Messages.sender_id' => $this->Auth->user('id')])
        ->order(['Messages.created' => 'DESC'])
        ->contain([
            'Users.Pictures',
        ]);

I am getting the Receiver data back but not the Sender data as well. Any help would be really appreciated

Dave
  • 28,833
  • 23
  • 113
  • 183
Wisd0m
  • 521
  • 1
  • 5
  • 14

2 Answers2

10

Your associations are wrong. If using the same model for multiple associations you need to use different aliases and the className property (just like in CakePHP 2):-

$this->belongsTo('Sender', [
    'className' => 'Users',
    'foreignKey' => 'sender_id',
    'propertyName' => 'sender',
]);
$this->belongsTo('Receiver', [
    'className' => 'Users',
    'foreignKey' => 'user_id',
    'propertyName' => 'receiver'
]);

This is described in the docs.

In your example code Receiver is overwriting the association for User so you only see the Receiver model in the results.

Your query then needs to be something like:-

$messages = $this->Messages->find()
    ->where(['Messages.user_id' => $this->Auth->user('id')])
    ->orwhere(['Messages.sender_id' => $this->Auth->user('id')])
    ->order(['Messages.created' => 'DESC'])
    ->contain([
        'Receivers' => ['Pictures'],
        'Senders' => ['Pictures']
    ]);
BadHorsie
  • 14,135
  • 30
  • 117
  • 191
drmonkeyninja
  • 8,490
  • 4
  • 31
  • 59
  • Thank you for the response @drmonkeyninja. Your suggestion was the first thing i tried but that gave me an error saying Messages is not associated with Users even though they are associated, which lead me to believe i was doing it wrong in cakePHP 3 so that's why i changed it. Any ideas as to why its giving that error? – Wisd0m Jun 19 '15 at 13:06
  • @Wisd0m is your Users model in a plugin? – drmonkeyninja Jun 19 '15 at 13:31
  • no my Users model isn't in a plugin. Its really strange that its giving me that error, could it have something to do with the Users hasMany('Messages') relationship? – Wisd0m Jun 19 '15 at 13:50
  • @Wisd0m if you're not using a plugin why have you got `contain(['Users.Pictures'])`? I wouldn't have thought the Users hasMany('Messages') relationship should matter as you are querying from the Messages model. – drmonkeyninja Jun 19 '15 at 13:55
  • I was using contain(['Users.Pictures']) to get the user data and user picture for each message. If i remove the contains i no longer get the user data as the multiple Messages belongsTo() isnt working. – Wisd0m Jun 19 '15 at 14:04
  • Is Pictures a model belonging to Users? – drmonkeyninja Jun 19 '15 at 14:29
  • Yes Pictures is a model that belongsTo the Users model. – Wisd0m Jun 19 '15 at 15:35
  • Your `contain` parameters look wrong. I've updated my answer with what I believe should be the query. Your error is probably occurring as you are referencing the `Users` model when your associations are `Senders` and `Receivers`. – drmonkeyninja Jun 19 '15 at 17:45
  • 1
    It is worth nothing that the Cake convention for `propertyName` is to use the lower-case underscored singular version of the model name. – BadHorsie Aug 08 '16 at 15:46
2

Thank you for your help @drmonkeyninja. I have found what was wrong, all i needed to do was call the Users associations i defined in the MessagesTable, i feel so stupid now.

MessagesTable

$this->belongsTo('Sender', [
    'className' => 'Users',
    'foreignKey' => 'sender_id',
    'propertyName' => 'Sender',
]);
$this->belongsTo('Receiver', [
    'className' => 'Users',
    'foreignKey' => 'user_id',
    'propertyName' => 'Receiver'
]);

The query that works:

$messages = $this->Messages->find()
        ->where(['Messages.user_id' => $this->Auth->user('id')])
        ->orwhere(['Messages.sender_id' => $this->Auth->user('id')])
        ->order(['Messages.created' => 'DESC'])
        ->contain([
            'Sender',
            'Receiver'
        ])
    ;
Wisd0m
  • 521
  • 1
  • 5
  • 14