yiiフレームワークを使ってみる(2)

[前回](http://qiita.com/nakau1/items/3d92906833d1002a3ba8)は、yiiのインストールからGiiを使ってUserモデルを作るところまで進みました
このユーザを管理するところと、ログインができるアプリケーションまでを作りたいですね

#CRUDを作ってみる
CRUDといえば「作る(C)・読む(R)・書き換える(U)・消す(D)」ですね
管理画面を作るとすれば基本的な画面になります
これもソースコードを書くことなくGiiで作れるらしいです

```
http://52.68.17.10/yiitest/index.php?r=gii/crud
```

ブラウザでこのURLにアクセスすると
`Crud Generator`というページが表示されます

前回、Userクラスが作られましたので
`Model Class`には`User`と入力しました
すると、`Controller ID`には自動で`user`と入力されました

previewを押すと、

+ controllers/UserController.php 
+ views/user/_form.php
+ views/user/_search.php
+ views/user/_view.php
+ views/user/admin.php
+ views/user/create.php
+ views/user/index.php 
+ views/user/update.php 
+ views/user/view.php 

これだけのファイルを作るよという表示が

前回と同じように書込権限の問題もあるので、
generateを押す前に
controllersとviewsディレクトリを777にしておきましょう

```
# cd /var/www/html/yiitest/protected/

# chmod 777 controllers/
# chmod 777 views/
```

generateを押すと
`The controller has been generated successfully. You may try it now.`と表示されました

`try it now`のところがリンクになっているので押下してみます

すると、`http://(IPアドレス)/yiitest/index.php?r=user`にリンクされ
ユーザ一覧ページが表示されます
もうすでにページャやソート、検索、閲覧や編集、追加、削除などの機能が備わっています

ちなみに、編集などの操作を行おうとすると、
ログイン画面に飛ばされますが、

username admin
password admin

でログインすればOKのようです

#管理画面まわりをカスタマイズしてみる
自動生成されたモデルクラスのファイル`User.php`を少しカスタマイズしてみます
ページに表示されるフォームの名前は
すべてデータベースのカラム名になっているので、
これを日本語に変えてみます

対象のファイルは前回作ったのでどこにあるかはすぐわかります
vimで編集します

```
# vim /var/www/html/yiitest/protected/models/User.php
```
```
        /**
         * @return array customized attribute labels (name=>label)
         */
        public function attributeLabels()
        {
                return array(
                        'id' => 'ID',
                        'username' => 'Username',
                        'password' => 'Password',
                        'email' => 'Email',
                );
        }
```

`attributeLabels()`というメソッドで設定されているようです
ここを下記のように日本語にしてみます

```
        /**
         * @return array customized attribute labels (name=>label)
         */
        public function attributeLabels()
        {
                return array(
                        'id' => 'ユーザ番号',
                        'username' => 'ユーザ名',
                        'password' => 'パスワード',
                        'email' => 'メールアドレス',
                );
        }
```

そして再度、
`http://(IPアドレス)/yiitest/index.php?r=user`にアクセスしてみると、
設定した通り、日本語が表示されました!

#認証画面をカスタマイズしてみる
実はこの自動生成されたWEBアプリケーションは
adminとdemoというIDとパスワードが同じユーザでログインすることになっています
そんなWEBアプリはよくないので、カスタマイズしてみます

せっかくユーザモデルを作って、管理もできるようになったので
このユーザで認証したいですね

ちなみに、[公式リファレンスの「ユーザ認証」](http://www.yiiframework.com/doc/blog/1.1/ja/prototype.auth)を参考にしました

##ユーザモデルの修正
とりあえず前提となるDBのユーザテーブルには
パスワードが平文で入ってしまっているので、
一旦`tbl_user`テーブルは空にしちゃいます
(ここはphpMyAdminなどで直接DBを触っちゃいましょう)

空にした後、`http://(IPアドレス)/yiitest/index.php?r=user`で
`No results found.`になればOKです

次に新たにユーザを追加する際には
パスワードを平文で入れないように変更したいと思います

Userモデルクラスをvimで編集します

```
# vim /var/www/html/yiitest/protected/models/User.php
```
```
        protected function beforeSave() {
            if(parent::beforeSave()) {
                $this->password = CPasswordHelper::hashPassword($this->password);
                return true;
            } else {
                return false;
            }
        }
```

上記のように `beforeSave()`メソッドをオーバライドするようです
`CPasswordHelper::hashPassword()`で、ハッシュ化されたパスワードを生成するみたいな処理ですね
自動生成されたソースコードには`beforeSave()`メソッドはないので、
追記する形になります

追記を保存したら、ブラウザからユーザを追加してみます
`Create User`メニューから適当なユーザを追加します
そうするとDBに新たにレコードが追加され、
パスワードがハッシュ化されていればOKですね

##認証処理を変更する
次に、現在のWEBアプリケーションがどのように認証処理をしているか
サラッと見てみます

認証処理をしているのは、
`CUserIdentity`というクラスを継承した`UserIdentity`クラスのようです
vimで開いてみます

```
# vim /var/www/html/yiitest/protected/components/UserIdentity.php 
```
```
class UserIdentity extends CUserIdentity
{
        /**
         * Authenticates a user.
         * The example implementation makes sure if the username and password
         * are both 'demo'.
         * In practical applications, this should be changed to authenticate
         * against some persistent user identity storage (e.g. database).
         * @return boolean whether authentication succeeds.
         */
        public function authenticate()
        {
                $users=array(
                        // username => password
                        'demo'=>'demo',
                        'admin'=>'admin',
                );
                if(!isset($users[$this->username]))
                        $this->errorCode=self::ERROR_USERNAME_INVALID;
                else if($users[$this->username]!==$this->password)
                        $this->errorCode=self::ERROR_PASSWORD_INVALID;
                else
                        $this->errorCode=self::ERROR_NONE;
                return !$this->errorCode;
        }
}
```
短いクラスだったので全部掲載しました
`authenticate()`メソッドに、admin と demo で認証するみたいな処理がありました

ここをUserモデルが絡む処理に変えてやればいいのですね
[こちらのページ](http://www.yiiframework.com/doc/guide/1.1/ja/topics.auth)にサンプルがありました
ひとまずこの通りに実装してみます

```
class UserIdentity extends CUserIdentity
{
    private $_id;
    public function authenticate()
    {
        $record=User::model()->findByAttributes(array('username'=>$this->username));
        if($record===null)
            $this->errorCode=self::ERROR_USERNAME_INVALID;
        else if(!CPasswordHelper::verifyPassword($this->password,$record->password))
            $this->errorCode=self::ERROR_PASSWORD_INVALID;
        else
        {
            $this->_id=$record->id;
            // $this->setState('title', $record->title); // この行は今回コメントします
            $this->errorCode=self::ERROR_NONE;
        }
        return !$this->errorCode;
    }
 
    public function getId()
    {
        return $this->_id;
    }
}
```

この実装後、一度ログアウトしてみて
再度ログイン画面で試験してみます

admin/admin のアカウントではログインできなくなっていればOKです

そして、追加したユーザのユーザ名とパスワードで
ログインができたらOKです!