Дочитал до строчки: «Данные мы получаем от GameBoss в виде XML фида, т.е. нам необходимо их разобрать и сохранить в базе.», и решил пойти альтернативным путём. XML — это уже база данных.
Конечно, для реализации подобного сайта база данных будет нужна в любом случае. Хотя-бы, для хранения аккаунтов пользователей. Но информацию об играх можно брать непосредственно из XML.
Пример надуманный, и на полноценный сайт не претендует. Так-же в статье не будет подробного рассмотрения XSLT ( и XPath). В статье я хочу показать лёгкость работы с XSLT на PHP.
Для работы с фидом я буду использовать XSLT.
В PHP5 по-умолчанию доступна поддержка XSLT. Класс для работы с ним называется XSLTProcessor. Если в подключённых модулях его нет (модуль xsl), то в консоле делаем следующее: sudo apt-get install php5-xsl (для Deb-based систем) , после чего рестартуем апач (sudo /etc/init.d/apache2 restart).
Под Windows нужно раскомментировать строчку «;extension=php_xsl.dll». Строчка может выглядеть немного по-другому, в зависимости от варианта установки PHP.
К сожалению, расширение базируется на libxml2, которая не поддерживает XSLT2.0. Но и на том спасибо.
Рассмотрим две страницы:
- Главная страница
- Страница игры
Каждая из страниц состоит из контролера (/*.php), который обрабатывает запрос, XSLT-документа (/*.xsl), который обрабатывает фид, и шаблона (/tpl/*.php).
Фид получаем по запросу вида http://gameboss.ru/x2.php?partner=[xxxxx]&limit=10000&genre=127&short=1&full=1&image=1,
где:
- partner — Ваш партнерский ID, выдаётся после регистрации
- limit — Требуемое количество игр в выдаче
- genre — битовая маска жанров (127 = все игры)
- short — если Вам нужно короткое описание игры
- full — если Вам нужно полное описание игры
- image — если Вам нужны скриншоты
Более подробно можно узнать на сайте партнерской программы.
Главная страница
Она же index.php
Сначала некоторые объявления и впомогательная функция для пейджера:
<?php
//Pager function
function pager($curr, $count, $className, $by, $order) {
$htm = "<ul class=\"$className\">";
for($i=1; $i<=$count; $i++) {
if ($i == $curr) {
$htm .= "<li>$i</li>";
} else {
$htm .= "<li><a href=\"?page=$i&by=$by&order=$order\">$i</a></li>";
}
}
return "$htm</ul>";
}
$feed = 'http://gameboss.ru/x2.php?partner=xxxxx&limit=10000&genre=127&short=1&full=1&image=1';
// Data-feed address
$file = 'games.xml';
//Cache
$gamePerPage = 9;
//Games per page
Далее мы кешируем наш фид:
clearstatcache(); //Clear file status cache
if (file_exists($file)) {
if (date("Ymd", filemtime($file)) < date("Ymd")) {
file_put_contents($file, file_get_contents($feed));
}
} else {
file_put_contents($file, file_get_contents($feed));
}
Суть в следующем: Если файл существует и дата последней модификации сегодняшняя, то используем этот файл, в противном случае обновляем его.
Дальше получаем из ГЕТа по-чём сортировать, как сортировать и номер страницы. Вычисляем позиции игр и подготавливаем наш XSLT-файл. Формируем стоку для сортировки и делаем замену по шаблону. О сортировке поговорим чуть-позже.
$by = !empty($_GET['by'])? $_GET['by']: 'RATE';
$order = !empty($_GET['order'])? $_GET['order']: 'descending';
$page = !empty($_GET['page'])? $_GET['page']: '1';
$from = $gamePerPage * ($page-1);
$to = $from + $gamePerPage;
$from += 1;
$sort_params = array(
'RATE' => '<xsl:sort select="RATE" order="'. $order .'" data-type="number"/>',
'NAME' => '<xsl:sort select="NAME" order="'. $order .'" data-type="text" lang="ru"/>'
);
$search = array("%%sort tag%%", "%%from%%", "%%to%%");
$replace = array($sort_params[$by], $from, $to);
$transformTemplate = str_replace($search, $replace, file_get_contents('index.xsl'));
загружаем фид и получаем количество игр и страниц:
//LOAD XML FILE
$games = new DOMDocument();
$games->load($file);
//Get count of games and calculate count of pages
$gameCount = $games->getElementsByTagName('count')->item(0)->nodeValue;
$pageCount = ceil($gameCount/$gamePerPage);
Инициируем XSLT процессор, загружаем xsl-документ и отдаём результат в браузер:
//START XSLT
$xslt = new XSLTProcessor();
$XSL = new DOMDocument();
$XSL->loadXML($transformTemplate, LIBXML_NOCDATA);
$xslt->importStylesheet($XSL);
//PRINT
$list = $xslt->transformToXML($games);
$pager = pager($page, $pageCount, 'pager', $by, $order);
include('tpl/main.php');
Файл tpl/main.php содержит следующий шаблон:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>site.domain</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-type"/>
<link rel="stylesheet" type="text/css" href="css/reset.css" />
<link rel="stylesheet" type="text/css" href="css/main.css" />
</head>
<body>
<div id="header"></div>
<div class="sort">
Sort by: RATE (<a href="?page=<?php echo $page;?>&by=RATE&order=ascending">ASC</a> | <a href="?page=<?php echo $page;?>&by=RATE&order=descending">DESC</a>),
NAME (<a href="?page=<?php echo $page;?>&by=NAME&order=ascending">ASC</a> | <a href="?page=<?php echo $page;?>&by=NAME&order=descending">DESC</a>)
</div>
<div><?php echo $list;?></div>
<div class="pager-wraper"><?php echo $pager;?></div>
<div id="footer"></div>
</body>
</html>
Теперь поговорим об XSLT.
XSLT (Extensible Stylesheet Language Transformations) — это декларативный язык преобразования документов. В версии 1.0 преобразовывать можно только из XML. Часто выходным форматом является XML или HTML, но в принципе ограничений на выходной формат нет. XSLT использует XPath для для выбора частей исходного XML-документа. Подробно эти два языка здесь рассматриваться не будут.
Теперь рассмотрим файл index.xsl:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- template for root -->
<xsl:template match="/">
<ul class="list">
<xsl:for-each select="response/result/ITEM">
<!-- put xsl:sort tag here -->
%%sort tag%%
<!-- set limit -->
<xsl:if test="(position() >= %%from%%) and (position() <= %%to%%)">
<li>
<!-- construct XML element -->
<xsl:element name="div">
<xsl:attribute name="class">gname</xsl:attribute>
<xsl:element name="a">
<xsl:attribute name="href">
game.php?game=<xsl:value-of select="position()"></xsl:value-of>
</xsl:attribute>
<xsl:value-of select="NAME"></xsl:value-of>
</xsl:element>
</xsl:element>
<xsl:element name="a">
<xsl:attribute name="href">
game.php?game=<xsl:value-of select="position()"></xsl:value-of>
</xsl:attribute>
<xsl:element name="img">
<xsl:attribute name="class">ss</xsl:attribute>
<xsl:attribute name="src">
<xsl:value-of select="MEDIUM_PIC"></xsl:value-of>
</xsl:attribute>
</xsl:element>
</xsl:element>
<xsl:element name="div">
<xsl:attribute name="class">grate</xsl:attribute>
rate: <xsl:value-of select="RATE"></xsl:value-of>
</xsl:element>
<xsl:element name="div">
<xsl:attribute name="class">gshort-descr</xsl:attribute>
<xsl:value-of select="SHORTDESCR"></xsl:value-of>
</xsl:element>
<xsl:element name="div">
<xsl:attribute name="class">down-link</xsl:attribute>
<xsl:element name="a">
<xsl:attribute name="href">
<xsl:value-of select="DOWNLOAD_LINK"></xsl:value-of>
</xsl:attribute>
DOWNLOAD
</xsl:element>
</xsl:element>
</li>
</xsl:if>
</xsl:for-each>
</ul>
</xsl:template>
</xsl:stylesheet>
Во время обхода дерева XML XSLT-процессор применяет шаблоны преобразований к найденным тегам. У нас существует только один шаблон корня документа. В этом шаблоне мы формируем HTML-код ненумерованного списка из нашего документа. В цикле (<xsl:for-each select=«response/result/ITEM»>) перебираем все элементы, удовлетворяющие запросу «response/result/ITEM». Используя XSLT2.0-процессор мы могли-бы избавиться от вложенного тега <xsl:if/>, составив запрос следующим образом: response/result/ITEM[position() = n to m].
Далее мы определяем критерии сортировки списков узлов. Элемент <xsl:sort/> имеет несколько атрибутов. Атрибут select определяет ключ сортировки для узла (элемента). Проводя аналогию с SQL, узел можно сравнить с таблицей, а ключ сортировки с полем этой таблицы в выражении ORDER BY. Атрибут order определяет порядок сортировки, и может принимать два значения: «ascending» и «descending». Атрибут data-type указывает тип ключа сортировки. Может принимать следующие значения: «text», «number» и QName. С первыми двумя всё должно быть понятно. Тип QName — это тип расширенного имени. Используется для работы с типами данных схем XML.
С помощью тега <xsl:if/> мы реализуем педжинацию. Если позиция узла находится между %%from%% и %%to%%, мы обрабатываем этот узел, иначе — просто пропускаем его. Это можно сравнить с выражением LIMIT в SQL-запросе. Нужные нам узлы мы трансформируем в HTML. Название тега <xsl:element/> Должно говорить само за себя. Он конструирует произвольный XML-тег. Тег <xsl:value-of/> вставляет значение выбранного узла в виде текста. Значением атрибута select всё так-же является выражение XPath.
Страница игры
Она же game.php.
По сравнению с index.php, здесь всё совсем просто:
<?php
$file = 'games.xml';
//Cache
$game = !empty($_GET['game'])? $_GET['game']: '1';
//Position of game
$transformTemplate = str_replace('%%game position%%', $game, file_get_contents('game.xsl'));
//LOAD XML FILE
$games = new DOMDocument();
$games->load($file);
//START XSLT
$xslt = new XSLTProcessor();
$XSL = new DOMDocument();
$XSL->loadXML($transformTemplate, LIBXML_NOCDATA);
$xslt->importStylesheet($XSL);
//PRINT
$info = $xslt->transformToXML($games);
include('tpl/game.php');
Файл tpl/game.php содержит следующий шаблон:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-type"/>
<link rel="stylesheet" type="text/css" href="css/reset.css" />
<link rel="stylesheet" type="text/css" href="css/main.css" />
<link rel="stylesheet" type="text/css" href="css/ui/jquery-ui-1.7.2.custom.css" />
<script type="text/javascript" src="js/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="js/jquery-ui-1.7.2.custom.min.js"></script>
<script type="text/javascript" src="js/game.js"></script>
</head>
<body>
<div id="header"></div>
<div class="game"><?php echo $info;?></div>
<div id="footer"></div>
<div id="popup">
<a id="dialogClose" href="#" class="ui-corner-all" role="button" unselectable="on" style="-moz-user-select: none;">
<span class="ui-icon ui-icon-closethick" unselectable="on" style="-moz-user-select: none;">close
</a>
<div id="showImg">
</div>
</div>
</body>
</html>
Джаваскрипт подключается для полноразмерных скриншотов.
Файл game.xsl не сложнее index.xsl:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="result1">
<xsl:apply-templates select="ITEM"/>
</xsl:template>
<!-- put position of game here -->
<xsl:template match="ITEM[%%game position%%]">
<h1>
<xsl:value-of select="NAME"></xsl:value-of>
</h1>
<xsl:element name="div">
<xsl:attribute name="class">game-prop</xsl:attribute>
Rate: <xsl:value-of select="RATE"></xsl:value-of> <br/>
Added: <xsl:value-of select="ADDED"></xsl:value-of> <br/>
Size: <xsl:value-of select="SIZE"></xsl:value-of> <br/>
</xsl:element>
<xsl:element name="img">
<xsl:attribute name="class">game-img</xsl:attribute>
<xsl:attribute name="src">
<xsl:value-of select="MEDIUM_PIC"></xsl:value-of>
</xsl:attribute>
</xsl:element>
<xsl:element name="div">
<xsl:attribute name="class">game-descr</xsl:attribute>
<xsl:value-of select="FULLDESCR"></xsl:value-of>
</xsl:element>
<xsl:element name="div">
<xsl:attribute name="class">screens-text</xsl:attribute>
СКИНШОТЫ:
</xsl:element>
<ul id="screens" class="screens">
<xsl:for-each select="SCREENSHOT">
<li>
<xsl:element name="img">
<xsl:attribute name="class">full</xsl:attribute>
<xsl:attribute name="src">
<xsl:value-of select="IMAGE"></xsl:value-of>
</xsl:attribute>
</xsl:element>
<xsl:element name="img">
<xsl:attribute name="class">thumbs</xsl:attribute>
<xsl:attribute name="src">
<xsl:value-of select="THUMBNAIL"></xsl:value-of>
</xsl:attribute>
</xsl:element>
</li>
</xsl:for-each>
</ul>
<xsl:element name="div">
<xsl:attribute name="class">down-link</xsl:attribute>
<xsl:element name="a">
<xsl:attribute name="href">
<xsl:value-of select="DOWNLOAD_LINK"></xsl:value-of>
</xsl:attribute>
DOWNLOAD
</xsl:element>
</xsl:element>
</xsl:template>
<xsl:template match="ITEM"></xsl:template>
<xsl:template match="count"></xsl:template>
</xsl:stylesheet>
Сылки: