Possible solution to Re: [Zope-CMF] How to list objects of custom type and not of their base type?

David (Hamish) Harvey david.harvey@bristol.ac.uk
Wed, 12 Jun 2002 17:36:47 +0100


--On Friday, June 07, 2002 15:43:00 +0000 Florent Guillaume <fg@nuxeo.com> 
wrote:

> I believe it's a bug, see if
> http://www.zope.org/Products/PTK/Tracker/483/1 matches your problem.

Spot on, thanks. I need to get better at finding my bugs in the collector.

I've created a mini-product which hotfixes PortalFolder and DynamicType to 
get round this. I'd appreciate comments on bugs, style, and reasons why it 
can't be done like this. It appears to me to work, but I haven't given any 
consideration to possible use cases in which this hideously breaks other 
things.

http://wemrc10.wemrc.bris.ac.uk/zope.html

Basically, the _objects attribute on PortalFolder holds id and meta_type. I 
presume this is an efficiency hack: as noted in the bug report above 
accessing each object would be slow. I want objectIds to filter on 
portal_type if it available, meta_type if not (non-portal stuff). I figured 
I'd need to add portal_type info to _objects. That's all fine'n'dandy, but 
portal_type can change after creation, and _objects would get out of sync. 
For this reason I modified DynamicType so that if the portal_type is 
changed, it's descendents will call a (new, also in the fix) method on 
PortalFolder which updates _objects.

After all that, we can modify objectIds to check for a portal_type, and if 
it's available compare that with spec, otherwise use meta_type.

One twist - it seems that for this to work, _morphSpec has to call 
listContentTypes with by_metatype=0. This I fear might have implications.

Note that this relies on the fix being in place before any items are 
"_setObject"ed on a PortalFolder. To get round this, there's an external 
method in the Extensions dir which will remove and re-add each object to 
the directory using _setObject. As it does so the necessary changes happen. 
It needs to be called in turn from a python script which passes it context. 
Is there any way for an external method to obtain the context in which it 
is called? I haven't worked this out.

> In my sites I use a customized folder listing because of this, one that
> doesn't call listFolderContents. With your example I'd call
> objectValues('Document') and then filter by hand on portal_type.

That would have worked, and might have fewer side effects that what I've 
done. It would have involved modifying all the plone templates to use it 
though, and then keeping them in sync. I've a hard enough job as it is with 
the changes I've made, so I figured I'd try to fix the problem at source. 
Besides, I like to live on the steep edge of the learning curve!

> (BTW you say content_meta_type but the attribute you want is really
> portal_type. content_meta_type is an attribute of the portal type itself.)

Thanks a lot for that. Saved me quit a bit of confusion :-)

As I say, comments would be welcome, especially if you notice something 
that is likely to bite me later - I'm trying to finish up a site based on 
plone and launch it.

Cheers,
Hamish