From 7c3d36ab56a2fc6d8cddc709deae34b50c55ad2a Mon Sep 17 00:00:00 2001 From: polidog Date: Fri, 31 Oct 2014 01:03:32 +0900 Subject: [PATCH 1/6] =?UTF-8?q?=E7=BF=BB=E8=A8=B3=E3=81=AE=E9=80=94?= =?UTF-8?q?=E4=B8=AD...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- best_practices/controllers.rst | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 best_practices/controllers.rst diff --git a/best_practices/controllers.rst b/best_practices/controllers.rst new file mode 100644 index 0000000..d60aa8d --- /dev/null +++ b/best_practices/controllers.rst @@ -0,0 +1,22 @@ +コントローラー +=========== + +Symfonyは薄いコントローラとファットなモデルという哲学に従います。 この哲学が意味する事は、様々な +アプリケーションを扱うに為にグルーコードな薄いコントローラを維持する事が必要だという事です。 + +経験則として、正確な基準はありませんが、コントローラに定義する変数は5個以下、 +アクションの数が10個以下で、各アクション内の行数は20行以内という「5-10-20ルール」に従う事は +コードをコントローラからサービスにリファクタリングする際に役に立ちます。 + +.. best-practice:: + + あなたがコントローラを作る場合``FrameworkBundle``のコントローラを継承し, + 可能な限り、ルーティング、キャッシングとセキュリティをアノテーションで設定してください。 + + +コントローラとフレームワークを連携させることで、フレームワークの機能すべてを +活用する事を可能にし、あなたの生産性を向上させます。 + +そして、コントローラーは薄く、数行のグルーコードであるべきで、 +フレームワークからそれらを切り離すそうとすると、時間かかるので長期的に見ると利益になりません。 +大量の時間を費やすだけで、何の価値もありません。 From cd977540ac548790c46be075febda4a42d48a4d9 Mon Sep 17 00:00:00 2001 From: polidog Date: Sun, 16 Nov 2014 02:25:20 +0900 Subject: [PATCH 2/6] =?UTF-8?q?=E3=82=AD=E3=83=A3=E3=83=83=E3=82=B7?= =?UTF-8?q?=E3=83=B3=E3=82=B0=E3=82=92=E3=82=AD=E3=83=A3=E3=83=83=E3=82=B7?= =?UTF-8?q?=E3=83=A5=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- best_practices/controllers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/best_practices/controllers.rst b/best_practices/controllers.rst index d60aa8d..41c6ac1 100644 --- a/best_practices/controllers.rst +++ b/best_practices/controllers.rst @@ -11,7 +11,7 @@ Symfonyは薄いコントローラとファットなモデルという哲学に .. best-practice:: あなたがコントローラを作る場合``FrameworkBundle``のコントローラを継承し, - 可能な限り、ルーティング、キャッシングとセキュリティをアノテーションで設定してください。 + 可能な限り、ルーティング、キャッシュとセキュリティをアノテーションで設定してください。 コントローラとフレームワークを連携させることで、フレームワークの機能すべてを From 905390aed21717cbe191703c68c9958caca1f558 Mon Sep 17 00:00:00 2001 From: polidog Date: Sun, 16 Nov 2014 03:23:48 +0900 Subject: [PATCH 3/6] =?UTF-8?q?=E3=83=AB=E3=83=BC=E3=83=86=E3=82=A3?= =?UTF-8?q?=E3=83=B3=E3=82=B0=E3=81=AE=E8=A8=AD=E5=AE=9A=E3=82=89=E3=81=B8?= =?UTF-8?q?=E3=82=93=E3=81=BE=E3=81=A7=E8=A8=98=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- best_practices/controllers.rst | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/best_practices/controllers.rst b/best_practices/controllers.rst index 41c6ac1..2569e3c 100644 --- a/best_practices/controllers.rst +++ b/best_practices/controllers.rst @@ -1,8 +1,7 @@ コントローラー =========== - -Symfonyは薄いコントローラとファットなモデルという哲学に従います。 この哲学が意味する事は、様々な -アプリケーションを扱うに為にグルーコードな薄いコントローラを維持する事が必要だという事です。 +Symfonyは薄いコントローラとファットなモデルという哲学に従います。 つまり、コントローラは、 +アプリケーションの様々な部分をとりまとめるグルーコードだけからなる薄いレイヤーにするべきです。 経験則として、正確な基準はありませんが、コントローラに定義する変数は5個以下、 アクションの数が10個以下で、各アクション内の行数は20行以内という「5-10-20ルール」に従う事は @@ -10,7 +9,7 @@ Symfonyは薄いコントローラとファットなモデルという哲学に .. best-practice:: - あなたがコントローラを作る場合``FrameworkBundle``のコントローラを継承し, + 開発者がコントローラを作る場合``FrameworkBundle``のコントローラを継承し、 可能な限り、ルーティング、キャッシュとセキュリティをアノテーションで設定してください。 @@ -20,3 +19,23 @@ Symfonyは薄いコントローラとファットなモデルという哲学に そして、コントローラーは薄く、数行のグルーコードであるべきで、 フレームワークからそれらを切り離すそうとすると、時間かかるので長期的に見ると利益になりません。 大量の時間を費やすだけで、何の価値もありません。 + +加えて、 ルーティング、キャッシュ、セキュリティに対してアノテーションを使用すると簡単に設定する事ができます。 +すべての設定は必要な場所に一つのフォーマットにすれば、YAML, XML, PHPなどの複数ファイルを見る必要がなくなります。 + +全体的にビジネスロジックをフレームワークから切り離すという手段は積極的に行うと +同時に、最大限に活用にするためにルーティングとコントローラは結合するべきです。 + +ルーティング設定 +--------------------- + +コントローラで定義されたアノテーションを利用するにはrouting.ymlに以下の設定を追加します。 + +.. code-block:: yaml + + # app/config/routing.yml + app: + resource: "@AppBundle/Controller/" + type: annotation + + From c5fd41390d4f3dfd57e7db1d12ca49a6d13b3af8 Mon Sep 17 00:00:00 2001 From: polidog Date: Sun, 16 Nov 2014 03:56:34 +0900 Subject: [PATCH 4/6] =?UTF-8?q?template=E3=81=AE=E3=82=A2=E3=83=8E?= =?UTF-8?q?=E3=83=86=E3=83=BC=E3=82=B7=E3=83=A7=E3=83=B3=E3=81=AB=E9=96=A2?= =?UTF-8?q?=E3=81=97=E3=81=A6=E3=81=AE=E5=85=88=E9=A0=AD=E9=83=A8=E5=88=86?= =?UTF-8?q?=E3=82=92=E7=BF=BB=E8=A8=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- best_practices/controllers.rst | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/best_practices/controllers.rst b/best_practices/controllers.rst index 2569e3c..2c2d49b 100644 --- a/best_practices/controllers.rst +++ b/best_practices/controllers.rst @@ -38,4 +38,32 @@ Symfonyは薄いコントローラとファットなモデルという哲学に resource: "@AppBundle/Controller/" type: annotation - +``src/AppBundle/Controller/`` ディレクトリとそのサブディレクトリからコントローラの +アノテーションをロードします。 +もしアプリケーションに多くのコントローラがある場合、それらをサブディレクトリへ移動する事が可能です。 + +.. code-block:: text + + / + ├─ ... + └─ src/ + └─ AppBundle/ + ├─ ... + └─ Controller/ + ├─ DefaultController.php + ├─ ... + ├─ Api/ + │ ├─ ... + │ └─ ... + └─ Backend/ + ├─ ... + └─ ... + +テンプレート設定 +---------------------- + +.. best-practice:: + + テンプレートの設定は ``@Template()`` アノテーションを使用しないでください。 + +``@Template``は便利ですがいくつかの魔法を伴うので、お勧めする事はできません。 From 75da09877691f4102ab11fd47c83bf0be103897e Mon Sep 17 00:00:00 2001 From: polidog Date: Mon, 17 Nov 2014 02:35:04 +0900 Subject: [PATCH 5/6] =?UTF-8?q?=E3=82=A2=E3=83=8E=E3=83=86=E3=83=BC?= =?UTF-8?q?=E3=82=B7=E3=83=A7=E3=83=B3=E9=83=A8=E5=88=86=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E8=A8=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- best_practices/controllers.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/best_practices/controllers.rst b/best_practices/controllers.rst index 2c2d49b..b94d263 100644 --- a/best_practices/controllers.rst +++ b/best_practices/controllers.rst @@ -67,3 +67,7 @@ Symfonyは薄いコントローラとファットなモデルという哲学に テンプレートの設定は ``@Template()`` アノテーションを使用しないでください。 ``@Template``は便利ですがいくつかの魔法を伴うので、お勧めする事はできません。 + +ほとんどの場合、``@Template``はパラメータの設定をせず使用されます。そして設定すると、どの +テンプレートを表示するかをわかりづらくします。それはまた、必ずコントローラはレスポンスオブジェクトを +返すべきだと言う事を初心者にわかりにくくしてしまいます。(あなたがビューレイヤーを利用している場合以外) From 7fde34cfb6502d65f2b7ebbc653aa55135edb017 Mon Sep 17 00:00:00 2001 From: polidog Date: Fri, 21 Nov 2014 02:15:42 +0900 Subject: [PATCH 6/6] =?UTF-8?q?=E3=82=82=E3=81=86=E3=81=99=E3=81=93?= =?UTF-8?q?=E3=81=97=E3=81=99=E3=81=99=E3=82=93=E3=81=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- best_practices/controllers.rst | 126 +++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/best_practices/controllers.rst b/best_practices/controllers.rst index b94d263..26db166 100644 --- a/best_practices/controllers.rst +++ b/best_practices/controllers.rst @@ -71,3 +71,129 @@ Symfonyは薄いコントローラとファットなモデルという哲学に ほとんどの場合、``@Template``はパラメータの設定をせず使用されます。そして設定すると、どの テンプレートを表示するかをわかりづらくします。それはまた、必ずコントローラはレスポンスオブジェクトを 返すべきだと言う事を初心者にわかりにくくしてしまいます。(あなたがビューレイヤーを利用している場合以外) + +最後に、@Templateアノテーションはkernel.viewイベントのイベントディスパッチのフックとして +TemplateListenerクラスで利用されます。そのリスナーのパフォーマンスへの影響を紹介します。 +ブログのサンプルアプリケーションのホームページをレンダリングする場合、$this->render()メソッドを +使った場合5ミリ秒かかり、@Templateアノテーションを使った場合26ミリ秒かかりました。 + +How the Controller Looks +------------------------ + +Considering all this, here is an example of how the controller should look +for the homepage of our app: + +.. code-block:: php + + namespace AppBundle\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\Controller; + use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; + + class DefaultController extends Controller + { + /** + * @Route("/", name="homepage") + */ + public function indexAction() + { + $em = $this->getDoctrine()->getManager(); + $posts = $em->getRepository('App:Post')->findLatest(); + + return $this->render('default/index.html.twig', array( + 'posts' => $posts + )); + } + } + +.. _best-practices-paramconverter: + +ParamConverterを使う +------------------------ + +もしDoctrineを使っている場合は必要に応じて`ParamConverter`_ を使い、自動的にエンティティを取得し、 +コントローラの引数として渡す必要があります。 + +.. best-practice:: + + シンプルかつ簡単な場合は、自動的にDoctrineのエンティティを取得出来るParamConverterを使用 + してください。 + +例: + +.. code-block:: php + + /** + * @Route("/{id}", name="admin_post_show") + */ + public function showAction(Post $post) + { + $deleteForm = $this->createDeleteForm($post); + + return $this->render('admin/post/show.html.twig', array( + 'post' => $post, + 'delete_form' => $deleteForm->createView(), + )); + } + +通常は ``showAction`` では ``$id`` という変数を引数として使うと思います。 +代わりに ``$post`` 引数と ``Post`` クラス(Doctrineのエンティティ)をタイプヒンティングする +ことによって、そのオブジェクトを自動的にParamConverterが``{id}`` の値と一致する +``$id`` プロパティのものを取得します。``Post`` が見つからなかった場合は404ページが表示されます。 + +高度な事 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This works without any configuration +This works without any configuration because the wildcard name ``{id}`` matches +the name of the property on the entity. If this isn't true, or if you have +even more complex logic, the easiest thing to do is just query for the entity +manually. In our application, we have this situation in ``CommentController``: + +.. code-block:: php + + /** + * @Route("/comment/{postSlug}/new", name = "comment_new") + */ + public function newAction(Request $request, $postSlug) + { + $post = $this->getDoctrine() + ->getRepository('AppBundle:Post') + ->findOneBy(array('slug' => $postSlug)); + + if (!$post) { + throw $this->createNotFoundException(); + } + + // ... + } + +You can also use the ``@ParamConverter`` configuration, which is infinitely +flexible: + +.. code-block:: php + + use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; + use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; + + /** + * @Route("/comment/{postSlug}/new", name = "comment_new") + * @ParamConverter("post", options={"mapping": {"postSlug": "slug"}}) + */ + public function newAction(Request $request, Post $post) + { + // ... + } + +The point is this: the ParamConverter shortcut is great for simple situations. +But you shouldn't forget that querying for entities directly is still very +easy. + +Pre and Post Hooks +------------------ + +If you need to execute some code before or after the execution of your controllers, +you can use the EventDispatcher component to `set up before/after filters`_. + +.. _`ParamConverter`: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html +.. _`set up before/after filters`: http://symfony.com/doc/current/cookbook/event_dispatcher/before_after_filters.html