Creating User Spaces

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:
  1. 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();
    }
    }


Powered by Dataface
(c) 2005-2007 All rights reserved