Skip to content

Commit

Permalink
Merge pull request #2136 from tarlepp/feat/enums-take-two
Browse files Browse the repository at this point in the history
Feat - Use `Language` enum instead of class constant
  • Loading branch information
tarlepp committed Mar 5, 2023
2 parents 9d62932 + 0fd5692 commit 1b9c647
Show file tree
Hide file tree
Showing 20 changed files with 458 additions and 59 deletions.
7 changes: 7 additions & 0 deletions src/AutoMapper/User/RequestMapper.php
Expand Up @@ -10,7 +10,9 @@

use App\AutoMapper\RestRequestMapper;
use App\Entity\UserGroup;
use App\Enum\Language;
use App\Resource\UserGroupResource;
use InvalidArgumentException;
use Throwable;
use function array_map;

Expand Down Expand Up @@ -56,4 +58,9 @@ protected function transformUserGroups(array $userGroups): array
$userGroups,
);
}

protected function transformLanguage(string $language): Language
{
return Language::tryFrom($language) ?? throw new InvalidArgumentException('Invalid language');
}
}
16 changes: 12 additions & 4 deletions src/DTO/User/User.php
Expand Up @@ -13,6 +13,7 @@
use App\Entity\Interfaces\UserGroupAwareInterface;
use App\Entity\User as Entity;
use App\Entity\UserGroup as UserGroupEntity;
use App\Enum\Language;
use App\Service\Localization;
use App\Validator\Constraints as AppAssert;
use Symfony\Component\Validator\Constraints as Assert;
Expand All @@ -25,6 +26,8 @@
* @author TLe, Tarmo Leppänen <tarmo.leppanen@pinja.com>
*
* @method Entity|EntityInterface update(EntityInterface $entity)
*
* @psalm-consistent-constructor
*/
#[AppAssert\UniqueEmail]
#[AppAssert\UniqueUsername]
Expand Down Expand Up @@ -60,8 +63,8 @@ class User extends RestDto

#[Assert\NotBlank]
#[Assert\NotNull]
#[AppAssert\Language]
protected string $language = Localization::DEFAULT_LANGUAGE;
//#[AppAssert\Language]
protected Language $language;

#[Assert\NotBlank]
#[Assert\NotNull]
Expand All @@ -81,6 +84,11 @@ class User extends RestDto

protected string $password = '';

public function __construct()
{
$this->language = Language::getDefault();
}

public function getUsername(): string
{
return $this->username;
Expand Down Expand Up @@ -137,12 +145,12 @@ public function setEmail(string $email): self
return $this;
}

public function getLanguage(): string
public function getLanguage(): Language
{
return $this->language;
}

public function setLanguage(string $language): self
public function setLanguage(Language $language): self
{
$this->setVisited('language');

Expand Down
16 changes: 7 additions & 9 deletions src/Doctrine/DBAL/Types/EnumLanguageType.php
Expand Up @@ -8,24 +8,22 @@

namespace App\Doctrine\DBAL\Types;

use App\Enum\Interfaces\DatabaseEnumInterface;
use App\Enum\Language;
use BackedEnum;

/**
* Class EnumLanguageType
*
* @package App\Doctrine\DBAL\Types
* @author TLe, Tarmo Leppänen <tarmo.leppanen@pinja.com>
*/
class EnumLanguageType extends EnumType
class EnumLanguageType extends RealEnumType
{
public const LANGUAGE_EN = 'en';
public const LANGUAGE_FI = 'fi';

protected static string $name = Types::ENUM_LANGUAGE;

/**
* @var array<int, string>
* @psalm-var class-string<DatabaseEnumInterface&BackedEnum>
*/
protected static array $values = [
self::LANGUAGE_EN,
self::LANGUAGE_FI,
];
protected static string $enum = Language::class;
}
102 changes: 102 additions & 0 deletions src/Doctrine/DBAL/Types/RealEnumType.php
@@ -0,0 +1,102 @@
<?php
declare(strict_types = 1);
/**
* /src/Doctrine/DBAL/Types/RealEnumType.php
*
* @author TLe, Tarmo Leppänen <tarmo.leppanen@pinja.com>
*/

namespace App\Doctrine\DBAL\Types;

use App\Enum\Interfaces\DatabaseEnumInterface;
use BackedEnum;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\ConversionException;
use Doctrine\DBAL\Types\Type;
use InvalidArgumentException;
use function array_map;
use function gettype;
use function implode;
use function in_array;
use function is_string;

/**
* Class RealEnumType
*
* @package App\Doctrine\DBAL\Types
* @author TLe, Tarmo Leppänen <tarmo.leppanen@pinja.com>
*/
abstract class RealEnumType extends Type
{
protected static string $name;

/**
* @psalm-var class-string<DatabaseEnumInterface&BackedEnum>
*/
protected static string $enum;

/**
* @return array<int, string>
*/
public static function getValues(): array
{
return static::$enum::getValues();
}

public function getSQLDeclaration(array $column, AbstractPlatform $platform): string
{
$enumDefinition = implode(
', ',
array_map(static fn (string $value): string => "'" . $value . "'", static::getValues()),
);

return 'ENUM(' . $enumDefinition . ')';
}

/**
* @inheritDoc
*/
public function convertToDatabaseValue($value, AbstractPlatform $platform): string
{
if (!in_array($value, static::$enum::cases(), true)) {
$message = sprintf(
"Invalid '%s' value '%s'",
static::$name,
is_string($value) ? $value : gettype($value),
);

throw new InvalidArgumentException($message);
}

return (string)parent::convertToDatabaseValue($value->value, $platform);
}

/**
* @inheritDoc
*/
public function convertToPHPValue($value, AbstractPlatform $platform): DatabaseEnumInterface
{
$value = (string)parent::convertToPHPValue($value, $platform);
$enum = static::$enum::tryFrom($value);

if ($enum !== null) {
return $enum;
}

throw ConversionException::conversionFailedFormat(
gettype($value),
static::$name,
'One of: "' . implode('", "', static::getValues()) . '"',
);
}

/**
* Parent method is deprecated, so remove this after it has been removed.
*
* @codeCoverageIgnore
*/
public function getName(): string
{
return '';
}
}
10 changes: 6 additions & 4 deletions src/Entity/User.php
Expand Up @@ -16,6 +16,7 @@
use App\Entity\Traits\Timestampable;
use App\Entity\Traits\UserRelations;
use App\Entity\Traits\Uuid;
use App\Enum\Language;
use App\Service\Localization;
use App\Validator\Constraints as AppAssert;
use Doctrine\Common\Collections\ArrayCollection;
Expand Down Expand Up @@ -186,8 +187,8 @@ class User implements EntityInterface, UserInterface, UserGroupAwareInterface
])]
#[Assert\NotBlank]
#[Assert\NotNull]
#[AppAssert\Language]
private string $language = Localization::DEFAULT_LANGUAGE;
//#[AppAssert\Language]
private Language $language;

#[ORM\Column(
name: 'locale',
Expand Down Expand Up @@ -252,6 +253,7 @@ class User implements EntityInterface, UserInterface, UserGroupAwareInterface
public function __construct()
{
$this->id = $this->createUuid();
$this->language = Language::getDefault();

$this->userGroups = new ArrayCollection();
$this->logsRequest = new ArrayCollection();
Expand Down Expand Up @@ -312,12 +314,12 @@ public function setEmail(string $email): self
return $this;
}

public function getLanguage(): string
public function getLanguage(): Language
{
return $this->language;
}

public function setLanguage(string $language): self
public function setLanguage(Language $language): self
{
$this->language = $language;

Expand Down
19 changes: 19 additions & 0 deletions src/Enum/Interfaces/DatabaseEnumInterface.php
@@ -0,0 +1,19 @@
<?php
declare(strict_types = 1);
/**
* /src/Enum/Interfaces/StringEnumInterface.php
*
* @author TLe, Tarmo Leppänen <tarmo.leppanen@pinja.com>
*/

namespace App\Enum\Interfaces;

/**
* Enum StringEnumInterface
*
* @package App\Enum\Interfaces
* @author TLe, Tarmo Leppänen <tarmo.leppanen@pinja.com>
*/
interface DatabaseEnumInterface extends StringEnumInterface
{
}
25 changes: 25 additions & 0 deletions src/Enum/Interfaces/StringEnumInterface.php
@@ -0,0 +1,25 @@
<?php
declare(strict_types = 1);
/**
* /src/Enum/Interfaces/StringEnumInterface.php
*
* @author TLe, Tarmo Leppänen <tarmo.leppanen@pinja.com>
*/

namespace App\Enum\Interfaces;

use BackedEnum;

/**
* Enum StringEnumInterface
*
* @package App\Enum\Interfaces
* @author TLe, Tarmo Leppänen <tarmo.leppanen@pinja.com>
*/
interface StringEnumInterface extends BackedEnum
{
/**
* @return array<int, string>
*/
public static function getValues(): array;
}
31 changes: 31 additions & 0 deletions src/Enum/Language.php
@@ -0,0 +1,31 @@
<?php
declare(strict_types = 1);
/**
* /src/Enum/Language.php
*
* @author TLe, Tarmo Leppänen <tarmo.leppanen@pinja.com>
*/

namespace App\Enum;

use App\Enum\Interfaces\DatabaseEnumInterface;
use App\Enum\Traits\GetValues;

/**
* Language Role
*
* @package App\Entity
* @author TLe, Tarmo Leppänen <tarmo.leppanen@pinja.com>
*/
enum Language: string implements DatabaseEnumInterface
{
use GetValues;

case EN = 'en';
case FI = 'fi';

public static function getDefault(): self
{
return self::EN;
}
}
28 changes: 28 additions & 0 deletions src/Enum/Traits/GetValues.php
@@ -0,0 +1,28 @@
<?php
declare(strict_types = 1);
/**
* /src/Enum/Traits/GetValues.php
*
* @author TLe, Tarmo Leppänen <tarmo.leppanen@pinja.com>
*/

namespace App\Enum\Traits;

use function array_column;

/**
* Trait GetValues
*
* @package App\Enum\Traits
* @author TLe, Tarmo Leppänen <tarmo.leppanen@pinja.com>
*/
trait GetValues
{
/**
* @return array<int, string>
*/
public static function getValues(): array
{
return array_column(self::cases(), 'value');
}
}
15 changes: 12 additions & 3 deletions src/EventSubscriber/JWTCreatedSubscriber.php
Expand Up @@ -8,6 +8,7 @@

namespace App\EventSubscriber;

use App\Enum\Language;
use App\Security\SecurityUser;
use App\Service\Localization;
use DateTime;
Expand Down Expand Up @@ -77,9 +78,17 @@ public function onJWTCreated(JWTCreatedEvent $event): void
*/
private function setLocalizationData(array &$payload, UserInterface $user): void
{
$payload['language'] = $user instanceof SecurityUser ? $user->getLanguage() : Localization::DEFAULT_LANGUAGE;
$payload['locale'] = $user instanceof SecurityUser ? $user->getLocale() : Localization::DEFAULT_LOCALE;
$payload['timezone'] = $user instanceof SecurityUser ? $user->getTimezone() : Localization::DEFAULT_TIMEZONE;
$payload['language'] = $user instanceof SecurityUser
? $user->getLanguage()->value
: Language::getDefault()->value;

$payload['locale'] = $user instanceof SecurityUser
? $user->getLocale()
: Localization::DEFAULT_LOCALE;

$payload['timezone'] = $user instanceof SecurityUser
? $user->getTimezone()
: Localization::DEFAULT_TIMEZONE;
}

/**
Expand Down

0 comments on commit 1b9c647

Please sign in to comment.