Heavymind
Gdyby ludzie rozmawiali tylko o tym, co rozumieją, zapadłaby nad światem wielka cisza.

31/10/2008

Mastering Zend Framework - HeadLink

Opublikowane jako: Off topic — Kubek Bartosz @ 18:08

Mastering Zend Framework

cześć I

View Helper HeadLink

Kubek Bartosz, www.heavymind.net
Wersja dokumentu 1.0
Copyright © 2008

Witam w pierwszej części artykułu serii “Mastering Zend Framework”. Argumentem do utworzenia oddzielnej serii, stała się tematyka artykułu. Ponieważ opisywane zagadnienia mają uzasadnienie bytu głównie dla średnich i dużych aplikacji, pragnę w ten sposób zaznaczyć jego stopień zaawansowania. Dla programistów zaczynających przygodę z programowaniem dla internetu, bądź z Zend Framework, jego treść może być mało interesująca - choć język dukumentu starałem się dobrać tak, by mógł być czytany przez wszystkich. Mam także nadzieję, iż będzie ciekawym punktem widzenia dla średnio zaawansowanych i ekspertów w dziedzinie. Zapraszam.

UWAGA: Ten dokument wymaga dobrej znajomości frameworka Zend Framework. Przykłady tutaj zawarte, przetestowane zostały w oparciu o Zend Framework w wersji 1.6. Najprawdopodobniej będą działały także z nowszymi wersjami, jednak jest mało prawdopodobne, by prawidłowo mogły być uruchamiane z wersjami wcześniejszymi niż wersja 1.5.0.

Optymalizacja stron internetowych w czasach gdy użytkowników internetu, a w tym potencjalnych gości naszej strony jest bardzo wiele - jest jest dziś sztuką. Najlepsze praktyki czerpać należy oczywiście od najbardziej doświadczonych. Dla przykładu Yahoo! posiada rozbudowany dokument, traktujący szeroko i konkretnie w tym temacie ( link, ver. PL przez Google translator ).

Jednymi z celów do jakich powinno się dążyć, podczas optymalizacji, a dotyczącymi stylów CSS - bo to o nich ten artykuł, są:

  • utrzymywanie skryptów CSS, generalnie stylów w osobnych plikach (nie wraz z HTML)
  • ładować należy tylko te style, które są wykorzystywane. Ładowanie wszystkich możliwych “zawsze” powoduje, że zrządzanie nimi staje się uciążliwe, a rozmiar pliku źle wpływa na “lekkość” serwisu
  • ładowanie plików CSS w nagłówku strony HTML ( sekcja HEAD )
  • minimalizacja ilości żądań jakie wysyła strona internetowa z przeglądarki do serwera, czyli m.in. zmniejszenie ilości załączonych plików CSS do minimum
  • kompresja plików CSS, poprzez usunięcie niepotrzebnych komentarzy, znaków nowej linii, spacji, tabulatorów

Zapewnienie stronie internetowej osiągnięcia powyższych punktów, w zauważalny sposób przyśpiesza jej ładowanie - szczególnie w dużych aplikacjach. Jednym z narzędzi które pozwalają badać szybkość ładowania poszczególnych elementów serwisu www, jest YSlow - plugin do Firefox’a pochodzący od Yahoo!. Polecam zapoznanie się z nim przy tej okazji.

Jako że twórcom Zend Framework są doskonale znane zasady optymalizacji stron internetowych, starają się najlepsze praktyki tworzenia stron przenosić do ich bibliotek. Od wersji 1.5, Zend Framework wprowadził m.in. dodatkowe Helper’y widoków. W centrum zainteresowania tego artykułu będzie View Hlper “HeadLink”. Domyślnie dostępny jest on developera jako standardowy element struktury Widoków, a ma pozwolić mu np. rozdzielić kod CSS na poszczególne osobne pliki, i dołączać je wg. potrzeby do jednej listy znaczników <link>, w sekcji <HEAD>. Postaram się bardziej obrazowo przedstawić tę popularną współcześnie sytuację.

Weźmy dla przykładu developera, który założył iż chce minimalizować ilość kodu CSS jaki się dołącza do generowanych przez niego stron www, dlatego też założył że najlepszym dla niego rozwiązaniem będzie:

  • utworzyć główny plik CSS “/styles/main.css”, który opisywać będzie stałe elementy strony (tj. layout)
  • aby generować modułowe elementy strony, tj, box z komentarzami, box z tagami, box nawigacyjny itp, skorzysta z “stosu akcji”, tj. techniki wykonywania w jednym wywołaniu strony, kolejki akcji w różnych kontrolerach akcji, aby każda z tych akcji wygenerowała część strony za jaką jest odpowiedzialna (np. tylko nawigację)
  • dzięki wykorzystaniu stosu akcji, decyduje się by charakterystyczne tylko dla danej akcji style, umieszczać w osobnych plikach CSS, i w każdej z tych akcji rejestrować ten plik w Helper’rze HeadLink

Założenia te są dobre. Jednak przyjrzyjmy się teraz dokładniej implementacji tego w kodzie.

Jako że developer korzysta z Zend_Layout, w głównym pliku layout.phtml, w sekcji <HEAD> podłącza Helper HeadLink, aby ten w trakcie generowania strony (jeden z ostatnich etapów całego procesu przetwarzania rządania w frameworku Zend Framework) dołączył w tym miejscu wszystkie zarejestrowanie elementy <link>, także pliki CSS:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
   <title>Basic Web Page</title>
   <?= $this->headLink() ?>
</head>
<body>

Jak już ustaliliśmy, developer posiada główny plik stylów, który musi zarejestrować jako pierwszy. Jako że wykonanie tego polecenia jest potrzebne zawsze, dla każdego wywołania, dla każdej strony serwisu, są dwa rozsądne miejsca w aplikacji, gdzie mógłby to wykonać.

  • w własnym plugin’ie kontrolera frontowego ( np. Album_Controller_Plugin_ApplicationInit ) który rozszerza klasę wzorcową Zend_Controller_Plugin_Abstract. Umieściłby pewnie swe wywołanie w funkcji routeStartup() aby jego główny plik CSS został zarejestrowany w bardzo wczesnym stadium procesu generowania wywołanej strony, lub:
  • w własnym głównym kontrolerze akcji ( np. Album_Controller_Action, omawiany w Zend Framework Tutorial - cześć II - Rozwijanie aplikcaji ), który rozszerzyłby domyślny główny kontroler akcji Zend_Controller_Action. Umieściłby w klasie tej metodę init(), która jest wywoływana przez framework przed uruchomieniem każdej akcji w kontrolerze.

W rozwiązaniu jakie obrał developer, czyli korzystania z “stosu akcji”, rozwiązanie 2gie jest mniej wygodne, ponieważ za wykonywaniem w jednym żądaniu każdej kolejej akcji, wspólna metoda init() została by wywołana przed każdą z nich - więc wielokrotnie. Dało by to niepożądane efekty, a rozwiązanie problemu wymagało by specjalnego oprogramowania. Dlatego decyduje się on na opcję pierwszą.

Rejestruje więc on swój plugin w front kontrolerze ( robi to w pliku bootstraper’a ):

$frontController = Zend_Controller_Front::getInstance();
$frontController->registerPlugin( new Album_Controller_Plugin_ApplicationInit () );

Po czym zapisuje owy plugin jako nowy plik z klasą :

<?php
class Album_Controller_Plugin_ApplicationInit extends Zend_Controller_Plugin_Abstract {

   /**
   * Default Front Controller route method. For more info see
   * Zend Framework Front Controller information:
   * http://framework.zend.com/manual/en/zend.controller.front.html
   *
   * At very first application step, initialize application settings
   *
   * @param Zend_Controller_Request_Http $request
   * @return void
   * @access public
   */
   public function routeStartup(Zend_Controller_Request_Abstract $request)
   {
      //use layout view pattern
      Zend_Layout::startMvc()->getView();

      $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
      $viewHeadlinks = $viewRenderer->view->getHelper( 'HeadLink' );
      $viewHeadlinks->appendStylesheet( '/styles/main.css' );

      }
}

Przy okazji okazało się, iż jest to dobre miejsce by wystartować silnik Zend_Layout. Dodatkowe wywołanie getView(), jest wymuszeniem inicjalizacji Widoku, na potrzeby tego co wykonuje się w kodzie zaraz po nim ( ponieważ na tym etapie wykonywania aplikacji, nie jest on jeszcze zainicjowany ).

Bardzo dobrze. Słowem podsumowania, przygotował developer sobie bazę. W tym momencie wywołanie jakiejkolwiek strony serwisu www, powoduje wygenerowanie się nagłówka strony, wraz z domyślnym arkuszem stylów:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
   <title>Basic Web Page</title>
   <link href=“/styles/main.css” media=“screen” rel=“stylesheet” type=“text/css” >
</head>

W tym momencie Developer podłącza w przykładowej akcji exampleAction() następującą kolejkę akcji:

// generate top navigatoin
$request = clone $this->getRequest();
$request->setActionName( 'mainMenu' );
$request->setControllerName( 'navigation' );
$this->_helper->actionStack( $request );

// generate left menu
$request = clone $this->getRequest();
$request->setActionName( 'subMenu' );
$request->setControllerName( 'navigation' );
$this->_helper->actionStack( $request );

// generate right info box
$request = clone $this->getRequest();
$request->setActionName( 'comments' );
$request->setControllerName( 'forum' );
$this->_helper->actionStack( $request );

Z kolei w każdej z tych akcji, które będą kolejno wykonywane, rejestruje dodatkowe arkusze stylów. Robi tak ponieważ ciągle przyświaca mu jeden i ten sam cel: minimalizacja ilości stylów CSS. Dlatego też specyficzne style dla każdego szablonu widoku, który istnieje rozdzielnie dla każdej akcji ( np. mainMenuAction(), mieszczące sie w /app/default/controllers/NavigationController.php, posiada swój szablon HTML w /app/default/view/scripts/navigation/mainMenu.phtml ) trzyma on osobno ( np. w /styles/navigation.mainmenu.css ).

Definiuje on więc co następujące :

  • w funkcji mainMenuAction() w NavigationController rejestruje :
    $this->view->getHelper(’HeadLink’)->appendStylesheet( ’styles/navigation.mainmenu.css’ );
  • w funkcji subMenuAction() w NavigationController rejestruje :
    $this->view->getHelper(’HeadLink’)->appendStylesheet( ’styles/navigation.submenu.css’ );
  • w funkcji commentsAction() w ForumController rejestruje :
    $this->view->getHelper(’HeadLink’)->appendStylesheet( ’styles/forum.comments.css’ );

Bardzo ważne jest by pamiętać, że wszystkie przedstawione ścieżki są przykładowe. Szczególnie umiejscowienie częściowych plików CSS jest propozycyjne. Dla aplikacji większego rozmiaru, takie rozwiązanie mogło by być niewygodne. Dlatego też z pewnością owy developer przygotowałby sobie specialną klasę do na przykłąd automatycznego dołanczania częściowych plików CSS z lokalizacji takiej jak “/app/default/view/styles/{controllerName}/{actionName}.css”. Zwracam na to uwagę, ponieważ nie istnieją standardy w tym zakresie i zdrowy rozsądek jest jedyną regułą.

Wracając do naszego developera, osiągnął on już swój cel. Uruchamiając aplikację, wywołując testową akcję, otrzymuje on odpowiedź w postacji kodu HTML, którego część nagłówkowa wygląda następująco:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
   <title>Basic Web Page</title>
   <link href=“/styles/main.css” media=“screen” rel=“stylesheet” type=“text/css” >
   <link href=“/styles/navigation.mainmenu.cssmedia=“screen” rel=“stylesheet” type=“text/css” >
   <link href=“/styles/navigation.submenu.cssmedia=“screen” rel=“stylesheet” type=“text/css” >
   <link href=“/styles/forum.comments.cssmedia=“screen” rel=“stylesheet” type=“text/css” >
</head>

W tym momencie przechodzimy do meritum problemu. Otórz ten skromny przykład już pokazuje że dla modułowej strony, składającej się dopiero z czterech różnych elementów: głównego layoutu, głównego menu, podrzędnego menu i listy komentarzy - mamy już cztery skrypty CSS “zalinkowane”. W dalszym rozwoju aplikacji, okazało by się szybko, iż liczba ta wzrasta, co jest bardzo niekorzystne.

Wracając do tego co zostało podsumowane w pięciu punktach na początku tego dokumentu - Zend Framework pozwala nam osiągnąć tylko ponad połowę z założeń. Primo - dzięki rozdzieleniu stylów CSS na mniejsze porcje, które pokrywają wyłącznie (czy też prawie tylko) to co jest aktualnie wyświetlane przez generowany kod HTML, zminimalizowaliśmy ilość kodu CSS. Oraz secundo - dzięki zastosowaniu View Helper’a HeadLink, znaczniki <link> do stylów znajdują się w osobnych plikach i są ładowane w sekcji HEAD, co przyśpiesza generowanie strony w przeglądarce użytkownika.

W tym oto miejscu pozwolić sobie mogę na wkroczenie w temat, który jest fundamentem tego artykułu. Pragnę zaproponować rozwiązanie, które pozwoli dopełnić pozostałe dwa punkty na naszej liście: minimalizacja iliści rządań do serwera, przez m.in. minimalizację ilości elementów <link>, oraz kompresję stylów CSS. Przejdę do konkretów.

Nic nie stanie się z niczego, dlatego dla potrzeb tego rozwiązania wprowadzamy w użycie dwie nowe, dodatkowe klasy. Są nimi Hm_View_Helper_HeadLink oraz Hm_File ( oraz ich klasy wyjątków: Hm_View_Helper_Exception i Hm_File_Exception ). Klasy wyjątków nie wymagają opisu. Klasa Hm_File nie będzie w tym przykładzie przez nas bezpośrednio wykorzystywana. Jest za to potrzebna do pracy klasie Hm_View_Helper_HeadLink. Może kilka słów o tej ostatniej - ponieważ tylko ona ma dla nas znaczenie.

Korzystając z obiektowego dobrodziejstwa, jakim jest dziedziczenie klas, oraz przeciążanie metod/funkcji, powstała klasa Hm_View_Helper_HeadLink, która oferuje sobą wszystko to co Zend_View_Helper_HeadLink, przy czym wprowadza dla nas kilka bardzo cennych nowych metod :

  • (get|set)IsMergeEnabled() - dzięki tym metodom możemy włączyć /wyłączyć scalanie zarejestrowanych do wyświetlenia plików CSS lub sprawdzić aktualne ustawienie. Domyślnie scalanie jest wyłączone.
  • (get|set)IsCompressEnabled() - dzięki tym metodom możemy włączyć /wyłączyć kompresję scalonych plików CSS lub sprawdzić aktualne ustawienie. Domyślnie kompresja jest wyłączona.
  • (get|set)MergePath() - dzięki tym metodom możemy ustawić ścieżkę pod którą scalane pliki będą zapisywane lub sprawdzić aktualne ustawienie. Domyślnie wartość jest pusta.
  • clearCssMerges() - metoda czyści “na rządanie” wszystkie scalone pliki CSS. Użyteczna, gdy zmiany wprowadzone w głównych, źródłowych plikach CSS nie są uwzględnione w plikach scalonych.

Taki zestaw funkcji daje nam wszysto co potrzeba, by usiągnąc dwa ostanie punkty z listy celów do osiągnięcia.

Jak działa? Otórz jeśli nakarzemy Helper’owi, by scalał nasze pliki CSS, oraz je kompresował i podamy przy tym miejsce gdzie scalone pliki powinien przechowywać:

$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
$viewHeadlinks = $viewRenderer->view->getHelper( 'HeadLink' );
$viewHeadlinks->setIsMergeEnabled( true );
$viewHeadlinks->setIsCompressEnabled( true );
$viewHeadlinks->setMergePath( "styles_cache/" );

…to zadba on o to by dla aktualnie generowanej listy plików CSS ( w naszym przykłądnie są to /styles/main.css, /styles/navigation.mainmenu.css, /styles/navigation.submenu.cssoraz /styles/forum.comments.css ) wygenerować unikalne ID. Sprawdzi wtem, czy plik scalania z takim ID (np. a7f5c0833b5e5425acd6225c49df961f.css ) już czasem nie istnieje, w katalogu w którym pliki scalone się znajdują.

Uwaga. Dla danego zestwu zarejestrowanych plików CSS, generowane ID jest stałe, dlatego też scalanie odbędzie się tylko raz dla tego zestawu, co zaoszczędza czasu i odciąża serwer. Jako że raz wygenerowane pliki scalania się nie odświerzają, pomocna okazuje się funkcja clearCssMerges().

Gdy plik scalania zostanie odnaleziony lub utworzony w przypadku jego braku ( oraz dodatkowo skompresowany jeśli taka opcja została włączona ), zostanie plik ten zwrócony jako jeden element <link> który pojawi się w nagłówku <HEAD> strony.

Wróćmy więc do naszego developera i sprawdźmy co uczymić musi, by skorzystać z tych funkcionalnośći.

Najpierw pobrać musi cztery pliki klas pakietu “Hm” z repozytorium SVN:

http://heavymind.googlecode.com/svn/hm/trunk/

i umieścić je w swoim katalogu z bibliotekami ( tak, w równorzędnym katalogu z katalogiem “Zend”, zawierającym Zend Framework ). Kolejnym krokiem jest zainkludowanie nowej implementacji Helpera HeadLink oraz jego skonfigurowanie. Zrobi to oczywiście w tym samym miejscu, gdzie inicjował Zend_Layout i dodawał stały główny arkusz styli do Hepler’a HeadLink - tj. w klasie Album_Controller_Plugin_ApplicationInit, w funkcji routeStartup() :

public function routeStartup(Zend_Controller_Request_Abstract $request)
{
   //use layout view pattern
   Zend_Layout::startMvc()->getView();

   $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
   $viewRenderer->view->addHelperPath( ‘Hm/View/Helper/’, ‘Hm_View_Helper’ );

   $viewHeadlinks = $viewRenderer->view->getHelper( ‘HeadLink’ );
   $viewHeadlinks->setIsMergeEnabled( true );
   $viewHeadlinks->setIsCompressEnabled( true );
   $viewHeadlinks->setMergePath( “styles_cache/” );
   $viewHeadlinks->appendStylesheet( ‘/styles/main.css’ );

   }

Utworzył on także na serwerze folder “styles_cache” ( równorzędny do “styles”) dla plików scalania. W tym momencie developer zastanawia się, cóż jeszcze powinien uczynić. Szybko jednak stwierdza że to koniec ; )

Oto treść wygenerowanego nagówka:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
   <title>Basic Web Page</title>
   <link href=“/styles_cache/a7f5c0833b5e5425acd6225c49df961f.css” media=“screen” rel=“stylesheet” type=“text/css” >
</head>

Tym szybkim zabiegiem zaliczył kompletnie wszystkie cele jakie miał przed sobą postawione. Aplikacja, dla każdej generowanej strony :

  • będzie posiadała minimum potrzebnego kodu CSS,
  • kod ten zawarty jest w osobnym pliku,
  • plik scalania “linkowany” jest z sekcji <HEAD>,
  • generalnie, ilość plików CSS ograniczona jest do minimum
  • treść plików CSS jest skompresowana

W ten oto sposób, wszystkie współczesne standardy zostały zachowane i to na bardzo wysokim poziomie.

Warto nadmienić, iż jeśli rejestrowane ( przez appendStylesheet() lub prependStylesheet() ) w HeadLink pliki CSS są różnego typu ( tzn. mają różne atrybuty takie jak “media”, “type” lub parametr “conditionalStylesheet” - opisany w dokumnetacji Zend Framework ) to pliki scalania zostaną także wygenerowane z osobna dla każdego z atrybutów/parametru. Kompatybilność tutaj jest pełna.

Cel osiągnięty, tamat zakończony. Myślę że nasz developer może zacząć zastanawiać się nad optymalizacją plików JS : )

Pozdrawiam

Kubek Bartosz



Komentarze: 17 »

  1. Świetne :) szkoda ze sam na to wczesniej nie wpadłem, bo przydałoby mi się do mojej pracy. Muślałeś o tym coby zgłosić ten fjuczer do Zenda? Myśle że można liczyć na akceptacje bo pomysł jest ciekawy i przydatny.

    Komentarz od Raven — 01/11/2008 @ 09:29

  2. a co jezeli ustawienia media beda inne? np jeden z css bedzie mial media=“print” ?
    w tydy trzeba by bylo generowac tyle arkuszy ile typow media.
    jezlei niektory style beda sie przeplatac np ta sama czesc bedzie dla screen i print to kod powinien byc zdublowany

    Komentarz od dartur — 01/11/2008 @ 11:39

  3. “kompresja plików CSS, poprzez usunięcie niepotrzebnych komentarzy, znaków nowej linii, spacji, tabulatorów”

    Tak praktycznie patrząc spacje, tabulatory za duzo nie waza.

    Komentarz od red — 01/11/2008 @ 18:16

  4. @dartur - w treści artykułu jest napisane, że dla różnego rodzaju np. media, zostaną wygenerowane oddzielne pliki scalania i poprawnie za<link>owane w sekcji <HEAD>

    @red - w tym cała rzecz, że dla wielkoskalowych serwisów www, każdy kilobajt jest na cenę złota, a gdy graficznie strona jest bogata, to stylów jest wystarczająco dużo, by było co kompresować

    Komentarz od Kubek Bartosz — 02/11/2008 @ 09:52

  5. Jak to dużo nie ważą? Można zystkać z 1/3. Można zawsze pousuwać ostatnie średniki i zooptymalizować kolory w HEX.

    Komentarz od snapshot — 02/11/2008 @ 12:13

  6. Fajny pomysł. Myślę, że coś podobnego dałoby się wykonać też na plikach js. Przydałby się też jeszcze jeden parametr określający czy dany plik ma zostać poddany operacji scalania czy też nie.

    Komentarz od bigZbig — 03/11/2008 @ 22:15

  7. Autorowi serdecznie dziękuję za KAWAŁ DOBREJ ROBOTY.
    Dzięki Twojej pracy kolego - zrozumienie ZF przyszło mi z łatwością jakiej się nie spodziewałem.
    Jeszcze raz wielkie dzięki za jasny i klarowny przekaz.
    Czekam na dalsze tutki (pewnie przerobię je kilka razy tak jak te opublikowane - tak już mam ;) ).
    Pozdrawiam - i… tak trzymać!

    Komentarz od Sławek — 07/11/2008 @ 03:04

  8. brawo. o to chodzi. cachujemy i kompresujemy wyszstko co sie da. oczywiscie tez pamietamy o zasadzie zeby nie porywac sie z armata na komara.

    Komentarz od qba — 21/11/2008 @ 12:38

  9. A jak do tego ma się wcześniejsza seria artykułów o Zendie w polączeniu ze Smarty. Kombinowałem żeby taką kompresję połączyć ze Smarty i lipa. Funkcja HeadLink oraz HeadScript działa natomiast wykłada się przy tworzeniu ApplicationInit. Dokładniej to kiedy przenoszę inicjację widoku z ActionControllera do ApplicationInit! Proponuję zmodyfikować ten artykuł tak aby zamieścić w nim uwagi co jeśli ktoś ma Smarty!

    Komentarz od grzana12 — 27/11/2008 @ 12:42

  10. Też mam problem ze smarty, dokładnie to chodzi o to że jeżeli mamy w action.php wywołanie Zend_Layout::startMvc(); to dostajemy błąd (analogicznie korzystając ze smarty też inicjalizujemy Zend Layout ) :

    Fatal error: Uncaught exception ‘Zend_Layout_Exception’ with message ’setOptions() expects either an array or a Zend_Config object’ in C:\Program Files\Apache Group\Apache2\htdocs\zf-tutorial2\library\Zend\Layout.php:232 Stack trace: #0 C:\Program Files\Apache Group\Apache2\htdocs\zf-tutorial2\library\Zend\Layout.php(178): Zend_Layout->setOptions(NULL) #1 C:\Program Files\Apache Group\Apache2\htdocs\zf-tutorial2\library\Album\Controller\Action.php(20): Zend_Layout::startMvc() #2 C:\Program Files\Apache Group\Apache2\htdocs\zf-tutorial2\application\controllers\IndexController.php(4): Album_Controller_Action->init() #3 C:\Program Files\Apache Group\Apache2\htdocs\zf-tutorial2\library\Zend\Controller\Action.php(118): IndexController->init() #4 C:\Program Files\Apache Group\Apache2\htdocs\zf-tutorial2\library\Zend\Controller\Dispatcher\Standard.php(261): Zend_Controller_Action->__construct(Object(Zend_Controller_Request_Http), Object(Zend_Controller_Response_Http), Array) #5 C:\Program Files\Apache Group\Apache2\htdocs\zf-tut in C:\Program Files\Apache Group\Apache2\htdocs\zf-tutorial2\library\Zend\Layout.php on line 232

    Komentarz od mike — 18/12/2008 @ 23:28

  11. Tutorial ciekawy, jednak muszę się przyczepić do jednej rzeczy - nie uwzględniłeś faktu iż przeglądarka zapisuje pliki CSS w swoim własnym cache. Mając kilka - kilkanaście podstron z różnymi zestawami dołączanych plików CSS cache nie zadziała - za każdym razem przeglądarka będzie pobierać nieco inny połączony arkusz. Tymczasem zestaw 2-3 większych plików zostanie pobrany tylko jeden raz. Po otwarciu kilku podstron łączna ilość pobranych bajtów może być mniejsza.

    Inny sposób na znaczne zmniejszenie objętości pobieranych plików to użycie mod_deflate. Można utworzyć jeden katalog i umieścić w nim (w odpowiednich podkatalogach) arkusze stylów, pliki JavaScriptu, szablony XSL itp., a następnie napisać prosty plik .htaccess który zatroszczy się o kompresję.

    Komentarz od Mateusz — 08/02/2009 @ 14:58

  12. Bardzo fajne tutki, dzięki wielkie. Mam mały problem, otóż robie tak jak w tutoriale i wyszstko niby ok z jednym problemem. Jak mam jeszcze w stronie stopke, którą dorzucam metodą $this->render(’footer.phtml’) to za zadne skarby nie renderuje mi tego w plikach widoku. CSS ładuje się dobrze, ale tak jakby przerywał mi wyświetlanie strony odrazu po załadowaniu layout.pthml.
    Jak mam zrobić aby w plikach widoku móc dorenderować footer w skrypcie widoku?

    Pozdrawiam

    Komentarz od BTK — 19/02/2009 @ 16:44

  13. BTK: nie zapominasz wysłać stopki poleceniem echo (echo $this->render(’footer.phtml’))?

    Komentarz od Mateusz — 23/02/2009 @ 11:22

  14. Już sobie poradziłem z tym. Otóż mam nowy problem. Chcę użyć Ajaxa do wyświetlania zawartości mojej strony. Problem polega na tym, że po użyciu ajaxa (konkretnie plugin Ajaxify do jquery) w linkach po przeładowaniu strony nie uzupełnia stylów css konkretnej akcji. Jeśli przejdę z kontrolera index akcji index np. do kontrolera profile akcji index to nie załaduje mi się do layoutu nowy styl. profile.index.css, załadowane są jedynie style które były na początku (czyli przy pierwszym załadowaniu strony niewykorzystującej AJAXA). Moje pytanie polega na tym w jaki sposób zmusić aby nawet przy wywołaniach ajaxowych HelperLink zadziałał i dołączył odpowiednie style css?
    Co najsmieszniejsze używając FireBug w firefoxie dostaje odpowiedź z dobrze dobranymi stylami jednak (jako że updatuje ajaxem content a nie całą stronę) to nie uzupełnia mi sekcji CSS..

    Pozdrawiam

    Komentarz od BTK — 23/02/2009 @ 16:15

  15. Ciekawe rozwiązanie (pod warunkiem, że zestaw tych samych CSSów powtarza się na kolejnych stronach).

    Trzeba jeszcze wspomnieć, że style w zależności od “media” można także zaszyć w jednym pliku (@media print {
    }).

    Do zrobienia:
    - możliwość dodania arkusza, ale wykluczenia z merge (albo metoda appendMerge, zamiast appendStylesheet)
    - wykluczenie konieczności wstawiania helpera w szablonie
    - bardziej zrozumiałe dla człowieka nazwy merge’ów
    - kompresja gzip
    - kompresja CSSTidy
    - kompresja JavaScript (obfuscate, gzip, dean edwards javascript compressor)

    Co bierzesz w następnej kolejności na tapetę? :)

    Komentarz od typografia — 04/05/2009 @ 00:21

  16. Panie, żądanie piszemy… no właśnie, przez “ż”.

    Komentarz od piotr — 22/06/2009 @ 09:23

  17. ok, tylko ciekaw jestem jak robicie linki do obrazków bo ja, arkusz stylów mam w katalogu z obrazkami dzieki temu nie musze pisac sciezek
    jesli jest

    /styles/mainmenu/bg.gif
    w kodzie s.css
    moge uzyc li{background:transparent url(bg.gif)}

    teraz weźmy

    /styles/submenu/bg.gif
    w kodzie s.css
    moge uzyc li{background:transparent url(bg.gif)}

    teraz sobie wyobrazmy ze mamy sporo obrazkow dla kazdego modulu
    gdybysmy chcieli uzywac sciezek bo kompresja do jednego CSSa jest trendy …
    mieli bysmy w kodzie
    odpowiednio:

    li{background:transparent url(mainmenu/bg.gif)}
    li{background:transparent url(submenu/bg.gif)}

    itd…. wtedy kompresja nie bedzie wpływała na ścieżki

    ale jaki mamy zysk skoro słowo “submenu” to co najmniej 28Bajtów (4Bajty*7)?

    Należało by się zastanowić czy jeden request, ale sumarycznie i tak wiekszego kodu (bo trzeba sciezki do obrazków poustawiac) leprzy
    czy pare requestów do CSS’ów ktore i tak się cachują w przeglądarce - ale bez ścieżek do obrazków …

    Komentarz od Roger — 21/08/2009 @ 13:23

Kanał RSS dla tego wpisu. TrackBack URL

Dodaj komentarz

Oparte na WordPress