[Zope-CMF] Directory-based skin layers?

Paul Winkler pw_lists at slinkp.com
Thu Apr 15 10:31:18 EDT 2004

On Wed, Apr 14, 2004 at 01:46:59PM -0700, Ricardo Newbery wrote:
> This idea is this.  I would like to enable directory-based skin 
> layers which would take higher precedence than the layers defined in 
> portal_skins.  I figure it would probably take some hacking of the 
> skinning machinery.  I'm not talking about an access rule that would 
> reset the skin name but rather a mechanism that would acquire any 
> skin layer folders in the current directory and its parents and 
> prepend them to the portal_skin layer list.

Definitely doable.
> I haven't researched this yet but I'm guessing that CMF makes a 
> dictionary from the portal_skin layers in order to overwrite 
> references to "lower" layer objects with references to "higher" layer 
> objects with the same id.

A reasonable guess, but nope :-)

Normally, if I ask for folder1.object1, acquisition does 
something like:

    if folder1 has an object named object1:
        use that
        delegate to folder1.aq_parent

(note: that does not at all describe the implementation, 
just the effective result.)

In a CMF site, eventually the chain of aq_parents will reach back to
the root PortalObject, which adds a step:

    if the current skin has an object named object1:
        use that 
    elif I have an object named object1:
        use that
        delegate to folder1.aq_parent

You can see how this is implemented by looking at  
CMFCore.Skinnable.SkinnableObjectManager, which PortalObject
inherits from.
The __getattr__ method is what does the delegation to the object
representing the current skin (assuming self.setupCurrentSkin() 
has been called).
But it's probably still not clear, as it wasn't to me,
exactly what the current skin object is, or how it looks up names. 
Read on...

> I figure it should be possible to hack it 
> so that it can do the same with the directory-based layers.

The nice thing in the above analysis is that the "current skin object" 
can be anything on which you can call getattr().  
So if you can arrange that to be some class of your own, you're
halfway done. To do so, I'd replace portal_skins with either a subclass 
or wrapper around the default SkinsTool implementation.
So, look at CMFCore/SkinsContainer.py and CMFCore/SkinsTool.py.
The methods of interest are getSkinByPath and/or getSkinByName.
Have these return your skin object.

It took me a while to grok the existing implementation,
because the docstrings are pretty minimal, and getSkinByPath 
doesn't return anything obvious like oh, say, an instance of any 
class with Skin in its name :-P  Instead, it just builds a (possibly 
really long) chain of acquisition-wrapped folders and returns that. 

Writing a CMF tool is not hard. Just look at some simple examples,
like CMFCalendar. I highly recommend giving it a try, 
tools really make development of services for CMF a lot more fun 
(as compared to writing a pile of scripts in the skins).

Have fun!


Paul Winkler
(random hero from isometric.spaceninja.com)

More information about the Zope-CMF mailing list