views:

124

answers:

2

What I need to accomplish is a single Application with a single database but multiple accounts (companies), each with multiple users.

The URL convention must be as follows: domain.com/account/controller/action

So ALL controllers are prefixed by the company/account name.

All accounts would share the single database, but each one would need to be able to restrict access to their data.

The question is, how do I implement this? I've thought about implementing some sort of htaccess rewrite where I strip out the first URL parameter (account) and pass as a query string parameter, which would be internally parsed by the app_controller. The challenge, however, is maintaining integrity with all of the links throughout the app. I.e. the cake routing would somehow need to be aware of the account parameter and pass it to all outputted links.

Has anyone accomplished something similar to this before?

A: 

It's perfectly possible to do this (but I've never done it).

I assume you use the standard CakePHP authentication scheme. If so, information about the currently logged in user can be found in the Auth->User array.

Cake expects you to have a users table in your database. You should alter your models to have a belongsTo relationship with the user table (i.e. all tables have a user_id field).

In your models you could probably utilize the afterFind() hook to check that the user_id field matches the currently logged in user and return false if thats not the case. In your controller you should then check all model operations for falseness.

The .htaccess idea is probably not very good. You should put the authorization as close as possible to the data source, in cake that would be in your model (you could put the afterFind callback in the AppModel class).

Extending your example:

User requests /someController/someAction.

someAction:

if($this->someModel->someOperation(someArgument)) {

   //OK, show view

} else {

   // Something went wrong
   // Your afterFind method provides a clue via the model->failure attribute

   $this->flash($this->someModel->failure);

}
matiasf
A: 

You can do two things, both with Routes.

First, setting a variable in the routes:

Router::connect('/:user/blog/*', array('controller' => 'blogs', 'action' => 'index'));

And now you can access the user variable with $this->params['user']. The thing with this is that you will have to manually set each controller and action you want to manage. I think it's no big deal, since most of the times it is better to rewrite the default routes architecture for CakePHP.

Second, you can tell you are waiting for a variable and will be accessible as a parameter in your function.

Router::connect('/(.*)/*', array('controller' => 'blogs', 'action' => 'index'));

In your controller:

function index($a, $b){
    pr($a);
    pr($b);
}

And now you will be getting both vars.

I don't know if it can be made automatically, perhaps rewriting the htaccess could be a good idea.

Hope it helped.

metrobalderas