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

ORM PHP Discussion :

Surcharger la méthode save() d'un objet


Sujet :

ORM PHP

  1. #1
    Membre émérite Avatar de Herode
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2005
    Messages
    825
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2005
    Messages : 825
    Par défaut Surcharger la méthode save() d'un objet
    Bonjour à tous,

    Je veux effectuer quelques actions (mise à jour de données secondaires) quand un objet est modifié. Naïvement, j'ai cherché à surcharger la méthode save() mais à mon grand désarroi, mes efforts sont vains.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
        public function save(Doctrine_Connection $conn = null) {
    	parent::save($conn);
    	// $this->refresh();
    	$this->processParentCategories();
     
        }
    Si j'appelle processParentCategories avant parent::save(), mon objet ($this) ne semble pas connaître les nouvelles informations à sauvegarder.
    Si je l'appelle après... non plus, qu'il y ait un refresh() ou pas.
    Du coup, processParentCategories() se comporte comme si l'objet n'avait pas été modifié.

    Je connais la méthode doUpdateObject() dans sfFormObject mais je ne veux pas passer par là : mon objet peut être modifié en dehors d'un formulaire, je dois donc intervenir dans save() pour être sûr de ne rien rater. N'importe quel framework orienté objet permet de type de surcharges basiques, je ne comprends pas pourquoi Symfony me bloque ici - et ce n'est pas la "documentation" de l'API qui me renseigne beaucoup...

    Snif.

  2. #2
    Membre éclairé
    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2003
    Messages
    307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Février 2003
    Messages : 307
    Par défaut
    il faudrait que détail un plus ton code de :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $this->processParentCategories();

  3. #3
    Membre émérite Avatar de Herode
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2005
    Messages
    825
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2005
    Messages : 825
    Par défaut
    Il n'y a rien de bien fascinant dans cette méthode. Des choses du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $count = $this->getParentCategories()->count()
    où ParentCategories est une collection associée à une relation 1-n du schéma.

    Le problème ici est que si j'ajoute une 'ParentCategory' en passant par un formulaire enchâssé (avec $form->embedRelation()), quand on arrive dans la méthode save(), $count vaut toujours 0 alors que je m'attends à ce qu'il vale 1.

    PS à l'attention des modérateurs : je me suis trompé de forum, pouvez-vous remonter ce post dans le forum symfony général siouplait ?

  4. #4
    Membre émérite Avatar de Herode
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2005
    Messages
    825
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2005
    Messages : 825
    Par défaut
    Ca y est, j'ai compris. Une partie du problème vient de ce que la méthode save() est appelée au milieu d'une transaction et que celle-ci n'a pas encore reçu son COMMIT. C'est pourquoi l'appel à refresh() est inopérant.

    En réalité, le problème de base ici est que Symfony confond deux couches : la couche métier (les objets métier indépendamment de ce qu'ils sont en base de données) et la couche ORM.

    J'en conclus qu'il est inutile de toucher à la méthode save(). Soit il en existe une autre pour faire le genre de travail que je veux faire (une méthode appelée automatiquement après le COMMIT et surchargeable), soit il va falloir bricoler ailleurs...

  5. #5
    Expert confirmé
    Avatar de Michel Rotta
    Homme Profil pro
    DPO
    Inscrit en
    Septembre 2005
    Messages
    4 954
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    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
    Par défaut
    Il y a deux méthodes pour attaquer la sauvegarde, save et doSave. Je savais qu'il y en avait une dans la transaction, mais mes souvenirs m'orientaient vers doSave... peut-être les deux ?

    Ma solution serait de transmettre le paramètre conn récupéré par save aux fonctions que tu utilises, pour qu'elle soient dans la transaction.

  6. #6
    Membre émérite Avatar de Herode
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2005
    Messages
    825
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2005
    Messages : 825
    Par défaut
    Mon souci est que doSave() est une méthode de sfFormObject. Or, ce que je voudrais surcharger, c'est le save() de l'objet lui-même car je peux très bien modifier et sauvegarder un objet en dehors d'un formulaire. Cela fait plus de 10 ans que je fais de la POO sur des grosses applis en C++ ou en Java et je n'ai jamais encore été bloqué comme ça.

    Passer le Doctrine_Connection ne m'arrange pas plus puisque le blocage vient de ce que je ne peux pas (ou que je ne sais pas...) obtenir des informations sur l'objet qui va être sauvegardé : par exemple, combien a t'il de ParentCategories.

    Et pour tout dire, aller mettre les mains dans le cambouis de l'objet UnitOfWork sous-jacent ne m'inspire pas du tout.

    J'ai provisoirement renoncé à faire ce que je voulais et je passe par le doSave() du formulaire avec plein de commentaires dans le code pour mettre en garde en cas d'utilisation directe de save() sans passer par les méthodes qui doivent l'encadrer mais ce n'est pas ce que j'appelle du codage propre.

    Je dois dire que ce genre de contraintes (il y en a quelques autres du même type sous Symfony) me gêne de plus en plus à tel point que je commence à me poser des questions sur l'utilisation de ce framework qui, pour le moment, me fait perdre beaucoup plus de temps qu'autre chose. Bon, ce n'est que mon deuxième projet (plus quelques essais persos chez moi), donc je ne désespère pas encore de trouver la clé pour utiliser Symfony et gagner vraiment en productivité. Mais crévindiou, toutes ces galères et le retard que je prends, ça me fait suer

  7. #7
    Expert confirmé
    Avatar de Michel Rotta
    Homme Profil pro
    DPO
    Inscrit en
    Septembre 2005
    Messages
    4 954
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    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
    Par défaut
    C'est lié aux premiers essais...

    Après, les prochains développement iront de plus en plus vite

    J'ai repris un code d'une vielle application où je fais aussi une intervention dans le save d'un objet.

    Il s'agit, à la création d'un nouveau user de rajouter des enregistrements, liés, dans plusieurs tables. Et le code passe sans problème, y compris la récupération du l'id du user après le save du parent.

    J'ai donc un peu de mal, avec le peu de code que tu donnes à comprendre d'où vient le problème.

    De plus, l'appel du save ce fait, sauf demande express du développeur, sans connexion définie. Donc hors transaction.

  8. #8
    Membre émérite Avatar de Herode
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2005
    Messages
    825
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2005
    Messages : 825
    Par défaut
    Citation Envoyé par Michel Rotta Voir le message
    J'ai repris un code d'une vielle application où je fais aussi une intervention dans le save d'un objet.

    Il s'agit, à la création d'un nouveau user de rajouter des enregistrements, liés, dans plusieurs tables. Et le code passe sans problème, y compris la récupération du l'id du user après le save du parent.
    Ca me rassure. Je préfère penser que le problème est dans mon code plutôt que dans le framework, ce sera plus facile à résoudre

    Dès que j'ai un peu de temps, je vais essayer de reproduire le problème en l'extrayant du projet histoire d'y voir plus clair.

  9. #9
    Membre éprouvé

    Homme Profil pro
    Software Engineer
    Inscrit en
    Août 2004
    Messages
    173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Software Engineer
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Août 2004
    Messages : 173
    Par défaut
    Au vu du besoin, je dirais qu'il ne faut pas travailler dans sfForm mais dans ton objet directement.

    dans ta classe tu définies la méthode
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
     
    public function postSave($event) {}
    et tu travailles là dedans

    Edit: attention cette méthode redéfinit une méthode abstraite de Doctrine_Record, et est invoquée après le processus de sauvegarde de l'objet

  10. #10
    Membre émérite Avatar de Herode
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2005
    Messages
    825
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2005
    Messages : 825
    Par défaut
    Ha, voila une méthode qui me plait.

    Malheureusement, ça ne marche toujours pas. Exemple : soit un produit associé à deux catégories, auquel j'en ajoute une troisième :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
        public function postSave($event) {
    	parent::postSave();
    	$this->refreshRelated('Categories');
    	sfContext::getInstance()->getLogger()->debug(__METHOD__." : ".$this->getCategories()->count());
     
    	$cats = ProductHasCategoryTable::getInstance()->createQuery()->where('product_id = ?', $this->getId())->execute();
    	sfContext::getInstance()->getLogger()->debug(__METHOD__." : ".$cats->count());
        }
    va renvoyer 3 sur les appels à count().
    Donc à ce niveau du code, la base de données n'est pas encore mise à jour avec les infos du formulaire embarqué. Les logs le confirment d'ailleurs, j'ai la race de l'INSERT juste après la trace du dernier debug du postSave().

    Il doit y avoir un loup planqué quelque part, mais où... ?

  11. #11
    Expert confirmé
    Avatar de Michel Rotta
    Homme Profil pro
    DPO
    Inscrit en
    Septembre 2005
    Messages
    4 954
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    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
    Par défaut
    Attention, les méthodes preSave() et postSave() ne sont pas des méthodes symfony mais des méthodes doctrine, héritée de Doctrine_Record.

    Je ne suis pas sur de ce que peux donner l'introduction d'objet symfony à ce niveau d'abstraction. Et je pense qu'il faut se référer à la documentation doctrine pour le maniement.

    Juste un petit warning.

  12. #12
    Membre éprouvé

    Homme Profil pro
    Software Engineer
    Inscrit en
    Août 2004
    Messages
    173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Software Engineer
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Août 2004
    Messages : 173
    Par défaut
    Citation Envoyé par Herode Voir le message
    Ha, voila une méthode qui me plait.

    Malheureusement, ça ne marche toujours pas. Exemple : soit un produit associé à deux catégories, auquel j'en ajoute une troisième :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
        public function postSave($event) {
    	parent::postSave();
    	$this->refreshRelated('Categories');
    	sfContext::getInstance()->getLogger()->debug(__METHOD__." : ".$this->getCategories()->count());
     
    	$cats = ProductHasCategoryTable::getInstance()->createQuery()->where('product_id = ?', $this->getId())->execute();
    	sfContext::getInstance()->getLogger()->debug(__METHOD__." : ".$cats->count());
        }
    va renvoyer 3 sur les appels à count().
    Donc à ce niveau du code, la base de données n'est pas encore mise à jour avec les infos du formulaire embarqué. Les logs le confirment d'ailleurs, j'ai la race de l'INSERT juste après la trace du dernier debug du postSave().

    Il doit y avoir un loup planqué quelque part, mais où... ?
    Pourquoi ne pas travailler au niveau de la classe catégorie, si les traitements ne concernent que celles-ci ?

Discussions similaires

  1. Réponses: 2
    Dernier message: 23/10/2012, 09h51
  2. [1.x] surcharger la méthode save() de la classe du modèle
    Par Mich972 dans le forum Symfony
    Réponses: 2
    Dernier message: 23/08/2010, 17h26
  3. Réponses: 4
    Dernier message: 13/08/2008, 22h16
  4. Comment surcharger la méthode OnClose d'un TFrame ?
    Par sdebrois dans le forum Composants VCL
    Réponses: 2
    Dernier message: 17/01/2005, 20h57
  5. Méthode Free d'un objet
    Par WebPac dans le forum Composants VCL
    Réponses: 3
    Dernier message: 12/10/2004, 15h28

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