0

我配置了以下 UserDataPersister (直接取自教程):

Information for Service "App\DataPersister\UserDataPersister"
============================================================= 
  Service ID       App\DataPersister\UserDataPersister            
  Class            App\DataPersister\UserDataPersister            
  Tags             api_platform.data_persister (priority: -1000)  
  Public           no                                             
  Shared           yes                                            
  Abstract         no                                             
  Autowired        yes                                            
  Autoconfigured   yes                                            

和以下用户夹具:

App\Entity\User:
    user_{1..10}:
        email: "usermail_<current()>\\@email.org"
        plainPassword: "plainPassword_<current()>"
        __calls:
          - initUuid: []

但是加载此夹具时出现错误:

  An exception occurred while executing 'INSERT INTO "user" (id, uuid, roles, password, email) VALUES (?, ?, ?, ?, ?)' with params [281, "16ac40d3-53af-45dc-853f-e26f188d  
  1818", "[]", null, "usermail1@email.org"]:                                                                                                                                
                                                                                                                                                                            
  SQLSTATE[23502]: Not null violation: 7 ERROR:  null value in column "password" of relation "user" violates not-null constraint                                            
  DETAIL:  Failing row contains (281, 16ac40d3-53af-45dc-853f-e26f188d1818, [], null, usermail1@email.org).                                                                 

我的 UserDataPersister 实现与相同。

4

1 回答 1

1

引用文章末尾

如果我们现在停下来......耶!我们还没有......真的......做任何事情:我们添加了这个新的 plainPassword 属性......但没有使用它!因此,请求最终会在数据库中爆炸,因为我们的 $password 字段将为空。

接下来,我们需要挂钩到请求处理过程:我们需要在反序列化之后但在持久化之前运行一些代码。我们将使用数据持久化器来做到这一点。

由于单元测试会发布请求,因此数据持久化器由 api-platform 调用,它将按事件获取编码逻辑。在固定装置的情况下,直接进行教条批量插入,这将绕过所有持久性逻辑并导致密码为空。

正如@rishta 提到的,有一种方法可以解决这个问题,如文档中所引用,使用处理器实现数据夹具的散列

<?php
namespace App\DataFixtures\Processor;

use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Fidry\AliceDataFixtures\ProcessorInterface;
use App\Entity\User;

final class UserProcessor implements ProcessorInterface
{
    private $userPasswordEncoder;

    public function __construct(EntityManagerInterface $entityManager, UserPasswordEncoderInterface $userPasswordEncoder) {
        $this->userPasswordEncoder = $userPasswordEncoder;
    }

    /**
     * @inheritdoc
     */
    public function preProcess(string $fixtureId, $object): void {
        if (false === $object instanceof User) {
            return;
        }

        $object = $this->userPasswordEncoder(
                $object,
                $object->getPlainPassword()
        );
    }

    /**
     * @inheritdoc
     */
    public function postProcess(string $fixtureId, $object): void
    {
        // do nothing
    }
}

注册服务:

# app/config/services.yml

services:
    _defaults:
        autoconfigure: true

    App\DataFixtures\Processor\UserProcessor: ~
        #add tag in case autoconfigure is disabled, no need for auto config
        #tags: [ { name: fidry_alice_data_fixtures.processor } ]

在 API 平台中进行输入屏蔽的更好方法之一是使用 DTO 模式,与文章建议的相反,您可以在其中:

  • 创建单独的输入和输出数据对象
  • 在对象之间转换基础日期
  • 在需要时为每个操作选择不同的 IO 对象

文档中有关 DTO 的更多信息

于 2021-04-20T09:53:34.163 回答