第9章 プロフィール編集機能

本章から読み始める方へ:

本章から読み始める方のために以下に前章までの成果物をダウンロードできるように準備しています。こちらから以下の3つのファイルをダウンロードしてください。

  • htdocs-chap8.zip
  • user.sql
  • bbs.sql

htdocs-chap8.zipは展開したあと中身をすべてC:\xampp\htdocsにコピーしてください。またMySQL上に空っぽのyiiという名前のデータベースを作り、そこに上記のuser.sqlとbbs.sqlをインポートしてください。xamppをインストールするとphpmyadminもインストールされているはずなので、そこにログインしてインポートから上記2ファイルを取り込んで頂ければ大丈夫です。

またyiiの設定ファイルを一部いじっていただく必要があります。c:\xampp\protected\config\main.phpを開いて42行目あたりのメール送信機能の設定の部分を御覧ください。

		// chap7: メール送信ライブラリを追加
		'mailer'=>array(
    			'class' => 'application.extensions.mailer.EMailer',
			    'From' => 'yii.juncheng@gmail.com', // 送信者のアドレス
			    'FromName' => 'yii-juncheng',// 名前
			    'CharSet' => 'iso-2022-jp',  //文字コード
			    'Encoding' => '7bit',
			    'Mailer'=>'smtp',
			    'Port'=>'587',
			    'SMTPSecure'=>'tls',
			    'Host'=> 'smtp.gmail.com',
			    'SMTPAuth' => true,
			    'Username' => 'xxxx@gmail.com', // gmailのメールアドレスがユーザ名となる
			    'Password' => 'xxxx',                // ここにGmailのアドレスを入力する
		),
  •  Username
  • Password

の部分をご自身がお持ちのGmailのアカウントの情報に書き換えてください。もちろん分かる人はGmail以外のメールアカウントでも構いません。

また本書ではMySQLのrootのパスワードをunko9314、データベース名をyiiと設定していますが、それ以外の設定を行っている人がいれば、同様に上記のファイルから該当の設定箇所が73行目あたりにあるのでご自身の設定に変えてください。


 メニューにプロフィール編集画面へのリンクを追加する

毎度おなじみですが、protected/views/layouts/main.php を開いてプロフィール編集画面へのリンクを追加します。今回はログインした場合にのみ表示されるためvisibleの部分にゲストではないという条件を追加します。またリンクのURLは/user/profileとします。そのため後ほどUserController.phpactionProfileというメソッドを追加していくこととなります。

	<div id="mainmenu">
		<?php $this->widget('zii.widgets.CMenu',array(
			'items'=>array(
				           array('label'=>'ホーム', 'url'=>array('/site/index')),
				           array('label'=>'当サイトについて', 'url'=>array('/site/page', 'view'=>'about')),
           				array('label'=>'お問い合わせ', 'url'=>array('/site/contact')),
				           array('label'=>'ユーザ登録','url'=>array('/site/registration'),'visible'=>Yii::app()->user->isGuest),
				           array('label'=>'メッセージ閲覧','url'=>array('/site/bbs'),), // chap8
				           array('label'=>'メッセージ投稿','url'=>array('/user/bbs'),'visible'=>Yii::app()->user->isUser), // chap8
				           array('label'=>'プロフィール編集', 'url'=>array('/user/profile'), 'visible'=>!Yii::app()->user->isGuest), // chap9
				           array('label'=>'ログイン', 'url'=>array('/site/login'), 'visible'=>Yii::app()->user->isGuest),
				           array('label'=>'ログアウト', 'url'=>array('/site/logout'), 'visible'=>!Yii::app()->user->isGuest)
			),
		)); ?>
	</div>

以下のように無事にリンクが追加されました。(ログイン時)

chap9-1

 


プロフィール編集のためのUserモデルの修正

さて本章ではプロフィールの編集機能を追加していきます。この章で行う改造の仕様として、

  • メールアドレス (email)
  • 名前(name)
  • パスワード(password)

の3つが変更できるようにします。

今回は、プロフィール編集用のフォームのためのモデルを新たに定義するということは行わず、そのまま現在のUserのモデルを改造していくことにします。

今回のプロフィール編集用のフォームには、メールアドレス、名前、パスワードの3つの入力欄が出現します。ただし今までにも述べたように、パスワードは暗号化されて保存されており、元の生のパスワードが何か分からない状態になっています。そこでパスワードのフォームの扱いとしては、パスワードを変更するときのみ入力してください・・・というスタンスにします。

そこで、その新規パスワードに対する入力は、User(モデル)passwordに直接格納されるという流れではなく、一旦newPasswordという別のプロパティを作ってそこに入力を受けるようにします。そこで以下のように、User.phpモデルファイルにnewPasswordというプロパティを追加します。

class User extends CActiveRecord
{
    	// chap9: プロフィール編集用のフォーム追加データ
	    public $newPassword;

次にUser.phprules()の中に以下の行を追加します。この中のnewPasswordCheckは、自分で定義するメソッドです。newPasswordに入力される値は、newPasswordCheckのメソッドで定義された検査内容を通過する必要があります。

			// chap9: 新しいパスワード
			array('newPassword','newPasswordCheck'), // newPasswordCheckメソッドにて記述

そしてnewPasswordCheckのメソッドは以下のように定義します。

	/**
	 * chap9: 新しいパスワードチェック用の独自ルール
	 */
	public function newPasswordCheck($attribute,$params) {
		    if(strlen($this->$attribute) > 0) { // $this->newPassword と同じ
			        if(!preg_match('/^[a-zA-Z0-9]{6,12}$/', $this->$attribute)) {
				            $this->addError($attribute, 'パスワードは半角英数字で6から12文字で入力してください');
        			}
	    	}
	}

この関数の意味は「もし新しいパスワードに何かが入力されて、なおかつ、それが半角英数字の6文字~12文字でなければ、検査エラーとみなす」ということです。

また、新しいパスワードが入力された場合は、それがvalidation (入力データのチェック)を通過したのちに、それが実際のパスワードに反映されなければなりません。それを自動で行うために、以下のようなメソッドを追加します。

	/*
	 * chap9: saveの前処理
	 */
	protected function beforeSave() {
    		// newPasswordに入力があれば
		    if(strlen($this->newPassword) > 0) $this->password = sha1($this->newPassword);
    		return parent::beforeSave();
	}

beforeSave()の関数は文字通り、データベースの内容を更新する直前に実行されるメソッドです。ここでは、もし新しいパスワード(newPassword)が入力されていた場合は、それを暗号化して、passwordに代入するという処理を行っています。

最後にnewPasswordのラベル名をattributeLabels()のメソッド内に追記しておきましょう。

	/**
	 * @return array customized attribute labels (name=>label)
	 */
	public function attributeLabels()
	{
		    return array(
			        'id' => 'ID',
			        'email' => 'Email',
			        'name' => 'Name',
			        'password'=> 'Password', // passwordを追加
			        'role' => 'Role', // roleを追加
			        'vcode' => 'Validation Code', // chap7: 認証コード
			        'valid' => 'Valid User', // chap7: 認証済みかどうか
			        'newPassword' => 'New Password', // chap9: 新しいパスワード
		    );
	}

 

次にnameの処理に関して、少し編集を加えます。もし悪意のあるユーザによって、有害なHTMLコードが入力されても大丈夫なように、validation(入力データのチェック)を行う前に自動的に、タグを除去するような処理を追記します。これは前の章にも出てきたbeforeValidateの関数に定義します。

	/*
	 * chap9: validationの前処理
	 */
	protected function beforeValidate() {
    		// 名前のHTMLコードの有害な文字を除去する
		    $this->name = htmlspecialchars($this->name,ENT_QUOTES);
    		return parent::beforeValidate();
	}

 


UserController.phpにプロフィール変更処理を追加

次にコントローラ側(protected/controllers/UserController.php)の編集を行います。actionにprofileという名前のアクションを追加します。

まずはアクセス権の部分にprofileのアクションを追加します。

	// アクセスルール
	public function accessRules()
	{
    	return array(
        		// 一般ユーザに対して以下に列挙するactionの実行を許可する
        array('allow',
				            'actions'=>array(
                 'index',
				                 'test',
				                 'bbs', // chap8 : メッセージ機能
				                 'profile', // chap9: プロフィール編集機能
				                 ),
				            'expression'=>'$user->isUser',
			        ),
			        // 上記のルールに適合しないすべてのユーザを排除
			        array('deny',
				            'users'=>array('*'), // *: 全ユーザ ?: 匿名ユーザ @: 認証済みのユーザ
			        ),
    		);
	}

次にそれに対応するメソッド:actionProfile()を以下のように定義します。ソースコードの細かい点については、下記で改めて説明します。またビューファイルはprotected/views/user/profile.php になります。

// chap9: プロフィールの編集機能
public function actionProfile() {
 // 更新に成功した場合
 $update = false;
 
 // 自身のユーザデータを取得
 $user = User::model()->findByPk(Yii::app()->user->id);
 
 // ajax
 if(isset($_POST['ajax']) && $_POST['ajax']==='profile-form')
 {
     echo CActiveForm::validate($user);
     Yii::app()->end();
 }
 
 // フォームに対して入力があった場合
 if(isset($_POST['User'])) {
     // ユーザからの入力を処理
     if(isset($_POST['User']['email']))
         $user->email = $_POST['User']['email'];
     if(isset($_POST['User']['name']))
         $user->name = $_POST['User']['name'];
     if(isset($_POST['User']['newPassword']))
         $user->newPassword = $_POST['User']['newPassword'];
 
     // データを保存:
     if($user->validate()) {
         $user->save();
         $update = true;
     }
 }
 
 // フォームviewを表示
 $this->render('profile',array('model'=>$user,'update'=>$update));
}

またビューファイルは上記のソースコードから見ればわかりますが、protected/views/user/profile.php になります。profile.phpの内容は以下のようになります。

<?php
// chap9
$this->pageTitle=Yii::app()->name . ' - プロフィール編集';
$this->breadcrumbs=array(
	'プロフィール編集',
);
?>

<h1>プロフィール編集</h1>

<div class="form">
<?php if($update == true):?>
    <p><font color="red">更新に成功しました</font></p>
<?php endif;?>
<?php $form=$this->beginWidget('CActiveForm', array(
	    'id'=>'profile-form',
	    'enableAjaxValidation'=>true, // ajaxで処理
	    'clientOptions'=>array(
		    'validateOnSubmit'=>true,
	   ),
)); ?>

	<p class="note"><span class="required">*</span>の項目は入力が必須となります</p>
	<p class="note">HTMLタグは自動的に変換されます。</p>

	<?php echo $form->errorSummary($model); ?>

	<div class="row">
		<?php echo $form->labelEx($model,'email'); ?>
		<?php echo $form->textField($model,'email'); ?>
		<?php echo $form->error($model,'email'); ?>
	</div>
	
	<div class="row">
		<?php echo $form->labelEx($model,'name'); ?>
		<?php echo $form->textField($model,'name'); ?>
		<?php echo $form->error($model,'name'); ?>
	</div>

	<div class="row">
		<?php echo $form->labelEx($model,'newPassword'); ?>
		<?php echo $form->textField($model,'newPassword'); ?>
		<?php echo $form->error($model,'newPassword'); ?>
	</div>


	<div class="row buttons">
		<?php echo CHtml::submitButton('プロフィールを編集する'); ?>
	</div>

<?php $this->endWidget(); ?>

</div><!-- form -->

 actionProfile() のメソッドの処理の流れは次のようになっています。

  • ユーザのデータをデータベースから取得します。
  • もしAjax経由のバックグランドの通信であれば、検証を行って、そのまま処理を終了します
  • if(isset($_POST[‘User’])) {…} はユーザがフォームに入力して送信した場合の処理だと考えてもらって構いません。入力があればユーザからのデータを$user に格納して、validation (入力データの検査) に合格すれば、データをSaveしてデータベースに反映させるという流れです。
  • なお変数: $update はプロフィール情報の更新に成功したらtrueになり、そのままビューファイルprofile.php に渡されます。profile.php内では$updatetrueになっていた場合に、画面上に赤い文字で「更新に成功しました」 という文字を表示します。

今回の成果物

ダウンロードはこちらからおこなってください。

  • htdocs-chap9.zip はプログラムのソースコードです。xamppのディレクトリ以下のhtdocs内に内容をコピーしてください。
  • user.sqlbbs.sql はデータベースのファイルです。前回からデータベース構造に変化はないので、すでにmysql上に存在している場合は無視しても構いません。