Fare l'override di una viewlet
medio
Nelle sezioni precedenti si è imparato come aggiungere e nascondere una viewlet per un viewlet manager per uno specifico tema. Sapendo ciò è possibile fare l'override di una viewlet di Plone con una versione personalizzata.
Teoria
Il concetto chiave per fare quanto desiderato è lo skin layer di Zope 3.
Nei capitoli precedenti si è utilizzato lo skin layer di Zope 3 per aggiugere viewlet in modo esclusivo al nostro prodotto, ora verrà utilizzato per l'override di una viewlet standard di Plone.
La logica è questa:
Nel nuovo prodotto (o package) in configure.zcml viene dichiarata una viewlet con lo stesso nome di una di quelle standard di Plone, ma con una classe costruttore o template differente dall'originale.
Utilizzando l'attributo layer nella dichiarazione zcml di una viewlet la leghiamo ad uno skin layer di Zope3. Quest'ultimo ha lo stesso nome del tema aggiunto nel tool portal_skins.
Gli skin layer sono legati allo skin scelto in portal_skins grazie al package plone.theme. Ciò significa che uno skin layer è utilizzato quando il suo nome e lo skin selezionato in portal_skins coincidono.
Le viewlet legate ad uno skin layer sono renderizzate quando quel layer è utilizzato, facendo l'override di tutte le viewlet con lo stesso nome, anche nel caso in cui non siano registrate per quel layer.
Pratica
E' possibile applicare tutto ciò al prodotto che si è iniziato a sviluppare, MyTheme.
L'obiettivo è ora quello di far sì che il footer mostri un testo differente da quello del tema standard di Plone.
Creare/Registrare lo skin layer di Zope 3
Sia ZopeSkel che DIYPloneStyle generano codice che definisce l'interfaccia dello skin layer in MyTheme/browser/interfaces.py. La classe interfaccia si chiama IThemeSpecific ed eredita da zope.publisher.interfaces.browser.IDefaultBrowserLayer.
Il template plone3_theme di ZopeSkel genera di default un package che include una cartella browser/ ad uno skin layer di Zope 3.
Lo script generator di DIYPloneStyle non fa la stessa cosa. Per far sì che anche lui aggiunga lo skin layer di Zope 3 bisogna lanciare lo script con l'opzione --add-viewlet-example. Qualora si fosse già generato il prodotto senza questa opzione, è possibile aggiungere a mano lo skin layer come spiegato nelle sezioni precedenti.
Identificare la viewlet di cui fare l'override
Per identificare la viewlet che interessa e il viewlet manager presso cui è registrata, Plone fornisce una semplice interfaccia per riodinare, nascondere e mostrare le viewlet all'interno dei proprio viewlet manager. Per accedervi si può usare un URL del tipo http://localhost:8080/portal/@@manage-viewlets dove portal è il sito Plone.
La pagina di gestione delle viewlet dovrebbe essere simile a qualcosa del genere (utilizzando il tema Plone Default):
Alla fine della pagina si può vedere la zona del footer e notare che è generata da un viewlet manager chiamato plone.portalfooter, contenente due viewlet: plone.footer e plone.colophon. La prima viewlet è quella che deve essere modificata dal nostro tema.
Scrivere il codice che genera la viewlet
Ora che si sa quale viewlet sostituire, bisogna guardare il codice dell'installazione di Plone nel file system. Le viewlet di default di Plone sono dichiarate nel package plone.app.layout.viewlets, che di solito si trova in $INSTANCE_HOME/lib/python/plone/app/layout/viewlets/ anche se potrebbe essere ovunque nel $PYTHONPATH.
Alla fine del configure.zcml del package plone.app.layout.viewlets vi è la dichiarazione della viewlet plone.footer di default:
<!-- Footer --> <browser:viewlet name="plone.footer" for="*" manager=".interfaces.IPortalFooter" template="footer.pt" permission="zope.Public" />
E' interessante notare che questa viewlet non è renderizzata da una vista di Zope 3, ma direttamente dal template footer.pt.
Si può perciò copiare questo template nella cartella browser/ di MyTheme (non è necessario cambiarne il nome) e modificarlo in modo che scriva un testo differente dal solito, per esempio:
<div id="portal-footer" i18n:domain="plone"> <p> <span i18n:translate="design_author" tal:omit-tag=""> Design by <span i18n:name="author" tal:omit-tag=""> <a href="http://mypage.org">John Doe</a> </span>. </span> </p> </div>
Registrare la viewlet personalizzata nel configure.zcml
Per registrare il template nel viewlet manager del footer del portale è sufficiente copiare la relativa porzione di codice, che si trova in $INSTANCE_HOME/lib/python/plone/app/layout/viewlets/configure.zcml, nel MyTheme/browser/configure.zcml e modificarlo in modo da essere sicuri che utilizzi la giusta interfaccia per il manager e lo skin layer di Zope 3:
<!-- The customized footer --> <browser:viewlet name="plone.footer" for="*" manager="plone.app.layout.viewlets.interfaces.IPortalFooter" layer=".interfaces.IThemeSpecific" template="footer.pt" permission="zope.Public" />
Fine
Installando il nostro prodotto, dopo il riavvio del server Zope, dal Pannello di controllo > Prodotti aggiuntivi possiamo vedere il risultato al fondo della pagina.
Altro esempio
Un altro esempio di overriding di una viewlet può essere trovato in DIYPloneStyle/example/custom_footer/. E' abbastanza semplice da capire, soprattutto dopo aver letto fin qua.
Questo esempio è leggermente differente dal precedente poichè usa una vista browser di Zope 3 per generare la nuova viewlet, ma i principi sono gli stessi.
Inoltre il layout del prodotto varia un po' rispetto a quelli tipicamente generati con DIYPloneStyle o ZopeSkel. Tutto il codice della viewlet è mantenuto nel primo livello del package nel modulo browser.py, senza avere una sotto cartella browser. Ciò è stato fatto per mostrare che ci sono differenti modi di organizzare un prodotto/package per un tema Plone.
- In browser.py si trovano IThemeSpecific, l'interfaccia dello skin layer di Zope 3, e FooterViewlet, la classe della viewlet che fa l'override di quella di default di Plone.
- footer.pt è il template renderizzato da FooterViewlet.
- profiles/default/ è il tipico profilo di Generic Setup per il prodotto.
- Sia l'interfaccia che la viewlet e il profilo di GS sono dichiarati in un singolo configure.zcml.
