Taming Slim 2.0

Slim este un cadru ușor care împachetează o mulțime de pumn pentru amprenta sa minusculă. Dispune de un sistem de rutare incredibil și oferă o bază solidă pentru a lucra fără a vă împiedica. Lasa-ma sa-ti arat!

Dar asta nu înseamnă că Slim nu are probleme; setarea unui fișier devine aglomerată pe măsura creșterii aplicației. În acest articol, vom analiza modul de structurare a unei aplicații Slim pentru a nu numai să susțină, ci și să-i îmbunătățească funcționalitatea și să păstreze lucrurile ordonate și sistematice.


Vanilie Slim

Să începem prin a privi un cod comun Slim pentru a identifica problema. După ce instalați Slim through Composer, trebuie să creați o instanță a Subţire obiect și definiți rutele dvs.:

 get ('/', function () echo "Pagina de pornire";); $ app-> get ('/ testPage', funcția () utilizează ($ app) $ app-> render ('testpage.php');); $ App-> run ();

Să transformăm obiectul Slim în "controler".

Primul apel de metodă stabilește o nouă rută pentru URI rădăcină (/) și conectează funcția dată la acel traseu. Acest lucru este destul de verbose, dar ușor de configurat. A doua metodă de apel definește o rută pentru URI testPage. În cadrul metodei furnizate, folosim Slim face() pentru a face o viziune.

Aici se află prima problemă: această funcție (o închidere) nu este apelată în contextul actual și nu are nici o modalitate de a accesa caracteristicile lui Slim. De aceea trebuie să folosim utilizare cuvânt cheie pentru a transmite referința la aplicația Slim.

Al doilea aspect provine din arhitectura lui Slim; este menit să fie definit într-un singur fișier. Desigur, puteți externaliza variabila într-un alt fișier, dar devine dezordonat. În mod ideal, dorim ca abilitatea de a adăuga controlere pentru a modula cadrul în componente individuale. Ca un bonus, ar fi frumos ca acești controlori să ofere acces nativ la caracteristicile lui Slim, eliminând necesitatea de a transmite referințe în închideri.


Un mic inginer invers

Este discutabil dacă citirea codului sursă dintr-un proiect cu sursă deschisă este considerată tehnologie inversă, dar este termenul pe care îl voi respecta. Înțelegem cum să folosim Slim, dar ce se întâmplă sub capotă? Să ne uităm la o cale mai complicată pentru a ajunge la rădăcina acestei întrebări:

 $ app-> get ('/ users /: name', funcția ($ name) echo "Hello". $ name;);

Această definiție a traseului folosește un colon cu cuvântul, Nume. Acesta este un substituent, iar valoarea folosită în locul său este trecută la funcție. De exemplu, / Utilizatori / Gabriel se potrivește cu această rută și "gabriel" este transferat la această funcție. Ruta, / utilizatori, pe de altă parte, nu este un meci deoarece lipsește parametrul.

Dacă vă gândiți în mod logic la aceasta, există un număr de pași care trebuie să fie finalizați pentru a procesa un traseu.

  • Primul pas: verificați dacă ruta se potrivește cu URI-ul curent.
  • Pasul doi: extrageți toți parametrii din URI.
  • Pasul al treilea: apelați închiderea conectată și treceți parametrii extrași.

Pentru a optimiza mai bine procesul, Slim - folosind callback-urile și grupurile de regiștri - stochează substituenții, în timp ce verifică meciurile. Aceasta combină doi pași într-una, lăsând doar necesitatea de a executa funcția conectată când Slim este gata. Devine clar că obiectul traseului este autonom și, sincer, tot ceea ce este necesar.

În exemplul precedent, am avut acces la caracteristicile lui Slim în parsarea rutelor, dar am trebuit să trecem printr-o referință de obiect Slim deoarece altfel nu ar fi disponibilă în contextul execuției funcției. Asta e tot ce ai nevoie pentru majoritatea aplicațiilor, deoarece logica aplicației ar trebui să apară în controler.

În acest sens, să extragem partea "rutare" într-o clasă și să transformăm obiectul Slim în "controler".


Noțiuni de bază

Pentru a începe, să descărcați și să instalați "vanilla Slim" dacă nu ați făcut deja acest lucru. O să presupun că ați instalat Composer, dar dacă nu, urmați pașii .

Într-un nou director, creați un fișier numit composer.json, și adăugați următoarele:

 "nume": "nettuts / slim-mvc", "necesită": "slim / slim": "*", "slim / extras": "*"

Într-o fereastră terminală, navigați la directorul respectiv și tastați compozitorul instala. Te voi trec prin aceste pachete, dacă ești prima dată când folosești Slim.

  • slim / slim - cadrul real Slim.
  • Slim / Extra - un set de clase opționale pentru a extinde Slim.
  • crenguță / crenguță - motorul de template-uri din Twig.

Din punct de vedere tehnic, nu aveți nevoie de instrumentele Slim Extra sau Twig pentru acest tutorial, dar îmi place să folosesc Twig în locul șabloanelor standard PHP. Dacă utilizați Twig, cu toate acestea, aveți nevoie de extras Slim, deoarece oferă o interfață între Twig și Slim.

Acum permiteți adăugarea fișierelor personalizate și vom începe prin adăugarea unui director la vânzătorii pliant. Îmi voi spune numele Nettuts, dar nu ezitați să vă numiți pe orice vreți. Dacă sunteți încă în terminal, asigurați-vă că fereastra terminalului se află în directorul proiectului și tastați următoarele:

mkdir vendor / Nettuts

Acum, editați composer.json prin adăugarea referinței la acest dosar nou:

 "nume": "nettuts / slim-mvc", "cer": "slim / slim": "*" autoload ": " psr-0 ": " Nettuts ":" furnizor / "

Vrem ca aplicația noastră să încarce automat clase din Nettuts spațiul de nume, astfel încât acesta îi spune Compozitorului să elaboreze toate cererile Nettuts la standardul PSR-0 începând de la furnizor pliant.

Acum executați:

compozitor dump-autoload

Aceasta recompune autoloader-ul pentru a include noua referință. Apoi, creați un fișier numit Router.php, în cadrul Nettuts și introduceți următoarele:

  

Am văzut că fiecare obiect de traseu are o funcție autonomă care determină dacă se potrivește cu URI-ul furnizat. Deci, vrem o serie de trasee și o funcție de analizat prin ele. De asemenea, vom avea nevoie de o altă funcție pentru a adăuga noi rute și o modalitate de a prelua URI din cererea curentă HTTP.

Să începem prin adăugarea unor variabile membre și a constructorului:

 Class Router trasee protejate $; protejate cererea $; funcția publică __construct () $ env = \ Slim \ Mediu :: getInstance (); $ this-> request = new \ Slim \ Http \ Cerere ($ env); $ this-> trasee = array (); 

Am setat rute variabilă pentru a conține rutele și cerere variabilă pentru a stoca modelul Slim Cerere obiect. Apoi, avem nevoie de abilitatea de a adăuga rute. Pentru a respecta cele mai bune practici, o voi rupe în două etape:

funcția publică addRoutes ($ rută) foreach ($ rută ca $ route => calea $) $ method = "any"; dacă (strpos ($ path, "@")! == false) lista ($ path, $ method) = explode ("@", calea $);  $ func = $ this-> processCallback (calea $); $ r = nou \ Slim \ Route ($ rută, $ func); $ R-> setHttpMethods (strtoupper (metoda $)); array_push ($ this-> trasee, $ r); 

Această funcție publică acceptă o gamă asociativă de rute în formatul route => cale, Unde traseu este un traseu Slim standard și cale este un șir cu următoarea convenție:

Opțional, puteți lăsa anumiți parametri să utilizeze o valoare implicită. De exemplu, numele clasei va fi înlocuit cu Principal dacă l-ați lăsat afară, index este implicit pentru numele funcțiilor omise, iar metoda implicită pentru metoda HTTP este orice. Desigur, orice nu este o metodă reală HTTP, dar este o valoare pe care Slim o folosește pentru a se potrivi cu toate tipurile de metode HTTP.

addRoutes funcția începe cu un a pentru fiecare buclă care circulă pe rute. Apoi, setăm metoda implicită HTTP, opțional înlocuind-o cu metoda furnizată dacă @ simbolul este prezent. Apoi trecem restul căii către o funcție pentru a prelua un apel invers și a le atașa la un traseu. În cele din urmă, adăugăm traseul spre matrice.

Acum, să ne uităm la processCallback () funcţie:

funcția protejatăCallback ($ path) $ class = "Main"; dacă (strpos ($ path, ":")! == false) lista ($ class, $ path) = explode (":", calea $);  $ function = ($ cale! = "")? $ cale: "index"; $ func = funcția () folosiți ($ class, $ function) $ class = '\ Controllers \\'. clasa $; $ class = noua clasă $ (); $ args = func_get_args (); returnați call_user_func_array (array ($ class, $ function), $ args); ; returnează $ func; 

Al doilea aspect provine din arhitectura lui Slim; este menit să fie definit într-un singur fișier.

Mai întâi setăm clasa implicită la Principal, și suprascrie această clasă dacă este găsit simbolul colonului. Apoi, determinăm dacă este definită o funcție și folosiți metoda implicită index daca este necesar. Apoi, trecem numele de clase și funcții la închidere și le returnez pe traseu.

În interiorul închiderii, prefixăm numele clasei cu spațiul de nume. Apoi, creăm o nouă instanță a clasei specificate și preluăm lista argumentelor transmise acestei funcții. Dacă vă aduceți aminte, în timp ce Slim verifică dacă un traseu se potrivește, acesta construiește încet o listă de parametri bazată pe metacaractere din traseu. Această funcție (func_get_args ()) poate fi folosit pentru a obține parametrii trecuți într-o matrice. Apoi, folosind call_user_func_array () ne permite să specificăm clasa și funcția, în timp ce transmitem parametrii către controler.

Nu este o funcție foarte complicată odată ce o înțelegi, dar este un exemplu foarte bun când închiderile vin la îndemână.

Pentru a recapitula, am adăugat o funcție pentru noi Router care vă permite să transmiteți o matrice asociativă care conține rute și căi care se potrivesc cu clasele și funcțiile. Ultimul pas este de a procesa rutele și de a executa orice potrivire. Păstrați-vă convenția numelui Slim, să o numim alerga:

funcționarea funcției publice () $ display404 = true; $ uri = $ aceasta-> cerere-> getResourceUri (); $ metodă = $ this-> request-> getMethod (); ($ rută-> suportăHttpMethod ($ method) || $ route-> supportsHttpMethod ("ANY ")) call_user_func_array ($ rută-> getCallable (), array_values ​​($ route-> getParams ())); $ display404 = false;  dacă ($ display404) echo "404 - ruta nu a fost găsită"; 

Începem prin stabilirea display404 variabilă, care nu reprezintă trasee găsite, la Adevărat. Dacă găsim o rută potrivită, vom seta această opțiune fals și ocolind mesajul de eroare. Apoi, utilizăm obiectul cererii Slim pentru a prelua metoda curentă URI și HTTP.

Vom folosi aceste informații pentru a trece și a găsi potriviri din matricea noastră.

Odată ce este obiectul traseului chibrituri() funcția execută, sunteți în stare să sunați getParams () pentru a prelua parametrii analizați. Folosind această funcție și getCallable () , putem executa închiderea și transmite parametrii necesari. În cele din urmă, vom afișa un mesaj 404 dacă niciun traseu nu corespunde cu URI-ul curent.

Să creăm clasa de controler care deține apelurile de apel pentru aceste rute. Dacă ați urmat de-a lungul, atunci ați fi dat seama că nu am forțat niciodată un tip de protocol sau de clasă. Dacă nu doriți să creați o clasă de controlor, atunci orice clasă va funcționa bine.

Deci, de ce se creează o clasă de controler? Răspunsul scurt este că încă nu am folosit Slim! Am folosit părți din Slim pentru solicitarea și rutele HTTP, dar întregul punct a fost acela de a avea acces ușor la toate proprietățile lui Slim. Clasa noastră de controlor va extinde clasa actuală Slim, obținând acces la toate metodele lui Slim.

Puteți la fel de ușor să omiteți acest lucru și subclasa Slim direct de la controlorii dvs..


Construirea controlerului

Acest controler practic vă permite să modificați Slim în timp ce păstrați-l încă vanilie. Denumiți fișierul Controller.php, și scrieți următorul cod:

date = $ setări ['model'];  părinte :: __ construct (setări $); 

Când inițializați Slim, puteți trece într-o varietate de setări, variind de la modul de depanare al aplicației la motorul de template-uri. În loc de a codifica greu orice valoare în constructor, le-am încărcat dintr-un fișier numit settings.php și treci matricea în constructorul părintelui.

Deoarece extindem Slim, m-am gândit că ar fi bine să adaug o setare "model", permițând oamenilor să-și prindă obiectul de date direct în controler.

Aceasta este secțiunea pe care o puteți vedea în mijlocul codului de mai sus. Verificăm dacă model setarea a fost setată și alocați-o operatorului date dacă este necesar.

Acum, creați un fișier numit settings.php în rădăcina proiectului dvs. (dosarul cu composer.json fișier) și introduceți următoarele:

 noul \ Slim \ Extras \ Views \ Twig (), 'templates.path' => '... returnează setările $;

Acestea sunt setări standard Slim, cu excepția modelului. Indiferent ce valoare este atribuită model proprietate este trecut la date variabil; aceasta ar putea fi o matrice, o altă clasă, un șir, etc ... Am pus-o la un obiect deoarece îmi place să folosesc -> notație în loc de notația consolei (matrice).

Acum putem testa sistemul. Dacă vă amintiți în Router class, prefixăm numele clasei cu "Controlor"spațiu de nume. Deschideți composer.json adăugați următoarele direct după definiția de la psr-0 pentru Nettuts Spațiu de nume:

"nume": "nettuts / slim_advanced", "necesită": "slim / slim": "2.2.0" autoload ": " psr-0 ": " Nettuts ":" furnizor / "," Controller ":" ./ "

Apoi, ca și înainte, dați drumul autoloaderului:

compozitor dump-autoload

Dacă am setat doar calea de bază la directorul rădăcină, atunci spațiul de nume Controlor va harta la un folder numit "Controlor"în rădăcina aplicației noastre, deci creați acel director:

Controller mkdir

În interiorul acestui dosar, creați un nou fișier numit main.php. În interiorul fișierului trebuie să declare spațiul de nume și să creăm o clasă care să ne extindă Controlor clasa de bază:

a datelor> mesaj;  test public function () echo "pagina de test"; 

Acest lucru nu este complicat, dar să-l luăm cu moderatie. În această clasă, definim două funcții; numele lor nu contează pentru că le vom cartografia mai târziu. Este important să observăm că acces direct la proprietăți din controler (adică modelul) în prima funcție și, de fapt, veți avea acces deplin la toate comenzile lui Slim.

Să creați actualul fișier public. Creați un nou director în rădăcina proiectului dvs. și denumiți-l public. După cum sugerează și numele, toate acestea vor fi toate chestiile publice. În interiorul acestui dosar, creați un fișier numit index.php și introduceți următoarele:

 'Principal: index @ get', '/ test' => 'Principal: test @ get'); $ Router-> addRoutes ($ rute); $ Router-> run ();

Includem biblioteca autoloading Composer și creăm o nouă instanță a ruterului nostru. Apoi definim două rute, le adăugăm la obiectul routerului și îl executăm.

De asemenea, trebuie să activați mod_rewrite în Apache (sau echivalentul utilizând un alt server web). Pentru a seta acest lucru, creați un fișier numit .htaccess în interiorul public și completați-l cu următoarele:

RewriteEngine pe RewriteCond% REQUEST_FILENAME! -F RewriteRule ^ index.php [QSA, L]

Acum, toate cererile către acest dosar (care nu se potrivesc cu un fișier real) vor fi transferate la index.php.

În browser-ul dvs., navigați la dvs. public director, și ar trebui să vedeți o pagină care spune "Hello World". Navigheaza catre "/Test"și ar trebui să vedeți mesajul" Pagină de testare ". Nu este deloc interesant, dar am mutat cu succes codul logic în controluri individuale.


Runda doi

Slim nu este CodeIgniter, nu este Symfony și nu este Laravel.

Deci, avem funcționalități de bază, dar există câteva margini aspre. Să începem cu routerul.

În momentul de față, afișăm un mesaj de eroare simplu dacă nu există o rută. Într-o aplicație reală, dorim aceeași funcționalitate ca încărcarea unei pagini obișnuite. Vrem să profităm de capacitatea lui Slim de a încărca vizualizări, precum și de a seta codul de eroare al răspunsului.

Să adăugăm o nouă variabilă de clasă care deține o cale opțională (la fel ca celelalte rute). În partea de sus a fișierului, adăugați următoarea linie imediat după definiția obiectului cererii:

protejat $ errorHandler;

Apoi, să creăm o funcție care acceptă o cale și îi atribuie o funcție de apel invers. Acest lucru este relativ simplu deoarece am abstracționat deja această funcție:

funcția publică set404Handler (calea $) $ this-> errorHandler = $ this-> processCallback ($ path); 

Acum să ajustăm alerga comanda pentru a executa opțional apelul de apel în loc de a afișa doar mesajul de eroare:

dacă ($ display404) dacă (is_callable ($ this-> errorHandler)) call_user_func ($ this-> errorHandler);  altceva echo "404 - ruta nu a fost găsită"; 

Deschideți clasa de controler. Aici puteți regla funcționalitatea lui Slim în funcție de preferințele dvs. personale. De exemplu, aș dori opțiunea de a omite extinderea fișierului când încărcați vizualizări. Deci, în loc să scrie $ This-> render ( "home.php");, Vreau doar să scriu: $ This-> render ( "acasă");. Pentru a face acest lucru, să ignorăm metoda de redare:

funcția publică render ($ nume, $ date = array (), $ status = null) if (strpos ($ nume, ".php") === false) $ nume = $ nume. ".Php";  parent :: render ($ nume, $ date, $ status); 

Acceptăm aceiași parametri ca și funcția mamă, dar verificăm dacă este prevăzută extensia de fișier și adăugați-o dacă este necesar. După această modificare, trecem fișierul la metoda parentală pentru procesare.

Acesta este doar un singur exemplu, dar ar trebui să punem și alte modificări aici în face() metodă. De exemplu, dacă încărcați aceleași pagini cu antet și subsol în toate documentele dvs., puteți adăuga o funcție renderPage (). Această funcție ar încărca vizualizarea trecută între apeluri pentru a încărca antetul și subsolul regulat.

Apoi, să aruncăm o privire asupra încărcării unor vizualizări. În rădăcina proiectului, creați un folder numit "Vizualizări"(locația și numele pot fi ajustate în settings.php fişier). Să creați doar două vederi numite test.php și error.php.

Interior test.php, adăugați următoarele:

titlu

Aceasta este pagina name!

Și înăuntru error.php fișier, introduceți acesta:

404

Traseul pe care îl căutați nu a putut fi găsit

De asemenea, modificați Principal controler prin schimbarea index() funcționează la următoarele:

indexul funcției publice () $ this-> render ("test", array ("title" => $ this-> data-> message, "name" => "Home")); 

Aici, redați vizualizarea de testare pe care tocmai am făcut-o și o transmiteți pentru afișare. Apoi, să încercăm un traseu cu parametrii. Schimba Test() funcționează la următoarele:

testul funcției publice ($ title) $ this-> render ("test", array ("title" => $ title, "name" => "Test")); 

Aici, vom trece cu un pas mai departe prin preluarea titlului paginii de la URI în sine. Nu în ultimul rând, să adăugăm o funcție pentru pagina 404:

funcția publică notFound () $ this-> render ('error', array (), 404); 

Noi folosim face() al treilea parametru opțional al funcției, care stabilește codul de stare HTTP al răspunsului.

Editarea noastră finală este în index.php să includem noi rute:

$ router-> addRoutes ($ routes); $ router-> set404Handler ("Main: notFound"); $ route = array (' ") $ router-> run ();

Acum ar trebui să navigați pe cele trei rute și să vedeți opiniile respective.


Concluzie

Cu tot ce am realizat, aveți sigur că aveți câteva întrebări despre motivul pentru care Slim nu oferă deja aceste modificări. Ele par logice, nu se abate de la implementarea lui Slim prea departe și au multă sens. Josh Lockhart (creatorul lui Slim) a pus cel mai bine:

"Slim nu este CodeIgniter, nu este Symfony, și nu este Laravel, Slim este Slim, a fost construit pentru a fi ușor și distractiv, în timp ce încă în măsură să rezolve aproximativ 80% din cele mai frecvente probleme.În loc să vă faceți griji despre marginea cazuri, se concentrează pe a fi simplu și având o bază de cod ușor de citit. "

Uneori, în calitate de dezvoltatori, suntem atât de prinși în scenariu nebun încât uităm de ceea ce este cu adevărat important: codul. Modurile, precum cea din acest tutorial, sunt posibile numai din cauza simplității și a verbosității codului. Deci, da, ar putea exista cazuri de margine care necesită o atenție deosebită, dar veți obține o comunitate activă, care, în opinia mea, depășește cu greutate costurile.

Sper că ți-a plăcut acest articol. Dacă aveți întrebări sau comentarii, lăsați un mesaj de mai jos. De asemenea, puteți să mă contactați prin canalul IRC pe Freenode la #nettuts canal.

Cod