投稿は
この質問に触発され
ています。 標準のSymfonyイベントを使用して、コントローラーの出力をオーバーライドします。 だから、一般的に、これはすべてどのように機能します:
- Ajaxアノテーションを作成して、コントローラーのコンテンツタイプを処理します
- イベントを通じてこの注釈を処理します。
- 注釈で選択されたタイプに従ってコンテンツタイプを再定義します
私はすぐに警告します、コードは完璧であるふりをせず、キャッシングは使用されません(これについては後で説明します)が、主なアイデアは理解できると思います。 また、
公式ドキュメントでSymfony2 Internalsの詳細を読むことができ
ます 。
それでは、違反してみましょう。
最初に、注釈クラスを定義します。
namespace SomeNamespace\SomeBundle\Annotations; class Ajax { public $contentType; public $parameters; public function __construct($data) { if (isset($data['value'])) { $this->contentType = $data['value']; } if (isset($data['parameters'])) { $this->parameters = $data['parameters']; } } public function setContentType($contentType) { $this->contentType = $contentType; } public function getContentType() { return $this->contentType; } }
この注釈は、コントローラーが提供するコンテンツのタイプを決定します。
次に、イベントリスナーを作成します。
namespace SomeNamespace\SomeBundle\Event; use Symfony\Component\HttpKernel\Event\KernelEvent; use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; use Doctrine\Common\Annotations\Reader; use Symfony\Component\HttpFoundation\Response; class ControllerListener { private $container; private $parameters; private $annotationReader;
そして、システムに登録します:
#SomeBundle\Resources\config\services.yml services: my.ajax.listener: class: "SomeNamespace\SomeBundle\Event\ControllerListener" tags: [{name: kernel.event_listener, event: kernel.response, method: onKernelResponse, priority: -128}, {name: kernel.event_listener, event: kernel.request, method: onKernelRequest}, {name: kernel.event_listener, event: kernel.view, method: onKernelView, priority: -128}, {name: kernel.event_listener, event: kernel.controller, method: onKernelController}] arguments: [@service_container, @annotation_reader]
もう1つの議論、優先度に注意してください。 イベントの優先度を設定します。 例として、Drupalが思い浮かびます。 これはモジュール重量の類似物であり、正反対です。 Drupalでは、重みが大きいほど、フックが後で呼び出されます。 また、Symfonyでは、優先度が高いほど、イベントが早く呼び出されます。
したがって、各コンテンツタイプの構造は次のようになります。
開始するには、インターフェースを作成します。
namespace SomeNamespace\SomeBundle\Core; interface ContentTypeInterface { public static function getName(); public function encodeParameters($data); public function decodeParameters($data); public function hookPre($request); public function hookPost($response); }
そして今、私はより詳細に教えます:
- encodeParameters-入力データを目的のコンテンツタイプにエンコードします(たとえば、JSONの場合はjson_encodeになります)
- decodeParameters-入力データを目的のコンテンツタイプにデコードします(たとえば、JSONの場合はjson_decodeになります)。 これは、1つのPOSTパラメーターで同じコンテンツタイプにデータが詰め込まれている場合に便利です。
- hookPre-コントローラーに対してリクエストが行われたときに呼び出されます。ここでは、content-typeはリクエストオブジェクトで何でもできます
- hookPost-コントローラーが応答するときに呼び出されます。ここでは、content-typeは応答オブジェクトで何でもできます
次に、インターフェイスを実装するクラスを作成し、そこからすべてのコンテンツタイプが継承されます。
namespace SomeNamespace\SomeBundle\Core; class ContentType implements ContentTypeInterface { protected $container; protected $parameters; public function __construct($container, $params = array()){ $this->container = $container; $this->parameters = $params; } public static function getName() { return 'contentType'; } public function encodeParameters($data) { return $data; } public function decodeParameters($data) { return $data; } public function hookPre($request) { } public function hookPost($response) { return $response; } }
ご覧のとおり、ContentTypeInterfaceインターフェースを実装しています。
これで、独自のコンテンツタイプを作成できるようになりました。たとえば、jsonコンテンツタイプを提供します。
namespace SomeNamespace\SomeBundle\Core\ContentTypes; use SomeNamespace\SomeBundle\Core\ContentType; class JSONContentType extends ContentType { private $params; public static function getName() { return "json"; } public function hookPost($response) { return $response; } public function encodeParameters($data) { return json_encode($data); } public function decodeParameters($data) { return json_decode($data); } }
結論として、ルートとパラメーターの生成に使用されるjavascriptコードを提供します。
そして、この全体を保存して使用するjavascriptも:
(function () { SF = function () { }; SF.prototype.fn = SF.prototype; SF = new SF(); SF.fn.Storage = {}; SF.fn.hasValue = function (name) { return this.Storage[name] !== undefined; }; SF.fn.getValue = function (name) { if (this.hasValue(name)) { return this.Storage[name]; } else { return void 0; } }; SF.fn.getAllValues = function () { return this.Storage }; SF.fn.loggingEnabled = function () { return this.parameters.debug; }; SF.fn.messagingEnabled = function () { return this.parameters.messaging !== undefined && this.parameters.messaging; }; SF.fn.getMessages = function () { return !this.framework || this.framework.messaging === undefined ? { } : this.framework.messaging; };
さて、今、最も興味深いのは仕事の例です。 コントローラーでアクションを作成します。
コントローラーの応答は次のようになります。
{ a: "b", d: "c" }
また、javascriptの例:
SF.l(SF.path('JSBundle_ajax', {'key': 'asd'}));
Symfonyでデバッグが無効になっている場合、コンソールには何も印刷されませんが、そうでない場合は印刷されます:
/ ajax / asd
PSアドオンは大歓迎です。 賢い考えを聞いてうれしいです。