Nézzük a két részletet, amelyek az előző részből kimaradtak. Az első rész a számláló növeléséért felelős. Ezt egy sima adatbázis UPDATE végzi a DBI interfészen keresztül. Fontos, hogy a finish() metódussal felszabadítsuk az utasítást, különben “lógna” a levegőben azaz a memóriában. A cookie-zás (sütizés) az egy kliensből történő többszöri like-olás megakadályozását szolgálja és az üzenetfejlécben állítjuk illetve kérdezzük le, mégis teszt célokból jelen kódban ki van “ütve”.
my $cookie = $r->headers_in->get('Cookie');
my $uri = URI::Encode->new( { encode_reserved => 1 } );
my $uri_encoded_referer = $uri->encode($http_referer);
#print $uri_encoded_referer;
my $wasliked = $cookie ne '' && $cookie =~ /$uri_encoded_referer/;
if ($like && ! $wasliked ) {
# increment counter
my $sthupd = $dbh->prepare('UPDATE mylike SET counter = counter + 1 WHERE approved = 1 and referer = ?');
$sthupd->execute($http_referer);
$sthupd->finish();
my $cookie = CGI::Cookie->new(-name => 'mylike'.$http_referer,
-value => 'SET');
$r->headers_out->set('Set-Cookie' => $cookie);
$wasliked = 1;
# !! TEST ONLY !! temporary turn off cookie-mechanism !! COMMMENT OUT FOLLOWING TWO LINES FOR USE !!
$r->headers_out->set('Set-Cookie' => '');
$wasliked = 0;
}
A like változó értékadása az előző részben szerepel, a GET metódus révén átadott paraméterként kerül kiértékelésre. Az alábbi gomb onclick javascript eseményéből kerül meghívásra like=1URI változóként.
my $req = CGI->new($r);
my $like = $req->param('like');
A második kimaradt részecske maga a “like” gomb megjelenítéséért felelős. Ha már like-oltuk az oldalt, akkor disabled a gomb, azaz nem lehet többször megnyomni. 🙂
Minden további leírás helyett ideollózom a mylike-dbi.cgi azon részeit, amelyek a like-ok számának megjelenítéséért felelősek, illetve amelyek az első bejegyzés létrehozására alkalmasak.
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
use Apache2::RequestRec ();
use Apache2::RequestUtil ();
use CGI;
use CGI::Cookie;
use URI::Encode;
my $r = Apache2::RequestUtil->request;
my $req = CGI->new($r);
my $like = $req->param('like');
#print $like;
my $http_referer = $ENV{'HTTP_REFERER'};
my $dbh = DBI->connect('DBI:mysql:mylike', 'mylike', 'mylike1'
) || die "Could not connect to database: $DBI::errstr";
if ($http_referer) {
# LIKE BUTTON CODE WAS HERE ##################
my $sth = $dbh->prepare('SELECT id FROM mylike WHERE approved = 1 and referer = ?');
$sth->execute($http_referer);
my @result = $sth->fetchrow_array();
my $len = @result;
#print "numof result $len\n";
$sth->finish();
if ($len == 0) {
# insert data into the links table
my $sql = "INSERT INTO mylike (referer) VALUES(?)";
my $stmt = $dbh->prepare($sql);
# execute the query
if($stmt->execute($http_referer)) {
# ok
#print "Mylike $http_referer inserted successfully";
}
$stmt->finish();
}
$sth = $dbh->prepare('SELECT counter FROM mylike WHERE approved = 1 and referer = ?');
$sth->execute($http_referer);
@result = $sth->fetchrow_array();
print "$result[0] like(s)<br>\n";
# LIKE BUTTON CODE WAS HERE ##################
$sth->finish();
} else {
# test
my $results = $dbh->selectall_hashref('SELECT * FROM mylike', 'id');
foreach my $id (keys %$results) {
print "!!TEST!! ID $id: referer is $results->{$id}->{'referer'}, counter is $results->{$id}->{'counter'}\n";
}
}
$dbh->disconnect();
A kód magyarázata.
Kivesszük a fejlécből a HTTP_REFERER-t. Ha ez definiált, akkor “éles” működés, ha nem akkor tesztüzemmód. Tesztüzemben az alábbi kimenetet kapjuk.
Látható, hogy két REFERER szerepel az adatbázisunkban. Ezeket sorolja fel tesztüzemmódban a script.
Éles üzemnél megvizsgálja a programunk, hogy létezik-e adatbázis-bejegyzés adott REFERER-rel. Ha még nincs, létrehoz egyet 0-ás like-oltsággal. 🙂 Ezután egy sima print utasítással kijelzi a kedvelések számát.
A következő részben megnézhetjük magának a “like” gombnak is a működését és a mögötte álló programkódot is. Ebben a forrásban ezt a
# LIKE BUTTON CODE WAS HERE ##################
részek jelölik.
A SELECT-jeinkben az approved = 1 az adminisztrátori funkció további lehetőségét hordozza magában. Tehát le lehet “tiltani” egy-egy beágyazást.
Látható a kód elején a use kulcsszavaknál, hogy használunk egynéhány modult. 🙂 Szinte gyerekjáték a Perl programozás.
Megjegyzem, hogy ez a like megvalósítás különböző webcímű (URI) weboldalanként ad lehetőséget like-olásra. Egy webcímen belül több like nem lehet. Nem a tökély a cél, csupán a megvalósíthatóság bemutatása.
Lehet saját handler-t is írni, de most enm tértünk ki erre a lehetőségre. 🙂
Nézzük a hello-world-dbi.cgi programocskánkat majd a beágyazását az apartman “Képek” oldalába.
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
use Apache2::RequestRec ();
use Apache2::RequestUtil ();
my $r = Apache2::RequestUtil->request;
print "The referer in your HTTP-Header is: ", $ENV{'HTTP_REFERER'}, "\n";
my $dbh = DBI->connect('DBI:mysql:mylike', 'mylike', 'mylike1'
) || die "Could not connect to database: $DBI::errstr";
print "<br>\n";
my $results = $dbh->selectall_hashref('SELECT * FROM mylike', 'id');
foreach my $id (keys %$results) {
print "Value of ID $id is $results->{$id}->{'referer'}\n";
}
$dbh->disconnect();
Használjuk a DBI és az új Apache2-es Request modulokat, majd lekérdezzük a HTTP_REFERER-t illetve egy select-tel belefetchelünk az adatbázisba. 🙂
Figyelem! Nagyon fontos a helyes beállítás az apache config oldalon.
A kis appunkat beágyazzuk mint widget-et az alábbi módon.
Mit is kell tudjon egy tetszőleges oldalba beágyazható like alkalmazás? Tulajdonképpen esetünkben arról van szó, hogy egy tetszőleges oldalon a weblapról egy tetszésnyilvánítást rögzíthessünk illetve kijelezzük a tetszésnyilvánítások számát. Nyilvánvalóan adatbázisra lesz szükségünk a dinamikus működés biztosításához.
I. Először is két részre kell bontsuk a megvalósítást. Van egy számláló-kijelzés funkciónk, azaz hogy hány like volt eddig illetve egy “like” gomb, hogy a számláló értékét növelhessük. Továbbá beágyazhatóvá kell tennünk egy tetszőleges weboldalba a funkciót. Innentől like-widget-ről beszélhetünk (https://hu.wikipedia.org/wiki/Vez%C3%A9rl%C5%91elem).
II. Másodszor is hozzá kell kötnünk a like widget-ünket a megjelenés helyéhez. Ez a funkcionalitás a REFERER HTTP fejléc attribútum adatbázisban letárolásával és vizsgálatával oldható meg. Ez az attribútum a hivatkozott oldal címét tartalmazza (https://hu.wikipedia.org/wiki/Referer). Innen fogjuk tudni, hogy melyik a “hívó” webcím.
III. Harmadszor pedig meg kell vizsgálnunk, hogy a like funkciót felhasználóhoz vagy böngésző példányhoz kössük-e nyilvánvalóan azért, hogy ne lehessen egy személynek többször like-olnia ugyanazon a helyen. Ha felhasználóhoz kötjük, úgy a facebook stílusú megoldást kapjuk. Ez nekünk azonban túl bonyolult volna, így egyszerűen a böngészőben fogunk letárolni egy cookie-t, hogy az adott kliensen már történt egy like-olás azaz egy tetszésnyilvánítás adott webcímre.
A tervezési megfontolások nagyjából ennyit tesznek ki. Még foglalkozhatnánk a színes-szagos külcsínyről is, de azt most elhanyagoljuk. Egyszerűen egy félkövér szám lesz a like-ok száma, alatta pedig sortöréssel egy “like” feliratú gomb. Ha nem “szürke” azaz “disabled”, akkor adott kliens még nem like-olt, azaz lehet like-olni. Ennyi. 🙂
Látható, hogy 1-et ír ki, ha parancssorban futtatjuk.
Ha megnézzük weben is a http://localhost/cgi-bin/counter.sh cím alatt, ugyanez az eredmény. Látható, hogy elég a Content-type beállítása a válasz fejlécében, majd kettő soremelés után bármit kiírathatunk. 🙂
gvamosi@gergo1:/usr/lib/cgi-bin$ gcc counter.c -o counter.cgi
gvamosi@gergo1:/usr/lib/cgi-bin$ ls -l
total 32
-rw-r--r-- 1 gvamosi gvamosi 216 Aug 12 03:05 counter.c
-rwxr-xr-x 1 gvamosi gvamosi 16720 Aug 12 03:05 counter.cgi
-rwxr-xr-x 1 gvamosi gvamosi 158 Aug 12 02:47 counter.pl
-rwxr-xr-x 1 gvamosi gvamosi 84 Aug 12 02:37 counter.sh
gvamosi@gergo1:/usr/lib/cgi-bin$ ./counter.cgi
Content-type: text/html
The current count is: 1
Bámulatos, nem? 🙂 Hogy mire lesz jó ez az egész három különböző nyelvű, méghozzá benne egy natív C implementáció is? A következő fejezetekben kiderül!
Megjegyzés: natívan, bár gyorsabb a végeredmény, azért nem fejlesztünk többnyire, mert rendkívül bonyoluttá válik összetett oldalak esetén a programkód. Továbbá elég egy pici hiba, és már is “vulnerable”, azaz sérülékeny lehet a weboldalunk, amit a hacker-ek ún. exploit-tal ki tudnak használni, azaz adott esetben fel is törthetik az oldalainkon keresztül a szervereinket.
Először is telepítsük a sendmail levélszervert és a mail levelező programot, hogy legalább localhost-on le tudjuk tesztelni a levélküldést. Nagyon nem lesz nehéz dolgunk a CodeIgniter-t illetőleg, mivel támogatja a sendmail levelező csomagot.
gvamosi@gergo1:/var/www/html/apartman/application$ mail -s "Teszt levél" gvamosi@localhost < /dev/null
mail: Null message body; hope that's ok
gvamosi@gergo1:/var/www/html/apartman/application$ mail
"/var/mail/gvamosi": 1 message 1 new
>N 1 gvamosi Fri Aug 7 00:46 14/520 Teszt levél
? q
Held 1 message in /var/mail/gvamosi
Láthatjuk, hogy a levelünk “Teszt levél” tárggyal és üres tartalommal elküldésre került és szerencsésen meg is érkezett. 🙂 Helyben került kézbesítve, helyi feladótól. Ne ijedjünk meg, ha picit lassú a kézbesítés, a névfeloldás megy nehezen a sendmail-ünknek, mivel nem vagyunk internetre kötött ún. SMTP host, azaz hivatalos levélküldő szerver. Attól sem kell félnünk, hogy igazi levelet tudunk küldeni a nagyvilágba, ez így lehetetlen. 🙂
Mindez szép és jó, de hogyan küldjük el akkor egy webes form-ból a levelet az adminisztrátornak, tehát a kapcsolatfelvételi formot hogyan is programozzuk le?
Vegyünk egy sima, nem JavaScript-es form-ot az egyszerűség kedvéért, majd használjuk a CodeIgniter email könyvtárát. Annyi lesz az egész, hogy be kell konfiguráljuk a sendmail-ünket, és meg kell hívnunk a megfelelő rutinokat a controller-ünkben űrlapküldés után.
Elsőnek hozzuk létre a kapcsolati űrlapotviews/contact.php néven!
Nézzük meg azt a három metódust, amivel a controllers/Apartments.php vezérlőnket bővítettük!
public function contact() {
$data = array();
$this->template->set('title', $this->lang->line('menu_contact'));
$this->template->load('menu_layout', 'contents', 'contact', $data);
}
public function send() {
$this->load->library('email');
$config['protocol'] = 'sendmail';
$config['mailpath'] = '/usr/sbin/sendmail';
$config['charset'] = 'utf-8';
$this->email->initialize($config);
$this->email->from($this->input->post('email'), $this->input->post('name'));
// mail of administrator
$this->email->to('gvamosi@localhost');
$this->email->subject('Mail from booking site');
$this->email->message($this->input->post('message'));
$this->email->send();
redirect(base_url('index.php/apartments/contact_sent'));
}
public function contact_sent() {
$data = array();
$this->template->set('title', $this->lang->line('menu_contact'));
$this->template->load('menu_layout', 'contents', 'contact_sent', $data);
}
A contact() metódus csupán kirajzol egy oldalt, ahogy a contact_sent() is. Az érdekesebb metódusunk a send(), amiben a tulajdonképpeni levélküldés történik. Ennyi az egész! 🙂 A valóságban persze az adminisztrátorok és a fejlesztők együttműködésére és közreműködésére van szükség mind fejlesztés, mind pedig a webalkalmazás telepítése során.
Kis várakozás után megkapjuk a levelünket. Kettes sorszámmal látható a parancssori levelezőnkben. 🙂
gvamosi@gergo1:/var/www/html/apartman/application$ mail
"/var/mail/gvamosi": 2 messages 1 new 1 unread
U 1 gvamosi Fri Aug 7 00:46 17/564 Teszt levél
>N 2 Teszt Elek Fri Aug 7 01:14 23/823 Mail from booking site
? q
Held 2 messages in /var/mail/gvamosi
Az adminisztrátori vagyis foglalás-menedzsment funkcionalitás eleve rejtve van a kíváncsi tekintetek elől, hiszen ha kint is van az Interneten, vagyis a “webtérben” az oldal, link nincs az admin oldalunkra a honlapon. Azonban ennél azért nagyobb biztonságra lesz szükségünk, ezért az egész admin funkcionalitást el kell rejtsük egy jelszóval védett területre.
A jelszavas védelmet a CodeIgniter keretrendszer alapban nem támogatja, viszont egyszerűen megvalósíthatjuk. Egyszerűen úgy működik, hogy a controller-ben a kívánt funkciók hívása előtt megvizsgáljuk, hogy előzőleg tároltunk-e el a szerver session-jében “user” változót a korábban lezajló login folyamat során, amelyben adatbázisban ellenőrizzük a felhasználó/jelszó párt. Van benne még technikailag pár átirányítás, hogy a webalkalmazásunk “visszataláljon” a “hívó” oldalra (referer) a sikeres jelszó hitelesítés (authentikáció) vagyis belépés (login) után.
És akkor most nézzük a konkrét implementációt.
Először is kell egy modell. Ez az models/Auth_model.php file-unk. Összezsúfoltam picit a kódot – nem szokásom amúgy -, hogy minél kevesebb sorban oldjam meg a feladatot. 🙂
<?php
class Auth_model extends CI_Model {
public function login(){
$query = $this->db->get_where('users', array('name' => $this->input->post('username'), 'password' => $this->input->post('password')));
$result = $query->result();
return (empty($result)?false:(empty($result[0])?false:true));
}
}
Ez a login() metódus egy boolean – logikai – értékkel tér vissza attól függően, hogy megvan-e az adatbázisban a felhasználó/jelszó páros. Pár technikai észrevétel: a felhasználónévnek egyedinek kell lenni (ezt egy ún. unique key vagyis egyedi kulcs bitosítja SQL technikában), hogy nyilvánvalóan különbözzenek a felhasználóink. A gyakorlatban általában az e-mail címeket választják ki a mérnökök erre a célra, hiszen az mindenképpen egyedi. 🙂 Aztán a jelszó. Nem kódoltam le ebben a pilot alkalmazásban, de illik valamilyen egyirányú kódoló algoritmussal titkosítani, hogy senki se fejthesse vissza a jelszavakat az adatbázis ismeretében. 🙂
Ebben érdekes, hogy egy sima formot használunk, nem JavaScript-eset, és hogy password típusú mezőbe kérjük be a jelszót, amit nem lehet elolvasni a képernyőn, miközben begépeljük, csak pontokat látni a karakterek helyén. Ez a biztonságot szolgálja. Más kérdés, hogy a billentyűzetről is le tudja olvasni egy ügyes tekintetű illető a jelszót, úgyhogy ilyenkor illik “nem oda nézni” a harmadik félnek. 🙂
Majd nézzük a szintén nem túl bonyolult controller-ünket (controllers/AuthController.php). Megjegyzem, hogy végre beállítottam a config/config.php => $config['base_url'] = 'http://localhost/apartman/'; értéket, hogy használhassam az a base_url($path) metódust a redirect-ek (átirányítások) miatt. 🙂
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class AuthController extends CI_Controller {
public function __construct(){
parent::__construct();
}
public function is_logged($referer){
$user = $this->session->userdata('user');
if (empty($user)) {
// not authenticated
$this->session->set_userdata('login_url', $referer);
redirect(base_url('index.php/AuthController/login_form'));
}
}
public function login_form(){
$data = array();
$data['auth_errors'] = '';
if (!empty($this->session->flashdata('auth_errors'))) {
$data['auth_errors'] = $this->session->flashdata('auth_errors');
}
$this->template->set('title', 'Login');
$this->template->load('menu_layout', 'contents', 'login', $data);
}
public function login(){
$this->load->model('auth_model');
$success = $this->auth_model->login();
if ($success) {
$this->session->set_userdata('user', $this->input->post('username'));
redirect($this->session->userdata('login_url'));
} else {
// login fail
$this->session->set_flashdata('auth_errors', 'Login failed.');
redirect($_SERVER['HTTP_REFERER']);
}
}
public function logout(){
$this->session->set_userdata('login_url', null);
$this->session->set_userdata('user', null);
}
}
Látható, hogy három fontos metódust tartamaz. Az is_logged($referer) gondoskodik arról, hogy megvizsgáljuk, van-e belépett felhasználó (user) a session-ben. A login_form() hibaüzenetek kezelését, illetve a login form kirajzolását végzi, míg a login() a tulajdonképpeni beléptetést a modellhívással. A logout() csak játék, technikailag vettem fel. Egyszerűen töröl minden session-ban tárolt változót.
Ezt a controller-t az alkalmazásunk fő vezérlőjében (controllers/Apartments.php) az alábbi módon használjuk.
<?php
include APPPATH.'controllers/AuthController.php';
class Apartments extends AuthController {
public function admin() {
// check if user is authenticated
// config/config.php => $config['base_url'] = 'http://localhost/apartman/';
$this->is_logged(base_url('index.php/apartments/admin'));
$this->load->model('reservations_model');
$data['query'] = $this->reservations_model->get_reservations();
$this->template->set('title', 'Admin');
$this->template->load('menu_layout', 'contents' , 'admin', $data);
}
public function admin_approve_ajax($id) {
// check if user is authenticated
$this->is_logged(base_url('index.php/apartments/admin'));
$this->load->model('reservations_model');
$this->reservations_model->approve_reservation($id);
$data = $this->reservations_model->get_reservation($id)[0];
header('Content-Type: application/json');
echo json_encode($data);
}
}
Látható, hogy az AuthController-t include-oljuk a kód elején, majd extends-szel alaposztályként hivatkozunk rá. Innentől egy is_logged($referer) hívással mindkét adminisztrátori metódus legelején eldöntjük, hogy “be van-e lépve” az adminisztrátor. Ha nem, akkor átirányítjuk a login form-ra, ha igen, megy tovább a buli. 🙂
És akkor nézzük a login form-unkat! A http://localhost/apartman/index.php/AuthController/login_form webcím alatt látható, ha az admin oldalt szeretnénk megnyitni, és a session változó már elévült a webszerverünkön vagy netán kipróbáltuk a logout() funkciót. 🙂
Most már, hogy egy űrlapon keresztül foglalásokat lehet elküldeni, szükségünk lesz egy admin oldalra, ahol az apartman ügyintézője meg tudja tekinteni, illetve jóvá tudja hagyni a foglalásokat.
Hogy mit jelent itt az hogy AJAX JSON? Elég érdekes öszvér elnevezés. 🙂 AJAX-szal normál esetben egy XML adatstruktúrát vinnénk át az aszinkron javascript üzenetben, ami valahogy így nézne ki egy konkrét foglalás (reservation) adataira.
Látható, hogy egy eléggé egyszerű adatszerkezet. A JSON leírása részletesen az alábbi címen érhető el: https://hu.wikipedia.org/wiki/JSON.
És akkor nézzük meg a konkrét implementációt. Először is bővítenünk kell amodels/Reservations_model.phpmodellünket három metódussal.
public function get_reservations() {
$this->db->select()->from('reservations')->order_by('created_at', 'DESC');
$query = $this->db->get();
return $query->result();
}
public function get_reservation($id) {
$query = $this->db->get_where('reservations', array('id' => $id));
return $query->result();
}
public function approve_reservation($id) {
$date = date('Y-m-d H:i:s');
$this->db->set('updated_at', $date);
$this->db->set('approved', 1);
$this->db->where('id', $id);
$this->db->update('reservations');
}
Az első get_reservations() metódus a foglalások keletkezésének idejével csökkenő sorrendben egy listát ad vissza a foglalások adataival.
A második get_reservation($id) metódus egy konkrét foglalás adatait adja vissza.
A harmadik approve_reservation($id) metódus pedig UPDATE-eli, tehát frissíti a megadott ID-jű foglalás rekordunkat a frissítés dátumával és beállítja az jóváhagyott foglalás értékét 1-esre, ami esetünkben a jóváhagyás tényét jelzi adatbázis szinten.
Nézzük a views/admin.phpview-nkat, hogy mi is kerül bele.
Látható, hogy ebbe egy táblázat került a foglalások adataival, melynek minden sora egy-egy foglalást tartalmaz. Erről az iterációról a <?php foreach ($query as $item):?><?php endforeach;?> blokk gondoskodik. Minden sort a foglalás ID-je azonosít. Minden sorhoz kerül egy-egy JavaScript blokk is a megfelelő Approve (Jóváhagy) gomb megfelelő “click” eseményének lekezelésével.
Felhívnám a figyelmet a JSON üzenet dekódolására. Ez a var obj = $.parseJSON(JSON.stringify(response)); sorban történik. Először szükséges sztringgé alakítani a válaszüzenetet, mivel az objektum-ként érkezik. Ez a JSON.stringify metódussal történik. Utána csak egy sima parse-olásra lesz szükségünk. 🙂
Nézzük meg végül a controllers/Apartments.phpcontroller-ünket. Két új metódussal bővül. Az admin() metódusban csak kirajzoljuk az oldalunkat a modell réteg lista SQL SELECT metódusának meghívásával. Az admin_approve_ajax($id) metódusban pedig SQL UPDATE hívás majd egy SQL SELECT hívás történik a modell rétegben, illetve a válasz üzenet JSON becsomagolása.
public function admin() {
$this->load->model('reservations_model');
$data['query'] = $this->reservations_model->get_reservations();
$this->template->set('title', 'Admin');
$this->template->load('menu_layout', 'contents' , 'admin', $data);
}
public function admin_approve_ajax($id) {
$this->load->model('reservations_model');
$this->reservations_model->approve_reservation($id);
$data = $this->reservations_model->get_reservation($id)[0];
header('Content-Type: application/json');
echo json_encode($data);
}
Látható, hogy viszonylag egyszerűen megoldottuk az egész adminisztrátori funkcionalitást az AJAX form vezérlés / adatátvitel és a JSON adatformátum hsználatával. 🙂
Látható, hogy a legfelső, az Approved true, tehát jóváhagyott rendelés – mivel csak angol nyelven implementáltam mindent az egyszerűség kedvéért – melletti Approve gomb már kiszürkült, nem megnyomható újra. Az Updated at – frissítés dátuma – pedig a késői vagy kora hajnali órát jelzi, amikor elkészültem a pilot kódokkal. 🙂
Szeretnénk elérni, hogy a dátum mezőket ki lehessen választani a népszerű módon úgy, hogy “feljön” egy kis naptár egy ún. popup ablakban, ahol rákattintunk a kívánt napra, és a kivlasztott dátum bemásolódik a beviteli mezőnkbe a megadott formátumban.
Ehhez le kell tölenünk a jQuery UI-t a https://jqueryui.com/download/all/ webcímről, majd az assets könyvtárunk megfelelő js, css és css/image könyvtáraiba kell bemásolnunk a megfelelő file-okat.
Ezek után a views/booking_ajax.php view-nkban a <script> részhez az alábbi két új függvényt fűzzük hozzá a $(document).ready(function() rész alá új elemként.
Itt egy sima inicializálásról van szó ID Selector alapján, a megfelelő ISO 8601 formátumban. Már működik is! 🙂
Lehetne hozzá sőt kell is még írni egy belső validációt, ami mégegyszer ellenőrzi a dátumformátumot adatbázisba írás előtt, de most ettől eltekintunk.
Ugyanígy kimaradtak az form serialize aspektusai is az előző fejezet AJAX űrlapküldésénél, továbbá még két apróság. Ugyanis a kettővel ezelőtti fejezetben nem másoljuk be a mező értékeket abban az esetben a form-unkba, ha valami validációs hiba történik, illetve az előző fejezetben nem töröljük a form mezőket (reset), ha sikeres a foglalás.
Apróságnak tűnnek, de ezek különböztetnek meg egy professzionális weblapot egy kezdetlegesebbtől. 🙂
Az AJAX, azaz Asynchronous JavaScript and XML arra szolgál, hogy ne kelljen az egész weblapot újratölteni a form elküldésekor, hanem csak az adatokat, mintegy csendben a “háttérben” elküldeni, majd valami <div> tag-ben megjeleníteni a kívánt felhasználói üzeneteket. Részletesebb leírás az alábbi címen található https://hu.wikipedia.org/wiki/Ajax_(programoz%C3%A1s).
Nem nagyobb feladatra vállalkozunk, minthogy az előbbi foglalás-űrlap elküldésünket aszinkron JavaScript hívásra cseréljük.
Először pár apróság. A views/layouts/menu_layout.php file-ban előre kell vennünk a fejlécbe a JavaScript forrás beillesztéseket, hogy tudjuk használni a jQuery funkcionalitásait.
Aztán át kell “drótoznunk” a menüt pl. a views/photos.php file-ban.
Nézzük mi változott! Minden form mezőnek, az elküldő gombnak és a felhasználói üzenet résznek (#response_message_text és #response_message) egyedi azonosítót, id-attribútumot adtunk, hogy a JavaScript részben #id néven hivatkozhassunk rájuk. Ezt a hivatkozási módszert amúgy css szelektornak hívjuk, ezen belül is ún. ID Selector, részletek itt https://www.w3.org/wiki/CSS3/Selectors.
Látható a <script> tag-ben az ajax hívásunk. Kiolvassuk az űrlapmezők értékeit, majd egy hívást indítunk, mind success (siker), mind error (hiba) esetére megfelelő válaszokkal.
Modellünk nem változik viszont a controller-ünkbe elkél két új metódus. Nézzük a controllers/Apartments.php file-t.
public function booking_ajax() {
$data = array();
$this->template->set('title', $this->lang->line('menu_booking'));
$this->template->load('menu_layout', 'contents', 'booking_ajax', $data);
}
public function book_ajax() {
$this->load->library('form_validation');
$this->form_validation->set_rules('name', 'Name', 'required');
$this->form_validation->set_rules('email','Email','trim|required|valid_email');
$this->form_validation->set_rules('checkin', 'Check-in', 'required');
$this->form_validation->set_rules('checkout', 'Check-out', 'required');
if($this->form_validation->run() == FALSE) {
echo validation_errors();
} else {
$this->load->model('reservations_model');
$this->reservations_model->insert_reservation();
echo "Thanks for booking!";
}
}
A booking_ajax metódus csak betölti a view-nkat.
A book_ajax metódus már összetettebb. Tartalmaz egy ellenőrzést, ami email címnél valid_email-lel is bővül, tehát megvizsgálja a formátumot is és egy trim-mel, ami az esetleges felesleges ún. “trailing space” karaktereket vágja le (üres karakterek az elején és a végén).
Látható, hogy validációs hibák esetén visszatér hibával, ez ki is lesz írva a view-nkban a megfelelő div-nél, illetve ha sikerült, akkor a “Köszönet a foglalásért!” üzenettel válaszol. Ennyi az egész :).
És akkor vessünk egy pillantást egy sikeres foglalásra!