Aplica ție de ticket -ing ș i urmă rire a task -urilor în cadrul unei corporaț ii [626218]

Universitatea “Politehnica” din București
Facultatea de Electronică, Telecomunicații și Tehnologia Informației

Aplica ție de ticket -ing ș i urmă rire a task -urilor în cadrul unei corporaț ii

Proiect de diplomă
prezentat ca cerință parțială pentru obținer ea titlului de
Inginer în domeniul Electronică si Telecomunicații,
programul de studii de licență Tehnologii și Sisteme de Telecomunicații

Conducator științific Absolvent: [anonimizat]. Dan GALAȚCHI Constantin -Cătălin POSEA

2017

Cuprins
Introducere ………………………….. ………………………….. ………………………….. ………………………….. ………….. 13
1.Schema b azei de date cu constrângerile și legăturile necesare ………………………….. ………………………. 15
1.1Structura tabelelor ………………………….. ………………………….. ………………………….. …………………….. 15
1.1.1Tabelul user ………………………….. ………………………….. ………………………….. ……………………….. 15
1.1.2Tabelul departamente ………………………….. ………………………….. ………………………….. ………….. 16
1.1.3 Tabelul proiect ………………………….. ………………………….. ………………………….. ………………….. 16
1.1.4 Tabelul task ………………………….. ………………………….. ………………………….. ………………………. 17
1.1.5 Tabelul projectUsers ………………………….. ………………………….. ………………………….. ………….. 17
1.2Relaționările și constrângerile tabelelor ………………………….. ………………………….. ……………………. 18
1.3Programe utlizate ………………………….. ………………………….. ………………………….. ……………………… 22
1.4Diagrama relațională a bazei de date ………………………….. ………………………….. ……………………….. 22
2.Tipuri de utilizatori și drepturile acestora în cadrul aplicației ………………………….. ……………………….. 23
2.1Tipuri de utilizatori ………………………….. ………………………….. ………………………….. …………………… 23
2.2Diagrama de drepturi ………………………….. ………………………….. ………………………….. ………………… 23
2.3Matricea de drepturi în funcție de rolul utilizatorului ………………………….. ………………………….. …. 24
3.Tehnologii util izate ………………………….. ………………………….. ………………………….. ………………………… 27
3.1 Pagina web ………………………….. ………………………….. ………………………….. ………………………….. …. 27
3.2Compozitorul ………………………….. ………………………….. ………………………….. ………………………….. . 28
3.3Limbajul PHP ………………………….. ………………………….. ………………………….. ………………………….. . 28
3.3.1Introducere în PHP ………………………….. ………………………….. ………………………….. ……………… 28
3.3.2 Tipuri de dată si variabilele în PHP ………………………….. ………………………….. …………………… 29
3.3.3PHP Superglobals ………………………….. ………………………….. ………………………….. ………………. 29
3.3.4Framework -urile PHP ………………………….. ………………………….. ………………………….. …………. 30
3.4 Framework -ul Symfony : ………………………….. ………………………….. ………………………….. …………… 30
3.4.1 Introducere în Symfony ………………………….. ………………………….. ………………………….. ……… 30
3.4.2 Structura directoarelor ………………………….. ………………………….. ………………………….. ……….. 31
3.4.3 Componente ale Symfony ………………………….. ………………………….. ………………………….. …… 31
3.4.4 “Pachetele” ………………………….. ………………………….. ………………………….. ……………………….. 32
3.4.5 Integrarea framework -ului cu Doctrine ORM ………………………….. ………………………….. ……. 34
3.5Framework -ul Bootstrap ………………………….. ………………………….. ………………………….. ……………. 35
3.6HTML ………………………….. ………………………….. ………………………….. ………………………….. ………… 35
3.7JavaScript ………………………….. ………………………….. ………………………….. ………………………….. ……. 36
3.8CSS ………………………….. ………………………….. ………………………….. ………………………….. ……………. 36
3.9MySQL ………………………….. ………………………….. ………………………….. ………………………….. ………. 36
3.9.1 Introduc ere în MySQL ………………………….. ………………………….. ………………………….. ……….. 36

3.9.2 Tipuri de date în MySQL ………………………….. ………………………….. ………………………….. ……. 37
4.Implementarea și utilizarea aplicației ………………………….. ………………………….. ………………………….. .. 39
4.1Prezentare generală ………………………….. ………………………….. ………………………….. …………………… 39
4.2Pagina de înregistrare ………………………….. ………………………….. ………………………….. ………………… 40
4.3Pagina de autentificare ………………………….. ………………………….. ………………………….. ………………. 41
4.4Pagina acasă ………………………….. ………………………….. ………………………….. ………………………….. … 41
4.5Pagina utilizatorilor ………………………….. ………………………….. ………………………….. …………………… 43
4.6Pagina departamentelor ………………………….. ………………………….. ………………………….. ……………… 46
4.7Pagina proiectelor ………………………….. ………………………….. ………………………….. …………………….. 48
4.8Pagina task -urilor ………………………….. ………………………….. ………………………….. ……………………… 51
Concluzii ………………………….. ………………………….. ………………………….. ………………………….. …………….. 55
Bibliografie ………………………….. ………………………….. ………………………….. ………………………….. …………. 57
Anexa 1 ………………………….. ………………………….. ………………………….. ………………………….. ………………. 59

Listă figuri și tabele

Figura 1.1 Structura tabelului user
Figura 1.2 Structura tabelului departamente
Figura 1.3 Structura tabelului proiect
Figura 1.4 Structura tabelului task
Figura 1.5 Structura tabelului projectUsers
Figura 1.6 Diagrama relațională a baz ei de date
Figura 2.1 Diagrama de drepturi în funcție de rolul utilizatorului
Figura 3.1 Comunicația între navigatorul web și serverul web
Figura 3.2 Principiul de funcționare Doctrine
Figura 4.1 Pagina de înregistrare
Figura 4.2 Pagina de autentificare
Figura 4.3 Interfața aplicației cu rol de utilizator
Figura 4.4 Interfața aplicației cu rol de manager
Figura 4.5 Interfața aplicației cu rol de administrator
Figura 4.6 Pagina cu toți utilizatorii aplicației
Figura 4.7 Pagina de setări a utilizatorului acce sată de administrator
Figura 4.8 Pagina de setări a utilizatorului fără drept de administrator
Figura 4.9 Pagina de creare a unui departament
Figura 4.10 Pagina de vizualizare a unui departament
Figura 4.11 Pagina de editare a unui departament
Figura 4.12 Pagina de listare a departamentelor
Figura 4.13 Pagina de adăugare a unui proiect
Figura 4.14 Pagina de editare a unui proiect
Figura 4.15 Pagina de vizualizare a unui proiect
Figura 4.16 Pagina de listare a proiectelor din cadrul firmei
Figura 4.17 Pagin a de creare a unui task
Figura 4.18 Pagina de vizualizare a unui task
Figura 4.19 Pagina de editare a unui task
Figura 4.20 Pagina de listare a task -urilor existente
Tabelul 2.1 Matricea de drepturi a utilizatorilor
Tabelul 3.1 Directoare opționale într -un pachet Symfony

Listă acronime

PHP – Hypertext Preprocessor
HTML – Hypertext Markup Language
CSS – Cascading Style Sheets
HTTP – Hypertext Transfer Protocol
MVC – Model -View -Controller
DBAL – “strat” de a bstractizare pentru baza de date
URL – Uniform Resource Locator
GUI – Graphic User Interface
ACL – Acces Control List
POO – Programarea orientată pe obiecte
API – Application Programming Interface
PDO – PHP Data Objects
XML – Extensible Markup Language

13

Introducere

Această lucrare are ca scop realizarea unei aplicații web, ce are rolul de a administra și urmări task-
urile ce sunt asignate că tre utilizatori. Ierarhia utilizatorilor est e diviz ată în 3 tipuri: utilizator , manager
și administrator.

Rolul de utilizator este asignat automat c ătre un angajat atunci c ând se înregistrează, rolul de manager
este asociat unui utilizator de că tre administrator, iar administratorul re prezintă pers oana care
gestionează activitatea din firmă. În scopul realizării acestei aplicații am utilizat următoarele tehnologii:
Framework -ul Symfony, PHP, My SQL, Javascripts, HTML, CSS, etc.

În cadrul primului capitol se va prezenta schema bazei de date împreun ă cu constrângerile acesteia, dar
și legăturile dintre t abele. Tot aici se va prezenta ș i diagrama relațională a bazei de date .

În cel de -al doilea capitol se va discuta despre rolurile angajaților, precum ș i despre drepturile pe care
aceștia le au .

Cel de -al treilea capitol va cuprinde noțiuni generale despre tehnologiile utilizate,c ât și o scurtă
descriere a paginii web.

Cel de -al patrulea capitol va descrie cum a fost implementată aplicația cu ajutorul tehnologiilor
descrise în capitolul anterior, dar ș i interfața acesteia în funcție de rolul utilizatorilor.

În ultimul capitol se va vorbi despre concluziile si opinia mea personală despre aplicația dezvoltată.

14

15
1. Schema b azei de date cu constrângerile ș i legăturile necesare

1.1 Structura tabelelor

Baza de date a fost creată cu a jutorul framework -ului Symfony ș i aplicației XAMPP ce creea ză o
conexiune între framework ș i sql. Fiecare tabelă din baza de date reprezintă o entitate în S ymfony. În
cadrul fiecărei entități creat e,atunci câ nd i se adaugă un nou câmp ,trebuie să se specifice numele
câmpului , tipul de dată , dar și constrângerile ne cesare . În scopul realizării acestei aplicații web am
folosit baza de date ce cuprinde următoarele tabele:

1.1.1 Tabelul user

Tabelul user : reprezintă entitatea Base User din cadrul framework -ului symfony ș i este creată de către
acesta utilizând FOSUserBundle. FOSUserBundle este o componentă a acestui framework ce este
utilizată pentru a crea, modifica sau șterge useri dintr -o bază de date. Acesta creează automat entit atea
user, atunci câ nd este instalat în cadrul proiectului și vine cu un număr de stul de mare de coloane î n
tabel a user. Pe lângă aceste coloane, ce su nt im plicite, se pot adăuga oricâ nd altele noi.
Structura tabelului user este următoarea :

Figura 1.1 Str uctura tabelului user

Câmpurile tabelulu i user sunt id (INT – valoare întreagă), department_id (INT – valoare întreagă)
careeste cheie străină către tabelul departament , username (VARCHAR), username_canonical
(VARCHAR), email (VARCHAR), email_canonical (V ARCHAR), enabled (TINYINT), salt
(VARCHAR), password (VARCHAR), last_login (DATETIME), confirmation_token (VARCHAR),

16
password_req (DATETIME), roles (LONGTEXT), active_flag (SMALLINT), fname (VARCHAR),
lname (VARCHAR).
Cheia primară a unui tabel din baza de date are valori distincte pentru toate rândurile din tabel și are
rolul de identificator unic al acestora, iar cheia străină reprezintă câmpul ce conține valorile
corespunzătoare valorilor din cheia primară a altui tabel .

– Câmpul id din tabelul user este c heie primară.
– Câmpul department_id ce poartă constrângerea de cheie străină , poate conține valorile ce se
regăsesc și în câmpul departament_id din tabelul Departament. Aceas tă valoare este null până
când userul este inclus într -un depart ament.
– Câmpurile u sername_canonical si email_ canonical poartă constrângerea de chei unice, deoarece
nu se pot înregistra 2 utilizat ori cu același username sau acee ași adresă de email.
– Câmpul confirmation_token poartă constrângerea de cheie unică. Acesta reprezintă jetonul d e
confirmare , generat fiecărui utilizator , atunci când se utilizează înregistrarea prin confirmare a
adresei de email și trebuie să fie unic pentru fiecare utilizator în parte .

Tipul VARCHAR se folosește pentru șiruri de caractere de lungime variabilă. Proprietatea
AUTO_INCREMENT indică modul de formare a coloanei id.
Tipul de dată DATETIME utilizează TIMESTAMP și oferă posibilitatea de a data automat operațiile
de tip “creează ” și “update ”, implicit este format din 14 caractere pentru formatul
‘YYYYMMDDhh mmss’ , dar putem specifica la crearea tabelului câte caractere să conțină. Câmpurile
ce au bifată coloana cu allow nulls specifică faptul că acele câmpuri pot primi ca intrări valori de null.

1.1.2 Tabelul departamente

Tabelul d epartamente este compus din câmpurile :id (INT) ce are proprietatea de
AUTO_INCREMENT , dar și de cheie primară, departament_manager ce are proprietatea de cheie
străină către tabelul User (deoarece un departament are un manager, care este un utilizator cu rol de
manager) , nume (VAR CHAR), organization_id (INT), created (DATETIME), updated (DATETIME)
și status (INT).

Figura 1.2 Structura tabelului departamente
1.1.3 Tabelul proiect

Tabelul proiect are în componența sa câmpurile id (INT) ,ce este cheie primară , nume (VARCHAR),
created (DATETIME), updated (DATETIME), desc riere (VARCHAR) și status (INT).

17

Figura 1.3 Structura tabelului proiect

1.1.4 Tabelul task

Tabelul taskeste format din câmpurile : id (INT), assigned_to_id (INT) și assigned_by_id (INT) ce sunt
chei străine căt re tabelul user , proi ect_id (INT) este cheiestrăină către tabelul proiect, title
(VARCHAR), description (VARCHAR), status (INT), created_at și updated_ at car e sunt de tipul
DATETIME și se setează automat a tunci când se inserează sau se updatează un task , priority (INT),
estimated_time (INT) . Câmpurile assigned_to_id și assigned_by_id sunt chei străine și pot conține
valorile ce se află în cheia primară “id” din tabelul User, iar câmpul proiect_id este tot cheie străină ce
poate conține valorile din cheia pr imară “proiect_id” a tabelul ui Proiect. Câmpurile priority și
estimated_time sunt s etate de un utilizator atunci câ nd creează un task.

Figura 1.4 Structura tabelului task

1.1.5 Tabelul projectUsers

Tabelul ProjectUsers este alcătuit din câmpurile: id (INT) ce este cheie primară, proiect_id (INT) ce are
proprietatea de cheie străină către tabelul Proiect, user_id (INT) ce este cheie străină către tabelul User
și câmpul is_owner, care es te de tip boolean și ne ajută să monitorizăm cine a creat proiect ul. Acest

18
tabel este utilizat pentru a putea alcătui o echipă atunci când se creează un proiect și pentru a putea
monitoriza această echipă pentru fiecare proiect în parte.

Figura 1.5 Structura tabelului projectUsers

1.1.6 Tabelul file

Tabelul file este al cătuit din câmpurile id (INT), basename (VARCHAR), filename (VARCHAR),
ref_id (INT), ref_type (VARCHAR), size (INT), extension (VARCHAR), iar created_at și updated_at
sunt de tipul DATETIME. Tabelul file se relaționează cu alte tabele prin 2 coloane: ref_i d și ref_type.
Câmpul ref_type reprezintă entitatea cu care fișierul se relaționează, iar câmpul ref_id este id -ul
entității relaționate.

Figura 1.6 Structura tabelului file

1.2 Relaționările și constrângerile tabelelor

Relaționările și constrângeril e ce se fac între tabelele bazei de date se reali zează î n cadrul
fiecărei entități create în symfony. Există 4 tipuri de relaționări ce se pot realiza cu ajutorul acestuia :

1. One-To-One
2. One-To-Many
3. Many -To-One
4. Many -To-Many

În tabelul User a fost declarată o cheie străină , ce reprezintă relațion are de tipul Many -To-One
în interiorul entității User din cadrul symfony , deoarece un utilizator poate fi inclus în mai multe

19
departamente. Din perspectiva ta belului department, tipul relațion ării va fi de tipul One -To-
Many, pentru că un departament poate fi asignat către mai mulți utilizatori. Pe lângă aceste relaționări
ce le pr imește câmpul departament_id , acest a prime ște și constrângerea de a accepta null ca valoare de
intrare. Codul PHP ce realizează aceste relațion ări cu alte tabele și constrângerile necesare se vor scrie
în clasa U ser și arată a stfel:

/**
* @var Departament
*
* @ORM \ManyToOne(targetEntity="LicentaBundle \Entity \Departament", inversedBy="users")
* @ORM \JoinColumn(name="departame nt_id", referencedColumnName="id", nullable=true)
*/
protected $departament;

Pentru a crea câmpul departament_id, mai intâi se declară tipul de variabilă, în acest caz fiind
de tipul Departament, apoi se specifică ce tip de relaționa re va exista între tabela user ș i tabela
departament , aceasta fiind de tipul ManyToOne.S e specifică în paranteze entitatea țintă și proprietatea
din această entitate țintă ce se referă la obiectul user (inversedBy =”users”) . Apoi se vor specifica
numele coloanei di n tabelă, precum și constrângerile ce intervin asupra acesteia (nullable = true , ce ne
indică faptul că această coloană poate primi valoarea null ),iar la final se va seta un nume proprietății ce
va fi asociat unui identificator de acces (protected $departament ). În cazul celui de -al doilea câmp,
procedura este aceeași ca la departament, numai că de data aceasta ne vom referi la entitatea proiect.

Pentru ca relaționările între tabelele user, departament și proiect să fie complete t rebuie ca în
clasele Proiect ș i Departament să definim proprietatea “users” c e va fi de tipul One -To-Many și va
arăta în felul următor:

– În interiorul clasei Departament se va specifica tipul relaționării, e ntitatea țintă care, în cazul de
față,este User,p recum și obiectul la care se re feră (mappedBy = ” departament”), carea fost
declarat în clasa User :

/**
* @ORM \OneToMany(targetEntity="LicentaBundle \Entity \User", mappedBy="departament")
*/
private $users;

– În interiorul clasei Proiect se va repeta același proces, numai că de data aceasta , obiectul la care
se referă users (mappedBy = “proiect”) va fi proprietatea proiect declarată în interiorul clasei
User:

20
/**
* @ORM \OneToMany(targetEntity="LicentaBundle \Entity \User", mappedBy="proiect")
*/
private $users;

În tabelul Task s-au definit 3 chei străine, acestea reprezintă relaționări de tipul Many -To-One
ce s-au definit în cadrul entității Task. Primele 2 chei străine le reprezintă câmpurile assigned_to_id și
assigned_by_id ce au ca entitate țintă tabelul Use r, deoarece un task este creat ș i asignat către un
utilizator, iar cea de -a treia cheie străină o repre zintă câmpul p roject_id,deoarece ,atunci când se creează
un task , va trebui să -i corespundă unui proiect. Clasa Task va conține următoarele bucăți de cod pentru
a se put ea realiza relaționările între tabelele task, user și proiect:

/**
* @ORM \ManyToOne(targetEntity="LicentaBundle \Entity \User", inversedBy="tasks")
* JoinColumn(name="assigned_to", referencedColumnName="id", nullable=false)
*/
private $as signedTo;

/**
* @ORM \ManyToOne(targetEntity="LicentaBundle \Entity \User", inversedBy="tasks")
* JoinColumn(name="assigned_by", referencedColumnName="id", nullable=false)
*/
private $assignedBy;

/**
* @var int
*
* @ORM \ManyToOne(targetEntity="LicentaBundle \Entity \Proiect", inversedBy="tasks")
* @ORM \JoinColumn(name="project_id", referencedColumnName="id" , nullable =false )
*/
private $proiect;

Primul câmp î l reprezintă cheia st răină că tre tabelul user, care este o relaționare de tipul Many –
To-One din perspectiva tabelului Task, deoarece un task poate fi asignat către mai mulți utilizatori, deci
o să primească ca pa rametri en titatea țintă User și obiectul de t ip tasks definit î n interiorul clasei User.
Singurele constrângeri ce intervin asupra acestui câmp din tabela ta sk le reprezintă cheia străină ș i
faptul că acest câmp nu acceptă null ca valoare de intrare (pentru că atunci când se creează un task
trebuie ș tiut de către cine a fost creat și către cine a fost asignat) . Cel de -al doilea câmp este tot o c heie
străină către tabelul user, identică cu cea explicată mai sus, dar care se setează automat cu numele
utilizatorului ce a creat task -ul prin intermediul unu i controller despre care voi discuta în alt capitol. A
treia cheie străin ă este proi ect_id care este tot o relaționare de tipul Many -To-One, deoarece pot exista
mai multe task -uri pe același proiect. Aceasta primește ca parametri entitatea țintă Proiect și obiectul de

21
tip tasks declarat în interiorul clasei Proiect. Constrângerile ce intervin asupra acestui câ mp le
reprezintă cheia străină ș i faptul că nu poate accepta null ca valoare de intrare (pentru că atunci când se
creează un task trebuie știut pe ce proiect este creat task -ul).
În cele din urmă, pentru ca relaționările între tabele le task, proiect și user să fie
complete, trebuie declarată proprietatea task s în interiorul tabelelor User ș i Proiect , ce va fi de tipul
One-To-Many, deoarece un proiect sau un user poate fi asignat pe mai multe taskuri . Această
proprietate va arăta astfel :

– În interiorul clasei User se va specifica tip ul relaționării, entitatea țintă care,în cazul de față, este
Task, precum și obiectul la care se referă (mappedBy="users") :

/**
* @ORM \OneToMany(targetEntity="LicentaBundle \Entity \Task", mappedBy="users")
*/
private $tasks;

– Din perspectiva clasei Proiect procedura este aceeași, numai că de data aceasta , obiectul la care
se referă va fi ( mappedBy="proiect" ):

/**
* @ORM \OneToMany(targetEntity="LicentaBundle \Entity \Task", mappedBy="proiect")
*/
private $tasks;

În cadrul tabelului projectUsers s-au declarat 2 chei străine, acestea reprezentând relațion ări de
tipul Many -To-One declarate în cadrul entităț ii ProjectUsers. Prima cheie o reprezintă câmpul
proiect_id , ce are ca entitate țintă tabelul Proiect, iar cea de -a doua cheie, o reprezintă câmpul user_id
ce va avea ca entitate țintă, tabelul User. Clasa ProjectUsers va conține următoarea porțiune de cod
pentru a se putea realiza relaționările discutate mai sus :

/**
* @var Proiect
*
* @ORM \ManyToOne(targetEntity="LicentaBundle \Entity \Proiect", inversedBy="users")
* @ORM \JoinColumn(name="proiect_id", referencedColumnName="proiect_id",
onDelete="CASCADE")
*/
private $proiect;

/**
* @var User
*

22
* @ORM \ManyToOne(targetEntity="LicentaBundle \Entity \User", inversedBy="projectUsers")
* @ORM \JoinColumn(name="user_id", referencedColumnName="id", onDelete="CASCAD E")
*/
private $user;

1.3 Programe utlizate

XAMPP – acționează ca un web server capabil de a servi pagini dinamice , utilizând limbaje de
programare ca și PHP. Este utilizat în general pentru dezvoltarea aplicațiilor web.
Acesta asigură suport pentru crearea și manipularea bazelor de date în MySQL.

HeidiSQL – este un instr ument foarte folositor atunci câ nd se lucrează cu un server MySQL și limbajul
de programare PHP, deoarece un browser web nu se poate conecta direct la serverul MySQL. A ceastă
conexiune între browser ș i baza de date se face prin intermediul limbajului de programare PHP care
poate stabi li o conexiune cu baza de date ș i poate prelucra informațiile din aceasta (codul PHP ce arată
cum se creează un tabel nou în baza de date sau cum se realizează constrângerile între tabele a fost
expus mai sus la discuția despre tabele).

Symfony – în cadrul framework -ului va trebui să configurăm o conexiune cu baza de date, adică va
trebui să declarăm această conexiune în fișierul parameters.yml din cadrul proiectului. Mai multe
discuții despre această conexiune vor fi tratate în capitolele următoare.

1.4 Diagrama relațională a bazei de date

Figura 1.6 Diagrama relațională a bazei de date

23
2. Tipuri de utilizatori și drepturile acestora în cadrul aplicaț iei

2.1 Tipuri de utilizatori

În scopul realizării acestei aplicații s -au introdus 3 tipuri de utilizatori :

– Utilizator
– Manager
– Admin istrator

1. Rolul de utilizator este asignat automat unui angajat în momentul în care acesta se înregistrează .
Drepturile pe care le au utilizatorii în cadrul aplicației se reduc la a crea, a modifica sau așterge
un task și de a -și modifica setările personale.
2. Rolul de manager poate fi asignat unui utilizator numai de către un administrator și reprezintă
persoana responsabilă de un departament în cadrul unei organizații . Drepturile ce îi revin
acestuia sunt de a crea, a modifica sau a șterge un proiect, dar au acces și la pagina
corespunzătoare task -urilor.
3. Rolul de administrator necesită un nume de utilizator și o parolă. Acesta are acces în orice
pagină a aplicație i, poate crea o orga nizație, un departament, un proiect sau un task și
poateasigna rolul de manager unui utilizator existent.

2.2 Diagrama de drepturi

Drepturile pe care le au utilizatorii în cadrul aplicației pot fi expuse și printr -o diagramă care arată în
felul următor:

Figura 2.1 Diagrama de drepturi în funcție de rolul utilizatorului

24

Etapele ce trebuie respectate pentru a se putea crea un task sunt următoarele :

1. Administratorul creează un departament.
2. Administratorul sau managerul creează un proiect.
3. Administrator ul, managerul sau userul pot crea un task acum, deoarece s -a creat un proiect, iar
un task trebuie să -i aparțină unui proiect.

2.3 Matrice a de drepturi în funcție de rolul utilizatorului

Tabelul 1.1 Matrice a de drepturi a utilizatorilor
Numele paginii Utilizator Manager Administrator
Acțiuni
Departamente
Adaugă un departament nou X
Editează un departament X
Șterge un departament X
Vezi toate departamentele X
Utilizatori
Vezi toți utilizatorii X
Șterge un utilizator X
Modifică drepturile utilizatorului X
Vezi toți utilizatorii X
Proiecte
Creează un proiect nou X X
Modifică un proiect deja existent X X
Șterge un proiect X X
Vezi toate proiectele X X
Task-uri
Adaugă un task nou X X X
Editează un task deja existent X X X
Șterge un task X X X
Vezi toate task-urile X X X
Acasă X X X

25
Așa cum este expus î n tabelul de mai sus, în funcție de rolul pe care utilizatorul îl deține în cadrul
firmei, acesta poate accesa numai anumite pagini. Accesul asupra fiecărei pagini se definește în fișierul
“security.yml” din cadrul proiectului symfony ,unde se creeaz ă o nouă intrare numită “access_control” ,
ce necesită ca utilizatorul să fie autentificat sau nu pentru a putea accesa acest e URL -uri. Porțiunea de
cod c e stabilește aceste chestiuni legate de securitate arată astfel :

access_control:

– Paginile de login, înregistrare și de resetare a parolei pot fi accesate de către oricine, chiar dacă
nu este înregistrat.
– { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
– { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
– { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
– Pagina departamentelor și a utilizatorilor poate fi accesată numai de către un utilizator cu
drepturi de administrator.
– { path: ^/departament, role: ROLE_ADMIN }
– { path : ^/user, role: ROLE_ADMIN}
– Pagina proiectelor poate fi accesa tă doar de către administrator ș i manager.
– { path: ^/proiect, role: [ROLE_ ADMIN , ROLE_MANAGER ]}

– Pagina task -urilor este accesibilă tuturor utilizatorilor aplicației, indiferent de drepturile
acestora, dacă aceștia sunt autentificați.

Mai multe detalii despre cum pot accesa utilizatorii aceste pagini și despre cum au fost create vor fi
discutate într -un capitol ulterior.

26

27
3.Tehnologii utili zate

3.1 Pagina web

Construc ția unei pagini web are la bază protocolul numit HTTP, care este un protocol rapid ce
se potrivește foart e bine cu sistemele multimedia,f iind distribuite în salturile dintre site -uri.
Web -ul are la bază pagini cu informa ții provenite de la gazde, ce rul ează software de tip server
web [1].
Web server -ul reprezintă un program ce furnizează paginile web la cerere. Spre exemplu, atunci
când un utilizator de la o anumită adresă IP solicit ă un anumit f ișier, server -ul web încearcă să
obțină fișierul respectiv și să-l trimită înapoi către utilizator. Fișierul poate fi codul sursă HTML al
unei pagini, un fișier de tip XML, o imagine,etc.

Pagina web reprezintă o resursă a spațiului web din Internet, care de obicei se regăsește în
form at HTML, dar și în a lte formate. Navigatorul afișează paginile web prin intermediul unor
marcatori , definiți cu ajutorul limbajului HTML , utilizați pentru a codifica pagina web cu
informația ce se dorește a fi afișată. Aceștia au diferite semnificații, de exemplu, pot stabili modul
în care va fi afișată informația în pagină sau pot stabili legături între documente ș i fișiere.
În mod normal, o pagină web este legată de mai multe tipuri de fișiere, cum ar fi cele de tip text,
multimedia sau grafice. Denumirea căii de acces î ntre aceste fișiere este hipertext.
În momentul în c are utilizatorul acționează prin click de mouse către o legătură, cum ar fi o
imagine,o porțiune de text, etc, navigatorul va incărca fișierul către care punctează legătura ș i îl va
afișa.

Un site web reprezintă un ansamblu de informații prezentat sub forma unor pagini web,
documente, fișiere multimedia, dar si alte tipuri, între care există o cale de acces(legatură).
În momentul realizării unui site web to ate fișierele sunt păstrate, în mod uzual, într-un folder sau o
colecție de foldere pe hard disk -ul local ce trebuie să conțină software -ul,prin intermediul căruia
site-ul este transmis către navigatoarele web ale calculatoarelor conectate la Internet. Din
momentul în care site -ul este publ icat, acest a se transformă din site local î n site web, interacțiunea
utilizatoruluise desfășoară conform figurii 3.1.

Figura 3.1 Comunicația între navigatorul web și serverul web

28
3.2 Compozitorul

Compozitorul reprezintă u n instrument de linie de comand ă, ce conți ne biblioteci de administrare
software care sunt scrise în limbajul PHP. Pe lângă faptul că el este un administrator de pa chete (care
permite instalarea ș i organizarea bibliotecilor într -un mod standardizat ), compozitorul detectează dacă
o bibli otecă depinde de o altă bibliotecă și instalează automat toate bibliotecile necesare. Acest
instrument descarcă bibliotecile într -un folder numit “vendor/” care se află în folderul rădăcină al
proiectului [2].
Cele mai utilizate linii de comandă ale compoz itorului sunt:

– composer install: instalează toate librăriile aflate în fișierul “composer.lock” din cadrul
proiectului
– composer update: actualizează toate librăriile la cea mai nouă versiune a acestora
– composer require <vendor/package>: instalează o nouă bibliotecă și o adaugă automat în
fișierul “composer.json”, unde <vendor/package> reprezintă numele pachetului ce se dorește a
fi instalat.
– composer update <vendor/package>: instalează sau actualizează o anume bibliotecă.

În cadrul proiectului, am folosi t Compozitor ul pentru administrarea aplicației Symfony și pentru a
instala bibliotecile și pachetele necesare acesteia.

3.3 Limbajul PHP

3.3.1 Introducere în PHP

PHP reprezintă un limbaj de scripting utilizat pe scară largă, realizat și distribuit în si stem Open
Source, care a fost special conceput pentru a putea construi pagini web dinamice. Sintaxa acestuia
provine din limbaje de programare, precum C, Java și Perl, și prezintă avantajul de a fi ușor de învățat.
PHP permite furnizarea unui conținut web dinamic, adică un conținut ce se poate mo difica de la un
minut la altul [3].
Spre deosebire de limbajele de scripting, precum JavaScript, PHP rulează pe serverul web, nu în
browser -ul web. În consecință, acesta poate obține accesul la fișiere, la baza de d ate, dar și la alte
resurse ce -i sunt inaccesibile limbajului JavaScript.
Există trei domenii principale unde sunt folosite scripturile PHP:

– Primul domeniu îl reprezintă scripturile ce rulează pe server. Acesta este cel mai important
aspect al PHP -ului și este nevoie de trei lucruri pentru ca el să funcționeze: interpretorul PHP,
un browser web și serverul web (ce trebuie să fie pornit și să aibă o conexiune de PHP
instalată). Rezultatul programelor PHP poate fi vizualizat cu ajutorul unui browser web prin
intermediul serverului web.

29
– Al doilea domeniu se ocupă de scripting -ul în linia de comandă. Codul PHP poate fi rulat fără a
fi nevoie de un server sau de un browser web, ci doar prin intermediul interpretorului PHP.
Această metodă este folosită de obicei pentru sarcini simple de procesare a textului.
– Ultimul domeniu vizează scrierea de aplicații ce rulează de partea clientului în mod grafic
(GUI). PHP nu este cel mai folosit limbaj pentru a scrie aplicații cu ferestre pentru Windows
sau alte sisteme de ope rare, dar dacă se dorește folosirea unor funcționalități mai avansate ale
acestuia în aplicațiile ce rulează de partea utilizat orului, se poate folosi PHP -GTK, care
reprezintă o extensie a PHP -ului, nedisponibilă în distribuția principală.

PHP are sintaxa foarte asemănătoare cu limbajul C, la care s -au adăugat caracteristici necesare
dezvoltării aplicațiilor web. Instrucțiunile de bază sunt următoarele: if, for, which, switch, do while.
Codul PHP p oate fi inclus în fișierele HTM, sau po ate fi utilizat în fișiere cu extensia “.php” , ce conțin
doar cod PHP. Pentru ca acesta să fie executat de interpretor , codul trebuie să fie inclus între tagurile
PHP: “<?php //aici trebuie să se afle codul ?>”.

3.3.2 Tipuri de dată si variabile le în PHP

PHP poate suporta opt tipuri de data [3] :
– Patru dintre acestea sunt tipuri scalare: string, float (numere în virgulă mobilă), integer și
Boolean.
– Două tipuri sunt compuse: array și obiect.
– Două tipuri ce sunt speciale: resource și null.
Programatorul nu trebuie să declare tipul unei variabile, este decis la rulare de că tre PHP, în funcție de
contextu l în care variabila este folosită.
Variabilele sunt reprezentate folosind un semn “$” urmat de nu mele variabilei, cu mențiunea că aceste
variabile sunt case -sensitive. PHP dispu ne de un număr mare de variabile implicite. Multe dintre
acestea, nu pot fi documentate , deoarece sunt dependente de serverul pe care rulează, iar unele dintre
ele nu vor fi folosite atunci când PHP rulează în linie de comandă.

3.3.3 PHP Superglobals

$_SESSION –Conține variabilele registrate unei sesiunii a script -ului.
$GLOBALS – Reprezintă o referință la fiecare variabilă care este valabilă în scopul global al script –
ului.
$_SERVER – Conține variabilele setate de serverul web sau legate direct de mediul de execuție al
scriptului.
$_GET – Reprezintă variabilele oferite script -ului prin HTTP GET.
$_POST – Reprezintă variabilele oferite script -ului prin HTTP POST.
$_FILES – Conține variabilele oferite script -ului prin încărcarea de fișiere folosind modul PO ST din
HTTP.
$_ENV – Reprezintă variabilele oferite script -ului prin mediu.
$_REQUEST – Reprezintă variabilele oferite script -ului prin mecanismele de GET, POST și COOKIE.

30
3.3.4 Framework -urile PHP :

Pentru a se realiza dezvoltarea rapidă a aplicațiilor we b, comunitatea PHP a dezvoltat o serie de
framework -uri web. Cele mai utilizate și populare dintre acestea sunt: CodeIgniter, CakePHP, Laravel,
Symfony, Yii, Zend, etc. În următoarea secțiune a acestui capitol vom discuta despre Symfony,
framework pe care l-am ales pentru dezvoltarea acestei aplicații.

3.4 Framework -ul Symfony :

3.4.1 Introducere în Symfony

Symfony are la baz ă limbajul PHP ce a fost descris în secțiunea anterioară . Acest framework a
apărut în anul 2005, este open source și a devenit unul dintre cele mai populare cadre de lucru PHP
datorită multiplelor avantaje, dar și a bunei documentații [4].

Arhitectura MVC este compusă din 3 nivele:
-Primul nivel îl reprezintă modelul (nivelul datelor) care conține partea de business logic și
interacț iunea cu baza de date.
-Cel de -al doilea nivel îl reprezintă view-ul(interfața utilizator) , acesta este responsabil de
interacțiunea cu utilizatorul și conține template engine -ul.
-Ultimul nivel este controller -ul (gestiunea interacțiunilor) și reprezintă o bu cată de cod ce apelează
modelul în scopul obținerii de date ce urmează a fi transmise view -ului, pentru a putea fi redate
utilizatorului.
Avantajele utilizării acestui ti p de arhitectură sunt următoarele : poate fi scrisă ușor și timpul de
execuție es te mic . Acesta prezintă însă și dezavantaj ul inexistenț ei unei verificări de eroare (dacă
conexiune a cu baza de date se întrerupe) [5].

Entitatea este o clasă în care sunt descrise coloanele unei tabele ș i include metodele de setare și afișare
ale acestora. Ace astă entitate poate fi generată î n 2 moduri: utilizând comanda “php bin/console
generate:doctrine:entity ” direct în terminal sau poate fi generată manual. În ambele situaț ii, valorile
corespunzătoare coloan elor din baza de date trebuie s ă aibă o denumire, trebuie specificat tipul de dată
(ex: integer, s tring, float, etc) asociat fiecă reia, dar și da că acestea vor fi unice sau dacă pot accepta și
valori de null.

Rela țiile între aceste entități sunt de 4 tipuri:

1. One-To-One
2. One-To-Many
3. Many -To-One
4. Many -To-Many

31
Aceste relaționări trebuie să apară în fișierele de tipul “NumeEntitate.php” și se folosesc pentru a crea
chei străine sau chei primare în SQL. Spre exemplu, dacă avem o enitate numită Angajat și o entitate
numită Proiect, relaționarea o să fie de tipul One-To-Many din perspectiva angajatului, iar din
perspectiva proiectului o să fie de tipul Many -To-One.

CRUD
Utilizând comanda “php bin/console generate:doctrine:crud” în terminal, symfony va genera un
controller de baz ă pentru o anumită entitate. Acest c ontroller permite executarea celor 5 operații de
bază asupra unui model: afișează toate înregistrările de tipul entității respective, arată o anumită
înregistrare identificată după cheia primară, creează o nouă înregistrare, editează o înregistrare deja
existent ă în baza de date ș i șterge o înregistrare existen tă în tabel. Pe lângă aceste metode , de citire,
adăugare, editare ș i ștergere, CRUD -ul generează și paginile HTML de bază , corespunzătoare fiecărei
metode în parte, care pot fi modificate ulterior după bunul plac.

3.4.2 Structura directoarelor

O instalare corespunzătoare a framework -ului Symfony2 va genera următoare a structură de directoare :

– app/: reprezintă directorul ce conține fișierele de configurare, ce se regăsesc în format YAML.
– src/: reprezin tă directorul ce conține codul aplicației
– vendor/: este directorul ce conține codul “terță”, instalat prin intermediul Compozitorului,
inclusiv , framework -ul Symfony și toate bibliotecile acestuia.
– web/: reprezintă directorul ce trebuie configurat ca un se rver web rădăcină și care poate fi
accesat prin intermediul unui browser web.

Aceasta reprezintă structura directoarelor din cadrul framework -ului Symfony2, ce am folosit -o
pentru a realiza această aplicație, dar care este puțin diferită față de structura framework -ului
Symfony3.
Directorul “web/” va conține resursele de front -end cum ar fi: CSS, JavaScript, imagini, etc, dar și
scripturile necesare controller -ului “frontal” ce corespund fiecărui mediu Symfony (“prod”, “dev” și
“test”).Symfony utilizează modelul controller -ului “frontal” (acesta fiind specific aplicațiilor web), care
constă în a avea un singur punct de intrare în aplicație prin intermediul adresei URL.
Directorul “app/” va conține, pe lângă fișierele de configurare, clasa Appkernel, care p reia o solicitare
HTTP de la client și o propagă în sistemul de rutare al framework -ului. De asemenea, în această clasă
se regăsesc și pachetele înregistrate cu ajutorul cărora se va crea aplicația.

3.4.3 Componente ale Sym fony

O componentă a framework -ului Symfony reprezintă o bibliotecă software autonomă, scrisă în
PHP, care implemente ază o funcționalitate specifică, necesară dezvoltării unei aplicații web. Aceste
componente stau la baza framework -ului Symfony. Versiunea 1.0 a acestuia poate fi folosită doar cu
setul de componente ce le cuprinde framework -ul. În versiunea 2.0, s -a introdus conceptul de

32
componente, ce face acest framework mult mai flexibil. Asta înseamnă că se pot instala doar
componentele necesare pentru a putea real iza un proiect, fiind capabil să le instaleze separat. Deci,
putem alege între a utiliza Symfony “full -stack” (cu toate componentele acestuia) sau putem folosi doar
componentele de care avem nevoie. Printre cele mai importante componente ale Symfony sunt
următoarele:

– Form: ce oferă suport pentru crearea, procesare a și reutilizarea formularelor HTML
– HttpFoundation : interfața POO ce lucrează cu protocolul HTTP
– HttpKernel : oferă instrumente ce ajută la crearea unui framework web bazat pe HTTP
– DependencyInjection : oferă metode de standardizare și de centralizare a creării de obiecte
– EventDispatcher : oferă posibilitatea ca modulele aplicației să poată comunica mai ușor, prin
intermediul “evenimentelor” și a “ascultătorilor”.
– Routing : mapează o cerere HTTP către un set de variabile c onfigurabile.
– Security : oferă un sistem de securitate peste resursele aplicației, prin autentificare și ACL.
– Templating : oferă instrumentele necesare pentru a se putea construi un sistem “șablon”.
– Yaml : analizează fișierele de tip YAML și le transformă în array -uri de tip PHP .

3.4.4 “Pachetele”

O aplicație Symfony este compusă dintr -o colecție de “pachete”. Un “pachet” reprezintă un director
ce conține codul care implementează un modul al aplicației și oferă o singură funcționalitate importantă
a acestui a [6]. “Pachetele” pot fi clasificate în:

– “Pachete” ale Symfony “full -stack” din distribuția standard a acestuia, care completează și
leagă componentele descrise în subcapitolul anterior.
– “Pachetele terță”, ce se regăsesc în directorul “vendor/” și care p ot fi instalate prin intermediul
compozitorului. Acestea oferă funcționalitățile de bază care sunt deja implementate, dar care
pot fi ignorate de programator. De obicei, nu se poate modifica codul acestora, dar se pot ignora
în cadrul propriilor noastre pachete.
– “Pachete” ale directorului “src/”, care conțin codul nostru personalizat specific aplicației.

Structura unui “pachet ”poate fi :

• Student /…
• LicențăBundle
• LicențăBundle.php
• Controller/
• Resources/
• meta/
• License
• config / (conține fișierele de configurare)
• doc/ (conține documentația)

33
• index.rst
• translations/ (conține fișierele de translatare)
• views/
• public/ (fișierele publice accesibile)
• Tests (fișierele de test)

În interiorul directorului “ src/”, primul director ar trebui să fie, de obicei, un director cu numele firmei
care dezvoltă aplicația. Acest lucru este util atunci când există mai multe companii ce lucrează pe
același proiect. Apoi, acest director poate conține și alt director, dar ul timul trebuie să conțină su bfixul
“Bundle”, care, de fapt, reprezintă pachetul. Un pachet va avea un nume atribuit, care se formează pr in
concatenarea numelor tuturor directoarelor superioare din “src/”. În cazul nostru, numele pachetului va
fi: StudentLic ențăBundle.
De asemenea, într -un pachet putem avea și alte directoare, conținute de directoarele existente . Acestea
sunt opționale :

Tabelul 3.1 Directoare opționale într -un pachet Symfony

Tip Director Detalii
Comenzi Command/ Comenzile Symfony
Controllere Controller/ Clasele controller-ului
Extensii ale containerului de serviciu DependencyInjection/ Fișierele de configurare ale serviciilor
Ascultătorii evenimentului EventListener/ Clasele ce definesc evenimentele și ascultătorii
Configurarea Resources/config Fișierele de configurare în format XML sau YAML
Resursele web Resources/public Fișierele accesibile public (JS, CSS, imagini, etc.)
Fișierele de translatare Resources/translations/ Fișierele de translatare
Template-urile Resources/views/ Fișierele HTML și TWIG
Testele Tests/ Fișierele de test

34
Principalele pachete ale framework -ului Symfony sunt :

• Frame workBundle : are rolul de a lega și corela toate componentele descrise în subcapitolul anterior.
• SecurityBundle : oferă securitatea necesară accesări i resurselor
• TwigBundle : oferă integrarea dintre Symfony și template -ul Twig
• WebProfilerBundle : oferă i nformații despre depanarea aplicației programatorilor
• SwiftMailerBundle : oferă posibilitatea de a se trimite automat un mail
• MonologBundle : oferă servicii de autentificare
• AsseticBundle : administrează resursele publice din front -end
• DoctrineBundle : oferă suport atunci când se lu crează cu Doctrine ORM și baze de date

3.4.5 Integrarea framework -ului cu Doctrine ORM

Doctrine reprezintă un sistem de relaționare a obiectelor, adică un ORM folosit pentru PHP ,
începând cu versiunea 5.2.3, ce are la bază un DBAL. Doctrine reprezintă înce putul diferitelor librării
PHP, c e sunt focusate în principal pe păstrarea bazelor de date și maparea obiectelor. Symfony
integrează Doctrine -ul pentru a se putea mapa obiecte către baza de date . DBAL este un API, bazat pe
PDO care abstractizează comunicația dintre aplicație și bazele de date [7].

ORM reprezintă o modalitate de programare ce face posibilă accesarea și gestionarea datelor
fără ca programatorii să fie interesați de sursa acestora. Rolul ORM -ului este de a crea o conexiune
între limbajul orientat pe obiecte cu câmpurile din baza de date, care să fie fiabilă și de durată.
Principalul avantaj pe care -l prezintă ORM -ul este că programatorii nu trebuie să lucreze direct cu
tipurile de dată ale bazelor de date și nu vor folosi secvențe de cod SQL direct în cod. De asemenea,
Doctrine ORM aduce noi me tode de a interoga baza de date prin intermediul unui nou dialect SQL,
numit DQL, care permite utilizarea obiectelor și proprietățile acestora în declarațiile in terogării, în
locul tabelelor și coloanelor din baza de date. Doctrine poate fi utilizat în orice proiect PHP și poate fi
instalat prin intermediul compozitorului, în majoritatea framework -urilor PHP acesta fiind instalat
implicit [8].

Așa cum am menționat într -un capitol anterior, Doctrine este preinstalat în cadrul framework –
ului Symfony. Într -un pachet Symfony, o să avem în legătură cu Doctrine două directoare: “/Entity” și
“/Repository”. Directorul “/Entity” o să conțină toate clasele entit ate, care vor mapa obiectele către
tabelele din baza de d ate. Maparea poate fi scrisă în: adnotări PHP, fișiere YAML sau fișiere XML. În
directorul “/Repository” se vor găsi clasele ce au în componență metode PHP , care pot fi executate
asupra bazei de date .

35

Figura 3.2 Principiul de funcționare Doctrine

Doctrine cuprinde 4 etape:

1. Crearea: reprezintă etapa de instanțiere a obiectului și setarea proprietăților acestuia. Pentru
exemplul utilizat în figura de mai sus $angajat se folosește ca și un obiect normal, iar
instanțierea se face utilizând $angajat = new Angajat().
2. Citirea: se face din baza de date.
3. Update -ul: preia obiectul de la doctrine, îl modifică și apoi folosește funcț ia flush(), ce va că uta
toate obiectele ce trebuie persistate (funcț ia per sist() permite ca doctrine să poată administra
obiectul).
4. Ștergerea: reprezintă apelarea metodei remove(), query -ul de ștergere către baza de date
făcându -se numai după ce se apelează metoda flush().

3.5 Framework -ul Bootstrap

Bootstrap este un framework de front -end, open -source, dezvoltat inițial de Twitter, ce reprezintă o
colecție de instrumente care pot dezvolta foarte ușor interfața utilizatorului din pagina web. Acest
framework este compus din fișiere HTML, CSS și JavaScript, care oferă un set de elemente predefinite
cum ar fi: butoane, liste, meniuri, tabele, panouri, etc. Aceste elemente pot fi incluse sau personalizate
în funcție de cerinț ele proiectului. Cea mai valor oasă componentă a acestui fr amework, este sistemul
grilelor, care permite pozi ționarea ușoară a elementelor din pagină și poate construi interfețe
impresionabile ce -și modifică conținutul în funcție de rezoluția ecranului. Ace sta reprezintă un mare
avantaj, d eoarece un site web poate fi folosit pe orice dispozitiv, indiferent de rez oluție [9].

3.6 HTML

HTML reprezintă un “limbaj de marcare” , ce este utilizat pentru crearea paginilor web , care pot fi
afișate într -un browser [10]. Acesta este implementat ca o mulțime de tag -uri pentru a marca paginile
text, iar browserele le folosesc pentru a crea și afișa informații. Paginile web pot conține legături
hypertext către alte pagini. Componența unui document HTML este:

36

1. Versiunea HTML a documentului
2. Zona head cu tag -urile <head></head>
3. Zona body cu tag -urile <body></body>

3.7 JavaScript

Așa cum s -a descris în subcapitolul anterior, HTML este un limbaj de markup. El permite crearea
layout -ului paginilor și a formularelor, dar nimic mai mult. Dacă se dorește dezvoltarea unor interfețe
sofisticate și intuitive este necesar un limbaj de scri pting la nivel de client. Scripting -ul permite
utilizarea unor bucăți de cod ce rulează în browser [11].
JavaScript reprezintă cel mai cunoscut limbaj de scripting pe parte de client, deoarece este
suportat de aproape orice browser existent. Utilizând Java Script se poate realiza foarte ușor: animarea
textului și a imaginilor, validarea formularelor, crearea de meniuri drop -down și a controalelor de
navigare, se pot face procesări de bază numerice asupra textelor, etc.
Scripting -ul permite programatorilor să detecteze și să proceseze evenimentele ce se petrec în
browser. Exemple de evenimente pot fi: pagina care se încarcă, mișcarea pointer -ului mouse -ului,
acțiunea de click a mouse -ului. Script -urile pot fi executate automat de către browser atunci când aces te
evenimente se petrec.
Aceste script -uri pot fi incluse în codul HTML sau pot fi salvate în fișiere externe și legate în
interiorul codului HTML.

3.8 CSS

CSS este un standard al formatării elementelor din cadrul unui document HTML. Stilurile se pot at așa
tag-urilor HTML prin intermediul unor fișiere externe sau în cadrul documentului, prin elementul
<style> sau a atributului style [12].

3.9 MySQL

3.9.1 Introducere în MySQL

MySQL reprezintă un sistem de ge stiune a bazelor de date relațio nal, produs d e compania MySQL
AB și distribuit sub Licență Publică Generală. Este cel mai popular sistem de gestiune al bazelor de
date open -source, fiind o componentă cheie a stivei LAMP (Linux, Apache, MySQL, PHP).
Chiar dacă este folosit de cele mai multe ori împreu nă cu limbajele de programare PHP sau Java, cu
ajutorul acestuia se pot construi aplicații în aproape orice limbaj major. Există multe scheme API
disponibile pentru MySQL ce permit dezvoltarea aplicațiilor în diferite limbaje de programare pentru
accesarea bazelor de date MySQL, cum ar fi: Java, Perl, PHP, Python, C, C++, etc., fiecare dintre ele
folosind un model specific de API. Pentru a administra bazele de date MySQL se poate folosi linia de
comandă sau o interfață grafică. Serverul de baze de date MySQ L este foarte rapid, fiabil și ușor de
utilizat [13].

37

Câteva caracteristici de bază ale MySQL pot fi:

– Dispune de API pentru C, C++, Java, Perl, PHP, Pyton, etc.
– Folosește tabele temporare stocate în memorie
– Poate funcționa pe diferite platforme : Windows , AIX, MAC OS X, GNU/LINUX, Solaris,
NetBSD, SunOS.
– Oferă motoare tranzacționale și non -tranzacționale de stocare a datelor
– Folosește un sistem de alocare a memoriei foarte eficient care este bazat pe thread -uri
– Serverul este disponibil ca soft separat ce poate fi folosit într -un mediu de tip client/server, însă,
este disponibil și ca bibliotecă ce poate fi inclusă în aplicații.

3.9.2 Tipuri de date în MySQL

Tipurile de date care pot să apară în coloanele MySQL sunt diferite în funcție de tipul acestora.
MySQL alocă spațiu pe disc în funcție de tipul de date specificat de programator. Tipuri de date:

– Tipul de dată TimeStamp oferă posibilitatea de a data automat operațiile de tip “inserează” și
“actualizează” ce se efectuează asupra câmpului respectiv. Imp licit, el este compus din 14
caractere pentru a res pecta formatul “YYYYMMDDhhmmss”, dar se poate specifica în
momentul creări i unui tabel dacă dorim să conțină mai puține caractere.
– Tipurile de dată string ce pot să apară în MySQL sunt: BLOB, TEXT, CHAR, V ARCHAR,
ENUM și SET. Câmpul de tip BLOB poate conține o cantitate variabilă de informație,
asemănător cu tipul de câmp TEXT, însă, căutarea într -un câmp BLOB este case sensitive, iar
într-un câmp TEXT nu este. Câmpul de tip VARCHAR este similar tipului TEX T cu
deosebirea că într -o coloană de tip VARCHAR se poate specifica numărul maxim de caractere
admis.
– Tipurile de dată numerice pot fi: tinyint, boolean , smallint, mediumint, int, decimal, float și
double.

38

39
4.Implementarea ș i utilizarea aplicației

4.1 Prezentare generală

Așa cum am precizat într -un capitol anterior, aplicația poate avea diferite interfețe , în funcție de
rolul utilizatorului. În cadrul acestei aplicații am utilizat 3 roluri de utilizato r:

– Utilizator: este rolul pe care îl are asignat orice angajat odată cu înregistrarea acestuia în
aplicație
– Manager: reprezintă managerul unui departament, care deține câteva drepturi în plus față de un
utilizator normal și este creat de către administrat or
– Administrator: reprezintă ad ministratorul aplicației care are nevoie de un cont de acces.

Rolul aplicației este de a ușura munca de zi cu zi angajaților din cadrul unei firme. În cadrul acesteia
se pot crea și gestiona: departamente, proiecte și task -uri. Departamentele pot fi create ș i gestionate
doar de către administrator ii firmei, proiectele pot fi accesate doar de către administrator ș i manager,
iar task -urile pot f i folosite de toți utilizatorii aplicației. Pentru ca aceasta să poată fi utilizată , fiecare va
trebui să se creeze u n cont cu care fiecare utilizator se va autentifica. Atunci când se creează un cont
acesta va avea rolul de utilizator. Dacă dorim ca acel utilizator să aibă rolul de manager, trebuie să se
folosească pagina utilizatorilor, pe care doa r administratorul o poate accesa .
Pentru ca toate aceste lucruri să fie posibile am utilizat următoarele pagini:

– Pagina de înregistrare
– Pagina de autentificare
– Pagina departamentelor
– Pagina proiectelor
– Pagina task -urilor
– Pagina utilizatorilor
– Pagina acasă

Toate paginile vor extinde pagina base.html.twig, care reprezintă pagina de bază , unde se vor include
template -urile respective header -ului și footer -ului ce vor apărea în toate paginile, mai puțin cele de
înregistrare și autentificare. Tot în această pagină se vor include fișierele JavaScript și CSS, cu ajutorul
cărora s -au stilizat paginile și s -a creat un conținut dinamic. Paginile HTML sunt compuse din patru
blocuri: blocul în care se includ fișierele javascripts, blocul în care se includ fișierele CSS , corpul
blocului și blocul titlului care v or fi diferit e pentru fiecare pagină. Aceste blocuri sunt declarate în
interiorul fiecărei pagini, dar vor fi incluse automat cele ale paginii base, pentru că toate paginile o
extind pe aceasta.
În urm ătoarele subcapitole voi detalia cum au fost create aceste pagini împreună cu toate explicațiile
necesare.

40
4.2 Pagina de înregistrare

Pentru ca angajatul să poată utiliza aplicația trebuie ca acesta să -și creeze un cont. El poate face acest
lucru prin in termediul paginii de înregistrare sau administratorul aplicației o poate face cu ajutorul
consolei , utilizând comanda “php bin/console fos:user:create testuser test@example.com p@ssword ”,
unde testuser reprezintă numele utilizatorului, text@example.com adresa de email a acestuia, iar
p@ssword este parola asociată. Pentru a -i asigna rolul de administrator (acesta fiind primul
administrator din aplicație, apoi se pot asigna roluri către alți utilizatori din cadrul setăr ilor acestora
doar de către un administrator ) unui utilizator , trebuie ca administratorul aplicației să ruleze comanda
“php bin/console fos:user:promote testuser ROLE_ADMIN ” în consolă, astfel utilizatorul cu numele
testuser va primi rolul de administrator .

Figura 4.1 Pagina de înregistrare

Așadar, dacă accesăm ruta /register a aplicației, se va deschide pagina de înregistrare care este generată
de către FosUserBundle (un “pachet” al framework -ului Symfony) și pe care am rescris -o. Aceasta este
compus ă dintr -un formular ce conține câmpurile cu datele necesare unui utilizator pentru a se înregistra
și un buton ce face request -ul către ba za de date. Câmpurile username ș i email sunt verificate , se va
verifica dacă în baza de date există un utilizator cu a celași nume sau aceeași adresă de email introduse,
pentru că nu pot exista doi utilizatori cu aceleași valori. Dacă valorile introduse nu există în baza de

41
date, se va face înre gistrarea, iar utilizatorul va fi autentificat automat . Însă, dacă valorile int roduse nu
sunt valide, utilizatorul va primi un mesaj de eroare.

4.3 Pagina de autentificare

După ce și-a creat un cont , utilizatorul se poate autentifica prin intermediul paginii de login. Aceasta
este compusă dintr -un formular ce cuprinde două câmpuri: username și password, precum și butonul de
autentificare. Dacă datele introduse în cele două câmpuri sunt valide , utilizatorul va fi autentificat, dacă
nu, acesta va primi un mesaj de eroare. Și pagina de login este creată automat de către FosUserBundle,
la fel ca și în cazul paginii de înregistrare, numai că a fost rescrisă. După etapa de autentificare,
utilizatorul poate utiliza aplicația, i se pot asigna task -uri, poate face parte dintr -un departament, etc.

Figura 4.2 Pagina de autentificare

4.4 Pagina acasă

Reprezintă pagina în care un utilizator este redirecționat ime diat după ce și -a creat un cont sau s -a
autentificat. Aceasta este o pagină HTML ce extinde pagina base.html.twig, adică implicit meniul,
header -ul și footer -ul, despre care am di scutat în cadrul primului subcapitol. În cor pul blocului este

42
afișată o listă cu toate task -urile asignate către utilizator, astfel încât fiecare utilizator își poate vizualiza
propriile task -uri. În continuare, vor fi afișate imagini cu interfața aplicați ei în funcție de rolul
utilizatorului.
Dacă utilizatorul autentificat nu are rolul de manager sau de administrator, acesta va avea acces doar la
pagina acasă și la pagina task -urilor:

Figura 4.3 Interfața aplicației cu rol de utilizator

Dacă utilizato rul autentificat are rolul de manager, acesta va avea acces la o pagină în plus față de
utilizatorul normal (pagina proiectelor).

Figura 4.4 Interfața aplicației cu rol de manager

43
În ultimul caz, utilizatorul autentificat poate avea rol de administrator . Administratorul poate accesa
toate paginile aplicației. Paginile la care doar administratorul poate avea acces sunt: pagina
departamentelor și pagina utilizatorilor.

Figura 4.5 Interfața aplicației cu rol de administrator

În toate cele trei cazuri, pagina acasă va arăta fiecarui utilizator în parte task -urile la care acesta a fost
asignat.

4.5 Pagina utilizatorilor

Pagina utilizatorilor este pagina în care vor fi afișați toți utilizatorii înregistrați în aplicație și
care poate fi accesată doar de către administratori. Prin intermediul acestei pagini administratorul poate
modifica setările utilizatorilor existenți și îi poate adăuga într -un departament. Pentru a putea asigna un
utilizator către un departament (un angajat poate aparține de un singur departament) trebuie să se apese
click pe iconița de editare a utilizatorului (din dreapta paginii) , care va deschide pagina
corespunzătoare setărilor acestuia . Tot din pagina de editare a utilizator ului, administratorul poate
modifica rolul acestuia, care implicit este user. Formularul din pagina de editare este realizat cu
ajutorul fișierul ui UserType.php din directorul Form al “pachetului” LicentaBundle. Utilizatorii sunt
afișați cu ajutorul “pachetului” TwigBundle ce permite accesul la câmpurile din tab elul User direct din
front -end. De exemplu, dacă dorim să afișăm numele utilizatorului vom accesa acest câmp prin
comanda “{{ user.username }}”. Acest tabel cu utilizatori , pe care doar administratorul îl poate accesa,
reprezintă un tabel creat în pagina H TML index.html.twig a ut ilizatorilor, unde s -a parcurs un for,
astfel încât vor fi afișați toți utilizatorii aflați în tabelul User din baza de date a aplicației.

44
Orice utilizator are acces la profilul său, dar și la setările acestuia (dacă utilizatorul n u are rol de
administrator, el își poate modifica doar numele, prenumele și adresa de email). Utilizatorul nu poate
accesa pagina de editare a altui utilizator, doar administratorul o poate face.

Figura 4.6 Pagina cu toți utilizatorii aplicației

Pagina de setări a utilizatorului este diferi tă în funcție de rolul acestuia:

– Pentru a verifica dacă utilizatorul conectat este cel care accesează pagina de setări (un utilizator
nu poate accesa pagina setărilor a altui utilizator, doar administratorul o poat e face) s -a impus
condiția: {% if app.user.id == user.id or is_granted('ROLE_ADMIN') %} , care verifică dacă
utilizatorul con ectat este același cu cel care î ncearcă să acceseze pagina și dacă acesta are rol de
administrator. Dacă condiția este adevărată, at unci pagina de editare poate fi accesată, dacă nu,
va primi un mesaj în care i se spune că nu poate accesa pagina de setări a altui utilizator.

– Dacă utilizatorul autentificat este administrator, acesta poate modifica departament ul și rolul
oricărui utiliz ator. Pentru a verifica dacă utilizatorul este administrator se impune condiția: {%
if is_granted('ROLE_ADMIN') %} , care, dacă este adevărată, va afișa rândurile
corespunzătoare departamentului și rolului, dacă nu, acestea nu vor fi afișate.

45

Figura 4.7 Pagina de setări a utilizatorului accesată de administrator

– Dacă utilizatorul nu are rol de administrator, din pagina de setări vor dispărea rân durile legate
de departamentul ș i de rolul acestuia, deoarece doar administratorul poate lua o decizie cu
privire la acestea.

Figura 4.8 Pagina de setări a utilizatorului fără drept de administrator

46
4.6 Pagina departamentelor

Pagina departamentelor cuprinde etapele de creare, editare, ștergere și listare a tuturor departamentelor
din cadrul firmei. Accesul către această pagină îi este permis doar administratorului. Pentru a adăuga
un departament nou se folosește pagina new.html.twig (ruta /departament/new) din cadrul directorului
app/resources/views/departament, unde administratorul poate alege un nume și u n manager acestuia.

Figura 4.9 Pagina de creare a unui departament

În cazul câmpului manager, se va afișa un meniu de tip ul dropdown, care listează toți utilizatorii cu
rolul de manager din baza de date.
După ce s -a creat departamentul, acesta poat e fi vizualizat în pagina show.html.twig (ruta
/departament/{ id}) din cadrul directorului app/resources/views/departament.

Figura 4.10 Pagina de vizualizare a unui departament

47
Pentru a -l edita, se utilizează pagina edit.html.twig (ruta departament/{i d}/edit) din același director,
unde i se poate modifica numele sau managerul departamentului. În cazul paginii de editare, dacă
departamentul are deja un manager, acesta va fi afișat în câmpul managerului, iar dacă se dorește a fi
modificat, se poate selec ta altul din listă (care să dețină rolul de manager).

Figura 4.11 Pagina de editare a unui departament

În cadrul etapei de listare, se va utiliza pagina index.html.twig (ruta /departamente), unde vor fi listate
toate departamentele existente în firm ă. Tot prin intermediul acestei paginii , se pot șterge
departamentele.

Figura 4.1 2 Pagina de listare a departamentelor

48
Codul ce face posibilă selectarea utilizatorilor cu rolul de manager din tabelul User este scris în
interiorul funcției buildForm() di n cadrul fișierului DepartamentType, care creează formularele din
paginile de adăugare, editare și listare. Codul sursă:

public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder ->add('nume', TextType::class, [
'label' => false
])
->add('manager', EntityType::class, [
'class' => 'LicentaBundle \Entity \User',
'label' => false,
'choice_label' => 'username',
'query_builder' => f unction (UserRepository $ur) {
$qb = $ur ->createQueryBuilder('u');
$qb->where($qb ->expr() ->like('u.roles', ':roles'))
->setParameter('roles', '%"' . UserRoles::ROLE_MANAGER . '"%');
return $qb;
},
]);
}

Primul element din builder reprezintă câmpul nume din formular, iar cel de -al doilea este dropdown -ul
cu toți managerii din cadrul aplicației, care face un query către baza de date și caută to ți utilizatorii care
au în dreptul coloanei roles, valoarea de ROLE_MANAGER.

4.7 Pagina proiectelor

La fel ca și pagina departamentelor, pagina proiectelor cuprinde etapele de creare, editare, ștergere și
listare a tuturor proiectelor adăugate în firmă . Accesul către această pagină este permis și
adminis tratorilor, dar și managerilor.

Pentru a se adăuga un proiect nou se folosește pagina new.html.twig (ruta /proiect/new) din cadrul
directorului /app/resources/views/proiect. În corpul blocului se află f ormularul de creare al unui proiect
nou, unde se pot introduce date despre numele proiectului, descrierea acestuia, echipa asignată pe
proiectul respectiv și statusul.

49

Figura 4.13 Pagina de adăugare a unui proiect

După ce s -a creat proiectul , acesta p oate fi editat prin intermediul paginii edit.html.twig (ruta
/proiect/{id}) din cadrul directorului /app/resources/views/proiect. Cu ajutorul acestei paginii,
managerul sau administratorul poate edita proiectul.

Figura 4.14 Pagina de editare a unui pr oiect

După ce s -au efectuat modificările dorite, proiectul poate fi vizualizat în pagina show.html.twig (ruta
/proiect/{id}) din cadrul directorului /app/resources/views/proiect. Owner -ul proiectului este setat

50
automat atunci când se creează proiectul. Data creă rii și actualizării sunt datate automat de către
framework atunci când se inserează sau când se editează un proiect.

Figura 4.15 Pagina de vizualizare a unui proiect

Etapa de listare a tuturor proiectelor existente în firmă se face prin intermediul pa ginii index.html.twig
(ruta /proiecte) din cadrul directorului /app/resources/views/proiect. Aceasta conține un tabel cu toate
proiectele și cu informațiile despre acestea.

Figura 4.16 Pagina de listare a proiectelor din cadrul firmei

51
4.8 Pagina tas k-urilor

Pagina task -urilor poate fi accesată de orice utilizator al aplicației, indiferent de rolul acestuia. Pentru a
se putea crea un task s -a utilizat pagina new.html.twig (ruta /task/new) din cadrul directorului
/app/resources/views/task. Prin interm ediul paginii de adăugare, orice utilizator poate crea un task către
un alt utilizator. Câmpurile necesare pentru crearea unui task sunt puse într -un formular pe care
utilizatorul îl completează în momentul creării.

Figura 4.17 Pagina de creare a unui task

După ce s -a creat task -ul acesta poate fi vizualizat prin intermediul paginii show.html.twig (ruta
/task/{id}/edit) din cadrul directorului /app/resources/views/task. Cu ajutorul acestei pagini se poate
vizualiza fiecare task în parte , precum și inf ormațiile legate de acesta.

Câmpul “Asignat de” reprezintă persoana care a creat task -ul, câmpul “asignat către” reprezintă
persoana căreia i s -a asignat task -ul, iar prioritatea este setată atunci când se creează task -ul. Câmpul
proiect, este unul din pr oiectele existente în firmă, deoarece atunci când se creează un task, acesta va
aparține de un proiect. Timpul estimat este introdus de persoana ce a asignat task -ul. Datele ce intră în
acest formular se realizează cu ajutorul funcției buildForm() din fiși erul TaskType.php , care se află în
directorul /LicentaBundle/Form. Cu ajutorul acestuia se pot extrage toți utilizatorii aplicației, toate
proiectele existente, precum și celelalte câmpuri ale formularului.

Pentru ca valoarea câmpului “Asignat de” să se completeze automat cu numele utilizatorului care a
creat task -ul, trebuie ca în metoda de newAction(), din fișierul TaskController.php care se află în
directorul /LicentaBundle/TaskController să se folosească următoarea porțiune de cod:
if ($form ->isSubmit ted() && $form ->isValid()) {
$em = $this ->getDoctrine() ->getManager();

52
$task ->setAssignedBy($this ->getUser());
$task ->setStatus(6);
$em->persist($task);
$em->flush();

return $this ->redirectToRoute('task_show', array('id' => $task ->getId()));
}

Prima lucru ce trebuie făcut atunci când se creează un task , este de a verifica dacă formularul este valid
și dacă utilizatorul a apăsat pe butonul de creare. Apoi, în cea de -a doua lini e se apelează funcțiile
getDoctrine și getManager care obțin accesul către entitatea Task, adică către baza de date. Cea de -a
treia linie reprezintă funcția ce setează automat user -ul atunci când un task este creat. Următoarea linie
setează statusul unui t ask la valoarea de “nou” atunci când este creat. Aceste funcții vor fi intrepretate
ca și query -uri către baza de date apelând funcția persist pe variabila $task. În cele din urmă, pentru ca
valorile să se introducă în baza de d ate, se folosește funcția fl ush (această funcție poate face mai multe
query -uri către baza de d ate printr -o singură apelare).

Figura 4.18 Pagina de vizualizare a unui task

Pentru a se putea edita un task trebuie accesată pagina edit.html.twig (ruta /task/{id}/edit) din cadrul
directorului /app/resources/views/task. Această pagină conține un formular cu toate informațiile pe care
task-ul le are deja și care pot fi modificate.

53

Figura 4.19 Pagina de editare a unui task

Listarea task -urilor se face cu ajutorul paginii index.ht ml.twig (ruta /tasks) ce se află în directorul
/app/resources/views/task, care arată în felul următor:

Figura 4.20 Pagina de listare a task -urilor existente

Tot din cadrul acestei pagini se poate șterge un task, utilizând iconița de ștergere din dreap ta tabelului,
ce utilizează metoda de deleteAction() descrisă în interiorul fișierului TaskController.php. Această
metodă face un query către baza de date pentru a șterge un anumit câmp al tabelului Task.

54

55
Concluzi i

Scopul dezvoltării acestei aplicații este de a ține evidența sarcinilor angajaților din cadrul unei
firme. Aplicația este utilizată pentru a gestiona proiectele și task -urile ce pot apărea în munca de zi cu
zi a acestora. Astfel, fiecare angajat al firm ei poate avea o listă cu toate task -urile ce i-au fost atribuite
și poate modifica sau șterge aceste task -uri.

La baza aplicației stă limbajul de programare PHP, care este un limbaj foarte des utilizat. Din acest
motiv am ales acest limbaj pentru dezvol tarea aplicației. Cele mai des distribuite aplicații din zilele
noastre sunt scrise în PHP, deoarece prezintă o soluție optimă pentru proiectarea unei aplicații
electronice utilizată de clienții care nu dispun de un buget prea mare.

Această aplicație est e primul meu proiect creat cu ajutorul framework -ului Symfony. Symfony este
un software open source, care realizează legăturile între codul de front -end (HTML, CSS, JS) și cel de
back -end (PHP, MySQL), ceea ce în domeniul programării web prezintă un mare a vantaj.

Aplicația poate fi îmbunătățită, adăugând noi facilități, în funcție de necesitățile clientului.

56

57

Bibliografie

[1] “Pagini web”, https://ro.wikipedia.org/wiki/Pagin%C4%83_web , accesat la data de 20.03.2017

[2] “Compozitorul”, https://getcomposer.org/doc/01 -basic -usage.md

[3] “PHP”, https://ro.wikipedia.org/wiki/PHP , accesat la data de 03.04.2017

[4] “Symfony”, http://symfony.com/doc/current/index.html , accesat la data de 07.07.2017

[5] https://ro.wikipedia.org/wiki/Model -view -controller

[6] http://symfony.com/doc/current/bundles.html

[7] http://www.doctrine -project.org/

[8] https://en.wikipedia.org/wiki/Object -relational_mapping

[9] https ://en.wikipedia.org/wiki/Bootstrap_(front -end_framework)

[10] https://ro.wikipedia.org/wiki/HyperText_Markup_Language

[11] https://ro.wikipedia.org/wiki/JavaScript

[12] https://ro.wikipedia.org/wiki/Cascading_Style_Sheets

[13] https://ro.wikipedia.org/wiki/M ySQL

58

59
Anexa 1

confirmed.html.twig:

{% extends "@FOSUser/layout.html.twig" %}

{% block title %}Congrats{% endblock %}

{% block body %}
<section class="section">
<div class="container">
<header class="heading small text -center">
<h1>Felicitari!</h1>
Contul dumneavoastra a fost creat, acum sunteti logat!
<br> <br> <br>
<a class="btn btn -blue btn -medium" href="{{ path ('homepage') }}">Inapoi la prima pagina</a>
</header>
</div>
</section>
{% endblock %}

Register.html.twig

{% block javascripts %}
<script src="{{ asset("js/jquery -2.1.1.min.js") }}"></script>
<script src="{{ asset("js/jque ry.nicescroll.js") }}"></script>
<script src="{{ asset("js/scripts.js") }}"></script>
<!–//scrolling js –>
<script src="{{ asset("js/bootstrap.js") }}"> </script>
{% endblock %}
{% block stylesheets %}
<link href="{{ asset("css/bootstrap.c ss") }}" rel="stylesheet" type="text/css" media="all">
<!– Custom Theme files –>
<link href="{{ asset("css/custom.css") }}" rel="stylesheet" type="text/css" media="all"/>
<link href="{{ asset("css/style.css") }}" rel="stylesheet" type="text/c ss" media="all"/>
<!–js–>
<!–icons -css–>
<link href="{{ asset("css/font -awesome.css") }}" rel="stylesheet">
{% endblock %}

{% block body %}
{% block fos_user_content %}
{% include "@FOSUser/Registration/register_content.html.t wig" %}
{% endblock fos_user_content %}
{% endblock %}

Register_content.html.twig

{% trans_default_domain 'FOSUserBundle' %}

{% block fos_user_content %}

<div class="signup -page-main">
<div class="signup -main">
<div class="s ignup -head">
<h1>Creeaza -ti un cont !</h1>
</div>
{% if error is defined %}
<div>{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}
<div class="signu p-block">
{{ form_start(form, {'method': 'post', 'action': path('fos_user_registration_register'), 'attr': {'class': 'fos_user_registra tion_register'}, 'attr':
{'id':'register -form'}}) }}

{{ form_row(form.username, {'attr': {'placeholder' : 'Username'}, 'label': false }) }}
{{ form_row(form.email, {'attr': {'placeholder' : 'Email'}, 'label': false }) }}
{{ form_row(form.plainPassword.first, {'attr': {'placeholder' : 'Parola'}, 'label': false }) }}
{{ form_row(form.plainPassword.second, {'attr': {'placeholder' : 'Reintrodu parola'}, 'label': false }) }}

<button class="btn btn -primary btn -md register -btn" type="submit">Inregistrare</button>

60
{{ form_end(form) }}

<div class="sign -down">
<h4>Ai deja un cont? <a href="{{ path('fos_user_security_login') }}"> Autentificate aici.</a></h4>
<h5><a href="{{ path('homepage') }}">Mergi inapoi in aplicatie</a></h5>
</div>
</div>
</div>
</div>
{% endblock fos_user_content %}

Login.html.twig

{#{% extends 'base.html.twig' %}#}
{#{% block title %} Pagina de autentificare {% endblock %}#}

{% block javascripts %}
<script src="{{ asset("js/jquery -2.1.1.min.js") }}"></script>
<script src="{{ asset("js/jquery.nicescroll.js") }}"></script>
<script src="{{ asset("js/scripts.js") }}"></script>
<!–//scrolling js –>
<script src="{ { asset("js/bootstrap.js") }}"> </script>
{% endblock %}
{% block stylesheets %}
<link href="{{ asset("css/bootstrap.css") }}" rel="stylesheet" type="text/css" media="all">
<!– Custom Theme files –>
<link href="{{ asset("css/custom.css") }}" rel="stylesheet" type="text/css" media="all"/>
<link href="{{ asset("css/style.css") }}" rel="stylesheet" type="text/css" media="all"/>
<!–js–>
<!–icons -css–>
<link href="{{ asset("css/font -awesome.css") }}" rel="stylesheet">
{% endbloc k %}

{% block body %}
{% block fos_user_content %}
<div class="login -page">
<form id="login -form" action="{{ path("fos_user_security_check") }}" method="post">
<input type="hidden" name="_csrf_token" value="{{ csrf_token }}"/>
<div class="login -main">
<div class="login -head">
<h1>Login</h1>
</div>
<div class="login -block">
{% if error %}
<div>{{ error.messageKey|trans(error.messageData, ' security') }}</div>
{% endif %}
<form>
<input type="text" id="username" name="_username" data -constraints="@NotEmpty" placeholder="Utilizator" value="{{ last_username }}"
required="required"/>
{#<input type="text" name="email" placeholder="Email" required="">#}
<input type="password" name="_password" class="lock" placeholder="Parola">
<div class="forgot -top-grids">
<div cl ass="forgot -grid">
<ul>
<li>
<input type="checkbox" id="brand1" value="">
<label for="brand1"><span></span>Tine -ma minte</la bel>
</li>
</ul>
</div>
{#<div class="forgot">#}
{#<a href="#">Ai uitat parola?</a>#}
{#</div>#}
<div class="clearfix"> </div>
</div>
<input type="submit" name="Sign In" value="Login">
<h3>Nu ai cont?<a href="{{ path('fos_user_registration_register') }}">Inregistreaza -te</a></h3>
</form>
</div>
</div>
</div>

61
{% endblock fos_user_content %}
{% endblock %}

Home/index.html.twig

{% block title %} Homepage {% endblock %}

{% extends 'base.html.twig' %}

{% block body %}
<div class="chit -chat-layer1">
<div class="col -md-12 ">
<div class="work -progres">
<div class="chit -chat-heading">
Task -urile mele
</div>
{% if usersTasks is not empty %}
<div class="table -responsive">
<table id="tasks" class="table table -hover">
<thead>
<tr>
<th>#ID</th>
<th>Titlu</ th>
<th>Proiect</th>
<th>Descriere</th>
<th>Prioritate</th>
<th>Status</th>
<th>Assignat de</th>
<th>Assignat catre</th>
<th>Timp estimat</th>
<th>Creat</th>
<th>Modificat</th>
<th>Setari</th>
</tr>
</thead>
<tbody>
{% for task in usersTasks %}
<tr>
<td><span class="badge badge -info">{{ task.id }}</span></td>
<td><a href="{{ path('task_show', {'id' : task.id }) }}">{{ task.title }}</a></td>
<td>{{ task.proiect }}</td>
<td><span class="col -md-3 col -xs-12">{{ task.description }}</span></td >
<td>{{ task.priority|taskPriority }}</td>
<td><span class="label label -danger">{{ task.status|taskStatus }}</span></td>
<td>{{ task.assignedBy }}</td>
<td>{{ task.assignedTo }}</td>
<td>{{ task.estimatedTime }} ore</td>
<td>{{ task.createdAt|date('Y -m-d') }}</td>
<td>{{ task.updatedAt| date('Y -m-d') }}</td>
<td>
<a class="show -task" href="{{ path('task_show', { 'id': task.id }) }}">
<i class="fa fa -eye" aria -hidden="true"></i>
</a>
<a class="edit -task" href="{{ path('task_edit', { 'id': task.id }) }}">
<i class="fa fa -pencil -square -o" aria -hidden="true"></i>
</a>
<a class="delete -task" href="{{ path('task_delete', { 'id': task.id }) }}">
<i class="fa fa -trash " aria -hidden="true"></i>
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</table>
</div>
{% el se %}
<div class="col -md-12 col -xs-12 no -tasks">
<span>Nu aveti niciun task asignat momentan.</span>
</div>
{% endif %}
</div>

62
</div>

<div class="clearfix"></d iv>
</div>

{% endblock %}

{% block javascripts %}
<script>
var toggle = true;

$(".sidebar -icon").click(function () {
if (toggle) {
$(".page -container").addClass("sidebar -collapsed").removeClass("sideba r-collapsed -back");
$("#menu span").css({"position": "absolute"});
}
else {
$(".page -container").removeClass("sidebar -collapsed").addClass("sidebar -collapsed -back");
setTimeout(functio n () {
$("#menu span").css({"position": "relative"});
}, 400);
}
toggle = !toggle;
});
</script>
<!– script -for sticky -nav –>
<script>
$(document).ready(function () {
var navoffeset = $(".header -main").offset().top;
$(window).scroll(function () {
var scrollpos = $(window).scrollTop();
if (scrollpos >= navoffeset) {
$(".header -main").addClass("f ixed");
} else {
$(".header -main").removeClass("fixed");
}
});

});
</script>
{% endblock %}

User/edit.html.twig

{% extends 'base.html.twig' %}

{% block javascripts %}
<scri pt>
$(document).ready(function () {
$('#licentabundle_user_roles').select2({
placeholder: 'Adauga un rol, momentan este utilizator',
theme: 'bootstrap'
});
});

</script>
{% endblo ck %}

{% block body %}
{% if app.user.id == user.id or is_granted('ROLE_ADMIN') %}
<h1>Editare utilizator</h1>
<div class="row submit -form text -left edit -user-content panel -widget btn -effcts">
{{ form_start(edit_form) }}
<div class="col -sm-12 col -md-12">
<div class="form -group col -md-4">
<label for="fname" class="small required">Nume</label>
{{ form_row(edit_form.fname, {'attr': {'placeholder': 'Nume', 'clas s' : 'form -control'}}) }}
</div>
</div>
<div class="col -sm-12 col -md-12">
<div class="form -group col -md-4">
<label for="lname" class="small required">Prenume</label>

63
{{ form_row(edit_form.lname, {'attr': {'placeholder': 'Prenume', 'class' : 'form -control'}}) }}
</div>
</div>
<div class="col -sm-12 col -md-12">
<div class="form -group col -md-4">
<label for="email" class="small required">Email</label>
{{ form_row(edit_form.email, {'attr': {'placeholder': 'Email', 'required': 'required', 'class' : 'form -control'}}) }}
</div>
</div>
{{ form_widget(edit_form._token) }}
{% if is_granted('ROLE_ADMIN') %}
<div class="col -sm-12 col -md-12">
<div class="form -group col -md-4">
<label for="department" class="small required">Dep artament</label>
{{ form_row(edit_form.departament, {'attr' : {'class' : 'form -control'}}) }}
</div>
</div>
<div class="col -sm-12 col -md-12">
<div class="form -group col -md-4">
<label for="user -role" class="small ">Rol de acces </label>
{{ form_row(edit_form.roles, {'attr' : {'class' : 'form -control'}}) }}
</div>
</div>
{% endif %}
<br>
<div class="col -sm-12 col -md-12">
<input type="submit" class="btn btn -success edit -user-button" value="Editeaza"/>
</div>
</div>
{{ form_end(edit_form, {'render_rest': fa lse }) }}

{% elseif app.user.id != user.id %}
<div class="warning col -md-12">
<span>Nu ai accesul de a modifica setarile altui utilizator</span>
</div>
{% endif %}
{% endblock %}

User/index.html.twig

{% extends 'base. html.twig' %}

{% block javascripts %}
<script>
$(document).ready(function () {
$('#users').DataTable();
});
</script>
<script>
$(document).ready(function () {
$('.delete -user').on('click', functi on (e) {
var row = $(this).closest('tr');
var url = row.find('td a.delete -user').attr("href");
e.preventDefault();
swal({
title: "Esti sigur?",
text: "Proiectul va fi sters definitiv",
type: "warning",
showCancelButton: true,
confirmButtonClass: 'btn -danger',
confirmButtonText: 'Da, sterge',
cancelButtonText: "Nu, anuleaza!"
},
function (isConfirm) {
if (isConfirm) {

$.ajax({
url: url,
type: 'delete',
success: function (data) {
if (data === 'OK') {
row.remove();

64
}
},
error: function (e) {
console.log(e.responseText);
}
});
} else {
//nimic
}
});
});
});
</script>
{% endblock %}

{% block body %}
<h1 class="users -title">Lista utilizatorilor</h1>

<table id="users" class="table table -striped table -bordered" cellspacing="0" width="100%">
<thead>
<tr>
<th>Id</th>
<th>Nume</th>
<th>Prenume</th>
<th>Email</th>
<th>Departament</th>
<th>Rol</th>
<th>Ultima logare</th >
<th>Setari</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td><a href="{{ path('user_show', { 'id': user.id }) }}">{{ user.id }}</a></td>
<td>{{ user.fname }}</td>
<td>{{ user.lname }}</td>
<td>{{ user.email }}</td>
<td>{{ user.departament }}</td>
<td>{% if user.roles|userRoles == 'ROLE_ADMIN' %}
<span>Administrator</span>
{% elseif user.roles|userRoles == 'ROLE_MANAGER' %}
<span>Manager</span>
{% else %}
<span>Utilizator</span>
{% endif %}</td>
<td>{{ user.lastLogin|date('d -m-Y') }}</td>
<td>
<a class="show -user" href="{{ path('user_show', { 'id': user.id }) }}">
<i class="fa fa -eye" aria -hidden="true"></i>
</a>
<a class="edit -user" href="{{ path('user_edit', { 'id': user.id }) }}">
<i class="fa fa -pencil -square -o" aria -hidden="true"></i>
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>

{% endblock %}

Departament/new.html.twig

{% extends 'base.html.twig' %}

{% block title %}Adauga un departament{% endblock %}

{% block javascripts %}
<script>
$(document).ready(function () {
$('#licentabund le_departament_users').select2({

65
placeholder: 'Adauga membri',
theme: 'bootstrap'
});
});

</script>
{% endblock %}

{% block body %}
<h1>Adauga un departament nou</h1>
{{ form_start(form) }}
{{ form_row(form._token) }}
<div class="row submit -form text -left new -project -content panel -widget btn -effcts">
<!– RD form –>
<div class="col -md-12">
<div class="form -group col -md-4">
<label for="title " class="small required">Nume</label>
{{ form_row(form.nume, {'attr': {'placeholder': 'Nume', 'required': 'required', 'class' : 'form -control'}}) }}
</div>
</div>
<div class="col -md-12">
<div class="f orm-group col -md-4">
<label for="department -manager" class="small ">Manager</label>
{{ form_row(form.manager, {'attr': { 'class' : 'form -control'}}) }}
</div>
</div>
<div class="col -md-12">
{{ form_widget(form) }}
<input type="submit" class="btn btn -success mleft15" value="Create"/>
</div>
<div class="col -md-12 panel -widget">
<br>
<a class="hvr -icon-back" href="{{ path('departament_ind ex') }}">Inapoi la lista departamentelor</a>
</div>
{{ form_end(form) }}
</div>
{% endblock %}

Departament/edit.html.twig

{% extends 'base.html.twig' %}

{% block title %}Editare{% endblock %}

{% block javascripts %}
<script>
$(document).ready(function () {
$('#licentabundle_departament_users').select2({
theme: 'bootstrap'
});
});

</script>
{% endblock %}

{% block body %}
<h1>Departament edit</h1>
<div class="ed it-department row panel -widget btn -effcts">

{{ form_start(edit_form) }}
<div class="col -md-12">
<div class="form -group col -md-4">
<label for="title" class="small required">Nume</label>
{{ form_ro w(edit_form.nume, {'attr': {'placeholder': 'Nume', 'required': 'required', 'class' : 'form -control'}}) }}
</div>
</div>
<div class="col -md-12">
<div class="form -group col -md-12 col -xs-12 ">
<label for ="departament -manager" class="small required">Manager</label>
{{ form_row(edit_form.manager, {'attr': {'class' : 'form -control'}}) }}
</div>
</div>

66

{{ form_widget(edit_form) }}
<div class="col -md-12">
<input type="submit" class="btn btn -success mleft15" value="Editeaza"/>
</div>
{{ form_end(edit_form) }}
</div>
<div class="col -md-3 department -edit-buttons">

<div class="back -to-departments">
<a href= "{{ path('departament_index') }}" class="btn btn -info">Inapoi la lista cu departamente</a>
</div>
<div class="delete -department">
{{ form_start(delete_form) }}
<input type="submit" class="btn btn -danger" value="Sterg e">
{{ form_end(delete_form) }}
</div>
</div>

{% endblock %}

Departament/index.html.twig

{% extends 'base.html.twig' %}

{% block title %}Editare{% endblock %}

{% block javascripts %}
<script>
$(document).ready(funct ion () {
$('#licentabundle_departament_users').select2({
theme: 'bootstrap'
});
});

</script>
{% endblock %}

{% block body %}
<h1>Departament edit</h1>
<div class="edit -department row panel -widg et btn -effcts">

{{ form_start(edit_form) }}
<div class="col -md-12">
<div class="form -group col -md-4">
<label for="title" class="small required">Nume</label>
{{ form_row(edit_form.nume, {'attr': { 'placeholder': 'Nume', 'required': 'required', 'class' : 'form -control'}}) }}
</div>
</div>
<div class="col -md-12">
<div class="form -group col -md-12 col -xs-12 ">
<label for="departament -manager" class ="small required">Manager</label>
{{ form_row(edit_form.manager, {'attr': {'class' : 'form -control'}}) }}
</div>
</div>

{{ form_widget(edit_form) }}
<div class="col -md-12">
<input type="submi t" class="btn btn -success mleft15" value="Editeaza"/>
</div>
{{ form_end(edit_form) }}
</div>
<div class="col -md-3 department -edit-buttons">

<div class="back -to-departments">
<a href="{{ path('departament_index' ) }}" class="btn btn -info">Inapoi la lista cu departamente</a>
</div>
<div class="delete -department">
{{ form_start(delete_form) }}
<input type="submit" class="btn btn -danger" value="Sterge">
{{ form_end( delete_form) }}
</div>

67
</div>

{% endblock %}

Departament/show.html.twig

{% extends 'base.html.twig' %}

{% block title %}Editare{% endblock %}

{% block javascripts %}
<script>
$(document).ready(function () {
$('#lice ntabundle_departament_users').select2({
theme: 'bootstrap'
});
});

</script>
{% endblock %}

{% block body %}
<h1>Departament edit</h1>
<div class="edit -department row panel -widget btn -effcts">

{{ form_start(edit_form) }}
<div class="col -md-12">
<div class="form -group col -md-4">
<label for="title" class="small required">Nume</label>
{{ form_row(edit_form.nume, {'attr': {'placeholder': 'Nume', 'requi red': 'required', 'class' : 'form -control'}}) }}
</div>
</div>
<div class="col -md-12">
<div class="form -group col -md-12 col -xs-12 ">
<label for="departament -manager" class="small required">Manager</la bel>
{{ form_row(edit_form.manager, {'attr': {'class' : 'form -control'}}) }}
</div>
</div>

{{ form_widget(edit_form) }}
<div class="col -md-12">
<input type="submit" class="btn btn -success mle ft15" value="Editeaza"/>
</div>
{{ form_end(edit_form) }}
</div>
<div class="col -md-3 department -edit-buttons">

<div class="back -to-departments">
<a href="{{ path('departament_index') }}" class="btn btn -info">In apoi la lista cu departamente</a>
</div>
<div class="delete -department">
{{ form_start(delete_form) }}
<input type="submit" class="btn btn -danger" value="Sterge">
{{ form_end(delete_form) }}
</div >
</div>

{% endblock %}

Task/new.html.twig

{% extends 'base.html.twig' %}

{% block title %}Creare task{% endblock %}
{% block stylesheets %}
<link rel="stylesheet" href="{{ asset('lib/jquery -upload/css/jquery -ui.min.css') }}"/>
{% endblock %}
{% block javascripts %}
<script src="{{ asset('lib/jquery -upload/js/jquery -ui.min.js') }}"></script>
<script src="{{ asset('lib/jquery -upload/js/jquery.ui.widget.js') }}"></script>
<script src="{{ asset('lib/jquery -upload/js/tmpl.min.js') }}"></ script>
<script src="{{ asset('lib/jquery -upload/js/load -image.all.min.js') }}"></script>

68
<script src="{{ asset('lib/jquery -upload/js/canvas -to-blob.min.js') }}"></script>
<script src="{{ asset('lib/jquery -upload/js/bootstrap.min.js') }}"></scr ipt>
<script src="{{ asset('lib/jquery -upload/js/jquery.blueimp -gallery.min.js') }}"></script>
<script src="{{ asset('lib/jquery -upload/js/jquery.iframe -transport.js') }}"></script>
<script src="{{ asset('lib/jquery -upload/js/jquery.fileupload. js') }}"></script>
<script src="{{ asset('lib/jquery -upload/js/jquery.fileupload -process.js') }}"></script>
<script src="{{ asset('lib/jquery -upload/js/jquery.fileupload -image.js') }}"></script>
<script src="{{ asset('lib/jquery -upload/js/jquer y.fileupload -validate.js') }}"></script>
<script src="{{ asset('lib/jquery -upload/js/jquery.fileupload -ui.js') }}"></script>
{% include 'task/uploader_template.html.twig' %}
<script>
$(function () {
'use strict';

$(".fileinput -button .btn").click(function () {
$(".fileinput -button input").click();
});
// Initialize the jQuery File Upload widget:
$('#fileupload').fileupload({
// Uncomment the foll owing to send cross -domain cookies:
//xhrFields: {withCredentials: true},
autoUpload: true,
url: "{{ oneup_uploader_endpoint('task') }}"
}).bind('fileuploadadd', function (e, data) {
$('.uploading -files').removeClass('display -none');
$('.file -upload .uploaded -header -loading').show();
}).bind('fileuploaddone', function (e, data) {
$('.file -upload .uploaded -header -loading').hide();
$('.uploading -files').addClass('display -none');
$('.uploading -complete').removeClass('display -none');
$('.uploading -complete').fadeIn("fast", function () {
$(".uploading -complete").fadeOut(3000);
});
});

// Enable iframe cross -domain access via redirect option:
$('#fileupload').fileupload(
'option',
'redirect',
window.location.href.replace(
/\/[^\/]*$/,
'/cors/result.html?%s'
)
);
// Load existing files:
$('#fileupload').addClass('fileupload -processing');
});

// Drag'n drop uploader script
$(document).bind('dragover', function (e) {
var dropZone = $('.dropzone'),
foundDropzone,
timeout = window.dropZoneTimeout;
if (!timeout) {
dropZone.addClass('in');
}
else {
clearTimeout(timeout);
}
var found = false,
node = e.target;
do {
if ($(node).hasClass('dropzone')) {
found = true;
foundDropzone = $(node);
break;
}
node = node.parentNode;
} while (node != null);
dropZone.removeClass('in hover');
if (found) {
foundDropzone.addClas s('hover');

69
}
window.dropZoneTimeout = setTimeout(function () {
window.dropZoneTimeout = null;
dropZone.removeClass('in hover');
}, 100);
});
</script>
{% endblock %}

{% block body %}
<h1>Creeaza un task nou</h1>

{{ form_start(form) }}
{{ form_row(form._token) }}
<div class="row submit -form text -left new -project -content panel -widget btn -effcts">
<div class="col -sm-12">
<!– RD form –>
<form class="inset -6 col -md-12 col -xs-12 new -task" novalidate>
<div class="form -group col -md-4">
<label for="title" class="small required">Titlu</label>
{{ form_row(form.title, {'attr': {'placeh older': 'Titlu', 'required': 'required', 'class' : 'form -control'}}) }}
</div>
<div class="form -group col -md-4">
<label for="priority" class="small required">Prioritate</label>
{{ form _row(form.priority, {'attr': {'placeholder': 'Prioritate', 'required': 'required', 'class' : 'form -control'}}) }}
</div>
<div class="form -group col -md-4">
<label for="assignedTo" class="small required">As ignat catre</label>
{{ form_row(form.assignedTo, {'attr': {'placeholder': 'Asignat catre', 'required': 'required', 'class' : 'form -control'}}) }}
</div>
<div class="form -group col -md-4">
<label for="project" class="small required">Proiect</label>
{{ form_row(form.proiect, {'attr': {'placeholder': 'Proiect', 'required': 'required', 'class' : 'form -control'}}) }}
</div>
<div class="form -group col -md-4">
<label for="status" class="small required">Status</label>
{{ form_row(form.status, {'attr': {'placeholder': 'Status', 'required': 'required', 'class' : 'form -control'}}) }}
</div>
<div class="form -group col -md-4">
<label for="estimated -time" class="small required">Timp estimat</label>
{{ form_row(form.estimatedTime, {'attr': {'placeholder': 'Timp estimat in ore', 'required': 'requ ired', 'class' : 'form -control'}}) }}
</div>
<div class="form -group col -md-12">
<label for="description" class="small required">Descriere</label>
{{ form_row(form.description, {'attr': {'placeholder': 'Descriere', 'required': 'required', 'class' : 'form -control'}}) }}
</div>
<div class="row field -block">
<div class="col -xs-12 col -md-3">
<label for="create001">Im agini</label>
</div>

<div class="add -dropzone col -xs-12 col -md-12">
<div id="dropzone" class="fade well">
<p>Drag & drop fisiere aici</p>
<span class="details">Formate acceptate: JPG, JPEG, PNG (max 2MB)</span>
<p class="or">sau</p>
{% include 'task/uploader.html.twig' %}
</div>
</div>

</div>
{{ form_row(form.uploadSubdir) }}
{{ form_widget(form, {'attr': {'class' : 'form -group col -md-12 col -xs-12'}}) }}
<div class="form -group col -md-12">
<button type="submi t" class="btn btn -1 btn -success btn -create col -md-3 col -xs-12">Creeaza</button>
</div>
{{ form_end(form) }}
</form>
</div>
</div>
{{ form_end(form) }}
{% endblock %}

70

Task/edit.html.twig

{% exten ds 'base.html.twig' %}

{% block javascripts %}
{% endblock %}

{% block body %}
<h1 class="col -md-12 col -xs-12">Task edit</h1>
<br>
<div class="row panel -widget btn -effcts">
{{ form_start(edit_form) }}
<div class="col -md-12">
<div class="form -group col -md-4">
<label for="title" class="small required">Titlu</label>
{{ form_row(edit_form.title, {'attr': {'placeholder': 'Titlu', 'required': 'required', 'class' : 'form -control'}}) }}
</div>
<div class="form -group col -md-4">
<label for="assignedTo" class="small required">Asignat catre</label>
{{ form_row(edit_form.assignedTo, {'attr': {'placeholder': 'Asignat catre', 'required': 'requir ed', 'class' : 'form -control'}}) }}
</div>
<div class="form -group col -md-4">
<label for="project" class="small required">Proiect</label>
{{ form_row(edit_form.proiect, {'attr': {'placeholder': 'Proiec t', 'required': 'required', 'class' : 'form -control'}}) }}
</div>
</div>
<div class="col -md-12">
<div class="form -group col -md-4">
<label for="status" class="small required">Status</label>
{{ form_row(edit_form.status, {'attr': {'placeholder': 'Status', 'required': 'required', 'class' : 'form -control'}}) }}
</div>
<div class="form -group col -md-4">
<label for="status" class="small required">Priorit ate</label>
{{ form_row(edit_form.priority, {'attr': {'placeholder': 'Prioritate', 'required': 'required', 'class' : 'form -control'}}) }}
</div>
<div class="form -group col -md-4">
<label for="estimated Time" class="small required">Prioritate</label>
{{ form_row(edit_form.estimatedTime, {'attr': {'placeholder': 'Timp estimat in ore', 'required': 'required', 'class' : 'form -control'}}) }}
</div>
</div>
<div class ="col -md-12">
<div class="form -group col -md-4">
<label for="description" class="small required">Descriere</label>
{{ form_row(edit_form.description, {'attr': {'placeholder': 'Descriere', 'required': 'required', ' class' : 'form -control'}}) }}
</div>
</div>
<div class="col -md-12">
<input type="submit" class="btn btn -success save -task" value="Edit"/>
</div>
{{ form_end(edit_form) }}
</div>

<div class="c ol-md-12">
<ul class="edit -tasks">
<li class="back -to-list">
<a href="{{ path('task_index') }}" class="btn btn -info">Back to the list</a>
</li>
<li class="delete -task">
{{ form_sta rt(delete_form) }}
<input type="submit" class="btn btn -danger" value="Delete">
{{ form_end(delete_form) }}
</li>
</ul>
</div>

{% endblock %}

LicentaBundle/Controller/UserController

<?php

71
namespace LicentaBundle \Controller;

use LicentaBundle \Entity \User;
use LicentaBundle \Maps \UserRoles;
use Sensio \Bundle \FrameworkExtraBundle \Configuration \Security;
use Symfony \Bundle \FrameworkBundle \Controller \Controller;
use Sensio \Bundle \FrameworkExtraBundle \Configuration \Method;
use Sensio \Bundle \FrameworkExtraBundle \Configuration \Route;
use Symfony \Component \HttpFoundation \JsonResponse;
use Symfony \Component \HttpFoundation \Request;

/**
* User controller.
*
* @Route("user")
*/
class UserController extends C ontroller
{
/**
* Lists all user entities.
*
* @Route("s", name="user_index")
* @Method("GET")
*/
public function indexAction()
{
$em = $this ->getDoctrine() ->getManager();

$users = $em ->getRepository('L icentaBundle:User') ->findAll();

return $this ->render('user/index.html.twig', array(
'users' => $users,
));
}

/**
* Creates a new user entity.
*
* @Route("/new", name="user_new")
* @Method({"GET", "P OST"})
*/
public function newAction(Request $request)
{
$user = new User();
$form = $this ->createForm('LicentaBundle \Form \UserType', $user);
$form ->handleRequest($request);

if ($form ->isSubmitted() && $form ->isValid()) {
$em = $this ->getDoctrine() ->getManager();
$em->persist($user);
$em->flush();

return $this ->redirectToRoute('user_show', array('id' => $user ->getId()));
}

return $this ->render('use r/new.html.twig', array(
'user' => $user,
'form' => $form ->createView(),
));
}

/**
* Finds and displays a user entity.
*
* @Route("/{id}", name="user_show")
* @Method("GET")
*/
public fu nction showAction(User $user)
{
$deleteForm = $this ->createDeleteForm($user);

return $this ->render('user/show.html.twig', array(

72
'user' => $user,
'delete_form' => $deleteForm ->createView(),
));
}

/**
* Displays a form to edit an existing user entity.
*
* @Route("/{id}/edit", name="user_edit")
* @Method({"GET", "POST", "PATCH"})
*/
public function editAction(Request $request, User $user)
{
$deleteForm = $th is->createDeleteForm($user);
$editForm = $this ->createForm('LicentaBundle \Form \UserType', $user, [
'method' => 'PATCH'
]);
$editForm ->handleRequest($request);
$em = $this ->getDoctrine() ->getManager();

if ($editForm ->isSubmitted() && $editForm ->isValid()) {
$roles = $editForm ->getData() ->getRoles();
$user ->setRoles($roles);
$em->persist($user);
$em->flush();
$this ->getDoctrine() ->getManager() ->flush();

return $this ->redirectToRoute('user_show', array('id' => $user ->getId()));
}

return $this ->render('user/edit.html.twig', array(
'user' => $user,
'edit_form' => $editForm ->createView(),
'delete_form' => $deleteForm ->createView(),
));
}

/**
* Deletes a user entity.
*
* @Route("/{id}", name="user_delete")
* @Method("DELETE")
*/
public function deleteAction(Request $request, User $user)
{

$em = $this ->getDoctrine() ->getManager();
$em->remove($user);
$em->flush();

return new JsonResponse("OK");
}

/**
* Creates a form to delete a user entity.
*
* @param User $user The user entity
*
* @return \Symfony \Component \Form \Form The form
*/
private function createDeleteForm(User $user)
{
return $this ->createFormBuilder()
->setAction($this ->generateUrl('user_delete', array('id' => $user ->getId())))
->setMethod('DELETE')
->getForm();
}
}

LicentaBundle/Controller/TaskController

<?php

73

namespace LicentaBundle \Controller;

use LicentaBundle \Entity \Task;
use LicentaBundle \Maps \TaskStatuses;
use Symfony \Bundle \FrameworkBundle \Control ler\Controller;
use Sensio \Bundle \FrameworkExtraBundle \Configuration \Method;
use Sensio \Bundle \FrameworkExtraBundle \Configuration \Route;
use Symfony \Component \HttpFoundation \JsonResponse;
use Symfony \Component \HttpFoundation \Request;

/**
* Task controlle r.
*
* @Route("task")
*/
class TaskController extends Controller
{
/**
* Lists all task entities.
*
* @Route("s", name="task_index")
* @Method("GET")
*/
public function indexAction()
{
$em = $this ->getDoctrin e()->getManager();

$tasks = $em ->getRepository('LicentaBundle:Task') ->findAll();

return $this ->render('task/index.html.twig', array(
'tasks' => $tasks,
));
}

/**
* Creates a new task entity.
*
* @Route("/new", name="task_new")
* @Method({"GET", "POST"})
*/
public function newAction(Request $request)
{
$task = new Task();
$form = $this ->createForm('LicentaBundle \Form \TaskType', $task);
$form ->handleRequest ($request);

if ($form ->isSubmitted() && $form ->isValid()) {
$tempToken = $request ->request ->get('licentabundle_task')['uploadSubdir'];
$uploadMapping = 'task/' . $tempToken;
$em = $this ->getDoctrine() ->getManage r();
$task ->setAssignedBy($this ->getUser());
$em->persist($task);
$em->flush();

// Assign the uploaded files (if any) to the entity
$this ->get('file_handler') ->assignOrphansToEntity(
$task,
$this ->get('gaufrette.orphanage_filesystem'),
$this ->get('gaufrette.uploads_filesystem'),
$this ->get('session'),
$uploadMapping
);

$this ->get('file_handler' )->clearOrphanage($uploadMapping);

return $this ->redirectToRoute('task_show', array('id' => $task ->getId()));
}

return $this ->render('task/new.html.twig', array(
'task' => $task,
'form' => $form ->create View(),

74
));
}

/**
* Finds and displays a task entity.
*
* @Route("/{id}", name="task_show")
* @Method("GET")
*/
public function showAction(Task $task)
{
$deleteForm = $this ->createDeleteForm($task);

return $this ->render('task/show.html.twig', array(
'task' => $task,
'delete_form' => $deleteForm ->createView(),
));
}

/**
* Displays a form to edit an existing task entity.
*
* @Route("/{id} /edit", name="task_edit")
* @Method({"GET", "POST"})
*/
public function editAction(Request $request, Task $task)
{
$deleteForm = $this ->createDeleteForm($task);
$editForm = $this ->createForm('LicentaBundle \Form \TaskType', $task);
$editForm ->handleRequest($request);

if ($editForm ->isSubmitted() && $editForm ->isValid()) {
$this ->getDoctrine() ->getManager() ->flush();

return $this ->redirectToRoute('task_edit', array('id' => $task ->getId ()));
}

return $this ->render('task/edit.html.twig', array(
'task' => $task,
'edit_form' => $editForm ->createView(),
'delete_form' => $deleteForm ->createView(),
));
}

/**
* Deletes a task entity.
*
* @Route("/{id}", name="task_delete")
* @Method("DELETE")
*/
public function deleteAction(Request $request, Task $task)
{
$em = $this ->getDoctrine() ->getManager();
$em->remove($task);
$em->flush();

return new JsonResponse("OK");
}

/**
* Creates a form to delete a task entity.
*
* @param Task $task The task entity
*
* @return \Symfony \Component \Form \Form The form
*/
private func tion createDeleteForm(Task $task)
{
return $this ->createFormBuilder()
->setAction($this ->generateUrl('task_delete', array('id' => $task ->getId())))
->setMethod('DELETE')
->getForm()

75
;
}
}

Licenta Bundle/Controller/DepartamentController

<?php

namespace LicentaBundle \Controller;

use LicentaBundle \Entity \Departament;
use Sensio \Bundle \FrameworkExtraBundle \Configuration \Security;
use Symfony \Bundle \FrameworkBundle \Controller \Controller;
use Sensio \Bundle \FrameworkExtraBundle \Configuration \Method;
use Sensio \Bundle \FrameworkExtraBundle \Configuration \Route;
use Symfony \Component \HttpFoundation \JsonResponse;
use Symfony \Component \HttpFoundation \Request;

/**
* Departament controller.
* @Security("has_ role('ROLE_ADMIN')")
* @Route("departament")
*/
class DepartamentController extends Controller
{
/**
* Lists all departament entities.
*
* @Route("e", name="departament_index")
* @Method("GET")
*/
public function indexAct ion()
{
$em = $this ->getDoctrine() ->getManager();

$departamente = $em ->getRepository('LicentaBundle:Departament') ->findAll();

return $this ->render('departament/index.html.twig', array(
'departamente' => $departamen te,
));
}

/**
* Creates a new departament entity.
*
* @Route("/new", name="departament_new")
* @Method({"GET", "POST"})
*/
public function newAction(Request $request)
{
$departament = new Departamen t();
$form = $this ->createForm(
'LicentaBundle \Form \DepartamentType',
$departament
);
$form ->handleRequest($request);

if ($form ->isSubmitted() && $form ->isValid()) {
$em = $this ->getDoctr ine()->getManager();
$em->persist($departament);
$em->flush();

return $this ->redirectToRoute('departament_show', array('id' => $departament ->getId()));
}

return $this ->render('departament/new.html.twig' , array(
'departament' => $departament,
'form' => $form ->createView(),
));
}

/**

76
* Finds and displays a departament entity.
*
* @Route("/{id}", name="departament_show")
* @Method("GET")
*/
public function showAction(Departament $departament)
{
$deleteForm = $this ->createDeleteForm($departament);

return $this ->render('departament/show.html.twig', array(
'departament' => $departament,
'delete_for m' => $deleteForm ->createView(),
));
}

/**
* Displays a form to edit an existing departament entity.
*
* @Route("/{id}/edit", name="departament_edit")
* @Method({"GET", "POST"})
*/
public function editAction(Re quest $request, Departament $departament)
{
$deleteForm = $this ->createDeleteForm($departament);
$editForm = $this ->createForm(
'LicentaBundle \Form \DepartamentType',
$departament
);
$editForm ->han dleRequest($request);
if ($editForm ->isSubmitted() && $editForm ->isValid()) {
$this ->getDoctrine() ->getManager() ->flush();
return $this ->redirectToRoute('departament_edit', array('id' => $departament ->getId()));
}

return $this ->render('departament/edit.html.twig', array(
'departament' => $departament,
'edit_form' => $editForm ->createView(),
'delete_form' => $deleteForm ->createView(),
));
}

/**
* Delete s a departament entity.
*
* @Route("/{id}", name="departament_delete")
* @Method("DELETE")
*/
public function deleteAction(Request $request, Departament $departament)
{
$em = $this ->getDoctrine() ->getManager();
$em->remove($departament);
$em->flush();

return new JsonResponse("OK");
}

/**
* Creates a form to delete a departament entity.
*
* @param Departament $departament The departament entity
*
* @return \Symfony \Component \Form \Form The form
*/
private function createDeleteForm(Departament $departament)
{
return $this ->createFormBuilder()
->setAction($this ->generateUrl('departament_delete', array('id' => $departament ->getId())))
->setMethod('DELETE')
->getForm();
}
}

77
LicentaBundle/Controller/ProiectController

<?php

namespace LicentaBundle \Controller;

use LicentaBundle \Entity \Proiect;
use LicentaBundle \Entity \ProjectUsers;
use Sensio \Bundle \FrameworkEx traBundle \Configuration \Security;
use Symfony \Bundle \FrameworkBundle \Controller \Controller;
use Sensio \Bundle \FrameworkExtraBundle \Configuration \Method;
use Sensio \Bundle \FrameworkExtraBundle \Configuration \Route;
use Symfony \Component \HttpFoundation \JsonRe sponse;
use Symfony \Component \HttpFoundation \Request;

/**
* Proiect controller.
*
* @Route("proiect")
*/
class ProiectController extends Controller
{
/**
* Lists all proiect entities.
*
* @Route("e", name="proiect_index")
* @Me thod("GET")
*/
public function indexAction()
{
$em = $this ->getDoctrine() ->getManager();

$proiecte = $em ->getRepository('LicentaBundle:Proiect') ->findAll();

return $this ->render('proiect/index.html.twig', array(
'proiecte' => $proiecte,
));
}

/**
* Creates a new proiect entity.
*
* @Route("/new", name="proiect_new")
* @Method({"GET", "POST"})
*/
public function newAction(Request $request)
{
$proiect = new Proiect();
$form = $this ->createForm(
'LicentaBundle \Form \ProiectType',
$proiect,
[
'entityManager' => $this ->getDoctrine() ->getManager(),
'loggedInUser' => $this ->getUser()
]
);
$form ->handleRequest($request);

if ($form ->isSubmitted() && $form ->isValid()) {
$formData = $request ->request ->get('licentabundle_proiect');

$em = $this ->getDoctrine() ->getManager();
$userRepository = $em ->getRepository('LicentaBundle:User');

$em->persist($proiect);

$owner = new ProjectUsers();
$owner ->setProiect($proiect);
$owner ->setUser($this ->getUser());
$owner ->setIsOwner(true);
$em->persist($owner);

78
if (!empty($formData['users'])) {
foreach ($formData['users'] as $user) {
$userObj = $userRepository ->find($user);
$projectUser = new Pro jectUsers();
$projectUser ->setUser($userObj);
$projectUser ->setProiect($proiect);
$projectUser ->setIsOwner(false);
$em->persist($projectUser);
}
}

$em->flush();

return $this ->redirectToRoute('proiect_show', array('id' => $proiect ->getId()));
}
return $this ->render('proiect/new.html.twig', array(
'proiect' => $proiect,
'form' => $form ->createView(),
));
}

/**
* Finds and displays a proiect entity.
*
* @Route("/{id}", name="proiect_show")
* @Method("GET")
*/
public function showAction(Proiect $proiect)
{
$deleteForm = $this ->createD eleteForm($proiect);

return $this ->render('proiect/show.html.twig', array(
'proiect' => $proiect,
'delete_form' => $deleteForm ->createView(),
));
}

/**
* Displays a form to edit an existing proiect ent ity.
* @param Request $request
* @param Proiect $proiect
* @return \Symfony \Component \HttpFoundation \RedirectResponse| \Symfony \Component \HttpFoundation \Response
* @Route("/{id}/edit", name="proiect_edit")
* @Method({"GET", "POST"})
*/
public function editAction(Request $request, Proiect $proiect)
{
$deleteForm = $this ->createDeleteForm($proiect);
$editForm = $this ->createForm(
'LicentaBundle \Form \ProiectType',
$proiect,
[
'entityManager' => $this ->getDoctrine() ->getManager(),
'loggedInUser' => $this ->getUser()
]
);
$editForm ->handleRequest($request);

if ($editForm ->isSubmitted() && $editForm ->isValid() ) {
$formData = $request ->request ->get('licentabundle_proiect');
$em = $this ->getDoctrine() ->getManager();
$userRepository = $em ->getRepository('LicentaBundle:User');
$projectUserRepository = $em ->getReposito ry('LicentaBundle:ProjectUsers');
//luam toti membri proiectului
$users = $projectUserRepository ->findBy(['is_owner' => false, 'proiect' => $editForm ->getNormData()]);
//ii stergem
foreach($users as $user){
$em->remove($user);
}
// adaugam membri selectati in formularul de edit
if (!empty($formData['users'])) {
foreach ($formData['users'] as $user) {

79
$userObj = $userReposit ory->find($user);
$projectUser = new ProjectUsers();
$projectUser ->setUser($userObj);
$projectUser ->setProiect($editForm ->getNormData());
$projectUser ->setIsOwner(false);
$em->persist($projectUser);
}
}
//salvam in baza de date
$em->flush();

return $this ->redirectToRoute('proiect_edit', array('id' => $proiect ->getId()));
}

retur n $this ->render('proiect/edit.html.twig', array(
'proiect' => $proiect,
'edit_form' => $editForm ->createView(),
'delete_form' => $deleteForm ->createView(),
));
}

/**
* Deletes a proiect entity.
*
* @Route("/{id}", name="proiect_delete")
* @Method("DELETE")
*/
public function deleteAction(Request $request, Proiect $proiect)
{

$em = $this ->getDoctrine() ->getManager();
$em->remove($proiect);
$em->flus h();

return new JsonResponse("OK");
}

/**
* Creates a form to delete a proiect entity.
*
* @param Proiect $proiect The proiect entity
*
* @return \Symfony \Component \Form \Form The form
*/
private function createDeleteForm(Proiect $proiect)
{
return $this ->createFormBuilder()
->setAction($this ->generateUrl('proiect_delete', array('id' => $proiect ->getId())))
->setMethod('DELETE')
->getForm();
}
}

LicentaBu ndle/Controller/HomeController

<?php

namespace LicentaBundle \Controller;

use Sensio \Bundle \FrameworkExtraBundle \Configuration \Method;
use Sensio \Bundle \FrameworkExtraBundle \Configuration \Route;
use Sensio \Bundle \FrameworkExtraBundle \Configuration \Secur ity;
use Symfony \Bundle \FrameworkBundle \Controller \Controller;
use Symfony \Component \HttpFoundation \Request;

class HomeController extends Controller
{
/**
* Arata homepage
*
* @Route("/", name="homepage")
* @Security("has_role('ROL E_USER')")

80
* @Method("GET")
*/
public function homeIndexShow(Request $request)
{
$em = $this ->getDoctrine() ->getManager();
$taskRepository = $em ->getRepository('LicentaBundle:Task');
return $this ->render(':Home:ind ex.html.twig', [
'usersTasks' => $taskRepository ->findBy(['assignedTo' => $this ->getUser()])
]);
}
}

Similar Posts