Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [Kohana] 3.1 _has_many
Forum PHP.pl > Forum > PHP > Frameworki
Kedan
Chciałbym utworzyć relację wiele-do-wielu obiektów tej samej klasy, tzn móc swobodnie pobierać potomków lub/i rodziców danej kategorii (każda kategoria może mieć wielu potomków i wielu rodziców). Mam taki model:
  1. class Model_Category extends ORM {
  2.  
  3. protected $_has_many = array(
  4. 'categories' => array(
  5. 'model' => 'category',
  6. 'through' => 'categories_categories'
  7. ),
  8. 'children' => array(
  9. 'model' => 'category',
  10. 'through' => 'categories_categories'
  11. )
  12. );
  13.  
  14. }


Tabele:
  1. CREATE TABLE IF NOT EXISTS `categories` (
  2. `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  3. `name` VARCHAR(64) NOT NULL,
  4. PRIMARY KEY (`id`)
  5. ) ENGINE=INNODB DEFAULT CHARSET=utf8;
  6.  
  7. CREATE TABLE IF NOT EXISTS `categories_categories` (
  8. `category_id` INT(10) UNSIGNED NOT NULL,
  9. `child_id` INT(10) UNSIGNED NOT NULL,
  10. PRIMARY KEY (`category_id`,`child_id`),
  11. KEY `fk_child_id` (`child_id`),
  12. KEY `fk_category_id` (`category_id`)
  13. ) ENGINE=INNODB DEFAULT CHARSET=utf8;
  14.  
  15. ALTER TABLE `categories_categories`
  16. ADD CONSTRAINT `categories_categories_ibfk_1` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE CASCADE,
  17. ADD CONSTRAINT `categories_categories_ibfk_2` FOREIGN KEY (`child_id`) REFERENCES `categories` (`id`) ON DELETE CASCADE;


Testując poniższym kodem:
  1. $model = new Model_Category(1);
  2. $array = $model->children->find_all();
  3. foreach($array as $obj) {
  4. echo $obj->name
  5. foreach($obj->categories as $parent) {
  6. print_r($parent); // zwraca Array()
  7. }
  8. }


Pobieranie potomków działa bez zarzutu - pobieranie rodziców zwraca pustą tablicę. Zastanawiam się jak to zrobić:
1. Utworzyć tabelę relacji z trzema kolumnami: category - parent - child (co dość kosmicznie wydłużyłoby tabelę relacji, dlategoż ten pomysł mi się nie podoba)
2. Utworzyć dwie osobne tabele relacji: jedną dla potomków, drugą dla rodziców (ku czemu się skłaniam)

Czy może jest jakiś bardziej elegancki sposób?
lukaskolista
  1. foreach($obj->categories as $parent) {
zmien na
  1. foreach($obj->categories->find_all() as $parent) {


Pamietaj, ze w KO3 przy relacji 1:n lub n:n dla rodzica (w tym przypadku rodzicem jest potomek) zawsze musisz uzyc find_all(), bo w KO2 chyba samo sie pobieralo (ale glowy nie dam)
Kedan
Przecierałem oczy ze zdumienia, jak mogłem nie zauważyć braku find_all(), ale to jednak nie to.
$obj->children->find_all() generuje zapytanie:
  1. SELECT `categories`.* FROM `categories` JOIN `categories_children` ON (`categories_children`.`child_id` = `categories`.`id`) WHERE `categories_children`.`category_id` = 27 ORDER BY `categories`.`id` ASC


natomiat $obj->categories->find_all() :
  1. SELECT `categories`.* FROM `categories` JOIN `categories_children` ON (`categories_children`.`category_id` = `categories`.`id`) WHERE `categories_children`.`category_id` = '257' ORDER BY `categories`.`id` ASC

gdzie tak naprawdę inny powinien być warunek WHERE i zapytanie powinno wyglądać tak:
  1. SELECT `categories`.* FROM `categories` JOIN `categories_children` ON (`categories_children`.`category_id` = `categories`.`id`) WHERE `categories_children`.`child_id` = '257' ORDER BY `categories`.`id` ASC


Nie wiem czy to problem kohany, czy po prostu zrypałem tabelę SQL. Zapytanie $obj->categories->where('child_id','=',$obj->id)->find_all(), też nic nie da, bo generuje się coś takiego:
  1. SELECT `categories`.* FROM `categories` JOIN `categories_children` ON (`categories_children`.`category_id` = `categories`.`id`) WHERE `categories_children`.`category_id` = '257' AND `child_id` = '257' ORDER BY `categories`.`id` ASC

Dopiero za pomocą:
  1. $obj->categories->or_where('categories_children.child_id','=',$obj->id)->find_all();

wskórałem coś sensownego.
  1. SELECT `categories`.* FROM `categories` JOIN `categories_children` ON (`categories_children`.`category_id` = `categories`.`id`) WHERE `categories_children`.`category_id` = '257' OR `categories_children`.`child_id` = '257' ORDER BY `categories`.`id` ASC

Ale to obejście problemu a nie rozwiązanie.
lukaskolista
moze ustaw jeszcze w modelu far_key i foreign_key, w przypadku has_many through foreign_key powinien wskazywac na swoj model, a far_key na model w relacji. Na przykladzie uzytkownika i jego roli

Model user
  1. protected $_has_many = array(
  2. 'roles' => array('model' => 'role', 'through' => 'users_roles', 'foreign_key' => 'user_id', 'far_key' => 'role_id')
  3. );
Kedan
O to to właśnie chodziło smile.gif Działa pięknie i bez zarzutu.
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.