After reading through the documentation, I find that the role based ACL and work flow can be more tightly integrated. Therefore I made all the transaction into many FSMs and my work flow component now consists of one work flow library and one work flow management model. As I am going a more normalized design (I use denormalized design in work as it deals with a lot of documents, however for a small project like mine, a denormalized design should do well).
So for the current stage, I have a set of relations as follows.
Resources (resource_id, name, description) a nested set table
Roles (role_id, name, description) a nested set table
Resources table stores resources available in the system (duh~), and Roles table stores roles available in the system… Both of them are nested set table as they store hierarchical data (handled by doctrine). The documentation provided by Zend states that:
- a resource is an object to which access is controlled.
- a role is an object that may request access to a Resource.
Put simply, roles request access to resources. For example, if a parking attendant requests access to a car, then the parking attendant is the requesting role, and the car is the resource, since access to the car may not be granted to everyone.
So in my project, to further simplifying the concept, a resource simply means a table which access is managed.
Then I have a states table, which is one of the key tables in work flow component.
States (state_id, name, description, is_start, is_end, is_delete)
Each record has a state, therefore each of the record references to this table to find out what the state is. There are three boolean fields added, which is `is_start`, `is_end` and `is_delete`, to further describe the status. As there is a is_delete field, the site will have the unwanted record soft deleted at first.
Then we have a composite table to link up resource and states to be used later
States_Resources (state_resource_id, state_id *, resource_id *)
Followed by the actions table, which provide a set of verbs that can be used as action name. The primary concern of having this table is to achieve consistency. Otherwise I would have URL in the form of user/profile/edit, post/update, feed/edit.
Actions (action_id, name, description)
Followed by the transition table, which stores possible transition for each of the resource at every state. Speaking in terms of Zend_ACL, each transition is like a privilege which is explained by Zend as follows:
Zend_Acl also supports privileges on resources (e.g., “create”, “read”, “update”, “delete”), so the developer can assign rules that affect all privileges or specific privileges on one or more resources.
Transitions (transition_id, action_id *, from_resource_state_id *, to_resource_state_id *)
Then I have access_rules table which stores the actual ACL
Access_Rules (access_rules_id, role_id, transition_id)
To check whether a transition is doable, frequently I would have to check the condition through some callback functions, therefore I need to store them into another table.
Transitions_Callbacks (transition_callback_id, transition_id *, callback_class_id *)
Callback_Classes (callback_class_id, name)
Lastly, the history table (there is nothing much to track at the moment)
Transition_History (transition_history_id, transition_id, user_id, ip_address, timestamp)