Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [ZF]Skojarzenia tabel
Forum PHP.pl > Forum > PHP > Frameworki
amii
Mam problem, którego nie mogę rozgryźć. Mam 4 table: users, trainings, training_instance oraz training_instance_user. Table są powiązane tak:

Do każdego jednego treningu może należeć wiele jego instancji
- Tabela trainings powiązana relacją 1:n z tabelą training_instance

Każdy użytkownik może brać udział w dowolnej ilości treningów i do każdego treningu może należeć wielu użytkowników
- Tabela trainings powiązana relacją n:m (wiele do wielu) z tabelą users za pomocą tabeli haszującej training_instance_user
- Tabela users powiązana relacją n:m z tabelą trainings za pomocą tabeli haszującej training_instance_user


Potrzebuję wypisać dane z tabel trainings oraz trainings_instance danego użytkownika kiedy jednocześnie spełnione są warunki:
training_instance_user->status =1
training_instance_user->canceled = 0
training_instance->date_start <= NOW()

Na razie robię to tak w kontrolerze przekazuję do widoku rekord z id użytkownika. W widoku z kolei pobieram trainings skojarzone z użytkownikiem, dzięki metodzie getInstance pobieram również skojarzoną training_instance i wyświetlam datę. Pytanie jak i gdzie dorzucić te dodatkowe warunki do zapytania ?
  1. //kontroler
  2. //pobieramy rekord dla zalogowanego usera
  3. $user_model = new Application_Model_DbTable_Users();
  4. $s = $user_model->select()->where('id = ?', $this->view->login->id);
  5. //przekazujemy dane zalogowanego usera do widoku
  6. $this->view->user = $user_model->fetchRow($s);
  7.  
  8. //widok
  9. foreach ($this->user->getCourses() as $kursy) {
  10. $data = $kursy->getInstance()->current()->date_start;
  11. echo "<tr><td>$kursy->title</td><td>$kursy->category</td><td>$data</td></tr>";
  12. }
  13.  
  14.  
  15. //pojedynczy rekord z tabeli users class Application_Model_DbTable_Users_Row extends Zend_Db_Table_Row
  16. //metoda pobiera liste treningów (z tabeli trainings) skojarzonych z danym uzytkownikiem (z tabeli users). Zwracany jest obiekt Zend_Db_Table_Rowset
  17. public function getCourses() {
  18. return $this->findManyToManyRowset(
  19. 'Application_Model_DbTable_Trainings',
  20. 'Application_Model_DbTable_TrainingInstanceUser'
  21. );
  22.  
  23. }
  24.  
  25.  
  26. //pojedynczy rekord z tabeli trainings class Application_Model_DbTable_Trainings_Row extends Zend_Db_Table_Row
  27. //metoda pobiera liste training_instance skojarzonych z danym rekordem trainings na rzecz, kto//pojedynczy rekord z tabeli users class Application_Model_DbTable_Users_Row extends Zend_Db_Table_Rowgo wywoływana jest metoda
  28. public function getInstance() {
  29. return $this->findDependentRowset('Application_Model_DbTable_TrainingInstance');
  30. }
Fluke
W kontrolerze

  1. $user_model = new Application_Model_DbTable_Users();
  2. $s = $user_model->select()->where('id = ?', $this->view->login->id)
  3. ->join(array('tr_in' => 'trainings_instance '), 'id = tr_in.idUser')
  4. ->join(array('tr_in_user' => 'traings_isntance_user'), 'tr_in.idUser = tr_in_user.Id')
  5. ->where('tr_in_user.status = ?', 1)
  6. ->where('tr_in_user.canceled = ?', 0)
  7. ->where('tr_in.date_start <= NOW()');
  8.  
  9. //przekazujemy dane zalogowanego usera do widoku
  10. $this->view->user = $user_model->fetchRow($s);


Lecz lepiej to zrobić w modelu typu masz model: Application_Model_DbTable_Users() oraz metode getUsersAndTrainsngs($idUser, $status, $canceled, $start);
amii
W takiej formie, zwraca mi zero rekordów. Robiłem rzutowanie obiektu $this-user jak i $this-user-getCourses().

W wersji z dwoma joinami obiekt:$this-user zwraca tablicę z 55 rekordami czyli ok bo pobieramy jednego usera.
Natomiast obiekt $this-user->getCourses() zwraca pustą tablicę i to jest problem.

W wersji z jednym join obiekt $this-user->getCourses() zwraca tablicę z dwoma danymi i to jest ok.
Natomiast obiekt $this-user zwraca tablicę z 36 danymi i to też jest ok.

  1. $user_model = new Application_Model_DbTable_Users();
  2. $s = $user_model->select(Zend_Db_Table_Abstract::SELECT_WITH_FROM_PART);
  3. $s->setIntegrityCheck(false);
  4. $s->from(array('u' => 'users'), array('id'))
  5. ->join(array('tui' => 'training_instance_user'), 'u.id=tui.id_user')
  6. ->join(array('tr_in' => 'training_instance'), 'tui.id_training_instance=tr_in.id_training') //jesli wytne tego joina jest ok
  7. ->where('u.id = ?', $this->view->login->id)
  8. ->where('tui.status = ?', 1)
  9. ->where('tui.canceled = ?', 0)
  10. ->where('tr_in.date_start <= NOW()'); //wycinam takze warunek dla join
  11. ;
  12. //przekazujemy dane zalogowanego usera do widoku
  13. $this->view->user = $user_model->fetchRow($s);


W phpmyadmin jeśli wykonam takie zapytanie dostaje 44 rekordy

  1. SELECT users . * , training_instance_user . * , training_instance . *
  2. FROM users
  3. JOIN training_instance_user ON users.id = training_instance_user.id_user
  4. JOIN training_instance ON training_instance_user.id_training_instance = training_instance.id_training
  5. WHERE users.id =106
  6. AND training_instance_user.STATUS =1
  7. AND training_instance_user.canceled =0
  8. AND training_instance.date_start <= NOW( )
Fluke
Pamiętaj o tym, że gdy masz 1 rekord w users i 5 rekordów powiązanych z tabelą users to mysql zwróci tablicę 5 wartości, gdzie dane user`a nie będą zmienione natomiast wartości w drugiej tabeli będą się zmienić.
amii
Może ktoś wyjaśnić dlaczego te dwa sposoby zwracają różną ilość rekordów ?


Sposób 1 w tym przypadku zwraca rekrody tak jak tego oczekuje i tak jak pokazuje phpmyadmin po przekopiowaniu zapytania:
  1.  
  2. //kontroler
  3. $kurs_model = new Application_Model_DbTable_Trainings();
  4.  
  5. $sql = 'SELECT T0.title, T0.category, T0.id, T0.seo_title,
  6. T1.date_start, T1.id AS id_instance
  7. FROM trainings AS T0 JOIN training_instance AS T1 ON T0.id=T1.id_training
  8. WHERE T1.date_start>=NOW() ORDER BY T1.date_start ASC';
  9.  
  10. $stmt = new Zend_Db_Statement_Mysqli($kurs_model->getAdapter(), $sql);
  11. $this->view->stmt = $stmt;
  12. $stmt->execute();
  13.  
  14. //widok
  15. while ($row = $this->stmt->fetch()) {
  16. $id_kursu = '<a target="_blank" href="http://www.stronka.pl/zapisz-sie?id='.$row['id_instance'].'">Zapisz się</a>';
  17. echo '<tr><td>'.$row['title'].'</td><td>'.$row['category'].'</td><td>'.$row['seo_title'].'</td><td>'.$id_kursu.'</td></tr>';
  18. }



Sposób 2 zwraca większą ilość rekordów w dodatku trzeba cudować ze złączeniami bo zend wymusza stosowanie kluczy obcych
  1. //kontroler
  2. $kurs_model = new Application_Model_DbTable_Trainings();
  3.  
  4. $s = $kurs_model->select(Zend_Db_Table_Abstract::SELECT_WITH_FROM_PART);
  5. $s->setIntegrityCheck(false);
  6. $s->distinct()->from(array('t' => 'trainings'), array('id', 'title','category', 'seo_title'))
  7. ->join(array('ti' => 'training_instance'), 't.id=ti.id_training')
  8. ->where('ti.date_start >= ?', new Zend_Db_Expr('NOW()'))
  9. ->order('ti.date_start ASC')
  10. ;
  11.  
  12. $this->view->kursy = $kurs_model->fetchAll($s);
  13.  
  14. //widok
  15. foreach ($this->kursy as $kurs) {
  16.  
  17. $id_kursu = '<a target="_blank" href="http://www.stronka.pl/zapisz-sie?id='.$kurs->id.'">Zapisz się</a>';
  18. echo "<tr><td>$kurs->title</td><td>$kurs->category</td><td>$kurs->seo_title</td><td>$id_kursu</td></tr>";
  19. }
Fluke
Zobacz czy select w 2 sposobie wygląda tak samo jak w 1.

  1. $kurs_model = new Application_Model_DbTable_Trainings();
  2.  
  3. $s = $kurs_model->select(Zend_Db_Table_Abstract::SELECT_WITH_FROM_PART);
  4. $s->setIntegrityCheck(false);
  5. $s->distinct()->from(array('t' => 'trainings'), array('id', 'title','category', 'seo_title'))
  6. ->join(array('ti' => 'training_instance'), 't.id=ti.id_training')
  7. ->where('ti.date_start >= ?', new Zend_Db_Expr('NOW()'))
  8. ->order('ti.date_start ASC')
  9. ;
  10.  
  11. echo $s; //powino ci zwrócić 'SELECT * FROM ....'

porównaj sobie czy takie same, jak nie to musisz dalej kombinować z join, where, order, itp...
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.