Back to index

plone3  3.1.7
Facade.py
Go to the documentation of this file.
00001 __metaclass__ = type
00002 
00003 from Products.Archetypes.Schema import BasicSchema
00004 from Products.Archetypes.Field import *
00005 from Products.Archetypes.interfaces.schema import IBindableSchema
00006 from Products.Archetypes.Storage.Facade import FacadeMetadataStorage
00007 from Products.Archetypes.ClassGen import generateMethods
00008 
00009 from AccessControl import ClassSecurityInfo
00010 from Products.CMFCore.utils import getToolByName
00011 from Products.CMFCore.permissions import View
00012 
00013 # Crude mapping for now. We should instantiate
00014 # the right widgets for some specialized fields
00015 # that map better.
00016 _field_mapping = {'CheckBoxField':BooleanField,
00017                   'DateTimeField':DateTimeField,
00018                   'EmailField':StringField,
00019                   'FileField':FileField,
00020                   'FloatField':FloatField,
00021                   'IntegerField':IntegerField,
00022                   'LinesField':LinesField,
00023                   'LinkField':StringField,
00024                   'ListField':LinesField,
00025                   'ListTextAreaField':LinesField,
00026                   'MethodField':StringField,
00027                   'MultiCheckBoxField':LinesField,
00028                   'MultiListField':LinesField,
00029                   'PasswordField':StringField,
00030                   'PatternField':StringField,
00031                   'RadioField':StringField,
00032                   'RangedIntegerField':StringField,
00033                   'RawTextAreaField':StringField,
00034                   'StringField':StringField,
00035                   'TALESField':StringField,
00036                   'TextAreaField':StringField}
00037 
00038 def getFactory(name):
00039     return _field_mapping.get(name)
00040 
00041 def fieldsFromSet(set, schema):
00042     fields = {}
00043     for element in set.getElements():
00044         factory = getFactory(element.field_type)
00045         name = '%s%s' % (set.id, element.id)
00046         field = factory(name,
00047                         metadata_name=element.id,
00048                         storage=schema.storage,
00049                         schemata=schema.schemata,
00050                         default=element.getDefault(schema.context),
00051                         required=element.isRequired(),
00052                         isMetadata=schema.isMetadata)
00053         field.widget.label = element.title_or_id()
00054         field.widget.description = element.Description()
00055         fields[name] = field
00056     return fields
00057 
00058 def fieldNamesFromSet(set, schema):
00059     fields = []
00060     for element in set.getElements():
00061         name = '%s%s' % (set.id, element.id)
00062         fields.append(name)
00063     return fields
00064 
00065 class CMFMetadataFieldsDescriptor:
00066     """A nice descriptor that computes a set of Archetypes
00067     fields from a CMFMetadata Set (Formulator-based)"""
00068 
00069     def __get__(self, obj, objtype=None):
00070         pm = getToolByName(obj.context, 'portal_metadata', None)
00071         if pm is None:
00072             return {}
00073         set = pm.getMetadataSet(obj.set_id)
00074         fields = fieldsFromSet(set, obj)
00075         # TODO This would *really* benefit from some
00076         # caching/timestamp checking.
00077         # Calling generateMethods and reconstructing
00078         # the fields each time may actually be
00079         # *very very* expensive.
00080         klass = obj.context.__class__
00081         generateMethods(klass, fields.values())
00082         return fields
00083 
00084 class CMFMetadataFieldNamesDescriptor:
00085     """A nice descriptor that computes a set of Archetypes
00086     fields from a CMFMetadata Set (Formulator-based)"""
00087 
00088     def __get__(self, obj, objtype=None):
00089         pm = getToolByName(obj.context, 'portal_metadata', None)
00090         if pm is None:
00091             return []
00092         set = pm.getMetadataSet(obj.set_id)
00093         return fieldNamesFromSet(set, obj)
00094 
00095 class FacadeMetadataSchema(BasicSchema):
00096     """A Facade Schema, which adapts CMFMetadata 'Sets'
00097     to groups of Archetypes fields
00098     """
00099 
00100     __implements__ = IBindableSchema
00101 
00102     security = ClassSecurityInfo()
00103     security.setDefaultAccess('allow')
00104 
00105     _names = CMFMetadataFieldNamesDescriptor()
00106     _fields = CMFMetadataFieldsDescriptor()
00107 
00108     def __init__(self, *args, **kwargs):
00109         # Everything else is ignored.
00110         self.set_id = kwargs['set_id']
00111         self.schemata = kwargs['schemata']
00112         if not kwargs.get('storage'):
00113             kwargs['storage'] = FacadeMetadataStorage(self.set_id)
00114         self.storage = kwargs['storage']
00115         self.isMetadata = kwargs.get('isMetadata', True)
00116 
00117     def bind(self, context):
00118         self.context = context
00119 
00120     security.declareProtected(View, 'validate')
00121     def validate(self, instance=None, REQUEST=None,
00122                  errors=None, data=None, metadata=None):
00123         """Validate the state of the entire object.
00124 
00125         The passed dictionary ``errors`` will be filled with human readable
00126         error messages as values and the corresponding fields' names as
00127         keys.
00128 
00129         If a REQUEST object is present, validate the field values in the
00130         REQUEST.  Otherwise, validate the values currently in the object.
00131         """
00132         if REQUEST:
00133             fieldset = REQUEST.form.get('fieldset', None)
00134         else:
00135             fieldset = None
00136         fields = []
00137 
00138         if fieldset is not None:
00139             schemata = instance.Schemata()
00140             fields = [(field.getName(), field)
00141                       for field in schemata[fieldset].fields()]
00142         else:
00143             if data:
00144                 fields.extend([(field.getName(), field)
00145                                for field in self.filterFields(isMetadata=0)])
00146             if metadata:
00147                 fields.extend([(field.getName(), field)
00148                                for field in self.filterFields(isMetadata=1)])
00149 
00150         if REQUEST:
00151             form = REQUEST.form
00152         else:
00153             form = None
00154         _marker = []
00155         field_data = {}
00156         for name, field in fields:
00157             value = None
00158             widget = field.widget
00159             if form:
00160                 result = widget.process_form(instance, field, form,
00161                                              empty_marker=_marker)
00162             else:
00163                 result = None
00164             if result is None or result is _marker:
00165                 accessor = field.getAccessor(instance)
00166                 if accessor is not None:
00167                     value = accessor()
00168                 else:
00169                     # can't get value to validate -- bail
00170                     continue
00171             else:
00172                 value = result[0]
00173             field_data[name] = value
00174 
00175         pm = getToolByName(self.context, 'portal_metadata', None)
00176         set = pm.getMetadataSet(self.set_id)
00177         set.validate(self.set_id, field_data, errors)
00178         return errors