views:

47

answers:

1

Hello everyone,

As the title suggests, I've inherited a php/MySQL application which has fairly well written procedural code, but only has one admin user login. The client naturally wants to split out functionality into different users/roles and ultimately update the application code with best-practice techniques.

For the example of updating someone's username in the admin section, the original version simply displays a text field prepopulated with the username (code simplified for brevity):

<input type="text" name="username" value="<?= $username; ?>">

The POST is then checked against a regular expression and saved to the database.

I have been asked to look at how to change the existing code so that it can deal with different user 'roles' and have quite happily mocked up an example application with tables like user, role, permission, user-role and role-permission to explain how this would work in practice. I just wonder if any of you have any tips on how to write the permissions into the codebase? Is it wise to simply wrap up the existing code either in the template or in a function into something like:

// $access_type can be the result of a function call, an array value, etc.
switch($access_type){
    case 'edit':
        echo '<input type="text" name="username" value="' . $username . '">';
        break;
    case 'readonly':
        echo $username;
        break;
    case NULL:
    default:
        // Don't display anything.
}

My question is how well does this scale with larger chunks of code? There are a couple of 'interactive features' which use quite a lot of HTML & JavaScript to POST back several values at once. We'd effectively have a seperate version of this custom control for each role. Sticking each version into a switch smells a bit (whether inline code or included as a separate file)... Similarly, on the backend, the script to process the POST would have several versions depending on the role.

I know there must be a hundred ways to do this, but what have other people done in the past? If you have some insight, could you demonstrate it in a procedural style as there is no OO to be seen in this project! Thanks!

+1  A: 

You can use something like:

interface User {
    /* stores several roles */
    /**
     * Combines the permissions of the several roles
     * of the user and returns the result.
     * @return Permission */
    function getPermission($key);
}
interface Role {
    /* stores several permissions */
    /* if there's no record of this kind of this
     * particular permission, return an empty one */
    /** @return Permission */
    function getPermission($key);
}
interface Permission {
    /** @return Permission */
    function combine(array $permissions);
    /** @return bool */
    function canEdit();
    function canRead();
}

and then just do:

/* user factory takes care of creating the instances and
 * wiring them together */
$u = UserFactory::loadCurrentUser();
if ($u->getPermission('admin_page')->canWrite()) {
    //...
}
Artefacto
Hi Artefacto, thanks for your answer. However, I am looking for advice on how to best include the HTML/JavaScript chunks into the if/else or switch code and how to deal with the scenario where the access type 'canWrite()' isn't granular enough - canWrite() returns a boolean whereas I'm looking at a scenario which has the potential to return one of many access types ('edit', 'readonly' and potentially 'constrain_to_8_characters', 'lowercase_only' for example) which will all use different HTML forms and backend validation. Thanks!
Bendos
@Bendos You can achieve that extra granularity by adding extra permissions. For instance, `if ($u->getPermission('admin_page_uppercase_stuff')->canWrite()) { ... }`
Artefacto
@Atrefacto - I'd like to display a different bunch of HTML/JavaScript depending on whether the permission returned `edit`, `readonly` or `lowercase_only`. Would your example work if it were more like `switch($u->getPermission('username')->getEditability()) { ... }` ?
Bendos