Comment programmer avec Yii2 Comportements répréhensibles

Ce que vous allez créer

Si vous demandez, "Qu'est-ce que Yii?" Découvrez mon tutoriel précédent: Introduction au framework Yii, qui passe en revue les avantages de Yii et inclut un aperçu des nouveautés de Yii 2.0, publiées en octobre 2014.

Dans cette série de programmation avec Yii2, je guide les lecteurs dans l'utilisation du framework Yii2 pour PHP récemment mis à jour. Dans ce tutoriel, je vous guiderai à travers un autre comportement intéressant de Yii2: aider à automatiser la tâche de développement Web commune consistant à attribuer créée par et mise à jour par user_ids sur les modèles de votre application Web en utilisant le codage DRY et Yii2 BlameableBehavior. Nous allons également créer un journal qui enregistre les personnes ayant mis à jour le tableau des statuts pour chaque modification apportée..

Pour ces exemples, nous allons continuer à imaginer que nous construisons un cadre pour la publication de mises à jour de statut simples, par exemple. notre propre mini-Twitter.

Juste un rappel, je participe aux commentaires ci-dessous. Je suis particulièrement intéressé si vous avez des approches différentes, des idées supplémentaires ou si vous souhaitez suggérer des sujets pour de futurs tutoriels..

Qu'est-ce qu'un comportement?

Yii2 Les comportements sont essentiellement des mixins. Wikipedia décrit les mixins comme "une classe contenant une combinaison de méthodes d'autres classes. La manière dont cette combinaison est réalisée dépend de la langue, mais ce n'est pas un héritage."

Yii les décrit ainsi:

La liaison d'un comportement à un composant "injecte" les méthodes et propriétés du comportement dans le composant, rendant ces méthodes et propriétés accessibles comme si elles avaient été définies dans la classe de composant elle-même..

Yii2 offre plusieurs comportements intégrés dont nous allons documenter la plupart, notamment sluggable (voir Programmation avec Yii2: comportement sluggable), blameable et timestamp (à venir, consultez la page de la série). Les comportements constituent un moyen simple de réutiliser du code commun dans bon nombre de vos modèles de données sans avoir à répéter le code à plusieurs endroits. L'injection d'un comportement dans un modèle peut souvent être réalisée avec seulement deux lignes de code. À mesure que le nombre de modèles dans votre application augmente, les comportements deviennent de plus en plus utiles..

Quel est le comportement blâmable?

Blameable facilite la mise en œuvre de la tâche fréquemment nécessaire consistant à affecter l'utilisateur actuellement connecté à des insertions et des mises à jour dans un modèle ActiveRecord, en définissant automatiquement les propriétés de créé par et Mis à jour par.

Dans Programmation avec Yii2: Autorisation avec le filtre de contrôle d'accès, nous avons implémenté notre propre comportement répréhensible en deux parties. Tout d'abord, nous avons créé une migration pour ajouter un créé par champ à notre table d'état:

db-> nomDuPort === 'mysql') $ tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB';  $ this-> addColumn ('% status', 'created_by', Schema :: TYPE_INTEGER. 'NOT NULL'); $ this-> addForeignKey ('fk_status_created_by', '% status', 'created_by', '% user', 'id', 'CASCADE', 'CASCADE'); 

Deuxièmement, nous avons assigné le créé par champ au courant identifiant d'utilisateur dans l'action create de StatusController:

fonction publique actionCreate () $ model = new Status (); if ($ model-> load (Yii :: $ app-> request-> post ())) $ model-> created_by = Yii :: $ app-> user-> getId ();

L'implémentation du comportement Blameable le fera automatiquement pour nous et pourra être facilement ajoutée à tous les modèles ActiveRecord d'une application Web..

Implémentation du comportement irréprochable dans le modèle d'état

Extension de la table d'état

Premièrement, nous devons étendre une nouvelle fois la table Status avec une migration pour prendre en charge une Mis à jour par champ.

Jeff $ ./yii migrate / create extend_status_table_for_updated_by Yii Migration Tool (basé sur Yii v2.0.2) Créer une nouvelle migration '/Users/Jeff/Sites/hello/migrations/m150209_200619_extend_status_table_for_updated_by.php'? (oui | non) [non]: oui Nouvelle migration créée avec succès.

Voici le code de migration que nous allons utiliser:

db-> nomDuPort === 'mysql') $ tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB';  $ this-> addColumn ('% status', 'updated_by', Schema :: TYPE_INTEGER. 'NOT NULL'); $ this-> addForeignKey ('fk_status_updated_by', '% status', 'updated_by', '% user', 'id', 'CASCADE', 'CASCADE');  public function down () $ this-> dropForeignKey ('fk_status_updated_by', '% status'); $ this-> dropColumn ('% status', 'updated_by');  

Si vous essayez d'exécuter cette migration avec des données existantes dans votre base de données, vous obtiendrez une erreur en essayant de créer l'index de clé étrangère, car Mis à jour par est 0 et n'existe pas dans la table utilisateur. 

bonjour Jeff $ ./yii migrate / up Yii Outil de migration (basé sur Yii v2.0.2) Total 1 nouvelle migration à appliquer: m150209_200619_extend_status_table_for_updated_by Appliquer la migration ci-dessus? (yes | no) [no]: yes *** application de m150209_200619_extend_status_table_for_updated_by> ajouter une colonne updated_by entier NOT NULL à la table % status… done (heure: 0.042s)> ajouter une clé étrangère fk_status_updated_by: % status (updated_by) reference % user (id)… Exception 'yii \ db \ IntegrityException' avec le message 'SQLSTATE [23000]: Violation de contrainte d'intégrité: 1452 Impossible d'ajouter ou de mettre à jour une ligne enfant: une contrainte de clé étrangère échoue (' bonjour '.' # sql-22f_1d0 ', CONSTRAINT' fk_status_updated_by 'FOREIGN KEY (' updated_by ') REFERENCES' user '(' id ') SUR DELETE CASCADE SUR UPDATE CASCADE) Le SQL a été exécuté: ALTER TABLE' status 'ADD CONSTRAINT 'fk_status_updated_by' FOREIGN KEY ('updated_by') REFERENCES 'user' ('id') ON EFFACER CASCADE SUR UPDATE CASCADE 'dans /Users/Jeff/Sites/hello/vendor/yiisoft/yii2/db/Schema.php. Info: Array ([0] => 23000 [1] => 1452 [2] => Impossible d'ajouter ou de mettre à jour une ligne enfant: une contrainte de clé étrangère échoue ('bonjour'. '# Sql-22f_1d0', CONSTRAINT 'fk_status_updated_by' FORE TOUCHE IGN ('updated_by') REFERENCES 'utilisateur' ('id') SUR EFFACER CASCADE SUR UPDATE CASCADE)) 

Nous pourrions contourner ce problème en mettant à jour les données manuellement dans la migration, puis en ajoutant une clé étrangère. Cependant, puisqu'il s'agit d'une plate-forme de test, il est plus simple de migrer vers le bas en trois étapes: supprimer la table Status et ses données de test, puis migrer à nouveau:

salut Jeff $ ./yii migrate / down 3 Yii Outil de migration (basé sur Yii v2.0.2) Total 3 migrations à inverser: m150128_233458_extend_status_table_table_for_slugs m150128_003709_xend_status_tatus_forable (yes | no) [no]: yes *** rétablissant m150128_233458_extend_status_table_for_slugs> supprime le slug de colonne de la table % status… done (heure: 0,009s) *** retourné m150128_233458_extend_status_table_for_slugs m150128_003709_extend_status_table_for_created_by> supprimer la clé étrangère fk_status_created_by de la table % status ... done (time: 0.010s)> 0.019s) *** annulation de la conversion de m141201_013120_create_status_table> table de suppression % status… terminée (heure: 0,001s) *** annulée m141201_013120_create_status_table (heure: 0.002s). Migration réussie. hello Jeff (yes | no) [no]: yes *** application de m141201_013120_create_status_table> créer une table % status… done (heure: 0,007s) *** appliquée m150128_00370_i colonne created_by integer NOT NULL à la table % status… done (heure: 0.007s)> ajouter la clé étrangère fk_status_created_by: % status (created_by) références % user (id)… done (time : Appliquez m150128_003709_extend_status_table_for_created_by par (time: 0.016s) *** m150128_233458_extend_status_table_for_slugs_by> a ajouté des articles de la catégorie : 0.008s) *** application de m150209_200619_extend_status_table_table_for_updated_by> ajouter une colonne updated_by au entier NOT NULL à la table % status… done (heure: 0.007s)> ajouter la clé étrangère fk_status_updated_by: % status (update_by) références  % utilisateur (id)… terminé (heure: 0.007s) *** appliqué m 150209_200619_extend_status_table_for_updated_by (time: 0.015s) Migration réussie.

Ajout du comportement BlameableBehavior au modèle d'état

Ensuite, nous allons associer le comportement BlameableBehavior à notre modèle Status. Dans models / Status.php, nous ajoutons le BlameableBehavior après Sluggable:

statut de classe étend \ yii \ db \ ActiveRecord const PERMISSIONS_PRIVATE = 10; const PERMISSIONS_PUBLIC = 20; fonction publique comportements () return [['class' => SluggableBehavior :: className (), 'attribut' => 'message', 'immuable' => vrai, 'EnsureUnique' => vrai,], ['classe' => BlameableBehavior :: className (), 'createdByAttribute' => 'created_by', 'updatedByAttribute' => 'updated_by',],]; 

Nous devons également inclure le comportement Blameable au sommet de notre modèle:

Ensuite, nous supprimons la règle requise pour créé par dans les règles modèles:

règles de fonction publique () return [['' message ',' created_at ',' updated_at ',' created_by '],' required '],

Comme ça:

règles de fonction publique () return [[['' message '', 'created_at', 'updated_at'], 'required'],

Cela permet à la validation de réussir et de continuer avec les comportements.

Nous pouvons également commenter ou supprimer le StatusController créé par affectation dans l'action create:

fonction publique actionCreate () $ model = new Status (); if ($ model-> load (Yii :: $ app-> request-> post ())) // $ model-> created_by = Yii :: $ app-> user-> getId ();

Une fois que tous ces changements sont terminés, nous pouvons écrire un nouvel article de statut:

Et nous pouvons jeter un coup d’œil dans la vue tableau avec PHPMyAdmin et voir les paramètres created_by et updated_by:

Consignation des mises à jour dans la table d'état

Lorsqu'une publication d'état est créée, nous savons toujours qui a créé la première entrée. Mais, avec Blameable Behaviors, nous ne saurons que qui a mis à jour le dernier enregistrement.

Passons en revue une simple implémentation de journal pour enregistrer l'identifiant de la personne qui effectue chaque mise à jour. Ensuite, vous pouvez facilement voir l'historique des programmes de mise à jour ou en faire un journal de révision complet..

Création de la table pour StatusLog

Premièrement, nous devons créer une migration pour le StatusLog:

bonjour Jeff $ ./yii migrer / créer create_status_log_table Outil de migration Yii (basé sur Yii v2.0.2) Créer une nouvelle migration '/Users/Jeff/Sites/hello/migrations/m150209_204852_create_status_log_table.php'? (oui | non) [non]: oui Nouvelle migration créée avec succès.

Ensuite, nous codons la migration pour inclure les champs relationnels de l’ID de la table d’état et de l’utilisateur Mis à jour par des champs:

db-> nomDuPort === 'mysql') $ tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB';  $ this-> createTable ('% status_log', ['id' => Schema :: TYPE_PK, 'status_id' => Schema :: TYPE_INTEGER. 'NOT NULL', 'updated_by' => Schema :: TYPE_INTEGER. 'NOT NULL', 'created_at' => Schéma :: TYPE_INTEGER. 'NOT NULL',], $ tableOptions); $ this-> addForeignKey ('fk_status_log_id', '% status_log', 'status_id', '% status', 'id', 'CASCADE', 'CASCADE'); $ this-> addForeignKey ('fk_status_log_updated_by', '% status_log', 'updated_by', '% user', 'id', 'CASCADE', 'CASCADE');  public function down () $ this-> dropForeignKey ('fk_status_updated_by', '% status_log'); $ this-> dropForeignKey ('fk_status_id', '% status_log'); $ this-> dropColumn ('% status_log', 'updated_by');  

Ensuite, nous lançons la migration:

salut Jeff $ ./yii migrate / up Outil de migration Yii (basé sur Yii v2.0.2) Total 1 nouvelle migration à appliquer: m150209_204852_create_status_log_table Appliquer la migration ci-dessus? (yes | no) [no]: yes *** application de m150209_204852_create_status_log_table> créer une table % status_log… terminé (heure: 0.008s)> ajouter une clé étrangère fk_status_log_id: % status_log (status_id) % status (id)… done (heure: 0.008s)> ajouter la clé étrangère fk_status_log_updated_by: % status_log (updated_by) fait référence à % user (id)… done (heure: 0.008s) ** * appliqué m150209_204852_create_status_log_table (heure: 0.028s) Migrée vers le haut avec succès.

Le moyen le plus rapide de créer un modèle pour StatusLog (et les fichiers CRUD afin que nous puissions facilement parcourir la table) consiste à utiliser le générateur de code de Yii2, Gii. Vous m'avez vu l'utiliser dans des tutoriels précédents.

Visitez le site http: // localhost: 8888 / hello / gii et créez le modèle avec les paramètres suivants:

Voici les paramètres CRUD:

Ensuite, nous étendons l'événement AfterSave dans le modèle Status:

fonction publique afterSave ($ insert, $ modifiedAttributes) parent :: afterSave ($ insert, $ modifiedAttributes); // quand insert false, l'enregistrement a été mis à jour si (! $ insert) // ajoute l'entrée StatusLog $ status_log = new StatusLog; $ status_log-> status_id = $ this-> id; $ status_log-> updated_by = $ this-> updated_by; $ status_log-> created_at = time (); $ status_log-> save (); 

Cette méthode appelle la fonctionnalité parent par défaut pour après la sauvegarde mais crée ensuite une nouvelle entrée StatusLog chaque fois qu'il y a une mise à jour d'une ligne Status:

Théoriquement, nous pourrions également étendre BlameableBehavior, mais comme vous devez vous assurer qu'il existe un modèle de journal pour chaque modèle ActiveRecord avec lequel vous l'utilisez, il semblait plus facile de générer cette fonctionnalité dans Status..

Si vous mettez à jour quelques enregistrements de statut, vous pouvez parcourir le StatusLog à l'aide du CRUD de Gii. L'image ci-dessous montre deux modifications apportées par Status.id 1.

Si vous voulez aller plus loin, il devrait être relativement simple d’étendre cela à une table de révision avec le texte d’état précédent et nouveau afin de prendre en charge la fonctionnalité de restauration..

Et après?

J'espère que vous avez apprécié l'apprentissage de Yii2 Behaviors and Blameable. Nous explorerons ensuite les comportements d’horodatage, qui permettent de réduire la quantité de code à écrire avec chaque nouveau modèle pour l’opération courante de création d’horodatages pour les insertions et les mises à jour..

Surveillez les prochains tutoriels de ma série Programming With Yii2 pendant que je continue à plonger dans différents aspects du cadre. Vous pouvez également consulter ma série Construire votre démarrage avec PHP qui utilise le modèle avancé de Yii2 pour créer une application du monde réel..

Je me félicite des demandes de fonctionnalités et de sujets. Vous pouvez les poster dans les commentaires ci-dessous ou m'envoyer un email sur mon site Lookahead Consulting.

Si vous souhaitez savoir quand le prochain tutoriel Yii2 arrive, suivez-moi @reifman sur Twitter ou consultez ma page d'instructeur. Ma page d’instructeur comprendra tous les articles de cette série dès leur publication.. 

Liens connexes

  • Le guide définitif Yii2: comportements
  • Documentation Yii2: Comportement répréhensible
  • Yii2 Developer Exchange, mon propre site de ressources Yii2