Bonjour,

Je suis actuellement en train d'essayer de créer un système d'amis et j'utilise deux associations belongsToMany pour gérer quel User (ou Profile, dans mon cas) envoie la demande d'amitié qui sont définies comme ça :

// dans ProfilesTable
$this->belongsToMany('FriendsOfMine', [
    'className' => 'Profiles',
    'joinTable' => 'friends',
    'foreignKey' => 'profile_from',
    'targetForeignKey' => 'profile_to'
]);
$this->belongsToMany('FriendOf', [
    'className' => 'Profiles',
    'joinTable' => 'friends',
    'foreignKey' => 'profile_to',
    'targetForeignKey' => 'profile_from'
]);

Avec ceci, j'arrive très bien à retrouver qui envoie la demande, qui la reçoit et si elle est confirmée ou non (Friends.status, dans mon cas). Là où ça me pose un soucis, c'est lorsque j'essaie de réunir une liste complète ou partielles de tous les amis d'un Profile dans mon controller.

// dans ProfilesController
 $profile = $this->Profiles->find()
 ->where(['pseudo' => $pseudo])
 ->contain([
    'FriendsOfMine' => function ($q) {
            return $q->where(['status' => true]); // les amitiés acceptées
    }, 
    'FriendOf' => function ($q) {
            return $q->where(['status' => true]);
     }
 ])
 ->first();

Je me retrouve bel et bien avec les deux associations $profile->friends_of_my et $profile->friend_of.

Mon problème est le suivant : j'aimerais pouvoir construire une liste sans distinction entre l'auteur de la demande d'amitié. Pour l'instant, la seule façon que j'ai trouvé est d'utiliser $friends = (object) array_merge($profile->friends_of_mine, $profile->friend_of); comme ceci, mais j'ai l'impression d'être un peu barbare et de bloquer le contrôle de limites ou de pagination (au besoin).

Je me demandais donc s'il existait une quelconque façon de fusionner deux associations belongsToMany (ou alors s'il faut que je m'y prenne autrement) , un peu comme il est possible de le faire sur Laravel avec merge.

Je tiens à préciser, aussi, que je ne suis pas le meilleur avec Cakephp 3 et que j'en suis encore au point d'expérimenter le framework.

Merci d'avance !

6 réponses


Bonjour Ptolam ( comme on se retrouve ! ), as tu réussis à répondre à ta question ? Ou, peut-on en parler ? ( je ne suis pas le meilleur non plus avec CakePHP mais je me débrouille )

Hello.
Je ne suis pas sûr de comprendre. Tu veux récupérer tous les Friends liés au profil ?
En gros toutes les entrées de la table friends dont profile_from ou profile_to sont à l'ID des profils que tu récupères avec ta requête ?

Ptolam
Auteur

Cest ça oui.

J'ai trouvé quelqu'un qui recherchait la même chose sur le github de Cake, mais j'ai un peu de mal à voir où il voulait en venir et la démarche n'est pas complète...
https://github.com/cakephp/cakephp/issues/7514

Je n'ai jamais eu à mettre en place de genre d'associations.

La solution que tu proposes (le array_merge entre tes deux tableaux d'associations) me paraît pas si idiote que ça en fait...
Après tu peux peut être faire un truc plus propre avec formatResults ou bien créer une nouvelle associations Profile hasMany Friends en spécifiant une des deux colonnes en FK (peu importe laquelle) couplé à un customFinder pour ajouter l'autre clé et quand tu fais ta requête faire un contain(['Friends']). A tester.

Si j'arrive à trouver un peu de temps dans la semaine, je vais essayer de monter un proto pour voir ce qu'il est possible de faire.
Tiens moi au courant si tu testes d'autres choses.

J'avais proposé ceci https://www.grafikart.fr/forum/topics/19094#p75727 à l'époque (Mais je n'avais pensé au array_merge, le nul. ^^)

Ptolam
Auteur

@PhiSyX : J'ai fait une longue recherche sur le forum et ailleurs (stack overflow et github) avant de venir poser ma question ici et j'étais bel et bien tombé sur ce que tu proposais dans ce sujet. Seulement, il s'agit d'une association toute simple en belongsToMany où il y a deux entrées dans la table pour chaque User. J'imagine que la technique fonctionne très bien et qu'il me serait quand même possible de trouver qui a envoyé la demande le premier et qui doit la valider, etc., mais j'ai l'impression que ce ne soit pas optimale. C'est peut-être moi qui suis en tort, mais j'ai l'impression qu'une association belongsToMany devrait pouvoir se faire dans les deux sens, sans être obligé d'avoir un doublon dans la table de données.

Il me semble avoir lu quelque part qu'il était possible de définir 'foreignKey' => false et d'utiliser les conditions pour définir un finder différent, mais ça me renvoie un erreur SQL - ce qui est assez embêtant.

array_merge fonctionne pour l'instant, certes, mais l'idée de ne pas pouvoir ordonner ou paginer mes résultats correctement ne me plaît pas tellement. Je vais quand même m'y tenir pour l'instant et continuer d'explorer un peu. Si jamais quelqu'un trouve une meilleure solution par contre, je suis preneur. :)