PHP Manual
/
フォーム

マルチイヤーフォーム

16. 09. 2019

Obsah článku

時には、フォームをいくつかの部分(ページ)に分割し、別々に処理した後、1つの結果に組み立てる必要があります。

この記事では、そのための手法やデザインパターンについて解説しています。

注意:

フォームを複数のステップに分割する問題は非常に複雑で、特にそれをうまくやりたい場合は、非常に複雑です。私はこれまで、さまざまなアプローチに出会ってきましたが、ここで紹介するのはその一部です。一見魅力的なアプローチに見えますが、特定のケースにしか使えないナイーブなものもあります。それぞれのアプローチについて、どのような場合に意味があり、どのような場合に意味がないかを説明します。

理論解の設計

通常、最初のページの最初のフォームから基本データを取得し、それを検証して、「どこかに」保存し、次のページを表示することが目的です。

ユーザーが最後のページにたどり着いたら、全体のフォームを送信し、入力内容を処理する必要があります。

各ステップでは、常にすべてのデータを慎重に検証し、ユーザーが自由にページをスキップして戻れるようにすることで、エラーが発生したときにデータを修正できるようにすることが重要です。また、すでに取得したデータをもとに条件付きでフォームをレンダリングする場合は、非常に負荷の高い処理となります。

帳票自体の実装

個々のフォームを純粋なHTMLで独自に実装し、PHPで処理を行うか、Nette formsのような既製のソリューションを利用することができます。

生活の中での例:

初心者のプログラマーが私にメールを送ってきて、一見簡単そうに見える質問をすることがよくありますが、これには既成の解答があります。例えば、PHPでのフォーム処理について具体的に。

私はいつも、手動処理を完全にスキップして、代わりに既製のソリューションを使用することをお勧めします。現実には、例えば、入力された電子メールと2つのフィールド内のパスワードが一致するかどうかのバリデーションを正しく実装し、一方で、ユーザーのデータに応じて事前に入力されたフォームにリダイレクトし、エラーが発生した場合にはエラーメッセージを表示することは、非常に複雑なことなのです。

なぜなら、人々は知らないことを知らないので、99.99%の問題に対する既製のソリューションを学ぶために1時間の時間を投資する代わりに、独自のソリューションを選択することを好み、それを何十時間もかけてデバッグし、フォームが機能しない、エラーを吐く、セキュリティ脆弱性がある、入力データを保護しないケースがまだあるのです。

つまり、このステップのゴールは、空白のフォームを含む、異なるURLの複数のページを実装することです。

各フォームを独立して(アトミックに)実装し、状態の受け渡しは別のアプリケーション層で処理することをお勧めします。というのも、それぞれのフォームは実際にはデータのバリデーションの扱いも、その出力の書き方も、エラーの扱いも違うし、時間の経過とともに拡張したり変更したりしたいだろうから、そのために全体の文脈を知って何十サイトも変更する必要はない。

状態遷移

最初のフォームを処理するとき、まず受け取ったデータを検証し、それが正しければ、ユーザーを2番目のステップにリダイレクトさせたい。なぜなら、データが有効でないことが簡単に起こり得るからです。その場合、ユーザーを次のステップではなく、最初のフォームに戻したいのです。

状態を保存する方法は、基本的に4通りあります。

推奨しない:

  • この場合、ユーザーがURLで送信したデータを変更することができるため、入力の偽装が可能になるというデメリットがあります。あるいは、URLの中にあるパスワードなどの機密情報を開示することも可能です。
  • **セッション**に継続的に追加する、つまり、新しく取得したデータをキーごとにフィールドにインクリメンタルに挿入することです。これは、アプリケーションがエラーを起こした場合、ユーザーはそのセッションから抜け出せず、何らかの方法でエラーを解決できない(クッキーを削除する以外には、ほとんどの人にとって非常に困難)という欠点があります。さらに、未完成のフォームでは、データが事前に入力されたままとなり、他の誰かに見られる可能性があります。しかし、セッションの有効期間が非常に短く(例えば5分)、ユーザーが最後のステップを埋めるときに最初のステップのデータを失うと、より悪いケースが発生します...これはかなり厄介なことになります。

推奨:

  • データベースの保存と識別子の受け渡し。最初にフォームが送信されたときに、収集したすべてのデータをデータベースのテーブルに保存し、ページ間でパラメータとして渡すランダムな識別子(例えば10文字の長い文字列)を生成します。この利点は、任意の帳票を処理する際に、新たに検索・検証したデータを直接テーブルに書き込むことができ、障害発生時には、解析した帳票の物理的なバックアップを持ち、それに基づいて行動できることである。例えば、注文に不備があった場合、未完了であることをユーザーにメールで伝えることで、販売機会を増やすことができます。
  • 現在ログインしているアカウントに保存**は、ランダムな識別子(トークン)の代わりに、現在ログインしているユーザーのID(存在する場合)へのセッションを使用する以外は、ID経由の転送と全く同じ動作をします。 メリットは、事前に入力したデータを将来的に任意にユーザーに表示できることです。

結論

上記のどの解決策も完璧ではなく、唯一の正しい解決策です。私自身、多段階のソリューションを手がける際には、複数のアプローチを組み合わせています。例えば、私はショッピングカートをデータベースのテーブルとして解決し、そこに既に収集したデータを割り当て、ユーザー(ログインしている場合)またはセッション(ログインしておらず、まだお互いを知らない場合)にバインドします。

Jan Barášek   Více o autorovi

Autor článku pracuje jako seniorní vývojář a software architekt v Praze. Navrhuje a spravuje velké webové aplikace, které znáte a používáte. Od roku 2009 nabral bohaté zkušenosti, které tímto webem předává dál.

Rád vám pomůžu:

Související články

1.
3.
Status:
All systems normal.
2024