Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #212: Implemented enums in database #300

Merged
merged 7 commits into from
Feb 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@
"psr-4": {
"Admin\\App\\": "src/App/src/",
"Admin\\Admin\\": "src/Admin/src/",
"Admin\\Setting\\": "src/Setting/src/"
"Admin\\Setting\\": "src/Setting/src/",
"Admin\\Fixtures\\": "data/doctrine/fixtures"
}
},
"autoload-dev": {
Expand Down
2 changes: 1 addition & 1 deletion config/autoload/authentication.global.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
'doctrine' => [
'authentication' => [
'orm_default' => [
'object_manager' => 'doctrine.entitymanager.orm_default',
'object_manager' => 'doctrine.entity_manager.orm_default',
'identity_class' => Admin::class,
'identity_property' => 'identity',
'credential_property' => 'password',
Expand Down
29 changes: 18 additions & 11 deletions config/autoload/doctrine.global.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

declare(strict_types=1);

use Admin\Admin\DBAL\Types\AdminStatusEnumType;
use Admin\App\DBAL\Types\SuccessFailureEnumType;
use Admin\App\DBAL\Types\YesNoEnumType;
use Admin\App\Resolver\EntityListenerResolver;
use Doctrine\Persistence\Mapping\Driver\MappingDriverChain;
use Dot\Cache\Adapter\ArrayAdapter;
Expand All @@ -11,7 +14,17 @@
use Ramsey\Uuid\Doctrine\UuidType;

return [
'doctrine' => [
'doctrine' => [
'cache' => [
'array' => [
'class' => ArrayAdapter::class,
],
'filesystem' => [
'class' => FilesystemAdapter::class,
'directory' => getcwd() . '/data/cache',
'namespace' => 'doctrine',
],
],
'configuration' => [
'orm_default' => [
'entity_listener_resolver' => EntityListenerResolver::class,
Expand Down Expand Up @@ -49,17 +62,11 @@
UuidType::NAME => UuidType::class,
UuidBinaryType::NAME => UuidBinaryType::class,
UuidBinaryOrderedTimeType::NAME => UuidBinaryOrderedTimeType::class,
],
'cache' => [
'array' => [
'class' => ArrayAdapter::class,
],
'filesystem' => [
'class' => FilesystemAdapter::class,
'directory' => getcwd() . '/data/cache',
'namespace' => 'doctrine',
],
AdminStatusEnumType::NAME => AdminStatusEnumType::class,
SuccessFailureEnumType::NAME => SuccessFailureEnumType::class,
YesNoEnumType::NAME => YesNoEnumType::class,
],
'fixtures' => getcwd() . '/data/doctrine/fixtures',
],
'resultCacheLifetime' => 600,
];
3 changes: 0 additions & 3 deletions config/cli-config.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,4 @@

$entityManager = $container->get(EntityManager::class);

// register enum type for doctrine
$entityManager->getConnection()->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');

return DependencyFactory::fromEntityManager($config, new ExistingEntityManager($entityManager));
8 changes: 5 additions & 3 deletions data/doctrine/fixtures/AdminLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Persistence\ObjectManager;

use function assert;
use function password_hash;

use const PASSWORD_DEFAULT;
Expand All @@ -18,14 +19,15 @@ class AdminLoader implements FixtureInterface, DependentFixtureInterface
{
public function load(ObjectManager $manager): void
{
$role = $manager->getRepository(AdminRole::class)->findOneBy(['name' => AdminRole::ROLE_SUPERUSER]);
assert($role instanceof AdminRole);

$admin = (new Admin())
->setIdentity('admin')
->setPassword(password_hash('dotadmin', PASSWORD_DEFAULT))
->setFirstName('DotKernel')
->setLastName('Admin')
->addRole(
$manager->getRepository(AdminRole::class)->findOneBy(['name' => AdminRole::ROLE_SUPERUSER])
);
->addRole($role);

$manager->persist($admin);
$manager->flush();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240627134952 extends AbstractMigration
final class Version20241120150458 extends AbstractMigration
{
public function getDescription(): string
{
Expand All @@ -20,11 +20,11 @@ public function getDescription(): string
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE admin (uuid BINARY(16) NOT NULL, identity VARCHAR(100) NOT NULL, firstName VARCHAR(255) DEFAULT NULL, lastName VARCHAR(255) DEFAULT NULL, password VARCHAR(100) NOT NULL, status ENUM(\'pending\', \'active\'), created DATETIME NOT NULL, updated DATETIME DEFAULT NULL, UNIQUE INDEX UNIQ_880E0D766A95E9C4 (identity), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4');
$this->addSql('CREATE TABLE admin (identity VARCHAR(100) NOT NULL, firstName VARCHAR(255) DEFAULT NULL, lastName VARCHAR(255) DEFAULT NULL, password VARCHAR(100) NOT NULL, status ENUM(\'active\', \'inactive\') DEFAULT \'active\' NOT NULL, uuid BINARY(16) NOT NULL, created DATETIME NOT NULL, updated DATETIME DEFAULT NULL, UNIQUE INDEX UNIQ_880E0D766A95E9C4 (identity), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4');
$this->addSql('CREATE TABLE admin_roles (userUuid BINARY(16) NOT NULL, roleUuid BINARY(16) NOT NULL, INDEX IDX_1614D53DD73087E9 (userUuid), INDEX IDX_1614D53D88446210 (roleUuid), PRIMARY KEY(userUuid, roleUuid)) DEFAULT CHARACTER SET utf8mb4');
$this->addSql('CREATE TABLE admin_login (uuid BINARY(16) NOT NULL, adminIp VARCHAR(50) DEFAULT NULL, country VARCHAR(50) DEFAULT NULL, continent VARCHAR(50) DEFAULT NULL, organization VARCHAR(50) DEFAULT NULL, deviceType VARCHAR(20) DEFAULT NULL, deviceBrand VARCHAR(20) DEFAULT NULL, deviceModel VARCHAR(40) DEFAULT NULL, isMobile ENUM(\'yes\', \'no\'), osName VARCHAR(20) DEFAULT NULL, osVersion VARCHAR(20) DEFAULT NULL, osPlatform VARCHAR(20) DEFAULT NULL, clientType VARCHAR(20) DEFAULT NULL, clientName VARCHAR(40) DEFAULT NULL, clientEngine VARCHAR(20) DEFAULT NULL, clientVersion VARCHAR(20) DEFAULT NULL, loginStatus ENUM(\'success\', \'fail\'), identity VARCHAR(100) DEFAULT NULL, created DATETIME NOT NULL, updated DATETIME DEFAULT NULL, PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4');
$this->addSql('CREATE TABLE admin_role (uuid BINARY(16) NOT NULL, name VARCHAR(30) NOT NULL, created DATETIME NOT NULL, updated DATETIME DEFAULT NULL, UNIQUE INDEX UNIQ_7770088A5E237E06 (name), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4');
$this->addSql('CREATE TABLE settings (uuid BINARY(16) NOT NULL, identifier VARCHAR(50) NOT NULL, value LONGTEXT NOT NULL, created DATETIME NOT NULL, updated DATETIME DEFAULT NULL, admin_uuid BINARY(16) DEFAULT NULL, INDEX IDX_E545A0C5F166D246 (admin_uuid), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4');
$this->addSql('CREATE TABLE admin_login (adminIp VARCHAR(50) DEFAULT NULL, country VARCHAR(50) DEFAULT NULL, continent VARCHAR(50) DEFAULT NULL, organization VARCHAR(50) DEFAULT NULL, deviceType VARCHAR(20) DEFAULT NULL, deviceBrand VARCHAR(20) DEFAULT NULL, deviceModel VARCHAR(40) DEFAULT NULL, isMobile ENUM(\'yes\', \'no\') NOT NULL, osName VARCHAR(20) DEFAULT NULL, osVersion VARCHAR(20) DEFAULT NULL, osPlatform VARCHAR(20) DEFAULT NULL, clientType VARCHAR(20) DEFAULT NULL, clientName VARCHAR(40) DEFAULT NULL, clientEngine VARCHAR(20) DEFAULT NULL, clientVersion VARCHAR(20) DEFAULT NULL, loginStatus ENUM(\'success\', \'failure\') NOT NULL, identity VARCHAR(100) DEFAULT NULL, uuid BINARY(16) NOT NULL, created DATETIME NOT NULL, updated DATETIME DEFAULT NULL, PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4');
$this->addSql('CREATE TABLE admin_role (name VARCHAR(30) NOT NULL, uuid BINARY(16) NOT NULL, created DATETIME NOT NULL, updated DATETIME DEFAULT NULL, UNIQUE INDEX UNIQ_7770088A5E237E06 (name), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4');
$this->addSql('CREATE TABLE settings (identifier VARCHAR(50) NOT NULL, value LONGTEXT NOT NULL, uuid BINARY(16) NOT NULL, created DATETIME NOT NULL, updated DATETIME DEFAULT NULL, admin_uuid BINARY(16) DEFAULT NULL, INDEX IDX_E545A0C5F166D246 (admin_uuid), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4');
$this->addSql('ALTER TABLE admin_roles ADD CONSTRAINT FK_1614D53DD73087E9 FOREIGN KEY (userUuid) REFERENCES admin (uuid)');
$this->addSql('ALTER TABLE admin_roles ADD CONSTRAINT FK_1614D53D88446210 FOREIGN KEY (roleUuid) REFERENCES admin_role (uuid)');
$this->addSql('ALTER TABLE settings ADD CONSTRAINT FK_E545A0C5F166D246 FOREIGN KEY (admin_uuid) REFERENCES admin (uuid)');
Expand Down
11 changes: 6 additions & 5 deletions src/Admin/src/Controller/AdminController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Admin\Admin\Adapter\AuthenticationAdapter;
use Admin\Admin\Entity\Admin;
use Admin\Admin\Entity\AdminIdentity;
use Admin\Admin\Entity\AdminLogin;
use Admin\Admin\Enum\AdminStatusEnum;
use Admin\Admin\Form\AccountForm;
use Admin\Admin\Form\AdminDeleteForm;
use Admin\Admin\Form\AdminForm;
Expand All @@ -17,6 +17,7 @@
use Admin\Admin\InputFilter\EditAdminInputFilter;
use Admin\Admin\Service\AdminServiceInterface;
use Admin\App\Common\ServerRequestAwareTrait;
use Admin\App\Enum\SuccessFailureEnum;
use Admin\App\Exception\IdentityException;
use Admin\App\Message;
use Admin\App\Pagination;
Expand Down Expand Up @@ -269,9 +270,9 @@ public function loginAction(): ResponseInterface
$this->adminService->logAdminVisit(
$this->getServerParams(),
$data['username'],
AdminLogin::LOGIN_SUCCESS
SuccessFailureEnum::Success
);
if ($identity->getStatus() === Admin::STATUS_INACTIVE) {
if ($identity->getStatus() === AdminStatusEnum::Inactive) {
$this->authenticationService->clearIdentity();
$this->messenger->addError('Admin is inactive', 'user-login');
$this->messenger->addData('shouldRebind', true);
Expand All @@ -285,7 +286,7 @@ public function loginAction(): ResponseInterface
$this->adminService->logAdminVisit(
$this->getServerParams(),
$data['username'],
AdminLogin::LOGIN_FAIL
SuccessFailureEnum::Failure
);
$this->messenger->addData('shouldRebind', true);
$this->forms->saveState($form);
Expand Down Expand Up @@ -449,7 +450,7 @@ public function simpleLoginsAction(): ResponseInterface
'params' => $params,
'logins' => $logins['rows'],
'settings' => $settings?->getValue() ?? [],
'statuses' => [AdminLogin::LOGIN_FAIL, AdminLogin::LOGIN_SUCCESS],
'statuses' => SuccessFailureEnum::cases(),
'identities' => $this->adminService->getAdminLoginIdentities(),
'identifier' => Setting::IDENTIFIER_TABLE_ADMIN_LIST_LOGINS_SELECTED_COLUMNS,
'pagination' => new Pagination($logins['total'], $params['offset'], $params['limit']),
Expand Down
23 changes: 23 additions & 0 deletions src/Admin/src/DBAL/Types/AdminStatusEnumType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Admin\Admin\DBAL\Types;

use Admin\Admin\Enum\AdminStatusEnum;
use Admin\App\DBAL\Types\AbstractEnumType;

class AdminStatusEnumType extends AbstractEnumType
{
public const NAME = 'admin_status_enum';

protected function getEnumClass(): string
{
return AdminStatusEnum::class;
}

public function getName(): string
{
return self::NAME;
}
}
24 changes: 6 additions & 18 deletions src/Admin/src/Entity/Admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Admin\Admin\Entity;

use Admin\Admin\Enum\AdminStatusEnum;
use Admin\Admin\Repository\AdminRepository;
use Admin\App\Entity\AbstractEntity;
use Admin\App\Entity\TimestampsTrait;
Expand All @@ -23,13 +24,6 @@ class Admin extends AbstractEntity implements AdminInterface
{
use TimestampsTrait;

public const STATUS_ACTIVE = 'active';
public const STATUS_INACTIVE = 'pending';
public const STATUSES = [
self::STATUS_ACTIVE,
self::STATUS_INACTIVE,
];

#[ORM\Column(name: "identity", type: "string", length: 100, unique: true)]
protected string $identity;

Expand All @@ -42,22 +36,16 @@ class Admin extends AbstractEntity implements AdminInterface
#[ORM\Column(name: "password", type: "string", length: 100)]
protected string $password;

#[ORM\Column(
name: "status",
type: "string",
length: 20,
nullable: false,
columnDefinition: "ENUM('pending', 'active')"
)]
protected string $status = self::STATUS_ACTIVE;
#[ORM\Column(type: "admin_status_enum", options: ["default" => AdminStatusEnum::Active])]
protected AdminStatusEnum $status = AdminStatusEnum::Active;

#[ORM\ManyToMany(targetEntity: AdminRole::class, fetch: "EAGER")]
#[ORM\JoinTable(name: "admin_roles")]
#[ORM\JoinColumn(name: "userUuid", referencedColumnName: "uuid")]
#[ORM\InverseJoinColumn(name: "roleUuid", referencedColumnName: "uuid")]
protected Collection $roles;

#[ORM\OneToMany(mappedBy: 'admin', targetEntity: Setting::class)]
#[ORM\OneToMany(targetEntity: Setting::class, mappedBy: 'admin')]
protected Collection $settings;

public function __construct()
Expand Down Expand Up @@ -137,12 +125,12 @@ public function verifyPassword(string $password): bool
return password_verify($password, $this->getPassword());
}

public function getStatus(): string
public function getStatus(): AdminStatusEnum
{
return $this->status;
}

public function setStatus(string $status): self
public function setStatus(AdminStatusEnum $status): self
{
$this->status = $status;

Expand Down
5 changes: 3 additions & 2 deletions src/Admin/src/Entity/AdminIdentity.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@

namespace Admin\Admin\Entity;

use Admin\Admin\Enum\AdminStatusEnum;
use Mezzio\Authentication\UserInterface;

class AdminIdentity implements UserInterface
{
public function __construct(
protected string $uuid,
protected string $identity,
protected string $status,
protected AdminStatusEnum $status,
protected array $roles = [],
protected array $details = []
) {
Expand All @@ -27,7 +28,7 @@ public function getIdentity(): string
return $this->identity;
}

public function getStatus(): string
public function getStatus(): AdminStatusEnum
{
return $this->status;
}
Expand Down
5 changes: 3 additions & 2 deletions src/Admin/src/Entity/AdminInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Admin\Admin\Entity;

use Admin\Admin\Enum\AdminStatusEnum;
use Doctrine\Common\Collections\ArrayCollection;

interface AdminInterface
Expand All @@ -26,9 +27,9 @@ public function getPassword(): ?string;

public function setPassword(string $password): self;

public function getStatus(): string;
public function getStatus(): AdminStatusEnum;

public function setStatus(string $status): self;
public function setStatus(AdminStatusEnum $status): self;

public function getRoles(): array;

Expand Down
28 changes: 10 additions & 18 deletions src/Admin/src/Entity/AdminLogin.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
use Admin\Admin\Repository\AdminLoginRepository;
use Admin\App\Entity\AbstractEntity;
use Admin\App\Entity\TimestampsTrait;
use Admin\App\Enum\SuccessFailureEnum;
use Admin\App\Enum\YesNoEnum;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: AdminLoginRepository::class)]
Expand All @@ -17,11 +19,6 @@ class AdminLogin extends AbstractEntity
{
use TimestampsTrait;

public const IS_MOBILE_YES = 'yes';
public const IS_MOBILE_NO = 'no';
public const LOGIN_SUCCESS = 'success';
public const LOGIN_FAIL = 'fail';

#[ORM\Column(name: "adminIp", type: "string", length: 50, nullable: true)]
protected ?string $adminIp = null;

Expand All @@ -43,13 +40,8 @@ class AdminLogin extends AbstractEntity
#[ORM\Column(name: "deviceModel", type: "string", length: 40, nullable: true)]
protected ?string $deviceModel = null;

#[ORM\Column(
name: "isMobile",
type: "string",
nullable: true,
columnDefinition: "ENUM('yes', 'no')"
)]
protected ?string $isMobile = null;
#[ORM\Column(type: "yes_no_enum")]
protected ?YesNoEnum $isMobile = null;

#[ORM\Column(name: "osName", type: "string", length: 20, nullable: true)]
protected ?string $osName = null;
Expand All @@ -72,8 +64,8 @@ class AdminLogin extends AbstractEntity
#[ORM\Column(name: "clientVersion", type: "string", length: 20, nullable: true)]
protected ?string $clientVersion = null;

#[ORM\Column(name: "loginStatus", type: "string", nullable: true, columnDefinition: "ENUM('success', 'fail')")]
protected ?string $loginStatus = null;
#[ORM\Column(type: "success_failure_enum")]
protected ?SuccessFailureEnum $loginStatus = null;

#[ORM\Column(name: "identity", type: "string", length: 100, nullable: true)]
protected ?string $identity = null;
Expand Down Expand Up @@ -162,12 +154,12 @@ public function setDeviceModel(?string $deviceModel): self
return $this;
}

public function getIsMobile(): ?string
public function getIsMobile(): ?YesNoEnum
{
return $this->isMobile;
}

public function setIsMobile(?string $isMobile): self
public function setIsMobile(?YesNoEnum $isMobile): self
{
$this->isMobile = $isMobile;

Expand Down Expand Up @@ -258,12 +250,12 @@ public function setClientVersion(?string $clientVersion): self
return $this;
}

public function getLoginStatus(): ?string
public function getLoginStatus(): ?SuccessFailureEnum
{
return $this->loginStatus;
}

public function setLoginStatus(?string $loginStatus): self
public function setLoginStatus(?SuccessFailureEnum $loginStatus): self
{
$this->loginStatus = $loginStatus;

Expand Down
Loading
Loading