Development

Documentation/it_IT/book/1.1/12-Caching (diff)

You must first sign up to be able to contribute.

Changes from Version 1 of Documentation/it_IT/book/1.1/12-Caching

Show
Ignore:
Author:
garak (IP: 85.18.214.242)
Timestamp:
10/24/08 12:22:41 (9 years ago)
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Documentation/it_IT/book/1.1/12-Caching

    v0 v1  
     1{{{ 
     2#!WikiMarkdown  
     3 
     4Capitolo 12 - Caching 
     5===================== 
     6 
     7Uno dei metodi per velocizzare un'applicazione è quello di memorizzare pezzi di codice HTML, o anche pagine intere, per richieste future. Tale tecnica prende il nome di caching, e può essere utilizzata sia lato server che lato client. 
     8 
     9Symfony offre un sistema di caching lato server molto flessibile. Permette di salvare l'intera risposta, il risultato di un'azione, un partial, un segmento di template in un file, attraverso un setup molto intuitivo basato su file YAML. Quando i dati sottostanti cambiano, puoi pulire facilmente parti della cache tramite la linea di comando od un'azione speciale. Symfony fornisce anche un semplice modo di controllare la cache lato client tramite gli header HTTP 1.1. Questo capitolo affronterà queste tematiche, e ti darà qualche suggerimento per monitorare i miglioramenti che il caching può portare alla tua applicazione. 
     10 
     11Caching della risposta 
     12---------------------- 
     13 
     14Il principio del caching HTML è piuttosto semplice: parte o tutto il codice HTML spedito ad un utente dopo una richiesta può essere riutilizzato per richieste simili. Tale codice HTML viene memorizzato in una cartella particolare (in symfony nella cartella `cache/`), dove il front controller guarderà prima di eseguire un'azione. Se viene trovata una versione in cache, viene spedita senza eseguire l'azione, cosi' il processo viene velocizzato. Se non viene trovata alcuna versione, l'azione viene eseguita ed il suo risultato (la vista) viene memorizzato nella cartella di cache per le richieste future. 
     15 
     16Dato che tutte le pagine possono contenere informazioni dinamiche, la cache HTML è disabilitata per default. Sta all'amministratore abilitarla per migliorare le performance. 
     17 
     18Symfony gestisce tre tipi di cache HTML: 
     19 
     20  * Cache di un'azione (con o senza layout) 
     21  * Cache di un partial, di un component od un component slot 
     22  * Cache di un fragment 
     23 
     24I primi due vengono gestiti tramite file YAML. Il terzo tramite chiamate a helper nelle template. 
     25 
     26### Impostazioni globali della cache 
     27 
     28Per ogni applicazione di un progetto, il meccanismo di cache HTML può essere abilitato o disabilitato (default), per ambiente, nell'impostazione `cache` del file `settings.yml`. Il Listato 12-1 mostra come abilitarla. 
     29 
     30Figura 12-1 - Cache di un'azione 
     31 
     32    dev: 
     33      .settings: 
     34        cache:                  on 
     35 
     36### Cache di un'azione 
     37 
     38Le azioni che mostrano informazioni statiche (dati non dipendenti dal db o dalla sessione) od azioni che leggono dati da un database ma non lo modificano (tipicamente richieste GET) sono spesso ideali per la cache. La Figura 12-1 mostra quali elementi della pagina vengono cachati in questo caso: il risultato di un'azione (la sua template) od il risultato insieme al layout. 
     39 
     40Figure 12-1 - Caching an action 
     41 
     42![Caching an action](/images/book/F1201.png "Caching an action") 
     43 
     44Ad esempio, considera un'azione `user/list` che restituisce la lista degli utenti di un sito. A meno che un utente venga modificato, aggiunto o rimosso (e questo argomento sarà discusso in seguito nella sezione "Rimuovere oggetti dalla cache"), la lista sarà sempre la stessa, per cui è una buona candidata per la cache. 
     45 
     46L'attivazione e le impostazioni della cache, azione per azione, sono definiti nel file cache.yml, dentro la cartella `config/` del modulo. Il Listato 12-2 ne mostra un esempio. 
     47 
     48Listato 12-2 - Attivare la cache per un'azione, in frontend/modules/user/config/cache.yml 
     49 
     50    list: 
     51      enabled:     on 
     52      with_layout: false   # Default value 
     53      lifetime:    86400   # Default value 
     54 
     55Questa configurazione definisce che la cache è attiva per l'azione `list`, ed il layout non viene incluso (che è il comportamento di default). Ciò significa che anche se una versione dell'azione viene trovata in cache, il layout (con partial e component) viene eseguito lo stesso. Se l'opzione `with_layout` viene impostata a `true`, anche il layout viene messo in cache con l'azione e non viene eseguito. 
     56 
     57Per testare le impostazioni della cache, chiama l'azione nell'ambiente di sviluppo dal tuo browser: 
     58 
     59    http://myapp.example.com/frontend_dev.php/user/list 
     60 
     61Noterai un bordo attorno all'area dell'azione nella pagina. La prima volta tale area ha un header blu, che significa che la pagina non proviene dalla cache. Aggiorna la pagina, e noterai che ora l'header è giallo, che significa che stavolta proveniva dalla cache (con un significativo decremento del tempo di risposta). Più avanti in questo capitolo saranno approfonditi i metodi per testare e monitorare la cache. 
     62 
     63>**NOTE** 
     64>Gli slot sono parte dei template, quindi fare il cache di un'azione significa anche memorizzare il valore dello slot definito dal template dell'azione. Per cui la cache funziona nativamente per gli slot. 
     65 
     66Il sistema di cache funziona anche per le pagine con argomenti. Il modulo `user` potrebbe avere, ad esempio, un'azione `show` che si aspetta un `id` per mostrare i dettagli di un utente. Modifica il file `cache.yml` per abilitare la cache anche per questo caso, come mostrato nel Listato 12-3. 
     67 
     68Per organizzare i tuoi `cache.yml`, puoi raggruppare le impostazioni comuni a tutte le azioni di un modulo sotto la chiave `all:`, anch'essa mostrata nel Listato 12-3. 
     69 
     70Listato 12-3 - Esempio di `cache.yml, in frontend/modules/user/config/cache.yml` 
     71 
     72    list: 
     73      enabled:    on 
     74    show: 
     75      enabled:    on 
     76 
     77    all: 
     78      with_layout: false   # Default value 
     79      lifetime:    86400   # Default value 
     80 
     81Ora, ogni chiamata all'azione `user/show` con un `id` diverso produrrà nuovi record nella cache. Per cui la cache per: 
     82 
     83    http://myapp.example.com/user/show/id/12 
     84 
     85sarà diversa da quella per: 
     86 
     87    http://myapp.example.com/user/show/id/25 
     88 
     89>**CAUTION** 
     90>Azione chiamate in POST o GET non vengono memorizzate in cache. 
     91 
     92L'impostazione `with_layout` merita qualche parola in più. Essa determina effettivamente che tipo di dati sono memorizzati nella cache. Per cache senza layout, vengono immagazzinati solo il risultato dell'esecuzione di un template e le variabili dell'azione. Per cache con layout, tutta la risposta viene memorizzata. Ciò significa che la cache con il layout è molto più veloce di quella senza. 
     93 
     94Se funzionalmente ti puoi permettere di farlo (ovvero se il layout non si basa sulla sessione) dovresti scegliere sempre la cache con layout. Sfortunatamente, il layout contiene spesso elementi dinamici (ad esempio, il nome dell'utente connesso), per cui la cache senza layout è l'impostazione piu' comune. Comunque, i feed RSS, i pop-up, e le pagine che non dipendono dai cookie possono essere messe in cache con il loro layout. 
     95 
     96### Cache di un partial, component, o component slot 
     97 
     98Il Capitolo 7 ha spiegato come riutilizzare frammenti di codice in diversi template, utilizzando l'helper `include_partial()`. Un partial è facile da mettere in cache quanto un'azione, e l'attivazione segue le stesse regole, come mostrato in Figura 12-2. 
     99 
     100Figura 12-2 - Cache di un partial, component, o component slot 
     101 
     102![Caching a partial, component, or component slot](/images/book/F1202.png "Caching a partial, component, or component slot") 
     103 
     104Ad esempio, il Listato 12-4 mostra come modificare il file `cache.yml` per abilitare la cache di un partial `_my_partial.php` del modulo `user`. Nota che l'opzione `with_layout` non ha senso in questo caso. 
     105 
     106Listato 12-4 - Cache di un partial, in `frontend/modules/user/config/cache.yml` 
     107 
     108    _my_partial: 
     109      enabled:    on 
     110    list: 
     111      enabled:    on 
     112    ... 
     113 
     114Ora tutti i template che usano questo partial non ne eseguiranno effettivamente il codice PHP, bensì utilizzeranno la versione in cache. 
     115 
     116    [php] 
     117    <?php include_partial('user/my_partial') ?> 
     118 
     119Come per le azioni, anche il caching dei partial diventa importante quando il risultato di tale partial dipende da parametri. Il sistema di cache memorizzerà tante versioni del template quanti sono i parametri. 
     120 
     121    [php] 
     122    <?php include_partial('user/my_other_partial', array('foo' => 'bar')) ?> 
     123 
     124>**TIP** 
     125>La cache di un'azione è più potente di quella di un partial, in quanto quando un'azione viene messa in cache il template non viene neanche eseguita; se il template contiene chiamate ai partial, tali chiamate non vengono eseguite. Perciò, il caching dei partial diventa utile quando non metti in cache l'azione chiamante o per partial inclusi nel layout. 
     126 
     127Un piccolo promemoria dal Capitolo 7: un component è una leggera azione situata all'inizio del partial, ed un component slot è un component per il quale l'azione cambia a seconda delle azioni chiamanti. Questi due tipi di inclusioni sono molto simili ai partial, e supportano il caching nello stesso modo. Ad esempio, se il tuo layout globale include un component chiamato `day` con `include_component('general/day')` per mostrare la data odierna, per abilitarne la cache imposta il file `cache.yml` del modulo `general` nel modo seguente: 
     128 
     129    _day: 
     130      enabled: on 
     131 
     132Quando metti in cache un component od un partial, devi decidere se memorizzare una singola versione per tutte le template chiamanti oppure una versione per ognuna di esse. Per default, un component è memorizzato indipendentemente dalla template che lo chiama. Ma component contestuali, ad esempio quelli che visualizzano una barra laterale differente con ogni azione, dovrebbero essere memorizzati tante volte quante sono i template che li chiamano. Il sistema di cache gestisce questo caso, se tu imposti il parametro `contextual` a `true`, nel modo seguente: 
     133 
     134    _day: 
     135      contextual: true 
     136      enabled:   on 
     137 
     138>**NOTE** 
     139>I componenti globali (quelli situati nella cartella `templates/` dell'applicazione) possono essere messi in cache, se dichiari le loro impostazioni nel file `cache.yml` dell'applicazione. 
     140 
     141### Cache di un template fragment 
     142 
     143La cache delle azioni si applica solo ad un loro sottoinsieme. Per le altre, ovvero quelle che aggiornano dati o mostrano nella template informazioni dipendenti dalla sessione, c'è ancora spazio per miglioramenti dovuti alla cache, ma in modo diverso. Symfony mette a disposizione un terzo tipo di cache, dedicato ai fragment dei template ed abilitato direttamente al loro interno. In questa modalità, l'azione viene sempre eseguita, e il template viene diviso in fragment ed essi messi in cache, come mostrato dalla Figura 12-3. 
     144 
     145Figura 12-3 - Caching di un fragment 
     146 
     147![Caching a template fragment](/images/book/F1203.png "Caching a template fragment") 
     148 
     149Ad esempio, potresti avere una lista di utenti che mostrano un link all'utente acceduto per ultimo, e tale informazione è dinamica. L'helper `cache()` definisce le parti di una template che devono andare in cache. Vedi il Listato 12-5 per dettagli sulla sintassi. 
     150 
     151Listato 12-5 - Usare l'helper `cache()`, in `frontend/modules/user/templates/listSuccess.php` 
     152 
     153    [php] 
     154    <!-- Codice eseguito ogni volta --> 
     155    <?php echo link_to('last accessed user', 'user/show?id='.$last_accessed_user_id) ?> 
     156 
     157    <!-- Codice in cache --> 
     158    <?php if (!cache('users')): ?> 
     159      <?php foreach ($users as $user): ?> 
     160        <?php echo $user->getName() ?> 
     161      <?php endforeach; ?> 
     162      <?php cache_save() ?> 
     163    <?php endif; ?> 
     164 
     165Ecco come funziona: 
     166 
     167  * Se viene trovata in cache una versione del fragment '`users`', viene sostituito al codice tra le linee `<?php if (!cache($unique_fragment_name)): ?>` e `<?php endif; ?>`. 
     168  * Altrimenti, il codice tra tali linee viene processato e salvato in cache, ed identificato con il nome `$unique_fragment_name`. 
     169 
     170Il codice non incluso tra tali linee viene sempre processato e mai salvato in cache. 
     171 
     172>**CAUTION** 
     173>L'azione (`list`nell'esempio) non deve avere la cache abilitata, altrimenti l'intera template verrebbe bypassata e la dichiarazione di cache del fragment ignorata. 
     174 
     175L'aumento di velocità dovuto alla cache dei fragment non è significatico quanto quello dovuto al caching delle azioni, dato che l'azione viene sempre eseguita, il template parzialmente processata ed il layout sempre usato per la decoration. 
     176 
     177Puoi dichiarare fragment addizionali nella stessa template, però devi dare ad ognuno di essi un nome unico, in modo che il sistema di cache riesca ad identificarli in seguito. 
     178 
     179Come per le azioni ed i component, anche i fragment in cache possono accettare un lifetime come secondo parametro, specificato in secondi, per l'helper `cache()`: 
     180 
     181    [php] 
     182    <?php if (!cache('users', 43200)): ?> 
     183 
     184Se non ne viene specificato alcuno, viene usato il valore di default (86400 secondi, ovvero un giorno). 
     185 
     186>**TIP** 
     187>Una maniera alternativa per rendere un'azione "cacheabile" è quella di inserire le variabili che la rendono dinamica nel suo pattern di routing. Ad esempio, se una home page mostra il nome dell'utente connesso, non può essere messa in cache a meno che la URL non ne contenga lo username. Un altro esempio è per le applicazioni internazionalizzate: se vuoi abilitare la cache di una pagina che ha diverse traduzioni, il codice della lingua deve in qualche modo essere incluso nell'URL. Questa scorciatoia moltiplicherà il numero delle pagine in cache, ma può essere di grande aiuto per velocizzare applicazioni pesantemente interattive. 
     188 
     189### Configurazione dinamica della cache 
     190 
     191Il file `cache.yml` è un modo per definire le impostazioni della cache, ma ha l'inconveniente di essere fisso. Comunque, come al solito in symfony, puoi usare PHP invece di YAML, e questo ti permette di configurare la cache dinamicamente. 
     192 
     193Perché vorresti poter cambiare la cache dinamicamente? Un buon esempio è una pagina il cui contenuto varia a seconda che un utente sia autenticato o meno, ma la sua URL rimane la stessa. Immagina una pagina `article/show` con un sistema di votazione per gli articoli. Tale funzionalità di votazione è disabilitata per gli utenti non autenticati; per loro, il link della votazione porta alla pagina di login. Questa versione della pagina può essere messa in cache. D'altra parte, per gli utenti autenticati, cliccare sul link di votazione scatena una richiesta in POST e crea un nuovo voto. Questa volta la cache deve essere disabilitata, in modo che symfony possa costruirla dinamicamente. 
     194 
     195Il posto giusto per definire le impostazioni della cache dinamica è in un filtro eseguito prima di `sfCacheFilter`. Infatti, in symfony la cache non è altro che un filtro, proprio come la web debug toolbar e le funzionalità di sicurezza. Per abilitare la cache per la pagina `article/show` solo se l'utente non è autenticato, crea un `conditionalCacheFilter` nella cartella `lib/` dell'applicazione, come mostrato nel Listato 12-6. 
     196 
     197Listato 12-6 - Configurare la cache in PHP, in `frontend/lib/conditionalCacheFilter.class.php` 
     198 
     199    [php] 
     200    class conditionalCacheFilter extends sfFilter 
     201    { 
     202      public function execute($filterChain) 
     203      { 
     204        $context = $this->getContext(); 
     205        if (!$context->getUser()->isAuthenticated()) 
     206        { 
     207          foreach ($this->getParameter('pages') as $page) 
     208          { 
     209            $context->getViewCacheManager()->addCache($page['module'], $page['action'],array('lifeTime' => 86400)); 
     210          } 
     211        } 
     212 
     213        // Esegue il prossimo filtro 
     214        $filterChain->execute(); 
     215      } 
     216    } 
     217 
     218Devi registrare questo filtro nel file `filters.yml` prima di `sfCacheFilter`, come mostrato nel Listato 12-7. 
     219 
     220Listato 12-7 - Registrare un filtro personalizzato, in `frontend/config/filters.yml` 
     221 
     222    ... 
     223    security: ~ 
     224 
     225    conditionalCache: 
     226      class: conditionalCacheFilter 
     227      param: 
     228        pages: 
     229          - { module: article, action: show } 
     230 
     231    cache: ~ 
     232    ... 
     233 
     234Pulisci la cache (per auto-caricare il nuovo filtro), e la cache condizionale è pronta. Essa abiliterà la cache delle pagine definite nel parametro `pages}} solo per utenti non autenticati. 
     235 
     236Il metodo `addCache()` dell'oggetto `sfViewCacheManager` si aspetta il nome di un modulo, di un'azione ed un array associativo con gli stessi parametri che definiresti in un file `cache.yml`. Ad esempio, se tu volessi definire che l'azione `article/show` debba essere messa in cache con il layout ed un lifetime di 3600 secondi, scrivi: 
     237 
     238    [php] 
     239    $context->getViewCacheManager()->addCache('article', 'show', array( 
     240      'withLayout' => true, 
     241      'lifeTime'   => 3600, 
     242    )); 
     243 
     244>**SIDEBAR** 
     245>Sistema di memorizzazione della cache alternativo 
     246> 
     247>Per default, symfony memorizza i dati in file sul disco rigido del web server. Potresti voler immagazzinare i dai in memoria (ad esempio tramite `memcache`) oppure in un database (specialmente se vuoi condividere la cache tra più server o velocizzarne la rimozione). Puoi modificare facilmente tale impostazione in quanto è definita nel file `factories.yml`. 
     248> 
     249>Il sistema di memorizzazione di default è la classe `sfFileCache`: 
     250> 
     251>     view_cache: 
     252>         class: sfFileCache 
     253>         param: 
     254>           automaticCleaningFactor: 0 
     255>           cacheDir:                %SF_TEMPLATE_CACHE_DIR% 
     256> 
     257>Puoi sostituire la `class` con il tuo sistema di memorizzazione personalizzato o con una delle classi alternative di symfony (inclusi `sfAPCCache`, `sfEAcceleratorCache`, `sfMemcacheCache`, e `sfSQLiteCache`). I parametri definiti sotto la chiave `param` sono passati al costruttore della classe di cache come array associativo. Ogni metodo alternativo di memorizzazione deve implementare tutti i metodi che si trovano nella classe astratta `sfCache`. Per maggiori informazioni su questo argomento consulta il Capitolo 19. 
     258 
     259### Utilizzare la cache super veloce 
     260 
     261Anche una pagina in cache coinvolge l'esecuzione di codice PHP. Per tali pagine, symfony carica la configurazione, costruisce la risposta e così via. Se tu fossi veramente sicuro che una pagina non cambierà per un certo periodo di tempo, potresti bypassare symfony completamente mettendone il codice HTML risultante direttamente dentro la cartella `web/`. Questo funziona grazie alle impostazioni `mod_rewrite` di Apache, supposto che le tue regole di routing specifichino pattern senza suffisso o terminanti con `.html`. 
     262 
     263Puoi fare ciò a mano, pagina per pagina, con una semplice chiamata a linea di comando: 
     264 
     265    > curl http://myapp.example.com/user/list.html > web/user/list.html 
     266 
     267Dopo questo, ogni volta che viene richiesta l'azione `user/list`, Apache trova la corrispondente pagina `list.html` e bypassa symfony completamente. La controparte è che non puoi controllare più il cashing della pagina tramite symfony (lifetime, delegazione automatica e così via), ma il guadagno in velocità è veramente impressionante. 
     268 
     269Alternativamente, puoi usare il plugin di symfony `sfSuperCache`, che automatizza questo processo e supporta lifetime e pulizia della cache. Consulta il Capitolo 17 per maggiori informazioni sui plugin. 
     270 
     271>**SIDEBAR** 
     272>Altre tattiche di velocizzazione 
     273> 
     274>In aggiunta alla cache HTML, symfony possiede altri due meccanismi di cache, che sono completamente automatici e trasparenti allo sviluppatore. Nell'ambiente di produzione, la configurazione e le traduzioni delle template sono cachate nella cartelle `myproject/cache/config/` e `myproject/cache/i18n/` senza alcun intervento. 
     275> 
     276>Gli acceleratori PHP (eAccelerator, APC, XCache e così via), anche chiamati moduli di caching opcode, incrementano le performance degli script PHP mettendoli in cache in uno stato compilato, in modo che l'overhead dovuto al parsing ed alla compilazione venga quasi completamente eliminato. Questo è particolarmente efficiente per le classi Propel, che contengono una grande quantità di codice. Questi acceleratori sono compatibili con symfony e possono facilmente triplicare la velocità di un'applicazione. Essi sono raccomandati in ambienti di produzione per qualsiasi applicazione symfony che abbia una grande audience. 
     277> 
     278>Con un acceleratore PHP, puoi immagazzinare manualmente dati persistenti in memoria, evitando così lo stesso processo ad ogni richiesta, tramite la classe `sfProcessCache`. E se volessi memorizzare in cache il risultato di un'operazione molto impegnativa per la CPU, probabilmente userai l'oggetto `sfFunctionCache`. Consulta il Capitolo 18 per maggiori informazioni su questi meccanismi. 
     279 
     280Rimuovere elementi dalla cache 
     281------------------------------ 
     282 
     283Se gli script od i dati della tua applicazione cambiano, la cache conterrà informazioni scadute. Per evitare incoerenze e bug, puoi eliminare elementi dalla cache in diversi modi, a seconda delle tue esigenze. 
     284 
     285### Pulire l'intera cache 
     286 
     287Il task `cache:clear` della linea di comando di symfony elimina l'intera cache (HTML, configurazione e i18N). Puoi passare degli argomenti per eliminare solo alcune parti, come mostrato dal Listato 12-8. Ricorda di chiamarlo solo dalla root di un progetto symfony. 
     288 
     289Listato 12-8 - Eliminare la cache 
     290 
     291    // Eliminare l'intera cache 
     292    > php symfony cache:clear 
     293 
     294    // Sintassi abbreviata 
     295    > php symfony cc 
     296 
     297    // Eliminare solo la cache dell'applicazione frontend 
     298    > php symfony cache:clear --app=frontend 
     299 
     300    // Eliminare solo la cache HTML dell'applicazione frontend 
     301    > php symfony cache:clear --app=frontend --type=template 
     302 
     303    // Eliminare solo la configurazione in cache dell'applicazione frontend 
     304    // I tipi possibili sono config, i18n, routing, e template. 
     305    > php symfony cache:clear --app=frontend --type=config --env=prod 
     306 
     307### Eliminare parti specifiche della cache 
     308 
     309Quando un database viene aggiornato, la cache delle azioni relative ai dati modificati deve essere cancellata. Potresti pulire l'intera cache, ma questo sarebbe uno spreco per tutte le azioni non relative alle modifiche del modello. Qui è dove il metodo `remove()` dell'ggetto `sfViewCacheManager` ci viene in aiuto. Esso si aspetta come argomento una URI interna (lo stesso tipo di parametro che passeresti a `link_to()`), ed elimina la relativa azione dalla cache. 
     310 
     311Ad esempio, immagina che l'azione `update` del modulo `user` modifica le colonne dell'oggetto `User`. La versione in cache delle azioni `list` e `show` hanno bisogno di essere eliminate, altrimenti esse, con dati erronei, sarebbero visualizzate. Per gestire questo caso, usa il metodo `remove()`, come mostrato nel Listato 12-9. 
     312 
     313Listato 12-9 - Eliminare la cache per una data azione, in `modules/user/actions/actions.class.php` 
     314 
     315    [php] 
     316    public function executeUpdate($request) 
     317    { 
     318      // Aggiorna un utente 
     319      $user_id = $request->getParameter('id'); 
     320      $user = UserPeer::retrieveByPk($user_id); 
     321      $this->foward404Unless($user); 
     322      $user->setName($request->getParameter('name')); 
     323      ... 
     324      $user->save(); 
     325 
     326      // Pulisci la cache per le azioni relative a tale utente 
     327      $cacheManager = $this->getContext()->getViewCacheManager(); 
     328      $cacheManager->remove('user/list'); 
     329      $cacheManager->remove('user/show?id='.$user_id); 
     330      ... 
     331    } 
     332 
     333Eliminare partial, component e component slot è leggermente più complicato. Dato che gli puoi passare qualsiasi tipo di parametro (inclusi oggetti), è quasi impossibile modificare la loro versione in cache. Concentriamo la nostra attenzione sui partial, comunque la spiegazione vale anche per gli altri componenti delle template. Symfony identifica un partial in cache con un prefisso speciale (`sf_cache_partial`), il nome del modulo ed il nome del partial, più un hash di tutti i parametri usati per chiamarlo, come segue: 
     334 
     335    [php] 
     336    // Un partial chiamato da 
     337    <?php include_partial('user/my_partial', array('user' => $user) ?> 
     338 
     339    // Viene identificato in cache come 
     340    @sf_cache_partial?module=user&action=_my_partial&sf_cache_key=bf41dd9c84d59f3574a5da244626dcc8 
     341 
     342In teoria, potresti rimuovere un partial in cache tramite il metodo `remove()` se tu sapessi il valore dei parametri hash usati per identificarlo, ma ciò è veramente impraticabile. Fortunatamente, se aggiungi un parametro `sf_cache_key` alla chiamata dell'helper `include_partial()`, puoi identificare il partial in cache con tale chiave. Come puoi vedere dal Listato 12-10, pulire la cache da un singolo partial (ad esempio per eliminare i dati in cache relativi ad uno `User` modificato) diventa facile. 
     343 
     344Listato 12-10 - Rimozione di un partial dalla cache 
     345 
     346    [php] 
     347    <?php include_partial('user/my_partial', array( 
     348      'user'         => $user, 
     349      'sf_cache_key' => $user->getId() 
     350    ) ?> 
     351 
     352    // Viene identificato in cache come 
     353    @sf_cache_partial?module=user&action=_my_partial&sf_cache_key=12 
     354 
     355    // Elimina _my_partial per uno specifico utente in cache con $cacheManager->remove('@sf_cache_partial?module=user&action=_my_partial&sf_cache_key='.$user->getId()); 
     356 
     357Non puoi usare questo metodo per eliminare dalla cache tutte le occorrenze di un partial. Imparerai come farlo piu' avanti in questo capitolo, nella sezione "Svuotare la cache manualmente". 
     358 
     359Per eliminare dalla cache template fragment, usa lo stesso metodo `remove()`. La chiave che identifica il fragment nella cache è lo stesso prefisso `sf_cache_partial`, il nome del modulo, quello dell'azione ed il parametro `sf_cache_key`. Il Listato 12-11 ne mostra un esempio. 
     360 
     361Listato 12-11 - Eliminare fragment dalla cache 
     362 
     363    [php] 
     364    <!-- Codice in cache --> 
     365    <?php if (!cache('users')): ?> 
     366      ... // Whatever 
     367      <?php cache_save() ?> 
     368    <?php endif; ?> 
     369 
     370    // Viene identificato in cache come 
     371    @sf_cache_partial?module=user&action=list&sf_cache_key=users 
     372 
     373    // Eliminalo con 
     374    $cacheManager->remove('@sf_cache_partial?module=user&action=list&sf_cache_key=users'); 
     375 
     376>**SIDEBAR** 
     377>La pulizia selettiva della cache può danneggiare il tuo cervello 
     378> 
     379>La parte piu' complicata dell'operazione di pulizia della cache è capire quali azioni sono influenzate da un aggiornamento dei dati. 
     380> 
     381>Ad esempio, immagina che la tua applicazione corrente abbia un modulo `publication` dove le pubblicazioni vengano elencate (azione `list`) e descritte singolarmente (azione `show`), insieme a qualche dettaglio sull'autore (istanza della classe `User`). Modificare un utente coinvolgerà tutte le descrizioni ed anche l'elenco. Ciò significa che devi aggiungere all'azione `update` del modulo `user` qualcosa come: 
     382> 
     383>     [php] 
     384>     $c = new Criteria(); 
     385>     $c->add(PublicationPeer::AUTHOR_ID, $request->getParameter('id')); 
     386>     $publications = PublicationPeer::doSelect($c); 
     387> 
     388>     $cacheManager = sfContext::getInstance()->getViewCacheManager(); 
     389>     foreach ($publications as $publication) 
     390>     { 
     391>       $cacheManager->remove('publication/show?id='.$publication->getId()); 
     392>     } 
     393>     $cacheManager->remove('publication/list'); 
     394> 
     395>Quando cominci ad usare la cache HTML, devi avere una visione chiara delle dipendenze tra modello e azioni, in modo che non accadano errori dovuti ad incomprensioni. Tieni in mente che tutte le azioni che modificano il modello dovrebbero contenere una manciata di chiamate al metodo `remove()`, se la cache HTML è usata da qualche parte nell'applicazione. 
     396> 
     397>E, se non vuoi danneggiare il tuo cervello con analisi troppo complicate, puoi sempre svuotare l'intera cache ogni volta che aggiorni il modello. 
     398 
     399### Pulire diverse parti di cache contemporanamente (nuovo in symfony 1.1) 
     400 
     401Il metodo `remove()` accetta chiavi con caratteri jolly. Ti permette di rimuovere diverse parti di cache con una sola chiamata. Per esempio puoi fare: 
     402 
     403    $cacheManager->remove('user/show?id=*');    // Remove for all user records 
     404 
     405Un altro buon esempio è la gestione di applicazioni con diverse lingue, dove i codici delle lingue appaiono in tutte le URL. La URL per la pagina di un profilo utente dovrebbe essere così: 
     406 
     407    http://www.myapp.com/en/user/show/id/12 
     408 
     409Per rimuovere un profilo utente in cache con id 12 in tutte le lingue, puoi fare semplicemente: 
     410 
     411    $cache->remove('user/show?sf_culture=*&id=12'); 
     412 
     413Questo funziona anche per i partial: 
     414 
     415    $cacheManager->remove('@sf_cache_partial?module=user&action=_my_partial&sf_cache_key=*');    // Remove for all keys 
     416 
     417Il metodo `remove()` accetta due parametri in più, consentendoti di definire quali host e header `Vary` vuoi pulire nella cache. Questo perché symfony tiene una versione di cache per ogni host e header `Vary`, quindi due applicazioni che condividono lo stesso codice ma non lo stesso host usano cache diverse. Questo puà essere molto utile, ad esempio, quando un'applicazione interpreta il sottodominio come parametro di richiesta (come `http://php.askeet.com` e `http://life.askeet.com`). Se non vuoi passare gli ultimi due parametri, symfony pulirà la cache per l'host corrente e per tutti gli header `Vary`. Alternativamente, se vuoi pulire la cache per un altro host, richiama `remove()` come segue: 
     418 
     419    $cacheManager->remove('user/show?id=*');                     // Cancella i record per l'host corrente e tutti gli utenti 
     420    $cacheManager->remove('user/show?id=*', 'life.askeet.com');  // Cancella i record per l'host life.askeet.com e tutti gli utenti 
     421    $cacheManager->remove('user/show?id=*', '*');                // Cancella i record per tutti gli host e tutti gli utenti 
     422  
     423Il metodo `remove()` funziona in tutte le strategie di caching che puoi definire in `factories.yml` (non solo `sfFileCache`, ma anche `sfAPCCache`, `sfEAcceleratorCache`, `sfMemcacheCache`, `sfSQLiteCache`, e `sfXCacheCache`). 
     424 
     425### Pulire la cache tra applicazioni (nuovo in symfony 1.1) 
     426 
     427 Pulire la cache tra applicazioni diverse può essere un problema. Per esempio, se l'amministratore modifica un record nella tabella utenti nell'applicazione `backend`, tutte le azioni che dipendono da quell'utente nell'applicazione `frontend` hanno bisogno di essere pulite dalla cache. Ma il gestore di cache `view` disponibile nell'applicazione `backend` non conosce le regole di routing dell'applicazione `frontend` (le applicazioni sono isolate tra loro). Quindi non puoi scrivere questo codice in `backend`: 
     428 
     429    $cacheManager = sfContext::getInstance()->getViewCacheManager(); // Recuper il gestore di cache view del backend 
     430    $cacheManager->remove('user/show?id=12');                        // Il percorso non viene trovato, perché il template è in cache nel frontend 
     431  
     432La soluzione è inizializzare un oggetto `sfCache` a mano, con le stesse impostazioni del gestore di cache del frontend. Fortunatamente, tutte le classi della cache di symfony forniscono un metodo `removePattern` che fornisce lo stesso servizio del `remove` del gestore di cache di `view`. 
     433 
     434Per esempio, se l'applicazione `backend` ha bisogno di pulire la cache per l'azione `user/show` nell'applicazione `frontend` per l'utente con id 12, può usare il seguente: 
     435 
     436    $frontend_cache_dir = sfConfig::get('sf_root_cache_dir').DIRECTORY_SEPARATOR.'frontend'.DIRECTORY_SEPARATOR.SF_ENV.DIRECTORY_SEPARATOR.'template'; 
     437    $cache = new sfFileCache(array('cache_dir' => $frontend_cache_dir)); // Usa le stesse impostazioni definite in factories.yml del frontend 
     438    $cache->removePattern('user/show?id=12'); 
     439 
     440Per diverse strategie di caching, hai bisogno solo di cambiare l'inizializzazione dell'oggetto `cache`, ma il processo di pulizia resta lo stesso:  
     441 
     442    $cache = new sfMemcacheCache(array('prefix' => 'frontend')); 
     443    $cache->removePattern('user/show?id=12'); 
     444 
     445Testare e monitorare la cache 
     446----------------------------- 
     447 
     448La cache HTML, se non gestita correttamente, può creare inconsistenze nella visualizzazione dei dati. Ogni volta che disabiliti la cache per un elemento, devi testarlo estensivamente e controllare la velocità di caricamento. 
     449 
     450### Building a Staging Environment 
     451 
     452Il sistema di cache è incline ad errori nell'ambiente di produzione che non appaiono in quello di sviluppo, in quanto per default nell'ambiente di sviluppo la cache non è abilitata. Se abiliti la cache HTML per qualche azione, devi aggiungere un nuovo ambiente, chiamato di staging in questa sezione, con le stesse impostazioni dell'ambiente `prod` (quindi, con la cache abilitata), ma con `web_debug` impostato su `on`. 
     453 
     454Per impostarlo, modifica il file `settings.yml` della tua applicazione aggiungendo all'inizio del file il codice del Listato 12-12. 
     455 
     456Listato 12-12 - Impostazione di un ambiente di `staging`, in `frontend/config/settings.yml` 
     457 
     458    staging: 
     459      .settings: 
     460        web_debug:  on 
     461        cache:      on 
     462 
     463In aggiunta, crea un nuovo front controller copiando quello di produzione (probabilmente `myproject/web/index.php`) con nome `frontend_staging.php`. Modificalo per cambiare i valori di `SF_ENVIRONMENT` e `SF_DEBUG` come segue: 
     464 
     465    [php] 
     466    $configuration = ProjectConfiguration::getApplicationConfiguration('frontend', 'staging', true); 
     467 
     468è tutto, hai un nuovo ambiente. Usalo aggiungendo il nome del front controller dopo il nome del dominio: 
     469 
     470    http://myapp.example.com/frontend_staging.php/user/list 
     471 
     472### Monitorare le performance 
     473 
     474Il Capitolo 16 affronterà nel dettaglio la web debug toolbar e le sue funzioni. Comunque, dato che la toolbar offre informazioni importanti riguardo la cache, seguono alcune informazioni sulle sue funzioni per la cache. 
     475 
     476Quando navighi una pagina che contiene elementi "cacheabili" (azioni, partial, fragment e cosi' via) la web debug toolbar (nell'angolo in alto a destra) mostra un pulsante per ignorare la cache (una freccetta verde arrotondata), come mostrato in Figura 12-4. Tale pulsante ricarica la pagina e forza la processione degli elementi in cache. Fai attenzione che questo non svuota la cache. 
     477 
     478L'ultimo numero sul lato destro è la durata dell'esecuzione della richiesta. Se abiliti la cache in una pagina, questo numero dovrebbe diminuire il numero dei secondi necessari al suo caricamento, dato che symfony usa i dati della cache invece di riprocessare gli script. Puoi monitorare facilmente le prestazioni della cache con questo indicatore. 
     479 
     480Figura 12-4 - La web debug toolbar per pagine che usano la cache 
     481 
     482![Web debug toolbar for pages using caching](/images/book/F1204.png "Web debug toolbar for pages using caching") 
     483 
     484La debug toolbar mostra anche il numero di query eseguite durante il processo della richiesta, ed i dettagli delle durate per categoria (clicca sul totale della durata per visualizzare i dettagli). Monitorare tali dati, insieme alla durata totale, ti aiuterà a capire i miglioramenti dovuti alla cache. 
     485 
     486### Benchmarking 
     487 
     488La modalità di debug decrementa notevolmente la velocità della tua applicazione, dato che vengono loggati molto dati e resi disponibili alla toolbar. Per cui il tempo di calcolo visualizzato quando navighi l'ambiente `staging` non è rappresentativo per quello di produzione, dove la modalità di debug è `off`. 
     489 
     490Per avere una migliore panoramica del tempo di processo di ogni richiesta, dovresti utilizzare strumenti per misurare le prestazioni, come Apache Bench o JMeter. Questi strumenti permettono il test del carico e forniscono 2 importanti tipi di informazioni: la media del tempo di caricamento di una singola pagina e la capacità massima del tuo server. La media del tempo di caricamento è molto utile per monitorare i miglioramenti delle performance dovuti all'utilizzo della cache. 
     491 
     492### Identificare parti della cache 
     493 
     494Quando la web debug toolbar è abilitata, gli elementi in cache sono individuati in una pagina con un bordo rosso, ognuno avente un piccolo riquadro di informazione sull'angolo in alto a sinistra, come mostrato in Figura 12-5. Il riquadro ha uno sfondo blu se l'elemento è stato eseguito, o giallo se viene dalla cache. Cliccando sul link vedrai l'identificatore dell'elemento in cache, il suo lifetime, ed il tempo trascorso dall'ultima modifica. Questo ti aiuterà ad identificare i problemi nella gestione di elementi fuori dal contesto, per vedere quale elemento è stato creato e quale parte di una template puoi effettivamente mettere in cache. 
     495 
     496Figura 12-5 - Identificazione di un elemento in cache 
     497 
     498![Identification for cached elements in a page](/images/book/F1205.png "Identification for cached elements in a page") 
     499 
     500HTTP 1.1 e cache lato client 
     501---------------------------- 
     502 
     503Il protocollo HTTP 1.1 definisce una manciata di header che possono essere di grande utilizzo per incrementare la velocità di un applicazione controllando il sistema di cache del browser. 
     504 
     505Le specifiche HTTP 1.1 del World Wide Web Consortium (W3C, [http://www. w3.org/Protocols/rfc2616/rfc2616-sec14.html]) descrivono tali header in dettaglio. Se un'azione ha la cache abilitata, ed usa l'opzione `with_layout`, può utilizzare uno o piu' meccanismi descritti in questa sezione. 
     506 
     507Anche se qualche browser degli utenti del tuo sito potrebbero non supportare HTTP 1.1, non vi è alcun rischio nell'utilizzare le funzionalità di cache del protocollo. Un browser che riceve header che non conosce semplicemente gli ignora, per cui sei incoraggiato ad usare i meccanismi di cache HTTP 1.1. 
     508 
     509Inoltre, gli header HTTP 1.1 sono compresi anche dai proxy e dai server di cache. Anche se il browser di un utente non comprende il protocollo, ci potrebbe essere sul percorso fino ad esso un server che se ne avvantaggia. 
     510 
     511### Aggiungere un header ETag per evitare di rispedire contenuto non modificato 
     512 
     513Quando la funzionalità ETag è abilitata, il web server aggiunge alla risposta un header speciale che contiene la firma della risposta stessa. 
     514 
     515    ETag: 1A2Z3E4R5T6Y7U 
     516 
     517Il browser dell'utente memorizza tale firma, e la spedisce insieme alla richiesta la volta successiva in cui fabbisogna della stessa pagina. Se la nuova firma mostra che la pagina non è cambiata dalla richiesta precedente, il browser non rimanda indietro la risposta. Spedisce invece un header `304: Not modified`, cosa che fa risparmiare tempo di CPU (ad esempio se la compressione gzip fosse abilitata) e banda (trasferimento della pagina) al server, e tempo (trasferimento della pagina) al client. Soprattutto, le pagine in cache con ETag sono piu' veloci da caricare di quelle senza. 
     518 
     519In symfony, puoi abilitare la funzionalità ETag per l'intera applicazione nel file `settings.yml`. Ecco l'impostazione di default: 
     520 
     521    all: 
     522      .settings: 
     523        etag: on 
     524 
     525Per azioni in cache con layout, la risposta viene presa direttamente dalla cartella `cache/`, cosa che velocizza maggiormente l'intero processo. 
     526 
     527### Aggiungere un header Last-Modified per evitare di rispedire contenuto ancora valido 
     528 
     529Quando il server spedisce la risposta al browser, può aggiungere un header che specifica quando il contenuto della pagina è stato modificato l'ultima volta: 
     530 
     531    Last-Modified: Sat, 23 Nov 2006 13:27:31 GMT 
     532 
     533I browser possono capire tale header, e quando richiedono nuovamente la stessa pagina, aggiungono un `If-Modified` di conseguenza: 
     534 
     535    If-Modified-Since: Sat, 23 Nov 2006 13:27:31 GMT 
     536 
     537Il server può quindi confrontare il valore del client e quello restituito dalla propria applicazione. Se i due corrispondono, il server restituisce l'header `304: Not modified`, risparmiando proprio come con ETag tempo di CPU e banda. 
     538 
     539In symfony, puoi impostare l'header di risposta `Last-Modified` proprio come faresti per un altro header. Ad esempio, puoi usarlo in un'azione nel seguente modo: 
     540 
     541    [php] 
     542    $this->getResponse()->setHttpHeader('Last-Modified', $this->getResponse()->getDate($timestamp)); 
     543 
     544Questa data può essere effettivamente quella dell'ultimo aggiornamento dei dati della pagina, presa dal tuo database o dal tuo filesystem. Il metodo `getDate()` dell'oggetto `sfResponse` converte un timestamp in una data nel formato di cui necessiti nell'header `Last-Modified` (RFC1123). 
     545 
     546### Aggiungere l'header  Vary per permettere versioni differenti di una pagina in cache 
     547 
     548Un altro header HTTP 1.1 è `Vary`. Esso definisce da quali parametri dipende una pagina, ed è utilizzato da browser e proxy per costruire chiavi di cache. Ad esempio, se il contenuto di una pagina dipende da cookie, puoi impostare l'header `Vary` come segue: 
     549 
     550    Vary: Cookie 
     551 
     552Molto spesso è difficile abilitare la cache sulle azioni a causa del fatto che la pagina potrebbe cambiare a seconda dei cookie, della lingua o qualcos'altro. Se per te non è un problema espandere la dimensione della cache, imposta correttamente l'header `Vary`. Ciò può essere fatto per l'intera applicazione o per azione, utilizzando il file di configurazione `cache.yml` od il relativo metodo `sfResponse` come segue: 
     553 
     554    [php] 
     555    $this->getResponse()->addVaryHttpHeader('Cookie'); 
     556    $this->getResponse()->addVaryHttpHeader('User-Agent'); 
     557    $this->getResponse()->addVaryHttpHeader('Accept-Language'); 
     558 
     559Symfony memorizzerà diverse versioni della pagina in cache per ogni valore di tali parametri. Questo aumenterà significativamente la dimensione della cache, ma ogni qualvolta il server riceverà una richiesta corrispondente a tali header, la risposta sarà presa dalla cache invece di essere processata. Si tratta di un grande strumento di aumento delle prestazioni per le pagine che variano solo in base agli header di richiesta. 
     560 
     561### Aggiungere un header Cache-Control per abilitare la cache lato client 
     562 
     563Fino ad ora, anche aggiungendo gli header visti, il browser continua a spedire richieste al server anche quando possiede una versione in cache di una pagina. Puoi evitare questo comportamento aggiungendo gli header `Cache-Control` ed `Expires` alla risposta. Questi header per default sono disabilitati in PHP, ma symfony può farne l'override per evitare richieste non necessarie al server. 
     564 
     565Come al solito, puoi scatenare tale comportamento chiamando un metodo dell'oggetto `sfResponse`. In un'azione, definisci il tempo massimo in secondi in cui una pagina dovrebbe essere messa in cache: 
     566 
     567    [php] 
     568    $this->getResponse()->addCacheControlHttpHeader('max_age=60'); 
     569 
     570Puoi anche specificare sotto quali condizioni una pagina può essere messa in cache, in modo da non lasciare memorizzati dati privati (come ad esempio un numero di conto corrente) in cache: 
     571 
     572    [php] 
     573    $this->getResponse()->addCacheControlHttpHeader('private=True'); 
     574 
     575utilizzando la direttiva HTTP `Cache-Control`, avrai la capacità di regolare i diversi meccanismi di cache fra il tuo server ed il browser client. Per maggiori dettagli su tali direttive, consulta le specifiche W3C di `Cache-Control`. 
     576 
     577Un ultimo header può essere spedito tramite symfony: `Expires`. 
     578 
     579    [php] 
     580    $this->getResponse()->setHttpHeader('Expires', $this->getResponse()->getDate($timestamp)); 
     581 
     582>**CAUTION** 
     583>La conseguenza principale dell'abilitazione del meccanismo `Cache-Control` è che il tuo server non mostrerà tutte le richieste eseguite dagli utenti, ma solo quelle ricevute effettivamente. Se le performance migliorano, l'apparente popolarità del sito potrebbe diminuire nelle statistiche. 
     584 
     585Sommario 
     586-------- 
     587 
     588Il sistema di cache fornisce accelerazioni variabili delle performance a seconda del tipo di cache scelta. Dal maggior guadagno al minimo, i tipi di cache sono i seguenti: 
     589 
     590  * Super cache 
     591  * Cache di azioni con layout 
     592  * Cache di azioni senza layout 
     593  * Cache di fragment nelle template 
     594 
     595Inoltre è possibile mettere in cache anche partial e component. 
     596 
     597Se il cambiamento di dati nel modello o nella sessione ti obbliga a svuotare la cache per una questione di coerenza, puoi farlo con fine granularità per ottimizzare le prestazioni, ovvero elimina solo gli elementi che sono cambiati e mantieni gli altri. 
     598 
     599Ricorda di testare con maggior attenzione le pagine con cache abilitata, dato che potrebbero apparire nuovi bug se metti in cache gli elmenti sbagliati o se dimentichi di svuotarla quando aggiorni i dati sottostanti. Un ambiente di staging, dedicato al test della cache, è di grande utilità a questo scopo. 
     600 
     601Infine, trai il meglio dagli header del protocollo HTTP 1.1 grazie alle funzionalità avanzate di symfony, con il coinvolgimento del client nelle operazioni di caching ed un ulteriore incremento delle prestazioni. 
     602 
     603}}}