2010-01-11 7 views
5

J'ai une table Projects et une table Users qui sont liées par une relation HABTM. Dans la page "Ajouter" du nouveau projet, j'ai une section à cocher multiple pour sélectionner les utilisateurs pour le nouveau projet. Je veux avoir au moins un utilisateur pour le projet. Quelle est la meilleure façon d'aborder cela dans CakePHP?Validation de formulaire HABTM dans CakePHP

Répondre

19

Essayez ceci:

// app/models/project.php 
/** 
* An additional validation check to ensure at least one User is 
* selected. Spoofs Cake into thinking that there are validation 
* errors on the Project model by invalidating a non-existent field 
* on the Project model, then also invalidates the habtm field as 
* well, so when the form is re-displayed, the error is displayed 
* on the User field. 
**/ 
function beforeValidate() { 
    if (!isset($this->data['User']['User']) 
    || empty($this->data['User']['User'])) { 
    $this->invalidate('non_existent_field'); // fake validation error on Project 
    $this->User->invalidate('User', 'Please select at least one user'); 
    } 
    return true; 
} 
+0

Parfait! Merci Neil. – Sabourinov

+0

Cela fonctionne pour valider, mais lorsque la page se recharge, j'ai perdu certaines données, et obtenir des erreurs en raison de données manquantes. Des pensées? – Dave

2

Le blog de teknoid propose une solution assez complète à votre problème ici. La façon la plus Cakey de le faire serait d'ajouter une validation personnalisée à votre modèle, comme vous l'avez mentionné dans votre commentaire ci-dessus. Consultez http://teknoid.wordpress.com/2008/10/16/how-to-validate-habtm-data/

de l'article, où Tag HABTM Post (:: Utilisateurs du projet HABTM):

D'abord, nous validons le modèle Tag, par en utilisant les données du formulaire pour assurer que, à au moins un tag a été sélectionné. Si ainsi, nous sauvegardons la poste et les étiquettes pertinentes.

6

Je viens cherche moi-même à son problème sur un projet et est tombé sur une solution un peu plus élégante, aussi longtemps que vous êtes seulement faire face à une relation HABTM et vous devez vous assurer qu'au moins une case à cocher est sélectionnée.

donc par exemple vous modifiez un projet et vous voulez qu'il soit associé à au moins un utilisateur

Ajouter à ce beforeValidate()

// vérifier HABTM modèle et ajouter aux données

foreach($this->hasAndBelongsToMany as $k=>$v) { 
    if(isset($this->data[$k][$k])) 
    { 
    $this->data[$this->alias][$k] = $this->data[$k][$k]; 
    } 
    } 

Dans les règles de validation ajouter ce qui suit:

'User' => array(
    'rule' => array('multiple', array('min' => 1)), 
    'message' => 'Please select one or more users' 
) 
+1

Cela fonctionne bien pour la plupart, mais la div contenant l'erreur n'apparaît pas. Des idées? – Joseph

12

I er umbled sur le même problème, mais maintenant - 3 ans plus tard - avec CakePHP 2.3.

Pour être clair; Group a et appartient à User. J'ai eu une forme comme ceci:

// View/Groups/add.ctp 
echo $this->Form->input('name'); 
echo $this->Form->input('User'); 

Avec la règle de validation comme dans la réponse de user448164:

// Model/Group.php 
public $validate = array(
    'User' => array(
     'rule' => array('multiple', array('min' => 1)), 
     'message' => 'Please select one or more users' 
    ) 
); 

qui ne fonctionnait pas, après googler, je trouve cette question qui couldn » t être toujours la meilleure solution. Alors j'ai essayé plusieurs choses, et a découvert que cela fonctionne très bien:

// View/Groups/add.ctp 
echo $this->Form->input('name'); 
echo $this->Form->input('Group.User'); 

Way trop de solution facile, mais a dû creuser pour trouver cela fonctionne de cette façon.

J'espère que cela aidera quelqu'un un jour.

Mise à jour pour CakePHP 2.4.x (2.3.x peut-être aussi bien)

Quand j'ai écrit cette réponse, j'utilisais CakePHP 2.3.x. À l'époque, cela fonctionnait parfaitement pour la validation et l'enregistrement des données.Maintenant, en appliquant le même code sur un nouveau projet, en utilisant CakePHP 2.4.x, cela ne fonctionnait plus.

J'ai créé un test, en utilisant le code suivant:

$data = array(
    'User' => array(
     'Client' => array(8) 
    ), 
); 
$this->User->create(); 
$this->User->saveAll($data); 

Ma première pensée a été: Enregistrer tous les moyens de sauvegarde tous les modèles « root », ce qui fait réellement sens pour moi. Pour enregistrer plus profond que les "root", vous devrez ajouter l'option deep. Donc, je me suis retrouvé avec le code suivant:

$data = array(
    'User' => array(
     'Client' => array(8) 
    ), 
); 
$this->User->create(); 
$this->User->saveAll($data, array('deep' => true)); 

Fonctionne comme un charme! Codage heureux. :)

Mise à jour (2014/03/06)

Aux prises avec le même problème, dans ce cas avec hasMany au lieu de habtm. On dirait qu'il se comporte de la même manière. Mais je me suis retrouvé à la recherche de cette réponse et j'ai été confus.

Je tiens à préciser qu'il est essentiel d'utiliser Group.User au lieu de User dans votre entrée. Sinon, il n'utilisera pas la validation du modèle User.

+3

C'est la bonne réponse pour Cake 2.3 – Steven

+1

J'ai fait cette modification à mon code pour un problème similaire. La validation fonctionne correctement, mais la table de base de données liée via HABTM n'enregistre plus automatiquement les nouvelles données. Qu'est-ce qui manque? – Blazemonger

+0

@Blazemonger Quand je l'ai écrit, cela a fonctionné à la fois pour la validation et l'enregistrement. Mais d'une manière ou d'une autre, c'est cassé dans la dernière version de CakePHP. Faisons un peu plus de creusage ... --- Voir la réponse à la mise à jour pour plus d'informations! –

1

Si vous utilisez CakePHP 2.3.x, vous devrez peut-être ajouter ce code à votre modèle en plus du code qui GuidoH fourni, sinon vos données modèles HABTM ne peuvent pas sauver:

public function beforeSave($options = array()){ 
    foreach (array_keys($this->hasAndBelongsToMany) as $model){ 
    if(isset($this->data[$this->name][$model])){ 
     $this->data[$model][$model] = $this->data[$this->name][$model]; 
     unset($this->data[$this->name][$model]); 
    } 
    } 
    return true; 
} 
0

D'après mon commentaire sur la réponse de Guido ci-dessus, j'utilise exactement la réponse de Guido, mais je modifie les données avec le rappel beforeSave avant de sauvegarder dans la base de données.

J'ai cette question sur le gâteau 2.4.5+

public function beforeSave($options = array()) { 
    $temp = $this->data['Group']['User']; 
    unset($this->data['Group']['User']); 
    $this->data['User']['User'] = $temp; 

    return true; 
} 
2

2016 mise à jour pour CakePHP 2.7

réponse complète ici: HABTM form validation with CakePHP 2.x


TL; DR;

AppModel.php

public function beforeValidate($options = array()){ 
    foreach (array_keys($this->hasAndBelongsToMany) as $model){ 
    if(isset($this->data[$model][$model])) 
     $this->data[$this->name][$model] = $this->data[$model][$model]; 
    } 
    return true; 
} 

public function afterValidate($options = array()){ 
    foreach (array_keys($this->hasAndBelongsToMany) as $model){ 
    unset($this->data[$this->name][$model]); 
    if(isset($this->validationErrors[$model])) 
     $this->$model->validationErrors[$model] = $this->validationErrors[$model]; 
    } 
    return true; 
} 

Dans le modèle principal de votre HABTM:

public $validate = array(
    'Tag' => array(
     'rule' => array('multiple', array('min' => 1)), 
     'required' => true, 
     'message' => 'Please select at least one Tag for this Post.' 
     ) 
    );