Poate că ați auzit chiar despre modele de design și chiar ați răsfoit aceste cărți minunate:
- E. Gamma, R. Helm, R. Johnson, J. Vlissides „Tehnici de proiectare orientate pe obiecte. Modele de design";
- M. Fowler „Arhitectura aplicațiilor software pentru întreprinderi”.
Acest articol va fi util în primul rând pentru începători. În orice caz, sper că în câteva ore vă veți putea face o idee despre implementarea modelului MVC, care stă la baza tuturor cadrelor web moderne și, de asemenea, să obțineți „hrană” pentru o reflecție ulterioară despre „cum să Fă-o." La sfârșitul articolului există o selecție de link-uri utile care vă vor ajuta, de asemenea, să înțelegeți în ce constau cadrele web (pe lângă MVC) și cum funcționează.
Este puțin probabil ca programatorii PHP experimentați să găsească ceva nou pentru ei înșiși în acest articol, dar comentariile și comentariile lor asupra textului principal ar fi de mare ajutor! Deoarece Fără teorie, practica este imposibilă, iar fără practică, teoria este inutilă, atunci mai întâi va fi puțină teorie și apoi vom trece la practică. Dacă sunteți deja familiarizat cu conceptul MVC, puteți sări peste secțiunea teorie și să treceți direct la practică.
1. Teorie Modelul MVC descrie o modalitate simplă de a structura o aplicație, al cărei scop este separarea logicii de afaceri de interfața cu utilizatorul. Ca rezultat, aplicația este mai ușor de scalat, testat, întreținut și, bineînțeles, implementat.Să ne uităm la diagrama conceptuală a modelului MVC (în opinia mea, aceasta este cea mai de succes diagramă pe care am văzut-o):
În arhitectura MVC, modelul oferă datele și regulile logicii de afaceri, vizualizarea este responsabilă pentru interfața cu utilizatorul, iar controlerul asigură interacțiunea între model și vizualizare.
Un flux tipic al unei aplicații MVC poate fi descris după cum urmează:
Aceasta afișează o vedere a, să zicem, pagina principală a site-ului.
care, de exemplu, conține apeluri model care citesc informații din baza de date.
Modelul nu trebuie să interacționeze direct cu utilizatorul. Toate variabilele legate de cererea utilizatorului trebuie procesate în controler.
Modelul nu trebuie să genereze HTML sau alt cod de afișare care se poate modifica în funcție de nevoile utilizatorului. Un astfel de cod ar trebui procesat în vizualizări.
Același model, de exemplu: modelul de autentificare a utilizatorului poate fi utilizat atât în partea de utilizator, cât și în partea administrativă a aplicației. În acest caz, puteți muta codul general într-o clasă separată și puteți moșteni de la acesta, definind metode specifice sub-aplicației în descendenții săi.
Vizualizare - folosit pentru a specifica afișarea externă a datelor primite de la controler și model.
Vizualizările conțin markup HTML și mici inserții de cod PHP pentru a parcurge, formata și afișa datele.
Nu ar trebui să acceseze direct baza de date. Asta ar trebui să facă modelele.
Nu ar trebui să funcționeze cu datele obținute dintr-o solicitare a utilizatorului. Această sarcină trebuie îndeplinită de controlor.
Poate accesa direct proprietățile și metodele unui controler sau modele pentru a obține date gata de ieșire.
Vizualizările sunt de obicei împărțite într-un șablon general, care conține un marcaj comun tuturor paginilor (de exemplu, un antet și un subsol) și părți ale șablonului care sunt utilizate pentru a afișa datele rezultate din model sau pentru a afișa formulare de introducere a datelor.
Controlerul este lipiciul care conectează modele, vederi și alte componente într-o aplicație de lucru. Operatorul este responsabil pentru procesarea cererilor utilizatorilor. Controlerul nu trebuie să conțină interogări SQL. Este mai bine să le păstrați în modele. Controlerul nu trebuie să conțină HTML sau alte markupuri. Merită să-l aduceți la vedere.
Într-o aplicație MVC bine proiectată, controlerele sunt de obicei foarte subțiri și conțin doar câteva zeci de linii de cod. Nu același lucru se poate spune despre Stupid Fat Controllers (SFC) în CMS Joomla. Logica controlerului este destul de tipică și cea mai mare parte este transferată la clasele de bază.
Modelele, dimpotrivă, sunt foarte groase și conțin cea mai mare parte a codului legat de prelucrarea datelor, deoarece structura datelor și logica de afaceri conținute în ele sunt de obicei destul de specifice unei anumite aplicații.
Sper că ați observat deja că diferite site-uri pot avea formate complet diferite pentru construirea barei de adrese. Fiecare format poate afișa arhitectura unei aplicații web. Deși nu este întotdeauna cazul, în majoritatea cazurilor este un fapt clar.
Să luăm în considerare două opțiuni pentru bara de adrese, care afișează un text și un profil de utilizator.
Cod de procesare aproximativ în acest caz:
comutați($_GET["acțiune"]) (case "despre": require_once("about.php"); // "Despre noi" pauză de pagină; case "contacts": require_once("contacts.php"); // „Contact” ruptură de pagină;
Cred că aproape toată lumea a făcut asta înainte.
Folosind un motor de rutare URL, vă puteți configura aplicația să accepte astfel de solicitări pentru a afișa aceleași informații:
http://www.example.com/contacts/feedback
Aici contactele reprezintă controlerul, iar feedbackul este metoda controlerului de contacte care afișează formularul de feedback etc. Vom reveni asupra acestei probleme în partea practică.
De asemenea, merită să știți că multe routere ale cadrelor web vă permit să creați rute URL personalizate (specificați ce înseamnă fiecare parte a URL-ului) și reguli pentru procesarea acestora.
Acum avem suficiente cunoștințe teoretice pentru a trece la practică.
Privind în viitor, voi spune că clasele de bază Model, View și Controller vor fi stocate în folderul de bază.
Copiii lor vor fi stocați în directoarele de controlere, modele și vizualizări. Fișierul index.php este punctul de intrare în aplicație. Fișierul bootstrap.php inițiază încărcarea aplicației, conectând toate modulele necesare etc.
Vom merge secvenţial; Să deschidem fișierul index.php și să-l completăm cu următorul cod:
ini_set("erori_afișare", 1); require_once "application/bootstrap.php";
Nu ar trebui să fie întrebări aici.
Apoi, să mergem imediat la fișierul bootstrap.php:
require_once "core/model.php"; require_once "core/view.php"; require_once "core/controller.php"; require_once "core/route.php"; Traseu::start(); //porniți routerul
Primele trei linii vor include fișiere kernel inexistente în prezent. Ultimele linii includ fișierul cu clasa de router și îl lansează pentru execuție apelând metoda static start.
RewriteEngine On RewriteCond %(REQUEST_FILENAME) !-f RewriteCond %(REQUEST_FILENAME) !-d RewriteRule .* index.php [L]
Acest cod va redirecționa toată procesarea paginii către index.php, care este ceea ce avem nevoie. Vă amintiți că în prima parte am vorbit despre Front Controller?!
Vom plasa rutarea într-un fișier separat route.php în directorul de bază. În acest fișier vom descrie clasa Route, care va rula metode de controler, care la rândul lor vor genera vizualizarea paginii.
Conținutul fișierului route.php
clasa Route (funcția statică start() ( // controler și acțiune implicită $controller_name = "Main"; $action_name = "index"; $routes = explode("/", $_SERVER["REQUEST_URI"]); // obține numele controlerului dacă (!empty($rute)) ( $nume_controller = $rute; ) // obține numele acțiunii dacă (!empty($rute)) ( $nume_acțiune = $rute; ) // adaugă prefixe $nume_model = " Model_".$controller_name = "Controller_".$controller_name = "action_".$action_name // conectați fișierul cu clasa model (poate să nu existe un fișier de model) $model_file = strtolower; ($nume_model ".php"; $model_path = "application/models/".$model_file; if(file_exists($model_path)) (include "application/models/".$model_file; ) // conectați fișierul cu clasa de controler $controller_file = strtolower ($controller_name).php"; $controller_path = "application/controllers/".$controller_file; if(file_exists($controller_path)) (include "application/controllers/".$controller_file; ) altfel ( /* ar fi corect să aruncăm o excepție aici, dar pentru a simplifica lucrurile, vom redirecționa imediat către pagina 404 */ Route::ErrorPage404(); ) // creăm un controler $controller = new $controller_name ; $action = $action_name; if(method_exists($controller, $action)) ( // apelează acțiunea controlerului $controller->$action(); ) else ( // aici ar fi, de asemenea, mai înțelept să aruncăm o excepție Route::ErrorPage404(); ) ) funcția ErrorPage404( ) ( $host = "http://".$_SERVER["HTTP_HOST"]."/"; header("HTTP/1.1 404 Nu a fost găsit"); header("Stare: 404 Nu a fost găsit") ; antet("Locație:".$gazdă."404");
Observ că clasa implementează o logică foarte simplificată (în ciuda codului voluminos) și poate avea chiar probleme de securitate. Acest lucru a fost făcut intenționat, pentru că... scrierea unei clase de rutare cu drepturi depline merită cel puțin un articol separat. Să ne uităm la punctele principale...
Elementul de matrice globală $_SERVER["REQUEST_URI"] conține adresa completă la care a contactat utilizatorul.
De exemplu: example.ru/contacts/feedback
Folosind funcția exploda Adresa este împărțită în componente. Ca rezultat, obținem numele controlerului, pentru exemplul dat, acesta este controler contacteși numele acțiunii, în cazul nostru - părere.
Apoi, fișierul model (modelul poate lipsi) și fișierul controler, dacă există, sunt conectate și, în final, este creată o instanță a controlerului și acțiunea este apelată, din nou, dacă a fost descrisă în clasa controlerului.
Astfel, atunci când mergi la, de exemplu, adresa:
exemplu.com/portfolio
sau
exemplu.com/portfolio/index
Routerul va efectua următoarele acțiuni:
exemplu.com/ufo
apoi va fi redirecționat către pagina „404”:
exemplu.com/404
Același lucru se va întâmpla dacă utilizatorul accesează o acțiune care nu este descrisă în controler.2.2. Să revenim la implementarea MVC Să mergem la folderul de bază și să adăugăm încă trei fișiere în fișierul route.php: model.php, view.php și controller.php
Permiteți-mi să vă reamintesc că vor conține clase de bază, pe care acum vom începe să le scriem.
Conținutul fișierului model.php
Model de clasă (funcția publică get_data() ( ) )
Clasa model conține o singură metodă de preluare a datelor goală, care va fi suprascrisă în clasele descendente. Când creăm clase descendente, totul va deveni mai clar.
Conținutul fișierului view.php
Vizualizare clasă ( //public $template_view; // aici puteți specifica vizualizarea generală implicită. function generate($content_view, $template_view, $data = null) ( /* if(is_array($data)) ( // convert array elemente în variabile extract($date ) */ include "application/views/".$template_view;
Nu este greu de ghicit că metoda Genera menită să formeze o vedere. Ii sunt trecuți următorii parametri:
pentru a afișa conținutul unei anumite pagini.
În cazul nostru, șablonul general va conține antet, meniu, bară laterală și subsol, iar conținutul paginii va fi conținut într-un formular separat. Din nou, acest lucru este făcut pentru simplitate.
Conținutul fișierului controller.php
Class Controller ( public $model; public $view; function __construct() ( $this->view = new View(); ) function action_index() ( ) )
Metodă action_index- aceasta este o acțiune numită implicit, o vom înlocui atunci când implementăm clasele descendente;
În figura anterioară, fișierul template_view.php este evidențiat separat - acesta este un șablon care conține un marcaj comun tuturor paginilor. În cel mai simplu caz, ar putea arăta astfel:
Acasă
Pentru a oferi site-ului un aspect prezentabil, creăm un șablon CSS și îl integrăm în site-ul nostru prin modificarea structurii marcajului HTML și conectarea fișierelor CSS și JavaScript:
La sfârșitul articolului, în secțiunea „Rezultat”, există un link către un depozit GitHub cu un proiect în care s-au făcut pași pentru integrarea unui șablon simplu.
clasa Controller_Main extinde Controller (funcția action_index() ( $this->view->generate("main_view.php", "template_view.php"); ) )
In metoda Genera sunt transmise o instanță a clasei View, numele fișierelor șablonului general și vizualizarea cu conținutul paginii.
Pe lângă acțiunea de index, controlerul poate conține desigur și alte acțiuni.
Am examinat mai devreme fișierul de vizualizare generală. Luați în considerare fișierul de conținut main_view.php:
Bine ati venit!
OLOLOSHA TEAM este o echipă de specialiști de primă clasă în domeniul dezvoltării site-urilor web cu mulți ani de experiență în colecția de măști mexicane, statui din bronz și piatră din India și Ceylon, basoreliefuri și sculpturi create de maeștrii Africii Ecuatoriale de cinci sau șase secole. în urmă...
Acesta conține un marcaj simplu, fără apeluri PHP.
Pentru a afișa pagina principală, puteți utiliza una dintre următoarele adrese:
Vom lua în considerare un exemplu folosind o vizualizare care afișează datele obținute din modelul de mai jos. 2.3.2. Creați o pagină „Portofoliu” În cazul nostru, pagina „Portofoliu” este singura pagină care utilizează modelul.
Modelul include de obicei metode de eșantionare a datelor, de exemplu:
Plasați fișierul model model_portfolio.php în folderul modele. Iată conținutul acestuia:
clasa Model_Portfolio extinde Model (funcția publică get_data() ( return array(array("Year" => "2012", "Site" => "http://DunkelBeer.ru", "Description" => "Site-ul promoțional al bere neagră Dunkel de la producătorul german Löwenbraü produsă în Rusia de compania producătoare de bere „SUN InBev.”, array(„Anul” => „2012”, „Site” => „http://ZopoMobile.ru”, „Descriere” " => "Catalogul în limba rusă de telefoane chinezești de la Zopo bazat pe sistemul de operare Android și accesorii pentru ele."), // todo ) )
Clasa model controller este conținută în fișierul controller_portfolio.php, aici este codul său:
clasa Controller_Portfolio extinde Controller ( function __construct() ( $this->model = new Model_Portfolio(); $this->view = new View(); ) function action_index() ( $data = $this->model->get_data(); ); $this->view->generate("portfolio_view.php", "template_view.php", $data ) );
La o variabilă date se scrie matricea returnată de metodă Obțineți date la care ne-am uitat mai devreme.
Această variabilă este apoi transmisă ca parametru de metodă Genera, care mai conține: numele fișierului cu șablonul general și numele fișierului care conține vizualizarea cu conținutul paginii.
Vizualizarea care conține conținutul paginii se află în fișierul portfolio_view.php.
Portofoliu
An | Proiect | Descriere |
Totul este simplu aici, vizualizarea afișează datele obținute din model. 2.3.3. Crearea paginilor rămase Paginile rămase sunt create în același mod. Codul lor este disponibil în depozitul GitHub, un link către care este furnizat la sfârșitul articolului, în secțiunea „Rezultat”.3. Rezultat Iată ce s-a întâmplat până la urmă:
Captură de ecran a site-ului web de cărți de vizită rezultat
Link GitHub: https://github.com/vitalyswipe/tinymvc/zipball/v0.1
Dar în această versiune am schițat următoarele clase (și tipurile lor corespunzătoare):
- Controller_Login în care se generează o vizualizare cu un formular de introducere a login-ului și a parolei, după completarea căreia se efectuează procedura de autentificare și, dacă reușește, utilizatorul este redirecționat către panoul de administrare.
- Contorller_Admin cu o acțiune de index care verifică dacă utilizatorul a fost autorizat anterior pe site ca administrator (dacă da, este afișată panoul de administrare) și o acțiune de deconectare pentru deconectare.
Dar, utilizarea cadrelor web precum Yii sau Kohana, constând din câteva sute de fișiere, atunci când se dezvoltă aplicații web simple (de exemplu, site-uri de cărți de vizită) nu este întotdeauna recomandabilă. Acum putem crea un model MVC frumos pentru a nu amesteca codul PHP, Html, CSS și JavaScript într-un singur fișier.
Acest articol este mai mult un punct de plecare pentru a învăța CMF decât un exemplu de ceva cu adevărat corect pe care îl puteți folosi ca bază pentru aplicația dvs. web. Poate chiar v-a inspirat și vă gândiți deja să vă scrieți propriul microframework sau CMS bazat pe MVC. Dar, înainte de a reinventa următoarea roată cu „blackjack și curve”, gândiți-vă din nou: poate ar fi mai rezonabil să vă direcționați eforturile către dezvoltarea și ajutarea comunității unui proiect deja existent?!
P.S.: Articolul a fost rescris ținând cont de unele comentarii lăsate în comentarii. Critica s-a dovedit a fi foarte utilă. Judecând după răspuns: comentarii, PM-uri și numărul de utilizatori care au adăugat postarea la favorite, ideea de a scrie această postare s-a dovedit a fi nu atât de rea. Din păcate, nu este posibil să ținem cont de toate dorințele și să scriem mai mult și mai detaliat din lipsă de timp... dar poate că acei indivizi misterioși care au votat negativ versiunea originală vor face acest lucru. Mult succes cu proiectele tale!
5. O selecție de link-uri utile pe subiect Articolul abordează foarte des subiectul cadrelor web - acesta este un subiect foarte larg, deoarece chiar și microframework-urile constau din multe componente interconectate inteligent și ar fi nevoie de mai mult de un articol pentru a vorbi despre acestea componente. Totuși, am decis să prezint aici o mică selecție de link-uri (pe care le-am urmărit în timp ce scriam acest articol) care într-un fel sau altul se referă la tema cadrelor.Etichete: Adăugați etichete
Cum se încarcă un fișier pe server folosind PHP? În acest articol vom analiza această problemă în detaliu cu exemple.
Formular HTML pentru trimiterea unui fișierPrimul lucru pe care trebuie să-l știți pentru a încărca fișiere pe server sunt caracteristicile formularelor HTML care trimit fișierul.
Iată un exemplu de cod HTML pentru acest formular:
Formular de încărcare a fișieruluiCe este unic la acest formular:
După ce serverul primește o solicitare HTTP de la un astfel de formular, acesta scrie fișierul într-un folder temporar de pe server.
Dacă doriți ca fișierul să fie salvat într-un director diferit în această etapă, specificați-l în directiva upload_tmp_dir a fișierului php.ini.
Pentru a muta un fișier încărcat într-o locație nouă, utilizați funcția move_uploaded_file.
Dar înainte de a începe să lucrăm cu această funcție, trebuie să examinăm matricea bidimensională $_FILES, prin care accesăm caracteristicile fișierului încărcat.
Deci, după ce scriptul a primit datele formularului cu fișierul transferat, a scris fișierul într-un folder special și a scris datele despre fișier într-o matrice bidimensională $_FILES .
Să ne uităm la un exemplu care afișează conținutul matricei $_FILES pe ecran.
Iată ce obținem ca rezultat al acestui script:
Fig.1. matrice $_FILES.
Acum să ne uităm la ceea ce este conținut în această matrice.
Matricea noastră bidimensională $_FILES are un element, filename . Aceasta este valoarea câmpului de nume din elementul formular:
Date pentru acest fișier:
- $_FILES["nume fișier"]["nume"] - nume fișier;
- $_FILES["nume fișier"]["tip"] - tip fișier;
- $_FILES["filename"]["tmp_name"] - calea completă către directorul temporar de pe disc;
- $_FILES["filename"]["error"] - conține codul de eroare, care este 0 dacă operația a avut succes;
- $_FILES[„nume fișier”][„dimensiune”] - dimensiunea fișierului.
Ar fi posibil să specificați două câmpuri pentru fișiere din formular, de exemplu astfel:
În acest caz, matricea noastră ar arăta astfel:
Fig.2. matrice $_FILES.
Deci, acum știm cum este structurată matricea $_FILES și următorul pas este să punem fișierul rezultat în locația de care avem nevoie.
funcția move_uploaded_fileDupă cum am scris deja, funcția move_uploaded_file este folosită pentru a muta un fișier încărcat într-o locație nouă.
Sintaxa funcției move_uploaded_file este:
move_uploaded_file (de unde să transferați, unde să transferați)
Funcția move_uploaded_file returnează o valoare booleană:
- TRUE - dacă are succes,
- FALSE - dacă primul argument este un fișier încărcat, dar din anumite motive nu poate fi mutat în locația specificată, în acest caz nu se întreprinde nicio acțiune.
Să folosim această funcție într-un exemplu:
Acest script mută imaginea în același folder în care se află ea însăși. Pentru a face acest lucru, folosim constantele încorporate PHP pentru a specifica calea:
- __DIR__ este una dintre constantele „magice”; conține directorul fișierelor.
- DIRECTORY_SEPARATOR este o constantă predefinită care conține separatorul de cale. Pentru sistemul de operare Windows este „\”, pentru sistemul de operare Linux și altele este „/”.
Notă: Dacă fișierul rezultat există deja, acesta va fi suprascris.
funcția is_uploaded_fileMai există o funcție care trebuie utilizată atunci când lucrați cu încărcarea fișierelor pe server. Aceasta este funcția is_uploaded_file și este utilizată din motive de securitate.
is_uploaded_file - Determină dacă fișierul a fost încărcat folosind HTTP POST și returnează TRUE dacă da.
Folosirea acestei funcții este utilă pentru a vă asigura că un utilizator rău intenționat nu încearcă să păcălească scriptul pentru a lucra cu fișiere pe care nu ar trebui - de exemplu, /etc/passwd.
Vă rugăm să rețineți: pentru ca funcția is_uploaded_file să funcționeze corect, trebuie să treceți calea către fișierul de stocare temporară pe server, adică un argument precum $_FILES["filename"]["tmp_name"] , dar numele lui fișierul încărcat pe computerul client ($_FILES[" filename"]["name"]) nu se aplică aici.
Exemplul nostru final de script care se ocupă de formularul de trimitere a fișierului ar arăta astfel:
Limitarea dimensiunii fișieruluiÎn unele cazuri, trebuie să limitați dimensiunea fișierului care poate fi încărcat pe server. De exemplu, pentru a permite încărcarea pe server numai fișiere care nu sunt mai mari de 3 MB, scriptul de mai sus conține codul:
Dimensiunea maximă a fișierului de încărcare poate fi setată și folosind directiva upload_max_filesize din fișierul php.ini. Valoarea implicită a acestei directive este de 2 MB:
Setări PHP.ini pentru încărcarea fișierelor pe server
Așadar, am aflat despre directiva upload_max_filesize a fișierului php.ini, care stabilește dimensiunea maximă a fișierului încărcat. Ce alte directive din fișierul php.ini sunt responsabile pentru încărcarea fișierelor pe server?
Apropo, dacă doriți să aflați unde se află fișierul dvs. php.ini, rulați scriptul:
Deci, lista de directive din fișierul php.ini:
- file_uploads - capacitatea de a interzice sau de a permite încărcarea fișierelor pe server în ansamblu, activată implicit (valoarea Activată).
- post_max_size - limita superioară generală a dimensiunii datelor transmise într-o solicitare POST. Dacă trebuie să transferați mai multe fișiere în același timp sau să lucrați cu fișiere mari, modificați valoarea acestei directive. Valoarea implicită este 8MB.
- upload_max_filesize este directiva despre care am discutat deja. Nu uitați să schimbați și post_max_size dacă este necesar.
- upload_tmp_dir - directorul temporar de pe server unde vor fi plasate toate fișierele încărcate.
Atât am vrut să vă spun la subiectul „Încărcarea fișierelor pe un server în PHP”.
În aproape fiecare tutorial sau răspuns la SO văd o modalitate comună de a trimite date de la un controler la o vizualizare, clasa View arată adesea ceva ca codul de mai jos:
Vizualizare clasă (protejat $_file; protejat $_data = array(); funcția publică __construct($fișier) ( $this->_file = $fișier; ) set de funcții publice ($cheie, $valoare) ( $this-> _data[ $cheie] = $valoare; ) funcția publică get($cheie) ( return $this->_data[$key]; ) public function output() ( dacă (!file_exists($this->_file)) (aruncă new Exception ("Șablonul " . $this->_file . " nu există." ) extract($this->_data(); include($this->_file); ); ob_end_clean();
Nu înțeleg de ce trebuie să pun datele într-o matrice și apoi să apelez extract($this -> _data). De ce nu puneți niște proprietăți direct în vizualizarea de la controler, de exemplu
$this->_view->title = "bună lume"; !}apoi în fișierul meu de aspect sau șablon aș putea pur și simplu să fac:
Echo $this->title;
Este logic să grupați în mod logic datele de vizualizare și să le distingeți de proprietățile clasei de vizualizare interioară.
PHP vă va permite să atribuiți în mod dinamic proprietăți, astfel încât să puteți instanția pur și simplu clasa View și să vă atribuiți datele ca proprietăți. Personal nu as recomanda asta. Ce se întâmplă dacă doriți să parcurgeți datele de vizualizare sau pur și simplu să le aruncați pentru depanare?
Stocarea datelor de vizualizare într-o matrice sau care conține un obiect dosn"t înseamnă că trebuie să utilizați $this->get("x") pentru a le accesa. O opțiune este să utilizați supraîncărcarea proprietății PHP5 care vă va permite să stocați datele ca o matrice, dar au o interfață $this->x cu date din șablon.
Vizualizare clasă (protejat $_data = matrice(); ... ... funcție publică __get($nume) ( if (array_key_exists($name, $this->_data)) ( returnează $this->_data[$name] ;)))
Metoda __get() va fi apelată dacă încercați să accesați o proprietate care nu există. Deci acum puteți:
$view = new View("home.php"); $view->set("titlu", "Stackoverflow");
În șablon:
Bănuiesc că motivul ar putea fi doar „a tast mai puțin”, dar are câteva efecte secundare frumoase:
- Este de ajutor atunci când cei care scriu șabloanele sunt noi în php și în acest fel nu trebuie să-și facă griji cu privire la „ce ar putea însemna acest $this->? "
- A avea un container separat pentru variabile ajută și atunci când există unele proprietăți de vizualizare care trebuie să fie private pentru acea clasă și bibliotecarii nu doresc să le expună șabloanelor
- Previne conflictele de nume cu proprietățile vizualizării native și variabilele șablonului.
- Mult mai rapid decât schemele de acces bazate pe metode. Este posibil să nu fie relevant acum, așa cum a fost atunci când, de exemplu, a fost creat smarty (a lucrat și cu php4).
Poate că ați auzit chiar despre modele de design și chiar ați răsfoit aceste cărți minunate:
- E. Gamma, R. Helm, R. Johnson, J. Vlissides „Tehnici de proiectare orientate pe obiecte. Modele de design";
- M. Fowler „Arhitectura aplicațiilor software pentru întreprinderi”.
Acest articol va fi util în primul rând pentru începători. În orice caz, sper că în câteva ore vă veți putea face o idee despre implementarea modelului MVC, care stă la baza tuturor cadrelor web moderne și, de asemenea, să obțineți „hrană” pentru o reflecție ulterioară despre „cum să Fă-o." La sfârșitul articolului există o selecție de link-uri utile care vă vor ajuta, de asemenea, să înțelegeți în ce constau cadrele web (pe lângă MVC) și cum funcționează.
Este puțin probabil ca programatorii PHP experimentați să găsească ceva nou pentru ei înșiși în acest articol, dar comentariile și comentariile lor asupra textului principal ar fi de mare ajutor! Deoarece Fără teorie, practica este imposibilă, iar fără practică, teoria este inutilă, atunci mai întâi va fi puțină teorie și apoi vom trece la practică. Dacă sunteți deja familiarizat cu conceptul MVC, puteți sări peste secțiunea teorie și să treceți direct la practică.
1. Teorie Modelul MVC descrie o modalitate simplă de a structura o aplicație, al cărei scop este separarea logicii de afaceri de interfața cu utilizatorul. Ca rezultat, aplicația este mai ușor de scalat, testat, întreținut și, bineînțeles, implementat.Să ne uităm la diagrama conceptuală a modelului MVC (în opinia mea, aceasta este cea mai de succes diagramă pe care am văzut-o):
În arhitectura MVC, modelul oferă datele și regulile logicii de afaceri, vizualizarea este responsabilă pentru interfața cu utilizatorul, iar controlerul asigură interacțiunea între model și vizualizare.
Un flux tipic al unei aplicații MVC poate fi descris după cum urmează:
Aceasta afișează o vedere a, să zicem, pagina principală a site-ului.
care, de exemplu, conține apeluri model care citesc informații din baza de date.
Modelul nu trebuie să interacționeze direct cu utilizatorul. Toate variabilele legate de cererea utilizatorului trebuie procesate în controler.
Modelul nu trebuie să genereze HTML sau alt cod de afișare care se poate modifica în funcție de nevoile utilizatorului. Un astfel de cod ar trebui procesat în vizualizări.
Același model, de exemplu: modelul de autentificare a utilizatorului poate fi utilizat atât în partea de utilizator, cât și în partea administrativă a aplicației. În acest caz, puteți muta codul general într-o clasă separată și puteți moșteni de la acesta, definind metode specifice sub-aplicației în descendenții săi.
Vizualizare - folosit pentru a specifica afișarea externă a datelor primite de la controler și model.
Vizualizările conțin markup HTML și mici inserții de cod PHP pentru a parcurge, formata și afișa datele.
Nu ar trebui să acceseze direct baza de date. Asta ar trebui să facă modelele.
Nu ar trebui să funcționeze cu datele obținute dintr-o solicitare a utilizatorului. Această sarcină trebuie îndeplinită de controlor.
Poate accesa direct proprietățile și metodele unui controler sau modele pentru a obține date gata de ieșire.
Vizualizările sunt de obicei împărțite într-un șablon general, care conține un marcaj comun tuturor paginilor (de exemplu, un antet și un subsol) și părți ale șablonului care sunt utilizate pentru a afișa datele rezultate din model sau pentru a afișa formulare de introducere a datelor.
Controlerul este lipiciul care conectează modele, vederi și alte componente într-o aplicație de lucru. Operatorul este responsabil pentru procesarea cererilor utilizatorilor. Controlerul nu trebuie să conțină interogări SQL. Este mai bine să le păstrați în modele. Controlerul nu trebuie să conțină HTML sau alte markupuri. Merită să-l aduceți la vedere.
Într-o aplicație MVC bine proiectată, controlerele sunt de obicei foarte subțiri și conțin doar câteva zeci de linii de cod. Nu același lucru se poate spune despre Stupid Fat Controllers (SFC) în CMS Joomla. Logica controlerului este destul de tipică și cea mai mare parte este transferată la clasele de bază.
Modelele, dimpotrivă, sunt foarte groase și conțin cea mai mare parte a codului legat de prelucrarea datelor, deoarece structura datelor și logica de afaceri conținute în ele sunt de obicei destul de specifice unei anumite aplicații.
Sper că ați observat deja că diferite site-uri pot avea formate complet diferite pentru construirea barei de adrese. Fiecare format poate afișa arhitectura unei aplicații web. Deși nu este întotdeauna cazul, în majoritatea cazurilor este un fapt clar.
Să luăm în considerare două opțiuni pentru bara de adrese, care afișează un text și un profil de utilizator.
Prima varianta:
A doua varianta:
Puteți vedea abordarea multi-touchpoint pe forumurile phpBB. Forumul este vizualizat prin script-ul viewforum.php, subiectul este vizualizat prin viewtopic.php etc. A doua abordare, accesată printr-un singur fișier script fizic, poate fi văzută în CMS MODX-ul meu preferat, unde toate apelurile trec prin index.php.
Aceste două abordări sunt complet diferite. Prima este tipică pentru modelul Page Controller, iar a doua abordare este implementată de modelul Front Controller. Controlerul de pagină este bun pentru site-uri cu o logică destul de simplă. La rândul său, controlorul de cereri consolidează toate activitățile de procesare a cererilor într-un singur loc, ceea ce îi oferă capabilități suplimentare care vă pot permite să implementați sarcini mai complexe decât sunt rezolvate de obicei de controlerul de pagină. Nu voi intra in detalii despre implementarea controller-ului de pagina, ci voi spune doar ca in partea practica va fi controlerul de solicitare (ceva asemanator) cel care va fi dezvoltat.
1.2. Rutarea URL Rutarea URL vă permite să configurați aplicația dvs. să accepte solicitări de la URL-uri care nu corespund fișierelor aplicației reale și să utilizați CNC-uri semnificative din punct de vedere semantic pentru utilizatori și preferate pentru optimizarea motoarelor de căutare.De exemplu, pentru o pagină obișnuită care afișează un formular de contact, adresa URL poate arăta astfel:
http://www.example.com/contacts.php?action=feedback
Cod de procesare aproximativ în acest caz:
comutați ($_GET ["acțiune" ]) (case "despre": require_once ("about.php"); // "Despre noi" ruptură de pagină; case "contacts": require_once ("contacts.php"); // pagina „Contacte” break ; case „feedback” : require_once („feedback.php” );
Cred că aproape toată lumea a făcut asta înainte.
Folosind un motor de rutare URL, vă puteți configura aplicația să accepte astfel de solicitări pentru a afișa aceleași informații:
http://www.example.com/contacts/feedback
Aici contactele reprezintă controlerul, iar feedbackul este metoda controlerului de contacte care afișează formularul de feedback etc. Vom reveni asupra acestei probleme în partea practică.
De asemenea, merită să știți că multe routere ale cadrelor web vă permit să creați rute URL personalizate (specificați ce înseamnă fiecare parte a URL-ului) și reguli pentru procesarea acestora.
Acum avem suficiente cunoștințe teoretice pentru a trece la practică.
Privind în viitor, voi spune că clasele de bază Model, View și Controller vor fi stocate în folderul de bază.
Copiii lor vor fi stocați în directoarele de controlere, modele și vizualizări. Fișierul index.php este punctul de intrare în aplicație. Fișierul bootstrap.php inițiază încărcarea aplicației, conectând toate modulele necesare etc.
Vom merge secvenţial; Să deschidem fișierul index.php și să-l completăm cu următorul cod:
ini_set("erori_afișare" , 1 ); require_once "application/bootstrap.php" ;
Nu ar trebui să fie întrebări aici.
Apoi, să mergem imediat la fișierul bootstrap.php:
require_once "core/model.php" ; require_once "core/view.php"; require_once "core/controller.php"; require_once "core/route.php"; Traseu::start(); //porniți routerul
Primele trei linii vor include fișiere kernel inexistente în prezent. Ultimele linii includ fișierul cu clasa de router și îl lansează pentru execuție apelând metoda static start.
RewriteEngine On RewriteCond %(REQUEST_FILENAME) !-f RewriteCond %(REQUEST_FILENAME) !-d RewriteRule .* index.php [L]
Acest cod va redirecționa toată procesarea paginii către index.php, care este ceea ce avem nevoie. Vă amintiți că în prima parte am vorbit despre Front Controller?!
Vom plasa rutarea într-un fișier separat route.php în directorul de bază. În acest fișier vom descrie clasa Route, care va rula metode de controler, care la rândul lor vor genera vizualizarea paginii.
Conținutul fișierului route.php
clasa Route (funcția statică start () ( // controler și acțiune implicită $controller_name = "Main" ; $action_name = "index" ; $routes = explode("/" , $_SERVER ["REQUEST_URI" ]); // obține numele controlerului dacă (!empty ($rute )) ( $nume_controller = $rute ; ) // obține numele acțiunii dacă (!gol ($rute )) ( $nume_acțiune = $rute ; ) // adaugă prefixe $nume_model = " Model_" .$controller_name ; $controller_name = "Controller_" .$controller_name ; $action_name = "action_" .$action_name .$action_name ; ($nume_model ) ".php" ; $model_path = "application/models/" .$model_file ; if (file_exists($model_path )) (include "application/models/" .$model_file ; ) // conectați fișierul cu clasa de controler $controller_file = strtolower ($controller_name).php" ; $controller_path = "application/controllers/" .$controller_file ; if (file_exists($controller_path )) (include "application/controllers/" .$controller_file ; ) altfel ( /* ar fi corect să aruncăm o excepție aici, dar pentru a simplifica lucrurile, vom redirecționa imediat către pagina 404 */ Route::ErrorPage404(); ) // creăm un controler $controller = new $controller_name ; $action = $action_name ; if (method_exists($controller , $action )) ( // apelează acțiunea controlerului $controller ->$action (); ) else ( // aici ar fi, de asemenea, mai înțelept să aruncăm o excepție Route::ErrorPage404(); ) ) funcția ErrorPage404 ( ) ( $host = "http://" .$_SERVER ["HTTP_HOST" ]."/" ; header("HTTP/1.1 404 Nu a fost găsit" ); header("Stare: 404 Negăsit" ) ; antet("Locație:" .$host ."404" ) );
Observ că clasa implementează o logică foarte simplificată (în ciuda codului voluminos) și poate avea chiar probleme de securitate. Acest lucru a fost făcut intenționat, pentru că... scrierea unei clase de rutare cu drepturi depline merită cel puțin un articol separat. Să ne uităm la punctele principale...
Elementul de matrice globală $_SERVER["REQUEST_URI"] conține adresa completă la care a contactat utilizatorul.
De exemplu: example.ru/contacts/feedback
Folosind funcția exploda Adresa este împărțită în componente. Ca rezultat, obținem numele controlerului, pentru exemplul dat, acesta este controler contacteși numele acțiunii, în cazul nostru - părere.
Apoi, fișierul model (modelul poate lipsi) și fișierul controler, dacă există, sunt conectate și, în final, este creată o instanță a controlerului și acțiunea este apelată, din nou, dacă a fost descrisă în clasa controlerului.
Astfel, atunci când mergi la, de exemplu, adresa:
exemplu.com/portfolio
sau
exemplu.com/portfolio/index
Routerul va efectua următoarele acțiuni:
exemplu.com/ufo
apoi va fi redirecționat către pagina „404”:
exemplu.com/404
Același lucru se va întâmpla dacă utilizatorul accesează o acțiune care nu este descrisă în controler.2.2. Să revenim la implementarea MVC Să mergem la folderul de bază și să adăugăm încă trei fișiere în fișierul route.php: model.php, view.php și controller.php.
Permiteți-mi să vă reamintesc că vor conține clase de bază, pe care acum vom începe să le scriem.
Conținutul fișierului model.php
Model de clasă (funcția publică get_data ( ) ( ) )
Clasa model conține o singură metodă de preluare a datelor goală, care va fi suprascrisă în clasele descendente. Când creăm clase descendente, totul va deveni mai clar.
Conținutul fișierului view.php
Vizualizare clasă ( //public $template_view; // aici puteți specifica vizualizarea generală implicită. function generate ($content_view , $template_view , $data = null) ( /* if(is_array($data)) ( // convert array elemente în variabile extract($date ) */ include "application/views/" .$template_view ;
Nu este greu de ghicit că metoda Genera menită să formeze o vedere. Ii sunt trecuți următorii parametri:
pentru a afișa conținutul unei anumite pagini.
În cazul nostru, șablonul general va conține antet, meniu, bară laterală și subsol, iar conținutul paginii va fi conținut într-un formular separat. Din nou, acest lucru este făcut pentru simplitate.
Conținutul fișierului controller.php
Controller de clasă ( public $model ; public $view ; funcția __construct () ( $this ->view = new View(); ) ) )
Metodă action_index- aceasta este acțiunea numită implicit, o vom înlocui atunci când implementăm clasele descendente;
În figura anterioară, fișierul template_view.php este evidențiat separat - acesta este un șablon care conține un marcaj comun tuturor paginilor. În cel mai simplu caz, ar putea arăta astfel:
Acasă
Pentru a oferi site-ului un aspect prezentabil, creăm un șablon CSS și îl integrăm în site-ul nostru prin modificarea structurii marcajului HTML și conectarea fișierelor CSS și JavaScript:
La sfârșitul articolului, în secțiunea „Rezultat”, există un link către un depozit GitHub cu un proiect în care s-au făcut pași pentru integrarea unui șablon simplu.
clasa Controller_Main extinde Controller (funcția action_index () ( $this ->view->generate("main_view.php" , "template_view.php" ); ) )
In metoda Genera sunt transmise o instanță a clasei View, numele fișierelor șablonului general și vizualizarea cu conținutul paginii.
Pe lângă acțiunea de index, controlerul poate conține desigur și alte acțiuni.
Am examinat mai devreme fișierul de vizualizare generală. Luați în considerare fișierul de conținut main_view.php:
Bine ati venit! OLOLOSHA TEAM este o echipă de specialiști de primă clasă în domeniul dezvoltării site-urilor web cu mulți ani de experiență în colecția de măști mexicane, statui din bronz și piatră din India și Ceylon, basoreliefuri și sculpturi create de maeștrii Africii Ecuatoriale de cinci sau șase secole. în urmă...
Acesta conține un marcaj simplu, fără apeluri PHP.
Pentru a afișa pagina principală, puteți utiliza una dintre următoarele adrese:
- metode ale bibliotecilor care implementează abstractizarea datelor. De exemplu, metode ale bibliotecii PEAR MDB2;
- metode ORM;
- metode de lucru cu NoSQL;
- si etc. Pentru simplitate, nu vom folosi aici interogări SQL sau instrucțiuni ORM. În schimb, vom emula date reale și vom returna imediat o serie de rezultate.
Plasați fișierul model model_portfolio.php în folderul modele. Iată conținutul acestuia:
clasa Model_Portfolio extinde Model ( funcția publică get_data () ( return array (matrice ("Anul" => "2012" , "Site" => "http://DunkelBeer.ru" , "Descriere" => "Site-ul promoțional al bere Dunkel neagră de la producătorul german Löwenbraü produsă în Rusia de compania de bere „SUN InBev ), matrice („Anul” => „2012” , „Site” => „http://ZopoMobile.ru” , „Descriere”. " => "Catalogul în limba rusă de telefoane chinezești de la Zopo bazat pe sistemul de operare Android și accesorii pentru ele."), // todo ) )
Clasa model controller este conținută în fișierul controller_portfolio.php, aici este codul său:
clasa Controller_Portfolio extinde Controller ( function __construct () ( $this ->model = new Model_Portfolio(); $this ->view = new View(); ) function action_index () ( $data = $this ->model->get_data(); ); $this ->view->generate("portfolio_view.php" , "template_view.php" , $data ) );
La o variabilă date se scrie matricea returnată de metodă Obțineți date la care ne-am uitat mai devreme.
Această variabilă este apoi transmisă ca parametru de metodă Genera, care mai conține: numele fișierului cu șablonul general și numele fișierului care conține vizualizarea cu conținutul paginii.
Vizualizarea care conține conținutul paginii se află în fișierul portfolio_view.php.
Portofoliu
An | Proiect | Descriere |