Jak napisać wtyczkę dla BatFlat'a

Jak napisać wtyczkę dla BatFlat'a

W kwestii samych modułów autorzy systemu zostawili użytkownikom (developerom) otwartą furtkę. Jeżeli brakuje mi jakiejś funkcjonalności zawsze mogę ją sobie utworzyć.

Chciałbym mieć możliwość podpinania do postów plików, które czytelnicy będą mogli łatwo pobrać na swój dysk. W tym celu napiszemy odpowiedni moduł.

Założenia

  1. Nowa funkcjonalność BF, zrealizowana w formie modułu.
  2. Panel administracyjny powinien umożliwiać:
    • upload plików do ~/uploads/FilesToDownload,
    • modyfikację nazw i ikon plików,
    • usuwanie plików;
  3. Dla każdego pliku wpis w bazie danych powinien zawierać:
    • id,
    • nazwę ikony wyświetlanej przy linku do pobrania (fontawesome),
    • nazwę pliku przyjazną użytkownikowi,
    • skróconą nazwę pliku (slug),
    • rozmiar pliku w B,
    • nazwę pliku,
    • pełną ścieżkę do pliku;
  4. Na podstawie skróconej nazwy pliku (slug) powinien zostać utworzony tag umożliwiający dodanie odpowiedniego widoku.
  5. Domyślny widok pliku do pobrania powinien zawierać się w jednym wyjustowanym wierszu i przedstawiać się w następującej kolejności:
    • ikona,
    • nazwa przyjazna użytkownikowi,
    • "stretch",
    • rozmiar pliku,
    • przycisk "Pobierz".

Trochę teorii

Dokumentacja zawiera niezbędne informacje pomocne w tracie pracy nad modułami czy motywami dla tego systemu. Znajdziesz tam krótki opis dostępnych funkcji wraz z przykładami. Na potrzeby tego wpisu przytoczę na razie tylko kilka faktów dotyczących struktury katalogu z modułem.

Logika modułu opiera się o trzy główne pliki:

  • Admin.php (odpowiedzialny za część dostępną w panelu administracyjnym),
  • Site.php (odpowiedzialny za pracę modułu podczas kiedy użytkownik przegląda nieświadomie stronę),
  • Info.php (odpowiedzialny za opis, instalację, deinstalację i rejestrację naszego modułu w systemie).

Dodatkowo w katalogach view oraz lang zawierają się wykorzystywane widoki i pliki językowe.

Routing

W zarządzaniu danymi modułu i podczas wykonywania wszelkich akcji typu zapisz, usuń, zmień, etc bardzo ważną rolę pełni routing. Moim zdaniem trzeba go poznać i opanować, aby bezproblemowo napisać moduł jaki potrzebujemy.

Komunikacja pomiędzy stroną (czy to publiczną czy fragmentem panelu administracyjnego) opiera się o adresy url. Wiedząc jak to wykorzystać mamy możliwość wywoływania najrozmaitszych funkcji naszego modułu poprzez odpowiednie przekierowania.

Adres url https://pplaczek.pl/blog/post/wprowadzenie składa się z następujących elementów:

  • https://pplaczek.pl/ - protokół i domena(host),
  • blog - uruchomiony moduł,
  • post - zmienna modułu powodująca pobranie z bazy danych postu przekazanego jako następny parametr,
  • wprowadzenie - slug postu będący parametrem dla funkcji uruchomianej przez post.
// URL: http://example.com/blog/post/lorem-ipsum
  $this->route('blog/post/(:str)', function($slug) {
  $this->importPost($slug);
  });

Funkcje uruchamiane poprzez wysłanie formularza nie muszą być rejestrowane. Wymogiem jest wyłącznie dostosowanie jej nazwy do rodzaju formularza.
Jeżeli formularz jest wysyłany metodą POST, nazwa funkcji musi zawierać prefix post. W przypadku formularzy GET, konieczny jest prefix get. Proste? Zobacz przykład poniżej:

  // Po wysłaniu poniższego formularza
  echo '<form action="http://localhost/admin/FilesToDownload/saveFile" method="post"></form>';
  // Wywołana zostanie funkcja z pliku Admin.php
  public function postSaveFile()
  {
  // kod
  }

  // Natomiast w tym przypadku
  echo '<a href="http://localhost/admin/FilesToDownload/modifyFile/1"></a>';
  // Wywołana zostanie funkcja
  public function getModify($id)
  {
  // kod
  // $id == 1
  }
  

Rozpoczynamy pracę

Zakładam, że posiadasz już uruchomiony serwer lokalny ze swoją kopią roboczą BatFlat-a. W katalogu /inc/modules/sample/ znajdziesz przygotowany przez twórców systemu przykładowy pusty moduł. Wykorzystamy go do napisania własnego.

Zgodnie z założeniami potrzebna będzie tabela w bazie danych i katalog przeznaczony na wgrywane pliki. Żeby mieć to już za sobą modyfikujemy plik Info.php. W jaki sposób go opiszesz, nazwiesz, jaką dasz ikonę czy licencję to w większości Twoja sprawa i nie będę się w to teraz zagłębiał. Interesują nas pola install oraz uninstall .

W pierwszym z nich budujemy i wykonujemy kwerendę przygotowującą tabelę w bazie danych i tworzymy sobie katalog na nasze pliki. Ten zestaw instrukcji jest wykonywany przy każdej aktywacji modułu (Panel administracyjny -> Moduły -> Nieaktywne -> Aktywuj).

'install' => function () use ($core) {
  $core->db()->pdo()->exec("CREATE TABLE IF NOT EXISTS `pdev_ftd` (
  `id` integer NOT NULL PRIMARY KEY AUTOINCREMENT,
  `icon` text NOT NULL,
  `name` text NOT NULL,
  `slug` text NOT NULL,
  `size` integer NOT NULL DEFAULT 0,
  `file` text NOT NULL,
  `path` text NOT NULL
  )");

  if (!file_exists(UPLOADS.'/pdev_ftd')) {
  mkdir(UPLOADS.'/pdev_ftd', 0755, true);
  }
  },

Natomiast instrukcje z drugiego pola wykonywane są podczas dezaktywacji modułu i służą "posprzątaniu" po nim.

'uninstall' => function () use ($core) {
  $core->db()->pdo()->exec("DROP TABLE `pdev_ftd`");
  deleteDir(UPLOADS.'/pdev_ftd');
  }

Na tym etapie, wykonując AktywacjęDezaktywację modułu możesz zauważyć co się dzieje w bazie danych i katalogu uploads.

Widoki dla panelu administracyjnego

W panelu administracyjnym zakładam, że będą dwa widoki. Pierwszy umożliwiający dodanie nowego pliku i podgląd dostępnych plików oraz drugi umożliwiający modyfikację jednego wybranego pliku.

W tym celu w katalogu /view/admin tworzymy dwa pliki:

  • index.html (pierwszy widok),
  • modify.html (drugi widok).

Zdecydowałem się na przedstawienie danych w formie tabeli. Biorąc pod uwagę, że BatFlat wykorzystuje Bootstrap 3 szybko sformatowałem tabele tak aby odpowiadały moim preferencjom, a ich przygotowanie nie zabierało zbyt wiele czasu.

Admin.php

Na początek zdefiniujmy sobie funkcję odpowiedzialną za przygotowanie głównego widoku w panelu administracyjnym. Wykorzystamy do tego wcześniej przygotowany szablon /view/admin/index.thml.
Funkcja getIndex() powinna pobierać wszystkie rekordy z naszej tabeli (utworzonej w polu install pliku Info.php) i przekazywać je do widoku, który odpowiednio je zwizualizuje. Ponieważ zakładam, że pole z nazwą wykorzystywanej ikonki opatrzone będzie również tą ikoną, definiuję funkcję init() wewnątrz której dodaję do rdzenia plik css od fontawesome.

/**
  * Initialize module. Add fontawesome css.
  */
  public function init(){
  $this->core->addCss('https://use.fontawesome.com/releases/v5.3.1/css/all.css');
  }
/**
  * GET: /admin/filestodownload/index
  * Subpage method of the module
  *
  * @return string
  */
  public function getIndex()
  {
  $entries = $this->core->db('pdev_ftd')->toArray();
  return $this->draw('index.html', ['entries' => $entries]);
  }

Następnie definiuję metody odpowiedzialne za operacje na bazie danych:

  • postSaveFile() - wywoływana po wysłaniu formularza dodawania nowego pliku do bazy metodą post,
  • getModify($id) - wywoływana po kliknięciu odnośnika Zmień, aby otworzyć widok edycji; jako parametr przyjmuje wartość ID danego wpisu,
  • postModifyFile() - wywoływana po wysłaniu formularza modyfikacji wpisu (metodą post)
  • getRemove($id) - wywoływana po kliknięciu odnośnika Usuń - usuwa wpis o podanym jako parametr numerze ID.

Widoki wykorzystywane na stronie

Domyślny widok efektu działania modułu, czyli plik do pobrania dostępny na stronie, opisany jest w punkcie 5. założeń. Aby go zrealizować, umieszczany w katalogu /view prostą strukturę i dodatkowy plik stylów. W arkuszu stylów definiujemy całość jako flexbox i nadajemy odpowiednie marginesy.

  <div class="pdev_ftd">
  <i class="fas fa-{$ftd.icon}"></i>
  <p>{$ftd.name}</p>
  <div class="strech"><div class="baseline"></div></div>
  <p>{?= $ftd.size ?} B</p>
  <a href="{$ftd.path}" class="btn btn-primary" target="blank">
  {$lang.filestodownload.download}</a>
  </div>

Site.php

Logika odpowiedzialna za prawidłowe wykonywanie się modułu w części strony odwiedzanej przez użytkowników, powinna być zdefiniowana w pliku Site.php. W naszym przypadku można wszystko zawrzeć w funkcji inicjalizującej.

Potrzebne nam będą dwa style (fontawesome oraz styl widoku na stronie), które dodajemy do rdzenia oraz tablica zawierająca odpowiednie widoki dla każdego wpisu z bazy danych. O ile kwestia rejestracji stylów nie wymaga większych przemyśleń, tak algorytm przygotowania tablicy może na początku wydawać się zawiły, ale na pewno będzie przydatny przy kolejnych modułach.

Tablica przypisań

Potrzebna nam będzie tablica, którą przypiszemy do tagu pdev_ftd. Edytując treść strony lub posta będziemy mogli się do niej odwoływać poprzez znacznik , gdzie key będzie slugiem przypisanym na etapie dodawania pliku do bazy. Natomiast wartością tego pola, czyli tym co zostanie wstawione na stronie w miejscu znacznika, będzie kod html bazujący na przygotowanej wcześniej strukturze.

/**
  * Module initialization
  * Here everything is done while the module starts
  *
  * @return void
  */
  public function init()
  {
  // Add styles
  $this->core->addCss('https://use.fontawesome.com/releases/v5.3.1/css/all.css');
  $this->core->addCss(url('inc/modules/filestodownload/view/pdev_ftd.css'));

  // Get db items
  $files = $this->core->db('pdev_ftd')->toArray();

  // Create assigns array
  $assign = array();
  dump($files);
  foreach ($files as $file) {
  dump($file);
  $view = $this->draw('fileToDownload.html', ['ftd' => $file]);
  $assign[$file['slug']] = $view;
  }

  // Create user tag
  $this->tpl->set('pdev_ftd', $assign);
  }

Dla każdego elementu w bazie danych generujemy jego widok (funkcja draw) i umieszczamy w tablicy $assign jako wartość dla klucza opisanego polem slug dla danego wpisu. Ostatecznie całą tablicę rejestrujemy w systemie.

Gotowy moduł FTD v1.1.1

9582 B

Pobierz