PHP/Studium przypadku/System newsów
System newsów
edytujSpró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
edytujSystem 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:
- Istnieje grupa kategorii
- Każda kategoria może zawierać dowolną liczbę newsów, ale pojedynczy news może należeć tylko do jednej z nich.
- 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
edytujNapiszemy 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:
- initSystem() - inicjacja systemu; nawiązuje połączenie z bazą danych i włącza buforowanie wyjścia.
- doneSystem() - aktualnie tylko kończy buforowanie wyjścia. Być może znajdziesz dla niej jakieś ciekawe dodatkowe zastosowania.
- commentsAllowed() - funkcja zwraca true, jeżeli internauta ma prawo dodawać komentarze i false, jeżeli już takowy niedawno dodał.
- validTextField() - prosta funkcja do kontroli danych. Zwraca true, jeżeli długość tekstu mieści się w podanym zakresie.