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

Source: https://habr.com/ru/post/J92066/


All Articles