2

電子メールを送信するための基本的な HTML フォームがあるとします。

<form action="contactSubmit" method="POST">
    <label for="name" class="italic">Name:</label>
    <input type="text" name="name" value="" maxlength="20" required="required" autofocus="autofocus" />
    <label for="email" class="italic">E-mail:</label>
    <input type="email" name="reply_to" value="" maxlength="255" required="required" />
    <label for="comments" class="italic">Comments:</label>
    <textarea name="message" rows="10" cols="50" required="required"></textarea>
    <br />
    <input type="submit" class="submit" value="Send" />
</form>

現在、すべての検証はコントローラーで行われています。

// submit contact request
public function contactSubmit() {
    // process form if submitted
    if ( $this->formSubmit() ) {
        // validate input
        $name = isset($_POST['name']) && $this->validate($_POST['name'], null, 20) ? $_POST['name'] : null;
        $reply_to = isset($_POST['reply_to']) && $this->validate($_POST['reply_to'], 'email', 255) ? $_POST['reply_to'] : null;
        $message  = isset($_POST['message']) && $this->validate($_POST['message']) ? $_POST['message'] : null;

        // proceed if required fields were validated
        if ( isset( $name, $reply_to, $message ) ) {
            $to = WEBMASTER;
            $from = 'nobody@' . $_SERVER['SERVER_NAME'];
            $reply_to = $name . ' <' . $reply_to . '>';
            $subject = $_SERVER['SERVER_NAME'] . ' - Contact Form';

            // send message
            $mail = $this->model->build('mail');
            if ( $mail->send($to, $from, $reply_to, $subject, $message ) ) {
                $_SESSION['success'] = 'Your message was sent successfully.';
            } else {
                // preserve input
                $_SESSION['preserve'] = $_POST;

                // highlight errors
                $_SESSION['failed'] = 'The mail() function failed.';
            }
        } else {
            // preserve input
            $_SESSION['preserve'] = $_POST;

            // highlight errors
            if ( !isset( $name ) ) {
                $_SESSION['failed']['name'] = 'Please enter your name.';
            }
            if ( !isset( $reply_to ) ) {
                $_SESSION['failed']['reply_to'] = 'Please enter a valid e-mail.';
            }
            if ( !isset( $message ) ) {
                $_SESSION['failed']['message'] = 'Please enter your comments.';
            }
        }
    }

    $this->view->redirect('contact');
}

「ファット コントローラー」から離れて「ファット モデル」に移行したいのですが、前のコントローラーから前のモデルに検証をきれいに移植する方法を一生理解できません。

public function send( $to, $from, $reply_to, $subject, $message ) {
    // generic headers
    $headers = 'MIME-Version: 1.0' . PHP_EOL;
    $headers .= 'From: ' . $from . PHP_EOL; // should belong to a domain on the server
    $headers .= 'Reply-to: ' . $reply_to . PHP_EOL;

    // send message
    return mail( $to, $subject, $message, $headers );
}

フォームには 3 つの必須フィールドしかありませんが、モデルのメソッドは 5 つを受け入れます。フォーム フィールドの説明は入力名とは異なるため、他のアプリケーションで使用するためにモデルを移植可能に保ちながら、エラー メッセージをカスタマイズすることが難しくなっています。私が行うすべての試みは途方もなく太ってしまい、それでも最初のアプローチと同じ柔軟性を達成していないようです.

カスタムエラーメッセージの柔軟性を維持し、他のアプリケーションで使用するためのモデルの移植性を維持しながら、コントローラーからモデルに検証を移動するクリーンな方法を誰かが教えてくれませんか?

4

2 に答える 2

1

どちらも太ってはいけないと思います。HTML フォームを扱う場合、独自のフィールド レベルの検証を行うフィールド オブジェクト (例: ) を持つFormようなオブジェクトを用意するのが最もクリーンだと思います。CommentFormEmailField extends Field

フォームが検証されれば、クリーンなデータが得られることが保証されます。フォームは、さまざまなモデルを作成して返すこともできます。これらのモデル自体も、メンバー レベルで検証を行います。しかし、何も太っていません...各ビットは、すぐに関係するものについて知る必要があるだけです。

コントローラーは次のようになります。

if ($form->validate($request->post())) {
  // grab the email model from the form
  $email = $form->getEmail();

  // assume $mailTransport implements some mailer interface
  if ($mailTransport->send($email) == true) {
    // sent email
    return $response->redirect('success');
  }
  else {
    // something unexpected happened
    $view->flashError('Unable to send email');
  }
}

$view->form = $form;

処理するすべてのコントローラーは、非常によく似た非常にクリーンな外観になります。モデルは HTML フォームについて何も知りません。何度もリピートしやすいパターンです。

これを行うには多くの方法があります。上記はたまたま私のお気に入りの汎用ソリューションです。

于 2013-10-15T03:09:53.373 に答える
1

まず第一に、あなたは本当に純粋な OOP を使っていますか? 外部データでモデル メソッドを使用するのはなぜですか? モデルは独自のプロパティで動作する必要があります。オブジェクトの作成に必要なデータが有効でない場合、モデル オブジェクトをインスタンス化しないでください。

モデルと通信するレイヤーをさらに作成する必要があります。たとえば、この検証を処理できる modelFactory レイヤーを使用できます。user model があり、 modelFactories レイヤーに UserFactory があるとします。ここに検証ロジックを配置できます。User モデルの作成に必要なデータが有効でない場合は、モデルを作成しないでください。

より抽象的な方法は、dataTransferObjects レイヤーのようなレイヤーを追加することです。ここでは、モデルまたはモデル ファクトリにデータを転送するオブジェクトを設定できます。ここでも検証ロジックを配置し、modelFactories を使用して UserDTO オブジェクト (ユーザー データ転送オブジェクト) からユーザー モデルを作成できます。

問題は、検証のように、事前にデータを準備せずにモデルを作成してはならないということです。そのため、モデルは独自のプロパティで動作し、外部データを直接渡さないでください (データを渡してオブジェクトを初期化するだけです)。

ドメイン駆動設計と設計パターンの詳細を読む必要があります。

このようにして、モデルは分離されたままになり、他のアプリケーションで再利用できます。

于 2013-10-14T23:44:00.333 に答える