|Version 31 (modified by 9 years ago) ( diff ),|
Component resources are an S3 framework concept to simplify the implementation of and access to aggregation models, which is the most common type of data models used in Sahana-Eden.
Typically, such an aggregation model has a master entity and a number of associated (sub-)entities ("have"-relationships):
- organisations = have => offices, projects, teams
- persons = have => addresses, identities
- groups = have => members, tasks
Each of these relationships can be represented by a join between the respective tables.
The "Component Resource" extension provides the functionality to pre-configure and re-use these joins as pseudo-attributes ("components") of the master entity, thereby replacing the joins by simple identifiers (aliases) which can be used to construct queries, e.g. in URLs:
# Join "office": org_organisation <-- id/organisation_id --> org_office /org/organisation/5/office
# Join "contact": pr_person <-- pe_id/pe_id --> pr_contact /pr/person?contact.contact_method=EMAILfirstname.lastname@example.org
The "Component Resource" extension is one of the fundamental RAD concepts of the S3 framework.
Besides simplified construction of queries, views and self-processing forms it also allows implicit (=keyless) constraints in S3XML which simplifies the mapping and transformation from and to other data models using XSLT:
<s3xml> <!-- an organisation record --> <resource name="org_organisation"> <data>...</data> <!-- an office "of this organisation" (=keyless constraint) --> <resource name="org_office"> <data>...</data> </resource> </resource> </s3xml>
The following diagram describes the joins which are currently supported:
Note that, for efficiency reasons, "components" can not be nested in queries.
Components can be bound to their master records via link-tables. In such cases, the foreign key constraints for the component link are all in a separate link-table, whereas both the master table and the component table are completely independent:
master (primary key) <==== (foreign key) link table (foreign key) ====> (primary key) component
Link-table component links have some advantages over simple foreign key constraints:
- they can carry attributes of their own (attributed link)
- they provide the option to bind the same component record to multiple master records (many-to-many)
- there are several different ways to actuate such links
- link-table links work both ways (i.e. with master/component exchanged, can be declared both ways at the same time)
However, they do have disadvantages too:
- overhead to maintain a separate database table (processing time, migration issues etc.)
- increased complexity to access and query resources (3 tables instead of 2)
- increased complexity to handle such links in CRUD and XML/XSLT
Link Actuation Options
The RESTful methods can handle the link-table in a number of different ways, depending on the CRUD method and the configured option:
- replace: hides the link table and always operates on the component table
- hide: hides the component table and always operates on the link table
- link: operates on the component table for single-record requests, and on the link table for summary requests (=without record ID) and delete
- embed: operates on the link table, embeds the component record in single-record requests
The following table gives an overview of link actuation in S3CRUD:
|CRUD Method||Link Actuation Option|
|create||create-form for component||create-form for link||create-form for link||create-form for link with component embedded|
|read||read-view of component||read-view of link||read-view of component||read-view of link (with component embedded2)|
|update||update-form for component||update-form for link||update-form for component||update-form for link with component embedded|
|delete||deletes both, component and link||deletes the link||deletes the link1||deletes the link1|
|list||list view of component||list view of link||list view of link||list view of link (with component embedded2)|
- 1 = deletes the component together with the last link if autodelete option is set
- 2 = not implemented yet
Other RESTful methods such as S3Search or S3Report may have their own definitions.
The basic syntax of a link-table component link declaration is:
s3db.add_component("my_component", # Tablename of the component my_master=dict( # Tablename of the master table name="alias", # Use this 'alias' as the component name link="my_linktable", # Tablename of the link table joinby="fieldname", # FK of the master table (=left key constraint) key="fieldname", # FK of the component table (=right key constraint) actuate="replace", # Actuation option (see above, optional, defaults to "link") autodelete=False # Delete the component record together with the last link (optional, default is False) widget=Widget, # Widget to use for embedding (optional, defaults to S3EmbedComponentWidget) autocomplete="fieldname", # Field in the component to use for autocomplete when embedding the component ))
If no field is defined for autocomplete, then no autocomplete-widget will be used, but a standard SELECT of options for key (default behavior).
Important: if you specify a widget for embedding (e.g. S3AddPersonWidget), then you must ensure that the foreign key in the link-table doesn't also use either this widget or any other widget validator!
name='alias' is specified, the component would not be addressed in the URL as
master/component but as
master/alias. This allows to link the same component table to the same master table more than once using different link tables.