Sitemap applicata ad una cartella rapida e veloce? si, grazie!
Note: Return to tutorial view.
Introduzione
In alcune situazioni è utile disporre di "sitemap" di sezione, soprattutto quando la sezione è molto ricca di contenuti o si presenta come un mini sito.
Molti sono i modi per farlo, ma cercando di prendere mano con le tecnologie Zope 3, riuseremo quanto già disponibile in Plone (anche se in maniera in parte "poco" ortodossa.. ma si tratta di esercizio!).
portal_catalog.searchResults(path={'query':'/path/fisica/della/radice/della/mappa', 'depth': 2}) Tuttavia resterebbe l'onere di specificare le varie regole necessarie a definire cosa mostrare, in che posizione mostrarlo, etc. etc.
Generazione della site map di Plone 3.0
La site map che si ottiene da Plone standard nasce dal template sitemap.pt che troviamo in plone_templates di portal_skins.
Dal template risulta chiaro che il grosso del lavoro è delegato alla vista sitemap_view.
Andiamo quindi a scoprire cosa si cela in tale vista, che troviamo definita in CMFPlone.browser.sitemap.SitemapView.
Per prima cosa osserviamo che SitemapView implementa ISitemapView, il cui unico metodo è createSiteMap, nome abbastanza eloquente da non lasciare equivoci. Di fatto SitemapView non fa altro che restituire il rendering del template portlet_navtree_macro, dopo aver ottenuto i dati per la costruzione della site map da una ulteriore vista, ricavata adattando il contesto e la request al nome
“sitemap_builder_view”:: view = getMultiAdapter((context, self.request), name='sitemap_builder_view') data = view.siteMap() Il livello di annidamento delle logiche aumenta: scopriamo come è costruito questo adapter, definito in CMFPlone.browser.navigation.CatalogSiteMap. CatalogSiteMap implementa l'interfaccia ISiteMap, dotata di un solo metodo: siteMap.
Ancora una volta troviamo una implementazione piuttosto semplice, che restituisce il risultato del metodo buildFolderTree, “reciclato” da plone.app.layout.navigation.navtree (a pensarci un attimo, è piuttosto ovvia la parentela tra la site map e l'albero di navigazione..).
buildFolderTree realizza un meccanismo piuttosto complesso che, dato il contesto, produce come risultato gli elementi corrispondenti ad una specifica query a cui si è interessati, rispettando una strategia con cui modulare gli esiti della query.
Per capirci, tramite la query definiamo la richiesta da operare a catalogo per ottenere ad esempio tutti gli elementi figli del contesto e delle eventuali sottocartelle fino a una certa profondità. Con la strategia possiamo andare a modulare I risultati ottenuti chiedendo ad esempio di mostrare “esplosi” solo i figli del contesto il cui titolo inizia per “A” (ricordate che questo è solo un povero esempio ;)).
Nel caso della sitemap di Plone il queryBuilder è definito mediante il SitemapQueryBuilder, definito in CMFPlone.browser.navtree, e può essere sintetizzato così:
self.query['path'] = {'query' : portal_url.getPortalPath(), 'depth' : sitemapDepth} Di fatto non fa altro che chiedere il calcolo dell'albero che ha origine nel portale per una profondità parametrizzata, modificabile dal pannello di controllo di Plone.
Per quanto riguarda la strategia, invece, essa è chiaramente mantenuta identica a quella definita per l'albero di navigazione, e ottenuta per adattamento del contesto e della CatalogSiteMap all'interfaccia INavtreeStrategy.
Il nostro scoprire le carte si ferma qui, e per quanto riguarda i punti critici per la realizzazione del nostro intento, l'unico inconveniente è rappresentato dalla “cablatura” della radice dell'albero al portale definita in SitemapQueryBuilder.
Progettiamo il nostro LocalMap
Il motivo per cui non possiamo manipolare il meccanismo della site map di Plone per "centrare" velocemente la mappa dove serve a noi è evidentemente il fatto che la query usata a tal scopo non è in alcun modo sensibile al contesto.
Andiamo quindi a "duplicare" tutto quanto necessario, partendo dall'interfaccia ISitemapView, che per noi sarà ILocalmapView.
Lasciamo che l'implementazione di ILocalmapView deleghi a sua volta la gestione della mappa a un adattatore, che chiameremo localmap_builder_view, e che nella sua realizzazione di base implementerà l'interfaccia ILocalMap.
A questo punto affidiamo anche noi il grosso del lavoro a buildFolderTree, a cui però potremo offrire il nostro queryBuilder, in cui la radice sarà rappresentata dal contesto locale.
Ultimi ritocchi: la strategia di base deve essere identica a quella applicata al portale, per cui lasciamo che valga quanto definito per il portale.
Scorciatoie
La realizzazione di quanto descritto la lasciamo all'esercizio del lettore, piuttosto, per nostro esercizio, ci chiediamo se esiste un modo per ottenere quanto necessario sacrificando un po' di flessibilità e qualche salto “di troppo”. Be', pare di sì :)
Non preoccupandosi di creare delle apposite interfacce per la Localmap, possiamo definire un template localmap.pt esattamente identico a sitemap.pt, facendogli tuttavia usare la nostra vista ContextmapViev, che implementa ISitemapView come segue:
from Acquisition import aq_inner from zope.interface import implementsfrom Products.Five import BrowserView
from Products.CMFPlone.browser.interfaces import ISitemapView from Products.CMFPlone.browser.navtree import NavtreeQueryBuilder from Products.CMFPlone.browser.navtree import SitemapNavtreeStrategy
from plone.app.layout.navigation.navtree import buildFolderTree
class ContextmapView(BrowserView): implements(ISitemapView)
def createSiteMap(self): context = aq_inner(self.context)
queryBuilder = ContextmapQueryBuilder(context) query = queryBuilder()
portal = context.restrictedTraverse(
@@plone_portal_state).portal() strategy = SitemapNavtreeStrategy(portal)data = buildFolderTree(context, obj=context, query=query, strategy=strategy) return context.portlet_navtree_macro(children=data.get(
children,[]), level=1, bottomLevel=2) class ContextmapQueryBuilder(NavtreeQueryBuilder): “““Build a folder tree query suitable for a sitemap “““def __init__(self, context): NavtreeQueryBuilder.__init__(self, context) self.query['path'] = {
query:/.join(context.getPhysicalPath()),depth: 2}
Chiaramente la browser view va configurata in un adeguato file zcml come segue:
<configure
xmlns=“http://namespaces.zope.org/zope“
xmlns:browser=“http://namespaces.zope.org/browser“
i18n_domain=“plone“> <browser:page
for=““
name=“contextmap_view“
class=“.contextmap.ContextmapView“
permission=“zope.Public“
allowed_interface=“Products.CMFPlone.browser.interfaces.ISitemapView“
/>
</configure>
