Komponent modelu MVC - widok i implementacja szablonu w PHP
Komponent modelu MVC - kontroler
Komponent modelu MVC - model i wydruk danych z tabeli
Interfejs PDO - połączenie z bazą danych
Wydruk danych z bazy danych
Wprowadzanie danych do bazy danych
Modyfikacja szablonu głównego i style CCS w projekcie
Wzorzec MVC
W ramach zajęć zostanie przedstawiona konstrukcja aplikacji w oparciu o wzorzec MVC.
Wzorzec MVC składa się z trzech komponentów programowych - modelu, widoku i kontrolera.
Komponent kontrolera odpowiedzialny jest za sterowanie aplikacją, powinien zawierać kod php,
brak zapytań do bazy danych oraz brak kodu HTML. Komponent szablonów odpowiedzialny jest
za przygotowanie stron przesyłanych do użytkownika. Zawiera on skrypty wprowadzające wartości
zmiennych do odpowiednich szablonów przygotowanych w języku HTML. Na koniec komponent modelu
zawiera interfejs połączenia z źródłem danych, zawiera on instrukcje względnie polecenia
przetwarzające dane w źródle. Komponent ten nie powinien zawierać kodu HTML.
Na rys.1 przedstawiono przykładowy diagram sekwencji prezentujący przepływ danych w ramach
modelu MVC.
Rys.1 Przykładowy diagram sekwencji realizowany w modelu MVC.
W ramach zajęć zostanie opracowana prosta aplikacja spełniające przedstwione powyżej kryteria.
Struktura plików w opracowanym projekcie została przedstawiona poniżej.
W ramach tego zadania przedstawione zostaną skrypty realizujące funkcjonalność
widoku w naszej prostej aplikacji zrealizowanej zgodnie
z wzorcem MVC. Na początek prosty szablon, w którym będziemy modyfikować niektóre
fragmenty kodu. Wykorzystamy język php i polecenia
echo lub print.
Szablon w HTML. Tworzymy plik hello.tpl i umieszczamy w katalogu template.
W kolejnym punkcie zadania opracujemy klasę do obsługi wykorzystywanych
w projekcie szablonów. Klasa ta będzie wykorzystywana w naszym projekcie "Simple MVC"
do obsługi widoku. Klasę View zapisujemy w pliku View.php i umieszczamy w katalogu appl.
<?php
include 'appl/View.php' ;
use appl\View ;
$view = new view('hello');
$view->title = 'Simple MVC' ;
$view->header = 'Test template' ;
$view->content = '<p>Hello, World</p>' ;
echo $view ;
?>
Kontroler naszej aplikacji
Zadaniem kontrolera jest odbiór żądań klienta i odpowiednia ich obsługa.
W przypadku prostego żądania wystarczy pobrać odpowiedni szablon i wysłać odpowiedź
do klienta poprzez widok, w bardziej złożonej sytuacji, należy pobrać dane np. z bazy
danych i po przetworzeniu wysłać informację do klinta.
Ten element zadania najczęciej wykonuje w wzorcu MVC komponent modelu.
W ramach tego punktu opracujemy prosty kontroler
dla naszej aplikacji. Do sterowania wykorzystamy parametry przesyłane w
części QUERY_STRING adresu URL'u wywołania.
Schematycznie można to przedstawić następująco:
index.php?sub=zadanie&action=polecenie
gdzie poprzez zmienną sub wybierzemy zadanie, a poprzez action
wybierzemy odpowiednie polecenie.
W ramach naszego projektu kolejne funkcjonalności aplikacji będą umieszczane
w osobnych katalogach. Każda funkcjonalność będzie obsługiwana
przez swój kontroler, który będzie rozszerzał funkcjonalność głównego kontrolera.
Klasa głównego kontrolera Controller została umieszczona
w pliku Controller.php w katalogu appl.
Na początek opracujemy klasę kontrolera Test testującą poprawność naszego rozwiązania.
Klasa ta dziedziczy po klasie Controller. Odpowiedni skrypt umieścimy w katalogu test/ pod nazwą Test.php.
<?php
include 'appl/View.php' ;
include 'appl/Controller.php' ;
include 'test/Test.php' ;
use test\Test ;
$obj = new Test() ;
echo $obj->index() ;
?>
Komponent model i jego implementacja w projekcie
Na początek opracujemy prosty model dostarczający dane z zawartej w nim tabeli.
W kolejnym etapie zrealizujemy część aplikacji,
wyświetlającą dane zawarte w tabeli. Opracowane w ramach tego punktu skrypty
będą już fragmentem naszej docelowej aplikacji, będzie to część informacyjna.
Odpowiednie skrypty i klasy zostaną umieszczone w katalogu info.
Na początek tworzymy klasę modelu - Model i umieszczamy
ją w pliku Model.php w katalogu info/.
<?php
namespace info ;
use appl\ { View, Controller } ;
// use appl\Controller ;
class Info extends Controller {
protected $layout ;
protected $model ;
function __construct() {
parent::__construct();
$this->layout = new View('main') ;
$this->layout->css = $this->css ;
// $this->layout->css = "<link rel=\"stylesheet\" href=\"css/main.css\" type=\"text/css\" media=\"screen\" >" ;
$this->layout->menu = $this->menu ;
// $this->layout->menu = file_get_contents ('template/menu.tpl') ;
$this->layout->title = 'Simple MVC' ;
}
function index() {
$this->layout->header = 'Simple MVC' ;
$this->layout->content = 'Template - test !' ;
return $this->layout ;
}
function help() {
$this->model = new Model();
$this->layout->header = 'Simple MVC' ;
$this->view = new View('table') ;
$this->view->data = $this->model->getTable() ;
$this->layout->content = $this->view ;
return $this->layout ;
}
function error( $text ) {
$this->layout->content = $text ;
return $this->layout ;
}
}
?>
Tworząc widok wykorzystujemy szablony main.tpl i table.tpl. Szablon main.tpl
jest kopią szablonu hello.tpl natomiast zawartość szablonu table.tpl przedstawia poniższy skrypt.
Ostatnim elementem naszej aplikacji wymaganym do poprawnego działania jest przygotowanie
odpowiedniego pliku index.php. Przedstawiony poniżej plik zawiera funkcje __autoload()
oraz prostą logikę przetwarzającą żądanie przesłane przez klienta.
Do realizacji projektu wymagana jest baza danych. Przykładową bazę danych
utworzymy w katalogu sql nadając mu uprawnienia:
u+r+w+x g+r a+r+w+x. W katalogu tym utworzymy bazę danych baza.db wykorzystując
poniższy skrypt sql.
create table osoba ( imie char(20), nazwisko char(20), miejscowosc char(20) ) ;
insert into osoba ( imie, nazwisko, miejscowosc ) values ('Adam', 'Kowalski','Krakow');
insert into osoba ( imie, nazwisko, miejscowosc ) values ('Marek','Babacki','Zakopane') ;
insert into osoba ( imie, nazwisko, miejscowosc ) values ('Zofia','Cabacka','Warszawa') ;
insert into osoba ( imie, nazwisko, miejscowosc ) values ('Marta','Dadacka','Olsztyn') ;
insert into osoba ( imie, nazwisko, miejscowosc ) values ('Michal','Zawadzki','Katowice') ;
Polecenie budujące bazę danych - sqlite3 baza.db < baza.sql. Uprawnienia do pliku u+r+w g+r a+r+w.
Wydruk rekordów zawartych w bazie danych - klasa PDO
Do realizacji tego zadania wymagane jest opracowanie następujących skryptów:
skrypt modelu do obsługi bazy danych, skrypt kontrolera oraz pliku szablonu.
Na początek przedstawiona zostanie klasa Model zawierająca obsługę bazy danych.
Klasa ta została zawarta w pliku baza/Model.php.
<?php
namespace baza ;
use appl\ { View, Controller } ;
// use appl\Controller ;
class Baza extends Controller
{
protected $layout ;
protected $model ;
function __construct() {
parent::__construct();
$this->layout = new View('main') ;
$this->layout->css = $this->css ;
// $this->layout->css = "<link rel=\"stylesheet\" href=\"css/main.css\" type=\"text/css\" media=\"screen\" >" ;
$this->layout->title = 'Baza danych SQL' ;
$this->layout->menu = $this->menu ;
// $this->layout->menu = file_get_contents ('template/menu.tpl') ;
$this->model = new Model() ;
}
function listAll() {
$this->layout->header = 'Lista wszystkich rekordow' ;
$this->view = new View('listAll') ;
$this->view->data = $this->model->listAll() ;
$this->layout->content = $this->view ;
return $this->layout ;
}
function info ( $text ) {
$this->layout->content = $text ;
return $this->layout ;
}
function index () {
// $this->layout->content = $text ;
return $this->layout ;
}
}
?>
Wprowadzanie danych do bazy
Kolejnym elementem tworzonego serwisu będzie opracowanie formularza do wprowadzania danych.
W tym celu dodamy do klasy kontrolera dwie metody: pierwsza wywołuje formularz natomiast
druga zapisuje dane do bazy danych. Dodatkowo należy dodać metodę zapisującą dane do
bazy danych w modelu oraz na koniec opracować odpowiednie szalony.
Na początek dodajemy odpowiednie metody do klasy kontrolera (plik baza/class/Baza.php).
Wymagane są dwie metody: insertRec() - metoda wyświetlająca odpowiedni formularz
do wprowadzania danych oraz saveRec() - metoda umożliwiająca zapis danych do bazy danych.
Po uzupełnieniu metod klasa kontrolera została przedstawiona poniżej.
Plik zawierający klasę Baza (Baza.php) (po modyfikacji).
<?php
namespace baza ;
use appl\ { View, Controller } ;
// use appl\Controller ;
class Baza extends Controller
{
protected $layout ;
protected $model ;
function __construct() {
parent::__construct();
$this->layout = new View('main') ;
$this->layout->css = $this->css ;
// $this->layout->css = "<link rel=\"stylesheet\" href=\"css/main.css\" type=\"text/css\" media=\"screen\" >" ;
$this->layout->title = 'Baza danych SQL' ;
$this->layout->menu = $this->menu ;
// $this->layout->menu = file_get_contents ('template/menu.tpl') ;
$this->model = new Model() ;
}
function listAll() {
$this->layout->header = 'Lista wszystkich rekordow' ;
$this->view = new View('listAll') ;
$this->view->data = $this->model->listAll() ;
$this->layout->content = $this->view ;
return $this->layout ;
}
function insertRec() {
$this->layout->header = 'Wprowadzanie danych do bazy' ;
$this->view = new View('form') ;
$this->layout->content = $this->view ;
return $this->layout ;
}
function saveRec() {
$data = $_POST['data'] ;
$obj = json_decode($data) ;
if ( isset($obj->fname) and isset($obj->lname) and isset($obj->city) ) {
// echo "fn= ".$obj->fname." ln= ".$obj->lname." city= ".$obj->city ;
$response = $this->model->saveRec($obj) ;
}
return ( $response ? "Dodano rekord" : "Blad " ) ;
}
function info ( $text ) {
$this->layout->content = $text ;
return $this->layout ;
}
function index () {
// $this->layout->content = $text ;
return $this->layout ;
}
}
?>
Kolejnym etapem tego zadania jest modyfikacja komponentu modelu.
Do kodu modelu - klasa Model dodajemy metodę saveRec(). Po uzupełnieniu zawartość klasy
modelu przedstawiono poniżej.
<?php
namespace baza ;
use PDO ;
class Model
{
static $dsn = 'sqlite:sql/baza.db' ;
protected static $db ;
private $sth ;
function __construct()
{
$data = explode(':',self::$dsn) ;
if ( ! file_exists ( $data[1] ) ) { throw new Exception ( "Database file doesn't exist." ) ; }
self::$db = new PDO ( self::$dsn ) ;
self::$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION) ;
}
public function listAll()
{
$this->sth = self::$db->prepare('SELECT * FROM osoba') ;
$this->sth->execute() ;
$result = $this->sth->fetchAll() ;
return $result ;
}
public function saveRec($obj)
{
$this->sth = self::$db->prepare('INSERT INTO osoba VALUES ( :fname, :lname, :city) ') ;
$this->sth->bindValue(':fname',$obj->fname,PDO::PARAM_STR) ;
$this->sth->bindValue(':lname',$obj->lname,PDO::PARAM_STR) ;
$this->sth->bindValue(':city',$obj->city,PDO::PARAM_STR) ;
$resp = ( $this->sth->execute() ? 'true' : 'false' ) ;
return $resp ;
}
}
?>
Do zrealizowania tego zadania należy jeszcze opracować: szablon formularza (form.tpl)
oraz wysyłanie danych z przeglądarki z wykorzystaniem skryptów w JavaScript i technologii AJAX'a.
Na początek szablon formularza.
Skrypt w języku JavaScript realizujący funckjonalość zapisu do bazy danych
o nazwie baza.js umieszczamy w katalogu js. Należy również dodać odpowiedni wpis
w szablonie main.tpl: <script src="js/baza.js"></script>.
function fn_save()
{
var fname = document.getElementById("fname").value ;
var lname = document.getElementById("lname").value ;
var city = document.getElementById("city").value ;
document.getElementById("data").style.display = "none" ;
json_data = "{\"fname\":\"" + fname + "\",\"lname\":\"" + lname + "\",\"city\":\"" + city + "\"}" ;
var msg = "data=" + encodeURIComponent(json_data) ;
// alert ( '['+msg+']' ) ;
url = "index.php?sub=Baza&action=saveRec" ;
resp = function(response) {
document.getElementById("response").innerHTML = response ;
}
xmlhttpPost (url, msg, resp) ;
}
function xmlhttpPost(strURL, mess, respFunc) {
var xhr = new XMLHttpRequest();;
xhr.open('POST', strURL);
xhr.addEventListener("load", e => {
if ( xhr.status == 200 ) {
respFunc ( xhr.response ) ;
}
})
xhr.setRequestHeader("X-Requested-With","XMLHttpRequest");
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded; ");
xhr.send(mess);
}
Modyfikacja szablonu głównego
Na koniec zmodyfikujemy wygląd naszej prostej aplikacji. Przygotujemy plik
arkuszy styli baza.css, który umieścimy w katalogu css oraz przygotujemy plik
szablonu menu.tpl umożliwiający nawigację po opracowanej aplikacji.
Dodatkowo należy zmienić wpisy w kostruktorze klasy controller wprowadzając,
odpowiednie wskazania do opracowanych przez nas plików: baza.css i menu.tpl.
Poprawną modyfikację przedstawia poniższy fragment kodu.
W pliku szablonu main.tpl należy dodać wpisy umożliwiające podłączenie styli
i pliku z kodem JavaScript obsługującego wpisywanie danych do bazy danych.