2

I'm writing my first real MVC-application with PHP. I'm not using a framework because my application is so small that I figured it would be faster to write everything from scratch.

In my app, users can register, login and then write/edit/delete content. Each piece of content references its owner by a userid-column in the database.

I am now about to implement user access restrictions (in the sense that users can only view/edit/delete their OWN content/items/models). I'm wondering where the check for "valid access" should happen and where user-objects are instantiated.

I mean, I definitely need information about the current user in controllers, models and views. So I'm thinking if it's viable to have a global user object (defined in index.php) that stores all the user information so I could access it comfortably from each part of my application.

At the moment, this snippet grants my controllers access to user information which I then also store in the data-array that is passed to the view:

class Controller {
    protected $data, $id, $user;
    public function __construct($action = null, $data = null) {
        if (User::isLoggedIn()) {
            $this->user = new User($_SESSION['user']);
            $this->data['user'] = $this->user;
        }
    }
}

Following this pattern, I'd have to pass on user information to each model I create or alternatively have them instantiate their own user-object.

What is the way to go here? Global user object, instantiation in each model or passing the user-object as a parameter to models and views?

Thank you for your help!

PeeHaa
  • 71,436
  • 58
  • 190
  • 262
Macks
  • 1,696
  • 5
  • 23
  • 38
  • 4
    Regarding ACL you may find this post interesting: http://stackoverflow.com/questions/3430181/acl-implementation/9685039#9685039 – PeeHaa Dec 11 '12 at 22:03
  • Hey PeeHaa! Thanks for the link. That was definitely an interesting read even though I don't want to get that complex. Now I know that "ACL" is the term I'm looking for. Maybe what I'll do, is build an ACL-class and not use a global user-object (but instantiate it in both model and controller and whenever needed). I'm still not quite sure though if my model needs access to the ACL or if I can manage all user access from my controller. – Macks Dec 11 '12 at 23:20
  • 2
    Globals *bad*. [Dependency Injection](http://en.wikipedia.org/wiki/Dependency_injection) *good*. Tightly-coupled code may be easier to write, but it's harder to maintain. Loosely-coupled code is harder to write and conceptualize, but can be amazingly easier to work with in the long-run. (Bonus points if you can name the prehistoric internet meme I just conjured up.) – Charles Dec 11 '12 at 23:21
  • Hey Charles! Thank you for your comment. I agree. I'm pretty sure your comment was aimed at the consideration of a global user-object. I'll definitely not be going that way. However I'm still not quite sure if my model needs access to the ACL or if I can manage all user access from my controller. – Macks Dec 11 '12 at 23:33

1 Answers1

5

There are several things to note here. Firstly: "I then also store in the data-array that is passed to the view:"

In MVC, the view has direct access to the model, see my answer here How is MVC supposed to work in CodeIgniter for an overview of that.

Secondly, your question is really about Dependency Management. Globals (and by extension statics) are problematic ( Make all variables global, PHP , Are global variables bad? , Static methods or not? ). The preferred method is passing the fully-constructed $user object into class which requires it.

class Controller {
    protected $data, $id, $user;
    public function __construct(User $user) {
        if ($user->isLoggedIn()) {
    //...
       }
    }
}

However, in this case you can't have a fully-constructed user object because you need to know whether the user is logged in prior to constructing the object so pass a mapper, factory or DAO object into the constructor and create the user as needed.

class Controller {
    protected $data, $id, $user;
    public function __construct(DataMapper $userMapper) {
        if (isset($_SESSION['user'])) {
    $user = $userMapper->find($_SESSION['user']);
       }
    }
}

Finally, however, if you take my first point, that Views can access their model directly and don't get passed data by their controller, then your controller may not even need to know whether the user is logged in. This is, after all, domain logic so belongs in the model.

Community
  • 1
  • 1
Tom B
  • 2,735
  • 2
  • 24
  • 30
  • Hi Tom! Thank you very much for your well-written response. Regarding the "MVC vs. PAC"-issue: my views do access the models directly, they are just "loaded" into an array by the controller. So if a user wants to edit links, then the controller loads the corresponding view and passes it an array of link-models. Does that count as MVC? Regarding dependency management: it makes sense that I should avoid using global variables and such as much as possible. However, I don't really understand how your second code sample differentiates that much from my own code sample. – Macks Dec 12 '12 at 14:07