初めてPHPのフレームワーク（Yii）を使ってみる　その４

まずは復習を兼ねて、新規会員登録フォームを作ってみます。
その後、UserとUserProfileのバリデーションなどを作り上げてみたいと思います。

***

#新規会員登録フォームを作る
##UserモデルのCRUD実装コードを自動生成する
Giiを使ってUserモデルのCRUD機能を生成する
Gii->Crud Generator->Model ClassにUserを入力してpreview->Generate

##UserモデルのbeforeSave()をオーバーライドする
パスワードはデータベースに登録する前にハッシュをかけるので、beforeSave()をオーバーライドする

```php:User.php
...
	protected function beforeSave() {
		if(parent::beforeSave()) {
			$this->password = CPasswordHelper::hashPassword($this->password);
			return true;
		} else {
			return false;
		}
	}
...
```

##_form.phpの編集とconfirm.phpの作成
特に難しいこともなく、その３のUserProfileと同じように作成、編集する
反復練習大事
ただし_form.phpにはメールアドレスとパスワードの確認入力欄を追加している

```php:/views/user/_form.php
<div class="form">

<?php $form=$this->beginWidget('CActiveForm', array(
	'id'=>'user-form',
	// Please note: When you enable ajax validation, make sure the corresponding
	// controller action is handling ajax validation correctly.
	// There is a call to performAjaxValidation() commented in generated controller code.
	// See class documentation of CActiveForm for details on this.
	'enableAjaxValidation'=>false,
)); ?>

	<p class="note">Fields with <span class="required">*</span> are required.</p>

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

	<div class="row">
		<?php echo $form->labelEx($model,'mailaddr'); ?>
		<?php echo $form->textField($model,'mailaddr',array('size'=>60,'maxlength'=>128)); ?>
		<?php echo $form->error($model,'mailaddr'); ?>
	</div>

	<div class="row">
		<?php echo $form->labelEx($model,'verifymailaddr'); ?>
		<?php echo $form->textField($model,'verifymailaddr',array('size'=>60,'maxlength'=>128)); ?>
		<?php echo $form->error($model,'verifymailaddr'); ?>
	</div>

	<div class="row">
		<?php echo $form->labelEx($model,'password'); ?>
		<?php echo $form->passwordField($model,'password',array('size'=>60,'maxlength'=>32)); ?>
		<?php echo $form->error($model,'password'); ?>
	</div>

	<div class="row">
		<?php echo $form->labelEx($model,'verifypassword'); ?>
		<?php echo $form->passwordField($model,'verifypassword',array('size'=>60,'maxlength'=>32)); ?>
		<?php echo $form->error($model,'verifypassword'); ?>
	</div>

	<div class="row buttons">
		<?php echo CHtml::submitButton('確認画面へ', array('name' => 'confirm')); ?>
	</div>

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

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

```php:/views/user/confirm.php
<?php
/* @var $this UserController */
/* @var $model User */

$this->breadcrumbs=array(
	'Users'=>array('index'),
	$model->id,
);

$this->menu=array(
	array('label'=>'List User', 'url'=>array('index')),
	array('label'=>'Create User', 'url'=>array('create')),
	array('label'=>'Update User', 'url'=>array('update', 'id'=>$model->id)),
	array('label'=>'Delete User', 'url'=>'#', 'linkOptions'=>array('submit'=>array('delete','id'=>$model->id),'confirm'=>'Are you sure you want to delete this item?')),
	array('label'=>'Manage User', 'url'=>array('admin')),
);
?>

<h1>記入内容確認</h1>

<?php $this->widget('zii.widgets.CDetailView', array(
	'data'=>$model,
	'attributes'=>array(
		//'id',
		'mailaddr',
		'password',
		//'auth',
	),
)); ?>
<!-- 以下を追加　-->
<div class="form">
<?php 
echo CHtml::statefulForm();
echo CHtml::submitButton('戻る', array('name' => 'back'));
echo CHtml::submitButton('次へ', array('name' => 'finish'));
?>
</form>
</div>
```

##UserController.phpの編集
同様に、UserController.phpも編集する
変えたところはaccessRules()とactionCreate(),actionUpdate()

```php:/controllers/UserController.php
...

	public function accessRules()
	{
		return array(
			/*array('deny', // ログインしている会員は新規登録できない
				'actions'=>array('create'),
				'users'=>array('@'),
			),*/
			array('allow',  // allow all users to perform 'index' and 'view' actions
				'actions'=>array('create','index','view'),
				'users'=>array('*'),
			),
			array('allow', // allow authenticated user to perform 'create' and 'update' actions
				'actions'=>array('update'),
				'users'=>array('@'),
			),
			array('allow', // allow admin user to perform 'admin' and 'delete' actions
				'actions'=>array('admin','delete'),
				'users'=>array('admin'),
			),
			array('deny',  // deny all users
				'users'=>array('*'),
			),
		);
	}

...

	public function actionCreate()
	{
		$model=new User;

		// Uncomment the following line if AJAX validation is needed
		// $this->performAjaxValidation($model);

		if(isset($_POST['confirm']))
		{
			$model->attributes=$_POST['User'];
			if($model->validate())
			{
				$this->setPageState('create', $_POST['User']);
				$this->render('confirm', compact('model'));
				return;
			}
		} else if(isset($_POST['back']))
		{
			$model->attributes = $this->getPageState('create');
		}
		else if(isset($_POST['finish']))
		{
			$model->attributes = $this->getPageState('create');
			if($model->save()) {
				// ここで今作ったアカウントで自動ログインする
				$id = new UserIdentity($model->mailaddr, $password);
				$id->authenticate();
				if($id->errorCode===UserIdentity::ERROR_NONE) {
					Yii::app()->user->login($id, 0);
				}
				$this->redirect(Yii::app()->baseUrl.'?r=userProfile/create');
			}
		}
		$this->render('create', compact('model'));
	}

	/**
	 * Updates a particular model.
	 * If update is successful, the browser will be redirected to the 'view' page.
	 * @param integer $id the ID of the model to be updated
	 */
	public function actionUpdate()
	{
		$model=$this->loadModel(Yii::app()->user->id);

		// Uncomment the following line if AJAX validation is needed
		// $this->performAjaxValidation($model);

		if(isset($_POST['confirm']))
		{
			$model->attributes=$_POST['User'];
			if($model->validate())
			{
				$this->setPageState('update', $_POST['User']);
				$this->render('confirm', compact('model'));
				return;
			}
		} else if(isset($_POST['back']))
		{
			$model->attributes = $this->getPageState('update');
		}
		else if(isset($_POST['finish']))
		{
			$model->attributes = $this->getPageState('update');
			if($model->save()) {
				$this->redirect(Yii::app()->baseUrl);
			}
		}
		$this->render('update', compact('model'));
	}

...
```

#バリデーションを作成する
User.phpとUserProfile.phpのrules()を書き換えて検証ルールを宣言する
（まだとりあえず感があるが...）
これは公式サイトがわかりやすい
[検証ルールの宣言](http://www.yiiframework.com/doc/guide/1.1/ja/form.model#sec-3)

メールアドレスとパスワードに関しては、確認欄を設けているので、verifymailaddrとverifypasswordを新たにプロパティに加えて、rules()にも記述しておく
確認欄の追加の仕方はここがわかりやすかった
[verify password yii framework](http://stackoverflow.com/questions/11948350/verify-password-yii-framework)

```php:User.php
...
class User extends CActiveRecord
{

	public $verifymailaddr;
	public $verifypassword;

...

	public function rules()
	{
		// NOTE: you should only define rules for those attributes that
		// will receive user inputs.
		return array(
			array('mailaddr, password', 'required'),
			array('mailaddr', 'length', 'max'=>128),
			array('mailaddr', 'unique', 'message' => Yii::t('app',"This user's email adress already exists.")),
			array('verifymailaddr', 'compare', 'compareAttribute'=>'mailaddr'),
			array('password', 'length', 'max'=>32),
			array('verifypassword', 'length', 'max'=>32),
            array('verifypassword', 'compare', 'compareAttribute'=>'password'),
			array('mailaddr', 'email'),
			// The following rule is used by search().
			// @todo Please remove those attributes that should not be searched.
			array('id, mailaddr, password, auth', 'safe', 'on'=>'search'),
		);
	}

...
```

```php:Userprofile.php
...

	public function rules()
	{
		// NOTE: you should only define rules for those attributes that
		// will receive user inputs.
		return array(
			array('id, firstname, lastname, kana_firstname, kana_lastname, zipcode, address, phone1', 'required'),
			array('firstname, lastname, kana_firstname, kana_lastname, post, phone1, phone2, fax', 'length', 'max'=>20),
			array('kana_firstname, kana_lastname, kana_corporation', 'match', 'pattern'=>'/^[ァ-ヶｦ-ﾟー]+$/u'),
			array('phone1, phone2, fax', 'match', 'pattern'=>'/^([+]?[0-9 -]+)$/'),
			array('corporation, kana_corporation', 'length', 'max'=>50),
			//array('zipcode, deliverable_zipcode', 'length', 'max'=>10),
			array('zipcode, deliverable_zipcode', 'match', 'pattern'=>'/^[0-9]{3}[-]?[0-9]{4}$/'),
			array('address, deliverable_address', 'length', 'max'=>100),
			array('email2', 'length', 'max'=>128),
			array('email2', 'email'),
			// The following rule is used by search().
			// @todo Please remove those attributes that should not be searched.
			array('id, firstname, lastname, kana_firstname, kana_lastname, corporation, kana_corporation, post, zipcode, address, phone1, phone2, fax, email2, deliverable_zipcode, deliverable_address, point', 'safe', 'on'=>'search'),
		);
	}
...

```

***