Bonjour à tous !

Tout d'abord, je tiens à vous remercier d'avance pour l'attention que vous porterez à ce poste.
Je viens de m'inscrire à ce forum parce que je fais face à un problème sur la version 3 de CakePHP.

Au sein de ma base de données, figurent les 3 tables suivantes :

  • <strong>posts</strong> : table dans laquelle je stocke tous les articles (ou posts).
  • <strong>posts_authors</strong> : Table dans laquelle je stocke les auteurs des articles.
  • <strong>users</strong> : Table dans laquelle je stocke tous les utilisateurs.

<strong>FONCTIONNEMENT DE MA PARTIE POSTS :</strong>

J'ai ajouté une fonctionnalité qui permet d'ajouter un ou plusieurs auteurs supplémentaires aux articles. Il suffit de sélectionner un auteur dans une liste déroulante, puis un input caché avec ses informations est ajouté dans le code en utilisant du JavaScript (son nom est également ajouté dans un table HTML de la page qui liste les auteurs de l'article en question). Lorsque j'enregistre, le ou leurs auteur(s) sont ajoutés dans une table associée : <strong>posts_authors</strong>. Lors de l'édition d'un article, il est possible de supprimer un auteur de l'article en cliquant sur une icône (Ajax).

<strong>MON PROBLEME :</strong>

<strong>Scénario numéro 1 :</strong> Lorsque j'ajoute un article en sélectionnant un auteur, CakePHP enregistre bien l'auteur dans la table associée posts_authors, mais n'enregistre pas la valeur des champs du modèle courant posts (par exemple title, slug, content).

<strong>Scénario numéro 2 :</strong> Si j'ajoute un article sans sélectionner d'auteur, les champs titre, slug et content du modèle courant sont bels et bien ajoutés en base.

<strong>Scénario numéro 3 :</strong> Lorsque j'édite un article existant, tout fonctionne correctement.

<strong>MON CODE :</strong>

<strong>PostsController.php (Contrôleur)</strong>

<pre><code>
public function add()
{
$post = $this->Posts->newEntity();
$authors = $this->Posts->Users->find('list')->order(['Users.name' => 'ASC']);
$categories = $this->Posts->Categories->find('list')->order(['Categories.name' => 'ASC']);

    if ($this->request->is('post'))
    {
        $post = $this->Posts->patchEntity($post, $this->request->data);

        if ($this->Posts->save($post)) {
            $this->Flash->success($this->record_saved);
            return $this->redirect(['action' => 'index']);
        }

        $this->Flash->error($this->unable_add_record);
    }
    else
    {
        $post->id = $this->Posts->getDraftId($this->Posts, ['user_id' => $this->Auth->user('id')]);
     }

    $this->set(compact(
        ['post', $post],
        ['authors', $authors],
        ['categories', $categories]
    ));

    $this->render('edit');
}
 </code></pre>

<strong>PostsTable.php (Modèle)</strong>

<pre><code>class PostsTable extends Table
{
public function initialize(array $config)
{
$this->addBehavior('Timestamp');
$this->addBehavior('Romano83/Cakephp3Draft.Draft');

    $this->addBehavior(
        'Media.Media', [
            'path' => 'img/upload/%y/%m/%f',
            'extensions' => ['jpg', 'png'],
            'limit' => 0,
            'max_width' => 0,
            'max_height' => 0,
            'size' => 0
        ]
    );

    $this->hasMany('Users', ['foreignKey' => 'user_id']);
    $this->hasMany('Categories', ['foreignKey' => 'category_id']);

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

}</code></pre>

<strong>PostsAuthorsTable.php (Modèle)</strong>

<pre><code> class PostsAuthorsTable extends Table
{
public function initialize(array $config)
{
$this->addBehavior('Timestamp');

        $this->belongsTo('Users', [
            'className' => 'Users',
            'foreignKey'    => 'user_id',
            'joinType' => 'INNER'
        ]);
    }
}</code></pre>

Dans tous les cas, si je fais un debug de <strong>$this->request->data</strong>, j'obtiens pourtant tous mes champs...

<pre><code> /src/Controller/Backoffice/PostsController.php (line 55)

[
    'name' => 'title example',
    'slug' => 'slug-example',
    'content' => '<p>content example</p> ',
    'publication' => '2015-11-23',
    'publication_time' => '09:08:23',
    'authors' => '',
    'Posts' => [
        'posts_authors' => [
            (int) 3 => [
                'user_id' => '32'
            ]
        ],
        'posts_categories' => [
            (int) 4 => [
                'category_id' => '4'
            ]
        ]
    ],
    'categories' => '',
    'online' => '1'
]</code></pre>

Merci d'avance pour votre aide ! :)

7 réponses


Bonjour.
Dis moi, tu n'aurais pas un problème au niveau de tes tables ?
As-tu le référant de l'article dans la table PostsAuthors en plus de celui de l'utilisateur ?
Montres nous un peu la composition de tes tables (concernant les champs bien sûr).
Ensuite, tu utilises mal compact.
Ce n'est pas :

$this->set(compact(
            ['post', $post],
            ['authors', $authors],
            ['categories', $categories]
        ));

Mais :

$this->set(compact('post', 'authors', 'categories'));

Sinon, autant que tu ne l'utilises pas.

elmo
Auteur

Merci pour ta réponse. Pour compact, je l'ai justement modifié plus tôt aujourd'hui.

Sinon, j'ai bien le référant à l'article dans ma table PostsAuthors, ainsi que le référant à l'utilisateur.

Voici la composition des 3 tables concernées :

  • posts : id, name, slug, content, publication, publication_time, created, modified, user_id, featured, online.
  • posts_authors : id, post_id, user_id.
  • users : id, name, slug, email, password, country_id, job_title, avatar, pgp_public_key, jabber_account, otr_fingerprint, twitter_username, biography, created, modified, user_id.

Hello,

Comme à dit Lartak, il y a déjà un problème avec les relations de tes tables.
La table PostsAuthorsTable devrais, en plus de la relation belongsTo avec les Users, avoir une autre relation belongsTo pour les Posts.
Le schema de la table Posts est bizarre. Pourquoi il y a un champ user_id, alors que tu veux un système multi-auteurs ?
Et pourquoi il y a posts_categories et que dans ta table posts il y a rien concernant les catégories ?

elmo
Auteur

Je vais revoir ces relations tout de suite, et vous fait un retour après.

La table Posts a un champ user_id pour stocker l'id de l'utilisateur qui a créé l'article de base (user_id qui ne reçoit pas de valeur pour l'instant parce que je dois l'ajouter, mais je le ferai après). En fait, la personne qui créer l'article est systématiquement dans la liste des auteurs. Mais il est aussi possible (en ayant le rôle qui l'autorise) de retirer cet utilisateur de la liste des auteurs (à condition d'en ajouter au minimum un autre). Si cet utilisateur ne figure plus dans la liste des auteurs, nous savons toujours que c'est lui qui a créé l'article à la base.

Première chose qui n'est pas logique, que fais un champ user_id dans ta table users ?
Ensuite, je suppose que le champ user_id dans la table posts, fait référence à l'auteur principal et que les utilisateurs qui sont lié au post dans la table posts_authors, sont en fait les contributeurs, sinon, je ne vois aucun intérêt à mettre un champ user_id dans la table posts.
Par contre, étant donné qu'un utilisateur peut avoir plusieurs posts et qu'un post peut appartenir à plusieurs utilisateurs, ne vaudrait-il pas mieux faire une relation belongsToMany entre les posts et les utilisateurs ?

Ah d'accord.
Dans ce cas il faut un truc comme ça :

class PostsTable extends Table
{
    public function initialize(array $config)
    {
         //...

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

        $this->belongsTo('Category', [
            'className' => 'Categories',
            'foreignKey' => 'category_id'
        ]);

        $this->belongsToMany('Authors', [
            'className' => 'PostsAuthors',
            'foreignKey' => 'user_id'
        ]);
    }
}

Et tu devrais avoir un résultat similaire à ceci si tu sélectionne le post 1 par exemple :

[
        'id' => (int) 1,
        'name' => 'title example',
        'slug' => 'slug-example',
        'user_id' => (int) 1,
        'content' => ' content example',
        'publication' => '2015-11-23',
        'publication_time' => '09:08:23',
        //Tout les auteurs du post.
        'authors' => [
            (int) 0 => object(App\Model\Entity\User) {
                'id' => (int) 1,
                'username' => 'test',
                //etc
            },
            (int) 1 => object(App\Model\Entity\User) {
                'id' => (int) 2,
                'username' => 'test2',
                //etc
            },
        ],
        //Le createur du post.
        'creator' => object(App\Model\Entity\User) {
            'id' => (int) 1,
            'username' => 'test',
            //etc
        },
        //La categorie.
        'category' =>  => object(App\Model\Entity\Category) {
            'id' => (int) 1,
            'name' => 'Awesome Category',
            //etc
        },
        'online' => '1'
    ]
elmo
Auteur

Désolé de répondre 21 heures après la dernière réponse, j'avais quelques petites urgences à régler.

@Xeta, j'ai essayé ce que tu m'as conseillé. Lorsque je met un "belongsToMany" pour "Authors", j'obtiens une erreur parce que CakePHP ne trouve pas la bonne table. Cependant ça fonctionne avec le hasMany suivant:

$this->hasMany('Authors', ['className' => 'PostsAuthors']);

La ligne ci-dessus fonctionne et enregistre bien les le user_id et le post_id dans une nouvelle entrée de la table posts_authors.

Mais toujours même problème au niveau des champs du modèle courant. Ils ne sont pas stockés en base lorsque je sélectionne un auteur (mais apparaissent bien dans le debug du $this->request->data).