
git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@3685 fd906abe-77d9-0310-91a1-e0d9ade77398
115 lines
4 KiB
Python
115 lines
4 KiB
Python
from Acquisition import aq_base, aq_chain
|
|
from ZODB.interfaces import IConnection
|
|
from ZPublisher.BaseRequest import RequestContainer
|
|
from zExceptions import NotFound
|
|
from persistent import IPersistent
|
|
from zope.component import adapter, adapts
|
|
from zope.app.component.hooks import getSite
|
|
from zope.interface import implements, implementer
|
|
from zope.app.keyreference.interfaces import IKeyReference, NotYet
|
|
from zope.app.keyreference.persistent import KeyReferenceToPersistent
|
|
from site import get_root, aq_iter
|
|
from zope.app.container.interfaces import IObjectAddedEvent
|
|
|
|
|
|
@adapter(IPersistent)
|
|
@implementer(IConnection)
|
|
def connectionOfPersistent(obj):
|
|
""" zope2 cxn fetcher for wrapped items """
|
|
for parent in aq_iter(obj):
|
|
conn = getattr(parent, '_p_jar', None)
|
|
if conn is not None:
|
|
return conn
|
|
|
|
|
|
@adapter(IPersistent, IObjectAddedEvent)
|
|
def add_object_to_connection(ob, event):
|
|
"""Pre-add new objects to their persistence connection"""
|
|
connection = IConnection(ob, None)
|
|
if None is not connection:
|
|
connection.add(aq_base(ob))
|
|
|
|
|
|
class KeyReferenceToPersistent(KeyReferenceToPersistent):
|
|
"""a zope2ish implementation of keyreferences that unwraps objects
|
|
that have Acquisition wrappers
|
|
|
|
These references compare by _p_oids of the objects they reference.
|
|
|
|
@@ cache IConnection as a property and volative attr?
|
|
"""
|
|
implements(IKeyReference)
|
|
adapts(IPersistent)
|
|
|
|
key_type_id = 'five.intid.keyreference'
|
|
|
|
def __init__(self, wrapped_obj):
|
|
# make sure our object is wrapped by containment only
|
|
try:
|
|
self.path = '/'.join(wrapped_obj.getPhysicalPath())
|
|
except AttributeError:
|
|
self.path = None
|
|
|
|
# If the path ends with /, it means the object had an empty id.
|
|
# This means it's not yet added to the container, and so we have
|
|
# to defer.
|
|
if self.path is not None and self.path.endswith('/'):
|
|
raise NotYet(wrapped_obj)
|
|
self.object = aq_base(wrapped_obj)
|
|
connection = IConnection(wrapped_obj, None)
|
|
|
|
if not getattr(self.object, '_p_oid', None):
|
|
if connection is None:
|
|
raise NotYet(wrapped_obj)
|
|
connection.add(self.object)
|
|
|
|
try:
|
|
self.root_oid = get_root(wrapped_obj)._p_oid
|
|
except AttributeError:
|
|
# If the object is unwrapped we can try to use the Site from the
|
|
# threadlocal as our acquisition context, hopefully it's not
|
|
# something odd.
|
|
self.root_oid = get_root(getSite())._p_oid
|
|
self.oid = self.object._p_oid
|
|
self.dbname = connection.db().database_name
|
|
|
|
@property
|
|
def root(self):
|
|
return IConnection(self.object)[self.root_oid]
|
|
|
|
@property
|
|
def wrapped_object(self):
|
|
if self.path is None:
|
|
return self.object
|
|
try:
|
|
obj = self.root.unrestrictedTraverse(self.path)
|
|
except (NotFound, AttributeError,):
|
|
return self.object
|
|
chain = aq_chain(obj)
|
|
# Try to ensure we have a request at the acquisition root
|
|
# by using the one from getSite
|
|
if not len(chain) or not isinstance(chain[-1], RequestContainer):
|
|
site = getSite()
|
|
site_chain = aq_chain(site)
|
|
if len(site_chain) and isinstance(site_chain[-1],
|
|
RequestContainer):
|
|
req = site_chain[-1]
|
|
new_obj = req
|
|
# rebuld the chain with the request at the bottom
|
|
for item in reversed(chain):
|
|
new_obj = aq_base(item).__of__(new_obj)
|
|
obj = new_obj
|
|
return obj
|
|
|
|
def __call__(self):
|
|
return self.wrapped_object
|
|
|
|
def __hash__(self):
|
|
return hash((self.dbname,
|
|
self.object._p_oid,
|
|
))
|
|
|
|
def __cmp__(self, other):
|
|
if self.key_type_id == other.key_type_id:
|
|
return cmp((self.dbname,self.oid), (other.dbname, other.oid))
|
|
return cmp(self.key_type_id, other.key_type_id)
|