The HttpKernel Component: The HttpKernel Class

If you were to use our framework right now, you would probably have to add support for custom error messages. We do have 404 and 500 error support but the responses are hardcoded in the framework itself. Making them customizable is straightforward though: dispatch a new event and listen to it. Doing it right means that the listener has to call a regular controller. But what if the error controller throws an exception? You will end up in an infinite loop. There should be an easier way, right?

私たちのフレームワークをすぐに使用する場合は、おそらくカスタム エラー メッセージのサポートを追加する必要があります。 404 および 500 エラーのサポートはありますが、応答はフレームワーク自体にハードコーディングされています。ただし、それらをカスタマイズ可能にするのは簡単です。新しいイベントをディスパッチして、それをリッスンします。正しく行うということは、リスナーが通常のコントローラーを呼び出さなければならないことを意味します。しかし、エラー コントローラが例外をスローした場合はどうなるでしょうか。無限ループに陥ります。もっと簡単な方法があるはずですよね?

Enter the HttpKernel class. Instead of solving the same problem over and over again and instead of reinventing the wheel each time, the HttpKernel class is a generic, extensible and flexible implementation of HttpKernelInterface.

HttpKernel クラスに入ります。同じ問題を何度も解決し、毎回車輪を再発明する代わりに、HttpKernel クラスは、HttpKernelInterface の汎用的で拡張可能で柔軟な実装です。

This class is very similar to the framework class we have written so far: it dispatches events at some strategic points during the handling of the request, it uses a controller resolver to choose the controller to dispatch the request to, and as an added bonus, it takes care of edge cases and provides great feedback when a problem arises.

このクラスは、これまでに作成したフレームワーク クラスと非常によく似ています。リクエストの処理中にいくつかの戦略的なポイントでイベントをディスパッチし、コントローラー リゾルバーを使用して、コントローラーを選択してリクエストをディスパッチします。エッジケースの世話をし、問題が発生したときに素晴らしいフィードバックを提供します.

Here is the new framework code:

新しいフレームワーク コードは次のとおりです。
1
2
3
4
5
6
7
8
// example.com/src/Simplex/Framework.php
namespace Simplex;

use Symfony\Component\HttpKernel\HttpKernel;

class Framework extends HttpKernel
{
}

And the new front controller:

そして新しいフロントコントローラー:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// example.com/web/front.php
require_once __DIR__.'/../vendor/autoload.php';

use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel;
use Symfony\Component\Routing;

$request = Request::createFromGlobals();
$requestStack = new RequestStack();
$routes = include __DIR__.'/../src/app.php';

$context = new Routing\RequestContext();
$matcher = new Routing\Matcher\UrlMatcher($routes, $context);

$controllerResolver = new HttpKernel\Controller\ControllerResolver();
$argumentResolver = new HttpKernel\Controller\ArgumentResolver();

$dispatcher = new EventDispatcher();
$dispatcher->addSubscriber(new HttpKernel\EventListener\RouterListener($matcher, $requestStack));

$framework = new Simplex\Framework($dispatcher, $controllerResolver, $requestStack, $argumentResolver);

$response = $framework->handle($request);
$response->send();

RouterListener is an implementation of the same logic we had in our framework: it matches the incoming request and populates the request attributes with route parameters.

RouterListener は、フレームワークで使用していたのと同じロジックの実装です。受信リクエストを照合し、requestattributes にルート パラメーターを設定します。

Our code is now much more concise and surprisingly more robust and more powerful than ever. For instance, use the built-in ErrorListener to make your error management configurable:

私たちのコードはこれまで以上に簡潔になり、驚くほど堅牢で強力になりました。たとえば、組み込みの ErrorListener を使用して、エラー管理を構成可能にします。
1
2
3
4
5
6
$errorHandler = function (Symfony\Component\ErrorHandler\Exception\FlattenException $exception) {
    $msg = 'Something went wrong! ('.$exception->getMessage().')';

    return new Response($msg, $exception->getStatusCode());
};
$dispatcher->addSubscriber(new HttpKernel\EventListener\ErrorListener($errorHandler));

ErrorListener gives you a FlattenException instance instead of the thrown Exception or Error instance to ease exception manipulation and display. It can take any valid controller as an exception handler, so you can create an ErrorController class instead of using a Closure:

ErrorListener は、例外の操作と表示を容易にするために、スローされた Exception または Error インスタンスの代わりに FlattenException インスタンスを提供します。例外ハンドラーとして有効なコントローラーを使用できるため、クロージャーを使用する代わりに ErrorController クラスを作成できます。
1
2
3
4
$listener = new HttpKernel\EventListener\ErrorListener(
    'Calendar\Controller\ErrorController::exception'
);
$dispatcher->addSubscriber($listener);

The error controller reads as follows:

エラー コントローラは次のように読み取ります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// example.com/src/Calendar/Controller/ErrorController.php
namespace Calendar\Controller;

use Symfony\Component\ErrorHandler\Exception\FlattenException;
use Symfony\Component\HttpFoundation\Response;

class ErrorController
{
    public function exception(FlattenException $exception)
    {
        $msg = 'Something went wrong! ('.$exception->getMessage().')';

        return new Response($msg, $exception->getStatusCode());
    }
}

Voilà! Clean and customizable error management without efforts. And if your ErrorController throws an exception, HttpKernel will handle it nicely.

ほら!労力をかけずにクリーンでカスタマイズ可能なエラー管理。そして、yourErrorController が例外をスローした場合、HttpKernel は適切に処理します。

In chapter two, we talked about the Response::prepare() method, which ensures that a Response is compliant with the HTTP specification. It is probably a good idea to always call it just before sending the Response to the client; that's what the ResponseListener does:

第 2 章では、Response::prepare() メソッドについて説明しました。これは、Response が HTTP 仕様に準拠していることを保証します。 Response をクライアントに送信する直前に常に呼び出すことをお勧めします。それが ResponseListener の機能です。
1
$dispatcher->addSubscriber(new HttpKernel\EventListener\ResponseListener('UTF-8'));

If you want out of the box support for streamed responses, subscribe to StreamedResponseListener:

すぐに使えるストリーミング レスポンスのサポートが必要な場合は、StreamedResponseListener にサブスクライブします。
1
$dispatcher->addSubscriber(new HttpKernel\EventListener\StreamedResponseListener());

And in your controller, return a StreamedResponse instance instead of a Response instance.

そしてコントローラーで、Response インスタンスの代わりに StreamedResponse インスタンスを返します。

Tip

ヒント

Read the Built-in Symfony Events reference to learn more about the events dispatched by HttpKernel and how they allow you to change the flow of a request.

ビルトイン Symfony イベント リファレンスを読んで、HttpKernel によってディスパッチされるイベントと、リクエストの流れをどのように変更できるかについて学んでください。

Now, let's create a listener, one that allows a controller to return a string instead of a full Response object:

それでは、コントローラーが完全な Response オブジェクトではなく文字列を返すことを可能にするリスナーを作成しましょう。
1
2
3
4
5
6
7
8
9
10
11
12
class LeapYearController
{
    public function index($year)
    {
        $leapYear = new LeapYear();
        if ($leapYear->isLeapYear($year)) {
            return 'Yep, this is a leap year! ';
        }

        return 'Nope, this is not a leap year.';
    }
}

To implement this feature, we are going to listen to the kernel.view event, which is triggered just after the controller has been called. Its goal is to convert the controller return value to a proper Response instance, but only if needed:

この機能を実装するには、コントローラーが呼び出された直後にトリガーされる kernel.viewevent をリッスンします。その目標は、コントローラーの戻り値を適切な Response インスタンスに変換することですが、必要な場合のみです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// example.com/src/Simplex/StringResponseListener.php
namespace Simplex;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ViewEvent;

class StringResponseListener implements EventSubscriberInterface
{
    public function onView(ViewEvent $event)
    {
        $response = $event->getControllerResult();

        if (is_string($response)) {
            $event->setResponse(new Response($response));
        }
    }

    public static function getSubscribedEvents()
    {
        return ['kernel.view' => 'onView'];
    }
}

The code is simple because the kernel.view event is only triggered when the controller return value is not a Response and because setting the response on the event stops the event propagation (our listener cannot interfere with other view listeners).

コントローラーの戻り値が Response でない場合にのみ kernel.view イベントがトリガーされ、イベントに response を設定するとイベントの伝播が停止するため、コードは単純です (リスナーは他のビュー リスナーに干渉できません)。

Don't forget to register it in the front controller:

フロントコントローラーに登録することを忘れないでください:
1
$dispatcher->addSubscriber(new Simplex\StringResponseListener());

Note

ノート

If you forget to register the subscriber, HttpKernel will throw an exception with a nice message: The controller must return a response (Nope, this is not a leap year. given)..

サブスクライバーを登録するのを忘れた場合、HttpKernel は適切なメッセージと共に例外をスローします: The controller must return a response(いいえ、これはうるう年ではありません。与えられた)..

At this point, our whole framework code is as compact as possible and it is mainly composed of an assembly of existing libraries. Extending is a matter of registering event listeners/subscribers.

この時点で、フレームワーク コード全体は可能な限りコンパクトになり、主に既存のライブラリのアセンブリで構成されています。拡張は、イベント リスナー/サブスクライバーの登録の問題です。

Hopefully, you now have a better understanding of why the simple looking HttpKernelInterface is so powerful. Its default implementation, HttpKernel, gives you access to a lot of cool features, ready to be used out of the box, with no efforts. And because HttpKernel is actually the code that powers the Symfony framework, you have the best of both worlds: a custom framework, tailored to your needs, but based on a rock-solid and well maintained low-level architecture that has been proven to work for many websites; a code that has been audited for security issues and that has proven to scale well.

シンプルな外観の HttpKernelInterface が非常に強力である理由について、理解を深めていただければ幸いです。デフォルトの実装である HttpKernel を使用すると、多くの優れた機能に簡単にアクセスでき、すぐに使用できます。また、HttpKernel は実際には Symfony フレームワークを強化するコードであるため、両方の長所を活用できます。つまり、ニーズに合わせて調整されたカスタム フレームワークですが、あらゆる Web サイトで動作することが証明されている堅固で適切に維持された低レベル アーキテクチャに基づいています。セキュリティの問題について監査され、十分に拡張できることが証明されたコード。