私はSymfonyのソースを読んで、それを動作させるためにいくつかのトリックを試してきました(私のプロジェクトで、サードパーティのバンドルをインストールせずに、その機能ではなく)。私はCompilerPass(https://symfony.com/doc/current/service_container/compiler_passes.html)... 3つの段階で動作します使用:
1.は、app/AppKernel.php
にロードするために私の最初のバンドルですので、私はAppBundle
を選びましバンドル
でbuild
メソッドを定義します。
のsrc/AppBundle/AppBundle.php
<?php
namespace AppBundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class AppBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new AppCompilerPass());
}
}
2.カスタムを書くCompilerPass
のSymfonyシリアライザはserializer
サービスで全てです。だから私はちょうどそれを取得し、そのinstanciationをキャッチするために、それにconfigurator
オプションを追加しました。
のsrc/AppBundle/AppCompilerPass.php
<?php
namespace AppBundle;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
class AppCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$container
->getDefinition('serializer')
->setConfigurator([
new Reference(AppConfigurer::class), 'configureNormalizer'
]);
}
}
3.コンフィギュラを書く...ここ
、あなたはカスタムCompilerPass(Iに書いたものを、次のクラスを作成しますchoosed AppConfigurer
)...カスタムコンパイラパスで選択した名前の後に名前が付けられたインスタンスメソッドを持つクラス(私はconfigureNormalizer
を選択しました)。
このメソッドは、symfony内部シリアライザが作成されるときに呼び出されます。
symfonyのシリアライザは、プライベート/保護されたプロパティとして正規化し、デコーダと、このような事を含まれています。だから、PHPの\Closure::bind
メソッドを使用してsymfonyシリアライザの範囲を$this
としてラムダのような関数(PHP Closure)にしました。
ノルマライザ($this->normalizers
)をループすると、ビヘイビアをカスタマイズできます。実際には、これらのノミナライザのすべてが循環参照ハンドラ(DateTimeNormalizer
など)を必要としているわけではありません。
のsrc/AppBundle/AppConfigurer.php
<?php
namespace AppBundle;
class AppConfigurer
{
public function configureNormalizer($normalizer)
{
\Closure::bind(function() use (&$normalizer)
{
foreach ($this->normalizers as $normalizer)
if (method_exists($normalizer, 'setCircularReferenceHandler'))
$normalizer->setCircularReferenceHandler(function ($object)
{
return $object->getId();
});
}, $normalizer, $normalizer)();
}
}
結論
としては、先に述べた、私はFOSRestBundleも第三者バンドルなどを望んでいたdind'tので、私は私のプロジェクトのためにそれをやりました私は解決策としてインターネットを見てきました。その部分ではなく(セキュリティのためかもしれません)。私のコントローラーは今のように...
<?php
namespace StoreBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class ProductController extends Controller
{
/**
*
* @Route("/products")
*
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$data = $em->getRepository('StoreBundle:Product')->findAll();
return $this->json(['data' => $data]);
}
/**
*
* @Route("/product")
* @Method("POST")
*
*/
public function newAction()
{
throw new \Exception('Method not yet implemented');
}
/**
*
* @Route("/product/{id}")
*
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$data = $em->getRepository('StoreBundle:Product')->findById($id);
return $this->json(['data' => $data]);
}
/**
*
* @Route("/product/{id}/update")
* @Method("PUT")
*
*/
public function updateAction($id)
{
throw new \Exception('Method not yet implemented');
}
/**
*
* @Route("/product/{id}/delete")
* @Method("DELETE")
*
*/
public function deleteAction($id)
{
throw new \Exception('Method not yet implemented');
}
}
優れたソリューション!コンパイラが作成された場所を渡すのは、これが理由です。 –
あまりにも多くの可能性、あまりにも短い時間、あまりにも簡潔で良いとあまりにも広すぎるドキュメント。そして、OPが述べたように、この完璧な解決策を得るまで、彼は一週間を過ごしました。それは私たちの多くが持っていない贅沢です。 :(したがって、私は個人的にこの解決策に行くだろう:https://stackoverflow.com/a/44286659/261332。 – userfuser
@urserfuserあなたのコメントと共に、その解決策を読んだ。私が見つけた解決策を投稿した理由(2) "完璧な解決策"の時点でそうは言いませんが、シリアライザ(JSON、XML、YAMLなど)をインスタンス化したかったわけではありません。私のAPIの各ルート(3)OOPの設計では、私はそのClosure :: bindを誇りに思っていません。それはphpのコアであり、PHPのデザインリークとよく似ています。 Symfonyは自動的にJSON、YAML、またはXMLフォーマットを同様に処理するので、私はあなたの選択によってこのソリューションを選択します。 –