Bonjour à tous,

Je suis nouveau sur cakephp et je rencontre un problème avec mon application. J'affiche un tableau représentant un programme sportif qui sert également de formulaire pour modifier le programme (exercices, séries, poids, etc.).

J'ai une table programmes identifiant le nom du programme et le propriétaire du programme, et une table detailsprogrammes pour le contenu. J'ai fais une association hasMany.
Maintenant, j'aimerais mettre à jour les données modifiées. En suivant la doc j'ai fait ceci, mais j'ai beau me creuser la tête je ne trouve pas la solution pour faire fonctionner le save() :

--- ProgrammesController.php ---

    //Envoi à la vue du programme
                    $programmeAModifier = $this->Programmes->find('all')->matching(
                        'Detailsprogrammes', function ($q) use ($programme) {
                            return $q->where(['Detailsprogrammes.programme_id' => $programme]);
                        }
                    );

                    $this->set(compact('programmeAModifier'));

                    //Réception du formulaire de modification
                    $programmeAModifier = $this->Programmes->newEntity();

                    if($this->request->is('put')) {
                        $programmeAModifier = $this->Programmes->patchEntity($programmeAModifier, $this->request->data, [
                            'associated' => [
                                'Detailsprogrammes'
                            ]
                        ]);

                        if($this->Programmes->save($programmeAModifier)) {
                            debug('sauvegarde reussie');
                        }

--- Edit.ctp ---

    <?php
    if(isset($programmeAModifier)) {
    echo $this->Form->create($programmeAModifier);
    ?>
    <table>

        <tr>
            <th></th>
            <th>Séries</th>
            <th>Répétitions</th>
            <th>Charge</th>
            <th>Repos</th>
        </tr>
        <?php

        foreach ($programmeAModifier as $monProgramme):     
            $champSeries = "detailsprogrammes." .$monProgramme['_matchingData']['Detailsprogrammes']['id']. ".series";
            $champRepet = "detailsprogrammes." .$monProgramme['_matchingData']['Detailsprogrammes']['id']. ".repetitions";
            $champPoids = "detailsprogrammes." .$monProgramme['_matchingData']['Detailsprogrammes']['id']. ".poids";
            $champRepos = "detailsprogrammes." .$monProgramme['_matchingData']['Detailsprogrammes']['id']. ".repos";
         ?>
        <tr>
            <td>

                 <?= h($monProgramme['_matchingData']['Detailsprogrammes']['exercice']) ?>

                <?= $this->Html->link('Supprimer', [
                        'controller' => 'Detailsprogrammes',
                        'action' => 'delete/'. $monProgramme->id .'/'. $monProgramme['_matchingData']['Detailsprogrammes']['exercice']
                    ]) ?>
            </td>
        </tr>
        <tr>
            <td></td>
            <td>
                <input type='text' name='<?= $champSeries ?>' value='<?= h($monProgramme['_matchingData']['Detailsprogrammes']['series']) ?>' />
            </td>
            <td>
                <input type='text' name='<?= $champRepet ?>' value='<?= h($monProgramme['_matchingData']['Detailsprogrammes']['repetitions']) ?>' />
            </td>
            <td>
                <input type="text" name='<?= $champPoids ?>' value='<?= h($monProgramme['_matchingData']['Detailsprogrammes']['poids']) ?>' />
            </td>
            <td>
                <input type="text" name='<?= $champRepos ?>' value='<?= h($monProgramme['_matchingData']['Detailsprogrammes']['repos']) ?>' />
            </td>
        </tr>
        <caption><?= h($monProgramme->nom) ?></caption>
        <?php

        endforeach;

        ?>

    </table>

    <?php
    echo $this->Form->button(__("Modifier"));

    echo $this->Form->end();
    }
    ?>

Je n'ai pas utilisé le form helper pour les inputs car ça faisait planter lorsque je mettais la variable en nom du champ.
Je ne reçois pas d'erreur mais la sauvegarde ne se fait pas. Comme je n'ai pas tout compris de la doc, je me tourne vers vous. J'espère avoir été clair. Je vous remercie d'avance.

15 réponses


Dirt
Auteur
Réponse acceptée

Je te remercie quand même de ton aide. J'ai réussi à contourner le problème mais j'aurais préféré quelquechose de plus élégant :

                        $data = $this->request->data;
                        $detailsprogrammes = TableRegistry::get('Detailsprogrammes');

                        foreach ($data as $modification) {
                            foreach ($modification as $key) {
                                $programmeModifie = $detailsprogrammes->newEntity($key);
                                if($detailsprogrammes->save($programmeModifie)) {
                                    $this->Flash->success(__("Reussie"));
                                }
                            }
                        }

Montre nous un debug(); histoire de voir le _POST à ton controller.

debug($this->request->data);
Dirt
Auteur

Juste après réception dans le controller ça donne ça :

    [
    'detailsprogrammes_1_series' => '4',
    'detailsprogrammes_1_repetitions' => '20',
    'detailsprogrammes_1_poids' => '0',
    'detailsprogrammes_1_repos' => '60',
    'detailsprogrammes_2_series' => '5',
    'detailsprogrammes_2_repetitions' => '12',
    'detailsprogrammes_2_poids' => '40',
    'detailsprogrammes_2_repos' => '60'
    ]

Est ce que tes champs respecte les conventions ?

echo $this->Form->input('Modelname.0.fieldname');
echo $this->Form->input('Modelname.1.fieldname');
//Affichera
<input type="text" id="Modelname0Fieldname"  name="data[Modelname][0][fieldname]">
<input type="text" id="Modelname1Fieldname"  name="data[Modelname][1][fieldname]">

Ensuite tu fais un updateAll

Dirt
Auteur

J'avais fait quelquechose du genre, mais je ne sais pas pourquoi ma page charge dans le vide lorsque je fais :
<?= $this->Form->input('Detailsprogrammes.0.series') ?>

J'ai respecté les conventions de nommages des champs en utilisant des balises input du coup. Je ne sais pas trop comment utiliser updateAll, comment définir mes champs, j'ai donc remodelé mon controller comme ça :

//Réception du formulaire de modification
if($this->request->is('put')) {
    $data = $this->request->data;
    $programmes = TableRegistry::get('Programmes');
    $programmeAModifier = $programmes->newEntity($data, [
        'associated' => ['Detailsprogrammes']
    ]);
    debug($data);
    $programmes->save($programmeAModifier);
}

J'obtiens pour le debug :


[
    'data' => [
        'Detailsprogrammes' => [
            (int) 0 => [
                'series' => '5',
                'repetitions' => '20',
                'poids' => '0',
                'repos' => '60'
            ],
            (int) 1 => [
                'series' => '4',
                'repetitions' => '12',
                'poids' => '40',
                'repos' => '60'
            ]
        ]
    ]
]

Affichage du formulaire
Pour populer un formulaire, $request->data doit être charger avec des données à la sortie du controller .
$this->request->data = $programmeAModifier;

<?= $this->Form->create('Detailsprogramme', array('action' => "nomAction")) ?>
<? foreach ($programmeAModifier as $key => $monProgramme): ?>
<tr>
<?= $this->Html->tableCells(array(
    $this->Form->input('Detailsprogramme.{$key}.series'),
    $this->Form->input('Detailsprogramme.{$key}.repetitions'),
    $this->Form->input('Detailsprogramme.{$key}.poids'),
     $this->Form->input('Detailsprogramme.{$key}.repos')
));?>
</tr>
<? endforeach; ?>
<?= $this->Form->end() ?>

Envoie du formulaire
De plus à en regardant de prés le debug que tu présente est englobé par la clé 'data' .
CakePHP doit lire un nom de model, en mettant data il crois que c'est un modéle.
Ensuite pour respecter les conventions, le modéle Detailsprogrammes doit être sans 's'.

En clair ton request->data doit ressembler à ceci:

   'Detailsprogramme' => [
            (int) 0 => [
                'series' => '5',
                'repetitions' => '20',
                'poids' => '0',
                'repos' => '60'
            ],
            (int) 1 => [
                'series' => '4',
                'repetitions' => '12',
                'poids' => '40',
                'repos' => '60'
            ]
        ]
Dirt
Auteur

J'obtiens le même debug que toi, c'est déjà ça. Ensuite je fais comme dans la doc pour l'update mais j'ai du louper quelquechose. Je suis désolé pour le dérangement, je patauge pas mal.

                    //Réception du formulaire de modification
                    if($this->request->is('post')) {
                        $data = $this->request->data;
                        $programmes = TableRegistry::get('Programmes');

                        $programmeAModifier = $programmes->newEntity($data, [
                            'associated' => ['Detailsprogrammes']
                        ]);

                        debug($programmeAModifier);

                        if($programmes->save($programmeAModifier)) {
                            $this->Flash->success(__('Sauvegarde réussie'));
                        }
                    }

Nous aurions du commencer par là, tu es en cakePHP 2x ou 3x ?
T'a un message d'erreur ou il ne se passe rien ?

Dirt
Auteur

Ah ... cakephp 3. Non pas de message d'erreur il ne se passe juste rien.

Aprés toute ces modifications, ton request->data à la reception du formulaire donne quoi ?

Dirt
Auteur

J'obtiens ça :

[
    'Detailsprogramme' => [
        (int) 0 => [
            'series' => '8',
            'repetitions' => '1',
            'poids' => '5',
            'repos' => '60'
        ],
        (int) 1 => [
            'series' => '4',
            'repetitions' => '5',
            'poids' => '40',
            'repos' => '60'
        ]
    ]
]

il manque les id pour chaque rentré.
Un champ input avec l'id de l'enregistrement de type hidden fera l'affaire.

Dirt
Auteur

En effet, j'arrive à rentrer dans ma boucle de sauvegarde, j'ai même le message "Sauvegarde réussie".

    if($programmes->save($programmeAModifier)) {
              $this->Flash->success(__('Sauvegarde réussie'));
    }

Mais les enregistrements ne sont pas mis à jour. Mon request->data :

[
    'id' => '2',
    'Detailsprogramme' => [
        (int) 0 => [
            'id' => '1',
            'series' => '8',
            'repetitions' => '20',
            'poids' => '0',
            'repos' => '60'
        ],
        (int) 1 => [
            'id' => '2',
            'series' => '4',
            'repetitions' => '12',
            'poids' => '40',
            'repos' => '60'
        ]
    ]
]

Le premier id est l'id du programme, les autres de detailsprogramme. C'est ça ? Ne faut il pas utiliser newEntities ?

Par contre pour les question 3.x je sais pas t'aider, moi je dévloppe encore en 2.x
Il ne devrait pas y'avoir de 'id'=>'2' là, l'id de chaque enregistrement concerné doit être comme indiquer à 'id' => '2'.

Le $request->data est sensible à la structure du tableau et à la case(min/maj) des clés. Une seul faute et rien ne sera enregistrer dans la table.