A Kézikönyv (CakePHP 1.1-hez)
Üdvözlünk a CakePHP 1.1-es Kézikönyv megújult oldalán.
A már lefordított dokumentáció oldalai közül a jobb oldalon található Tartalomjegyzékből kedved szerint választhatod ki a neked megfelelőt.
Köszönettel,
a CakePHP.hu csapat
1 Előszó
Hallgatóság
Ez a kézikönyv azon emberek részére készült el, akik a webalkalmazásokat gyorsabban, és sokkal élvezhetőbben szeretnék csinálni. A CakePHP célja, hogy segítse a PHP felhasználókat robosztus, és könnyen kezelhető alkalmazások elkészítésében.
Ez a kézikönyv alap PHP és HTML tudást feltételez. Jártasság a Model-Nézet-Vezérlő (Model-View-Controller = MVC) programozásban előny, de ezt is tárgyalni fogjuk a tananyag során azoknak, akik újak az MVC-ben. A kézikönyv segíti az olvasót a saját web szervere konfigurálásában, és karbantartásában, de a téma teljes lefedése nem tartozik bele. Alapvető tudásra mindenféleképpen szükség van, ezért az ezt átfogó ismeretekre nem térünk ki a tananyag során.
A CakePHP ingyenes
Ami azt jelenti, hogy nem kell érte fizetned, arra használhatod amire szeretnéd. A CakePHP az MIT licensz keretén belül kerül fejlesztésre. A CakePHP nyílt forráskódú projekt, tehát teljes hozzáférést nyújt a forráskódhoz. A legutóbbi verzió letöltéséhez látogass el a http://www.cakephp.org oldalra. A teljes és utoljára fejlesztett forráskód is megtalálható itt.
Közösség
A CakePHP-t keményen dolgozó emberek fejlesztik. Különböző országokból valók, és együttműködésükkel szeretnék elérni, hogy a CakePHP a legszélesebb körökben is elterjedhessen. Az aktív fejlesztői, és közösségi információk megtekintéséhez látogass el a http://www.cakephp.org oldalra. Az IRC csatornánkon mindig található segítőkész "Pék". Ha elakadtál egy kódrészletben, vagy csak figyelő fülekre vágysz, vagy a kódolási eljárásokról szeretnél vitát nyitni, akkor nézz be hozzánk: #cakephp on irc.freenode.com.
2 Bevezető a CakePHP-ba
Mi az a CakePHP?
A CakePHP egy ingyenes, nyílt forráskódú, gyors fejlesztői keretrendszer PHP-hez. Könyvtárak, osztályok struktúrája és run-time infrastruktúra azon webes alkalmazásokat készítő programozók számára, akiket megihletett a Ruby on Rails keretrendszer. Elsődleges célunk hogy lehetővé tegyük számodra a rendezett és gyors munkát – a rugalmasság elvesztése nélkül.
Miért a CakePHP?
A CakePHP-nek számos olyan tulajdonsága van, ami egy nagyszerű keretrendszerré teszi, amivel gyorsan és problémamentesen fejleszthetőek alkalmazások. Íme pár tulajdonság, a sorrend nem lényeges:
-
Aktív, barátságos közösség
-
Rugalmas licensz
-
PHP4 és PHP5 kompatibilitás
-
Integrált CRUD az adatbázishoz és egyszerűsített lekérések
-
Alkalmazás scaffolding (GyorsVáz)
-
Modell-Nézet-Vezérlő (MVC) felépítés
-
Lekérés vezérlő jól kinéző, egyedi URL-ekkel
-
Beépített űrlap-ellenőrzés
-
Gyors és flexibilis sablonozás (PHP szintaxis, Segítőkkel)
-
Segítők AJAX-hoz, Javascript-hez, HTML űrlapokhoz, stb.
-
Biztonság, Munkamenet (Session), és Lekérés kezelő komponensek
-
Flexibilis Elérési Szintek
-
Data Sanitization
-
Flexibilis gyorsítótár
-
Bármely weboldal alkönyvtárából működik, kisebb Apache konfigurálás után
A CakePHP története
2005-ben, Michal Tatarynowicz megírta PHP-ben a Gyors Alkalmazás Keretrendszer minimális verzióját. Rájött, hogy ez egy nagyon jó keretrendszer kezdete. Michal a keretrendszert Cake néven adta ki a MIT licenc alatt és megnyitotta azt egy fejlesztői közösségnek, akik mostmár a Cake-t a CakePHP név alatt fejlesztik.
3 Alapkoncepció
Bevezetés
Ebben a fejezetben röviden, tömören szeretnénk bemutatni a Cake-ben is megvalósított MVC koncepciót. Ha számodra új dolog az MVC (Model View Controller – Modell Nézet Vezérlő) filozófia, akkor semmiképp ne ugord át ezt a részt. Az MVC általános bemutatásával kezdjük, utána megnézzük, hogyan is lett megalósítva az MVC a CakePHP-ban, majd néhány egyszerű CakePHP példán keresztül megmutatjuk hogyan lehet alkalmazni.
Az MVC tervezési minta
A Model-View-Controller (Modell Nézet Vezérlő) tervezési minta segítségével logikailag csoportosíthatjuk a kódot, elősegítvén az újrahasznosítást, a karbantarthatóságot, és általában véve jobb kód készítését. Az MVC-t először a Gang of Four szerzői csoport írta le. Idézet Dean Helman által írt "Objective Toolkit Pro" fehér könyvből:
"Az MVC paradigma egy módszer arra, hogy hogyan osszunk egy alkalmazást, vagy akár egy alkalmazás felületének egy részét három részre: a Modellre, a Nézetre és a Vezérlőre. Az MVC-t eredetileg arra tervezték, hogy a hagyományos input, feldolgozás és output feladatok leképezzék a grafikus interfésszel rendelkező alkalmazásokban.
Adatbevitel – Feldolgozás – Eredmény kiírása
Vezérlő – Modell – Nézet"A felhasználói adatbevitel, a külső világ modellezése és a vizuális visszajelzés a felhasználó felé, e három tevékenység a Model (Modell), View (Nézet) és Controller (Vezérlő) objektumokra vannak szétválasztva és ezekben vannak lekezelve. A Controller értelmezi az adatbevitelt az egérről és a billentyűzetről, ezeket a felhasználói akciókat parancsokká képezi le, amely parancsok aztán a Model és/vagy View objektumok által feldolgozva előidézik a kívánt változásokat. A Model egy vagy több adatelemért felelős, információt nyújt az állapotukról, illetve képes azokat megváltoztatni. A View egy téglalap alakú kijelző területen jeleníti meg az adatokat, szövegek és grafikus elemek kombinációjaként."
A Cake terminológiájában a Model jelképezi az egyes adatbázis táblákat/rekordokat, és azok kapcsolatait más táblákhoz/rekordokhoz, valamint ez az egység tartalmazza az adat-érvényességi szabályokat, melyeket az adatok bevitelekor vagy frissítésekor kell figyelembe venni.
A View a Cake nézet fájlait jelenti, amelyek PHP kóddal beágyazott szabvány HTML fájlok.
A Cake Controller-e kezeli a szerver felőli kéréseket. Ez a modul fogadja a felhasználói adatbevitelt (GET vagy POST adatokon keresztül), megvalósítja az üzleti logikát, a Model-t felhasználva írja/olvassa az adatbázis és más adatvforrások adatait, és végül megjelenítendő adatokat küld a megfelelő View fájloknak.
Azért, hogy alkalmazásainkat a lehető legegyszerűbben építhessük fel, a Cake az alkalmazáson belüli objektumok interakciójának kezelésén felül a fájok tárolásának megszervezésére (lásd következő szakasz) is használja az MVC mintát.
A Cake fájlszerkezetének áttekintése
Amikor kicsomagoljuk a Cake-t, a szerveren a következő 3 fő könyvtárat találjuk:
app
cake
vendors appcakevendors
A cake mappában találhatók a rendszer magjához tartozó könyvtárak. Ezt a könyvtárat általában sosem kell módosítani.
Az app könyvtárban fognak elhelyezkedni az alkalmazásunk fájljai. A cake és app mappa különválasztásával lehetővé válik, hogy több app folder osztozzon egyetlen cake könyvtárrendszeren. Emiatt a CakePHP frissítése is egyszerűvé válik: csak töltsd le a Cake legfrissebb válozatát és másold a cake könyvtárba, felülírva a régi fájlokat. Nem kell aggódnod amiatt, hogy a saját alkalmazásod fájljait cseréled ki.
A vendor könyvtárban a mások által fejlesztett alkalmazásokat tároljuk. A későbbiekben részletesen ismertetjük ezeket, elöljáróban csak annyit, hogy az alapötlet az, hogy a Cake vendor() függvényének segítségével érhetjük el az itt lehelyezett osztályokat.
Lássuk egyben a fájlszerkezetet:
/app
/config - config fájlokat tartalmaz az adatbázishoz, ACL-hez, stb
/controllers - Vezérlők helye
/components - Komponensek helye
/index.php - Lehetővé teszi, hogy a cake a /app könyvtárat DocumentRoot-ként kezelje
/models - Modellek helye
/plugins - Plugin-ok helye
/tmp - cache és log fájlok helye
/vendors - külső alkalmazások helye
/views - Nézetek helye
/elements - elemek, kis nézet-darabok
/errors - testreszabott hibaüzenet oldalak helye
/helpers - Helperek/Segitők helye
/layouts - az alkalmazás layout fájljainak helye
/pages - statikus nézetlapok helye
/webroot - az alkalmazás DocumentRoot-ja
/css
/files
/img
/js
/cake - CAKE rendszerkönyvtár. Ne módosítsd.
index.php
/vendors - szerveroldali külső alkamazásokhoz használt könyvtár.
VERSION.txt - a telepített Cake rendszer verziószáma. /app/config - config fájlokat tartalmaz az adatbázishoz, ACL-hez, stb/controllers - Vezérlők helye/components - Komponensek helye/index.php - Lehetővé teszi, hogy a cake a /app könyvtárat DocumentRoot-ként kezelje/models - Modellek helye/plugins - Plugin-ok helye/tmp - cache és log fájlok helye/vendors - külső alkalmazások helye/views - Nézetek helye/elements - elemek, kis nézet-darabok/errors - testreszabott hibaüzenet oldalak helye/helpers - Helperek/Segitők helye/layouts - az alkalmazás layout fájljainak helye/pages - statikus nézetlapok helye/webroot - az alkalmazás DocumentRoot-ja/css/files/img/js/cake - CAKE rendszerkönyvtár. Ne módosítsd.index.php/vendors - szerveroldali külső alkamazásokhoz használt könyvtár.VERSION.txt - a telepített Cake rendszer verziószáma.
4 A CakePHP telepítése
Bevezetés
Feltehetően mostanra már mindent tudsz az összes CakePHP modul felépítéséről és szándékáról, vagy kihagyhatod ezt a részt, mert nem érdekel mindez, és szeretnél elkezdeni játszani a rendszerrel. Bármelyik utat is választod, be kell piszkítani a kezed.
Ez a rész leírja, mit kell feltelepítened a szerveren. Több módszer kerül bemutatásra, hogyan állítsd be a szervert. A CakePHP letöltését és telepítését, a CakePHP megtekintése és néhány tipp az esetlegesen előforduló hibákról, ha valami éppenséggel nem sikerült a terveknek megfelelően.
Rendszerigény
Ha a használni szeretnéd a CakePHP-t, előszőr is egy szerverrel kell rendelkezned, amelyen elérhetőek mindazok a modulok és programok, amelyek szükségesek a CakePHP futásához:
Szerverkövetelemények
íme:
-
Egy HTTP szerver, mint például az Apache, amelyen engedélyezettek: session, mod_rewrite (nem feltétlen kötelező, de ajánlott) modulok.
-
4.3.2 PHP verzió vagy annál újabb. Igen, a CakePHP a 4-es és az 5-ös PHP-vel is működik.
-
Egy adatbáziskezelő (ezidág a MySQL 4+, a PostgreSQL és egy ADODB interfész alkalmazható).
A CakePHP telepítése
Szerezd meg a legújabb stabil verziót
Van néhány módszer, hogy beszerezz egy példányt a CakePHP-ból: egy stabil verzió beszerzéséhéz látogasd meg a CakeForge oldalt, vagy töltsd le a legfrissebb éjszakai csomagot vagy a folyamatosan frissülő SVN példányt.
A stabil verzió letöltéséhez látogass el a CakeForge oldalon a CakePHP projekt aloldalra a http://cakeforge.org/projects/cakephp/ elérési úton.
A legfrissebb éjszakai csomagot a http://cakephp.org/downloads/index/nightly elérési úton töltheted le. Ezek az éjszakai csomagok gyakran számos hiba javítását is tartalmazzák az egymást követő stabil verziók között.
Ha egy friss példányt szeretnél, azt az SVN tárhelyről töltheted le, ehhez használhatod a kedvenc SVN kliensedet, kapcsolódj a https://svn.cakephp.org/repo/trunk/cake/ SVN szolgáltatóhoz és válaszd ki a verziót, amit keresel.
Kicsomagolás
Nos, miután letöltötted a legfrissebb verziót, e becsomagolt fájt helyezd el a webszervered gyökér elérési útjára. Most ki kell csomagolnod a CakePHP könyvtárat. Erre két módszer van. Az egyik egy fejlesztői változat telepítése, amivel több CakePHP alkalmazást telepíthetsz egy domain alá. A másik lehetőség egy végleges telepítést, amivel egy CakePHP alkalmazást fejleszthetsz egy domain alatt.
A CekePHP beállítása
Az első módszer, amivel a CakePHP-t beállítjuk, csak fejlesztési környezetre ajánlott, a kevésbé biztonságos volta miatt. A másik módszer az biztonságosabb és inkább végleges környezetre ajánlott.
MEGJEGYZÉS: /app/tmp elérési útnak írhatónak kell annak a felhasználónak, amelyen fut a webszerver. (szerk.: Linux szerver esetén az apache-nek kell tudnia írni ezt a könyvtárat)
Fejlesztői telepítés
Fejlesztéskor a teljes Cake telepítési könyvtárstuktúráját közvetlenül a webelérési útra be lehet másolni, mint ahogyan látható:
/wwwroot
/cake
/app
/cake
/vendors
.htaccess
index.php /wwwroot/cake/app/cake/vendors.htaccessindex.php
A fejlesztői telepítéskor a wwwroot könyvtár mint a web gyökérkönyvtára funkcionál, ezért az URL-jeid a következőképpen néznek ki (mod_rewrite használata esetén):
<a href="http://www.example.com/cake/controllerName/actionName/param1/param2" title="Linkification: http://www.example.com/cake/controllerName/actionName/param1/param2">www.example.com/cake/controllerName/actionName/param1/param2</a>
<a href="http://www.example.com/cake/controllerName/actionName/param1/param2" title="Linkification: http://www.example.com/cake/controllerName/actionName/param1/param2">www.example.com/cake/controllerName/actionName/param1/param2</a>
Végleges telepítés
A végleges telepítés testreszabásához szükséges a DocumentRoot-hoz való jogok a szerveren. Ebben az esetben a teljes domain, mint egy teljes CakePHP alkalmazás működik.
A végleges telepítés a következő felépítéssel bír:
../path_to_cake_install
/app
/config
/controllers
/models
/plugins
/tmp
/vendors
/views
/webroot <-- Ennek az elérési útnak kell lennie a DocumentRoot-nak
.htaccess
index.php
/cake
/vendors
.htaccess
index.php ../path_to_cake_install/app/config/controllers/models/plugins/tmp/vendors/views/webroot <-- Ennek az elérési útnak kell lennie a DocumentRoot-nak.htaccessindex.php/cake/vendors.htaccessindex.php
httpd.conf ajánlott beállításai
DocumentRoot /útvonal_a_cakehez/app/webroot
DocumentRoot /útvonal_a_cakehez/app/webroot
Ilyen beállítások esetén a webroot könyvtár, mint web gyökérkönyvtára érhető el és az URL-ek a következőképpen néznek ki (mod_rewrite használata esetén):
http://www.example.com/controllerName/actionName/param1/param2
http://www.example.com/controllerName/actionName/param1/param2
Haladó telepítés: alternatív telepítési opciók
Vannak szituációk, amikor több Cake példányt szeretnél elhelyezni a tárhelyen. Ez adódhat egy közös hoszt megkötései miatt, vagy éppenséggel több webalkalmazásod szeretné ugyanazt a Cake-könyvtárat használni.
Három fő része van egy Cake-alkalmazásnak:
-
A valós CakePHP könyvtár - /cake alatt található meg
-
A te alkalmazásod kódja (vezérlő, modellek, oldalszerkezetek és nézetek) - /app alatt találhatóak meg
-
Az alkalmazásod webroot állományai (képek, javascript kódok és a css) - /app/webroot alatt találhatóak meg.
Bármelyik fenti három könyvtár bárhol elhelyezkedhet a fájlrendszerben, kivéve a webroot-ot, amelyhez hozzáférést kell biztosítani a webszervernek. Még a webroot könyvtárat is áthelyezheted az app-ból bárhová, amennyiben megadod a Cake-nek, hová tetted azt.
A telepített Cake konfigurálásához a /app/webroot/index.php állományba (ahogy a Cake disztribúcióban található) kell beleírni. Három konstans található, amelyet szükséges megadni: ROOT, APP_DIR és a CAKE_CORE_INCLUDE_PATH.
-
A ROOT konstansban adhatod meg az app könyvtár elérési útját.
-
Az APP_DIR konstansban adom meg a webroot állományokat (képek, javascript és css).
-
A CAKE_CORE_INCLUDE_PATH konstansban kell megadnod a Cake könyvtár elérési útját.
/app/webroot/index.php (kivonat, kommentek eltávolítva)
if (!defined('ROOT'))
{
define('ROOT', dirname(dirname(dirname(__FILE__))));
}
if (!defined('APP_DIR'))
{
define ('APP_DIR', basename(dirname(dirname(__FILE__))));
}
if (!defined('CAKE_CORE_INCLUDE_PATH'))
{
define('CAKE_CORE_INCLUDE_PATH', ROOT);
} if (!defined('ROOT')){define('ROOT', dirname(dirname(dirname(__FILE__))));}if (!defined('APP_DIR')){define ('APP_DIR', basename(dirname(dirname(__FILE__))));}if (!defined('CAKE_CORE_INCLUDE_PATH')){define('CAKE_CORE_INCLUDE_PATH', ROOT);}
Egy példa talán segít tisztán látni. Képzeld el, hogy én azt szeretném, hogy a Cake a következő beállításokkal működjön:
-
Azt akarom, hogy a Cake könyvtáramhoz más alkalmazások is hozzáférjenek, és a /usr/lib/cake alatt érhetőek el.
-
Az én Cake webgyökérkönyvtáram a /var/www/mysite/ alatt legyen elérhető.
-
Az alkalmazás állományai a /home/me/mysite alatt legyenek elérhetőek.
Így néz ki az állományok és mappák leosztása:
/home
/me
/mysite <-- általában a /cake_install/app mappa
/config
/controllers
/models
/plugins
/tmp
/vendors
/views
index.php
/var
/www
/mysite <-- általában a /cake_install/app/webroot mappa
/css
/files
/img
/js
.htaccess
css.php
favicon.ico
index.php
/usr
/lib
/cake <-- általában a /cake_install/cake mappa
/cake
/config
/docs
/libs
/scripts
app_controller.php
app_model.php
basics.php
bootstrap.php
dispatcher.php
/vendors Így néz ki az állományok és mappák leosztása:/home/me/mysite <-- általában a /cake_install/app mappa/config/controllers/models/plugins/tmp/vendors/viewsindex.php/var/www/mysite <-- általában a /cake_install/app/webroot mappa/css/files/img/js.htaccesscss.phpfavicon.icoindex.php/usr/lib/cake <-- általában a /cake_install/cake mappa/cake/config/docs/libs/scriptsapp_controller.phpapp_model.phpbasics.phpbootstrap.phpdispatcher.php/vendors
Ilyen beállítások mellett a web gyökérkönyvtárában az index.php állományt szerkeszteni kell (amely a jelen példában /var/www/mysite/index.php alatt érhető el) és a következőképpen néz ki:
Ajánlott a 'DS' konstans használata a perjel helyett, a mappák elválasztó karaktereként. Ez megakadályozza a 'hiányzó állomány' jellegű hiábüzeneteket, a hibás elválasztó karater használatából eredően, és a kód is hordozhatóbb lesz.
if (!defined('ROOT'))
{
define('ROOT', DS.'home'.DS.'me');
}
if (!defined('APP_DIR'))
{
define ('APP_DIR', 'mysite');
}
if (!defined('CAKE_CORE_INCLUDE_PATH'))
{
define('CAKE_CORE_INCLUDE_PATH', DS.'usr'.DS.'lib'.DS.'cake');
} if (!defined('ROOT')){define('ROOT', DS.'home'.DS.'me');}if (!defined('APP_DIR')){define ('APP_DIR', 'mysite');}if (!defined('CAKE_CORE_INCLUDE_PATH')){define('CAKE_CORE_INCLUDE_PATH', DS.'usr'.DS.'lib'.DS.'cake');}
A mod_rewrite modul beállítása Apache alatt
Mivel kezdetektől úgy állították be a CakePHP-t, hogy működjön a mod_rewrite-tal, észrevettük, hogy néhány felhasználónak nehézséget okozott, hogy minden simán működjön a saját rendszerükön. Itt van néhány dolog, ami talán segíthet a helyes működés eléréséhez:
-
Engedélyezd a .htaccess felülírását: a httpd.conf fájlban található egy rész, ahol az összes mappa beállításai találhatóak. Nézd meg, hogy az AllowOverride változó All -ra van állítva a megfelelő mappán.
-
Bizonyosodj meg róla, hogy a rendszer httpd.conf állományát módosítod, nem pedig a felhasználó- vagy weboldalspecifikus httpd.conf állományt.
-
Lehetséges, hogy a szükséges .htaccess állomány nem tartalmazza az általad letöltött CakePHP-t. Ilyesmi akkor fordulhat elő, amikor az operációs rendszer megakadályozza a '.'-al kezdődő fájlok másolását. Bizonyosodj meg, hogy a CakePHP példányod SVN-ről töltötted le.
-
Bizonyosodj meg, hogy a mod_rewrite betöltése sikeres! A httpd.conf állományban szerepelni kell LoadModule rewrite_module libexec/httpd/mod_rewrite.so és AddModule mod_rewrite.c bejegyzéseknek.
-
Amennyiben a felhasználó mappája alá telepítetted a Cake-t(http://example.com/~myusername/), módosítanod kell a .htaccess állományt a telepített Cake alapkönyvtárában. Csak add hozzá a "RewriteBase /~myusername/" sort a .htaccess állományhoz.
-
Amennyiben egy zavaro hosszú session azonosító található az URL-ben(http://example.com/posts/?CAKEPHP=4kgj577sgabvnmhjgkdiuy1956if6ska), a .htaccess állományodba a "php_flag session.trans_id off" sort kell beilleszteni a telepített Cake főkönyvtárába.
Bizonyosodj meg a helyes működésről
Rendben, nézzük mit csináltunk. Attól függően melyik telepítést választottad, a böngésződ http://www.example.com vagy http://www.example.com/cake elrési útra kell beállítani. Ennél a pontnál a CakePHP alapoldala fog megjennni és egy üzenetet kapsz, amely mutatja az adatbáziskapcsolatod státuszát.
Gratulálunk! Készen állsz az első Cake alkalmazásod készítésére.
5 Configuration
Database Configuration
Your app/config/database.php file is where your database configuration all takes place. A fresh install doesn't have a database.php, so you'll need to make a copy of database.php.default. Once you've made a copy and renamed it you'll see the following:
app/config/database.php
var $default = array('driver' => 'mysql',
'connect' => 'mysql_connect',
'host' => 'localhost',
'login' => 'user',
'password' => 'password',
'database' => 'project_name',
'prefix' => ''); var $default = array('driver' => 'mysql','connect' => 'mysql_connect','host' => 'localhost','login' => 'user','password' => 'password','database' => 'project_name','prefix' => '');
Replace the information provided by default with the database connection information for your application.
One note about the prefix key: the string you enter there will be prepended to any SQL call that Cake makes to your database when working with tables. You define it here once so you don't have to specify it in other places. It also allows you to follow Cake's table naming conventions if you're on a host that only gives you a single database. Note: for HABTM join tables, you only add the prefix once: prefix_apples_bananas, not prefix_apples_prefix_bananas.
CakePHP supports the following database drivers:
-
mysql
-
postgres
-
sqlite
-
pear-drivername (so you might enter pear-mysql, for example)
-
adodb-drivername
The 'connect' key in the $default connection allows you to specify whether or not the database connection will be treated as persistent or not. Read the comments in the database.php.default file for help on specifying connection types for your database setup.
Your database tables should also follow the following conventions:
-
Table names used by Cake should consist of English words in plural, like "users", "authors" or "articles". Note that corresponding models have singular names.
-
Your tables must have a primary key named 'id'.
-
If you plan to relate tables, use foreign keys that look like: 'article_id'. The table name is singular, followed by an underscore, followed by 'id'.
-
If you include a 'created' and/or 'modified' column in your table, Cake will automatically populate the field when appropriate.
You'll also notice that there is a $test connection setting included in the database.php file. Fill out this configuration (or add other similarly formatted configurations) and use it in your application by placing something like:
var $useDbConfig = 'test';
var $useDbConfig = 'test';
Inside one of your models. You can add any number of additional connection settings in this manner.
Global Configuration
CakePHP's global configuration can be found in app/config/core.php. While we really dislike configuration files, it just had to be done. There are a few things you can change here, and the notes on each of these settings can be found within the comments of the core.php file.
DEBUG: Set this to different values to help you debug your application as you build it. Specifying this setting to a non-zero value will force Cake to print out the results of pr( ) and debug( ) function calls, and stop flash messages from forwarding automatically. Setting it to 2 or higher will result in SQL statements being printed at the bottom of the page.
Also when in debug mode (where DEBUG is set to 1 or higher), Cake will render certain generated error pages, i.e. "Missing Controller," "Missing Action," etc. In production mode, however (where DEBUG is set to 0), Cake renders the "Not Found" page, which can be overridden in app/views/errors/error404.thtml.
CAKE_SESSION_COOKIE: Change this value to the name of the cookie you'd like to use for user sessions in your Cake app.
CAKE_SECURITY: Change this value to indicate your preferred level of sessions checking. Cake will timeout sessions, generate new session ids, and delete old session files based on the settings you provide here. The possible values are:
-
high: sessions time out after 20 minutes of inactivity, and session id's are regenerated on each request
-
medium: sessions time out after 200 minutes of inactivity
-
low: sessions time out after 600 minutes of inactivity
CAKE_SESSION_SAVE: Specify how you'd like session data saved. Possible values are:
-
cake: Session data is saved in tmp/ inside your Cake installation
-
php: Session data saved as defined in php.ini
-
database: Session data saved to database connection defined by the 'default' key.
Routes Configuration
"Routing" is a pared-down pure-PHP mod_rewrite-alike that can map URLs to controller/action/params and back. It was added to Cake to make pretty URLs more configurable and to divorce us from the mod_rewrite requirement. Using mod_rewrite, however, will make your address bar look much more tidy.
Routes are individual rules that map matching URLs to specific controllers and actions. Routes are configured in the app/config/routes.php file. They are set-up like this:
Route Pattern
<?php
$Route->connect (
'URL',
array('controller'=>'controllername',
'action'=>'actionname', 'firstparam')
);
?> <?php$Route->connect ('URL',array('controller'=>'controllername','action'=>'actionname', 'firstparam'));?>
Where:
-
URL is the regular expression Cake URL you wish to map,
-
controllername is the name of the controller you wish to invoke,
-
actionname is the name of the controller's action you wish to invoke,
-
and firstparam is the value of the first parameter of the action you've specified.
Any parameters following firstparam will also be passed as parameters to the controller action.
The following example joins all the urls in /blog to the BlogController. The default action will be BlogController::index().
Route Example
<?php
$Route->connect ('/blog/:action/*', array('controller'=>'Blog', 'action'=>'index'));
?> <?php$Route->connect ('/blog/:action/*', array('controller'=>'Blog', 'action'=>'index'));?>
A URL like /blog/history/05/june can then be handled like this:
Route Handling in a Controller
<?php
class BlogController extends AppController
{
function history ($year, $month=null)
{
// .. Display appropriate content
}
}
?> <?phpclass BlogController extends AppController{function history ($year, $month=null){// .. Display appropriate content}}?>
The 'history' from the URL was matched by :action from the Blog's route. URL elements matched by * are passed to the active controller's handling method as parameters, hence the $year and $month. Called with URL /blog/history/05, history() would only be passed one parameter, 05.
The following example is a default CakePHP route used to set up a route for PagesController::display('home'). Home is a view which can be overridden by creating the file /app/views/pages/home.thtml.
Setting the Default Route
<?php
$Route->connect ('/', array('controller'=>'Pages', 'action'=>'display', 'home'));
?> <?php$Route->connect ('/', array('controller'=>'Pages', 'action'=>'display', 'home'));?>
Advanced Routing Configuration: Admin Routing and Webservices
There are some settings in /app/config/core.php you can take advantage of in order to organize your application and craft URLs that make the most sense to you and your users.
The first of these is admin routing. If your application has a ProductsController as well as a NewsController, you might want to set up some special URLs so users with administrative privileges can access special actions in those controllers. To keep the URLs nice and easy to read, some people prefer /admin/products/add and /admin/news/post to something like /products/adminAdd and /news/adminPost.
To enable this, first, uncomment the CAKE_ADMIN line in your /app/config/core.php file. The default value of CAKE_ADMIN is 'admin', but you can change it to whatever you like. Remember this string, because you'll need to prepend it to your administrative actions in your controller. So, admin actions in this case would be named admin_actionName(). Here's some examples of desired URLs and possible CAKE_ADMIN and controller action settings:
/admin/products/add CAKE_ADMIN = 'admin'
name of action in ProductsController = 'admin_add()'
/superuser/news/post CAKE_ADMIN = 'superuser'
name of action in NewsController = 'superuser_post()'
/admin/posts/delete CAKE_ADMIN = 'admin'
name of action in PostsController = 'admin_delete()'
/admin/products/add CAKE_ADMIN = 'admin'name of action in ProductsController = 'admin_add()'/superuser/news/post CAKE_ADMIN = 'superuser'name of action in NewsController = 'superuser_post()'/admin/posts/delete CAKE_ADMIN = 'admin'name of action in PostsController = 'admin_delete()'
Using admin routes allows you to keep your logic organized while making the routing very easy to accomplish. When enabled, you can easily determine in the controller whether an admin route has been accessed by using:
$this->params[CAKE_ADMIN];
or, assuming 'admin' is the value of CAKE_ADMIN,
$this->params['admin'];
Please note that enabling admin routes or using them does not enable any sort of authentication or security. You'll need implement those yourself.
Similarly, you can enable Cake's webservices routing to make easier there as well. Have a controller action you'd like to expose as a webservice? First, set WEBSERVICES in /app/config/core.php to 'on'. This enables some automatic routing somewhat similar to admin routing, except that a certain set of route prefixes are enabled:
-
rss
-
xml
-
rest
-
soap
-
xmlrpc
What this does is allows you to provide an alternate views that will automatically be available at /rss/controllerName/actionName or /soap/controllerName/actionName. This allows you to create a single action that can have two views: one for normal HTML viewiers, and another for webservices users. By doing this, you can easily allow much of the functionality of your application to be available via webservices.
For example, let's say I have some logic in my application that tells users who is on the phone in my office. I already have a HTML view for this data, but I want to offer it in XML so it can be used in a desktop widget or handheld application. First I need to enable Cake's webservice routing:
/app/config/core.php (partial)
/**
* The define below is used to turn cake built webservices
* on or off. Default setting is off.
*/
define('WEBSERVICES', 'on'); /*** The define below is used to turn cake built webservices* on or off. Default setting is off.*/define('WEBSERVICES', 'on');
Next, we need to define a component for the type of webservice you want to handle. For XML, you'd need to include an XmlComponent, with RSS, and RssComponent. Components are defined in /app/controllers/components, and extend the Object class.
Once that's done, I can structure the logic in my controller just as I normally would:
messages_controller.php
<?php
class PhonesController extends AppController
{
function doWhosOnline()
{
// this action is where we do all the work of seeing who's on the phone...
// If I wanted this action to be available via Cake's xml webservices route,
// I'd need to include a view at /app/views/phones/xml/do_whos_online.thtml.
// Note: the default view used here is at /app/views/layouts/xml/default.thtml.
// If a user requests /phones/doWhosOnline, they will get an HTML version.
// If a user requests /xml/phones/doWhosOnline, they will get the XML version.
}
}
?> <?phpclass PhonesController extends AppController{function doWhosOnline(){// this action is where we do all the work of seeing who's on the phone...// If I wanted this action to be available via Cake's xml webservices route,// I'd need to include a view at /app/views/phones/xml/do_whos_online.thtml.// Note: the default view used here is at /app/views/layouts/xml/default.thtml.// If a user requests /phones/doWhosOnline, they will get an HTML version.// If a user requests /xml/phones/doWhosOnline, they will get the XML version.}}?>
(Optional) Custom Inflections Configuration
Cake's naming conventions can be really nice - you can name your model Box, your controller Boxes, and everything just works out. There are occasions (especially for our non-english speaking friends) where you may run into situations where Cake's inflector (the class that pluralizes, singularizes, camelCases, and under_scores) might not work as you'd like. If Cake won't recognize your Foci or Fish, editing the custom inflections configuration file is where you'll need to go.
Found at /app/config/inflections.php is a list of Cake variables you can use to adjust the pluralization, singularization of classnames in Cake, along with definining terms that shouldn't be inflected at all (like Fish and Deer, for you outdoorsman cakers) along with irregularities.
Follow the notes inside the file to make adjustments, or use the examples in the file by uncommenting them. You may need to know a little regex before diving in.
6 GyorsVáz azaz Scaffolding képességek
A Cake GyorsVáz (Scaffolding) képességei nagyon jók
Annyira jó, hogy éles alkalamzásokban is szeretnéd használni. Nos, mi is azt gondoljuk, hogy jó, de vedd észre, hogy a GyorsVáz nem más, mint GyorsVáz. Egy projekt kezdeti stádiumában egy jó adag tudást kell összeszedned. Ennek elősegítésére szolgál, nem pedig, hogy teljesen rugalmas legyen. Amennyiben az alkalmazásod logikáját és nézeteit testre szeretnéd szabni, eljön az ideje elvetni a GyorsVáz képességeket, és saját kódot kell készítened.
Egy webes alkalmazás első felében nagy segítséget nyújt a GyorsVáz. A kezdeti adatbázissémák nagyon képlékenyek és állandóan változnak, ami teljesen természetes egy tervezési folyamat elején. Ennek van egy hátránya: a webfejlesztő nem szívesen készít űrlapokat, amelyeknek nincs tényleges haszna. A fejlesztő erőlködésének könnyítése végett lett a scaffolding képesség a Cake-be beépítve.
A GyorsVáz folyamat megvizsgálja, analizálja adatbázisod tábláit, és egy listát készít szerkesztés céljából, hozzáad, töröl, és módosít gombokkal, illetve a űrlapokat, valamint nézeteket, melyekkel az egyes adatbáziselemeket lehet vizsgálni. Ha GyorsVáz képességet szeretnél alkalmazásodhoz adni, add a $scaffold változót a vezérlőhöz:
<?php
class CategoriesController extends AppController
{
var $scaffold;
}
?> <?phpclass CategoriesController extends AppController{var $scaffold;}?>
Egy fontos dolog, amit a GyorsVázzal kapcsoaltban megjegyeznék: a tábla minden olyan mezője, amely _id-vel végződik, az egy külső kulcs egy táblához, amelynek neve megegyezik az aláhúzás jelet megelőző karaktersorral. Például, ha van egy beágyazott kategóriád, akkor feltehetően van egy meződ parent_id elnevezéssel. Ebben az esetben, a legjobb megoldás az lenne, ha átneveznéd parentid-nek. Akkor is, amikor egy tábla egy külső kulccsal rendelkezik (például a címek tábla egy category_id mezőt tartalmaz), és a modelljeidet megfelelően kapcsoltad össze (lásd Kapcsolatok 6.2 fejezet), egy lenyíló menü automatikusan fel lesz töltve adatokkal, amelyeket a kapcsolt táblából (category) vesz a show/edit/new nézetekben.
A kapcsolt táblából választandó mező beállításához a $displayField változót kell a kapcsolt modellben beállítani. A kategória (category) példánk folytatásaként beállítjuk a címek modelt:
<?php
class Category extends AppModel
{
var $name = 'Category';
var $displayField = 'title';
}
?> <?phpclass Category extends AppModel{var $name = 'Category';var $displayField = 'title';}?>
GyorsVáz nézetek testreszabása
Ha valami mást keresel a GyorsVáz nézetekben, magad is megcsinálhatod. Továbbra sem ajánljuk ezt a technikát éles alkalmazások esetén, de egy nézet ilyen jellegű testreszabása nagyon hasznos lehet egyszerűbb esetekben.
Amennyiben meg szeretnéd változtatni a GyorsVáz nézeteidet, a saját nézeteidet kell feltölteni:
Tetszőleges Scaffolding nézet egy egyszerű vezérlőhöz
A PostsController szokványos scaffolding nézetét ehhez hasonlóan kell elhelyezni:
/app/views/posts/scaffold/scaffold.index.thtml /app/views/posts/scaffold/scaffold.show.thtml /app/views/posts/scaffold/scaffold.edit.thtml /app/views/posts/scaffold/scaffold.new.thtml
/app/views/posts/scaffold/scaffold.index.thtml/app/views/posts/scaffold/scaffold.show.thtml/app/views/posts/scaffold/scaffold.edit.thtml/app/views/posts/scaffold/scaffold.new.thtml
Szokásos Scaffolding nézetek az egész alkalmazás számára
Szokásos scaffolding nézetet így kell megadni, minden vezérlő számára:
/app/views/scaffold/scaffold.index.thtml /app/views/scaffold/scaffold.show.thtml /app/views/scaffold/scaffold.edit.thtml /app/views/scaffold/scaffold.new.thtml
/app/views/scaffold/scaffold.index.thtml/app/views/scaffold/scaffold.show.thtml/app/views/scaffold/scaffold.edit.thtml/app/views/scaffold/scaffold.new.thtml
Ha ennél a pontnál a vezérlőlogikát is meg szeretnéd változtatni, itt az ideje a GyorsVáz elvetésének az alkalmazásodban, és elkezdeni magad felépíteni.
A Cake kódgenerátorának nagyon hasznos képessége a Bake. A Bake megcsinálja neked a GyorsVáz kódok kódolt verzióját, amit magad is testreszabhatsz az alkalmazásodhoz illesztve.
7 Models
What is a model?
What does it do? It separates domain logic from the presentation, isolating application logic.
A model is generally an access point to the database, and more specifically, to a certain table in the database. By default, each model uses the table who's name is plural of its own, i.e. a 'User' model uses the 'users' table. Models can also contain data validation rules, association information, and methods specific to the table it uses. Here's what a simple User model might look like in Cake:
Example User Model, saved in /app/models/user.php
<?php
//AppModel gives you all of Cake's Model functionality
class User extends AppModel
{
// Its always good practice to include this variable.
var $name = 'User';
// This is used for validation, see Chapter "Data Validation".
var $validate = array();
// You can also define associations.
// See section 6.3 for more information.
var $hasMany = array('Image' =>
array('className' => 'Image')
);
// You can also include your own functions:
function makeInactive($uid)
{
//Put your own logic here...
}
}
?> <?php//AppModel gives you all of Cake's Model functionalityclass User extends AppModel{// Its always good practice to include this variable.var $name = 'User';// This is used for validation, see Chapter "Data Validation".var $validate = array();// You can also define associations.// See section 6.3 for more information.var $hasMany = array('Image' =>array('className' => 'Image'));// You can also include your own functions:function makeInactive($uid){//Put your own logic here...}}?>
Model Functions
From a PHP view, models are classes extending the AppModel class. The AppModel class is originally defined in the cake/ directory, but should you want to create your own, place it in app/app_model.php. It should contain methods that are shared between two or more models. It itself extends the Model class which is a standard Cake library defined in cake/libs/model.php.
While this section will treat most of the often-used functions in Cake's Model, it's important to remember to use http://api.cakephp.org for a full reference.
User-Defined Functions
An example of a table-specific method in the model is a pair of methods for hiding/unhiding posts in a blog.
Example Model Functions
<?php
class 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');
}
}
}
?> <?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');}}}?>
Retrieving Your Data
Below are a few of the standard ways of getting to your data using a model:
- findAll
- string $conditions
- array $fields
- string $order
- int $limit
- int $page
- int $recursive
Returns the specified fields up to $limit records matching $conditions (if any), start listing from page $page (default is page 1). $conditions should look like they would in an SQL statement: $conditions = "race = 'wookie' AND thermal_detonators > 3", for example.
When the $recursive option is set to an integer value greater than 1, the findAll() operation will make an effort to return the models associated to the ones found by the findAll(). If your property has many owners who in turn have many contracts, a recursive findAll() on your Property model will return those associated models.
Set $recursive to -1 if you want no associated data fetched during the find.
- find
- string $conditions
- array $fields
- string $order
- int $recursive
Returns the specified (or all if not specified) fields from the first record that matches $conditions.
When the $recursive option is set to an integer value between 1 and 3, the find() operation will make an effort to return the models associated to the ones found by the find(). The recursive find can go up to three levels deep. If your property has many owners who in turn have many contracts, a recursive find() on your Property model will return up to three levels deep of associated models.
Set $recursive to -1 if you want no associated data fetched durint the find.
- findBy<fieldName>
- string $value
- findAllBy<fieldName>
- string $value
These magic functions can be used as a shortcut to search your tables for a row given a certain field, and a certain value. Just tack on the name of the field you wish to search, and CamelCase it (depending on your PHP version). Examples (as used in a Controller) might be:
//PHP 5 Users
$this->Post->findByTitle('My First Blog Post');
$this->Author->findByLastName('Rogers');
$this->Property->findAllByState('AZ');
$this->Specimen->findAllByKingdom('Animalia');
$this->Foo->findAllByThreeWordField('bar');
//PHP 4 Users
$this->Post->findByTitle('My First Blog Post');
$this->Author->findByLast_name('Rogers'); //PHP4 isn't as case-friendly
$this->Property->findAllByState('AZ');
$this->Specimen->findAllByKingdom('Animalia');
$this->Foo->findAllByThree_word_field('bar'); //PHP4 isn't as case-friendly //PHP 5 Users$this->Post->findByTitle('My First Blog Post');$this->Author->findByLastName('Rogers');$this->Property->findAllByState('AZ');$this->Specimen->findAllByKingdom('Animalia');$this->Foo->findAllByThreeWordField('bar');//PHP 4 Users$this->Post->findByTitle('My First Blog Post');$this->Author->findByLast_name('Rogers'); //PHP4 isn't as case-friendly$this->Property->findAllByState('AZ');$this->Specimen->findAllByKingdom('Animalia');$this->Foo->findAllByThree_word_field('bar'); //PHP4 isn't as case-friendly
The returned result is an array formatted just as would be from find() or findAll().
- findNeighbours
- string $conditions
- array $field
- string $value
Returns an array with the neighboring models (with only the specified fields), specified by $field and $value, filtered by the SQL conditions, $conditions.
This is useful in situations where you want 'Previous' and 'Next' links that walk users through some ordered sequence through your model entries. It only works for numeric and date based fields.
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));
}
} 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));}}
This gives us the full $image['Image'] array, along with $neighbours['prev']['Image']['id'] and $neighbours['next']['Image']['id'] in our view.
- field
- string $name
- string $conditions
- string $order
Returns as a string a single field from the first record matched by $conditions as ordered by $order.
- findCount
- string $conditions
Returns the number of records that match the given conditions.
- generateList
- string $conditions
- string $order
- int $limit
- string $keyPath
- string $valuePath
This function is a shortcut to getting a list of key value pairs - especially handy for creating a html select tag from a list of your models. Use the $conditions, $order, and $limit parameters just as you would for a findAll() request. The $keyPath and $valuePath are where you tell the model where to find the keys and values for your generated list. For example, if you wanted to generate a list of roles based on your Role model, keyed by their integer ids, the full call might look something like:
$this->set(
'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'
); $this->set('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
- string $fields
- string $id
Use this function to get the fields and their values from the currently loaded record, or the record specified by $id.
The recursiveness of the result depends on the value of $recursive in the model.
- query
- string $query
- execute
- string $query
Custom SQL calls can be made using the model's query() and execute() methods. The difference between the two is that query() is used to make custom SQL queries (the results of which are returned), and execute() is used to make custom SQL commands (which require no return value).
Custom Sql Calls with query()
<?php
class 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;
}
}
?> <?phpclass Post extends AppModel{var $name = 'Post';function posterFirstName(){$ret = $this->query("SELECT first_name FROM posters_tableWHERE poster_id = 1");$firstName = $ret[0]['first_name'];return $firstName;}}?>
Complex Find Conditions (using arrays)
Most of the model's finder calls involve passing sets of conditions in one way or another. The simplest approach to this is to use a WHERE clause snippet of SQL, but if you need more control, you can use arrays. Using arrays is clearer and easier to read, and also makes it very easy to build queries. This syntax also breaks out the elements of your query (fields, values, operators, etc.) into discrete, manipulatable parts. This allows Cake to generate the most efficient query possible, ensure proper SQL syntax, and properly escape each individual part of the query.
At it's most basic, an array-based query looks like this:
Basic find conditions array usage example:
$conditions = array("Post.title" => "This is a post");
//Example usage with a model:
$this->Post->find($conditions); $conditions = array("Post.title" => "This is a post");//Example usage with a model:$this->Post->find($conditions);
The structure is fairly self-explanatory: it will find any post where the title matches the string "This is a post". Note that we could have used just "title" as the field name, but when building queries, it is good practice to always specify the model name, as it improves the clarity of the code, and helps prevent collisions in the future, should you choose to change your schema. What about other types of matches? These are equally simple. Let's say we wanted to find all the posts where the title is not "This is a post":
array("Post.title" => "<> This is a post") array("Post.title" => "<> This is a post")
All that was added was '<>' before the expression. Cake can parse out any valid SQL comparison operator, including match expressions using LIKE, BETWEEN, or REGEX, as long as you leave a space between the operator an the expression or value. The one exception here is IN (...)-style matches. Let's say you wanted to find posts where the title was in a given set of values:
array("Post.title" => array("First post", "Second post", "Third post")) array("Post.title" => array("First post", "Second post", "Third post"))
Adding additional filters to the conditions is as simple as adding additional key/value pairs to the array:
array
(
"Post.title" => array("First post", "Second post", "Third post"),
"Post.created" => "> " . date('Y-m-d', strtotime("-2 weeks"))
) array("Post.title" => array("First post", "Second post", "Third post"),"Post.created" => "> " . date('Y-m-d', strtotime("-2 weeks")))
By default, Cake joins multiple conditions with boolean AND; which means, the snippet above would only match posts that have been created in the past two weeks, and have a title that matches one in the given set. However, we could just as easily find posts that match either condition:
array
("or" =>
array
(
"Post.title" => array("First post", "Second post", "Third post"),
"Post.created" => "> " . date('Y-m-d', strtotime("-2 weeks"))
)
) array("or" =>array("Post.title" => array("First post", "Second post", "Third post"),"Post.created" => "> " . date('Y-m-d', strtotime("-2 weeks"))))
Cake accepts all valid SQL boolean operations, including AND, OR, NOT, XOR, etc., and they can be upper or lower case, whichever you prefer. These conditions are also infinitely nestable. Let's say you had a hasMany/belongsTo relationship between Posts and Authors, which would result in a LEFT JOIN on the find done on Post. Let's say you wanted to find all the posts that contained a certain keyword or were created in the past two weeks, but you want to restrict your search to posts written by Bob:
array
("Author.name" => "Bob", "or" => array
(
"Post.title" => "LIKE %magic%",
"Post.created" => "> " . date('Y-m-d', strtotime("-2 weeks")
)
) array("Author.name" => "Bob", "or" => array("Post.title" => "LIKE %magic%","Post.created" => "> " . date('Y-m-d', strtotime("-2 weeks")))
Saving Your Data
To save data to your model, you need to supply it with the data you wish to save. The data handed to the save() method should be in the following form:
Array
(
[ModelName] => Array
(
[fieldname1] => 'value'
[fieldname2] => 'value'
)
) Array([ModelName] => Array([fieldname1] => 'value'[fieldname2] => 'value'))
In order to get your data posted to the controller in this manner, it's easiest just to use the HTML Helper to do this, because it creates form elements that are named in the way Cake expects. You don't need to use it however: just make sure your form elements have names that look like data[Modelname][fieldname]. Using $html->input('Model/fieldname') is the easiest, however.
Data posted from forms is automatically formatted like this and placed in $this->data inside of your controller, so saving your data from web forms is a snap. An edit function for a property controller might look something like the following:
function edit($id)
{
//Note: 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
}
} function edit($id){//Note: 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 checkingif ($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}}
Notice how the save operation is placed inside a conditional: when you try to save data to your model, Cake automatically attempts to validate your data using the rules you've provided. To learn more about data validation, see Chapter "Data Validation". If you do not want save() to try to validate your data, use save($data, false).
Other useful save functions:
- del
- string $id
- boolean $cascade
Deletes the model specified by $id, or the current id of the model.
If this model is associated to other models, and the 'dependent' key has been set in the association array, this method will also delete those associated models if $cascade is set to true.
Returns true on success.
- saveField
- string $name
- string $value
Used to save a single field value.
- getLastInsertId
Returns the ID of the most recently created record.
Model Callbacks
We've added some model callbacks that allow you to sneak in logic before or after certain model operations. To gain this functionality in your applications, use the parameters provided and override these functions in your Cake models.
- beforeFind
- string $conditions
The beforeFind() callback is executed just before a find operation begins. Place any pre-find logic in this method. When you override this in your model, return true when you want the find to execute, and false when you want it to abort.
- afterFind
- array $results
Use this callback to modify results that have been returned from a find operation, or perform any other post-find logic. The parameter for this function is the returned results from the model's find operation, and the return value is the modified results.
- beforeValidate
Use this callback to modify model data before it is validated. It can also be used to add additional, more complex validation rules, using Model::invalidate(). In this context, model data is accessible via $this->data. This function must also return true, otherwise save() execution will abort.
- beforeSave
Place any pre-save logic in this function. This function executes immediately after model data has been validated (assuming it validates, otherwise the save() call aborts, and this callback will not execute), but before the data is saved. This function should also return true if you want the save operation to continue, and false if you want to abort.
One usage of beforeSave might be to format time data for storage in a specifc database engine:
// Date/time fields created by HTML Helper:
// This code would be seen in a view
$html->dayOptionTag('Event/start');
$html->mont