Slik programmerer du med Yii2 Skyldig oppførsel

Hva du skal skape

Hvis du spør, "Hva er Yii?" sjekk ut min tidligere opplæring: Introduksjon til Yii Framework, som vurderer fordelene med Yii og inneholder en oversikt over hva som er nytt i Yii 2.0, utgitt i oktober 2014.

I denne programmeringen med Yii2-serien, er jeg veiledende lesere i bruk av den nylig oppgraderte Yii2 Framework for PHP. I denne veiledningen vil jeg veilede deg gjennom en annen av Yii2s interessante atferd: Hjelpe å automatisere den vanlige webutviklingsoppgaven med å tildele opprettet av og oppdatert av user_ids på tvers av modellene i din webapp ved hjelp av DRY-koding og Yii2 BlameableBehavior. Vi lager også en logg som registrerer hvem som oppdaterte statustabellen for hver endret endring.

For disse eksemplene fortsetter vi å forestille oss at vi bygger et rammeverk for å legge ut enkle statusoppdateringer, f.eks. vår egen mini-Twitter.

Bare en påminnelse, jeg deltar i kommentar tråder nedenfor. Jeg er spesielt interessert hvis du har forskjellige tilnærminger, flere ideer, eller ønsker å foreslå emner for fremtidige opplæringsprogrammer.

Hva er en oppførsel?

Yii2 Behavior er i hovedsak mixins. Wikipedia beskriver mixiner som "en klasse som inneholder en kombinasjon av metoder fra andre klasser. Hvordan en slik kombinasjon gjøres avhenger av språket, men det er ikke av arv."

Yii beskriver dem på denne måten:

Ved å knytte en oppførsel til en komponent injiserer adferdens metoder og egenskaper inn i komponenten, noe som gjør disse metodene og egenskapene tilgjengelige som om de ble definert i komponentklassen selv.

Yii2 tilbyr flere innebygde oppføringer, hvorav de fleste dokumenterer, inkludert sluggable (se Programmering med Yii2: Sluggable Behavior), skyldig og tidsstempel (kommende, sjekk serieresiden). Atferd er en enkel måte å gjenbruke felles kode på mange av datamodellene uten å gjenta koden på mange steder. Injiserer en oppførsel i en modell kan ofte gjøres med bare to linjer med kode. Etter hvert som antall modeller i søknaden din øker, blir atferdene mer og mer nyttige.

Hva er skyldig oppførsel?

Blameable gjør det enkelt for oss å implementere den ofte trengte oppgaven med å tilordne den gjeldende loggede brukeren til innlegg og oppdateringer i en ActiveRecord-modell, automatisk innstilling av egenskapene for laget av og updated_by.

I programmering med Yii2: Autorisasjon Med tilgangskontrollfilteret implementerte vi vår egen skyldige oppførsel i to deler. Først opprettet vi en migrering for å legge til en laget av feltet til vårt Status-bord:

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

For det andre tildelte vi laget av feltet til gjeldende bruker-ID i StatusControllers opprettingshandling:

offentlig funksjon actionCreate () $ model = new Status (); hvis ($ modell-> last (Yii :: $ app-> forespørsel-> post ())) $ model-> created_by = Yii :: $ app-> bruker-> getId ();

Implementering av skyldig oppførsel vil gjøre dette automatisk for oss og kan enkelt legges til alle ActiveRecord-modellene i et webprogram.

Implementere den skyldige oppførselen i statusmodellen

Utvider statustabellen

Først må vi forlenge statustabellen med en migrering en gang til for å støtte en updated_by felt.

Jeff $ ./yii migrere / opprett extend_status_table_for_updated_by Yii Migration Tool (basert på Yii v2.0.2) Opprett ny migrasjon '/Users/Jeff/Sites/hello/migrations/m150209_200619_extend_status_table_for_updated_by.php'? (ja | nei) [nei]: ja Ny migrasjon ble opprettet.

Her er overføringskoden vi skal bruke:

db-> drivernavn === 'mysql') $ tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB';  $ this-> addColumn ('% status', 'updated_by', Schema :: TYPE_INTEGER. 'IKKE NULL'); $ this-> addForeignKey ('fk_status_updated_by', '% status', 'updated_by', '% user', 'id', 'CASCADE', 'CASCADE');  offentlig funksjon ned () $ this-> dropForeignKey ('fk_status_updated_by', '% status'); $ Dette-> dropColumn ( '% status', 'updated_by');  

Hvis du prøver å kjøre denne overføringen med eksisterende data i databasen, får du en feil når du prøver å opprette den utenlandske nøkkelindeksen, fordi updated_by er 0 og eksisterer ikke i brukertabellen. 

hei Jeff $ ./yii migrere / opp Yii Migreringsverktøy (basert på Yii v2.0.2) Totalt 1 ny migrasjon som skal brukes: m150209_200619_extend_status_table_for_updated_by Bruk overføringen ovenfor? (ja | nei) nei: ja *** gjelder m150209_200619_extend_status_table_for_updated_by> legg til kolonne updated_by heltall NOT NULL til tabell % status ... ferdig (tid: 0.042s)> legg til utenlandsk nøkkel fk_status_updated_by: % status (updated_by) referanser % user (id) ... Unntak 'yii \ db \ IntegrityException' med melding 'SQLSTATE [23000]: Krenkelse av integritetsbegrensning: 1452 Kan ikke legge til eller oppdatere en barnrad: en fremmednøkkelbegrensning feiler hallo '.' # sql-22f_1d0 ', CONSTRAINT' fk_status_updated_by 'FOREIGN KEY (' updated_by ') REFERANSER' bruker '(' id ') PÅ DELETE CASCADE ON UPDATE CASCADE) SQL blir utført var: ALTER TABLE' status 'ADD CONSTRAINT 'fk_status_updated_by' FOREIGN KEY ('updated_by') REFERANSER 'bruker' ('id') PÅ DELETE CASCADE ON UPDATE CASCADE 'i /Users/Jeff/Sites/hello/vendor/yiisoft/yii2/db/Schema.php:532 Feil Info: Array ([0] => 23000 [1] => 1452 [2] => Kan ikke legge til eller oppdatere en barrad: En utenlandsk nøkkelbegrensning feiler ('hallo'. '# Sql-22f_1d0', CONSTRAINT 'fk_status_updated_by' FORE IGN KEY ('updated_by') REFERANSER 'bruker' ('id') PÅ DELETE CASCADE PÅ OPPDATERING CASCADE)) 

Vi kunne jobbe rundt dette ved å oppdatere dataene manuelt i overføringen, og deretter legge til en fremmednøkkel. Men siden dette er en testplattform, er det enklest å bare trekke ned tre trinn - slippe Status-tabellen og dens testdata - og deretter migrere opp igjen:

hei Jeff $ ./yii migrere / ned 3 Yii Migreringsverktøy (basert på Yii v2.0.2) Totalt 3 migreringer som skal returneres: m150128_233458_extend_status_table_for_slugs m150128_003709_extend_status_table_for_created_by m141201_013120_create_status_table Tilbakestill overstående migrasjoner? (ja | nei) nei: ja *** tilbake m150128_233458_extend_status_table_for_slugs> slipp kolonne slug fra tabell status status ... ferdig (tid: 0.009s) *** tilbakestilt m150128_233458_extend_status_table_for_slugs (tid: 0.013s) *** tilbakestilling m150128_003709_extend_status_table_for_created_by> slett utenlandsk nøkkel fk_status_created_by fra bordet % status ... ferdig (tid: 0.010s)> dråpe kolonne created_by fra bordet % status ... ferdig (tid: 0.008s) *** tilbakestilt m150128_003709_extend_status_table_for_created_by (tid: 0.019s) *** tilbake m141201_013120_create_status_table> drop table status status ... ferdig (tid: 0.001s) *** tilbakeført m141201_013120_create_status_table (tid: 0.002s) Migrert ned med hell. hei Jeff $ ./yii migrere / opp 4 Yii Migreringsverktøy (basert på Yii v2.0.2) Totalt 4 nye migrasjoner som skal brukes: 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 Bruk de ovennevnte migrasjonene? (ja | nei) nei: ja *** bruk m141201_013120_create_status_table> opprett tabell % status ... ferdig (tid: 0,007s) *** brukt m141201_013120_create_status_table (tid: 0,010s) *** gjelder m150128_003709_extend_status_table_for_created_by> legg til kolonne created_by heltal IKKE NULL til tabell % status ... ferdig (tid: 0.007s)> legg til utenlandsk nøkkel fk_status_created_by: % status (created_by) referanser % user (id) ... ferdig : 0.008s) *** brukt m150128_003709_extend_status_table_for_created_by (tid: 0,016s) *** bruker m150128_233458_extend_status_table_for_slugs> legg til kolonne slug streng IKKE NULL til tabell % status ... ferdig (tid: 0.007s) *** brukt m150128_233458_extend_status_table_for_slugs : 0.008s) *** m150209_200619_extend_status_table_for_updated_by> Legg til kolonne updated_by heltall NOT NULL til tabell % status ... ferdig (tid: 0.007s)> legg til utenlandsk nøkkel fk_status_updated_by: % status (updated_by) referanser  % bruker (id) ... ferdig (tid: 0,007s) *** brukt m 150209_200619_extend_status_table_for_updated_by (tid: 0.015s) Migrert opp med hell.

Legge til BlameableBehavior til statusmodellen

Deretter knytter vi BlameableBehavior til vår Status-modell. I modeller / Status.php legger vi til BlameableBehavior etter Sluggable:

Klassestatus utvider \ yii \ db \ ActiveRecord const PERMISSIONS_PRIVATE = 10; const PERMISSIONS_PUBLIC = 20; Offentlig funksjon oppførsel () return [['class' => SluggableBehavior :: className (), 'attribute' => 'melding', 'immutable' => true, 'sikreUnique' => true,], => BlameableBehavior :: className (), 'createdByAttribute' => 'created_by', 'updatedByAttribute' => 'updated_by',],]; 

Vi må også inkludere Skyllbar oppførsel på toppen av modellen vår:

Da fjerner vi den nødvendige regelen for laget av i modellreglene:

offentlige funksjon regler () return [[['message', 'created_at', 'updated_at', 'created_by'], 'required'],

Som dette:

offentlige funksjon regler () retur [[['melding', 'created_at', 'updated_at'], 'required'],

Dette gjør at valideringen kan lykkes og fortsette til atferdene.

Vi kan også kommentere eller slette StatusControllerens laget av oppgave i opprettingsaksjonen:

offentlig funksjon actionCreate () $ model = new Status (); if ($ model-> load (Yii :: $ app-> request-> post ())) // $ model-> created_by = Yii :: $ app-> bruker-> getId ();

Når alle disse endringene er ferdige, kan vi skrive et nytt statuspost:

Og vi kan kikke inn i tabellvisningen med PHPMyAdmin og se opprettet_by og oppdatert_by innstillinger:

Logging oppdateringer til status tabellen

Når et statuspost er opprettet, vet vi alltid hvem som opprettet den første oppføringen. Men, med skyldig adferd, vet vi bare hvem som sist oppdaterte posten.

La oss gå gjennom en enkel loggimplementering for å registrere iden til personen som lager hver oppdatering. Da kan du enkelt se en oppdateringshistorikk eller utvide dette til å være en fullstendig revisjonslogg.

Opprette tabellen for StatusLog

Først må vi opprette en migrering for StatusLog:

hei Jeff $ ./yii migrere / lag create_status_log_table Yii Migreringsverktøy (basert på Yii v2.0.2) Opprett ny migrasjon '/Users/Jeff/Sites/hello/migrations/m150209_204852_create_status_log_table.php'? (ja | nei) [nei]: ja Ny migrasjon ble opprettet.

Deretter kodes vi migreringen for å inkludere relasjonsfelt for Status-tabell-ID og bruker updated_by Enger:

db-> drivernavn === 'mysql') $ tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB';  $ this-> createTable ('status status_log', ['id' => Skjema :: TYPE_PK, 'status_id' => Skjema :: TYPE_INTEGER. 'NOT NULL', 'updated_by' => Skjema :: TYPE_INTEGER. 'NOT NULL', 'created_at' => Skjema :: TYPE_INTEGER. 'NOT NULL',], $ tableOptions); $ this-> addForeignKey ('fk_status_log_id', 'status status_log', 'status_id', '% status', 'id', 'CASCADE', 'CASCADE'); $ this-> addForeignKey ('fk_status_log_updated_by', 'status status_log', 'updated_by', '% user', 'id', 'CASCADE', 'CASCADE');  offentlig funksjon ned () $ this-> dropForeignKey ('fk_status_updated_by', 'status status_log'); $ Dette-> dropForeignKey ( 'fk_status_id', '% status_log'); $ Dette-> dropColumn ( '% status_log', 'updated_by');  

Deretter kjører vi overføringen:

hei Jeff $ ./yii migrere / opp Yii Migreringsverktøy (basert på Yii v2.0.2) Totalt 1 ny migrering som skal brukes: m150209_204852_create_status_log_table Bruk overføringen ovenfor? (ja | nei) nei: ja *** bruk m150209_204852_create_status_log_table> opprett tabell % status_log ... ferdig (tid: 0.008s)> legg til utenlandsk nøkkel fk_status_log_id: % status_log (status_id) referanser  % status (id) ... ferdig (tid: 0.008s)> legg til utenlandsk nøkkel fk_status_log_updated_by: % status_log (updated_by) referanser % user (id) ... ferdig (tid: 0.008s) ** * brukt m150209_204852_create_status_log_table (tid: 0.028s) Migrert opp med hell.

Den raskeste måten å opprette en modell for StatusLog (og CRUD-filer, slik at vi enkelt kan bla gjennom bordet), er med Yii2s kodegenerator, Gii. Du har sett meg bruke den i tidligere opplæringsprogrammer.

Besøk http: // localhost: 8888 / hei / gii og opprett modellen med disse innstillingene:

Her er CRUD-innstillingene:

Deretter utvider vi AfterSave-hendelsen i Status-modellen:

offentlig funksjon afterSave ($ insert, $ changedAttributes) foreldre :: afterSave ($ insert, $ changedAttributes); // når du legger inn falsk, er opptaket oppdatert hvis (! $ insert) // legg til StatusLog oppføring $ status_log = ny StatusLog; $ status_log-> status_id = $ this-> id; $ status_log-> updated_by = $ this-> updated_by; $ status_log-> created_at = time (); $ Status_log-> Lagre (); 

Denne metoden kaller standard foreldrefunksjonalitet for afterSave men så oppretter en ny StatusLog-oppføring når det er en oppdatering til en statusrad:

Teoretisk sett kan vi også utvide BlameableBehavior, men siden du må sørge for at det finnes en loggmodell for hver ActiveRecord-modell du bruker den med, virket det lettere å bygge denne funksjonaliteten i Status.

Hvis du oppdaterer et par statusoppføringer, kan du bla gjennom StatusLog ved hjelp av Giis CRUD. Bildet nedenfor viser to endringer gjort av Status.id 1.

Hvis du vil gå videre, bør det være relativt grei å utvide dette til en revisjonstabell som er komplett med forrige og nye statustekst for å støtte tilbakevendingsfunksjonalitet.

Hva blir det neste?

Jeg håper du har likt å lære om Yii2 Behaviors og Blameable. Deretter vil vi undersøke Timestamp Behaviors, som reduserer mengden kode du trenger å skrive med hver ny modell for den felles driften av å lage tidsstempler for innlegg og oppdateringer.

Se etter kommende opplæringsprogrammer i min programmering med Yii2-serien når jeg fortsetter å dykke inn i ulike aspekter av rammen. Du vil kanskje også sjekke ut Bygg opp din oppstart med PHP-serien som bruker Yii2s avanserte mal når jeg bygger en ekte verdensapplikasjon.

Jeg aksepterer funksjon og emneforespørsler. Du kan legge inn dem i kommentarene under eller sende meg en e-post på Lookahead Consulting.

Hvis du vil vite når neste Yii2 opplæring kommer, følg meg @ reifman på Twitter eller sjekk min instruktørside. Min instruktørside vil inkludere alle artiklene fra denne serien så snart de er publisert. 

Relaterte linker

  • Den Yii2 Definitive Guide: Behaviors
  • Yii2 Dokumentasjon: Skyldig oppførsel
  • Yii2 Developer Exchange, mitt eget Yii2 ressursområde