Accueil > PHP > CSaveRelationsBehavior : un comportement Yii pour enregistrer les données relationnelles

CSaveRelationsBehavior : un comportement Yii pour enregistrer les données relationnelles

Yii Framework

CSaveRelationsBehavior, un comportement pour Yii Framework, vient d’être publié par votre serviteur.

L’objet de ce comportement est d’étendre les fonctionnalité des ActiveRecords afin de permettre l’enregistrement automatique des données relationnelles HasMany et ManyMany lorsque le modèle principal est créé ou modifié.

En effet, contrairement à d’autres framework comme CakePHP ou Symphony, cette fonctionnalité n’est pas incluse nativement dans Yii. Rien de bien problématique dans la mesure ou cette opération peut être écrite au besoin au niveau des modèles le nécessitant. Mais comme j’étais lassé de devoir reproduire ce genre de code fréquemment, l’écriture d’un comportement pour les ActiveRecord c’est assez naturellement imposé.

Amis développeurs Yii, vos commentaires sont les bienvenus :)

[Edit 17/05/2010 : Deux applications de démonstrations sont maintenant disponibles en téléchargement sur le dépôt de l'extension. Elles permettent de se faire une idée très précise de ce qui est réalisable avec cette extension qui est désormais également hébergée sur Google Code (documentation, dépôt SVN, rapport de bugs...).]

Configuration requise

  • Yii Framework 1.0.4 ou plus

Installation

  • Décompressez le fichier et copier-le dans protected/components de votre projet

Utilisation

  • Ajouter le code suivant au modèle dans lequel vous voulez utiliser le comportement :
    1
    2
    3
    4
    5
    
    public function behaviors(){
       return array('CSaveRelationsBehavior' =>
          array('class' => 'application.components.CSaveRelationsBehavior')
       );
    }
  • Dans votre contrôleur, appelez simplement :
    1
    2
    
    $model->setRelationRecords('relationName',$data);
    $model->save();
  • Pour les relations ManyMany, $data doit être fourni sous la forme d’un tableau valeurs de clés étrangères (ex. array(2,5,43)) ou un tableau de tableaux associatifs fournissant les valeurs de clés étrangères composites du modèle lié (ex. array(array('pk1'=>2,'pk2'=>'fr'),array('pk1'=>5,'pk2'=>'en')).
    Typiquement, vous retrouverez ces données à partir d’une série de cases à cocher listant les identifiants du modèle lié.
  • Pour les relations HasMany, $data doit être fourni sous la forme d’un tableau de tableaux associatifs donnant la valeur des attributs du modèles lié (ex. array(array(‘id’=>123, ‘name’=>’someValue’, ‘visible’=>true), array(‘id’=>456, ‘name’=>’someOtherValue’, ‘visible’=>false));
    Vous pouvez fournir ces données en utilisant la technique des données tabulaires à l’intérieur du formulaire du modèle principal (http://www.yiiframework.com/doc/guide/form.table)
  • Dans les deux cas, les clés étrangères relatives au modèle principal seront automatiquement remplies avec la ou les valeurs des clés primaires du modèle principal.
  • La plupart du temps, vous appellerez setRelationRecords de la façon suivante :
    1
    
    $model->setRelationRecords('relationName',is_array(@$_POST['ModelName']) ? $_POST['ModelName'] : array());
  • Par défaut, le comportement gérera la sauvegarde en mode transactionnel de telle sorte que si une erreur quelconque intervient pendant la sauvegarde des données de relations, l’intégrité relationnelle ne sera pas affectée. Par ailleurs, si une erreur se produit pendant la sauvegarde, la propriété hasError prendra la valeur true.

Fonctionnalité additionnelles

  • 1
    
    $model->addSaveRelation('relationName'[,'customErrorMessage'])

    Vous pouvez utiliser cette méthode afin de forcer la sauvegarde d’une relation.
    Vous pouvez également passer le message d’erreur de la relation comme deuxième paramètre (voir setSaveRelationMessage plus loin)

  • 1
    
    $model->removeSaveRelation('relationName')

    Fait simplement l’inverse

  • 1
    
    $model->setSaveRelationMessage('relationName','customErrorMessage')

    Défini le message à afficher dans le résumé d’erreurs du modèle principal

Téléchargement

Vous avez aimé cet article ? Partagez-le :
  1. 14/05/2010 à 21:15 | #1

    Ca m est deja arrive de devoir sauvegarder les donnees dans plusieurs tables mais dans le cas ou je veux definir une cle etrangere et la sauvegarder, je la recupere dabord avec la fonction getlastinsertid avant de faire save.
    Est ce pour eviter ce genre de manip que cette classe existe ,

  2. 15/05/2010 à 09:17 | #2

    @saegeek
    Oui, c’est partiellement le but. L’idée principale est de pouvoir se servir des attributs de relations définis dans un modèle Yii afin de pouvoir simplement les sauvegarder (en cas d’ajout, de modification ou de suppression) en même temps que modèle principal en 3 lignes de codes maximum. Donc, pas seulement dans le cas d’un enregistrement fraîchement créé (la méthode getlastinsertid à laquelle tu fais référence) mais également en cas de mise à jour.
    Cette classe permet également d’effectuer automatiquement les enregistrements en mode transactionnel afin de garantir l’intégrité des données.
    Enfin, elle permet d’enregistrer les données HasMany en mode tabulaire (création ou modification de plusieurs enregistrements relationnels à partir du formulaire contenant les données du modèle principal).

    Un exemple d’application fonctionnelle est en cours de création et je le publierai dès que possible (cela devrait éclaircir les choses sur les possibilités offertes par ce composant).

    Merci pour ton commentaire.

    PS. Si tu passes par les ActiveRecords pour faire tes enregistrements, sache que tu n’as pas besoin de passer par la méthode getlastinsertid afin de récupérer la valeur de la clé primaire. Tu peux directement récupérer la valeur des attributs du modèle ($model->id par exemple) après sauvegarde.

  3. 15/05/2010 à 18:47 | #3

    merci pour la technique $model->id ça marche impeccable.
    et puis pour la classe ça n’est pas encore très clair dans ma tête, j’attendrai ta mini application exemple.

  4. 15/05/2010 à 19:46 | #4

    Les applications de démonstration sont à présent disponibles en téléchargement sur le dépot de Yii Framework. Bons tests :)

  5. Co-k-ine
    18/07/2010 à 19:09 | #5

    Bonjour,

    Je viens de tomber par hasard sur votre blog ! J’étais justement en train de me prendre la tête avec yii pour ajouter des données sur plusieurs tables. J’ai du bidouiller avec les $_POST !

    J’éspère être capable d’arriver à utiliser votre extension.

    Merci énormément pour votre travail :)

  6. 19/07/2010 à 15:39 | #6

    @Co-k-ine
    Heureux d’apprendre que ce comportement puisse vous être utile.
    N’hésitez pas à me faire part de vos retours d’expériences sur son utilisation et vos souhaits éventuels d’évolution et d’améliorations.

    Merci pour vos encouragements.

  7. Co-k-ine
    19/07/2010 à 19:30 | #7

    Bonjour,

    Donc j’ai essayer de suivre vos tutoriel pour y ajouter votre extension, et lors de l’ajout des données yii me retournais un message d’erreur sur votre script ! J’ai donc abandonné à cause de mon cruel manque d’expérience dans les framework !

    Désoler de ne pas pouvoir vous aider plus que cela …

  8. 20/07/2010 à 08:16 | #8

    1 – Pouvez-vous me donner l’erreur remontée par Yii ? De très fréquentes erreurs se produisent si la définition des tables SQL sont insuffisantes (pas de clés primaires, par de clés étrangères définies pour les tables de relations many to many)
    2 – Je vous invite à télécharger les applications de démonstration qui constituent un bon point de départ pour comprendre le mode de fonctionnement du comportement.

  9. Co-k-ine
    30/07/2010 à 19:31 | #9

    Veuillez m’excuser de la réponse tardive ! J’aurais jamais pensé que mon cas pouvais vous intéresser !

    Donc selon vous cela serait une erreur plutôt dû aux relations de ma base de données ? Auriez vous un tutoriel à me conseiller pour m’aider dans ce genre de chose ?

    Je vais essayer de concevoir un petit site avec tous les exemples de relations que j’utilise et y ajouter votre add-ons pour voir les erreurs que je peux comète !

  10. Co-k-ine
    01/08/2010 à 17:48 | #10

    Bonjour,

    Alors j’aimerais coder un site pour le monde du sous-titrage des mangas (fansubing).

    Voici le shémas de la bdd :
    http://www.imagup.com/pics/1280741714.html

    Comme vous pouvez le voir il y a la table « membre » qui servira à stocké les informations relatives au membres, ainsi que le table « message » qui me servira pour le systeme de messagerie privée. Cette table message contient un champ « from_id » avec une relation 1:n (pour identifier l’envoyeur) ainsi qu’un autre champ « to_id » avec une relation 1:n (pour identifier le recepteur du message).
    Je suppose que cette conception est fausse, j’espère que vous pourrez m’éclairer la dessus.

    Il y a la table « animes » qui contient toutes les informations relatives au mangas.
    Afin de ne pas enregistrer plusieurs fois le même genre j’ai voulu créer une relation n:n avec la tables « animes_genres ».

    La tables « animes_ddl », elle contient les liens de téléchargement des sous-titres. J’ai voulu créer une relation 1:n avec la tables « animes ». J’ai aussi voulu créer une relation n:n avec la table membre pour identifier la personne qui a ajouter le sous-titre.

    Pourriez vous m’éclairer sur les erreurs de conception ?
    merci de votre aide

  11. 02/08/2010 à 18:15 | #11

    Bonjour,

    Je suis actuellement en congés et je n’ai donc hélas pas trop de temps à vous consacrer pour le moment.

    Après lecture rapide de votre schéma relationnel, cela me semble être tout à fait correcte. Attention toutefois que si vous désirez enregistrer les données supplémentaires dans les tables MANY_MANY (en dehors des clés étrangères), vous devrez passer par une relation HAS_MANY dans la déclaration de votre modèle et passer par la technique utilisée dans l’application de démos.
    Sinon, votre schéma est assez classique et devrait être géré sans problèmes avec le comportement.

    Quel est l’erreur précise que vous retourne Yii lorsque vous enregistrez vos données ?

    Alban.

    PS. Je serai de retour avec plus de disponibilités à partir du lundi 9 Août.

  12. Co-k-ine
    16/08/2010 à 17:53 | #12

    Bonjour,

    Alors voila je viens de me replongé dans le code et je rencontre une difficulté.

    Voici mon shémas de bdd :
    http://img.devince.eu/uploads/1281385433.png

    Dans mon cas non allons nous intéresser uniquement aux tables « animes » et « animes_has_animes_genres ».

    Enfaite un mangas peut avoir plusieurs genres qui seront stocké dans la table : « animes_genres ». Ces genres sont fixe (par exemple : amour & amitié, art martiaux etc …).

    Comme je ne souhaite pas ajouter de nouveau genre je traite la relation comme une 1:n. Donc j’ajoute dans la table : « animes_has_animes_genres » l’id de l’anime et l’id du genre. Seulement un mangas peut avoir plusieurs genres, il faudrait donc que votre extension puisse ajouter plusieurs fois dans la table « animes_has_animes_genres ».

    Hors je ne sais pas comment faire :s

  13. 16/08/2010 à 18:57 | #13

    @Co-k-ine
    Tout d’abord, votre modèle de données est tout à fait standard. Pas de soucis apparent si ce n’est que le champ « id » de la table « animes_has_animes_genres » n’est pas nécessaire. Pour ce genre de table, généralement on se limite aux 2 clés étrangères comme clé primaire composite (anime_id et anime_genres_id).

    Votre cas peut être traité exactement de la même manière que dans l’application de démonstration en ce qui concerne la gestion de la relation des services de la bibliothèque. Cela devrait fonctionner sans soucis…

  14. jp
    25/04/2011 à 12:23 | #14

    Bonjour,
    Bravo! Pour ce super code!
    J’ai une inscription à faire sur des tables à 3 niveaux: un correspondant peut inscrire (hasMany) un ou plusieurs participants à une ou plusieurs disciplines (manyMany). Le tout sur une même fiche. Comment puis-je aborder cette situation. Les disciplines ne sont pas accrochées au modèle principal Correspondant mais au modèle Participant? Je dois créer en même temps un nouveau Correspondant avec plusieurs nouveaux Participant et chacun avec plusieurs nouvelles associations aux disciplines (ParticipantDiscpline).
    Merci de vos commentaires.

  15. 07/05/2011 à 08:50 | #15

    Bonjour et merci pour votre gentil commentaire.

    Il n’y a malheureusement rien de prévu nativement pour gérer des enregistrements en cascade de la manière dont vous le décrivez.
    A mon avis, il faudrait passer par les événements afterSave de chaque modèles pour associer les données successivement.
    Ou alors, procéder à l’enregistrement successif des différents modéles dans le controleur (en partant du plus bas dans la hiérarchie) au sein d’une transaction (désactiver la fonction du behavior dans ce cas pour la contrôler vous-même).

    En espérant que cela puisse vous aider.

  1. Pas encore de trackbacks

Performance Optimization WordPress Plugins by W3 EDGE

Switch to our mobile site