I have the following UserDataPersister (taken straight from the tutorial) configured:
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
and the following User fixture:
App\Entity\User:
user_{1..10}:
email: "usermail_<current()>\\@email.org"
plainPassword: "plainPassword_<current()>"
__calls:
- initUuid: []
But I get errors when loading this fixture:
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).
My implementation of UserDataPersister is identical with this.
Quote from Article at the end
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.
Since unit test would POST the request, the data persistor is called by api-platform and it will pick up encoding logic by event. In case of fixtures, direct doctrine batch insert is done, this will bypass all persistence logic and would result in null password.
There is a way to solve this as mentioned by @rishta Use Processor to implement hash to your data fixtures as referenced in 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
}
}
Register service :
# 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 } ]
One of the better ways to do input masking in API Platform is to use DTO Pattern as oppose to suggested by article, in which you are allowed to :
More on DTO in documentation