AJAX a knižnica článkov s fulltextovým vyhľadávaním – práca s článkami

27. dubna 2007

V tomto článku bude uvedený popis súborov, ktoré umožňujú zobrazenie článkov podľa parametrov nastavených vo vstupnom formulári v úvodnej stránke.

Súbor clanky.class.php

K zlepšeniu funkcionality systému bola vytvorená trieda Clanky. V triede Clanky sú atribúty polí (premenné) typu public a private, metódy (funkcie), konštruktor a deštruktor. Trieda Clanky slúži ostatným súborom na vytváranie a spracovanie výsledkov databázy. Oddelenie vytvárania vrstiev funkcionality aplikácie umožňuje flexibilné a rozšíriteľné aplikácie.

<?php
// zavedie súbor pre ošetrenie chýb a konfiguračný súbor
require_once(‚error.php‘);
require_once(‚config.php‘);
// definuje triedu Clanky
class Clanky {
  // premenná pre požiadavku SQL
  public $mQuery;
  // premenná určujúca stĺpce pre match
  public $mCol;
  // ovládač dátabaze
  private $mMysqli;
  // konštruktor triedy
  function __construct() {
    $this->mMysqli = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_DATABASE);
  }
  // deštruktor triedy
  function __destruct() {
    if ($this->mMysqli) $this->mMysqli->close();
  }
  // funkcia pre spracovanie fulltextového vyhľadávania
  public function createFullText($query, $col,$whole) {
    // zakódovanie dát pre ich bezpečné použitie v príkazoch SQL
    $query = $this->mMysqli->real_escape_string(trim($query));
    $col = $this->mMysqli->real_escape_string($col);
    $whole = $this->mMysqli->real_escape_string($whole);
    // zadefinovanie stĺpcov pre match vo fulltextovom vyhľadávaní
    $this->mCol = $col == ‚autori‘ ? $col : $col.‘,nazov‘;
    // zostavenie požiadavky pre SQL
    switch ($col){
      case ‚autori‘:
      $query = ereg_replace(quotemeta(„+|-|*|~|\\|\“|<|>|(|)“),““,$query);
      $this->mQuery = ‚“‚.$query.'“‚;
      break;
      case ‚abstrakt‘:
      $words = explode(‚ ‚,$query);
      for ($i=0;$i<count($words);$i++) if (Strlen($words[$i])>3 && !$whole) $words[$i] .= ‚*‘;
        $this->mQuery = implode(‚ ‚,$words);
        break;
      }
    }
    // vráti počet článkov
    public function getNumRows ($query) {
      if ($result = $this->getQuery($query)) {
        $numRows = $result->num_rows;
        $result->close();
      }
      return $numRows;
    }
    // vráti celkový počet článkov pri SELECT COUNT(*)
    public function getNumAllRows ($query) {
      if ($result = $this->getQuery($query)) {
        $row = $result->fetch_row();
        $result->close();
      }
      return $row[0];
    }
    // vráti obsah riadku
    public function getRow ($query) {
      if ($result = $this->getQuery($query)) {
        $row = $result->fetch_array(MYSQLI_ASSOC);
        $result->close();
      }
      return $row;
    }
    // vráti príkaz SQL
    public function getQuery($query) {
      return $this->mMysqli->query($query);
    }
  }
}
?>

Pri tvorbe databázy používame objektove orientovanú knižnicu mysqli, ktorá bola implementovaná v PHP 5. Pomocou konštruktora __construct sa vytvára inštancia triedy a automaticky vytvára spojenie na databázu. Deštruktor __destruct sa volá po zániku objektu a tým sa uzatvára databázové spojenie. Pre vysvetlenie činnosti fulltextového vyhľadávania odporúčame preštudovať si článok Erika Hoffmanna Fulltextové vyhľadávanie v MySQL – prax.

Súbor clanky-top.php

Súbor clanky-top.php sa načíta v súbore clanky.php a pomocou globálnych premenných $_POST, respektíve $_GET, nastavuje $_SESSION. Následne inicializuje premenné $_question, $_col, $_whole, $_lim a $_skip použité v súbore clanky.php.

<?php
// zavedie súbor pre ošetrenie chýb a pre triedu Clanky
require_once(‚error.php‘);
require_once(‚clanky.class.php‘);
// štart session
session_start();
// nastaví session podľa $_POST a $_GET
if (isset($_POST[‚q‘])) {
  $_SESSION[‚values‘][‚s_query‘] = $_POST[‚q‘];
  if (isset($_POST[‚whole‘])) $_SESSION[‚values‘][‚s_whole‘] = ‚yes‘; else $_SESSION[‚values‘][‚s_whole‘] = “;
  if (isset($_POST[‚col‘])) $_SESSION[‚values‘][‚s_col‘] = $_POST[‚col‘];
}
if (isset($_GET[‚skip‘])) $_SESSION[‚values‘][‚s_skip‘] = sprintf(„%d“, $_GET[‚skip‘]);
// nastavi premenne pre subor clanky.php
$_query = $_SESSION[‚values‘][‚s_query‘]; $_col = $_SESSION[‚values‘][‚s_col‘];
$_skip = $_SESSION[‚values‘][‚s_skip‘]; $num = $_SESSION[‚values‘][‚s_num‘];
$_whole = $_SESSION[‚values‘][‚s_whole‘]; $lim = ROWS_PER_VIEW;
?>

Súbor clanky.php

Súbor clanky.php je vyvolaný klasicky kliknutím na button „Články“ vo vstupnom formulári úvodnej stránky. Metódou POST sú odovzdané parametre formulára a zobrazia sa nájdené články v databáze. Počet zobrazených článkov je nastavený v súbore config.php. V prípade väčšieho počtu článkov ako je nastavený počet zobrazených článkov, môžeme pomocou príkazov v spodnom riadku zobrazovať nasledujúce stránky s článkami. Súčasne s XHTML kódom stránky sa načítavajú súbory clanky.css a abstrakt.js.

<?php
// zavedie súbory pre ošetrenie chyb a clanky_top.php.
require_once(‚error.php‘);
require_once(‚clanky_top.php‘);
echo ‚<?xml version=“1.0″ encoding=“utf-8″ ?>‘.“\n“;
?>
<!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“ xml:lang=“sk“ lang=“sk“>
<head>
<meta http-equiv=“Content-Type“ content=“text/html; charset=utf-8″ />
<meta http-equiv=“Content-Language“ content=“sk“/>
<title>Knižnica–Články</title>
<link rel=“stylesheet“ type=“text/css“ href=“clanky.css“ />
<script type=“text/javascript“ src=“request.js“></script>
<script type=“text/javascript“ src=“abstrakt.js“></script>
</head>
<body>
<h1>Knižnica článkov</h1>
<div id=“wrap“>
<h2>Články</h2>
<?php
// vytvorí inštanciu triedy Clanky
$_sql = new Clanky();
// spracuje premenné pre fulltextové vyhľadávanie
$_sql->createFullText($_query, $_col, $_whole);
$query = „SELECT *“;
// vytovorí SQL pre zobrazenie všetkých článkov
if ($_query == ‚?‘) {
  $num = $_SESSION[‚values‘][‚s_count‘];
  $query .= “ FROM clanky“;
}
// vytvorí SQL pre zobrazenie článkov pre fulltextové vyhľadávanie, min. tri znaky
elseif (StrLen(trim($_query)) > 3) {
  if ($_col != ‚autori‘) $query .= „,MATCH($_sql->mCol) AGAINST(‚$_sql->mQuery‘ IN BOOLEAN MODE) AS vaha“;
  $query .= “ FROM clanky WHERE MATCH($_sql->mCol) AGAINST(‚$_sql->mQuery‘ IN BOOLEAN MODE)“;
  // poradie pri fulltextovom vyhľadávaní je určené váhou
  if ($_col != ‚autori‘) $query .= “ ORDER BY vaha DESC“; else $query .= “ ORDER BY nazov ASC“;
  // zobrazenie mena autora alebo kľúčových slov
  if ($_col != ‚autori‘) echo ‚<p>Kľúčové slová: ‚; else echo ‚Autor: ‚;
  echo ‚<i>‘.htmlspecialchars($_query).'</i></p>‘;
  // ak počet riadov nebol načítaní v JS
  if ($num == -1) $num = $_sql->getNumRows($query);
  // ošetrenie chýb
  if ($num == 0) echo ‚<p>Ľutujeme, ale nenašiel sa žiaden článok!</p>‘;
}
else echo ‚<p>Ľutujeme, ale nezadali ste meno autora alebo kľúčové slová (minimálne štyri znaky)!</p>‘;
if ($num > 0) {
  echo ‚<p id=“top“>Počet článkov: <b>‘.$num.'</b>‘;
  if (trim($_query) != ‚?‘) echo ‚ z ‚.$_SESSION[‚values‘][‚s_count‘];
  if ($num > $lim) echo ‚ <span>Stránka: <b>‘.sprintf(„%d“,($_skip/$lim+1)).'</b> (‚.sprintf(„%d“, ($num-1)/$lim+1).‘)</span>‘;
  echo ‚</p> <ul>‘;
  $query .= “ LIMIT $_skip, $lim“;
  // vykoná SQL požiadavku
  if ($result = $_sql->getQuery($query)) {
  while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
    // tvorba zoznamu článkov
    echo ‚<li><span><a href=“abstrakt.php?id=‘.$row[„ID“].'“ title=“Abstrakt-html“><img src=“icon_html.png“ alt=“Abstrakt-html“ /></a><a href=“‚.$row[„clanok“].'“ title=“Článok-pdf“><img src=“icon_pdf.png“ alt=“Článok-pdf“ /></a></span>‘.$row[„autori“].‘: <em>‘.$row[„nazov“].‘, </em>‘.$row[„kde“].'<div /></li>‘;
    echo ‚</ul>‘.“\n“;
    $result->close();
  }
}
else echo ‚<p>Ľutujeme, ale sa nepodarilo pripojiť na server, pokúste sa opäť!</p>‘;
// tvorba foot
echo ‚<p class=“foot“>‘;
if ($num>$_skip && $_skip>=$lim) echo ‚<a href=“clanky.php?skip=‘.($_skip – $lim).'“>predchádzajúca stránka</a>‘;
echo ‚ <a href=“./“>úvodná stránka</a> ‚;
if ($num>$_skip+$lim) echo ‚<a href=“clanky.php?skip=‘.($_skip + $lim).'“>nasledujúca stránka</a>‘;
echo ‚</p>‘.“\n“;
?>
</div>
</body>
</html>

Súbor abstrakt.js

Pomocou JavaScriptu a objektu XMLHttpRequest môžeme načítať – bez opätovného načítania stránky – obsah vybraného abstraktu kliknutím na príslušnú ikonku. Súbor abstrakt.js spolupracuje so súborom abstrakt.php. V prípade asynchrónneho spojenia okrem parametra id článku posielame metódou GET aj parameter xml=1.

//spustí po načítaní stránky
window.onload = function() {
  // vytvorí odkazy na <li>
  var lis = document.getElementsByTagName(‚li‘);
  // pri stlačení ikonky abstraktu definuje odkaz
  for (var i=0; i<lis.length; i++) {
    lis[i].getElementsByTagName(‚a‘)[0].onclick = function() {
      // vytvorí inštanciu objektu XMLHttpRequest
      var request = requestObj ();
      // vytvorí odkaz na element <div>
      var div = this.parentNode.parentNode.lastChild;
      // pri kliknutí sa obsah abstraktu schová
      div.onclick = function () {this.innerHTML = „“; this.className = „“;}
      // ak je objekt XMLHttpRequest
      if(request) {
        // metóda pre spracovanie odpovede zo servera
        request.onreadystatechange = function() {
        // ak prebehlo všetko v poriadku
        if (request.readyState == 4) {
          if (request.status == 200) {
            try {
              // extrahuj XML zo servera
              var rootXML = request.responseXML.documentElement;
              // ošetrenie chyby pre Firefox
              if (rootXML.nodeName == „parsererror“) throw(„“);
              // načítanie dát do elementu <div>
              else div.innerHTML = rootXML.firstChild.data;
            }
            // sprava pre uzivatela v pripade chyby servera
            catch (e) {div.innerHTML = „Ľutujeme, nepodarilo sa pripojiť na server, pokúste sa opäť!“;}
          } else {div.innerHTML = „Ľutujeme, nepodaril sa prenos zo servera, pokúste sa opäť!“}
        }
      }
      // zobraz obsah abstraktu
      div.className = „show“;
      // správa pre prípad pomalého Internetu
      if (div.innerHTML == „“) div.innerHTML = „<b>Abstrakt</b> sa načítáva…“;
      // na serveri spusti stránku abstrakt.php s parametrami id a xml
      request.open(„GET“, this.href+“&xml=1″, true);
      // pošle žiadosľ na server
      request.send(null);
    }
    // v prípade neúspechu vráti true a vykoná sa pôvodný odkaz v HTML
    else {return true;}
    // v prípade úspešného načítania abstraktu vráti false
    return false;
    }
  }
}

Každý článok používa vlastný objekt XMLHttpRequest. Toto najjednoduchšie riešenie zabezpečuje, že nedôjde k strate požiadavky na server. Pri spracovaní odozvy sa postupuje štandardným spôsobom. Chyby sa vychytávajú pomocou metódy try/catch v prehliadačoch MSIE a Opera. Firefox generuje hlásenie o chybe v koreni súboru XML, ktorý nazýva „parsererror“. V prípade Firefoxu vygeneruje sa pomocou throw výnimka, ktorá sa zachytí ako u ostatných prehliadačoch v catch. V prípade korektnej odozvy servera sa obsah abstraktu načíta do kontajnera div pomocou innerHTML. V prípade pomalého pripojenia k internetu sa objavuje správa, že sa súbor načítáva.

Súbor abstrakt.php

Súbor abstrakt.php v úvode načíta súbor clanky.class.php pre načítanie obsahu abstraktu z databázy. Súbor spracúva požiadavky generované JavaScriptom. V prípade, ak prehliadač nemá implementovaný objekt XMLHttpRequest alebo je zakázaný JavaScript, súbor abstrakt.php je volaný odkazom priamo zo stránky clanky.php. V prvom prípade je generovaný súbor typu XML, v druhom prípade súbor typu XHTML, ktorý je zobrazený samostatne v okne prehliadača.

<?php
// zavedie súbory pre ošetrenie chýb a triedy Clanky
require_once(‚error.php‘);
require_once (‚clanky.class.php‘);
// štart session
session_start();
// nastavenie premených podľa $_GET
if (isset($_GET[‚id‘])) $user_id = $_GET[‚id‘]; else $user_id = 0;
if (isset($_GET[‚xml‘])) $user_xml = $_GET[‚xml‘]; else $user_xml = 0;
// vytvorí inštanciu triedy Clanky
$_sql = new Clanky();
// tvorba SQL príkazu
$query = sprintf(„SELECT autori,nazov,abstrakt FROM clanky WHERE ID = %d“, $user_id);
// vykoná prikaz SQL
$row = $_sql->getRow ($query);
// ak požiadavka je cez AJAX, tvorba XML súboru
if ($user_xml==1) {
  header(‚content-type: text/xml‘);
  echo ‚<?xml version=“1.0″ encoding=“utf-8″ ?><abstrakt><![CDATA[‚.$row[„abstrakt“].‘]]></abstrakt>‘;
}
// inak tvorba XHTML súboru
else {
  // . . . . . .
  // generuje sa XHTML abstraktu
  // . . . . . . . . . .
}
?>

V prípade vytvorenia súboru XHTML sa súčasne načíta aj abstrakt.css, ktorý určuje vzhľad stránky.

Súbor o_kniznici.html

Klasický statický hypertextový súbor slúži ako zdroj informácii o použití knižnice. Súčasne sa načíta aj súbor o_kniznici.css, ktorý určuje vzhľad stránky.

Záver

Klasické statické stránky sa stávajú minulosťou. V súčasnosti sa dostávajú do popredia interaktívne stránky, využívajúce PHP script na strane servera a JavaScript spojený s objektom XMLHttpRequest na strane klienta. Internetové aplikácie sa svojím správaním približujú desktopovým aplikáciám, ale ich realizácia býva spravidla jednoduchšia. Klasické statické stránky sa používajú najmä ako informačné stránky.

Předchozí článek Pracovní režimy prohlížečů
Další článek webovy-servis.cz
Štítky: Články

Mohlo by vás také zajímat

Nejnovější

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *