2011-11-22 8 views
6

Od jakiegoś czasu staram się używać funkcji Containable Behavior w CakePHP, ale nie mogę sprawić, by działało tak, jak się spodziewałem.CakePHP: Korzystanie z wielopoziomowego zachowania się w kontenerze

Moja aplikacja jest inna, ale dla uproszczenia wstawię ten przykład. Załóżmy, że mam forum z wątkami i działaniami, a działania można ocenić. Ogólne stosunki byłoby:

Forum: hasMany [Temat]
Temat: belongsTo [Forum] hasMany [Aktywny]
aktywny: belongsTo [Temat] hasMany [Ranking]
Ocena: belongsTo [Aktywny]

To, co chcę osiągnąć, to za pomocą metody wyszukiwania uzyskać wszystkie oceny wystawione na określonym forum. Co Przypuszczam, należy zrobić to:

$this->Rating->find('count', array(
    'contain' => array(
     'Activity' => array(
      'Thread' 
     ) 
    ), 
    'conditions' => array(
     'Thread.forum_id' => 1 
    ) 
)); 

Ale zapytanie wynikiem jest:

SELECT COUNT(*) AS `count` FROM `ratings` AS `Rating` LEFT JOIN `activities` AS `Activity` ON (`Rating`.`activity_id` = `Activity`.`id`) WHERE `Thread`.`forum_id` = 1; 

Mam dokonał tego za pomocą „łączy” opcji, ale jest to bardziej skomplikowane i muszę używaj tego rodzaju działań w wielu sytuacjach.

Wszystkie pliki związane z tym przykładzie można znaleźć tutaj: http://dl.dropbox.com/u/3285746/StackOverflow-ContainableBehavior.rar

Dzięki

Aktualizacja 23/11/2011

Po zbadaniu ramy i dzięki odpowiedziach Moz Morris i api55 Znalazłem źródło problemu.

Podstawowy problem polegał na tym, że jak rozumiem CakePHP, pomyślałem, że za każdym razem wysyła zapytanie za pomocą złączeń. Chodzi o to, że nie robi tego, że prawdziwa praca to wykonać, aby uzyskać wynik szukałem byłoby coś takiego:

SELECT * FROM Rating JOIN Activity... 
SELECT * FROM Activity JOIN Thread... 
SELECT * FROM Activity JOIN Thread... 
... 

znaczy, że byłoby to zrobić kwerendę, aby wszystkie działania a następnie, dla każdego działania, wykonaj zapytanie, aby uzyskać wątki ... Moje podejście zawodziło nie z powodu niewłaściwego użycia funkcji Containable Behavior, ale ponieważ opcja "conditions" została zastosowana do wszystkich zapytań i, po pierwsze, rozbił się z powodu braku tabeli wątków. Po znalezieniu na to uwagę, istnieją dwa możliwe rozwiązania:

  • Jak api55 powiedział, stosując warunki wewnątrz „zawierać” tablicy byłoby zastosować je tylko na zapytania z wykorzystaniem tabeli wątku. Ale robiąc to, problem nadal istnieje, ponieważ mamy zbyt wiele pytań.

  • Jak powiedział Moz Morris, działanie modelu Thread na Rating również będzie działało i wykona pojedyncze zapytanie, czego chcemy. Problem polega na tym, że widzę to jako łatę, która pomija relacje pomiędzy modelami i nie jest zgodna z filozofią CakePHP.

Rozwiązałem api55 jako poprawną, ponieważ rozwiązuje ona konkretny problem, który miałem, ale oba rozwiązują problem.

Odpowiedz

5

Po pierwsze, czy umieściłeś zmienną "actAs" w appModelu ??bez niego to beahaviour w ogóle nie zadziała (widzę, że nie działa poprawnie, ponieważ nie przyłączył się do tabeli wątków)

Zrobiłbym to od góry, mam na myśli z forum, więc wybierasz swoje forum (nie jestem pewien, czy chcesz forum lub wątku) i uzyskać wszystkie jego oceny, jeśli tam brak oceny zostaniesz z pustym kluczem oceny.

coś takiego

appModel

public $actsAs = array('Containable'); 

kontrolera znamionowej

$this->Rating->Activity->Thread->Forum->find('count', array(
    'contain' => array(
     'Thread' => array(
      'Activity' => array(
       'Rating' => array (
         'fields' => array ('Rating.*') 
       ) 
      ) 
     ) 
    ), 
    'conditions' => array(
     'Forum.id' => 1 
    ) 
)); 

Następnie jeśli trzeba tylko wartość w tabeli znamionowej wystarczy użyć Set: ekstrakt aby uzyskać tablicę tej wartości .

Jak to zrobiłeś to powinno działać tak czy inaczej, ale ja sugest nie używać forum_id tam, ale w warunkach wewnątrz zawierać jak ten

'contain' => array(
    'Activity' => array(
     'Thread' => array(
       'conditions' => array('Thread.forum_id' => 1) 
     ) 
    ) 
), 

Ponadto, nigdy nie zapomnieć o zmiennej actsas w modelu za pomocą mieszczące behaviuor (lub w modelu aplikacji)

+0

Przeniesienie "warunków" wewnątrz tablicy wątków nie będzie działać, ponieważ wyniki będą nadal zwracane dla wszystkich innych elementów, z pustą tablicą "Wątek". –

+0

@MozMorris to prawda, ponieważ zostało złączone ... ale jeśli uruchomi go z góry (z forum/wątku), otrzyma wszystkie oceny lub puste, ale będzie miał dużo irytującego drzewa (zwykle używam linkable zachowanie) – api55

+0

Dzięki za odpowiedź. Próbowałem tego na kodzie podanym w linku, a zapytanie to: SELECT COUNT (*) AS count Z forów AS Forum WHERE Forum.id = 1'. Mam już ustawienie Containable Behavior ustawione na AppModelu i wszystko. Nie wiem, czy mam jakiś problem z konfiguracją, czy coś takiego, ale wygląda na to, że nie działa poprawnie. –

2

Whist Podobał mi się rozwiązanie api55, myślę, że wyniki są trochę chaotyczne - zależy to od tego, co zamierzasz zrobić z danymi, które myślę.

Przypuszczam, że kiedy mówi używając „łączy” metodę Mówiłeś o użyciu tej metody:

$this->Rating->bindModel(array(
    'belongsTo' => array(
    'Thread' => array(
     'foreignKey' => false, 
     'conditions' => 'Thread.id = Activity.thread_id', 
    ), 
    'Forum' => array(
     'foreignKey' => false, 
     'conditions' => 'Forum.id = Thread.forum_id' 
    ) 
) 
)); 

$ratings = $this->Rating->find('all', array(
    'conditions' => array(
    'Forum.id' => 1 // insert forum id here 
) 
)); 

To właśnie wydaje się nieco czystsze do mnie, a nie trzeba się martwić o używaniu możliwe do opanowania zachowanie w swoim AppModelu. Warte rozważenia.

+0

Jeśli potrzebujesz hrabiego, to po prostu zamień "wszystkie" na "count", oczywiście. :) –

+0

Nigdy nie myślałem o tym XD, ale to jest jego czystsze, w przeciwnym razie daje wiele rekursji ... – api55

+0

Dziękuję za odpowiedź, która działałaby na tym przykładzie. Problem polega na tym, że w prawdziwej aplikacji muszę to robić wiele razy i chcę zrobić to bardziej modułowo (mając tablicę z "włączonymi" modelami do użycia). Robiąc to, co powinieneś, powinienem także ustawić wszystkie warunki za każdym razem. Poza tym, budzi mnie to, że to nie działa, to jest to, na co powinno się polegać działanie Containable Behavior, nie wiem, czy czegoś brakuje. W każdym razie dziękuję. –

Powiązane problemy