任意の場所からログイン中のユーザを取得する

This is a problem that comes up often. Generally you need access to the session to retrieve
information about the logged in user. In the view this is done with the session helper.

これはよく問題になります。一般に、ログイン中のユーザについての情報を取り出すには、セッションにアクセスする必要があります。ビューの中では session ヘルパーを使うことでアクセスできます。

$session->read('Auth.User.id'); 

In the controller you can use the SessionComponent.

コントローラの中では Session コンポーネントを使うことができます。

$this->Session->read('Auth.User.id'); 

But what if you have a model where you need to set a modified user field every time you save? It
would be great if you could handle this automatically in the beforeFilter. You can always cheat
and use the $_SESSION superglobal, but that’s not very Cakey. Plus, now we are using three
different methods depending on the part of the app we’re in.

しかしもしあるモデルを保存するたびに、どのユーザが修正を行ったのかをフィールドに設定する必要があるとしたらどうでしょうか。できることならその操作を beforeFilter の中で自動的に行うことができれば良いのですが[モデルから直接セッションにアクセスする方法がないのでできません]。ズルをしてスーパーグローバル変数 $_SESSION を使うことはいつでもできますが、それはあまりCake的なやり方ではありません。そのうえ、[モデルの中からどうセッションにアクセスするにせよ]アプリケーションの[モデル、ビュー、コントローラの]どの部分[の開発を行っているか]に応じて3種類の異なる方法を使い分けている[のも問題です]。

How awesome would it be if you could just call User::get(‘id’) from anywhere? On a scale of
0%-100%, that’s like 82% awesome, right?

もし仮に、任意の場所から、ただ User::get(‘id’) を呼ぶだけで良いとしたら、どんなに素晴らしいことでしょう。0〜100%で言ったら82%くらいは素晴らしいと思いませんか?

The User Model
User モデル

Here’s how to do it. First you need a User model, which you probably already have. This code is
a little misplaced among the rest of the User model code, but for the User::get syntax to work it
has to go in the model. Deal with it.

これが[これから述べるのが]その方法です。まずは User モデルが必要ですが、きっとあなたは既に持っていることでしょう。この[項で紹介する]コードは、User モデルの他のコードの間に置くには少し場違いなのですが、User::get という構文で動くようにするためにはモデルの中に入れておかなければいけません。我慢してください。

The first thing you’ll need is a way to get a singleton instance of your user instance.

まず最初に、ユーザの唯一のインスタンスを得る方法が必要になるでしょう。

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]; 
} 

This method will be used internally to store and retrieve the user’s information. Don’t worry if you
don’t understand what’s going on here. Just trust that it works.

このメソッドはユーザ情報を格納したり取り出したりするために、内部的に使用されます。もしここで何が起こっているのか理解できなくても心配はいりません。動くということを信頼してください。

Before you can access the user info you need to store the user in the static instance. The method
“set” is already taken by Cake’s base Model class so we’ll use “store”. The store method is very
simple:

ユーザ情報にアクセスする前に、ユーザを静的なインスタンスに格納しておく必要があります。”set” メソッドは既に Cake の Model 基底クラスに取られてしまっているので、”store” を使うことにします。store メソッドはとても単純です。

function store($user) { 
  User::getInstance($user); 
} 

In The AppController
AppController の中で

The User::store method is used in the AppController BeforeFilter.

User::store メソッドは AppController の BeforeFilter の中で使用されます。

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

The logged in user is pulled from the AuthComponent and passed as a parameter to the store
method. If you’re not using the AuthComponent you can substitute whatever half-assed, cobbled-
together authentication system you’re using. You just need to pass in the user information as an
array.

ログイン中のユーザを AuthComponent から引き出して store メソッドの引数として渡します。もし AuthComponent を使っていないのなら、あなたが使っている認証システムに置き換えてください。そのシステムがどんなにいい加減で急ごしらえであっても置き換えることができます。単にユーザ情報を配列として渡すだけだからです。

Back to the User Model
User モデルに戻って

The User::get method can then be used to get the instance and pull out a specific piece of
information from the user array.

これで User::get メソッドを使用できます。User::get メソッドはユーザのインスタンスを取得して、配列から特定の一部分を取り出します。

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]; 
} 

Usage
使い方

To get the currently logged in user’s id:

現在ログイン中のユーザのidを得るには:

User::get('id'); 

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

現在ログイン中のユーザのユーザ名(users テーブルには username フィールドがあると仮定します)を得るには:

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');  

What About The Configure Class?
Configure クラスはどうなの?

Some of this code will look familiar to those of you who have dug around in the Cake core. That’s
because it’s blatantly stolen inspired by the Configure class. Obviously, you could skip all the
user setup and just use Configure like this:

Cake のコアを丹念に調べた経験がある人なら、このコードのいくらかは見覚えがあるでしょう。それは Configure クラスから露骨にパクったインスパイアされたものだからです。だからもちろん、ユーザのセットアップを全て省いて単に Configure を使うこともできます。こんな感じで:

//in the AppController 
Configure::write('User', $this->Auth->user()); 
//from anywhere else 
Configure::read('User.id'); 

It’s not awful, but the syntax isn’t as appealing. But, wait. Why not just use the same setup for
User, but have it wrap calls to Configure. Then User doesn’t have to bother getting the static
instance of itself and you get the cooler User::get() syntax. Again, certainly an option. I
wouldn’t hold it against you if you did it that way. However sticking the logged in user in the
Configure class is a bit misplaced. It’s not “end of the world” bad to do it this way. More like “shit,
I just dropped my iPod in the toilet” bad.

悪くはありませんが、構文は見劣りします。でも待って。なぜユーザに対して同じセットアップを行って、Configure に対する呼び出しを覆ってしまわないのでしょうか?そうすれば User はわざわざ自分自身の静的なインスタンスを取得する必要はなくなりますし、より格好の良い User::get() 形式の構文も使えるようになります。改めて言いますが、確かにそれも一つの選択肢です。もしあなたがその方法をとったとしても非難するつもりはありません。しかしログイン中のユーザを Configure クラスに突っ込んでおくのは、いささか場違いというものです。その方法をとるのは「世も末」というほど悪くはありません。「くそっ、iPodをトイレに落としてしまった!」くらいの悪さです。

Really it’s a personal decision that each developer will need to search deep withing their
programmer souls to find the solution that fits them best.

それは本当に個人的な判断によるものなのです。最適な答えを見つけ出すには開発者それぞれが自分のプログラマー魂の中を深く探索する必要があります。

Full Source
完全なソース

Here is the full source, which is also available on GitHub.

これが完全なソースコードです。GitHubからも入手できます。

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(); 
  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]; 
} 

著作権およびライセンスについては表紙を参照してください。

Leave a Reply