Orzan Stefanita1 [304643]
[anonimizat]. Univ. Dr. Ing. Anca Udiștoiu
Iulie 2019
[anonimizat]. Univ. Dr. Ing. Anca Udiștoiu
Iulie 2019
CRAIOVA
„Învățătura este o comoară care își urmează stăpânul pretutindeni.”
[anonimizat], student: [anonimizat], Calculatoare și Electronică a [anonimizat], [anonimizat]:
[anonimizat]. ING. [anonimizat] 2019.
[anonimizat]:
reproducerea exactă a [anonimizat]-o [anonimizat]-o [anonimizat],
[anonimizat], [anonimizat] a unor aplicații realizate de alți autori fără menționarea corectă a [anonimizat] a [anonimizat].
Pentru evitarea acestor situații neplăcute se recomandă:
plasarea între ghilimele a citatelor directe și indicarea referinței într-o [anonimizat] a [anonimizat] a sursei originale de la care s-a [anonimizat] s-[anonimizat], figuri, imagini, statistici, [anonimizat], a căror paternitate este unanim cunoscută și acceptată.
Data, Semnătura candidat: [anonimizat],
LUCRARE DE DISERTAȚIE
REFERATUL CONDUCĂTORULUI ȘTIINȚIFIC
În urma analizei lucrării candidat: [anonimizat]:
[anonimizat]:
Data, [anonimizat]. Rezumatul lucrării are menirea de a da potențialilor cititori o imagine succintă a temei abordate și a motivației alegerii acesteia, a [anonimizat] a tehnologiilor utilizate, a problemelor întâlnite pe parcursul realizării acesteia și modul de soluționare al acestora. [anonimizat].
Termenii cheie: [autorul va enumera aici cuvintele cheie ale lucrării].
MULȚUMIRI
De-a [anonimizat], [anonimizat], care s-[anonimizat], cât și la masterat. Prin prisma experiențelor din alte instituții de învățământ atât din țara cât și din afară, am realizat că avem un corp profesoral foarte bine pregătit și care se dezvoltă continuu.
Pe această cale aș vrea să mulțumesc tuturor cadrelor didactice care au contibuit la dezvoltarea mea profesională, dar și mai mult decât atâta, la dezvoltarea mea ca om. Datorez tot succesul omului care sunt acum fiecărui cadru didactic care a pus o cărămidă la temelia mea profesională.
Nu în ultimul rând aș vrea să mulțumesc doamnei Conf. Univ. Dr. Ing. Anca Udiștoiu, coordonatul lucrării de disertație, pentru tot sprijinul și toate sfaturile acordate de-a lungul studiului pentru această lucrare.
CUPRINSUL
1 Introducere 1
1.1 Scopul 1
1.2 Motivația 1
2 Convenții de redactare 2
2.1 Cerințe generale 2
2.2 Structura documentului 2
2.3 Dimensiunile lucrării 3
2.4 Elemente de tehnoredactare 3
2.5 Formulele matematice 4
2.6 Ilustrațiile 4
2.6.1 Figurile 4
2.6.2 Tabelele 4
2.6.3 Legenda (unei figuri/tabele) 6
3 Termeni de utilizare 7
3.1 Autorii 7
3.2 Licența de utilizare 7
4 Concluzii 8
5 Bibliografie 9
6 Referințe web 10
A. Codul sursă 11
B. Site-ul web al proiectului 12
C. CD / DVD 13
Index 14
LISTA FIGURILOR
Figura 1. Selectarea prin click dreapta a opțiunii „Update field” 5
Figura 2. Actualizarea întregului tabel 5
LISTA TABELELOR
Tabelul 1. Nume de utilizatori și valorile rezumat ale parolelor acestora 5
Introducere
Scopul
Scopul acestei platforme Web este de a usura cautarile utilizatorilor atunci cand doresc sa plece intr-o vacanta sau sa caute anumite informatii despre un oras dorit. Fiecare persoana care acceseaza platforma, va putea cauta unitati de cazare, bilete de avion catre o destinatie dorita si va avea acces catre o harta mai detaliata a locatiei dorite, toate acestea intr-un singur loc.
Rezervarea biletelor de avion, a locurilor de cazare, hartilor oraselor dorite si obiectivele din apropiere au devenit acum mult mai simplu de accesat datorita acestei platforme.
Motivația
Motivatia principala in realizarea acestei platforme este reducerea timpului de cautare a informatiilor dorite si evitatea accesarii a mai multor platforme web. Aceasta are roulul de a elimina orice efort suplimentar depus in cautarea vacantei dumneavoastra de vis.
Platforma este integrate cu cele mai mari site-uri de calatorie (Wizz AIR, Blue AIR, Ryanair) precum si cu unul din cele mai accesate link-uri de rezervari pentru unitatile de cazare (Booking)
tehnologii folosite
Pentru realizarea siteului am folosit ca limbaj de programare PHP, framework-ul utilizat fiind Symfony 4. Designul site-ului este realizate folosind HTML, CSS si JavaScript, mai exact Bootstrap 4.
Limbajul PHP
PHP (PHP: Hypertext Prepocessor), este un limbaj de programare de tip interpretat. Asta înseamnă că fișierele ce conțin cod-sursă PHP sunt interpretate că atare în momentul execuției, de către PHP. Așadar, pentru execuția unei porțiuni de cod PHP este folosit codul-sursă așa cum a fost scris el, și nu este transformat într-o formă intermediară (binară sau cod-mașină) cum se întâmplă la Java sau C/C++. Acest lucru oferă flexibilitate, întrucât orice modificare a fișierelor sursă va fi aplicată imediat la următoarea execuție, fără alți pași intermediari. Există și dezavantaje la acest mod de lucru, cum ar fi timp mai mare de execuție a codului, dar în anumite situații avantajele pot cântări mai mult decât dezavantajele. Datorită faptului că limbajul este unul interpretat, PHP mai este numit și limbaj de scripting.
În sens mai larg, PHP este un limbaj de programare universal (sau general-purpose), oferind toate facilitățile oricărui limbaj avansat. Codul scris în PHP poate face aproape aceleași lucruri că un cod de C/C++ sau Java. Cu toate astea, PHP s-a impus în zona web, ca limbaj server-side, ce extinde funcționalitatea serverelor web. Din acest motiv programarea în PHP mai este denumită și programare web sau programare web server-side.
Figura 1 – Deservirea unei pagini dinamice, modificata de PHP in momentul request-ul
Interpretorul PHP acționează că o componentă adițională, o extensie a serverului web care este invocată de ori câte ori o pagină PHP este accesată. Această componentă procesează codul-sursă din pagină și apoi transmite rezultatul înapoi la web-server, ajungând în final în browserele utilizatorilor.
Din imaginile de mai jos, se observă că atunci când nu există un interpretor PHP, paginile sunt transmise direct către utilizatori așa cum sunt salvate pe disc, fără modificări. Pentru a actualiza conținutul acestora, este nevoie de intervenție directă asupra lor și salvarea modificărilor pe server. Aceste pagini sunt denumite "pagini statice".
Figura 2 – Deservirea unei pagini statice, fara interventia interpretorului
Programele PHP sunt o mixtură de trei elemente : text, cod HTML și script PHP. Pentru că paginile ce conțin script PHP să poată fi procesate de modulul PHP implementat în Apache sau alt server de pagini Web este necesar ca paginile să aibă acea extensie pe care ați specificat-o la încărcarea modulului în serverul de web (standard, extensia implicită este .php).
Exemplu de program – deschideti un editor de text si scrieti :
<HTML>
<BODY>Program 1 <BR>
<?php
echo “Salut studentule !!”;
?>
</BODY>
</HTML>
Salvati acest fisier in directorul radacina al paginilor de web, sub numele de program1.php, directorul radacina al paginilor web fiind pentru htdocs, creandu-se in cadrul acestuia un folder propriu in care se vor salva toate fisierele dvs. Pentru a deschide o pagina de tip PHP se va scrie in browser-ul de Internet adresa: http://localhost/ urmat de numele directorului in care este salvat fisierul.
Funcțiile sunt porțiuni de cod definite pentru a executa anumite sarcini. Ele pot fi chemate de mai multe ori pe parcursul execuției unui program, primind argumente (valori de intrare) cu ajutorul cărora execută câteva operații după care returnează o valoare. Funcțiile transferă orice valoare primită ca argument în variabile temporare numite parametrii ce pot fi folosiți numai pe parcursul execuției funcției.
Definirea unei funcții se face astfel:
function <nume_functie> (<parametrii>)
{//cod
//cod}
Exemplu:
function tva($lei)
{$total=$lei*1.19;
return $total;}
Apelarea acestei funcții de forma: echo tva(100000); va produce rezultatul 119000. Funcția poate fi apelata si fara argumente :
function tva()
{echo “Valoarea tva este de 19%”;}
Variabilele din interiorul funcțiilor nu se pot vedea in exteriorul lor (se distrug la terminarea funcției) decat daca sunt transmise ca referința.
Variabilele pot fi :
globale
locale
Variabilele globale – sunt variabilele ce își mențin existența pe parcursul execuției întregului program, în timp ce variabilele locale sunt variabilele din interiorul funcțiilor ce își încetează existența după terminarea funcției.
Daca dorim o vizualizare globala a variabilelor locale funcției avem 2 posibilitați :
le trimitem ca referința
le asociem parametrul global inainte de a opera cu variabilele sau folosind vectorul $GLOBALS[]
Variabilele statice – sunt folosite atunci cand este necesar ca acestea sa existe pe parcursul mai multor apelari ale funcțiilor, fara a mai fi necesara o reatribuire.
<?
function vizitatori()
{return ++$vizitatori;}
?>
Rezultatul acestui exemplu este la apelul de forma: echo vizitatori(); – 1 vizitator, iar daca se mai executa inca o data atunci rezultatul va fi tot 1, deoarece variabila este statica.
Este destul ne neplacut ca pe parcursul unei numaratori sa se reseteaza variabila la fiecare apelare a funcției. Pentru a asigura persistenta variabilei, se foloseste cuvantul cheie static.
<?
function vizitatori(){
static $vizitatori;
return ++$vizitatori;}
?>
Rezultatul acestei funcții la prima apelare prin echo vizitatori(); – va fi 1 vizitator, iar prin repetarea apelulului se va afisa 2 vizitatori.
Lucrul cu clientul
PHP poate prelua interactiv datele de la client prin intermediul formularelor. Elementele cele mai importante ale unui formular sunt :
– ACTION – transmite serverului la ce pagina sa se duca si sa transmita datele completate in momentul in care utilizatorul a trimis formularul.
– METHOD – reprezinta modul in care datele sunt trimise serverului.
Metoda GET adauga variabilele in campul de adresa al paginii web.
Metoda POST trimite ascuns variabilele catre pagina descrisa la ACTION.
In cadrul formularului putem avea campuri :
text
textarea
list box (select)
radio
checkbox
hidden
password
Aceste campuri se trimit catre scriptul PHP printr-un buton de tip submit.
Limbajul HTML
Unul din primele elemente fundamentale ale WWW (World Wide Web) este HTML ( Hypertext Markup Language ), care descrie formatul primar în care documentele sunt distribuite și văzute pe Web. Multe din trăsăturile lui, cum ar fi independența față de platformă, structurarea formatării și legăturile hipertext, fac din el un foarte bun format pentru documentele Internet și Web. Primele specificații de bază ale Web-ului au fost HTML, HTTP și URL. HTML a fost dezvoltat inițial de Tim Berners-Lee la CERN în 1989. HTML a fost văzut că o posibilitate pentru fizicienii care utilizează computere diferite și schimbă între ei informație utilizând Internetul. Erau prin urmare necesare câteva trăsături : independența de platformă, posibilități hypertext și structurarea documentelor. Independența de platformă înseamnă că un document poate fi afișat în mod asemănător de computere diferite ( deci cu fonte, grafica și culori diferite ), lucru vital pentru o audienta atât de variata. Hipertext înseamnă că orice cuvânt, frază, imagine sau alt element al documentului văzut de un utilizator (client) poate face referință la un alt document, ceea ce ușurează mult navigarea între multiple documente sau chiar în interiorul unui aceluiași document. Structurarea riguroasă a documentelor permite convertirea acestora dintr-un format în altul precum și interogarea unor baze de date formate din aceste documente
Orice document HTML începe cu notația <html> și se termină cu notația </html>. Aceste "chestii" se numesc în literatura de specialitate "TAG-uri". Prin convenție, toate informațiile HTML încep cu o paranteză unghiulară deschisă " < " și se termină cu o paranteză unghiulară închisă " > ".
Tag-urile între aceste paranteze transmit comenzi către browser pentru a afișa pagina într-un anumit mod. Unele blocuri prezintă delimitator de sfârșit de bloc, în timp ce pentru alte blocuri acest delimitator este opțional sau chiar interzis.
Limbaj de marcare utilizat pentru crearea paginilor web ce pot fi afișate intr-un browser” conform Wikipedia. HTML-ul permite cu ajutorul unor metadate structurarea conținutului astfel încât să fie mai ușor de folosit de către oricine dorește să realizeze un proiect web.
HTML-ul poate fi folosit de orice utilizator capabil să înțeleagă conceptele de bază și datorită proiectării sale în format text poate fi ușor de scris în orice tip de editor, cum ar fi: Sublime, Notepad++, Brackets, etc. Scrierea paginilor presupune totuși conoașterea sintaxei și atenție la detalii pentru a nu interveni anumite greșeli care pot duce la compromiterea aplicației.
O pagină de tip HTML conține etichete și tag-uri specifice care trebuie deschise și închise pentru a păstra ordinea corectă a sintaxei.Nerespectarea acestor convenții duc la erori care pot apărea în cadrul aplicației. O pagină HTML se salvează cu extensia „htm” sau „html”.
Un document HTML este alcătuit din 3 părți:
– partea de început a limbajului folosind <html> și </html>
– partea de header folosind etichetele <header> </header>.În această secțiune aflându-se titlu aplicației dar și anumite elemente de CSS sau chiar JavaScript;
– partea de body folosind etichetele <body></body>.În această secțiunea aflându-se corpul aplicației, structurarea ei în anumite secțiuni.
Datorită evoluției atât pe partea de hardware cât si pe partea de software s-a putut ajunge la a cincea iterație a HTML-ului, HTML5 comparativ cu HTML4 introducând elemente noi in mod nativ care înainte erau disponibile prin intermediul tehnologiei Flash sau Javascript.
CSS3 (Cascading Style Sheets)
„Este un standard pentru formatarea elementelor unui document HTML” conform Wipipedia. Prima versiune a acestuia a apărut in data de December 17, 1996, fiind dezvoltat de către Håkon Wium Lie si Bert Bos.
Css-ul poate fi folosind în cadrul aplicațiilor atât în interiorul codului HTML folosind elementul <style> dar poate fi accesat și extern din alt fișier salvat cu extensia .css. Este de preferat a fi utilizat într-un fișier extern pentru o mai bună organizare si modularizare a codului, pentru a separa partea de logică de partea de user interface.
CSS3 aduce imbunatatiri de mult asteptate cum ar fi colturi rotunjite, umbre, gradienti, tranzitii si animatii.
Mai multe module sunt deja stabile :
Color Module Level 3 ( adauga proprietatea opacitate si functiile hsl(), hsla(), rgba() si rgb()
Selectors Level 3
CSS Namespaces Module
Media Queries
CSS Style Attributes
CSS Backgrounds and Borders Module Level 3
CSS Multi-column Layout Module
CSS Speech Module
CSS Image Values and Replaced Content Module Level 3
CSS Flexible Box Layout Module
CSS Conditional Rules Module Level 3
CSS Text Decoration Module Level 3
CSS Fonts Module Level 3
CSS Cascading and Inheritance Level 3
CSS Writing Modes Module Level 3
CSS Shapes Module Level 1
CSS Masking Module Level 1
Web Animations
CSS Syntax Level 3
CSS Transitions
CSS Animations
JavaScript (JS)
„Este un limbaj de programare orientat pe obiect bazat pe conceptul prototipurilor” conform Wikipedia. Este folosit mai ales pentru introducerea unor functionalități în paginile web, codul JavaScript din aceste pagini fiind rulat de către browser. Dezvoltatorul inițial a fost Brendan Eich de la Netscape Communications Corporation sub numele de Mocha, apoi LiveScript, și denumit în final JavaScript.
JavaScript conferă un caracter dinamic aplicației web facilitând relația utilizator aplicație, făcând această comunicare mult mai plăcută și mai intuitivă. Astfel, tehnici cum sunt AJAX (Asynchronous JavaScript and XML) folosite împreună cu JavaScript permit paginilor web, fără a necesita foarte multă lățime de bandă, să ceară server-ului anumite date si sa le afiseze în browser-ul utilizatorului fără a mai fi nevoie sa se reîncarce conținutul întregii pagini web, acest lucru ducând la o experiență de navigare pe Internet mult mai placută și la timpi de așteptare mult mai mici pentru a fi servită. De asemenea, și serverele care folosesc aceasta tehnică au de câștigat din moment ce nu mai este nevoie să construiască întreaga pagină web de la zero.
Fig. 4 – Cum funcționează AJAX
Pentru ca JavaScript rulează într-o varietate largă de medii, o parte importantă a testării si debugging-ului este verificarea că JavaScript funcționează pe mai multe browsere. După cum ziceam, JavaScript rulează pe partea de client (browser), de aceea o parte din puterea de procesare a server-ului web si din lațimea de bandă consumată în mod normal pentru a încărca din nou o pagină este salvată.
jQuery
Platformă de dezvoltare JavaScript, concepută pentru a ușura și îmbunătăți procese precum traversarea arborelui DOM în HTML. Jquery oferă o mulțime de facilități pentru a îmbunătăți partea vizuală și a reda un caracter dinamic aplicației.
Sintaxa jQuery este gandită pentru a fi mai ușor să navighezi printr-un document, să selectezi elemente DOM, să creezi animatii, să manipulezi evenimente și să dezvolți aplicații Ajax. Spre exemplu, jQuery poate fi folosit pentru a gasi un element cu o anumita proprietate (cum este tagul h1), pentru a schimba unul sau mai multe atribute (culoare, vizibilitate) etc.
jQuery include urmatoarele optiuni:
selectie elemente DOM
manipulare DOM bazata pe selectori CSS, cum ar fi id si class
evenimente
efecte si animatii
Ajax
parsare JSON
extensibilitate prin pluginuri
Alte avantaje ale jQuery sunt reprezentate de:
ultima versiune disponibilă in momentul actual are numai 85KB, chiar mai puțin decât o simplă imagine afișată pe website;
implementările JavaScript pot să difere în funcție de browser-ul folosit, jQuery îndepărtând acest impediment și micșorând timpul necesar dezvoltării unei aplicații și testării acesteia
sintaxa este una foarte ușor de învățat si de manipulat
există foarte multe extensii care se pot folosi împreuna cu jQuery
mai puțin cod scris comparativ cu JavaScript
Fig. 5 – Comparație complexitate JavaScript si jQuery
Bootstrap
Prezintă o colecție de instrumente folosite pentru crearea paginilor web.Este o extensie a CSS-ului. Datorită modului de ierarhizare a coloanelor Boostrap oferă un caracter responsiv site-ului permițând astfel vizualizarea aplicației pe orice tip de dispozitiv: tabletă, telefon, laptop.
Bootstrap 3 suporta ultimele versiuni ale browserelor populare cum este Google Chrome, Firefox, Internet Explorer, Opera si Safari (exceptand Windows).
De la versiunea 2.0, Bootstrap implementeaza design web responsive, paginile web ajustandu-se dinamic, tinand cont de caracteristicile dispozitivelor folosite (tablete, telefoane mobile, desktop).
Bootstrap 4 a rescris aproape in totalitate versiunea 3, printre schimbarile semnificante numarandu-se:
Incetarea suportului pentru IE8, IE9 si iOS6
Trecerea de la pixeli la ems
Schimbarea marimii fontului global de la 14px la 16px
Rescrierea aprope a tuturor componentelor, plugin-urilor jQuery si a documentatiei
Avantaje ale Bootstrap:
este ușor de folosit
ține pasul cu ultimele apariții in materie de dispozitive mobile, rămănând în continuare foarte responsive, neavând probleme cu scalarea paginilor web
este foarte customizabil, putând să alegi ce dorești sa incluzi în proiect si ce nu
suportul este excelent datorită comunității care se află într-o continuă expansiune
împachetează componente JavaScript cum ar fi alerte, ferestre modale etc
ușor de integrat
componente pre-stilizate
Serverul web Apache
Serverul de Web Apache sta la baza a peste 60% din domenii, potrivit unui studiu Netcraft Web Server. Providerii de Internet si companiile de gazduire de aplicatii pe Web apeleaza deseori la Apache din cauza suportului sau pentru numeroase platforme, capabilitatilor de gazduire virtuala usor de implementat si modulelor sale care ii extind capabilitatile.
Caracteristica Apache Portable Routine(APR) optimizeaza capabilitatile precum administrarea proceselor pentru fiecare sistem de operare, dar permite serverului propriu-zis sa ignore distinctiile specifice fiecarei platforme. Acest lucru a imbunatatit performanta si stabilitatea implementarilor Windows, prin eliminarea emulatorului. Mai mult APR este accesibil si dezvoltatorilor Web care scriu programe multi-platforme in C, care este mai rapid decit limbajele interpretative, precum PHP si Perl, folosite de obicei pentru dezvoltare Web.
La acest lucru se adauga faptul ca serverul propriu-zis este independent de protocoale. Cu toate ca este in principal un server HTTP(Web), este proiectat sa suporte alternative cum ar fi FTP. O astfel de structura simplifica administrarea si reduce riscurile de securitate. O parte insemnata din atractivitatea Apache o constituie versabilitatea sa. API-ul sau deschis a permis dezvoltatorilor sa scrie diferite module care i-au schimbat comportamentul. Daca serverului ii lipseste o functie de care are nevoie un sit, sunt mari sanse ca undeva sa fie disponibil un modul plug-in.
Serverele de Web au ca functionalitate de baza receptionarea de cereri anonime de la clienti si furnizarea de informatii intr-o maniera dorita a fi eficienta si rapida. De fapt un server Web este un daemon care accepta conexiuni conforme protocolului HTTP, raspunzind cererilor receptionate de la clienti. Pentru a asigura servicii HTTP, serverul Apache trebuie sa fie instalat in sistem(in mod uzual, fiind vorba de un pachet RPM in Linux sau de un program executabil .exe in Windows), iar daemon-ul httpd pornit. Apache este un sistem modular, alcatuit dintr-un server de baza si mai multe module care sunt incarcate dinamic intr-un mod similar cu functionarea modulelor din nucleul Linux.
Apache poate fi configurat cu ajutorul interfetei grafice apacheconf(Apache Configuration Tool). Fisierul de configurare principal este http-conf si este de obicei localizat in directorul /etc/httpd (in versiunile de Linux sau Unix).
In anumite cazuri, este necesar sa se restrictioneze accesul la anumite documente, prin intermediul autentificarii prin nume de utilizator si parola sau in functie de adresa calculatorului clientului Web.
Pentru autentificarea utilizatorilor, vom parcurge doi pasi:
Se creeaza un fisier continind numele si parolele utilizatorilor care vor avea acces la anumite date de pe serverul Web(in particular Apache)
Se configureaza serverul pentru a seta care resurse vor fi protejate si care sunt utilizatorii avind permisiunea accesarii lor, dupa introducerea unei parole valide
Configurarea serverului se poate realiza fie prin fisierul httpd-conf, fie prin .htacces, indicind o zona protejata, de obicei in functie de directoarele dorite a fi accesate pe baza de autentificare. Fisierul .htaccess va fi stocat in directorul asupra caruia dorim sa modificam comportamentul implicit al serverului Web. Inainte de a modifica maniera de autentificare din fisierul .htaccess, administratorul serverului Apache va specifica in httpd.conf ca autentificarile sa se realizeze via .htaccess.
De asemenea, Apache ofera posibilitatea de a servi mai multe site – uri Web simultan, altfel spus, gazduire virtuala(virtual hosting). Exista doua metode de implementare a gazduirii virtuale: prima bazata pe nume si a doua bazata pe adrese IP. Masinile virtuale bazate pe adresa utilizeaza adresa IP a conexiunii pentru a determina masina virtuala corecta. Astfel pentru fiecare gazduire virtuala bazata pe nume, determinarea masinii virtuale se face pe baza numelui acestuia.
Gazduirea virtuala bazata pe nume este mai simplu de implementat, si este recomandata utilizarea acesteia. Pentru a utiliza serviciul de gazduire virtuala, trebuie mai intii stabilite adresa IP si portul pentru serverul care va accepta cereri pentru respectiva masina virtuala.
Symfony
Symfony este scris în PHP urmărind modelul MVC (model-view-controller), este gratis sub licența MIT. Acest framework este open source, apărut în varianta inițială cu mai bine de zece ani în urmă (octombrie 2005) și devenit unul dintre cele mai populare framework-uri de lucru PHP datorită multiplelor facilități și a bunei documentații. Facilități:
instrumentele puternice, predefinite;
viteză, flexibilitate, componente reutilizabile;
testare;
Symfony își propune să accelereze crearea și întreținerea aplicațiilor web și să înlocuiască sarcinile de codificare repetitive.
Symfony are scopul de a construi aplicații robuste într-un context al întreprinderii și are scopul de a oferi dezvoltatorilor controlul complet asupra configurației: de la structura directoarelor la bibliotecile străine, aproape totul poate fi personalizat. Pentru a se potrivi cu instrucțiunile de dezvoltare a întreprinderii, Symfony este asociat cu instrumente suplimentare pentru a ajuta dezvoltatorii să testeze, să depaneze și să documenteze proiectele.
Symfony a fost puternic inspirată de Spring Framework.
Symfony utilizează în mare parte proiectele PHP open-source existente ca parte ale framework-ului, incluzând:
– Doctrine pentru maparea entitatilor cu tabelele bazei de date
– PHPUnit, un framework pentru testare unitara
– Twig, folosit ca templating engine
– Swift Mailer, o bibliotecă de e-mail
Symfony folosește și propriile componente, disponibile gratuit pe site-ul Symfony Components pentru diverse alte proiecte:
– Symfony YAML, un parser YAML bazat pe Spyc
– Symfony Event Dispatcher
– Symfony Dependency Injector, injector de dependență
descrierea aplicatiei
Aplicația Traveler își propune să îmbunătățească experiență utilizatorilor în ceea ce privește planificarea unei vacanțe de succes. Astfel, aplicația reunește o serie de module gândite pentru a avea la îndemână tot ceea ce îi este necesar unui utilizator pentru a realiza o vacanță de succes.
Necesitatea aceste aplicații web pornește de la ideea de a- ți planifică vacanță dintr -o singur ă aplicație , fără a mai fi nevoie pentru persoană în cauza să acceseze mai multe site – uri web și să grupeze informațiile la final. Principalele atuuri pe care o aplicație de genul Traveler sunt următoarele: – accesarea unui singur site web pentru a realiza planificarea unei vacanțe – gestionarea unui volum ridicat de informații primit de la partenerii ale căror API- uri sunt integrate – interfață intuitivă , ușor de folosit până și de utilizatorii mai puț în experimentați – accesibilitatea sporită acordată utilizatorilor de către mediul online Într- un mediu economic deosebit de dinamic, prezența pe internet este o necessitate.
Interfața aplicației este una responsive și se adaptează dispozitivului de pe care aplicația este accesat, făcând aplicația să treacă de clasică barieră în care se putea accesa un site web doar de pe un desktop cu un ecran mare și facilitând accesul de pe dispozitive de mici dimensiuni precum smartphone- uri și tablete.
De asemenea, prezentând o arhitectură scalabila și o singur ă metadata, utilizatorii pot naviga cu ușurință prin multitudinea de informații ce le este pusă la dispoziție de către partenerii aplicației prin intermediul site-ului web.
Din punctul de vedere al unui utilizator, consumul de resurse al aplicației este insesizabil, tot ceea ce se înseamnă procesarea datelor este facută de serverul Web. Această aplicațieputând fi accesată de pe orice browser. Aplicația Traveler este un produssoftware accesibil oricărei categorii de utilizatori ai unui dispozitiv inteligent .
manualul de utilizare
Meniu principal
La accesarea aplicației web utilizatorul este întâmpinat de catre meniul principal, în care se regăsesc componentele de baza ale aplicației și anume:
– Hotel Search ( funcție folosită pentru a caută hotelurile disponibile dintr -o anumită locație într -un interval de timp și un număr de persoane, date inserate de către utilizator) – Flight Search ( funcție folosită pentru a caută zboruri cu avionul)
– Car Rental ( funcție folosită pentru a lista oferte în ceea ce privește serviciile
de închirieri mașini )
– Maps( funcție folosită pentru a explora destinația inserată de către utilizator)
Figura 3 – Meniu principal
Elementele corespondente meniului principal sunt descrise de urmatoarele linii de cod:
<div class="element-animate">
<div class="nav nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
<a class="nav-link p-3 active" id="v-pills-hotel-tab" data-toggle="pill"
href="#v-pills-home"
role="tab" aria-controls="v-pills-home" aria-selected="true"><span>01</span> Hotel</a>
<a class="nav-link p-3" id="v-pills-flight-tab" data-toggle="pill" href="#v-pills-profile"
role="tab" aria-controls="v-pills-profile" aria-selected="false"><span>02</span>
Flight</a>
<a class="nav-link p-3" id="v-pills-car-tab" data-toggle="pill" href="#v-pills-car"
role="tab" aria-controls="v-pills-car" aria-selected="false"><span>03</span>
Car Rental</a>
<a class="nav-link p-3" id="v-pills-messages-tab" data-toggle="pill"
href="#v-pills-messages" role="tab" aria-controls="v-pills-messages"
aria-selected="false"><span>04</span> Maps</a>
</div>
</div>
Se va vorbi detaliat despre fiecare sectiune in parte in subcapitolele ce urmeaza.
Cautare Hotel
Căutarea de hotel permite unui utilizator să aibă acces la o multitudine de oferte din partea diverșilor parteneri ai aplicației web în ceea ce privește închirierea de proprietăți . Astfel, utilizatorul inserează datele de căutare pentru care dorește să obțină rezultate in următoarele câmpuri:
Search location (reprezintă locația inserată de către utilizator, locație pentru care vor fi căutate proprietățile)
Check-in date ( data la care se doreste realizarea cazării )
Check-out date ( data la care se doreste părăsirea proprietății)
Guest ( numarul de persoane care se vor caza într-o anumită proprietate)
Figura 4 – Cautare hoteluri
Interfață este prietenoasă cu utilizatorul, în cazul câmpurilor de tip dată se folosește datetimepicker, componentă a jQuery pentru a facilita selectarea datei dorite:
Figura 5 – Selectare data
Randarea input-urilor pentru generarea unei cautari este realizata de urmatorul fragment de cod:
<div class="tab-content py-5" id="v-pills-tabContent">
<div class="tab-pane fade show active" id="v-pills-home" role="tabpanel"
aria-labelledby="v-pills-home-tab">
<div class="block-17">
<form method="post" class="d-block d-lg-flex" id="hotel-search-form">
<div class="fields d-block d-lg-flex">
<div class="textfield-search one-third">
<input type="text" name="location" id="searched-location-id"
class="form-control" required
placeholder="Search Location">
</div>
<div class="check-in one-third">
<input type="text" name="arrivalDate" id="checkin_date" class="form-control"
placeholder="Check-in date">
</div>
<div class="check-out one-third">
<input type="text" name="departureDate" id="checkout_date"
class="form-control"
placeholder="Check-out date">
</div>
<div class="select-wrap one-third">
<div class="icon"><span class="ion-ios-arrow-down"></span></div>
<select name="guests" id="" class="form-control">
<option value="">Guest</option>
<option value="">1</option>
<option value="">2</option>
<option value="">3</option>
<option value="">4+</option>
</select>
</div>
</div>
<input id="hotel-search-submit" name="submit" type="submit"
class="search-submit btn btn-primary"
value="Find Hotels">
</form>
</div>
</div>
Sistemul de cautare hoteluri este implementat folosindu-se API-ul unui partener al Booking, API care, in functie de datele cu care este apelat, intoarce o multitudine de informatii care urmeaza sa fie procesate de catre aplicatia Traveler pentru a fi listate intr-o forma cat mai facila si „user-friendly” utilizatorului care a initiat cautarea.
Mai precis, pentru a putea fi generata o cautare considerata valida este nevoie de mai multe API call-uri. Prima serie de API call-uri este realizata pentru a valida locatiile inserate de catre utilizator.
try {
parse_str($request->query->get('formData'), $data);
$checkLocationRequest = $apiCallService->buildRequestDto(
AutoCompleteRequestDto::REQUEST_CLASS_SHORT_NAME,
array(
AutoCompleteRequestDto::LOCATION_API_KEY => $data[AutoCompleteRequestDto::LOCATION_API_KEY],
)
);
/** @var AutoCompleteResponseDto $checkLocationResult */
$checkLocationResult = $apiCallService->doRequest($checkLocationRequest);
$getHotelsRequest = $apiCallService->buildRequestDto(
ListPropertiesRequestDto::REQUEST_CLASS_SHORT_NAME,
array(
ListPropertiesRequestDto::DESTINATION => $checkLocationResult->getDestinationId(),
ListPropertiesRequestDto::CHECKIN_DATE => $data[ListPropertiesRequestDto::CHECKIN_DATE],
ListPropertiesRequestDto::CHECKOUT_DATE => $data[ListPropertiesRequestDto::CHECKOUT_DATE],
)
);
$hotelsResponse = $apiCallService->doRequest($getHotelsRequest);
return new JsonResponse(
array(
'data' => json_encode($hotelsResponse),
'error' => false,
)
);
} catch (\Throwable $t) {
return new JsonResponse(
array(
'error' => true,
'message' => $t->getMessage(),
)
);
}
Pentru a micsora timpul de implementare si complexitatea apelurilor API s-a ales abstractizarea intr-o mare masura a generarii datelor de interogare ale apelului API. Astfel, pentru a realiza un API call au fost folosite DTO-uri de tip Request si Response. Acestea inglobeaza atat proprietatile pe baza carora se va face cautarea cat si logica folosita pentru a construi apelul necesar.
Obiectul de tip Request implementeaza, in mod indirect, prin extinderea unei clase abstracte urmatoarea interfata:
interface ApiRequestInterface
{
public function getApiPath(): string;
public function getBaseUrl(): string;
public function getResponseDtoMapping(): string;
public function apiFieldsToClassPropertiesMapping(): array;
}
Interfata este menita pentru a uniformiza felul in care un obiect de tip Request arata. Astfel, prin implementarea aceste interfete se poate construi facil URL-ul catre care se va face apelul API si se pot popula cu precizie si fara efort proprietatile obiectului in cauza.
Intr-o maniera similara obiectele de tip Response implementeaza o interfata prin care sa se poata procesa raspunsul primit in urma efectuarii apelului API:
interface ApiResponseInterface
{
function processResponse();
}
Datorita implementarii interfetei este realizabila construirea obiectelor de tip Request si Response dinamic, fara a fi apelat constructorul in mod implicit:
public function buildRequestDto($className, array $properties = null)
{
$className = 'App\Dto\Request\\' . $className;
if (!new $className instanceof AbstractApiRequest) {
throw new \Exception('Class not found!');
}
$apiRequestDto = new $className;
$mappings = $apiRequestDto->apiFieldsToClassPropertiesMapping();
if (!empty($properties)) {
foreach ($properties as $key => $value) {
$setter = 'set' . ucfirst($key);
if (array_key_exists($key, $mappings)) {
$setter = 'set' . $mappings[$key];
}
if (method_exists($apiRequestDto, $setter)) {
$apiRequestDto->$setter($value);
}
}
}
return $apiRequestDto;
}
Dupa instantierea noului obiect se verifica existenta proprietatilor acestuia pentru a le seta cu datele introduce de catre utilizator. Pentru executarea request-urilor catre API endpoint s-a folosit ca librarie UniRest:
public function doRequest(AbstractApiRequest $apiRequestDto, $defaultMethod = 'get')
{
/** @var UniRestResponse $response */
$response = UniRestRequest::$defaultMethod(
$apiRequestDto->buildApiRequestUrl(),
$apiRequestDto->getRequestHeader(),
$apiRequestDto->getParameters()
);
return $this->instantiateResponseDto(
$apiRequestDto->getResponseDtoMapping(),
json_decode($response->raw_body, true)
);
}
Raspunsul oferit de catre apelul API este apoi procesat de catre Response unde sunt aplicate diverse validari pentru a extrage datele intr-un format corect:
src/Dto/Response/AutoCompleteResponseDto.php
public function processResponse(array $response = array())
{
$this->findCityDestinationType();
return $this;
}
/**
* @throws \Exception
*/
private function findCityDestinationType()
{
foreach ($this->items as $currentItem) {
$currentItem = $this->stdClassToArray($currentItem);
if ($currentItem[self::DESTINATION_TYPE_KEY] === self::DESTINATION_TYPE_CITY) {
$this->destinationName = $this->getArrayValueByKey($currentItem, self::NAME_KEY);
$this->destinationId = $this->getArrayValueByKey($currentItem, self::DESTINATION_ID_KEY);
$this->cityUfi = $this->getArrayValueByKey($currentItem, self::CITY_UFI_KEY);
break;
}
}
if ($this->destinationId === null) {
throw new \Exception('Location not found!');
}
}
src/Dto/Response/SinglePropertyResponseDto.php
public function processResponse(array $hotelDetails = array())
{
$this->processResponse($hotelDetails);
$this->hotelId = $hotelDetails[self::HOTEL_ID];
$this->hotelName = $hotelDetails[self::HOTEL_NAME];
$this->price = $hotelDetails[self::PRICE];
$this->currency = $hotelDetails[self::CURRENCY];
$this->address = $hotelDetails[self::ADDRESS];
$this->propertyUrl = $hotelDetails[self::PROPERTY_URL];
$this->distance = $hotelDetails[self::DISTANCE];
$this->mainPhoto = $this->getHigherResMainPhoto($hotelDetails[self::MAIN_PHOTO]);
$this->reviewScore = $hotelDetails[self::REVIEW_SCORE];
$this->reviewNumber = $hotelDetails[self::REVIEW_NUMBER];
}
src/Dto/Response/ListPropertiesResponseDto.php:
public function processResponse(array $data = array())
{
$this->properties = new ArrayCollection();
foreach ($data[self::RESULT] as $singleData) {
if ($singleData[SinglePropertyResponseDto::PRICE] !== 0) {
$this->properties->add(new SinglePropertyResponseDto($singleData));
}
}
return $this;
}
Randarea propriu zisa a datelor intoarse de catre API se face in JavaScript prin intermediul jQuery:
function getHotels() {
blockUi();
$.ajax({
url: Routing.generate('hotel_search'),
data: {
formData: $("#hotel-search-form").serialize(),
},
dataType: 'json',
success: function (result) {
$('.hotels-section').empty();
if (result.error) {
renderModal(result.message);
}
$.each(JSON.parse(result.data), function (key, value) {
var hotel = JSON.parse(value);
$('.hotels-section').append(buildHotelEntry(hotel));
});
unblockUi();
},
error: function (xhr, status, error) {
unblockUi();
},
});
}
function buildHotelEntry(hotel) {
return ' <div class="col-md-6 col-lg-3 ftco-animate fadeInUp ftco-animated hotel-item">\n' +
'<a target="_blank" rel="noopener noreferrer" href="' + hotel.propertyUrl + '" class="block-5"' +
' style="background-image: url(\'' + hotel.mainPhoto + '\');">\n' +
' <div class="text">\n' +
' <span class="price">' + hotel.price + ' ' + hotel.currency + '</span>\n' +
' <h3 class="heading">' +
'' + hotel.hotelName + '</h3>\n' +
' <div class="post-meta">\n' +
' <span>' + hotel.address + '</span>\n' +
' </div>\n' +
' ' + computeStars(hotel.reviewScore) +
'<span>' + hotel.reviewNumber + ' reviews</span></p>\n' +
' </div>\n' +
' </a>' +
'</div>';
}
Pentru fiecare element procesat va fi randata urmatoarea interpretare a acestuia:
Figura 6 – Rezultate cautare hoteluri – element
Utilizatorului ii este afisat pretul proprietatii, numele si adresa acestuia si numarul de review-uri:
public/js/api/hotel.js:
function computeStars(score) {
var element = '<p class="star-rate">';
for (i = 0; i < Math.floor(score / 2); i++) {
element += '<span class="icon-star"></span>';
}
if (score – Math.floor(score) >= 0.5) {
element += '<span class="icon-star-half-full"></span>';
}
return element;
}
Rezultatele unei cautari valide efectuate de catre utilizator arata astfel:
Figura 6 – Rezultate cautare hoteluri
Cautare zboruri
Cautarea de zboruri permite unui utilizator sa aiba acces la o multitudine de oferte din partea diversilor parteneri ale aplicatiei web in ceea ce priveste ofertele referitoare la . Astfel, utilizatorul insereaza datele de cautare pentru care doreste sa obtina rezultate in urmatoarele campuri:
From Location ( locatia din care utilizatorul va prelua zborul)
To Location ( locatia destinatie a utilizatorului)
Check-in date ( data de plecare)
Check-out date ( data de sosire)
Guest ( numarul de persoane)
La fel ca in cazul cautarii de hoteluri, input-urile de tip data sunt afisate intr-un mod user-friendly prin utilizarea dateTimePicker. Interfata de cautare zboruri arata astfel:
Figura 7 – Campuri cautare zboruri
Pentru a fi posibila realizarea unei accesari a API-ului care ofera date referitoare la zboruri este nevoie de generarea unei chei unice, cheie definita de catre informatiile introduse de catre utilizator in campurile de cautare.
Astfel, la fiecare cautare a utilizatorului, de fapt se fac mai multe apeluri API. Primul dintre acestea este pentru a valida locatia introdusa de catre utilizator si a o asocia codului unic prin care este definit un aeroport, conform standardului IATA.
/**
* @Route("/api/airport-code-search", options={"expose"=true}, name="code_search")
*
* @param Request $request
* @param ApiCallService $apiCallService
*
* @return JsonResponse
*
* @throws \Exception
*/
public function searchAirportCode(Request $request, ApiCallService $apiCallService): JsonResponse
{
parse_str($request->query->get('formData'), $formInput);
try {
$fromAirportSearchRequest = $apiCallService->buildRequestDto(
AirportFinderRequestDto::REQUEST_CLASS_SHORT_NAME,
array(
AirportFinderRequestDto::LOCATION => $formInput['fromLocation'],
)
);
$fromAirportResponse = $apiCallService->doRequest($fromAirportSearchRequest);
$toAirportSearchRequest = $apiCallService->buildRequestDto(
AirportFinderRequestDto::REQUEST_CLASS_SHORT_NAME,
array(
AirportFinderRequestDto::LOCATION => $formInput['toLocation'],
)
);
$toAirportResponse = $apiCallService->doRequest($toAirportSearchRequest);
return new JsonResponse(
array(
'data' => array(
'from' => json_encode($fromAirportResponse),
'to' => json_encode($toAirportResponse)
)
)
);
} catch (\Throwable $t) {
return new JsonResponse($t->getMessage());
}
}
In cazul in care nu se pot identifica aeroporturi utilizatorul va fi atentionat:
Figura 8 – Cautare zboruri, error handling
Logica de procesare si de identificare a codului unui aeroport dupa numele locatiei este urmatoarea:
src/Dto/Response/AirportFinderResponseDto.php:
/**
* @throws \Exception
*/
public function processResponse()
{
if ($this->airports->isEmpty()) {
throw new \Exception('No airport found for given location!');
}
foreach ($this->airports as $airport) {
if (array_key_exists(self::AIRPORT_KEY, $airport)) {
$this->airportId = $airport[self::AIRPORT_KEY];
}
break;
}
}
Pe parte de JavaScript, se executa un apel de tip AJAX care sa aduca informatiile despre aeroporturi pentru a fi prelucrate ulterior:
function getAirportCode() {
formData = $("#ticket-form").serialize();
$.ajax({
url: Routing.generate('code_search'),
data: {
formData: formData,
},
dataType: 'json',
success: function (result) {
if (result.error) {
renderModal(result.message);
}
fromAirportCode = JSON.parse(result.data.from).airportId;
toAirportCode = JSON.parse(result.data.to).airportId;
fetchFlightPrices(fromAirportCode, toAirportCode);
},
error: function (xhr, status, error) {
unblockUi();
},
});
}
function fetchFlightPrices(fromAirportCode, toAirportCode) {
blockUi();
$.ajax({
url: Routing.generate('fetch-price'),
data: {
formData: formData,
fromAirportCode: fromAirportCode,
toAirportCode: toAirportCode
},
success: function (result) {
if (result.error) {
renderModal(result.message);
unblockUi();
}
// $('.hotels-section').hide();
$('.tickets-section').empty();
// $('#maps').empty();
// $('.tickets-section').show();
var data = JSON.parse(result.data);
$.each(data.offers, function (key, value) {
$('.tickets-section').append(buildTicketEntry(value));
});
unblockUi();
},
error: function (xhr, status, error) {
unblockUi();
},
});
}
Dupa validarea datelor de intrare in ceea ce priveste destinatia de plecare si cea de sosire si identificarea codului unic IATA, pentru fiecare cautare se face un API call care genereaza o cheie unica la nivel de cautare. Pentru a se genera URL-ul prin care se acceseaza API-ul de generare cheie unica a fost nevoie de suprascrierea metodei de baza aferenta serviciului FlightService:
/**
* @return string
*/
public function buildApiRequestUrl(): string
{
return self::SKY_SCANNER_FLIGHT_BASE_URL . $this->getApiPath();
}
Pentru apelarea API-ului de generare token a fost folosit alt client de tip request, si anume Requests, deoarece cu Unirest serverul nu accepta request-ul si raspundea intr-un mod eronat. Astfel,
a fost necesara si implementarea acestui client:
/**
* @param AbstractApiRequest $apiRequestDto
* @param string $defaultMethod
* @param bool $isCarRental
*
* @return mixed
*
* @throws \Exception
*/
public function doSessionRequest(AbstractApiRequest $apiRequestDto, $defaultMethod = 'post', $isCarRental = false)
{
$response = \Requests::$defaultMethod(
$apiRequestDto->buildApiRequestUrl(),
$apiRequestDto->getRequestHeader(),
$apiRequestDto->getParameters()
);
return $this->extractSessionKey($response, $isCarRental);
}
Deoarece token-ul facea parte dintr-un string in care se aflau si alte informatii a fost nevoie si procesarea acestuia:
/**
* @param $response
* @param bool $isCarRental
*
* @return mixed
*
* @throws \Exception
*/
public function extractSessionKey($response, $isCarRental)
{
if ($response->success == false){
throw new \Exception($response->body);
}
$rawSessionKey = $response->headers->getValues('location')[0];
$sessionKey = explode('/', $rawSessionKey);
if (empty($sessionKey)) {
throw new \Exception('Unable to find tickets for given locations!');
}
$sessionKey = end($sessionKey);
if ($isCarRental) {
$sessionKey = strtok($sessionKey, '?');
}
return $sessionKey;
}
Token-ul unic per cautare pentru accesarea API-ului si initializarea cautarii propriu-zise se salveaza in sesiune pentru a nu fi necesara generarea acestuia de fiecare data si pentru a reduce timpul de asteptare al utilizatorului.
$sessionHash = sha1($checkInDate . $checkOutDate . $fromAirportCode . $toAirportCode . $passengerNo);
Session::init(360000);
if (Session::get($sessionHash)) {
return $sessionHash;
}
In cazul in care token-ul nu exista va fi necesara generarea acestuia si salvarea sa:
$sessionKey = $apiCallService->doSessionRequest($sessionKeyRequest, 'post');
Session::set($sessionHash, $sessionKey);
Dupa generarea token-ului se poate interoga API-ul care furnizeza datele necesare popularii aplicatiei web. Datele intoarse de API sunt procesate pentru a putea fi interpretate de catre aplicatie:
src/Dto/Response/FlightInfoResponseDto.php
/**
* @param array $response
* @throws \Exception
*/
public function processResponse(array $response = array())
{
if (empty($response[self::ITINERARIES])) {
throw new \Exception('No flights found for given date!');
}
foreach ($response[self::ITINERARIES] as $itinerary) {
foreach ($itinerary[self::PRICING] as $pricingOptions) {
$currentOffer = [
self::PRICE_KEY => $pricingOptions[self::PRICE_VALUE],
self::TICKET_URL_KEY => $pricingOptions[self::TICKET_URL_VALUE],
self::AGENT_KEY => reset($pricingOptions[self::AGENT_VALUE])
];
$this->offers[] = $currentOffer;
}
}
if (!empty($response[self::AGENT_VALUE])) {
foreach ($response[self::AGENT_VALUE] as $agent) {
$this->agents[$agent[self::ID]] = [
self::NAME_KEY => $agent[self::NAME_VALUE],
self::IMAGE_URL_KEY => $agent[self::IMAGE_URL_VALUE]
];
}
}
}
In cazul in care nu se gaseste nici-un zbor pentru informatiile introduse utilizatorul este informat:
Figura 9 – Cautare zboruri, zboruri inexistente
De asemenea, exista validari pe partea de API pentru a introduce corecte data de plecare si data de sosire:
Figura 10 – Date inserate gresit
In cazul in care se gasesc zboruri pentru datele inserate de catre utilizator acestea se vor construi pentru a fi randate de catre browser:
function buildTicketEntry(ticketData) {
return '<div class="col-sm-auto col-lg-2 ftco-animate fadeInUp ftco-animated ticket-item">\n' +
'<a target="_blank" rel="noopener noreferrer" href="' + ticketData.buyUrl + '" class="block-5" ' +
'style="background-image: url(\'' + ticketData.airLineData.imageUrl + '\');background-size:auto">\n' +
' <div class="text">\n' +
' <span class=" price" >' + ticketData.price + ' RON' + '</span>\n' +
'</div>' +
'</a>' +
'</div>';
}
Figura 12 – Element interfata cumparare bilet
Utilizatorului ii este afisat pretul biletului si compania care ii va asigura zborul:
Figura 11 – Cautare finalizata cu succes
Pentru a vedea mai multe detalii si a finaliza procesul propriu zis se da click pe optiunea aleasa:
Figura 12 – Finalizare proces cumparare bilete
Inchirieri autovehicule
Pentru a completa suita de optiuni, dupa cautarea biletelor de zbor si cumpararea acestora, aplicatia este capabila de a cauta oferte in ceea ce priveste inchirierea de autovehicule. Autovehiculele vor fi preluate de la aeroport si returnate in locul stabilit de comun acord prin aplicatie.
Astfel, utilizatorul insereaza datele de cautare pentru care doreste sa obtina rezultate in urmatoarele campuri:
Pickup place ( locatia din care utilizatorul va prelua automobilul)
Pickup date( data in care utilizatorul va prelua automobilul)
Check-out date ( data in care utilizatorul va returna automobilul)
Your age ( varsta utilizatorului)
Figura 13 – Interfata inchirieri autovehicule
Pentru a popula datele aferente meniului de inchirieri autovehicule este nevoie de nu mai putin de trei apeluri API:
Validare locatie inserata de utilizator
Generare token unic per cautare
Cautarea propriu zisa
La apasarea butonului Find Cars este folosit JavaScript pentru a asculta evenimentul on click:
$(document).ready(function () {
$("#car-search-submit").click(function (event) {
event.preventDefault();
getAirportIATA();
});
});
In functie de locatia inserata se cauta codul IATA al aeroportului:
public/js/api/flight.js:
function getAirportIATA() {
formData = $("#car-form").serialize();
$.ajax({
url: Routing.generate('airport_iata'),
data: {
data: formData,
},
dataType: 'json',
success: function (result) {
var data = JSON.parse(result.data);
getCarsOffers(data.airportId);
},
error: function (xhr, status, error) {
},
});
}
src/Controller/CarRentalController.php:
/**
* @Route("/api/airport-iata", options={"expose"=true}, name="airport_iata")
*
* @param Request $request
* @param ApiCallService $apiCallService
*
* @return JsonResponse
*/
public function getAirportIATA(Request $request, ApiCallService $apiCallService)
{
parse_str($request->query->get('data'), $formInput);
try {
$requestDto = $apiCallService->buildRequestDto(
AirportFinderRequestDto::REQUEST_CLASS_SHORT_NAME,
array(
AirportFinderRequestDto::LOCATION => $formInput['pickupPlace'],
)
);
$responseDto = $apiCallService->doRequest($requestDto);
return new JsonResponse(
array(
'error' => false,
'data' => json_encode($responseDto)
)
);
} catch (\Throwable $throwable) {
return new JsonResponse(
array(
'error' => true,
'message' => $throwable->getMessage(),
)
);
}
}
Dupa validarea cu succes a locatiei se verifica daca exista deja generat token-ul unic per cautare:
Session::init(360000);
if (Session::get($sessionHash)) {
return $sessionHash;
}
In cazul in care acesta nu exista se va face un apel API pentru generarea acestuia:
/**
* @param ApiCallService $apiCallService
* @param $request
*
* @return mixed|string|null
*
* @throws \Exception
*/
public function generateApiSessionKey(ApiCallService $apiCallService, $request)
{
parse_str($request->query->get('data'), $formInput);
$pickupPlace = $formInput['pickupPlace'];
$pickupDate = $formInput['pickupDate'] . 'T12:00';
$dropOffDate = $formInput['dropOffDate'] . 'T12:00';
$driverAge = $formInput['driverAge'];
$sessionHash = sha1($pickupPlace . $pickupDate . $dropOffDate . $driverAge);
Session::init(360000);
if (Session::get($sessionHash)) {
return $sessionHash;
}
$properties = array(
'pickupPlace' => $request->query->get('airportId'),
'dropOffPlace' => $request->query->get('airportId'),
'pickupDate' => $pickupDate,
'dropOffDate' => $dropOffDate,
"driverAge" => $driverAge,
'userIp' => self::LOCALHOST
);
$sessionKeyRequest = $apiCallService->buildRequestDto(
CarRentalSessionRequestDto::REQUEST_CLASS_SHORT_NAME,
$properties
);
$sessionKey = $apiCallService->doSessionRequest($sessionKeyRequest, 'get', true);
Session::set($sessionHash, $sessionKey);
return $sessionHash;
}
Dupa generarea token-ului unic se face apel API pentru a intoarce datele necesare popularii paginii web:
src/Controller/CarRentalController.php:
/**
* @Route("/api/rental-offers", options={"expose"=true}, name="rental_offers")
*
* @param Request $request
* @param CarRentalService $carRentalService
* @param ApiCallService $apiCallService
*
* @return JsonResponse
*/
public function getCarsOffers(Request $request, CarRentalService $carRentalService, ApiCallService $apiCallService)
{
try {
$sessionHash = $carRentalService->generateApiSessionKey($apiCallService, $request);
$response = $carRentalService->getCarsOffers($apiCallService, $sessionHash);
return new JsonResponse(
array(
'error' => false,
'data' => json_encode($response)
)
);
} catch (\Throwable $throwable) {
return new JsonResponse(
array(
'error' => true,
'message' => $throwable->getMessage()
)
);
}
}
public/js/api/flight.js:
function getCarsOffers(airportId) {
blockUi();
formData = $("#car-form").serialize();
$.ajax({
url: Routing.generate('rental_offers'),
data: {
data: formData,
airportId: airportId,
},
dataType: 'json',
success: function (result) {
if (result.error) {
renderModal(result.message);
}
var data = JSON.parse(result.data);
$.each(data.carsOffers, function (key, value) {
var car = buildCarOfferEntry(value);
if (value.imageUrl) {
$('.car-rental-section').append(car);
}
});
},
error: function (xhr, status, error) {
},
});
unblockUi();
}
Datele intoarse de API sunt filtrare si procesate pentru popularea paginii:
src/Dto/Response/CarRentalOffersResponseDto.php:
/**
* @param array $response
* @throws \Exception
*/
public function processResponse(array $response = array())
{
if (empty($response[self::CARS_API])) {
throw new \Exception('No cars were found for given dates!');
}
foreach ($response[self::CARS_API] as $car) {
$this->carsOffers[$car[self::IMAGE_ID_API]] = array(
self::IMAGE_ID_LOCAL => $car[self::IMAGE_ID_API],
self::PRICE_LOCAL => (int)$car[self::PRICE_API],
self::VEHICLE_LOCAL => $car[self::VEHICLE_API],
self::SEATS_LOCAL => $car[self::SEATS_API],
self::DOORS_LOCAL => $car[self::DOORS_API],
self::BUY_LINK_LOCAL => $car[self::BUY_LINK_API],
self::ADDRESS_LOCAL => $car['location']['pick_up']['address']
);
foreach ($response[self::IMAGES_API] as $image) {
if ($image[self::ID] === $car[self::IMAGE_ID_API]) {
$this->carsOffers[$car[self::IMAGE_ID_API]]['imageUrl'] = $image['url'];
break;
}
}
}
}
Intrarile intoarse de catre API sunt randate astfel:
function buildCarOfferEntry(car) {
return '<div class="col-sm-auto col-lg-2 ftco-animate fadeInUp ftco-animated ticket-item">\n' +
'<a target="_blank" rel="noopener noreferrer" href="' + car.buyUrl + '" class="block-5" ' +
'style="background-image: url(\'' + car.imageUrl + '\');background-size:auto">\n' +
' <div class="text">\n' +
' <span class=" price" >' + car.price + ' RON' + '</span>\n' +
' <div class="post-meta">\n' +
' <span>' + car.address + '</span>\n' +
' </div>\n' +
'<span>' + car.name + '</span></p>\n' +
'</div>' +
'</a>' +
'</div>';
}
Astfel, sunt afisate informatiile de baza despre autovehicule cum ar fi pretul de inchiriere per perioada selectat, marca masinii si adresa de preluare a masinii:
Figura 14 – Rezultare cautari inchiriere autovehicule
Rezultatul final este urmatorul:
Figura 15 – Rezultare cautari inchiriere autovehicule – wide
La apasarea pe unul dintre autovehicule se va deschide o noua fereastra pentru a vedea mai multe detalii despre autovehiculul selectat si finalizarea procesului de rezervare:
Figura 15 – Finalizare inchiriere autoturism
Cautare locatie harti
Cautarea unei locatii in tab-ul de harti ii intoarce utilizatorului o reprezentare a unei harti aferente locatiei inserate:
Figura 15 – Interfata cautare harta
Astfel, utilizator poate sa exploreze imprejurimile pentru a cauta diverse puncte de atractie pe care sa le viziteze:
Figura 15 – Rezultat cautare harta
Harta este capabila de zoom in si zoom out:
Figura 16 – Zoom in harta
De asemenea, se poate naviga prin harta, aceasta nu restrange user-ul doar la nivelul de detalii afisat anterior:
Figura 16 – Navigare harta
Termeni de utilizare
Autorii
Această aplicație a fost creată de Orzan Stefanita – Constantin , sub îndrumarea doamnei Conf. Univ. Dr. Ing. Anca Udristoiu
Licența de utilizare
Nu există restricții de utilizare. Documentul nu este constrâns de nicio licență.
Concluzii
Într-o perioada când realizarea aplicațiilor este o necesitate se remarcă o nevoie din ce în ce mai mare de programatori care să cunoască aceste limbaje de dezvoltare și a modului în care acestea se completează în vederea atingerii scopului final. Fie că este vorba despre o aplicație web acestea se completează în vederea atingerii scopului final
De aceea, pentru a oferi un grad de dinamism a datelor prezentate, o combinație de tehnologii trebuie folosite. Bazele de date oferă suportul pentru a salva și a obține informații într-un mod foarte ușor, javascript-urile sunt acele secvențe de cod care contribuie la crearea unor elemente unice în aplicație, iar limbajul PHP este ceea ce le unește pe ambele, creând o aplicație calitativă.
Lucrarea de față are scopul de prezentare a aplicației numită „Nume aplicatie”. Aplicația este prezentată printr-un exemplu elocvent, implicarea mai multor limbaje de programare pentru a atinge scopul final.
În concluzie, factorul cheie al aplicației a stat în menținerea unei idei simple cu un scop bine definit, cu un grad de interactivitate ridicat, gândită și lucrată într-un mod excepțional pentru că utilizatorii ei să fie mulțumiți.
Bibliografie
Introducere in Internet, Editura Teora, București, 1995- Popa S.
PHP and MySQL Web Development, Sams Publishing, 2001 – Luke Welling, Laura Thomson
Proiectarea bazelor de date relaționale, Editura Sitech ,1997-Giurgițeanu N.
Programarea în Web, Jamsa Press, 1996 – Kris Jamsa, Suleiman Lalani, Steve Weakley
Securitatea comerțului electronic, Editura All, 2001 – Patriciu V. V, Ene-Pietroșanu M., Bică I., Văduva C., Voicu N.
“Baze de date – Proiectare, implementare, gestionare”, T. Conolly, C. Begg, A. Strachman, Editura Teora, București, 2001
“Baze de date pentru începători”, J Patterson, Editura All, 2003
“Proceduri stocate in SQL Server, XML, HTML”, Editura Teora, 2003, traducerea I. Bedea, E. Sipos
“Teoria generală a bazelor de date”, I. Despi, G. Petrov, R. Reisz, A Stepan, Editura Mitron, Timișoara, 2000
Referințe web
https://php.net/
https://symphony.com/
https://w3schools.com/html/
https://w3schools.com/js/
Codul sursă
În această anexă se adaugă codul sursă al aplicației…
CD / DVD
Index
B
Bibliografie 9
C
CUPRINSUL xi
D
Dimensiuni 3
F
Figuri 4
Formulele matematice 4
I
Ilustrațiile 4
L
Legenda 6
LISTA FIGURILOR xii
LISTA TABELELOR xiii
R
Referințe web 10
S
Structura documentului 2
T
Tabele 5
Copyright Notice
© Licențiada.org respectă drepturile de proprietate intelectuală și așteaptă ca toți utilizatorii să facă același lucru. Dacă consideri că un conținut de pe site încalcă drepturile tale de autor, te rugăm să trimiți o notificare DMCA.
Acest articol: Orzan Stefanita1 [304643] (ID: 304643)
Dacă considerați că acest conținut vă încalcă drepturile de autor, vă rugăm să depuneți o cerere pe pagina noastră Copyright Takedown.
