Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [php][oop] Architektura aplikacji
Forum PHP.pl > Forum > PHP > Object-oriented programming
jastu
Witam
problem opiszę na przykładzie :
- mamy w bazie rekord który dla różnych profili użytkownika wyświetla inne kolumny

Gdzie powinno się znaleźć zapytanie o rekord ?
- czy w klasie ModelUserProfil dziedziczącej po klasie ModelUser (chyba nie) ?
( tutaj mamy tylko kod do operacji na danych użytkownika )
- czy w klasie ModelDane która odpowiada za dane które chcemy uzyskać (raczej tak) ?
( wtedy trzeba do ModelDane przekazać informacje o profilu bierzącego użytkownika )
- czy w klasie ViewDane który generuje odpowiedni widok dla bierzącego usera (zdecydowanie tak) ?
( przekazujemy informacje o profilu użytkownika do widoku i na tej podstawie wyświetlamy tylko własciwe dla użytkownika dane, ale pobieramy zawsze komplet danych )

3 rozwiązanie chyba najlepsze, tylko w ModelDane zawsze byśmy pobierali te same dane, a nie każdy profil wymaga pobrania danych dla rekordu z 3 tabel (po np. jeden z profili wymaga danych z jednej tabeli) - co wtedy z wydajnością ?

Jak rozwiązujecie to u siebie ?
pzdr
Sedziwoj
Jak dla mnie problem nie jest dokładnie opisany.
Na starcie nie podoba mi się odniesienie do rekordu... bo to ma niewiele wspólnego. Ważniejsze jest co to są za dane.
Piszesz o że jest to zależne od użytkownika co wyświetli, ale w jaki sposób?
Bo jak to są różnice typu NIP, nazwa itd. dla firmy a dla osoby fizycznej brak to inaczej bym to rozwiązał, niż informacje o czymś i w zależności od typu użytkownika wyświetla je lub nie. No i czy to jest parę typów czy całkowita dowolność i ilość przez to.
jastu
Wydawało mi się że opisałem jasno sad.gif

Przykładowy przykład nr 2.
- mamy aplikację do ewidencji bydła hehe
- w aplikacji mamy trzy rodzaje użytkowników (użytkownik,moderator,administrator)
- wyświetlenie informacji dla użytkownika o jakimś bydlaku wymaga pobrania danych z jednej tabeli
- wyświetelenie informacji o bydlaku dla moderatora wymaga pobrania danych z dwóch tabel (join), dla administratora z 3 (join)

Pytanie -> gdzie umieścić zapytania o te dane lub/czy pobierać wszystkie dane a wyświetlać tylko wybrane (wydajność) ?

Cytat
Piszesz o że jest to zależne od użytkownika co wyświetli, ale w jaki sposób?

no właśnie ?
Cytat
Bo jak to są różnice typu NIP, nazwa itd. dla firmy a dla osoby fizycznej brak to inaczej bym to rozwiązał, niż informacje o czymś i w zależności od typu użytkownika wyświetla je lub nie.

czy o wyświetlonych informacjach/danych/linkach/przyciskach/opcjach nie decuduje właśnie typ/profil/grupa użytkownika ?
Sedziwoj
Cytat(jastu @ 13.06.2007, 00:36:34 ) *
Wydawało mi się że opisałem jasno sad.gif

Może ja jestem po prostu tępy biggrin.gif

Czyli problem jest uprawnienia użytkownika i gdzie mają być egzekwowane, na poziomie modelu czy widoku.
Teraz w tym co korzystam uprawnienia są na poziomie controlera, po ale mam właściwie dwa typy osób, użytkownik i administrator. Więc po zalogowaniu jako admin masz dostęp do panelu gdzie jest wszytko.
Ogólnie jak masz prezentować różne ilości danych to i tak powinny być to różne widoki, aby w każdym to dobrze wyglądało, choć jest czasem tak że pewne elementy się ukrywa dla nie uprawnionych.
Czyli w tym moim przypadku, nie wiem czy dobre jest to rozwiązanie, z modelu jest pobierany komplet informacji.
Ludvik
Ja pomyślał bym nad fabryką i DAO dla obiektów reprezentujących wyświetlane dane. Szkoda trochę wydajności, żeby w większości przypadków (odwołania przeciętnych użytkowników) wykonywać potrójnego joina. Najlepiej widać to na pseudo-kodzie.
  1. <?php
  2. class UserData {
  3. public function getSomething() {}
  4. }
  5.  
  6. class ModData extends UserData {
  7. public function getSomethingMore() {}
  8. }
  9.  
  10. class AdminData extends ModData {
  11. public function getSomethingElse() {}
  12. } 
  13.  
  14. class DataDAOFactory {
  15. public static function getDAO(User $u) {
  16. if ($u->isAdmin()) {
  17. return new AdminDataDAO();
  18. } else if ($u->isMod()) {
  19. return new ModDataDAO();
  20. } else {
  21. return new UserDataDAO();
  22. }
  23. }
  24. }
  25.  
  26. interface DataDAO {
  27. public function getUserData(User $u);
  28. }
  29.  
  30. class UserDataDAO implements DataDAO {
  31. public function getUserData(User $u) {
  32. // Pobierasz dane dla zwykłego użytkownika
  33. return new UserData();
  34. }
  35. }
  36.  
  37. class ModDataDAO implements DataDAO {
  38. public function getUserData(User $u) {
  39. // Pobierasz dane dla moderatora
  40. return new ModData();
  41. }
  42. }
  43.  
  44. class AdminDataDAO implements DataDAO {
  45. public function getUserData(User $u) {
  46. // Pobierasz dane dla administratora
  47. return new AdminData();
  48. }
  49. }
  50. ?>

Tyle, że z tym rozwiązaniem jest jeden problem: dużo klas. Przyda się, jeżeli w tym DAO będziesz miał więcej operacji zależnych od typu użytkownika. Jeżeli będziesz miał tylko jedną metodę, może to być strata czasu. Wtedy można utworzyć uniwersalne DAO, w którym dokonasz wyboru zapytania po uprawnieniach (tak jak w fabryce wyboru DAO). Wypada wtedy fabryka i dwie klasy DAO. Widok możesz wybrać po typie obiektu z danymi albo uprawnieniach użytkownika.
Reigon
Sprawdzalbym uprawnienia (admin, mod, user) czy to w jakies specjalnej klasie z uprawnieniami, czy to zwyczajnie w kontrolerze i w zaleznosci o tego wykonywal metode klasy DAO (cos jak poprzednik opisal, tylko on to zrobil na wielu klasach) - szukaj(dla usera), szukajMod(), szukajAdmin(). Ja mam np. klase macierzysta dla warstwy DAO - SQL, a w niej zklejanie zapytania i wyszukiwanie i zwracanie badz to obiektu modelu badz tablicy obiektow. Wtedy mozesz napisac klase User, a w niej dodatkowe metody dla moda i admina. W nich pisalbys zapytanie ze zlaczeniem (az do WHERE) i zwracal poczatek zapytania do klasy realizujacej jego dalsze sklejanie.
jastu
Tworzenie DAO dla każdego użytkownika jest chyba najlepszym rozwiazaniem ( wg mnie najbardziej elastycznym w kontekscie zmian ). Rozumiem też, że w tej sytuacji trzeba będzie budować odrębne klasy prezentacji danych ( lub szablony ) questionmark.gif lub widok generować wspólny, ale każdy przycisk/link/cokolwiek w tym widoku (wywołujący kontroler/metodę/akcję) sprawdzać przed wyświetleniem uwzględniając właśnie uprawnienia użytkownika ... i może to że użytkownik jest jego właścicielem (np ja edytuję swój post więc button edit mi się wyświetli) questionmark.gif?

W tej sytuacji tworzenie odrębnych widoków (bądź jego elementów) wydaje się dobry rozwiązaniem, chociaż wg mnie nie jest to najlepsze rozwiązanie (w przypadku zmian nie jest to już jeden szablon)
  1. <?php
  2. class Fast{
  3.  
  4. static function check($user,$controller,$function,$param){
  5.  // pobranie informacji o wymaganiach żądania (bądź wartości domyślne)
  6. $actionDemand = getActionDemand($controller,$function,$param); 
  7.  
  8. // pobranie uprawnień użytkownika dla tego żądania,(jeśli brak to dane domyślne )
  9. $userPossibility = getUserPossibility($user,$controller,$function,$param);
  10.  
  11.  
  12. // sprawdzenie czy użytkownik może zrealizować ządanie (flagi bitowe)
  13.  ((int)$actionDemand & (int)$userPossibility == $actionDemand) ? return true : return false ;
  14. }
  15. }
  16.  
  17. // i gratis helper do linków :)
  18. function Link($link,$name,$title){
  19. return '<a href= " '.base_url().$link.' "  title= " '$title' " >'.$name.'</a>';
  20. }
  21.  
  22. // wykorzystanie w szablonie 
  23. if(Fast::check($this->User,'post','delete',3)){ echo link('/post/delete/3','Usuń','Usuń tego posta');}
  24. ?>



Skomplikowane moze być pobieranie danych w aspekcie jakiegoś lokalnego wydarzenia zależnego od parametru dla wskazanej funkcji w kontrollerze tzn. jestem moderatorem jakiegoś subforum na forum, i w moim subforum do przycisku usuń_posta uprawnienia mają już trzy osoby (user do swojego posta oraz moderator i administrator do każdego posta)...więc procedura spradzenia czy przycisk usuń_linka może odbiegać od innych.


Obecnie walcze z uzyskaniem zgrabnego rozwiązania dla generowania widoków (zależnych od uprawnień) i dynamicznym przydzielaniem uprawnień .

Wnoisek : mamy dla kontrollera DAO zależne od profilu użytkownika...czy z widokiem zrobić tak samo ?

Poradzicie coś ? aarambo.gif



////////////////////////////////////////////////////////////////////////////////////////


Pozwolę sobię odświeżyć El Temato worriedsmiley.gif
Napisałem klasę wykorzystującą wzorzec Composite View, jest to jedna klasa która przyjmuje tablicę z danymi i nazwę szablonu - po czym podstawia zmienne,wykonuje kod php w szablonie i wyświetla lub przechowuje wynik uruchomienia szablonu.

  1. <?php
  2. // ZAWARTOŚĆ CONTROLLERA
  3.  
  4. $tplName =  'calendar';
  5. $data =  array('poniedziałek','środa','czwartek');
  6. // 3 argument to false tzn.wynik wykanania kodu php w szablonie jest w składowej $calendar_view
  7. $calendar_view = new View($tplName,$data,false);
  8. $banner_view = new View('banner',false,false);
  9.  
  10. $viewElements = array('calendar' => $calendar_view,'banner'=>$banner_view);
  11.  
  12. // wyświetlenie
  13. new View('startPage',$viewElements,true);
  14. ?>


Co zrobić z uprawnieniami do np. opcji w menu dostępnych tylko dla moderatora. Schemat działania widoku jest prosty - przyjmuje on już przygotowane przez kontroler dane....tzn że w kontrolerze zadecydujemy czy button USUŃ ma się wyświetlić bieżącemu userowi ? Kolejnym rozwiązaniem jest przekazanie danych o uprawnieniach do klasy View....tylko wtedy ta klasa powinna mieć możliwość komunikacji z modelem żeby w oparciu o uprawnienia odpowiednie dane pobierać. Czy ktoś potrafi przedstawić wstępny zarys działania takiej implementacji ?

Można...
- napisać 5 różnych szablonów tego samego widoku i ładować odpowiedni w zależności od uprawnień ?

Nie mam już innego pomysłu .....

-------------------------------------------------------------------------
Może się komuś przyda (dla prostych wywołań typu CI czy VFrame) :
- bieżący uzytkownik (zalogowany czy nie) ma jakiś tam profil (administrator/moderator czy Anonymous)
- do szablonu widoku przekazujemy obiekt użytkownika
- zanim wyświetlimy jakiś link lub przycisk sprawdzamy czy user ma uprawnienia do akcji wywoływanej przez ten link
- sprawdzić instancję użytkownika można podczas wywołania kontrollera w jednej z jego metod lub w konstruktorze
KLASA UŻYTKOWNIKA
  1. <?php
  2.  
  3. class User{
  4. private $instance = null;
  5.  
  6. function isAdministrator(){
  7. // sprawdzenie czy user jest administratorem
  8. // return true : false
  9. }
  10.  
  11. function isModerator($id = null){
  12.  // sprawdzenie czy user jest moderatorem czegośtam o wskazanym ID
  13.  // return true : false
  14. }
  15.  
  16. // pozostały kod
  17. }
  18.  
  19. ?>



KONTROLER
  1. <?
  2. class index extends controller{
  3.  
  4. function index(){
  5. $this->load->class('User');
  6. $this->view->display('index',array('user'=>User::init()));
  7.  
  8. }
  9. }
  10. ?>




  1. <html>
  2. <body>
  3. <!-- jakaś treść strony -->
  4. <? php 
  5. <? if( $user->isAdministrator() ) { echo '<a href="www.system.pl/destroy.php">Link</a>' ; } ?>
  6.  
  7.  
  8. </body>
  9. </html>


Czekam na słowa krytyki...
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.