Bonjour la compagnie ;) voici mon petit soucis que j'ai beau retourné dans tout les sens, je n'arrive pas à résoudre.
j'ai suivis la formation à la lettre pourtant : http://www.grafikart.fr/formation/cakephp/associations-model
J'ai une table posts, tags, posts_tags, authors (Mon Model Blog utilise la table posts)
donc tout se passe bien au niveau de la récupération de mes posts de l'auteur mais dès qu'il s'agit de récupérer les noms des tags la sa ne fonctionne pas. Pourtant quand je fait un debug('$posts'); je récupère bien tout les valeur voulus.
Voici mon code :
Erreur obtenue quand je veut récupéré le Tag associé a l'article.
Notice (8): Undefined index: name [APP\View\Blog\index.ctp, line 19]

debug('post'); :

\app\Controller\BlogController.php (line 7)
array(
    (int) 0 => array(
        'Blog' => array(
            'id' => '1',
            'title' => 'article numéro 1',
            'content' => 'chabada chabada',
            'created' => '2014-01-29 14:17:29',
            'slug' => 'article-numero-1',
            'category_id' => '1',
            'author_id' => '1',
            'url' => array(
                'controller' => 'blog',
                'action' => 'view',
                'id' => '1',
                'slug' => 'article-numero-1'
            )
        ),
        'Category' => array(
            'id' => '1',
            'name' => 'Music',
            'slug' => 'music',
            'blog_count' => '1'
        ),
        'Author' => array(
            'id' => '1',
            'name' => 'Xander'
        ),
        'TagR' => array(
            (int) 0 => array(
                'id' => '1',
                'tag_id' => '1',
                'post_id' => '1'
            ),
            (int) 1 => array(
                'id' => '2',
                'tag_id' => '2',
                'post_id' => '1'
            )
        ),
        'Tag' => array(
            (int) 0 => array(
                'id' => '1',
                'name' => 'Panda Roux',
                'PostsTag' => array(
                    'id' => '1',
                    'tag_id' => '1',
                    'post_id' => '1'
                )
            ),
            (int) 1 => array(
                'id' => '2',
                'name' => 'Bubble Gum',
                'PostsTag' => array(
                    'id' => '2',
                    'tag_id' => '2',
                    'post_id' => '1'
                )
            )
        )
    ),
    (int) 1 => array(
        'Blog' => array(
            'id' => '2',
            'title' => 'article numéro 2',
            'content' => 'chabada chabada SUPER CHABADA',
            'created' => '2014-01-29 14:17:29',
            'slug' => 'article-2',
            'category_id' => '2',
            'author_id' => '1',
            'url' => array(
                'controller' => 'blog',
                'action' => 'view',
                'id' => '2',
                'slug' => 'article-2'
            )
        ),
        'Category' => array(
            'id' => '2',
            'name' => 'Voyage',
            'slug' => 'voyage',
            'blog_count' => '1'
        ),
        'Author' => array(
            'id' => '1',
            'name' => 'Xander'
        ),
        'TagR' => array(),
        'Tag' => array()
    )
)

BlogController.php

<?php
class BlogController extends AppController {

    public function index(){
        $posts = $this->Blog->find('all');
        debug($posts);
        // recursive permet de faire automatiquement les liasons dépend de la valeur associé
        //array('recursive' => 1);
                              // -1 supprime toute les liaisons
                              // 0 fera les liaisons qu'il peut faire en ultilisant les LEFT joins (hasOne et belongsTo)
                              // 1 fera automatiquement les LEFT joins les liaisons hasMany et hasAndBelongsToMany (HABTM pour les intimes)
                              // 2 HAUTEMENT DECONSEILLER fera toute les liaisons et entraine un Flow de commande inutile !
        $this->set(compact('posts'));

    }
    public function beforeFilter(){
        parent::beforeFilter();
        $this->Auth->allow();
    }

    public function view(){

    }
}
?>

Blog/index.ctp

<?php foreach ($posts as $k => $post): ?>
        <?php // récupération des Posts ?>
            <h2><?= $post'Blog']'title']; ?> - <span><?= $post'Blog']'created']; ?> </span></h2>
            <img src="pandapanda.jpg" alt="" >
            <p class="description-articles">
                <?= $post'Blog']'content']; ?> 
            </p>
            <?= $this->Html->link('Lire la suite ?', $post'Blog']'url']); ?>
            <p class="author"><span>4 commentaires   -  </span><span>Auteur   :  </span><?= $post'Author']'name']; ?>   -  <span>Catégorie : </span><?= $post'Category']'name']; ?>   <span>Mots clés :  </span><strong><?= $post'Tag']'name']; ?></strong></p>
        <?php endforeach ?>

Voila donc je n'arrive pas a récupéré les 'Tag']'name']; Si vous avez des pistes je suis preneurs.

16 réponses


B-Art
Réponse acceptée

Salut Xander,

Alors, as-tu avancé?

Amethyste a raison, dans ton debug il manque une liaison permettant à Cake de faire le lien entre Tag et name

Dans ce debug le nom du tag est $post'Tag'][0]'tagname'] et non pas $post'Tag']'name']

J'ai re-regarder la formation de Graf' et vers la fin il utilise le Model de la table de liaison pour récupérer le Tag.

$posts = $this->Blog->TagR->find('all', array(...

Le problème vient peut-être de là??!

Bon dèv'

amethyste
Réponse acceptée

Essaies ca dans ta vue :

<?php foreach ($posts as $post): ?>
    <h2>
        <?php echo $post'Blog']'title']; ?> - <span><?php echo $post'Blog']'created']; ?> </span>
    </h2>
    <img src="http://ljdchost.com/h5gOiNc.gif" alt="" >
    <p class="description-articles">
        <?php echo $post'Blog']'content']; ?> 
    </p>
    <?php echo $this->Html->link('Lire la suite ?', $post'Blog']'url']); ?>
    <p class="author">
        <span>4 commentaires   -  </span>
        <span>Auteur   :  </span><?= $post'Author']'name']; ?>   -  
        <span>Catégorie : </span><?= $post'Category']'name']; ?>   
        <span>Mots clés :  </span>
        <?php foreach ($post'Tag'] as $tag): ?>
            <strong>
                <?php echo $tag'tagname']; // ou $tag'name'] ?>
            </strong> - 
        <?php endforeach ?>
    </p>
<?php endforeach ?>

Salut Xander,

Tu dois pouvoir déclarer les liaisons en utilisant le behavior 'containable'.

Dans AppModel:

public $actsAs = array('Containable');

Dans ton BlogController:

$this->Blog->contain('Tags');

J'espère que ça règlera ton problème!

Bon dèv'

xander
Auteur

Re Merci de ton aide voici ce que j'obtiens comme message d'erreur :
Warning (512): Model "Blog" is not associated with model "Tags" [CORE\Cake\Model\Behavior\ContainableBehavior.php, line 342]

alors que mon model Blog est mon model Tag sont bien associés entre eux.
Voici leur code :

Blog.php

<?php
class Blog extends AppModel{
    public $useTable = 'posts'; // me permet d'utilisé la table posts pour mes article
    // Cette fonction beforesave va nous servire à créer le slug avant toute les sauvgarde dans la BDD si le slug n'existe pas.
    public function beforeSave($options = array()){
        if(isset($this->data'Blog']'title']) && !isset($this->data'Blog']'slug']))
        {
            $this->data'Blog']'slug'] = strtolower(Inflector::slug($this->data'Blog']'title'], '-'));
        }
    }
    public function afterFind($results, $primary = false){
        foreach($results as $k => $result){
            if(
                isset($result'Blog']'id']) &&
                isset($result'Blog']'slug'])
            ){
                $results$k]'Blog']'url'] = array(
                    'controller' => 'blog',
                    'action' => 'view',
                    'id' => $result'Blog']'id'],
                    'slug' => $result'Blog']'slug']
                );
            }
        }
        return $results;
    }
    //function qui servira a faire les associations (ici belongsTo relation de type 1:N et hasMany relation de type N:1)
    public $belongsTo = array(
        'Author',
        'Category' => array(
            'counterCache' => true // counterCache me permet de compté combien d'article par categories
        )
    );
    // function qui servira a faire l'associastion entre les tags et les articles (ici relation de type N:N conc j'utilise le hasAndBelongsToMany)
    public $hasAndBelongsToMany = array('Tag');
    public $hasMany = array('TagR');
}
?>

Tag.php

<?php
class Tag extends AppModel{
    public $hasAndBelongsToMany = array('Blog');
}
?>

Voici comment j'ai inclus ta méthode :

AppModel.php

<?php
/**
 * Application model for CakePHP.
 *
 * This file is application-wide model file. You can put all
 * application-wide model-related methods here.
 *
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
 * @link http://cakephp.org CakePHP(tm) Project
 * @package app.Model
 * @since CakePHP(tm) v 0.2.9
 * @license http://www.opensource.org/licenses/mit-license.php MIT License
 */
App::uses('Model', 'Model');
/**
 * Application model for Cake.
 *
 * Add your application-wide methods in the class below, your models
 * will inherit them.
 *
 * @package app.Model
 */
class AppModel extends Model {
    public $actsAs = array('Containable');
}

BlogController.php

<?php
class BlogController extends AppController {
    public function index(){
        $this->Blog->contain('Tags');
        $posts = $this->Blog->find('all');
        debug($posts);
        // recursive permet de faire automatiquement les liasons dépend de la valeur associé
        //array('recursive' => 1);
                              // -1 supprime toute les liaisons
                              // 0 fera les liaisons qu'il peut faire en ultilisant les LEFT joins (hasOne et belongsTo)
                              // 1 fera automatiquement les LEFT joins les liaisons hasMany et hasAndBelongsToMany (HABTM pour les intimes)
                              // 2 HAUTEMENT DECONSEILLER fera toute les liaisons et entraine un Flow de commande inutile !
        $this->set(compact('posts'));

    }
    public function beforeFilter(){
        parent::beforeFilter();
        $this->Auth->allow();
    }

    public function view(){

    }
}

Merci de m'éclairé ^^

Pas besoin de containable ici, dans ton premier billet, tu récupères bien tout ce dont tu as besoin. Concernant la première erreur

Notice (8): Undefined index: name [APP\View\Blog\index.ctp, line 19]

C'est sûrement que dans ta boucle foreach, tu es tombé sur un post sans tag, soit

$post'Tag'] = array();

Du coup l'index $post'Tag']'name'] est effectivement non défini. Donc rempli ta base :)

xander
Auteur

Pourtant dans mon debug de $posts je récupère bien tout mes posts et leur tag associés je ne tombe pas dans des posts dont le tag est vide =s

app\Controller\BlogController.php (line 6)
array(
    (int) 0 => array(
        'Blog' => array(
            'id' => '1',
            'title' => 'article numéro 1',
            'content' => 'chabada chabada',
            'created' => '2014-01-29 14:17:29',
            'slug' => 'article-numero-1',
            'category_id' => '1',
            'author_id' => '1',
            'url' => array(
                'controller' => 'blog',
                'action' => 'view',
                'id' => '1',
                'slug' => 'article-numero-1'
            )
        ),
        'Category' => array(
            'id' => '1',
            'name' => 'Music',
            'slug' => 'music',
            'blog_count' => '1'
        ),
        'Author' => array(
            'id' => '1',
            'name' => 'Xander'
        ),
        'TagR' => array(
            (int) 0 => array(
                'id' => '1',
                'tag_id' => '1',
                'post_id' => '1'
            )
        ),
        'Tag' => array(
            (int) 0 => array(
                'id' => '1',
                'tagname' => 'Panda Roux',
                'PostsTag' => array(
                    'id' => '1',
                    'tag_id' => '1',
                    'post_id' => '1'
                )
            )
        )
    ),
    (int) 1 => array(
        'Blog' => array(
            'id' => '2',
            'title' => 'article numéro 2',
            'content' => 'chabada chabada SUPER CHABADA',
            'created' => '2014-01-29 14:17:29',
            'slug' => 'article-2',
            'category_id' => '2',
            'author_id' => '1',
            'url' => array(
                'controller' => 'blog',
                'action' => 'view',
                'id' => '2',
                'slug' => 'article-2'
            )
        ),
        'Category' => array(
            'id' => '2',
            'name' => 'Voyage',
            'slug' => 'voyage',
            'blog_count' => '1'
        ),
        'Author' => array(
            'id' => '1',
            'name' => 'Xander'
        ),
        'TagR' => array(
            (int) 0 => array(
                'id' => '2',
                'tag_id' => '2',
                'post_id' => '2'
            )
        ),
        'Tag' => array(
            (int) 0 => array(
                'id' => '2',
                'tagname' => 'Bubble Gum',
                'PostsTag' => array(
                    'id' => '2',
                    'tag_id' => '2',
                    'post_id' => '2'
                )
            )
        )
    )
)

Dans ce debug le nom du tag est $post'Tag'][0]'tagname'] et non pas $post'Tag']'name']

xander
Auteur

oui j'avais zapé que j'avais changé le name en tagname dans la BDD mais sa change rien a l'erreur meme si je corrige $post'Tag']'tagname']

Oui mais $post'Tag'] est un tableau imbriqué de plusieurs tableaux lui-même . Dans Blog/index.ctp

<p class="author">
                <span>4 commentaires   -  </span>
                <span>Auteur   :  </span><?= $post'Author']'name']; ?>   -  
                <span>Catégorie : </span><?= $post'Category']'name']; ?>   
                <span>Mots clés :  </span>
                <strong>
                    <?= foreach ($post'Tag'] as $tag): ?>
                    <?= $tag'tagname']; ?>
                    <?= endforeach ?>

                </strong>
            </p>
xander
Auteur

la méthode que tu viens de me donné je l'avais déjà essayé mais j'obtenais cette erreur a chaque fois que j'ai essayé de mettre un foreach dans un foreach ou de mettre 2 conditions dans mon foreach =s

Error: syntax error, unexpected 'foreach' (T_FOREACH)   
File: F:\wamp\www\YAcake\app\View\Blog\index.ctp    
Line: 19
xander
Auteur

Re je reviens vers vous car je viens de bossé les behavior, j'ai donc ajouté

Model Blog.php

public $actsAs = array('Containable', 'Slug');

BlogController.php

public function index(){
        $posts = $this->Blog->find('all', array(
            'contain' => array('Tag.name', 'Category.name')
            ));
        debug($posts);
        $this->set(compact('posts'));

    }

Je récupère bien toute les infos dont j'ai besoin voici le Debug (j'ai renomé tagname en name dans ma BDD)

\app\Controller\BlogController.php (line 8)
array(
    (int) 0 => array(
        'Blog' => array(
            'id' => '1',
            'title' => 'article numéro 1',
            'content' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc in mi id turpis facilisis tristique. Quisque sed lobortis est. Phasellus aliquet sed elit vel porttitor.',
            'created' => '2014-01-29 14:17:29',
            'slug' => 'article-numero-1',
            'category_id' => '1',
            'author_id' => '1',
            'url' => array(
                'controller' => 'blog',
                'action' => 'view',
                'id' => '1',
                'slug' => 'article-numero-1'
            )
        ),
        'Category' => array(
            'name' => 'Music'
        ),
        'Tag' => array(
            (int) 0 => array(
                'name' => 'Panda Roux',
                'PostsTag' => array(
                    'id' => '1',
                    'tag_id' => '1',
                    'post_id' => '1'
                )
            )
        )
    ),
    (int) 1 => array(
        'Blog' => array(
            'id' => '3',
            'title' => 'Ma Super Pizza 4 fromages',
            'content' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc in mi id turpis facilisis tristique. Quisque sed lobortis est. Phasellus aliquet sed elit vel porttitor.',
            'created' => '2014-01-30 23:02:26',
            'slug' => 'ma-super-pizza-4-fromages',
            'category_id' => '1',
            'author_id' => '1',
            'url' => array(
                'controller' => 'blog',
                'action' => 'view',
                'id' => '3',
                'slug' => 'ma-super-pizza-4-fromages'
            )
        ),
        'Category' => array(
            'name' => 'Music'
        ),
        'Tag' => array(
            (int) 0 => array(
                'name' => 'Bubble Gum',
                'PostsTag' => array(
                    'id' => '3',
                    'tag_id' => '2',
                    'post_id' => '3'
                )
            )
        )
    ),
    (int) 2 => array(
        'Blog' => array(
            'id' => '2',
            'title' => 'article numéro 2',
            'content' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc in mi id turpis facilisis tristique. Quisque sed lobortis est. Phasellus aliquet sed elit vel porttitor.',
            'created' => '2014-01-29 14:17:29',
            'slug' => 'article-2',
            'category_id' => '2',
            'author_id' => '1',
            'url' => array(
                'controller' => 'blog',
                'action' => 'view',
                'id' => '2',
                'slug' => 'article-2'
            )
        ),
        'Category' => array(
            'name' => 'Voyage'
        ),
        'Tag' => array(
            (int) 0 => array(
                'name' => 'Bubble Gum',
                'PostsTag' => array(
                    'id' => '2',
                    'tag_id' => '2',
                    'post_id' => '2'
                )
            )
        )
    )
)

Mais malgrès sa j'ai toujours la même erreur : Notice (8): Undefined index: name [APP\View\Blog\index.ctp, line 24]
Quand j'essaye de récupéré $post'Tag']'name'];

index.ctp

<?php foreach ($posts as $k => $post): ?>
        <?php // récupération des Posts ?>
            <h2><?= $post'Blog']'title']; ?> - <span><?= $post'Blog']'created']; ?> </span></h2>
            <img src="http://wallnen.com/wp-content/uploads/2013/06/Red-Panda-10-HD-Wallpaper.jpg" alt="" >

            <p class="description-articles"><?= $post'Blog']'content']; ?></p>
                <?= $this->Html->link('Lire la suite ?', $post'Blog']'url']); ?>
            <p class="author">
                <span>4 commentaires   -  </span>
                <span>Auteur   :  </span><?= $post'Author']'name']; ?>   -  
                <span>Catégorie : </span><?= $post'Category']'name']; ?>   
                <span>Mots clés :  </span><?= $post'Tag']'name']; ?>
            </p>
        <?php endforeach ?>

quelque lumière sur ce message d'erreur qui me rend fou je sens que la réponse est proche merci

xander
Auteur

re salut B-Art oui il utilise la liaison avec le model TagR que j'ai aussi effectué :
TagR.php :

<?php
class TagR extends AppModel{
    public $useTable = 'posts_tags';
    public $belongsTo = array('Blog', 'Tag');
}
?>

j'ai testé de voir se que me retournais $posts = $this->Blog->TagR->find('all'); et j'ai obtenue une database error.

Database Error
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'TagR.blog_id' in 'on clause'
SQL Query: SELECT `TagR`.`id`, `TagR`.`tag_id`, `TagR`.`post_id`, `Blog`.`id`, `Blog`.`title`, `Blog`.`content`, `Blog`.`created`, `Blog`.`slug`, `Blog`.`category_id`, `Blog`.`author_id`, `Tag`.`id`, `Tag`.`name` FROM `yacake`.`posts_tags` AS `TagR` LEFT JOIN `yacake`.`posts` AS `Blog` ON (`TagR`.`blog_id` = `Blog`.`id`) LEFT JOIN `yacake`.`tags` AS `Tag` ON (`TagR`.`tag_id` = `Tag`.`id`) WHERE 1 = 1
xander
Auteur

je récupère bien les toutes les valeur avec

public function index(){
        $posts = $this->Blog->find('all',array(
            'order' => array('created' => 'desc'), 'limit' => 4, 
            'contain' => array(
            'Tag.name', 'Category.name', 'Author.name')
        ));
        debug($posts);

et en utilisant <?= $post'Tag'][0]'name']; ?>
mais je ne comprend pas d'ou sort le [0] =s

xander
Auteur

je réédite, sa fonctione bien se que tu ma donné amethyste ^^ j'avais zapé que j'avais rehcangé tagname en name
la question est de savoir qu'es ce qu'étais mon erreur ?

Salut Xander,

En faite tes résultats sont retournés sous forme de tableau.
Foreach te permet de parcourir ce tableau et de retourner la valeur de l'élément.

Dans ton cas tu n'a qu'un seul élément Tag mais un Post peux avoir plusieurs Tag.
Si tu utilisait

<?= $post'Tag'][0]'name']; ?>

(en supposant que ça marche!) tu ne retournerais qu'une seule valeur de Tag et pas les autres...

Si tu ajoute un autre Tag et que tu fais un debug de nouveau tu devrais avoir un truc du genre:

'Tag' => array(
            (int) 0 => array(
                'name' => 'Bubble Gum'
                )
            (int) 1 => array(
                'name' => 'Tag 2'
                )
            etc...
            )

Sans le foreach, il ne sais pas quelle valeur retourner...

Bref, problème enfin résolu grâce à Amethyste! ;)

Bon dèv'

xander
Auteur

Merci beaucoup de votre aide ;) et vos explications