Compare commits

...

14 commits

Author SHA1 Message Date
Jérémy Munsch
583984b157
fix workflow
Some checks are pending
PHP Composer / build (push) Waiting to run
2023-06-02 12:54:18 +02:00
Jérémy Munsch
8bd0bb17e4
update build status 2023-06-02 12:53:10 +02:00
Jérémy Munsch
385552f454
remove scrore cards 2023-06-02 12:44:49 +02:00
Jérémy Munsch
b671dd3e1c
revert and fix phpunit 2023-06-02 12:38:08 +02:00
Jérémy Munsch
beb64c6470
composer .lock ignore 2023-06-02 12:37:50 +02:00
Jérémy Munsch
0277f4d0bc
test for score cards 2023-06-02 12:19:55 +02:00
Jérémy Munsch
3687d37c2f
fix score cards php version 2023-06-02 12:17:10 +02:00
Jérémy Munsch
ff3f6336db
remove composer lock 2023-06-02 12:15:42 +02:00
Jérémy Munsch
7b2f3530e9
fix scorecards 2023-06-02 12:14:30 +02:00
Jérémy Munsch
606c380e97
Bumped for php 8.2 + fix unit test and phpcs 2023-06-02 12:12:37 +02:00
Jérémy Munsch
8b25893b99
phpcs fix 2023-05-30 09:40:09 +02:00
Jérémy Munsch
71f45fa5ed
Create scorecards.yml 2022-11-06 18:53:36 +01:00
Jérémy Munsch
cb2ec1bd82
Delete composer.lock 2022-11-06 15:10:43 +01:00
Jérémy Munsch
57a94ab316
Update php.yml
Test
2022-11-06 15:07:40 +01:00
37 changed files with 618 additions and 8151 deletions

View file

@ -18,7 +18,7 @@ jobs:
- name: Setup PHP - name: Setup PHP
uses: shivammathur/setup-php@v2 uses: shivammathur/setup-php@v2
with: with:
php-version: '7.3' php-version: '8.2'
tools: phpcs tools: phpcs
- name: Validate composer.json and composer.lock - name: Validate composer.json and composer.lock
@ -34,7 +34,7 @@ jobs:
${{ runner.os }}-php- ${{ runner.os }}-php-
- name: Install dependencies - name: Install dependencies
run: composer install --prefer-dist --no-progress run: composer install --no-progress
# Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit" # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit"
# Docs: https://getcomposer.org/doc/articles/scripts.md # Docs: https://getcomposer.org/doc/articles/scripts.md

1
.gitignore vendored
View file

@ -3,4 +3,5 @@ vendor
.phpunit.result.cache .phpunit.result.cache
.phpunit.cache .phpunit.cache
.vscode/launch.json .vscode/launch.json
composer.lock
build build

View file

@ -2,6 +2,8 @@
All notable changes to `Enum` will be documented in this file. All notable changes to `Enum` will be documented in this file.
## **Version 3.0.0**
- Changed use of php8.2 and more only For laravel 10 usage
## **Version 2.1.3** ## **Version 2.1.3**

View file

@ -16,14 +16,15 @@
"Enum" "Enum"
], ],
"require": { "require": {
"php": ">=7.3" "php": ">=8.2"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "~9", "phpunit/phpunit": "^9",
"squizlabs/php_codesniffer": "^3", "squizlabs/php_codesniffer": "^3",
"orchestra/testbench": "^6", "orchestra/testbench": "^8",
"slevomat/coding-standard": "^7", "slevomat/coding-standard": "^7",
"phpunit/php-code-coverage": "^9" "phpunit/php-code-coverage": "^9",
"nunomaduro/collision": "^6.4"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {

7950
composer.lock generated

File diff suppressed because it is too large Load diff

161
phpcs.xml
View file

@ -3,67 +3,82 @@
<arg name="colors" /> <arg name="colors" />
<arg name="extensions" value="php" /> <arg name="extensions" value="php" />
<file>src/</file> <file>src/</file>
<rule ref="PSR1" /> <rule ref="PSR1" />
<rule ref="PSR12" /> <rule ref="PSR12" />
<rule ref="Generic.CodeAnalysis.EmptyStatement" />
<rule ref="Generic.CodeAnalysis.ForLoopShouldBeWhileLoop" /> <rule ref="Generic.Classes.DuplicateClassName"/>
<rule ref="Generic.CodeAnalysis.ForLoopWithTestFunctionCall" /> <rule ref="Generic.CodeAnalysis.EmptyStatement"/>
<rule ref="Generic.CodeAnalysis.JumbledIncrementer" /> <rule ref="Generic.CodeAnalysis.ForLoopShouldBeWhileLoop"/>
<rule ref="Generic.CodeAnalysis.UnconditionalIfStatement" /> <rule ref="Generic.CodeAnalysis.ForLoopWithTestFunctionCall"/>
<rule ref="Generic.CodeAnalysis.UnnecessaryFinalModifier" /> <rule ref="Generic.CodeAnalysis.JumbledIncrementer"/>
<rule ref="Generic.CodeAnalysis.UnusedFunctionParameter" /> <rule ref="Generic.CodeAnalysis.UnconditionalIfStatement"/>
<rule ref="Generic.CodeAnalysis.UselessOverridingMethod" /> <rule ref="Generic.CodeAnalysis.UnnecessaryFinalModifier"/>
<rule ref="Generic.Commenting.Todo" /> <rule ref="Generic.CodeAnalysis.UnusedFunctionParameter"/>
<rule ref="Generic.Commenting.Fixme" /> <rule ref="Generic.CodeAnalysis.UselessOverridingMethod"/>
<rule ref="Generic.ControlStructures.InlineControlStructure" /> <rule ref="Generic.Commenting.DocComment.SpacingBeforeTags"/>
<rule ref="Generic.Files.ByteOrderMark" /> <rule ref="Generic.Commenting.Todo"/>
<rule ref="Generic.Files.LineEndings" /> <rule ref="Generic.Commenting.Fixme"/>
<rule ref="Generic.Files.LineLength" /> <rule ref="Generic.ControlStructures.InlineControlStructure"/>
<rule ref="Generic.Formatting.DisallowMultipleStatements" /> <rule ref="Generic.Files.ByteOrderMark"/>
<rule ref="Generic.Formatting.MultipleStatementAlignment" /> <rule ref="Generic.Files.LineEndings"/>
<rule ref="Generic.Formatting.NoSpaceAfterCast" /> <rule ref="Generic.Files.LineLength"/>
<rule ref="Generic.Functions.CallTimePassByReference" /> <rule ref="Generic.Formatting.DisallowMultipleStatements"/>
<rule ref="Generic.Functions.FunctionCallArgumentSpacing" /> <rule ref="Generic.Formatting.MultipleStatementAlignment"/>
<rule ref="Generic.Metrics.CyclomaticComplexity" /> <rule ref="Generic.Formatting.NoSpaceAfterCast"/>
<rule ref="Generic.Metrics.NestingLevel" /> <rule ref="Generic.Functions.CallTimePassByReference"/>
<rule ref="Generic.NamingConventions.ConstructorName" /> <rule ref="Generic.Functions.FunctionCallArgumentSpacing"/>
<rule ref="Generic.NamingConventions.UpperCaseConstantName" /> <rule ref="Generic.Metrics.CyclomaticComplexity"/>
<rule ref="Generic.NamingConventions.CamelCapsFunctionName" /> <rule ref="Generic.Metrics.NestingLevel"/>
<rule ref="Generic.PHP.DeprecatedFunctions" /> <rule ref="Generic.NamingConventions.ConstructorName"/>
<rule ref="Generic.PHP.DisallowShortOpenTag" /> <rule ref="Generic.NamingConventions.UpperCaseConstantName"/>
<rule ref="Generic.PHP.ForbiddenFunctions" /> <rule ref="Generic.NamingConventions.CamelCapsFunctionName"/>
<rule ref="Generic.PHP.LowerCaseConstant" /> <rule ref="Generic.PHP.DeprecatedFunctions"/>
<rule ref="Generic.PHP.NoSilencedErrors" /> <rule ref="Generic.PHP.DisallowShortOpenTag"/>
<rule ref="Generic.Strings.UnnecessaryStringConcat" /> <rule ref="Generic.PHP.ForbiddenFunctions"/>
<rule ref="Generic.WhiteSpace.DisallowTabIndent" /> <rule ref="Generic.PHP.NoSilencedErrors"/>
<rule ref="Generic.WhiteSpace.ScopeIndent" /> <rule ref="Generic.Strings.UnnecessaryStringConcat"/>
<rule ref="MySource.PHP.EvalObjectFactory" /> <rule ref="Generic.WhiteSpace.DisallowTabIndent"/>
<rule ref="MySource.PHP.GetRequestData" /> <rule ref="Generic.WhiteSpace.ScopeIndent"/>
<rule ref="MySource.PHP.AjaxNullComparison" /> <rule ref="MySource.PHP.EvalObjectFactory"/>
<rule ref="PEAR.Classes.ClassDeclaration" /> <rule ref="MySource.PHP.GetRequestData"/>
<rule ref="PEAR.Commenting.InlineComment" /> <rule ref="MySource.PHP.AjaxNullComparison"/>
<rule ref="PSR1.Classes.ClassDeclaration" /> <rule ref="PEAR.Classes.ClassDeclaration"/>
<rule ref="PSR1.Files.SideEffects" /> <rule ref="PEAR.Commenting.InlineComment"/>
<rule ref="Squiz.PHP.CommentedOutCode" /> <rule ref="PSR1.Classes.ClassDeclaration"/>
<rule ref="Squiz.PHP.DisallowSizeFunctionsInLoops" /> <rule ref="PSR1.Files.SideEffects"/>
<rule ref="PSR2.Classes.ClassDeclaration"/>
<rule ref="PSR2.Classes.PropertyDeclaration"/>
<rule ref="PSR2.ControlStructures.ElseIfDeclaration"/>
<rule ref="PSR2.ControlStructures.SwitchDeclaration"/>
<rule ref="PSR2.Files.EndFileNewline"/>
<rule ref="PSR2.Methods.MethodDeclaration"/>
<rule ref="PSR2.Namespaces.NamespaceDeclaration"/>
<rule ref="PSR2.Namespaces.UseDeclaration"/>
<rule ref="Squiz.PHP.CommentedOutCode"/>
<rule ref="Squiz.PHP.DisallowMultipleAssignments">
<exclude name="Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure" />
</rule>
<rule ref="Squiz.PHP.DisallowSizeFunctionsInLoops"/>
<rule ref="Squiz.PHP.DiscouragedFunctions"> <rule ref="Squiz.PHP.DiscouragedFunctions">
<properties> <properties>
<property name="error" value="true" /> <property name="error" value="true"/>
</properties> </properties>
</rule> </rule>
<rule ref="Squiz.PHP.Eval" /> <rule ref="Squiz.PHP.Eval"/>
<rule ref="Squiz.PHP.GlobalKeyword" /> <rule ref="Squiz.PHP.GlobalKeyword"/>
<rule ref="Squiz.PHP.Heredoc" /> <rule ref="Squiz.PHP.Heredoc"/>
<rule ref="Squiz.PHP.InnerFunctions" /> <rule ref="Squiz.PHP.InnerFunctions"/>
<rule ref="Squiz.PHP.LowercasePHPFunctions" /> <rule ref="Squiz.PHP.LowercasePHPFunctions"/>
<rule ref="Squiz.PHP.NonExecutableCode" /> <rule ref="Squiz.PHP.NonExecutableCode"/>
<rule ref="Squiz.Scope.MemberVarScope" /> <rule ref="Squiz.Scope.MemberVarScope"/>
<rule ref="Squiz.Scope.MethodScope" /> <rule ref="Squiz.Scope.MethodScope"/>
<rule ref="Squiz.Scope.StaticThisUsage" /> <rule ref="Squiz.Scope.StaticThisUsage"/>
<rule ref="Squiz.WhiteSpace.MemberVarSpacing" /> <rule ref="Squiz.WhiteSpace.LanguageConstructSpacing"/>
<rule ref="Squiz.WhiteSpace.ObjectOperatorSpacing"> <rule ref="Squiz.WhiteSpace.LogicalOperatorSpacing"/>
<rule ref="Squiz.WhiteSpace.MemberVarSpacing">
<properties> <properties>
<property name="ignoreNewlines" value="true"/> <property name="spacingBeforeFirst " value="false"/>
</properties> </properties>
</rule> </rule>
<rule ref="Squiz.WhiteSpace.OperatorSpacing"> <rule ref="Squiz.WhiteSpace.OperatorSpacing">
@ -71,7 +86,39 @@
<property name="ignoreNewlines" value="true"/> <property name="ignoreNewlines" value="true"/>
</properties> </properties>
</rule> </rule>
<rule ref="Squiz.WhiteSpace.ScopeKeywordSpacing" /> <rule ref="Squiz.WhiteSpace.ObjectOperatorSpacing">
<rule ref="Squiz.WhiteSpace.SemicolonSpacing" /> <properties>
<property name="ignoreNewlines" value="true"/>
</properties>
</rule>
<rule ref="Squiz.WhiteSpace.ScopeKeywordSpacing"/>
<rule ref="Squiz.WhiteSpace.SemicolonSpacing"/>
<rule ref="Squiz.Commenting.BlockComment">
<exclude name="Squiz.Commenting.BlockComment.WrongStart" />
</rule>
<rule ref="Squiz.Commenting.ClassComment">
<exclude name="Squiz.Commenting.ClassComment.Missing" />
<exclude name="Squiz.Commenting.ClassComment.TagNotAllowed" />
</rule>
<rule ref="Squiz.Commenting.DocCommentAlignment"/>
<rule ref="Squiz.Commenting.EmptyCatchComment"/>
<rule ref="Squiz.Commenting.FunctionComment">
<exclude name="Squiz.Commenting.FunctionComment.MissingParamComment" />
</rule>
<rule ref="Squiz.Commenting.FunctionCommentThrowTag"/>
<rule ref="Squiz.Commenting.InlineComment">
<exclude name="Squiz.Commenting.InlineComment.DocBlock" />
</rule>
<rule ref="Squiz.Commenting.LongConditionClosingComment">
<exclude name="Squiz.Commenting.LongConditionClosingComment.SpacingBefore" />
</rule>
<rule ref="Squiz.Commenting.PostStatementComment"/>
<rule ref="Squiz.Commenting.VariableComment"/>
<rule ref="SlevomatCodingStandard.Namespaces.UnusedUses.UnusedUse" /> <rule ref="SlevomatCodingStandard.Namespaces.UnusedUses.UnusedUse" />
<!-- For Laravel migrations -->
<rule ref="PSR1.Classes.ClassDeclaration.MissingNamespace">
<exclude-pattern>*/database/migrations/*</exclude-pattern>
</rule>
</ruleset> </ruleset>

View file

@ -1,5 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/autoload.php" backupGlobals="false" backupStaticAttributes="false" colors="true" verbose="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"> <phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
bootstrap="vendor/autoload.php"
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
verbose="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage cacheDirectory=".phpunit.cache/code-coverage" processUncoveredFiles="true"> <coverage cacheDirectory=".phpunit.cache/code-coverage" processUncoveredFiles="true">
<include> <include>
<directory suffix=".php">src/</directory> <directory suffix=".php">src/</directory>
@ -20,7 +32,6 @@
</testsuites> </testsuites>
<php> <php>
<env name="APP_ENV" value="testing"/> <env name="APP_ENV" value="testing"/>
<env name="DB_CONNECTION" value="sqlite"/> <env name="DB_CONNECTION" value="testing"/>
<env name="DB_DATABASE" value=":memory:"/>
</php> </php>
</phpunit> </phpunit>

View file

@ -2,7 +2,7 @@
![GitHub](https://img.shields.io/github/license/Kwaadpepper/enum?style=flat-square) ![GitHub](https://img.shields.io/github/license/Kwaadpepper/enum?style=flat-square)
[![Latest Version on Packagist][ico-version]][link-packagist] [![Latest Version on Packagist][ico-version]][link-packagist]
[![Total Downloads][ico-downloads]][link-downloads] [![Total Downloads][ico-downloads]][link-downloads]
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/Kwaadpepper/enum/PHP%20Composer?style=flat-square) ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/Kwaadpepper/enum/php.yml?branch=master?style=flat-square)
This package goal is to provide a complete solution to lack a long time php weakness : it do not have any `enum` support. This package goal is to provide a complete solution to lack a long time php weakness : it do not have any `enum` support.
This will change with [**php 8 enums proposition**](https://php.watch/versions/8.1/enums). In the mean time we still a support for this allowing us to generate generic and extendable applications (instead of have singletons sql tables..). This will change with [**php 8 enums proposition**](https://php.watch/versions/8.1/enums). In the mean time we still a support for this allowing us to generate generic and extendable applications (instead of have singletons sql tables..).

View file

@ -2,16 +2,12 @@
namespace Kwaadpepper\Enum; namespace Kwaadpepper\Enum;
use BadMethodCallException;
use JsonSerializable;
use Kwaadpepper\Enum\Exceptions\DuplicateDefinitionException; use Kwaadpepper\Enum\Exceptions\DuplicateDefinitionException;
use Kwaadpepper\Enum\Exceptions\DuplicateLabelsException; use Kwaadpepper\Enum\Exceptions\DuplicateLabelsException;
use Kwaadpepper\Enum\Exceptions\DuplicateValuesException; use Kwaadpepper\Enum\Exceptions\DuplicateValuesException;
use Kwaadpepper\Enum\Exceptions\EmptyDefinitionException; use Kwaadpepper\Enum\Exceptions\EmptyDefinitionException;
use Kwaadpepper\Enum\Exceptions\EnumNotRoutableException; use Kwaadpepper\Enum\Exceptions\EnumNotRoutableException;
use Kwaadpepper\Enum\Exceptions\UnknownEnumProperty; use Kwaadpepper\Enum\Exceptions\UnknownEnumProperty;
use ReflectionClass;
use TypeError;
/** /**
* This Base Enum is the class which should * This Base Enum is the class which should
@ -20,18 +16,15 @@ use TypeError;
* @property-read int|string $value The enum value, can be string or int * @property-read int|string $value The enum value, can be string or int
* @property-read string $label The enum label, is a string * @property-read string $label The enum label, is a string
*/ */
abstract class BaseEnum implements JsonSerializable abstract class BaseEnum implements \JsonSerializable
{ {
/** /**
* @var string|int * @var string|integer
* @readonly
*/ */
protected $value; protected $value;
/** /**
* @var string * @var string
* @readonly
*/ */
protected $label; protected $label;
@ -42,13 +35,16 @@ abstract class BaseEnum implements JsonSerializable
// -- ENUM MAGIC METHODS -- // -- ENUM MAGIC METHODS --
/** /**
* @param int|string $value * @param integer|string $value
* @param string $label * @param string $label
* @throws TypeError If anything else than string or int is used for value. * @throws \TypeError If anything else than string or int
* @throws EnumNotRoutableException If provided value are null * is used for value.
* @throws \Kwaadpepper\Enum\Exceptions\EnumNotRoutableException If provided value are null.
* @phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
*/ */
public function __construct($value = null, string $label = null) public function __construct($value = null, string $label = null)
{ {
// phpcs:ignore
/** /**
* This cannot be allowed, happens with laravel resolver * This cannot be allowed, happens with laravel resolver
* when using BaseEnum instead of BaseEnumRoutable * when using BaseEnum instead of BaseEnumRoutable
@ -62,8 +58,8 @@ abstract class BaseEnum implements JsonSerializable
/** /**
* @param string $attribute * @param string $attribute
* @return int|string * @return integer|string
* @throws UnknownEnumProperty * @throws \Kwaadpepper\Enum\Exceptions\UnknownEnumProperty As it could not be found.
*/ */
public function __get(string $attribute) public function __get(string $attribute)
{ {
@ -78,20 +74,22 @@ abstract class BaseEnum implements JsonSerializable
/** /**
* @param string $name * @param string $name
* @param array $arguments * @param array $arguments
* @return static * @return static
* @throws TypeError If anything else than string or int is used. * @throws \TypeError If anything else than string or int is used.
* @throws BadMethodCallException If a matching definition cannot be found. * @throws \BadMethodCallException If a matching definition cannot be found.
* @throws EnumNotRoutableException If provided value are null * @throws \Kwaadpepper\Enum\Exceptions\EnumNotRoutableException If provided value are null.
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUsed
*/ */
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUsed
public static function __callStatic(string $name, array $arguments) public static function __callStatic(string $name, array $arguments)
{ {
// phpcs:enable
return static::make($name); return static::make($name);
} }
/** /**
* Output the value as a string * Output the value as a string
*
* @return string * @return string
*/ */
public function __toString(): string public function __toString(): string
@ -149,7 +147,8 @@ abstract class BaseEnum implements JsonSerializable
// -- DEFINITON METHODS -- // -- DEFINITON METHODS --
/** /**
* @return string[]|int[]|Closure * Get all values
*
* @return array<string, string|int> | Closure(string):(int|string) * @return array<string, string|int> | Closure(string):(int|string)
*/ */
protected static function values() protected static function values()
@ -158,7 +157,8 @@ abstract class BaseEnum implements JsonSerializable
} }
/** /**
* @return string[]|Closure * Get all labels
*
* @return array<string, string> | Closure(string):string * @return array<string, string> | Closure(string):string
*/ */
protected static function labels() protected static function labels()
@ -185,21 +185,23 @@ abstract class BaseEnum implements JsonSerializable
/** /**
* Parse a value to create its corresponding enumeration value. * Parse a value to create its corresponding enumeration value.
* *
* @param string|int $value * @param string|integer $value
* @return static * @return static
* @throws TypeError If anything else than string or int is used. * @throws TypeError If anything else than string or int is used.
* @throws BadMethodCallException If a matching definition cannot be found. * @throws \BadMethodCallException If a matching definition cannot be found.
* @throws EnumNotRoutableException If provided value are null * @throws \Kwaadpepper\Enum\Exceptions\EnumNotRoutableException If provided value are null.
* @phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
*/ */
public static function make($value): BaseEnum public static function make($value): BaseEnum
{ {
// phpcs:enable
self::assertValidValue($value); self::assertValidValue($value);
$definition = static::findDefinition($value); $definition = static::findDefinition($value);
if ($definition === null) { if ($definition === null) {
$enumClass = static::class; $enumClass = static::class;
throw new BadMethodCallException( throw new \BadMethodCallException(
"There's no value $value defined for enum $enumClass, consider adding it in the docblock definition." "There's no value $value defined for enum $enumClass, consider adding it in the docblock definition."
); );
} }
@ -212,16 +214,19 @@ abstract class BaseEnum implements JsonSerializable
return $obj; return $obj;
} }
public function equals(BaseEnum ...$others): bool /**
* Test if an enum values is equal to another
*
* @param \Kwaadpepper\Enum\BaseEnum $other
* @return boolean
*/
public function equals(BaseEnum $other): bool
{ {
foreach ($others as $other) { if (
// @phpcs:disable PSR2.ControlStructures.ControlStructureSpacing.SpacingAfterOpenBrace get_class($this) === get_class($other)
if ( && $this->value === $other->value
get_class($this) === get_class($other) ) {
&& $this->value === $other->value return true;
) {
return true;
}
} }
return false; return false;
} }
@ -241,7 +246,7 @@ abstract class BaseEnum implements JsonSerializable
// -- PRIVATE METHODS -- // -- PRIVATE METHODS --
/** /**
* @param string|int $input * @param string|integer $input
* @return \Kwaadpepper\Enum\BaseEnumDefinition|null * @return \Kwaadpepper\Enum\BaseEnumDefinition|null
*/ */
private static function findDefinition($input): ?BaseEnumDefinition private static function findDefinition($input): ?BaseEnumDefinition
@ -255,15 +260,22 @@ abstract class BaseEnum implements JsonSerializable
} }
/** /**
* Resolve enum defintion
*
* @return \Kwaadpepper\Enum\BaseEnumDefinition[] * @return \Kwaadpepper\Enum\BaseEnumDefinition[]
* @throws \Kwaadpepper\Enum\Exceptions\EmptyDefinitionException If there is any.
* @throws \Kwaadpepper\Enum\Exceptions\DuplicateValuesException If there is any in labels map.
* @throws \Kwaadpepper\Enum\Exceptions\DuplicateValuesException If there is any in values map.
* @phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
*/ */
private static function resolveDefinition(): array private static function resolveDefinition(): array
{ {
// phpcs:enable
if (isset(self::$definitionCache[static::class])) { if (isset(self::$definitionCache[static::class])) {
return self::$definitionCache[static::class]; return self::$definitionCache[static::class];
} }
$reflectionClass = new ReflectionClass(static::class); $reflectionClass = new \ReflectionClass(static::class);
$docComment = $reflectionClass->getDocComment(); $docComment = $reflectionClass->getDocComment();
preg_match_all('/@method\s+static\s+self\s+([\w_]+)\(\)/', $docComment, $matches); preg_match_all('/@method\s+static\s+self\s+([\w_]+)\(\)/', $docComment, $matches);
@ -297,7 +309,9 @@ abstract class BaseEnum implements JsonSerializable
throw new DuplicateLabelsException('You have duplicates values in enum labels method.'); throw new DuplicateLabelsException('You have duplicates values in enum labels method.');
} }
return self::$definitionCache[static::class] = $definition; self::$definitionCache[static::class] = $definition;
return self::$definitionCache[static::class];
} }
/** /**
@ -322,13 +336,13 @@ abstract class BaseEnum implements JsonSerializable
* *
* @param mixed $value * @param mixed $value
* @return void * @return void
* @throws TypeError If anything else than string or int is used. * @throws \TypeError If anything else than string or int is used.
*/ */
private static function assertValidValue($value): void private static function assertValidValue(mixed $value): void
{ {
if (!(is_string($value) || is_int($value))) { if (!(is_string($value) || is_int($value))) {
$enumClass = static::class; $enumClass = static::class;
throw new TypeError("Only string and integer are allowed values for enum $enumClass."); throw new \TypeError("Only string and integer are allowed values for enum $enumClass.");
} }
} }
} }

View file

@ -8,8 +8,7 @@ namespace Kwaadpepper\Enum;
*/ */
class BaseEnumDefinition class BaseEnumDefinition
{ {
/** @var string|integer */
/** @var string|int */
public $value; public $value;
/** @var string */ /** @var string */
@ -19,9 +18,9 @@ class BaseEnumDefinition
private $methodName; private $methodName;
/** /**
* @param string $methodName * @param string $methodName
* @param string|int $value * @param string|integer $value
* @param string $label * @param string $label
*/ */
public function __construct(string $methodName, $value, string $label) public function __construct(string $methodName, $value, string $label)
{ {
@ -31,8 +30,8 @@ class BaseEnumDefinition
} }
/** /**
* @param string|int $input * @param string|integer $input
* @return bool * @return boolean
*/ */
public function equals($input): bool public function equals($input): bool
{ {

View file

@ -29,37 +29,43 @@ abstract class BaseEnumRoutable extends BaseEnum implements UrlRoutable
/** /**
* Get the route key for the model. * Get the route key for the model.
* *
* @phpcs:disable Squiz.Commenting.FunctionComment.InvalidNoReturn
*
* @return string * @return string
* @throws \Kwaadpepper\Enum\Exceptions\NotImplementedException GetRouteKeyName not implemented,
* should not be used.
*/ */
public function getRouteKeyName() public function getRouteKeyName()
{ {
// phpcs:enable
// @codeCoverageIgnoreStart // @codeCoverageIgnoreStart
throw new NotImplementedException('getRouteKeyName not implemented, should not be used.'); throw new NotImplementedException('GetRouteKeyName not implemented, should not be used.');
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd
} }
/** /**
* Retrieve the model for a bound value. * Retrieve the model for a bound value.
* *
* @param mixed $value * @param mixed $value
* @param string|null $field * @param string|null $field
* @return \Kwaadpepper\Enum\BaseEnum|null * @return \Kwaadpepper\Enum\BaseEnum|null
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassAfterLastUsed
*/ */
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassAfterLastUsed public function resolveRouteBinding(mixed $value, $field = null)
public function resolveRouteBinding($value, $field = null)
{ {
// try to cast numeric value first // phpcs:enable
// Try to cast numeric value first.
try { try {
// try cast to int // Try cast to int.
$iValue = (is_numeric($value) and floatval(intval($value)) === floatval($value)) ? $iValue = (is_numeric($value) and floatval(intval($value)) === floatval($value)) ?
(int)$value : $value; (int)$value : $value;
return static::make($iValue); return static::make($iValue);
} catch (BadMethodCallException | EnumNotRoutableException | TypeError $e) { } catch (BadMethodCallException | EnumNotRoutableException | TypeError $e) {
// try string value after that // Try string value after that.
try { try {
return static::make($value); return static::make($value);
} catch (BadMethodCallException | EnumNotRoutableException | TypeError $e) { } catch (BadMethodCallException | EnumNotRoutableException | TypeError $e) {
// could not find a suitable value // Could not find a suitable value.
return null; return null;
} }
} }
@ -68,16 +74,22 @@ abstract class BaseEnumRoutable extends BaseEnum implements UrlRoutable
/** /**
* Retrieve the child model for a bound value. * Retrieve the child model for a bound value.
* *
* @param string $childType * @phpcs:disable Squiz.Commenting.FunctionComment.InvalidNoReturn
* @param mixed $value *
* @param string|null $field * @param string $childType
* @param mixed $value
* @param string|null $field
* @return \Illuminate\Database\Eloquent\Model|null * @return \Illuminate\Database\Eloquent\Model|null
* @throws NotImplementedException * @throws \Kwaadpepper\Enum\Exceptions\NotImplementedException ResolveChildRouteBinding not implemented,
* should not be used.
* @phpcs:disable Squiz.Commenting.FunctionComment.ScalarTypeHintMissing
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
*/ */
public function resolveChildRouteBinding($childType, $value, $field) public function resolveChildRouteBinding($childType, $value, $field)
{ {
// phpcs:enable
// @codeCoverageIgnoreStart // @codeCoverageIgnoreStart
throw new NotImplementedException('resolveChildRouteBinding not implemented, should not be used.'); throw new NotImplementedException('ResolveChildRouteBinding not implemented, should not be used.');
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd
} }
} }

View file

@ -7,14 +7,29 @@ use Illuminate\Support\Facades\File;
class CreateEnum extends Command class CreateEnum extends Command
{ {
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'make:enum'; protected $signature = 'make:enum';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new enum class'; protected $description = 'Create a new enum class';
// phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh /**
* Handle the command
*
* @return integer|void
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
*/
public function handle() public function handle()
{ {
// phpcs:enable
$validate = false; $validate = false;
$info = [ $info = [
'name' => false, 'name' => false,
@ -108,6 +123,13 @@ class CreateEnum extends Command
$this->info(\sprintf('File generated %s', \app_path("Enums/$name.php"))); $this->info(\sprintf('File generated %s', \app_path("Enums/$name.php")));
} }
/**
* Replace the class name
*
* @param string $templateEnum
* @param array $info
* @return void
*/
private function replaceClassName(string &$templateEnum, array $info): void private function replaceClassName(string &$templateEnum, array $info): void
{ {
$targetDefinition = "class TemplateEnum"; $targetDefinition = "class TemplateEnum";
@ -116,6 +138,13 @@ class CreateEnum extends Command
$templateEnum = str_replace($targetDefinition, $replaceDefinition, $templateEnum); $templateEnum = str_replace($targetDefinition, $replaceDefinition, $templateEnum);
} }
/**
* Replace definition
*
* @param string $templateEnum
* @param array $info
* @return void
*/
private function replaceDefinition(string &$templateEnum, array $info): void private function replaceDefinition(string &$templateEnum, array $info): void
{ {
$targetDefinition = " * ##VALUES\n"; $targetDefinition = " * ##VALUES\n";
@ -129,6 +158,13 @@ class CreateEnum extends Command
$templateEnum = str_replace($targetDefinition, $replaceDefinition, $templateEnum); $templateEnum = str_replace($targetDefinition, $replaceDefinition, $templateEnum);
} }
/**
* Insert lables and values
*
* @param string $templateEnum
* @param array $info
* @return void
*/
private function insertLabelsAndValues(string &$templateEnum, array $info): void private function insertLabelsAndValues(string &$templateEnum, array $info): void
{ {
$targetDefinition = " // ##OVERRIDE\n"; $targetDefinition = " // ##OVERRIDE\n";

View file

@ -20,7 +20,7 @@ class EnumServiceProvider extends ServiceProvider
__DIR__ . '/../resources/lang' => resource_path('lang/vendor/enum'), __DIR__ . '/../resources/lang' => resource_path('lang/vendor/enum'),
]); ]);
// Register the command if we are using the application via the CLI // Register the command if we are using the application via the CLI.
if ($this->app->runningInConsole()) { if ($this->app->runningInConsole()) {
$this->commands([ $this->commands([
CreateEnum::class, CreateEnum::class,

View file

@ -12,5 +12,4 @@ use Exception;
*/ */
class DuplicateDefinitionException extends Exception class DuplicateDefinitionException extends Exception
{ {
//
} }

View file

@ -12,5 +12,4 @@ use Exception;
*/ */
class DuplicateLabelsException extends Exception class DuplicateLabelsException extends Exception
{ {
//
} }

View file

@ -9,7 +9,7 @@ use Exception;
* contain multiple times the same value * contain multiple times the same value
* *
* This should only happen if you override the values method * This should only happen if you override the values method
*/ class DuplicateValuesException extends Exception */
class DuplicateValuesException extends Exception
{ {
//
} }

View file

@ -12,5 +12,4 @@ use Exception;
*/ */
class EmptyDefinitionException extends Exception class EmptyDefinitionException extends Exception
{ {
//
} }

View file

@ -12,5 +12,4 @@ use Exception;
*/ */
class EnumNotRoutableException extends Exception class EnumNotRoutableException extends Exception
{ {
//
} }

View file

@ -11,5 +11,4 @@ use Exception;
*/ */
class NotImplementedException extends Exception class NotImplementedException extends Exception
{ {
//
} }

View file

@ -6,5 +6,4 @@ use Exception;
class UnknownEnumClass extends Exception class UnknownEnumClass extends Exception
{ {
//
} }

View file

@ -10,9 +10,19 @@ use Exception;
*/ */
class UnknownEnumProperty extends Exception class UnknownEnumProperty extends Exception
{ {
/**
* The error message
*
* @var string
*/
protected $message; protected $message;
/**
* Construct the exception. Note: The message is NOT binary safe.
*
* @param string $attribute
* @return void
*/
public function __construct(string $attribute) public function __construct(string $attribute)
{ {
$this->message = "Unknown attribute $attribute, enumeration only have propeties `label` and `value`."; $this->message = "Unknown attribute $attribute, enumeration only have propeties `label` and `value`.";

View file

@ -8,7 +8,6 @@ use Kwaadpepper\Enum\Exceptions\UnknownEnumClass;
abstract class BaseEnumRule implements Rule abstract class BaseEnumRule implements Rule
{ {
/** @var string $enum */ /** @var string $enum */
protected $enumClass; protected $enumClass;
@ -18,6 +17,7 @@ abstract class BaseEnumRule implements Rule
* *
* @param string $enumClass * @param string $enumClass
* @return void * @return void
* @throws \Kwaadpepper\Enum\Exceptions\UnknownEnumClass If the class passed is not an enum.
*/ */
public function __construct(string $enumClass) public function __construct(string $enumClass)
{ {
@ -30,11 +30,14 @@ abstract class BaseEnumRule implements Rule
/** /**
* Determine if the validation rule passes. * Determine if the validation rule passes.
* *
* @param string $attribute * @param string $attribute
* @param mixed $value * @param mixed $value
* @return bool * @return boolean
* @phpcs:disable Squiz.Commenting.FunctionComment.ScalarTypeHintMissing
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
*/ */
abstract public function passes($attribute, $value): bool; abstract public function passes($attribute, $value): bool;
// phpcs:enable
/** /**
* Get the validation error message. * Get the validation error message.

View file

@ -10,19 +10,21 @@ use TypeError;
*/ */
class EnumIsValidRule extends BaseEnumRule class EnumIsValidRule extends BaseEnumRule
{ {
/** /**
* Determine if the validation rule passes. * Determine if the validation rule passes.
* *
* @param string $attribute * @param string $attribute
* @param mixed $value * @param mixed $value
* @return bool * @return boolean
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
* @phpcs:disable Squiz.Commenting.FunctionComment.ScalarTypeHintMissing
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
*/ */
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
public function passes($attribute, $value): bool public function passes($attribute, $value): bool
{ {
// phpcs:enable
try { try {
// try cast to int if is int // Try cast to int if is int.
$value = (is_numeric($value) and floatval(intval($value)) === floatval($value)) ? $value = (is_numeric($value) and floatval(intval($value)) === floatval($value)) ?
(int)$value : $value; (int)$value : $value;
forward_static_call([$this->enumClass, 'make'], $value); forward_static_call([$this->enumClass, 'make'], $value);

View file

@ -2,10 +2,8 @@
namespace Kwaadpepper\Enum\Traits; namespace Kwaadpepper\Enum\Traits;
use BadMethodCallException;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Kwaadpepper\Enum\BaseEnum; use Kwaadpepper\Enum\BaseEnum;
use TypeError;
/** /**
* @property array $attributes Laravel model attributes * @property array $attributes Laravel model attributes
@ -15,15 +13,16 @@ use TypeError;
*/ */
trait CastsEnums trait CastsEnums
{ {
/** /**
* Get a plain attribute (not a relationship). * Get a plain attribute (not a relationship).
* *
* @param string $key * @param string $key
* @return mixed * @return mixed
* @phpcs:disable Squiz.Commenting.FunctionComment.ScalarTypeHintMissing
*/ */
public function getAttributeValue($key) public function getAttributeValue($key)
{ {
// phpcs:enable
$value = parent::getAttributeValue($key); $value = parent::getAttributeValue($key);
if ($this->hasEnumCast($key)) { if ($this->hasEnumCast($key)) {
@ -36,18 +35,23 @@ trait CastsEnums
/** /**
* Set a given attribute on the model. * Set a given attribute on the model.
* *
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @return $this * @return $this
* @throws \TypeError If cast fails.
* @throws \BadMethodCallException If cast fails.
* @phpcs:disable Squiz.Commenting.FunctionComment.ScalarTypeHintMissing
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
*/ */
public function setAttribute($key, $value) public function setAttribute($key, $value)
{ {
// phpcs:enable
try { try {
if ($enum = $this->castToEnum($key, $value) and $enum instanceof BaseEnum) { if ($enum = $this->castToEnum($key, $value) and $enum instanceof BaseEnum) {
$this->attributes[$key] = $enum->value; $this->attributes[$key] = $enum->value;
return $this; return $this;
} }
} catch (TypeError | BadMethodCallException $e) { } catch (\TypeError | \BadMethodCallException $e) {
Log::debug(\sprintf('%s : trait CastEnums error, %s', __CLASS__, $e->getMessage())); Log::debug(\sprintf('%s : trait CastEnums error, %s', __CLASS__, $e->getMessage()));
if (in_array(config('app.env'), ['debug', 'testing'])) { if (in_array(config('app.env'), ['debug', 'testing'])) {
throw $e; throw $e;
@ -61,13 +65,15 @@ trait CastsEnums
/** /**
* Determine whether an attribute should be cast to a enum. * Determine whether an attribute should be cast to a enum.
* *
* @param string $key * @param string $key
* @return bool * @return boolean
*/ */
public function hasEnumCast($key): bool public function hasEnumCast(string $key): bool
{ {
// This can happen if this trait is added to the model /**
// but no enum casts have been added yet * This can happen if this trait is added to the model
* but no enum casts have been added yet.
*/
if ($this->enumCasts === null) { if ($this->enumCasts === null) {
return false; return false;
} }
@ -79,13 +85,13 @@ trait CastsEnums
/** /**
* Casts the given key to an enum instance * Casts the given key to an enum instance
* *
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @return \Kwaadpepper\Enum\BaseEnum|mixed|null * @return \Kwaadpepper\Enum\BaseEnum|mixed|null
* @throws TypeError — If anything else than string or int is used. * @throws TypeError — If anything else than string or int is used.
* @throws BadMethodCallException — If a matching definition cannot be found. * @throws BadMethodCallException — If a matching definition cannot be found.
*/ */
protected function castToEnum($key, $value) protected function castToEnum(string $key, mixed $value)
{ {
if ( if (
$value === null or $value === null or
@ -99,7 +105,7 @@ trait CastsEnums
$value = $this->castAttribute($key, $value); $value = $this->castAttribute($key, $value);
} }
// try cast to int // Try cast to int.
$value = (is_numeric($value) and floatval(intval($value)) === floatval($value)) ? $value = (is_numeric($value) and floatval(intval($value)) === floatval($value)) ?
(int)$value : $value; (int)$value : $value;

View file

@ -15,19 +15,19 @@ use Kwaadpepper\Enum\Tests\Enums\NotRoutableEnum;
use Kwaadpepper\Enum\Tests\Models\Alarm; use Kwaadpepper\Enum\Tests\Models\Alarm;
use Kwaadpepper\Enum\Tests\Models\Journal; use Kwaadpepper\Enum\Tests\Models\Journal;
use Kwaadpepper\Enum\Tests\Models\Report; use Kwaadpepper\Enum\Tests\Models\Report;
use Orchestra\Testbench\TestCase;
use SplFileObject;
class BaseEnumRoutableTest extends TestCase class BaseEnumRoutableTest extends TestCase
{ {
/** /**
* Defines aliases * Defines aliases
* *
* @param [type] $app * @param \Illuminate\Foundation\Application $app
* @return void * @return void
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
*/ */
protected function getPackageAliases($app) protected function getPackageAliases($app)
{ {
// phpcs:enable
$app->alias(Alarm::class, 'Alarm'); $app->alias(Alarm::class, 'Alarm');
$app->alias(Journal::class, 'Journal'); $app->alias(Journal::class, 'Journal');
$app->alias(Report::class, 'Report'); $app->alias(Report::class, 'Report');
@ -40,15 +40,17 @@ class BaseEnumRoutableTest extends TestCase
/** /**
* Get package providers. * Get package providers.
* *
* @param \Illuminate\Foundation\Application $app * @param \Illuminate\Foundation\Application $app
* *
* @return array * @return array
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
*/ */
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
protected function getPackageProviders($app) protected function getPackageProviders($app)
{ {
// phpcs:enable
return [ return [
'Kwaadpepper\Enum\EnumServiceProvider', \Kwaadpepper\Enum\EnumServiceProvider::class,
]; ];
} }
@ -110,39 +112,45 @@ class BaseEnumRoutableTest extends TestCase
/** /**
* Define routes setup. * Define routes setup.
* *
* @param \Illuminate\Routing\Router $router * @param \Illuminate\Routing\Router $router
* *
* @return void * @return void
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
*/ */
protected function defineRoutes($router) protected function defineRoutes($router)
{ {
// phpcs:enable
$router->get('/journals/{journal}', function (Journal $journal) { $router->get('/journals/{journal}', function (Journal $journal) {
return response()->json([$journal->day]); return response()->json([$journal->day]);
})->middleware('bindings')->name('journal.view'); })->middleware(\Illuminate\Routing\Middleware\SubstituteBindings::class)->name('journal.view');
$router->get('/reports/{report}', function (Report $report) { $router->get('/reports/{report}', function (Report $report) {
return response()->json([$report->day]); return response()->json([$report->day]);
})->middleware('bindings'); })->middleware(\Illuminate\Routing\Middleware\SubstituteBindings::class);
$router->get('/alarms/{alarm}', function (Alarm $alarm) { $router->get('/alarms/{alarm}', function (Alarm $alarm) {
return response()->json([$alarm->day]); return response()->json([$alarm->day]);
})->middleware('bindings'); })->middleware(\Illuminate\Routing\Middleware\SubstituteBindings::class);
$router->get('/days/{day}', function (Days $day) { $router->get('/days/{day}', function (Days $day) {
return response()->json([$day]); return response()->json([$day]);
})->middleware('bindings'); })->middleware(\Illuminate\Routing\Middleware\SubstituteBindings::class);
$router->get('/day-validation', function (PassDayRequest $request) { $router->get('/day-validation', function (PassDayRequest $request) {
return response()->json([Days::make((int)$request->day)]); return response()->json([Days::make((int)$request->day)]);
})->middleware('bindings'); })->middleware(\Illuminate\Routing\Middleware\SubstituteBindings::class);
$router->get('/civilities/{civility}', function (ContactFormCivility $civility) { $router->get('/civilities/{civility}', function (ContactFormCivility $civility) {
return response()->json([$civility]); return response()->json([$civility]);
})->middleware('bindings'); })->middleware(\Illuminate\Routing\Middleware\SubstituteBindings::class);
$router->get('/force/{force}', function (ForceStringsFromInteger $force) { $router->get('/force/{force}', function (ForceStringsFromInteger $force) {
return response()->json([$force]); return response()->json([$force]);
})->middleware('bindings'); })->middleware(\Illuminate\Routing\Middleware\SubstituteBindings::class);
$router->get('/notroutable/{notroutable}', function (NotRoutableEnum $notroutable) { $router->get('/notroutable/{notroutable}', function (NotRoutableEnum $notroutable) {
dd($notroutable);
return response()->json([$notroutable]); return response()->json([$notroutable]);
})->middleware('bindings'); })->middleware(\Illuminate\Routing\Middleware\SubstituteBindings::class);
} }
/**
* Test route values
*
* @return void
*/
public function testRoutesDays() public function testRoutesDays()
{ {
$response = $this->json('GET', sprintf('/days/%s', Days::none()->value)); $response = $this->json('GET', sprintf('/days/%s', Days::none()->value));
@ -153,6 +161,11 @@ class BaseEnumRoutableTest extends TestCase
$response->assertExactJson([Days::mon()]); $response->assertExactJson([Days::mon()]);
} }
/**
* Test route with example civilities
*
* @return void
*/
public function testRoutesCivilities() public function testRoutesCivilities()
{ {
$response = $this->json('GET', sprintf('/civilities/%s', ContactFormCivility::mme()->value)); $response = $this->json('GET', sprintf('/civilities/%s', ContactFormCivility::mme()->value));
@ -160,6 +173,11 @@ class BaseEnumRoutableTest extends TestCase
$response->assertExactJson([ContactFormCivility::mme()]); $response->assertExactJson([ContactFormCivility::mme()]);
} }
/**
* Test route with enum as string
*
* @return void
*/
public function testRoutesWithEnumIntString() public function testRoutesWithEnumIntString()
{ {
$response = $this->json('GET', sprintf('/force/%s', ForceStringsFromInteger::valueB()->value)); $response = $this->json('GET', sprintf('/force/%s', ForceStringsFromInteger::valueB()->value));
@ -167,12 +185,22 @@ class BaseEnumRoutableTest extends TestCase
$response->assertExactJson([ForceStringsFromInteger::valueB()]); $response->assertExactJson([ForceStringsFromInteger::valueB()]);
} }
/**
* Test route with enum not found
*
* @return void
*/
public function testRoutesWithEnumNotFound() public function testRoutesWithEnumNotFound()
{ {
$response = $this->json('GET', '/force/6'); $response = $this->json('GET', '/force/6');
$response->assertNotFound(); $response->assertNotFound();
} }
/**
* Test routes with enums as pk
*
* @return void
*/
public function testRoutesWithEnumAsPrimaryKey() public function testRoutesWithEnumAsPrimaryKey()
{ {
$response = $this->json('GET', sprintf('/reports/%s', Days::none()->value)); $response = $this->json('GET', sprintf('/reports/%s', Days::none()->value));
@ -187,6 +215,11 @@ class BaseEnumRoutableTest extends TestCase
$response->assertNotFound(); $response->assertNotFound();
} }
/**
* Test routes with enum as pk without cast enums
*
* @return void
*/
public function testRoutesWithEnumAsPrimaryKeyWithoutCastEnums() public function testRoutesWithEnumAsPrimaryKeyWithoutCastEnums()
{ {
$response = $this->json('GET', sprintf('/alarms/%s', Days::none()->value)); $response = $this->json('GET', sprintf('/alarms/%s', Days::none()->value));
@ -201,9 +234,15 @@ class BaseEnumRoutableTest extends TestCase
$response->assertNotFound(); $response->assertNotFound();
} }
/**
* Test routes wit henum as pk without cast enums
*
* ! This test includes getRouteKey method for coverage
*
* @return void
*/
public function testRoutesWithEnumAsPrimaryKeyWithoutCastEnumsAndCast() public function testRoutesWithEnumAsPrimaryKeyWithoutCastEnumsAndCast()
{ {
// This test includes getRouteKey method for coverage
$response = $this->json('GET', \route('journal.view', Days::none())); $response = $this->json('GET', \route('journal.view', Days::none()));
$response->assertOk(); $response->assertOk();
$response = $this->json('GET', \route('journal.view', Days::mon())); $response = $this->json('GET', \route('journal.view', Days::mon()));
@ -216,6 +255,11 @@ class BaseEnumRoutableTest extends TestCase
$response->assertNotFound(); $response->assertNotFound();
} }
/**
* Test enum is valid rule
*
* @return void
*/
public function testRules() public function testRules()
{ {
$rule = new EnumIsValidRule(Days::class); $rule = new EnumIsValidRule(Days::class);
@ -224,24 +268,45 @@ class BaseEnumRoutableTest extends TestCase
$this->assertFalse($rule->passes('day', Days::mon())); $this->assertFalse($rule->passes('day', Days::mon()));
} }
/**
* Test route with enum
*
* @return void
*/
public function testRulesRequest() public function testRulesRequest()
{ {
$response = $this->json('GET', sprintf('/day-validation?day=%s', Days::fri()->value)); $response = $this->json('GET', sprintf('/day-validation?day=%s', Days::fri()->value));
$response->assertOk(); $response->assertOk();
} }
/**
* Test route fails on non enum
*
* @return void
*/
public function testRulesRequestFail() public function testRulesRequestFail()
{ {
$response = $this->json('GET', sprintf('/day-validation?day=%s', '"!:')); $response = $this->json('GET', sprintf('/day-validation?day=%s', '"!:'));
$response->assertJsonValidationErrors('day'); $response->assertJsonValidationErrors('day');
} }
/**
* Test Enum validate enum class on non enum class
*
* @return void
*/
public function testRulesRequestInvalid() public function testRulesRequestInvalid()
{ {
$this->expectException(UnknownEnumClass::class); $this->expectException(UnknownEnumClass::class);
new EnumIsValidRule(SplFileObject::class); new EnumIsValidRule(\SplFileObject::class);
} }
/**
* Test enum is not routable
*
* @return void
*/
public function testNotRoutableEnum() public function testNotRoutableEnum()
{ {
$response = $this->json('GET', sprintf('/notroutable/%s', '1')); $response = $this->json('GET', sprintf('/notroutable/%s', '1'));

View file

@ -2,8 +2,6 @@
namespace Kwaadpepper\Enum\Tests; namespace Kwaadpepper\Enum\Tests;
use BadMethodCallException;
use Exception;
use Kwaadpepper\Enum\Exceptions\DuplicateLabelsException; use Kwaadpepper\Enum\Exceptions\DuplicateLabelsException;
use Kwaadpepper\Enum\Exceptions\DuplicateValuesException; use Kwaadpepper\Enum\Exceptions\DuplicateValuesException;
use Kwaadpepper\Enum\Exceptions\UnknownEnumProperty; use Kwaadpepper\Enum\Exceptions\UnknownEnumProperty;
@ -12,13 +10,14 @@ use Kwaadpepper\Enum\Tests\Enums\DuplicatedLabels;
use Kwaadpepper\Enum\Tests\Enums\DuplicatedValues; use Kwaadpepper\Enum\Tests\Enums\DuplicatedValues;
use Kwaadpepper\Enum\Tests\Enums\ForceStringsFromInteger; use Kwaadpepper\Enum\Tests\Enums\ForceStringsFromInteger;
use Kwaadpepper\Enum\Tests\Models\Report; use Kwaadpepper\Enum\Tests\Models\Report;
use Orchestra\Testbench\TestCase;
use ReflectionClass;
use stdClass;
use TypeError;
class BaseEnumTest extends TestCase class BaseEnumTest extends TestCase
{ {
/**
* Test enum
*
* @return void
*/
public function testEnum() public function testEnum()
{ {
$mon = Days::mon(); $mon = Days::mon();
@ -28,17 +27,17 @@ class BaseEnumTest extends TestCase
Days::toLabels(); Days::toLabels();
json_encode($tue); json_encode($tue);
// basic tests // Basic tests.
$this->assertEquals('Monday', $mon->label, 'Days::mon()->value should be equals to `Monday`'); $this->assertEquals('Monday', $mon->label, 'Days::mon()->value should be equals to `Monday`');
$this->assertEquals(2, $mon->value, 'Days::mon()->value should be equals to `2`'); $this->assertEquals(2, $mon->value, 'Days::mon()->value should be equals to `2`');
$this->assertClassHasAttribute('value', Days::class, 'Days should have a value property'); $this->assertTrue(\property_exists(Days::class, 'value'), 'Days should have a value property');
$this->assertClassHasAttribute('label', Days::class, 'Days should have a label property'); $this->assertTrue(\property_exists(Days::class, 'label'), 'Days should have a label property');
// undef prop test // Undef prop test.
$exception = null; $exception = null;
try { try {
$mon->propthatdontexists; $mon->propthatdontexists;
} catch (Exception $e) { } catch (\Exception $e) {
$exception = $e; $exception = $e;
} finally { } finally {
$this->assertEquals( $this->assertEquals(
@ -92,16 +91,26 @@ class BaseEnumTest extends TestCase
); );
} }
/**
* Test cannot assign an enum value
*
* @return void
*/
public function testCannotAssignAnEnumValue() public function testCannotAssignAnEnumValue()
{ {
$this->expectError(); $this->expectException(\Error::class);
$enum = Days::mon(); $enum = Days::mon();
$enum->value = 'anything'; $enum->value = 'anything';
} }
/**
* Test cannot assign an enum label
*
* @return void
*/
public function testCannotAssignAnEnumLabel() public function testCannotAssignAnEnumLabel()
{ {
$this->expectError(); $this->expectException(\Error::class);
$enum = Days::mon(); $enum = Days::mon();
$enum->label = 'anything'; $enum->label = 'anything';
} }
@ -114,7 +123,7 @@ class BaseEnumTest extends TestCase
public function testHackingEnumValueCouldConfuseCache() public function testHackingEnumValueCouldConfuseCache()
{ {
$enum = Days::mon(); $enum = Days::mon();
$refClass = new ReflectionClass($enum); $refClass = new \ReflectionClass($enum);
$property = $refClass->getProperty('value'); $property = $refClass->getProperty('value');
$property->setAccessible(true); $property->setAccessible(true);
$property->setValue($enum, 'anything'); $property->setValue($enum, 'anything');
@ -125,6 +134,11 @@ class BaseEnumTest extends TestCase
); );
} }
/**
* Test setting enum value onto model prop
*
* @return void
*/
public function testValidEnumSet() public function testValidEnumSet()
{ {
$this->expectNotToPerformAssertions(); $this->expectNotToPerformAssertions();
@ -133,27 +147,47 @@ class BaseEnumTest extends TestCase
$report->day = Days::mon()->value; $report->day = Days::mon()->value;
} }
/**
* Test setting invalid enum value onto model prop
*
* @return void
*/
public function testInvalidEnumSet() public function testInvalidEnumSet()
{ {
$this->expectException(BadMethodCallException::class); $this->expectException(\BadMethodCallException::class);
$report = new Report(); $report = new Report();
$report->day = Days::mon()->label; $report->day = Days::mon()->label;
} }
/**
* Test setting prop enum with float (invalid)
*
* @return void
*/
public function testInvalidEnumSetWithFloat() public function testInvalidEnumSetWithFloat()
{ {
$this->expectException(TypeError::class); $this->expectException(\TypeError::class);
$report = new Report(); $report = new Report();
$report->day = 0.1; $report->day = 0.1;
} }
/**
* Test setting invalid enum prop with object
*
* @return void
*/
public function testInvalidEnumSetNotAuthorizedType() public function testInvalidEnumSetNotAuthorizedType()
{ {
$this->expectException(TypeError::class); $this->expectException(\TypeError::class);
$report = new Report(); $report = new Report();
$report->day = new stdClass(); $report->day = new \stdClass();
} }
/**
* Test setting enum prop with null as valid
*
* @return void
*/
public function testInvalidEnumCanSetNull() public function testInvalidEnumCanSetNull()
{ {
$this->expectNotToPerformAssertions(); $this->expectNotToPerformAssertions();
@ -161,12 +195,22 @@ class BaseEnumTest extends TestCase
$report->day = null; $report->day = null;
} }
/**
* Test enum has duplicated values
*
* @return void
*/
public function testDuplicatedValues() public function testDuplicatedValues()
{ {
$this->expectException(DuplicateValuesException::class); $this->expectException(DuplicateValuesException::class);
DuplicatedValues::one(); DuplicatedValues::one();
} }
/**
* Test enm has duplicated labels
*
* @return void
*/
public function testDuplicatedLabels() public function testDuplicatedLabels()
{ {
$this->expectException(DuplicateLabelsException::class); $this->expectException(DuplicateLabelsException::class);

View file

@ -11,6 +11,11 @@ use Kwaadpepper\Enum\BaseEnumRoutable;
*/ */
final class ContactFormCivility extends BaseEnumRoutable final class ContactFormCivility extends BaseEnumRoutable
{ {
/**
* Output the value as a string
*
* @return string
*/
public function __toString(): string public function __toString(): string
{ {
return (string)$this->label; return (string)$this->label;

View file

@ -16,6 +16,11 @@ use Kwaadpepper\Enum\BaseEnumRoutable;
*/ */
final class Days extends BaseEnumRoutable final class Days extends BaseEnumRoutable
{ {
/**
* All values
*
* @return array
*/
protected static function values(): array protected static function values(): array
{ {
return [ return [
@ -30,6 +35,11 @@ final class Days extends BaseEnumRoutable
]; ];
} }
/**
* All labels
*
* @return array
*/
protected static function labels(): array protected static function labels(): array
{ {
return [ return [
@ -44,6 +54,11 @@ final class Days extends BaseEnumRoutable
]; ];
} }
/**
* Output the value as a string
*
* @return string
*/
public function __toString(): string public function __toString(): string
{ {
return (string)$this->label; return (string)$this->label;
@ -52,7 +67,7 @@ final class Days extends BaseEnumRoutable
/** /**
* Checks if days contain this day * Checks if days contain this day
* *
* @param int $days * @param integer $days
* @return boolean * @return boolean
*/ */
public function has(int $days) public function has(int $days)

View file

@ -11,6 +11,11 @@ use Kwaadpepper\Enum\BaseEnumRoutable;
*/ */
final class DuplicatedLabels extends BaseEnumRoutable final class DuplicatedLabels extends BaseEnumRoutable
{ {
/**
* All labels
*
* @return array
*/
protected static function labels(): array protected static function labels(): array
{ {
return [ return [

View file

@ -11,6 +11,11 @@ use Kwaadpepper\Enum\BaseEnumRoutable;
*/ */
final class DuplicatedValues extends BaseEnumRoutable final class DuplicatedValues extends BaseEnumRoutable
{ {
/**
* All values
*
* @return array
*/
protected static function values(): array protected static function values(): array
{ {
return [ return [

View file

@ -11,6 +11,11 @@ use Kwaadpepper\Enum\BaseEnumRoutable;
*/ */
final class ForceStringsFromInteger extends BaseEnumRoutable final class ForceStringsFromInteger extends BaseEnumRoutable
{ {
/**
* All values
*
* @return array
*/
protected static function values(): array protected static function values(): array
{ {
return [ return [

View file

@ -11,6 +11,11 @@ use Kwaadpepper\Enum\BaseEnum;
*/ */
final class NotRoutableEnum extends BaseEnum final class NotRoutableEnum extends BaseEnum
{ {
/**
* All values
*
* @return array
*/
protected static function values(): array protected static function values(): array
{ {
return [ return [

View file

@ -9,14 +9,39 @@ class Alarm extends Model
{ {
use CastsEnums; use CastsEnums;
/**
* Indicates if the model should be timestamped.
*
* @var boolean
*/
public $timestamps = false; public $timestamps = false;
/**
* The primary key for the model.
*
* @var string
*/
protected $primaryKey = 'day'; protected $primaryKey = 'day';
/**
* The "type" of the primary key ID.
*
* @var string
*/
protected $keyType = 'int'; protected $keyType = 'int';
/**
* Indicates if the IDs are auto-incrementing.
*
* @var boolean
*/
public $incrementing = false; public $incrementing = false;
/**
* The attributes that are mass assignable.
*
* @var string[]
*/
protected $fillable = [ protected $fillable = [
'day' 'day'
]; ];

View file

@ -10,22 +10,57 @@ class Journal extends Model
{ {
use CastsEnums; use CastsEnums;
/**
* The attributes that are mass assignable.
*
* @var boolean
*/
public $timestamps = false; public $timestamps = false;
/**
* The primary key for the model.
*
* @var string
*/
protected $primaryKey = 'day'; protected $primaryKey = 'day';
/**
* The "type" of the primary key ID.
*
* @var string
*/
protected $keyType = 'int'; protected $keyType = 'int';
/**
* Indicates if the IDs are auto-incrementing.
*
* @var boolean
*/
public $incrementing = false; public $incrementing = false;
/**
* The attributes that are mass assignable.
*
* @var string[]
*/
protected $fillable = [ protected $fillable = [
'day' 'day'
]; ];
/**
* The attributes that should be cast.
*
* @var string[]
*/
protected $casts = [ protected $casts = [
'day' => 'int' 'day' => 'int'
]; ];
/**
* The attributes that should be to enum.
*
* @var string[]
*/
protected $enumCasts = [ protected $enumCasts = [
'day' => Days::class 'day' => Days::class
]; ];

View file

@ -10,18 +10,48 @@ class Report extends Model
{ {
use CastsEnums; use CastsEnums;
/**
* Indicates if the model should be timestamped.
*
* @var boolean
*/
public $timestamps = false; public $timestamps = false;
/**
* The primary key for the model.
*
* @var string
*/
protected $primaryKey = 'day'; protected $primaryKey = 'day';
/**
* The "type" of the primary key ID.
*
* @var string
*/
protected $keyType = 'int'; protected $keyType = 'int';
/**
* Indicates if the IDs are auto-incrementing.
*
* @var boolean
*/
public $incrementing = false; public $incrementing = false;
/**
* The attributes that are mass assignable.
*
* @var string[]
*/
protected $fillable = [ protected $fillable = [
'day' 'day'
]; ];
/**
* The attributes that should be to enum.
*
* @var string[]
*/
protected $enumCasts = [ protected $enumCasts = [
'day' => Days::class 'day' => Days::class
]; ];

View file

@ -11,7 +11,7 @@ class PassDayRequest extends FormRequest
/** /**
* Determine if the user is authorized to make this request. * Determine if the user is authorized to make this request.
* *
* @return bool * @return boolean
*/ */
public function authorize() public function authorize()
{ {

40
tests/TestCase.php Normal file
View file

@ -0,0 +1,40 @@
<?php
namespace Kwaadpepper\Enum\Tests;
abstract class TestCase extends \Orchestra\Testbench\TestCase
{
/**
* Automatically loads environment file if available.
*
* @var boolean
*/
protected $loadEnvironmentVariables = false;
/**
* Setup custom phpunit catch for deprecated error cathing.
*
* @return void
*/
public function setUp(): void
{
set_error_handler(
static function ($errno, $errstr) {
throw new \Exception($errstr, $errno);
},
E_ALL
);
parent::setUp();
}
/**
* Restore phpunit handler
*
* @return void
*/
public function tearDown(): void
{
restore_error_handler();
parent::tearDown();
}
}