CodeIgniter modell réteg az adatbázissal és a Hello, World!

Programozóknak ugyan nem kell bemutatni Hello, World! fogalmát, de most kell hogy beszéljünk róla. A mai fejezetben szeretnénk létrehozni az adatbázist MySQL-ben, legyártani a modell réteget, majd adattal feltölteni, és a weben megjelentíteni. Mindezt mind saját kézzel írt kóddal, lehetőleg kevés kódsorban megvalósítva! Ez a Hello, World! – Helló, Világ! példánkban.

https://en.wikipedia.org/wiki/%22Hello,_World!%22_program

Hozzunk létre egy adatbázist a MySQL szerverünkön a https://wlammpp.wordpress.com/2019/10/04/i-resz-wordpress-webfejlesztes-a-wordpress-telepitese korábbi fejezetben ismertetett módon. Van egy adatbázis dump-om, ezt kell “bejátszani”.

-- MySQL dump 10.13 Distrib 5.7.29, for Linux (x86_64)
-- Host: localhost Database: evaap_devel

-- Server version 5.7.29
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
--
-- Table structure for table apartments
DROP TABLE IF EXISTS apartments;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE apartments (
id bigint(20) NOT NULL AUTO_INCREMENT,
name varchar(255) DEFAULT NULL,
address varchar(255) DEFAULT NULL,
created_at datetime NOT NULL,
updated_at datetime NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table apartments
LOCK TABLES apartments WRITE;
/*!40000 ALTER TABLE apartments DISABLE KEYS */;
INSERT INTO apartments VALUES (1,'Budapest I','VII. kerulet','2020-03-20 00:26:35','2020-03-20 00:26:35');
/*!40000 ALTER TABLE apartments ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table reservations
DROP TABLE IF EXISTS reservations;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE reservations (
id bigint(20) NOT NULL AUTO_INCREMENT,
name varchar(255) DEFAULT NULL,
email varchar(255) DEFAULT NULL,
phone varchar(255) DEFAULT NULL,
checkin date DEFAULT NULL,
checkout date DEFAULT NULL,
message text,
approved tinyint(1) DEFAULT NULL,
apartment_id int(11) DEFAULT NULL,
locale varchar(255) DEFAULT NULL,
created_at datetime NOT NULL,
updated_at datetime NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table users
DROP TABLE IF EXISTS users;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE users (
id bigint(20) NOT NULL AUTO_INCREMENT,
name varchar(255) DEFAULT NULL,
email varchar(255) DEFAULT NULL,
password varchar(255) DEFAULT NULL,
is_admin tinyint(1) DEFAULT NULL,
created_at datetime NOT NULL,
updated_at datetime NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table users
LOCK TABLES users WRITE;
/*!40000 ALTER TABLE users DISABLE KEYS */;
INSERT INTO users VALUES (1,'admin','gvamosi@linux.hu','manager',1,'2020-03-19 00:00:00','2020-03-19 00:00:00');
/*!40000 ALTER TABLE users ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2020-04-07 14:05:14

Az alábbi módon:

gvamosi@gergo1:/var/www/html/apartman$ mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 50
Server version: 5.7.29 MySQL Community Server (GPL)
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> CREATE DATABASE apartman_devel CHARACTER SET utf8 COLLATE utf8_general_ci;
Query OK, 1 row affected (0.01 sec)
mysql> CREATE USER 'apartman'@'localhost' IDENTIFIED BY 'apartman1';
Query OK, 0 rows affected (0.02 sec)
mysql> GRANT ALL PRIVILEGES ON apartman_devel.* TO 'apartman'@'localhost';
Query OK, 0 rows affected (0.00 sec)
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.01 sec)
mysql> \q
Bye
gvamosi@gergo1:/var/www/html/apartman$ mysql -u apartman -p apartman_devel < db/create_and_insert_tables.sql
Enter password:
gvamosi@gergo1:/var/www/html/apartman$

Hozzuk létre az alkalmazás modell rétegét! Ehhez először be kell konfigurálnunk az adatbázist.

gvamosi@gergo1:/var/www/html/apartman/application$ vi config/database.php

$db['default'] = array(
'dsn' => '',
'hostname' => 'localhost',
'username' => 'apartman',
'password' => 'apartman1',
'database' => 'apartman_devel',
'dbdriver' => 'mysqli',
'dbprefix' => '',
'pconnect' => FALSE,
'db_debug' => (ENVIRONMENT !== 'production'),
'cache_on' => FALSE,
'cachedir' => '',
'char_set' => 'utf8',
'dbcollat' => 'utf8_general_ci',
'swap_pre' => '',
'encrypt' => FALSE,
'compress' => FALSE,
'stricton' => FALSE,
'failover' => array(),
'save_queries' => TRUE
);

Ez eddig 3 string (karakterlánc)! 🙂 Aztán meg kell írnunk az Apartments_model.php file-t!

gvamosi@gergo1:/var/www/html/apartman/application$ vi models/Apartments_model.php

<?php
class Apartments_model extends CI_Model {
public function get_last_ten_entries()
{
$query = $this->db->get('apartments', 10);
return $query->result();
}
}

Ez 8 sor. 🙂 Most írjuk meg a controller-t!

gvamosi@gergo1:/var/www/html/apartman/application$ vi controllers/Apartments_controller.php
<?php
class Apartments_controller extends CI_Controller {
public function index() {
echo 'Helló, Világ!!';
$this->load->model('apartments_model');
$data['query'] = $this->apartments_model->get_last_ten_entries();
$this->load->view('apartments', $data);
}
}

Ez újabb 9 sor! Nem sok ez egy listáért? És akkor írjuk meg a view-t is!

gvamosi@gergo1:/var/www/html/apartman/application/views$ vi apartments.php

<ul>
<?php foreach ($query as $item):?>
<li><?php echo $item->address;?></li>
<?php endforeach;?>
</ul>

Ez húzós 5 sor! 🙂 Állítsuk be az útvonalakat, az autoload-ot (még két sor :)), majd hívjuk meg a következő módon a böngészőnkből az “oldalunkat”!

gvamosi@gergo1:/var/www/html/apartman/application$ vi config/routes.php
$route['apartmanok'] = 'apartments_controller/index';

gvamosi@gergo1:/var/www/html/apartman/application$ vi config/autoload.php
$autoload['libraries'] = array('database','session');

http://localhost/apartman/index.php/apartmanok

Listázza az egy darab apartmanunk címét, Budapesten. Siker! 🙂

Airbnb apartman foglalás – esettenulmány – PHP CodeIgniter keretrendszerben

Amint megígértem, ebben az évben folytatom, és remélhetőleg be is fejezem a webprogramozásról szóló online könyvemet. 🙂

Hogy jobban megértsük a webprogramozást, egy kis architektúrális ismertetőt kell tartsak. Általánosságban már szóltam a kliens-szerver felépítésről (https://wlammpp.wordpress.com/2019/10/03/mit-ertunk-webprogramozas-webfejlesztes-alatt). Egy webes alkalmazás a felhasználóval a böngészőn (browser) keresztül “lép interaktív kapcsolatba”. Ez azt jelenti, hogy a felhsználó egy böngésző ablakban illetve tabfülön keresztül látja illetve használja a grafikus felhasználói felületet (GUI – graphical user interface, ide tartozik még a népszerű Ui / UX Design fogalma, vagyis a felhasználói felület és élmény tervezés). A felhasználó az alkalmazás funkcióit a böngészőben megjelenő felületen keresztül éri el: elolvas információkat, regisztrál egy webes űrlapon (formon) keresztül, keres, navigál, “kattint” (click-el). Ezek közül komolyabb programozást az űrlapkitöltés és a keresés igényel, illetve a különböző grafikai látványelemek is.

Az egész webprogramozás illetve -fejlesztés azért tűnhet bonyolultnak, mert egyrészt kellenek a “szerver oldali” dolgok: egy adatbázis – esetünkben relációs -, amit az ún. SQL nyelven lehet manipuláni, lekérdezni, feltölteni, frissíteni illetve törölni (https://hu.wikipedia.org/wiki/SQL), továbbá egy beágyazott, illetve szerver oldalon értelmezett (ún. script) nyelv, ez a PHP 7-es verzió konkrét esetünkben (https://www.php.net/), amely a funkcionalitást, az “üzleti folyamatot” valósítja meg (implementálja). A PHP Hyprtext Preprocessor-nak hirdeti magát, ami azt jelenti, hogy a HTML nyelven (ez a weblapok nyelve) írt hypertext-be van beágyazva, amit a webszerverünk megfelelő modulja értelmez, amikor valaki az adott weboldalt a böngészőjében megnyitja. Tehát nincs előre lefordítva, mint például egy C nyelven írt kernel modul (Linux), hanem “on the fly” fordul (compile), és “fut” (run). Ezt szemléltetném is egy pár soros kódban.

<!DOCTYPE html>
<html>
<head>
<title>Lapcím</title>
</head>
<body>

<h1>Ez egy címsor.</h1>
<p>Ez egy bekezdés.</p

<!-- Ez egy megjegyzés. Ide jön a PHP kódrészlet. -->

<?php
phpinfo();
?>

</body>
</html>

Ebben a rövid kódrészletben (snippet) ún. HTML tag-eket láthatunk. Az eleje egy dokumentum típus megjelölés, majd html, head – fejléc, body – törzs olvashatóak. Látható, hogy <? ?> jelek között van a PHP kódrészlet, ami konkrétan egy hosszú és részletes kiírást eszközöl a szerverünk beállításáról, ha megnézzük böngészőben (írtam már róla itt: https://wlammpp.wordpress.com/2019/10/04/i-resz-wordpress-webfejlesztes-a-wordpress-telepitese). Ezek a tag-ek mind “kacsacsőrök” között vannak. Ez a leíró nyelvek sajátossága. Az XML is ilyen formátumú. 🙂

A HTML oldal önmagában statikus, ha pl. PHP kódrészletet nem tartalmaz. Lehet benne hivatkozás képre, hangra, videóra, tehát Hypertext, ugyanakkor nem igényel szerveroldali processzálást (feldolgozást). Ezért a szerveren statikus oldalként kerül kiszolgálásra. Erre általában az oldalt tartalmazó állomány nevének kiterjesztése utal, ez többnyire .html – PHP oldalak esetében pedig .php. A nagy különbség egy “honlap” és egy “webalkalmazás” között abban rejlik, hogy milyen és mennyi “kód” van mögötte és benne a szerveren, illetve a kliens oldalon JavaScript formájában, értsd: hogy mennyire interaktív. Alábbiakban egy kis összefoglaló a HTML struktúráról, a tag-ekről.

<!-- Nyitó és záró tag, közte a tartalom. -->
<tagnev>Töltelék.</tagnev>

<!-- Önmagában záródó tag (XML helyes), paraméterekkel. -->
<tagnev parameter1="ertek1" parameter2="ertek2" />

<!-- A legegyszerűbb "beágyazás". -->
<tag1>
<tag2 />
</tag1>

Ha ez már bonyolult volna, szólnom kell még a kliens oldalon fontossá váló komponensekről. Ezek az előbbiekben taglalt az oldalak alapvető struktúrájáért és megjelenéséért felelős HTML (Hypertext Markup Language – https://www.w3schools.com/html/), a látványért felelős CSS (https://hu.wikipedia.org/wiki/Cascading_Style_Sheets, https://www.w3schools.com/css/) illetve a dinamikus működésért felelős JavaScript (https://www.w3schools.com/js/) nyelveken implementált böngészőben futó, “héj” réteg. A könyv legelején taglalt MVC architektúra (Model – View – Controller) View – nézet rétegéről szól ez a kliens oldali rész. A dinamikus működést biztosító JavaScript, ha AJAX-ról (https://hu.wikipedia.org/wiki/Ajax_(programoz%C3%A1s)) beszélünk, akkor lehet “okos” Controller – vezérló működésű is, sőt bizonyos szempontból még Model – adatszerkezet érintettségről is beszélhetünk, amennyiben XML-formátumban történik az adatátvitel pl. egy kliens oldali űrlap (form) és a szerver oldali Controller között.

A szerveroldali részek azonban a Model és a Controller rétegbe tartoznak. Technikailag ugyan a View is a szerver oldalon van, ámde csupán a böngészőben válik látvánnyá. Ha jól implementáltuk (programoztuk) az alkalmazást, az architektúrális elveknek megfelelően, akkor elválnak egymástól a rétegek. Ettől áttekinthető és karbantartható marad a kódunk. Sokkal kisebb a hibalehetőség, illetve egyszerűbb továbbfejleszteni, módosítani és dokumentálni. Hogy ezt az architektúrális szétválasztást tényleg meg is tehessük, segítségül hívtuk a CodeIgniter (https://codeigniter.com/) keretrendszert (framework-öt).

A CodeIgniter-t (3-as verzió) egész egyszerűen letöltjük (https://codeigniter.com/download), és kicsomagoljuk a webszerverünk gyökér könyvtára alatt létrehozott “apartman” könyvtárba.

gvamosi@gergo1:/var/www/html$ sudo mkdir apartman
[sudo] password for gvamosi:
gvamosi@gergo1:/var/www/html$ sudo chown gvamosi:gvamosi apartman/
gvamosi@gergo1:/var/www/html$ cd apartman/
gvamosi@gergo1:/var/www/html/apartman$ cp ~/Downloads/bcit-ci-CodeIgniter-3.1.11-0-gb73eb19.zip .
gvamosi@gergo1:/var/www/html/apartman$ unzip bcit-ci-CodeIgniter-3.1.11-0-gb73eb19.zip
gvamosi@gergo1:/var/www/html/apartman$ mv bcit-ci-CodeIgniter-b73eb19/* .
gvamosi@gergo1:/var/www/html/apartman$ l
total 3836
drwxr-xr-x 14 gvamosi gvamosi 4096 Sep 19 2019 application
-rw-r--r-- 1 gvamosi gvamosi 2758337 Apr 6 11:30 bcit-ci-CodeIgniter-3.1.11-0-gb73eb19.zip
drwxr-xr-x 2 gvamosi gvamosi 4096 Apr 6 11:32 bcit-ci-CodeIgniter-b73eb19
-rw-r--r-- 1 gvamosi gvamosi 594 Sep 19 2019 composer.json
-rw-r--r-- 1 gvamosi gvamosi 6841 Sep 19 2019 contributing.md
-rw-r--r-- 1 gvamosi gvamosi 1117463 Apr 6 11:23 framework-4.0.2.zip
-rwxr-xr-x 1 gvamosi gvamosi 10255 Sep 19 2019 index.php
-rw-r--r-- 1 gvamosi gvamosi 1114 Sep 19 2019 license.txt
-rw-r--r-- 1 gvamosi gvamosi 2343 Sep 19 2019 readme.rst
drwxr-xr-x 8 gvamosi gvamosi 4096 Sep 19 2019 system
drwxr-xr-x 14 gvamosi gvamosi 4096 Sep 19 2019 user_guide

Ezek után megnézhetjük a “helyi” webszerverünket, hogy sikerült-e a telepítés. Írjuk be a kedvenc böngészőnkbe (én a Google Chrome-ot használom) a következő címet: http://localhost/apartman/. 🙂

Siker! 🙂 Jól látható, hogy vagy 5 nyelven kell tudnunk kódolni egy átlagos webalkalmazáshoz. 😀 Megjegyzem, hogy ez az esettanulmány ugyan konkrét példát mutat be, azonban általános érvényű az architektúrában és főbb irányelveiben.