Symfony 4序列化实体没有关系

nic*_*ram 5 serialization entity doctrine-orm symfony4

我必须记录每个实体的更改。我有侦听器,用于侦听preRemove,postUpdate和postDelete上的事件。我的实体AccessModule有关系:

App \ Entity \ AccessModule.php

/**
 * @ORM\OneToMany(targetEntity="App\Entity\AccessModule", mappedBy="parent")
 * @ORM\OrderBy({"id" = "ASC"})
 */
private $children;

/**
 * @ORM\ManyToOne(targetEntity="App\Entity\AccessModule", inversedBy="children")
 * @ORM\JoinColumn(name="parent_id", referencedColumnName="id", nullable=true)
 */
private $parent;

/**
 * @ORM\ManyToMany(targetEntity="App\Entity\AccessModuleRoute", inversedBy="access_modules")
 * @ORM\JoinTable(name="access_routes",
 *     joinColumns={@ORM\JoinColumn(name="access_module_id", referencedColumnName="id")},
 *     inverseJoinColumns={@ORM\JoinColumn(name="route_id", referencedColumnName="id")})
 *
 */
private $routes;
Run Code Online (Sandbox Code Playgroud)

在侦听器中: App \ EventListener \ EntityListener.php

use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;


    $encoders = [new XmlEncoder(), new JsonEncoder()];
    $normalizer = new ObjectNormalizer();

        $normalizer->setCircularReferenceHandler(function ($object) {
            return $object->getId();
        });

    $this->serializer = new Serializer([$normalizer], $encoders);


public function createLog(LifecycleEventArgs $args, $action){
    $em = $args->getEntityManager();
    $entity = $args->getEntity();
    if ($this->tokenStorage->getToken()->getUser()) {
        $username = $this->tokenStorage->getToken()->getUser()->getUsername();
    } else {
        $username = 'anon'; // TODO Remove anon. set null value
    }

    $log = new Log();
//      $log->setData('dddd')
        $log->setData($this->serializer->serialize($entity, ''json)
            ->setAction($action)
            ->setActionTime(new \DateTime())
            ->setUser($username)
            ->setEntityClass(get_class($entity));
        $em->persist($log);
        $em->flush();
    }
Run Code Online (Sandbox Code Playgroud)

我在使用序列化时遇到问题,在使用$log->setData($entity)Circular时遇到问题。当我进行序列化时,$log->setData($this->serializer->serialize($entity, ''json)我与父母的孩子,与孩子的孩子有充分的联系。结果我得到一棵完整的树:/我想得到

期望

[
 'id' => ID,
 'name' => NAME,
 'parent' => parent_id // ManyToOne, I'd like get its id
 'children' => [$child_id, $child_id, $child_id] // array of $id of children array collection
]
Run Code Online (Sandbox Code Playgroud)

(当然这是在将其编码为json之前的草稿)

没有完全联系,如何获得期望的数据?

Rob*_*ert 9

您正在寻找的东西称为序列化组:herehere

现在让我解释一下它是如何工作的。这很简单。假设您有 Post 实体:

class Post
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     * @Groups({"default"})
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\User\User")
     * @Groups({"default"})
     */
    private $author;
}
Run Code Online (Sandbox Code Playgroud)

你还有用户实体:

class User
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     * @Groups({"default"})
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=40)
     * @Groups({"default"})
     */
    private $firstName;

    /**
     * @ORM\Column(type="string", length=40)
     */
    private $lastName;
}
Run Code Online (Sandbox Code Playgroud)

帖子可以有作者(用户),但我不想每次都返回所有用户数据。我只对 id 和名字感兴趣。

仔细看看@Groups注释。您可以指定所谓的序列化组。这只不过是告诉 Symfony 您希望在结果集中包含哪些数据的便捷方式。

您必须通过在属性/getter 上方以注释的形式添加相关组来告诉 Symfony 序列化程序您希望保留哪些关系。您还必须指定要保留的关系的哪些属性或 getter。

现在如何让 Symfony 知道这些东西?

当您准备/配置您的序列化服务时,您只需提供如下定义的组:

return $this->serializer->serialize($data, 'json', ['groups' => ['default']]);
Run Code Online (Sandbox Code Playgroud)

围绕原生 symfony 序列化程序构建某种包装服务是很好的,这样您就可以简化整个过程并使其更可重用。

还要确保正确配置了序列化程序 - 否则它不会考虑这些组。

这也是“处理”循环引用的一种方式(以及其他方式)。

现在您只需要研究如何格式化结果集。

  • 很好的答案。我想添加一点:要告诉 Symfony 你想从注释中读取组,你必须这样做。$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); 定义 classMetadataFactory 并将其作为参数传递给 ObjectNormalizer。$normalizer = new ObjectNormalizer($classMetadataFactory); https://symfony.com/doc/current/components/serializer.html#configure-name-conversion-using-metadata (2认同)

Bre*_*lsh 6

ignored_attributes提供了一种快速、简单的方法来完成您正在寻找的任务。

$serializer->serialize($object, 'json', ['ignored_attributes' => ['ignored_property']]); 
Run Code Online (Sandbox Code Playgroud)

下面是如何与序列化器一起使用:

use Acme\Person;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

$person = new Person();
$person->setName('foo');
$person->setAge(99);

$normalizer = new ObjectNormalizer();
$encoder = new JsonEncoder();

$serializer = new Serializer([$normalizer], [$encoder]);
$serializer->serialize($person, 'json', ['ignored_attributes' => ['age']]); 
Run Code Online (Sandbox Code Playgroud)

文档:https ://symfony.com/doc/current/components/serializer.html#ignoring-attributes