Hoe te programmeren met Yii2 Blameable Behaviors

Wat je gaat creëren

Als je vraagt: "Wat is Yii?" bekijk mijn eerdere tutorial: Introductie tot het Yii Framework, die de voordelen van Yii bekijkt en een overzicht bevat van wat er nieuw is in Yii 2.0, uitgebracht in oktober 2014.

In deze serie Programming With Yii2 begeleid ik lezers in gebruik van het onlangs bijgewerkte Yii2 Framework voor PHP. In deze tutorial leid ik je door een ander interessant gedrag van Yii2: help mee met het automatiseren van de gemeenschappelijke webontwikkelingstaak toewijzen gemaakt en bijgewerkt door user_ids voor de modellen in je web-app met DRY-codering en Yii2 Blameable Behavior. We maken ook een logboek waarin wordt vastgelegd wie de statustabel voor elke gemaakte wijziging heeft bijgewerkt.

Voor deze voorbeelden blijven we ons voorstellen dat we een raamwerk bouwen voor het plaatsen van eenvoudige statusupdates, bijvoorbeeld onze eigen mini-Twitter.

Ter herinnering, ik neem wel deel aan de commentaarthreads hieronder. Ik ben vooral geïnteresseerd in verschillende benaderingen, aanvullende ideeën of onderwerpen voor toekomstige zelfstudies.

Wat is een gedrag?

Yii2 Gedragingen zijn in wezen mixins. Wikipedia beschrijft mixins als "een klasse die een combinatie van methoden uit andere klassen bevat." Hoe een dergelijke combinatie wordt gedaan, is afhankelijk van de taal, maar niet van overerving. "

Yii beschrijft ze op deze manier:

Door een gedrag aan een component toe te voegen, worden de methoden en eigenschappen van het gedrag in de component geïnjecteerd, waardoor die methoden en eigenschappen toegankelijk worden alsof ze in de componentklasse zelf zijn gedefinieerd.

Yii2 biedt verschillende ingebouwde gedragingen, waarvan we de meeste zullen documenteren, inclusief trage (zie Programming With Yii2: Sluggble Behavior), blameable en timestamp (aankomende, bekijk de seriepagina). Gedragingen zijn een gemakkelijke manier om veelgebruikte code in veel van uw datamodellen te hergebruiken zonder de code op veel plaatsen te hoeven herhalen. Het injecteren van een gedrag in een model kan vaak worden gedaan met slechts twee regels code. Naarmate het aantal modellen in uw toepassing toeneemt, worden gedragingen steeds nuttiger.

Wat is het Blameable Behavior?

Blameable maakt het ons gemakkelijk om de vaak benodigde taak van het toewijzen van de huidige ingelogde gebruiker aan invoegingen en updates in een ActiveRecord-model, waarbij automatisch de eigenschappen voor gemaakt door en updated_by.

In Programming With Yii2: Autorisatie Met het toegangscontrolefilter implementeerden we ons eigen blameable gedrag in twee delen. Eerst hebben we een migratie gemaakt om een ​​toe te voegen gemaakt door veld naar onze status tabel:

db-> driverName === 'mysql') $ tableOptions = 'KARAKTER 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 '); 

Ten tweede hebben we de gemaakt door veld naar de huidige gebruikersnaam in de actie Create van de StatusController:

public function actionCreate () $ model = nieuwe status (); if ($ model-> load (Yii :: $ app-> request-> post ())) $ model-> created_by = Yii :: $ app-> user-> getId ();

Het implementeren van het Blameable-gedrag zal dit automatisch voor ons doen en kan eenvoudig worden toegevoegd aan alle ActiveRecord-modellen in een webapplicatie.

Het Blameable Behavior implementeren in het Statusmodel

De statuslijst uitbreiden

Ten eerste moeten we de Status-tabel opnieuw uitbreiden met een migratie om ondersteuning te bieden voor een updated_by veld-.

Jeff $ ./yii migrate / create extend_status_table_for_updated_by Yii Migration Tool (gebaseerd op Yii v2.0.2) Maak nieuwe migratie '/Users/Jeff/Sites/hello/migrations/m150209_200619_extend_status_table_for_updated_by.php'? (ja | nee) [nee]: ja Nieuwe migratie is succesvol gemaakt.

Dit is de migratiecode die we zullen gebruiken:

db-> driverName === 'mysql') $ tableOptions = 'KARAKTER 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 ( '% de status', 'updated_by');  

Als u deze migratie probeert uit te voeren met bestaande gegevens in uw database, krijgt u een foutmelding bij het maken van de index van de buitenlandse sleutel, omdat de updated_by is 0 en bestaat niet in de gebruikerstabel. 

hallo Jeff $ ./yii migrate / up Yii Migration Tool (gebaseerd op Yii v2.0.2) Totaal 1 nieuwe migratie die moet worden toegepast: m150209_200619_extend_status_table_for_updated_by De bovenstaande migratie toepassen? (yes | no) [nee]: yes *** apply m150209_200619_extend_status_table_for_updated_by> voeg kolom updated_by integer NOT NULL toe aan table % status ... done (time: 0.042s)> add foreign key fk_status_updated_by: % status (updated_by) referenties % user (id) ... Uitzondering 'yii \ db \ IntegrityException' met het bericht 'SQLSTATE [23000]: schending van de integriteitsbeperking: 1452 Kan geen onderliggende rij toevoegen of bijwerken: een beperking van een externe sleutel mislukt (' hello '.' # sql-22f_1d0 ', CONSTRAINT' fk_status_updated_by 'FOREIGN KEY (' updated_by ') REFERENTIES' user '(' id ') OP VERWIJDEREN CASCADE OP UPDATE CASCADE) De SQL die werd uitgevoerd was: ALTER TABLE' status 'ADD CONSTRAINT 'fk_status_updated_by' FOREIGN KEY ('updated_by') REFERENTIES 'user' ('id') OP DELETE CASCADE OP UPDATE CASCADE 'in /Users/Jeff/Sites/hello/vendor/yiisoft/yii2/db/Schema.php:532 Fout Info: Array ([0] => 23000 [1] => 1452 [2] => Kan een onderliggende rij niet toevoegen of bijwerken: een externe sleutelbeperking mislukt ('hallo'. '# Sql-22f_1d0', CONSTRAINT 'fk_status_updated_by' FORE IGN KEY ('updated_by') REFERENTIES 'user' ('id') OP VERWIJDERING CASCADE OP UPDATE CASCADE)) 

We kunnen dit omzeilen door de gegevens handmatig bij de migratie bij te werken en vervolgens een externe sleutel toe te voegen. Aangezien dit een testplatform is, is het echter het eenvoudigst om drie stappen naar beneden te migreren - de statustabel en de testgegevens te verwijderen - en vervolgens opnieuw te migreren:

hallo Jeff $ ./yii migrate / down 3 Yii Migration Tool (gebaseerd op Yii v2.0.2) Totaal 3 migraties die moeten worden teruggezet: m150128_233458_extend_status_table_for_slugs m150128_003709_extent_status_table_for_created_by m141201_013120_create_status_table Zet de bovenstaande migraties terug? (ja | nee) [nee]: ja *** terugzetten m150128_233458_extend_status_table_for_slugs> drop slick in kolom uit tabel % status ... klaar (tijd: 0.009s) *** teruggezet m150128_233458_extend_status_table_for_slugs (tijd: 0.013s) *** terugdraaien m150128_003709_extend_status_table_for_created_by> drop foreign key fk_status_created_by from table % status ... done (time: 0.010s)> drop column created_by uit table % status ... done (time: 0.008s) *** teruggezet m150128_003709_extend_status_table_for_created_by (tijd: 0.019s) *** terugzetten m141201_013120_create_status_table> drop table % status ... done (time: 0.001s) *** teruggezet m141201_013120_create_status_table (tijd: 0.002s) Migratie succesvol uitgevoerd. hallo Jeff $ ./yii migrate / up 4 Yii Migration Tool (gebaseerd op Yii v2.0.2) Totaal 4 nieuwe migraties toe te passen: m141201_013120_create_status_table m150128_003709_extend_status_table_for_created_by m150128_233458_extend_status_table_for_slugs m150209_200619_extend_status_table_for_updated_by De bovenstaande migraties toepassen? (ja | nee) [nee]: ja *** toepassen m141201_013120_create_status_table> tabel maken % status ... klaar (tijd: 0.007s) *** toegepast m141201_013120_create_status_table (tijd: 0.010s) *** apply m150128_003709_extend_status_table_for_created_by> toevoegen column created_by integer NOT NULL to table % status ... done (time: 0.007s)> add foreign key fk_status_created_by: % status (created_by) references % user (id) ... done (time : 0.008s) *** applied m150128_003709_extend_status_table_for_created_by (time: 0.016s) *** apply m150128_233458_extend_status_table_for_slugs> voeg kolom-slugreeks NOT NULL toe aan tabel % status ... klaar (tijd: 0.007s) *** toegepast m150128_233458_extend_status_table_for_slugs (time : 0.008s) *** apply m150209_200619_extend_status_table_for_updated_by> voeg kolom updated_by integer NOT NULL toe aan tabel % status ... done (time: 0.007s)> voeg buitenlandse sleutel toe fk_status_updated_by: % status (updated_by) referenties  % gebruiker (id) ... klaar (tijd: 0.007s) *** toegepast m 150209_200619_extend_status_table_for_updated_by (time: 0.015s) Migratie succesvol uitgevoerd.

De Blameable Behavior toevoegen aan het statusmodel

Vervolgens koppelen we de Blameable Behavior aan ons statusmodel. In modellen / Status.php voegen we de BlameableBehavior toe na Sluggable:

class Status extends \ yii \ db \ ActiveRecord const PERMISSIONS_PRIVATE = 10; const PERMISSIONS_PUBLIC = 20; public function behaviors () return [['class' => SluggableBehavior :: className (), 'attribute' => 'message', 'immutable' => true, 'sureUnique' => true,], ['class' => BlameableBehavior :: className (), 'createdByAttribute' => 'created_by', 'updatedByAttribute' => 'updated_by',],]; 

We moeten ook het Blameable-gedrag bovenaan ons model opnemen:

Vervolgens verwijderen we de vereiste regel voor gemaakt door in de modelregels:

public function rules () return [['message', 'created_at', 'updated_at', 'created_by'], 'required'],

Zoals dit:

public function rules () return [['' message ',' created_at ',' updated_at '],' required '],

Hierdoor kan de validatie slagen en doorgaan met het gedrag.

We kunnen ook de StatusController's commentaar geven of verwijderen gemaakt door toewijzing in de actie maken:

public function actionCreate () $ model = nieuwe status (); if ($ model-> load (Yii :: $ app-> request-> post ())) // $ model-> created_by = Yii :: $ app-> user-> getId ();

Zodra al deze wijzigingen zijn voltooid, kunnen we een nieuw Status-bericht schrijven:

En we kunnen met PHPMyAdmin naar de tabelweergave kijken en de instellingen created_by en updated_by bekijken:

Updates registreren bij de statustabel

Wanneer een statusbericht wordt gemaakt, weten we altijd wie het eerste item heeft gemaakt. Maar met Blameable Behaviors weten we alleen wie het record voor het laatst heeft bijgewerkt.

Laten we een eenvoudige log-implementatie doorlopen om de id te registreren van de persoon die elke update maakt. Dan zou je gemakkelijk een geschiedenis van updaters kunnen zien of uitbreiden om een ​​volledig revisielog te zijn.

De tabel maken voor statuslog

Ten eerste moeten we een migratie maken voor de StatusLog:

hallo Jeff $ ./yii migreren / create create_status_log_table Yii Migration Tool (gebaseerd op Yii v2.0.2) Maak nieuwe migratie '/Users/Jeff/Sites/hello/migrations/m150209_204852_create_status_log_table.php'? (ja | nee) [nee]: ja Nieuwe migratie is succesvol gemaakt.

Vervolgens coderen we de migratie om relationele velden op te nemen voor de statustabel-id en gebruiker updated_by gebieden:

db-> driverName === 'mysql') $ tableOptions = 'KARAKTER 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' => Schema :: 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');  

Vervolgens voeren we de migratie uit:

hallo Jeff $ ./yii migreren / omhoog Yii Migration Tool (gebaseerd op Yii v2.0.2) Totaal 1 nieuwe migratie toe te passen: m150209_204852_create_status_log_table Pas de bovenstaande migratie toe? (ja | nee) [nee]: ja *** toepassen m150209_204852_create_status_log_table> tabel maken % status_log ... klaar (tijd: 0.008s)> externe sleutel toevoegen fk_status_log_id: % status_log (status_id) referenties  % status (id) ... klaar (tijd: 0.008s)> externe sleutel toevoegen fk_status_log_updated_by: % status_log (updated_by) referenties % user (id) ... done (tijd: 0.008s) ** * applied m150209_204852_create_status_log_table (time: 0.028s) Migratie succesvol uitgevoerd.

De snelste manier om een ​​model voor StatusLog (en CRUD-bestanden te maken zodat we gemakkelijk door de tabel kunnen bladeren) is met Yii2's codegenerator, Gii. Je hebt me het in vorige handleidingen zien gebruiken.

Ga naar http: // localhost: 8888 / hello / gii en maak het model met deze instellingen:

Dit zijn de CRUD-instellingen:

Vervolgens breiden we de AfterSave-gebeurtenis uit in het Statusmodel:

openbare functie afterSave ($ insert, $ changedAttributes) parent :: afterSave ($ insert, $ changedAttributes); / / wanneer invoegen false, dan record is bijgewerkt als (! $ insert) // toevoegen StatusLog entry $ status_log = nieuwe StatusLog; $ status_log-> status_id = $ dit-> id; $ status_log-> updated_by = $ this-> updated_by; $ status_log-> created_at = time (); $ Status_log-> save (); 

Voor deze methode wordt de standaard bovenliggende functionaliteit aangeroepen afterSave maar maakt vervolgens een nieuw StatusLog-item aan wanneer er een update is naar een statusregel:

Theoretisch zouden we ook Blameable Behavior kunnen uitbreiden, maar omdat je er zeker van moet zijn dat er een logmodel is voor elk ActiveRecord-model waarmee je het gebruikt, leek het gemakkelijker om deze functionaliteit in Status te bouwen.

Als u een aantal statusrecords bijwerkt, kunt u bladeren door het StatusLog met behulp van Gii's CRUD. De onderstaande afbeelding toont twee wijzigingen die zijn aangebracht door Status.id 1.

Als u verder wilt gaan, moet het relatief eenvoudig zijn om dit uit te breiden naar een revisietabel, compleet met vorige en nieuwe statustekst om de rollback-functionaliteit te ondersteunen.

Wat is het volgende?

Ik hoop dat je het leuk hebt gevonden om meer te weten te komen over Yii2 Behaviors en Blameable. Vervolgens zullen we Timestamp-gedrag verkennen, waarmee u de hoeveelheid code die u met elk nieuw model moet schrijven, vermindert voor de gemeenschappelijke bewerking van het maken van tijdstempels voor invoegingen en updates.

Kijk uit naar komende tutorials in mijn Programming With Yii2-serie terwijl ik verder duik in verschillende aspecten van het framework. Je kunt ook mijn Building Your Startup With PHP-serie bekijken, die de geavanceerde sjabloon van Yii2 gebruikt terwijl ik een toepassing uit de echte wereld samenstel.

Ik verwelkom aanvragen voor functies en onderwerpen. Je kunt ze plaatsen in de reacties hieronder of e-mail me op mijn Lookahead Consulting-website.

Als je wilt weten wanneer de volgende Yii2-handleiding aankomt, volg me dan @reifman op Twitter of bekijk mijn instructeurspagina. Op mijn instructeurspagina staan ​​alle artikelen uit deze serie zodra ze zijn gepubliceerd. 

Gerelateerde Links

  • De Yii2 definitieve gids: gedrag
  • Yii2-documentatie: Blameable Behavior
  • Yii2 Developer Exchange, mijn eigen Yii2-bronsite