Skip to content

Best practices controllers #337

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
7c3d36a
翻訳の途中...
polidog Oct 30, 2014
cd97754
キャッシングをキャッシュに変更
polidog Nov 15, 2014
905390a
ルーティングの設定らへんまで記述
polidog Nov 15, 2014
c5fd413
templateのアノテーションに関しての先頭部分を翻訳
polidog Nov 15, 2014
75da098
アノテーション部分を追記
polidog Nov 16, 2014
7fde34c
もうすこしすすんだ
polidog Nov 20, 2014
02d754e
Merge remote-tracking branch 'origin/master' into best-practices-cont…
DQNEO Jul 4, 2015
b908c6e
apply https://github.com/symfony-japan/symfony-docs-ja/pull/319#discu…
DQNEO Jul 4, 2015
1e19c51
refine best-practice
DQNEO Jul 4, 2015
110c3e7
refine document
DQNEO Jul 4, 2015
258c1bc
refine document
DQNEO Jul 4, 2015
1bc22d9
improve wording
DQNEO Jul 4, 2015
f0c2565
refine document
DQNEO Jul 4, 2015
bd4dd98
refine document
DQNEO Jul 4, 2015
6fb13dd
refine document
DQNEO Jul 4, 2015
20d91a9
refine document
DQNEO Jul 4, 2015
d77d16a
refine document
DQNEO Jul 4, 2015
f94b728
more readable
DQNEO Jul 4, 2015
72d726a
「コントローラ」で統一
DQNEO Jul 4, 2015
aae993a
improve wording
DQNEO Jul 4, 2015
e2ae95f
improve wording
DQNEO Jul 4, 2015
8369140
improve wording
DQNEO Jul 4, 2015
44afbf4
improve wording
DQNEO Jul 4, 2015
0051fd6
improve wording
DQNEO Jul 4, 2015
90692d7
improve wording
DQNEO Jul 4, 2015
0303175
translate
DQNEO Jul 4, 2015
ec2b073
use latest version
DQNEO Jul 4, 2015
2d780a9
refine document
DQNEO Jul 4, 2015
46103a0
update code block
DQNEO Jul 4, 2015
d2d9986
最新の英語版ではこれはなかったので
DQNEO Jul 4, 2015
d09ddd8
improve wording
DQNEO Jul 4, 2015
d38f234
update to latest
DQNEO Jul 4, 2015
f8d8992
translate
DQNEO Jul 4, 2015
5effa17
translate
DQNEO Jul 4, 2015
25bd601
translate
DQNEO Jul 4, 2015
144ddcd
translate title
DQNEO Jul 4, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
198 changes: 198 additions & 0 deletions best_practices/controllers.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
コントローラー
===========
Symfonyは薄いコントローラとファットなモデルという哲学を信奉します。 つまり、コントローラはアプリケーションの様々な部分をとりまとめるグルー(糊)コードだけからなる薄いレイヤーにするべきです。

だいたいの目安として、次の「5-10-20ルール」に従うとよいでしょう。
1コントローラで定義する変数を5個以下にすること、含まれるアクションを10個以下にすること、1アクションのコード行数を20行以下にすること。
この数字に科学的な根拠はありませんが、コントローラーからサービスへリファクタリングすべきタイミングを見極める基準としては役立ちます。


.. best-practice::

コントローラを作る場合``FrameworkBundle``のベースコントローラを継承し、
ルーティング、キャッシュ、セキュリティを設定するときはなるべくアノテーションを使ってください。


コントローラを基底フレームワークに結合させることで、フレームワークの機能すべてを
活用する事が可能になり、生産性が向上します。

コントローラは薄く数行のグルーコードであるべきです。何時間もかけてコントローラを
フレームワークから切り離そうとしても、長期的にはメリットがありません。
それに時間を費やしても何の価値もありません。

加えて、 ルーティング、キャッシュ、セキュリティに対してアノテーションを使えば設定がシンプルになります。
そうすれば、
YAML, XML, PHPなどのいろんなフォーマットで作られた何十もの設定ファイルを見る必要はなくなります。全ての設定は必要な場所に収まり、1つのフォーマットで済むでしょう。


あなたのビジネスロジックをフレームワークから切り離しながらも、
同時に、ルーティングとコントローラはフレームワークに積極的に結合するべきということです。
そうすればフレームワークを最大限活用できるでしょう。


ルーティングの設定
---------------------


コントローラでアノテーションとして定義されたルーティングを読み込むには、routing.ymlに以下の設定を追加します。

.. code-block:: yaml

# app/config/routing.yml
app:
resource: "@AppBundle/Controller/"
type: annotation

このように設定すると、``src/AppBundle/Controller/`` ディレクトリとそのサブディレクトリにあるコントローラのアノテーションを読み込んでくれます。・
もしアプリケーションに多くのコントローラがある場合、それらを下図のようにサブディレクトリを作ってその中に移動しても全く問題ありません。


.. code-block:: text

<your-project>/
├─ ...
└─ src/
└─ AppBundle/
├─ ...
└─ Controller/
├─ DefaultController.php
├─ ...
├─ Api/
│ ├─ ...
│ └─ ...
└─ Backend/
├─ ...
└─ ...

テンプレート設定
----------------------

.. best-practice::

コントローラから呼ばれるテンプレートの設定をするのに ``@Template()`` アノテーションを使用しないでください。

``@Template``は便利ですがある種の魔法を伴います。魔法を使うに値するとは思えないのでお勧めしません。

ほとんどの場合、``@Template``はパラメータなしで使われますが、そうするとどのテンプレートが呼ばれるのかわかりづらくなります。
また、コントローラは必ずレスポンスオブジェクトを返すべきだと言う事を初心者にわかりにくくします。(ビューレイヤーを使わない場合)

コントローラはこんな感じにしよう
------------------------

上記のことをふまえると、アプリケーションのホームページを表示するコントローラはこんな感じにするのがよいでしょう。

.. 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()
{
$posts = $this->getDoctrine()
->getRepository('AppBundle: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

use AppBundle\Entity\Post;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

/**
* @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ページを表示してくれます。

もっと複雑になったときは
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

上記のコードが設定なしで動くのは、ワイルドカード名``{id}``がエンティティのプロパティ名に一致するからです。
もしそうでない場合、またはもっと複雑なロジックがある場合、これを実現する簡単な方法は手動でエンティティを取得することです。
本アプリケーションでは``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();
}

// ...
}

``@ParamConverter`` 設定を使うこともできます。そうすればどこまでも柔軟にできます。:

.. code-block:: php

use AppBundle\Entity\Post;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Component\HttpFoundation\Request;

/**
* @Route("/comment/{postSlug}/new", name = "comment_new")
* @ParamConverter("post", options={"mapping": {"postSlug": "slug"}})
*/
public function newAction(Request $request, Post $post)
{
// ...
}

ポイントは、ParamConverterはシンプルなケースでは素晴らしいということです。
一方エンティティを直接取得するのも簡単にできるということを忘れないでください。

事前フックと事後フック
------------------

もしコントローラの実行前後で任意のコードを実行したいなら、EventDipatcherコンポーネントを使うことができます。
:doc:`set up before and after filters </cookbook/event_dispatcher/before_after_filters>`.

.. _`ParamConverter`: https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html