SlideShare a Scribd company logo
Views and viewlets for
  Plone 3.0 Product
    Development
        Tom Lazar
Who are you?

• Not a veteran Zope Developer
• A Plone integrator with Zope/Plone 2.x
  experience (CMF based skins)
• Entirely new to Plone (Congratulations!)
• Sceptical and / or confused about this stuff
Who am I?
• Self-employed Developer, Sysad and
  Consultant, based in Berlin, Germany
• Started working with Plone in 2003
• Contributor since April 2006 (Archipelago
  Sprint, where development of 3.0 started)
• Started Plone 3.0 based product in March
  2007, following trunk
History I
            CMF skins
• A skin is a collection of templates and
  ressources (CSS, JS, images, scripts, macros)
• CMF skins have ordered layers
• customization = copy to a higher layer
• Acquisition based lookup (“Which template
  is producing this markup?!”)
History II
              Macros

• re-use sub-page templates (navigation, etc.)
• Aquisition based lookup (“Which macro is
  really being called?!”)
• Clumsy parameter handling
History III
              Slots
• “Macros on steroids”
• i.e. add CSS links to header from body
  template, advanced loops
• extremely powerful
• only one macro per slot, though
History III
        Python scripts

• security limitations (can’t use
  unrestrictedSearchResults, can’t
  import all packages etc.)
• cumbersome to debug (enablesettrace)
• Clumsy parameter handling (pyflakes)
History III
        Python scripts

• No subclassing (let alone interfaces)
• Acquisition based lookup (“Which script is
  being called?!”)
• hard (impossible?) to test
History IV
            The Good
• very straightforward: copy, edit, reload
• very flexible: easy to override defaults
• instant gratification (TTW support)
• large factor in Zope 2’s success
History V
             The Bad
• “implicit magic”: WTF is going on here?!
• tendency to overload templates with
  application logic (‘dummy’ calls, anyone?)
• “maze of python scripts”
• in summary: “messy”
History VI
  The Ugly
“Acquisition is a
jealous mistress”
                   Martin Aspeli



     ‘Nuff said!
Enter Zope3
• Rewritten from the ground up
• “Component Architecture”: Interfaces,
  Adapters... and Views
• pluggable via configuration a.k.a.“XML sit-
  ups” (Grok is changing that, though)
• lots of other Goodies (buildout, eggs,
  events)
Benefits of the CA

• makes it easy to write small, specific, easy
  to understand code
• re-usability
• explicit (it never guesses! no magic!)
portalstatusmessages
Interface                                            Adapter
from zope.interface import Interface, Attribute
                                                     from base64 import encodestring, decodestring
                                                     from pickle import dumps, loads
                                                     import sys

                                                     from zope.annotation.interfaces import IAnnotations
                                                     from zope.i18n import translate
                                                     from zope.interface import implements

class IMessage(Interface):                           from Products.statusmessages import STATUSMESSAGEKEY
                                                     from Products.statusmessages.message import Message

    quot;quot;quot;A single status message.quot;quot;quot;                   from Products.statusmessages.interfaces import IStatusMessage

                                                     import logging
                                                     logger = logging.getLogger('statusmessages')

                                                     class StatusMessage(object):


    message = Attribute('The text of this message.
                                                         quot;quot;quot;Adapter for the BrowserRequest to handle status messages.

                                                         Let's make sure that this implementation actually fulfills the


Usally a Message object.')
                                                         'IStatusMessage' API.

                                                           >>> from zope.interface.verify import verifyClass
                                                           >>> verifyClass(IStatusMessage, StatusMessage)
                                                           True
                                                         quot;quot;quot;
                                                         implements(IStatusMessage)

    type = Attribute('The type of this message.')        def __init__(self, context):
                                                             self.context = context # the context must be the request

                                                         def addStatusMessage(self, text, type=''):
                                                             quot;quot;quot;Add a status message.
                                                             quot;quot;quot;
                                                             text = translate(text, context=self.context)
                                                             annotations = IAnnotations(self.context)


class IStatusMessage(Interface):                             old = annotations.get(STATUSMESSAGEKEY, self.context.cookies.get(STATUSMESSAGEKEY))
                                                             value = _encodeCookieValue(text, type, old=old)


    quot;quot;quot;An adapter for the BrowserRequest to handle
                                                             self.context.RESPONSE.setCookie(STATUSMESSAGEKEY, value, path='/')
                                                             annotations[STATUSMESSAGEKEY] = value

                                                         def showStatusMessages(self):

status messages.quot;quot;quot;                                          quot;quot;quot;Removes all status messages and returns them for display.
                                                             quot;quot;quot;
                                                             annotations = IAnnotations(self.context)
                                                             value = annotations.get(STATUSMESSAGEKEY, self.context.cookies.get(STATUSMESSAGEKEY))
                                                             if value is None:
                                                                 return []

    def addStatusMessage(text, type=''):                     value = _decodeCookieValue(value)
                                                             # clear the existing cookie entries
                                                             self.context.cookies[STATUSMESSAGEKEY] = None

        quot;quot;quot;Add a status message.quot;quot;quot;                          self.context.RESPONSE.expireCookie(STATUSMESSAGEKEY, path='/')
                                                             annotations[STATUSMESSAGEKEY] = None
                                                             return value

                                                     def _encodeCookieValue(text, type, old=None):
                                                         quot;quot;quot;Encodes text and type to a list of Messages. If there is already some old


    def showStatusMessages():
                                                             existing list, add the new Message at the end but don't add duplicate
                                                             messages.
                                                         quot;quot;quot;
                                                         results = []

        quot;quot;quot;Removes all status messages and returns       message = Message(text, type=type)

                                                         if old is not None:

them for display.                                            results = _decodeCookieValue(old)
                                                         if not message in results:
                                                             results.append(message)

        quot;quot;quot;                                              # we have to remove any newlines or the cookie value will be invalid
                                                         return encodestring(dumps(results)).replace('n','')

                                                     def _decodeCookieValue(string):
                                                         quot;quot;quot;Decode a cookie value to a list of Messages.
                                                             The value has to be a base64 encoded pickle of a list of Messages. If it
                                                             contains anything else, it will be ignored for security reasons.
                                                         quot;quot;quot;
                                                         results = []
                                                         # Return nothing if the cookie is marked as deleted
                                                         if string == 'deleted':
                                                              return results
                                                         # Try to decode the cookie value
                                                         try:
                                                              values = loads(decodestring(string))
                                                         except: # If there's anything unexpected in the string ignore it
                                                              logger.log(logging.ERROR, '%s n%s',
                                                                         'Unexpected value in statusmessages cookie',
                                                                         sys.exc_value
                                                                         )
                                                              return []
                                                         if isinstance(values, list): # simple security check
                                                              for value in values:
                                                                  if isinstance(value, Message): # and another simple check
                                                                      results.append(value)
                                                         return results
Views + Templates
        Adapters
    (Application Logic)



           View



        Template
Views + Templates


 Let’s dumb this down further ;-)
Views + Templates

• Think “View = Dictionary”
• Views collect data from the application into
  a dictionary
• Templates take the data from the dictionary
  and insert it into the markup
Views + Templates

• Templates insert, replace and loop
  (conditionally) – keep them ‘dumb’
• use methods (with @property, @memoize
  at your discretion)

• use kw dictionary for simple attributes:
  kw.update(‘foo’, bar)
Views + Templates

• Templates insert, replace and loop
  (conditionally) – keep them ‘dumb’
• use methods (with @property, @memoize
  at your discretion)

• use kw dictionary for simple attributes:
  kw.update(‘foo’, bar)
Views + Templates


       Demo
Views + Templates

• avoid using self.foo for attributes (for
  consistency’s sake)
• python expressions in templates are not
  inherently evil! (only to abuse them is)
• python expressions are ca. 3x faster than
  path expressions!
On to the
practical stuff

    Questions?
A Simple View
from Products.Five.browser import BrowserView

class MyView(BrowserView):

    def __call__(self, *args, **kw):

        kw.update({‘foo’ : self.bar()})

        return super(MyView, self).__call__(*args, **kw)

    @property

    def some_value(self):

        return something_complicated()
A Simple Viewlet
from Products.Five.browser import BrowserView

class MyView(BrowserView):

    def __call__(self, *args, **kw):

        kw.update({‘foo’ : self.bar()})

        return super(MyView, self).__call__(*args, **kw)

    @property

    def some_value(self):

        return something_complicated()
Debugging Views
from Products.Five.browser import BrowserView

class MyView(BrowserView):

    def __call__(self, *args, **kw):

        import pdb ; pdb.set_trace()

        return super(MyView, self).__call__(*args, **kw)
Context
     from Acquisition import aq_inner

     from Products.Five.browser import BrowserView

     class MyView(BrowserView):

          def some_view_function(self):

               context = aq_inner(self.context)



 “If you forget the aq_inner() it will probably still work 9 times out of 10,
but the 10th time you're screwed and wondering why you're getting insane
         errors about user folders and attributes not being found.”
                                                                     Martin Aspeli
View Interfaces
   • a contract between developer and designer
from zope.interface import Interface
from zope.interface import implements
from Products.Five.browser import BrowserView

class ISummaryPage(Interface):
  def summary():
    pass
  def body():
    pass

class IntroPageView(BrowserView):
    implements(ISummaryPage)

 def summary(self):
   return foo()
Dos and Don’ts

• don’t use __init__()
• use __call__()
• don’t use context/foo (expensive!)
• use kw + options/foo and/or Interfaces
Hack No. 1
    View + skin template
    For extra flexibility you can hook up a Five
         view with a skin based template:

from Acquisition import aq_acquire
from Products.Five.browser import BrowserView

class IntroPageView(BrowserView):
    def __call__(self, *args, **kw):
        kw.update({'some_name' : nifty_method()})
        return aq_acquire(self.context, 'intro-page')(**kw)
Skin switching
• Use a different skin depending on URL
• Useful for editing sites with heavily customized
  public skin
• For example: use Plone’s default skin when
  accessed via HTTPS
• Old method with External Method and ‘Set
    Access Rule’ no longer works (plone.theme
    marks request with default skin before rule is
    processed)
•   New method is actually easier and less code
Skin switching
 The Code
def setskin(site, event):
    if event.request.URL.startswith('https'):
        site.changeSkin(“Plone Default”, event.request)



 The Glue
<subscriber
    for=quot;Products.CMFPlone.interfaces.IPloneSiteRoot
         zope.app.publication.interfaces.IBeforeTraverseEventquot;
    handler=quot;.skinswitcher.setskinquot; />
Caching

  Two basic approaches:
• cache results of view methods: memoize
• cache entire view/viewlet: lovely.viewcache
Caching
from plone.memoize.instance import memoize
from Products.Five.browser import BrowserView
class MyView(BrowserView):

   @memoize

   def expensiveMethod(self):

    return foo
lovely.viewcache
from lovely.viewcache.view import
cachedView

class View(BrowserView):
    pass

CachedView = cachedView(View)

Now use CachedView instead of View in your .zcml
       Works just the same for Viewlets
lovely.viewcache

• Entire page usually not cacheable
• But caching viewlets is particularly useful
• By using views and viewlets you futureproof
  your product for later scalability!
subclass BrowserView

• common methods for all your views
• group and share similar behaviour
• hierarchy easier to debug than Acquisition!
Hack No. 2: custom
           viewlet per page
     Usecase: custom logo viewlet for frontpage only.
     Didn’t want to add extra logic to view class and
                  template just for that.
        Solution: custom template for frontpage
<browser:viewlet
    name=quot;plone.logoquot;
    manager=quot;plone.app.layout.viewlets.interfaces.IPortalHeaderquot;
    class=quot;.viewlets.LogoViewletquot;
    permission=quot;zope2.Viewquot;
    layer=quot;.interfaces.IMySkinSpecificquot;
    />
Hack No. 2: custom
           viewlet per page
from Products.CMFPlone.interfaces import IPloneSiteRoot
from plone.app.layout.viewlets.common import LogoViewlet as
LogoViewletBase
class LogoViewlet(LogoViewletBase):

    _template = ViewPageTemplateFile('logo.pt')
    _frontpage_template = ViewPageTemplateFile('logo-frontpage.pt')

    def render(self):
        if IPloneSiteRoot.providedBy(self.context):
            return self._frontpage_template()
        else:
            return self._template()
Hack No. 2: custom
           viewlet per page
               That’s stupid, don’t do that!
     Viewlet accepts view attribute, problem solved!

<browser:viewlet
    name=quot;plone.logoquot;
    manager=quot;plone.app.layout.viewlets.interfaces.IPortalHeaderquot;
    class=quot;.viewlets.FrontpageLogoViewletquot;
    permission=quot;zope2.Viewquot;
    layer=quot;.interfaces.IMySkinSpecificquot;
    view=”IFrontpageView”
    />
Fun with Views

• Remember:Views are just multi-adapters
  that return (in most cases) HTML
• ZPT is just a default behavior
• Let’s use... Genshi
Genshi
from zope.publisher.browser import BrowserPage
class HelloGenshi(BrowserPage):
    def __call__(self):
        tmpl = loader.load('helloworld.html')
        stream = tmpl.generate(
            request=self.request,
            who=self.request.principal.id
        )
        return stream.render('html',
            doctype='html')
Genshi
<div xmlns:py=quot;http://genshi.edgewall.org/quot;>
    <p>Hello $who</p>
    <p>Hello ${request.principal.id}</p>
    <table>
      <tr py:for=quot;key in requestquot;
           py:if=quot;key.startswith('HTTP')quot;>
         <td>$key</td>
         <td>${request[key]}</td>
      </tr>
    </table>
</div>
Genshi

• everything you love about ZPT
• (hardly) anything you hate about ZPT
• also works with non-markup
• still valid XHTML
• less verbose
Thank you.

More Related Content

What's hot

Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Rails
rstankov
 
«Objective-C Runtime в примерах» — Алексей Сторожев, e-Legion
«Objective-C Runtime в примерах» — Алексей Сторожев, e-Legion«Objective-C Runtime в примерах» — Алексей Сторожев, e-Legion
«Objective-C Runtime в примерах» — Алексей Сторожев, e-Legion
e-Legion
 
Actionsscript Cheat Sheet Letter
Actionsscript Cheat Sheet LetterActionsscript Cheat Sheet Letter
Actionsscript Cheat Sheet Letter
guest2a6b08
 
Actionsscript cheat sheet_letter
Actionsscript cheat sheet_letterActionsscript cheat sheet_letter
Actionsscript cheat sheet_letter
Radik Setagalih
 
Backbone js
Backbone jsBackbone js
Backbone js
rstankov
 
Prototype Framework
Prototype FrameworkPrototype Framework
Prototype Framework
Julie Iskander
 
jQuery1.2.cheatsheet.v1.0
jQuery1.2.cheatsheet.v1.0jQuery1.2.cheatsheet.v1.0
jQuery1.2.cheatsheet.v1.0
guest644d1d
 
JQuery New Evolution
JQuery New EvolutionJQuery New Evolution
JQuery New Evolution
Allan Huang
 
Single page webapps & javascript-testing
Single page webapps & javascript-testingSingle page webapps & javascript-testing
Single page webapps & javascript-testing
smontanari
 
Data20161007
Data20161007Data20161007
Data20161007
capegmail
 
Understanding redux
Understanding reduxUnderstanding redux
Understanding redux
David Atchley
 

What's hot (11)

Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Rails
 
«Objective-C Runtime в примерах» — Алексей Сторожев, e-Legion
«Objective-C Runtime в примерах» — Алексей Сторожев, e-Legion«Objective-C Runtime в примерах» — Алексей Сторожев, e-Legion
«Objective-C Runtime в примерах» — Алексей Сторожев, e-Legion
 
Actionsscript Cheat Sheet Letter
Actionsscript Cheat Sheet LetterActionsscript Cheat Sheet Letter
Actionsscript Cheat Sheet Letter
 
Actionsscript cheat sheet_letter
Actionsscript cheat sheet_letterActionsscript cheat sheet_letter
Actionsscript cheat sheet_letter
 
Backbone js
Backbone jsBackbone js
Backbone js
 
Prototype Framework
Prototype FrameworkPrototype Framework
Prototype Framework
 
jQuery1.2.cheatsheet.v1.0
jQuery1.2.cheatsheet.v1.0jQuery1.2.cheatsheet.v1.0
jQuery1.2.cheatsheet.v1.0
 
JQuery New Evolution
JQuery New EvolutionJQuery New Evolution
JQuery New Evolution
 
Single page webapps & javascript-testing
Single page webapps & javascript-testingSingle page webapps & javascript-testing
Single page webapps & javascript-testing
 
Data20161007
Data20161007Data20161007
Data20161007
 
Understanding redux
Understanding reduxUnderstanding redux
Understanding redux
 

Viewers also liked

Plone3 Generateur d'applications et gestion de contenu 2.0
Plone3 Generateur d'applications et gestion de contenu 2.0Plone3 Generateur d'applications et gestion de contenu 2.0
Plone3 Generateur d'applications et gestion de contenu 2.0
Paris, France
 
zc.buildout para desarrolladores Plone
zc.buildout para desarrolladores Plonezc.buildout para desarrolladores Plone
zc.buildout para desarrolladores Plone
Roberto Allende
 
New in Plone 3.3. What to expect from Plone 4
New in Plone 3.3. What to expect from Plone 4New in Plone 3.3. What to expect from Plone 4
New in Plone 3.3. What to expect from Plone 4
Quintagroup
 
Struts N E W
Struts N E WStruts N E W
Struts N E W
patinijava
 
Ruby On Rails Tutorial
Ruby On Rails TutorialRuby On Rails Tutorial
Ruby On Rails Tutorial
sunniboy
 
PECL Picks - Extensions to make your life better
PECL Picks - Extensions to make your life betterPECL Picks - Extensions to make your life better
PECL Picks - Extensions to make your life better
ZendCon
 
Informix and PHP
Informix and PHPInformix and PHP
Informix and PHP
David Bernhardt
 
Plone 4 and 5, plans and progress
Plone 4 and 5, plans and progressPlone 4 and 5, plans and progress
Plone 4 and 5, plans and progress
Geir Bækholt
 
Show cooking 1
Show cooking 1Show cooking 1
Show cooking 1
Ricardo Pires
 

Viewers also liked (10)

Plone3 Generateur d'applications et gestion de contenu 2.0
Plone3 Generateur d'applications et gestion de contenu 2.0Plone3 Generateur d'applications et gestion de contenu 2.0
Plone3 Generateur d'applications et gestion de contenu 2.0
 
zc.buildout para desarrolladores Plone
zc.buildout para desarrolladores Plonezc.buildout para desarrolladores Plone
zc.buildout para desarrolladores Plone
 
Plone@tigem
Plone@tigemPlone@tigem
Plone@tigem
 
New in Plone 3.3. What to expect from Plone 4
New in Plone 3.3. What to expect from Plone 4New in Plone 3.3. What to expect from Plone 4
New in Plone 3.3. What to expect from Plone 4
 
Struts N E W
Struts N E WStruts N E W
Struts N E W
 
Ruby On Rails Tutorial
Ruby On Rails TutorialRuby On Rails Tutorial
Ruby On Rails Tutorial
 
PECL Picks - Extensions to make your life better
PECL Picks - Extensions to make your life betterPECL Picks - Extensions to make your life better
PECL Picks - Extensions to make your life better
 
Informix and PHP
Informix and PHPInformix and PHP
Informix and PHP
 
Plone 4 and 5, plans and progress
Plone 4 and 5, plans and progressPlone 4 and 5, plans and progress
Plone 4 and 5, plans and progress
 
Show cooking 1
Show cooking 1Show cooking 1
Show cooking 1
 

Similar to Tom Lazar Using Zope3 Views And Viewlets For Plone 3.0 Product Development

Testing your javascript code with jasmine
Testing your javascript code with jasmineTesting your javascript code with jasmine
Testing your javascript code with jasmine
Rubyc Slides
 
Jython: Python para la plataforma Java (EL2009)
Jython: Python para la plataforma Java (EL2009)Jython: Python para la plataforma Java (EL2009)
Jython: Python para la plataforma Java (EL2009)
Leonardo Soto
 
Vbscript reference
Vbscript referenceVbscript reference
Vbscript reference
Rahul Ranjan
 
Jython: Python para la plataforma Java (JRSL 09)
Jython: Python para la plataforma Java (JRSL 09)Jython: Python para la plataforma Java (JRSL 09)
Jython: Python para la plataforma Java (JRSL 09)
Leonardo Soto
 
Frank Rodenbaugh Portfolio
Frank Rodenbaugh PortfolioFrank Rodenbaugh Portfolio
Frank Rodenbaugh Portfolio
FrankRodenbaugh
 
DataMapper
DataMapperDataMapper
DataMapper
Yehuda Katz
 
Unit test candidate solutions
Unit test candidate solutionsUnit test candidate solutions
Unit test candidate solutions
benewu
 
Hidden Gems in Swift
Hidden Gems in SwiftHidden Gems in Swift
Hidden Gems in Swift
Netguru
 
The Scalactic Way
The Scalactic WayThe Scalactic Way
The Scalactic Way
bvenners
 
Backbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The BrowserBackbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The Browser
Howard Lewis Ship
 
Barcamp Auckland Rails3 presentation
Barcamp Auckland Rails3 presentationBarcamp Auckland Rails3 presentation
Barcamp Auckland Rails3 presentation
Sociable
 
Qtp test
Qtp testQtp test
Qtp test
G.C Reddy
 
Learning Java 4 – Swing, SQL, and Security API
Learning Java 4 – Swing, SQL, and Security APILearning Java 4 – Swing, SQL, and Security API
Learning Java 4 – Swing, SQL, and Security API
caswenson
 
Practical Experience Building JavaFX Rich Clients
Practical Experience Building JavaFX Rich ClientsPractical Experience Building JavaFX Rich Clients
Practical Experience Building JavaFX Rich Clients
Richard Bair
 
descriptive programming
descriptive programmingdescriptive programming
descriptive programming
Anand Dhana
 
比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotation
javatwo2011
 
Swift で JavaScript 始めませんか? #iOSDC
Swift で JavaScript 始めませんか? #iOSDCSwift で JavaScript 始めませんか? #iOSDC
Swift で JavaScript 始めませんか? #iOSDC
Tomohiro Kumagai
 
Scripting as a Second Language
Scripting as a Second LanguageScripting as a Second Language
Scripting as a Second Language
Rob Dunn
 
Fabric.js @ Falsy Values
Fabric.js @ Falsy ValuesFabric.js @ Falsy Values
Fabric.js @ Falsy Values
Juriy Zaytsev
 
前端MVC 豆瓣说
前端MVC 豆瓣说前端MVC 豆瓣说
前端MVC 豆瓣说
Ting Lv
 

Similar to Tom Lazar Using Zope3 Views And Viewlets For Plone 3.0 Product Development (20)

Testing your javascript code with jasmine
Testing your javascript code with jasmineTesting your javascript code with jasmine
Testing your javascript code with jasmine
 
Jython: Python para la plataforma Java (EL2009)
Jython: Python para la plataforma Java (EL2009)Jython: Python para la plataforma Java (EL2009)
Jython: Python para la plataforma Java (EL2009)
 
Vbscript reference
Vbscript referenceVbscript reference
Vbscript reference
 
Jython: Python para la plataforma Java (JRSL 09)
Jython: Python para la plataforma Java (JRSL 09)Jython: Python para la plataforma Java (JRSL 09)
Jython: Python para la plataforma Java (JRSL 09)
 
Frank Rodenbaugh Portfolio
Frank Rodenbaugh PortfolioFrank Rodenbaugh Portfolio
Frank Rodenbaugh Portfolio
 
DataMapper
DataMapperDataMapper
DataMapper
 
Unit test candidate solutions
Unit test candidate solutionsUnit test candidate solutions
Unit test candidate solutions
 
Hidden Gems in Swift
Hidden Gems in SwiftHidden Gems in Swift
Hidden Gems in Swift
 
The Scalactic Way
The Scalactic WayThe Scalactic Way
The Scalactic Way
 
Backbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The BrowserBackbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The Browser
 
Barcamp Auckland Rails3 presentation
Barcamp Auckland Rails3 presentationBarcamp Auckland Rails3 presentation
Barcamp Auckland Rails3 presentation
 
Qtp test
Qtp testQtp test
Qtp test
 
Learning Java 4 – Swing, SQL, and Security API
Learning Java 4 – Swing, SQL, and Security APILearning Java 4 – Swing, SQL, and Security API
Learning Java 4 – Swing, SQL, and Security API
 
Practical Experience Building JavaFX Rich Clients
Practical Experience Building JavaFX Rich ClientsPractical Experience Building JavaFX Rich Clients
Practical Experience Building JavaFX Rich Clients
 
descriptive programming
descriptive programmingdescriptive programming
descriptive programming
 
比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotation
 
Swift で JavaScript 始めませんか? #iOSDC
Swift で JavaScript 始めませんか? #iOSDCSwift で JavaScript 始めませんか? #iOSDC
Swift で JavaScript 始めませんか? #iOSDC
 
Scripting as a Second Language
Scripting as a Second LanguageScripting as a Second Language
Scripting as a Second Language
 
Fabric.js @ Falsy Values
Fabric.js @ Falsy ValuesFabric.js @ Falsy Values
Fabric.js @ Falsy Values
 
前端MVC 豆瓣说
前端MVC 豆瓣说前端MVC 豆瓣说
前端MVC 豆瓣说
 

More from Vincenzo Barone

Sally Kleinfeldt - Plone Application Development Patterns
Sally Kleinfeldt - Plone Application Development PatternsSally Kleinfeldt - Plone Application Development Patterns
Sally Kleinfeldt - Plone Application Development Patterns
Vincenzo Barone
 
Where's the source, Luke? : How to find and debug the code behind Plone
Where's the source, Luke? : How to find and debug the code behind PloneWhere's the source, Luke? : How to find and debug the code behind Plone
Where's the source, Luke? : How to find and debug the code behind Plone
Vincenzo Barone
 
ItalianSkin: an improvement in the accessibility of the Plone interface in or...
ItalianSkin: an improvement in the accessibility of the Plone interface in or...ItalianSkin: an improvement in the accessibility of the Plone interface in or...
ItalianSkin: an improvement in the accessibility of the Plone interface in or...
Vincenzo Barone
 
How to market Plone the Web2.0 way
How to market Plone the Web2.0 wayHow to market Plone the Web2.0 way
How to market Plone the Web2.0 way
Vincenzo Barone
 
Lennart Regebro What Zope Did Wrong (And What To Do Instead)
Lennart Regebro   What Zope Did Wrong (And What To Do Instead)Lennart Regebro   What Zope Did Wrong (And What To Do Instead)
Lennart Regebro What Zope Did Wrong (And What To Do Instead)
Vincenzo Barone
 
Wichert Akkerman Plone Deployment Practices The Plone.Org Setup
Wichert Akkerman   Plone Deployment Practices   The Plone.Org SetupWichert Akkerman   Plone Deployment Practices   The Plone.Org Setup
Wichert Akkerman Plone Deployment Practices The Plone.Org Setup
Vincenzo Barone
 
Philipp Von Weitershausen Untested Code Is Broken Code
Philipp Von Weitershausen   Untested Code Is Broken CodePhilipp Von Weitershausen   Untested Code Is Broken Code
Philipp Von Weitershausen Untested Code Is Broken Code
Vincenzo Barone
 
Duco Dokter - Plone for the enterprise market: technical musing on caching, C...
Duco Dokter - Plone for the enterprise market: technical musing on caching, C...Duco Dokter - Plone for the enterprise market: technical musing on caching, C...
Duco Dokter - Plone for the enterprise market: technical musing on caching, C...
Vincenzo Barone
 
Rocky Burt Subtyping Unleashed
Rocky Burt   Subtyping UnleashedRocky Burt   Subtyping Unleashed
Rocky Burt Subtyping Unleashed
Vincenzo Barone
 
Alec Mitchell Relationship Building Defining And Querying Complex Relatio...
Alec Mitchell   Relationship Building   Defining And Querying Complex Relatio...Alec Mitchell   Relationship Building   Defining And Querying Complex Relatio...
Alec Mitchell Relationship Building Defining And Querying Complex Relatio...
Vincenzo Barone
 
Wageindicator Foundation: a Case Study
Wageindicator Foundation: a Case StudyWageindicator Foundation: a Case Study
Wageindicator Foundation: a Case Study
Vincenzo Barone
 
Xavier Heymans Plone Gov Plone In The Public Sector. Panel Presenting The...
Xavier Heymans   Plone Gov   Plone In The Public Sector. Panel Presenting The...Xavier Heymans   Plone Gov   Plone In The Public Sector. Panel Presenting The...
Xavier Heymans Plone Gov Plone In The Public Sector. Panel Presenting The...
Vincenzo Barone
 
Brent Lambert Plone In Education A Case Study Of The Use Of Plone And Educa...
Brent Lambert   Plone In Education A Case Study Of The Use Of Plone And Educa...Brent Lambert   Plone In Education A Case Study Of The Use Of Plone And Educa...
Brent Lambert Plone In Education A Case Study Of The Use Of Plone And Educa...
Vincenzo Barone
 
Wichert Akkerman - Plone.Org Infrastructure
Wichert Akkerman - Plone.Org InfrastructureWichert Akkerman - Plone.Org Infrastructure
Wichert Akkerman - Plone.Org Infrastructure
Vincenzo Barone
 
Philipp Von Weitershausen Plone Age Mammoths, Sabers And Caveen Cant The...
Philipp Von Weitershausen   Plone Age  Mammoths, Sabers And Caveen   Cant The...Philipp Von Weitershausen   Plone Age  Mammoths, Sabers And Caveen   Cant The...
Philipp Von Weitershausen Plone Age Mammoths, Sabers And Caveen Cant The...
Vincenzo Barone
 
Denis Mishunov Making Plone Theme 10 Most Wanted Tips
Denis Mishunov   Making Plone Theme   10 Most Wanted Tips Denis Mishunov   Making Plone Theme   10 Most Wanted Tips
Denis Mishunov Making Plone Theme 10 Most Wanted Tips
Vincenzo Barone
 
Duncan Booth Kupu, Past Present And Future
Duncan Booth   Kupu, Past Present And FutureDuncan Booth   Kupu, Past Present And Future
Duncan Booth Kupu, Past Present And Future
Vincenzo Barone
 
Jeroen Vloothuis Bend Kss To Your Will
Jeroen Vloothuis   Bend Kss To Your WillJeroen Vloothuis   Bend Kss To Your Will
Jeroen Vloothuis Bend Kss To Your Will
Vincenzo Barone
 
Jared Whitlock Open Source In The Enterprise Plone @ Novell
Jared Whitlock   Open Source In The Enterprise    Plone @ NovellJared Whitlock   Open Source In The Enterprise    Plone @ Novell
Jared Whitlock Open Source In The Enterprise Plone @ Novell
Vincenzo Barone
 
Paul Everitt Community And Foundation Plones Past, Present, Future
Paul Everitt   Community And Foundation   Plones Past, Present, Future Paul Everitt   Community And Foundation   Plones Past, Present, Future
Paul Everitt Community And Foundation Plones Past, Present, Future
Vincenzo Barone
 

More from Vincenzo Barone (20)

Sally Kleinfeldt - Plone Application Development Patterns
Sally Kleinfeldt - Plone Application Development PatternsSally Kleinfeldt - Plone Application Development Patterns
Sally Kleinfeldt - Plone Application Development Patterns
 
Where's the source, Luke? : How to find and debug the code behind Plone
Where's the source, Luke? : How to find and debug the code behind PloneWhere's the source, Luke? : How to find and debug the code behind Plone
Where's the source, Luke? : How to find and debug the code behind Plone
 
ItalianSkin: an improvement in the accessibility of the Plone interface in or...
ItalianSkin: an improvement in the accessibility of the Plone interface in or...ItalianSkin: an improvement in the accessibility of the Plone interface in or...
ItalianSkin: an improvement in the accessibility of the Plone interface in or...
 
How to market Plone the Web2.0 way
How to market Plone the Web2.0 wayHow to market Plone the Web2.0 way
How to market Plone the Web2.0 way
 
Lennart Regebro What Zope Did Wrong (And What To Do Instead)
Lennart Regebro   What Zope Did Wrong (And What To Do Instead)Lennart Regebro   What Zope Did Wrong (And What To Do Instead)
Lennart Regebro What Zope Did Wrong (And What To Do Instead)
 
Wichert Akkerman Plone Deployment Practices The Plone.Org Setup
Wichert Akkerman   Plone Deployment Practices   The Plone.Org SetupWichert Akkerman   Plone Deployment Practices   The Plone.Org Setup
Wichert Akkerman Plone Deployment Practices The Plone.Org Setup
 
Philipp Von Weitershausen Untested Code Is Broken Code
Philipp Von Weitershausen   Untested Code Is Broken CodePhilipp Von Weitershausen   Untested Code Is Broken Code
Philipp Von Weitershausen Untested Code Is Broken Code
 
Duco Dokter - Plone for the enterprise market: technical musing on caching, C...
Duco Dokter - Plone for the enterprise market: technical musing on caching, C...Duco Dokter - Plone for the enterprise market: technical musing on caching, C...
Duco Dokter - Plone for the enterprise market: technical musing on caching, C...
 
Rocky Burt Subtyping Unleashed
Rocky Burt   Subtyping UnleashedRocky Burt   Subtyping Unleashed
Rocky Burt Subtyping Unleashed
 
Alec Mitchell Relationship Building Defining And Querying Complex Relatio...
Alec Mitchell   Relationship Building   Defining And Querying Complex Relatio...Alec Mitchell   Relationship Building   Defining And Querying Complex Relatio...
Alec Mitchell Relationship Building Defining And Querying Complex Relatio...
 
Wageindicator Foundation: a Case Study
Wageindicator Foundation: a Case StudyWageindicator Foundation: a Case Study
Wageindicator Foundation: a Case Study
 
Xavier Heymans Plone Gov Plone In The Public Sector. Panel Presenting The...
Xavier Heymans   Plone Gov   Plone In The Public Sector. Panel Presenting The...Xavier Heymans   Plone Gov   Plone In The Public Sector. Panel Presenting The...
Xavier Heymans Plone Gov Plone In The Public Sector. Panel Presenting The...
 
Brent Lambert Plone In Education A Case Study Of The Use Of Plone And Educa...
Brent Lambert   Plone In Education A Case Study Of The Use Of Plone And Educa...Brent Lambert   Plone In Education A Case Study Of The Use Of Plone And Educa...
Brent Lambert Plone In Education A Case Study Of The Use Of Plone And Educa...
 
Wichert Akkerman - Plone.Org Infrastructure
Wichert Akkerman - Plone.Org InfrastructureWichert Akkerman - Plone.Org Infrastructure
Wichert Akkerman - Plone.Org Infrastructure
 
Philipp Von Weitershausen Plone Age Mammoths, Sabers And Caveen Cant The...
Philipp Von Weitershausen   Plone Age  Mammoths, Sabers And Caveen   Cant The...Philipp Von Weitershausen   Plone Age  Mammoths, Sabers And Caveen   Cant The...
Philipp Von Weitershausen Plone Age Mammoths, Sabers And Caveen Cant The...
 
Denis Mishunov Making Plone Theme 10 Most Wanted Tips
Denis Mishunov   Making Plone Theme   10 Most Wanted Tips Denis Mishunov   Making Plone Theme   10 Most Wanted Tips
Denis Mishunov Making Plone Theme 10 Most Wanted Tips
 
Duncan Booth Kupu, Past Present And Future
Duncan Booth   Kupu, Past Present And FutureDuncan Booth   Kupu, Past Present And Future
Duncan Booth Kupu, Past Present And Future
 
Jeroen Vloothuis Bend Kss To Your Will
Jeroen Vloothuis   Bend Kss To Your WillJeroen Vloothuis   Bend Kss To Your Will
Jeroen Vloothuis Bend Kss To Your Will
 
Jared Whitlock Open Source In The Enterprise Plone @ Novell
Jared Whitlock   Open Source In The Enterprise    Plone @ NovellJared Whitlock   Open Source In The Enterprise    Plone @ Novell
Jared Whitlock Open Source In The Enterprise Plone @ Novell
 
Paul Everitt Community And Foundation Plones Past, Present, Future
Paul Everitt   Community And Foundation   Plones Past, Present, Future Paul Everitt   Community And Foundation   Plones Past, Present, Future
Paul Everitt Community And Foundation Plones Past, Present, Future
 

Recently uploaded

Recruiting in the Digital Age: A Social Media Masterclass
Recruiting in the Digital Age: A Social Media MasterclassRecruiting in the Digital Age: A Social Media Masterclass
Recruiting in the Digital Age: A Social Media Masterclass
LuanWise
 
Building Your Employer Brand with Social Media
Building Your Employer Brand with Social MediaBuilding Your Employer Brand with Social Media
Building Your Employer Brand with Social Media
LuanWise
 
The Influence of Marketing Strategy and Market Competition on Business Perfor...
The Influence of Marketing Strategy and Market Competition on Business Perfor...The Influence of Marketing Strategy and Market Competition on Business Perfor...
The Influence of Marketing Strategy and Market Competition on Business Perfor...
Adam Smith
 
Authentically Social by Corey Perlman - EO Puerto Rico
Authentically Social by Corey Perlman - EO Puerto RicoAuthentically Social by Corey Perlman - EO Puerto Rico
Authentically Social by Corey Perlman - EO Puerto Rico
Corey Perlman, Social Media Speaker and Consultant
 
Call 8867766396 Satta Matka Dpboss Matka Guessing Satta batta Matka 420 Satta...
Call 8867766396 Satta Matka Dpboss Matka Guessing Satta batta Matka 420 Satta...Call 8867766396 Satta Matka Dpboss Matka Guessing Satta batta Matka 420 Satta...
Call 8867766396 Satta Matka Dpboss Matka Guessing Satta batta Matka 420 Satta...
bosssp10
 
Authentically Social Presented by Corey Perlman
Authentically Social Presented by Corey PerlmanAuthentically Social Presented by Corey Perlman
Authentically Social Presented by Corey Perlman
Corey Perlman, Social Media Speaker and Consultant
 
FIA officials brutally tortured innocent and snatched 200 Bitcoins of worth 4...
FIA officials brutally tortured innocent and snatched 200 Bitcoins of worth 4...FIA officials brutally tortured innocent and snatched 200 Bitcoins of worth 4...
FIA officials brutally tortured innocent and snatched 200 Bitcoins of worth 4...
jamalseoexpert1978
 
Taurus Zodiac Sign: Unveiling the Traits, Dates, and Horoscope Insights of th...
Taurus Zodiac Sign: Unveiling the Traits, Dates, and Horoscope Insights of th...Taurus Zodiac Sign: Unveiling the Traits, Dates, and Horoscope Insights of th...
Taurus Zodiac Sign: Unveiling the Traits, Dates, and Horoscope Insights of th...
my Pandit
 
Satta Matka Dpboss Matka Guessing Kalyan Chart Indian Matka Kalyan panel Chart
Satta Matka Dpboss Matka Guessing Kalyan Chart Indian Matka Kalyan panel ChartSatta Matka Dpboss Matka Guessing Kalyan Chart Indian Matka Kalyan panel Chart
Satta Matka Dpboss Matka Guessing Kalyan Chart Indian Matka Kalyan panel Chart
➒➌➎➏➑➐➋➑➐➐Dpboss Matka Guessing Satta Matka Kalyan Chart Indian Matka
 
Best practices for project execution and delivery
Best practices for project execution and deliveryBest practices for project execution and delivery
Best practices for project execution and delivery
CLIVE MINCHIN
 
How to Implement a Real Estate CRM Software
How to Implement a Real Estate CRM SoftwareHow to Implement a Real Estate CRM Software
How to Implement a Real Estate CRM Software
SalesTown
 
Top mailing list providers in the USA.pptx
Top mailing list providers in the USA.pptxTop mailing list providers in the USA.pptx
Top mailing list providers in the USA.pptx
JeremyPeirce1
 
Hamster Kombat' Telegram Game Surpasses 100 Million Players—Token Release Sch...
Hamster Kombat' Telegram Game Surpasses 100 Million Players—Token Release Sch...Hamster Kombat' Telegram Game Surpasses 100 Million Players—Token Release Sch...
Hamster Kombat' Telegram Game Surpasses 100 Million Players—Token Release Sch...
SOFTTECHHUB
 
Zodiac Signs and Food Preferences_ What Your Sign Says About Your Taste
Zodiac Signs and Food Preferences_ What Your Sign Says About Your TasteZodiac Signs and Food Preferences_ What Your Sign Says About Your Taste
Zodiac Signs and Food Preferences_ What Your Sign Says About Your Taste
my Pandit
 
Unveiling the Dynamic Personalities, Key Dates, and Horoscope Insights: Gemin...
Unveiling the Dynamic Personalities, Key Dates, and Horoscope Insights: Gemin...Unveiling the Dynamic Personalities, Key Dates, and Horoscope Insights: Gemin...
Unveiling the Dynamic Personalities, Key Dates, and Horoscope Insights: Gemin...
my Pandit
 
-- June 2024 is National Volunteer Month --
-- June 2024 is National Volunteer Month ---- June 2024 is National Volunteer Month --
-- June 2024 is National Volunteer Month --
NZSG
 
Best Forex Brokers Comparison in INDIA 2024
Best Forex Brokers Comparison in INDIA 2024Best Forex Brokers Comparison in INDIA 2024
Best Forex Brokers Comparison in INDIA 2024
Top Forex Brokers Review
 
Creative Web Design Company in Singapore
Creative Web Design Company in SingaporeCreative Web Design Company in Singapore
Creative Web Design Company in Singapore
techboxsqauremedia
 
Part 2 Deep Dive: Navigating the 2024 Slowdown
Part 2 Deep Dive: Navigating the 2024 SlowdownPart 2 Deep Dive: Navigating the 2024 Slowdown
Part 2 Deep Dive: Navigating the 2024 Slowdown
jeffkluth1
 
Training my puppy and implementation in this story
Training my puppy and implementation in this storyTraining my puppy and implementation in this story
Training my puppy and implementation in this story
WilliamRodrigues148
 

Recently uploaded (20)

Recruiting in the Digital Age: A Social Media Masterclass
Recruiting in the Digital Age: A Social Media MasterclassRecruiting in the Digital Age: A Social Media Masterclass
Recruiting in the Digital Age: A Social Media Masterclass
 
Building Your Employer Brand with Social Media
Building Your Employer Brand with Social MediaBuilding Your Employer Brand with Social Media
Building Your Employer Brand with Social Media
 
The Influence of Marketing Strategy and Market Competition on Business Perfor...
The Influence of Marketing Strategy and Market Competition on Business Perfor...The Influence of Marketing Strategy and Market Competition on Business Perfor...
The Influence of Marketing Strategy and Market Competition on Business Perfor...
 
Authentically Social by Corey Perlman - EO Puerto Rico
Authentically Social by Corey Perlman - EO Puerto RicoAuthentically Social by Corey Perlman - EO Puerto Rico
Authentically Social by Corey Perlman - EO Puerto Rico
 
Call 8867766396 Satta Matka Dpboss Matka Guessing Satta batta Matka 420 Satta...
Call 8867766396 Satta Matka Dpboss Matka Guessing Satta batta Matka 420 Satta...Call 8867766396 Satta Matka Dpboss Matka Guessing Satta batta Matka 420 Satta...
Call 8867766396 Satta Matka Dpboss Matka Guessing Satta batta Matka 420 Satta...
 
Authentically Social Presented by Corey Perlman
Authentically Social Presented by Corey PerlmanAuthentically Social Presented by Corey Perlman
Authentically Social Presented by Corey Perlman
 
FIA officials brutally tortured innocent and snatched 200 Bitcoins of worth 4...
FIA officials brutally tortured innocent and snatched 200 Bitcoins of worth 4...FIA officials brutally tortured innocent and snatched 200 Bitcoins of worth 4...
FIA officials brutally tortured innocent and snatched 200 Bitcoins of worth 4...
 
Taurus Zodiac Sign: Unveiling the Traits, Dates, and Horoscope Insights of th...
Taurus Zodiac Sign: Unveiling the Traits, Dates, and Horoscope Insights of th...Taurus Zodiac Sign: Unveiling the Traits, Dates, and Horoscope Insights of th...
Taurus Zodiac Sign: Unveiling the Traits, Dates, and Horoscope Insights of th...
 
Satta Matka Dpboss Matka Guessing Kalyan Chart Indian Matka Kalyan panel Chart
Satta Matka Dpboss Matka Guessing Kalyan Chart Indian Matka Kalyan panel ChartSatta Matka Dpboss Matka Guessing Kalyan Chart Indian Matka Kalyan panel Chart
Satta Matka Dpboss Matka Guessing Kalyan Chart Indian Matka Kalyan panel Chart
 
Best practices for project execution and delivery
Best practices for project execution and deliveryBest practices for project execution and delivery
Best practices for project execution and delivery
 
How to Implement a Real Estate CRM Software
How to Implement a Real Estate CRM SoftwareHow to Implement a Real Estate CRM Software
How to Implement a Real Estate CRM Software
 
Top mailing list providers in the USA.pptx
Top mailing list providers in the USA.pptxTop mailing list providers in the USA.pptx
Top mailing list providers in the USA.pptx
 
Hamster Kombat' Telegram Game Surpasses 100 Million Players—Token Release Sch...
Hamster Kombat' Telegram Game Surpasses 100 Million Players—Token Release Sch...Hamster Kombat' Telegram Game Surpasses 100 Million Players—Token Release Sch...
Hamster Kombat' Telegram Game Surpasses 100 Million Players—Token Release Sch...
 
Zodiac Signs and Food Preferences_ What Your Sign Says About Your Taste
Zodiac Signs and Food Preferences_ What Your Sign Says About Your TasteZodiac Signs and Food Preferences_ What Your Sign Says About Your Taste
Zodiac Signs and Food Preferences_ What Your Sign Says About Your Taste
 
Unveiling the Dynamic Personalities, Key Dates, and Horoscope Insights: Gemin...
Unveiling the Dynamic Personalities, Key Dates, and Horoscope Insights: Gemin...Unveiling the Dynamic Personalities, Key Dates, and Horoscope Insights: Gemin...
Unveiling the Dynamic Personalities, Key Dates, and Horoscope Insights: Gemin...
 
-- June 2024 is National Volunteer Month --
-- June 2024 is National Volunteer Month ---- June 2024 is National Volunteer Month --
-- June 2024 is National Volunteer Month --
 
Best Forex Brokers Comparison in INDIA 2024
Best Forex Brokers Comparison in INDIA 2024Best Forex Brokers Comparison in INDIA 2024
Best Forex Brokers Comparison in INDIA 2024
 
Creative Web Design Company in Singapore
Creative Web Design Company in SingaporeCreative Web Design Company in Singapore
Creative Web Design Company in Singapore
 
Part 2 Deep Dive: Navigating the 2024 Slowdown
Part 2 Deep Dive: Navigating the 2024 SlowdownPart 2 Deep Dive: Navigating the 2024 Slowdown
Part 2 Deep Dive: Navigating the 2024 Slowdown
 
Training my puppy and implementation in this story
Training my puppy and implementation in this storyTraining my puppy and implementation in this story
Training my puppy and implementation in this story
 

Tom Lazar Using Zope3 Views And Viewlets For Plone 3.0 Product Development

  • 1. Views and viewlets for Plone 3.0 Product Development Tom Lazar
  • 2. Who are you? • Not a veteran Zope Developer • A Plone integrator with Zope/Plone 2.x experience (CMF based skins) • Entirely new to Plone (Congratulations!) • Sceptical and / or confused about this stuff
  • 3. Who am I? • Self-employed Developer, Sysad and Consultant, based in Berlin, Germany • Started working with Plone in 2003 • Contributor since April 2006 (Archipelago Sprint, where development of 3.0 started) • Started Plone 3.0 based product in March 2007, following trunk
  • 4. History I CMF skins • A skin is a collection of templates and ressources (CSS, JS, images, scripts, macros) • CMF skins have ordered layers • customization = copy to a higher layer • Acquisition based lookup (“Which template is producing this markup?!”)
  • 5. History II Macros • re-use sub-page templates (navigation, etc.) • Aquisition based lookup (“Which macro is really being called?!”) • Clumsy parameter handling
  • 6. History III Slots • “Macros on steroids” • i.e. add CSS links to header from body template, advanced loops • extremely powerful • only one macro per slot, though
  • 7. History III Python scripts • security limitations (can’t use unrestrictedSearchResults, can’t import all packages etc.) • cumbersome to debug (enablesettrace) • Clumsy parameter handling (pyflakes)
  • 8. History III Python scripts • No subclassing (let alone interfaces) • Acquisition based lookup (“Which script is being called?!”) • hard (impossible?) to test
  • 9. History IV The Good • very straightforward: copy, edit, reload • very flexible: easy to override defaults • instant gratification (TTW support) • large factor in Zope 2’s success
  • 10. History V The Bad • “implicit magic”: WTF is going on here?! • tendency to overload templates with application logic (‘dummy’ calls, anyone?) • “maze of python scripts” • in summary: “messy”
  • 11. History VI The Ugly “Acquisition is a jealous mistress” Martin Aspeli ‘Nuff said!
  • 12. Enter Zope3 • Rewritten from the ground up • “Component Architecture”: Interfaces, Adapters... and Views • pluggable via configuration a.k.a.“XML sit- ups” (Grok is changing that, though) • lots of other Goodies (buildout, eggs, events)
  • 13. Benefits of the CA • makes it easy to write small, specific, easy to understand code • re-usability • explicit (it never guesses! no magic!)
  • 14. portalstatusmessages Interface Adapter from zope.interface import Interface, Attribute from base64 import encodestring, decodestring from pickle import dumps, loads import sys from zope.annotation.interfaces import IAnnotations from zope.i18n import translate from zope.interface import implements class IMessage(Interface): from Products.statusmessages import STATUSMESSAGEKEY from Products.statusmessages.message import Message quot;quot;quot;A single status message.quot;quot;quot; from Products.statusmessages.interfaces import IStatusMessage import logging logger = logging.getLogger('statusmessages') class StatusMessage(object): message = Attribute('The text of this message. quot;quot;quot;Adapter for the BrowserRequest to handle status messages. Let's make sure that this implementation actually fulfills the Usally a Message object.') 'IStatusMessage' API. >>> from zope.interface.verify import verifyClass >>> verifyClass(IStatusMessage, StatusMessage) True quot;quot;quot; implements(IStatusMessage) type = Attribute('The type of this message.') def __init__(self, context): self.context = context # the context must be the request def addStatusMessage(self, text, type=''): quot;quot;quot;Add a status message. quot;quot;quot; text = translate(text, context=self.context) annotations = IAnnotations(self.context) class IStatusMessage(Interface): old = annotations.get(STATUSMESSAGEKEY, self.context.cookies.get(STATUSMESSAGEKEY)) value = _encodeCookieValue(text, type, old=old) quot;quot;quot;An adapter for the BrowserRequest to handle self.context.RESPONSE.setCookie(STATUSMESSAGEKEY, value, path='/') annotations[STATUSMESSAGEKEY] = value def showStatusMessages(self): status messages.quot;quot;quot; quot;quot;quot;Removes all status messages and returns them for display. quot;quot;quot; annotations = IAnnotations(self.context) value = annotations.get(STATUSMESSAGEKEY, self.context.cookies.get(STATUSMESSAGEKEY)) if value is None: return [] def addStatusMessage(text, type=''): value = _decodeCookieValue(value) # clear the existing cookie entries self.context.cookies[STATUSMESSAGEKEY] = None quot;quot;quot;Add a status message.quot;quot;quot; self.context.RESPONSE.expireCookie(STATUSMESSAGEKEY, path='/') annotations[STATUSMESSAGEKEY] = None return value def _encodeCookieValue(text, type, old=None): quot;quot;quot;Encodes text and type to a list of Messages. If there is already some old def showStatusMessages(): existing list, add the new Message at the end but don't add duplicate messages. quot;quot;quot; results = [] quot;quot;quot;Removes all status messages and returns message = Message(text, type=type) if old is not None: them for display. results = _decodeCookieValue(old) if not message in results: results.append(message) quot;quot;quot; # we have to remove any newlines or the cookie value will be invalid return encodestring(dumps(results)).replace('n','') def _decodeCookieValue(string): quot;quot;quot;Decode a cookie value to a list of Messages. The value has to be a base64 encoded pickle of a list of Messages. If it contains anything else, it will be ignored for security reasons. quot;quot;quot; results = [] # Return nothing if the cookie is marked as deleted if string == 'deleted': return results # Try to decode the cookie value try: values = loads(decodestring(string)) except: # If there's anything unexpected in the string ignore it logger.log(logging.ERROR, '%s n%s', 'Unexpected value in statusmessages cookie', sys.exc_value ) return [] if isinstance(values, list): # simple security check for value in values: if isinstance(value, Message): # and another simple check results.append(value) return results
  • 15. Views + Templates Adapters (Application Logic) View Template
  • 16. Views + Templates Let’s dumb this down further ;-)
  • 17. Views + Templates • Think “View = Dictionary” • Views collect data from the application into a dictionary • Templates take the data from the dictionary and insert it into the markup
  • 18. Views + Templates • Templates insert, replace and loop (conditionally) – keep them ‘dumb’ • use methods (with @property, @memoize at your discretion) • use kw dictionary for simple attributes: kw.update(‘foo’, bar)
  • 19. Views + Templates • Templates insert, replace and loop (conditionally) – keep them ‘dumb’ • use methods (with @property, @memoize at your discretion) • use kw dictionary for simple attributes: kw.update(‘foo’, bar)
  • 21. Views + Templates • avoid using self.foo for attributes (for consistency’s sake) • python expressions in templates are not inherently evil! (only to abuse them is) • python expressions are ca. 3x faster than path expressions!
  • 22. On to the practical stuff Questions?
  • 23. A Simple View from Products.Five.browser import BrowserView class MyView(BrowserView): def __call__(self, *args, **kw): kw.update({‘foo’ : self.bar()}) return super(MyView, self).__call__(*args, **kw) @property def some_value(self): return something_complicated()
  • 24. A Simple Viewlet from Products.Five.browser import BrowserView class MyView(BrowserView): def __call__(self, *args, **kw): kw.update({‘foo’ : self.bar()}) return super(MyView, self).__call__(*args, **kw) @property def some_value(self): return something_complicated()
  • 25. Debugging Views from Products.Five.browser import BrowserView class MyView(BrowserView): def __call__(self, *args, **kw): import pdb ; pdb.set_trace() return super(MyView, self).__call__(*args, **kw)
  • 26. Context from Acquisition import aq_inner from Products.Five.browser import BrowserView class MyView(BrowserView): def some_view_function(self): context = aq_inner(self.context) “If you forget the aq_inner() it will probably still work 9 times out of 10, but the 10th time you're screwed and wondering why you're getting insane errors about user folders and attributes not being found.” Martin Aspeli
  • 27. View Interfaces • a contract between developer and designer from zope.interface import Interface from zope.interface import implements from Products.Five.browser import BrowserView class ISummaryPage(Interface): def summary(): pass def body(): pass class IntroPageView(BrowserView): implements(ISummaryPage) def summary(self): return foo()
  • 28. Dos and Don’ts • don’t use __init__() • use __call__() • don’t use context/foo (expensive!) • use kw + options/foo and/or Interfaces
  • 29. Hack No. 1 View + skin template For extra flexibility you can hook up a Five view with a skin based template: from Acquisition import aq_acquire from Products.Five.browser import BrowserView class IntroPageView(BrowserView): def __call__(self, *args, **kw): kw.update({'some_name' : nifty_method()}) return aq_acquire(self.context, 'intro-page')(**kw)
  • 30. Skin switching • Use a different skin depending on URL • Useful for editing sites with heavily customized public skin • For example: use Plone’s default skin when accessed via HTTPS • Old method with External Method and ‘Set Access Rule’ no longer works (plone.theme marks request with default skin before rule is processed) • New method is actually easier and less code
  • 31. Skin switching The Code def setskin(site, event): if event.request.URL.startswith('https'): site.changeSkin(“Plone Default”, event.request) The Glue <subscriber for=quot;Products.CMFPlone.interfaces.IPloneSiteRoot zope.app.publication.interfaces.IBeforeTraverseEventquot; handler=quot;.skinswitcher.setskinquot; />
  • 32. Caching Two basic approaches: • cache results of view methods: memoize • cache entire view/viewlet: lovely.viewcache
  • 33. Caching from plone.memoize.instance import memoize from Products.Five.browser import BrowserView class MyView(BrowserView): @memoize def expensiveMethod(self): return foo
  • 34. lovely.viewcache from lovely.viewcache.view import cachedView class View(BrowserView): pass CachedView = cachedView(View) Now use CachedView instead of View in your .zcml Works just the same for Viewlets
  • 35. lovely.viewcache • Entire page usually not cacheable • But caching viewlets is particularly useful • By using views and viewlets you futureproof your product for later scalability!
  • 36. subclass BrowserView • common methods for all your views • group and share similar behaviour • hierarchy easier to debug than Acquisition!
  • 37. Hack No. 2: custom viewlet per page Usecase: custom logo viewlet for frontpage only. Didn’t want to add extra logic to view class and template just for that. Solution: custom template for frontpage <browser:viewlet name=quot;plone.logoquot; manager=quot;plone.app.layout.viewlets.interfaces.IPortalHeaderquot; class=quot;.viewlets.LogoViewletquot; permission=quot;zope2.Viewquot; layer=quot;.interfaces.IMySkinSpecificquot; />
  • 38. Hack No. 2: custom viewlet per page from Products.CMFPlone.interfaces import IPloneSiteRoot from plone.app.layout.viewlets.common import LogoViewlet as LogoViewletBase class LogoViewlet(LogoViewletBase): _template = ViewPageTemplateFile('logo.pt') _frontpage_template = ViewPageTemplateFile('logo-frontpage.pt') def render(self): if IPloneSiteRoot.providedBy(self.context): return self._frontpage_template() else: return self._template()
  • 39. Hack No. 2: custom viewlet per page That’s stupid, don’t do that! Viewlet accepts view attribute, problem solved! <browser:viewlet name=quot;plone.logoquot; manager=quot;plone.app.layout.viewlets.interfaces.IPortalHeaderquot; class=quot;.viewlets.FrontpageLogoViewletquot; permission=quot;zope2.Viewquot; layer=quot;.interfaces.IMySkinSpecificquot; view=”IFrontpageView” />
  • 40. Fun with Views • Remember:Views are just multi-adapters that return (in most cases) HTML • ZPT is just a default behavior • Let’s use... Genshi
  • 41. Genshi from zope.publisher.browser import BrowserPage class HelloGenshi(BrowserPage): def __call__(self): tmpl = loader.load('helloworld.html') stream = tmpl.generate( request=self.request, who=self.request.principal.id ) return stream.render('html', doctype='html')
  • 42. Genshi <div xmlns:py=quot;http://genshi.edgewall.org/quot;> <p>Hello $who</p> <p>Hello ${request.principal.id}</p> <table> <tr py:for=quot;key in requestquot; py:if=quot;key.startswith('HTTP')quot;> <td>$key</td> <td>${request[key]}</td> </tr> </table> </div>
  • 43. Genshi • everything you love about ZPT • (hardly) anything you hate about ZPT • also works with non-markup • still valid XHTML • less verbose