seminarski rad na praksi -...

60
Seminarski rad na praksi Tema: CakePHP, MVC (Model – View – Controller) Juli, 2007 Mentor: Student: Mustafa Hodžić Jasmina Šero

Upload: others

Post on 30-Aug-2019

28 views

Category:

Documents


6 download

TRANSCRIPT

Seminarski rad na praksiTema: CakePHP, MVC (Model – View – Controller)

Juli, 2007

Mentor: Student: Mustafa Hodžić Jasmina Šero

SADRŽAJ

Seminarski rad na praksi ...................................................................................................... 1 SADRŽAJ ............................................................................................................................ 2 1. Uvod ................................................................................................................................. 3 2. MVC (Models – Views – Controllers) ............................................................................. 4

2.1. Model ........................................................................................................................ 5 2.1.1. Definiranje i upit sa hasOne: ............................................................................. 7 2.1.2. Definiranje i upit sa belongsTo .......................................................................... 8 2.1.3. Definiranje i upit sa hasMany ............................................................................ 9 2.1.4. Definiranje i upit sa hasAndBelongsToMany (HABTM) ............................... 11

2.2. View ....................................................................................................................... 20 2.3. Controller ................................................................................................................ 23

2.3.2. Controller callback ........................................................................................... 27 Možemo kreirati callback u našem aplikacijskom Model-u ili Controller file-u. U ovom primjeru šaljemo email iz Model-a .................................................................................... 27 3. Helper ............................................................................................................................. 28

3.1. HTML Helper ........................................................................................................ 28 3.2. TimeHelper ............................................................................................................ 31 3.3. NumberHelper ......................................................................................................... 32

4. Scaffolding ..................................................................................................................... 34 5. Data Validation ............................................................................................................. 35 6. Components ................................................................................................................... 37 7. Servis “Anketa” ............................................................................................................. 39

7.1. Tabele servisa .......................................................................................................... 39 7.2. MVC servisa ........................................................................................................... 41

7.2.1. Model .............................................................................................................. 41 7.2.2. View ................................................................................................................. 42 7.2.3. Controller ......................................................................................................... 46

7. 3. Upustvo za servis .................................................................................................. 52 ZAKLJUČAK .................................................................................................................... 59 LITERATURA .................................................................................................................. 60

2

1. Uvod

CakePHP je open source web aplikacijski framework napisan za PHP, distribuiran od MIT license. Razvoj Cake-a počinje u 2005-oj godini od tada je nastalo nekoliko projekata i još uvijek se radi na razvoju novih.CakePHP je dobro dokumentovan framework, inspiriran konceptom predstavljenim u RoR-u (Ruby on Rails), koji može biti primjenjen u PHP4 – PHP5. Cake olakšava komunikaciju user interface-a sa bazom podataka, brz je, koristi MVC ( Model – View – Controller ) arhitekturu, te time forsira objektno i uredno programiranje. Ima podršku za cashe, ajax, RSS Helper, a uskoro bi trebao dobiti još “masu” stvari. Kod testiranja i debagiranja aplikacije bilo koji developer koji primjenjuje CakePHP strukturu će biti sposoban da locira i ispravi grešku bez znanja svih detalja o kodu.

Neke osobine CakePHP- a:

- Kompatibilan je sa PHP4 i PHP5- Fleksibalan View Cashing- Application Scaffolding- Access Control List- View Helpers za AJAX, Javascript, HTML forme,...- Radi iz bilo kojeg website poddirektorija- Brz, fleksibilan template (PHP sintaksa sa Helper metodama)- Ugrađena validacija- Website directory nezavisan- View caching

Da bi koristili CakePHP moramo imati HTTP sever (wamp, apache), PHP 4 ili 5, database engine (MaSQL, PostgreSQL).Instalacija Cake-a: downloadujemo jednu od verzija CakePHP-a (www.cakephp.org, www.forgephp.org ). Otpakujemo folder i snimimo na web server u webroot direktorij ( wamp, apache,…npr. C:\wamp\www), zatim učitamo stranicu kao localhost u web browser-u. Indexnu stranu podešavamo u /app/config/routes.php file-u, detalje o podešavanju i instalaciji CakePHP-a možemo naći u CakePHP Manual dokumentu, (www.cakephp.org ).

3

2. MVC (Models – Views – Controllers)

MVC je arhitekturalni patern koji se koristi u softverskom inžinjeringu, u kompleksnim kompjuterskim aplikacijama koje predstavljaju dugi niz korisničkih podataka. Developeri često žele odvojiti podatke (model) od korisničkog interfejsa (view), tako da mijenjaju korisnički interfejs koji ne daje podatke i podaci mogu biti reorganizovani bez mijenjanja interfejsa. MVC rješava ovaj problem odvajanjem pristupa podacima od biznis logike iz prezentacijskih podataka i korisničkog interfejsa, uključujući komponentu controller.

MVC često vidimo u web aplikacijama, gdje je view ustvari HTML stranica, a controller je kod koji skuplja dinamičke podatke i generira sadržaj sa HTML-om. Model je predstavljen stvarnim sadržajem, koji je obićno smješten u bazu podataka ili XML fajl. MVC je software dizajn patern koji pomaže u logičkom odvajanju koda, to je kao konceptualna paradigma, koja postoji kao veza između tri objekta: Model, View i Controller. Svi naši entiteti (Models), funkcije ovih entiteta (Controllers), korisnički interfejs (Views) smješteni su u odvojenim fajlovima, tako da nećemo mijenjati Contoller ako želimo promijeniti izgled nekog input polja,… Controller i View zavise od Model-a, zato što zahtijevaju podatke iz Model-a, bilo koji input dolazi preko Controllera, koji zatim odabire View za prikaz rezultata tj, Controller prima svaki HTTP zahtijev, a View generira HTTP odgovor, kao što možemo vidjeti na sljedećoj slici

Input -> Processing -> Output

Controller -> Model -> View

4

- Model enkapsulira aplikacijeske podatke, aplikacijski flow i business logic- View ekstraktuje podatke iz Modela i formatira ih za prezentaciju- Controller pristupa aplikacijskom flow, prima ulaze (zahtijeve) i prevodi ih za

Model i View

Modeli, views (pogledi) i kontroleri nalaze se u predefinisanom direktoriju sa CakePHP–ovom direktori strukturom, kao što se može vidjeti u sljedećem primjeru:

• app/o config/o controllers/o models/o plugins/o tmp/o vendors/o views/o webroot/

• cake/o config/o docs/o libs/

• vendors/

2.1. Model

5

Model je objekt MVC arhitekture, sadrži aplikacijske podatke i logiku, ponaša se kao primarni drajver u aplikaciji, nema nikakve prezentacijske osobine i nikakvu odgovornost prema HTTP zahtijevima,tj. odvaja prezentacijku logiku od aplikacijske. Omogućava pristup bazi podataka i tabelama u bazi. Po defaultnu imena modela su u jednini i imaju ime isto kao i tabela u bazi, s tim da je ime tabele u množini, npr. ako imamo tabelu “answers”, trebamo imati i model “Answer”. Primjer:

Answer model se treba snimiti u app/models/answer.php<?php

class Answer extends AppModel{ var $name = 'Answer';}

?>

Domain Model je layer objekt koji apstraktnu logiku, podatke i probleme aplikacije odvaja. Može se klasificirati u dvije kategorije:

- Simple Domain Model ima one – to – one odgovornost između business objekata i tabela u bazi podataka

- Rich Domain Model uključuje kompleksne web objekte i mnoge dizajn paterneKoji model ćemo koristiti zavisi od konteksta aplikacije.

Jedna od najmočniji osobina CakePHP je veza između modela. Postoje četiri tipa veza:- hasOne- hasMany- belongsTo- hasAndBelongsToMany

Kada je veza između modela definisana, Cake automatski povezuje modele. Za korektno korištenje asocijacije najbolje je slijediti CakePHP konvenciju imenovanja. Ukoliko koristimo CakePHP konvenciju imenovanja, možemo koristiti scaffolding da predstavimo sebi aplikacijske podatke, jer scaffolding pronalazi i koristi asocijacije između modela. Naravno, možemo uvijek podesiti model asocijacije da rade bez CakePHP konvencije imenovanja.

CakePHP konvencija imenovanja odnosi se na foreign (strani) ključ, ime modela i ime tabele:

- Foreign (strani) ključ: [ime modela u jednini]_id, npr. strani ključ u “authors” tabeli za povezivanje sa Post modelom koristi asocijaciju Authors belongs to, starni ključ u “authors” tabeli bi trabao biti “post_id”.

- Ime tabele: [ime objekta u množini], npr. ako želimo snimiti informacije o blog postu i autorima, imena tabela trebaju biti “posts” i “authors”.

- Ime modela: [ime tabele u jednini], ime modela za tabelu “posts” je “Post”, a ime modela za tabelu ”authors” je “Author”.

6

CakePHP scaffolding očekuje asocijacije u istom poretku kao i kolona, tako ako imamo Article koji belongsTo (pripada) modelima: Author, Editor i Publisher. Trebamo i tri ključa: author_id, editor_id, publisher_id. Scaffolding očekuje asocijacije u istom poretku kao što su ključevi u tabeli, npr. prva Author, druga Editor i posljednja Publisher.

Primjer: Ako želimo kreirati jednostavni user menađment sistem za blog, svaki user ima jedinstven profil što omogućava asocijaciju hasOne (User hasOne Profile). Međutim user-i mogu dodavati i komentare pa imamo asocijaciju hasMany (User hasMany Comments). Kada želimo da user sistem radi dozvolit ćemo Posts koji će biti povezan sa Tag objektima, tako da imamo asocijaciju hasAndBelongToMany (Post hasAndBelongToMany Tags).

2.1.1. Definiranje i upit sa hasOne:

<?phpclass User extends AppModel{ var $name = 'User'; var $hasOne = array('Profile' => array('className' => 'Profile', 'conditions' => '', 'order' => '', 'dependent' => true, 'foreignKey' => 'user_id' ) );}?>

Varijablu $hasOne Cake koristi za pravljenje asocijacije između User i Profile modela. Svaki ključ u nizu dozvoljava nam dalju konfiguraciju asocijacije:

- className: ime klase modela koji želimo povezati , npr. ako želimo specifirati “Profile” ime klase modela

- uslovi: SQL fragmenti stanja (uslova) koji definišu taj odnos. Možemo koristiti ovo da kežemo Caku-u da samo poveže Profile koji ima green header, da definišemo ovakav uslov treba specifirati SQL uslov: “Profile.header_color = ’green’ ”.

- order: redoslije asocijacija modela, ako želimo veze modela u specifičnom redoslijedu, postavimo vrijednost ključa koristeći SQL redoslijed: “Pofile.name ASC”

7

- zavisnost: ukoliko je podešena na true, pridruženi model je uništen kada je uništen

predhodni - forgeinKey: ime stranog ključa koji povezuje odgovarajući model

Kada izvršimo find() ili findAll() poziva korišteni Profile model, trebali bi vidjeti asocijaciju User modela, kao što je:

$user = $this->User->read(null, '25');print_r($user);

//output:

Array( [User] => Array ( [id] => 25 [first_name] => John [last_name] => Anderson [username] => psychic [password] => c4k3roxx )

[Profile] => Array ( [id] => 4 [name] => Cool Blue [header_color] => aquamarine [user_id] = 25 ))

2.1.2. Definiranje i upit sa belongsTo

Međutim User može zahtijevati da vidi Profil, to ćemo omogućiti pomoću asocijacije belongsTo koju kreiramo u modelu Profil, primjer, putanja : /app/models/profile.php<?phpclass Profile extends AppModel{ var $name = 'Profile'; var $belongsTo = array('User' => array('className' => 'User', 'conditions' => '', 'order' => '', 'foreignKey' => 'user_id' ) );}?>

8

$belongsTo niz Cake koristi da poveže modele Profil i User.

Kada izvršimo find() ili findAll() poziv Profil modela, trebali bi vidjeti pridruženi User model kao što je:$profile = $this->Profile->read(null, '4');print_r($profile);

//output:

Array(

[Profile] => Array ( [id] => 4 [name] => Cool Blue [header_color] => aquamarine [user_id] = 25 )

[User] => Array ( [id] => 25 [first_name] => John [last_name] => Anderson [username] => psychic [password] => c4k3roxx ))

2.1.3. Definiranje i upit sa hasMany

Sada kada su User i Profile model povezani i rade, treba napraviti sistem da User arhivu poveže sa Comment arhivom. U User model trebamo dodati: <?phpclass User extends AppModel{ var $name = 'User'; var $hasMany = array('Comment' => array('className' => 'Comment', 'conditions' => 'Comment.moderated = 1', 'order' => 'Comment.created DESC', 'limit' => '5', 'foreignKey' => 'user_id', 'dependent' => true, 'exclusive' => false, 'finderQuery' => '' ) );

9

Cake koristi $hasMany niz da napravi vezu User i Comment modela. Svaki ključ u nizu dozvoljava dalju konfiguraciju veze:

- className: ime modela koji želimo povezati- uslovi: SQL fragmenti stanja (uslova) koji definišu taj odnos. Možemo koristiti uslov da kažemo Cake-u da poveže samo Comment koji je ograničen, npr. “Comment.modereted = 1”- redoslijed: redoslijed povezani modela, ako želimo povezati modele u određeni redoslijed, postavimo vrijednost ključa da koristi SQL redoslijed, npr. “Comment.created DESC”- limit (ograničenje)- maksimalan broj veza modela, koji želimo da nam Cake dohvati, u ovom primjeru nismo htjeli sve komentare, već samo 5- foreignKey: ime stranog ključa koji povezuje pridruženi model- exclusive: ako je posatvljeno na true, svi povezani objekti će biti obrisani u jednoj SQL izjavi bez da se beforeDelete callback pokrene- finderQuery: specifikacija kompletne SQL izjave za dohvat veze, ovo je dobar način za kompleksne asocijacije koje ovise o više tabela

Kada izvršimo find() ili findAll() poziv User modela, trebali bi vidjeti povezane Comment modele, kao što je:$user = $this->User->read(null, '25');print_r($user);

//output:

Array( [User] => Array ( [id] => 25 [first_name] => John [last_name] => Anderson [username] => psychic [password] => c4k3roxx )

[Profile] => Array ( [id] => 4 [name] => Cool Blue [header_color] => aquamarine [user_id] = 25 )

10

[Comment] => Array ( [0] => Array ( [id] => 247 [user_id] => 25 [body] => The hasMany assocation is nice to have. )

[1] => Array ( [id] => 256 [user_id] => 25 [body] => The hasMany assocation is really nice to have. )

[2] => Array ( [id] => 269 [user_id] => 25 [body] => The hasMany assocation is really, really nice to have. )

[3] => Array ( [id] => 285 [user_id] => 25 [body] => The hasMany assocation is extremely nice to have. )

[4] => Array ( [id] => 286 [user_id] => 25 [body] => The hasMany assocation is super nice to have. )

))

Dobra ideja je definirati “Comment belongsTo User” asocijaciju, tako da oba modela mogu vidjeti jedan drugi. Ne definiranje asocijacija iz oba modela je često uobičajna greška kada pokušamo koristiti scaffolding.

2.1.4. Definiranje i upit sa hasAndBelongsToMany (HABTM)

HasAndBelongsToMany je najteži za “pravljenje”, ali je takođe i najviše korišten,koristan je kad imamo dva modela koja su povezana zajedno sa pridruženim tabelama. Pridružene tabele sadrže individualne redove koji su povezani jedan sa drugim. Razlika između hasMany I hasAndBelongsToMany je ta što sa hasMany, asocijacija

11

modela nije dijeljena (shared). Ako imamo User hasMany Comments, samo je user povezan sa komentarima, sa HABTM, asocijacije modela su dijeljene.

HABTM pridružene tabele, jednostavni modeli i pridružena im imena tabela:- Posts i Tags: posts_tag - Monkeys i IceCubes: ice_cubes_monkeys- Categories i Articles: articles_categories

HABTM da poveže tabele treba najmanje dva strana ključa modela koji su povezani. Za naš primjer to su “post_id” i “tag_id”. Primjer Posts HABTM Tags:---- Table structure for table `posts`--

CREATE TABLE `posts` ( `id` int(10) unsigned NOT NULL auto_increment, `user_id` int(10) default NULL, `title` varchar(50) default NULL, `body` text, `created` datetime default NULL, `modified` datetime default NULL, `status` tinyint(1) NOT NULL default '0', PRIMARY KEY (`id`)) TYPE=MyISAM;

-- --------------------------------------------------------

---- Table structure for table `posts_tags`--

CREATE TABLE `posts_tags` ( `post_id` int(10) unsigned NOT NULL default '0', `tag_id` int(10) unsigned NOT NULL default '0', PRIMARY KEY (`post_id`,`tag_id`)) TYPE=MyISAM;

-- --------------------------------------------------------

---- Table structure for table `tags`--

CREATE TABLE `tags` ( `id` int(10) unsigned NOT NULL auto_increment, `tag` varchar(100) default NULL, PRIMARY KEY (`id`)) TYPE=MyISAM;

12

Sa ovim tabelama definišemo asocijaciju u Post modelu:/app/models/post.php hasAndBelongsToMany<?phpclass Post extends AppModel{ var $name = 'Post'; var $hasAndBelongsToMany = array('Tag' => array('className' => 'Tag', 'joinTable' => 'posts_tags', 'foreignKey' => 'post_id', 'associationForeignKey'=> 'tag_id', 'conditions' => '', 'order' => '', 'limit' => '', 'uniq' => true, 'finderQuery' => '', 'deleteQuery' => '', ) );}?>

Cake koristi $hasAndBelongsToMany niz da napravi asocijaciju između Post i Tag modela. Kada izvršimo find() ili findAll() poziv Post modela, trebali bi vidjeti pridruženi

Tag model kao što je:$post = $this->Post->read(null, '2');print_r($post);

//output:

Array( [Post] => Array ( [id] => 2 [user_id] => 25 [title] => Cake Model Associations [body] => Time saving, easy, and powerful. [created] => 2006-04-15 09:33:24 [modified] => 2006-04-15 09:33:24 [status] => 1 )

[Tag] => Array ( [0] => Array ( [id] => 247 [tag] => CakePHP )

13

[1] => Array ( [id] => 256 [tag] => Powerful Software ) ))

2.1.1. Model funkcije

Modeli su klase proširene AppModel klasom, AppModel klasa je orginalno definisana u cake/ direktoriju, ali ako želimo kreirati vlastitu, treba je smjestiti u /app/app_model.php. Treba da sadrži metode koje su dijeljene između dva ili više modela. Time ona proširuje klasu Model koja je standardna Cake biblioteka definisana u cake/libs/model.php.

Primjer specifične metode u modelu je par metoda za hiding/unhiding post u blogu, kao što vidimo u sljedećem primjeru:<?phpclass Post extends AppModel{ var $name = 'Post';

function hide ($id=null) { if ($id) { $this->id = $id; $this->saveField('hidden', '1'); } }

function unhide ($id=null) { if ($id) { $this->id = $id; $this->saveField('hidden', '0'); }

14

}}?>

U sljedećem primjeru vidimo nekoliko standardni načina za dobivanje naših podataka koristeći model:

findAll ($conditions //primjer:$conditions="race='wookie' AND thermal_detonators > 3", $fields, $order, $limit, $page, $recursive);

string $conditions; array $fields;string $order;int $limit;int $page;int $recursive;

Kada je $recursive opcija postavljena na vrijednost veću od 1, findAll( ) operacije pokušavaju vratiti odgovarajući model nađen sa findAll( ). Ako naš property ima više vlasnika koji su uključeni u više ugovora, findAll( ) na našem Property modelu će vratiti te odgovarajuće modele.

find ($conditions $fields, $order, $recursive);

string $conditions; array $fields;string $order;int $recursive;

Vraća specifično polje iz prvog rekorda koje odgovara $conditions. Ove magične funkcije mogu biti korištene kao shortcut za pretragu tabela za redom koji je dat određenim poljem i određenom vrijednošću. Treba samo izabrati ime polja koji želimo tražiti, primjer:$this->Post->findByTitle('My First Blog Post');$this->Author->findByLastName('Rogers');$this->Property->findAllByState('AZ');$this->Specimen->findAllByKingdom('Animalia');

Povratni rezultat je niz formatiran koji je nađen sa find() ili findAll( ).

15

findNeighbours ($conditions

$field, $value);

string $conditions; array $field;string $value;

Vraća niz sa susjednim modelom (sa samo navedenim poljima), specifiran sa $field i $value i filtriran sa SQL uslovima, $conditions. Ovo može biti korisno u situaciji kada želimo 'Previous' i 'Next' linkove koji vode korisnika kroz uređenu sekvencu u našem model-u ulaza. Ovo radi samo za numerička i date polja. Primjer:class ImagesController extends AppController{ function view($id) { // Say we want to show the image...

$this->set('image', $this->Image->find("id = $id");

// But we also want the previous and next images...

$this->set('neighbours', $this->Image->findNeighbours(null, 'id', $id);

}}

findCount ($conditions);string $conditions;

Vraća broj rekorda koji odgovaraju zadanim uslovima.

generateList ($conditions, $order, $limit, $keyPath, $valuePath);

string $conditions;string $order;int $limit;string $keyPath;string $valuePath;

Ova funkcija je shortcut za dobivanje liste ključnih vrijednosti parova – pogotovo praktična za kreiranje html select tagova iz liste našeg modela. Npr. ako želimo generirati listu uloga baziranu na Role modelu, puni poziv može izgledati kao u sljedećem primjeru:

$this->set(

16

'Roles', $this->Role->generateList(null, 'role_name ASC', null, '{n}.Role.id', '{n}.Role.role_name'));

//This would return something like:array( '1' => 'Account Manager', '2' => 'Account Viewer', '3' => 'System Manager', '4' => 'Site Visitor');

read ( $fields, $id);string $fields;string $id;

Ovu funkciju možemo koristiti da dobijemo polja i vrijednosti polja iz trenutačno učitanog rekorda ili rekorda specifiranog sa $id.

query ($query);string $query;

execute ($query);string $query;

SQL poziv možemo napraviti koristeći model query( ) i execute ( )metode. Razlika između query( ) i execute ( ) je ta što, query( ) koristimo da napravimo korisnički SQL upit, a execute( ) koristimo da napravimo korisničke SQL komande.Primjer:<?phpclass Post extends AppModel{ var $name = 'Post';

function posterFirstName() { $ret = $this->query("SELECT first_name FROM posters_table WHERE poster_id = 1"); $firstName = $ret[0]['first_name']; return $firstName; }}?>

Većina model pretraživača uključuju prosljeđivanje uslova u jednom ili u drugom pravcu. Najjednostavniji pristup ovome je pomoću WHERE klauzule iz SQL-a, ali ako nam je potrebno više kontrole možemo koristiti nizove. Korištenje nizova je jednosatvno i lako za čitanje i jednostavno je za pravljenje upita. Sintaksa odvaja elemente upita u diskretne,

17

manipulativne dijelove. Ovo dozvoljava Cake-u da generira najviše moguće efikasne upite, osigurava odgovarajuću SQL sintaksu. Upit baziran na nizu izgleda ovako:

$conditions = array("Post.title" => "This is a post");

//Example usage with a model:$this->Post->find($conditions);

Traži bilo koji post gdje naslov odgovara stringu “This is a post”, mogli smo koristiti samo “title” kao ime polja. Kada pravimo upite, dobra je praksa uvijek specificirati ime modela, kao poboljšanje jasnoće koda i kao pomoć pri prevenciji kolizija u budućnosti ako odlučimo mijenjati našu šemu. I sa drugim komparacijama je isto, npr. ako želimo naći sve postove gdje naslov nije “This is a post”.

array("Post.title" => "<> This is a post")

Sve što je dodano nalazi se između ‘< >’ tagova prije izraza. Cake može obraditi bilo koju validnu SQL komparaciju operatora uključujući odgovarajuće izraze koristeći LIKE, BETWEEN. Npr. Ako želimo naći post gdje je naslov dat kao set vrijednosti:

array("Post.title" => array("First post", "Second post", "Third post"))

Dodavanje dodatnih filtera uslovima je jednostavno kao dodavanje dodatnih parova vrijednosti /ključeva nizu.

array( "Post.title" => array("First post", "Second post", "Third post"), "Post.created" => "> " . date('Y-m-d', strtotime("-2 weeks")))

Cake prihvata sve validne SQL bool-ove operacije, uključujući AND, OR, NOT, XOR,...i možemo ih pisati malim ili velikim slovima. Po defaultu, Cake pristupa višestrukim uslovima sa bool-ovim AND, što znači, odlomak koji želimo odgovara samo postu koji je kreiran prije dvije sedmice i naslov odgovara jednom u datom setu. Mi možemo jednostavno naći post koji odgovara bilo kojem uslovu:array("or" => array ( "Post.title" => array("First post", "Second post", "Third post"), "Post.created" => "> " . date('Y-m-d', strtotime("-2 weeks")) ))

18

Snimanje podatakaDa bi snimili podatke u naš model, trebamo dostaviti podatke koje želimo snimiti, podaci koji se šalju save( ) metodi trebaju biti u sljedećoj formi:

Array( [ModelName] => Array ( [fieldname1] => 'value' [fieldname2] => 'value' ))

U redoslijedu slanja podataka controller-u u ovom načinu, lakše je koristiti HTML helper za ovo, jer kreira forme elemenata koje su imenovane na način koji Cake očekuje. Samo trebamo biti sigurni da forme elemenata imaju imena kao što je data[Modelname][fieldname], koristiti $html->input('Model/fieldname') je najjednostavnije. Podaci poslani iz forme se automatski formatiraju i budu smješteni u $this->data u contoller-u, tako da je snimanje podataka iz web formi brzo. Edit funkcija za svojstvo controller-a može izgledati ovako:

function edit($id){

// The property model is automatically loaded for us at $this->Property.

// Check to see if we have form data... if (empty($this->data)) { $this->Property->id = $id; $this->data = $this->Property->read();//populate the form fields with the current row } else { // Here's where we try to save our data. Automagic validation checking if ($this->Property->save($this->data['Property'])) { //Flash a message and redirect. $this->flash('Your information has been saved.', '/properties/view/'.$this->data['Property']['id'], 2); } //if some fields are invalid or save fails the form will render }}

Delete funkcija:del ( $id,

19

$cascade);string $id;boolean $cascade;

Brisanje modela specificiramo sa $id ili sa aktualnim id-om modela. Ako je model povezan sa drugim modelima, ova metoda će takođe obrisati povezani model. Ako je $cascade posatvljen na true, vraća true pri uspjehu, tj. nakon uspješnog brisanja.

2.2. View

View je page template, koji se obično imenuje poslije akcije, npr. view za PostController::add() nalazi se u /app/views/posts/add.thtml.<h1>Add Post</h1><form method="post" action="<?php echo $html->url('/posts/add')?>"> <p> Title: <?php echo $html->input('Post/title', array('size' => '40'))?> <?php echo $html->tagErrorMsg('Post/title', 'Title is required.') ?> </p> <p> Body: <?php echo $html->textarea('Post/body', array('rows'=>'10')) ?> <?php echo $html->tagErrorMsg('Post/body', 'Body is required.') ?> </p> <p> <?php echo $html->submit('Save') ?> </p></form>

20

Svi pogledi (views) unutar Cake-a se nalaze u odvojenim fajlovima (*.thtml) koji su slobodni od kompleksnog PHP koda. Cake views su prilično jednostavni PHP file-ovi, najviše view file-ova sadrži HTML. View takođe može biti bilo koji set podataka, npr. XML, image,..Views omogućava sve aspekte prezentacije, eksktaktuje podatke iz Model-a i priprema ih kao HTML za web stranicu ili kao XML za web server ili kao tekst za mail. View ima pristup Model-u, ali nije dobro da View poziva metode Model-a kao što je update, to bi trebalo uraditi preko Controller-a. HTML Helper je po defaultu dostupan u svakom view-u i to je najkorišteniji helper u view-u. Koristan je kod kreiranja formi, uključuje scripte, linkove, mediu…Mnoge funkcije u view-u su dostupne preko helpera, Cake dolazi sa velikim brojem helper-a, a može se kreirati i vlastiti. View ne treba sadržavati puno logike, zato nema puno korištenih javnih funkcija u view-u. Postoje dva dizajn paterna koja se koriste u view-u: Template View i Transform View. Razlika između Template View-a i Transform View-a je u pristupu data flow-u. U Template počinje se sa skeletom outputa i insertuju domain podaci u to, dok u Transform View-u počinje se sa podacima i gradi se output prema tome.

Template View je primarni patern koji koristi template file (obično HTML) koji uključuje specijalne markere koji su zamijenjeni sa podacima iz modela kada je Template View izvršen. Popularni template Smarty je primjer template-a koji koristi custem syntax metodu. Transform View ekstraktuje podatke iz modela i transformiše ih u traženi output format. View :

- layouts- elements

2.2.1. Layouts

Layouts sadrži prezentacijski kod i bilo što što želimo vidjeti u view-u treba biti smješteno u layout-u. Layout file-ovi nalaze se u /app/views/layouts. Cake-ov defaultni layout može biti zamijenjen novim defaultnim layout-om kao /app/views/layouts/defaults.thtml. Jednom kada defaultni layout bude kreiran, controller view kod biva smješten unutar defaultnog layout-a. Kada kreiramo layout treba “reči” Cake gdje se nalazi controller. Primjer kako može izgledati defaultni layout

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title><?php echo $title_for_layout?></title><link rel="shortcut icon" href="favicon.ico" type="image/x-icon"></head><body>

<!-- If you'd like some sort of menu to show up on all of your views, include it here --><div id="header"> <div id="menu">...</div>

21

</div>

<!-- Here's where I want my views to be displayed --><?php echo $content_for_layout ?>

<!-- Add a footer to each displayed page --><div id="footer">...</div>

</body></html>

Možemo kreirati koliko hoćemo layout-a u Cake-u samo ih treba smjestiti u /app/views/layouts direktorij.

2.2.2. Elements

Mnoge aplikacije imaju male blokove prezentacijskog koda koji se treba ponavljati na više stranica, ponekad u različitim mjestima u layout-u. Cake pomaže da ponavljamo dio website-a koji nam je potreban. Help boksovi, navigacijka kontrola,ekstra meniji su implementirani u Cake-u kao elementi. Element je bazično mini view koji koji može biti uključen u drugi View. Elementi se nalaze u /app/views/elements/ folderu I imaju .thtml file ekstenziju. Elementi po defaultu nemaju nikakav pristup podacima, da bi dozvolili pristup podacima šaljemo ih kao imenovani parameter u niz.

Primjer: Poziv elemenata bez parametra <?php echo $this->renderElement('helpbox'); ?>

Poziv elementa kao niza podataka:

<?php echo$this->renderElement('helpbox', array("helptext" => "Oh, this text is very helpful.")); ?>

U Element file-u sve propuštene varijable su varijable imenovane kao i niz , elementi se mogu koristiti da View učine više čitljivim.

22

2.3. Controller

Controller procesira i odgovara na događaje, tipična korisnička akcija i poziva promjene na modelu.Controller se koristi za logičko upravljanje modelom, ime Controllera u Cake-u je uvijek u množini. Ime controller klase zavrašava sa „Controller“ npr. PeopleController, UsersController, klase AppController-a definisane su u app/app_controller.php i treba da sadrže metode koje su dijeljenene imeđu dva ili više Contoller-a. Ime controller file-a piše se malim slovima i završava sa '_controller', pa ako imamo controller klasu koja se zove PostsController, file controller će biti posts_controller.php, primjeri: people_controller.php, line_items_controller.php, really_nifty_things_controller.php. Da bi zaštitili vidljivost, ime akcije controller-a treba početi sa '-', za privatnu vidljivost,ime treba početi sa '- -'. Manipulacija sa nekoliko specijalnih varijabli u controller-u dozvoljava da koristimo neke prednosti extra Cake funkcionalnosti.

Imamo dvije vrste Controller-a: - Front Controller- Application Controller

Front Controller često pomaže u centralizaciji aplikacijkog flow-a u jednostavnim tačkama. Centralizacija može pomoći da razumijemo kako kompleksan sistem operira i navodi jednostavna mjesta gdje možemo ubaciti globalni kod. Front Controller je odličan za centralizaciju. Application Controller je centar onog čime MVC Controller operira. Primarna odgovornost je da odluči šta aplikacija treba odgovoriti na traženi zahtijev. Tipičan način impelmentacije Controller-a je koristeći Command paterne. Command patern enkapsulira akciju u objekte, tako da možemo parametrizirati upit. U sadržaju web aplikacije koristan je cilj koda koji odvaja koncentrirani Command da brine o radu pojedinačni HTTP zahtijeva.

2.3.1. Controller varijable:

23

- $uses – ako controller koristi više od jednog modela, FragglesController će

automatski učitati $this->Fraggle, ali ako želimo pristupiti $this->Smurf, treba pokušati dodati sljedeću liniju koda u controller: var $uses = array('Fraggle','Smurf'); Treba primjetiti da smo uključili Fraggle model u $uses niz, iako je automatski prije bio dostupan.

- $helper – ova varijabla se koristi za učitavanje helpera u view. HTML helper se automatski učitava, ali može se ova varijabla koristiti i za druge helpere npr. var $helpers = array('Html','Ajax','Javascript'). Treba uključiti HtmlHelper u $helpers ako ga želimo koristiti, dostupan je po defaultu ali ako definišemo $helper bez HtmlHelpera, dobit ćemo poruku o greški u view-u.

- $autoRender - postavljajući ovo na false će zaustaviti akciju od automatskog izvođenja

- $components – kao $helpers i $uses, ova varijabla koristi se za učitavanje komponenata koje su nam potrebne npr. var $components = array('acl');

- $beforeFilter – koristimo ovu varijablu ako želimo da se kod pokreće svaki put kada se akcija pozove . Ova funkcionalnost je veoma dobra za access control- možemo vidjeti korisničke permisije prije nego se izvrši bilo koja akcija. Primjer:

class ProductsController extends AppController{ var $beforeFilter = array('checkAccess');

function checkAccess() { //Logic to check user identity and access would go here.... }

function index() { //When this action is called, checkAccess() is called first. }}

2.3.1.Controller parametri Controller parametri su dostupni preko $this->params u Cake controller-u, ova varijabla se koristi da dajemo podatke u controller i omogućava pristup informacijama o tačnom upitu. Najčešće se koristi da se dobiju informacije (podaci) koje su date controller-u preko POST ili GET operatora.$this->data

Primjer: slanje podataka POST metodom iz HTML Helper-a u controller// A HTML Helper is used to create a form element

$html->input('User/first_name');

24

// When rendered in the HTML would look something like:

<input name="data[User][first_name]" value="" type="text" />

// And when submitted to the controller via POST,// shows up in $this->data['User']['first_name']

Array( [data] => Array ( [User] => Array ( [username] => mrrogers [password] => myn3ighb0r [first_name] => Mister [last_name] => Rogers )

))

Akcija je jedinstvena funkcionalnost kontrolera, pokreće se automatski po zahtijevu.

- set( ) funkcija je glavni put da uzmemo podatke iz controller-a da bi ih vidjeli, parametri funkcije mogu biti jednostavne vrijednosti, nizovi... set($var,$value), string $var, mixed $value. Funkciju set( ) možemo koristiti da uzmemo bilo šta: jednosatvne vrijednosti, cijele nizove,..Jednom kada koristimo set(), varijablama može se pristupiti u view-u, ako napišemo set('color','blue') , controller napravi varijablu $color dostupnom u view-u.

- $this->flash( ) funkcija zove se upravljačka funkcija koja prikazuje korisniku poruku npr. $this->flash ('Your post has been saved.','/posts'); tj. Ispisuje poruku korisniku da je njegov post snimljen ili $this->flash ('The post with id: '.$id.' has been deleted.', '/posts'); ispisuje poruku da je post izbrisan. Save() metoda provjerava greške i neće snimiti podatke ako postoji greška.

- validateErrors( ) - vraća broj grešaka koje su generirane pri neuspješnom snimanju podataka.

- render ( ) je funkcija koja se često ne koristi, jer render se automatski poziva na kraju svake kontrolne akcije.

U sljedećem primjeru imamo Post controller sa četiri funkcije: funkcija index ( ), add ( ), edit ( ) i delete ( ). Funkcija index nam prikazuje početnu stranicu tj. stranicu koju smo postavili da bude indexna, početna, koja prikazuje naslov postojeće vijesti. Omogućava dodavanje novih vijesti, edit i delete vijesti koje su nalaze u bazi.

25

<?php

class PostsController extends AppController{ var $name = 'Posts';

function index()

{ $this->set('posts', $this->Post->findAll()); }

function view($id = null) { $this->Post->id = $id; $this->set('post', $this->Post->read()); }

function add() { if (!empty($this->data)) { if ($this->Post->save($this->data)) { $this->flash('Your post has been saved.','/posts'); } } }

function delete($id){ $this->Post->del($id); $this->flash('The post with id: '.$id.' has been deleted.', '/posts');}function edit($id = null){ if (empty($this->data)) { $this->Post->id = $id; $this->data = $this->Post->read(); } else { if ($this->Post->save($this->data['Post'])) { $this->flash('Your post has been updated.','/posts'); } }}}

?>

26

2.3.2. Controller callback

U Cake-u callback je način izvršavanja nekog koda prije ili poslije Model ili Contoller metoda. Cake controller omogućava odgovarajući broj callback-ova koji možemo iskoristiti da bi ubacili logiku prije ili poslije značajnih funkcija controller-a. Treba deklarisati funkcije u controller-u koristeći parametre i povratne vrijednosti. - beforeFilter ( ); poziva se prije svake controller akcije, korisna za provjeru aktivni

sesija i provjeru uloga- afterFilter ( ); poziva se nakon svake controller akcije- beforeRender ( ); poziva se nakon controller logike i prije nego što je view prikazan

Sljedeće funkcije su dio Cake objekt klase, ali one mogu biti dostupne i u controller-u - requestAction ( $url, $options);

string $url;array $options;Ova funkcija poziva controller akciju iz bilo koje lokacije i vraća tj. prikazuje view. $url je Cake URL (/controllername/actionname/params), ako $extra niz uključuje 'return' , AutoRender automatski postavlja true za controller akciju. Možemo koristiti requestAction da dobijemo podatke iz druge controller akcije ili da dobijemo potpuni render view iz controller-a. Uzimanje podataka iz controller-a je jednostavno, koristi se samo upitna akcija u view-u u iz kojeg trebamo podatke.

// Ovdje je jednostavni controller

class UsersController extends AppController

{

function getUserList()

{

$this->User->findAll();

}

}

Možemo kreirati callback u našem aplikacijskom Model-u ili Controller file-u. U ovom primjeru šaljemo email iz Model-a

<?php

// File: /app/models/bookmark.php

class Bookmark extends AppModel{

27

var $name = 'Bookmark';

function afterSave(){

// mail me when a new bookmark is addedmail('[email protected]', 'Bookmark saved to database');return true;

}

}

?>

3. HelperCake ima nekoliko već kreiranih helpera koje možemo iskoristiti, a to su: - HTML- AJAX- Javacript- Number- Text- Time- Cache

Svaka metoda u helperu treba da prihvati argumente u sljedeći način: helperMethod(mixed $params[, mixed $secondArg = null[, ...]])U svakoj funkciji treba provjeriti je li prvi argument niz, to provjeravamo sa funkcijom is_array ( ), ako je prvi argument niz, treba provjeriti specifični ključ sa funkcijom array_key_exists ( ).

3.1. HTML Helper

HTML Helper je jedan od načina Cake-a za brži i manje monoton razvoj. HTML Helper ima dva cilja:

1. Omogućiti ubacivanje često ponovljene sekcije HTML koda 2. Omogućiti brzo i jednostavno kreiranje web formiMnoge funkcije u HTML Helper-u koriste HTML tagove definisane u file-u tags.ini.php. Ako želimo neke promjene napravimo kopiju /cake/config/tags.ini.php i snimimo je u /cake/config/ folder. HTML Helper funkcije takođe uključuju $htmlAttributes parametre. Ako želimo koristiti Cake za ubacivanje dobro formirani i često korištenih elemenata u HTML kodu, HTML Helper je veoma dobar u tome. Postoje funkcije u ovom helperu koje insertuju mediu, tabele, liste,…

Generiranje charset MET-a taga:charset ( $charset, $return );

28

string $charset;boolean $return;

Kreiranje linka u CSS stylesheet-u : css( $path, $rel=’stylesheet’, //$rel parameter dozvoljava kreiranje rel=vrijednost za tag $htmlAttributes, $return = ‘false’);

string $path;string $rel=’stylesheet’;array $htmlAttributes;boolean $return = ‘false’;

HTML HelperiAko napišemo: <?php echo $html->css('donutczar'); ?>

CakePHP nam vraća:<link rel="stylesheet" type="text/css" href="/cake1point2/css/donutczar.css" />

koji učitava stil za našu stranicu

Ako napišemo: <?php echo $html->link('CakePHP Home','http://www.cakephp.org'); ?>

Cake nam vraća:<a href="http://www.cakephp.org" >CakePHP Home</a>

koji vidimo kao CakePHP Home

Ako napišemo:

<?php echo $html->tableHeaders(array('First Name','Last Name','Email'),); ?>

Cake nam vraća:

<tr><th>First Name</th> <th>Last Name</th> <th>Email</th></tr> što prikazuje kao

First Name Last Name Email

Ako napišemo:

<?php echo $html->tableCells(array('Dunnottar','Ceiteach','email')); ?>

CakePHP nam vraća:

29

<tr><td>Dunnottar</td> <td>Ceiteach</td> <td>email</td></tr>

što prikazuje : Dunnottar Ceiteach email

Ako napišemo:

<?php echo $html->image('cake.icon.png',array('alt'=>'CakePHP icon')); ?>

CakePHP nam vraća:

<img src="/cake1point2/img/cake.icon.png" alt="CakePHP icon" /> što prikazuje

Primjer definicije HtmlHelper::link ( )<?phpfunction link($params, $href = null, $options = null, $confirm = null){ if (is_array($params)) { extract($params, EXTR_OVERWRITE); } else { $title = $params; }

if (!isset($title)) { $title = null; } if (!isset($href)) { $href = $title; } if (!isset($options)) { $options = null; } if (isset($confirm)) { $options['confirm'] = $confirm; unset($confirm); }

if (strpos($href, '://') === false) { $href = $this->url($href);

30

}

$values = array( 'href' => $href, 'options' => $this->_parseOptions($options), 'tagValue' => $title );

return $this->assign('link', $values);}?>

Form tagovi koje HTML Helper može generirati:- password - submit

password ($fieldName, $htmlAttributes, $return = false);

string $filedName;array $htmlAttributes;boolean $return = false;

submit ( $buttonCaption, $htmlAttributes, $return = false);

string $buttonCaption; array $htmlAttributes; boolean $return = false;

3.2. TimeHelper- trim

Ako napišemo:<?php echo $time->trim('Source character string.',12,'...'); ?>

CakePHP vraća: Source chara...

- niceAko napišemo: <?php echo $time->nice('07-11-2007 18:13:15'); ?>

31

CakePHP vraća: Mon, Apr 29th 2013, 18:13

- dayAsSqlAko napišemo:<?php echo $time->daysAsSql('07-11-2007 18:13:15','07-01-2007 00:00:00','created'); ?>

CakePHP vraća: (created >= '2013-04-29 00:00:00') AND (created <= '2012-06-29 23:59:59')

- isTodayAko napišemo: <?php echo $time->isToday('07-11-2007 18:13:15'); ?>

CakePHP vraća true ako je dati datum današnji

3.3. NumberHelper- precision

Ako napišemo: <?php echo $number->precision('123456789',3); ?>

CakePHP vraća: 123.457

- toPercentageAko napišemo:

<?php echo $number->toPercentage('98.7654321',2); ?>

CakePHP vraća: 98.77%

- currencyAko napišemo:<?php echo $number->currency ('98765.4321','USD'); ?>

CakePHP vraća: $98,765.43

- formatAko napišemo:<?php echo $number->format('98765.4321',2,'.',''); ?>

32

CakePHP vraća:98,765.43

- toReadableSizeAko napišemo:<?php echo $number->toReadableSize('123456789'); ?>

CakePHP vraća: 117.74 MB

3.4. Kreiranje vlastitih helpera

Konvencija imenovanja je slična kao u modelu:

• LinkHelper = class name• link = key in helpers array• link.php = name of php file in /app/views/helpers

Ako želimo kreirati helper koji će koristiti output CSS style linka koji trebamo u aplikaciji, prvo trebamo kreirati novu klasu u app/views/helpers, npr. da se naš helper zove LinkHelper, file php klase trebao bi izgledati ovako:

Putanja: /app/views/helpers/link.phpclass LinkHelper extends Helper{ function makeEdit($title, $url) { // Logic to create specially formatted link goes here... }}

Postoji nekoliko funkcija uključenih u Cake helper klase koje možemo iskoristiti:output ( $string, $return = false);string $string;boolean $return = false;

Ako koristimo output ( ) za formatiranje naših linkova title i URL i vraćanje ih u view, u link.php trebamo dodati:

Putanja: /app/views/helpers/link.phpclass LinkHelper extends Helper{ function makeEdit($title, $url) {

33

// Use the helper's output function to hand formatted // data back to the view:

return $this->output("<div class=\"editOuter\"><a href=\"$url\" class=\"edit\">$title</a></div>"); }}

Možemo koristiti neke već postojeće funkcionalnosti drugog helpera. Da koristimo prednosti drugi helpera trebamo specificirati helper koji želimo koristiti, $helper nizom, zatim pišemo funkcije kao u controller-u npr.

Putanja: /app/views/helpers/link.php ( korištenje drugi helpera)class LinkHelper extends Helper{

var $helpers = array('Html');

function makeEdit($title, $url) { // Use the HTML helper to output // formatted data:

$link = $this->Html->link($title, $url, array('class' => 'edit'));

return $this->output("<div class=\"editOuter\">$link</div>"); }}

Kada kreiramo vlastiti helper snimimo ga u /app/views/helpers/ i bit ćemo u mogućnosti da ga uključimo u naš contoller-u preko specijalne varijable $helpers, npr.class ThingsController{ var $helpers = array('Html', 'Link');}

4. Scaffolding

Scaffolding je dobar način uzimanja početnog dijela web aplikacije, početna šema baze i tema se mijenjaju, što je normalno u početnom dijelu dizajna procesa. Web developeri ne vole kreirati forme koje nikad neće “stavrno” koristiti. Da bi smanjili pritisak na developere, scaffolding je uključen u Cake. Scaffolding analizira tabele u bazi i kreira standradnu listu sa add, delete i edit dugmićima. Strandardnu formu za edit i standardni

34

view za provjeru jednostavni item-a u bazi. Za dodavanje scaffoldinga u aplikaciju, u controller treba dodati varijablu $scaffold;

<?phpclass CategoriesController extends AppController{ var $scaffold;}?>

Scaffold očekuje da bilo koje ime polja koje završava sa “_id” je strani ključ za tabelu koja ima ime koje predhodi “ _”, npr. Ako imamo tabelu category i kolonu parent_id, parent_id je strani ključ za tabelu parent. Kada imamo strani ključ u tabeli (tabela title sa category_id) i imamo asocijaciju modela, označeni box će se automatski popuniti sa redom iz strane tabele (category) u show/edit/new view. Da postavimo koje polje u stranoj tabeli će se prikazivati, postavimo varijablu $displayField u strani model. Primjer:

<?phpclass Title extends AppModel{ var $name = 'Title';

var $displayField = 'title';}?>

Ako želimo nešto drugačiji scaffolding view, možemo kreirati vlastiti. Primjer: Custom scaffolding views for a PostsController should be placed like so:

/app/views/posts/scaffold/index.scaffold.thtml/app/views/posts/scaffold/show.scaffold.thtml/app/views/posts/scaffold/edit.scaffold.thtml/app/views/posts/scaffold/new.scaffold.thtml

Osobina koja može koristiti u Cake-u je kod generator: Bake. Bake dozvoljava da generiramo kodiranu verziju scaffold koda, koju zatim možemo premjestiti i modifikaovati prema zahtijevima aplikacije.

5. Data Validation

Kreiranje korisnički validacijski pravila pomaže da podaci budu sigurni u Model-u uz pravila aplikacije, npr. lozinka može biti samo osam karaktera, korisničko ime može sadržavati samo slova,…Prvi korak u data validation je kreiranje validacijskih pravila u Model-u. Da bi to uradili koristimo Model:: validate array u Model definiciji, primjer:

35

Putanja: /app/models/user.php<?phpclass User extends AppModel{ var $name = 'User';

var $validate = array( 'login' => '/[a-z0-9\_\-]{3,}$/i', 'password' => VALID_NOT_EMPTY, 'email' => VALID_EMAIL, 'born' => VALID_NUMBER );}?>Validacije se definišu koristeći Perl kompatibilne regularne ekspresije, neke od njih su predefinisane u /lib/validators.php, to su:

VALID_NOT_EMPTY VALID_NUMBER VALID_EMAIL VALID_YEAR

Ako postoji bilo koja validacija u modelu definicije ($validate array) bit će analizirana i provjerena tokom snimanja (Model:: save() method). Za direktnu validaciju podataka koristimo Model::validates() (vraća false ako su podaci pogrešni) i Model::invalidFields() (vraća error message kao niz). Ali su obično podaci u kodu controller-a, primjer:

/app/controllers/blog_controller.php<?phpclass BlogController extends AppController {

var $uses = array('Post');

function add () { if (empty($this->data)) { $this->render(); } else { if($this->Post->save($this->data)) { //ok cool, the stuff is valid } else { //Danger, Will Robinson. Validation errors. $this->set('errorMessage', 'Please correct errors below.'); $this->render(); }

36

} }}?>

View za blog može izgledati ovako:/app/views/blog/add.thtml<h2>Add post to blog</h2><form action="<?php echo $html->url('/blog/add')?>" method="post">

<div class="blog_add"><p>Title:

<?php echo $html->input('Post/title', array('size'=>'40'))?>

<?php echo $html->tagErrorMsg('Post/title', 'Title is required.')?>

</p><p>Body

<?php echo $html->textarea('Post/body') ?><?php echo $html->tagErrorMsg('Post/body', 'Body is

required.')?></p> <p><?=$html->submit('Save')?></p>

</div></form>

Controller::validates($model[,$model…] se koristi za provjeru bilo koje korisničke validacije dodane u model.Controller::validationErrors() vraća bilo koju poruku o grešci u modelu, tako da može biti prikazana sa tagErrorMsg() u view-u.

6. Components

Komponente se koriste kao pomagalo controller-a u specifičnim situacijama. Developeri više vole koristiti specijalne funkcije koje prave u komponentama, nego proširene Cake biblioteke. Komponente su za controller, isto što i helper za view. Glavna razlika u tome je što komponente enkapsuliraju biznis logiku, dok helperi enkapsuliraju prezentacijsku logiku. Primjer: autentifikacija korisnika, ako želimo login, logout, permisije za korisnike (akcije: edit, add, del,..) to je biznis logika, tako da je ova autentifikacija komponenta. Ako želimo dodati još neke unose na glavni meni kada je korisnik logiran, to je prezentacijska logika. Možemo kreirati i vlastite komponente, tako što dodamo file u /app/controllers/components direktorij. Primjer: ako želimo kreirati komponentu foo.php, u file-u trebamo definirati klasu koja ima ime isto kao i komponenta.

class FooComponent extends Object{ var $someVar = null; var $controller = true;

37

function startup(&$controller) { // This method takes a reference to the controller which is loading it. // Perform controller initialization here. } function doFoo() { $this->someVar = 'foo'; }}

Da bi koristili komponentu trebamo dodati sljedeći kod u definiciju controller-avar $components = array('Foo');

Sada u controller-u možemo koristiit:$this->Foo->doFoo();

Komponente imaju dozvolu controller-a da se učitaju u startup() metodi, ova metoda se poziva poslije Controller::beforeFilter(). Ovo nam dozvoljava da postavimo osobine komponente u beforeFilter() metodu koja komponenta će se izvršiti u startup() metodi. Da bi koristili naš model u komponenti, trebamo kreitati instancu:

$foo =& new Foo();

Možemo koristiti i druge komponente u vlastitoj komponenti, jednostavno u našoj komponenti deklariramo koju komponentu želimo kotistiti. Primjer: ako želimo koristiti session komponentu:var $components = array('Session');

38

7. Servis “Anketa”

7.1. Tabele servisaServis se sastoji od pet tabela:

39

1. polls - u tabelu „polls“ smještamo id (primarni ključ tabele), ime ankete (name), ukupno odgovora (ukupno_odg) tj. broj korisnika koliko ih je glasalo i broj odgovora (noq) tj. broj odgovora koliko će imati anketa. Tabela „polls“ je u odnosu 1:1 sa tabelom „questions“ tj. jedna anketa može imati samo jedno pitanje, a 1:n u odnosu na tabelu „results“, jer jedna anketa može imati više rezultata.

40

2. answers – u tabelu „answers“ smještamo id (primarni ključ tabele), odgvore

(odgovor), lang_id povezuje tabelu “answers” sa tabelom ”languages” u odnosu 1:n, tj. odgovore možemo pisati na više jezika. Tabelu answers pitanja_id povezuje sa tabelom “questions” u odnosu 1:n, jedno pitanje može imati više odgovora. rezultati_id povezuje sa tabelom “results” u odnosu 1:1,tj. jedan odgovor može imati samo jedan rezultat.

3. questions – u tabelu „questions“ smještamo id (primarni ključ tabele), polje anketa_id povezuje tabelu „questions“ sa tabelom „polls“ u odnosu 1:1, lang_id i pitanje

4. results – u tabelu „results“ smještamo id (primarni ključ tabele), rezultat tj. ukupan broj glasova za svaki odgovor, polje anketa_id povezuje sa tabelom „polls“ u odnosu 1:1, svaki rezultat (odgovor) povezan je sa anketom, kao što možemo vidjeti u sljedećem primjeru. U koloni rezultat smješteni su rezultati odgovora koji se vežu za jednu anketu „anketa_id = 1“;

id rezultat anketa_id 1 15 12 10 13 20 14 8 1

5. checkip – u tabelu „checkip“ smještamo id (primarni ključ tabele), IP adresu korisnika. Na osnovu ove tabele provjeravamo da li je korisnik već glasao i poll_code. Tabela „checkip“ nije povezana sa drugim tabelama, služi za snimanje IP adresa.

7.2. MVC servisa

7.2.1. Model

Servis „Anketa“ ima četiri modela:

1. question.phpclass Question extends AppModel{ var $name = 'Question';

41

}

2. poll.phpclass Poll extends AppModel{ var $name = 'Poll';

}

3. answer.phpclass Answer extends AppModel{ var $name = 'Answer';

}

4. result.phpclass Result extends AppModel{ var $name = 'Result';

}

7.2.2. View

Servis „Anketa“ ima view „polls“ koji se sastoji od četiri php file-a:

1. admin_index.php

<tr> <td colspan="3"><table width="100%" border="0" cellspacing="10" cellpadding="0"> <tr> <td><span class="naslov_kategorije"><strong>Kreirati:</strong></span><br />

42

<a class="menu" href="<?php echo $rootPath ?>Polls/admin_add/"> [Dodati novu anketu]</a><br /></td> </tr> </table></td> </tr>

Admin_index.php služi za ispis linka za dodavanje nove ankete. Kreiramo tabelu i u redove/kolone tabele dodajemo link zbog preglednosti na stranici. Dodali smo i css class „naslov_kategorije“ za ispis „Kreirati“ i class „menu“ za link [Dodati novu anketu], zatim pišemo putanju tj. koji view i php file se poziva, u našem primjeru Polls/admin_add/.

2. admin_add.php

<tr> <td colspan="3"><form method="post" action="<?php echo $rootPath.'/Polls/admin_add_qu';?>" enctype="multipart/form-data" > <table width="100%" border="0" cellspacing="10" cellpadding="0"> <tr> <td><table> <tr>

<td>Pitanje</td> <td><?php echo $html->input('Poll/name', array('size' => '40'))?> <?php //echo $html->tagErrorMsg('Poll/ name', 'Name is required.') ?> </td>

</tr> <tr>

<td>Broj odgovora:</td><td><?php echo $html->input('Poll/noq', array('size' => '10'))?></td>

<td><?php //echo $html->tagErrorMsg('Poll/noq, 'Br_odg is required.') ?></td> <tr> <td><?php echo $html->submit('Save') ?></td>

</tr>

U admin_add.php file-u kreirali smo formu koja pomoću metode post unesene podatke šalje admin_add_qu.php file-u. Zatim smo kreirali tabelu i koristili smo html helpere za unos naziva ankete i broj odgovora u anketi. Koristili smo html helpere za poruku u slučaju greške koje smo poslije stavili pod komentar jer nisu bili neophodni i html helper za snimanje (prosljeđivanje) tj. dugmić „Save“.

3.admin_add_qu.php

<tr> <td colspan="3"><form method="post" action="<?php echo $rootPath.'/Polls/admin_add_an';?>" enctype="multipart/form-data" > <?php

43

foreach ($langs as $lang){ echo $html->hidden('Pages_'.$lang['Language']

['code'].'/poll_id', array('value' => $poll_id));echo $html->hidden('Pages_'.$lang['Language']['code'].'/lang',

array('value' => $lang['Language']['id'])); ?> <table width="700" border="0" align="center" cellpadding="0" cellspacing="0"> <tr> <td width="12" height="25">&nbsp;</td> <td width="329">&nbsp;</td> <td width="9">&nbsp;</td> </tr> <tr> <td height="35" bgcolor="#666666">&nbsp;</td> <td bgcolor="#666666" class="naslov_kategorije"><table width="100%" border="0" cellspacing="0" cellpadding="0"> <tr> <td width="4%"><img src="<?php echo $imgPath; ?>lang/<?php echo $lang['Language']['code']; ?>.gif" alt="" /></td> <td width="96%" class="atributi_p"><?php echo $lang['Language']['name']; ?></td> </tr> </table></td> <td bgcolor="#666666">&nbsp;</td> </tr> <tr> <td height="25" bgcolor="#E1E1E1">&nbsp;</td> <td bgcolor="#E1E1E1" class="naslov_kategorije">Pitanje:</td> <td bgcolor="#E1E1E1">&nbsp;</td> </tr> <tr> <td height="25" bgcolor="#E1E1E1">&nbsp;</td> <td bgcolor="#E1E1E1"><?php echo $html->input('Pages_'.$lang['Language']['code'].'/question', array('size' => '80'))?></td> <td bgcolor="#E1E1E1">&nbsp;</td> </tr> <tr> <td height="25" bgcolor="#E1E1E1">&nbsp;</td> <td bgcolor="#E1E1E1">&nbsp;</td> <td bgcolor="#E1E1E1">&nbsp;</td> </tr> <tr> <td height="25" bgcolor="#E1E1E1">&nbsp;</td> <td bgcolor="#E1E1E1">Odgovori:</td> <td bgcolor="#E1E1E1">&nbsp;</td> </tr> <tr> <td height="25" bgcolor="#E1E1E1">&nbsp;</td> <td bgcolor="#E1E1E1"> <table width="100%" border="0" cellspacing="0" cellpadding="0"> <?php $j =1; foreach($pitanja as $pitanje){?> <tr>

44

<td width="5%"><?php print $j; ?></td> <td width="95%"><?php echo $html->input('Pages_'.$lang['Language']['code'].'/answer_'.$j, array('size' => '80'));

echo $html->hidden('Pages_'.$lang['Language']['code'].'/result_id_'.$j, array('value' => $pitanja[$j-1])); ?> </td> </tr> <?php $j++; }?> </table></td> <td bgcolor="#E1E1E1">&nbsp;</td> </tr> <tr> <td height="25" bgcolor="#E1E1E1">&nbsp;</td> <td bgcolor="#E1E1E1">&nbsp;</td> <td bgcolor="#E1E1E1">&nbsp;</td> </tr> </table> <?php

}?> <table width="700" border="0" align="center" cellpadding="0" cellspacing="0"> <tr> <td width="12" height="25">&nbsp;</td> <td width="454"></td> </tr> <tr> <td height="35" bgcolor="#666666">&nbsp;</td> <td bgcolor="#666666"><?php

echo $html->submit('Save'); ?></td> </tr> </table> </form></td> </tr>

U file-u admin_add_qu.php napravili smo formu koja pomoću metode post unesene podatke prosljeđuje admin_add_an.php file-u. Imamo dvije foreach petlje, prvu foreach petlju koristimo da izlistamo sve jezike koji se nalaze u bazi. Drugu foreach petlju koristimo da ispišemo pitanja i odgovore na svim jezicima. Tabeli smo u neke redove i kolone dodali boju pozadine, css class, zastavu pored naziva jezika...Koristimo html helper za skriveno „hidden“ polje za provjeru poll_id i coda za jezik, tj. id tabele „languages“, html helper za snimanje/submit i html helper za unos/input.

4.admin_add_an.php

<tr> <td colspan="3"><table width="100%" border="0" cellspacing="10"

45

cellpadding="0"> <tr> <td><h1>Hellooooo!!!!<br /></h1></td> </tr> </table></td> </tr> <tr> <td colspan="3"><a class="menu" href="<?php echo $rootPath ?>Polls/admin_add/"><h5>Povratak na stranicu za kreiranje ankete</h5i></a></td> </tr> <tr> <td colspan="3" align="center"><span class="copy">Copyright &copy; 2007 <a href="http://www.dnc.ba" target="_blank">DNC Spinnaker</a></span></td> </tr> </table></td></tr>

U file-u admin_add_an.php kreirali smo tabelu i link za povratak na stranicu za kreiranje ankete, dodali smo u kolonu i poruku „Hellooooo!!!!“, zatim imamo link za DNC stranu.

7.2.3. Controller

Servis „Anketa“ ima četiri controller-a: polls_controller.php, results_controller.php, answers_controlller.php i questions_controller.php, u contoller-u pišemo funkcije koje se izvršavaju u view-u.

1. polls_controller.php

Kreiranje controller-a: class PollsController extends AppController { var $name = 'Polls'; }

Kada kreiramo controller , dodamo funkcije koje su nam potrebne:

46

function admin_index() { $this->set('rootPath', 'http://localhost/cake/'); $this->set('imgPath', 'http://localhost/cake/img/'); }

Funkcija admin_index() služi za kreiranje varijeble za prikaz početne strane. U našem primjeru kreiramo varijablu $rootPath, koju zatim pozivamo u funkcijama kada trebamo prikazati početnu stranu, u našem primjeru 'http://localhost/cake/' i kreiramo varijablu $imgPath za prikaz slika, odnosno loga i slika potrebnih za bolji dizajn strane.

function admin_add_qu() { $this->set('rootPath', 'http://localhost/cake/'); $this->set('imgPath', 'http://localhost/cake/img/');

if ($this->data) { $n = $this->data;

$name=$n['Poll']['name']; $noq=$n['Poll']['noq'];

$ret = $this->Poll->query("SELECT max(id) FROM polls"); $ret = $ret[0]; $id = $ret[0]['max(id)']+1; if($id == 0) $id = 1; $polls_id = $id;

$this->Poll->query("INSERT INTO polls(`id`,`name`, `ukupno_odg`,`noq`) VALUES('$polls_id','$name', '0','$noq')");

$ret = $this->Poll->query("SELECT max(id) FROM results"); $ret = $ret[0];

$id = $ret[0]['max(id)']+1; if($id == 0) $id = 1;

for($i=0; $i<$noq; $i++){ $id += $i; $pitanje_id[$i] = $id;$this->Poll->query("INSERT INTO results(`id`, `rezultat`, `anketa_id`) VALUES('$id', '0', '$polls_id')");

}

$this->set('langs', $this->requestAction('/languages/getLanguages'));

47

$this->set('poll_id', $polls_id);$this->set('pitanja', $pitanje_id);

}}

Funkciaj admin_add_qu() provjerava da li postoje podaci. Ako postoje podaci uzima max id tabele polls i u tabelu polls smješta podatke tj. ime ankete i broj odgovora. Zatim uzima max id od „results“ i prolazi kroz for petlju onoliko puta koliko ima odgovora u anketi i u tabelu „results“ unosi rezultat tj. ukupan broj glasova za svaki odgovor i anketa_id da poveže odgovore sa anketom.

function admin_add_an(){

$this->set('rootPath', 'http://localhost/cake/');$this->set('imgPath', 'http://localhost/cake/img/');

if ($this->data){$ret = $this->Poll->query("SELECT max(id) FROM questions");

$ret = $ret[0]; $id = $ret[0]['max(id)']+1;if($id == 0)$id = 1;$questions_id = $id;

foreach($this->data as $podaci){

$this->Poll->query("INSERT INTO questions (`id`, `anketa_id`, `lang_id`, `pitanje`)VALUES('$questions_id','{$podaci['poll_id']}', '{$podaci['lang']}','{$podaci['question']}')");

$i = 1;while(isset($podaci['answer_'.$i])){

$odgovor = $podaci['answer_'.$i];$result_id = $podaci['result_id_'.$i];

$this->Poll->query("INSERT INTO answers (`odgovor`, `lang_id`, `pitanja_id`, `rezultati_id`) VALUES('$odgovor', '{$podaci['lang']}', '$questions_id', '$result_id')");

$i++;}

$questions_id++;

}

}

48

Funkcija admin_add_an() provjerava da li postoje podaci. Ako postoje podaci uzima max id iz tabele „questions“, prolazi kroz foreach petlju dok postoje podaci, upisuje id ankete, id jezika i pitanje u tabelu „questions“, a odgovore, id jezika, id pitanja i id rezultata upisuje u tabelu „answers“. Varijabla $i se inkrementuje onoliko puta koliko imamo odgovora i $questions_id onoliko puta koliko ima jezika u bazi.

function rezultati($id ){

return $this->Poll->query("SELECT r.rezultat, a.odgovor FROM answers a, results r WHERE a.rezultati_id = r.id AND a.lang_id = '$id'");

}

Funkcija rezultati() vraća broj glasova za svaki odgovor u anketi.

function ukupnoGlasaova($id ){$page = array ('id' => $id);

$ukupno = $this->Poll->findAll($page);return $ukupno[0]['Poll']['ukupno_odg'];

}

Funkcija ukupnoGlasaova() vraća ukupan broj glasova i ispisuje ih na indexnu stranu, tj. na stranu gdje se nalazi anketa.

2. results_controller.php

class ResultsController extends AppController { var $name = 'Results';

}

function inc($id){ $page = array ('id' => $id);

49

$rez = $this->Result->findAll($page);

$rez_id = $rez[0]['Result']['id'];

$this->Result->query("UPDATE `results` SET

`rezultat` = `rezultat` + 1

WHERE

id = '$rez_id'");

$this->Result->query("UPDATE `polls` SET

`ukupno_odg` = `ukupno_odg` + 1 ");

$ip_ = getenv ("REMOTE_ADDR"); $this->Result->query("INSERT INTO checkip (`IP`, `poll_code`) VALUES ('$ip_', ' ')");

setcookie("DNCCMSANKETA", "glasao");

}

Funkcija inc() inkrementuje broj odgovora i ukupan broj glasova, tj. vrši update tabele results i polls. Pomoću funkcije getenv() uzima ip adrese korisnika i snima ih u tabelu “checkip“ i postavlja cookie ako je korisnik glasao.

function provjeraGlasanja(){ $ip_ = getenv ("REMOTE_ADDR");

if($this->Result->query("SELECT poll_code FROM checkip WHERE IP = '$ip_'"))$uslov1 = false;

else$uslov1 = true;

if(isset($_COOKIE['DNCCMSANKETA']))$uslov2 = false;

else$uslov2 = true;

50

if(($uslov1) && ($uslov2))

return true;else

return false;

}

Funkcija provjeraGlasanja() provjerava da li postoji korisnikova IP adresa u bazi i da li ima cookie. Ako ima IP ili cookie ili oboje, prikazuje reultate ankete, a ako ne prikazuje anketu i korisnik ima mogućnost glasanja. Ova funkcija se poziva u /pages/display.php file-u.

3. answers_controller.php

<?phpclass AnswersController extends AppController { var $name = 'Answers';

function odgovori() {return $this->Answer->query('SELECT a.odgovor, a.rezultati_id FROM answers a, questions q WHERE q.anketa_id = 1 AND q.id = a.pitanja_id AND a.lang_id = 1');

}

}?>

Controller answers ima samo funkciju odgovori() koja vraća odgovore i rezultati_id koji su povezani preko anketa_id, pitanje_id i land_id. U našem primjeru anketa_id = 1, land_id = 1 i pitanje_id u tabeli „answers“odgovara id-u u tabeli „questions“.

4. questions_controller.php

class QuestionsController extends AppController { var $name = 'Questions';

function admin_index() { $this->set('rootPath', 'http://localhost/cake/'); $this->set('imgPath', 'http://localhost/cake/img/'); }function view($id = null) {

51

$this->Question->id = $id; $this->set('questions', $this->Question->read()); } }

Funkcija admin_index() ima istu funkciju kao u controller-u polls, funkcija view() služi za prikaz pitanja na osnovu id-a.

function pitanje($id = 1, $lang_id = 1){ $pitanje = array ('anketa_id' => $id, 'lang_id' => $lang_id);

$pitanje = $this->Question->findAll($pitanje);

return $pitanje[0]['Question']['pitanje'];

}

Funkcija pitanje() služi za ispis pitanja na indexnoj strani, poziva se u /pages/display.php file-u.

7. 3. Upustvo za servisServis „Anketa“ sa aspekta adminstracijskog dijela treba da omogući kreiranje, editovanje i brisanje ankete. Administrator kreira anketu, unosi naziv ankete i broj odgovora, zatim pitanje i odgovore.

1. Na admin strani kliknemo na link anketa

52

2. Zatim se otvara nova strana sa linkom za dodavanje nove ankete

3. Admin unosi naziv ankete npr. anketa br.1 i broj odgovora u anketi

53

4. Admin unosi pitanje i odgovore na više jezika tj. na sve jezike koje ima u bazi

54

55

Sa aspekta korisnika:

1. Korisnik posjećuje stranu2. Provjerava se korisnikova IP adresa i cookie3. Ako nema u bazi IP adrese i korisnik nema cookie-a, dozvoljava se glasanje,

nakon klika na dugmić “glasati“, prikažu se rezultati glasanja

4. Ako postoji IP adresa ili cookie, korisniku se prikazuju rezultati ankete

Ključne mogućnosti servisa:- kreiranje ankete- glasanje- pregled rezultata ankete

Aplikacija dozvoljava da korisnik može samo jednom glasati na anketi na osnovu IP adrese i cookie-a. Ako korisnik pokuša drugi put glasati, prikazuje mu automatski rezultat ankete. Servis je implementiran na 3 jezika (bosanski, engleski, njemački) i ima mogućnost dodavanja novi jezika. Servis treba biti dostupan 24h svih sedam dana u

56

sedmici. Servis nam treba omogućiti da dobijemo mišljenje korisnika o anketi „temi“ koju postavimo.

Izvještaji:

- prezentacijski dio- administracijski dio

Usability:

- Lakoća korištenja servisa, potrebno je osnovno poznavanje rada na računaru ( za kriranje ankete) i mogućnosti i znanje korištenja interneta ( za glasanje i pregled rezultata)

Kategorije korisnika:

- obični korisnici (imaju mogućnost glasanja i pregleda rezultata)- administratori ( imaju mogućnost kreiranja ankete)

CASE:Naziv: CASE1- kreiranje ankete

Cilj: Kreirati anketu da bi dobili informacije od korisnika

Prioritet: Visok

Grupa korisnika:

Admin

Preduslovi: Server mora biti online

Scenario: 1. Admin kreira anketu na admin dijelu

2. Anketa je prikazana na prezentacijskom dijelu

Naziv: CASE2 - glasanje

Cilj: Glasati na anketi

Prioritet: Visok

Grupa korisnika:

Gost

57

Preduslovi: Server mora biti online, gost mora biti online, posjetiti stranicu, da nije

prije glasao

Scenario: 1. Gost posjećuje stranicu

2. Provjera gostove IP adrese i cookie-a,

3. Na osnovu IP adrese i cookie-a daje se mogućnost glasanja ili pregleda rezultata

Naziv: CASE3 – pregled rezultata

Cilj: Pregledati rezultate glasanje ankete

Prioritet: Visok

Grupa korisnika:

Admin, gost

Preduslovi: Server mora biti online, korisnik mora biti online, posjetiti stranicu za pregled rezultata

Scenario: Za gosta:1. Gost posjećuje stranicu 2. Ako prvi put glasa, za pregled treba kliknuti da dugnić

„Pregled rezultata“3. Ako je već glasao, automatski se prikazuju rezultati

Za admina:1. Posjećuje stranicu2. Analizira rezultate ankete

Dokumentacija seminarskog:

- osnove CakePHP-a- opis aplikacije- MVC za servis „Anketa“ - case-ovi servisa „Anketa“

58

ZAKLJUČAK

CakePHP je framework koji ima podršku za puno stvari kao što je memcache, xcache, html helperi, ajax,..a uskoro bi trebao dobiti podršku za I18 arhitekturu, CakeAMFPHP za vezivanje na flash,..Primarni cilj seminarskog je bio predstaviti strukturu frameworka koji omogućava PHP korisnicima svih nivoa brzi razvoj web aplikacija, bez gubljenja fleksibilnosti. Jedini nedostatak koji sam pročitala tokom istraživanja za seminarski je što se do sada core cakephp mijenjao nekoliko puta, no s verzijom 2.0 bi se to trebalo stabilizirati. MVC framework možemo iskoristiti za većinu aplikacija u PHP-u koje želimo na brzinu iskodirati i time sami sebi uštediti vrijeme i natjerati se da se držimo nekih standarda. Svi MVC framework-ovi nastoje zadovoljiti iste ciljeve i u MVC filozofiji su pravila jasna, tako da ni implementacija ne može biti toliko različita. MVC arhitektura pomaže sa čistim predstavljanjem database funkcijalnosti, biznis logike i prezentacije. CakePHP developri rade na razvoju preko 100 projekata. Cakephp ima napravljene komponente za autentifikaciju, brute force protection, pagination, automatic layout switcher... Primjenom frameworka se dobiva mnogo prednosti: portabilnost, stabilnost, ubrzanje razvoja,višejezičnost,…

.

59

LITERATURA

1. CakePHP Manual2. PHP Design Patterns3. ETF Sarajevo, RI, SPIS 20064. Cakesheet

Web stranice:

www.cakephp.orgwww.forgephp.orgwww.wikipedia.orgwww.mi3dot.orghttp://bakery.cakephp.org

60