erp5-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Erp5-dev]global classification


From: Jean-Paul Smets
Subject: Re: [Erp5-dev]global classification
Date: Mon, 9 Sep 2002 14:41:39 +0200
User-agent: KMail/1.4.3

Le Lundi 9 Septembre 2002 14:15, shan sverige a écrit :
> Hello,
>
> I'm implementing a global classification in my own projects in a
> similar way you describe in
> http://www.erp5.org/wiki/whitepaper/ImplementingMetaLevel
>
> Now, because each Category (you call it leaf of a classification tree)
> has a many-2-many relationship with a content object (one content object
> can belong to more Categories and one Category classifies multiple
> content objects), I plan to use the mxmRelation product.
> Because mxmRelation comes with a nice interface (5 methods) and all
> other approaches too implement many-2-many seems clumsy. Downside
> of MxmRelation is it's lack of scalability
>
> Are you also using that product or do you implement many-2-many
> differently?
>

I implement categories in a "original" different way actually. I know 
mxmRelation and I think it is very interesting. I liked it a lot. However, 
one of the issues for ERP5 is scalability and performance. Another issue is 
RAD (rapid application development).

For the performance issue, I developed something called "ZSQLCatalog" which 
maps all objects of Zope into a set of SQL set of tables.  ZSQLCatalog 
completely replaces the ZOpe Catalog (and the CatalogTool) and allows to:
        - boost Zope performance considerably (up to 200x)
        - have a Zope system running on multiple CPUs
        - make complex queries
        - provide a single UID to each object in the Zope database and a 
relation 
between paths and UIDs

The ZSQL Catalog is a central tool in ERP5 which can be viewed as a kind of 
advanced index / repository.

Relations and categories are implemented within the RAD system through a new 
type of attribute : "reference". Here is an example of Property Sheet

class SalesOpportunity:
  """
    Sales Opportunity properties and categories
  """

  _properties = (
    { 'id'          : 'client_organisation',
      'description' : 'The organisation involved',
      'type'        : 'reference',
      'mode'        : '' },
    { 'id'          : 'client_person',
      'description' : "The contact person involved",
      'type'        : 'reference',
      'mode'        : '' },
  )

  _categories = ('role', 'group', 'activity', 'function',
           'social_form', 'skill', 'market_segment')

The approach is inspired by an "mxm" article. The type "reference" is used 
by the code (bellow) to generate getters and setters methods for each 
class. The same thing is done for categories. This way, all the 
inplementation of categories and references is encapsulated in the base 
class of ERP5 and in a few portal tools

Currently, references and categories are implemented by doing lookups in the 
ZSQLCatalog. 

Last but not least, the base class defines an edit method which combined to 
ERP5 formumlator allows to define new complex object types in nearly no 
time.

I am finishing a first demo CRM system so that you can have look at how it 
is implemented in details (the code is not yet into the CVS).

Regards,

JPS.



import os, string
from Globals import package_home
from DateTime import DateTime

import zLOG

_dtmldir = os.path.join( package_home( globals() ), 'dtml' )

defaults = {
    'float'              : 0.0,
    'int'                : 0,
    'long'               : 0L,
    'date'               : DateTime(),
    'string'             : '',
    'text'               : '',
    'boolean'            : 0,
    'lines'              : [],
    'tokens'             : [],
    'selection'          : [],
    'multiple selection' : [],
}

def InitializeDefaultProperties(klasses):
    for klass in klasses:
      if getattr(klass, 'isRADContent', 0):
        SetDefaultProperties(klass)

def SetDefaultProperties(klass):
    """
    Set default attributes in current object for all properties in 
'_properties'
    This also implements the reference type in ERP5
    """
    legalTypes = defaults.keys()
    # First build the property list from the property sheet
    # and the class properties
    prop_list = []
    prop_list += getattr(klass,'_properties',[])
    cat_list = []
    for base in klass.property_sheets:
        prop_list += base._properties
        if hasattr(base, '_categories'):
          cat_list += base._categories
    # Then convert reference and multiple reference
    # properties into string and int
    converted_prop_list = []
    for prop in prop_list:
      if prop['type'] == 'reference':
        id = prop['id']
        prop = prop.copy()
        prop['type'] = 'string'
        prop['id'] = id + '_path'
        converted_prop_list += [prop]
        prop = prop.copy()
        prop['type'] = 'int'
        prop['id'] = id + '_uid'
        converted_prop_list += [prop]
        CreateDefaultReferenceAccessors(klass, id)
      elif prop['type'] == 'multiple reference':
        id = prop['id']
        prop = prop.copy()
        prop['type'] = 'lines'
        prop['id'] = id + '_path_list'
        converted_prop_list += [prop]
        prop = prop.copy()
        prop['type'] = 'tokens'
        prop['id'] = id + '_uid_list'
        converted_prop_list += [prop]
        CreateDefaultMultipleReferenceAccessors(klass, id)
      else:
        converted_prop_list += [prop]
        CreateDefaultAccessors(klass, prop['id'])
    # Create Category Accessors
    for cat in cat_list:
      CreateCategoryAccessors(klass, cat)
    # Set the properties of the class
    klass._properties = tuple(converted_prop_list)
    klass._categories = tuple(cat_list)
    # And the default values
    for prop in klass._properties:
        if prop['type'] in legalTypes:
            setattr(klass, prop['id'], defaults[prop['type']])
        else:
            raise TypeError, '"%s" is illegal type for propertysheet' % \
                                            prop['type']

def UpperCase(key):
  """
    This function turns an attribute name into
    a method name according to the ERP5 naming conventions
  """
  result = ''
  parts = string.split(str(key),'_')
  for part in parts:
    letter_list = list(part)
    letter_list[0] = string.upper(letter_list[0])
    result = result + string.join(letter_list,'')
  #zLOG.LOG('Accessor Name',100,result)
  return result

def CreateDefaultAccessors(klass, id):
  """
    This function creates accessor and setter for a class
    and a property
  """
  accessor_name = 'get' + UpperCase(id)
  accessor_str = "lambda o: o.%s" % id
  accessor = eval(accessor_str)
  setattr(klass, accessor_name, accessor)
  setter_name = 'set' + UpperCase(id)
  setter_str = "lambda o,value: (setattr(o,'%s',value),o.reindexObject())" % 
\
                id
  setter = eval(setter_str)
  setattr(klass, setter_name, setter)
  setter_name = '_set' + UpperCase(id)
  setter_str = "lambda o,value: setattr(o,'%s',value)" % \
                id
  setter = eval(setter_str)
  setattr(klass, setter_name, setter)

def CreateDefaultReferenceAccessors(klass, id):
  """
    This function creates accessor and setter for a class
    and a property
  """
  accessor_name = 'get' + UpperCase(id)
  accessor_str = "lambda o: o._getReference('%s')" % id
  accessor = eval(accessor_str)
  setattr(klass, accessor_name, accessor)
  accessor_name = 'get' + UpperCase(id) + 'Path'
  accessor_str = "lambda o: o._getReferencePath('%s')" % id
  accessor = eval(accessor_str)
  setattr(klass, accessor_name, accessor)
  setter_name = 'set' + UpperCase(id)
  setter_str = "lambda o,value: (o._setReference('%s',value), 
o.reindexObject())" % \
                id
  setter = eval(setter_str)
  setattr(klass, setter_name, setter)
  setter_name = '_set' + UpperCase(id)
  setter_str = "lambda o,value: o._setReference('%s',value)" % \
                id
  setter = eval(setter_str)
  setattr(klass, setter_name, setter)

def CreateDefaultMultipleReferenceAccessors(klass, id):
  """
    This function creates accessor and setter for a class
    and a property
  """
  accessor_name = 'get' + UpperCase(id) + 'List'
  accessor_str = "lambda o: o._getReferenceList('%s')" % id
  accessor = eval(accessor_str)
  setattr(klass, accessor_name, accessor)
  setter_name = 'set' + UpperCase(id) + 'List'
  setter_str = "lambda o,value: (o._setReferenceList('%s',value), 
o.reindexObject())" % \
                id
  setter = eval(setter_str)
  setattr(klass, setter_name, setter)
  adder_name = 'add' + UpperCase(id)
  adder_str = "lambda o,value: (o._addReference('%s',value), 
o.reindexObject())" % \
                id
  adder = eval(adder_str)
  setattr(klass, adder_name, adder)
  deleter_name = 'del' + UpperCase(id)
  deleter_str = "lambda o,value: (o._delReference('%s',value), 
o.reindexObject())" % \
                id
  deleter = eval(deleter_str)
  setattr(klass, deleter_name, deleter)
  setter_name = '_set' + UpperCase(id) + 'List'
  setter_str = "lambda o,value: o._setReferenceList('%s',value)" % \
                id
  setter = eval(setter_str)
  setattr(klass, setter_name, setter)
  adder_name = '_add' + UpperCase(id)
  adder_str = "lambda o,value: o._addReference('%s',value)" % \
                id
  adder = eval(adder_str)
  setattr(klass, adder_name, adder)
  deleter_name = '_del' + UpperCase(id)
  deleter_str = "lambda o,value: o._delReference('%s',value)" % \
                id
  deleter = eval(deleter_str)
  setattr(klass, deleter_name, deleter)

def CreateCategoryAccessors(klass, id):
  """
    This function creates accessor and setter for a class
    and a property
  """
  accessor_name = 'get' + UpperCase(id) + 's'
  accessor_str = "lambda o: o._getCategoryMultipleMembership('%s')" % id
  accessor = eval(accessor_str)
  setattr(klass, accessor_name, accessor)
  accessor_name = 'get' + UpperCase(id)
  accessor_str = "lambda o: o._getCategorySingleMembership('%s')" % id
  accessor = eval(accessor_str)
  setattr(klass, accessor_name, accessor)
  setter_name = 'set' + UpperCase(id)
  setter_str = "lambda o,value: (o._setCategorySingleMembership('%s', 
value), \
                o.reindexObject())" % id
  setter = eval(setter_str)
  setattr(klass, setter_name, setter)
  setter_name = 'set' + UpperCase(id) + 's'
  setter_str = "lambda o,value: (o._setCategoryMultipleMembership('%s', 
value), \
                o.reindexObject())" % id
  setter = eval(setter_str)
  setattr(klass, setter_name, setter)


-- 
Jean-Paul Smets-Solanes 
Nexedi CEO    Tel. +33(0)6 62 05 76 14    Fax. +33(0)1 53 01 09 29

About www.nexedi.com 

Nexedi is a consulting and development services company helping small and 
medium organisations to choose open source / free software and fulfill 
their IT application needs. Nexedi is the founder of the ERP5 project, a 
Free / Open Source ERP software based on innovative technologies 
(www.erp5.org).

About www.storever.com

Storever provides a reliable source for OpenBrick, notebooks and servers 
preconfigured with the GNU/Linux operating system




reply via email to

[Prev in Thread] Current Thread [Next in Thread]