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)
|