API 平台 + alice UserDataPersister 无法使用固定装置

API Platform + alice UserDataPersister not working with fixtures

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

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 实现与 this 相同。

文末引用

If we stopped now... yay! We haven't... really... done anything: we added this new plainPassword property... but nothing is using it! So, the request would ultimately explode in the database because our $password field will be null.

Next, we need to hook into the request-handling process: we need to run some code after deserialization but before persisting. We'll do that with a data persister.

由于单元测试会 POST 请求,数据持久化器由 api 平台调用,它将按事件获取编码逻辑。在固定装置的情况下,直接原则批量插入完成,这将绕过所有持久性逻辑并导致空密码。

有一种方法可以解决这个问题,正如@rishta 提到的那样,使用处理器对您的数据固定装置实施哈希,如 Documentation

中所引用
<?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 对象

documentation

中有关 DTO 的更多信息