[Zope-CMF] adding a type with a new factory method

Karl Anderson kra@monkey.org
22 Jul 2002 11:29:08 -0700


Florent Guillaume <fg@nuxeo.com> writes:

> Karl Anderson  <kra@monkey.org> wrote:
> > I'm trying to create a new type based on an existing one (CMFPost,
> > part of CMFForum).  
> > 
> > Right now, I'm only trying to change the factory method.  So, I copied
> > the CMFPost type to MyCMFPost, and changed the factory method to
> > "myAddPost".  To create myAddPost, I added an External Method to the
> > portal root, adapted from CMFPost.addPost, the old factory method (in
> > the Python product).
> > 
> > However, this fails, apparently because the External Method is called
> > differently - self isn't the container.  I couldn't use a
> > Script(Python), because I can't call _setObject from it.
> > 
> > I finally got this working (so far) by adding a keyword argument called
> > 'thecontainer' to the External Method, and having the skin that the
> > MyCMFPost-adding action uses pass its context as the 'thecontainer'
> > argument to context.invokeFactory (I couldn't use 'container', because
> > PortalTypes.constructContent() complained about extra values for that
> > keyword argument, which I still don't understand).

> Usually my factory method are in the product, not in external methods,
> so I don't know what's your problem exactly. Could you post your
> problematic code?

I copied the portal type "Post" to "PostCS", and changed the factory
method from "addPost" to "addPostCS".

addPostCS is an External Method in the portal root.  addPost was a
function imported from Post.py (confusingly, a method of the Post
class, also referenced in the module scope and exported there -
possibly because posts can be added to forums and to other posts).  I
needed to us an External Method becuase it had to call _setObject.
This external method is what's making me think that I should stop
trying to follow CMF's aspect philosophy and subclass Post :)

I customized the skin post_add to invoke the factory for PostCS.
This is what is called by the relevant UI skin to add a post.

post_add:

## Script (Python) "post_add"
##bind container=container
##bind context=context
##bind namespace=_
##bind script=script
##bind subpath=traverse_subpath
##parameters=author='', email='', text='', title='', submit='', file=''
##title=Add a new Post
##
member = context.portal_membership.getAuthenticatedMember()

new_id='msg_' + str(int( context.ZopeTime()))
context.invokeFactory('PostCS', id=new_id, title=title,
                      email=member.getProperty('email'),
                      author=member.getId(), text=text, file=file,
                      thecontainer=context)
url = '%s/%s' % (context.absolute_url(), context.getTypeInfo().getActionById('view',''))
return context.REQUEST.RESPONSE.redirect(url)



addPostCS.py:



def addPostCS(id='', title='', text='', author='', email='', file=None,
              REQUEST=None, **kw):
    """Add a Post to its container"""

    from Products.CMFForum.Post import Post, generate_id

    # we can't pass a kw of 'container' for some reason
    thecontainer = kw['thecontainer']

    if not id:
        id = generate_id(thecontainer)
    item = Post(id, title=title, text=text, author=author, email=email)
    thecontainer._setObject(id, item)
    post = getattr(thecontainer, id)

    if file and file.filename:
        id = string.split(file.filename, "\\")[-1]
        body = file.read()
        content_type = file.headers['Content-Type']
        if guess_content_type(id, body)[0][0:5] == 'image':
            post.invokeFactory( 'Image', id=id, file=file, content_type=content_type)
        else:
            post.invokeFactory( 'File', id=id, file=file, content_type=content_type)

    #if REQUEST is not None:
    #    return .manage_main(self, REQUEST)

-- 
Karl Anderson      kra@monkey.org           http://www.monkey.org/~kra/