[Top][All Lists]
[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