Od czasu zamieszczenia reedycji "Piszemy engine 3" minęło zaledwie kilka minut, a ja już biorę się do pisania kolejnej :). Jak w poprzedniej wersji tego tekstu, chciałbym podziękować za znalezione w systemie szablonów błędy Wanksterowi. Mam nadzieję, iż inni też będą je wytrwale tropić.
W tym odcinku zajmiemy się dwoma kolejnymi elementami: interfejsem layoutów, oraz interfejsem do zarządzania stronami. Na początek dwie nowe tabelki do bazy MySQL:
CREATE TABLE pages (
page_id int(10) NOT NULL auto_increment,
page_file varchar(128) NOT NULL default '',
page_type tinyint(1) default NULL,
page_layout mediumint(8) default NULL,
PRIMARY KEY (page_id)
) TYPE=MyISAM;
INSERT INTO pages VALUES (1, 'strona1.php', 0, 1);
CREATE TABLE templates (
tpl_id mediumint(8) NOT NULL auto_increment,
tpl_dir varchar(128) default NULL,
PRIMARY KEY (tpl_id)
) TYPE=MyISAM;
INSERT INTO templates VALUES (1, 'z'); |
Stwórz dodatkowo nowy katalog w folderze "templates" - nazwij go po prostu "z". Będą tam pliki layoutu nazwanego "z" do silnika.
Na samym początku zajmiemy się dwoma potrzebnymi nam klasami SQL - "page" i "tpl_data". Pierwszą z nich ulokujemy w pliku "pages.php", a drugą w "tpl_data.php", a te z kolei w katalogu "engine". Oto kod:
<?php
class page extends table{
var $page_id;
var $page_file;
var $page_type;
var $page_layout;
function load_from_db($id){
$r = mysql_query('SELECT * FROM pages WHERE page_id = '.$id);
if($row = mysql_fetch_row($r)){
$this -> page_id = $row[0];
$this -> page_file = $row[1];
$this -> page_type = $row[2];
$this -> page_layout= $row[3];
}
}
function save_to_db(){
mysql_query('INSERT INTO pages (page_file, page_type, page_layout) VALUES(
\''.$this->page_file.'\',
\''.$this->page_type.'\',
\''.$this->page_layout.'\'
)');
return mysql_insert_id();
}
function delete_from_db($id){
mysql_query('DELETE FROM pages WHERE page_id = '.$id);
}
}
function load_page($id, $type){
$page = new page;
$r = mysql_query('SELECT * FROM pages WHERE page_id = '.$id.' AND page_type = '.$type);
if($row = mysql_fetch_row($r)){
$page -> page_id = $row[0];
$page -> page_file = $row[1];
$page -> page_type = $row[2];
$page -> page_layout= $row[3];
return $page;
}
return 0;
}
?> |
Klasy SQL raczej omawiać nie trzeba, natomiast należy się wyjaśnienie odnośnie funkcji "load_page". Otóż ma ona za zadanie utworzyć obiekt klasy SQL, lecz samodzielnie wprowadza do niego dane z powodu konieczności uwzględnienia w zapytaniu pola "page_type". Oznacza ono położenie strony. Jeśli jego wartość wynosi 0, strona jest publiczna, a jeśli 1, znajduje się w panelu administracyjnym. Funkcja ta ma więc za zadanie oszczędzić nam kłopotu w plikach index.php i admin.php, które strony te będą obsługiwać.
A oto klasa do obsługi layoutów. Jak w powyższym kodzie, tak i tu pominąłem część metod klasy SQL - dopiszesz je sobie sam, jeśli będą Ci potrzebne:
<?php
class tpl_data extends table{
var $tpl_id;
var $tpl_dir;
function load_from_db($id){
$r = mysql_query('SELECT * FROM templates WHERE tpl_id = '.$id);
if($row = mysql_fetch_row($r)){
$this -> tpl_id = $row[0];
$this -> tpl_dir = $row[1];
}
}
function save_to_db(){
mysql_query('INSERT INTO templates (tpl_dir) VALUES(\''.$this->tpl_dir.'\')');
return mysql_insert_id();
}
function delete_from_db($id){
mysql_query('DELETE FROM templates WHERE tpl_id = '.$id);
}
}
?> |
Zanim przedstawię dalszą część kodu, opiszę może, jak zamierzam obsługiwać strony. Otóż będą dwa pliki uruchomieniowe: index.php i admin.php. Aby uruchomić stronę, trzeba będzie podać im parametr "pid" z identyfikatorem cyfrowym strony. Plik uruchomieniowy spróbuje wczytać dane strony, po czym ustawi dla niej layout i uruchomi pliki generujące dane dla nagłówka i stopki (to w następnej części). Następnie wykona samą stronę, której zadaniem ostatecznie jest zwrócenie nazwy uchwytu, pod którym zawarła swój plik TPL. Uchwyt ten trafi do metody kończącej pracę jądra, tam zostanie przetworzony, a zawartość wyświetlona na ekran. Kod w tym miejscu będzie CZĘŚCIOWO zgodny z nadchodzącym PHP 5 - mianowicie jeśli posiadamy PHP 4, destruktor będzie wywoływany ręcznie. W przeciwnym wypadku PHP sam sobie go uruchomi i my nie będziemy musieli się tym nawet martwić.
Teraz do dzieła. Do klasy "z_engine" dodaj następujące metody:
function setup_tpl($id){
global $tpl;
$this -> template = new tpl_data;
$this -> template -> load_from_db($id);
$tpl -> set_root($this -> prefix.'templates/'.$this -> template -> tpl_dir);
}
function setup_page(&$page){
if(is_object($page)){
$this -> page = &$page;
return 1;
}
return 0;
}
function __destruct(){
global $tpl, $handle;
$tpl -> parse($handle);
echo $tpl -> compiled;
mysql_close();
} |
Pierwsza z metod ma za zadanie stworzyć interfejs layoutu, używając layoutu o podanym ID. Druga ustawia interfejs strony utworzony przez funkcję load_page(), a trzecia przetwarza wszystko i zamyka połączenie z bazą. Teraz zabierzmy się za plik "index.php" leżący bezpośrednio w katalogu z engine'm:
<?php
require('./engine/basic.php');
require('./engine/config.php');
require('./engine/templates.php');
require('./engine/z-engine.php');
require('./engine/tpl_data.php');
require('./engine/pages.php'); |
Na początku dołączamy wszystkie potrzebne pliki.
if($zengine -> setup_page(load_page($zengine -> input -> input['pid'], 0))){
$zengine -> setup_tpl($zengine -> page -> page_layout);
require('./sources/'.$zengine -> page -> page_file);
$handle = zengine_page();
}else{
echo 'Page not found<br/>';
} |
Te kod dołącza stronę i uruchamia ją. Każda strona musi mieć jedną funkcję: zengine_page(), w której będzie zawarty jej kod. Funkcja ta musi zwrócić nazwę uchwytu, pod którym zapisała swój plik TPL.
$testVer = intval(str_replace('.', '', '5.0.0'));
$curVer = intval(str_replace('.', '', phpversion()));
if($curVer < $testVer){
$zengine -> __destruct();
}
?> |
Kod ten porównuje wersje PHP, po czym w zależności od posiadanej, albo uruchamia destruktor obiektu $zengine ręcznie, albo zostawia to samemu PHP.
Teraz przedstawię kod TPL dla pierwszej strony testowej: index.tpl:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>{PAGE_TITLE}</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-2">
</head>
<body>
<center>Przykładowa strona testowa<br></center>
</body>
</html> |
I odpowiadający jej kod PHP (sources/strona1.php):
<?php
function zengine_page(){
global $tpl, $zengine;
$tpl -> set_filename('strona', 'page1.tpl');
$zengine -> set_page_title('Przykladowa strona Z-ENGINE');
return 'strona';
}
?> |
Skrypt jest gotowy do odpalenia: "http://localhost/~z-engine/index.php?pid=1".
I to w zasadzie... tyle! :) W następnym odcinku opiszę, na jakiej zasadzie działa system obsługi nagłówka i stopki strony, oraz interfejs generowania menu. Wtedy już engine nabierze sensownych kształtów.