したがって、私の問題は2つの質問に要約されると思います。
パフォーマンスを考慮しながら隣接リスト モデル アプローチを使用してツリーが MySQL (2 つのテーブル間) に格納されている場合、PHP でトラバース可能なツリー構造を構築するにはどうすればよいですか?
トラバーサル コードを複製したり、if/else ステートメントや switch ステートメントでロジックを散らかしたりせずに、必要な形式でツリーを表示するための保守可能なアプローチは何ですか?
詳細は以下のとおりです。
Zend フレームワークを使用しています。
問診票を扱っています。これは、質問と質問グループの 2 つの別個のテーブル間の MySQL データベースに保存されます。各テーブルは、適切な Zend_Db_Table_* クラスを拡張します。階層は、隣接リスト モデル アプローチを使用して表されます。
私が直面している問題は、ツリー構造を RDBMS に詰め込んでいるという事実が原因である可能性が高いことを認識しているため、代替手段を受け入れています。ただし、アンケートの回答者とその回答も保存しているため、別のアプローチでそれをサポートする必要があります。
アンケートは、さまざまな HTML 形式で表示する必要があります。
- 回答を入力するためのフォームとして (Zend_Form を使用)
- 質問別またはグループ別の回答を表示するためのリンクとして、質問 (およびいくつかのグループ) を含む順序付けられた (ネストされた) リストとして。
- 各質問に回答が追加された順序付きリスト (ネストされた) として。
質問はリーフ ノードであり、question_groups には他の question_group や質問を含めることができます。組み合わせると、処理および表示する行が 100 行を少し超えます。
現在、再帰を使用してすべての処理を行い、question_group の子 (2 つのテーブル間で UNION を実行するクエリ: QuestionGroup::getChildren($id)) を取得するビュー ヘルパーがあります。さらに、質問の回答とともにアンケートを表示する場合、各質問に対する回答者とその回答を取得するために、追加の 2 つのクエリが必要です。
ページの読み込み時間はそれほど長くはありませんが、このアプローチは間違っているように感じます. ほとんどすべてのノードに対して再帰と複数のデータベース クエリを実行しても、内部が非常に暖かくぼんやりしているとは感じません。
UNION から返された完全なツリー配列に対して再帰のない方法と再帰的な方法を試し、トラバースして表示する階層配列を構築しました。ただし、グループと質問が別々のテーブルに格納されているため、ノード ID が重複しているため、これはうまくいかないようです。多分私はそこに何かが欠けている...
現在、上記の形式でツリーを表示するロジックは非常に混乱しています。トラバーサル ロジックをいたるところに複製することは避けたいと思います。ただし、いたるところにある条件は、保守が最も容易なコードを生成するものでもありません。私はビジター、デコレータ、およびいくつかの PHP SPL イテレータについて読みましたが、Zend_Db_Table、Zend_Db_Table_Rowset、および Zend_Db_Table_Row を拡張するクラスとすべてがどのように連携するかについては、まだよくわかりません。特に、データベースから階層を構築するという以前の問題を解決していないためです。新しい表示形式を追加する (または既存のものを変更する) のは、いくらか簡単にできるとよいでしょう。