plone: event driven programming

23
Matt Hamilton ...or how to extend Plone the lazy way Event Driven Programming in Plone Matt Hamilton Technical Director, Netsight

Upload: matt-hamilton

Post on 08-May-2015

3.103 views

Category:

Technology


3 download

DESCRIPTION

A talk I gave at the European Plone Symposium 2010 in Sorrento. Event Driven Programming in Plone - or how to extend Plone the lazy way Ever wanted to extend Plone somehow but not wanted to change the existing code for a product? Want to learn the easy way to extend Plone's functionality? Events! I will show you some examples of how to use Plone's event subscriber and workflow systems to extend Plone without having to change any existing products. Using a number of common Plone products and the events system to combine them you can come up with unlimited possibilities. I'll use examples from two websites I've been working on recently to show you how you can make authors have to pay (using GetPaid) to publish content on a site, and how to check the comments are not spam on your discussion board.

TRANSCRIPT

Page 1: Plone: Event Driven Programming

Matt Hamilton

...or how to extend Plone the lazy way

Event Driven Programming in Plone

Matt HamiltonTechnical Director, Netsight

Page 2: Plone: Event Driven Programming

Matt Hamilton European Plone Symposium 2010, Sorrento

Who am I?

2

- Matt Hamilton

- Technical Director of Netsight Internet Solutions

- A Plone ‘integrator’

[email protected]

@hammertoe

Page 3: Plone: Event Driven Programming

Matt Hamilton European Plone Symposium 2010, Sorrento

Who is this talk for?

- Integrators

- Those newish to Plone, they can assemble together a site from a number of products, but don't really want to alter them

- I consider myself 'experienced' but this was a bit of an epiphany for me

3

Page 4: Plone: Event Driven Programming

Matt Hamilton European Plone Symposium 2010, Sorrento

What is the problem?

4

?

Page 5: Plone: Event Driven Programming

Matt Hamilton European Plone Symposium 2010, Sorrento

What is the problem?

I want to change the functionality of an existing product, but don't want to change the guts of it.

5

Page 6: Plone: Event Driven Programming

Matt Hamilton European Plone Symposium 2010, Sorrento

What is the problem?

Came from a real life problem. Developing Netsight's new website. Wanted to use plone.app.discussion, but needed to add spam checking on comments

6

Page 7: Plone: Event Driven Programming

Matt Hamilton European Plone Symposium 2010, Sorrento

What is the problem?

7

Page 8: Plone: Event Driven Programming

Matt Hamilton European Plone Symposium 2010, Sorrento

What is the problem?

plone.app.discussion has captcha support already, but I wanted to add Akismet support, but no easy extension point

8

Page 9: Plone: Event Driven Programming

Matt Hamilton European Plone Symposium 2010, Sorrento

Admittedly, I could have offered to refactor the whole p.a.discussion code ;)

9

Page 10: Plone: Event Driven Programming

Matt Hamilton European Plone Symposium 2010, Sorrento

Considered Approaches

- I could subclass the product and override it

➡ A lot of boiler-plate for small change

- I could use an adapter and adapt the behaviour

➡ No adapter lookup where I needed it

- I could 'just hack it in the original code'

➡ Yuck! Maintainability nightmare

10

Page 11: Plone: Event Driven Programming

Matt Hamilton European Plone Symposium 2010, Sorrento 11

Eureka!

Page 12: Plone: Event Driven Programming

Matt Hamilton European Plone Symposium 2010, Sorrento

Eureka!

Use Events!

12

Page 13: Plone: Event Driven Programming

Matt Hamilton European Plone Symposium 2010, Sorrento

Eureka!

- I realised I could leave p.a.discussion alone, and just listen for an event for when a comment is added and then check it for spam

- I can listen for an event from Plone and then do the behaviour afterwards

13

Page 14: Plone: Event Driven Programming

Matt Hamilton European Plone Symposium 2010, Sorrento

Advantages

- Leave the existing code alone

- Work around lack of suitable extension point

- Very little boilerplate code

- All happens in same transaction still

14

Page 15: Plone: Event Driven Programming

Matt Hamilton European Plone Symposium 2010, Sorrento

Zope's Event System

- Events

- Subscribers

15

Page 16: Plone: Event Driven Programming

Matt Hamilton European Plone Symposium 2010, Sorrento

A Simple Event

16

in configure.zcml:

<subscriber for=".interfaces.IMyObject .interfaces.IMyEvent" handler=".events.myEventHandler" />

in events.py:

def myEventHandler( object, event): object.doSomeThing()

Page 17: Plone: Event Driven Programming

Matt Hamilton European Plone Symposium 2010, Sorrento

Event Simpler Event

17

in events.py:

from five import grokfrom interfaces import IMyObject, IMyEvent

@@grok.subscribe(IMyObject, IMyEvent)def myEventHandler( object, event): object.doSomeThing()

Page 18: Plone: Event Driven Programming

Matt Hamilton European Plone Symposium 2010, Sorrento

Example - Spam Checking

18

in events.py:

from five import grokfrom plone.app.discussion.interfaces \ import ICommentfrom zope.lifecycleevent.interfaces \ import IObjectAddedEvent

@@grok.subscribe(IComment, IObjectAddedEvent)def checkForSpam( comment, event): wf = getToolByName(comment, 'portal_workflow') if is_spam(comment.text): wf.doActionFor(comment, ‘spam’)

Page 19: Plone: Event Driven Programming

Matt Hamilton European Plone Symposium 2010, Sorrento

Next Example - GetPaid

19

GetPaid is an eCommerce add-on to Plone

➡ Allows you to mark any piece of content as ‘buyable’

Page 20: Plone: Event Driven Programming

Matt Hamilton European Plone Symposium 2010, Sorrento

PloneConf 2010 Registration

20

User clicks ‘register’

User fills in ‘add attendee’ form, and hits submit

Event fired indicating object added to container

Event subscriber marks item as buyable, adds to shopping cart, and then redirects to cart view

Page 21: Plone: Event Driven Programming

Matt Hamilton European Plone Symposium 2010, Sorrento

GetPaid Example

21

from Products.CMFCore.utils import getToolByNamefrom getpaid.core.interfaces import workflow_statesimport interfaces

def handlePaymentReceived( order, event ):

    if event.destination !=workflow_states.order.finance.CHARGED:        return            for item in order.shopping_cart.values():        ob = item.resolve()        workflow = getToolByName( ob, 'portal_workflow')        state = workflow.getInfoFor( ob, 'review_state' )                    if state == 'published':            return        workflow.doActionFor( ob, 'publish')

Page 22: Plone: Event Driven Programming

Matt Hamilton European Plone Symposium 2010, Sorrento

Other Ideas

- Whenever a Folder is created, add some default content to it

- When a Page is added, set some metadata fields

- When an Event is added, check that an expiry date has been set no more than 12 months in the future

22