一周以来,我一直在阅读 Symfony 源代码并尝试一些技巧来使其工作(在我的项目中并且没有安装第三方包:不是为了那个功能),我终于得到了一个。我使用了 CompilerPass (https://symfony.com/doc/current/service_container/compiler_passes.html)...分三个步骤工作:
1。在bundle中定义build方法
我选择了AppBundle,因为它是我的第一个要在app/AppKernel.php 中加载的包。
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 服务下。所以我只是获取了它并添加了一个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 中编写的内容创建一个类(我选择了 AppConfigurer)... .
这个方法会在 symfony 内部序列化器被创建时被调用。
symfony 序列化器包含规范化器和解码器以及诸如私有/受保护属性之类的东西。这就是为什么我使用 PHP 的 \Closure::bind 方法将 symfony 序列化器作为 $this 作用于我的 lambda-like 函数(PHP Closure)。
然后通过 nomalizers ($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 或任何第三方捆绑包,正如我在 Internet 上看到的那样作为解决方案:不是为了那个部分(可能是为了安全)。我的控制器现在是...
<?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');
}
}