Cum să programați cu Yii2 Comportamente nevinovate

Ce veți crea

Dacă vă întrebați: "Ce este Yii?" verificați tutorialul meu anterior: Introducere în Cadrul Yii, care analizează beneficiile Yii și include o prezentare generală a ceea ce este nou în Yii 2.0, lansat în octombrie 2014.

În această serie de programare cu seria Yii2, îndrumăm cititorii în folosirea noii tehnologii Yii2 Framework for PHP. În acest tutorial, vă vom îndruma către un alt comportament interesant al lui Yii2: ajuta la automatizarea sarcinii comune de dezvoltare web de atribuire creată și actualizată de user_ids pe modelele aplicației dvs. web utilizând codificarea DRY și Yii2 BlameableBehavior. De asemenea, vom crea un jurnal care înregistrează cei care au actualizat tabelul de stare pentru fiecare schimbare făcută.

Pentru aceste exemple, vom continua să ne imaginăm că construim un cadru pentru afișarea actualizărilor de stare simple, de ex. propriul mini-Twitter.

Doar un memento, eu particip la comentariile de mai jos. Sunt interesat în special dacă aveți abordări diferite, idei suplimentare sau doriți să sugerați subiecte pentru tutoriale viitoare.

Ce este o comportament?

Comportamentele Yii2 sunt, în esență, amestecuri. Wikipedia descrie mixurile ca fiind "o clasă care conține o combinație de metode din alte clase. Cum se face o astfel de combinație depinde de limbă, dar nu de moștenire".

Yii le descrie astfel:

Atașarea unui comportament la o componentă "injectă" metodele și proprietățile comportamentului în componentă, făcând acele metode și proprietăți accesibile ca și când ar fi fost definite în clasa componentelor.

Yii2 oferă mai multe comportamente încorporate, dintre care majoritatea vom fi documentare, printre care se numără și programele (consultați Programarea cu Yii2: comportament slujitor), blameable și timestamp (viitoare, verificați pagina seriei). Comportamentele sunt o modalitate ușoară de a reutiliza codul comun pe multe dintre modelele dvs. de date fără a trebui să repetați codul în multe locuri. Injectarea unui comportament într-un model poate fi făcută adesea doar cu două linii de cod. Pe măsură ce numărul de modele din aplicația dvs. crește, comportamentele devin din ce în ce mai utile.

Care este comportamentul nevinovat ?.?

Raportarea neconfirmată ne face ușor să implementăm sarcina frecvent necesară de alocare a utilizatorului curent înregistrat la inserții și actualizări într-un model ActiveRecord, setând automat proprietățile pentru creat de și updated_by.

În programarea cu Yii2: autorizare Cu filtrul de control al accesului, am implementat propriul nostru comportament blameabil în două părți. Mai întâi, am creat o migrare pentru a adăuga o creat de câmp tabelul nostru de stare:

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

În al doilea rând, i-am atribuit creat de câmp la curent numele de utilizator în acțiunea de creare a StatusController:

funcția publică funcțiaCreate () $ model = new Status (); dacă ($ model-> încărcați (Yii :: $ app-> request-> post ())) $ model-> create_by = Yii :: $ app-> user-> getId ();

Implementarea comportamentului Blameable va face acest lucru automat pentru noi și poate fi ușor adăugat la toate modelele ActiveRecord dintr-o aplicație web.

Punerea în aplicare a comportamentului nevinovat în modelul de stare

Extinderea tabelului de stare

În primul rând, trebuie să extinem tabela de stare cu o migrare încă o dată pentru a accepta o updated_by camp.

Jeff $ ./yii migrați / creați extens_status_table_for_updated_by Instrumentul de migrare Yii (bazat pe Yii v2.0.2) Creați noua migrare '/Users/Jeff/Sites/hello/migrations/m150209_200619_extend_status_table_for_updated_by.php'? (da | nu) [no]: da Migrația nouă a fost creată cu succes.

Iată codul de migrare pe care îl vom folosi:

db-> driverName === 'mysql') $ tableOptions = 'SETAREA CHARACTERULUI 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 ');  funcția publică jos () $ this-> dropForeignKey ('fk_status_updated_by', '% status'); $ This-> dropColumn ( 'status%' 'updated_by');  

Dacă încercați să rulați această migrare cu datele existente în baza de date, veți primi o eroare la încercarea de a crea indexul cheii străine, deoarece updated_by este 0 și nu există în tabelul de utilizatori. 

hello Jeff $ ./yii migrați / up Instrumentul de migrare Yii (bazat pe Yii v2.0.2) Total 1 migrare nouă care va fi aplicată: m150209_200619_extend_status_table_for_updated_by Aplicați migrarea de mai sus? (da | nu) [nu]: da *** aplicând m150209_200619_extend_status_table_for_updated_by> adăugați coloană actualizată_în integer NOT NULL la tabel status ... făcut (timp: 0,042s)> adăugați cheie străină fk_status_updated_by: % status (update_by) referințe % user (id) ... Excepție "yii \ db \ IntegrityException" cu mesajul "SQLSTATE [23000]: violarea constrângerii de integritate: 1452 Nu se poate adăuga sau actualiza un rând copil: salut '.' # sql-22f_1d0 ', CONSTRAINT' fk_status_updated_by 'FOREIGN KEY (' update_by ') REFERINȚE' user '(' id ') ON DELETE CASCADE ON UPCATE CASCADE) SQL a fost: ALTER TABLE' status 'ADD CONSTRAINT 'fk_status_updated_by' FOREIGN KEY ('updated_by') REFERINȚE 'user' ('id') pe DELETE CASCADE LA UPCATE CASCADE 'în /Users/Jeff/Sites/hello/vendor/yiisoft/yii2/db/Schema.php:532 Eroare Info: Array ([0] => 23000 [1] => 1452 [2] => Nu se poate adăuga sau actualiza un rând copil: o constrângere chei străine eșuează (' Fore IGN KEY ('updated_by') REFERINȚE 'user' ('id') la DELETE CASCADE ON UPCATE CASCADE)) 

Am putea face acest lucru prin actualizarea manuală a datelor în migrare și apoi prin adăugarea unei chei străine. Cu toate acestea, deoarece aceasta este o platformă de testare, este mai ușor să migrați în jos în trei pași - să abandonați tabelul de stare și datele de testare - și apoi să migrați din nou:

hello Jeff $ ./yii migrați / down 3 Instrument de migrare Yii (bazat pe Yii v2.0.2) Total 3 migrații care urmează să fie returnate: m150128_233458_extend_status_table_for_slugs m150128_003709_extend_status_table_for_created_by m141201_013120_create_status_table Reveniți la migrațiile de mai sus? (da: nu): nu *** reverting m150128_233458_extend_status_table_for_slugs> mutați coloana din tabel % status ... făcut (timpul: 0.009s) *** reverted m150128_233458_extend_status_table_for_slugs *** reverting m150128_003709_extend_status_table_for_created_by> aruncați o cheie străină fk_status_created_by din tabelul % status ... done (time: 0.010s)> drop column created_by din tabelul status status done (time: 0.008s) *** reversed m150128_003709_extend_status_table_for_created_by 0.019s) *** revenire m141201_013120_create_status_table> drop table % status ... făcut (timpul: 0.001s) *** reverted m141201_013120_create_status_table (timpul: 0.002s) Migrate cu succes. hello Jeff $ ./yii Migrație / sus 4 Instrument de migrare Yii (bazat pe Yii v2.0.2) Total 4 noi migrații care trebuie aplicate: 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 Aplicați migrațiile de mai sus? (da: nu): da *** aplicarea m141201_013120_create_status_table> crea tabelul % status ... făcut (timpul: 0.007s) *** aplicat m141201_013120_create_status_table (time: 0.010s) *** aplicând m150128_003709_extend_status_table_for_created_by> add (time%: 0.007s)> adăugați cheia străină fk_status_created_by: % status (created_by) referințe user user (id) ... done : 0.008s) *** aplicat m150128_003709_extend_status_table_for_created_by (timpul: 0.016s) *** aplicarea m150128_233458_extend_status_table_for_slugs> adauga coloana de sir de coloane NULL la tabelul status status ... done (time: 0.007s) *** aplicat m150128_233458_extend_status_table_for_slugs : 0.008s) *** aplicând m150209_200619_extend_status_table_for_updated_by> adăugați coloană updated_by integer NOT NULL la tabel status status ... done (time: 0.007s)> adăugați cheie străină fk_status_updated_by: status % user (id) ... făcut (timpul: 0.007s) *** aplicat m 150209_200619_extend_status_table_for_updated_by (timpul: 0.015s) Migrată cu succes.

Adăugarea comportamentului Blameable la modelul de stare

Apoi, vom atașa modulul BlameableBehavior la modelul nostru de stare. În modelele / Status.php adăugăm comportamentul Blameable after compliant:

class Status se extinde \ yii \ db \ ActiveRecord const PERMISSIONS_PRIVATE = 10; const PERMISSIONS_PUBLIC = 20; funcția publică "() return '[' class '=> SluggableBehavior :: className (),' attribute '=>' message ',' immutable '=> true, => BlameableBehavior :: clasaName (), 'createdByAttribute' => 'created_by', 'updatedByAttribute' => 'updated_by',],]; 

De asemenea, trebuie să includem comportamentul Blameable în partea de sus a modelului nostru:

Apoi, eliminăm regula necesară creat de în regulile modelului:

reguli de funcționare publică () return [[['message', 'created_at', 'updated_at', 'created_by'], 'required'],

Asa:

reguli de funcționare publică () return [[['message', 'created_at', 'updated_at'], 'required'],

Acest lucru permite validarea pentru a reuși și continuarea comportamentelor.

De asemenea, putem să comentăm sau să ștergem StatusController-ul creat de cesiune în acțiunea de creare:

funcția publică funcțiaCreate () $ model = new Status (); dacă ($ model-> încărcați (Yii :: $ app-> request-> post ())) // $ model-> create_by = Yii :: $ app-> user-> getId ();

Odată ce toate aceste modificări sunt complete, putem scrie un nou post de stare:

Și putem să aruncăm o privire asupra tabelului cu PHPMyAdmin și să vedem setările create_by și updated_by:

Înregistrează actualizări la tabela de stare

Când se creează o postare de stare, vom ști întotdeauna cine a creat prima intrare. Dar, cu comportamente nevinovate, vom ști doar cine a actualizat ultima dată înregistrarea.

Să mergem printr-o implementare simplă a jurnalului pentru a înregistra id-ul persoanei care face fiecare actualizare. Apoi, ați putea vedea cu ușurință un istoric al updaters sau extindeți acest lucru pentru a fi un jurnal complet de revizie.

Crearea tabelului pentru StatusLog

În primul rând, trebuie să creăm o migrare pentru statuslog:

hello Jeff $ ./yii migrați / creați create_status_log_table Instrumentul de migrare Yii (bazat pe Yii v2.0.2) Creați noua migrare '/Users/Jeff/Sites/hello/migrations/m150209_204852_create_status_log_table.php'? (da | nu) [no]: da Migrația nouă a fost creată cu succes.

Apoi, codificăm migrarea pentru a include câmpurile relaționale pentru ID-ul tabelului Stare și Utilizator updated_by câmpuri:

db-> driverName === 'mysql') $ tableOptions = 'SETAREA CHARACTERULUI utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB';  $ this-> createTable ('% status_log', ['id' => Schema :: TYPE_PK, 'status_id' => Schema :: TYPE_INTEGER. 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');  funcția publică jos () $ this-> dropForeignKey ('fk_status_updated_by', '% status_log'); $ This-> dropForeignKey ( 'fk_status_id', '% status_log'); $ This-> dropColumn ( '% status_log' 'updated_by');  

Apoi, rulați migrația:

hello Jeff $ ./yii Migrați / up Yii Instrumentul de migrare (bazat pe Yii v2.0.2) Se va aplica o nouă migrare totală: m150209_204852_create_status_log_table Aplicați migrarea de mai sus? (da: nu): da *** aplicând m150209_204852_create_status_log_table> creați tabelul % status_log ... făcut (timpul: 0.008s)> adăugați cheia străină fk_status_log_id: status_log (time%: 0.008s) adăugați cheia străină fk_status_log_updated_by: % status_log (updated_by) referințe user (id) * aplicat m150209_204852_create_status_log_table (timpul: 0.028s) Migrați cu succes.

Cea mai rapidă modalitate de a crea un model pentru StatusLog (și fișierele CRUD pentru a putea naviga cu ușurință în tabel) este cu generatorul de cod Yii2, Gii. M-ai văzut folosindu-mă în tutorialele anterioare.

Vizitați http: // localhost: 8888 / hello / gii și creați modelul cu următoarele setări:

Iată setările CRUD:

Apoi, extindem evenimentul AfterSave în modelul Status:

funcția publică după Setați ($ insert, $ changedAttributes) părinte :: după Salvează ($ insert, $ changedAttributes); // când se introduce false, atunci înregistrarea a fost actualizată dacă (! $ insert) // adăugați intrarea StatusLog $ status_log = new StatusLog; $ status_log-> status_id = $ acest-> id; $ status_log-> updated_by = $ this-> updated_by; $ status_log-> created_at = timp (); $ Status_log-> Salvare (); 

Această metodă numește funcția părinte implicită pentru afterSave dar apoi creează o nouă intrare StatusLog ori de câte ori există o actualizare a unui rând Status:

Teoretic, am putea extinde și BlameableBehavior, dar din moment ce trebuie să vă asigurați că există un model de jurnal pentru fiecare model ActiveRecord pe care îl utilizați, părea mai ușor să construiți această funcționalitate în Status.

Dacă actualizați câteva înregistrări de stare, puteți naviga în StatusLog folosind GUD's CRUD. Imaginea de mai jos arată două modificări efectuate de Status.id 1.

Dacă doriți să mergeți mai departe, ar trebui să fie relativ simplu să extindeți acest lucru la o tabelă de revizuire completată cu textul anterior și noul statut pentru a suporta funcționalitatea de revizuire.

Ce urmeaza?

Sper că te-ai bucurat de învățare despre comportamentele Yii2 și Blameable. Apoi, vom explora comportamentele Timestamp, care reduc cantitatea de cod de care aveți nevoie pentru a scrie cu fiecare nou model pentru operațiunea comună de creare a timestampurilor pentru inserții și actualizări.

Urmăriți tutorialele viitoare din programul meu de programare cu seria Yii2, deoarece continuam să scufundăm în diferite aspecte ale cadrului. Ați putea dori, de asemenea, să verificați clădirea dvs. Startup cu seria PHP care utilizează șablonul avansat al lui Yii2, pe măsură ce construiesc o aplicație din lumea reală.

Salut cererile de teme și teme. Puteți să le postați în comentariile de mai jos sau puteți să ne trimiteți un e-mail pe site-ul meu Lookahead Consulting.

Dacă doriți să știți când vine următorul tutorial Yii2, urmați-mă @reifman pe Twitter sau verificați pagina de instructor. Pagina mea de instructor va include toate articolele din această serie de îndată ce vor fi publicate. 

Link-uri conexe

  • Ghidul definitiv Yii2: comportamente
  • Documentația Yii2: comportament necuvenit
  • Yii2 Developer Exchange, propriul site de resurse Yii2
Cod