<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
grzegorz-jamroz / sf-doctrine-api-auth-bundle example snippets
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Ifrost\DoctrineApiAuthBundle\Entity\ApiUserInterface;
use PlainDataTransformer\Transform;
use Ramsey\Uuid\Doctrine\UuidV7Generator;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
#[ORM\Entity(readOnly: true)]
class User implements ApiUserInterface
{
#[ORM\Id]
#[ORM\Column(type: "uuid_binary", unique: true)]
#[ORM\GeneratedValue(strategy: "CUSTOM")]
#[ORM\CustomIdGenerator(class: UuidV7Generator::class)]
private UuidInterface $uuid;
#[ORM\Column(length: 180, unique: true)]
private string $email;
/**
* @var string The hashed password
*/
#[ORM\Column]
private string $password;
/**
* @var array<int, string>
*/
#[ORM\Column]
private array $roles;
public function __construct(
UuidInterface $uuid,
string $email,
string $password = '',
array $roles = [],
) {
$this->uuid = $uuid;
$this->email = $email;
$this->password = $password;
$this->roles = $roles;
}
public function getUuid(): UuidInterface
{
return $this->uuid;
}
public function getEmail(): string
{
return $this->email;
}
public function getUsername(): string
{
return $this->getEmail();
}
/**
* A visual identifier that represents this user.
*
* @see UserInterface
*/
public function getUserIdentifier(): string
{
return $this->email;
}
/**
* @see UserInterface
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
/**
* @see PasswordAuthenticatedUserInterface
*/
public function getPassword(): string
{
return $this->password;
}
/**
* @see UserInterface
*/
public function eraseCredentials(): void
{
// If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null;
}
public static function getTableName(): string
{
return 'user';
}
/**
* @return array<int, string>
*/
public static function getFields(): array
{
return [
...array_keys(self::createFromArray([])->jsonSerialize()),
'password',
];
}
public function jsonSerialize(): array
{
return [
'uuid' => (string) $this->uuid,
'email' => $this->email,
'roles' => $this->getRoles(),
];
}
public function getWritableFormat(): array
{
return [
...$this->jsonSerialize(),
'uuid' => $this->uuid->getBytes(),
'password' => $this->password,
'roles' => json_encode($this->getRoles()),
];
}
public static function createFromArray(array $data): static|self
{
return new self(
$data['uuid'] ?? Uuid::uuid7(),
Transform::toString($data['email'] ?? ''),
Transform::toString($data['password'] ?? ''),
Transform::toArray($data['roles'] ?? []),
);
}
public static function createFromRequest(array $data): static|self
{
return new self(
isset($data['uuid']) ? Uuid::fromString($data['uuid']) : Uuid::uuid7(),
Transform::toString($data['email'] ?? ''),
Transform::toString($data['password'] ?? ''),
Transform::toArray($data['roles'] ?? []),
);
}
}
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Ifrost\DoctrineApiAuthBundle\Entity\TokenInterface;
use PlainDataTransformer\Transform;
use Ramsey\Uuid\Doctrine\UuidV7Generator;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
#[ORM\Entity(readOnly: true)]
class Token implements TokenInterface
{
#[ORM\Id]
#[ORM\Column(type: "uuid_binary", unique: true)]
#[ORM\GeneratedValue(strategy: "CUSTOM")]
#[ORM\CustomIdGenerator(class: UuidV7Generator::class)]
private string $uuid;
#[ORM\ManyToOne(targetEntity: User::class)]
#[ORM\JoinColumn(name: 'user_uuid', referencedColumnName: 'uuid', nullable: false)]
private string $userUuid;
#[ORM\Column(type: "uuid_binary", unique: true)]
private string $refreshTokenUuid;
#[ORM\Column]
private int $iat;
#[ORM\Column]
private int $exp;
#[ORM\Column(length: 255, nullable: true)]
private string $device;
public function __construct(
UuidInterface $uuid,
UuidInterface $userUuid,
UuidInterface $refreshTokenUuid,
int $iat,
int $exp,
string $device,
) {
$this->uuid = $uuid;
$this->userUuid = $userUuid;
$this->refreshTokenUuid = $refreshTokenUuid;
$this->iat = $iat;
$this->exp = $exp;
$this->device = $device;
}
public function getUuid(): UuidInterface
{
return $this->uuid;
}
public function getUserUuid(): UuidInterface
{
return $this->userUuid;
}
public function getRefreshTokenUuid(): UuidInterface
{
return $this->refreshTokenUuid;
}
public function getIat(): int
{
return $this->iat;
}
public function getExp(): int
{
return $this->exp;
}
public function getDevice(): string
{
return $this->device;
}
public static function getTableName(): string
{
return 'token';
}
/**
* @return array<int, string>
*/
public static function getFields(): array
{
return array_keys(self::createFromArray([])->jsonSerialize());
}
public function jsonSerialize(): array
{
return [
'uuid' => (string) $this->uuid,
'user_uuid' => (string) $this->userUuid,
'refresh_token_uuid' => (string) $this->refreshTokenUuid,
'iat' => $this->iat,
'exp' => $this->exp,
'device' => $this->device,
];
}
public function getWritableFormat(): array
{
return [
...$this->jsonSerialize(),
'uuid' => $this->uuid->getBytes(),
'user_uuid' => $this->userUuid->getBytes(),
'refresh_token_uuid' => $this->refreshTokenUuid->getBytes(),
];
}
public static function createFromArray(array $data): static|self
{
return new self(
$data['uuid'] ?? Uuid::uuid7(),
$data['user_uuid'] ?? Uuid::uuid7(),
$data['refresh_token_uuid'] ?? Uuid::uuid7(),
Transform::toInt($data['iat'] ?? 0),
Transform::toInt($data['exp'] ?? 0),
Transform::toString($data['device'] ?? ''),
);
}
public static function createFromRequest(array $data): static|self
{
return new self(
isset($data['uuid']) ? Uuid::fromString($data['uuid']) : Uuid::uuid7(),
isset($data['user_uuid']) ? Uuid::fromString($data['user_uuid']) : Uuid::uuid7(),
isset($data['refresh_token_uuid']) ? Uuid::fromString($data['refresh_token_uuid']) : Uuid::uuid7(),
Transform::toInt($data['iat'] ?? 0),
Transform::toInt($data['exp'] ?? 0),
Transform::toString($data['device'] ?? ''),
);
}
}
declare(strict_types=1);
namespace App\Controller;
use App\Entity\User;
use Ifrost\ApiFoundation\Attribute\Api;
use Ifrost\ApiFoundation\Enum\Action;
use Ifrost\DoctrineApiBundle\Controller\DoctrineApiController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Annotation\Route;
#[Api(entity: User::class, path: 'users', excludedActions: [Action::CREATE])]
class UserController extends DoctrineApiController
{
#[Route('/users', name: 'users_create', methods: ['POST'])]
public function create(): Response
{
$data = $this->getApiRequest(User::getFields());
$data['password'] = $this->getPasswordHasher()->hashPassword(
User::createFromArray($data),
$data['password']
);
$this->getApiRequestService()->setData($data);
return $this->getApi()->create();
}
public static function getSubscribedServices(): array
{
return array_merge(parent::getSubscribedServices(), [
UserPasswordHasherInterface::class => '?' . UserPasswordHasherInterface::class,
]);
}
protected function getPasswordHasher(): UserPasswordHasherInterface
{
$passwordHasher = $this->container->get(UserPasswordHasherInterface::class);
$passwordHasher instanceof UserPasswordHasherInterface ?: throw new \RuntimeException(sprintf('Container identifier "%s" is not instance of %s', UserPasswordHasherInterface::class, UserPasswordHasherInterface::class));
return $passwordHasher;
}
}
php bin/console lexik:jwt:generate-keypair
php bin/console make:migration
php bin/console doctrine:migrations:migrate
php bin/console debug:router
------------------- -------- -------- ------ --------------------------
Name Method Scheme Host Path
------------------- -------- -------- ------ --------------------------
_preview_error ANY ANY ANY /_error/{code}.{_format}
login ANY ANY ANY /login
logout POST ANY ANY /logout
refresh_token POST ANY ANY /token/refresh
------------------- -------- -------- ------ --------------------------
php bin/console debug:router
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.