[Edit] : Utiliser champ d'un Contain dans Where

Par JeremyB, il y a 11 ans


EDIT : nouvelle requête, plus simple.

Bonjour,

Voici la requête fonctionnant dans phpMyAdmin :

SELECT SeanceUsers.id AS `SeanceUsers__id`, SeanceUsers.user_id AS `SeanceUsers__user_id`, SeanceUsers.content AS `SeanceUsers__content`, SeanceUsers.level AS `SeanceUsers__level`, SeanceUsers.intensity AS `SeanceUsers__intensity`, SeanceUsers.duration AS `SeanceUsers__duration`, SeanceUsers.help AS `SeanceUsers__help`, SeanceUsers.observation AS `SeanceUsers__observation`, SeanceUsers.views_count AS `SeanceUsers__views_count`, SeanceUsers.comments_count AS `SeanceUsers__comments_count`, SeanceUsers.created AS `SeanceUsers__created`, SeanceUsers.modified AS `SeanceUsers__modified`, Users.id AS `Users__id`, Users.last_seance_id AS `Users__last_seance_id`, Users.username AS `Users__username`, Users.avatar AS `Users__avatar`, Users.slug AS `Users__slug`, Users.objectif AS `Users__objectif`, Users.weight AS `Users__weight`, Users.size AS `Users__size` FROM seance_users SeanceUsers LEFT JOIN users Users ON Users.id = (SeanceUsers.user_id) WHERE SeanceUsers.id = Users.last_seance_id ORDER BY SeanceUsers.created desc

Le but étant d'afficher seulement la dernière séance de chaque membre. Car un membre peut avoir plusieurs séances, mais à l'affichage sur l'index, j'aimerai lister que la séance la plus récente de chaque membre.

J'enregistre donc la dernière séance (last_seance_id) dans la table user.

Malheureusement, je n'arrive pas utiliser un champs se trouvant dans un contain. Pour l'instant, je n'ai que ceci :

// SeanceController.php $this->loadModel('SeanceUsers'); $seances = $this->SeanceUsers ->find() //->autoFields(true) ->contain([ 'Users' => function ($q) { return $q->select(['id' ,'last_seance_id', 'username', 'avatar', 'slug', 'objectif', 'weight', 'size']); } ]) ->where([ 'SeanceUsers.id' => 'Users.last_seance_id' ]) ->order([ 'SeanceUsers.created' => 'desc' ]);

Ce qui me donne en SQL :c0 à la place de Users.last_seance_id, il ne prend pas en compte mon champs:

'params' => [ ':c0' => [ 'value' => 'Users.last_seance_id', 'type' => 'integer', 'placeholder' => 'c0' ] ]

Donc comment utiliser un champs se trouvant dans un contain (dans user, je veux last_seance id) pour le comparer par la suite avec l'id de la séance ?

Merci d'avance.

4 réponses

le furet 17, il y a 11 ans

Premiere question dans le model tu as bien l'association ?
2° que donne le result avec juste ->contain(['Users'])

JeremyB, il y a 11 ans

Petit Up s'il vous plait. J'ai éditer complètement mon message ci-dessus car j'ai revu toute ma requête SQL.

JeremyB, il y a 11 ans

Dans SeancesController.php :

$this->loadModel('SeanceUsers'); $this->paginate = [ 'maxLimit' => Configure::read('Seance.seance_per_page') ]; $seances = $this->SeanceUsers ->find() ->contain([ 'Users' => function ($q) { return $q->select(['id' ,'last_seance_id', 'username', 'avatar', 'slug', 'objectif', 'weight', 'size']); } ]) ->where([ 'SeanceUsers.id' => 'Users.last_seance_id' ]) ->order([ 'SeanceUsers.created' => 'desc' ]); $seances = $this->paginate($seances); $this->set(compact('seances'));

Dans SeanceUsersTable.php :

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

Dans UsersTable.php :

$this->hasMany('SeanceUsers', [ 'foreignKey' => 'user_id', 'dependent' => true, 'cascadeCallbacks' => true ]);

Avec une requête simple comme ceci :

$this->loadModel('SeanceUsers'); $this->paginate = [ 'maxLimit' => Configure::read('Seance.seance_per_page') ]; $seances = $this->SeanceUsers ->find() ->contain([ 'Users' => function ($q) { return $q->select(['id', 'username', 'avatar', 'slug', 'objectif', 'weight', 'size']); } ]) ->order([ 'SeanceUsers.created' => 'desc' ]); $seances = $this->paginate($seances); $this->set(compact('seances'));

Ça me donne ceci dans la table seance_users :

id | user_id | created -------|------------|------------ 3 | 2 | 18/01/15 2 | 2 | 17/01/15 1 | 1 | 16/01/15

Mais avec ce code là (en groupant par rapport à user_id) :

$this->loadModel('SeanceUsers'); $this->paginate = [ 'maxLimit' => Configure::read('Seance.seance_per_page') ]; $seances = $this->SeanceUsers ->find() ->contain([ 'Users' => function ($q) { return $q->select(['id', 'username', 'avatar', 'slug', 'objectif', 'weight', 'size']); } ]) ->group([ 'SeanceUsers.user_id' ]) ->order([ 'SeanceUsers.created' => 'desc' ]); $seances = $this->paginate($seances); $this->set(compact('seances'));

J'aurai voulu avoir :

id | user_id | created -------|------------|------------ 3 | 2 | 18/01/15 1 | 1 | 16/01/15

(résultat obtenu avec ma requête SQL dans mon premier message)

Mais ça me donne ça :

id | user_id | created -------|------------|------------ 2 | 2 | 17/01/15 1 | 1 | 16/01/15

En gros, le group sur user_id me prend le plus petit id de la séance (soit la première séance du membre) alors que j'aimerai qu'il me donne le dernier id de la séance du membre ! une sorte de group by sur user_id mais desc sur l'id de la séance.

Je dois buguer quelque part, et pourtant ça ne doit pas être compliqué à récupérer ce genre d'info (comme récupérer le dernier article pour chaque catégorie, récupérer le dernier sujet de chaque forum etc).

JeremyB, il y a 11 ans

Bonjour,

J'ai résolu mon problème en faisant autrement : dans ma table seance_users, j'ai rajouté un champs is_last prenant comme valeur 0 ou 1. Ainsi, lorsque je rajoute une séance, je mets la nouvelle séance à 1 et l'ancienne à 0, et à l'index, je fais une requête en prenant en compte is_last = 1 dans le where.

Beaucoup plus simple, moins prise de tête. Merci quand même.