chevron-left chevron-right

[PHP][CodeIgniter] Jak utworzyć wielopoziomowe kategorie?

Ostatnio, pobawiłem się trochę frameworkiem PHP o nazwie CodeIgniter (moim zdaniem jeden z fajniejszych frameworków PHP) i w ramach sprawdzenia go stworzyłem prosty CMS.
Jednym z problemów jakie trzeba było rozwiązać był problem utworzenia wielopoziomowego drzewa kategorii newsów, aby wstawić go do znacznika <select> w kodzie formularza. Jestem pewien, że wiele osób miało/ma z tym problem.

Rekurencja - co to jest?

By wykonać tego typu zadanie należy zaznajomić się z pojęciem rekurencji.

Rekurencja - (w programowaniu) odwoływanie się funkcji do samej siebie

Definicja jest prosta w zrozumieniu, a jak to wygląda w przypadku funkcji w PHP (w tym przypadku, frameworku PHP - CodeIgniter)?

Przygotowanie bazy danych

Na początku należy utworzyć w bazie danych tabelę z trzema kolumnami:

  • kategoria_id
  • rodzic_id
  • kategoria_nazwa

Wedle następującego schematu:

Generowanie wielopoziomowych kategorii w CodeIgniter

W oparciu o tak podany schemat bazodanowy, utworzymy odpowiednie funkcje, które należy wstawić do modelu, który ma obsługiwać system newsów.
Należy pamiętać o tym, że programując cokolwiek z użyciem frameworków PHP, korzystamy ze wzorca MVC (odpowiednio dostosowanego do PHP) i aplikację mamy podzieloną na 3 części składowe:

  • Model (M) - w nim znajdują się metody/funkcje odpowiedzialne za przetwarzanie danych z bazy danych oraz danych wprowadzanych przez użytkownika
  • Widok (V) - w nim znajduje się szablon strony na której dane (odpowiednio przygotowane przez model, a następnie przekierowane przez kontroler) będą wyświetlane
  • Kontroler (C) - w nim znajdują się metody/funkcje pozwalające na odpowiednie przygotowanie danych przed wysłaniem do modelu czy widoku

Kod odpowiedzialny za tworzenie wielopoziomowych kategorii wygląda następująco:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/*
 * Funkcja generująca widok listy rozwijanej <select>
 */
function getCategories() 
{
    $list = '';
    $q = 'SELECT * FROM kategorie WHERE rodzic_id IS NULL';
    $wynik = $this->db->query($q);
    $rodzic = $wynik->result_array();
    $mainlist = '<select name="kategoria">';
    foreach($rodzic as $p)
        $mainlist .= $this->categoryTree($list, $p, $append = 0);
    $mainlist .= '</select>';
    return $mainlist;
}
 
/*
 * Funkcja generująca kolejne gałęzie drzewa kategorii
 * na liście rozwijanej <select>
 * dla widoku pisania newsa
 */
function categoryTree($list, $rodzic, $append)
{
    if($this->hasChild($rodzic['kategoria_id']))
    {
        $append++;
        $list = '<optgroup label="'.$this->addWhitespace($append).$rodzic['kategoria_nazwa'].'">';
        $q = 'SELECT * FROM kategorie WHERE rodzic_id = "'.$rodzic['kategoria_id'].'"';
        $wynik = $this->db->query($q);
        $dziecko = $wynik->result_array();
        foreach($dziecko as $rodzic)
            $list .= $this->categoryTree($list, $rodzic, $append);
        $list .= '</optgroup>';
    }
    else
    {
        $list = '<option value="'.$rodzic['kategoria_id'].'">'.$this->addWhitespace($append,1).$rodzic['kategoria_nazwa'].'</option>';
    }
    return $list;
}
 
/*
 * Funkcja dodająca twarde spacje do ciągu
 * w celu sformatowania układu
 */
protected function addWhitespace($n,$dodaj=0)
{
    $w = '&nbsp;&nbsp;&nbsp;&nbsp;';
    $space = '';
    for($i=0;$i<$n;$i++)     
        $space .= $w;
    if($dodaj==1)
        return $space.'&nbsp;&nbsp;&nbsp;&nbsp;';
    else
        return $space;
}

Uważam że kod jest dość jasno opisany i nie potrzebuje większego tłumaczenia. Jednak muszę wspomnieć o tym, że przed wykonaniem powyższego kodu należy pamiętać o zaladowaniu biblioteki CodeIgnitera dzięki której będzie możliwe korzystanie z metod bazodanowych, np.: $this->db->query.
Bardzo możliwe, że znajdzie się ktoś kto powyższy kod mógłby jeszcze bardziej zoptymalizować, ale na potrzeby tego tutoriala jest on całkowicie wystarczający i jasny (mam nadzieję).