Ostatnio w projekcie Symfony 1.1 z użyciem Doctrine, dzięki webdebug toolbarowi, dostrzegłem czegoś, co mnie przeraziło. Otóż, jeśli w wygenerowanym przez Symfony adminie mamy klucze obce na liście, to wywoła on tyle zapytań ile elementów * ilość kluczy obcych.

Załóżmy, że mamy następujący schemat:

Kategoria:
  columns:
    nazwa: string(255)

Produkt:
  columns:
    nazwa: string(255)
    kategoria_id: integer
  relations:
    kategoria:
      class: Kategoria

Natomiast w generator.yml mamy zdefiniowane:

generator:
  class:              sfDoctrineAdminGenerator
  param:
    model_class:      Produkt
    theme:            default
    list:
      display:        [nazwa,kategoria]

To w przypadku kategoria, generator będzie wywoływał zapytanie w stylu

select * from kategoria where id = ?

co przy domyślnych 20 rekordach na stronę i przykładowo 3 kluczach obcych wygeneruje ponad 60 zapytań. Tego prawdopodobnie nie chcemy.

Rozwiązaniem w tej sytuacji jest zastosowanie parametru peer_method (znanego mi jeszcze z czasów używania Propela), znajdujące się w sekcji list.

Występuje tu jednak kilka założeń, o których warto wiedzieć. Po pierwsze: metoda którą określamy w peer_method musi znajdować się w klasie wskazanej w model_class (w naszym przypadku Produkt) i nie może być to metoda statyczna. Po drugie: metoda ta musi zwracać instancję klasy Doctrine_Query. Po trzecie, metoda ta musi mieć zakończenie nazwy pod postacią TableProxy. Po czwarte (tu tkwi największy trick): w złączeniach DQL nie możemy używać własnych aliasów, tylko aliasować pełnymi nazwami klas.

Oto przykład:

plik /lib/model/doctrine/Produkt.class.php

class Produkt extends BaseProdukt
{
  public function polaczZKategoriamiTableProxy()
  {
    return Doctrine_Query::create()->from('Produkt')->innerJoin('Produkt.kategoria'); //->from('Produkt p')->innerJoin('p.kategoria') jest błędne!
  }
}

plik /apps/backend/modules/produkty/config/generator.yml

generator:
  class:              sfDoctrineAdminGenerator
  param:
    model_class:      Produkt
    theme:            default
    list:
      peer_method:    polaczZKategoriami
      display:        [nazwa,kategoria]

Dzięki temu w znaczynym stopniu ograniczymy zapytania do bazy 🙂

edit: już wkrótce to rozwiązanie tego samego problemu dla Symfony 1.2 (tam niestety zrezygnowano z peer_method).