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 对象
中有关 DTO 的更多信息
我配置了以下 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 对象