PHP/Studium przypadku/System newsów

< PHP
Poprzedni rozdział: phpMyAdmin
Następny rozdział: Bazy danych - Co dalej?

System newsów edytuj

Spróbujmy teraz zaimplementować zdobytą przez nas wiedzę w praktyce. Napiszemy prosty system newsów z podziałem na kategorie i możliwością dodawania komentarzy. Podręcznik ten pokaże, jak zacząć, natomiast twoim zadaniem będzie dopisanie (z pomocą wskazówek) wszystkich dodatków niezbędnych do tego, aby system był w pełni funkcjonalny. Nowością w porównaniu do księgi gości będzie to, iż nie będziemy już umieszczać kodu HTML bezpośrednio we właściwym pliku, lecz umieścimy go jako zbiór funkcji w osobnym. Dzięki temu poprawi się czytelność kodu, a ty poznasz zalety separacji tych dwóch elementów jeszcze przed przejściem do omawiania systemów szablonów.

Projekt bazy danych edytuj

System newsów oparty będzie o bazę danych MySQL, w której ulokujemy trzy tabelki. Będą one połączone ze sobą relacją jeden do wielu:

  1. Istnieje grupa kategorii
  2. Każda kategoria może zawierać dowolną liczbę newsów, ale pojedynczy news może należeć tylko do jednej z nich.
  3. Każdy news może zawierać dowolną ilość komentarzy.

Układ tabelek zostanie tak zoptymalizowany, aby jak najrzadziej zmuszać bazę do wykonywania funkcji COUNT() w celu zliczenia ilości wpisów.

Zacznijmy od tabeli kategorii:

CREATE TABLE `categories` (
  `id` int(11) NOT NULL auto_increment,
  `title` varchar(40) NOT NULL,
  `description` varchar(255) NOT NULL,
  `news_num` int(11) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Oprócz typowych pól informacyjnych: title oraz description (tytuł i opis), mamy też pole news_num przechowujące aktualną liczbę newsów wewnątrz kategorii. Musimy pamiętać, aby nasz system poprawnie zmniejszał i zwiększał jego zawartość w trakcie edycji i wprowadzania nowych elementów do bazy.

Następne w kolejności są newsy:

CREATE TABLE `news` (
  `id` int(11) NOT NULL auto_increment,
  `title` varchar(128) NOT NULL,
  `body` text NOT NULL,
  `date` int(11) NOT NULL,
  `author` varchar(30) NOT NULL,
  `category_id` int(11) NOT NULL,
  `comment_num` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `category_id` (`category_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Tabela zaczyna się od pól informacyjnych. Z punktu widzenia projektanta bazy najistotniejsze są jednak dwa ostatnie. category_id przechowuje ID kategorii, do której należy news; w tym miejscu tworzymy naszą relację. comment_num działa na podobnej zasadzie, jak w kategoriach. Dzięki temu nie trzeba będzie wykonywać skomplikowanych zapytań przy pobieraniu listy newsów, aby pokazać tam jednocześnie ilość komentarzy.

Na samym końcu zapoznamy się z tabelą komentarzy:

CREATE TABLE `comments` (
  `id` int(11) NOT NULL auto_increment,
  `news_id` int(11) NOT NULL,
  `author` varchar(30) NOT NULL,
  `date` int(11) NOT NULL,
  `body` text NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `news_id` (`news_id`,`date`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Zwróć uwagę, w jaki sposób założony jest podwójny indeks na pola news_id oraz date. Gdyby utworzyć tutaj dwa osobne indeksy, w zasadzie nic byśmy nie uzyskali. Popatrzmy na to tak: nigdy nie wyświetlamy wszystkich komentarzy, jakie mamy w bazie. Zawsze są one powiązane z jakimś konkretnym newsem, dlatego tak istotne jest odzwierciedlenie tego w strukturze indeksów. Przy osobnych indeksach pole date zostanie posortowane globalnie, a wybierając komentarze tylko dla pojedynczego newsa, system DB i tak będzie musiał przeskanować całą tabelę, aby je względem tejże daty wybrać.

Od strony bazy danych to tyle. Przejdźmy do kodowania.

Funkcje podstawowe edytuj

Napiszemy teraz plik functions.php. Umieścimy w nim różne podstawowe funkcje. W tej chwili jest ich stosunkowo niewiele: łączenie się z bazą, kontrola długości wprowadzonego tekstu, prymitywne zabezpieczenie przed floodem. Plik ten przyda Ci się jednak podczas samodzielnej rozbudowy; prawdopodobnie rozrośnie się wtedy znacznie. Jego zawartość wygląda następująco:

<?php

	function initSystem()
	{
		global $sql;
		
		$sql = new pdo('host=localhost;port=3305;dbname=artykuly', 'root', 'root');
		$sql -> exec('SET NAMES `utf8`');
		
		ob_start();
	} // end initSystem();
	
	function doneSystem()
	{
		ob_end_flush();
	} // end doneSystem();
	
	function commentsAllowed()
	{
		if(isset($_COOKIE['a84skljf']))
		{
			return false;		
		}
		setcookie('a84skljf', 1, time() + 3600);
		return true;	
	} // end commentsAllowed();
	
	function validTextField($text, $min, $max)
	{
		if(strlen($text) > $min && strlen($text) < $max)
		{
			return true;
		}
		return false;	
	} // end validTextField();

?>

Opis poszczególnych funkcji:

  1. initSystem() - inicjacja systemu; nawiązuje połączenie z bazą danych i włącza buforowanie wyjścia.
  2. doneSystem() - aktualnie tylko kończy buforowanie wyjścia. Być może znajdziesz dla niej jakieś ciekawe dodatkowe zastosowania.
  3. commentsAllowed() - funkcja zwraca true, jeżeli internauta ma prawo dodawać komentarze i false, jeżeli już takowy niedawno dodał.
  4. validTextField() - prosta funkcja do kontroli danych. Zwraca true, jeżeli długość tekstu mieści się w podanym zakresie.

DAO edytuj

Kod HTML edytuj

Składamy system w całość edytuj

Ćwiczenia edytuj

Zakończenie edytuj