あいどる💖たいむ

あいどるやってます。

Phalconでのデータ登録の流れ

概要

ユーザの登録を想定して、Phalconのデータ登録の流れをみる。 Phalconプロジェクト名は”todo"としている。

環境

  • phalcon 3.2.2
  • phalcon-devtools 3.2.3
  • MySQL 5.7.19

モデル作成

まず、DBにモデルのテーブルを作成する。
その後、Phalcon-toolsを使い、作成したテーブルのモデルクラスを作成する。 (Djangoのように、先にモデルクラスを作って、そこからテーブルを作成するようなのはできなさげ)

最初に、ユーザを管理するusersテーブルを作成する。

CREATE TABLE users (
  name     VARCHAR(255) PRIMARY KEY ,
  password VARCHAR(255)
);

つぎに、Phalcon-toolsを使いusersモデルクラスを生成する。 phalcon modelを実行するが、実行前にアプリケーションルート(todo/)に移動しておく。

# phalcon model users

Phalcon DevTools (3.2.3)


  Success: Model "Users" was successfully created.

これで、todo/app/models/にUsers.phpが生成される。

サインアップページの作成

コントローラ作成

モデルと同じようにPhalcon-toolsを使って、accountsコントローラを作成する。

# phalcon controller --name accounts

Phalcon DevTools (3.2.3)


  Success: Controller "accounts" was successfully created.

/var/www/html/todo/app/controllers/AccountsController.php

app/controllers/AccountsController.phpが作成されたので、これをいじっていく。

フォーム追加

コントローラ編集前に、サインアップページに表示するフォームを追加する。

まず、フォームを配置するディレクトリtodo/app/formsを作成。
このディレクトリをconfig.php, loader.phpにロード対象として追加する。 (ここconfigで登録したいディレクトリだけ別のリストに保持するとかすれば、loader.phpは変更しなくてよくできそう)

// config.php
    'application' => [
        'appDir'         => APP_PATH . '/',
        'controllersDir' => APP_PATH . '/controllers/',
        'modelsDir'      => APP_PATH . '/models/',
        'migrationsDir'  => APP_PATH . '/migrations/',
        'viewsDir'       => APP_PATH . '/views/',
        'pluginsDir'     => APP_PATH . '/plugins/',
        'libraryDir'     => APP_PATH . '/library/',
        'cacheDir'       => BASE_PATH . '/cache/',
        'formsDir'       => APP_PATH . '/forms/', // <- 追加
// loader.php

$loader->registerDirs(
    [
        $config->application->controllersDir,
        $config->application->modelsDir,
        $config->application->formsDir // <- 追加
    ]
)->register();

次にSignUpFormクラスを作成する。

<?php

use Phalcon\Forms\Form;
use Phalcon\Forms\Element\Text;
use Phalcon\Forms\Element\Password;
use Phalcon\Validation\Validator\PresenceOf;
use Phalcon\Validation\Validator\StringLength;
use Phalcon\Validation\Validator\Confirmation;

/**
 * SignUpフォーム
 */
class SignUpForm extends Form
{

    /**
     * フォーム初期化
     *
     * @access public
     *
     * @param Users $entity
     * @param array $options
     */
    public function initialize($entity = null, $options = array())
    {
        $name = new Text('name');
        $name->setLabel('name');
        $name->addValidators(
            [
                new PresenceOf(
                    [
                        'message' => 'nameを入力してください',
                    ]
                ),
                new StringLength(
                    [
                        "max" => 255,
                        "messageMaximum" => "nameは255文字以下で入力してください",
                    ]
                )
            ]
        );
        $this->add($name);

        $password = new Password('password');
        $password->setLabel('パスワード');
        $password->addValidators(
            [
                new PresenceOf(
                    [
                        'message' => 'パスワードを入力してください',
                    ]
                ),
                new StringLength(
                    [
                        'max' => 255,
                        'messageMaximum' => 'パスワードは255文字以下で入力してください',
                    ]
                ),
                new Confirmation(
                    [
                        'with' => 'password2',
                        'message' => 'パスワードが一致していません'
                    ]
                )
            ]
        );
        $this->add($password);

        $password2 = new Password('password2');
        $password2->setLabel('パスワード(確認用)');
        $password2->addValidators(
            [
                new PresenceOf(
                    [
                        'message' => 'パスワード(確認用)を入力してください',
                    ]
                ),
            ]
        );
        $this->add($password2);
    }
}

こんな感じ。
validationについては以下を参照。 docs.phalconphp.com

アクション追加

生成されたコントローラにsignUpActionを追加 上で作成したフォームを指定している。

    public function signUpAction(){
        # 使用するフォームを指定
        $this->view->form = new SignUpForm();
    }

ビュー追加

todo/views/accounts/signUp.viewを作成する。 {% for element in form %} ...のような感じでやれば、上で作成したフォームをレンダリングできる。

<h1 class="text-center">アカウント登録</h1>
{{ content() }}
<div class="form-container">
    {{ form("", 'role': 'form','class':'form-horizontal') }}

    <fieldset>
        {% for element in form %}
            <div class="form-group">
                {{ element.label(['class': 'col-sm-3 control-label']) }}
                <div class="col-sm-9">
                    {{ element.render(['class': 'form-control']) }}
                </div>
            </div>
        {% endfor %}
    </fieldset>
    <div class="row">
        <div class="col-sm-offset-3 col-sm-9 ">
            {{ submit_button("登録", "class": "btn-wide btn btn-primary") }}
        </div>
    </div>
    {{ end_form() }}
</div>

{{ content() }}は、viewが階層になっているとき、子viewをここにレンダリングするよってもの。 このviewは最下層だけど、flashメッセージを表示するために記述している。
flashメッセージは階層の一番下に付け足されるイメージなのかな?

階層については以下を参照。

Using Views — Phalcon 3.1.1 documentation (English)

画面確認

http://<host名>/todo/accounts/signUpにアクセス

f:id:shiccocsan:20171019162821p:plain

登録処理の実装

signUpActionを、postのときは登録処理を行うよう変更する。

    public function signUpAction()
    {
        if ($this->request->ispost()) {

            $form = new SignUpForm();
            $user = new Users();

            $data = $this->request->getpost();

            // formのvalidation
            $errors = null;
            if (!$form->isvalid($data, $user)) {
                $errors = $form->getmessages();
            } else {
                // データ登録(validation含む)
                if ($user->create() == false) {
                    $errors = $user->getmessages();
                }
            }


            if ($errors !== null) {
                $e = [];
                foreach ($errors as $error) {
                    $this->flash->error($error);
                }
            } else {
                $form->clear();
                $this->flash->success("ユーザを登録しました");
                return $this->dispatcher->forward(['controller' => 'index', 'action' => 'index']);
            }

        }

        # 使用するフォームを指定
        $this->view->form = new SignUpForm();
    }

formのisvalidメソッドにrequestデータとモデルを渡すことで、validationと一緒にモデルにpostデータもバインドしてくれる。 また、モデルのcreateやsaveメソッドはモデルに設定されているvalidation後に更新処理を行う。

一意制約違反のメッセージ変更

UsersモデルのgetMessageをオーバーライドし、一意制約違反のメッセージを変更する。

    public function getMessages()
    {
        $messages = array();
        // 一意制約違反のメッセージのみ書き換えている
        foreach (parent::getMessages() as $message) {
            switch ($message->getType()) {
                case 'InvalidCreateAttempt':
                    $messages[] = 'この名前はすでに登録されています';
                    break;
                default:
                    $messages[] = $message;
            }
        }
        return $messages;
    }

not null制約や外部キー制約違反などのメッセージ変更できるので、詳しくは以下を参照。

docs.phalconphp.com

動作確認

登録画面で適当に入力し、登録ボタンをクリック。 usersテーブルにデータが登録され、http://<host名>/todo/に遷移できればOK。

おわりに

練習でtodoアプリを作ってるので、その過程を残せたらと思ってたけど、予想以上に書くのが大変だった。 今後は、tipsみたいなのを書いていけたらと思う。