IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Symfony PHP Discussion :

save fait une boucle infinie.


Sujet :

Symfony PHP

  1. #1
    Membre du Club
    Homme Profil pro
    Webmaster
    Inscrit en
    Août 2006
    Messages
    55
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Webmaster
    Secteur : Santé

    Informations forums :
    Inscription : Août 2006
    Messages : 55
    Points : 46
    Points
    46
    Par défaut save fait une boucle infinie.
    Bonjour,

    Dans le cadre d'un projet symfony avec doctrine, j'utilise sfDoctrineGuardUser et définis donc mes utilisateurs sur 2 tables jointes : GessehEtudiant et sfGuardUser.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    GessehEtudiant:
    actAs:
    Timestampable:
    created: { disabled: true }
    updated: { format: Y-m-d }
    columns:
    promo_id: { type: integer, notnull: true }
    classement: { type: integer, notnull: true }
    tel: { type: string(14), notnull: false }
    naissance: { type: date, notnull: false }
    anonyme: { type: boolean, default: false }
    utilisateur: { type: integer, notnull: true }
    relations:
    GessehPromo: { onDelete: CASCADE, local: promo_id, foreign: id }
    sfGuardUser: { onDelete: CASCADE, local: utilisateur, type: one, foreign: id }
    (le schéma de sfGuardUser est celui du plugin sans le moindre changement).

    Dans le backend, j'utilises l'admin generator :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    generator:
    class: sfDoctrineGenerator
    param:
    model_class: GessehEtudiant
    theme: admin
    non_verbose_templates: true
    with_show: false
    singular: ~
    plural: ~
    route_prefix: gesseh_etudiant
    with_doctrine_route: true
    actions_base_class: sfActions
     
    config:
    actions: ~
    fields:
    utilisateur: { label: Utilisateur, help: Utilisateur correspondant }
    promo_id: { label: Promotion }
    sfGuardUser: { label: Étudiant, help: Informations du compte utilisateur correspondant }
    gesseh_promo: { label: Promotion }
    tel: { label: Téléphone }
    naissance: { label: Date de naissance }
    list:
    title: Liste des étudiants
    display: [=sfGuardUser, gesseh_promo, tel, naissance]
    sort: [promo_id, asc]
    max_per_page: 50
    actions:
    _new: { label: Ajouter }
    autoUpdatePromo: { label: Passage à la promo supérieure }
    deleteAncien: { label: Maintenance (hors promo) }
    # importNew: { label: Importer }
    batch_actions: {}
    # horsPromo: { label: Sortir des promos }
    object_actions:
    _edit: { label: Modifier }
    table_method: retrieveEtudiant
    filter:
    display: [promo_id]
    form:
    class: GessehEtudiantForm
    display: [promo_id, sfGuardUser, tel, naissance, classement]
    fields:
    promo_id: { help: Hors Promo désactive automatiquement le compte utilisateur }
    classement: { label: Classement (choix), help: Ordre de classement pour les choix dans la promo }
    edit:
    title: Modifier %%sfGuardUser%%
    actions:
    _delete: { label: Supprimer }
    _list: { label: Retour à la liste }
    _save: { label: Enregistrer }
    new:
    title: Nouvel étudiant
    actions:
    _list: { label: Retour à la liste }
    _save: { label: Enregistrer }
    _save_and_add: { label: Ajouter un autre }
    et j'ai un peu modifié le save de sfGuardUser :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    class sfGuardUser extends PluginsfGuardUser
    {
    /* Enregistrement personnalisé d'un utilisateur */
    public function save (Doctrine_Connection $conn = null)
    {
    /* Paramètres prédéfinis pour l'enregistrement d'un étudiant */
    if ($this->getId() != null) {
    if ($etudiant = Doctrine::getTable('GessehEtudiant')->findOneByUtilisateur($this->getId())) {
    if ($etudiant->getPromoId() == Doctrine::getTable('GessehPromo')->findOneByActive(false)->getId()) {
    $this->setIsActive(false);
    } else {
    $this->setIsActive(true);
    }
    if (!$this->hasGroup('etudiant')) {
    $this->addGroupByName('etudiant');
    }
    }
    }
     
    if ($this->getPassword() == null) {
    $this->setPassword($this->generatePassword(8));
    }
     
    return parent::save($conn);
    }
     
    /* Auto-génération d'un mot de passe */
    private function generatePassword ($length)
    {
    $characters = array ('a','z','e','r','t','y','u','p','q','s','d','f','g','h','j','k','m','w','x','c','v','b','n','2','3','4','5','6','7','8','9','A','Z','E','R','T','Y','U','P','S','D','F','G','H','J','K','L','M','W','X','C','V','B','N');
     
    $password = '';
     
    for ($i = 0 ; $i < $length ; $i++) {
    $rand = array_rand($characters);
    $password .= $characters[$rand];
    }
     
    return $password;
    }
    }
    Or, si la procédure fonctionne parfaitement lorsqu'il s'agit d'éditer un utilisateur-étudiant, je me retrouve avec un "Fatal error: Maximum execution time of 30 seconds exceeded in ..." lors de la création d'un nouvel utilisateur-étudiant.


    En creusant les logs, je me suis rendu compte que c'était la fonction save qui bouclait à l'infini.


    Je ne comprends pas pourquoi d'autant que je suis persuadé d'avoir réussi à créer des utilisateurs il y a 10 jours au moment où j'ai procédé à la modification du save (pas re-vérifié depuis, je m'en suis rendu compte lors du test en "prod" juste avant de lancer l'appli réellement en production).

  2. #2
    Membre averti
    Inscrit en
    Août 2007
    Messages
    360
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 360
    Points : 396
    Points
    396
    Par défaut
    Bonjour,

    Y a une condition qui me fait mal aux yeux :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    $etudiant->getPromoId() == Doctrine::getTable('GessehPromo')->findOneByActive(false)->getId()
    Effectivement ce code marchera pour la création de nouveaux utilisateurs, mais jamais pour la modification...

    Je te laisse regarder ce que te renvoie :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Doctrine::getTable('GessehPromo')->findOneByActive(false)
    Parce que je pense que si tu as plus d'une "GessehPromo" dont le champ "active" est à false, tu n'auras jamais le résultat que tu veux...

    Pour le reste, on verra plus tard...

    Cordialement,

    Mathieu

  3. #3
    Membre du Club
    Homme Profil pro
    Webmaster
    Inscrit en
    Août 2006
    Messages
    55
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Webmaster
    Secteur : Santé

    Informations forums :
    Inscription : Août 2006
    Messages : 55
    Points : 46
    Points
    46
    Par défaut
    Je suis conscient que ce bout de code manque d'élégance mais il fait son travail (que ce soit dans l'édition ou dans la création) dans la mesure où, comme tu le précises bien, il n'y a bien qu'une seule promo inactive (davantage serait superflu) créée par défaut, l'administrateur ne pouvant ajouter que des promos actives.

    Par contre ça ne m'explique pas pourquoi le "return parent::save($conn)" boucle à l'infini sur une création et pas sur une édition : j'ai dû rater un truc.

    Edit: Quoique, à la lumière de ta remarque, j'ai fait quelques tests supplémentaires et il semble en effet que ce problème de boucle infini n'apparaisse que lorsqu'on ajoute un étudiant dans cette seule promo inactive (ce qui n'arrive jamais en théorie en utilisation quotidienne et qui explique pourquoi je n'avais pas noté ce bug auparavant : cas limite jusqu'alors non testé). Je vais creuser de ce côté, bien que la logique de cette boucle ne m'apparaisse pas évidente, pour le moment.

  4. #4
    Membre averti
    Inscrit en
    Août 2007
    Messages
    360
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 360
    Points : 396
    Points
    396
    Par défaut
    Bonjour,

    Tout d'abord, je n'aurais pas réécrit cette méthode, pour ne pas interférer avec le comprtement de base du plugin, qui je te le rappelle, garanti la sécurité de ton application...

    Tu aurais du avoir recours à une méthode save() ou doSave() d'un formulaire que tu aurais hérité du formulaire de création d'utilisateurs du plugin !!!

    Ceci dit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    31
    32
    33
    34
    35
    36
    37
    38
     
     
    public function save (Doctrine_Connection $conn = null)
      {
         // Je me souviens plus si le sfGuardUser dispose d'une PK 'id'
         if (strlen(trim($this->get('id'))) !== 0) {
     
           // Pourquoi il n'y a pas de PK sur cette table ??
           $etudiant = GessehEtudiant::getInstance()->findOneByUtilisateur($this->get('id'));
     
           if ($etudiant instanceof GessehEtudiant) 
          {
             // Tu sais déjà ce que j'en pense...
             $promoid = Doctrine::getTable('GessehPromo')->findOneByActive(false)->get('id');
     
            $this->setIsActive(true);
     
            if ($etudiant->get('promo_id') === $promoid) 
            {
              $this->setIsActive(false);
            } 
     
            if (! $this->hasGroup('etudiant')) 
            {
               // TU créele groupe, mais tu ne l'affecte pas à l'utilisateur...
               $this->addGroupByName('etudiant');
            }
          }
        }
     
        if (strlen(trim($this->get('password'))) === 0) 
        {
           $this->setPassword($this->generatePassword(8));
        }
     
        // As-tu été regardé dans la classe parente cette méthode ??
        return parent::save($conn);
      }
    Voila dans le détail ce que j'en pense...

    Cordialement,

    Mathieu

  5. #5
    Expert éminent
    Avatar de Michel Rotta
    Homme Profil pro
    DPO
    Inscrit en
    Septembre 2005
    Messages
    4 954
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : DPO
    Secteur : Distribution

    Informations forums :
    Inscription : Septembre 2005
    Messages : 4 954
    Points : 8 486
    Points
    8 486
    Par défaut
    Or, si la procédure fonctionne parfaitement lorsqu'il s'agit d'éditer un utilisateur-étudiant, je me retrouve avec un "Fatal error: Maximum execution time of 30 seconds exceeded in ..." lors de la création d'un nouvel utilisateur-étudiant.
    L'Id n'existe pas pour un objet non sauvegadé. Dans le cycle de vie, l'Id utilisateur n'est récupérer qu'après le cycle de la sauvegarde. Donc vouloir te base sur la valeur de cet Id avant l'action de sauvegarde semble provoquer cette action de sauvegarde qui va essayer de trouver l'Id utilisateur et donc générer une action de sauvegarde qui va essayer de trouver l'Id... et tu es mort !

    Il faut sortir cette récupération de la boucle save(). Ou tester si l'utilisateur est isNew().

    Et effectivement, il ne faut pas, sauf exception exceptionnellement exceptionnel toucher le code d'un plugin et à fortiori celui de sfGuard plus que tout autre.
    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 !

Discussions similaires

  1. Réponses: 18
    Dernier message: 26/04/2006, 11h39
  2. Une boucle infinie crontab
    Par tsing dans le forum Administration système
    Réponses: 10
    Dernier message: 10/04/2006, 10h28
  3. Select qui fais une boucle infinie
    Par MaitrePylos dans le forum PostgreSQL
    Réponses: 3
    Dernier message: 28/03/2006, 17h29
  4. Réponses: 10
    Dernier message: 24/12/2005, 15h35
  5. [FTP] comment corriger une boucle infinie ?
    Par sofybj dans le forum Langage
    Réponses: 8
    Dernier message: 08/11/2005, 14h49

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo