File: ParentManagedSchema.py

package info (click to toggle)
zope-atseng 0.3.2-3
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 312 kB
  • ctags: 223
  • sloc: python: 1,301; makefile: 32; sh: 5
file content (210 lines) | stat: -rw-r--r-- 8,335 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# -*- coding: iso-8859-1 -*-

"""
ATSchemaEditorNG

(C) 2003,2004, Andreas Jung, ZOPYX Software Development and Consulting
and Contributors
D-72070 T´┐Żbingen, Germany

Contact: andreas@andreas-jung.com

License: see LICENSE.txt

$Id: ParentManagedSchema.py 10964 2005-08-15 02:20:50Z rafrombrc $
"""

from Globals import InitializeClass
from AccessControl import ClassSecurityInfo
from Acquisition import ImplicitAcquisitionWrapper
from Products.CMFCore.CMFCorePermissions import View
from Products.Archetypes.Schema import ManagedSchema
from zLOG import LOG, INFO
from interfaces import IParentManagedSchema, ISchemaEditor
from Products.CMFCore.utils import getToolByName
from Products.Archetypes.utils import shasattr
from util import create_signature
import config

class ManagedSchemaBase:
    """ mix-in class for AT content-types whose schema is managed by
        the parent container and retrieved through acquisition.
    """

    __implements__ = (IParentManagedSchema,)

    security = ClassSecurityInfo()  

    def _wrap_schema(self, schema):
        return ImplicitAcquisitionWrapper(schema , self)

    security.declareProtected(View, 'Schema')
    def Schema(self, schema_id=None):
        """ Retrieve schema from parent object. The client class should
            override the method as Schema(self) and then call his method
            of the baseclass with the corresponding schema_id.
        """

        # Schema() seems to be called during the construction phase when there is
        # no acquisition context. So we return the default schema itself.
        # XXX mind the difference btn 'hasattr' and 'shasattr' (latter strips acq)
        if not hasattr(self, 'aq_parent'):
            if shasattr(self, 'schema'):
                return self._wrap_schema(self.schema)
            else:
                raise ValueError('Instance has no "schema" attribute defined')

        if not self.lookup_provider().atse_isSchemaRegistered(self.portal_type):
            return self._wrap_schema(self.schema)

        # If we're called by the generated methods we can not rely on
        # the id and need to check for portal_type
        if not schema_id:
            schema_id = self.portal_type
            
        # Otherwise get the schema from the parent through
        # acquisition and assign it to a volatile attribute for performance
        # reasons
        self._v_schema = getattr(self, '_v_schema', None)
        if self._v_schema is None:

            # looking for changes in the schema held by the object
            self._v_schema = self._lookupChanges(schema_id)

            if not shasattr(self, '_md'):
                self.initializeArchetype()

            for field in self._v_schema.fields():

                ##########################################################
                # Fake accessor and mutator methods
                ##########################################################

                # XXX currently only honoring explicitly specified mutators
                #     or accessors if the method exists on the object.  if
                #     the methods are autogenerated the specified names will
                #     not be honored.

                name = field.getName()

                def atse_get_method(self=self, name=name, *args, **kw):
                    return self.getField(name).get(self, **kw)

                def atse_getRaw_method(self=self, name=name, *args, **kw):
                    return self.getField(name).getRaw(self, **kw)

                # workaround for buggy widget/keyword AT template that
                # uses field.accessor as catalog index name *grrrr*
                # XXX find another way to fix that
                if name != 'subject':
                    accessor_name = getattr(field, 'accessor', None)
                    if accessor_name and shasattr(self, accessor_name):
                        pass # the accessor exists, we're cool
                    else:
                        v_name = '_v_%s_accessor' % name
                        accessor_name = v_name
                        setattr(self, v_name, atse_get_method)
                    field.accessor = accessor_name
                    
                    # the edit accessor and the regular accessor can be the
                    # same in most cases, but not for ReferenceFields
                    # XXX any other cases?
                    edit_accessor_name = getattr(field, 'edit_accessor', None)
                    if edit_accessor_name and shasattr(self, edit_accessor_name):
                        pass # the edit_accessor_name exists, we're cool
                    else:
                        edit_v_name = '_v_%s_edit_accessor' % name
                        edit_accessor_name = edit_v_name
                        field_type = str(field.type).upper()
                        if field_type == 'REFERENCE':
                            setattr(self, edit_accessor_name, atse_getRaw_method)
                        else:
                            setattr(self, edit_accessor_name, atse_get_method)
                    field.edit_accessor = edit_accessor_name

                def atse_set_method(value, self=self, name=name, *args, **kw):
                    if name != 'id':
                         self.getField(name).set(self, value, **kw)
                        
                    # saving id directly (avoiding unicode problems)
                    else: self.setId(value)

                mutator_name = getattr(field, 'mutator', None)
                if mutator_name and shasattr(self, mutator_name):
                    pass # the mutator exists, we're cool
                else:
                    v_name = '_v_%s_mutator' % name
                    mutator_name = v_name
                    setattr(self, v_name, atse_set_method)
                field.mutator = mutator_name

                # Check if we need to update our own properties
                try:
                    value = field.get(self)
                except:
                    field.set(self, field.default)

        return self._wrap_schema(self._v_schema)

    def _lookupChanges(self, atse_schema_id):
        """ Checks if schema has changed """
        provider = self.lookup_provider()
        
        if config.ALWAYS_SYNC_SCHEMA_FROM_DISC == True:
            
            # looking if schema has changed
            atse_schema = provider.atse_getSchemaById(atse_schema_id)
            object_schema = self.schema

            if create_signature(atse_schema) != create_signature(object_schema):
                LOG('ATSchemaEditorNG', INFO, 'Schema <%s> changed - refreshing from disk' % atse_schema_id)
                provider.atse_reRegisterSchema(atse_schema_id, object_schema)

        return provider.atse_getSchemaById(atse_schema_id)


class ParentManagedSchema(ManagedSchemaBase):
    """ base class for content-types whose schema is managed by the parent folder """
    
    def lookup_provider(self):
        """ return schema provider instance """
        return self.aq_parent

InitializeClass(ParentManagedSchema)


class AcquisitionManagedSchema(ManagedSchemaBase):
    """ base class for content-types whose schema is managed by a
    provider somewhere up the acquisition tree """
    
    def lookup_provider(self):
        """ return schema provider instance """
        app = self.getPhysicalRoot()
        
        def get_aq_provider(obj):
            parent = obj.aq_parent
            if parent is app:
                raise SchemaEditorError(self.translate('atse_no_provider',
                                                       default="No Schema provider found"))
            if ISchemaEditor.isImplementedBy(parent):
                return parent
            else:
                return get_aq_provider(parent)

        return get_aq_provider(self)

InitializeClass(AcquisitionManagedSchema)
    

class ToolManagedSchema(ManagedSchemaBase):
    """ base class for content-types whose schema is managed by a global tool"""

    def lookup_provider(self):
        """ return schema provider instance """
        
        tool = getToolByName(self, TOOL_NAME, None)
        if not tool:
            raise LookupError('%s not found' % TOOL_NAME)
        return tool

InitializeClass(ToolManagedSchema)