1

ユーザーがログインできるプログラムがあります。Userクラスがあり、ユーザーがログインすると、すべての属性(権限、ユーザー名、実名など)がクラスプロパティとして保存されます。ただし、すべてのデータを検証する必要があるため、ユーザーに自分の情報を更新させるのが最善の方法であることに頭を悩ませています。

現在、ユーザーが自分の情報(メールアドレスなど)を更新しようとすると、次のようになります。

// Set new email
$try = $user->setEmail($_POST['new_email']);
if ($try !== true) {
    $errors[] = $try;
}
...
if (isset($errors) {
    // Tell user what went wrong
} else {
    $user->saveValuesToDB();
}

User->setEmail()それは正常に動作しますが、電子メールが複数の理由(ドメインが見つからない、無効な形式、空の文字列が提供されている、別のユーザーによってすでに使用されているなど)で無効になる可能性があるため、混合リターンタイプが必要なため、私にはかなり醜いようです正確な理由をユーザーに返す必要がありますが、私が理解しているように、混合リターンは一般的に推奨されていません。

私が考えたもう1つの方法は、検証を実行せずにすべてのプロパティを更新User->commitAllChanges()し、最後にすべての検証を実行することです。これにより、すべてのsetterメソッドから複数のリターンが取得され、削減されます。 commitメソッドのみに適用されますが、実際に設定されているプロパティは有効である必要があり、それでも問題を完全に取り除くことはできないと感じているため、これも本当に好きではありません。

ユーザーがオブジェクトのプロパティを設定し、それらを検証してエラーをユーザーに返送できるようにするために使用できる他の方法は何ですか?それとも私が今やっていることはうまくいっていますか?

4

5 に答える 5

2

私が考えたもう1つの方法は、検証を実行せずにすべてのプロパティを更新し、最後にUser-> commitAllChanges()を実行して、すべての検証を実行することです。これにより、すべての検証から複数のリターンが取得されます。 setterメソッドを作成し、commitメソッドのみに減らします。

これは一般的に良いアプローチです。また、プロセス全体をより小さな部分に分割して、より用途を広げることもできます。

たとえば、モデルvalidateには、単一のブール値を返すメソッド(すべてOKですか、それとも1つ以上のエラーがありますか?)と、getValidationErrors関心のあるすべての情報を保持する配列を返すメソッドがある場合があります(おそらく多次元)。エラーがまったくない場合にのみ変更commitを自動的に呼び出して保持するメソッドを持つことができます。validate

しかし、実際に設定されているプロパティは有効であるはずであり、それでも問題を完全に取り除くことはできないと思うので、これも本当に好きではありません。

「設定されない」プロパティは、IMOが当初考えていよりもはるかに厄介です。主な問題は、プロパティが設定に反対する場合(エラーコードを返すか、例外をスローすることによって)、プロパティへのすべてのアクセスを「保護」コードでラップする必要があることです。これは非常に速く退屈になります。

実際には、1回のヘルパーメソッドですべてのプロパティに値を大量に割り当ててから、結果がどうなるかを確認する方がはるかに便利です(たとえば、validate上記のようにメソッドを呼び出すことによって)。

また、実際には、データ入力フィールドの横に検証エラーを表示する必要があることを忘れないでください。これらのフィールドには、モデルのプロパティの値が事前に入力されるように配線されています。したがって、一方ではプロパティが有効である必要があり、他方ではユーザーが入力したものと正確に一致する必要があります(そうでない場合、ユーザーはあなたを殺したいと思うでしょう)。したがって、ユーティリティを優先して「常に有効である必要がある」という制約を緩和することをお勧めします。最近では、AJAXフォームとクライアント側の検証がどこにでもあるため、これはあまり関連性がなくなりつつあります。

于 2013-02-27T20:12:40.627 に答える
2

構造を使用しtry-catchます。

// somewhere in your project
class UserValidationException extends \Exception {}

// In your form handler, controller, or whatever you have
try {
    $user->setName($_POST['new_email']);
    $user->setEmail($_POST['new_name']);
    // etc.
}
catch (UserValidationException $e)
{
    // tell user what went wrong using $e->getMessage();
}

// In your User class
class User
{
    // ...
    public function setName($newName)
    {
        if (strlen($newName) < 2)
            throw new UserValidationException('User name is too short');
    }
}
于 2013-02-27T20:15:06.220 に答える
1

1つの方法は、ソリューション(setEmail関数)を維持し、より多くのOOPにすることです。setAction内で、エラーのリストを設定できます

$this->errors[] = 'Domain invaild';

次に、1つまたは2つの関数を作成して、クラスからエラーを取得します

public function hasErrors() {return false == empty($this->errors);}
public function getErrors() {return $this->errors;}
于 2013-02-27T20:09:21.310 に答える
1

現在のメソッドに問題はありませんが、できることは例外を使用することです。

次のようになります。

try
{
    $user->setEmail($_POST['new_email']);
}
catch (Exception $e)
{
    $errors[] = $e->getMessage();
}

また、setEmailメソッドは次のようになります。

setEmail($email)
{
    if ($tooShort) // validate length
        throw new Exception("Email is too short"); // perhaps have custom exceptions
}
于 2013-02-27T20:12:26.513 に答える
0

私はこれにMVC.NETアプローチのようなものを使用します。基本的に、例外をスローすることの悪い点はパフォーマンスです。なぜ1つだけをキャッチしたいのでしょうか。メールとパスワードの両方が無効な場合は、「メールが正しくない」ではなく、同時に通知してください-メールを修正します-再投稿します-「パスワードも間違っていたので、もっと早く教えてくれたかもしれませんが、お金を稼ぐだけです」

編集済み:
検証がfalseを返すため、例外をスローしないでください。意図的(ハッカー)であるかどうかに関係なく、無効なデータを取得することが予想されます。しかし、これが大規模な形でどのように処理されるかを見て、処理がどれほど遅くなるかを見てみましょう。検証エラーは保存してユーザーに表示する必要があります。これにより、プログラムは例外ではなく条件を入力するだけです。例外は、必要なリソースがない、誰かがコードを正しく実行するために必要なライブラリファイルまたはフレームワークを削除したなどのコード化されたエラーのために予約する必要があります。


    <?php

    class ChangePasswordModel
    {

        protected $OldPassword;

        protected $NewPassword;

        protected $ConfirmPassword;

        protected $ValidationMessages;

        protected $DisplayNames;

        public function __construct()
        {
            $this->DisplayNames = array(
                "OldPassword"       => "Old password",
                "NewPassword"       => "New password",
                "ConfirmPassword"   => "Confirm new password",
            );
        }

        public function LoadPost()
        {
            if ( !isset( $_POST["OldPassword"] ) || !isset( $_POST["NewPassword"] ) || !isset( $_POST["ConfirmPassword"] ) )
                return;

            $this->OldPassword      = trim( $_POST["OldPassword"] );
            $this->NewPassword      = trim( $_POST["NewPassword"] );
            $this->ConfirmPassword  = trim( $_POST["ConfirmPassword"] );

            if ( strlen( $this->OldPassword ) < 1 )
                $this->ValidationMessages["OldPassword"] = "Old password is not set";
            if ( strlen( $this->NewPassword ) < 6 )
                $this->ValidationMessages["NewPassword"] = "Password must be at least 5 characters.";
            if ( $this->NewPassword != $this->ConfirmPassword )
                $this->ValidationMessages["ConfirmPassword"] = "Passwords do not match.";
        }

        public function ValidationMessageFor( $name )
        {
            if ( !isset( $this->ValidationMessages[$name] ) )
                return "";

            return $this->ValidationMessages[$name];
        }

        public function DisplayNameFor( $name )
        {
            // Throw exception if not set
            return $this->DisplayNames[$name];
        }

    }

    $Model = new ChangePasswordModel();
    $Model->LoadPost();

    ?>
    <form action="" method="post">
        <div>
            <?= $Model->DisplayNameFor( "OldPassword" ) ?>
        </div>
        <div>
            <input type="password" name="OldPassword" />
            <span><?= $Model->ValidationMessageFor( "OldPassword" ) ?></span>
        </div>

        <div>
            <?= $Model->DisplayNameFor( "NewPassword" ) ?>
        </div>
        <div>
            <input type="password" name="NewPassword" />
            <span><?= $Model->ValidationMessageFor( "NewPassword" ) ?></span>
        </div>

        <div>
            <?= $Model->DisplayNameFor( "ConfirmPassword" ) ?>
        </div>
        <div>
            <input type="password" name="ConfirmPassword" />
            <span><?= $Model->ValidationMessageFor( "ConfirmPassword" ) ?></span>
        </div>

        <p>
            <input type="submit" value="Change Password" />
        </p>
    </form>
于 2013-05-23T20:38:32.707 に答える