1
2
3
4
5
6
7
8
9
10
11
12
13
14 __doc__="""$Id: ToManyRelationship.py,v 1.48 2003/11/12 22:05:48 edahl Exp $"""
15
16 __version__ = "$Revision: 1.48 $"[11:-2]
17
18 import logging
19 log = logging.getLogger("zen.Relations")
20
21 from Globals import DTMLFile
22 from Globals import InitializeClass
23 from AccessControl import ClassSecurityInfo
24 from Acquisition import aq_base
25 from OFS.ObjectManager import checkValidId, BeforeDeleteException
26 from ZODB.POSException import ConflictError
27
28 import OFS.subscribers
29 from OFS.event import ObjectWillBeAddedEvent
30 from OFS.event import ObjectWillBeRemovedEvent
31 from zope.event import notify
32 from zope.app.container.contained import ObjectAddedEvent
33 from zope.app.container.contained import ObjectRemovedEvent
34 from zope.app.container.contained import ContainerModifiedEvent
35 from zope.app.container.contained import dispatchToSublocations
36
37 from BTrees.OOBTree import OOBTree
38
39 from ToManyRelationshipBase import ToManyRelationshipBase
40
41 from Products.ZenRelations.Exceptions import *
42
43 from Products.ZenUtils.Utils import unused
44
52
53
54 addToManyContRelationship = DTMLFile('dtml/addToManyContRelationship',globals())
55
56
58 """
59 ToManyContRelationship is the ToMany side of a realtionship that
60 contains its related objects (like the normal Zope ObjectManager)
61 """
62
63 meta_type = "ToManyContRelationship"
64
65 security = ClassSecurityInfo()
66
67
69 """set our instance values"""
70 self.id = id
71 self._objects = OOBTree()
72
73
75 """when we are called return our related object in our aq context"""
76 return [ob.__of__(self) for ob in self._objects.values()]
77
78
80 """look in the two object stores for related objects"""
81 if self.__dict__.has_key("_objects"):
82 objects = self.__dict__['_objects']
83 if objects.has_key(name): return objects[name]
84 raise AttributeError( "Unable to find the attribute '%s'" % name )
85
86
88 """check to see if we have an object by an id
89 this will fail if passed a short id and object is stored
90 with fullid (ie: it is related not contained)
91 use hasobject to get around this issue"""
92 return self._objects.has_key(name)
93
94
96 "check to see if we have this object"
97 return self._objects.get(obj.id) == obj
98
99
107
108
109 - def _setObject(self,id,object,roles=None,user=None,set_owner=1):
115
116
120 manage_afterAdd.__five_method__ = True
121
125 manage_afterClone.__five_method__ = True
126
130 manage_beforeDelete.__five_method__ = True
131
132 - def _add(self,obj):
133 """add an object to one side of a ToManyContRelationship.
134 """
135 id = obj.id
136 if self._objects.has_key(id):
137 raise RelationshipExistsError
138 v=checkValidId(self, id)
139 if v is not None: id=v
140 self._objects[id] = aq_base(obj)
141 obj = aq_base(obj).__of__(self)
142
143
145 """remove object from our side of a relationship"""
146 if obj: objs = [obj]
147 else: objs = self.objectValuesAll()
148 for robj in objs:
149 notify(ObjectWillBeRemovedEvent(robj, self, robj.getId()))
150 if obj:
151 id = obj.id
152 if not self._objects.has_key(id):
153 raise ObjectNotFound(
154 "object %s not found on %s" % (
155 obj.getPrimaryId(), self.getPrimaryId()))
156 del self._objects[id]
157 else:
158 self._objects = OOBTree()
159 self.__primary_parent__._p_changed = True
160 for robj in objs:
161 notify(ObjectRemovedEvent(robj, self, robj.getId()))
162 notify(ContainerModifiedEvent(self))
163
164
178
179
181 """look up in our local store and wrap in our aq_chain"""
182 if self._objects.has_key(id):
183 return self._objects[id].__of__(self)
184 elif default == zenmarker:
185 raise AttributeError( "Unable to find %s" % id )
186 return default
187
188
189 security.declareProtected('View', 'objectIds')
191 """only return contained objects"""
192 if spec:
193 if type(spec)==type('s'): spec=[spec]
194 return [obj.id for obj in self._objects.values() \
195 if obj.meta_type in spec]
196 return [ k for k in self._objects.keys() ]
197 objectIdsAll = objectIds
198
199
200 security.declareProtected('View', 'objectValues')
202 """override to only return owned objects for many to many rel"""
203 if spec:
204 if type(spec)==type('s'): spec=[spec]
205 return [ob.__of__(self) for ob in self._objects.values() \
206 if ob.meta_type in spec]
207 return [ob.__of__(self) for ob in self._objects.values()]
208 security.declareProtected('View', 'objectValuesAll')
209 objectValuesAll = objectValues
210
211
213 """Generator that returns all related objects."""
214 for obj in self._objects.values():
215 yield obj.__of__(self)
216
217
219 """over ride to only return owned objects for many to many rel"""
220 if spec:
221 if type(spec)==type('s'): spec=[spec]
222 return [(key,value.__of__(self)) \
223 for (key,value) in self._objects.items() \
224 if value.meta_type in spec]
225 return [(key,value.__of__(self)) \
226 for (key,value) in self._objects.items()]
227 objectItemsAll = objectItems
228
229
230
231
232
233
234
235
236
237
238
239
240
242 """
243 make new relation add copies of contained objs
244 and refs if the relation is a many to many
245 """
246 rel = self.__class__(self.id)
247 rel.__primary_parent__ = container
248 rel = rel.__of__(container)
249 norelcopy = getattr(self, 'zNoRelationshipCopy', [])
250 if self.id in norelcopy: return rel
251 for oobj in self.objectValuesAll():
252 cobj = oobj._getCopy(rel)
253 rel._setObject(cobj.id, cobj)
254 return rel
255
256
258 """Return an xml representation of a ToManyContRelationship
259 <tomanycont id='interfaces'>
260 <object id='hme0'
261 module='Products.Confmon.IpInterface' class='IpInterface'>
262 <property></property> etc....
263 </object>
264 </tomanycont>
265 """
266 if self.countObjects() == 0: return
267 ofile.write("<tomanycont id='%s'>\n" % self.id)
268 for obj in self.objectValues():
269 obj.exportXml(ofile, ignorerels)
270 ofile.write("</tomanycont>\n")
271
272
273 InitializeClass(ToManyContRelationship)
274
275
277 """
278 Adapter so the event dispatching can propagate to children.
279 """
281 self.container = container
284