Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [ZendFramework] Dorobienie przycisku "wyświetl więcej"
Forum PHP.pl > Forum > PHP > Frameworki
Ravik
Witam,

Mam tutaj kod PHP odpowiadający za wyśietlenie określonych rekordów z bazy danych, których ilość na stronie jest limitowana również rekordem z bazy danych. Chodzi mi o to, że w pliku widoku chcę umieścić przycisk "wyświetl więcej" i po kliknięciu tego przycisku przeładowuje się strona i ilość wyświetlanych rekordów zwiększa się o 10. Przy kolejnym kliknięciu ma się dziać dokładnie to samo. Nie mam pojęcia jak zrobić to w Zendzie. W jaki sposób mam zmodyfikować ten kod PHP, aby po klknięciu w link zmienić zmienną $limit o +10 i w jaki sposób wysłać to w pliku wyglądu?

Będę wdzięczny za wszelkie wskazówki.

Pozdrawiam

  1. function newAction() {
  2.  
  3. $db = Zend_Registry::get('db');
  4. $db->setFetchMode(Zend_Db::FETCH_OBJ);
  5.  
  6. $settings = new SettingsTable;
  7. $limit = $settings->fetchRow('title = "newLimit"'); // limit pobierany z bazy danych i na tej podstawie jest określona liczba ogłoszeń, które mają się pojawiać na stronie
  8.  
  9. $select = $db->select();
  10. $select->from('advertisements', array('id', 'areaSize', 'price', 'description', 'city', 'announceDate', 'promo'))
  11. ->joinInner('propertyTypes', 'propertyTypes.id = advertisements.propertyType', 'type as propertyType')
  12. ->joinInner('advertisementTypes', 'advertisementTypes.id = advertisements.advertisementType', 'type as advertisementType')
  13. ->joinInner('provinces', 'provinces.id = advertisements.province', 'province')
  14. ->joinLeft('images', 'images.advertisementId = advertisements.id', 'image')
  15. ->where('dayCounter > 0')
  16. ->group('id')
  17. ->limit($limit->value, 0);
  18.  
  19. $result = $db->query($select);
  20. $this->view->advertisements = $result->fetchAll();
  21. $this->view->hideBack = 1;
  22.  
  23. }
Pilsener
Nie jestem pewien, czy paginator to akurat to, czego Ravik potrzebuje wink.gif

Przede wszystkim:
1. Pobranie danych z bazy to zadanie dla modelu
2. Link więcej to po prostu link do tej samej akcji z dodatkowym parametrem: page.com/module/controller/action/more/1

Obsługujesz to w kontrolerze tak:
  1. $model = new Model_YourTable();
  2. $this->view->data = $model->getYourData($this->_getParam('more'));


A w modelu tworzysz metodę z parametrem more:
  1. public function getYourData($more=null){
  2. //tutaj kod zapytania do bazy
  3.  
  4.  
  5. //obsługa parametru np. taka
  6. if(empty($more)){
  7. $select->limit(10);
  8. }else{
  9. $select->limit(10*$more);
  10. }
  11. }


Ale ja bym najlepiej to widział tak, że po prostu ajaxem to doładowujesz, bez przeładowywania strony. Chyba, że zależy nam mocno na liczbie odsłon.
Ravik
A czy potrzeba dopisać do tego linku routing? I w jaki sposób odwołać się to tej funkcji? Tzn. jak to się robi, bo w Zendzie jestem kompletnie zielony. I dziękuję za odpowiedź.
viking
Przede wszystkim Zend_Db ma metodę limitPage() która za Ciebie odpowiednio preparuje limitowanie danych. Tylko pokazujesz która strona i ile wyników per page. W routerze możesz sobie ustalić maskę że strona to [1-9][0-9]. Reszta to już wedle życzenia w kontrolerze. Czy paginator do tego wykorzystać to już twoja sprawa w zależności od potrzeb.
Ravik
Niech Wam Bóg w dzieciach wynagrodzi smile.gif

Niestety w żaden sposób tego pojąć nie mogę. W folderze modelu mam tylko pliki z kodem wyglądającym tak:

  1. class AdvertisementsTable extends Zend_Db_Table_Abstract {
  2. protected $_name = 'advertisements';
  3. protected $_primary = 'id';
  4. }
  5.  


Tylko w kolejnych plikach zmienia się $_name i $_primary. W modelu nie ma ani jednej funkcji zwracającej lub pobierającej coś.
Wszystko jest w plikach kontrolera. Plik który mi odpowiada za wyświetlanie tych rekordów wygląda tak:


  1. class AdvController extends Properties_Controller_Action {
  2.  
  3. function newAction() {
  4.  
  5. $db = Zend_Registry::get('db');
  6. $db->setFetchMode(Zend_Db::FETCH_OBJ);
  7.  
  8. $settings = new SettingsTable;
  9. $limit = $settings->fetchRow('title = "newLimit"');
  10.  
  11. $select = $db->select();
  12. $select->from('advertisements', array('id', 'areaSize', 'price', 'description', 'city', 'announceDate', 'promo'))
  13. ->joinInner('propertyTypes', 'propertyTypes.id = advertisements.propertyType', 'type as propertyType')
  14. ->joinInner('advertisementTypes', 'advertisementTypes.id = advertisements.advertisementType', 'type as advertisementType')
  15. ->joinInner('provinces', 'provinces.id = advertisements.province', 'province')
  16. ->joinLeft('images', 'images.advertisementId = advertisements.id', 'image')
  17. ->where('dayCounter > 0')
  18. ->group('advertisements.id')
  19. ->order('announceDate DESC')
  20. ->limit($limit->value, 0);
  21.  
  22. $result = $db->query($select);
  23. $this->view->advertisements = $result->fetchAll();
  24. $this->view->hideBack = 1;
  25.  
  26. }
  27. }


Wygląda na to, że nie został tu poprawnie zastosowany model MVC i teraz nie mam pojęcia jak zastosować wiedzę, którą mi przekazaliście, bo zbyt dużo pojęcia o Zendzie nie mam. Będę wdzięczny z jakieś wskazówki dotyczące mojego problemu związanego z wyświetleniem dodatkowych 10 rekordów w funkcji newAction po klknięciu przycisku w widoku.

Pozdrawiam
Pilsener
Cytat
zbyt dużo pojęcia o Zendzie nie mam
- zawsze można zajrzeć do dokumentacji, co prawda taka ona sobie ale lepsze to niż nic wink.gif

Dobrze montujesz zapytanie do bazy, musisz tylko przenieść to do modelu.
Cytat
Tylko w kolejnych plikach zmienia się $_name i $_primary. W modelu nie ma ani jednej funkcji zwracającej lub pobierającej coś.
- name to nazwa tabeli a primary to klucz główny - zalecane jest, aby jedna tabela w bazie odpowiadała jednemu modelowi stąd takie kodowanie.

Dlatego musisz dodać metodę (czy tam funkcję) do modelu:
  1. class AdvertisementsTable extends Zend_Db_Table_Abstract {
  2.  
  3. protected $_name = 'advertisements';
  4. protected $_primary = 'id';
  5.  
  6. public function getData($more=null){
  7.  
  8. }
  9. }


A wywołać ją w kontrolerze:
  1. $model = new Model_AdvertisementsTable();
  2. $this->view->data = $model->getData($this->_getParam('more'));


Oczywiście do metody getData wstawiasz swoje zapytanie:
  1. class AdvertisementsTable extends Zend_Db_Table_Abstract {
  2.  
  3. protected $_name = 'advertisements';
  4. protected $_primary = 'id';
  5.  
  6. public function getData($more=null){
  7. $select = $this->select();
  8. $select->setIntegrityCheck(false); //to takie dziwadło, domyślnie jest 'true' i nie można pobrać danych z innej tabeli (np. typu ogłoszenia)
  9. $select->from($this->_name, array('id', 'areaSize', 'price', 'description', 'city', 'announceDate', 'promo'))
  10. ->joinInner('propertyTypes', 'propertyTypes.id = advertisements.propertyType', 'type as propertyType')
  11. ->joinInner('advertisementTypes', 'advertisementTypes.id = advertisements.advertisementType', 'type as advertisementType')
  12. ->joinInner('provinces', 'provinces.id = advertisements.province', 'province')
  13. ->joinLeft('images', 'images.advertisementId = advertisements.id', 'image')
  14. ->where('dayCounter > 0')
  15. ->group('advertisements.id')
  16. ->order('announceDate DESC')
  17. ->limit($more, 0);
  18. return $this->fetchAll($select);
  19. }
  20. }


Taka jest mniej więcej logika tego.
Ravik
Kod, który podałeś mi do modelu wkleiłem do tej samej akcji, która odpowiada za wyświetlenie ogłoszeń na stronie głównej (od razu po jej załadowaniu). Czy zrobiłem to w dobrym miejscu?

plik AdvController.php
  1. function newAction() {
  2.  
  3. $db = Zend_Registry::get('db');
  4. $db->setFetchMode(Zend_Db::FETCH_OBJ);
  5.  
  6. $settings = new SettingsTable;
  7. $limit = $settings->fetchRow('title = "newLimit"');
  8.  
  9. $select = $db->select();
  10. $select->from('advertisements', array('id', 'areaSize', 'price', 'description', 'city', 'announceDate', 'promo'))
  11. ->joinInner('propertyTypes', 'propertyTypes.id = advertisements.propertyType', 'type as propertyType')
  12. ->joinInner('advertisementTypes', 'advertisementTypes.id = advertisements.advertisementType', 'type as advertisementType')
  13. ->joinInner('provinces', 'provinces.id = advertisements.province', 'province')
  14. ->joinLeft('images', 'images.advertisementId = advertisements.id', 'image')
  15. ->where('dayCounter > 0')
  16. ->group('advertisements.id')
  17. ->order('announceDate DESC')
  18. ->limit($limit->value, 0);
  19.  
  20. $model = new AdvertisementsTable();
  21. $this->view->data = $model->getData($this->_getParam('more'));
  22.  
  23. $result = $db->query($select);
  24. $this->view->advertisements = $result->fetchAll();
  25. $this->view->hideBack = 1;
  26.  
  27. }


Plik modelu AdvertisementsTable.php wygląda tak:

  1. class AdvertisementsTable extends Zend_Db_Table_Abstract {
  2. protected $_name = 'advertisements';
  3. protected $_primary = 'id';
  4.  
  5. public function getData($more=null){
  6.  
  7. $select = $this->select();
  8. $select->setIntegrityCheck(false); //to takie dziwadło, domyślnie jest 'true' i nie można pobrać danych z innej tabeli (np. typu ogłoszenia)
  9. $select->from($this->_name, array('id', 'areaSize', 'price', 'description', 'city', 'announceDate', 'promo'))
  10. ->joinInner('propertyTypes', 'propertyTypes.id = advertisements.propertyType', 'type as propertyType')
  11. ->joinInner('advertisementTypes', 'advertisementTypes.id = advertisements.advertisementType', 'type as advertisementType')
  12. ->joinInner('provinces', 'provinces.id = advertisements.province', 'province')
  13. ->joinLeft('images', 'images.advertisementId = advertisements.id', 'image')
  14. ->where('dayCounter > 0')
  15. ->group('advertisements.id')
  16. ->order('announceDate DESC')
  17. ->limit($more, 0);
  18. return $this->fetchAll($select);
  19. }
  20.  
  21. }


Czy dobrze zrozumiałem Twój przekaz? I śmiem jeszcze prosić o informację w jaki sposób mam skonstruować link w pliku widoku, gdyż dokumentacja zenda jest dla mnie co najmniej dziwna, ale w wielu przypadkach pomogła.

Dziękuję Ci Pilsener za dotychczasową pomoc i tak nawiasem mówiąc to zauważyłem, że chyba jako jeden z niewielu na forum nie wymądrzasz się w stylu "ja jestem najmądrzejszy masz tu link, twój problem jest zbyt prosty".

Pozdrawiam
Pilsener
Wygląda dobrze, jeśli działa to czego więcej chcieć?

Linki najlepiej tworzyć przy pomocy helpera url:
  1. echo $this->url(array('module'=>'articles','controller'=>'index','action'=>'article','id'=>123,'title'=>'test'),null,true,true);


1 parametr - to tablica parametrów, przekazywanych w adresie
2 parametr - to nazwa routingu, dzięki temu możemy tworzyć własne routingi a potem je zmieniać dowolnie i nie musimy przepisywać wszystkich linków od nowa, wystarczy zmienić ustawienia routingu
3 parametr - to wykorzystywanie parametrów z aktualnego url, dzięki temu nie musisz ciągle wpisywać tych parametrów, które są już w url
4 parametr - to escapowanie znaków w url porzez urlencode

Wszystkie parametry są opcjonalne. Trochę praktyki i dojdziesz co i jak.
Pilsener
Jak chcesz tylko dodać more/10 to wystarczy w widoku coś takiego:
  1. echo $this->url(array('more'=>10));


Chyba, że link ma kierować do innego kontrolera/akcji.
Pilsener
Cytat
Renderuję plik promo.phtml do widoku odpowiadającego na stronę główną i ogłoszenia już się nie wyświetlają. Próbowałem kod z promo.phtml wkleić do pliku widoku strony głównej i to też nie pomagało. Co może być nie tak?
- renderowanie widoku jak sama nazwa wskazuje - łączy go tylko ze zmiennymi przekazanymi przez kontroler, w widoku masz do dyspozycji tylko te zmienne, które zostały przekazane w danym kontrolerze/akcji.

Czyli: jeśli renderujesz jakiś widok odpalając np. strona.pl/artykuly/pokaz - kontroler artykuły i akcję pokaż, to w tym widoku masz dostępne tylko te zmienne, które przekazujesz w kontrolerze artykuły i akcji pokaż.

Można z tym sobie poradzić używając w widoku np. helpera action:
  1. echo $this->action('action','controller','module');
- to po prostu wywoła jeszcze raz całą aplikację i wyświetli widok/widoki podpięte do tej akcji. Ale trzeba uważać, bo to obniża nam wydajność.

Można też stworzyć akcję do przekazywania tych parametrów do widoku i wywoływać ją wiele razy. Dlatego używa się modeli - pobierasz dane w jednym miejscu a potem je tylko przekazujesz do odpowiednich kontrolerów i widoków.

Jeśli chcesz mieć coś dostępnego w całym kontrolerze to użyj metody init - będzie ona wywoływana zawsze razem z kontrolerem a przekazane tam zmienne będa dostępne we wszystkich akcjach.
Ravik
Ok, wszystko pięknie działa i chyba zacznę się mocniej przykładać do zenda bo to rzeczywiście całkiem ciekawy i fajny framework.

Dziękuję za pomoc.
Pozdrawiam,
Ravik
viking
Tylko się nie przyzwyczajaj bo za ~4 miesiące będzie ZF2 wink.gif Z nowym odrobinę podejściem i przereklamowanymi namespace'ami.
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.