こんにちは
Symfony 2フレームワークの開発を引き続き監視します。 このトピックでは、新しいSymfony 2(PR2)リリースでのコントローラーメカニズムについて説明します。 コントローラーインターフェイスモデルMVCを構築するためのカテゴリ6のオプション。
Symfony 2はプレビューリリース(PR1)になりました。 Sensio Labsの
FabienとDoctrine 2の開発者
Jonathan Wageによる
Twitterの投稿数から判断すると、フレームワークの作業は本格的です。 たとえば、最近ではすでに4つの新しいコンポーネントがあり
ます 。これらについては、
こちらで読むことができ
ます 。
Finderと
CssSelectorについての私の翻訳で個々のコンポーネントの詳細を読むことができます。 また
、GoogleグループのSymfony 2に関する多数の
議論に注目する価値があり
ます 。 フレームワークの開発と並行して、人気のあるORM
Doctrineの 2番目のブランチと
TWIGテンプレートエンジンが
集中的に開発されています。 これらすべては、PHP 5.3自体の開発とともに、そのような成長を続ける技術的有機体のイメージを作成し、その開発は非常に興味深いものです。 少し後、シャンパンのボトルを購入し、バーに入れて、最終リリースを楽しみにしています。 少し気を散らして申し訳ありませんが、Symfony 2 PR2フレームワークのステージに移動する際のコントローラーメカニズムの改善に関するSymfonyコミュニティの考えに従ってください(トピックの最後にあるディスカッションへのリンクを参照)。興味深いアイデアを提供し、それによってフレームワークを改善します。
実際、これは完全な翻訳ではありませんが、素材の主要部分は1つのソースから取られたものなので、翻訳としてデザインすることにしました。 テキストは非常にたくさんありますが、構造化され読みやすいので、すべてが1つのトピックに含まれています。
コントローラー
Symfony 2では、有効な呼び出し可能なコンストラクトは、コントローラー、関数、クラス/オブジェクトメソッド、またはラムダ/クロージャーとして機能します。 このトピックでは、最も一般的なケースとして、オブジェクトメソッドの形式でコントローラーについて説明します。
ジョブを実行するには(モデルを呼び出してパラメーターをビューに渡す)、コントローラーはいくつかのパラメーター(文字列)とサービス(オブジェクト)にアクセスできる必要があります。
コントローラーはMVCビューの中心部分であるため、そのインターフェイスに最適なオプションを選択するとき、およびパラメーターを渡してサービスにアクセスする方法を選択するときは、特別な注意が必要です。 最適なインターフェイスを選択する決定は、これらの問題を考慮して(重要度の高い順に)行う必要があります。
- 新しいコントローラーの作成はどれほど簡単/直感的ですか?
- その実装はどれくらい速いですか?
- 自動的にテストするのは簡単ですか(ユニットテスト)? [トピックでは、これらの問題を考慮していません。追加のリンクでは]
- パラメータとサービスにアクセスするには、どの程度冗長/コンパクトですか?
- 実装は分離概念とMVC設計パターンにどのように適合しますか?
実際、これが、Symfony 2のコントローラーインターフェースのさまざまなオプションを評価する基礎となります。
オプション1。これは、Symfony 2(PR1)のコントローラーのメカニズムです。
サービスとパラメーターへのアクセスを提供するために、Symfonyはコンテナーをコントローラーコンストラクターに挿入します(コントローラーコンストラクターはprotectedプロパティに格納されます)。
$controller = new Controller($container);
オプションとサービスへのアクセス
アクションが実行されると、名前とパス変数の一致によってメソッドの引数が挿入されます。
function showAction($slug){ ... }
対応するパスにslug:
/ articles /:slug変数がある場合、slug引数が渡されます。
パス変数の転送は次のとおりです。
- 引数名がパス変数名と一致する場合、この値を使用します(URLで渡されず、デフォルト値が定義されている場合でも、この例では$スラッグ)。
- そうでない場合、および引数にデフォルト値が指定されている場合、および引数がオプションである場合、デフォルト値を使用します。
- そうでない場合、例外をスローします。
パラメーターへのアクセスは次のとおりです。
function showAction($slug)
{
//
// :
$global = $ this ->container->getParameter( 'max_per_page' );
// :
$global = $ this ->container[ 'max_per_page' ];
// , request
$limit = $ this ->container->request->getParameter( 'max' );
// , :
$limit = $ this ->request->getParameter( 'max' );
}
サービスへのアクセスは次のとおりです。
function indexAction() {
//
$ this ->container->getUserService()->setAttribute(...);
//
$ this ->container->user->setAttribute(...);
}
長所と短所:
明らかな利点として、特定の種類のコンテナの理解可能性、シンプルさ、優れたパフォーマンス、便利なテストを区別できます。
短所:
- コントローラーにはコンテナーがロードされます(エンティティー分離)。
- コンテナへの非常にオープンなアクセス。開発者の正確さが必要です。
- オプションとサービスへのアクセスはやや冗長です。
- 開発者は、いわゆるsfContextコンテキストで考え始めるかもしれません。 つまり、コントローラーからコンテナーにアクセスできる場合、それをモデルクラスに渡すのは簡単ですが、これは最良のアイデアではありません。
- テスト中、開発者は実装に精通し、コントローラーがアクセスできるサービスを知る必要があります。
オプション2
このオプションは、パラメータ/サービスを操作する点で以前のオプションと異なります。 コンテナーをコンストラクターに渡す代わりに、必要なパラメーターとサービスのみを渡します。
protected $user, $request, $maxPerPage;
function __construct(User $user, Request $request, $maxPerPage)
{
$ this ->user = $user;
$ this ->request = $request;
$ this ->maxPerPage = $maxPerPage;
}
実際、最初のオプションがある程度までこのオプションの特殊なケースであることに気付くのは難しくありません。つまり、オプションは非常に互換性があります。
オプションとサービスへのアクセス
パラメーターとメソッドへのアクセスは、以前のオプションに似ていますが、もう少し簡単です:
function showAction($slug)
{
// ,
$limit = $ this ->request->getParameter( 'max' );
//
$global = $ this ->maxPerPage;
$ this ->user->setAttribute(...);
}
長所と短所:
利点:
- 柔軟性が高く、最初のオプションと完全に互換性があります。
- パラメータ/サービスを渡すときに型制御を有効にします。
- より明確な依存関係。
- 大きなオーバーヘッドコードではありません。
短所:
- コンストラクターはすべてのサービスとパラメーターを必要とします(ただし、ほとんどの場合、使用されるのはごく少数です)が、これらの場合にコンテナーメソッドを使用できることは安心です。
- より定型的なコード:開発者は、転送されたすべてのサービスを保護された変数に保存する必要があります。
オプション3
このバリアントでは、コンストラクターにサービスを挿入する代わりに、各コントローラーメソッドに直接挿入されます。
function showAction($slug, $userService, $doctrineManagerService, $maxPerPageParameter){ ... }
引数には、パス変数、サービス、またはグローバルパラメーターを指定できますが、パラメーターを渡すためのルールを明確にする必要があります。
- 引数名が「Service」で終わる場合、適切なサービス(この例では$ userService)を使用します。
- 引数名が「Parameter」で終わる場合、Dependency Injectorで対応するパラメーターを使用します(例では$ maxPerPageParameter)。
- そうでなく、引数名がパス変数と一致する場合、それを使用します(例では$ slug)。
- また、引数が定義されていない場合、例外をスローします。
メソッドシグネチャですべてのサービス/パラメーターを記述したくない場合は、コンテナーを使用できます(以前のバージョンで行われたように)。
// `slug`
function showAction($slug, Container $containerService){ ... }
// Request
function showAction(Request $requestService, Container $containerService){ ... }
オプションとサービスへのアクセス
この場合、パラメーターとサービスへのアクセスはほぼ直接実行されます。
function showAction($id, $userService, $doctrineManagerService) {
$user->setAttribute(...);
}
長所と短所:
利点:
- 各アクションは独立しており、自律的に動作します。
- メソッド内には、短く明確なコードがあります。
- 優れたパフォーマンス(メソッドの引数を分析および分析しているため);
- 非常に柔軟なオプション(必要に応じて完全なコンテナを使用できます)。
短所:
- パス変数のリストとサービスのリストが大きい場合、署名は非常に冗長になる可能性がありますが、この場合、リクエストとコンテナを作成できるという事実は安心です。
function showAction($year, $month, $day, $slug, $userService, $doctrineManagerService) { ... }
- メソッドは関数に似たものになります(何も結合しないため)。
- メソッドに引数としてサービスを渡す場合でも、それらの一部はメソッドのオプションである場合があります。 この場合、オンデマンドでコンテナからサービスにアクセスするよりもさらに多くのコードを取得します。
オプション4
このオプションは、オプション2と3を組み合わせたものです。サービスとパラメーターは、コンストラクターとアクションメソッドの両方に転送できます。
protected $user;
function __construct(User $user) {
$ this ->user = $user;
}
function showAction($slug, $mailerService, $maxPerPageParameter){ ... }
このオプションでは、メソッドがPHP4の関数と同様になるという問題はなくなりました。 クラスのグローバルサービスを作成し、アクションメソッドごとにローカルサービスを作成できます。
この近似は、どこでもすべてがオプションである場合、最初のオプションと100%互換性があります。 コンストラクターとアクションの両方でパラメーターを使用するか、デフォルトで作成されたコンテナーを使用する(またはコンテキスト依存にする)ことができます。
Symfony 1.xブランチからアクションをエミュレートすることもできます:
function showAction(Request $requestService){ ... }
このオプションは最も柔軟性が高いため、ドキュメントにはベストプラクティスを含める必要があります。
オプション5
VariantはVariant 4のほぼ完全なコピーです。ただし、アクション変数にパス変数を含めることはできません。 これにより、不要なサフィックス(パラメーターとサービス)を削除できます。 そして、パス変数へのアクセスは、リクエストオブジェクトへのアクセスを通じて発生します。
protected $user;
function __construct(User $user) {
$ this ->user = $user;
}
function showAction(Request $request, $mailer, $maxPerPage) {
$id = $request->getPathParameter( 'id' );
// ...
}
もう1つの適切な方法は、最初の引数にRequestオブジェクトを含めることです(一連のアプローチのため)。
オプション6
別の選択肢は、注釈を使用してオプションを含めることです。 Symfony 2はまだアノテーションを使用していないため、これについてはまだあまり議論されていません。
長所と短所:
利点:
- 一部のサードパーティライブラリは注釈の使用を開始しました(Doctrine 2、これまではオプション)。
短所:
- 追加コード;
- PHP開発者はアノテーションをほとんど使用しません。
- 注釈はネイティブのPHP言語の構成要素ではありません。
詳細については、以下の追加リンクから入手できます。 コメントでは、どのオプションが一番好きか、あるいは誰かが新しいものを提供するかを読むのは興味深いです。 個人的にはオプション1と5が好きです。
便利なリンク :
RFC:Symfony 2のコントローラーとGoogleグループのディスカッション:
パート1 、
パート2 、
パート3 。