Plone en Zope3… cada vez más cerca
Zope 3 trae un abanico de nuevas tecnologías que aplicadas a Plone pueden conseguir no tanto aumentar funcionalidades sino simplificar su diseño y aumentar la reusabilidad del código del muy posiblemente mejor gestor de contenidos libre existente en la actualidad.
El proyecto Goldegg se está encargando de acercar las nuevas tecnologías de Zope 3 a Plone. En su primera fase, integrará las vistas (View Components) de Zope para la renderización de distintos elementos de Plone. Con esto:
- Evitamos mezclar la lógica con la presentación, dejando la lógica a los objetos tipo View
- Aumentamos la legibilidad del código, al unificar en una clase python todo el código que atañe a una funcionalidad concreta
- Aumentamos la eficiencia del código, de dos formas:
- el código (ahora dentro de clases python) pasa a ser no reestrictivo (con respecto a por ejemplo los Script Python o las ZPT), y nos saltamos las numerosas comprobaciones de seguridad, con lo que se aumenta la velocidad de ejecución
- la lógica incluida en Script Python y en ZPTs hacen uso de adquisición y traversal, con lo que el tiempo de encontrar el script determinado que efectúa una tarea es bastante superior que cuando se llama a métodos de una vista, sobre todo cuando el script tiene que ser buscado de entre los layers del skin actual
- Se aumenta la reusabilidad del código, que deja de estar sometida al orden de los layers de un skin y pasan a clases que pueden heredarse y sobreescribir su funcionalidad. Además, el uso de los ficheros de configuración ZCML proporciona la capacidad de cambiar la vista que realiza una determinada función simplemente cambiando una línea de un ficheros ZCML (que es XML)
El uso de tecnologías Z3 en Plone se hace posible gracias a la existencia del producto Five, que integra algunas tecnologías usadas en Zope 3 en Zope 2 (3+2 = Five).
Sin entrar demasiado en detalles, veamos un ejemplo de como conseguir integrar una vista de Zope 3 en Plone. Veremos como pasar el portlet de noticias (portlet_news.pt) a una vista de Zope 3.
Bien, tradicionalmente el porlet de noticias se codifica en plone como sigue (nota: se han eliminado trozos de código, como referentes a traducciones que no ayudan en la explicación y que no podrían confundir al lector). Marcamos dentro del código los fragmentos más importantes en la explicación.
<div metal:define-macro="portlet"
tal:define="results python:request.get(’news’,
here.portal_catalog.searchResults(portal_type=’News Item’,
sort_on=’Date’,
sort_order=’reverse’,
review_state=’published’)[:5]);” >
<dl class=”portlet” id=”portlet-news”>
<dt class=”portletHeader”>
<a href=”#”
tal:condition=”python:’news’ in portal.contentIds()”
tal:attributes=”href string:${utool}/news” >News</a>
<a href=”#”
tal:condition=”python:’news’ not in portal.contentIds()”
tal:attributes=”href string:${utool}/news_listing” >News</a>
</dt>
<tal:newsitems tal:repeat=”obj results”>
<dd>
<a href=”"
tal:attributes=”href obj/getURL;
title obj/Description”>
<tal:block replace=”structure here/newsitem_icon.gif”/>
<span tal:replace=”obj/pretty_title_or_id”>
Plone 2.1 announced!
</span>
</a>
</dd>
</tal:newsitems>
<dd class=”portletFooter”>
<a href=”"
tal:condition=”python:’news’ in portal.contentIds()”
tal:attributes=”href string:${utool}/news”
>
More news…
</a>
<a href=”"
tal:condition=”python:’news’ not in portal.contentIds()”
tal:attributes=”href string:${utool}/news_listing”
>
More news…
</a>
</dd>
</dl>
</div>
Destaquemos algunos fragmentos de código:
- la obtención de las noticias se hace a través del catálogo con la definición:
tal:define="results python:request.get('news',
here.portal_catalog.searchResults(portal_type='News Item',
sort_on='Date',
sort_order='reverse',
review_state='published')[:5]);"
Con lo cual estamos mezclando la lógica y la presentación, y el código resultante es un poco enrevesado. Lo ideal es dejarle a la vista obtener las últimas noticias y no incrustarlas en código ZPT - Hay condiciones que se podrían dejar a la vista, como cuando incrusta el enlace final de acceder al listado de noticias. Ese
tal:condition="python:'news' in portal.contentIds()"que incluso obliga a duplicar el fragmento de ZPT (uno para la condición cierta y otro para la falsa) en varias ocasiones
Si usamos las vistas de Zope3, podríamos delegar la mayor parte de la lógica en ella. Supongamos que tenemos ya la clase creada con la vista que implementa una serie de métodos para obtención de noticias, sacar el enlace a otras noticias, etc. Con ello, el portlet de noticias se podría simplificar bastante:
<div metal:define-macro="portlet"
tal:define="view context/@@news_view;
results python:view.published_news_items()[:5];
news_link view/all_news_link” >
<dl class=”portlet” id=”portlet-news”>
<dt class=”portletHeader”>
<a href=”#”
tal:attributes=”href news_link” >
</dt>
<tal:newsitems tal:repeat=”obj results”>
<dd>
<a href=”"
tal:attributes=”href obj/getURL;
title obj/Description”>
<tal:block replace=”structure here/newsitem_icon.gif”/>
<span tal:replace=”obj/pretty_title_or_id”>
Plone 2.1 announced!
</span>
</a>
</dd>
</tal:newsitems>
<dd class=”portletFooter”>
<a href=”"
tal:attributes=”href news_link”
>
More news…
</a>
</dd>
</dl>
</div>
Como se puede ver, aquí si hay realmente una separación de lógica y presentación. El código ZPT es más limpio, más eficiente, más reutilizable (se puede extender el código de la vista para cambiar la lógica, por ejemplo para usar otras fuentes de noticias aparte del catálogo).
Bien ahora vamos a mostrar el código de la vista que implementarían las funciones published_news_items y all_news_link:
from zope.component import getView
from zope.interface import implements
from Products.CMFPlone import utils
from Products.CMFPlone.browser.interfaces import INewsPortlet
# class
class NewsPortlet(utils.BrowserView):
implements(INewsPortlet)
# methods
def published_news_items(self):
context = utils.context(self)
g = getView(context, ‘globals_view’, self.request)
portal_catalog = g.portal().portal_catalog
return self.request.get(’news’,
portal_catalog.searchResults(portal_type=’News Item’,
sort_on=’Date’,
sort_order=’reverse’,
review_state=’published’))
def all_news_link(self):
context = utils.context(self)
g = getView(context, ‘globals_view’, self.request)
portal = g.portal()
portal_url = g.portal_url()
if ‘news’ in portal.contentIds():
return ‘%s/news’ % portal_url
else:
return ‘%s/news_listing’ % portal_url
Vemos que efectivamente la vista implementa todas la lógica que antes estaba incrustada en la ZPT. Vemos que fácilmente podríamos heredar la clase con otra que cambie su funcionalidad, según nos convenga, sin tocar en absoluto el portlet de presentación de noticias.
De hecho, como dije al principio, otra ventaja de Zope 3 era el uso de ficheros en formato XML (ZCML) para la configuración de la aplicación que desarrollemos. Esto permitiría cambiar la vista por otra distinta simplemente cambiando una línea de un fichero de configuración. A modo de ejemplo, listamos un fragmento del fichero de configuración que registra la vista anterior (clase NewsPortlet) con el nombre news_view (obtenida en la ZPT en tal:define="view here/@@news_view"):
<browser:page
for="*"
name=”news_view”
class=”.portlets.news.NewsPortlet”
permission=”zope.Public”
allowed_interface=”.interfaces.INewsPortlet”
/>
Con esto creo que os quedará claro el funcionamiento de las vistas en Zope 3 y como se pueden aplicar perfectamente a Plone.
Igual que hemos visto aquí, se están cambiando el resto de plantillas ZPT y creando las vistas correspondientes (p.ej. ya están migrados todos los portlets) para hacer realidad el tener Plone funcionando en Zope 3, o al menos usando sus tecnologías con Five.
2 dEurope/Madrid Febrero dEurope/Madrid 2007 a las 16:51
Saludos, me gustaría si tienen alguna documentación de como usar Five que me la envíen, me sería de mucha ayuda. Gracias
30 dEurope/Madrid Mayo dEurope/Madrid 2007 a las 22:00
[…] Computados » Archivo del Blog » Plone en Zope3… cada vez más cerca By Yoda Computados » Archivo del Blog » Plone en Zope3… cada vez más cerca […]