Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> [ZF][ZendFramework] Bodowa Modelu
markus12
post
Post #1





Grupa: Zarejestrowani
Postów: 2
Pomógł: 0
Dołączył: 18.02.2011

Ostrzeżenie: (0%)
-----


Witam,

większość z was na pewno zna poradnik Quickstart w dokumentacji ZendFrameworka. Jest tam przykład budowy prostej książki gości.

I teraz chciałem zrobić katalog książek w ZF. Mam w bazie tabelki: Book, Author, Book_Author, Book_Genre, itd. Bazując na przykładzie modelu z dokumentacji Quickstart mogę zrobić coś w tym stylu:

  1. class Application_Model_Book
  2. {
  3. protected $_title;
  4. protected $_id;
  5.  
  6. public function __construct(array $options = null)
  7. {
  8. if (is_array($options)) {
  9. $this->setOptions($options);
  10. }
  11. }
  12.  
  13. public function __set($name, $value)
  14. {
  15. $method = 'set' . $name;
  16. if (('mapper' == $name) || !method_exists($this, $method)) {
  17. throw new Exception('Invalid book property');
  18. }
  19. $this->$method($value);
  20. }
  21.  
  22. public function __get($name)
  23. {
  24. $method = 'get' . $name;
  25. if (('mapper' == $name) || !method_exists($this, $method)) {
  26. throw new Exception('Invalid book property');
  27. }
  28. return $this->$method();
  29. }
  30.  
  31. public function setOptions(array $options)
  32. {
  33. $methods = get_class_methods($this);
  34. foreach ($options as $key => $value) {
  35. $method = 'set' . ucfirst($key);
  36. if (in_array($method, $methods)) {
  37. $this->$method($value);
  38. }
  39. }
  40. return $this;
  41. }
  42.  
  43. public function setTitle($text)
  44. {
  45. $this->_title = (string) $text;
  46. return $this;
  47. }
  48.  
  49. public function getTitle()
  50. {
  51. return $this->_title;
  52. }
  53.  
  54. public function setId($id)
  55. {
  56. $this->_id = (int) $id;
  57. return $this;
  58. }
  59.  
  60. public function getId()
  61. {
  62. return $this->_id;
  63. }
  64. }


  1. class Application_Model_BookMapper
  2. {
  3. protected $_dbTable;
  4.  
  5. public function setDbTable($dbTable)
  6. {
  7. if (is_string($dbTable)) {
  8. $dbTable = new $dbTable();
  9. }
  10. if (!$dbTable instanceof Zend_Db_Table_Abstract) {
  11. throw new Exception('Invalid table data gateway provided');
  12. }
  13. $this->_dbTable = $dbTable;
  14. return $this;
  15. }
  16.  
  17. public function getDbTable()
  18. {
  19. if (null === $this->_dbTable) {
  20. $this->setDbTable('Application_Model_DbTable_Book');
  21. }
  22. return $this->_dbTable;
  23. }
  24.  
  25. public function save(Application_Model_Book $book)
  26. {
  27. $data = array(
  28. 'title' => $book->getTitle(),
  29. );
  30.  
  31. if (null === ($id = $book->getId())) {
  32. unset($data['id']);
  33. $this->getDbTable()->insert($data);
  34. } else {
  35. $this->getDbTable()->update($data, array('id = ?' => $id));
  36. }
  37. }
  38.  
  39. public function find($id, Application_Model_Book $book)
  40. {
  41. $result = $this->getDbTable()->find($id);
  42. if (0 == count($result)) {
  43. return;
  44. }
  45. $row = $result->current();
  46. $book->setId($row->id)
  47. ->setTitle($row->title);
  48. }
  49.  
  50. public function fetchAll()
  51. {
  52. $resultSet = $this->getDbTable()->fetchAll();
  53. $entries = array();
  54. foreach ($resultSet as $row) {
  55. $entry = new Application_Model_Book();
  56. $entry->setId($row->id)
  57. ->setTitle($row->title);
  58. $entries[] = $entry;
  59. }
  60. return $entries;
  61. }
  62.  
  63. }


  1. class BookController extends Zend_Controller_Action
  2. {
  3.  
  4. public function init()
  5. {
  6. /* Initialize action controller here */
  7. }
  8.  
  9. public function indexAction()
  10. {
  11. $book = new Application_Model_BookMapper();
  12. $this->view->entries = $book->fetchAll();
  13. }
  14.  
  15. }


To jest w 90% kod z dokumentacji ZF. Ciekawe podejście, jedna klasa do obiektu książki ze zmiennymi takimi jak kolumny w bazie, druga klasa do operacji z bazą, której przesyłamy obiekt tej pierwszej klasy.

To wszystko rozumiem i jest ok. Ale teraz dochodzę do tego, że chciałbym pobrać listę książek wraz z nazwiskami ich autorów, gatunkami do których są przypisane i wyświetlić taką listę np. 20 książek wraz z pełnymi informacjami o każdej. W tej chwili metoda FetchAll wyciąga mi wszystko z tabelki Book. Nie mam pojęcia w jaki sposób podejść do tego, żeby dołączyć do tego też dane z innych tabel.

Tabela Author_Book jest do relacji między książkami i autorami. (czyli książka ma kilku autorów).

Nie wiem jak to ładnie zrobić żeby było zgodne z MVC itd. Czy porzucić całkowicie tej sposób z dwoma klasami czy nie, po prostu proszę o wskazówki w jaki sposób się takie coś robi.

pozdrawiam!
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi
Lysiur
post
Post #2





Grupa: Zarejestrowani
Postów: 66
Pomógł: 11
Dołączył: 25.07.2012

Ostrzeżenie: (0%)
-----


Witam, chciałbym odświerzyć nieco temat, ponieważ męczy mnie to samo zagadnienie co @markus12. Chodzi mi dokładnie jak najlepiej rozwiązać problem, gdy potrzebujemy pobrać "przysłowiową" książkę, oraz jej autorów, gatunek, etc. Oczywiście możemy zrobić funckję fetchAllBook(), ale zastanawia mnie jej zawrtość.

Użytkownik @quality, podał rozwiązanie bazujące na Zend_Db_Select wszsytko jest okej, ale wynik zwracany jest w postaci tablicy, kórej część pól nie ma odwzorowania w modelu Book. Zakładając, że przyjmujemy, iż mapper zwraca nam obiekt, to jakie atrybuty powinna posiadać klasa Book?

  1. class Application_Model_Book {
  2.  
  3. protected $_id = null;
  4. protected $_title = null;
  5.  
  6. protected $_autors = array();
  7.  
  8. public function setAutor(Application_Model_Autor $oAutor) {
  9. $this->_autors[] = $oAutor;
  10. return $this;
  11. }
  12. //....
  13. }
  14.  
  15. //Mapper
  16. public function fetchAllBook()
  17. {
  18. $resultSet = $this->getDbTable()->fetchAllBook(); // Czy zamiast tego lepiej poprstu zrobić Zend_Db_Select i zbudować zapytanie, a nie używać ZEnd_Db_Table w Application_Model_DbTable_Autor
  19. $entries = array();
  20. foreach ($resultSet as $row) {
  21. $entry = new Application_Model_Book($row); //Konstruktor uzupełni atrybuty
  22. $entry->setAutor(new Application_Model_Autor($row)); //j/w (o ile nie zostaną nadpisane),
  23. $entries[] = $entry;
  24. }
  25. return $entries;
  26. }
  27.  


Męczy mnie to zagadnienie, i nie bardzo mogę znaleźć rozwiązanie które by mnie satysfakcjonowało. Bo teraz szybko się okaże, że trzeba będzie wyświetlić obok listy książki i autorów, np.: gatunek, dział w którym się znajduje oraz np.: budynek. Model będzie się rozrastał i rozrastał. Rozbudujemy obiekt wg. sposobu opisanego wyżej.

Idąc dalej krokiem, będzie potrzeba w którymś miejscu wyświetlić jescze adres budynku w którym ta książka się znajduje, i mamy (np.: w widoku):
  1. //@var $oBook Application_Model_Book
  2. foreach(.... $key => $oBook):
  3. .... $oBook->getDepartament()->getAddress()->getFullAddres();
  4. endforach;


W takiej sytuacji robi się pewne misz-masz, bo na jednej liście (widoku) będziemy potrzebować wszystkich danych (łącznie z działem i budynkiem), a w innym widoku (bez tych dodatkowych danych). Wywołując fetchAllBook (w maperze) pakujemy obiekt złożony mimo, że nie zawsze jest on potrzebny.

Można zrobić tak, że w modelu Book, zrobić tak, że:

  1. class Application_Model_Book {
  2. ...
  3. public function getDepartament() {
  4. $mDepartament = new DeparatamentMapper();
  5. $this->departament = $mDepartament->findByIdBook($this->_id);
  6. }
  7. ...
  8. }


Jednakże w takiej sytuacji przy foreachowaniu $oBook będziemy za każdym razem wysyłali dodatkowe sqlki.


Jak rozwiązujecie takie sytuacje??

Ten post edytował Lysiur 14.12.2012, 10:54:40
Go to the top of the page
+Quote Post

Posty w temacie


Reply to this topicStart new topic
2 Użytkowników czyta ten temat (2 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 13.03.2026 - 01:23