Précédent   Forum des professionnels en informatique > PHP > Bibliothèques et frameworks > symfony
symfony Forum d'entraide sur le framework PHP symfony. Avant de poster : cours symfony et FAQ symfony
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 06/01/2011, 19h21   #1
Nouveau Membre du Club
 
Homme
Étudiant
Inscription : août 2006
Messages : 49
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations professionnelles :
Activité : Étudiant
Secteur : Santé

Informations forums :
Inscription : août 2006
Messages : 49
Points : 25
Points : 25
Par défaut Problème de requète entre symfony et doctrine lors du save d'un formulaire embarqué

Bonjour,

J'ai un formulaire qui rassemble une classe doctrine et ses relations (one-to-many). Au moment du save(), je me retrouve avec un :
Code :
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1' for key 'PRIMARY'
qui me renvoit sur (niveau logs) :
Code :
execute : INSERT INTO copisim_etudiant (anonyme, annee, id, fac, email_tmp, updated_at) VALUES (?, ?, ?, ?, ?, ?) - (0, TCEM1, 1, 13, , 2011-01-06)
L'erreur est normale, vu qu'il veut insérer l'utilisateur courant qui édite son formulaire. La question, à laquelle je n'arrive pas à répondre, c'est : pourquoi Symfony envoie-t-il un INSERT au lieu d'un UPDATE à Doctrine ?

J'ai vérifié avec WebDevelopper, les champs du formulaire sont correctement présents et remplis (notamment l'Id de l'utilisateur). J'ai dû rater un truc mais là je sèche depuis un moment...

Le schéma :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
CopisimEtudiant:
  actAs:
    Timestampable: 
      created: { disabled: true }
      updated: { format: Y-m-d }
  columns:
    nom: { type: string(50), notnull: true }
    prenom: { type: string(50), notnull: true }
    fac: { type: integer, notnull: true }
    naissance: { type: date }
    email: { type: string(100), notnull: false }
    email_tmp: { type: string(100), notnull: false }
    anonyme: { type: boolean, notnull: true, default: 0 }
    annee: { type: enum, values: ['DCEM4', 'DCEM4 doublant', 'TCEM1'], default: 'DCEM4' }
    classement: { type: integer, notnull: true }
  relations:
    CopisimFac: { local: fac, foreign: id }
 
CopisimChoix:
  actAs:
    Timestampable: ~
  columns:
    etudiant: { type: integer, notnull: true }
    poste: { type: integer, notnull: true }
    ordre: { type: integer(2), notnull: true }
  relations:
    CopisimEtudiant: { local: etudiant, foreign: classement }
    CopisimPoste: { local: poste, foreign: id }
 
[...]
La classe de formulaire (pas la plus clean du monde mais devrait quand même marcher) :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class CopisimEtudiantChoixForm extends BaseCopisimEtudiantForm
{
  public function configure()
  {
    unset($this['nom'], $this['prenom'], $this['naissance'], $this['email'], $this['adresse'], $this['classement'], $this['created_at'], $this['updated_at']);
 
		$this->widgetSchema['fac'] = new sfWidgetFormInputHidden();
		$this->widgetSchema['anonyme'] = new sfWidgetFormInputHidden();
		$this->widgetSchema['email_tmp'] = new sfWidgetFormInputHidden();
		$this->widgetSchema['annee'] = new sfWidgetFormInputHidden();
 
		$this->embedRelation('CopisimChoix');
 
		$newChoix = new CopisimChoixForm();
		$newChoix->setDefault('etudiant', $this->object->id);
		$this->embedForm('ajouter', $newChoix);
  }
 
  protected function doBind(array $values)
  {
  	if ('' === trim($values['ajouter']['poste']) && '' === trim($values['ajouter']['ordre']))
  	{
  		unset($values['ajouter'], $this['ajouter']);
  	}
 
  	parent::doBind($values);
  }
}
La classe actions :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[...]
 
public function executeEditchoix(sfWebRequest $request)
  {
    $this->user = $this->getUser()->getUsername();
    $this->forward404Unless($copisim_etudiant = Doctrine::getTable('CopisimEtudiant')->find(array('id' => $this->getUser()->getUsername())), sprintf('Utilisateur inconnu : (%s).', $this->getUser()->getUsername()));
    $this->form = new CopisimEtudiantChoixForm($copisim_etudiant);
  }
 
  public function executeUpdatechoix(sfWebRequest $request)
  {
    $this->user = $this->getUser()->getUsername();
    $this->forward404Unless($request->isMethod(sfRequest::POST));
    $this->form = new CopisimEtudiantChoixForm();
 
    $this->form->bind($request->getParameter($this->form->getName()), $request->getFiles($this->form->getName()));
    if($this->form->isValid())
    {
      $this->form->save();
      $this->redirect('etudiant/editchoix');
    }
    $this->setTemplate('editchoix');
  }
 
[...]
Je n'ai pas mis le reste, vu que ça n'apporte pas grand chose au problème... Concrètement, c'est ma classe de formulaire que je serais le plus enclin à mettre en doute, mais en pratique je ne comprends pas pour autant l'erreur entre INSERT et UPDATE. Si quelqu'un a une idée, merci d'avance !
CaraG33k est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 06/01/2011, 20h53   #2
Membre confirmé
 
Avatar de Vivian Pennel
 
Vivian Pennel
Developpeur Symfony | JSF/Seam
Inscription : août 2004
Messages : 173
Détails du profil
Informations personnelles :
Nom : Vivian Pennel
Âge : 23
Localisation : France, Hérault (Languedoc Roussillon)

Informations professionnelles :
Activité : Developpeur Symfony | JSF/Seam
Secteur : High Tech - Produits et services télécom et Internet

Informations forums :
Inscription : août 2004
Messages : 173
Points : 246
Points : 246
Essai d'utiliser $this->useFields(array()); au lieu des unset();

tu met dedans la liste des champs utilisés au lieu de lister ceux que tu ne veux pas.
Ca sent la clé pas unset la où il faut.

Cette méthode évite généralement les problèmes de clé étrangère. Il faut la mettre dans la classe form parent et celle de l'embedForm également.
__________________
Mon blog : http://blog.developpez.com/vivian-pennel/
Vivian Pennel est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 07/01/2011, 14h16   #3
Modérateur
 
Avatar de Michel Rotta
 
Homme Michel Rotta
Responsable d'exploitation informatique
Inscription : septembre 2005
Messages : 4 913
Détails du profil
Informations personnelles :
Nom : Homme Michel Rotta
Âge : 49
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Responsable d'exploitation informatique
Secteur : Distribution

Informations forums :
Inscription : septembre 2005
Messages : 4 913
Points : 7 505
Points : 7 505
Je vois que tu as un embed normal et un nouveau form qui est aussi en embed.

Personnellement, je ne procèderais pas ainsi. Je pense que c'est là l'origine du problème. Essaye de faire deux form dans ta page, le deuxième pour l'ajout et indépendant du premier au niveau html.
__________________
Si tu donnes un poisson à un homme, il mangera un jour. Si tu lui apprends à pêcher, il mangera toujours (Lao Tseu).
  • Pensez à valoriser les réponses pertinantes, cliquez sur le bouton vert +1 pour indiquer votre accord avec la solution proposée.
  • Pensez à utiliser la balise [code] pour afficher du code, elle est cachée sous le bouton [#] dans l'éditeur.
  • Une discussion est terminée ? Alors le bouton est votre ami !
Michel Rotta est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 07/01/2011, 14h55   #4
Nouveau Membre du Club
 
Homme
Étudiant
Inscription : août 2006
Messages : 49
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations professionnelles :
Activité : Étudiant
Secteur : Santé

Informations forums :
Inscription : août 2006
Messages : 49
Points : 25
Points : 25
Alors, j'ai testé avec $this->useFields(array()); en virant le unset, ça n'a rien changé.

J'ai également testé en introduisant une donnée en relation directement dans la base, et là j'ai eu message d'erreur au niveau de la validation qui disait que le champ inclu par embedRelation(); n'avait rien à faire dans le formulaire...

Chaque chose en son temps, et j'ai donc refait un test en virant le useFields(); et le unset();, après tout, c'est une édition, je ne devrais pas faire de bêtises. Là, apparaìt une chose intéressante : le champ CopisimEtudiant.classement apparaît comme un menu déroulant vide. Il faut savoir qu'il y a une relation One-to-one avec la table d'utilisateurs de sfDoctrineGuardPlugin... mais pour laquelle, je ne trouve pas de déclaration (c'est dans ces moment-là qu'on se dit qu'on a dû faire les choses salement : c'est un projet resté en veille faute de temps à y consacrer)... Ceci dit, ça n'explique pas pourquoi il est nul alors que la table mySQL ne l'est pas pour ce champ. Et par ailleurs, une autre classe de formulaire CopisimEtudiantForm fonctionne correctement sur la même table.

Pour ce qui est du embedRelation() associé à un embedForm() pour la création d'un nouvel enregistrement, c'est un point sur lequel j'avais trouvé quelques exemples sur le net, et ça ne semblait pas poser problème.

Edit : pour statuer là-dessus, j'ai commenté tour à tour, puis simultanément, les deux embed dans la classe de formulaire, avec toujours le même bug. Du coup, je me concentrerais plutôt sur les différence entre les classes CopisimEtudiantForm et CopisimEtudiantChoixForm...

CopisimEtudiantForm :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class CopisimEtudiantForm extends BaseCopisimEtudiantForm
{
  public function configure()
  {
    $this->embedForm('MdP', new copisimUserPasswordForm(sfContext::getInstance()->getUser()->getGuardUser()));
 
    unset($this['nom'], $this['prenom'], $this['fac'], $this['created_at'], $this['updated_at'], $this['classement']);
 
    $this->validatorSchema['email_tmp'] = new sfValidatorAnd(array(
      $this->validatorSchema['email_tmp'],
      new sfValidatorEmail(),
    ));
 
    $this->widgetSchema['email'] = new sfWidgetFormInputHidden();
    $this->widgetSchema->setLabel('email_tmp', 'Email');
  }
}
Et je n'en vois aucun qui justifie le changement de comportement de Symfony... Au niveau des actions, c'est le même appel en changeant le nom de la classe.
CaraG33k est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 07/01/2011, 16h35   #5
Nouveau Membre du Club
 
Homme
Étudiant
Inscription : août 2006
Messages : 49
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations professionnelles :
Activité : Étudiant
Secteur : Santé

Informations forums :
Inscription : août 2006
Messages : 49
Points : 25
Points : 25
Bon je suis honteux de vous avoir dérangés avec ça...

L'erreur était basique, l'erreur était logique : lors de la mise à jour de ma fonction Uptdatechoix($sfWebRequest), j'avais fait une erreur dans la requête Doctrine... Forcément, Symfony ne trouvait pas l'objet, forcément il voulait en insérer un nouveau... Bref.

Merci de vos réponses qui m'ont permis de me remettre sur les rails !

Encore quelques bugs (notamment le doSave) mais je devrais pouvoir m'en sortir. Encore merci !
CaraG33k est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 17h22.


 
 
 
 
Partenaires

Hébergement Web