В течение недели я читал исходный код Symfony и пробовал некоторые приемы, чтобы заставить его работать (в моем проекте и без установки стороннего пакета: не для этой функциональности), и наконец я получил его. Я использовал CompilerPass (https://symfony.com/doc/current/service_container/compiler_passes.html)... который работает в три этапа:
1. Определите метод 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
)... Класс с методом экземпляра, названным в честь того, что вы выбрали в пользовательском проходе компилятора (я выбрал 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 или какой-либо сторонний пакет, который я видел в Интернете в качестве решения: не для этой части (может быть, для безопасности). Мои контроллеры теперь стоят как...
<?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');
}
}
person
Salathiel Genèse
schedule
07.10.2017