Webes Alkalmazások Fejlesztése 1
Total Page:16
File Type:pdf, Size:1020Kb
WEBES ALKALMAZÁSFEJLESZTÉS 1. Horváth Győző Egyetemi adjunktus 1117 Budapest, Pázmány Péter sétány 1/C, 2.420 Tel: (1) 372-2500/1816 Tartalom 2 MVC ismétlés Mini MVC – saját MVC keretrendszer MVC részeinek finomítása Modell finomítása Nézet finomítása Vezérlő finomítása Egyéb funkciók beillesztése az MVC mintába 6 MVC ismétlés Ismétlés 7 Kiindulási pont: egyszerű listázó alkalmazás vegyes HTML és PHP kód vegyes funkcionalitások Kód funkcionális (és ezzel nyelvi) szétválasztása Nézet (view) Modell (model) Vezérlő (controller) Vezérlő (controller) 8 <?php include('albums_model.php'); $nev = ''; $leiras = ''; if (isset($_POST['nev'])) { $nev = $_POST['nev']; } if (isset($_POST['leiras'])) { $leiras = $_POST['leiras']; } $albums = get_albums($nev, $leiras); //modell include('list.php'); //view Modell (model) 9 <?php function get_albums($nev = '', $leiras = '') { $mysqli = new mysqli('localhost', 'wabp3', 'ab2009', 'wabp3'); if ($mysqli->connect_error) { die('Kapcsolodasi hiba' . $mysqli->connect_errno . $mysqli->connect_error); } $mysqli->query('set names utf8'); $stmt = $mysqli->prepare( "select * from photo_albums where nev like ? and leiras like ?"); $stmt->bind_param('ss', $nev, $leiras); $nev = "%{$nev}%"; $leiras = "%{$leiras}%"; $stmt->execute(); Modell (model) 10 $meta = $stmt->result_metadata(); $sor = array(); foreach ($meta->fetch_fields() as $field) { $params[] = &$sor[$field->name]; } call_user_func_array(array($stmt, 'bind_result'), $params); $albums = array(); while ($stmt->fetch()) { $albums[] = array( 'id' => $sor['id'], 'nev' => $sor['nev'], 'leiras' => $sor['leiras'], ); } $stmt->free_result(); $mysqli->close(); return $albums; } Nézet (view) 11 <html> <head> <title></title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> <body> <h1>Albumok listazasa</h1> <form action="index2.php" method="post"> Nev: <input type="text" name="nev" value="<?php echo $nev; ?>" ><br> Leiras: <input type="text" name="leiras" value="<?php echo $leiras; ?>" ><br> <input type="submit" value="Szur"> </form> Nézet (view) 12 <table> <tr> <th>Azonosító</th> <th>Név</th> <th>Leírás</th> </tr> <!--Dinamikus resz kezdete --> <?php foreach ($albums as $sor) : ?> <tr> <td><?php echo $sor['id']; ?></td> <td><?php echo $sor['nev']; ?></td> <td><?php echo $sor['leiras']; ?></td> </tr> <?php endforeach; ?> <!--Dinamikus resz vege --> </table> <a href="insert.php">Új album...</a> </body> </html> Ismétlés 13 Ez a megvalósítás az MVC architekturális tervezési mintát követi, valósítja meg Vezérlő Modell Nézet Ismétlés 14 MVC minta általánosságban MVC keretrendszerek CodeIgniter (professzionális MVC keretrendszer) 15 Mini MVC Saját MVC-s keretrendszer Saját MVC keretrendszer 16 Elvárások Egy belépési pontja legyen az alkalmazásnak Az MVC részei külön könyvtárba kerüljenek Elnevezési konvenciók Sablon nyelv a PHP (echo, if, foreach) Oldalsablon támogatás legyen OOP Front Controller 17 Az alkalmazás belépési pontja Vezérlők közös részeit tartalmazza munkamenet-kezelés, konfiguráció beolvasása, authentikáció, előszűrések, stb. Többi fájl elérhetetlensége .htaccess token definiálása a FC-ben és ellenőrzése a vezérlőkben index.php Kért oldal jelzése GET paraméterrel index.php?oldal=main Front Controller 1. 18 switch ($oldal) { function index() { case "index": index(); } break; case "page1": function page1() { page1(); break; } case "page2": page2(); function page2() { break; case "page3": } page3(); break; function page3() { default: index(); } } Front Controller 2. 19 if (function_exists($oldal)) { function index() { call_user_func($oldal); } } function page1() { } function page2() { } function page3() { } Front Controller 3. 20 switch ($oldal) { case "index": include "v3_index.php"; break; case "page1": include "v3_page1.php"; break; case "page2": include "v3_page2.php"; break; case "page3": include "v3_page3.php"; break; default: include "v3_index.php"; } Front Controller 4. 21 if (file_exists("v3_" . $oldal . ".php")) { include_once("v3_" . $oldal . ".php"); } Front Controller (index.php) 22 index.php?class=products&method=list define( "TOKEN", "mini_mvc" ); if (file_exists("controllers/" . $class . ".php")) { session_start(); include_once("controllers/" . $class . ".php"); if (class_exists($class . "_Controller")) { function __autoload($class_name) { $class .= "_Controller"; require_once $ctrl = new $class(); strtolower($class_name) . '.php'; if (method_exists($ctrl, $method)) { } //call_user_func(array($class, $method)); $ctrl->$method(); require "models/db.php"; } //Konfiguracio betoltese else { //Jogosultsagok ellenorzese include_once("error.html"); } $class = 'main'; } if (isset($_GET['class'])) { else { $class = $_GET['class']; include_once("error.html"); } } $method = 'index'; } if (isset($_GET['method'])) { else { $method = $_GET['method']; include_once("error.html"); } } Front Controller vs bootstrap 23 A fenti megoldásban a Front Controller procedurális, nem OOP-s Ha a Front Controllert osztálypéldányként (singleton) szeretnénk használni, akkor az az állomány, amely előkészíti és példányosítja a bootstrap állomány (index.php) Controller bootstrap Controller Front Front Könyvtárszerkezet 24 Vezérlő 25 <?php if (!defined('TOKEN')) exit('Ejnye-bejnye'); class Main_Controller { function index() { include('models/albums.php'); $nev = ''; $leiras = ''; if (isset($_POST['nev'])) { $nev = $_POST['nev']; } if (isset($_POST['leiras'])) { $leiras = $_POST['leiras']; } $model = new Albums_Model(); $albums = $model->get_albums($nev, $leiras); //modell $view = new View(); $view ->set('nev', $nev) ->set('leiras', $leiras) ->set('albums', $albums); $content = $view->get_include_contents('views/list.php'); include('views/template.php'); } } View osztály 26 class View { private $vars = array(); public function get_include_contents($filename) { extract($this->vars); if (is_file($filename)) { ob_start(); include $filename; $contents = ob_get_contents(); ob_end_clean(); return $contents; } return false; } public function set($name, $value) { $this->vars[$name] = $value; return $this; } } Modell 27 <?php if (!defined('TOKEN')) exit('Ejnye-bejnye'); class Albums_Model { function get_albums($nev = '', $leiras = '') { ... return $albums; } } Nézet 28 <table> <tr> <th>Azonosító</th> <th>Név</th> <th>Leírás</th> <th>Funkciók</th> </tr> <!--Dinamikus resz kezdete --> <?php foreach ($albums as $sor) : ?> <tr> <td><?php echo $sor['id']; ?></td> <td><a href="index.php?class=images&method=index&album_id=<?php echo $sor['id']; ?>"><?php echo $sor['nev']; ?></a></td> <td><?php echo $sor['leiras']; ?></td> <td><a href="index.php?class=main&method=delete&id=<?php echo $sor['id']; ?>">Torol</a></td> </tr> <?php endforeach; ?> <!--Dinamikus resz vege --> </table> <a href="index.php?class=main&method=insert">Új album...</a> Oldalsablon 29 <div id="wrap"> <div id="header"> <h1 id="logo-text"> <a href="index.html">Sablon</a> </h1> </div> <!-- content-wrap starts here --> <div id="content-wrap"> <div id="main"> <?php echo $content; ?> </div> </div> </div> 30 Modell finomítása Modell finomítása 31 Az alkalmazás adatait és az ezek feldolgozásához szükséges üzleti logikát tartalmazza További rétegekre bontható üzleti logikai réteg (üzleti logikához illeszkedő adatszerkezetek, objektumok) adatbázis-absztrakciós réteg (adatbázis- és táblaszerkezetnek megfelelő objektumok hierarchiája) adatbázis-elérési absztrakciós réteg adatbázis (táblák, tárolt eljárások, nézetek) Modell minták 32 Domain model: olyan réteg, amely a valós világ adatainak megfelelő absztrakt objektumokat, logikákat tartalmazza Simple Domain Model: egy-egy kapcsolat az üzleti objektumok és táblák között Active Record minta (rekord szintű) Table Data Gateway minta (tábla szintű) Data Mapper minta (táblaadatok üzleti objektum) Rich Domain Model: üzleti objektumok bonyolultabb kapcsolatrendszere (tipikusan nagyvállalati projektek) Adatbázis-elérési absztrakció 33 A modellünk jelenleg egy bizonyos adatbázis driverhez kötődik. Ha megváltozik az alkalmazásunk mögötti adatbáziskezelő, vagy egyszerűen olyan szerverre költözünk, ahol egy bizonyos driver nincsen feltelepítve, az átállás nagyon nehéz lehet. Megoldás: adatbázis-elérési absztrakciós réteg kialakítása, mely egy magasabb szintű absztrakt nyelvvel elfedi a konkrét adatbázis függvényeit. Adatbázis-elérési absztrakció 34 Adatbázis-elérési absztrakciós lehetőségek Saját magunk készítünk ilyen réteget Előre megírt függvénykönyvtárat alkalmazunk PHP PDO Doctrine Database Abstraction Layer http://www.doctrine-project.org/projects/dbal Saját absztrakciós réteg 35 db.php: konfiguráció mysql.php: absztrakt műveletek Mysqli interfésszel kifejtve oracle.php: absztrakt műveletek OCI8 interfésszel kifejtve albums.php: absztrakt interfésszel megvalósított modell PHP PDO 36 PHP „natív” absztrakciós Műveletkategóriák rétege Kapcsolatkezelés Többféle interfészt támogat CUBRID (PDO) Tranzakciókezelés MS SQL Server (PDO) Paraméterezett SQL Firebird/Interbase (PDO) utasítások és tárolt eljárások IBM (PDO) kezelése Informix (PDO) Hibakezelés MySQL (PDO) LOB-ok kezelése Oracle (PDO) http://www.php.net/manual ODBC and DB2 (PDO) /en/book.pdo.php PostgreSQL (PDO) SQLite (PDO) 4D (PDO) PHP PDO 37 PDO PDOStatement exec bindColumn query bindParam prepare bindValue lastInsertId execute beginTransaction rowCount inTransaction fetch commit fetch… rollBack closeCursor errorCode errorCode errorInfo errorInfo PHP PDO példa 38 $sth = $dbh->prepare('SELECT name, colour,