如何在 __contstruct 中注入服务?

How inject service in __contstruct?

我想在 __construct 中注入 Symfony\Component\Security\Core\Security 以获取当前用户。它需要我使用 @UniqueEnitity validator:

<?php

declare(strict_types=1);

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\Security;
//...


/**
 * @ApiResource()
 * @ORM\Entity(repositoryClass="App\Repository\SimpleEntityRepository")
 * @UniqueEntity(fields={"foo", "user"})
 */
class SimpleEntity
{

    //...

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\User")
     * @ORM\JoinColumn(nullable=false)
     */
    private $user;

    public function __construct(Security $security)
    {
        $this->user = $security->getUser();
    }

    //...
}

但我得到错误:Cannot create an instance of App\Entity\SimpleEntity from serialized data because its constructor requires parameter "security" to be present.

请帮忙

Symfony 可以将服务注入到其他服务的构造函数中,但不能注入到实体的构造函数中。

通常在实体上设置当前用户是通过装饰api内置的DataPersister来完成的。然而,持久化几乎发生在处理请求的末尾,而验证则发生得更早。因此,验证器将看不到持久者稍后设置的用户。因此,您需要在流程的早期设置用户,然后再进行验证。这可以通过 decorating Denormalizer 来完成。这是一项服务,因此您可以注入安全服务:

// api/src/Serializer/SimpleEntityDenormalizer

namespace App\Serializer;

use Symfony\Component\Security\Core\Security;
use Symfony\Component\Serializer\Normalizer\ContextAwareDenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\SerializerAwareInterface;
use Symfony\Component\Serializer\SerializerInterface;
use App\Entity\SimpleEntity;

final class SimpleEntityDenormalizer implements ContextAwareDenormalizerInterface, SerializerAwareInterface
{
    private $decorated;
    private $security;

    public function __construct(DenormalizerInterface $decorated, Security $security)
    {
        $this->decorated = $decorated;
        $this->security = $security;
    }

    public function supportsDenormalization($data, string $type, string $format = null, array $context = [])
    {
        if ($type !== SimpleEntity::class) return false;

        return $this->decorated->supportsDenormalization($data, $type, $format, $context);
    }

    public function denormalize($data, string $type, string $format = null, array $context = [])
    {
        $object = $this->decorated->denormalize($data, $type, $format, $context);

        if (null === $object->getUser()) {
            $object->setUser($this->security->getUser());
        }

        return $object;
    }

    public function setSerializer(SerializerInterface $serializer)
    {
        if($this->decorated instanceof SerializerAwareInterface) {
            $this->decorated->setSerializer($serializer);
        }
    }
}

将以下内容添加到 api/config/services.yaml:

'App\Serializer\SimpleEntityDenormalizer':
    arguments: 
    $decorated: '@api_platform.jsonld.normalizer.item' ]

这并没有取代装饰服务,而是增加了一个新服务。