2012年10月9日火曜日

Zend Framework 2 でのユーザー登録機能の実装

前回の投稿に引き続き、今回はユーザー登録機能の実装を行います。前回の投稿で以下のようなフォルダ階層となっていると思います。

 Auth/
|-- Module.php
|-- config
|   `-- module.config.php
|-- src
|   `-- Auth
|       `-- Controller
|           `-- AuthController.php
`-- view
    `-- auth
        `-- auth
            |-- login.phtml
            `-- signup.phtml

ここから登録機能の実装=>ログイン機能の実装という流れで行っていきます。

まずは登録機能です。ここではメールアドレス・パスワードでの登録を行っていきます。

それでは登録フォームの作成です。登録フォームはFormディレクトリを作成し、src/Authフォルダの中に登録フォルダを作成してその中で実装していきます。以下のファイルをFormディレクトリの中にRegisterForm.phpとして保存します。

<?php
//module/Auth/src/Auth/Form/RegisterForm.php

namespace Auth\Form;

use Zend\Form\Form;
use Zend\Form\Element;  //csrf用のタグの出力に利用

class RegisterForm extends Form
{
        public function __construct()
        {
                parent::__construct();
                $this->add(array(
                        'name' => 'email',
                        'attributes' => array(
                                'type' => 'text',
                        ),
                        'options' => array(
                                'label' => 'email',
                        ),
                ));
                $this->add(array(
                        'name' => 'password',
                        'attributes' => array(
                                'type' => 'password',
                        ),
                        'options' => array(
                                'label' => 'password',
                        ),
                ));
                $this->add(array(
                        'name' => 'submit',
                        'attributes' => array(
                                'type' => 'submit',
                                'value' => 'signup'
                        ),
                ));
                $this->add(new Element\Csrf('csrf'));
        }

}

これをコントローラーで呼び出し、ビューに渡します。

まずはコントローラーです。

<?php
//module/Auth/src/Auth/Controller/AuthController.php

namespace Auth\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Auth\Form\RegisterForm;

class AuthController extends AbstractActionController
{

    public function signupAction()
    {
        $form = new RegisterForm();

        return array('form' => $form);
    }

    public function loginAction()
    {

    }
}

次にビューです。

<?php
//module/Auth/view/auth/auth/signup.phtml

$title = 'signup form';
$this->headTitle($title);

$form = $this->form;
echo $this->form()->openTag($form);
echo $this->formRow($form->get('email'));
echo $this->formRow($form->get('password'));
echo $this->formHidden($form->get('csrf'));
echo $this->formSubmit($form->get('submit'));
echo $this->form()->closeTag($form);
?>

これでdomain.com/signup.phtmlにアクセスすると登録フォームが表示されると思います。これをモデルで受け取り、保存していきます。

まずはコントローラーの処理を加え、リクエストメソッドがポストされている場合にはDBに保存しましょう。

 Zend Framework 2でも、以前のバージョンのように実体を表すクラスとそれをオブジェクト表現するマッパーを組み合わせてモデルを実装することが出来ます。いずれDoctrine等のORMを用いるとして、今回はこれで実装します。

DBですが、今回は簡易に以下のカラムを利用します。DBはこのように作成してください。
  id: mediumint(9) NOT NULL AUTO_INCREMENT
  email: varchar(255) DEFAULT NULL
  password: varchar(20) DEFAULT NULL

コントローラーのsignupアクションを以下のように変更します。

<?php
//module/Auth/src/Auth/Controller/AuthController.php

//メンバ変数を加えます
protected $userTable;

//signupAction, getUserTableメソッドを実装します
    public function signupAction()
    {
        $form = new RegisterForm();
        $request = $this->getRequest();

        if($reqiest->isPost()){
            $user = new User();
            $user->exchangeArray($form->getData());
            $this->getUserTable()->registerUser($user);
        }

        return array('form' => $form);
    }
    private function getUserTable()
    {
        if(!$this->userTable) {
            $sm = $this->getServiceLocator();
            $this->userTable = $sm->get('Auth\Model\UserTable');
        }
        return $this->userTable;
    }


ここで、新しいクラスを2つ利用しています。UserクラスとUserTableクラスです。Userクラスは具体的なデータに対応するクラス、UserTableクラスは実際にDBとオブジェクトをつなぐクラスです。

上記のexhangeArrayメソッドでユーザークラスのメンバ変数に受け取ったデータを格納し、ユーザークラスを引数として、UserTableクラスのregisterUserメソッドでデータをDBに格納します。

それではUserクラスを作成します。以下のコードをUser.phpとしてsrc以下にmodelフォルダを作成して保存してください。

<?php
 // module/Auth/src/Auth/Model/User.php

namespace Auth\Model;

class User implements InputFilterAwareInterface
{
    public $email;
    public $password;

    public function exchangeArray(array $data)
    {
        $this->email = (isset($data['email'])) ? $data['email'] : null;
        $this->password = (isset($data['password'])) ? $data['password'] : null;
    }
}

ここで、exhangeArrayメソッドは配列型のデータを受け取り、メンバ変数に格納しています。
このクラスのインスタンスをUserTableに渡し、UserTableのregisterUserメソッドが実際にDBに保存します。

それではUserTableクラスの作成に移りましょう。ここで、上記のコントローラーではUserTableクラスを$this->getUserTable()として呼び出しています。getUserTableメソッドはサービスマネージャーに登録されたAuth\Model\UserTableというサービスを呼び出しています。

このままだとサービスマネージャーはこのサービスを呼び出せません。Module.phpにサービスあらかじめ登録します。

 <?php
//module/Auth/Module.php

//以下を追加します
use Auth\Model\UserTable;

//以下を追加します
    public function getServiceConfig()
    {
        return array(
            'factories' => array(
                'Auth\Model\UserTable' => function($serviceManager) {
                    $dbAdapter = $serviceManager->get('Zend\Db\Adapter\Adapter');
                    $table = new UserTable($dbAdapter);
                    return $table;
                }
            )
        );
    }

UserTableクラスを実装します。
<?php
//module/Auth/src/Auth/Model/UserTable.php

namespace Auth\Model;

use Zend\Db\Adapter\Adapter;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\AbstractTableGateway;

class UserTable extends AbstractTableGateway
{
    protected $table = 'user';

    public function __construct(Adapter $adapter)
    {
        $this->adapter = $adapter;

        $this->resultSetPrototype = new ResultSet();
        $this->resultSetPrototype->setArrayObjectPrototype(new User());

        $this->initialize();
    }

    public function registerUser(User $user)
    {
        $data = array(
            'email'     => $user->email,
            'password'  => $user->password,
        );

        $this->insert($data);
    }
}

詳細は割愛しますが、AbstractTableGatewayクラスを継承することでinsertメソッドからDBにデータを挿入できます。

最後にデータベースとの接続情報をファイルに書き込みます。この設定はモジュールディレクトリの外でグローバルに設定します。

configディレクトリ以下のautoloadディレクトリ内にあるglobal.phpファイルを以下のように書き換えます。

//config/autoload/global.php
    'db' => array(
        'driver'            => 'Pdo',
        'dsn'               => 'mysql:dbname=sukina_databasename;host=localhost',
        'driver_options'    => array(
            PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
        ),
    ),

また、local.phpファイルも加えます。

<?php

//config/autoload/local.php
return array(
    'db' => array(
        'username' => 'root',
        'password' => 'YesYourMajesty',
    ),
);

これで、一通り作成が完了しますが、この時点ではコントローラー内でのgetDataメソッドの使用方法が正しくありません。終わりにバリデーションを付けて完成させましょう。

コントローラーの修正です。
//module/Auth/src/Auth/Controller/AuthController.php
    public function signupAction()
    {
        $form = new RegisterForm();
        $request = $this->getRequest();

        if($request->isPost()){
            $user = new User();
            $form->setInputFilter($user->getInputFilter());
            $form->setData($request->getPost());

            if($form->isValid()) {
                $user->exchangeArray($form->getData());
                $this->getUserTable()->registerUser($user);
                exit('登録完了!以下の処理保留');
            }
        }

        return array('form' => $form);
    }

実体を表しているモデルのUserクラスのなかにバリデーションルールを書き込みます。

//module/Auth/src/Auth/Model/User.php

//クラスの利用
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\Factory as InputFactory;

    //メンバ変数の追加
    private $inputFilter;
    public function setInputFilter(InputFilterInterface $inputFilter)
    {
        throw new \Excepion("Not used");
    }
    public function getInputFilter()
    {
        if(!$this->inputFilter) {
            $inputFilter = new InputFilter();
            $factory = new InputFactory();

            $inputFilter->add($factory->createInput(array(
                'name'      => 'email',
                'required'  => true,
                'filters'   => array(
                    array('name'    => 'StripTags'),
                    array('name'    => 'StringTrim'),
                ),
                'validators'    => array(
                    array(
                        'name'  => 'StringLength',
                        'options'   => array(
                            'encoding'  => 'UTF-8',
                            'min'   => '7',
                            'max'   => '255',
                        ),
                    ),
                ),
            )));

            $inputFilter->add($factory->createInput(array(
                'name'      => 'password',
                'required'  => true,
                'filters'   => array(
                    array('name'    => 'StripTags'),
                    array('name'    => 'StringTrim'),
                ),
                'validators'    => array(
                    array(
                        'name'  => 'StringLength',
                        'options'   => array(
                            'encoding'  => 'UTF-8',
                            'min'   => '6',
                            'max'   => '20',
                        ),
                    ),
                ),
            )));

            $this->inputFilter = $inputFilter;
        }

        return $this->inputFilter;
    }

これでポストするとDBへの登録が出来ます。パスワードのハッシュ化等は好きなタイミングで行ってください。

0 件のコメント:

コメントを投稿