'Helper function to look up and declare dynamic components
for a table; called by get_components if dynamic_components
is configured for the table
@param tablename: the table name
@param exclude: names to exclude (static components)'

@classmethod
def add_dynamic_components(cls, tablename, exclude=None):

    mtable = cls.table(tablename)
    if (mtable is None):
        return
    if cls.get_config(tablename, 'dynamic_components_loaded'):
        return
    ttable = cls.table('s3_table')
    ftable = cls.table('s3_field')
    join = ttable.on((ttable.id == ftable.table_id))
    query = (((ftable.master == tablename) & (ftable.component_key == True)) & (ftable.deleted != True))
    rows = current.db(query).select(ftable.name, ftable.field_type, ftable.component_alias, ftable.settings, ttable.name, join=join)
    cls.configure(tablename, dynamic_components_loaded=True)
    components = {}
    for row in rows:
        hook = {}
        ctable = row['s3_table']
        ctablename = ctable.name
        default_alias = ctablename.split('_', 1)[(-1)]
        field = row['s3_field']
        alias = field.component_alias
        if (not alias):
            alias = default_alias
        if (exclude and (alias in exclude)):
            continue
        if (alias != default_alias):
            hook['name'] = alias
        hook['joinby'] = field.name
        settings = field.settings
        if settings:
            multiple = settings.get('component_multiple', DEFAULT)
            if (multiple is not DEFAULT):
                hook['multiple'] = multiple
        field_type = field.field_type
        if (field_type[:10] == 'reference    '):
            ktablename = field_type.split('    ', 1)[1]
            if ('.' in ktablename):
                (ktablename, pkey) = ktablename.split('.', 1)[1]
                if (pkey and (pkey != mtable._id.name)):
                    hook['pkey'] = pkey
        components[ctablename] = hook
    if components:
        cls.add_components(tablename, **components)
