Laravel despachetat sesiune, auth și cache

În ultimii ani, Laravel a devenit unul dintre cele mai proeminente cadre utilizate de inginerii software pentru construirea aplicațiilor lor web. Similar cu popularitatea pe care a savurat-o CodeIgniter în perioada de glorie, Laravel a fost laudat pentru ușurința în utilizare, prietenie cu începătorii și respectarea standardelor industriale.

Introducere

Totuși, un lucru pe care nu-l folosesc mulți programatori este sistemul bazat pe componente al lui Laravel. De la transformarea sa la componente compacte, Laravel 4 a devenit un sistem foarte modular, similar cu verbositatea cadrelor mai mature precum Symfony. Aceasta se numește Ilumina grup de componente, care, în opinia mea, nu este cadrul propriu-zis, ci este o compilație de biblioteci pe care un cadru poate să o utilizeze. Cadrul real al lui Laravel este reprezentat de aplicația scheletului Laravel (găsită pe laravel / laravel GitHub repository) care utilizează aceste componente pentru a construi o aplicație web.

În acest tutorial, vom fi scufundați într-un grup de aceste componente, învățând cum funcționează, modul în care sunt folosiți de cadru și modul în care putem să le extindem funcționalitatea.

Componenta sesiunii

Componenta sesiunii Laravel se ocupă de sesiuni pentru aplicația web. Acesta utilizează un sistem bazat pe driver, numit Laravel Manager, care acționează atât ca o fabrică, cât și ca un înveliș pentru oricare dintre driverele care sunt setate în fișierul de configurare. De la această scriere, componenta sesiunii are drivere pentru:

  • fişier - un driver de sesiune bazat pe fișiere, în care datele de sesiune sunt salvate într-un fișier criptat.
  • fursec - un driver de sesiune bazat pe cookie, în care datele sesiunii sunt criptate în cookie-urile utilizatorului.
  • Bază de date - datele de sesiune sunt salvate în baza de date care este configurată pentru aplicație.
  • apc - datele sesiunii sunt salvate în APC.
  • memcached - datele din sesiune sunt salvate în Memcached.
  • Redis - datele sesiunii sunt salvate în Redis.
  • mulțime - datele din sesiune sunt salvate într-o matrice PHP. Luați notă că driverul de sesiune de matrice nu suportă persistența și de obicei este folosit numai în comenzile consolei.

Prestatori de servicii

Cei mai mulți utilizatori Laravel nu își dau seama, dar o mare parte a modului în care lucrează Laravel este în cadrul furnizorilor de servicii. Acestea sunt în esență fișiere de bootstrap pentru fiecare componentă și sunt suficient de abstracte, astfel încât utilizatorii pot bootstrap orice componente, în orice mod.

O explicație clară a modului în care funcționează aceasta este mai jos:

  1. Este inițiată componenta Application Laravel. Acesta este principalul motor al întregului cadru, responsabil cu gestionarea solicitării HTTP, gestionarea furnizorilor de servicii, precum și cu rolul de container de dependență pentru cadrul.
  2. Odată ce un furnizor de servicii este fugit, este Inregistreaza-te se numește metoda. Acest lucru ne permite să instanțiăm orice componentă dorim.
    • Rețineți că toți furnizorii de servicii au acces la aplicația principală Laravel (prin $ This-> app), care ar permite furnizorilor de servicii să împingă instanțe ale claselor rezolvate în containerul de dependență.
  3. Odată ce aceste dependențe sunt încărcate, ar trebui să fim liberi să le folosim apelând la container, de exemplu, prin sistemul de fațade Laravel, App :: make.

Revenind la Sesiuni, să examinăm rapid SessionServiceProivider:

 / ** * Înregistrați instanța managerului de sesiuni. * * @return void * / registrul funcțiilor protejateSessionManager () $ this-> app-> bindShared ('session', funcția ($ app) returnează SessionManager nou ($ app););  / ** * Înregistrați instanța șoferului de sesiune. * * @return void * / registrul funcțiilor protejateSessionDriver () $ this-> app-> bindShared ('session.store', funcția ($ app) // În primul rând vom crea managerul de sesiuni care este responsabil pentru / / crearea diferiților drivere de sesiune atunci când sunt necesare de către instanța // aplicației și le va rezolva pe o bază de încărcare leneșă $ manager = $ app ['session'] return $ manager-> driver ();) ; 

Aceste două metode sunt numite de către Inregistreaza-te() funcţie. Primul, registerSessionManager (), este chemat să înregistreze inițial SessionManager. Această clasă extinde Administrator pe care am menționat-o în partea de sus. Al doilea, registerSessionDriver () înregistrează un manager de sesiuni pentru manager, pe baza a ceea ce am configurat. În cele din urmă, această metodă se numește Illuminate \ Suport \ Manager de clasă:

/ ** * Creați o nouă instanță a driverului. * * @parametru șir $ driver * @return mixt * * @throws \ InvalidArgumentException * / funcția protejată createDriver ($ driver) $ method = 'create'.ucfirst ($ driver). // Vom verifica dacă există o metodă creator pentru driverul dat. Dacă nu vom // vom verifica un creator de driver personalizat, care permite dezvoltatorilor să creeze // drivere folosind propriul creator de driver personalizat Closure to create it. dacă (isset ($ this-> customCreators [$ driver])) retur $ this-> callCustomCreator ($ driver);  elseif (method_exists ($ this, metoda $)) return $ this -> metoda $ ();  aruncați un nou \ InvalidArgumentException ("Driver [$ driver] nu este acceptat"); 

De aici, putem vedea că pe baza numelui driverului, din fișierul de configurare, se numește o metodă specifică. Deci, dacă am configurat să utilizeze fişier manager de sesiuni, va numi această metodă în SessionManager clasă:

/ ** * Creați o instanță a driverului de sesiune de fișiere. * * @return \ Iluminare \ Session \ Store * / funcția protejată createFileDriver () return $ this-> createNativeDriver ();  / ** * Creați o instanță a driverului sesiunii de fișiere. * * @return \ Iluminare \ Session \ Store * / funcția protejată createNativeDriver () $ path = $ this-> app ['config'] ['session.files']; returnați $ this-> buildSession (fișierul FileSessionHandler nou ($ this-> app ['files'], $ path)); 

Clasa șoferului este apoi injectată într-un a Magazin clasa, care este responsabilă pentru a apela metodele actuale de sesiune. Acest lucru ne permite să separăm de fapt implementarea SessionHandlerInterface de la SPL la drivere, Magazin clasa îl facilitează.

Crearea propriului nostru procesator de sesiuni

Să creați propriul Handler de Sesiune, un handler de sesiuni MongoDB. În primul rând, va trebui să creați o MongoSessionHandler în cadrul unei instanțe a proiectului Laravel nou instalat. (Vom împrumuta foarte mult Symfony \ Componenta \ HttpFoundation \ Session \ Storage \ Handler \ MongoDbSessionHandler) .:

config = $ config; $ conexiune_string = 'mongodb: //'; dacă ! empty ($ this-> config ['username']) &&! empty ($ this-> config ['parola'])) $ connection_string. : $ this-> config [ 'parola'] @ ";  $ conexiune_string. = "$ this-> config ['host']"; $ this-> conexiune = nou Mongo ($ connection_string); $ this-> collection = $ this-> conexiune-> selectCollection ($ this-> config ['database'], $ this-> config ['collection']);  / ** * @inheritDoc * / funcția publică deschisă ($ savePath, $ sessionName) return true;  / ** * @inheritDoc * / funcția publică close () return true;  / ** * @inheritDoc * / funcția publică citită ($ sessionId) $ session_data = $ this-> colecția-> findOne (array ('_id' => $ sessionId,)); dacă is_null ($ session_data)) return "; altceva return $ session_data ['session_data'] -> bin; / ** * inheritDoc $ this-> collection-> update (array ('_id' => $ sessionId), array ('$ set' => new MongoDate (),)), array ('upsert' => true, 'multiple' => false)); / ** * inheritDoc > colectare-> eliminați (array ('_id' => $ sessionId)); return true / ** * @inheritDoc * / funcția publică gc ($ lifetime) $ time = $ lifetime); $ this-> collection-> remove (array ('timestamp' => array ('$ lt' => $ time); 

Ar trebui să salvați acest lucru în furnizor / laravel / cadru / src / Illuminate / sesiune pliant. În scopul acestui proiect, îl vom pune aici, dar în mod ideal acest fișier ar trebui să se afle în propriul spațiu de nume al bibliotecii.

Apoi, trebuie să ne asigurăm că Administrator clasa poate suna acest driver. Putem face acest lucru prin utilizarea Managerul :: extinde metodă. Deschis furnizor / laravel / cadru / src / Illuminate / sesiune / SessionServiceProvider.php și adăugați următorul cod. În mod ideal, ar trebui să extinem furnizorul de servicii, dar acesta este în afara scopului acestui tutorial.

/ ** * Configurarea apelului Mongo Driver * * @return void * / funcția publică setupMongoDriver () $ manager = $ this-> app ['session']; $ manager -> extend ('mongo', functie ($ app) retur nou MongoSessionHandler (array ('host' => $ app ['config' => $ app ['config'] -> get ('session.mongo.password'), 'baza de date' => $ app ['config'] -> get ('session.mongo.collection')); ); 

Asigurați-vă că actualizați Inregistreaza-te() metodă pentru a apela această metodă:

/ ** * Înregistrați furnizorul de servicii. * * @return void * / registrul funcțiilor publice () $ this-> setupDefaultDriver (); $ This-> registerSessionManager (); $ This-> setupMongoDriver (); $ This-> registerSessionDriver (); 

Apoi, trebuie să definim configurația Mongo DB. Deschis app / config / session.php și definiți următoarele setări de configurare:

/ ** * Mongo DB setările * / 'mongo' => array ('host' => '127.0.0.1', 'username' => ',' password '=>', 'database' => 'laravel' 'colecție' => 'laravel_session_collection')

În timp ce suntem pe acest fișier, ar trebui să actualizăm, de asemenea conducător auto configurare sus:

"șofer" => "mongo"

Acum, încercați să accesați pagina principală (de obicei, localhost / somefolder / publice). Dacă această pagină se încarcă fără a afișa Hopa pagina, apoi felicitări, am creat cu succes un driver de sesiune nou! Testați-o prin setarea unor date falsificate pe sesiune, prin Sesiunea :: set () și apoi să-l repetați Sesiunea :: get ().

Componenta Auth

Componenta Laravel Auth se ocupă de autentificarea utilizatorilor pentru cadrul, precum și de gestionarea parolelor. Ceea ce a făcut componenta Laravel aici este de a crea o interpretare abstractă a sistemului tipic de management al utilizatorilor, care este utilizabil în majoritatea aplicațiilor web, ceea ce la rândul său ajută programatorul să implementeze cu ușurință un sistem de conectare. La fel ca și componenta sesiune, utilizează și managerul Laravel. În prezent, componenta Auth are drivere pentru:

  • elocvent - acest lucru face uz de Laravel încorporat în ORM numit Elocvent. De asemenea, utilizează pre-fabricate User.php clasa în interiorul modele pliant.
  • Bază de date - aceasta utilizează oricare dintre conexiunile bazei de date este configurată implicit. Folosește a GenericUser pentru a accesa datele utilizatorului.

Deoarece aceasta urmează aceeași implementare ca și Sesiune componentă, furnizorul de servicii este foarte asemănător cu ceea ce am văzut în partea de sus:

/ ** * Înregistrați furnizorul de servicii. * * @return void * / registrul funcțiilor publice () $ this-> app-> bindShared ('auth', funcția ($ app) // După ce serviciul de autentificare a fost solicitat de dezvoltator // o variabilă în aplicație indicând astfel.Aceasta ne ajută să știm că trebuie să setăm cookie-urile de așteptare în evenimentul ulterior după evenimentul următor: $ app ['auth.loaded'] = true; returnați noul AuthManager ($ app);) ; 

Aici, vedem că în principiu creează un AuthManager clasa care înfășoară în jurul oricărui conducător auto pe care îl folosim, precum și acționând ca o fabrică pentru aceasta. În interiorul AuthManager, acesta creează din nou conducătorul auto adecvat, înfășurat în jurul valorii de a guard clasa, care acționează în același mod ca și Magazin clasa de la Sesiune.

Crearea funcției noastre personale

Ca și înainte, să începem prin crearea unui MongoUserProvider:

config = $ config; $ conexiune_string = 'mongodb: //'; dacă ! empty ($ this-> config ['username']) &&! empty ($ this-> config ['parola'])) $ connection_string. : $ this-> config [ 'parola'] @ ";  $ conexiune_string. = "$ this-> config ['host']"; $ this-> conexiune = nou Mongo ($ connection_string); $ this-> collection = $ this-> conexiune-> selectCollection ($ this-> config ['database'], $ this-> config ['collection']);  / ** * Returnați un utilizator prin identificatorul lor unic. ($ identifier) ​​$ user_data = $ this-> colecție-> findOne (array ('_id' => $ identifier, )); dacă (! is_null ($ user_data)) returnează genericUser generic ((array) $ user_data);  / ** * Recuperarea unui utilizator prin acreditările date. * * @param array $ credentials * @return \ Illuminate \ Auth \ UserInterface | null * / funcția publică retrieveByCredentials (array $ credentials) // Încercarea de a căuta primul utilizator indiferent de parola // Vom face asta în validateCredentials metoda dacă (isset ($ credentials ['parola'])) unset ($ credentials ['parola']);  $ user_data = $ this-> colecția-> findOne ($ credentials); dacă (! is_null ($ user_data)) returnează genericUser generic ((array) $ user_data);  / ** * Validarea unui utilizator împotriva acreditărilor date. * * @param \ Illuminate \ Auth \ UserInterface $ user * @param array $ credentials * @return bool * / funcția publică validateCredentials (UserInterface $ user, array $ credentials) if (! isset ($ credentials ['parola']) ) return false;  return ($ credentials ['parola'] === $ user-> getAuthPassword ()); 

Este important să luați notă aici că nu verifică împotriva unei parole dezordonate, acest lucru a fost făcut din simplitate pentru a face mai ușor din partea noastră să creăm date fictive și să încercăm acest lucru mai târziu. În codul de producție, trebuie să vă asigurați că aveți o parolă. Verificați Illuminate \ Auth \ DatabaseUserProvider clasa pentru un exemplu foarte bun despre cum să faceți acest lucru.

Ulterior, trebuie să înregistrăm apelul nostru personalizat pentru șofer pe AuthManager. Pentru a face acest lucru, trebuie să actualizăm furnizorul de servicii Inregistreaza-te metodă:

/ ** * Înregistrați furnizorul de servicii. * * @return void * / registrul funcțiilor publice () $ this-> app-> bindShared ('auth', funcția ($ app) // După ce serviciul de autentificare a fost solicitat de dezvoltator // o variabilă în aplicație indicând astfel.Aceasta ne ajută să // știm că trebuie să setăm toate cookie-urile de așteptare în evenimentul ulterior după evenimentul următor: $ app ['auth.loaded'] = true; $ auth_manager = new AuthManager ($ app); $ auth_manager-> extend ('mongo', functie ($ app) returneaza noul MongoUserProvider (array ('host' => $ app ['config' => $ app ['config'] -> get ('auth.mongo.assername'), 'password' => $ app [ => $ app ['config'] -> get ('auth.mongo.collection'))); ); returnați $ auth_manager;); 

În cele din urmă, trebuie, de asemenea, să actualizăm auth.php configurați fișierul pentru a utiliza driverul Mongo, precum și pentru a-i oferi valorile corecte de configurare Mongo:

'driver' => 'mongo', ... / ** * Setări Mongo DB * / 'mongo' => array (' , 'bază de date' => 'laravel', 'colecție' => 'laravel_auth_collection')

Testarea este puțin mai dificilă, pentru a face acest lucru, utilizați Mongo DB CLI pentru a insera un nou utilizator în colecție:

mongo> utilizați laravel_auth trecut la db laravel_auth> db.laravel_auth_collection.insert (id: 1, e-mail: "[email protected]", parola: "test_password")> db.laravel_auth_collection.find : ObjectId ("530c609f2caac8c3a8e4814f"), "id" 1, "email": "[email protected]", "parola": "test_password"

Acum, testați-o încercând Auth :: Validează apel de metodă:

var_dump (Auth :: validate (array ('email' => '[email protected]', 'parola' => 'test_password')));

Acest lucru ar trebui să așeze a bool (true). În caz contrar, am creat cu succes driverul nostru de Auth!

Componenta cache

Componenta Laravel Cache se ocupă de mecanismele de caching pentru a fi utilizate în cadru. Ca și cele două componente pe care le-am discutat, se folosește și Laravel Manager (Observi un model?). Componenta Cache are drivere pentru:

  • apc
  • memcached
  • Redis
  • fişier - un cache bazat pe fișiere. Datele sunt salvate în app / depozitare / cache cale.
  • Bază de date - baza de date bazată pe cache. Datele sunt salvate în rânduri în baza de date. Schema bazei de date este descrisă în Documentația Laravel.
  • mulțime - datele sunt "memorate în cache" într-un matrice. Rețineți că mulțime cache-ul nu este persistent și este șters la fiecare încărcare a paginii.

Deoarece aceasta urmează aceeași implementare cu cele două componente pe care le-am discutat, puteți presupune în siguranță că furnizorul de servicii este destul de similar:

/ ** * Înregistrați furnizorul de servicii. * * @return void * / registrul funcțiilor publice () $ this-> app-> bindShared ('cache', funcția ($ app) returnează CacheManager nou ($ app);)); $ this-> app-> bindShared ("cache.store", funcția ($ app) return $ app ['cache'] -> driver ();); $ this-> app-> bindShared ('memcached.connector', function () returnează MemcachedConnector;); $ This-> registerCommands (); 

Inregistreaza-te() metoda aici creează o CacheManager, care din nou acționează ca un înveliș și o fabrică pentru șoferi. În cadrul managerului, acesta împachetează conducătorul auto în jurul valorii de a Repertoriu clasa, similar cu Magazin și guard clase.

Crearea propriului nostru manipulator de cache

Creați MongoStore, care ar trebui să extindă Illuminate \ cache \ StoreInterface:

config = $ config; $ conexiune_string = 'mongodb: //'; dacă ! empty ($ this-> config ['username']) &&! empty ($ this-> config ['parola'])) $ connection_string. : $ this-> config [ 'parola'] @ ";  $ conexiune_string. = "$ this-> config ['host']"; $ this-> conexiune = nou Mongo ($ connection_string); $ this-> collection = $ this-> conexiune-> selectCollection ($ this-> config ['database'], $ this-> config ['collection']);  / ** * Returnați un element din memoria cache-cheie. * * @parametru șir $ cheie * @return mixt * / funcția publică obține (cheia $) $ cache_data = $ this-> getObject (cheia $); dacă (! $ cache_data) return null;  returnați neserializarea ($ cache_data ['cache_data']);  / ** * Returneaza intregul obiect in loc de doar cache_data * * @param string $ cheie * @return array | null * / functie protejata getObject ($ key) $ cache_data = $ this-> collection-> findOne ('cheie' => cheie cheie,)); dacă (is_null ($ cache_data)) return null;  dacă (isset ($ cache_data ['expire']) && time ()> = $ cache_data ['expire']) $ this-> forget (cheia $); retur nul;  return $ cache_data;  / ** * Stocați un articol în memoria cache pentru un anumit număr de minute. * * @param string $ cheie * @param amestecat $ valoare * @param int $ minutes * @return void * / funcția publică pus ($ cheie, $ valoare, $ minute) $ expiry = $ this-> expirație ($ minute ); $ this-> collection-> update (array ('key' => $ key), array ('$ set' ttl '=> ($ minute * 60))), array (' upsert '=> true,' multiple '=> false));  / ** * Creșteți valoarea unui element în memoria cache. * $ @param string $ cheie * @param mixed $ value * @return void * * @throws \ LogicException * / increment functie publica ($ key, $ value = 1) $ cache_data = $ this-> getObject ; dacă $ $ cache_data) $ new_data = array ('cache_data' => serializează ($ value), 'expire' => $ this-> expirație (0), 'ttl' );  altfel $ new_data = array ('cache_data' => serialize ($ cache_data ['cache_data']) + valoarea $), 'expire' '] / 60)),' ttl '=> $ cache_data [' ttl ']);  $ this-> colecție-> actualizare (array ('key' => key), array ('$ set' => $ new_data), array ('upsert' => true, 'multiple' => false)) ;  / ** * Descrește valoarea unui element din memoria cache. ($ key, $ value = 1) $ cache_data = $ this-> getObject (cheia $) * * @param string $ cheie * @param amestecat $ valoare * @return void * * @throws \ LogicException * ; dacă ($ $ cache_data) $ new_data = array ('cache_data' => serialize ((0 - $ value)), 'expire' expirare (0));  altfel $ new_data = array ('cache_data' => serialize ($ cache_data ['cache_data']) - $ value), 'expire' '] / 60)),' ttl '=> $ cache_data [' ttl ']);  $ this-> colecție-> actualizare (array ('key' => key), array ('$ set' => $ new_data), array ('upsert' => true, 'multiple' => false)) ;  / ** * Stocați un articol în cache pe termen nelimitat. * * @param string $ cheie * @param mixed $ value * @return void * / funcția publică pentru totdeauna ($ key, $ value) return $ this-> put ($ key, $ value, 0);  / ** * Eliminați un element din memoria cache. * * @parametru șir $ cheie * @return void * / funcția publică uită ($ key) $ this-> collection-> remove (array ('key' => key));  / ** * Eliminați toate articolele din memoria cache. * * @return void * / funcția publică flush () $ this-> collection-> remove ();  / ** * Obțineți timpul de expirare pe baza minutelor date. * * @param int $ minutes * @return int * / expirarea funcției protejate ($ minute) if ($ minutes === 0) întoarcere 9999999999; timp de întoarcere () + ($ minute * 60);  / ** * Obțineți prefixul cheii cache. * * @ string retur * / funcția publică getPrefix () return ";

De asemenea, va trebui să adăugăm din nou apelul Mongo către manager:

/ ** * Înregistrați furnizorul de servicii. * * @return void * / registrul funcțiilor publice () $ this-> app-> bindShared ('cache', funcția ($ app) $ cache_manager = new CacheManager ($ app) ', funcția ($ app) returnează noul MongoStore (array (' host '=> $ app [' config '] -> get (' cache.mongo.host ' ] -> get ('cache.mongo.assername'), 'parola' => $ app ['config'] -> get ] -> get ('cache.mongo.database'), 'colecția' => $ app ['config'] -> get ('cache.mongo.collection')));) return $ cache_manager; ; $ this-> app-> bindShared ("cache.store", funcția ($ app) return $ app ['cache'] -> driver ();); $ this-> app-> bindShared ('memcached.connector', function () returnează MemcachedConnector;); $ This-> registerCommands (); 

În cele din urmă, va trebui să actualizăm cache.php dosar de configurare:

'driver' => 'mongo', ... / ** * Setări Mongo DB * / 'mongo' => array (' , 'bază de date' => 'laravel', 'colecție' => 'laravel_cache_collection')

Acum, încercați să utilizați Cache :: pune () și Cache :: get () metode. Dacă este făcut corect, ar trebui să putem folosi MongoDB pentru a arhiva datele!

Concluzie

În acest tutorial, am aflat despre următoarele:

  • Sistemul bazat pe componente a lui Laravel Ilumina, care este folosit de cadrul Laravel.
  • Furnizorii de servicii Laravel și un pic despre cum funcționează.
  • Sistemul managerului Laravel, care acționează ca ambalaje și fabrică pentru șoferi.
  • Sesiune, Auth și Cache și cum se creează drivere noi pentru fiecare.
  • Depozitele, Garda și depozitele care utilizează aceste drivere.

Sperăm că acest lucru îi ajută pe programatori să creeze propriile drivere și să extindă funcționalitatea actuală a cadrului Laravel.

Cod