Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Problem z praktycznym zastosowaniem programowania obiektowego
Forum PHP.pl > Forum > PHP > Object-oriented programming
Jarod
Dość dokładnie przerobiłem http://helion.pl/ksiazki/php5zp.htm, materiały na necie. Dużo też Was się pytałem na forum. Mam napisaną aplikacje strukturalnie. Chciałbym ją przepisać obiektowo i mam z tym problemy. Konkretnie z praktycznym zastosowaniem wiedzy teoretycznej..

Załóżmy, że mamy aplikację, która umożliwia logowanie. Jest też możliwy przydział uprawnień (tylko do odczytu lub do odczytu i zapisu) do konkretnego modułu aplikacji. Jedną z opcji aplikacji jest możliwośc wyświetlania spisu użytkowników aplikacji, z możliwością edycji danych, zmiany hasła, zmiany uprawnień, kasowania konta, itp.

Nie wiem jak się za to zabrać. Rozumiem, że pisząc aplikację obiektowo wszystko jest odwzorowane na obiekt. Czyli jeśli chciałbym wyświetlić listę użytkowników systemu, to pobieram wszystkich użytkowników z bazy, dla każdego tworzę obiekt i zapisuję do kolekcji a potem iterując ją wyświetlam na ekranie?

Jak się za to zabrać? Może macie jakieś praktyczne wskazówki? Będę wdzięczny.
envp
Propozycja moja jest taka:
-Tworzysz sobie klase User, ktora zawiera takie pola jakie powinna miec.. dla przykladu pokaze jak ja tozrbilem:

  1. <?php
  2. class client
  3. {
  4. private $_sCompany;
  5. private $_sStreet;
  6. private $_sCity;
  7. private $_sZipCode;
  8. private $_iNip;
  9. private $_sEmail;
  10. private $_sPassword;
  11. private $_sTelephone;
  12. private $_iId;
  13. private $_oMySQL;
  14. private $_bNotification;
  15.  
  16. public function __construct($iClientId=null,$aClientData=null)
  17. {
  18. //if(!is_int($iClient))
  19. //throw new CleintException('must be int');
  20. if($iClientId != null)
  21. {
  22. $this->_iId = $iClientId;
  23. require('_configure.php');
  24. $this->_oMySQL = new DataBaseMySQL($aDBParams);
  25. $this->_oMySQL->query("SELECT * from client where id='$iClientId'");
  26. $aClientData = $this->_oMySQL->fetch();
  27. }
  28.  
  29. $this->setCompany($aClientData['company']);
  30. $this->setStreet($aClientData['street']);
  31. $this->setCity($aClientData['city']);
  32. $this->setZipCode($aClientData['zip']);
  33. $this->setNip($aClientData['nip']);
  34. $this->setEmail($aClientData['email']);
  35. $this->setPassword($aClientData['password']);
  36. $this->setTelephone($aClientData['telephone']);
  37. $this->setNotification($aClientData['want_email']);
  38. }
  39.  
  40. public function setCompany($sCompany)
  41. {
  42. $this->_sCompany = $sCompany;
  43. }
  44.  
  45. public function setStreet($sStreet)
  46. {
  47.  $this->_sStreet = $sStreet;
  48. }
  49.  
  50. public function setCity($sCity)
  51. {
  52.  $this->_sCity = $sCity;
  53. }
  54.  
  55. public function setZipCode($sZip)
  56. {
  57. $this->_sZipCode = $sZip;
  58. }
  59.  
  60. public function setNip($iNip)
  61. {
  62. $this->_iNip = $iNip;
  63. }
  64.  
  65. public function setEmail($sEmail)
  66. {
  67. $this->_sEmail = $sEmail;
  68. }
  69.  
  70. public function setPassword($sPassword)
  71. {
  72. $this->_sPassword = $sPassword;
  73. }
  74.  
  75. public function setTelephone($sTelephone)
  76. {
  77. $this->_sTelephone = $sTelephone;
  78. }
  79.  
  80. public function setNotification($bNotify)
  81. {
  82. $this->_bNotification = (int)(bool)(int)$bNotify;
  83. }
  84.  
  85. public function getCompany()
  86. {
  87. return $this->_sCompany;
  88. }
  89.  
  90. public function getStreet()
  91. {
  92. return $this->_sStreet;
  93. }
  94.  
  95. public function getCity()
  96. {
  97. return $this->_sCity;
  98. }
  99.  
  100. public function getZipCode()
  101. {
  102. return $this->_sZipCode;
  103. }
  104.  
  105. public function getNip()
  106. {
  107. return $this->_iNip;
  108. }
  109.  
  110. public function getEmail()
  111. {
  112. return $this->_sEmail;
  113. }
  114.  
  115. public function getPassword()
  116. {
  117. return $this->_sPassword;
  118. }
  119.  
  120. public function getTelephone()
  121. {
  122. return $this->_sTelephone;
  123. }
  124.  
  125. public function getId()
  126. {
  127. return $this->_iId;
  128. }
  129.  
  130. public function getNotification()
  131. {
  132. return $this->_bNotification;
  133. }
  134.  
  135. public function getArrayed()
  136. {
  137.  
  138.  return array('email' => $this->_sEmail,
  139. 'password' => $this->_sPassword,
  140. 'company' => $this->_sCompany,
  141. 'street' => $this->_sStreet,
  142. 'city' => $this->_sCity,
  143. 'zip' => $this->_sZipCode,
  144. 'nip' => $this->_iNip,
  145. 'telephone' => $this->_sTelephone,
  146. 'want_email' => $this->_bNotification);
  147. }
  148.  
  149. public function update()
  150. {
  151. $oMySQL = $this->_oMySQL;
  152. $oMySQL->update('client',$this->getArrayed(),"id='$this->_iId'");
  153. }
  154.  
  155. public function delete()
  156. {
  157. $oMySQL = $this->_oMySQL;
  158. $oMySQL->query("DELETE from client where id='$this->_iId'");
  159. }
  160.  
  161. public function getReports()
  162. {
  163.  
  164.  $oReportCollectioner = new ReportCollectioner();
  165.  $oMySQL = $this->_oMySQL;
  166.  $oMySQL->query("SELECT id from report where client_id='$this->_iId'");
  167.  while($aRow = $oMySQL->fetch())
  168.  {
  169. $oReportCollectioner->pushReport(new report($aRow['id']));
  170.  }
  171.  
  172.  return $oReportCollectioner;
  173.  
  174. }
  175.  
  176. public function __toString()
  177. {
  178. return $this->_sCompany;
  179. }
  180.  
  181. public function addSelf()
  182. {
  183. require('_configure.php');
  184.  
  185. $this->_oMySQL = new DataBaseMySQL($aDBParams);
  186. $aClientData = $this->getArrayed();
  187. $aClientData['id'] = null;
  188.  
  189. $this->_oMySQL->insert('client', $aClientData);
  190. }
  191.  
  192.  
  193. }
  194. ?>


W klasie tej uzylem Liba do laczenia z baza, zywcem z Rapide...

dalej mamy Client Collectioner:

  1. <?php
  2. class ClientCollectioner implements Iterator
  3. {
  4.  
  5. private $_aClients;
  6. private $_bValidIterationPointer = true;
  7.  
  8. public function __construct(){
  9. $this->_aClients = array();
  10. }
  11.  
  12. public function rewind()
  13. {
  14. reset($this->_aClients);
  15. $this->_bValidIterationPointer = true;
  16. }
  17.  
  18. public function current()
  19. {
  20. return current($this->_aClients);
  21. }
  22.  
  23. public function key()
  24. {
  25. return key($this->_aClients);
  26. }
  27.  
  28. public function next()
  29. {
  30. if(next($this->_aClients) === false)
  31. $this->_bValidIterationPointer = false;
  32. else
  33. $this->_bValidIterationPointer = true;
  34. }
  35.  
  36. public function valid()
  37. {
  38. return $this->_bValidIterationPointer;
  39. }
  40.  
  41. public function pushClient(client $oClient)
  42. {
  43. array_push($this->_aClients, $oClient);
  44. //sort($this->_aClients);
  45. }
  46.  
  47. public function isFilled()
  48. {
  49. return count($this->_aClients) != 0 ? true : false;
  50. }
  51.  
  52. }
  53. ?>



i to wszystko, mozemy dodac klienta:

  1. <?php
  2. $aClientData = array('id' => null,
  3. 'email' => $_POST['email'],
  4. 'password' => md5($_POST['passwordfirst']),
  5. 'company' => $_POST['company'],
  6. 'street' => $_POST['street'],
  7. 'city' => $_POST['city'],
  8. 'zip' => $_POST['zip'],
  9. 'nip' => $_POST['nip'],
  10. 'telephone' => $_POST['telephone']);
  11.  
  12.  $oClient = new Client(null,$aClientData);
  13.  $oClient->addSelf();
  14. ?>


edytowac:

  1. <?php
  2. $oClient = new Client($iId);
  3. $oClient->setCompany($_POST['company']);
  4. $oClient->setEmail($_POST['email']);
  5. $oClient->setStreet($_POST['street']);
  6. $oClient->setZipCode($_POST['zip']);
  7. $oClient->setCity($_POST['city']);
  8. $oClient->setNip($_POST['nip']);
  9. $oClient->setTelephone($_POST['telephone']);
  10. $oClient->update();
  11. ?>


lub usuwac:

  1. <?php
  2. $oClient = new Client($_GET['id']);
  3. $oClient->delete();
  4. ?>


uff. mam nadzieje, ze zrozumiesz jak cos to sluze pomoca smile.gif

ofc: co do client collectioner mozemy go uzupelnic:
  1. <?php
  2. $oClientCollectioner = Utils::fillUpClientCollectioner($_GET['p'],$_GET['k']);
  3. ?>

i podac do foreach:
  1. <?php
  2. foreach($oClientCollectioner as $oClient)
  3.  {
  4.  ($styl=='nieparzysty')$styl='parzysty' : $styl='nieparzysty';
  5.  echo '<tr class="'.$styl.'">';
  6. echo '<td class="dane_d" style="border-left:1px #999999 solid;">'.$oClient->getCompany().'</td>';
  7. echo '<td class="dane_d">'.$oClient->getNip().'</td>';
  8. echo '<td class="dane_d">'.$oClient->getEmail().'</td>';
  9. echo '<td class="dane_d">'.$oClient->getStreet().'</td>';
  10. echo '<td class="dane_d">'.$oClient->getZipCode().' '.$oClient->getCity().'</td>';
  11. echo '<td class="dane_d">';
  12. echo '<a href="?part=reports&action=screports&clientid='.$oClient->getId().'">Pokaż raporty</a>';
  13. echo '<br />';
  14. echo '<a href="?part=reports&action=add&clientid='.$oClient->getId().'">Dodaj raport</a>';
  15.  '</td>';
  16. echo '</tr>';
  17.  }
  18.  
  19.  echo '</tbody></table>';
  20. ?>
Jarod
Nie rozumiem skąd wziąłeś to:
  1. <?php
  2. $oClientCollectioner = Utils::fillUpClientCollectioner($_GET['p'],$_GET['k']);
  3. ?>


Tyle pisania, żeby zrobić dodawanie użytkownika i wyświetlanie go. Zaraz zagłębie się bardziej w ten kod. Doceniam, że chciało Ci się tyle pisać. Czyli jesli chcę wyświetlić listę użytkowników wykonuję coś podobnego:
1. Pobieram pierwszego użytkownika tworząć obiekt.
2. Ładuję ten obiekt do kolekcji.
3. Powtarzam punkt 1 i 2 n-razy (dopóki są rekordy w bazie)
4. Iterując kolekcję wyświetlam użytkowników na ekranie?

W dobrą strone idę?
envp
Tak, dokładnie, a fillup:

  1. <?php
  2. require_once('DatabaseMySQL.class.php');
  3. require_once('ClientCollectioner.class.php');
  4. require_once('Client.class.php');
  5.  
  6. final class Utils
  7. {
  8.  
  9. static public function getClientIds()
  10. {
  11. require('_configure.php');
  12. $oMySQL = new DataBaseMySQL($aDBParams);
  13. $oMySQL->query('SELECT id from client order by company asc');
  14. while($aRow = $oMySQL->fetch())
  15. $aIds[] = (int)$aRow['id'];
  16. return $aIds;
  17. }
  18.  
  19. static public function fillUpClientCollectioner($iStart=null, $iStop=null)
  20. {
  21. $aIds = Utils::getClientIds();
  22.  
  23. if($iStart == null && $iStop == null){
  24. $iStart = 0;
  25. $iStop = count($aIds);
  26. }
  27.  
  28.  
  29.  
  30. if($iStop>count($aIds))
  31. {
  32. $iStop = count($aIds);
  33. }
  34.  
  35. $oClientCollectioner = new ClientCollectioner();
  36. for($i=$iStart;$i<$iStop;$i++)
  37. {
  38. $oClientCollectioner->pushClient(new Client($aIds[$i]));
  39. }
  40.  
  41. return $oClientCollectioner;
  42. }
  43.  
  44. ...
  45. ?>
g00fy
ja bym raczej nie bawil sie w takie rzeczy.
wolal bym sobie napisac klase z 40 lnijkami za pomoca phpDoctrine, i nie martwil bym sie o zadne relacje ,sql etc.
destroyerr
Chciałem zapytać czy jest rozsądne przy pobieraniu np. 10 klientów => 10 zapytań do bazy. Może to zły pomysł ale może lepiej przygotować tablice z Id klientów i wrzucić ją opowiednio do zapytania, korzystać z PDO i zwracać obiekty, wsadzić do tablicy zwrócić tablicę do Util::fillUpClientCollectioner() i wniej w pętli dopiero dodać do kolekcji??
I jeszcze jedno pytanie, jeśli klienci/użytkownicy należą do grup. To czy do pola klasy client::groups należy wstawić tablice z id poszczególnych grup?? Czy skorzystać z kolektora grup i w tym polu trzymać obiekt kolektora grup??
Athlan
destroyerr, jeżeli chodzi o grupy użytkowników, to zazwyczaj robi się 3 tabele:
- tabela userów
- tabela grup
- handler relacji user to group

Przykładowa budowa tabel:

user table:
- id usera
- nick usera
- haslo usera

groups table:
- id grupy
- nazwa grupy

handler:
- id usera
- id grupy
(na oba pola dajesz klucz priamry)

Logując uzytkownika pobierasz jego grupy z handlera, ewentualnie nazwy grup biorąc je JOIN'em przez jej id.

Zastosowanie proste, a jakże pratyczne - chyba każdy tak robi.

Pozdrawiam, Athlan smile.gif
kwiateusz
ja bym pominal handler i w user table: dopisał id grupy wydaje mi sie ze tak jest intuicujniej .. i mniej tabel winksmiley.jpg
ikioloak
taa ale pod warunkiem ze jeden user moze nalezec do jednej grupy. jesli moze naliczyc do wielu, to jest to relacja wiele do wielu i rozwiazanie powyzej jest poprawne.
siemakuba
Pytanie z innej beczki:
czy dodawanie/pobieranie klasy User nie lepiej zorganizować za pomocą magicznej metody __call()?

Montujemy metodę:
  1. <?php
  2. function __call($method, $params, $return)
  3. {  
  4. $method = strtolower($method);
  5.  
  6. if (strpos($method, 'set') === 0)
  7. {
  8. $data = '_s'.ucfirst(str_replace('set', '', $method));
  9. if (isset($this->$data))
  10. {  $this->$data = $params[0];
  11. }
  12. }
  13. else if (strpos($method, 'get') === 0)
  14. {
  15. $data = '_s'.ucfirst(str_replace('get', '', $method));
  16. $return = isset($this->$data) ? $this->$data : null;
  17. }
  18. else
  19. {  $return = false;
  20. return false;
  21. }
  22.  
  23. return true;
  24. }
  25.  
  26. // wykorzystanie
  27.  
  28. $obj->setName('siemakuba');
  29. $obj->getName('siemakuba');
  30. ?>


to dość przykładowe oczywiście, ale oszczędza pisania oddzielnych metod dla poszczególnych wartość.
Używam czegoś takiego w mojej klasie AppModel i sprawdza się znakomicie. Nie wyobrażam sobie ręcznego mapowania wszystkich właściwości poszczególnych klas potomnych modelu na odpowiadające im tabele w bazie danych.

pozdr.
ikioloak
@siemakuba w czym twoje rozwiazanie jest lepsze od zastosowania __get i __set. Po przegladnieciu twojego kodu nie bardzo rozumiem jaki jest sens jego stosowania.
siemakuba
@ikioloak: to co pokazałem to mój sposób na korzystanie z metod typu:

  1. <?php
  2. $obj->setName('whatever');
  3. $obj->getName();
  4. ?>
bez konieczności pisania metody do każdej właściwości klasy którą chcę w ten sposób ustawić.

Nigdzie nie napisałem, że jest to lepsze niż stosowanie metod __get i __set ;) Napisałem, że jest to lepsze niż pisanie n metod pobierających / zwracających dane z klasy. Popatrz na pierwszy post i zobacz ile tego tam jest. Można tu owszem użyć __get i __set, ale wtedy rezygnujemy z konstrukcji:
  1. <?php
  2. $obj->setName('whatever');
  3. $obj->getName();
  4. ?>
na rzecz:
  1. <?php
  2. $obj->Name = 'whatever';
  3. ?>
bez znaczenia czy będzie to już teraz realizowane przez __get i __set czy nie.

pozdr.
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.