Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Klasa Generująca Widoki - Problem
Forum PHP.pl > Forum > PHP > Object-oriented programming
reptilerex
Witam, jestem w trakcie tworzenia biblioteki do code ignitera, ale mniejsza o to bo to nie jest przedmiotem problemu.

Mam w planie stworzyć klasę, która za pomącą swoich metod będzie generować tabelkę HTML z wynikami z bazy danych + paginacja, filtry, sortowanie itd.
Klasa ma być w pełni konfigurowalna, to jest największym problemem, bo gdyby miała tylko działać dla mnie, to problem by nie istniał.

Póki co zrobiłem, generowanie kolumn + ustalanie nazw/nagłówków tych kolumn (wymieniając je z separatorem i rozdzielając później explodem)
Nazwy pól z bazy danych potrzebne do wyświetlenia/sortowania wyników są określane w taki sam sposób.

Cytat
Przykład:
Kolumna id | kolumna data | kolumna title
Pole id | Pole data | Pole title


Przekazuję sobie to do metody, która rozdziela to sobie i generuję kolumny po czym zapisuję to do zmiennej
Ok działa lecimy dalej.

Nadszedł czas na generowanie wierszy (rekordów), przesyłam więc z kontrolera result z bazy danych do metody mojej biblioteki i wyświetlam wyniki w foreachu, lecz tutaj problem.
Każda tabelka ma także narzuconą z góry kolumnę "Akcja" - dodaj, usuń, edytuj, generuj pdf itd itp
I muszę zrobić tak, aby była możliwość wyłączenia np dwóch lub trzech, a nawet wszystkich akcji dla danego rekordu.

Cytat
Przykład:

Rekord 1 - Usuń, Edytuj, Generuj PDF
Rekord 2 - Usuń, Edytuj, Generuj PDF
Rekord 3 - Usuń, Edytuj, Generuj PDF
Rekord 4 - Edytuj, Generuj PDF
Rekord 5 - Generuj PDF
Rekord 6 - [pusto]
Rekord 7 - Usuń, Edytuj, Generuj PDF


Nie mogę wpaść na pomysł jak się za to zabrać, proszę o wszelkie podpowiedzi.
Z góry dziękuję.
Fifi209
Pytanie skąd czerpiesz informacje o tym, który rekord można usunąć a który edytować
reptilerex
Właśnie nad tym się także zastanawiałem.
Myślałem o polu w bazie danych np: actions

Gdzie do każdego rekordu byłyby także jego opcje np: edit|del|pdf
Ale nie wiem czy to by było najlepsze rozwiązanie.

Jest taka sytuacja, że nazwy pól tabeli są także konfigurowalne np użytkownik klasy przekazuję do metody swoje nazwy pól:

id|title|data|godzina

I w pętli dosyć ciężko byĸłoby się dostać do akcji + ew je porozdzielać.

Swoja drogą mam przeczucie, ze strasznie sobie utrudniam życie, dlatego proszę o pomoc.
marcio
Robie cos podobnego a dokladnie admin generator'a..wiec jesli pobierasz rekordy z tej samej tabeli to dlaczego zaleznie od rekordu maja miec rozne akcje?skoro sa takiego samego "typu" to kazdy rekord z tej samej tabeli powinien miec te same akcje...nie myslisz?chyba ze czegos nie zrozumialem...

Masz 5 news'ow i pierwsze 3 mozesz usunac a nastepne 2 nie?bezsens....
reptilerex
A pomyśl np o liście zamówień
Są zamówienia do realizacji i zamówienia w trakcie.

Te w trakcie mają nie aktywny przycisk -> Do realizacji.
A te do realizacji maja aktywny.
Crozin
@marcio: Różne obiekty mogą mieć w takiej tabeli różne akcje, ponieważ przykładowo użytkownik może nie mieć praw do usunięcia części danych, część danych może nie być zdatna do generowania w PDF-ie itp.

Taka tabelka to wręcz książkowy przykład na to, gdzie można sensownie zastosować taki bardzo popularny ostatnio wzorzec MVC. Na dobrą sprawę jest to przykład na to gdzie w ogóle jest miejsce tego wzorca. Ale o tym już było nie raz i nie ma sensu ciągnąć tego tutaj. wink.gif

Zastanów się czego potrzebujesz. Potrzebujesz narzędzia uniwersalnego, które będzie w stanie przyjąć coś (konkretnie to implementację interfejsu, który sobie zdefiniujesz) co na podstawie jakiś tam informacji (np. filtry, paginacja) utworzy sobie kolekcję obiektów, które na końcu zostaną wyświetlone w jakiejś formie, np. tabelki. Narzędzie musi być rozbudowane. Inaczej przy pierwszej próbie zrobienia czegoś niestandardowego polegnie i będzie przyczyną całej masy problemów do obejścia.

Tutaj piszę bez większego namysłu - Ty powinieneś zastanowić się czy aby na pewno takie rozwiązanie nie ma jakiś defektów, czy nie będzie ograniczać w jakiś skrajnych przypadkach itp. itd.

Pierwsze co będzie potrzebne to to coś co ma zwracać odpowiednią kolekcję obiektów do wyświetlenia. Interfejs tego będzie bardzo prosty (wybacz słabe nazewnictwo)<!--Geshi:281492:php--><pre class="php-brief" style="font-family:monospace;"><div class="head">
  1. [topic=0]YPE</span> <span class="sy0">|</span> YouTube<span class="sy0">::</span><span class="me2">PLAYLIST_TYPE</span><span class="br0">)</span><span class="sy0">;</span></div><li class="li1"><div class="de1"> </div><li class="li2"><div class="de2"><span class="re0">$table</span><span class="sy0">-></span><span class="me1">setDataRepository</span><span class="br0">(</span><span class="re0">$data</span><span class="br0">)</span><span class="sy0">;</span></div>
  2. [/list]<div class="foot">[PHP] [url="./Pobierz-Plik-281493.html"]plaintext[/url] </div></pre><!--/Geshi:281493:php-->Na dobrą sprawę takie rzeczy jak paginacja czy sortowanie również powinny być zrealizowane przy pomocy odpowiednich interfejsów, kolejno PaginableInterface (get/setOffset, get/setLimit) oraz SortableInterface (get/setField, get/setOrder lub inny interfejs get/setComparator).
  3.  
  4. To właściwie załatwia sprawę określenia co ma zostać pobrane. Następny etap to określenie co ma zostać wyświetlone. Można to zrobić w bardzo prosty sposób, tj. poprzez określenie etykiety (w przypadku tabelki będzie to nagłówek kolumny) oraz metody zwracającej wartość.[php]$table->addColumn('Tytuł', 'getTitle');
  5. // Można by to zrobić też jako
  6. $table->addColumn('Opis', 'description'); // spróbuje wywołać metodę getDescription albo isDescription (standardowe gettery)
  7.  
  8. // Czasami potrzeba zrobić coś bardziej dynamicznego, wtedy można by zastosować coś takiego:
  9. $table->addColumn('Wielkość pliku', function($object) {
  10. return FilesystemUtils::formatFileSize($object->getFileSize()); // zwraca przykładowo 15 KiB, 7,2 GiB, 244 b
  11. });
  12.  
  13. // Albo nawet jako obiekt implementujący jakiś interfejs


Problem tego jakie konkretnie dane trzeba wyświetlać zdaje się również być rozwiązany. Kolejny problem to ustalenie jakie akcje (usuń, edytuj, drukuj, akceptuj itp.) mają być dostępne dla każdego obiektu. Takie akcje można również całkiem łatwo rozwiązać za pomocą obiektów, które będą implementowały prosty interfejs:
  1. interface ActionInterface {
  2. public function supports($object);
  3. }
Metoda ta zwraca prawdę bądź fałsz w zależności od tego czy dany akcja jest dostępna dla danego obiektu, przykładowo akcje usuń i akceptuj mogłby wyglądać tak:
  1. class RemoveAction implements ActionInterface {
  2. private $user;
  3. private $acl;
  4.  
  5. // konstruktur, get/set dla powyższych
  6.  
  7. public function supports($object) {
  8. return $this->acl->hasPermissions($this->user, $object, ACL::REMOVE);
  9. }
  10. }
  11.  
  12. class ActivateAction implements ActionInterface {
  13. public function supports($object) {
  14. return $object instanceof ActivatableInterface && !$object->isActive();
  15. }
  16. }
Później takie akcje trzeba dodać tylko do tabelki:
  1. $removeAction = new RemoveAction();
  2. $removeAction->setUser($this->getCurrentUser());
  3. $removeAction->setAcl($this->getAcl());
  4.  
  5. $activateAction = new ActivateAction();
  6.  
  7. $table->addObjectAction($removeAction);
  8. $table->addObjectAction($activateAction);


Na koniec pozostaje kwestia ostatecznego wyrenderowania tabelki. Za to również odpowiedzialny jest osobny obiekt (bo przecież możesz chcieć wyrenderować tabelkę, listę, kolekcję w JS/JSON/XML czy jeszcze coś innego). Taki renderer to oczywiście również implementacja jakiegoś tam interfejsu, który definiuje jakieś tam metody.
reptilerex
Dzięki za tak rozbudowana odpowiedź na pewno z tego skorzystam.
Lecz zastanawia mnie jedno, nie mogę sobie pozwolić na takie rozwiązanie z bazą danych jak mówiłem wcześniej.
Aby każdy rekord miał swoje zapisane akcje.

Dowiedziałem się, że mogę to zrobić za pomocą tablic... ale nie mam pojęcia jak.
Crozin
Cytat
Lecz zastanawia mnie jedno, nie mogę sobie pozwolić na takie rozwiązanie z bazą danych jak mówiłem wcześniej.
Aby każdy rekord miał swoje zapisane akcje.
O ile dobrze zrozumiałem to chodzi Ci tutaj o określenie czy dana akcja, ma być dostępna dla danego obiektu? Bo samo w sobie nijak ma się to do tej tabelki. wink.gif
Cytat
Dowiedziałem się, że mogę to zrobić za pomocą tablic... ale nie mam pojęcia jak.
Załóż nowy wątek, opisz problem oraz jak próbowałeś go rozwiązać.

PS. Widzę, że niestety forum coś zrypało mój wcześniejszy post. No niestety taki już pozostanie, bo nie mam ochoty go przepisywać. wink.gif
reptilerex
Dokładnie chodzi mi o możliwość określenia jakie dany rekord ma mieć dostępne akcje
Crozin
Popatrz jeszcze raz na ActionInterface::supports(). To tam określasz czy dany obiekt (przekazany w pierwszym argumencie) będzie posiadał daną akcję. A to na jakiej podstawie to określisz to już zupełnie inna sprawa, bo może to być ustalone na podstawie jakiegoś ACL-a, właściwości obiektu czy jeszcze czegoś innego.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.