PR2のコントローラーは何になりますか?

こんにちは Symfony 2フレームワークの開発を引き続き監視します。 このトピックでは、新しいSymfony 2(PR2)リリースでのコントローラーメカニズムについて説明します。 コントローラーインターフェイスモデルMVCを構築するためのカテゴリ6のオプション。



Symfony 2はプレビューリリース(PR1)になりました。 Sensio LabsのFabienとDoctrine 2の開発者Jonathan WageによるTwitterの投稿数から判断すると、フレームワークの作業は本格的です。 たとえば、最近ではすでに4つの新しいコンポーネントがあります 。これらについては、 こちらで読むことができますFinderCssSelectorについての私の翻訳で個々のコンポーネントの詳細を読むことができます。 また、GoogleグループのSymfony 2に関する多数の議論に注目する価値があります 。 フレームワークの開発と並行して、人気のあるORM Doctrineの 2番目のブランチとTWIGテンプレートエンジンが集中的に開発されています。 これらすべては、PHP 5.3自体の開発とともに、そのような成長を続ける技術的有機体のイメージを作成し、その開発は非常に興味深いものです。 少し後、シャンパンのボトルを購入し、バーに入れて、最終リリースを楽しみにしています。 少し気を散らして申し訳ありませんが、Symfony 2 PR2フレームワークのステージに移動する際のコントローラーメカニズムの改善に関するSymfonyコミュニティの考えに従ってください(トピックの最後にあるディスカッションへのリンクを参照)。興味深いアイデアを提供し、それによってフレームワークを改善します。



実際、これは完全な翻訳ではありませんが、素材の主要部分は1つのソースから取られたものなので、翻訳としてデザインすることにしました。 テキストは非常にたくさんありますが、構造化され読みやすいので、すべてが1つのトピックに含まれています。



コントローラー



Symfony 2では、有効な呼び出し可能なコンストラクトは、コントローラー、関数、クラス/オブジェクトメソッド、またはラムダ/クロージャーとして機能します。 このトピックでは、最も一般的なケースとして、オブジェクトメソッドの形式でコントローラーについて説明します。



ジョブを実行するには(モデルを呼び出してパラメーターをビューに渡す)、コントローラーはいくつかのパラメーター(文字列)とサービス(オブジェクト)にアクセスできる必要があります。 コントローラーはMVCビューの中心部分であるため、そのインターフェイスに最適なオプションを選択するとき、およびパラメーターを渡してサービスにアクセスする方法を選択するときは、特別な注意が必要です。 最適なインターフェイスを選択する決定は、これらの問題を考慮して(重要度の高い順に)行う必要があります。

  1. 新しいコントローラーの作成はどれほど簡単/直感的ですか?
  2. その実装はどれくらい速いですか?
  3. 自動的にテストするのは簡単ですか(ユニットテスト)? [トピックでは、これらの問題を考慮していません。追加のリンクでは]
  4. パラメータとサービスにアクセスするには、どの程度冗長/コンパクトですか?
  5. 実装は分離概念とMVC設計パターンにどのように適合しますか?
実際、これが、Symfony 2のコントローラーインターフェースのさまざまなオプションを評価する基礎となります。



オプション1。これは、Symfony 2(PR1)のコントローラーのメカニズムです。



サービスとパラメーターへのアクセスを提供するために、Symfonyはコンテナーをコントローラーコンストラクターに挿入します(コントローラーコンストラクターはprotectedプロパティに格納されます)。

$controller = new Controller($container);







オプションとサービスへのアクセス


アクションが実行されると、名前とパス変数の一致によってメソッドの引数が挿入されます。

function showAction($slug){ ... }





対応するパスにslug: / articles /:slug変数がある場合、slug引数が渡されます。



パス変数の転送は次のとおりです。
  1. 引数名がパス変数名と一致する場合、この値を使用します(URLで渡されず、デフォルト値が定義されている場合でも、この例では$スラッグ)。
  2. そうでない場合、および引数にデフォルト値が指定されている場合、および引数がオプションである場合、デフォルト値を使用します。
  3. そうでない場合、例外をスローします。
パラメーターへのアクセスは次のとおりです。

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(...);

}







長所と短所:


明らかな利点として、特定の種類のコンテナの理解可能性、シンプルさ、優れたパフォーマンス、便利なテストを区別できます。



短所:
  1. コントローラーにはコンテナーがロードされます(エンティティー分離)。
  2. コンテナへの非常にオープンなアクセス。開発者の正確さが必要です。
  3. オプションとサービスへのアクセスはやや冗長です。
  4. 開発者は、いわゆるsfContextコンテキストで考え始めるかもしれません。 つまり、コントローラーからコンテナーにアクセスできる場合、それをモデルクラスに渡すのは簡単ですが、これは最良のアイデアではありません。
  5. テスト中、開発者は実装に精通し、コントローラーがアクセスできるサービスを知る必要があります。

オプション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(...);

}







長所と短所:


利点:
  1. 柔軟性が高く、最初のオプションと完全に互換性があります。
  2. パラメータ/サービスを渡すときに型制御を有効にします。
  3. より明確な依存関係。
  4. 大きなオーバーヘッドコードではありません。
短所:
  1. コンストラクターはすべてのサービスとパラメーターを必要とします(ただし、ほとんどの場合、使用されるのはごく少数です)が、これらの場合にコンテナーメソッドを使用できることは安心です。
  2. より定型的なコード:開発者は、転送されたすべてのサービスを保護された変数に保存する必要があります。

オプション3



このバリアントでは、コンストラクターにサービスを挿入する代わりに、各コントローラーメソッドに直接挿入されます。

function showAction($slug, $userService, $doctrineManagerService, $maxPerPageParameter){ ... }





引数には、パス変数、サービス、またはグローバルパラメーターを指定できますが、パラメーターを渡すためのルールを明確にする必要があります。
  1. 引数名が「Service」で終わる場合、適切なサービス(この例では$ userService)を使用します。
  2. 引数名が「Parameter」で終わる場合、Dependency Injectorで対応するパラメーターを使用します(例では$ maxPerPageParameter)。
  3. そうでなく、引数名がパス変数と一致する場合、それを使用します(例では$ slug)。
  4. また、引数が定義されていない場合、例外をスローします。
メソッドシグネチャですべてのサービス/パラメーターを記述したくない場合は、コンテナーを使用できます(以前のバージョンで行われたように)。

// `slug`

function showAction($slug, Container $containerService){ ... }



// Request

function showAction(Request $requestService, Container $containerService){ ... }




オプションとサービスへのアクセス


この場合、パラメーターとサービスへのアクセスはほぼ直接実行されます。

function showAction($id, $userService, $doctrineManagerService) {

$user->setAttribute(...);

}





長所と短所:


利点: 短所:

オプション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はまだアノテーションを使用していないため、これについてはまだあまり議論されていません。



長所と短所:


利点:

短所: 詳細については、以下の追加リンクから入手できます。 コメントでは、どのオプションが一番好きか、あるいは誰かが新しいものを提供するかを読むのは興味深いです。 個人的にはオプション1と5が好きです。



便利なリンクRFC:Symfony 2のコントローラーとGoogleグループのディスカッション: パート1パート2パート3



All Articles