The latest version of this code can be found at http://github.com/mcurry/cakephp_static_user/

“How do I access the logged in user in a model?” I’ve seen this question a bunch of times. I’ve tried numerous solutions, but never really liking any of them. The guys over at debuggable.com have hinted at a User::get(’id’) method twice, but never revealed the details.

Early Attempts

This question has shown up on the Google Group. Nate (one of the Cake developers) responded:

There are two right ways of doing this. One is to make the session a formal part of your domain model, i.e. model it. This allows it to interact with other models at the model level.

I think I get what Nate is saying here. Make a Session model without a table, set relationships to this model in any other models that may use it (or do I just call it statically?) and (somehow) set the data from your session to the model in app_controller. Assuming I’m understanding this correctly (there’s a good chance I’m not), I wasn’t crazy about this approach. How do you get the session data to the model? How do you set up the relationships when one of the models is tableless?

Nate’s other approach was to set the session/user as a variable in the model with this code in the app_controller:

  function beforeFilter() {
        $this->{$this->modelClass}->setUserState($this->Auth->user());
   }

I used this approach for awhile, but had issues trying to access the user in cases where the model wasn’t the “primary” one. The code above only sets the user state for the one model class, not any related models. You could loop through all relationships recursively to make sure the data is set down the line, but ehhh…

What I’m Using Now

Here’s what I have. It’s not perfect, but it’s the best solution I’ve come up with so far. I liked the “User::get()” syntax used in the debuggable.com posts, so I worked from there. In your User model:

<?php
/*
 * Static methods that can be used to retrieve the logged in user
 * from anywhere
 *
 * Copyright (c) 2008 Matt Curry
 * www.PseudoCoder.com
 * http://github.com/mcurry/cakephp/tree/master/snippets/static_user
 * http://www.pseudocoder.com/archives/2008/10/06/accessing-user-sessions-from-models-or-anywhere-in-cakephp-revealed/
 *
 * @author      Matt Curry <matt@pseudocoder.com>
 * @license     MIT
 *
 */

//in AppController::beforeFilter:
//App::import('Model', 'User');
//User::store($this->Auth->user());

function &getInstance($user=null) {
  static $instance = array();

  if ($user) {
    $instance[0] =& $user;
  }

  if (!$instance) {
    trigger_error(__("User not set.", true), E_USER_WARNING);
    return false;
  }

  return $instance[0];
}

function store($user) {
  if (empty($user)) {
    return false;
  }

  User::getInstance($user);
}

function get($path) {
  $_user =& User::getInstance();

  $path = str_replace('.', '/', $path);
  if (strpos($path, 'User') !== 0) {
    $path = sprintf('User/%s', $path);
  }

  if (strpos($path, '/') !== 0) {
    $path = sprintf('/%s', $path);
  }

  $value = Set::extract($path, $_user);

  if (!$value) {
    return false;
  }

  return $value[0];
}
?>

In AppController, beforeFilter method (assuming you are using the Auth component):

App::import('Model', 'User');
User::store($this->Auth->user());

How It Works

To get the currently logged in user’s id:

User::get('id');

To get the currently logged in user’s username (assuming you have a field “username” in your users table):

User::get('username');

Any other fields in your user table can be retrieved in the same manner. Also if you store related model data in your user session it can be retrieved:

User::get('Model.fieldname');

Issues

To get the “User::get()” syntax to work this block has to be placed in the User model, but it feels slightly misplaced there.

Uses

This has code has come in really handy. I use it a behavior with a beforeSave callback to set the created by user id and modified user id. Likewise you can have a behavior that automatically filters rows for index pages to only show records appropriate for the logged in user. It also works in anywhere in your Cake app. In views you can use this instead of $session->read(’Auth.User.id’).

Update

I missed that Cake already has a Model::set method. To prevent the conflict the method to set the user has been changed to “store”. I also added an App::import in the AppController->beforeFilter to make sure the user model is already included.