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

include('albums_model.');

$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 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

Albumok listazasa

Nev:
Leiras:
Nézet (view)

12

Azonosító Név Leírás
Új album... 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

$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

class Albums_Model { function get_albums($nev = '', $leiras = '') { ... return $albums; } } Nézet

28

Azonosító Név Leírás Funkciók
Torol
Új album... Oldalsablon

29

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, calories FROM fruit WHERE calories < :calories AND colour = :colour'); $sth->bindParam(':calories', $calories, PDO::PARAM_INT); $sth->bindParam(':colour', $colour, PDO::PARAM_STR, 12); $calories = 150; $colour = 'red'; $sth->execute();

$sth = $dbh->prepare('SELECT name, colour, calories FROM fruit WHERE calories < ? AND colour = ?'); $calories = 150; $colour = 'red'; $sth->execute(array($calories, $colour)); Adatbázis-absztrakciós megoldások

40

 Általában egy adatbázis-elérési absztrakciós rétegen ülnek  Tipikusan egy-egy kapcsolatot teremtenek az adatbázisbeli táblák és az üzleti objektumok adattagjai között  Az adatbázist az üzleti objektum magas szintű absztrakt metódusain keresztül manipuláljuk  get, getAll, save (insert vagy update)  Általában ORM megoldások: Object Relational Mapping Adatbázis-absztrakciók

41

 Nem jelennek meg benne direkt SQL utasítások

 OOP felületen adjuk meg a logikát, mit szeretnénk, s az absztrakciós réteg generálja le a neki megfelelő SQL utasítást

 A megoldások egy részében saját lekérdező nyelven keresztül  Hibernate HQL  Doctrine DQL Object Relational Mapping

42

 Az ORM egy tábla-egy objektum kapcsolatot létesít

 Lehetőség van kapcsolatok megadására (1-N, N-N viszonyok) és ezeknek OOP-s felületen történő kezelésére  pl. $user->subjects PHP ORM megoldások

43

 Független projektek  Keretrendszerbe  ActiveRecord ágyazva  Doctrine  CodeIgniter  Eloquent   Propel   CakePHP  Kohana PHP  PHP ORM példa (ActiveRecord)

44

class User extends ActiveRecord\Model { }

// create Tito $user = User::create(array('name' => 'Tito', 'state' => 'VA'));

// read Tito $user = User::find_by_name('Tito');

// update Tito $user->name = 'Tito Jr'; $user->save();

// delete Tito $user->delete(); PHP ORM példa (ActiveRecord)

45 PHP ORM példa (ActiveRecord)

46 CodeIgniter specifikumok

47

 CodeIgniter a Database Classon keresztül biztosít  adatelérési-absztrakciós réteget  adatbázis-absztrakciós réteget (ActiveRecord minta alapján, de nem teljes ORM funkcionalitás) 48 Nézet finomítása Nézet finomítása

49

 Alkalmazott tervezési minták  Template view  Transform view  Layout view (oldalsablon megadása) Template view

50

 Általában ezt használjuk webalkalmazásokban

 A nézet ebben az esetben egy sablon, amiben speciális jelölőket cserélünk ki a modellből kinyert adatokkal

 Előző előadásban is ezt mutattuk be

 Részei  sablon (PHP, Smarty, stb.)  nézethez tartozó logika, melynek során a jelölőkhöz adatokat rendelünk, valamint a feldolgozó rész Template view példa (CodeIgniter)

51 class Products extends CI_Controller { public function index() { $data = array( 'alma' => 'piros', 'korte' => 'kukacos', ); $this->load->view('proba', $data); } }

My Blog

Az alma .

A körte .

Transform view

52

 A transform view adatokat nyer ki a modellből, és azokat a kimenetnek megfelelően átalakítja.

 A template view a kimenet vázlatával kezdi, és abba illeszti be az adatokat

 A transform view-nál az adatok az elsők, és abból építi fel a kimenetet

 Tipikusan technológia: XSLT Layout view

53

 A nézet további részekre bontását végzi el

 Egy weboldalon általában vannak viszonylag állandó részek: fejléc, az oldalelrendezés, lábléc, globális navigáció

 És vannak az oldalról oldalra változó tartalmi részek

 A nézetet ennek megfelelően szokták szétválasztani  oldal elrendezésére (layout)  tartalmi sablonra (template) CodeIgniter specifikumok

54

 Template view támogatott a View classon keresztül  $this->load->view('sablon.php');

 Transform view-t PHP támogatja az xml és xslt függvényein keresztül

 Layout view ld. később 55 Controller finomítása

Bootstrap, Front Controller, Application Controller Controller finomítása

56

 Példánkban a vezérlő nem csinált túl sok mindent

 Általában a vezérlőknek elég sok mindent kell elintéznie, mielőtt a konkrét művelet végrehajtásába kezd

 Ezek között sok olyan dolog van, ami minden vezérlő számára közös

 A közös dolgokat külön választják, ez lesz a Front Controller, az egyedi dolgok pedig az egyes műveletekben kerülnek megvalósításra További finomítás

57

 Alap esetben a Front Controller biztosítja az alkalmazás belépési pontját (ez előny)

 De ekkor szükségképpen tartalmaz procedurális kódot, így a Front Controller csak félig OOP-s

 A megfelelő művelet kiválasztása is külön vehető

 Ezért többfelé választják  Bootstrap  Front Controller  Application Controller Bootstrap

58

 index.php

 alkalmazás belépési pontja

 procedurális

 feladata  Front Controller példányosításának előkészítése  konfiguráció, alapváltozók  a példányosítás (singleton)  a példány kezdőmetódusának meghívása (run) Front Controller

59

 Objektum-orientált megközelítés

 tipikusan singleton

 Közös feladatok centralizált elvégzése  kérés feldolgozása  routing  caching  biztonság  konfiguráció

 Intercepting filter helye Intercepting filter

60

 Globális kódok és funkcionalitás a Front Controllerben az Intercepting filter minta felhasználásával kerülhetnek

 Kétféle megközelítés  szűrők szekvenciális végrehajtása az alkalmazásvezérlőig  elő- és utószűrők megadása Intercepting filter példa

61

class FrontController { var $_filter_chain = array();

function registerFilter(&$filter) { $this->_filter_chain[] =& $filter; } function run() { foreach(array_keys($this->_filter_chain) as $filter) { $this->_filter_chain[$filter]->preFilter(); } $this->_process(); foreach(array_reverse(array_keys($this->_filter_chain)) as $filter) { $this->_filter_chain[$filter]->postFilter(); } } function _process() { // FrontController tennivalói } } Intercepting filter példa

62

 Szűrő példa

class HtmlCommentFilter { function preFilter() { ob_start(); } function postFilter() { $page = ob_get_clean(); echo preg_replace( ‘~~ims’ ,’’ ,$page); } } Application Controller

63

 Ez az MVC vezérlő központi része: ő dönti el, hogy a bejövő kérés alapján az alkalmazás hogyan válaszoljon

 Tipikusan  egy nagy elágazás (if, switch)  vagy felparaméterezett tömb  vagy elnevezési konvenciók (kérés, file és osztálynév) Application Controller példa

64

 Paraméterezett asszociatív tömb

$action_map = array( 'del' => 'DeleteBookmark' ,'upd' => 'UpdateBookmark' ,'add' => 'InsertBookmark' ); $action_class = (array_key_exists($_POST['action'], $action_map)) ? $action_map[$_POST['action']] : 'DisplayBookmark'; if (!class_defined($action)) { require_once 'actions/'.$action_class.'.php'; } $action =& new $action_class; $action->run(); 65 Egyéb funkciók helye MVC-ben

Authentikáció, authorizácó (ACL), oldalsablon Vitatott kérdések

66

 Az MVC minta a vezérlő, a nézet és az adatok helyéről nyilatkozik általánosságban

 Egy webalkalmazásban azonban számos további funkció is helyet kap  munkamenet-kezelés  authentikáció  authorizáció  oldalsablon használata Munkamenet-kezelés

67

 Többféle elképzelés van, de ezek fontossága azonban elvi jelentőségű

 $_SESSION  modell: adatok vannak benne  vezérlő: az alkalmazás input oldalán jelennek meg  nézet: ha sütikkel oldjuk meg, akkor viszont HTTP specifikus Authentikáció

68

 Az authentikációs logika külön osztályban (library) megvalósítható

 Hol épüljön az alkalmazásba?

 Lehetőségek  őscontroller  hook Authorizáció

69

 Ez is külön osztályban megvalósítható

 Sok helyen ACL (Access Control List) néven hivatkoznak rá

 Sokféle megvalósítása van

 Népszerű a Zend ACL használata

 Helye  őscontroller  hook  controller  még alsóbb szinteken (feladatfüggő, pl. mezőszintű elérési szabályok) Layout használata

70

 Helye  őscontrollerben megírni  set_template_data  display_template  hook-ot készíteni rá  http://hasin.wordpress.com/2007/03/05/adding-yield- /  library-t készíteni rá  http://codeigniter.com/wiki/layout_library/ Layout ősvezérlőben

71

class MY_Controller extends CI_Controller { protected $template = 'template'; protected $template_data = array();

protected function set_template_part($part, $view, $data = array()) { $this->template_data[$part] = $this->load->view($view, $data, true); } protected function set_template_data($part, $data) { $this->template_data[$part] = $data; } protected function display_template($view = null, $data = array()) { if (!is_null($view)) { $this->set_template_part('content', $view, $data); } $this->load->view($this->template, $this->template_data); } } Layout használata

72

public function index() { $albums = $this->Albums_Model->get_albums(); $this->display_template('list', array( 'nev' => $nev, 'leiras' => $leiras, 'albums' => $albums, )); } 73 CodeIgniter plusz tulajdonságok

Input Class, Routing (remap) Input Class

74

 Az Input Class biztonságos adatelérést tesz lehetővé  megszűri a POST és COOKIE adatokat  igény szerint XSS szűrést hajt végre

 Nem kell külön betölteni (automatikusan történik)

 Metódusok  $this->input->post('vmi' [, true])  $this->input->cookie()  $this->input->server() Speciális útvonalak

75

 Alapból az URI eldönti, melyik vezérlő melyik metódusát hívjuk

 Ez utóbbi felülbírálható a _remap függvénnyel  Ha van, akkor mindig meghívódik  1. paraméter: metódus  2. paraméter: opcionális paraméterlista

 Pl. speciális előtag használata (pl. AJAX hívásnál) Speciális útvonal

76

public function _remap($method, $params = array()) { if ($this->request->is_ajax()) { $method = '_ajax_'.$method; } if (method_exists($this, $method)) { return call_user_func_array(array($this, $method), $params); } show_404(); } Speciális útvonalak

77

 Átirányítási szabályok (config/routes.php)

//Egy-egy leképezés $route['journals'] = "blogs"; $route['blog/joe'] = "blogs/users/34";

//Joker karakterek $route['product/:num'] = "catalog/product_lookup"; $route['product/(:any)'] = "catalog/product_lookup"; $route['product/(:num)'] = "catalog/product_lookup_by_id/$1";

//Reguláris kifejezések $route['products/([a-z]+)/(\d+)'] = "$1/id_$2"; // products/shirts/123 --> shirts/id_123