Transformácia kódu do OOP
Úvodné slová k objektovo orientovanému programovaniu máme za sebou. Povedali sme si, čo to je a ako to vyzerá a taktiež sme si názorne ukázali na triede pre databázu, ako sa triedy objektov vytvárajú a ako sa použijú v praxi. Trieda pre databázu je pre nás plne funkčná a dostatočná a obsahuje základ toho, čo OOP predsatvuje. Všetko čo súvisí s pripojením do databázy sa viaže na daný objekt a kód vyzerá približne tak, ako by mal kód OOP vyzerať.
Transformácia kódu pre pripojenie do databázy na OOP nezabrala veľa času a námahy a ani neobsahuje veľa riadkov. Taktiež to bolo také skôr jednorázové použitie, pretože teoreticky nám na celý program (informačný systém) stačí jeden objekt tejto triedy. Triedy objektov sa ale vo väčšine vytvárajú na mnohonásobné použitie objektov, resp. v kóde sa nachádza množstvo inštancií tried. Aby sme sa teda tomu povenovali troška viac a ešte si to vyskúšali, prerobíme si ešte nejakú časť kódu zo súboru index.php na OOP tým, že si zadefinujeme triedu, ktorej objekt (inštancia) bude predstavovať – reprezentovať jedného používateľa v našej databáze. Ak si trúfate, skúste si to sami, vytvorte si triedu s názvom User, skúste dať properties, ktoré vám bude treba a aj metódy, ktoré budú súvisieť s týmto objektom. Výsledok by mal byť taký, aby čo najviac kódu, ktorý súvisí s používateľom, sa nejako týkal objektu tejto triedy.
Pochopiteľne, nemusíte to hneď zvládnuť sami, ideme si to teraz postupne spolu prejsť. Ako vieme, prioritne na našej domovskej stránke zobrazujeme zoznam používateľov tabuľkovou formou v spodnej časti stránky. Okrem toho je možné pomocou tejto stránky používateľov pridávať, meniť, mazať a vyhľadávať. Začneme teda tým, že na výpis používateľov využijeme nami vytvorenú triedu pre jedného používateľa. Ako to teda bude vyzerať?
Začneme vytvorením triedy pre definovanie jedného používateľa, ktorý sa zobrazuje v tabuľke na jedom riadku. V tabuľke prioritne iba zobrazujeme základné údaje z databázy, takže jednotlivé stĺpce by mohli predstavovať properties našej triedy. Metódy zatiaľ nepotrebujeme, budeme iba potrebovať konštruktor, podobne ako pri databáze. Mohlo by to vyzerať takto:
index.php (zadefinovanie triedy User za definovanie triedy Databaza):
//TRIEDA USER (pouzivatel v tabulke users)
class User{
public $id = 0;
public $user_name = '';
public $user_surname = '';
public $age = 0;
public $role = '';
function __construct($id, $user_name, $user_surname, $age, $role){
$this->id = $id;
$this->user_name = $user_name;
$this->user_surname = $user_surname;
$this->age = $age;
$this->role = $role;
}
}
Tento kód by pre nás nemal byť problém, možno ste sa ale zamysleli, načo nám bude alebo skôr, ako a kde ho zakomponovať. Čo robíme v kóde na začiatku časti pre zobrazenie tabuľky s používateľmi? Načítame si všetky dáta z databázy, ktoré si následne uložíme do premennej typu pole. Každý prvok tohto poľa je iba jednoduché pole, ktoré obsahuje dáta o používateľovi (tiež pole), ktoré si následne prechádzame a zobrazujeme do riadkov tabuľky. Podstata OOP je, aby sme nemali premenné, ktoré majú iba premenné a podobne alebo aby obsahovali iba nejaké hodnoty. Cieľ je pracovať s objektami, takže práve toto pole (výsledok SELECTu z DB) si celé prejdeme a pretransformujeme ho na pole objektov. Následne si podobne toto pole prejdeme a vypíšeme údaje do tabuľky, tentokrát ale budeme vypisovať už properties objektu User a nie iba hodnoty prvkov pola. Malo by to vyzerať takto:
index.php (úprava existujúceho kódu):
…
<?php
//VYPIS POUZIVATELOV DO TABULKY
if (mysqli_num_rows($result) > 0) {
$data = mysqli_fetch_all($result, MYSQLI_ASSOC);
$users = [];
//TRANSFORMACIA DAT NA POLE OBJEKTOV
foreach($data as $key => $value){
$users[$key] = new User($value['id'], $value['user_name'], $value['user_surname'], $value['age'], $value['role']);
}
echo '<table class="persons">';
…
for($i=0; $i<count($users); $i++){
echo '<tr>';
foreach($users[$i] as $index => $value){
echo '<td>'.$value.'</td>';
}
echo '<td>';
echo '<a href="uprava-zaznamu.php?id_user='.$users[$i]->id.'">Upraviť záznam</a><br><br>';
echo '<a href="index.php?id_user='.$users[$i]->id.'" onclick="return showConfirm()">Vymazať záznam</a>';
echo '</td>';
echo '</tr>';
}
echo '</table>';
…
Ako vidíte v ukážke, za načítanie dát z databázy sme si zadeklarovali nové pole s názvom users. Následne si pole data, ktoré obsahuje dáta z databázy, prechádzame cyklom foreach a pre každý prvok poľa data vkladáme do poľa users nový objekt triedy User. Takto získame nie pole polí, ale pole objektov triedy User. Následne sme upravili kód pre výpis riadkov a buniek tabuľky tak, že namiesto poľa data prechádzame pole users a taktiež sme museli zmeniť výpis url pri odkazoch na editáciu (z ['id'] na ->id). Ak si dáte vypísať pole users pomocou príkazu print_r, tak uvidíte, že každý prvok je objekt User (je to napísané namiesto array).
Keď sa pozrieme na kód tabuľky, tak vidíme, že s používateľom okrem výpisu v nej už nič nevykonávame, takže tu už viac zakomponovať tento objekt nemáme ako, takže by to malo byť v poriadku. Vráťme sa ale k tomu, ako sme si povedali, že zobrazujeme zoznam používateľov. Zoznam nám v tomto prípade reprezentuje premenná users a taktiež s ním vykonávame operáciu – načítanie dát z databázy. Vyššie od výpisu tabuľky máme niekoľko riadkov kódu, ktoré vykonávajú načítanie dát z databázy (skladanie query pre SELECT). Tento kód obsahuje viacero premenných (pre filtrovanie, pre zoraďovanie), ktoré sa vytvárajú na danom mieste a s načítaním zoznamu súvisia. Čo keby sme si vytvorili triedu pre zoznam používateľov, ktorý by sa skladal z objektov triedy User? A samotné načítanie dát by bola jeho metóda? Troška by nám to upratalo kód a stal by sa čitatelnejším, poďme teda na to. Potrebujeme teda triedu napríklad s názvom UserList (zoznam používateľov), ktorá by mala v sebe obsahovať všetko, čo súvisí so zoznamom a načítanám dát z DB. Mohlo by to vyzerať asi takto:
index.php (pridanie novej triedy):
//TRIEDA USERLIST (zoznam pouzivatelov)
class UserList{
public $users = array();
public $search_keyword = '';
public $sort_by = 'id';
public $sort_type = 'ASC';
function loadData($db_connection){
$sql_query = "SELECT * FROM users";
if($this->search_keyword){
$sql_query .= " WHERE user_name LIKE '%".$this->search_keyword."%' OR user_surname LIKE '%".$this->search_keyword."%'";
}
if($this->sort_by){
$sql_query .= " ORDER BY ".$this->sort_by;
if($this->sort_type){
$sql_query .= " ".$this->sort_type;
}else{
$sql_query .= " ASC";
}
}
$result = mysqli_query($db_connection, $sql_query);
if (mysqli_num_rows($result) > 0) {
$data = mysqli_fetch_all($result, MYSQLI_ASSOC);
//TRANSFORMACIA DAT NA POLE OBJEKTOV
foreach($data as $key => $value){
$this->users[$key] = new User($value['id'], $value['user_name'], $value['user_surname'], $value['age'], $value['role']);
}
}
}
}
Ako vidíte na ukážke kódu, do tejto triedy sme si vložili samotný zoznam používateľov (users), ako aj parametre, ktoré súvisia s vyťahovaním dát z databázy (zoraďovanie a filtrovanie). Celé načítanie z databázy a pretransformovanie zoznamu na zoznam objektov User sa vykonáva v metóde loadData. Aby sme mohli vykonať query na databázu, museli sme si pripojenie do DB (ktoré sa v kóde vytvára na začiatku) preposlať ako parameter do tejto metódy. Vytvorenie tohto objektu a zavolanie funkcie loadData nám zabezpečí, že sa v property users tohto objektu bude nachádzať zoznam našich používateľov (objekty triedy User).
Po tomto kroku musíme prepísať všetky výskyty premenných sort_by, sort_type a search_keyword na $user_list->sort_by a podobne. Za pripojením do databázy by sme mali vytvoriť objekt zoznamu a následne načítať parametre (filtrovanie, zoraďovanie), aby sa uložili do tohto objektu a na záver potom zavolať funkciu loadData. Tieto kroky by mali viesť ku korektnému načítaniu používateľov z DB, ktorí sa budú nachádzať v objekte UserList v property users, kde každý prvok bude objekt triedy User. Kód použitia týchto objektov by mal vyzerať teda takto:
index.php (časti s objektami tried UserList a User):
//PRIPOJENIE DO DB
$db = new Database('localhost', 'root', 'root', 'zapr_db_1');
$db->connectToDb();
…
(starý kód pre vymazanie a vlozenie noveho usera)
…
<?php
$user_list = new UserList();
//SPRACOVANIE FILTROVANIA
if($_SERVER['REQUEST_METHOD'] == 'GET' && $_GET['search_form']){
$user_list->search_keyword = $_GET['search_keyword'];
}
//ZACHYTENIE PARAMETRA PRE TRIEDENIE DAT V TABULKE
$user_list->sort_by = $_GET['sort_by'];
$user_list->sort_type = $_GET['sort_type'];
$user_list->loadData($db->connection);
echo '<h2>Zoznam používateľov</h2>';
?>
<!-- Formular na filtrovanie usera -->
<form class="contact_form" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" method="get">
<label for="search_keyword">Meno</label>
<input type="text" name="search_keyword" id="search_keyword" value="<?php echo $user_list->search_keyword;?>">
<input type="hidden" name="sort_by" value="<?php echo $user_list->sort_by;?>">
<input type="hidden" name="sort_type" value="<?php echo $user_list->sort_type;?>">
<input type="submit" name="search_form" value="Filtruj">
</form>
<br>
<?php
//VYPIS POUZIVATELOV DO TABULKY
if($user_list->users){
echo '<table class="persons">';
echo '<tr>';
echo '<th>ID</th>';
echo '<th><a class="sortable';
if($user_list->sort_by == 'user_name'){
if($user_list->sort_type == 'ASC'){
echo ' asc';
}else{
echo ' desc';
}
}
echo '" href="index.php?sort_by=user_name';
if($user_list->sort_by == 'user_name'){
if($user_list->sort_type == 'ASC'){
echo '&sort_type=DESC';
}else{
echo '&sort_type=ASC';
}
}else{
echo '&sort_type=ASC';
}
if($user_list->search_keyword){
echo '&search_keyword='.$user_list->search_keyword.'&search_form=Filtruj';
}
echo '">Meno</a></th>';
echo '<th><a class="sortable';
if($user_list->sort_by == 'user_surname'){
if($user_list->sort_type == 'ASC'){
echo ' asc';
}else{
echo ' desc';
}
}
echo '" href="index.php?sort_by=user_surname';
if($user_list->sort_by == 'user_surname'){
if($user_list->sort_type == 'ASC'){
echo '&sort_type=DESC';
}else{
echo '&sort_type=ASC';
}
}else{
echo '&sort_type=ASC';
}
if($user_list->search_keyword){
echo '&search_keyword='.$user_list->search_keyword.'&search_form=Filtruj';
}
echo '">Priezvisko</a></th>';
echo '<th>Vek</th>';
echo '<th>Rola</th>';
echo '<th>Akcie</th>';
echo '</tr>';
for($i=0; $i<count($user_list->users); $i++){
echo '<tr>';
foreach($user_list->users[$i] as $index => $value){
echo '<td>'.$value.'</td>';
}
echo '<td>';
echo '<a href="uprava-zaznamu.php?id_user='.$user_list->users[$i]->id.'">Upraviť záznam</a><br><br>';
echo '<a href="index.php?id_user='.$user_list->users[$i]->id.'" onclick="return showConfirm()">Vymazať záznam</a>';
echo '</td>';
echo '</tr>';
}
echo '</table>';
} else {
echo "0 results were selected.";
}
echo '<br><br>';
mysqli_close($db->connection);
?>
Pri tomto kroku bolo najmä dôležité nahradiť všetky výskyty premenných pre zoraďovanie a filtrovanie property triedy UserList (aj hidden elementy vo formulároch). Ako vidíte, stránka sa správa skutočne tak ako predtým, len kód vyzerá podstatne inak. Teraz sa už náš kód skladá z deklarácie troch tried, za ktorými nasledujú dva riadky, ktoré sa pripoja do databázy (pomocou objektu pre pripojenie do db). Následne máme starý kód pre mazanie a vkladanie nového používateľa, za ktorým nasleduje kód pre načítanie zoznamu používateľov (objekt UserList, načítanie parametrov a načítanie dát). Na konci je už len formulár pre filtrovanie a samotná tabuľka.
Ako vidíte, pomocou týchto tried sme prepísali kód, ktorý sa týkal zoznamu používateľov v tabuľke. V týchto sekciách nemáme žiadne premenné v kóde a ani funkcie, ktoré nám nič nevravia, resp. nesúvisia (nie sú jeho časťou) so žiadnym objektom nejakej triedy. V nasledujúcej prednáške našu premenu kódu súboru index.php na OOP dokončíme.