[sujet réédité pour simplifier la question]

Salut à toutes et à tous!

Voici comment se compose mon système d'évènements : les utilisateurs peuvent créer des évènements où d'autres peuvent s'inscrirent.
Ces évènements sont listés dans un tableau :

Vendeur ...|... Evenement ...|... Ville ...|... Region ...|... Date ...|... Vendeur supp. ...|... Inscription
___________________________________________________________________________________________________________________________________
Jean......... foire ......... toulouse ..... midi-pyrénée . 01/01/2014 ..... 3 .............. Pierre - Julien - 1 place restante
Jean........ salon ......... toulouse ..... midi-pyrénée . 07/01/2014 ..... 4 .............. Adrien - Nicolas - 2 places restantes

J'ai 2 cas. Le premier c'est de récupérer tous les évènements que Jean a créé. Dans la colonne "Inscription", je veux récupérer tous les inscrits pour les évènements dont Jean fait partie.
En gros le schéma c'est :

Evènements que Jean a créé
.... foire
........ Pierre
........ Julien
.... salon
........ Adrien
........ Nicolas

Dans le second cas, je veux récupérer tous les évènements dont Jean fait partie avec les autres inscrits.
Le tableau d'exemple est le suivant :

Vendeur ...|... Evenement ...|... Ville ...|... Region ...|... Date ...|... Vendeur supp. ...|... Inscription
___________________________________________________________________________________________________________________________________
Pierre ......... foire ......... toulouse ..... midi-pyrénée . 01/01/2014 ..... 3 .............. Jean - Julien - 1 place restante
Adrien ........ salon ......... toulouse ..... midi-pyrénée . 07/01/2014 ..... 4 .............. Jean - Nicolas - 2 places restantes

Le schéma dans ce cas serait :

Evènements où Jean est inscrit
.... foire
........ Jean
........ Julien
.... salon
........ Jean
........ Nicolas

Les tables :
J'ai 3 tables events - users - events_users avec une relation HABTM que j'ai mise dans mes modèles Event et User. Un User peut s'inscrire à plusieurs évènement ET un évènement peut avoir plusieurs Users inscrits. Par contre un User peut créer plusieurs évènement MAIS un évènement ne peut être créé que par un User : dans ma table events j'ai les champs "user_id" et "username" pour savoir qui a créé un évènement donc à part que je me trompe il n'y a pas besoin de créer de relation dans ce cas.

--
-- Table structure for table `events`
--
CREATE TABLE IF NOT EXISTS `events` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `username` varchar(255) NOT NULL,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  `location` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  `region` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  `date` datetime NOT NULL,
  `additional` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

--
-- Table structure for table `users`
--
CREATE TABLE IF NOT EXISTS `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=33 ;

--
-- Table structure for table `events_users`
--
CREATE TABLE IF NOT EXISTS `events_users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `event_id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;

Vous savez tout sur mon petit système. Donc mes 2 cas plus haut, comment récupérer les données suivantes :

Evènements que Jean a créé
... foire
...... Pierre
...... Julien
... salon
...... Adrien
...... Nicolas

Evènements où Jean est inscrit
... foire
...... Jean
...... Julien
... salon
...... Jean
...... Nicolas

Je vous remercie grandement par avance :) parque je ne sais vraiment pas comment faire! Merci de votre aide!

17 réponses


Je te conseille d'utiliser un counterCache pour compter le nombre de personnes inscrites par évènement. Ensuite utilises-tu le comportement Containable ou pas ?

Salut Flourt,

j'ai pas encore utilisé le counter cache. Par contre j'utilise containable.

En fait j'ai réussi à récupérer tous les évènements puis afficher le nombre restant de place.
Là où je bloque c'est comment je peux récupérer les évenements où est inscrit un utilisateur avec en plus les autres inscrits? C'est la même chose mais en faisant une requête qui va chercher les évènements où est inscrit un utilisateur et tous les autres utilisateurs inscrits avec lui sur les évènements où il est inscrit donc.

Comment tu ferais ça? Pour l'instant on parle pas de code mais juste de procédé pour y arriver.

Si tu fais passer l'id de l'utilisateur auquel tu veux récupérer l'évènement tu peux utiliser :

$this->Event->find('first',
    array(
        'contain' => array(
            'User' => array(
                'conditions' => array('User.id' => $id)
            )
        )
    )
);

De tête si j’écris pas trop de bêtises

En revanche, si tu as directement l'id de l'évènement tu peux faire :

$this->Event->find('first',
    array(
        'contain' => array('User')
    )
);

Et là tu récupère tous les utilisateurs liés à ton évènement.

Salut Flourt et merci pour ta réponse.

J'ai fais les tests et ça ne récupère pas encore ce que je veux.
Les éléments que je possède sur ma page via ma session correspondent à l'utilisateur qui est loggé.
Donc j'ai son id. Partant de là il faudrait que ma requête récupère TOUS les EVENTS où le user est inscrit + TOUS les USERS qui sont inscrits avec lui.

Avec une requête comme la suivante, je récupère TOUS les évènements où l'utilisateur loggé est inscrit :

$d'user'] = $this->User->find('all', array('contain' => 'Event', 'conditions' => array('User.id' => $user_id)));
// debug $d
array(
    'user' => array(
        (int) 0 => array(
            'User' => array(
                'password' => ' *****',
                'id' => '32',
                'username' => 'user',
                'firstname' => 'livin',
                'lastname' => 'inchina',
                'mail' => 'email@yahoo.com',
                'telephone' => '1234567890',
                'address' => 'avenue lambda',
                'zipcode' => 'P7B 1S1',
                'city' => 'montreal',
                'region' => 'Quebec',
                'created' => '2013-05-11 02:21:35',
                'lastlogin' => '2013-05-21 06:47:11',
                'active' => '1'
            ),
            'Event' => array(
                (int) 0 => array(
                    'id' => '2',
                    'user_id' => '29',
                    'username' => 'admin',
                    'name' => 'Salon de l'automobile 2014 et portes ouvertes',
                    'location' => 'toronto',
                    'region' => 'ontario',
                    'date' => '2013-05-08 00:00:00',
                    'license' => false,
                    'additional' => '4',
                    'EventsUser' => array(
                        'id' => '2',
                        'user_id' => '32',
                        'event_id' => '2'
                    )
                )
            )
        )
    )
)

Par contre comme tu peux le voir dans l'array "Event" dernier champs 'EventsUser', je récupère bien l'utilisateur loggé ('user_id' => '32') mais je n'ai pas les autres inscrits avec lui. En fait le champs 'EventsUser' devrait lui même contenir un array avec tous les utilisateurs de l'Event 'id' => '2'.

J'espère que tu vois ce que je veux dire. Je sais pas si c'est comme ça que ça devrait être mais c'est comment je vois la chose pour l'instant.

Qu'est ce que t'en pense?

Merci encore de ton aide, j'espère que je t'embête pas trop avec mon système ^^

A ce moment tu fait un foreach($d'user']'Event'] as $event){

$this->Event->User->find('all',
    array(
        'contain' => array(
            'EventsUser' => array(
                'conditions' => array('EventsUser.event_id' => $event'id'])
            )
        )
    )
);

C'est pas super propre mais ça doit récupérer tes membres comme ça. As-tu essayé en mettant dans ta requête 'contain' => array('Event',EventsUser) ?

J'avais pas essayé, je viens de le tester mais ça ne récupère pas encore ce qu'il faut.
En tout cas avec toutes les solutions que tu proposes je pense qu'on va trouver.

Pour info, je suis sur la page de profil d'un utilisateur. Sur cette page, un utilisateur peut voir le profil d'un user, les events qu'il a créé et les events auxquels il s'est inscrit.
Pour schématiser :

  • Profil
  • Tableau des events créé par User
  • Tableau des events où User est inscrit

Pour ce faire, je suis dans mon controller UsersController.php. C'est ma fonction index qui est censé afficher ces résultats.
J'ai ma relation HABTM dans mon model User et je load le model Event dans mon controller UsersController.php (je sais pas si c'est bien mais je l'ai fait ^^). Enfin j'effectue mes requêtes.

Voilà ma fonction :

<?php
class UsersController extends AppController{
    function index(){
        $user_id = $this->Auth->user('id');
        if (!$user_id) {
            $this->redirect('/');
            die();
        }
        $this->User->id = $user_id;
        $this->loadModel('Event');
        $d'user'] = $this->Event->User->find('all',
            array(
                'contain' => array(
                    'EventsUser' => array(
                        'conditions' => array('EventsUser.user_id' => $user_id)
                        )
                    )
                )
            );
        // $e'events'] = $this->Event->find('all', array('contain' => 'User', 'conditions' => array('Event.user_id' => $user_id)));
        // $i'event'] = $this->Event->find('first',
        // array(
        // 'contain' => array(
        // 'User' => array(
        // 'conditions' => array('User.id' => $user_id)
        // )
        // )
        // )
        // );
        debug($d); die();
        // debug($e); die();
        // debug($i); die();
        // $this->set($d);
        // $this->set($e);
    }
}

Comme tu peux le voir j'ai tenté plusieurs solutions mais jusqu'à présent impossible de récupérer à la fois les events d'un utilisateur avec les autres inscrits.

Y'a forcément un truc que je fais pas comme il faut. Pour l'instant j'en reste au controller avec un debug() suivi d'un die() pour voir le tableau récupéré.

Est-ce que ça te permet d'en savoir plus?

Merci encore Flourt!

Je croyais que tu étais dans le controlleur EventsController depuis le début moi ^^
Euh au lieu de ça :

$d'user'] = $this->Event->User->find('all',
            array(
                'contain' => array(
                    'EventsUser' => array(
                        'conditions' => array('EventsUser.user_id' => $user_id)
                        )
                    )
                )
            );

Essaies ça :

$d'user'] = $this->User->find('all',
            array(
                'contain' => array(
                    'EventsUser' => array(
                        'conditions' => array('EventsUser.user_id' => $user_id)
                        ),
                    'Event'
                    )
                )
            );

Pas besoin de loader ton modèle Event si tu as ta liaison qui est faites dans ton modèle.

Non toujours pas.
Voici le debug de $d :

array(
    'user' => array(
        (int) 0 => array(
            'User' => array(
                'id' => '29',
                'username' => 'admin',
            ),
            'Event' => array(
                (int) 0 => array(
                    'id' => '2',
                    'user_id' => '29',
                    'username' => 'admin',
                    'name' => 'Salon de l'automobile 2014 et portes ouvertes',
                    'EventsUser' => array(
                        'id' => '4',
                        'user_id' => '29',
                        'event_id' => '2'
                    )
                ),
                (int) 1 => array(
                    'id' => '3',
                    'user_id' => '32',
                    'username' => 'user',
                    'name' => 'Marché de nuit',
                    'EventsUser' => array(
                        'id' => '3',
                        'user_id' => '29',
                        'event_id' => '3'
                    )
                )
            )
        ),
        (int) 1 => array(
            'User' => array(
                'id' => '32',
                'username' => 'user',
            ),
            'Event' => array(
                (int) 0 => array(
                    'id' => '2',
                    'user_id' => '29',
                    'username' => 'admin',
                    'name' => 'Salon de l'automobile 2014 et portes ouvertes',
                    'EventsUser' => array(
                        'id' => '2',
                        'user_id' => '32',
                        'event_id' => '2'
                    )
                )
            )
        )
    )
)

Le profil affiché est celui du User id 32. Donc le premier array user[0] est mauvais car le user 32 n'y est pas inscrit, il ne devrait pas s'afficher vu qu'on veut afficher uniquement les events où user 32 est inscrit ainsi que d'autres users inscrit avec lui. Dans le second array user[1] on récupère bien le profil user 32 mais dans Event[EventsUser] il manque le user admin id 29 qui est lui aussi inscrit.

C'est un véritable casse tête mon truc o_O!

Si il faut mes liaisons ne permettent pas de récupérer ces éléments, à savoir les évènements où est inscrit un user et ceux qui sont inscrits avec lui. Pourtant me semble que mes laisons sont bonnes : User HAMTM Event / Event HABTM User. Ensuite c'est la table events_users que je n'arrive pas à requêter, c'est justement là où j'ai tous mes inscrits. Non là vraimnt je sais plus où chercher...

En tout cas merci de ta patience, si t'en peux plus je comprendrais t'inquiètes pas. :)

Je crois que je viens de trouver grâce à ta méthode mais à l'envers, ça donne ça :

$d'user'] = $this->User->Event->find('all',
            array(
                'contain' => array(
                    'EventsUser' => array(
                        'conditions' => array('EventsUser.user_id' => $user_id)
                        ),
                    'User'
                    )
                )
            );

et le debug donne ça :

array(
    'user' => array(
        (int) 0 => array(
            'Event' => array(
                'id' => '1',
                'user_id' => '29',
                'username' => 'admin',
                'name' => 'Foire',
            ),
            'User' => array()
        ),
        (int) 1 => array(
            'Event' => array(
                'id' => '2',
                'user_id' => '29',
                'username' => 'admin',
                'name' => 'Salon de l'automobile 2014 et portes ouvertes',
            ),
            'User' => array(
                (int) 0 => array(
                    'id' => '32',
                    'username' => 'user',
                    'EventsUser' => array(
                        'id' => '2',
                        'user_id' => '32',
                        'event_id' => '2'
                    )
                ),
                (int) 1 => array(
                    'id' => '29',
                    'username' => 'admin',
                    'EventsUser' => array(
                        'id' => '4',
                        'user_id' => '29',
                        'event_id' => '2'
                    )
                )
            )
        ),
        (int) 2 => array(
            'Event' => array(
                'id' => '3',
                'user_id' => '32',
                'username' => 'user',
                'name' => 'Marché de nuit',
            ),
            'User' => array(
                (int) 0 => array(
                    'id' => '29',
                    'username' => 'admin',
                    'EventsUser' => array(
                        'id' => '3',
                        'user_id' => '29',
                        'event_id' => '3'
                    )
                )
            )
        ),
        (int) 3 => array(
            'Event' => array(
                'id' => '6',
                'user_id' => '29',
                'username' => 'admin',
                'name' => 'test event',
            ),
            'User' => array()
        )
    )
)

J'ai vérifié ma table events_users et les liaisons semblent correspondre!
Donc le premier array affiche les events et le second les users inscrits.
Par contre dans l'array 'User' je n'ai pas besoin du champs 'EventsUser', il est redondant puisqu'il m'affiche un tableau qui dit la même chose que les 2 arrays Event et User réunit. Soit je ne garde que celui là, soit je le supprime de la requête.

Tu vois un moyen de faire ça?

En tout cas je suis content grâce à toi ça prend forme! ^^ merci!

En reprenant ma requête et en forçant le récursive a 2 t'obtiens quoi ? Ou en reprenant avec le récursive la 1.

En regardant sur la doc on peut faire des associations plus "profondes" ils appellent ça "deep" en english.
http://book.cakephp.org/2.0/fr/core-libraries/behaviors/containable.html

Ça donnerais dans ton cas ceci :

$this->User->find('all', array(
    'contain' => array(
        'Event',
        'EventsUser' => array(
            'User'
        )
    )
));

A tester ..

Salut Flourt

Je suis allé voir la doc aussi pour creuser davantage le containable behaviour.
J'ai testé pas mal de possibilités et j'en ai trouvé une par contre je suis obligé de loader le model Event pour faire cette requête dans mon controller Users.

Sachant que j'ai l'id d'un user et que je veux tous les events où il est inscrit + les autres inscrits avec lui,
j'ai essayé ça :

$r'registered'] = $this->Event->find('all', array(
            'fields' => array('Event.id', 'Event.user_id', 'Event.username', 'Event.name'),
            'contain' => array(
                'User' => array(
                    'fields' => array('User.id', 'User.username')
                    ),
                'EventsUser'
                )
            )
        );

Bien sûr vu que je ne précise aucune condition j'ai une liste de tous les évènements avec leurs inscrits.

Voici le debug($r) :

array(
    'registered' => array(
        (int) 0 => array(
            'Event' => array(
                'id' => '1',
                'user_id' => '29',
                'username' => 'admin',
                'name' => 'Foire'
            ),
            'User' => array()
        ),
        (int) 1 => array(
            'Event' => array(
                'id' => '2',
                'user_id' => '29',
                'username' => 'admin',
                'name' => 'Salon de l'automobile 2014 et portes ouvertes'
            ),
            'User' => array(
                (int) 0 => array(
                    'id' => '32',
                    'username' => 'user',
                    'EventsUser' => array(
                        'id' => '2',
                        'user_id' => '32',
                        'event_id' => '2'
                    )
                ),
                (int) 1 => array(
                    'id' => '29',
                    'username' => 'admin',
                    'EventsUser' => array(
                        'id' => '4',
                        'user_id' => '29',
                        'event_id' => '2'
                    )
                )
            )
        ),
        (int) 2 => array(
            'Event' => array(
                'id' => '3',
                'user_id' => '32',
                'username' => 'user',
                'name' => 'Marché de nuit'
            ),
            'User' => array(
                (int) 0 => array(
                    'id' => '29',
                    'username' => 'admin',
                    'EventsUser' => array(
                        'id' => '3',
                        'user_id' => '29',
                        'event_id' => '3'
                    )
                )
            )
        ),
        (int) 3 => array(
            'Event' => array(
                'id' => '6',
                'user_id' => '29',
                'username' => 'admin',
                'name' => 'test event'
            ),
            'User' => array(
                (int) 0 => array(
                    'id' => '32',
                    'username' => 'user',
                    'EventsUser' => array(
                        'id' => '5',
                        'user_id' => '32',
                        'event_id' => '6'
                    )
                )
            )
        )
    )
)

Dans mon debug j'ai bien tous les events avec leurs inscrits respectifs. Mainteant ce que je voudrais c'est filtrer en affichant les résultats où le 'User'[id]=32. Autrement dit dans l'array ci-dessus, on aurait les arrays (int) 1 => array et (int) 3 => array qui comporttent le user id=32.

Là on y est presque, tu vois comment je peux placer la condition pour enfin y arriver?

Merci à toi Flourt

Ca devrait suffire ça non ?

$r'registered'] = $this->Event->find('all', array(
    'fields' => array('Event.id', 'Event.user_id', 'Event.username', 'Event.name'),
    'conditions' => array('Event.user_id' => $user_id),
    'contain' => array(
        'User' => array(
            'fields' => array('User.id', 'User.username')
            ),
        'EventsUser'
        )
    )
);

Justement non, ce serait logique pourtant mais ça ne fonctionne pas o_O

Voilà le debug :

array(
    'registered' => array(
        (int) 0 => array(
            'Event' => array(
                'id' => '3',
                'user_id' => '32',
                'username' => 'user',
                'name' => 'Marché de nuit'
            ),
            'User' => array(
                (int) 0 => array(
                    'id' => '29',
                    'username' => 'admin',
                    'EventsUser' => array(
                        'id' => '3',
                        'user_id' => '29',
                        'event_id' => '3'
                    )
                )
            )
        )
    )
)

Là il est censé récupérer le salon de l'auto et le test event puisque le user id=32 y est inscrit. Je suis en train de me rendre compte d'un truc. Dans ma table events, il y a un champs user_id qui me permet de sauvegarder l'id du user créateur de l'event. Tu pense que le fait de l'appeler 'user_id' peut porter à confusion avec le champ du même nom 'user_id' de la table events_users? Je verrai que ça là...

[EDIT] Apparement ça vient pas du champs user_id qui maintenant est userid. Retour à la case départ.
Avec la condition 'Event.user_id' => $user_id en fait on dit à la requête de récupérer les events avec le userid = 32. Forcément il nous affiche celui que user 32 a créé et non pas ceux où il est inscrit. Donc c'est pas encore ça.
On peut pas faire une liaison dans la condition en lui disant qu'il prenne tous les events qui correspondent à ceux dont le user 32 est inscrit dans la table events_users, genre :

$r'registered'] = $this->Event->find('all', array(
    'fields' => array('Event.id', 'Event.user_id', 'Event.username', 'Event.name'),
    'conditions' => array('Event.user_id' WHERE 'EventsUser.user_id' => $id),
    'contain' => array(
        'User' => array(
            'fields' => array('User.id', 'User.username')
            ),
        'EventsUser'
        )
    )
);

Tu vois dans la condition lui dire tous les events où le user est inscrit dans la table events_users, tu vois le truc?

Si tu peux créer des liaisons à la volée et dire par exemple que ton utilisateur connecté hasMany Event du coup il te récupèrera dans un premier temps tout tes events.

$this->User->unbindModel(
        array('hasAndBelongsToMany' => array('Event'))
    );
$this->User->bindModel(
        array('hasMany' => array(
                'Evenet' => array(
                    'className' => 'Event'
                )
            )
        )
    );

A tester ! :)

Je vais regarder ça d'un peu plus près dans la doc et je te dirais ce qu'il en est.
Si jamais je n'y arrive pas, dans la page profil d'un user où se trouvent le tableau des events dans lesquels le user est inscrit, je n'y mettrait qu'un lien pour se désinscrire. Il ne verra pas qui est inscrit avec lui ni s'il reste de la place mais tant pis, j'ai pas vraiment le choix.

Je regarde quand même et je te tiens au courant.
Merci encore pour ton aide Flourt, t'as vraiment assuré je me suis senti moins seul dans mon problème ^^

Pas de soucis mais de toute façon au pire tu peux le faire en plusieurs requête ce que tu veux faire c'est sûr.