multi-level acquisition (or the "images" folder problem)
OK, a lot of people have run into this class of problems before, but I haven't seen a general solution yet, so I thought I'd offer one. But first, let me explain the problem for those who haven't had it yet :-) OK, so as an example say we have a site set up like this: / | +-/images | | | +-img1 | +-/index_html | +-/folder | +-/index_html Both index_html methods contain something like <dtml-var "images.img1"> ...if you're familiar with how acquisition works, then you'll know that everything is OK...the images folder will be acquired from the root folder, and img1 is contained therein. OK, now say we want to add some images specific to the contents of folder. We can create an images subfolder, and put a new image in there: / | +-/images | | | +-img1 | +-/index_html | +-/folder | +-/images | | | +-img2 | +-/index_html ...and edit the tag in /folder/index_html to say <dtml-var "images.img2"> So far, still good. But now lets say that we want /folder/index_html to use both /images/img1 and /folder/images/img2... <dtml-var "images.img1"> <dtml-var "images.img2"> The first statement fails. This is an important subtlety about acquisition: once it finds an element of the path, it only searches within that for the rest of the path...so the first statement is looking for img1 in /folder/images. This trips up a lot of people who would expect Zope to keep searching up the path for other "images" folders until the full path is found (or until it reaches the root folder in the case that the path isn't present at all). There are a number of workarounds to this, but mostly they involve explicitly naming paths and avoiding acquisition entirely, which isn't always what you want. So I threw together a simple python script that I put in my root folder called "find" which takes a path (as a python sequence of names), starts at the current context, and moves up the acquisition chain looking for the specified path. So you'd replace the above with: <dtml-var "find(['images', 'img1'])"> <dtml-var "find(['images', 'img2'])"> ...and it would all work just fine. Best of all, you could later add an img1 to /folder/images to replace the default one in /images for everything under /folder, just as one might expect. It seems to work fine OMM, but hasn't been tested extensively, so use at your own risk :-) Also note that if the specified path doesn't exist at all anywhere in the acquisition chain, you'll get an error. Hope this helps some people out there! ## Script (Python) "find" ##bind container=container ##bind context=context ##bind namespace= ##bind script=script ##bind subpath=traverse_subpath ##parameters=path ##title= ## searchPoint = context target = None while searchPoint and not target: target = searchPoint.restrictedTraverse(path) if not target: searchPoint = searchPoint.aq_parent return target -- Tim Moore
participants (1)
-
Tim Moore