############################################################################## # # Copyright (c) 2005-2006 Brian Sutherland. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Package for compatibility code between five Zope2 and sqlos. """ from sets import Set import Acquisition import AccessControl from OFS.SimpleItem import Item from Globals import InitializeClass from zope.app import zapi from zope.app.container.constraints import checkFactory from zope.interface import implements, providedBy, directlyProvides from sqlos.interfaces import ISQLObject, IISQLObject from zope.app.exception.interfaces import UserError from Products.FiveSQLOS.interfaces import IFiveSQLObject class ItemWrapper(Acquisition.Implicit, AccessControl.Role.RoleManager, Item): """A wrapper for SQLOS objects that let them use Aquisition. This wrapper tries to solve the issue of both Acquisition and SQLObject being metaclassess. Wrap up a SQLObject in it and then it should support Aquisition. Unfortunately the code is rather delicate. Wrappers objects implement the interfaces of their context: >>> from zope.interface.verify import verifyObject >>> from zope.interface import Interface, Attribute, providedBy >>> class IStub(Interface): ... meth = Attribute('meth') >>> class IStub2(Interface): ... meth2 = Attribute('meth2') >>> class Stub: ... implements(IStub, IStub2) ... meth = 'id1' ... meth2 = 'id2' >>> stub = ItemWrapper(Stub()) >>> IStub.providedBy(stub) True >>> IStub2.providedBy(stub) True The attributes defined in the interface are available through the wrapper: >>> stub.meth 'id1' >>> stub.meth2 'id2' """ # XXX - this code needs a philosophy, right now it is just a jumble of stuff # that works, but with no clear direction. implements(IFiveSQLObject) _wrapped_methods = () _title = "" def getId(self): # XXX - this uses exactly the same logic as the name chooser in # sqlos.container (copy/paste), perhaps there should be function # to do this??? - jinty obj = self.context if ISQLObject.providedBy(obj): # Look for the SQLObject class our object is from, so get all # allowed factories for name, factory in zapi.getFactoriesFor(ISQLObject): if checkFactory(self.aq_parent, None, factory): # get the sqlobject class utility = zapi.queryUtility(IISQLObject, name) if utility is None: continue if obj.sqlmeta.table == utility.sqlmeta.table: # if the tables names are the same, we assume that the # sqlobject is an instance of that class, perhaps that # is wrong return "%s.%s" % (name, obj.id) raise UserError("Cannot find a name") # XXX better message, i18n? id = property(getId) def getTitle(self): if hasattr(self.context, 'title'): return self.context.title return self._title def setTitle(self, value): if hasattr(self.context, 'title'): self.context.title = value else: self._title = value title = property(getTitle, setTitle) def __init__(self, context): self.context = context _wrapped_methods = Set([]) interfaces = providedBy(context) directlyProvides(self, interfaces) for I in interfaces: _wrapped_methods.update(Set(list(I))) assert 'context' not in _wrapped_methods assert '_wrapped_methods' not in _wrapped_methods self._wrapped_methods = _wrapped_methods def __getattr__(self, name): return getattr(self.context, name) def __setattr__(self, name, value): if name in self._wrapped_methods: return setattr(self.context, name, value) object.__setattr__(self, name, value) InitializeClass(ItemWrapper)