I denne leksjonen vil vi opprette et CodeIgniter-bibliotek som gjør det mulig for oss å generere datanettverk automatisk for å administrere en databasetabell. Jeg skal forklare hvert trinn som kreves for å lage denne klassen; så du vil sannsynligvis lære noen nye OOP teknikker / konsepter i prosessen!
Som en bonus fortsetter vi å skrive noe jQuery-kode som gjør det mulig for en bruker å oppdatere datalinjens innhold uten å måtte vente på at en side oppdateres.
Denne opplæringen antar at du har en beskjeden forståelse av CodeIgniter og jQuery-rammer.
En datagrid er et bord som viser innholdet i en database eller et bord sammen med sorteringskontroller.
En datagrid er et bord som viser innholdet i en database eller et bord sammen med sorteringskontroller. I denne opplæringen vil vi være opptatt av å gi denne funksjonaliteten, men også lagre brukeren fra å vente på at siden skal oppdateres hver gang en operasjon utføres. Takket være jQuery, vil dette bli en ganske enkel oppgave!
Hva med brukerne som ikke har Javascript aktivert? Ikke bekymre deg, vi kompenserer også for dem!
Vi ønsker å bygge et verktøy som gjør det mulig for oss å lage datagrunnlag dynamisk for enhver databastabell som vi har. Dette betyr at koden ikke er bundet til noen bestemt tabellstruktur, og er dermed uavhengig av dataene selv. Alle koderen (utvikleren som bruker vår klasse) må vite er navnet på tabellen som skal omdannes til et rutenett og den primære nøkkelen til den tabellen. Her er forordet til klassen som vi skal utvikle for det meste av denne opplæringen:
Datagrid-klassen kan godt legges til søknad / bibliotekmappen, men vi skal legge den til som en hjelper til CodeIgniter-rammen. Hvorfor? Fordi lastebibliotek ikke tillater oss å passere argumenter til klassens konstruktør, og dermed laste den som en hjelper, løser problemet. Dette punktet vil gi mer mening for deg når vi er ferdig med å skrive konstruktøren.
offentlig funksjon __construct ($ tbl_name, $ pk_col = 'id') $ this-> CI = & get_instance (); $ Dette-> KI> last> database (); $ this-> tbl_fields = $ this-> CI-> db-> list_fields ($ tbl_name); hvis ! in_array ($ pk_col, $ this-> tbl_fields)) kaste ny unntak ("Primærnøkkel kolonne '$ pk_col' ikke funnet i tabellen '$ tbl_name'"); $ this-> tbl_name = $ tbl_name; $ this-> pk_col = $ pk_col; $ Dette-> KI> last> bibliotek ( 'tabell');
Vi har mye på gang allerede; men ikke bekymre deg, da jeg skal forklare alt for deg i neste avsnitt.
Konstruktøren tar to argumenter: Den første er navnet på tabellen i databasen du vil vise som datagrid til brukeren; Den andre parameteren er navnet på kolonnen som tjener som primærnøkkel for den tabellen (mer om det senere). Inne i konstruktørens kropp instanser vi CodeIgniter Object, Database Object og HTML Table class / library. Alle disse vil være nødvendig i hele Datagrid-objektets levetid og er allerede bygd inn i CI-rammen. Legg merke til at vi også sjekker om primærnøkkelen egentlig eksisterer i det oppgitte tabellen, og hvis det ikke gjør det, kaster vi et unntak som rapporterer feilen. Nå $ Dette-> tbl_fields
Medlemsbariabelen vil være tilgjengelig for senere bruk, så vi trenger ikke å hente databasen igjen.
"Vi kan bruke kommandoen,
$ KI> DB> list_fields ($ tbl_name)
for å hente navnene på alle feltene som et bord har. For bedre ytelse anbefaler jeg imidlertid å cache resultatene. "
offentlige funksjon setHeadings (array $ overskrifter) $ this-> overskrifter = array_merge ($ this-> overskrifter, $ overskrifter);
Dette tillater deg å tilpasse overskriftene i datagruten din - det vil si med det, kan du overskrive de opprinnelige kolonneavnene for bestemte tabellfelter. Det tar en assosiativ matrise
, slik: regdate => "Registreringsdato". I stedet for bare den tekniske "Regdater" som kolonneoverskriften for den typen data, har vi en mer menneskelig lesbar tittel på plass. Koden som er ansvarlig for å bruke overskriftene, vil bli avslørt kort tid.
offentlig funksjon ignoreFields (array $ felt) foreach ($ felt som $ f) if ($ f! = $ this-> pk_col) $ this-> hide_cols [] = $ f;
ignoreFields
mottar en matrise
inneholder feltene som skal ignoreres når data hentes fra databasen. Dette er nyttig når vi har tabeller med mange felt, men vi vil bare gjemme et par av dem. Denne metoden er smart nok til å spore et forsøk på å ignorere primærnøkkelfeltet og hoppe over det. Dette er slik fordi primærnøkkelen kan ikke bli ignorert av tekniske årsaker (du vil se hvorfor snart). Likevel, hvis du vil gjemme primærnøkkelkolonnen fra å vises i brukergrensesnittet, kan du bruke hidePkCol
metode:
offentlig funksjon hidePkCol ($ bool) $ this-> hide_pk_col = (bool) $ bool;
Denne metoden mottar en boolesk verdi for å indikere om vi vil gjemme primærnøkkelkolonnen slik at den ikke vises i datanettet. Noen ganger er det en stygg idé å vise pkey
data, som vanligvis er en numerisk kode uten noen betydning for brukeren.
Neste eksempel metode:
privat funksjon _selectFields () foreach ($ this-> tbl_fields som $ felt) if (! in_array ($ field, $ this-> hide_cols)) $ this-> CI-> db-> velg ($ field); // skjul pk kolonneoverskrift? hvis ($ field == $ this-> pk_col && $ this-> hide_pk_col) fortsetter; $ overskrifter [] = isset ($ this-> overskrifter [$ felt])? $ this-> overskrifter [$ felt]: ucfirst ($ field); hvis (! tomt ($ overskrifter)) // prepend en avkrysningsboks for bytte array_unshift ($ overskrifter, ""); $ this-> CI-> table-> set_heading ($ overskrifter);
Her har vi en hjelpemetode; Det er derfor den har den "private" modifikatoren og er prefiks med en understrekkskarakter (kodekonvensjon). Det vil bli brukt av generere()
metode - forklares kort tid - for å få de aktuelle tabellfeltene valgt og også de aktuelle overskriftene som er satt til bordet (generator) gjenstand
. Legg merke til følgende linje:
$ overskrifter [] = isset ($ this-> overskrifter [$ felt])? $ this-> overskrifter [$ felt]: ucfirst ($ field);
Det er her vi bruker de tilpassede overskriftene eller til standardene hvis ingen er gitt. Hvis pk
kolonnen skal skjules fra displayet, så er overskriften hoppet over. Legg også merke til følgende linje:
array_unshift ($ overskrifter,"");
Kommandoen ovenfor instruerer programmet for å legge ut en "Master" -boks som den første overskriften i tabellen. Denne avkrysningsruten er forskjellig fra andre avmerkingsbokser i rutenettet ved at den lar en bruker sjekke eller fjerne merket i alle boksene på bare én gang. Denne vekslefunksjonaliteten vil bli implementert om noen få minutter med en enkel jQuery-kodebit.
Nå kommer det som gjør det virkelige arbeidet for oss:
generell funksjon generere () $ this -> _ selectFields (); $ rader = $ this-> CI-> db -> fra ($ this-> tbl_name) -> get () -> result_array (); foreach ($ rader som & $ rad) $ id = $ rad [$ this-> pk_col]; // prepend en avkrysningsboks for å aktivere valg av elementer / rader array_unshift ($ row, ""); // skjul pk kolonne celle hvis ($ this-> hide_pk_col) unset ($ rad [$ this-> pk_col]); returnere $ this-> CI-> table-> generere ($ rader) ;
De generere
Metoden, som navnet antyder, er ansvarlig for å generere dataruten selv. Du bør bare ringe denne metoden etter at du har konfigurert objektet i henhold til dine behov. Det første som det gjør er å ringe $ Dette -> _ selectFields ()
metode for å utføre handlingene vi forklarte tidligere. Nå må den hente alle rader fra databasen og deretter løse gjennom dem, og legge til avmerkingsbokser til begynnelsen av hver rad:
// prepend en avkrysningsboks for å aktivere valg av elementer / rader array_unshift ($ row, "");
Inne i for hver
sløyfe på generere
metode, hvis $ Dette-> hide_pk_col
flagget er satt til ekte
, da må vi deaktivere primærnøkkeloppføringen i $ rad-array
så det vil ikke dukke opp som en kolonne når $ Dette-> KI> bordet
gjenstand
behandler alle rader og genererer den endelige html-utgangen. På dette tidspunktet er det greit å fjerne primærnøkkelen, om nødvendig, fordi vi ikke lenger trenger den informasjonen. EN
Men hva gjør brukeren med de valgte / merkede rader? For å svare på dette har jeg utarbeidet noen flere metoder. Den første lar oss lage "handlingsknapper" uten å måtte vite tekniske detaljer om hvordan nettverket fungerer internt:
offentlig statisk funksjon createButton ($ action_name, $ label) return "";
Bare pass navnet på handlingen som det første argumentet og et annet argument for å indikere etiketten for den genererte knappen. EN klasse
Attributtet genereres automatisk for den knappen, slik at vi kan leke med det lettere når vi jobber med det i JavaScript. Men hvordan vet vi om en bestemt handlingsknapp har blitt trykket av brukeren? Svaret finner du i neste metode:
offentlig statisk funksjon getPostAction () // få navn på innsendt handling (hvis noen) hvis (isset ($ _ POST ['dg_action'])) retur nøkkel ($ _ POST ['dg_action']);
Jepp! En annen statisk metode som hjelper oss når vi har å gjøre med former. Hvis noen datanett har blitt sendt, returnerer denne metoden navnet på handlingen (eller "operasjonen") som er knyttet til den innleverte hendelsen. I tillegg er et annet nyttig verktøy for behandling av datagrid-skjemaene?
offentlig statisk funksjon getPostItems () hvis (! tom ($ _ POST ['dg_item'])) return $ _POST ['dg_item']; retur array ();
? som returnerer en matrise
inneholder den valgte ids
slik at du kan spore hvilke rader som er valgt på rutenettet og deretter utføre en handling med dem. Som et eksempel på hva som kan gjøres med et utvalg av rad id
s, jeg har utarbeidet en annen metode - dette er en instansmetode, og ikke en statisk, fordi den benytter objektets forekomstressurser for å gjøre sin virksomhet:
offentlig funksjon deletePostSelection () // fjern valgte elementer fra db hvis (! tomt ($ _ POST ['dg_item']) returnere $ this-> CI-> db -> fra ($ this-> tbl_name) -> where_in ($ this-> pk_col, $ _ POST ['dg_item']) -> slett ();
Hvis minst en avkrysningsboks ble merket, ble deletePostSelection ()
Metoden vil generere og gjennomføre en SQL-setning som følgende (antar $ Tbl_name = 'my_table'
og $ Pk_col = 'id'
):
SLETT FRA my_table HVOR ID IN (1,5,7,3, etc?)
? som effektivt fjerner de valgte rader fra det vedvarende laget. Det kan være flere operasjoner du kan legge til i et datanett, men det vil avhenge av prosjektets spesifikasjoner. Som et tips kan du utvide denne klassen til å si, InboxDatagrid
, så, utover deletePostSelection
metode, det kan inkludere ekstra operasjoner, for eksempel moveSelectedMessagesTo ($ sted)
, etc?
Nå, hvis du har fulgt denne veiledningen trinn for trinn, burde du ha endt opp med noe som ligner på følgende:
klassen Datagrid private $ hide_pk_col = true; privat $ hide_cols = array (); privat $ tbl_name = "; privat $ pk_col ="; private $ overskrifter = array (); privat $ tbl_fields = array (); funksjon __construct ($ tbl_name, $ pk_col = 'id') $ this-> CI = & get_instance (); $ Dette-> KI> last> database (); $ this-> tbl_fields = $ this-> CI-> db-> list_fields ($ tbl_name); hvis ! in_array ($ pk_col, $ this-> tbl_fields)) kaste ny unntak ("Primærnøkkel kolonne '$ pk_col' ikke funnet i tabellen '$ tbl_name'"); $ this-> tbl_name = $ tbl_name; $ this-> pk_col = $ pk_col; $ Dette-> KI> last> bibliotek ( 'tabell'); offentlige funksjon setHeadings (array $ overskrifter) $ this-> overskrifter = array_merge ($ this-> overskrifter, $ overskrifter); offentlig funksjon hidePkCol ($ bool) $ this-> hide_pk_col = (bool) $ bool; offentlig funksjon ignoreFields (array $ felt) foreach ($ felt som $ f) if ($ f! = $ this-> pk_col) $ this-> hide_cols [] = $ f; privat funksjon _selectFields () foreach ($ this-> tbl_fields som $ felt) if (! in_array ($ field, $ this-> hide_cols)) $ this-> CI-> db-> velg ); // skjul pk kolonneoverskrift? hvis ($ field == $ this-> pk_col && $ this-> hide_pk_col) fortsetter; $ overskrifter [] = isset ($ this-> overskrifter [$ felt])? $ this-> overskrifter [$ felt]: ucfirst ($ field); hvis (! tomt ($ overskrifter)) // prepend en avkrysningsboks for bytte array_unshift ($ overskrifter, ""); $ this-> CI-> table-> set_heading ($ overskrifter); offentlig funksjon generere () $ dette -> _ selectFields (); $ rows = $ this-> CI-> db -> fra $ this-> tbl_name) -> get () -> result_array (); foreach ($ rader som & $ rad) $ id = $ row [$ this-> pk_col]; // prepend en avkrysningsboks for å aktivere valg av elementer array_unshift ($ rad, ""); // skjul pk kolonne? hvis ($ this-> hide_pk_col) unset ($ rad [$ this-> pk_col]); returner $ this-> CI-> table-> generer ($ rader); offentlig statisk funksjon createButton ($ action_name, $ label) return ""; offentlig statisk funksjon getPostAction () // få navn på innsendt handling (hvis noen) hvis (isset ($ _ POST ['dg_action'])) returnøkkel ($ _ POST ['dg_action']); offentlig statisk funksjon getPostItems () hvis (! tom ($ _ POST ['dg_item'])) return $ _POST ['dg_item']; retur array (); offentlig funksjon deletePostSelection () // fjerne valgte elementer fra db hvis (! tom ($ _ POST ['dg_item']) returnere $ this-> CI-> db -> fra ($ this-> tbl_name) -> where_in ($ this-> pk_col, $ _ POST ['dg_item' ]) -> slett ();
Merk: Ikke glem å lagre denne filen som datagrid_helper.php
, og legg den inn i "søknad / hjelper /"
Vi lager nå en enkel testkontroll og laster Datagrid-klassen som en hjelper i sin konstruktør. Men før det, bør vi definere en dummy database tabell og fylle den med noen sample data.
Utfør følgende SQL for å opprette databasen og brukertabellen:
CREATE DATABASE 'dg_test'; CREATE TABLE 'users' ('id' int (11) IKKE NULL AUTO_INCREMENT, 'brukernavn' varchar (80) IKKE NULL, 'passord' varchar (32) IKKE NULL, 'email' varchar (255) IKKE NULL, UNIQUE KEY ' id '(' id ')) ENGINE = MyISAM DEFAULT CHARSET = latin1 AUTO_INCREMENT = 5;
Deretter la vi legge til noen brukere til det:
INSERT TIL 'brukere' ('ID', 'brukernavn', 'passord', 'e-post') VÆRDIER (1, 'david', '12345', '[email protected]'), (2, 'maria' '464y3y', '[email protected]'), (3, 'alejandro', 'a42352fawet', '[email protected]'), (4, 'emma', 'f22a3455b2','[email protected] ');
Lagre følgende kode som "test.php
,"og legg det til mappen" application / controllers ":
last> hjelper (array ( 'Grid', 'url')); $ this-> Datagrid = ny Datagrid ('brukere', 'id'); funksjonsindeks () $ this-> load-> hjelper ('form'); $ Dette-> last> bibliotek ( 'session'); $ Dette-> Datagrid-> hidePkCol (true); $ Dette-> Datagrid-> setHeadings (array ( 'e' => 'E-post')); $ Dette-> Datagrid-> ignoreFields (array ( 'passord')); hvis ($ error = $ this-> session-> flashdata ('form_error')) echo "$ error"; echo form_open ('test / proc'); echo $ this-> Datagrid-> generere (); ekko Datagrid :: createButton ('delete', 'Delete'); echo form_close (); funksjon proc request_type = ") $ this-> load-> hjelper ('url'); hvis ($ action = Datagrid :: getPostAction ()) $ error = ""; bytte ($ action) case 'delete': if (! $ this-> Datagrid-> deletePostSelection ()) $ error = 'Objekter kunne ikke slettes'; gå i stykker; hvis ($ request_type! = 'ajax') $ this-> load-> library ('session'); $ Dette-> økt-> set_flashdata ( 'form_error', $ feil); omdirigere ( 'test / indeks'); ellers echo json_encode (array ('error' => $ feil)); else die ("Bad Request"); ?>
En forekomst av denne klassen er opprettet og bestått som en referanse til $ Dette-> Datagrid
medlem. Legg merke til at vi skal hente data fra et bord som heter "brukere" hvis primærnøkkel er "id" -kolonnen; På indeksmetoden tar vi da følgende trinn: Konfigurer Datagrid-objektet, gjør det inne i et skjema med en sletteknapp lagt til det og se om alt fungerer som forventet:
Svar: "Test :: proc ()
"Metoden tar seg av å behandle skjemaet og velge riktig operasjon for å søke mot id
s som ble valgt av skjemaets avsender. Det tar også vare på AJAX-forespørsler, så det vil ekko et JSON-objekt tilbake til klienten. Denne AJAX-oppmerksomme funksjonen kommer til nytte når jQuery kommer til handling, som er akkurat nå!
"Det er alltid en smart idé å lage webapplikasjoner som kompenserer for når JavaScript / AJAX ikke er tilgjengelig. På denne måten vil noen brukere ha en rikere og raskere opplevelse, mens de som ikke er aktivert for JavaScript, fortsatt vil kunne bruke programmet normalt."
Når brukeren klikker på knappen (eller en annen handlingsknapp), vil vi kanskje, for å forhindre at siden lastes ned og måtte generere alt igjen; Dette kan gjøre at brukeren av vår søknad sovner! Omgå dette problemet vil ikke være en vanskelig oppgave hvis vi holder oss til jQuery-biblioteket. Siden dette ikke er en "nybegynner" opplæring, vil jeg ikke gå gjennom alle detaljene knyttet til hvordan du får biblioteket, hvordan du inkluderer det på siden etc. Du forventes å kjenne disse trinnene på egen hånd.
Opprett en mappe med navnet "js
", legg til jQuery-biblioteket i, og opprett en visningsfil, navngitt users.php
. Åpne denne nye filen, og legg til:
Brukerhåndtering Datagrid-> hidePkCol (true); hvis ($ error = $ this-> session-> flashdata ('form_error')) echo "$ error"; echo form_open ('test / proc', array ('class' => 'dg_form')); echo $ this-> Datagrid-> generere (); ekko Datagrid :: createButton ('delete', 'Delete' ); ekko form_close ();?>
Visste du at vi har flyttet koden fra Test :: Hovedsiden
og inn i det nye visningsskriptet? Dette betyr at vi må endre Test :: indeks ()
metode i henhold til:
funksjonsindeks () $ this-> load-> hjelper ('form'); $ Dette-> last> bibliotek ( 'session'); $ Dette-> last> view ( 'brukere');
Det er bedre. Hvis du vil legge til noen styling i rutenettet, kan du bruke følgende CSS (eller lage et bedre layout på egen hånd):
.dg_form table border: 1px solid sølv; .dg_form th bakgrunnsfarge: grå; font-familie: "Courier New", Courier, mono; font-size: 12 piksler; .dg_form td bakgrunnsfarge: gainsboro; font-size: 12 piksler; .dg_form input [type = send] margin-top: 2px;
Nå, vær så snill, lag en "datagrid.js" -fil, sett den på "js" -katalogen, og start med denne koden:
$ (funksjon () // kule ting her?)
Innenfor denne lukkingen vil vi skrive kode som vil være oppdraget med å kontrollere visse sende hendelser når siden er fullstendig lastet. Det første vi må gjøre er å spore når en bruker klikker på en send-knapp på datagruten, og send deretter dataene som skal behandles på serveren.
$ ('. dg_form: submit'). klikk (funksjon (e) e.preventDefault (); var $ form = $ (dette) .parents ('form'); var action_name = $ (dette) .attr klasse "). erstatt (" dg_action_ "," "); var action_control = $ (''); $ Form.append (action_control); var post_data = $ form.serialize (); action_control.remove (); var script = $ form.attr ('action') + '/ ajax'; $ .post (script, post_data, funksjon (resp) if (resp.error) alert (resp.error); else switch (action_name) case 'delete': // fjerne slettede rader fra nettet $ form .find ('.dg_check_item: checked'). foreldre ('tr'). fjerne (); break; case 'anotherAction': // gjøre noe annet? break;, 'json'))
Alternativt kunne vi ha startet med noe som: $ ('. dg_form'). send inn (funksjon (e) ?)
. Men siden jeg vil spore hvilken knapp som er trykket og trekke ut navnet på den valgte handlingen basert på det, foretrekker jeg å knytte en hendelseshandler til selve Submit-knappen og deretter gå meg opp i nodenes hierarki for å finne skjemaet som den trykte knappen tilhører:
// finner skjemaet var $ form = $ (dette) .parents ('form'); // trekker ut navnet på handlingen var action_name = $ (dette) .attr ('class'). erstatt ("dg_action_", "");
Deretter legger vi til et skjult inngangselement i formelementet for å indikere hvilken handling som sendes:
// opprett den skjulte inputvaren action_control = $ (''); // legg til skjemaet $ form.append (action_control);
Dette er nødvendig fordi funksjonen ikke anser send-knappen som en gyldig skjemaoppføring. Så vi må ha den hack på plass når serialisering av skjemadataene.
action_control.remove ();
"Ikke glem: funksjonen ignorerer innleveringsknappen, avviser den som bare et annet stykke markup-søppel!"
Deretter fortsetter vi å få handling
attributt fra skjemaelementet og legg til strengen "/ ajax
"til den URL-en, så metoden vil vite at dette faktisk er en AJAX-forespørsel. Deretter bruker vi jQuery.post
funksjon for å sende dataene som skal behandles av den aktuelle kontrolleren, server-siden, og deretter avlyse svarhendelsen med en registrert tilbakeringing / lukning:
? var script = $ form.attr ('action') + '/ ajax'; $ .post (script, post_data, funksjon (resp) if (resp.error) alert (resp.error); else switch (action_name) case 'delete': // fjerne slettede rader fra nettet $ form .find ('.dg_check_item: checked'). foreldre ('tr'). fjerne (); pause; sak 'annenAction': // gjøre noe annet? pause;, 'json')
Legg merke til at vi ber svaret om å bli kodet som "json" siden vi passerer den strengen som fjerde argument av $ .post
funksjon. Innholdet i tilbakeringingen som omhandler serverresponsen bør være ganske enkelt å forstå; Det avgjør om det er en feil, og i så fall varsler det. Ellers vil det indikere at handlingen ble behandlet (i dette tilfellet, hvis det er en "" handling, fjerner vi rader som er relatert til id
s som ble valgt av brukeren).
Det eneste som mangler nå, er den vekslefunksjonaliteten som jeg lovet tidligere. Vi må registrere en tilbakeringingsfunksjon for når "Master" -boksen - som har en klassetributt satt til "dg_check_toggler
"- er klikket. Legg til følgende kodestykke etter den forrige:
$ ('.dg_check_toggler'). klikk (funksjon () var-bokser = $ (dette) .parents ('table'). finn ('.dg_check_item'); )) avkrysningsbokser.attr ('sjekket', 'ekte'); annet avkrysningsbokser.removeAttr ('sjekket');)
Når kryssboksen "toggler" klikkes, hvis den går til en "sjekket" -status, blir alle rader fra det tilhørende datanettet sjekket samtidig; ellers vil alt bli ukontrollert.
Vi har ikke nådd toppen av isfjellet når det gjelder datanettverk for mer komplekse innholdshåndteringssystemer. Andre funksjoner som kan vise seg å være nyttige er:
Takk for at du leste. Hvis du vil ha en oppfølgingstutorial, gi meg beskjed i kommentarene!