User / UserRepository

<?php
 
namespace App\Entity;
 
use ApiPlatform\Metadata\ApiResource;
use App\Repository\UserRepository;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
 
#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ApiResource]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
}
<?php
 
namespace App\Repository;
 
class UserRepository extends ServiceEntityRepository implements PasswordUpgraderInterface
{
}

Preprocessor в методе PATH / POST

src/Entity/User.php

<?php
 
namespace App\Entity;
 
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use App\Repository\UserRepository;
use App\State\UserHashPasswordProcessor;
use App\State\UserStateProcessor;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Annotation\SerializedName;
 
#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Table(name: '`user`')]
#[UniqueEntity(fields: ['email'], message: 'There is already an account with this email')]
#[ApiResource(
    operations: [
        new Get(),
        new GetCollection(),
        new Post(
            denormalizationContext: ['groups' => ['user:write']],
            processor: UserStateProcessor::class
        ),
        new Patch(
            denormalizationContext: ['groups' => ['user:patch:write']],
            processor: UserHashPasswordProcessor::class
        )
    ],
    normalizationContext: ['groups' => ['user:read']],
 
)]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
}

src/State/UserHashPasswordProcessor.php

<?php
 
namespace App\State;
 
use ApiPlatform\Doctrine\Common\State\PersistProcessor;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use App\Entity\User;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
 
class UserHashPasswordProcessor implements ProcessorInterface
{
    public function __construct(
        #[Autowire(service: PersistProcessor::class )] private readonly ProcessorInterface $processor,
        private readonly UserPasswordHasherInterface $userPasswordHasher,
    )
    {
    }
 
    public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): void
    {
       assert($data instanceof User);
 
       if($data->getPlainPassword()){
           $data->setPassword($this->userPasswordHasher->hashPassword($data, $data->getPlainPassword()));
       }
 
       $this->processor->process($data, $operation, $uriVariables, $context);
    }
}

Symfony / API Platform