Lier plusieurs tables

Par tapesec, il y a 14 ans


Bonjour amis de Grafikart :)

J'essaye de faire un blog.
Mon problème c'est que je n'arrive pas a lier des membres aux commentaires, je m'explique :

J'en suis à la partie ou quand je clic sur un article de mob blog, ça dirige vers une page où l'on peut lire l'article en entier.

Dans cette page représenté par ma fonction voir() dans mon PostsController, je voudrais donc lier trois tables qui sont les suivantes :

1 table users
1 table posts
1 tables comments

Pour que je puisse afficher dans ma vue voir.ctp

le pseudo de l'utilisateur lié au post affiché, les commentaires lié au post et pour finir, <u><strong>les users lié aux commentaires</strong></u>.

J'ai crée ces trois models

<?php
class Post extends AppModel{
    public $belongsTo = array('Category', 'User');
    public $hasMany = 'Comment';
}
?>

<?php
class Comment extends AppModel{
    public $belongsTo = array('Post', 'User');

}
?>

<?php
class User extends AppModel{
    public $hasMany = array('Comment', 'Post');
}
?>

Je pense pas m'etre trompé de ce coté là

Ensuite dans mon post controller j'ai écrit ça pour la fonction voir

<?php
function voir($id){
            $this->layout = 'default';
            $b = $this->Post->find('first', array('conditions' => array('Post.id' => $id)
            ));
            $d = $this->Post->Comment->User->find('all', array('conditions' => array('User.id' => 'Comment.user_id')
            )); //cette instruction je l'ai rajouté pour vous montrer ce que je tente de faire mais ça ne change rien que 
                            //je la mette ou non.
            $this->set('article', $b, $d);
        }?>

Voila pour finir quand je fais un débug voilà ce qui va s'afficher, quasiment tout sauf les users lié aux commentaires c'est ca mon probleme

Array
(
    [Post] => Array
        (
            [id] => 21
            [titre] => Helper Mark it up
            [contenu] => Ici le contenu de mon article.

            [created] => 2011-12-14 18:24:01
            [category_id] => 1
            [user_id] => 21
        )
    [Category] => Array
        (
            [id] => 1
            [titre] => Javascript
        )
    [User] => Array
        (
            [id] => 21
            [username] => tapesec
            [mail] => ******** @gmail.com
            [password] => 6450618408daa4c956a2a18abc0d1720838f9341
            [created] => 2012-01-05 07:16:13
            [lastlogin] => 2012-01-14 08:14:42
            [active] => 1
        )
    [Comment] => Array
        (
            [0] => Array
                (
                    [id] => 3
                    [post_id] => 21
                    [user_id] => 21
                    [contenu] => Voici un premier commentaire
                    [created] => 2012-01-12 00:00:00
                )
                  //j'aurai aimé afficher l'user auteur du commentaire 
            [1] => Array
                (
                    [id] => 4
                    [post_id] => 21
                    [user_id] => 22
                    [contenu] => voici un seconde commentaire 
                    [created] => 2012-01-12 00:00:00
                )
                //ici pareil
        )
)

26 réponses

tapesec, il y a 14 ans

Ca donnerai quoi ?

<?php
function voir($id){
            $this->layout = 'default';
            $b = $this->Post->find('first', array('conditions' => array('Post.id' => $id), 'recursive' => 0));
            $c = $this->Post->Comment->find('all', array('conditions' => array('Comment.post_id' => $id), 'recursive' => 0)); 
            $this->set('article', $b, $c);
        }
?>

SI c'est ca cela ne fonctionne pas mais je me doute que j'ai faux

extrarox, il y a 14 ans

Salut,

Essaye avec un recursive à 2.

tapesec, il y a 14 ans

J'ai du mal à comprendre a quoi sert et comment fonctionne recursive

tapesec, il y a 14 ans

Je ne sais pas où mettre le recursive partout où j'essaye ça donne des erreurs

extrarox, il y a 14 ans

Le récursive se mets comme ça :

$b = $this->Post->find('first', array(
        'conditions' => array('Post.id' => $id),
        'recursive' => 2
    ));

En gros c'est un niveau de profondeur.

A+

tapesec, il y a 14 ans

ça ne fonctionne pas ca marque SQLSTATE[42S22]: Column not found: 1054 Unknown column 'User.user_id' in 'field list'
je comprends pas

extrarox, il y a 14 ans

Essaye de mettre : posts.id pour le premier
Et : comments.id et users.id pour l'autre.

tapesec, il y a 14 ans

Non du tout ca marche pas puis comme je te dit la seconde ligne ne sert a rien ca fonctionne pas comme ca apparemment mais merci quand même de l'aide :)

tapesec, il y a 14 ans

Avec le comportement containable de extrarox ca me sort rien, enfin le même contenu que mon premier message sans les users de mes commentaires.
Franchement je me demande si j'ai bien fait ma base de donnée.

Dans ma table comment j'ai un champ post_id et un champ user_id j'ai bien fait non ?

extrarox, il y a 14 ans

Oui c'est bon, mais ta table c'est comment ou comments? Parce que c'est comments.

tapesec, il y a 14 ans

comments

extrarox, il y a 14 ans

Ta requête s'affiche quand tu exécutes la page via la fonctionnalité de cake? Si oui, ça affiche quoi?

extrarox, il y a 14 ans

Bon on abandonne le recursive, on va utiliser le comportement Containable :

On change Post :

<?php 
class Post extends AppModel{

    public $actsAs = array('Containable');
    public $belongsTo = array('Category', 'User');
    public $hasMany = 'Comment';

}
?>

Puis dans le find on fait:

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

A+

Grafikart, il y a 14 ans

Alors moi je simplifierais.
D'un côté un find sur Post pour récupérer l'article (recursive 0 pour avoir l'utilisateur lié)
Un autre find sur Comment avec la condition sur post_id et (recursive 0 pour avoir l'utilisateur lié)

tapesec, il y a 14 ans

J'ai donc cette fonction dans PostsController

function voir($id){
            $this->layout = 'default';
            $b = $this->Post->find('first', array('conditions' => array('Post.id' => $id), 'contain' => array('Comment' => array('User')
            )
            )); 
            $this->set('article', $b);
        }

Et quand je fais dans voir.ctp

echo debug($article);

ça m'affiche ceci :

Array
(
    [Post] => Array
        (
            [id] => 21
            [titre] => Helper Mark it up
            [contenu] => Amis du FriendBlog bonsoir,
  Ce soir je vais vous parler d'un helper pour integrer le célèbre plugin Jquery nommé "Mark it up".

            [created] => 2011-12-14 18:24:01
            [category_id] => 1
            [user_id] => 21
        )
    [Category] => Array
        (
            [id] => 1
            [titre] => Javascript
        )
    [User] => Array
        (
            [id] => 21
            [username] => tapesec
            [mail] => lionel.dupouy@gmail.com
            [password] => 6450618408daa4c956a2a18abc0d1720838f9341
            [created] => 2012-01-05 07:16:13
            [lastlogin] => 2012-01-14 08:14:42
            [active] => 1
        )
    [Comment] => Array
        (
            [0] => Array
                (
                    [id] => 3
                    [post_id] => 21
                    [user_id] => 21
                    [contenu] => Do your layouts deserve better than Lorem Ipsum? Apply as an art director and team 
                    [created] => 2012-01-12 00:00:00
                )
            [1] => Array
                (
                    [id] => 4
                    [post_id] => 21
                    [user_id] => 22
                    [contenu] => turpis. Curabitur id nibh mi, eu consectetur lacus. 
                    [created] => 2012-01-12 00:00:00
                )
        )
)
extrarox, il y a 14 ans

Ce que tu me montres n'a pas pris en compte le containable, tu as bien mis le actsAs dans ta class Post?

tapesec, il y a 14 ans

oui monsieur

<?php
class Post extends AppModel{
    public $actAs = array('Containable');
    public $belongsTo = array('Category', 'User');
    public $hasMany = 'Comment';
}
?>
extrarox, il y a 14 ans

C'est actsAs, il y a un "s"^^

tapesec, il y a 14 ans

oh punaise ça marche ce boulet ! merci infiniment ^^ tu es trop fort !

tapesec, il y a 14 ans

Attends mince du coup j'ai plus ma table category ...

EDIT : Ah c'est bon j'ai réussi à la rajouter dans la fonction (ca commence à rentrer).

Par contre j'aurai été curieux de savoir comment marche la maniere "plus simple" de grafikart, est ce que le comportement containable ne ralentit pas l'application inutilement ?

XciD, il y a 14 ans

non , enfin pour ma part je trouve cela bien plus optimisé, tu devrais spécifier les champs que tu veux pour optimiser au mieux la recherche
du genre :

$data = current($this->Operation->find('all',array(
            'conditions' => array(
                'Operation.nb' => $nb,
                'Operation.user_id' => $this->Auth->user('id'),
                'Operation.compte_nb'   => $co
                ),
            'contain' => array(
                'Compte' => array(
                    'conditions' => array(
                        'Compte.nb' => $co,
                        'Compte.user_id' => $this->Auth->user('id')),
                    'fields' => array('Compte.slug','Compte.nb','Compte.name')
                    ),
                'Category' => array(
                    'conditions' => array(
                        'Category.user_id' => $this->Auth->user('id'))  
                        )
                )   
            )
        )
        );

Tu choisis directement les champs nécessaires

tapesec, il y a 14 ans

Merci pour ces précisions.

Je me heurte maintenant a un autre probleme c'est celui de la validation des données de mon formulaire commentaire.

J'ai un seul champ c'est le contenu, vu que seul un membre connecté peut écrire un commentaire et que j'ai pas mis de titre à ce commentaire.

J'ai fait ça dans mon modele commentaire :

<?php
class Comment extends AppModel{
    public $belongsTo = array('Post', 'User');

    /* public $validate = array(
        'contenu' => array(
            'alphaNumeric' => array(
                'rule' => 'alphaNumeric',
                'allowEmpty' => false,
                'required' => true,
                'message' => 'Que des caractères alphanumérique'
            ),
            'length' => array(
                'rule' => array('minLength', '3'),
                'message' => 'Minimum 3 caractères'
            )
        )
    );
}
?>

et dans mon controller :

<?php
function voir($id){
    if(!empty($this->request->data)){
    if($this->Post->Comment->validates()){
        $this->Post->Comment->save($this->request->data);
            $this->Session->setFlash("Votre commentaire a bien été enregistré !", "notif"); 
    }else{
        $this->Post->Comment->validationErrors();
    }
    }   
    $this->layout = 'default';
    $b = $this->Post->find('first', array('conditions' => array('Post.id' => $id), 'contain' => array('Comment' => array('User'), 'Category'
    )
    )); 
    $this->set('article', $b);

    }?>

Ca me fait un erreur de syntaxe dans ma base de données un truc un peu abominable, je me demande si ca vient pas du fait que je travaille sur une fonction voir qui traite le modele Comment dans le controller Post. Ca m'embrouille grave je suis pas encore suffisament à l'aise avec cakePhP pour m'en sortir. Tu aurais un indice ? ;)

J'abuse un peu de ta gentillesse .

XciD, il y a 14 ans

tu peux poster l'erreur sql ?

tapesec, il y a 14 ans

Error: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'validationErrors' at line 1.

La voici, étrange non ?

XciD, il y a 14 ans

tu peux avoir la requette en cliquant sur l'erreur non ?

tapesec, il y a 14 ans

Salut xcid je rentre du travail désolé de pas avoir répondu plutôt.

Non je ne peux pas cliquer dessus.
Je vais recreer un post pour reposer ma question au propre ca sera peut être mieux :)