În această lecție, vom crea o bibliotecă CodeIgniter care ne permite să generăm grile de date în mod automat pentru gestionarea oricărei tabele de baze de date. Voi explica fiecare pas necesar pentru a crea această clasă; astfel încât probabil veți învăța câteva noi tehnici / concepte OOP în acest proces!
Ca bonus, vom continua să scriem un cod jQuery care va permite unui utilizator să actualizeze conținutul rețelei de date fără a trebui să aștepte o reîmprospătare a paginii.
Acest tutorial presupune că aveți o înțelegere modestă a cadrelor CodeIgniter și jQuery.
O datagrid este un tabel care afișează conținutul unei baze de date sau al unei tabele împreună cu comenzile de sortare.
O datagrid este un tabel care afișează conținutul unei baze de date sau al unei tabele împreună cu comenzile de sortare. În acest tutorial, vom fi însărcinați să furnizăm această funcționalitate, dar și să salvăm utilizatorul de la așteptarea refresh a paginii de fiecare dată când se efectuează o operație. Datorită jQuery, aceasta va fi o sarcină destul de simplă!
Cum rămâne cu utilizatorii care nu au activat Javascript? Nu vă faceți griji, le vom compensa și ele!
Vrem să construim un instrument care să ne permită să creăm în mod dinamic datagrame pentru orice tabel de baze de date pe care îl avem. Aceasta înseamnă că codul nu este legat de nicio structură de tabelă specifică și, prin urmare, este independent de datele în sine. Tot coderul (dezvoltatorul care folosește clasa noastră) trebuie să știe este numele tabelului care urmează să fie transformat într-o rețea și cheia primară pentru acel tabel. Iată prefața clasei pe care o vom dezvolta pentru cea mai mare parte a acestui tutorial:
Clasa Datagrid ar putea fi adăugată în folderul aplicație / bibliotecă, dar o vom adăuga ca ajutor în cadrul CodeIgniter. De ce? Deoarece bibliotecile de încărcare nu ne permit să transmitem argumente constructorului de clasă, încărcarea acestuia ca ajutor va rezolva problema. Acest punct va avea mai mult sens atunci când am terminat de scris constructorul.
funcția publică __construct ($ tbl_name, $ pk_col = 'id') $ aceasta-> CI = & get_instance (); $ This-> CI-> a sarcinii> baze de date (); $ this-> tbl_fields = $ acest-> CI-> db-> list_fields ($ tbl_name); dacă ! in_array ($ pk_col, $ this-> tbl_fields)) aruncați o nouă excepție ("coloana primară" $ pk_col "nu este găsită în tabelul" $ tbl_name ""); $ this-> tbl_name = $ tbl_name; $ this-> pk_col = $ pk_col; $ This-> CI-> a sarcinii> bibliotecă ( 'tabel');
Mai avem multe de făcut; dar nu vă faceți griji, pentru că vă voi explica totul în paragraful următor.
Constructorul are două argumente: primul fiind numele tabelului din baza de date pe care doriți să îl afișați ca datagrid utilizatorului; al doilea param este numele coloanei care servește drept cheie primară pentru acel tabel (mai târziu, mai târziu). În interiorul corpului constructorului, instanțiăm Obiectul CodeIgniter, Obiectul bazei de date și clasa / biblioteca din tabela HTML. Toate acestea vor fi necesare pe tot parcursul vieții unui obiect Datagrid și sunt deja construite în cadrul CI. Rețineți că verificăm, de asemenea, dacă cheia primară există într-adevăr în tabelul dat și, în caz că nu, vom arunca o excepție de raportare a erorii. Acum $ This-> tbl_fields
membră variabilă va fi disponibilă pentru utilizare ulterioară, deci nu trebuie să preluăm din nou baza de date.
Putem folosi comanda,
$ CI->> list_fields DB ($ tbl_name)
pentru a prelua numele tuturor câmpurilor care au un tabel. Cu toate acestea, pentru o performanță mai bună, vă recomandăm memorarea rezultatelor. "
funcții publice setHeadings (array $ headings) $ this-> headings = array_merge ($ this-> titluri, $ titluri);
Acest lucru vă permite să personalizați rubricile tabelului de grilă de date - adică, cu acesta, puteți suprascrie numele coloanelor originale pentru anumite câmpuri de tabelă. Este nevoie de o asociație mulțime
, astfel: regdate => "Data de înregistrare". În loc de "Regdate" tehnic ca coloană pentru acest tip de date, avem un titlu mai ușor de citit de om în locul său. Codul responsabil pentru aplicarea rubricilor va fi dezvăluit în scurt timp.
funcția publică ignoreFields (câmpurile array $) foreach (câmpurile $ ca $ f) if ($ f! = $ this-> pk_col) $ this-> hide_cols [] = $ f;
ignoreFields
primește un mulțime
conținând câmpurile care trebuie ignorate la preluarea datelor din baza de date. Acest lucru este util atunci când avem mese cu multe câmpuri, dar noi doar dorim să ascundem câteva dintre ele. Această metodă este suficient de inteligentă pentru a urmări o încercare de a ignora câmpul cheie primară și apoi să o ignorați. Acest lucru se datorează faptului că cheia primară nu poti fi ignorată din motive tehnice (veți vedea de ce în curând). Totuși, dacă doriți să ascundeți coloana cheii primare de la apariția în interfața de utilizare, puteți utiliza funcția hidePkCol
metodă:
funcția publică hidePkCol ($ bool) $ this-> hide_pk_col = (bool) $ bool;
Această metodă primește o valoare booleană pentru a indica dacă vrem să ascundem coloana cheii primare, astfel încât să nu apară în grila de date. Uneori, este o idee urâtă de a afișa pkey
date, care este, de obicei, un cod numeric fără nici o semnificație pentru utilizator.
Metoda următoarei instanțe:
funcția privată _selectFields () foreach ($ this-> tbl_fields ca câmp $) if (! in_array ($ field, $ this-> hide_cols)) $ acest-> CI-> db-> select (câmp $); // ascundeți rubrica coloanei pk? dacă ($ field == $ this-> pk_col && $ this-> hide_pk_col) continuați; $ headings [] = isset ($ this-> titluri [$ field])? $ this-> titluri [câmpul $]: ucfirst (câmpul $); dacă (! empty ($ headings)) // prefixați o casetă de selectare pentru comutarea array_unshift ($ headings, ""); $ this-> CI-> table-> set_heading ($ titluri);
Aici avem o metodă de ajutor; de aceea are modificatorul "privat" și este prefixat cu un caracter subliniere (convenție de cod). Acesta va fi utilizat de către Genera()
metodă - explicată în scurt timp - pentru a selecta câmpurile de tabele corespunzătoare și, de asemenea, rubricile corespunzătoare setate la tabel (generator) obiect
. Observați următoarea linie:
$ headings [] = isset ($ this-> titluri [$ field])? $ this-> titluri [câmpul $]: ucfirst (câmpul $);
Aici aplicăm anteturile personalizate sau le folosim pe cele implicite dacă nu este specificat nici unul. În cazul în care pk
coloana se presupune a fi ascunsă de la afișare, atunci se va anula rubrica. De asemenea, observați următorul rând:
array_unshift (rubricile $,“„);
Comanda de mai sus instruiește programul să prefixeze o casetă de selectare "Master" ca prima poziție a tabelului. Această casetă de selectare este diferită de alte casete de selectare din rețea, deoarece permite unui utilizator să verifice sau să debifeze toate casetele de selectare într-o singură etapă. Această funcție de comutare va fi implementată în câteva momente cu un fragment simplu de cod jQuery.
Acum vine lucrul care face lucrul real pentru noi:
funcția publică genera () $ this -> _ selectFields (); $ rows = $ this-> CI-> db -> de la ($ this-> tbl_name) -> get () -> result_array (); foreach ($ rânduri ca & $ rând) $ id = $ row [$ this-> pk_col]; // prefixați o casetă de selectare pentru a permite selectarea elementelor / rândurilor array_unshift ($ row, ""); // ascunde pk coloana celula? daca ($ this-> hide_pk_col) unset ($ row [$ this-> pk_col]); return $ this-> CI-> table-> generate ($ rows) ;
Genera
metoda, așa cum sugerează și numele, este responsabilă de generarea rețelei de date. Trebuie să apelați această metodă numai după ce ați configurat obiectul în funcție de nevoile dvs. Primul lucru pe care îl face este să sunați $ This -> _ selectFields ()
pentru a efectua acțiunile pe care le-am explicat mai devreme. Acum trebuie să preiau toate rândurile din baza de date și apoi să treacă prin ele, adăugând casete de bifare la începutul fiecărui rând:
// prefixați o casetă de selectare pentru a permite selectarea elementelor / rândurilor array_unshift ($ row, "„);
În interiorul pentru fiecare
buclă pe Genera
metoda, în cazul în care $ This-> hide_pk_col
steagul este setat la Adevărat
, atunci trebuie să dezactivați intrarea cheii primare în $ row array
așa că nu va apărea ca o coloană atunci când $ This-> CI-> tabel
obiect
procesează toate rândurile și generează outputul final html. În acest moment, este bine să eliminați cheia primară, dacă este necesar, deoarece nu mai avem nevoie de aceste informații. A
Dar ce face utilizatorul cu rândurile selectate / verificate? Pentru a răspunde la aceasta, am pregătit câteva metode. Primul ne permite să creăm "butoane de acțiune" fără a fi nevoie să cunoaștem detalii tehnice despre funcționarea sistemului de rețea:
funcția statică publică createButton ($ action_name, $ label) return "";
Pur și simplu treceți numele acțiunii ca primul argument și al doilea argument pentru a indica eticheta pentru butonul generat. A clasă
atributul este generat automat pentru butonul respectiv, astfel încât să putem juca cu el mai ușor atunci când lucrăm cu el în JavaScript. Dar, de unde știm dacă un anumit buton de acțiune a fost apăsat de utilizator? Răspunsul poate fi găsit în următoarea metodă:
funcția publică statică getPostAction () // obține numele acțiunii depuse (dacă există) dacă (isset ($ _ POST ['dg_action'])) cheia de întoarcere ($ _ POST ['dg_action']);
Da! O altă metodă statică care ne ajută atunci când avem de-a face cu formulare. Dacă a fost trimisă o rețea de date, această metodă va returna numele acțiunii (sau "operațiunii") asociată evenimentului de trimitere. În plus, un alt instrument util pentru prelucrarea formularelor noastre de dateagrid este?
funcția statică publică getPostItems () if (! empty ($ _ POST ['dg_item'])) retur $ _POST ['dg_item']; matrice retur ();
? care returnează un mulțime
conținând selectat id-uri
astfel încât să puteți urmări care rânduri au fost selectate pe grila și apoi să efectuați unele acțiuni cu ele. Ca un exemplu de ceea ce se poate face cu o selecție de rând id
s, am pregătit o altă metodă - aceasta fiind o metodă de instanță și nu o metodă statică, deoarece folosește resursele instanței obiectului pentru a-și desfășura activitatea:
funcția publică deletePostSelection () // elimina elementele selectate din db if (! empty ($ _ POST ['dg_item'])) return $ this-> CI-> db -> din ($ this-> tbl_name) ($ acest-> pk_col, $ _ POST ['dg_item']) -> șterge ();
Dacă a fost bifată cel puțin o casetă de selectare, deletePostSelection ()
metoda va genera și executa o instrucțiune SQL ca următoarea (să presupunem $ Tbl_name = 'my_table'
și $ Pk_col = 'id'
):
Șterge din my_table WHERE id IN (1,5,7,3, etc?)
? care va elimina efectiv rândurile selectate din stratul persistent. S-ar putea să existe mai multe operațiuni pe care le puteți adăuga la o rețea de date, dar aceasta va depinde de specificul proiectului dumneavoastră. Ca un sfat, puteți extinde această clasă la, să zicem, InboxDatagrid
, deci, dincolo de deletePostSelection
, ar putea include operațiuni suplimentare, cum ar fi moveSelectedMessagesTo (locul $)
, etc?
Acum, dacă ați urmat acest tutorial pas cu pas, ar fi trebuit să fi ajuns cu ceva similar cu următorul:
clasa Datagrid private $ hide_pk_col = true; privat $ hide_cols = array (); privat $ tbl_name = "; privat $ pk_col ="; titluri private $ $ = array (); privat $ tbl_fields = array (); funcția __construct ($ tbl_name, $ pk_col = 'id') $ aceasta-> CI = & get_instance (); $ This-> CI-> a sarcinii> baze de date (); $ this-> tbl_fields = $ acest-> CI-> db-> list_fields ($ tbl_name); dacă ! in_array ($ pk_col, $ this-> tbl_fields)) aruncați o nouă excepție ("coloana primară" $ pk_col "nu este găsită în tabelul" $ tbl_name ""); $ this-> tbl_name = $ tbl_name; $ this-> pk_col = $ pk_col; $ This-> CI-> a sarcinii> bibliotecă ( 'tabel'); funcții publice setHeadings (array $ headings) $ this-> headings = array_merge ($ this-> titluri, $ titluri); funcția publică hidePkCol ($ bool) $ this-> hide_pk_col = (bool) $ bool; funcția publică ignoreFields (array $ fields) foreach (câmpuri $ ca $ f) if ($ f! = $ this-> pk_col) $ this-> hide_cols [] = $ f; funcția privată _selectFields () foreach ($ this-> tbl_fields ca câmp $) if (! in_array ($ field, $ this-> hide_cols)) $ this-> CI-> db-> select ); // ascundeți rubrica coloanei pk? dacă ($ field == $ this-> pk_col && $ this-> hide_pk_col) continuați; $ headings [] = isset ($ this-> titluri [$ field])? $ this-> titluri [câmpul $]: ucfirst (câmpul $); dacă (! empty ($ headings)) // prefixați o casetă de selectare pentru comutarea array_unshift ($ headings, ""); $ this-> CI-> table-> set_heading ($ headings); funcția publică genera () $ this -> _ selectFields $ this-> tbl_name) -> get () -> result_array (); foreach ($ rânduri ca & $ row) $ id = $ row [$ this-> pk_col]; array_unshift ($ row, ""); // ascunde coloana pk; dacă ($ this-> hide_pk_col) unset ($ row [$ this-> pk_col]); return $ this-> CI-> table-> generate ($ rows); funcția publică statică createButton ($ action_name, $ label) return ""; funcția statică publică getPostAction () // obține numele acțiunii depuse (dacă există) dacă (isset ($ _ POST ['dg_action'])) cheia de întoarcere ($ _ POST ['dg_action' static function getPostItems () if (! empty $ _ POST ['dg_item'])) return $ _POST ['dg_item']; db if ($ this-> tbl_name) -> where_in ($ this-> pk_col, $ _ POST ['dg_item']) ]) -> șterge ();
Notă: Nu uitați să salvați acest fișier ca datagrid_helper.php
, și plasați-o în "aplicație / ajutor /"
Acum vom crea un controler de testare simplu și vom încărca clasa Datagrid ca ajutor în constructorul său. Dar înainte de aceasta, ar trebui să definim o tabelă de bază de date falsă și să o populam cu unele date de probă.
Executați următorul SQL pentru a crea baza de date și tabela de utilizatori:
CREAȚI DATABASE "dg_test"; CREATE TABLE "utilizatori" ('id' int (11) NU NULL AUTO_INCREMENT, 'username' varchar (80) NOT NULL, 'parola' varchar (32) id '(' id ')) MOTOR = MyISAM DEFAULT CHARSET = latin1 AUTO_INCREMENT = 5;
Apoi, să adăugăm unii utilizatori la acesta:
INSERT IN 'utilizatori' ('id', 'username', 'parola', 'email') VALUES (1, 'david', '12345', '[email protected]' (3, 'alejandro', 'a42352fawet', '[email protected]'), (4, 'emma', 'f22a3455b2','[email protected] ' „);
Acum, salvați următorul cod ca "test.php
,"și adăugați-l la dosarul" aplicație / controlori ":
a sarcinii> helper (array ( 'datagrid', 'url')); $ this-> Datagrid = Datagrid nou ("utilizatori", "id"); indexul funcției () $ this-> load-> helper ('form'); $ This-> a sarcinii> bibliotecă ( 'sesiune'); $ This-> Datagrid-> hidePkCol (true); $ This-> Datagrid-> setHeadings (array ( 'email' => 'E-mail')); $ This-> Datagrid-> ignoreFields (array ( 'parola')); dacă ($ error = $ this-> session-> flashdata ('form_error')) echo "$ eroare"echo $ formate_open ('test / proc'); echo $ this-> Datagrid-> generate (); echo form_close (); func proc ($) request_type = ") $ this-> load-> helper (" url "); dacă ($ action = Datagrid :: getPostAction ()) $ error = ""; comutare ($ action) case 'delete': if (! $ this-> Datagrid-> deletePostSelection ()) $ error = 'Elementele nu pot fi șterse'; pauză; dacă ($ request_type! = 'ajax') $ this-> load-> library ('session'); $ This-> Session-> set_flashdata ( 'form_error', $ eroare); redirecționa ( 'test / index'); altceva echo json_encode (array ('error' => $ error)); altceva die ("Cerere rea"); ?>
O instanță a acestei clase este creată și transmisă ca referință la $ This-> Datagrid
membru. Observați că vom prelua datele dintr-o tabelă numită "utilizatori" a cărei cheie primară este coloana "id"; apoi, pe metoda indexului, luăm următorii pași: configurați obiectul Datagrid, redați-l într-un formular cu un buton de ștergere adăugat la acesta și vedeți dacă totul funcționează așa cum era de așteptat:
Răspuns: ""Testul :: proc ()
"metoda se ocupă de prelucrarea formularului și de alegerea operațiunii potrivite pentru a aplica împotriva id
uri care au fost selectate de către expeditorul formularului. De asemenea, acesta are grijă de solicitările AJAX, astfel încât va repeta un obiect JSON înapoi la client. Această caracteristică AJAX-aware va fi utilă când jQuery va intra în acțiune, ceea ce este chiar acum!
"Este întotdeauna o idee inteligentă de a crea aplicații web care să compenseze când JavaScript / AJAX nu este disponibil. Astfel, unii utilizatori vor avea o experiență mai bogată și mai rapidă, în timp ce cei fără JavaScript activat vor putea să utilizeze aplicația în mod normal."
Când utilizatorul face clic pe butonul (sau orice alt buton de acțiune), ne-ar plăcea, probabil, să împiedicăm reîncărcarea paginii și să trebuiască să generăm totul din nou; acest lucru ar putea face ca utilizatorul aplicației noastre să adoarmă! Circumvarea acestei probleme nu va fi o sarcină dificilă dacă rămânem la biblioteca jQuery. Din moment ce nu este un tutorial "începători", nu voi trece prin toate detaliile legate de cum să ajung la bibliotecă, cum să o includ pe pagină etc. Se așteaptă să știi acești pași pe cont propriu.
Creați un dosar, numit "js
", adăugați biblioteca jQuery și creați un fișier de vizualizare numit users.php
. Deschideți acest fișier nou și adăugați:
Managementul utilizatorilor Datagrid-> hidePkCol (true); dacă ($ error = $ this-> session-> flashdata ('form_error')) echo "$ eroare"echo form_open ('test / proc', array ('class' => 'dg_form')); echo $ this-> Datagrid-> generate (); echo Datagrid :: createButton ); echo form_close ();?>
Ți-ai dat seama că am eliminat codul Testul :: indicele
și în noul script de vizualizare? Aceasta înseamnă că trebuie să schimbăm Test de :: Index ()
în consecință:
indexul funcției () $ this-> load-> helper ('form'); $ This-> a sarcinii> bibliotecă ( 'sesiune'); $ This->> vedere (a sarcinii 'utilizatori');
Asa e mai bine. Dacă doriți să adăugați un anumit stil în rețea, puteți utiliza următorul CSS (sau să faceți un aspect mai bun pe cont propriu):
.dg_form table border: 1px solid silver; .dg_form th culoare-fundal: gri; font-family: "Courier New", curier, mono; font-size: 12px; .dg_form td fundal-culoare: gainsboro; font-size: 12px; .dg_form introducere [type = submit] margin-top: 2px;
Acum, vă rugăm, creați un fișier "datagrid.js", puneți-l în directorul "js" și începeți cu acest cod:
$ (functie () // chestii interesante aici?)
În cadrul acestei închideri, vom scrie codul care va fi însărcinat cu controlul anumitor evenimente de prezentare odată ce pagina a fost complet încărcată. Primul lucru pe care trebuie să-l facem este urmărirea atunci când un utilizator face clic pe un buton de trimitere pe formularul de grilă de date și apoi trimite acele date care urmează să fie procesate pe server.
$ (this) .attr (') ($) ($) ($) ($) class ") înlocuiește (" dg_action_ "," "); var action_control = $ ('„); $ Form.append (action_control); var post_data = $ form.serialize (); action_control.remove (); var script = $ form.attr ('acțiune') + '/ ajax'; $ .post (script, post_data, function (resp) if (resp.error) alert (resp.error); alt comutare (action_name) case 'delete': // remove ruturi șterse din formularul $ grid .find ('.dg_check_item: checked') parintii ('tr') remove (); break; case 'anotherAction': // a face altceva;
Alternativ, am fi putut începe cu ceva de genul: $ ('. dg_form') trimite (funcția (e) ?)
. Cu toate acestea, deoarece vreau să urmăresc ce buton a fost apăsat și să extragă numele acțiunii alese pe baza acesteia, prefer să leagă un handler de evenimente la butonul de trimitere în sine și apoi să meargă până la ierarhia nodurilor pentru a găsi forma care butonul apăsat aparține:
// găsește formatul var $ form = $ (this) .parents ('form'); // extrage numele acțiunii var action_name = $ (this) .attr ('class') înlocuiește ("dg_action_", "");
Apoi, adăugăm un element de intrare ascuns în elementul de formă pentru a indica ce acțiune este trimisă:
// crea intrarea ascunsă var action_control = $ ('„); // adăugați la formularul $ form.append (action_control);
Acest lucru este necesar deoarece funcția nu consideră că butonul de trimitere este o intrare validă a formularului. Deci trebuie să avem acea hack în loc când serializăm datele formularului.
action_control.remove ();
"Nu uitați: funcția ignoră butonul de trimitere, respingând-o ca pe o altă piesă de marcare!"
Apoi, vom continua să obținem acțiune
atribuiți din elementul de formă și adăugați șirul "/ ajax
"la acea url, astfel încât metoda va ști că aceasta este, de fapt, o solicitare AJAX. jQuery.post
funcția de a trimite datele care urmează să fie procesate de către controlorul corespunzător, pe partea de server și apoi interceptați evenimentul de răspuns cu un apel inversat / închidere înregistrat:
? var script = $ form.attr ('acțiune') + '/ ajax'; $ .post (script, post_data, function (resp) if (resp.error) alert (resp.error); alt comutare (action_name) case 'delete': // remove ruturi șterse din formularul $ grid .find ('.dg_check_item: checked') parintii ('tr') remove (); pauza; case 'anotherAction': // a face altceva; pauza;, 'json')
Observați că solicităm ca răspunsul să fie codificat ca "json", deoarece vom transmite acel șir ca al patrulea argument al lui $ .post
funcţie. Conținutul apelului de răspuns care se ocupă de răspunsul la server trebuie să fie destul de simplu de înțeles; determină dacă există o eroare și, dacă da, o avertizează. În caz contrar, va indica faptul că acțiunea a fost procesată cu succes (în acest caz, dacă este o acțiune, eliminăm rândurile legate de id
s care au fost selectate de utilizator).
Singurul lucru care lipsește acum este funcția de comutare pe care am promis-o mai devreme. Trebuie să înregistrăm o funcție de apel invers atunci când caseta de selectare "Master" - care are un atribut de clasă setat la "dg_check_toggler
"- se face clic pe. Adăugați următorul fragment de cod după cel precedent:
$ (this) .is (': checked'). ('(dg_check_toggler'). )) checkboxes.attr ('checked', 'true'); altceva checkboxes.removeAttr ('checked');)
Când se face clic pe caseta de selectare "toggler", dacă se trece la o stare "verificată", toate rândurile din grila de date pertinentă vor fi verificate simultan; altfel totul nu va fi verificat.
Nu am ajuns la vârful aisbergului când vine vorba de rețelele de date pentru sisteme complexe de gestionare a conținutului. Alte caracteristici care s-ar putea dovedi utile sunt:
Vă mulțumim pentru lectură. Dacă doriți un tutorial de urmărire, anunțați-ne în comentarii!