I fear my answer will just be a useless ramble but here goes....
Try to use assertions along side strategy and/or/with state pattern. If you have your model objects well organized (say "comment" object and "edit field" object, you can query ACL for what the current user can do (which will become the state of the application). Then you can make a "comment" object editable by applying "edit field" to "comment" object's private property. So essentially you are creating a separate model object for every little peace of action ( edit, view this column, view that column - following "every class is responsible for only one thing" principle). Then you create larger model objects for resources ("the daily article" or smth).
Now, let the controller query the ACL for what the user needs to have access to, then create instances of the appropriate individual action objects dynamically (look up how to do dynamic class loading) and apply those instances to the properties of the main resources object. Make sure every action object implements same set of methods everywhere so the resoure object is able to use any one of them interchaingebly. Use those instances to display the appropriate content. So if you have a $columns private property of a post class:
You can do $this->columns->displayColumns();
And it should work no matter what class $this->columns instance points to because they all have displayColumns() method.
| Code: |
class dailyArticle() {
public $column; // public for example, use private with setters
public function displayPost() {
$this->column->displayColumns();
}
}
class adminColumn implements columnsAbstract() {
public function displayColumns() {
// sql query for admin columns
}
}
class userColumn implements columnsAbstract() {
public function displayColumns() {
// sql for users
}
}
// controller stuff
$post = new dailyArticle();
$post->columns = new adminColumn(); // or new userColumn becuase Post() does not care. Loaded dynamically as explained bellow....
$post->displayPost();
|
In the end, if you did all normalization correctly you should not have a single "if" statement.
Now, your next part of question is how to figure out what gruop user belongs to and what actions should be loaded.
For permissions as dynamic as yours writing permissions out explicitly like that is not going to work. You will have to make resources, users, permission, assertions as variable as possible. Save all the relations between users, groups, resources and permissions in database. You will end up with a lot of tables. Base tables will be users, groups, permissions (probably only 2 records, allow and deny) and actions. Then you need relation tables that match the base tables: "user to group" relation, "groups to resources" relation, " "groups to resources" to actions permissions" relation etc. until your DB has a fully normalized structure of your permissions. Your goal is to be able to generate a single SQL query that will bring up one nice and long row describing what the user does and where. Or maybe multiple rows - if you need to query the other way around - who can do a resource. But I don't think that will be necessary since usually work from user's point of view, but its up to you how you want to visualize it.
Now you want to build the ACL classes. And by build, I don't mean write them yourself, I mean create a class that builds ACL classes. Like a factory pattern but should be simpler. (Now, don't take that literally - I am not saying you should generate PHP code and do eval() on it either

)
All those strings in addResource(), addRole(), isAllowed() and just about anywhere you have a hardcoded value, need to be replaced with private variables of the ACL class. The values of those variables will come from the factory class. So essentially the ACL class never has to worry about how to get the data - one and only thing it will do is check if the current variables match or not. The actual data will be pushed on to it through public setters by the factory class which it in tern collects from the db tables you would have created in above paragraph.
This way factory pattern should align everything in a way where you can query the ACL class to figure out whether to load adminColumn() or userColumn() or, guestColumn() or even both, classes into $columns of dailyArticle class. I think "groups to resources" to actions permissions" relation table info will be the one which you want loaded into ACL class. Unfortunately, there is no ACL query for somethin like "what ALL am I allowed?" - only "am I allowed THIS?" query. So you can create a utility method in your ACL class that takes all actions availabe (again, taken from the factory) and filters out to see what is allowed from what is not. This collection of allowed actions it can keep in its own private array. Controller now can query this array and figure what actions to load into the dailyArticle().
I hope reading this (if you did) did not waste too much time.