Cross-application partial w symfony

Ostatnio zetknąłem się z problemem wspólnych partiali dla wszystkich aplikacji w projekcie Symfony (dokładnie frontend i backend). Dokładniej, to te partiale były templatkami mailowymi, wysyłanymi zarówno przy zdarzeniach wygenerowanych w frontendzie jak i w panelu administracyjnym. Jako, że ponad wszystko cenię zasadę DRY (Don’t Repeat Yourself, czyli Nie Powtarzaj Się), chciałem, aby moje templatki były napisane raz, a używane z każdego miejsca w projekcie. Pewnym rozwiązaniem byłoby zrobienie symlinka: apps/frontend/modules/mails -> apps/backend/modules/mails i to działa, ale nie jest zbyt eleganckie. Z pomocą przyszła analiza kodu Symfony (dzięki Bogu, że jest Open Source:-)).

Projekt w skrócie wygląda następująco: w aplikacji frontend, mamy moduł default z akcją index, w której to używamy partiala _hello. Partial ten natomiast leży w aplikacji backend w module mails. Z poziomu backendu dostęp do tego partiala jest bezproblemowy.

Cały przykładowy, działający projekt jest dostępny na githubie: http://github.com/wowo/crossApp

Zaczynamy od tego, że w configu mamy możliwość zdefiniowania klasy, która będzie odpowiedzialna za renderowanie partiali w poszczególnych modułach. Jest za to odpowiedzialny wpis mod_NAZWA-MODUŁU_partial_view_class. Aby to skonfigurować na nasze potrzeby, wpisujemy do ogólnej konfiguracji config/ProjectConfiguration.class.php do metody setup() – będzie ona dostępna dla wszystkich aplikacji:

config/ProjectConfiguration.class.php
sfConfig::set('mod_mails_partial_view_class', 'CrossApp');

Aby uczynić nasze rozwiązanie uniwersalnym, możemy dla modułów, którym zmieniamy domyślną klasę partial_view utworzyć odpowiednie wpisy w konfiguracji, definiujące w której aplikacji leży moduł z partialami:

config/ProjectConfiguration.class.php
sfConfig::set('mod_mails_partials_app', 'backend');

Teraz pozostaje napisanie klasy dziedziczącej po sfPartialView, której nazwa jest połączeniem pierwszej wartości konfiguracyjnej oraz suffiksu PartialView oraz umieszczenie jej w głównym folderze lib:

lib/CrossAppPartialView.class.php
<?php
class CrossAppPartialView extends sfPartialView
{
 public function setDirectory($directory)
 {
   if ($app = sfConfig::get(sprintf('mod_%s_partials_app', $this->getModuleName()))) {
     $directory = sprintf('%s/apps/%s/modules/%s/templates', sfConfig::get('sf_root_dir'), $app, $this->getModuleName());
   }
   parent::setDirectory($directory);
 }
}

W tej klasie nadpisujemy metodę setDirectory, uzyskując podmianę ścieżki, w sposób podany powyżej i cieszymy się partialami cross-aplikacyjnymi :-) Zaletą tego rozwiązania jest jego przeźroczystość, nie musimy nic zmieniać w wywołaniach partiali w obydwu aplikacjach – wyciągamy je standardowo.


Tagi: , ,

Podobne wpisy

2 Responses to “Cross-application partial w symfony”

  1. greg Says:
    Kwiecień 2nd, 2010 at 14:44

    dzięki za pomoc bo akurat tego szukałem.
    troche zmodyfikowałem dodatkowo setDirectory() bo ja pobierałem partiala nie dosc ze z innej aplikacji to jeszcze z zupełnie innego modułu (nie o tej samej nazwie). dzieki jeszcze raz, bo zaoszczędziłeś mi kilka godzin :)

  2. Bedger Says:
    Czerwiec 26th, 2010 at 19:59

    Ten sam efekt można uzyskać poprzez tymczasową zmianę aplikacji przez metodę statyczną switchTo dostępną z poziomu sfContext. Np.
    sfContext::switchTo(‘frontend’);
    $mailMessage = $this->getPartial(‘module/partial’, array(‘object’ => $object));
    sfContext::switchTo(‘backend’);

    Fakt, niektórzy nie lubią stosować sfContext, szczególnie że nie zawsze jest dostępny (głównie jeśli chodzi o taski z poziomu konsoli) ale imo do np. pobrania treści meila z poziomu akcji nadaje się w sam raz :)

Skomentuj