Adminによるユーザープロフィールの操作

FuelPHPで会員管理(アプリ編その8)

前回までは、ユーザー個人によるプロフィールの作成・更新・削除方法を調べてきましたが、今日は、Adminによる各ユーザーのプロフィールの作成や更新・削除方法を調べてみたいと思います。

テーマクラスのデータの受け渡し方法

1. 本題に入る前に、以前テーマクラスでコントローラからビューファイルへデータを渡せない(渡す方法が分からない)と記述しましたが、テーマクラスで、ビューへのデータを渡す方法が分かりましたので、お知らせいたします。下記に詳細ページのdetailアクションでビューファイルへデータを受け渡してみます。

app/classes/controller/user/admin.php

/*****************************************
 * 明細ページの表示
 *****************************************/
 public function action_detail(){
 //セッションにユーザーのidをセットする
 Session::set('member_id',Uri::segment(4));
 //個人データを取得
 $data['user']=Model_Admin::find('first',array(
 'where'=>array('id'=>Uri::segment(4))));
 //groupデータを取得
 $data['group']=Model_Admin::config_groups();
 //テーマのインスタンス化
 $theme=\Theme::forge();
 //テーマにテンプレートのセット
 $theme->set_template('template');
 //テーマのテンプレートにタイトルをセット
 $theme->get_template()->set('title','Winroad管理室');
 //テーマのテンプレートにサイドバーをセット
 $theme->get_template()->set('sidebar',$theme->view('user/admin/profile/sidebar'));
 //ビューにデータのセット
 $view=$theme->view('user/admin/detail',$data);
 //テーマのテンプレートにcontentとビューをセット
 $theme->get_template()->set('content',$view);
 return $theme;
 }

分かってみれば、きわめて簡単でした。先にテーマのビューにデータを渡して(21行目)、その渡したビューをテーマのテンプレートに読み込む(23行目)だけでした(^0^)。 ※私が間違えていたのは、テーマのビューにデータを渡す($theme->view)のではなく、View::forgeメソッドでビューにデータを渡して、それを読み込もうとしていました(>_<)。

これで、データを渡したビューファイルで、$userで個人データの配列を取得できますし、$user->usernameや$user[‘username’]でユーザー名を取得することが出来ます。又、$groupでConfigファイルSimpleAuthのgroups配列を取得することが出来ます。

2. 只、controllerからビューへのデータの受け渡し方法が分かったからと言って、毎回こんな長いコードを書くのは面倒ですので、やはりモデル内にテーマを呼び出すメソッドは作成しておいた方がいいと思います。尚、テーマを呼び出すメソッドを若干修正しましたので、下記に記述しておきます。

app/classes/model/admin.php

/*************************************
 * Admin用基本テーマ
 *************************************/
 public static function theme($content,$template='template'){
 //全ユーザー情報の取得
 $data=Model_Admin::pagedata();
 //SimpleAuthのConfig.groups情報の取得
 $data['group']=Model_Admin::config_groups();
 //テーマのインスタンス化
 $theme=\Theme::forge();
 //テーマにテンプレートのセット
 $theme->set_template($template);
 //テーマのテンプレートにタイトルをセット
 $theme->get_template()->set('title','Winroad管理室');
 //ビューにデータのセット
 $view=$theme->view($content,$data);
 //テーマのテンプレートにcontentとデータをセット
 $theme->get_template()->set('content',$view);
 return $theme;
 }

 /***************************************
 * プロフィール表示用テーマ
 ***************************************/ 
 public static function profile_theme($content,$template='template'){
 //個人ユーザー情報の取得
 $data['user']=Model_Admin::find('first',array(
 'where'=>array('id'=>Session::get('member_id'))));
 //プロフィールの配列取得(アンシリアライズ処理)
 $data['profile']=unserialize(Model_Admin::find('first',array(
 'where'=>array('id'=>Session::get('member_id'))))->profile_fields);

 //テーマのインスタンス化
 $theme=\Theme::forge();
 //テーマにテンプレートのセット
 $theme->set_template($template);
 //テーマのテンプレートにタイトルをセット
 $theme->get_template()->set('title','Winroad管理室');
 //テーマのテンプレートにsidebarをセット
 $theme->get_template()->set('sidebar',$theme->view('user/admin/profile/sidebar'));
 //ビューにデータをセット($user,$profile)
 $view=$theme->view($content,$data);
 //テーマのcontentにビューをセット
 $theme->get_template()->set('content',$view);
 return $theme;
 }

27~28行目の個人データの取得ですが、ユーザーの特定にセッションを使います。個人を選択するページで選択する個人のIDをSession::setメソッドでセットします。これでセッションをリセットするまで、個人のIDはSession::getメソッドで取得することが出来ます。

※尚、themeメソッドの第2引数のテンプレートの指定ですが、毎回同じテンプレートを使うのなら別に指定する必要も無いのでは無いかとの考えもありますが、これはコントローラ内のプログラムで変更できるように引数指定してあります。たとえばボタンのワンクリックで簡単にテンプレートを変更することも出来ますし、他にも面白い使い方が出来るかなと思い、第2引数に残してあります。ただ、それ以外の時に毎回’template’と指定するのは面倒ですので、初期値を指定することにしました。

3. ビューファイルdetai.phpを下記に記述します。

app/views/user/admin/detail.php

<div class="span10">
 <h3><?php echo Session::get_flash('success',$user['username'].'さんの明細');?></h3>
 <table class="table table-bordered table-striped">
 <thead>
 <tr>
 <th>項目</th>
 <th>内容</th>
 </tr>
 </thead>
 <tbody>
 <tr>
 <th>ID</th>
 <td><?php echo $user->id;?></td>
 </tr>
 <tr>
 <th>ユーザ名</th>
 <td><?php echo $user->username;?></td>
 </tr>
 <tr>
 <th>Eメール</th>
 <td><?php echo $user->email;?></td>
 </tr>
 <tr>
 <th>所属グループ</th>
 <td><?php echo $group[$user->group];?></td>
 </tr>
 <tr>
 <th>最終ログイン</th>
 <td><?php echo $user->last_login>0 ? date('Y/m/d',$user->last_login) : '';?></td>
 </tr>
 <tr>
 <th>作成日</th>
 <td><?php echo date('Y/m/d',$user->created_at);?></td>
 </tr>
 <tr>
 <th>更新日</th>
 <td><?php echo $user->updated_at>0 ? date('Y/m/d',$user->updated_at) : '';?></td>
 </tr>
 <tr>
 <th><?php echo Html::anchor('user/admin/profile','プロフィール')?></th>
 <td><?php echo $user->profile_fields;?>
 </td>
 </tr>
 </tbody>
 </table>
 </div>

生年月日の西暦・元号両対応入力フォーム

4. 『基本プロフィールの作成と表示』では、生年月日の入力は直接生年月日を文字入力するようにしていましたが、どうせなら、西暦・元号の両対応の入力フォームを作成しようと思いましたので、下記のように作成しました。FuelPHPとは余り関係ないかもしれませんが、よろしかったら参考にして下さい。

5. まず、生年月日入力用のビューファイルを下記のように作成します。

app/views/user/admin/profile/base.php

<?php $birth=Model_Admin::gengo($profile? $profile['生年月日']:'');?>
<div class="span7 hero-unit">
<h2 style="text-align:center"><?php echo Asset::img('winlogo.png');?></h2><br>
<h3 style="text-align:center"><?php echo $user['username']." さんの基本プロフィール";?></h3>
<?php echo Form::open(array('name'=>'pfofile','method'=>'post','class'=>'form-horizontal')); ?>
<?php echo '<div class="alert-error"><p>'.Session::get_flash('error').'</p></div>'?>
<div class="control-group">
 <label class="control-label" for="address">住所</label>
 <div class="controls">
 <?php echo Form::input('address',$profile ? $profile['住所']:'');?>
 </div>
</div>
<div class="control-group">
<label class="control-label" for="sex">性別</label>
<div class="controls">
<div class="span1">男性&nbsp;<?php echo Form::radio('sex','男性',$profile&&$profile['性別']=='男性' ? array('checked'=>'checked') : '');?></div>
<div class="span1">女性&nbsp;<?php echo Form::radio('sex','女性',$profile&&$profile['性別']=='女性' ? array('checked'=>'checked') : '');?></div>
</div>
</div>
<div class="control-group">
 <label class="control-label" for="birthday">生年月日</label>
 <div class="controls">
<div class="span1">西暦&nbsp;<?php echo Form::radio('gengo','西暦',$birth['gengo']=='西暦' ? array('checked'=>'checked') : '');?></div>
<div class="span1">大正&nbsp;<?php echo Form::radio('gengo','大正',$birth['gengo']=='大正' ? array('checked'=>'checked') : '');?></div>
<div class="span1">昭和&nbsp;<?php echo Form::radio('gengo','昭和',$birth['gengo']=='昭和' ? array('checked'=>'checked') : '');?></div>
<div class="span1">平成&nbsp;<?php echo Form::radio('gengo','平成',$birth['gengo']=='平成' ? array('checked'=>'checked') : '');?></div>
</div>
</div>
<div class="control-group">
<div class="controls">
 <?php echo Form::input('year',$birth['year'],array('class'=>'span1'));?>年
 <?php echo Form::input('month',$birth['month'],array('class'=>'span1'));?>月
 <?php echo Form::input('day',$birth['day'],array('class'=>'span1'));?>日
 </div>
 </div>
<?php echo Form::submit('submit','送信',array('class' => 'btn btn-primary btn-large span7'));?>
<?php echo Form::close();?>
</div><!--/span7-->

6. profileコントローラのbaseアクションを下記のように記述します。

app/classes/controller/user/admin/profile.php

/************************
 * profileの基本項目作成
 ************************/

 public function action_base(){
 //POST送信なら
 if(Input::method() == 'POST'){
 //バリデーションの初期化
 $val = Validation::forge();
 //バリデーションフィールドの追加
 $val->add_field('address', '住所', 'required|max_length[255]');
 $val->add_field('sex', '性別', 'required');
 $val->add_field('gengo', '元号', 'required');
 $val->add_field('year', '年', 'required');
 $val->add_field('month', '月', 'required');
 $val->add_field('day', '日', 'required');
 //バリデーションOKなら
 if($val->run())
 {
 //受信データの整理
 $address=Input::post('address');
 $sex=Input::post('sex');
 $gengo=Input::post('gengo');
 $year=Input::post('year');
 $month=Input::post('month');
 $day=Input::post('day');
 $birthday=Model_Admin::seireki($gengo,$year,$month,$day);
 //ユーザーの特定
 $id=Session::get('member_id');
 $user=Model_Admin::find('first',array(
 'where'=>array('id'=>$id)));
 //プロフィールを配列に変換
 $profile=unserialize($user->profile_fields);
 //受信データの整理
 $value=array(
 '住所'=>$address,
 '性別'=>$sex,
 '生年月日'=>$birthday,
 );
 //既存配列に受信した配列をセット
 Arr::set($profile,$value);
 //profile_fieldsにシリアライズしたデータをセット
 $user->profile_fields=serialize($profile);
 $user->save();
 //プロフィールページへ移動
 Response::redirect('user/admin/profile');
 }
 //バリデーションNGなら
 Session::set_flash('error', $val->show_errors());
 }
 return Model_Admin::profile_theme('user/admin/profile/base');
 }

27行目のseirekiメソッドは、POSTで受け取った各、元号、年、月、日のデータを西暦の日付に直すために作成しました。詳細は下記のseirkiメソッドをご覧下さい。32行目で取得したprofile_fieldsをunsereialize関数で一端配列に戻します。次に、Arr::setメソッドで新しく受け取った配列$valueを既存の配列$profileにセットします。そしてその$profileをシリアライズ処理して再度user_profile_fieldsにセットしてデータベースに保存します。方法としては、前回行った個人ユーザーのプロフィールの削除と同じです。

7. モデル内に作成したgengoメソッドを下記に記述します。

app/classes/model/admin.php

/********************************
 * 生年月日を元号に変換
 *********************************/

 public static function gengo($date){
 //日付を'/'で区切って変数に変換
 if($date && list($y,$m,$d)=explode('/',$date)){
 if($date >= "1989/01/08"){
 $gengo='平成';
 $y=$y-1988;
 $m=sprintf("%02d",$m);
 $d=sprintf("%02d",$d);
 }
 elseif($date >= "1926/12/25"){
 $gengo='昭和';
 $y=$y-1925;
 $m=sprintf("%02d",$m);
 $d=sprintf("%02d",$d);
 }
 elseif($date >= "1912/07/30"){
 $gengo='大正';
 $y=$y-1911;
 $m=sprintf("%02d",$m);
 $d=sprintf("%02d",$d);
 }
 else{
 $gengo='西暦';
 //$y=$y;
 $m=sprintf("%02d",$m);
 $d=sprintf("%02d",$d);
 }
 return(array('gengo'=>$gengo,'year'=>$y,'month'=>$m,'day'=>$d));
 }
 }

list関数は、1つ以上の変数に配列のインデックスを割り当てます。そして、explode関数は、第1引数で指定した文字で、第2引数の文字列を分割して、配列で返します。つまり、文字列$dateを’/’で区切って作成した配列を変数$y,$m,$dに値を割り当てています。あとは、それぞれ受け取った値$dateがその元号の始まった日付、つまり”1989/01/08″以上なら平成というように元号を確定します。明治も作成しても良かったのですが、実際問題100歳以上の方が会員になられることはほとんど無いので、省略しました。明治も作成したい方は、同様に明治の始まった西暦年月日を調べて、作成して下さい。そして最後に、”1912/07/30″以前に関しては、全て西暦として統一しました。

8. seirekiメソッドを下記に記述します。

app/classes/model/admin.php

/********************************
 * 生年月日を西暦に変換
 *********************************/

 public static function seireki($gengo,$y,$m,$d){
 if($gengo == '平成'){
 $y=$y+1988; 
 }
 elseif($gengo =='昭和'){
 $y=$y+1925;
 }
 elseif($gengo == '大正'){
 $y=$y+1911; 
 }
 return sprintf("%04d/%02d/%02d",$y,$m,$d);
 }

 生年月日を元号に変換するメソッドはきわめて簡単です。受け取った第1引数の文字が平成なら第2引数の数字に1988をプラス、昭和なら1925をプラス、大正なら1911をプラスして、sprintf関数でフォーマットした文字列を返します。

9. 入力した生年月日は、西暦でprofile_fieldsに保存されています。

10. また、西暦で入力されたデータも再入力(修正)するときは、元号で変換されて表示します。

Adminによるユーザープロフィールの操作

11. さて、前置きが長かったですが、Adminによる各会員(ユーザー)のプロフィールを操作する方法を調べてみたいと思います。

12. 前回も言ったように、SimpleAuthの各メソッドは、現在アクセス中のユーザーを処理するためのメソッドがほとんどです。そこで、Adminが特定のユーザーを操作するためには、Sessionによるデータの引き渡しが一番効率がいいと思います。Uri::segmentメソッドによるユーザー情報の受け渡しは、各ビューファイルが同じ階層にある場合はいいのですが、メニューバーなどで階層の違うページへ移動するときなどにsegmentの位置が変わる場合があります。

13. そこで、操作するユーザーを特定する箇所を1カ所にして、その時点で、Session::setメソッドで、セッションにデータをセットし、現在処理中のユーザーをSession::getメソッドで特定するようにすれば、いくらページが変わっても、セッションをセットし直さない限り、選択中のユーザーは変更されることはありません。

14. それでは、先程のaction_base以外のアクションを下記に記述しておきます。

app/classes/controller/user/admin/profile.php

<?php
/************************************
 * Admin操作用のプロフィール
 ************************************/ 
class Controller_User_Admin_Profile extends Controller{

 /**********************************
 * before(アクセス管理)アクション
 **********************************/
 public function before(){
 parent::before();
 //ログインしていなければ
 if(!Auth::check()){
 //ログインページへ移動
 Response::redirect('user/login');
 //ログインしていてもAdminでなければ
 }elseif(!Auth::member(100)){
 //user/indexページへ移動
 Response::redirect('user/index');
 }
 }

 /**********************************
 * Topページ
 **********************************/
 public function action_index(){
 //テーマの表示
 return Model_Admin::profile_theme('user/admin/profile/index');
 }

 /************************
 * profileの新規項目追加
 ************************/

 public function action_create(){
 //POST送信なら
 if(Input::method()=='POST'){
 //受信データの整理
 $key=Input::post('key');
 $value=Input::post('value');
 //バリデーションの初期化
 $val=Validation::forge();
 //バリデーションフィールドの追加
 $val->add_field('key','新規項目名','required');
 $val->add_field('value','データ内容','required');
 //バリデーションOKなら
 if($val->run()){
 //ユーザーの特定
 $user=Model_Admin::find('first',array(
 'where'=>array('id'=>Session::get('member_id'))));
 //既存プロフィールを配列で取得(アンシリアライズ処理)
 $profile=unserialize($user->profile_fields);
 //新しいプロフィールの整理
 $new_profile=array($key=>$value);
 //既存のプロフィールに新しいプロフィールを追加
 Arr::set($profile,$new_profile);
 //プロフィールをシリアライズ処理
 $user->profile_fields=serialize($profile);
 $user->save();
 //プロフィールのトップページへ移動
 Response::redirect('user/admin/profile');
 }
 //バリデーションNGなら
 Session::set_flash('error',$val->show_errors());
 } 

 //テーマの表示
 return Model_Admin::profile_theme('user/admin/profile/create');
 }

 /************************
 * profileの項目修正
 ************************/

 public function action_edit(){
 //POST送信なら
 if(Input::method()=='POST'){
 //受信データの整理
 $key=Input::post('key');
 $value=Input::post('value');
 //バリデーションの初期化
 $val=Validation::forge();
 //バリデーションフィールドの追加
 $val->add_field('value','データ内容','required');
 //バリデーションOKなら
 if($val->run()){
 //ユーザーの特定
 $user=Model_Admin::find('first',array(
 'where'=>array('id'=>Session::get('member_id'))));
 //既存プロフィールを配列で取得(アンシリアライズ処理)
 $profile=unserialize($user->profile_fields);
 //修正プロフィールの整理
 $edit=array($key=>$value);
 //既存のプロフィールを修正プロフィールで変更
 Arr::set($profile,$edit);
 //プロフィールをシリアライズ処理
 $user->profile_fields=serialize($profile);
 $user->save();
 //プロフィールのトップへ移動
 Response::redirect('user/admin/profile');
 }
 //バリデーションNGなら
 Session::set_flash('error',$val->show_errors());
 }
 //テーマの表示
 return Model_Admin::profile_theme('user/admin/profile/edit');
 }

 /************************
 * profileの項目削除
 ************************/

 public function action_delete(){
 //POST送信なら
 if(Input::method()=='POST'){
 //受信データの整理
 $key=Input::post('key');
 //ユーザの特定
 $user=Model_User::find('first',array(
 'where'=>array('id'=>Session::get('member_id'))));
 //既存プロフィールを配列で取得(アンシリアライズ処理)
 $profile=unserialize($user->profile_fields);
 //既存プロフィールから受信データをキーとする配列を削除
 Arr::delete($profile,$key);
 //profile_fieldsにシリアライズ処理した新しい$profileを渡す
 $user->profile_fields=serialize($profile);
 //データベースを保存
 $user->save();
 //プロフィールのトップページへ移動
 Response::redirect('user/admin/profile');
 }
 //テーマの表示
 return Model_Admin::profile_theme('user/admin/profile/delete');
 }
}

説明を端折りすぎかもしれませんが、ポイントは、シリアライズ処理、アンシリアライズ処理を自分自身で施して、配列の作成、修正、削除を直接データベース更新することにより実行すると言うことです。

15. これで、『FuelPHPで会員管理(アプリ編)』は終了します。後は、ご自身のニーズにあった会員管理プログラムを作成して下さい。

16. 現在、今までPHPで作成していた社内専用サイトをFuelPHPで作成し直そうと悪戦苦闘中です。もし、皆様にご紹介できるプログラムがありましたら、記事にしてご紹介いたしたいと思います。というか、私のメモ用に記事を書くと思いますが(^0^)。

本日は以上です。

 お詫び

坂本様からご指摘がありましたので、お詫びいたします。途中途中のプログラム記事で後から作成しようと思ったページのリンクなどを先に作成しておき、後からそのリンク先について触れずに終わっている箇所が何カ所かあります。お詫びいたします。

私としては作成過程やどのように作成しようと思ったのかという考え方も皆様に見ていただきたくて(というよりも私の覚え書きという方が正しいかもしれませんが)、このブログを書いております。ですので、途中で計画変更になり以前のブログ記事と整合性のとれていない箇所も何カ所かあります(ご指摘や間違いに気づいた箇所は早急に修正して参ります)。

極力気をつけたいとは思いますが、今後も記述ミスや尻切れトンボになる記事もあるかもしれませんが、温かい目で見守っていただければ幸いです。

2012/11/16 WinRoad徒然草管理人 中田

このエントリーを含むはてなブックマーク Buzzurlにブックマーク livedoorクリップ Yahoo!ブックマークに登録

トラックバック&コメント

この投稿のトラックバックURL:

コメントをどうぞ

このページの先頭へ