A leckében megismerkedünk egy professzionális webes MNV-s keretrendszerrel és annak filozófiájával.
A leckét elolvasva értenünk kell a CodeIgniter felépítését és filozófiáját, és korábbi MNV mintát használó programjainkat meg kell tudnunk valósítani CodeIgniterben is.
Saját keretrendszer fejlesztése nagy feladat, számos biztonsági hibát lehet elkövetni a készítése során, melyeket egy elterjedt, nyílt forráskódú professzionális keretrendszer esetén a keretrendszert használók, akik érdekeltek a keretrendszerben rejlő biztonsági hibák felderítésében és kijavításában. Saját fejlesztésű keretrendszer készítéséhez megfelelő fejlesztési tapasztalatra, körültekintő tervezésre van szükség, a keretrendszer logikáját, szabályait előre le kell fektetni. Természetesen a professzionális keretrendszerek elsősorban általános célokra használhatóak, speciális egyedi alkalmazások fejlesztése esetén érdemes lehet az adott célra készíteni egy keretrendszert. Ahhoz azonban, hogy képesek legyünk keretrendszert fejleszteni, érdemes megismerkedni egy professzionális, általános célú keretrendszerrel is. Ahogy a későbbiekben látni fogjuk az esetek nagyon nagy részében ezek a keretrendszerek elegendőek a fejlesztési feladatok gyors, hatékony elvégzésére.
Tananyagunkban a CodeIgniter keretrendszert fogjuk használni. Azért a CodeIgniterre esett a választásunk, mert széleskörűen használt, gyorsan tanulható, kiválóan dokumentált. A számunkra, adott feladatra megfelelő PHP keretrendszer kiválasztásához természetesen széleskörűen tanulmányozni kell az elérhető keretrendszereket. Az olvasó figyelmébe ajánljuk még a Zend Framework-öt, melyet elsősorban vállalati alkalmazások, és a Yii eseményvezérelt keretrendszert, melyet Web 2.0-s alkalmazások fejlesztéséhez ajánlják.
Az olvasó számára ajánlunk két hasznos oldalt a PHP keretrendszerek összehasonlítására:
Választásunkat indokolandó egy kis statisztikai adattal is szolgálunk az olvasónak. Mivel a PHP keretrendszerek elterjedtségéről reprezentatív felmérés nem áll rendelkezésre, ezért a Gooogle keresési trendek szolgáltatását vettük alapul annak vizsgálatára, hogy melyek a legelterjedtebb PHP keretrendszerek.
A diagramon jól látható, hogy a CodeIgniter és a Yii keretrendszerek igen elterjedtek és folyamatosan növekszik a keresletük.
A készítéskor kitűzött cél az volt, hogy létrehozzanak egy olyan eszközt, amivel lényegesen gyorsabb egy PHP oldalt elkészíteni, mint a nyers PHP-val, mindezt úgy, hogy a programozó szinte észre se vegye, hogy egy keretrendszerben dolgozik, mégis számos szolgáltatás álljon a rendelkezésére. A CodeIgniter egy egyszerű, hatékony, gyors és mégis kezelhető és könnyen használható keretrendszer, ami közel áll a szimpla PHP nyelvhez, viszont birtokolja a keretrendszerek nyújtotta előnyöket is.
A keretrendszer készítéskor kitűzött cél az volt, hogy egy olyan eszközt hozzanak létre, amivel lényegesen gyorsabb egy PHP-s alkalmazásokat elkészíteni, mindezt úgy, hogy a programozó szinte észre se vegye, hogy egy keretrendszerben dolgozik, mégis számos szolgáltatás álljon a rendelkezésére a gyakori feladatok elvégzéséhez. A CodeIgniter egy egyszerű, hatékony, gyors és mégis kezelhető és könnyen használható keretrendszer, ami közel áll a PHP nyelvhez, ugyanakkor rendelkezik a keretrendszerek nyújtotta előnyöket is.
A codeigniter.com oldalon letölthető a keretrendszer, valamint megtekinthető a nagyon hasznos kézikönyv (angol nyelven), míg magyarítása a codeigniter.hu/letoltesek oldalon található.
A CodeIgniter előnyei:
Ahogy a későbbiekben látni fogjuk egy egyszerű alkalmazást a keretrendszer komolyabb ismerete nélkül is el lehet készíteni.
A CodeIgniter 2.1-es verziótól használatához PHP 5.1.6 vagy újabb verzióra van szükség a szerveren.
Installálása nagyon egyszerű, letöltése (CodeIgniter legújabb verziójának letöltése), majd a tömörített állomány kicsomagolása után rögtön használható.
A másolás után az /application/config/config.php fájl használatával konfigurálhatjuk a rendszert. Az adatbázis elérés az /application/config/database.php fájlban állítható be. A folytatásban előbb megnézzük a CodeIgniter könyvtárszerkezetét, a kérések feldolgozásának menetét, a beállítási lehetőségeket, ezt követően egy példán keresztül megnézzük a CodeIgniter működését és használatát, majd a linkek felépítését, valamint a fontosabb osztályok működését részletesen.
A többi keretrendszerhez hasonlóan a CodeIgniter is megkötéseket tesz az elkészített fájlok elhelyezését illetően. A letöltött rendszer tartalmaz egy application (alkalmazásunk könyvtára), egy system (a keretrendszer könyvtára), egy user_guide (kézikönyv) könyvtárat, a licence.txt (licensz dokumentumot), és egy index.php (front controller) fájlt.
A CodeIgniter könyvtárszerkezete az alábbi:
A könyvtárszerkezetet természetesen mi magunk is bővíthetjük olyan mappákkal, mint például css, js, images, stb.
A CodeIgniter támogatja az MNV, Modell-Nézet-Vezérlő tervezési mintát. Fontos hozzátenni, hogy a keretrendszer csak támogatja a modellt, de nem kötelezi a fejlesztőt a használatára, azaz megteremti a környezetet a minta használatára, de a programozó feladata eldönteni, hogy alkalmazza-e azt, vagy sem. A továbbiakban feltesszük, hogy az alkalmazásokat az MNV modellnek megfelelően készítjük el. Egy CodeIgniter oldal főbb alkotóelemei a Controller, View és Model elemek, amelyek működését a Helper, Plugin, Core osztályok támogatják.
A CodeIgniter építőelemeinek a kapcsolatát és a működésben való szerepét a következő példa szemlélteti:
Egy felhasználó a böngészője segítségével megpróbálja elérni a http://www.inf.elte.hu/blog/olvas/12 címen lévő oldalt.
A keretrendszer konfigurációs állományai a /application/config/ könyvtárban találhatóak:
autoload.php: az automatikusan betöltendő könyvtárakat, helpereket, plugineket, konfigurációs állományokat, nyelvi fájlokat és modelleket adhatjuk meg. Az erőforrások legjobb kihasználása érdekében érdemes azonban csak a legfontosabbakat betölteni, a többit pedig csak használatkor. A leggyakrabban a default adatbázist szokás automatikusan betölteni az alábbi formában: $autoload['libraries'] = array('database');
config.php: Általános konfigurációs beállítások. A legfontosabbak az alábbiak:
constants.php: Rendszer-konstansok definiálása. Alapértelmezés szerint fájl- és könyvtár kezeléshez tartalmaz konstansokat.
database.php: Adatbázisok beállításai. Több csoportot is meg lehet adni. Az $active_group = "nev"; beállítással adhatjuk meg az alapértelmezés szerint használatos adatbázist. Alapértelmezés szerint a CodeIgniter egy ’default’ nevű csoportot tartalmaz. Az adatbázis lehetséges beállításai, például:
doctypes.php: HTML doctype definíciók.
foreign_chars.php: a nemzeti karakterek átalakítása angol nyelvi karakterekké.
hooks.php: Hook-ok használatának beállítása, melynek segítségével átírhatjuk a CodeIgniter keretrendszer magját, annak hackelése nélkül. Az alkalmazás template-jének hook-al történő beállításához az alábbi két hook lenne szükséges. Lásd később, a Template leírásakor:
$hook['post_controller_constructor'] = array( 'class' => 'Template', 'function' => 'set_template', 'filename' => 'Template.php', 'filepath' => 'libraries', 'params' => array() ); $hook['post_controller'] = array( 'class' => 'Template', 'function' => 'display_template', 'filename' => 'Template.php', 'filepath' => 'libraries', 'params' => array() );
migration.php: adatbázis séma módosításához szükséges beállítások. Alapértelmezetten nem engedélyezett.
mimes.php: Lehetséges mime típusok megadása az Upload osztály számára.
profiler.php: lefutási idő (benchmark) elemzés beállításai nyomkövetéshez és optimalizáláshoz.
routes.php: URI route-k megadása. Alapértelmezés szerint, egyben a legfontosabb a ‘default_controller’, mely akkor hívódik meg, amennyiben az URI nem tartalmaz egyéb vezérlő megadást. Az első vezérlőnk megírásakor be kell állítani, ellenkező esetben az alapértelmezés szerinti ’welcome’ nevű vezérlő fog meghívódni. Példa a használatára: $route['default_controller'] = "auth";
smileys.php: Smiley-k megadása a smiley nevű helper számára.
user_agents.php: Kliensek definiálása a User Agent Class számára, amennyiben alkalmazásunkat eltérő böngészőtípusokra, platformokra vagy mobil eszközökre szeretnénk optimalizálni.
Ezeken kívül a front controllerben (a CodeIgniter gyökérkönyvtárában található index.php állományban) bekapcsolhatjuk a naplózást, hibajelzéseket, azaz a működési módot, mely lehet például fejlesztői (development), tesztelés (testing) vagy éles (production). Megadhatjuk továbbá amennyiben a rendszer (system) mappát vagy az alkalmazás (application) mappát átneveztük, megadhatjuk az új könyvtárneveket, valamint itt is megadhatjuk az alapértelmezett vezérlőt (ezt a routes.php konfigurációs állományban érdemes megadni), vagy egyéb konfigurációs beállításokat.
A CodeIgniter rögtön tartalmaz egy vezérlőt és egy nézetet, melynek eredményét láttuk a böngészőben:
A CodeIgniter működését érdemes a korábbi feldolgozási ábra alapján megtekinteni. Felhasználóként a böngészőbe beírtuk a CodeIgniter elérhetőségét, jelen esetben például: localhost:8080/codeigniter.
A front controller lefutását követően a CodeIgniter a /application/config/routes.php konfigurációs fájlban megadott alapértelmezett vezérlőt hívja meg. Ez a példánkban: $route['default_controller'] = "welcome";.
A welcome.php nevű vezérlő, melyre hivatkozik a /application/controller könyvtárban található.
Nézzük a welcome.php nevű kódját:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); class Welcome extends CI_Controller { public function index() { $this->load->view('welcome_message'); } }
A kódot elemezve láthatjuk, hogy, az osztály neve megegyezik a vezérlő nevével (nagy kezdőbetűvel), a CI_Controller osztályból származik. A Welcome osztálynak jelenleg csak egy Index nevű metódusa van. Mivel meghíváskor nem adtunk meg a meghívandó metódus nevét, alapértelmezetten az Index került meghívásra. A linkek felépítését a következő részben tekintjük át.
A metódus csupán egyetlen sorból, $this->load->view('welcome_message'); azaz a welcome_message nézet betöltéséből áll. A welcome_message.php nevű nézetet a /application/view/ mappában találjuk. A nézet szerkezetileg egy HTML állomány, hiszen jelenleg nem tartalmaz csak egy pszeudó-változó kiírást jelző PHP kódot, az {elapsed_time}-t. E helyett használhattuk volna a <?php echo $this->benchmark->elapsed_time();?>-t is. Azaz az automatikusan meghívásra kerülő benchmark osztály elapsed_time metódusát. Mely kiírja a CodeIgniter meghívásától a böngésző számára kiküldött oldal előállításáig eltelt időt. Hasonlóan használhatjuk például a {memory_usage} kódot a felhasznált memória kiírására.
Ahhoz, hogy megnézhessük, hogyan tudunk egy a vezérlő által a modell segítségével kiolvasott adatot a nézetnek átadni a kezdeti példa nem elég, ahhoz további beállításokat kell elvégeznünk, létre kell hoznunk egy adatbázis táblát, valamint egy modellt is el kell készítenünk, végül természetesen módosítanunk kell a vezérlőt és a nézetet is.
Mielőtt további vezérlőket és nézeteket vinnénk fel, érdemes még a /application/config.php-ben is egy módosítást elvégeznünk, adjuk meg a CodeIgniter elérhetőségét, URL címét, példánkban:
$config['base_url'] = 'http://localhost:8080/codeigniter';
Adatbázis használatához a modellben négy teendőnk mindenféleképpen van:
1. Adatbázis konfigurálása: a /application/config/database.php állományban adjuk meg az adatbázis adatait, péládul:
$db['default']['hostname'] = 'localhost'; $db['default']['username'] = 'felhasznalo'; $db['default']['password'] = 'jelszo'; $db['default']['database'] = 'adatbazis'; $db['default']['dbdriver'] = 'mysql';
Itt jegyezzük meg, hogy az adatbázis-felhasználó biztonsági okokból ne a root felhasználó legyen, készítsünk egy felhasználót, akinek pontosan azon jogokat adjuk meg, amelyeket az alkalmazás megkövetel.
2. Adatbázis driver könyvtár meghívása a vezérlőből (erre később a modell részletes ismertetésénél térünk ki) vagy automatikus betöltése, mely utóbbihoz az /application/config/autolad.php fájlban az alábbi beállítást kell beírnunk: $autoload['libraries'] = array('database');
3. Hozzunk létre egy táblát az adatbázisban az alábbi SQL paranccsal:
CREATE TABLE `tabla` ( `id` int(11) NOT NULL auto_increment, `leiras` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin2;
Töltsük fel a táblát két rekorddal:
INSERT INTO `adatbazis`.`tabla` (`leiras`) VALUES ('szöveg1'), ( 'szöveg2');
4. A következő lépésben hozzuk létre a /application/models/ könyvtárban a tabla_model.php állományt az alábbi tartalommal:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); class Tabla_model extends CI_Model { function getData() { $query = $this->db->get('tabla'); return $query->result_array(); } } /* End of file tabla_model.php */ /* Location: ./application/models/tabla_model.php */
Azaz meghívjuk az adatbázis könyvtár (database_driver library) a get (kiolvasás) metódusát a tabla nevű táblára. A parancs eredménye a SELECT * FROM ’tabla’ SQL kód futtatása az adatbázisban. A kapott eredményt átadjuk a query változóba, melyet egy tömbként visszaad majd a modell a vezérlőnek.
A következő lépésben a vezérlőt kell módosítanunk (/application/controllers/welcome.php), hogy meghívja a tábla olvasást, majd a kiolvasott adatokat át kell adnia a nézetnek.
A vezérlőben az index metódus tartalmát az alábbiaknak megfelelően módosítsuk:
public function index() { $this->load->model('tabla_model'); $data['query'] = $this->tabla_model->getData(); $this->load->view('welcome_message',$data); } {forraskod_php} Az index metódusba betöltjük a tabla_model nevű modellt, majd meghívjuk a modell getData metódusát, azaz kiolvassuk a tábla tartalmát a data asszociatív tömbbe. Végül betöltjük a welcome_message nevű nézetet, átadva a megjelenítendő adatot. Ha jól megnézzük, mindez egyszerű alkalmazásunk üzleti logikája, eltekintve attól, hogy hogyan olvasunk az adatbázisból, illetve hogyan jelenítjük meg a kiolvasott tartalmat! A $this->load->model('tabla_model');-t érdemes a vezérlő konstruktorába helyezni, mert valószínűleg a vezérlő többi metódusában is használni szeretnénk. Az eredmény megjelenítéshez utolsó lépésben módosítanunk kell a nézetet, a vezérlőtől kapott adatokat meg kell jeleníteni. Ehhez az alábbi kódot illesszük be a /application/views/welcome_message.php nézet body tag-en belül található container nevű div-ben valahova: {forraskod_php} <?php foreach($query as $sor):?> <p>Azonosító: <?php echo $sor['id']; ?><br /> Leírás: <?php echo $sor['leiras']; ?></p> <?php endforeach;?>
A kód a vezérlőtől kapott query asszociatív tömb tartalmán végigmegy és kiírja annak, azaz végeredményben a tábla tartalmát.
A böngészőben futtatva az alábbi eredményt láthatjuk.
A továbbiakban áttekintjük a linkek felépítését, ennek alapján routing működését, valamint a vezérlő, a modell osztályokat, a nézet fájlokat, valamint a CodeIgniter bővítési lehetőségeit.
Az alábbiakban áttekintjük, hogy hogyan működik a keretrendszer Routing szolgáltatása. Egy alapértelmezett beállításokkal rendelkező, frissen telepített CodeIgniter a következő formában megadott linkeket dolgozza fel:
domain/index.php/vezerlo/metodus/param1/param2
Azaz meghívásra kerül a /application/controller mappában a vezerlo.php vezérlőnek a metodus nevű metódusa, a két paraméterrel. A metódus kódja az alábbihoz hasonló lehet:
public function metodus($param1, $param2) { }
A fenti linkben látható, hogy itt még szerepel az index.php az URL-ben, ez eltüntethető a programot futtató szerver .htacces konfigurációs fájljának módosításával. Ezután ilyenek lesznek az alapértelmezett URL-ek:
domain/vezerlo/metodus/param1/param2
A megadott URL-ben az első paraméter a vezérlő nevét, a második a vezérlő egy metódusának a nevét, a többi pedig a metódusnak átadandó paramétereket határozza meg. Megoldható az is, hogy minden URL végéhez ugyanaz a karaktersorozat legyen hozzáfűzve, amit persze csak a böngészőben látunk, a program működését nem fogja módosítani. Ehhez az application/config/config.php fájlban kell a $config[’url_suffix’] változónak egy értéket megadni. Ha például beállítjuk, hogy ez az url_suffix a .html legyen, akkor az URL-ek például az alábbi formában jelennek meg a böngészőben:
domain/vezerlo/metodus.html
Arra is lehetőség van, hogy a Routing által generált szép URL-eket kikapcsoljuk, amit ugyanebben a fájlban a $config[’enable_query_strings’] = TRUE; értékadással tehetünk meg. Ezután teljesen más formában fognak az URL-ek megjelenni:
domain/index.php?c=controllername&m=methodname&id=123
A példában a c lesz a vezérlő neve, az m a vezérlő egy metódusának a neve, az id pedig az átadandó paraméter, értéke pedig 123.
Természetesen az alapértelmezett Routing beállítások tetszőlegesen átszabhatók. Az /application/config/routes.php fájlban kezdetben két ilyen routing szabály található, melyekhez tetszőleges számú saját szabályt adhatunk. Az egyik megadott szabály megmondja, melyik vezérlő hívódjon meg, ha megnyitják az alkalmazásunkat paraméter nélkül, azaz mi legyen az alapértelmezett vezérlő, a másik pedig a scaffolding oldal nevét állítja be. Ezek után a $route[’URL’] = vezérlő/függvény formában megadhatók saját szabályok. Az URL megadásához felhasználhatók helyettesítő jelek (wildcard) és reguláris kifejezések. A helyettesítő jelek a :num vagy a :any azonosítók lehetnek.
A szemléltetés kedvéért következzen néhány példa:
-$route[’blog/admin’] = blog/users/13 : Ha a böngészőben a blog/admin paramétereket adjuk meg, a háttérben a blog vezérlő users függvénye hívódik meg ’13’ paraméterrel.
-$route[’article/(:num)’] = article/read/$1 : Az URL-ben az article karaktersorozat után egy számot vár paraméterként, és az article vezérlő read függvényét hívja ezzel a számmal, mint paraméter.
-$route[’article/:any’] = welcome: Az article után bármit megadhatunk, a welcome controller index metódusát hívja meg paraméter nélkül.
-$route[’product/([a-z]+)’] = product/$1 : A product azonosító után csak kisbetűket tartalmazó sztringet fogad el, és a product vezérlő paraméterként megadott függvényét hajtja végre.
Az MNV modell vezérlő rétegét hivatottak megvalósítani a Controller osztályok. Az MNV szerint ez a réteg hozzáfér az adatokat reprezentáló modell réteghez, azokon műveleteket hajthat végre, és a kívánt adatokat továbbítja a view rétegnek, ami megjeleníti azokat. Így működik ez a CodeIgniter esetében is, azzal a különbséggel, hogy a keretrendszer nem kötelezi a fejlesztőt az MNV modell alkalmazására, azaz az adatbázisban tárolt adatok elérhetők a modell réteget megkerülve, direkt SQL lekérdezések formájában, és a megjeleníteni szánt adatokat nem feltétlenül kell továbbküldeni a nézet rétegnek, mivel azokat ki lehet íratni a vezérlőn keresztül is. Mindenesetre az MNV modell megkönnyíti a fejlesztést, átláthatóbb, strukturáltabb kódot eredményez.
Egy vezérlő osztálynak követnie kell bizonyos minimális konvenciókat, melyek szerint a vezérlő és az őt tartalmazó fájl nevének egyeznie kell, úgy hogy a fájlnév kisbetűvel, az osztálynév pedig nagy kezdőbetűvel írandó. Ezt a fájlt az /application/controllers könyvtárba kell elhelyezni .php kiterjesztéssel úgy, hogy egy fájl csak egy vezérlő osztályt tartalmazhat és ez az osztály a keretrendszer magjához tartozó Controller ősosztályból kell, hogy származzon:
<?php class Albums extends CI_Controller {
Mint minden más osztálynak, így a vezérlő osztálynak is lehet konstruktora. Ennek a konstruktornak kötelező meghívnia a beépített Controller osztály konstruktorát:
function __construct() { parent::__construct(); //konstruktor kódja, például egy modell betöltése $this->load->model('pelda_model'); }
Ezen kívül a vezérlő tetszőleges függvényeket tartalmazhat, amik között van pár speciális viselkedésű is.
Ilyen például az index() nevű, ami a vezérlő alapértelmezett függvényét jelenti, vagy a _remap($param) függvény, amivel felüldefiniálhatók a Routing-nál megadott szabályok. Ez ennyit jelent, hogy ha egy vezérlőhöz kerül az irányítás, akkor attól függetlenül, hogy melyik függvényét hívták meg, ez a _remap($param) metódus fog végrehajtódni úgy, hogy paraméterként megkapja az URL controller utáni részét. Ez alapján hozhat döntést arról, hogy melyik függvény legyen az, ami ténylegesen lefut. Speciális funkcionalitást megvalósító függvény még az _output($output) is, ami paraméterként megkapja azokat az adatokat, amiket a vezérlő tovább küldött kiíratásra, és ezeken utómunkálatok végezhetők el még a megjelenítés előtt. Létrehozhatóak private metódusok is, amik nem érhetők el böngésző segítségével, csak a vezérlőn belül. Ahhoz, hogy egy metódust private-té tegyünk, egyszerűen csak egy aláhúzást kell tenni a neve elé.
A megjelenítésért felelősek a yiew fájlok, melyek tartalmazhatnak komplett HTML oldalakat, vagy csak egyszerű kódrészleteket, mint például egy fejléc, egy menü stb, akár templateket is.
A CodeIgniter motorja nem jelenít meg automatikusan nézeteket, az csak azért felelős, hogy az URL-nek megfelelő vezérlőt működésre bírja. Ez annyit jelent, hogy a view fájlokat a programozónak kell meghívnia a vezérlőn belül, amire a $this->load->view(’name’) függvény használható. Ahhoz, hogy egy nézetet meg lehessen hívni, először el kell menteni az /application/views/ könyvtárba .php kiterjesztéssel. Az adatok átadását a vezérlőből a nézetbe, szintén ez a view függvény végzi úgy, hogy a második paraméterének átadunk egy $data változót, ami lehet egy sima változó, egy összetett tömb, vagy akár egy objektum is, például:
$this->load->view('nezet',$data);
Az átadás után ez a változó elérhető lesz a nézeten belülről is. Ugyanez a metódus elfogad egy boolean típusú harmadik paramétert is, ami igaz érték esetén nem küldi el a view fájl által generált oldalt a felhasználónak, hanem visszatérési értékként visszaadja azt a vezérlőnek. Alapértelmezett beállítása false, ami azt jelent, hogy az oldal küldésre kerül, amint elkészül.
A HTML kód olvashatóbbá tétele miatt lehetővé tettek egy a megszokottól eltérő PHP szintaxis használatát. Ennek lényege, hogy a megjelenítéskor használt, if, foreach, for, és while nyitó- illetve csukó zárójeleit el lehet hagyni és helyettük sokkal átláthatóbb módon endif, endforeach, endfor, és endwile kulcsszavak használhatók, valamint a kiíró echo parancsok egy <?=változónév?> utasítással helyettesíthetők. Például:
<?php foreach($todo as $item): ?> <?=$item?> <?php endforeach; ?>
Előfordulhat, hogy a szerver, amin a program fut, nem támogatja ezeket a jelöléseket. Ilyenkor a CodeIgniter átírja a kódot a hagyományos formára.
A megjelenítő réteg, Helper osztályok formájában számos segítséget használhat az oldal egységesítésére, mindkezekről később a Helper részben lehet bővebben olvasni.
A modell osztályok feladata az adatokat tároló jellemzően adatbázis és az üzleti logikát megvalósító vezérlő réteg közötti kapcsolat megteremtése. A modell fájlokat az /application/models könyvtárba kell tenni úgy, hogy a fájlnév megegyezzen a benne tárolt modell nevével, azzal a különbséggel, hogy a modell neve nagybetűvel kezdődik, a fájlé pedig kicsivel. Egy modell minden esetben az ős Model osztályból származik, és ha van konstruktora, akkor meghívja az ősosztály konstruktorát is, hasonlóan a vezérlőhöz. Példánkban az adatbázis nevű drivert töltjük be, melynek segítségével egyszerűbben tudunk majd modellen belül műveleteket végezni az adatbázisban:
public function __construct() { parent::__construct(); $this->load->database(); }
Mivel a CodeIgniter nem használ natívan ORM technológiát, ezért egy modell osztály nem kötődik össze automatikusan a neki szánt adatbázis táblával, vagyis a programozó feladata a tábla mezőinek megfelelő változók létrehozása az osztályon belül, valamint ezen változók értékének a karbantartása is a fejlesztők felelőssége.
Egy modellen belül tetszőleges számú metódus valósítható meg, általában ezeket a metódusokat az adatbázis adatok lekérdezésére, módosítására és törlésére szokták használni.
Ha létrehoztuk a szükséges modelleket, akkor lehetőségünk van azokat a vezérlőben is felhasználni, amihez első lépésként meg kell hívni őket, amit a $this->load->model(’modellnév’) paranccsal tehetünk meg. Ha már meghívtuk, akkor a $this->modellnév->metódusnév() paranccsal érhetjük el a modellen belüli szolgáltatásokat.
A következő példához tegyük fel, hogy van egy Albums nevű modell, amiben egy get_albums() metódus kérdezi le az összes albumot. A vezérlő, ami az MVC modellnek megfelelően kiíratja ezeket a bejegyzéseket, így néz ki:
$this->load->model(’albums’); $data[’result’] = $this->albums->get_albums(); $this->load->view(’nézetnév’, $data);
Az albums.php nevű modellben lévő get_albums() metódus kódja pedig az alábbihoz hasonló lehet:
function get_albums() { $query = $this->db->get('albumok_tabla'); $result = $query->result_array(); return $result; }
Ahhoz, hogy a modellen belül hozzáférjünk az adatbázishoz, két lehetőséget biztosít a CodeIgniter. Az első a saját SQL lekérdezések írása, a második pedig az Active Record osztály használata. Ahhoz, hogy ezeket a szolgáltatásokat igénybe vegyük, a keretrendszerbe épített Database osztályt kell használnunk, ami db néven mindenhol elérhető egy projekteken belül. Az előző kódrészletben ez utóbbira láttunk egy példát.
Saját SQL parancsok végrehajtása a $this->db->query(SQL prancs) metódussal megtehető, és egy eredmény objektumot ad vissza, amiből kinyerhetők az eredményül kapott sorok. Az adatbázis védelme érdekében ajánlatos az SQL parancsunkat biztonságossá tenni, azaz escape-elni, amit a Database osztály escape(), escape_str() és escape_like_str() metódusokkal érhetünk el. Van lehetőség BIND használatára is: a query metódusnak átadott SQL parancsban a behelyettesítendő változók helyére egy kérdőjelet teszünk, és a függvénnyel a második paraméterben átadott tömbben közöljük ezeket az értékeket. Ilyenkor a beillesztendő értékek automatikusan escape-elődnek. Például:
$this->db->query(SELECT * FROM tábla WHERE name = ?, array(’alma’));
A keretrendszer által nyújtott Active Record szolgáltatás szerint SQL lekérdezések helyett, CodeIgniter parancsok egymás után fűzésével generálhatók a platformfüggetlen lekérdezések. Például a $this->db->get(’táblanév’) parancs a háttérben egy SELECT * FROM táblanév SQL lekérdezést generál. Amennyiben kiadunk az említett get parancs előtt egy where(’mezőnév operátor’, ’érték’) utasítást, akkor két függvény eredménye összefűződik, azaz lekérdezésként a SELECT * FROM táblanév WHERE mezőnév operátor érték utasítás hajtódik végre. Hasonlóan egymás után fűzhetők a select(), from(), select_min(), select_max(), select_avg(), select_sum(), or_where(), join(), where_in(), or_where_in(), where_not_in(), or_where_not_in(), like(), or_like(), not_like(), or_not_like(), group_by(), distinct(), having(), or_having(), order_by(), limit() parancsok, így tetszőleges bonyolultságú SQL lekérdezés generálható.
Akár a következő módon is:
$this->db->select(’author’)->from(’books’)->where(’price <’, 5000);
A példakód a SELECT author FROM books WHERE price < 5000 lekérdezést készíti el a háttérben. Hasonlóan használható az adatok beszúrására szolgáló insert(’tábla’, $data) , és a módosítást végző update(’tábla’, $data) függvények, ahol a $data lehet egy adatokat tartalmazó tömb, vagy objektum. A törlést a delete(’tábla’, feltételek) paranccsal lehet végrehajtani, ahol a feltételek változó, egy mező, érték párokat tartalmazó asszociatív tömb.
Mivel a lekérdezést végző függvények visszatérési értékként a lekérdezés eredményét adják, célszerű azt az eredményt egy változónak átadni, amiből később hasznos adatokat nyerhetünk ki. Egy sornak megfelelő objektumot a $result() paranccsal tudunk lekérdezni, míg a $result_array() ugyanezt végzi, csak objektum helyett tömbben adja vissza az eredményt. A $num_rows() és $num_fields() metódusok értelemszerűen a lekérdezés eredményében szereplő sorok, illetve oszlopok számát adják meg.
Példa:
function get_albums($id = '', $nev = '', $leiras = '') { $sql = "select id, nev, leiras from albums where id like ? and nev like ? and leiras like ? order by nev"; $result = $this->db->query($sql, array( "%$id%", "%$nev%", "%$leiras%" )); return $result->result_array(); }
Az eddig említett szolgáltatásokon kívül számos lehetőséget kínál a beépített Database osztály, például adatokat kérdezhetünk le a táblákról és mezőikről, a műveleteinket tranzakciókba zárhatjuk, a lekérdezéseket eltárolhatjuk egy cache-objektumban, adatbázisokat hozhatunk létre, törölhetünk ki.
A CodeIgniter működésébe van lehetőségünk belenyúlni az ún. hook fájlok segítségével, azaz az egyes munkafázisok elé vagy után szúrhatunk be tetszőleges logikát.
Ehhez engedélyezni kell a hook-ok használatát az /application/config/config.php-ban a $config['enable_hooks'] = TRUE; beállításával, majd az ugyanebben a könyvtárban található hooks.php fájlba elhelyezett deklaráció segítségével hozzá is rendelhetjük a kívánt függvényt az alkalmazás végrehajtási menetének egy lépéséhez. A deklaráció így néz ki:
$hook['hook_point'] = array( 'class' => 'MyClass', 'function' => 'Myfunction', 'filename' => 'Myclass.php', 'filepath' => 'hooks', 'params' => array('param1', 'param2') );
A hook_point mondja meg, a végrehajtás során, mikor hajtódjon végre a beszúrandó logika. Ez az alábbi értékeket veheti fel:
A deklarálás során használt class, function, és filename paraméterek mondják meg, melyik osztály, melyik függvényét szeretnénk futtatni, és ez melyik fájlban található. A filepath határozza meg, melyik könyvtárban helyezkedik el a keresendő fájl, és a params segítségével adhatók át paraméterek a függvénynek.
A CodeIgniter rendelkezik számos olyan beépített osztállyal, amelyek hatalmas segítséget nyújtanak a háttér logika megvalósításában. Az ilyen osztályokat a libraries vagy harmadik féltől szervezett kiegészítő osztályok esetén a third_party könyvtárban tároljuk és könyvtáraknak nevezzük. Egy meglévő könyvtárat a $this->load->library(’név’) módon lehet importálni egy vezérlőbe.
Amellett, hogy a beépített könyvtárakat használjuk, arra is van lehetőség, hogy saját könyvtárakat hozzunk létre, vagy kibővítsünk, sőt felülírjunk meglévőket. Saját könyvtár készítése nem jelent mást, mint egy osztály létrehozását és az /application/libraries könyvtárban való elhelyezését úgy, hogy mind az osztály neve, mind az őt tároló fájl neve nagybetűvel kell, hogy kezdődjön, és meg kell, hogy egyezzen. Ezután bármelyik vezérlőben meghívható és felhasználható a kisbetűs példánya segítségével.
Egy meglévő könyvtár felüldefiniálása nagyon egyszerű. A felülírandó osztály és fájl elnevezéseit használva el kell készíteni egy saját osztályt, amit ezután be kell másolni a libraries könyvtárba, ahol felül kell írni a meglévő fájlt és már kész is. A Database és Loader osztályok azok, amikhez nem lehet ilyen módon hozzányúlni, viszont az összes többi libraries-ben megtalálható szolgáltatás tetszőlegesen kiegészíthető és felülírható.
Néhány hasznos beépített osztály:
Bizonyára minden webfejlesztő használt már session-t a weblapjai elkészítése során arra, hogy adatokat tároljon, így nem meglepetés az, hogy a CodeIgniter is rendelkezik egy Session műveleteket támogató beépített osztállyal. A CodeIgniter session osztálya nem egyezik meg a PHP nyelv által felkínált munkamenet-kezeléssel.
Az adatok tárolásának CodeIgniterben két módja van: Alapértelmezés szerint a session-ben tárolni kívánt adatokat, tömb formájában, sorosítva fogja elraktározni az alkalmazás sütijei között úgy, hogy ezek az adatok opcionálisan még titkosíthatók is. Továbbá a nagyobb biztonság érdekében a session adatok eltárolhatók adatbázisban is. Ebben az esetben, az oldal betöltésekor, ha van a sütik között tárolt session adat, akkor lekérdezi az azonosítóját (Session ID) és megnézi, hogy van-e az adatbázisban hozzá tartozó bejegyzés. Ha nincs, új indul. Ahhoz, hogy adatbázisban tudjuk eltárolni a session adatainkat, létre kell hozni az ehhez szükséges adattáblát az alábbi struktúra szerint:
Táblanév: ci_sessions
session_id: varchar(40) DEFAULT '0' NOT NULL, PRIMARY KEY ip_address: varchar(16) DEFAULT '0' NOT NULL user_agent: varchar(50) NOT NULL last_activity: int(10) unsigned DEFAULT 0 NOT NULL user_data: text NOT NULL
Egy CodeIgniter-ben készített session minimum négy értéket tartalmaz. Ezek a session azonosító, az IP cím, adatok a felhasználóról (User Agent Data), és az utolsó aktivitás ideje. Ezek mellé lehet még saját adatokat is eltárolni, amihez a session->set_userdata($array) műveletet használva nyílik lehetőség. Paraméterként egy azonosító-érték párokat tartalmazó asszociatív tömböt vár. A tárolt értékeket kiolvasni a userdata(’azonosító’) paranccsal lehet. Az adatok törlését a Session osztály unset_userdata(’azonosító’) metódusa végzi, az egész session pedig a sess_destroy() paranccsal törölhető.
Általában olyan adatok kerülnek egy session-be, amikre huzamosabb ideig szükség van, mint például a bejelentkezett felhasználó azonosítója vagy, hogy be van-e jelentkezve a felhasználó. A beépített Session osztállyal olyan adatok is tárolhatók, amelyek csak a következő oldalletöltésig maradnak meg. Tipikusan ilyenek azon üzenetek, melyek a felhasználót értesítik valamilyen tevékenység sikerességéről, például sikeres belépés, kilépés, vásárlás esetén kiírni szánt üzenetek. Ezeket Flash adatoknak hívjuk és az említett osztály set_flashdata(’azonosító’,’érték’) művelettel lehet őket elmenteni, a flashdata(’azonosító’) szolgál az elérésükre és a keep_flashdata(’azonosító’) hívása után a megadott adat még egy oldalbetöltésig tárolva marad.
A session-ök egy tipikus felhasználása az, amikor a felhasználó egy webáruházban a kosárba teszi azokat a termékeket, amiket majd később meg szeretne venni, és a háttérben ezek a termékek egy session változóban kerülnek eltárolásra. Mivel egyre több webáruház elkészítésére van igény, így egy nagyon praktikus eszközt nyújt a fejlesztők számára a CodeIgniter Cart osztálya, ami pont ezt a bevásárlókocsi szolgáltatást valósítja meg.
A Cart osztály az előző pontban részletezett Session osztály segítségével kezeli és tárolja el az adatokat egy adattáblában, tehát a használatához létre kell hozni a szintén az előző pontban említett módon a ci_sessions adattáblát. Hacsak nem használjuk másra a Session osztályt, akkor nem szükséges meghívni a vezérlőben, ugyanis a Cart osztály, ezt automatikusan megteszi.
Adatok elhelyezéséhez a Cart osztály insert($data) metódusát kell használni, ahol a paraméterre bizonyos szerkezeti kritériumoknak teljesülniük kell:
$data = array( 'id' => 'azonosító', 'qty' => 1, 'price' => 2590, 'name' => 'Póló', 'options' => array('Méret' => 'L', 'Szín' => 'Piros') );
A paraméterként átadott adatok között kötelezően szerepelnie kell egy id, egy qty, egy price és egy name mezőnek, amelyek meghatározzák az egyedi azonosítót, mennyiséget, árat és termék nevet, továbbá opcionálisan megadhatók különböző tulajdonságok a tárolandó termékről. Ez utóbbi az options asszociatív tömb feltöltésével tehető meg.
A kosárban tárolt elemek módosításához az update($data) függvény használható, ahol a $data tömbnek szerkezete az alábbi:
array( 'rowid' => 'b99ccdf16028f015540f341130b6d8ec', 'qty' => 3 );
A megadott adatnak tartalmaznia kell egy sor azonosítót (Row ID), amely egyértelműen meghatározza, melyik termékről van szó, és egy mennyiség értéket. Ha a mennyiség nulla, akkor a kívánt termék eltávolításra kerül a kosáról. Az említett sor azonosító egy olyan azonosító, amit a Cart osztály generál akkor, amikor egy új termék kerül a kosárba. Erre azért van szükség, hogy azonos termékek, de különböző tulajdonságokkal is a kosárba kerülhessenek, például két ugyanolyan azonosítóval rendelkező póló, de az egyik piros, a másik kék színben.
Már volt szó a kosárba tételről, módosításról és törlésről, most nézzük a kosár megjelenítését. Ez egy tetszőleges view fájlban megtehető, ahol a kosár kinézete a fejlesztőre van bízva. A létrehozáshoz felhasználhatja a Cart osztály metódusait, azaz lekérdezheti egy lista formájában a kosár tartalmát a contents() függvénnyel, hozzáfér egy termék tetszőleges adatához, így a módosításhoz szükséges Row ID-hez is, kiírhatja a kosárban lévő termékek árának összegét a total() metódussal vagy akár az áruhoz megadott tulajdonságokat is lekérdezheti a product_options() segítségével.
Az űrlapokon keresztül megadott felhasználói adatok ellenőrzése az a művelet, amit weblap típustól függetlenül mindig el kell végezni, ellenkező esetben hibás működés következhet be. A CodeIgniter célja, a bemenő adatok egyszerű ellenőrzése úgy, hogy ne kelljen hosszú, átláthatatlan kódot írni a feladat elvégzéséhez.
Első lépésként egy nézet fájlban létre kell hozni az ellenőrizni kívánt form-ot, ahol az űrlap fejlécének elkészítéséhez célszerű a Form Helper segítségét igénybe venni. Ha megvan a nézet fájl, létre kell hozni az ezt kiszolgáló vezérlő osztályt, úgy hogy a vezérlő neve a nagybetűs változata legyen a form nevének.
A szükséges fájlok létrehozása után a vezérlőben, a form_validation osztály importálását követően, meg kell adni az űrlap mezőire vonatkozó szabályokat a form_validation->set_rule(’mezőnév’,’név’,’szabály’) módon. Itt a mezőnév, értelemszerűen a form-nál megadott input mező nevét jelenti, a név viszont az a név, amit egy esetleges hibaüzenetben szeretnénk, hogy megjelenjen. Ha megadtuk a mezőkre vonatkozó szabályokat, a form_validator->run() paranccsal ellenőrizhetjük le, hogy helyesen lettek-e megadva a bemenő adatok. Az említett függvény igaz értékkel tér vissza, ha az adatok helyesek, különben hamissal. A megadható szabályok a következők lehetnek:
Ha egy mezőhöz több szabályt szeretnénk megadni, akkor a szabályokat a | jellel tudjuk egymás után fűzni. Arra is van lehetőség, hogy az ellenőrzéshez ne a beépített szabályokat, hanem egy saját függvényt rendeljünk. Ilyenkor meg kell írni az ellenőrző függvényt úgy, hogy egy paramétere legyen, aminek majd a mező tartalma fog átadódni, és a mezőhöz a set_rule metódus harmadik paraméterének a ’callback_függvénynév’ értéket kell megadni.
A set_rule függvény nem csak szabályok mezőkhöz rendelésére jó, hanem elő is készíthetjük vele a felhasználó által megadott értéket a feldolgozásra. Erre bármilyen, olyan alap PHP függvény használható, ami egy paramétert fogad el (például md5, htmlentities stb.). Nézzünk egy példát: Van két beviteli mező, egy password és egy password2, nevű és azt szeretnénk, hogy a password mező ne legyen üres, tartalma megegyezzen a password2 mezőével és az ellenőrzés után az md5 függvénnyel kódolt értékét szeretnénk használni. Ebben az esetben a password mezőhöz tartozó szabály így néz ki:
set_rules('password', ’Jelszó’, 'required|matches[password2]|md5');
Természetesen, hibás mező esetén hibaüzenetet kell küldeni a felhasználónak, amik alapértelmezetten az /application/language/english/form_validation_lang.php fájlban vannak eltárolva. Minden hibaüzenetnek van egy neve, és ha azt szeretnénk, hogy egy szabály meghiúsulása esetén valamelyik hibaüzenet jelenjen meg, akkor a set_message(’szabály’,’hibanév’) metódust kell használni, ahol a hibaüzenetben a megfelelő helyre automatikusan beillesztődik a szükséges mező neve. Ez csak beállítja a hibaüzeneteket, de nem jeleníti meg. A megjelenítéshez el kell helyezni egy ’echo validation_errors()’ PHP sort a nézet fájlon belül.
A CodeIgniter alkalmazások fontos építőkövét jelentik a Helper, azaz segítő osztályok. Feladatuk valamilyen kisebb részproblémák megoldásának könnyebbé tétele. Helpereket a /application/helpers vagy a /system/helpers mappában tároljuk. Használatuk hasonló a könyvtárakhoz (library), a különbség a kettő között, hogy míg a library-k egy-egy összetett feladatra nyújtanak megoldást, a helperek általában kisebb feladatokra lettek kitalálva, szerkezetileg hasonlóak. Meghívásuk a kiegészítő könyvtárakhoz hasonlóan történik, például: $this->load->helper('url');
Néhány gyakran használt helper: