Ground Sunlight

Windowsで作る - Webプログラミングの開発環境(PHP)

ユーザ用ツール

サイト用ツール


サイドバー

メインメニュー

道具箱

リポジトリ編

フレームワーク編

Webサービス編

自然言語処理環境編

メタ
リンク


このページへのアクセス
今日: 1 / 昨日: 2
総計: 96

apricot:app:user-edit

Apricot ユーザ登録画面

y2sunlight 2020-05-11

Apricot に戻る

関連記事

ユーザ一覧画面に引き続き、ユーザ登録画面を作ります。本章の前にユーザ一覧画面もご覧下さい。尚、ルーティング設定に関しては既にユーザ一覧画面で終わっているので、そちらを参照して下さい。


ユーザモデル

ユーザ登録用にユーザモデル( User )を変更します。

/apricot/app/Model

User.php
<?php
namespace App\Models;
 
use App\Foundation\Model;
use ORM;
 
/**
 * ユーザモデル
 */
class User extends Model
{
    /**
     * ユーザ新規保存
     * {@inheritDoc}
     * @see \App\Foundation\Model::insert()
     */
    public function insert(array $inputs):ORM
    {
        // 新規登録時、パスワードは必須
        // パスワード暗号化
        $inputs['password'] = password_hash($inputs['password'], PASSWORD_DEFAULT);
 
        // 新規保存
        return parent::insert($inputs);
    }
 
    /**
     * ユーザデータ更新
     * {@inheritDoc}
     * @see \App\Foundation\Model::update()
     */
    public function update($id, array $inputs):ORM
    {
        // データ更新時、パスワードは入力した場合のみ変更
        if(empty($inputs['password'])) unset($inputs['password']);
 
        // パスワード暗号化
        if(array_key_exists('password', $inputs))
        {
            $inputs['password'] = password_hash($inputs['password'], PASSWORD_DEFAULT);
        }
 
        // データ更新
        return parent::update($id, $inputs);
    }
}
  • Modelクラスの insert() と update() をオーバーライドし、password を暗号化して保存します。
  • update()では、パスワードは入力した場合のみ変更します。


ユーザコントローラ

ユーザ登録用にユーザコントローラ( UserController )も変更します。

/apricot/app/Controllers

UserController.php
<?php
namespace App\Controllers;
 
use App\Exceptions\ApplicationException;
use App\Foundation\Controller;
use App\Models\User;
use Core\Input;
 
/**
 * ユーザコントローラ
 */
class UserController extends Controller
{
    /**
     * User
     * @var \App\Models\User
     */
    private $user;
 
    /**
     * ユーザコントローラの生成
     */
    public function __construct()
    {
        // モデル
        $this->user = new User();
    }
 
    /**
     * ユーザ一覧
     * @return \Core\Foundation\Response
     */
    public function index()
    {
        // 全件検索
        $users = $this->user->findAll();
        return render("user.index", ["users"=>$users]);
    }
 
    /**
     * ユーザ新規登録
     * @return \Core\Foundation\Response
     */
    public function create()
    {
        // 新規作成
        $user = $this->user->create();
        return render("user.create", ["user"=>$user]);
    }
 
    /**
     * ユーザレコード挿入
     * @return \Core\Foundation\Response
     */
    public function insert()
    {
        $inputs = Input::all();
 
        try
        {
            // ユーザレコード挿入
            $user = $this->user->insert($inputs);
        }
        catch(\Exception $e)
        {
            throw new ApplicationException(__('messages.error.db.insert'),$e->getMessage(),0,$e);
        }
 
        // ユーザ一編集画面にリダイレクト
        return redirect(route("user/{$user->id}/edit"))->with('msg',__('messages.success.db.insert'));
    }
 
    /**
     * ユーザ編集
     * @return \Core\Foundation\Response
     */
    public function edit(int $id)
    {
        // 主キー検索
        $user = $this->user->findOne($id);
        if ($user!==false)
        {
            return render("user.edit", ["user"=>$user]);
        }
        else
        {
            return redirect(route("users"))->withOldErrors();
        }
    }
 
    /**
     * ユーザレコード更新
     * @param int $id
     * @return \Core\Foundation\Response
     */
    public function update(int $id)
    {
        $inputs = Input::all();
 
        try
        {
            // レコード更新
            $this->user->update($id, $inputs);
        }
        catch(ApplicationException $e)
        {
            throw $e;
        }
        catch(\Exception $e)
        {
            throw new ApplicationException(__('messages.error.db.update'),$e->getMessage(),0,$e);
        }
 
        // ユーザ一編集画面にリダイレクト
        return redirect(route("user/{$id}/edit"))->with('msg',__('messages.success.db.update'));
    }
 
    /**
     * ユーザレコード削除
     * @param int $id
     * @return \Core\Foundation\Response
     */
    public function delete(int $id)
    {
        try
        {
            // レコード削除
            $this->user->delete($id);
        }
        catch(ApplicationException $e)
        {
            throw $e;
        }
        catch(\Exception $e)
        {
            throw new ApplicationException(__('messages.error.db.delete'),$e->getMessage(),0,$e);
        }
 
        // ユーザ一覧画面にリダイレクト
        return redirect(route("users"))->with('msg',__('messages.success.db.delete'));
    }
}
  • create() : ユーザ新規登録
    • Userモデルのcreate()で新しいユーザを作成します
    • ヘルパー関数render()を呼び出してレスポンスをレンダリングしています
    • render(string $view=null, array $variables=[])
      1. $view : テンプレート名
        上例では assets/views/user/create.blade.php がテンプレートファイルになります
      2. $variables : テンプレート変数の連想配列
        上例では新しいユーザ( $user )をテンプレートに渡しています
  • insert() : レコード挿入
    • Input::all()でフォームデータを取得します
    • Userモデルのinsert()でユーザレコードを挿入します
      • エラーの場合、ApplicationException をスローします
    • 処理成功の場合、ヘルパー関数redirect()でユーザ編集(user/{id}/edit)にリダイレクトします
  • edit(int $id) : ユーザ編集
    • UserモデルのfindOne($id)でユーザを検索します。
      • 検索エラーの場合、ヘルパー関数redirect()でユーザ一覧(users)にリダイレクトします
    • 検索成功の場合、ヘルパー関数render()を呼び出してレスポンスをレンダリングしています
    • render(string $view=null, array $variables=[])
      1. $view : テンプレート名
        上例では assets/views/user/edit.blade.php がテンプレートファイルになります
      2. $variables : テンプレート変数の連想配列
        上例では検索したユーザ( $user )をテンプレートに渡しています
  • update(int $id) : レコード更新
    • Input::all()でフォームデータを取得します
    • Userモデルのupdate()でユーザレコードを更新します
      • エラーの場合、ApplicationException をスローします
    • 処理成功の場合、ヘルパー関数redirect()でユーザ編集(user/{id}/edit)にリダイレクトします
  • delete(int $id) : レコード削除
    • Userモデルのdelete()でユーザレコードを削除します
      • エラーの場合、ApplicationException をスローします
    • 処理成功の場合、ヘルパー関数redirect()でユーザ一覧(users)にリダイレクトします
入力値のチェックは後述のバリデーションで、エラー処理についてはトランザクションで処理を実装します。この段階ではエラーが発生するとApplicationException がスローされエラー画面が表示されます(デバッグ時はWhoops提供のPrettyErrorHandlerのデバッグ画面が表示されます)。


HTMLテンプレート

ユーザ登録用のHTMLテンプレートは2つあります:

  • 新規登録用 — create.blade.php
  • 編集用 — edit.blade.php

Apricotでは出来るだけシンプルな実装を示すようにクライアント側のバリデーションは行っていません。必要に応じて追加してご使用下さい。尚、入力値のチェックは後述のサーバー側のバリデーションで行います。

また、以下のテンプレートでは、パスワードの確認入力がありません。これについても後述のバリデーションの章で追加する予定です。パスワードは新規登録時は必須入力ですが、更新時はパスワードを入力した場合のみ変更する仕様になっています。

新規登録用のテンプレート

以下にユーザコントローラの create アクションでレンダリングしているHTMLテンプレートを示します。

/apricot/assets/views/user

create.blade.php
{{-- 親レイアウト --}}
@extends('layout')
 
{{-- 追加スクリプト --}}
@push('scripts')
@endpush
 
{{-- タイトル --}}
@section('title', __('messages.user.create.title'))
 
{{-- コンテンツ --}}
@section('content')
    <form method="POST" name="fm">
        {{-- account --}}
        <div class="form-group row">
            <label for="account" class="col-md-2 col-form-label">{{__('messages.user.create.account')}}</label>
            <div class="col-md-10">
                <input type="text" name="account" id="account" class="form-control" value="{{old('account',$user->account)}}"
                    placeholder="{{__('messages.user.create.hint_account')}}">
            </div>
        </div>
        {{-- password --}}
        <div class="form-group row">
            <label for="password" class="col-md-2 col-form-label">{{__('messages.user.create.password')}}</label>
            <div class="col-md-10">
                <input type="text" name="password" id="password" class="form-control" value="{{old('password')}}"
                    placeholder="{{__('messages.user.create.hint_password')}}">
            </div>
        </div>
        {{-- email --}}
        <div class="form-group row">
            <label for="email" class="col-md-2 col-form-label">{{__('messages.user.create.email')}}</label>
            <div class="col-md-10">
                <input type="text" name="email" id="email" class="form-control" value="{{old('email',$user->email)}}"
                    placeholder="{{__('messages.user.create.hint_email')}}">
            </div>
        </div>
        {{-- note --}}
        <div class="form-group row">
            <label for="note" class="col-md-2 col-form-label">{{__('messages.user.create.note')}}</label>
            <div class="col-md-10">
                <input type="text" name="note" id="note" class="form-control" value="{{old('note',$user->note)}}"
                    placeholder="{{__('messages.user.create.hint_note')}}">
            </div>
        </div>
 
        {{-- button --}}
        <div class="mt-4">
            <button type="button" id="btn_back"   class="btn btn-secondary" onclick="location.href='{{route('users')}}'">{{__('messages.user.create.btn_back')}}</button>
            <button type="button" id="btn_cancel" class="btn btn-secondary" onclick="location.href='{{$_SERVER['REQUEST_URI']}}'">{{__('messages.user.create.btn_cancel')}}</button>
            <button type="post"   id="btn_insert" class="btn btn-secondary" formaction="{{route("user/insert")}}">{{__('messages.user.create.btn_insert')}}</button>
        </div>
 
    </form>
@endsection
  • extends, push, section の各ディレクティブについては、スタブ画面 を参照して下さい。
  • ボイラープレート__(), route() については、layout.blade.php を参照して下さい。
  • ユーザ新規登録
    • テンプレート変数 $user を使いユーザデータを表示しています。
    • ボイラープレートold()は 前回の入力値を取得するヘルバー関数です。前回値が存在しない場合は、テンプレート変数 $user の値を表示します(前回値が存在するのはバリデーションなどのエラーが発生した場合だけです)。
    • [保存]ボタン押下で、フォームデータを route(“user/insert”) に送信します。

HTMLテンプレートに関しては本編BladeOneのリンクを項を参照して下さい。


編集用のテンプレート

以下にユーザコントローラの edit アクションでレンダリングしているHTMLテンプレートを示します。

/apricot/assets/views/user

edit.blade.php
{{-- 親レイアウト --}}
@extends('layout')
 
{{-- 追加スクリプト --}}
@push('scripts')
@endpush
 
{{-- タイトル --}}
@section('title', __('messages.user.edit.title'))
 
{{-- コンテンツ --}}
@section('content')
    <form method="POST" name="fm">
        {{-- id --}}
        <input type="hidden" name="id" id="id" value="{{old('id',$user->id)}}">
 
        {{-- account --}}
        <div class="form-group row">
            <label for="account" class="col-md-2 col-form-label">{{__('messages.user.edit.account')}}</label>
            <div class="col-md-10">
                <input type="text" name="account" id="account" class="form-control" value="{{old('account',$user->account)}}" readonly>
            </div>
        </div>
        {{-- password --}}
        <div class="form-group row">
            <label for="password" class="col-md-2 col-form-label">{{__('messages.user.edit.password')}}</label>
            <div class="col-md-10">
                <input type="text" name="password" id="password" class="form-control" value="{{old('password')}}"
                    placeholder="{{__('messages.user.edit.hint_password')}}">
            </div>
        </div>
        {{-- email --}}
        <div class="form-group row">
            <label for="email" class="col-md-2 col-form-label">{{__('messages.user.edit.email')}}</label>
            <div class="col-md-10">
                <input type="text" name="email" id="email" class="form-control" value="{{old('email',$user->email)}}"
                    placeholder="{{__('messages.user.edit.hint_email')}}">
            </div>
        </div>
        {{-- note --}}
        <div class="form-group row">
            <label for="note" class="col-md-2 col-form-label">{{__('messages.user.edit.note')}}</label>
            <div class="col-md-10">
                <input type="text" name="note" id="note" class="form-control" value="{{old('note',$user->note)}}"
                    placeholder="{{__('messages.user.edit.hint_note')}}">
            </div>
        </div>
        {{-- version_no --}}
        <input type="hidden" name="version_no" id="version_no" value="{{old('version_no',$user->version_no)}}">
 
        {{-- button --}}
        <div class="mt-4">
            <button type="button" id="btn_back"   class="btn btn-secondary" onclick="location.href='{{route('users')}}'">{{__('messages.user.edit.btn_back')}}</button>
            <button type="post"   id="btn_delete" class="btn btn-secondary" onclick="return confirm('{{__('messages.user.edit.msg_delete')}}');" formaction="{{route("user/{$user->id}/delete")}}">{{__('messages.user.edit.btn_delete')}}</button>
            <button type="button" id="btn_cancel" class="btn btn-secondary" onclick="location.href='{{$_SERVER['REQUEST_URI']}}'">{{__('messages.user.edit.btn_cancel')}}</button>
            <button type="post"   id="btn_update" class="btn btn-secondary" formaction="{{route("user/{$user->id}/update")}}">{{__('messages.user.edit.btn_update')}}</button>
        </div>
    </form>
@endsection
  • extends, push, section の各ディレクティブについては、スタブ画面 を参照して下さい。
  • ボイラープレート__(), route() については、layout.blade.php を参照して下さい。
  • ユーザ編集
    • テンプレート変数 $user を使いユーザデータを表示しています。
    • ボイラープレートold()は 前回の入力値を取得するヘルバー関数です。前回値が存在しない場合は、テンプレート変数 $user の値を表示します(前回値が存在するのはバリデーションなどのエラーが発生した場合だけです)。
    • 楽観的ロックを行う為にユーザデータの version_no を hidden で持っている点に留意して下さい。
    • [保存]ボタン押下で、フォームデータを route(“user/{id}/update”) に送信します。
    • [削除]ボタン押下で、フォームデータを route(“user/{id}/delete”) に送信します。

HTMLテンプレートに関しては本編BladeOneのリンクを項を参照して下さい。


翻訳テキスト

翻訳ファイル( messages.php )を以下のように変更します。

apricot/assets/lang/ja

messages.php
<?php
return [
...
 
    'user'=>[
        'index'=> [
            ...
        ],
        'create'=>[
            'title'=>'ユーザ新規登録',
            'account'=>'アカウント',
            'password'=>'パスワード',
            'password_confirmation'=>'パスワード(確認)',
            'email'=>'メールアドレス',
            'note'=>'備考',
            'hint_account'=>'半角英数字で入力して下さい',
            'hint_password'=>'パスワードを入力して下さい',
            'hint_password_confirmation'=>'パスワードを再入力して下さい',
            'hint_email'=>'apricot@sample.com',
            'hint_note'=>'必要な場合は入力して下さい',
            'btn_back'=>'戻る',
            'btn_cancel'=>'キャンセル',
            'btn_insert'=>'保存',
 
        ],
        'edit'=>[
            'title'=>'ユーザ編集',
            'account'=>'アカウント',
            'password'=>'パスワード',
            'password_confirmation'=>'パスワード(確認)',
            'email'=>'メールアドレス',
            'note'=>'備考',
            'created_at'=>'登録日',
            'updated_at'=>'更新日',
            'hint_password'=>'変更する場合は入力して下さい',
            'hint_password_confirmation'=>'パスワードを再入力して下さい',
            'hint_email'=>'apricot@sample.com',
            'hint_note'=>'必要な場合は入力して下さい',
            'btn_back'=>'戻る',
            'btn_delete'=>'削除',
            'btn_cancel'=>'キャンセル',
            'btn_update'=>'保存',
            'msg_delete'=>'削除します。よろしいですか?',
        ],
    ],
];
  • ユーザ新規登録用の翻訳テキストを user.create に追加します。
  • ユーザ編集用の翻訳テキストを user.edit に追加します。


テスト実行

ユーザ登録をしてみましょう。ブラウザ上で以下のURLにアクセスしてみて下さい。

http://localhost/ws2019/apricot/public/

[Users]メニューをクリックしユーザ一覧画面を表示します。

■ [新規]ボタンを押して下さい。

■ データを入力して[保存]ボタンを押します。
■ 保存に成功すると以下の画面が表示されます。

■ データを修正して[保存]ボタンを押します。
■ 保存に成功すると画面が更新されます。


コメント

コメントを入力. Wiki文法が有効です:
 
apricot/app/user-edit.txt · 最終更新: 2020/06/03 14:15 by tanaka