Use MySQL temporary tables to create user spaces so that different users have access to different records.
Sometimes you want your application to be have a different face for different users. Consider this example:
You are developing a news feed application where users can subscribe to receive news feeds from various companies. You have the following tables:
- Companies
- Stores the companies that post news feeds. Columns: CompanyID, CompanyName.
- Feeds
- Stores the actual news feeds. Columns: FeedID, CompanyID, FeedSubject, FeedBody
- Users
- Stores the user accounts. Columns: UserID, Username
- User_Subscriptions
- A join table between Users and Companies that marks the companies from which a user wants to receive news feeds. Columns: CompanyID, UserID
-
Desired Functionality
When a user enters the Feeds table, we only want him to see feeds that were posted by companies to which the user is subscribed.
Simple permissions won't suffice
In a first attempt, you may try to implement a getPermissions() method in the delegate class of the Feeds table to limit access to the Feeds records as follows:
function getPermissions(&$record){
if ( ! $record ){
return Dataface_PermissionsTool::ALL();
// This is WAY over simplified.. we are giving all permissions when there is no record
// to check... this would give all users permission to create new records etc.. but
// for the sake of this example, it will do... this part is not important.
}
// get subscriptions matching this feed's company and this user
$subscription =& df_get_record(
"User_Subscriptions",
array(
'UserID'=>getLoggedInUserID(), // Note that we implemented the getLoggedInUserID() function elsewhere
'CompanyID'=>$record->strval('CompanyID')
)
);
if ( $subscription ){
// A subscription was found, so we have read permission
return Dataface_PermissionsTool::READ_ONLY();
} else {
// No subscription was found so we disable access
return Dataface_PermissionsTool::NO_ACCESS();
}
}
So what is wrong with this solution?
There are a few problems:
- The getPermissions() method is called for each record that is displayed. Each time that it is called we are calling the df_get_record() function which executes a query against the database. This is very expensive and will cause our application to slow to a crawl. NEVER perform an SQL query inside the getPermissions() method.
We can improve upon this method by changing it to only perform an SQL query the first time it is called as follows:
function getPermissions(&$record){
// We use a static variable to hold the ids of all of the companies to which
// the user is subscribed
static $subscriptions = 0;
if ( $subscriptions === 0 ){
$subscriptions = array();
$res = mysql_query("select CompanyID from User_Subscriptions where UserID='".getLoggedInUserID."'", df_db());
while ( $row = mysql_fetch_assoc($res) ) $subscriptions[$row['CompanyID']] = true;
// Now $subscriptions is a map with entries for all company ids.
}
if ( ! $record ){
return Dataface_PermissionsTool::ALL();
// This is WAY over simplified.. we are giving all permissions when there is no record
// to check... this would give all users permission to create new records etc.. but
// for the sake of this example, it will do... this part is not important.
}
if ( @$subscriptions[$record->strval('CompanyID')] ){
// A subscription was found, so we have read permission
return Dataface_PermissionsTool::READ_ONLY();
} else {
// No subscription was found so we disable access
return Dataface_PermissionsTool::NO_ACCESS();
}
}