diff --git a/composer.json b/composer.json index 1e884f2b..b640eb52 100644 --- a/composer.json +++ b/composer.json @@ -69,8 +69,8 @@ "mezzio/mezzio-authorization-rbac": "^1.7.0", "mezzio/mezzio-cors": "^1.11.1", "mezzio/mezzio-fastroute": "^3.11.0", - "ramsey/uuid-doctrine": "^2.0.0", - "roave/psr-container-doctrine": "^4.1.0" + "ramsey/uuid-doctrine": "^2.1.0", + "roave/psr-container-doctrine": "^5.2.2" }, "require-dev": { "filp/whoops": "^2.15.4", diff --git a/config/autoload/doctrine.global.php b/config/autoload/doctrine.global.php index 9d97a537..48eda1e7 100644 --- a/config/autoload/doctrine.global.php +++ b/config/autoload/doctrine.global.php @@ -23,7 +23,12 @@ ], ], 'doctrine' => [ - 'connection' => [ + 'configuration' => [ + 'orm_default' => [ + 'entity_listener_resolver' => EntityListenerResolver::class, + ], + ], + 'connection' => [ 'orm_default' => [ 'doctrine_mapping_types' => [ UuidBinaryType::NAME => 'binary', @@ -31,25 +36,20 @@ ], ], ], - 'driver' => [ + 'driver' => [ // default metadata driver, aggregates all other drivers into a single one. // Override `orm_default` only if you know what you're doing - 'orm_default' => [ + 'orm_default' => [ 'class' => MappingDriverChain::class, 'drivers' => [], ], - 'configuration' => [ - 'orm_default' => [ - 'entity_listener_resolver' => EntityListenerResolver::class, - ], - ], ], - 'types' => [ + 'types' => [ UuidType::NAME => UuidType::class, UuidBinaryType::NAME => UuidBinaryType::class, UuidBinaryOrderedTimeType::NAME => UuidBinaryOrderedTimeType::class, ], - 'fixtures' => getcwd() . '/data/doctrine/fixtures', + 'fixtures' => getcwd() . '/data/doctrine/fixtures', ], 'resultCacheLifetime' => 600, ]; diff --git a/config/autoload/local.test.php.dist b/config/autoload/local.test.php.dist index 6f577379..b7de6fd5 100644 --- a/config/autoload/local.test.php.dist +++ b/config/autoload/local.test.php.dist @@ -13,7 +13,7 @@ return [ 'connection' => [ 'orm_default' => [ 'params' => [ - 'url' => 'sqlite:///:memory:', + 'url' => 'sqlite3:///:memory:', ], ], ], diff --git a/data/doctrine/migrations/Version20220817121035.php b/data/doctrine/migrations/Version20220817121035.php deleted file mode 100644 index 0dfceb2d..00000000 --- a/data/doctrine/migrations/Version20220817121035.php +++ /dev/null @@ -1,58 +0,0 @@ -addSql('CREATE TABLE contact_message (uuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', email VARCHAR(150) NOT NULL, name VARCHAR(150) NOT NULL, subject LONGTEXT NOT NULL, message LONGTEXT NOT NULL, platform LONGTEXT NOT NULL, created DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); - $this->addSql('CREATE TABLE user (uuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', identity VARCHAR(191) NOT NULL, password VARCHAR(191) NOT NULL, status ENUM(\'pending\', \'active\'), isDeleted TINYINT(1) NOT NULL, hash VARCHAR(64) NOT NULL, created DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', UNIQUE INDEX UNIQ_8D93D6496A95E9C4 (identity), UNIQUE INDEX UNIQ_8D93D649D1B862B8 (hash), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); - $this->addSql('CREATE TABLE user_roles (userUuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', roleUuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', INDEX IDX_54FCD59FD73087E9 (userUuid), INDEX IDX_54FCD59F88446210 (roleUuid), PRIMARY KEY(userUuid, roleUuid)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); - $this->addSql('CREATE TABLE user_avatar (uuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', name VARCHAR(191) NOT NULL, created DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', userUuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', UNIQUE INDEX UNIQ_73256912D73087E9 (userUuid), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); - $this->addSql('CREATE TABLE user_detail (uuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', firstName VARCHAR(191) DEFAULT NULL, lastName VARCHAR(191) DEFAULT NULL, created DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', userUuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', UNIQUE INDEX UNIQ_4B5464AED73087E9 (userUuid), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); - $this->addSql('CREATE TABLE user_remember_me (uuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', rememberMeToken VARCHAR(100) NOT NULL, userAgent TEXT NOT NULL, expireDate DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', created DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', userUuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', UNIQUE INDEX UNIQ_D3E96EBD1BBB86A0 (rememberMeToken), INDEX IDX_D3E96EBDD73087E9 (userUuid), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); - $this->addSql('CREATE TABLE user_reset_password (uuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', expires DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', hash VARCHAR(64) NOT NULL, status VARCHAR(20) NOT NULL, created DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', userUuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', UNIQUE INDEX UNIQ_D21DE3BCD1B862B8 (hash), INDEX IDX_D21DE3BCD73087E9 (userUuid), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); - $this->addSql('CREATE TABLE user_role (uuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', name VARCHAR(30) NOT NULL, created DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', UNIQUE INDEX UNIQ_2DE8C6A35E237E06 (name), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); - $this->addSql('ALTER TABLE user_roles ADD CONSTRAINT FK_54FCD59FD73087E9 FOREIGN KEY (userUuid) REFERENCES user (uuid)'); - $this->addSql('ALTER TABLE user_roles ADD CONSTRAINT FK_54FCD59F88446210 FOREIGN KEY (roleUuid) REFERENCES user_role (uuid)'); - $this->addSql('ALTER TABLE user_avatar ADD CONSTRAINT FK_73256912D73087E9 FOREIGN KEY (userUuid) REFERENCES user (uuid)'); - $this->addSql('ALTER TABLE user_detail ADD CONSTRAINT FK_4B5464AED73087E9 FOREIGN KEY (userUuid) REFERENCES user (uuid)'); - $this->addSql('ALTER TABLE user_remember_me ADD CONSTRAINT FK_D3E96EBDD73087E9 FOREIGN KEY (userUuid) REFERENCES user (uuid)'); - $this->addSql('ALTER TABLE user_reset_password ADD CONSTRAINT FK_D21DE3BCD73087E9 FOREIGN KEY (userUuid) REFERENCES user (uuid)'); - } - - public function down(Schema $schema): void - { - // this down() migration is auto-generated, please modify it to your needs - $this->addSql('ALTER TABLE user_roles DROP FOREIGN KEY FK_54FCD59FD73087E9'); - $this->addSql('ALTER TABLE user_roles DROP FOREIGN KEY FK_54FCD59F88446210'); - $this->addSql('ALTER TABLE user_avatar DROP FOREIGN KEY FK_73256912D73087E9'); - $this->addSql('ALTER TABLE user_detail DROP FOREIGN KEY FK_4B5464AED73087E9'); - $this->addSql('ALTER TABLE user_remember_me DROP FOREIGN KEY FK_D3E96EBDD73087E9'); - $this->addSql('ALTER TABLE user_reset_password DROP FOREIGN KEY FK_D21DE3BCD73087E9'); - $this->addSql('DROP TABLE contact_message'); - $this->addSql('DROP TABLE user'); - $this->addSql('DROP TABLE user_roles'); - $this->addSql('DROP TABLE user_avatar'); - $this->addSql('DROP TABLE user_detail'); - $this->addSql('DROP TABLE user_remember_me'); - $this->addSql('DROP TABLE user_reset_password'); - $this->addSql('DROP TABLE user_role'); - } -} - diff --git a/data/doctrine/migrations/Version20240806123413.php b/data/doctrine/migrations/Version20240806123413.php new file mode 100644 index 00000000..d50bae81 --- /dev/null +++ b/data/doctrine/migrations/Version20240806123413.php @@ -0,0 +1,57 @@ +addSql('CREATE TABLE contact_message (uuid BINARY(16) NOT NULL, email VARCHAR(150) NOT NULL, name VARCHAR(150) NOT NULL, subject LONGTEXT NOT NULL, message LONGTEXT NOT NULL, platform LONGTEXT NOT NULL, created DATETIME NOT NULL, updated DATETIME DEFAULT NULL, PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4'); + $this->addSql('CREATE TABLE user (uuid BINARY(16) NOT NULL, identity VARCHAR(191) NOT NULL, password VARCHAR(191) NOT NULL, status ENUM(\'pending\', \'active\'), isDeleted TINYINT(1) NOT NULL, hash VARCHAR(64) NOT NULL, created DATETIME NOT NULL, updated DATETIME DEFAULT NULL, UNIQUE INDEX UNIQ_8D93D6496A95E9C4 (identity), UNIQUE INDEX UNIQ_8D93D649D1B862B8 (hash), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4'); + $this->addSql('CREATE TABLE user_roles (userUuid BINARY(16) NOT NULL, roleUuid BINARY(16) NOT NULL, INDEX IDX_54FCD59FD73087E9 (userUuid), INDEX IDX_54FCD59F88446210 (roleUuid), PRIMARY KEY(userUuid, roleUuid)) DEFAULT CHARACTER SET utf8mb4'); + $this->addSql('CREATE TABLE user_avatar (uuid BINARY(16) NOT NULL, name VARCHAR(191) NOT NULL, created DATETIME NOT NULL, updated DATETIME DEFAULT NULL, userUuid BINARY(16) NOT NULL, UNIQUE INDEX UNIQ_73256912D73087E9 (userUuid), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4'); + $this->addSql('CREATE TABLE user_detail (uuid BINARY(16) NOT NULL, firstName VARCHAR(191) DEFAULT NULL, lastName VARCHAR(191) DEFAULT NULL, created DATETIME NOT NULL, updated DATETIME DEFAULT NULL, userUuid BINARY(16) NOT NULL, UNIQUE INDEX UNIQ_4B5464AED73087E9 (userUuid), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4'); + $this->addSql('CREATE TABLE user_remember_me (uuid BINARY(16) NOT NULL, rememberMeToken VARCHAR(100) NOT NULL, userAgent LONGTEXT NOT NULL, expireDate DATETIME NOT NULL, created DATETIME NOT NULL, updated DATETIME DEFAULT NULL, userUuid BINARY(16) NOT NULL, UNIQUE INDEX UNIQ_D3E96EBD1BBB86A0 (rememberMeToken), INDEX IDX_D3E96EBDD73087E9 (userUuid), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4'); + $this->addSql('CREATE TABLE user_reset_password (uuid BINARY(16) NOT NULL, expires DATETIME NOT NULL, hash VARCHAR(64) NOT NULL, status VARCHAR(20) NOT NULL, created DATETIME NOT NULL, updated DATETIME DEFAULT NULL, userUuid BINARY(16) NOT NULL, UNIQUE INDEX UNIQ_D21DE3BCD1B862B8 (hash), INDEX IDX_D21DE3BCD73087E9 (userUuid), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4'); + $this->addSql('CREATE TABLE user_role (uuid BINARY(16) NOT NULL, name VARCHAR(30) NOT NULL, created DATETIME NOT NULL, updated DATETIME DEFAULT NULL, UNIQUE INDEX UNIQ_2DE8C6A35E237E06 (name), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4'); + $this->addSql('ALTER TABLE user_roles ADD CONSTRAINT FK_54FCD59FD73087E9 FOREIGN KEY (userUuid) REFERENCES user (uuid)'); + $this->addSql('ALTER TABLE user_roles ADD CONSTRAINT FK_54FCD59F88446210 FOREIGN KEY (roleUuid) REFERENCES user_role (uuid)'); + $this->addSql('ALTER TABLE user_avatar ADD CONSTRAINT FK_73256912D73087E9 FOREIGN KEY (userUuid) REFERENCES user (uuid)'); + $this->addSql('ALTER TABLE user_detail ADD CONSTRAINT FK_4B5464AED73087E9 FOREIGN KEY (userUuid) REFERENCES user (uuid)'); + $this->addSql('ALTER TABLE user_remember_me ADD CONSTRAINT FK_D3E96EBDD73087E9 FOREIGN KEY (userUuid) REFERENCES user (uuid)'); + $this->addSql('ALTER TABLE user_reset_password ADD CONSTRAINT FK_D21DE3BCD73087E9 FOREIGN KEY (userUuid) REFERENCES user (uuid)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE user_roles DROP FOREIGN KEY FK_54FCD59FD73087E9'); + $this->addSql('ALTER TABLE user_roles DROP FOREIGN KEY FK_54FCD59F88446210'); + $this->addSql('ALTER TABLE user_avatar DROP FOREIGN KEY FK_73256912D73087E9'); + $this->addSql('ALTER TABLE user_detail DROP FOREIGN KEY FK_4B5464AED73087E9'); + $this->addSql('ALTER TABLE user_remember_me DROP FOREIGN KEY FK_D3E96EBDD73087E9'); + $this->addSql('ALTER TABLE user_reset_password DROP FOREIGN KEY FK_D21DE3BCD73087E9'); + $this->addSql('DROP TABLE contact_message'); + $this->addSql('DROP TABLE user'); + $this->addSql('DROP TABLE user_roles'); + $this->addSql('DROP TABLE user_avatar'); + $this->addSql('DROP TABLE user_detail'); + $this->addSql('DROP TABLE user_remember_me'); + $this->addSql('DROP TABLE user_reset_password'); + $this->addSql('DROP TABLE user_role'); + } +} diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 9d2113f8..e8a04843 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1,11 +1,5 @@ - - - getUuidBuilder - setCodec - - getStorage diff --git a/src/App/src/Common/TimestampAwareInterface.php b/src/App/src/Common/TimestampAwareInterface.php deleted file mode 100644 index 23874eb3..00000000 --- a/src/App/src/Common/TimestampAwareInterface.php +++ /dev/null @@ -1,22 +0,0 @@ -touch(); - } - - public function getCreated(): ?DateTimeImmutable - { - return $this->created; - } - - public function getCreatedFormatted(?string $dateFormat = null): string - { - return $this->created->format($dateFormat ?? $this->dateFormat); - } - - public function getUpdated(): ?DateTimeImmutable - { - return $this->updated; - } - - public function getUpdatedFormatted(?string $dateFormat = null): ?string - { - return $this->updated?->format($dateFormat ?? $this->dateFormat); - } - - public function setDateFormat(string $dateFormat): void - { - $this->dateFormat = $dateFormat; - } - - public function touch(): void - { - try { - $this->created = new DateTimeImmutable(); - $this->updated = new DateTimeImmutable(); - } catch (Exception $exception) { - error_log($exception->getMessage()); - } - } -} diff --git a/src/App/src/Common/UuidAwareInterface.php b/src/App/src/Common/UuidAwareInterface.php deleted file mode 100644 index 74ed760b..00000000 --- a/src/App/src/Common/UuidAwareInterface.php +++ /dev/null @@ -1,12 +0,0 @@ -uuid) { - $this->uuid = UuidOrderedTimeGenerator::generateUuid(); - } - - return $this->uuid; - } -} diff --git a/src/App/src/Common/UuidOrderedTimeGenerator.php b/src/App/src/Common/UuidOrderedTimeGenerator.php deleted file mode 100644 index eea324e7..00000000 --- a/src/App/src/Common/UuidOrderedTimeGenerator.php +++ /dev/null @@ -1,29 +0,0 @@ -uuid1(); - } - - private static function getFactory(): UuidFactoryInterface - { - self::$factory = clone Uuid::getFactory(); - $codec = new OrderedTimeCodec(self::$factory->getUuidBuilder()); - self::$factory->setCodec($codec); - - return self::$factory; - } -} diff --git a/src/App/src/ConfigProvider.php b/src/App/src/ConfigProvider.php index c46af1ef..4444a42c 100644 --- a/src/App/src/ConfigProvider.php +++ b/src/App/src/ConfigProvider.php @@ -6,6 +6,7 @@ use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Mapping\Driver\AttributeDriver; use Dot\DependencyInjection\Factory\AttributedServiceFactory; use Frontend\App\Controller\LanguageController; use Frontend\App\Factory\EntityListenerResolverFactory; @@ -61,9 +62,16 @@ public function getDependencies(): array public function getDoctrineConfig(): array { return [ - 'configuration' => [ + 'driver' => [ 'orm_default' => [ - 'entity_listener_resolver' => EntityListenerResolver::class, + 'drivers' => [ + 'Frontend\App\Entity' => 'AppEntities', + ], + ], + 'AppEntities' => [ + 'class' => AttributeDriver::class, + 'cache' => 'array', + 'paths' => [__DIR__ . '/Entity'], ], ], ]; diff --git a/src/App/src/Common/AbstractEntity.php b/src/App/src/Entity/AbstractEntity.php similarity index 58% rename from src/App/src/Common/AbstractEntity.php rename to src/App/src/Entity/AbstractEntity.php index 60cf5392..19e62a72 100644 --- a/src/App/src/Common/AbstractEntity.php +++ b/src/App/src/Entity/AbstractEntity.php @@ -2,29 +2,36 @@ declare(strict_types=1); -namespace Frontend\App\Common; +namespace Frontend\App\Entity; -use DateTimeImmutable; +use Doctrine\ORM\Mapping as ORM; +use Ramsey\Uuid\Uuid; +use Ramsey\Uuid\UuidInterface; use function is_array; use function method_exists; use function ucfirst; -abstract class AbstractEntity implements UuidAwareInterface, TimestampAwareInterface +#[ORM\MappedSuperclass] +abstract class AbstractEntity { - use TimestampAwareTrait; - use UuidAwareTrait; + #[ORM\Id] + #[ORM\Column(name: 'uuid', type: "uuid_binary", unique: true)] + protected UuidInterface $uuid; public function __construct() { - $this->uuid = UuidOrderedTimeGenerator::generateUuid(); - $this->created = new DateTimeImmutable(); - $this->updated = new DateTimeImmutable(); + $this->uuid = Uuid::uuid4(); } - public function exchangeArray(array $data): void + public function getUuid(): UuidInterface { - foreach ($data as $property => $values) { + return $this->uuid; + } + + public function exchangeArray(array $array): void + { + foreach ($array as $property => $values) { if (is_array($values)) { $method = 'add' . ucfirst($property); if (! method_exists($this, $method)) { diff --git a/src/App/src/Entity/TimestampsTrait.php b/src/App/src/Entity/TimestampsTrait.php new file mode 100644 index 00000000..0cba6f4f --- /dev/null +++ b/src/App/src/Entity/TimestampsTrait.php @@ -0,0 +1,53 @@ +created; + } + + public function getCreatedFormatted(string $dateFormat = 'Y-m-d H:i:s'): string + { + return $this->created->format($dateFormat); + } + + public function getUpdated(): ?DateTimeImmutable + { + return $this->updated; + } + + public function getUpdatedFormatted(string $dateFormat = 'Y-m-d H:i:s'): ?string + { + if ($this->updated instanceof DateTimeImmutable) { + return $this->updated->format($dateFormat); + } + + return null; + } + + #[ORM\PrePersist] + public function created(): void + { + $this->created = new DateTimeImmutable(); + } + + #[ORM\PreUpdate] + public function touch(): void + { + $this->updated = new DateTimeImmutable(); + } +} diff --git a/src/Contact/src/Entity/Message.php b/src/Contact/src/Entity/Message.php index 3b8d656e..25367920 100644 --- a/src/Contact/src/Entity/Message.php +++ b/src/Contact/src/Entity/Message.php @@ -5,13 +5,17 @@ namespace Frontend\Contact\Entity; use Doctrine\ORM\Mapping as ORM; -use Frontend\App\Common\AbstractEntity; +use Frontend\App\Entity\AbstractEntity; +use Frontend\App\Entity\TimestampsTrait; use Frontend\Contact\Repository\MessageRepository; #[ORM\Entity(repositoryClass: MessageRepository::class)] #[ORM\Table(name: 'contact_message')] +#[ORM\HasLifecycleCallbacks] class Message extends AbstractEntity { + use TimestampsTrait; + public const PLATFORM_WEBSITE = 'website'; #[ORM\Column(name: 'email', type: 'string', length: 150)] diff --git a/src/User/src/Entity/User.php b/src/User/src/Entity/User.php index 7bce0e23..ea9a5600 100644 --- a/src/User/src/Entity/User.php +++ b/src/User/src/Entity/User.php @@ -9,17 +9,21 @@ use Doctrine\ORM\Mapping as ORM; use Dot\Authorization\Role\RoleInterface; use Exception; -use Frontend\App\Common\AbstractEntity; -use Frontend\App\Common\UuidOrderedTimeGenerator; +use Frontend\App\Entity\AbstractEntity; +use Frontend\App\Entity\TimestampsTrait; use Frontend\User\Repository\UserRepository; +use Ramsey\Uuid\Uuid; use function bin2hex; use function random_bytes; #[ORM\Entity(repositoryClass: UserRepository::class)] #[ORM\Table(name: 'user')] +#[ORM\HasLifecycleCallbacks] class User extends AbstractEntity implements UserInterface { + use TimestampsTrait; + public const STATUS_PENDING = 'pending'; public const STATUS_ACTIVE = 'active'; public const STATUSES = [ @@ -202,7 +206,7 @@ public static function generateHash(): string try { $bytes = random_bytes(32); } catch (Exception) { - $bytes = UuidOrderedTimeGenerator::generateUuid()->getBytes(); + $bytes = Uuid::uuid4()->getBytes(); } return bin2hex($bytes); diff --git a/src/User/src/Entity/UserAvatar.php b/src/User/src/Entity/UserAvatar.php index e30cf1bf..c89cf4c0 100644 --- a/src/User/src/Entity/UserAvatar.php +++ b/src/User/src/Entity/UserAvatar.php @@ -5,7 +5,8 @@ namespace Frontend\User\Entity; use Doctrine\ORM\Mapping as ORM; -use Frontend\App\Common\AbstractEntity; +use Frontend\App\Entity\AbstractEntity; +use Frontend\App\Entity\TimestampsTrait; use Frontend\User\EventListener\UserAvatarEventListener; use Frontend\User\Repository\UserAvatarRepository; @@ -15,6 +16,8 @@ #[ORM\EntityListeners([UserAvatarEventListener::class])] class UserAvatar extends AbstractEntity { + use TimestampsTrait; + #[ORM\OneToOne(inversedBy: 'avatar', targetEntity: User::class)] #[ORM\JoinColumn(name: 'userUuid', referencedColumnName: 'uuid', nullable: false)] protected UserInterface $user; diff --git a/src/User/src/Entity/UserDetail.php b/src/User/src/Entity/UserDetail.php index 4c74fa44..b8b61cd6 100644 --- a/src/User/src/Entity/UserDetail.php +++ b/src/User/src/Entity/UserDetail.php @@ -5,13 +5,17 @@ namespace Frontend\User\Entity; use Doctrine\ORM\Mapping as ORM; -use Frontend\App\Common\AbstractEntity; +use Frontend\App\Entity\AbstractEntity; +use Frontend\App\Entity\TimestampsTrait; use Frontend\User\Repository\UserDetailRepository; #[ORM\Entity(repositoryClass: UserDetailRepository::class)] #[ORM\Table(name: 'user_detail')] +#[ORM\HasLifecycleCallbacks] class UserDetail extends AbstractEntity { + use TimestampsTrait; + #[ORM\OneToOne(inversedBy: 'detail', targetEntity: User::class)] #[ORM\JoinColumn(name: 'userUuid', referencedColumnName: 'uuid', nullable: false)] protected UserInterface $user; diff --git a/src/User/src/Entity/UserRememberMe.php b/src/User/src/Entity/UserRememberMe.php index 8a9a7063..51c019aa 100644 --- a/src/User/src/Entity/UserRememberMe.php +++ b/src/User/src/Entity/UserRememberMe.php @@ -6,12 +6,16 @@ use DateTimeImmutable; use Doctrine\ORM\Mapping as ORM; -use Frontend\App\Common\AbstractEntity; +use Frontend\App\Entity\AbstractEntity; +use Frontend\App\Entity\TimestampsTrait; #[ORM\Entity] #[ORM\Table(name: 'user_remember_me')] +#[ORM\HasLifecycleCallbacks] class UserRememberMe extends AbstractEntity { + use TimestampsTrait; + #[ORM\ManyToOne(targetEntity: User::class)] #[ORM\JoinColumn(name: 'userUuid', referencedColumnName: 'uuid', nullable: false)] protected User $user; diff --git a/src/User/src/Entity/UserResetPassword.php b/src/User/src/Entity/UserResetPassword.php index 57ec0433..684cc94a 100644 --- a/src/User/src/Entity/UserResetPassword.php +++ b/src/User/src/Entity/UserResetPassword.php @@ -9,12 +9,16 @@ use DateTimeImmutable; use Doctrine\ORM\Mapping as ORM; use Exception; -use Frontend\App\Common\AbstractEntity; +use Frontend\App\Entity\AbstractEntity; +use Frontend\App\Entity\TimestampsTrait; #[ORM\Entity] #[ORM\Table(name: 'user_reset_password')] +#[ORM\HasLifecycleCallbacks] class UserResetPassword extends AbstractEntity { + use TimestampsTrait; + public const STATUS_COMPLETED = 'completed'; public const STATUS_REQUESTED = 'requested'; public const STATUSES = [ diff --git a/src/User/src/Entity/UserRole.php b/src/User/src/Entity/UserRole.php index 3983a264..055efb17 100644 --- a/src/User/src/Entity/UserRole.php +++ b/src/User/src/Entity/UserRole.php @@ -6,13 +6,17 @@ use Doctrine\ORM\Mapping as ORM; use Dot\Authorization\Role\RoleInterface; -use Frontend\App\Common\AbstractEntity; +use Frontend\App\Entity\AbstractEntity; +use Frontend\App\Entity\TimestampsTrait; use Frontend\User\Repository\UserRoleRepository; #[ORM\Entity(repositoryClass: UserRoleRepository::class)] #[ORM\Table(name: 'user_role')] +#[ORM\HasLifecycleCallbacks] class UserRole extends AbstractEntity implements RoleInterface { + use TimestampsTrait; + public const ROLE_ADMIN = 'admin'; public const ROLE_USER = 'user'; public const ROLE_GUEST = 'guest'; diff --git a/src/User/src/Repository/UserRepository.php b/src/User/src/Repository/UserRepository.php index e8b7d640..2bf5ebfa 100644 --- a/src/User/src/Repository/UserRepository.php +++ b/src/User/src/Repository/UserRepository.php @@ -11,7 +11,7 @@ use Exception; use Frontend\User\Entity\User; use Frontend\User\Entity\UserRememberMe; -use Ramsey\Uuid\Doctrine\UuidBinaryOrderedTimeType; +use Ramsey\Uuid\Uuid; /** * @extends EntityRepository @@ -24,12 +24,14 @@ class UserRepository extends EntityRepository */ public function findByUuid(string $uuid): ?User { + $uuid = Uuid::fromString($uuid)->getBytes(); + $qb = $this->getEntityManager()->createQueryBuilder(); $qb ->select('user') ->from(User::class, 'user') ->where("user.uuid = :uuid") - ->setParameter('uuid', $uuid, UuidBinaryOrderedTimeType::NAME) + ->setParameter('uuid', $uuid) ->setMaxResults(1); return $qb->getQuery()->useQueryCache(true)->getOneOrNullResult(); } @@ -51,7 +53,8 @@ public function exists(string $email = '', ?string $uuid = ''): ?User ->where('user.identity = :email')->setParameter('email', $email) ->andWhere('user.isDeleted = :isDeleted')->setParameter('isDeleted', User::IS_DELETED_NO); if (! empty($uuid)) { - $qb->andWhere('user.uuid != :uuid')->setParameter('uuid', $uuid, UuidBinaryOrderedTimeType::NAME); + $uuid = Uuid::fromString($uuid)->getBytes(); + $qb->andWhere('user.uuid != :uuid')->setParameter('uuid', $uuid); } try { @@ -104,7 +107,7 @@ public function findRememberMeUser(User $user, string $userAgent): ?UserRemember $qb->select('user_remember_me') ->from(UserRememberMe::class, 'user_remember_me') ->where('user_remember_me.user = :uuid') - ->setParameter('uuid', $user->getUuid(), UuidBinaryOrderedTimeType::NAME) + ->setParameter('uuid', $user->getUuid()->getBytes()) ->andWhere('user_remember_me.userAgent = :userAgent') ->setParameter('userAgent', $userAgent); diff --git a/src/User/src/Service/UserService.php b/src/User/src/Service/UserService.php index 56b064a5..4d677b15 100644 --- a/src/User/src/Service/UserService.php +++ b/src/User/src/Service/UserService.php @@ -12,7 +12,6 @@ use Dot\Mail\Service\MailServiceInterface; use Exception; use Frontend\App\Common\Message; -use Frontend\App\Common\UuidOrderedTimeGenerator; use Frontend\App\Service\CookieServiceInterface; use Frontend\User\Entity\User; use Frontend\User\Entity\UserAvatar; @@ -24,6 +23,7 @@ use Frontend\User\Repository\UserRoleRepository; use Laminas\Diactoros\UploadedFile; use Mezzio\Template\TemplateRendererInterface; +use Ramsey\Uuid\Uuid; use function file_exists; use function is_readable; @@ -188,7 +188,7 @@ protected function createAvatar(User $user, UploadedFile $uploadedFile): UserAva $fileName = sprintf( 'avatar-%s.%s', - UuidOrderedTimeGenerator::generateUuid()->toString(), + Uuid::uuid4()->toString(), self::EXTENSIONS[$uploadedFile->getClientMediaType()] ); diff --git a/test/Unit/App/Common/AbstractEntityTest.php b/test/Unit/App/Common/AbstractEntityTest.php deleted file mode 100644 index c52d5f16..00000000 --- a/test/Unit/App/Common/AbstractEntityTest.php +++ /dev/null @@ -1,61 +0,0 @@ -value = $value; - } - - public function getValue(): mixed - { - return $this->value; - } - - public function addValue(mixed $value): void - { - $this->value = $value; - } - }; - } - - public function testGetUuid(): void - { - $uuid = self::$entity->getUuid(); - $this->assertInstanceOf(UuidInterface::class, $uuid); - $this->assertSame($uuid, self::$entity->getUuid()); - } - - public function testExchangeArrayAddMethod(): void - { - self::$entity->exchangeArray([ - 'value' => [10], - ]); - - $this->assertSame(10, self::$entity->getValue()); - } - - public function testExchangeArraySetMethod(): void - { - self::$entity->exchangeArray([ - 'value' => 10, - ]); - - $this->assertSame(10, self::$entity->getValue()); - } -} diff --git a/test/Unit/App/Common/TimestampAwareTest.php b/test/Unit/App/Common/TimestampAwareTest.php deleted file mode 100644 index 6d0bd474..00000000 --- a/test/Unit/App/Common/TimestampAwareTest.php +++ /dev/null @@ -1,47 +0,0 @@ -assertNull($entity->getCreated()); - $this->assertNull($entity->getUpdated()); - - $entity->updateTimestamps(); - - $this->assertInstanceOf(DateTimeInterface::class, $entity->getCreated()); - $this->assertIsString($entity->getCreatedFormatted()); - $this->assertSame(date('Y-m-d H:i:s'), $entity->getCreatedFormatted()); - $this->assertSame(date('d-m-Y H:i:s'), $entity->getCreatedFormatted('d-m-Y H:i:s')); - - $this->assertInstanceOf(DateTimeInterface::class, $entity->getUpdated()); - $this->assertIsString($entity->getUpdatedFormatted()); - $this->assertSame(date('Y-m-d H:i:s'), $entity->getUpdatedFormatted()); - $this->assertSame(date('d-m-Y H:i:s'), $entity->getUpdatedFormatted('d-m-Y H:i:s')); - - $entity->setDateFormat('d-m-Y H:i:s'); - - $this->assertIsString($entity->getCreatedFormatted()); - $this->assertSame(date('d-m-Y H:i:s'), $entity->getCreatedFormatted()); - $this->assertSame(date('Y-m-d H:i:s'), $entity->getCreatedFormatted('Y-m-d H:i:s')); - - $this->assertIsString($entity->getUpdatedFormatted()); - $this->assertSame(date('d-m-Y H:i:s'), $entity->getUpdatedFormatted()); - $this->assertSame(date('Y-m-d H:i:s'), $entity->getUpdatedFormatted('Y-m-d H:i:s')); - } -} diff --git a/test/Unit/App/Common/UuidAwareTest.php b/test/Unit/App/Common/UuidAwareTest.php deleted file mode 100644 index 5d089915..00000000 --- a/test/Unit/App/Common/UuidAwareTest.php +++ /dev/null @@ -1,24 +0,0 @@ -getUuid(); - $this->assertInstanceOf(UuidInterface::class, $uuid); - $this->assertSame($uuid, $entity->getUuid()); - } -} diff --git a/test/Unit/App/Common/UuidOrderedTimeGeneratorTest.php b/test/Unit/App/Common/UuidOrderedTimeGeneratorTest.php deleted file mode 100644 index fa6cf5a3..00000000 --- a/test/Unit/App/Common/UuidOrderedTimeGeneratorTest.php +++ /dev/null @@ -1,23 +0,0 @@ -assertInstanceOf(UuidInterface::class, $firstUuid); - - $secondUuid = UuidOrderedTimeGenerator::generateUuid(); - $this->assertInstanceOf(UuidInterface::class, $secondUuid); - - $this->assertNotSame($firstUuid, $secondUuid); - } -} diff --git a/test/Unit/App/ConfigProviderTest.php b/test/Unit/App/ConfigProviderTest.php index 28e36f0f..55b68c73 100644 --- a/test/Unit/App/ConfigProviderTest.php +++ b/test/Unit/App/ConfigProviderTest.php @@ -80,18 +80,10 @@ public function testDependenciesHasAliases(): void public function testGetDoctrineConfig(): void { - $this->assertArrayHasKey('configuration', $this->config['doctrine']); - $this->assertIsArray($this->config['doctrine']['configuration']); - $this->assertArrayHasKey('orm_default', $this->config['doctrine']['configuration']); - $this->assertIsArray($this->config['doctrine']['configuration']['orm_default']); - $this->assertArrayHasKey( - 'entity_listener_resolver', - $this->config['doctrine']['configuration']['orm_default'] - ); - $this->assertSame( - EntityListenerResolver::class, - $this->config['doctrine']['configuration']['orm_default']['entity_listener_resolver'] - ); + $this->assertArrayHasKey('driver', $this->config['doctrine']); + $this->assertIsArray($this->config['doctrine']['driver']); + $this->assertArrayHasKey('orm_default', $this->config['doctrine']['driver']); + $this->assertIsArray($this->config['doctrine']['driver']['orm_default']); } public function testGetTemplates(): void diff --git a/test/Unit/User/Factory/AuthenticationAdapterFactoryTest.php b/test/Unit/User/Factory/AuthenticationAdapterFactoryTest.php index 3e393ca0..fd22c99d 100644 --- a/test/Unit/User/Factory/AuthenticationAdapterFactoryTest.php +++ b/test/Unit/User/Factory/AuthenticationAdapterFactoryTest.php @@ -61,44 +61,6 @@ public function testInvokeThrowsErrorInvalidConfigurationProvided(): void (new AuthenticationAdapterFactory())($container); } - /** - * @throws ContainerExceptionInterface - * @throws NotFoundExceptionInterface - * @throws Exception - */ - public function testInvokeThrowsErrorRepositoryNotFound(): void - { - $config = [ - 'doctrine' => [ - 'authentication' => [ - 'orm_default' => [ - 'identity_class' => User::class, - ], - ], - ], - ]; - - $container = $this->createMock(ContainerInterface::class); - $entityManager = $this->createMock(EntityManagerInterface::class); - - $entityManager->expects($this->once())->method('getRepository')->willReturn(null); - $container->expects($this->once())->method('has')->willReturn(true); - $container - ->expects($this->exactly(2)) - ->method('get') - ->willReturnOnConsecutiveCalls($entityManager, $config); - - $this->expectException(RuntimeException::class); - $this->expectExceptionMessage( - sprintf( - 'Could not find repository for identity class: %s', - $config['doctrine']['authentication']['orm_default']['identity_class'] - ) - ); - - (new AuthenticationAdapterFactory())($container); - } - /** * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface