Html
Model View Controller (MVC) - configurare in programarea WebModel-View-Controller (MVC)Model View Controller (MVC) este un concept foarte raspandit in programarea Web. Scopul MVC este de a ține separate logica business-ului și interfața utilizator, astfel incat cei care intrețin aplicația sa schimbe mult mai ușor o parte, fara a afecta alte parți. In MVC, modelul conține informațiile (datele) și regulile business; view conține elemente din interfața utilizator (texte, input-uri ale formularelor etc); controller-ul genstioneaza comunicația dintre model și view. In afara de MVC, Yii introduce un front-controller, cu numele application, care reprezinta contextul in care se executa procesarea cererii client. Application rezolva cererea utilizator și o trimite mai departe controller-ului corespunzator care va trata efectiv cererea. Urmatoarea diagrama din figura 2.4.1 arata structura statica a unei aplicații Yii: Structura statica a aplicației Yii
Figura 2.4.1. Fluxul tipic Urmatoarea diagrama arata fluxul tipic de lucru al unei aplicatii Yii atunci cand trateaza o cerere client: Fluxul tipic al aplicatiei Yii ApplicationApplication este locul unde se executa procesarea cererilor client. Rolul principal este analizarea cererii client și transmiterea ei la controller-ul corespunzator pentru a fi procesata in continuare. De asemenea, Application joaca un rol central pentru pastrarea configurațiilor la nivel de aplicație. De aceea, applicațion mai este numita front-controller (controller radacina, principal). Application este creata ca singleton de catre fișierul de intrare. In acest fel, accesul este posibil de oriunde via Yii::app() 1. Configurare La baza, application este o instanta a CWebApplication. Pentru customizare, in mod normal trebuie sa furnizam un fisier de configurare (care este de fapt un array) pentru a inițializa valorile proprietatților atunci cand instanta application este creata. Ca alternativa de customizare, putem extinde CwebApplication Configurația in sine este un array cu perechi key-value (cheie-valoare). Fiecare key reprezinta numele proprietații instantei application, iar valoarea reprezinta valoarea inițiala a proprietații. De exemplu, asa se configureaza proprietatile name și defaultController array( 'name'=>'Yii Framework', 'defaultController'=>'site', De obicei reținem configurația intr-un fișier PHP separat (ex.protected/config/main.php). Aici, se returneaza array-ul de configurare dupa cum urmeaza: return array(); Ca sa aplicam configurația, transmitem numele fișierului PHP ca parametru al constructorului clasei application, sau ca parametru al Yii::createWebApplication() in felul urmator (asa se face de obicei in fisierul de intrare $app=Yii::createWebApplication($configFile); Sfat: Daca aplicația are nevoie de o configurație complexa, putem sa o separam in mai multe fișiere, fiecare intorcand un array de configurare. Dupa aceea, in fișierul de configurare principal, adaugam cu include() fiecare fișier creat. 2. Application Base DirectoryApplication base directory se refera la directorul radacina care conține toate fișierele PHP care trebuie ascunse fața de clienți. Implicit, acest director este denumit protected și se afla in același director cu fișierul php accesibil clienților. Totuși, poate fi schimbat acest director prin proprietatea basePath din configura ia aplica iei Tot ce este in acest director special ar trebui protejat fata de orice client WEB. Cu Apache HTTP server protecția se face foarte simplu printr-un fișier.htaccess pus in acest director. Conținutul fișierului .htaccess este: deny from all 3. ComponenteFuncționalitatea aplicației poate fi ușor customizata și imbogațita datorita arhitecturii foarte flexibile de componente. Application gestioneaza un set de componente, fiecare implementand diverse features. De exemplu, application analizeaza o cerere client cu ajutorul componentelor CUrlManager și CHttpRequest Configurand proprietatea components, putem customiza orice valori ale componentelor folosite in aplicație. De exemplu, putem configura componenta CMemCache pentru a folosi mai multe servere memcache: array( 'components'=>array( 'cache'=>array( 'class'=>'CMemCache', 'servers'=>array( array('host'=>'server1', 'port'=>11211, 'weight'=>60), array('host'=>'server2', 'port'=>11211, 'weight'=>40), ), ), ), Adaugam elementul cache la array-ul components. Elementul cache reține clasa folosita de componenta, clasa fiind CMemCache, iar proprietarea servers ar trebui initializata in acest fel. Ca sa accesam o componenta, folosim Yii::app()->ComponentID, unde ComponentID se refera la ID-ul componentei (ex. Yii::app()->cache O componenta poate fi dezactivata atribuind lui enabled valoarea false. Daca incercam sa accesam o componenta dezactivata, atunci primim null. Implicit, componentele sunt create la cerere. Ca rezultat, componenta nu va fi creata daca nu este accesata in timpul unei cereri client. Ca rezultat, performanta per ansamblu nu va scadea, chiar daca aplicatia are o configurație cu foarte multe componente. Unele componente (ex. CLogRouter) poate ar trebui totusi sa fie create indiferent daca sunt accesate sau nu. Daca se doreste acest lucru, atunci ID-urile lor trebuie menționate in lista memorata in proprietatea preload 4. Componente nucleuYii activeaza implicit un set de componente nucleu pentru a asigura anumite features intalnite in majoritatea aplicațiilor Web. De exemplu, componenta request este folosita pentru a analiza cererile client si pentru a furniza informatii folositoare despre URL, cookies. Prin configurarea proprietatilor acestor componente nucleu, putem schimba comportamentul implicit al Yii aproape in orice privinta. Mai jos este o lista de componente nucleu care sunt pre-declarate de catre CWebApplication assetManager CassetManager - gestioneaza publicarea fișierelor private de tip asset (implicit acestea exista in directorul Asset). authManager CAuthManager - gestioneaza role-based access control (RBAC - control acces bazat pe roluri). cache CCache - asigura cache de date. Este de reținut ca trebuie specificata clasa care se va ocupa cu acest lucru (ex. CMemCache CDbCache). Altfel, atunci cand se va accesa componenta se va primi null. clientScript CClientScript -gestioneaza scripturile client (javascript si CSS). coreMessages CphpMessageSource - gestioneaza mesajele nucleu traduse folosite de platforma Yii. db CDbConnection - asigura conexiunea la baza de date. Este de reținut ca trebuie sa configuram proprietatea connectionString pentru a putea folosi aceasta componenta. errorHandler CErrorHandler - trateaza excepții si erori PHP.
messages CPhpMessageSource - gestioneaza mesaje traduse folosite de Yii. request CHttpRequest - furnizeaza informatii despre cererile client. securityManager CsecurityManager - asigura servicii de securitate, precum hashing si encryption. session CHttpSession - functionalitati la nivel de sesiune. statePersister CStatePersister -ofera o zona de date persistenta la nivel global al aplicatiei intre cererile client. urlManager CurlManager - creare si analizare URL. user CWebUser - reprezinta informatiile despre identitatea utilizatorului curent. themeManager CThemeManager - gestiune teme. 5. Ciclul de viata al aplicatieiAtunci cand se trateaza o cerere client, aplicatia va trece prin urmatoarele stadii: Seteaza tratarea de erori si autoloader-ul de clase; Inregistreaza componentele nucleu ale aplicatiei; Incarca configuratia aplicatiei; Initializeaza aplicatia cu CApplication::init() Incarca componentele statice ale aplicatiei; Activeaza evenimentul onBeginRequest Proceseaza cererea client: Analizeaza cererea client; Creaza controller-ul necesar; Ruleaza controller-ul; Activeaza evenimentul onEndRequest
Figura 2.4.2. Un utilizator face o cerere prin URL-ul https://www.example.com/index.php?r=post/show&id=1, iar serverul Web trateaza cererea prin executarea fisierul bootstrap index.php Fisierul index.php creaza o instanta application si o ruleaza. Aplicatia obtine informatii detaliate despre cererea utilizatorului de la o the detailed user request information fromcomponenta a aplicatiei cu numele request Aplicatia determina controller-ul si action-ul cu ajutorul componentei urlManager. In acest exemplu, controller-ul este post si se refera la clasa PostController; action-ul este show, iar semnificatia numelui este determinata de controller-ul in cauza. Aplicatia creaza o instanta a controller-ului necesar pentru a trata mai departe cererea. Controller-ul intelege ca show se refera la metoda cu numele actionShow din clasa controller-ului. Apoi, aplicatia creaza si executa filtrele (ex. controlul accesului, benchmarking, etc) asociate cu aceast action. Action-ul este executat daca este permis de catre filtre. Action-ul citeste din baza de date un model Post al carui ID este Action-ul genereaza un view cu numele show si cu modelul Post View-ul citeste si afiseaza atributele modelului Post View-ul executa cateva widget-uri Rezultatul generat de view este inclus intr-un layout Action-ul termina generarea view-ului si afiseaza rezultatul utilizatorului. ControllerUn controller este o instanta a clasei CController sau a unei clase derivate. Este creat de application atunci cand o cerere client are nevoie. Atunci cand ruleaza, un controller executa un action cerut de client. De obicei, action apeleaza modelele necesare si va genera un view corespunzator (rezultatul vazut de client). Un action, in cea mai simpla forma, este doar o metoda a clasei controllerului al carei nume incepe cu action Orice controller are un default action (actiune implicita). Atunci cand cererea client nu specifica ce action va fi apelat, default action va fi apelat. Implicit, default action are numele index. Dar poate fi schimbat prin setarea CController::defaultAction Mai jos este codul minim necesar pentru un controller. Din moment ce acest controller nu defineste nici un action, orice cerere pentru acest controller va genera o exceptie. class SiteController extends CController 1. RuteController-ele si action-urile sunt identificate prin ID-uri. ID-ul controller are formatulcale/catre/xyz care corespunde fisierului fizic al controller-uluiprotected/controllers/cale/catre/XyzController.php, where the token xyzshould be replaced by actual names (ex. post corespunde cuprotected/controllers/PostController.php). ID-ul action este numele metodei action fara prefixul action. De exemplu, daca o clasa controller contine o metoda cu numeleactionEdit, atunci ID-ul este edit Nota: Inainte de versiunea 1.0.3, ID-ul controller-ului era in formatul cale.catre.xyz in loc de cale/catre/xyz Utilizatorii cer un anumit controller si un anumit action prin intermediul unui route (ruta). Route este format prin concatenarea unui ID controller si al unui ID action separate prin slash (/). De exemplu, ruta post/edit se refera la controllerul PostController si la action-ul edit. Si implicit, URL-ul https://hostname/index.php?r=post/edit va cere acest controller si acest action. Nota: Implicit, rutele sunt case-sensitive. De la versiunea 1.0.1, este posibila crearea de rute case-insensitive prin setarea CUrlManager::caseSensitive cu valoarea false in configuratia aplicatiei. In modul case-insensitive, trebuie sa ne asiguram ca urmam conventia ca directoarele care contin fisierele cu clasele controller-ului sunt in lower case, si ca atat controller map cat si action map folosesc key-uri in lower case. Incepand cu versiunea 1.0.3, o aplicatie poate contine module. Ruta pentru un action dintr-un controller din interiorul unui modul are formatul moduleID/controllerID/actionID. Pentru mai multe detalii, trebuie vazuta sectiunea despre module 2. Instantierea Controller-uluiCand CWebApplication analizeaza o cerere de la client, atunci este creata o instanta a unui controller. Se primeste, prin ruta, ID-ul controller-ului, iar aplicatia va folosi urmatoarele reguli pentru a determina ce clasa controller este si unde este localizat fisierul fizic al clasei. Daca este specificat CWebApplication::catchAllRequest, va fi creat un controller pe baza acestei proprietati, iar ID-ul de controller primit de la client va fi ignorat. Aceasta este situatia cand dorim sa aducem aplicatia in modul de mentenanta, offline sau invizibila in Web in spatele unei pagini statice. Daca ID-ul este gasit in CWebApplication::controllerMap, configuratia controller-ului care este precizata acolo va fi folosita pentru a crea instanta controller-ului. Daca ID-ul este in formatul 'cale/catre/xyz', numele clasei controller-ului se presupune ca esteXyzControllersi fisierul fizic al clasei esteprotected/controllers/cale/catre/XyzController.php. De exemplu, un ID de controlleradmin.userar conduce la clasaUserControllersi la fisierul fizicprotected/controllers/admin/UserController.php`. Daca fisierul fizic al clasei nu exista, atunci se genereaza CHttpException In cazul in care modulele sunt folosite (posibil incepand cu versiunea 1.0.3), procesul de mai sus este un pic diferit. In particular, aplicatia va verifica daca ID-ul se refera la un controller din interiorul unui modul, si daca da, atunci va fi creata intai instanta modulului respectiv, iar apoi va fi creata instanta controller-ului. 3. ActionDupa cum am mentionat anterior, un action poate fi definit ca metoda al carei nume incepe cu cuvantul action. O modalitate mai avansata de a defini o clasa action este prin a cere controller-ului sa instantieze clasa action atunci cand este ceruta. Aceasta permite reutilizarea usoara in alte proiecte a clasei action, clasa action fiind independenta in felul acesta de aplicatia curenta. Pentru a defini o noua clasa action, facem urmatoarele: class UpdateAction extends CAction Pentru ca acest action sa fie vizibil de catre controller, suprascriem metoda actions() din clasa controller-ului: class PostController extends CController Mai sus, am folosit alias-ul application.controllers.post.UpdateAction pentru a specifica faptul ca fisierul fizic al clasei action este protected/controllers/post/UpdateAction.php Daca concepem action-urile fiind clase, putem sa organizam aplicatia modular. De exemplu, urmatoarea structura de directoare poate fi folosita pentru a organiza codul pentru controllere: protected/ controllers/ PostController.php UserController.php post/ CreateAction.php ReadAction.php UpdateAction.php user/ CreateAction.php ListAction.php ProfileAction.php UpdateAction.php 4. FilterFilter (filtru) este o bucata de cod care poate fi executata inainte si/sau dupa ce un action al unui controller a fost executat. De exemplu, un filtru de control de acces poate fi executat, pentru a se asigura ca utilizatorul este autentificat inainte de a executa action-ul cerut; sau un filtru de performanta poate fi folosit inainte si dupa executia unui action, pentru a masura timpul de executie al action-ului. Un action poate avea mai multe filtre. Filtrele sunt executate in ordinea in care apar in lista de filtre. Un filtru poate sa interzica executia celorlalte filtre ramase si a action-ului. Un filtru poate fi definit ca metoda in clasa controller-ului. Numele metodei trebuie sa inceapa cu filter. De exemplu, daca exista metoda filterAccessControl atunci se defineste un filtru cu numele accessControl. Metoda filtru trebuie sa fie in forma urmatoare: public function filterAccessControl($filterChain) $filterChain este o instanta a clasei CFilterChain si reprezinta o lista de filtre asociate cu action-ul cerut. In interiorul filtrului, putem apela $filterChain->run() pentru a continua filtrarea si executia action-ului. Dar un filtru poate sa fie si o instanta a clasei CFilter sau a unei clase derivate. Urmatorul cod defineste o clasa noua de filtru: class PerformanceFilter extends CFilter protected function postFilter($filterChain) Pentru a aplica filtre action-urilor, trebuie sa suprascriem metoda CController::filters(). Metoda ar trebui sa returneze un array cu configuratia filtrului. De exemplu: class PostController extends CController Codul de mai sus specifica doua filtre: postOnly si PerformanceFilter. Filtrul postOnly este definit ca metoda (metoda filtru corspunzatoare este definita deja in CController); filtrul PerformanceFilter este definit printr-o clasa. Aliasul application.filters.PerformanceFilter ne spune calea unde gasim fisierul fizic al clasei:protected/filters/PerformanceFilter. Filtrul PerformanceFilter are nevoie de un array pentru a isi initializa valorile proprietatilor. Aici, proprietatea unit din filtrul PerformanceFilterva fi initializata cu 'microsecunde' Folosind operatorii plus si minus, putem specifica la ce action-uri ar trebui aplicat (sau nu) un filtru. In codul de mai sus, filtrul postOnly va fi aplicat action-urilor edit si create, in timp ce filtrul PerformanceFilter ar trebui aplicat la toate action-urile CU EXCEPTIA action-urilor edit si create. Daca nu apare nici plus nici minus in configuratia filtrului, atunci filtrul va fi aplicat tuturor action-urilor. ModelUn model este o instanta a clasei CModel sau a unei clase derivate. Modelele sunt folosite pentru a pastra date si regulile lor de functionare relevante. Un model reprezinta un singur obiect de date. Poate fi un rand dintr-o tabela a bazei de date, sau poate fi un form cu input-uri venite de la utilizator. Fiecare camp al modelului reprezinta un atribut al modelului. Fiecare atribut are un label care poate fi validat cu un set de reguli. Yii implementeaza doua tipuri de modele: modelul form si active record. Ambele sunt derivate din aceeasi clasa de baza CModel Un model form este o instanta a clasei CFormModel. Modelul form este folosit pentru a pastra datele furnizate de utilizatorii Web. De obicei, aceste date sunt preluate, folosite, si apoi sterse. De exemplu, intr-o pagina login, putem folosi un model form care va contine numele utilizatorului si parola lui. Ele vor fi preluate de la un utilizator web. Pentru mai multe detalii, trebuie citita sectiunea Lucrul cu formularele Active Record (AR) este un concept foarte raspandit si folosit prin care se face accesul la baza de date asemanator accesului unui obiect. Fiecare obiect AR este o instanta a claseiCActiveRecord sau a unei clase derivate. Un obiect AR reprezinta un singur rand dintr-o tabela din baza de date. Campurile din acest rand sunt concepute ca proprietati ale obiectului AR. Detalii despre AR pot fi gasite in sectiunea Active Record ViewUn view este un fisier PHP care contine in principal elemente ale interfetei cu utilizatorul. Poate contine instructiuni PHP, dar este recomandat ca aceste instructiuni sa nu schimbe modelele de date si sa fie relativ simple. In spiritul de a mentine separarea intre programare si prezentare, bucatile mari de programare ar trebui puse in controller sau in model, nu in view. Un view are un nume care este folosit pentru a indentifica fisierul atunci cand trebuie generat view-ul. Numele unui view este acelasi cu numele fisierului view. De exemplu, view-ul edit se refera la un fisier view cu numele edit.php. Pentru a genera un view, apelam CController::render()cu numele view-ului. Metoda va cauta fisierul view corespunzator in directorul protected/views/ControllerID In fisierul view, putem accesa instanta controller-ului folosind $this. Putem astfel sa primim informatii din afara view-ului, in special proprietatile controller-ului, prin evaluarea $this->propertyName in interiorul view-lui. Putem de asemenea sa folosim metoda de a trimite date view-ului inainte de generarea lui: $this->render('edit', array( 'var1'=>$value1, 'var2'=>$value2, Atfel, metoda render() va extrage al doilea array de parametri. Acesti parametri vor deveni variabile in interiorul view-ului. Le vom putea accesa ca variabile locale, $var1 si $var2 1. LayoutLayout-ul este un view special. Este folosit pentru a crea un container unic pentru view-uri. Poate sa contina portiuni ale interfetei utilizator care sunt la fel in mai multe view-uri. De exemplu, un layout ar putea contine portiuni header si footer si sa includa la mijloc continutul view-ului: aici se defineste header-ul <?php echo $content; ?> aici se defineste footer-ul $content contine rezultatul generat pentru un view. Layout este implicit aplicat atunci cand se apeleaza render(). Implicit, fisierul view protected/views/layouts/main.php este folosit ca layout. Poate fi schimbat prin modificarea ori a CWebApplication::layoutori a CController::layout. Pentru a genera un view fara sa ii aplicam un layout, folosim renderPartial() 2. WidgetUn widget este o instanta a clasei CWidget sau a unei clase derivate. Este o componenta creata in special pentru scopuri de prezentare. Widget-urile sunt incluse de obicei intr-un fisier view pentru a genera unele interfete utilizator complexe, dar de sine statatoare. De exemplu, widget-ul calendar poate fi folosit pentru a genera un calendar complex. Widget-urile ajuta la o mai buna separare si reutilizare a codului din interfata utilizator. Pentru a folosi un widget intr-un fisier view, facem urmatoarele: <?php $this->beginWidget('path.to.WidgetClass'); ?> continut body care poate fi capturat de catre widget <?php $this->endWidget(); ?> sau <?php $this->widget('cale.catre.WidgetClass'); ?> A doua metoda este folosita atunci cand widget-ul nu necesita vreun continut body. Pentru a le customiza comportamentul, widget-urile pot fi configurate prin setarea valorilor initiale ale proprietatilor atunci cand se apeleazaCBaseController::beginWidget sau CBaseController::widget. De exemplu, atunci cand folosim widget-ul CMaskedTextField, am vrea sa specificam un mask care va fi folosit. Putem face acest lucru transmitand un array cu acele proprietati si cu valorile lor initiale dupa cum urmeaza: <?php $this->widget('CMaskedTextField',array( 'mask'=>'99/99/9999' ?> Ca de obicei, array-ul contine perechi key-value. Key contine numele proprietatii, iar value contine valoarea initiala a proprietatii respective. Pentru a defini un nou widget, derivam CWidget si suprascriem metodele init() si run() class MyWidget extends CWidget public function run() La fel ca un controller, un widget poate de asemenea avea un view personal. Implicit, fisierele view ale widget-urilor se gasesc in subdirectorulviews al directorului care contine fisierul clasei widget-ului. Aceste view-uri pot fi generate prin apelarea CWidget::render(), la fel ca in controller. Singura diferenta este ca la view-ul unui widget nu ii este aplicat nici un layout. 3. View-uri sistemView-urile sistem se refera la view-urile folosite de platforma Yii pentru a afisa informatii despre erori. De exemplu, atunci cand un utilizator cere un controller sau un action inexistent, Yii va genera o exceptie, prin care se explica eroarea. Yii afiseaza exceptia folosind un view sistem specific. Denumirea view-urilor sistem se face dupa unele reguli. Numele de genul errorXXX se refera la view-uri pentru afisarea ChttpException cu codul de eroare XXX. De exemplu, daca este generat CHttpException cu codul de eroare 404, atunci va fi afisat view-ul error404 Yii furnizeaza un set de view-uri sistem implicite. Acestea sunt localizate in directorul framework/views. Pot fi customizate prin crearea unor fisiere view cu acelasi nume dar in directorul protected/views/system
|