Compare commits
57 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
583984b157 | ||
|
|
8bd0bb17e4 | ||
|
|
385552f454 | ||
|
|
b671dd3e1c | ||
|
|
beb64c6470 | ||
|
|
0277f4d0bc | ||
|
|
3687d37c2f | ||
|
|
ff3f6336db | ||
|
|
7b2f3530e9 | ||
|
|
606c380e97 | ||
|
|
8b25893b99 | ||
|
|
71f45fa5ed | ||
|
|
cb2ec1bd82 | ||
|
|
57a94ab316 | ||
|
|
cc695e6a07 | ||
|
|
bbd0872389 | ||
|
|
34965dee37 | ||
|
|
1c342113b6 | ||
|
|
1e2e9bdecf | ||
| 4dfe0eb17c | |||
| 5b9806fd79 | |||
| 163eeabcd1 | |||
| 03bac5ba89 | |||
| fdfb6af639 | |||
| a7617753b1 | |||
| 19108c833e | |||
| 9c91bb3659 | |||
| c54d3602f3 | |||
| 0bb9a6f9b8 | |||
| 7bbbe28e27 | |||
| e687db37e7 | |||
| 1a5be20be2 | |||
| 5e3f825dca | |||
| b3f54a65c5 | |||
| 4cc27e6769 | |||
| 3e654f5d3c | |||
| bb09844610 | |||
| 5793cf591f | |||
| 2fb55ed30d | |||
| d8402c3397 | |||
| 402609ad07 | |||
| c80000e2fd | |||
| 8348fc06c5 | |||
| a9f6e0722a | |||
| 7b2f8ab01a | |||
| 4382d1c6fe | |||
| 416c941c8d | |||
| d9e7d57a24 | |||
| 4a33926706 | |||
| 6f25da234c | |||
| ff11dcd3d1 | |||
| a6821a62fa | |||
| 5c34cc5228 | |||
|
|
036cc602c0 | ||
|
|
1d4439d82b | ||
|
|
f9e2b960d8 | ||
| ead46dc7b2 |
48 changed files with 2167 additions and 7718 deletions
43
.github/workflows/php.yml
vendored
Normal file
43
.github/workflows/php.yml
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
name: PHP Composer
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: shivammathur/setup-php@v2
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.2'
|
||||
tools: phpcs
|
||||
|
||||
- name: Validate composer.json and composer.lock
|
||||
run: composer validate --strict
|
||||
|
||||
- name: Cache Composer packages
|
||||
id: composer-cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: vendor
|
||||
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-php-
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer install --no-progress
|
||||
|
||||
# Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit"
|
||||
# Docs: https://getcomposer.org/doc/articles/scripts.md
|
||||
|
||||
- name: Run test suite
|
||||
run: composer run-script test
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -1,2 +1,7 @@
|
|||
workspace.code-workspace
|
||||
vendor
|
||||
.phpunit.result.cache
|
||||
.phpunit.cache
|
||||
.vscode/launch.json
|
||||
composer.lock
|
||||
build
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
php:
|
||||
preset: laravel
|
||||
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"phpcs.executablePath": "vendor/bin/phpcs"
|
||||
}
|
||||
124
changelog.md
124
changelog.md
|
|
@ -2,11 +2,98 @@
|
|||
|
||||
All notable changes to `Enum` will be documented in this file.
|
||||
|
||||
## Version 0.0.1
|
||||
## **Version 3.0.0**
|
||||
- Changed use of php8.2 and more only For laravel 10 usage
|
||||
|
||||
### Initial release
|
||||
## **Version 2.1.3**
|
||||
|
||||
## Version 0.0.2
|
||||
### Fixed
|
||||
|
||||
- Allow usage on php 7.4 and more as php 8 for cross compatibility
|
||||
- Bumped orchestra to 6 to allow unit test for all php versions
|
||||
|
||||
## **Version 2.1.2**
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed check for label duplicates or missing declaration
|
||||
|
||||
## **Version 2.1.1**
|
||||
|
||||
### Fixed
|
||||
|
||||
- Reintroduce getRouteKey to handle router with model + tests
|
||||
|
||||
## **Version 2.1.0**
|
||||
|
||||
### Added
|
||||
|
||||
- Full unit tests with 100% coverage
|
||||
- A laravel command to generate an Enum ``php artisan make:enum`
|
||||
- examples and a full, readme doc
|
||||
|
||||
### Changed
|
||||
|
||||
- Code refactoring for most of the code
|
||||
- Removed unused code parts
|
||||
- Set requirements for unit test to laravel 7
|
||||
- translations are in php files
|
||||
|
||||
### Fixed
|
||||
|
||||
- An enum used as in a route will now provoque a 404 code instead of generating null enum
|
||||
- CheckEnumRule nows works properly and has unit tests
|
||||
|
||||
## **Version 2.0.0**
|
||||
|
||||
### Changed
|
||||
|
||||
- Now if you are using enums in laravel, you have to extend from `BaseEnumRoutable` instead of `BaseEnum`. This will allow for enum to be used in routes as a parameter getting them as a controller parameter with implicit binding.
|
||||
- All laravel dependencies have been removed, this allows enum to be used in another project type. The project is now dependency free.
|
||||
|
||||
## **Version 0.1.4**
|
||||
|
||||
### Added
|
||||
|
||||
- Validation rule EnumIsValidRule, the constructor needs a BaseEnum class
|
||||
eg: new EnumIsValidRule(ArcadiaMailType::class)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Unit tests with 0.1.2 changes
|
||||
|
||||
## **Version 0.1.3**
|
||||
|
||||
### Added
|
||||
|
||||
- Validation rule EnumIsValidRule, the constructor needs a BaseEnum class
|
||||
eg: new EnumIsValidRule(ArcadiaMailType::class)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Unit tests with 0.1.2 changes
|
||||
|
||||
## **Version 0.1.2**
|
||||
|
||||
### Changed
|
||||
|
||||
- Changed toJson to output array with label and value
|
||||
|
||||
## **Version 0.1.1**
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed performances issue on toValues and toLabels
|
||||
|
||||
## **Version 0.1.0**
|
||||
|
||||
### - Changed
|
||||
|
||||
- toArray Method now returns an array of BaseEnums
|
||||
this is because php numeric string array indexes to int, this would break
|
||||
origin enum values
|
||||
|
||||
## **Version 0.0.2**
|
||||
|
||||
### - Add
|
||||
|
||||
|
|
@ -21,33 +108,6 @@ All notable changes to `Enum` will be documented in this file.
|
|||
'status' => OrderStatus::class // This is a class that extends \Kwaadpepper\Enum\BaseEnum
|
||||
];
|
||||
|
||||
## Version 0.1.0
|
||||
## **Version 0.0.1**
|
||||
|
||||
### - Changed
|
||||
|
||||
- toArray Method now returns an array of BaseEnums
|
||||
this is because php numeric string array indexes to int, this would break
|
||||
origin enum values
|
||||
|
||||
## Version 0.1.1
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed performances issue on toValues and toLabels
|
||||
|
||||
## Version 0.1.2
|
||||
|
||||
### Changed
|
||||
|
||||
- Changed toJson to output array with label and value
|
||||
|
||||
## Version 0.1.3
|
||||
|
||||
### Added
|
||||
|
||||
- Validation rule EnumIsValidRule, the constructor needs a BaseEnum class
|
||||
eg: new EnumIsValidRule(ArcadiaMailType::class)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Unit tests with 0.1.2 changes
|
||||
### Initial release
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"name": "kwaadpepper/enum",
|
||||
"type": "library",
|
||||
"description": "Enums to use for any project",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
|
|
@ -15,13 +16,15 @@
|
|||
"Enum"
|
||||
],
|
||||
"require": {
|
||||
"illuminate/support": "~7|~8",
|
||||
"laravel/framework": "~7|~8"
|
||||
"php": ">=8.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~9.0",
|
||||
"squizlabs/php_codesniffer": "^3.5",
|
||||
"orchestra/testbench": "^6.13"
|
||||
"phpunit/phpunit": "^9",
|
||||
"squizlabs/php_codesniffer": "^3",
|
||||
"orchestra/testbench": "^8",
|
||||
"slevomat/coding-standard": "^7",
|
||||
"phpunit/php-code-coverage": "^9",
|
||||
"nunomaduro/collision": "^6.4"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
|
@ -39,5 +42,16 @@
|
|||
"Kwaadpepper\\Enum\\EnumServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"post-autoload-dump": [
|
||||
"@php ./vendor/bin/testbench package:discover --ansi"
|
||||
],
|
||||
"test": "vendor/bin/phpunit"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
7187
composer.lock
generated
7187
composer.lock
generated
File diff suppressed because it is too large
Load diff
16
examples/BasicEnum.php
Normal file
16
examples/BasicEnum.php
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @method static self child()
|
||||
* @method static self adult()
|
||||
* @method static self senior()
|
||||
*/
|
||||
final class BasicEnum extends BaseEnumRoutable
|
||||
{
|
||||
//
|
||||
}
|
||||
66
examples/Days.php
Normal file
66
examples/Days.php
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* This defines a day type with all
|
||||
* seven days of the week, include 'none'
|
||||
* to allow setting an 'undefined' value.
|
||||
*
|
||||
* @method static self none() This is used to set 'null' day
|
||||
* @method static self mon() The first day of the week
|
||||
* @method static self tue() The second day of the week
|
||||
* @method static self wed() The third day of the week
|
||||
* @method static self thu() The fourth day of the week
|
||||
* @method static self fri() The fifth day of the week
|
||||
* @method static self sat() The sixth day of the week
|
||||
* @method static self sun() The last day of the week
|
||||
*/
|
||||
final class Days extends BaseEnumRoutable
|
||||
{
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'none' => 1,
|
||||
'mon' => 1 << 1,
|
||||
'tue' => 1 << 2,
|
||||
'wed' => 1 << 3,
|
||||
'thu' => 1 << 4,
|
||||
'fri' => 1 << 5,
|
||||
'sat' => 1 << 6,
|
||||
'sun' => 1 << 7,
|
||||
];
|
||||
}
|
||||
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'none' => 'None',
|
||||
'mon' => 'Monday',
|
||||
'tue' => 'Tuesday',
|
||||
'wed' => 'Wednesday',
|
||||
'thu' => 'Thursday',
|
||||
'fri' => 'Friday',
|
||||
'sat' => 'Saturday',
|
||||
'sun' => 'Sunday'
|
||||
];
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string)$this->label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if days contain this day
|
||||
*
|
||||
* @param int $days
|
||||
* @return boolean
|
||||
*/
|
||||
public function has(int $days)
|
||||
{
|
||||
return (bool)($this->value & $days);
|
||||
}
|
||||
}
|
||||
22
license.md
22
license.md
|
|
@ -1,9 +1,21 @@
|
|||
# The license
|
||||
MIT License
|
||||
|
||||
Copyright (c) 28/02/2021, Jérémy Munsch <github@jeremydev.ovh>
|
||||
Copyright (c) 2021 Jérémy Munsch
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
|
|||
127
phpcs.xml
127
phpcs.xml
|
|
@ -1,11 +1,124 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ruleset name="RealWorld" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="vendor/squizlabs/php_codesniffer/phpcs.xsd">
|
||||
<arg name="colors"/>
|
||||
<arg name="extensions" value="php"/>
|
||||
<arg name="colors" />
|
||||
<arg name="extensions" value="php" />
|
||||
<file>src/</file>
|
||||
<file>tests/</file>
|
||||
<rule ref="PSR1"/>
|
||||
<rule ref="PSR2"/>
|
||||
<rule ref="PSR12"/>
|
||||
<rule ref="PSR2"/>
|
||||
<rule ref="PSR1" />
|
||||
<rule ref="PSR12" />
|
||||
|
||||
<rule ref="Generic.Classes.DuplicateClassName"/>
|
||||
<rule ref="Generic.CodeAnalysis.EmptyStatement"/>
|
||||
<rule ref="Generic.CodeAnalysis.ForLoopShouldBeWhileLoop"/>
|
||||
<rule ref="Generic.CodeAnalysis.ForLoopWithTestFunctionCall"/>
|
||||
<rule ref="Generic.CodeAnalysis.JumbledIncrementer"/>
|
||||
<rule ref="Generic.CodeAnalysis.UnconditionalIfStatement"/>
|
||||
<rule ref="Generic.CodeAnalysis.UnnecessaryFinalModifier"/>
|
||||
<rule ref="Generic.CodeAnalysis.UnusedFunctionParameter"/>
|
||||
<rule ref="Generic.CodeAnalysis.UselessOverridingMethod"/>
|
||||
<rule ref="Generic.Commenting.DocComment.SpacingBeforeTags"/>
|
||||
<rule ref="Generic.Commenting.Todo"/>
|
||||
<rule ref="Generic.Commenting.Fixme"/>
|
||||
<rule ref="Generic.ControlStructures.InlineControlStructure"/>
|
||||
<rule ref="Generic.Files.ByteOrderMark"/>
|
||||
<rule ref="Generic.Files.LineEndings"/>
|
||||
<rule ref="Generic.Files.LineLength"/>
|
||||
<rule ref="Generic.Formatting.DisallowMultipleStatements"/>
|
||||
<rule ref="Generic.Formatting.MultipleStatementAlignment"/>
|
||||
<rule ref="Generic.Formatting.NoSpaceAfterCast"/>
|
||||
<rule ref="Generic.Functions.CallTimePassByReference"/>
|
||||
<rule ref="Generic.Functions.FunctionCallArgumentSpacing"/>
|
||||
<rule ref="Generic.Metrics.CyclomaticComplexity"/>
|
||||
<rule ref="Generic.Metrics.NestingLevel"/>
|
||||
<rule ref="Generic.NamingConventions.ConstructorName"/>
|
||||
<rule ref="Generic.NamingConventions.UpperCaseConstantName"/>
|
||||
<rule ref="Generic.NamingConventions.CamelCapsFunctionName"/>
|
||||
<rule ref="Generic.PHP.DeprecatedFunctions"/>
|
||||
<rule ref="Generic.PHP.DisallowShortOpenTag"/>
|
||||
<rule ref="Generic.PHP.ForbiddenFunctions"/>
|
||||
<rule ref="Generic.PHP.NoSilencedErrors"/>
|
||||
<rule ref="Generic.Strings.UnnecessaryStringConcat"/>
|
||||
<rule ref="Generic.WhiteSpace.DisallowTabIndent"/>
|
||||
<rule ref="Generic.WhiteSpace.ScopeIndent"/>
|
||||
<rule ref="MySource.PHP.EvalObjectFactory"/>
|
||||
<rule ref="MySource.PHP.GetRequestData"/>
|
||||
<rule ref="MySource.PHP.AjaxNullComparison"/>
|
||||
<rule ref="PEAR.Classes.ClassDeclaration"/>
|
||||
<rule ref="PEAR.Commenting.InlineComment"/>
|
||||
<rule ref="PSR1.Classes.ClassDeclaration"/>
|
||||
<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">
|
||||
<properties>
|
||||
<property name="error" value="true"/>
|
||||
</properties>
|
||||
</rule>
|
||||
<rule ref="Squiz.PHP.Eval"/>
|
||||
<rule ref="Squiz.PHP.GlobalKeyword"/>
|
||||
<rule ref="Squiz.PHP.Heredoc"/>
|
||||
<rule ref="Squiz.PHP.InnerFunctions"/>
|
||||
<rule ref="Squiz.PHP.LowercasePHPFunctions"/>
|
||||
<rule ref="Squiz.PHP.NonExecutableCode"/>
|
||||
<rule ref="Squiz.Scope.MemberVarScope"/>
|
||||
<rule ref="Squiz.Scope.MethodScope"/>
|
||||
<rule ref="Squiz.Scope.StaticThisUsage"/>
|
||||
<rule ref="Squiz.WhiteSpace.LanguageConstructSpacing"/>
|
||||
<rule ref="Squiz.WhiteSpace.LogicalOperatorSpacing"/>
|
||||
<rule ref="Squiz.WhiteSpace.MemberVarSpacing">
|
||||
<properties>
|
||||
<property name="spacingBeforeFirst " value="false"/>
|
||||
</properties>
|
||||
</rule>
|
||||
<rule ref="Squiz.WhiteSpace.OperatorSpacing">
|
||||
<properties>
|
||||
<property name="ignoreNewlines" value="true"/>
|
||||
</properties>
|
||||
</rule>
|
||||
<rule ref="Squiz.WhiteSpace.ObjectOperatorSpacing">
|
||||
<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" />
|
||||
|
||||
<!-- For Laravel migrations -->
|
||||
<rule ref="PSR1.Classes.ClassDeclaration.MissingNamespace">
|
||||
<exclude-pattern>*/database/migrations/*</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
</ruleset>
|
||||
|
|
|
|||
30
phpunit.xml
30
phpunit.xml
|
|
@ -1,13 +1,37 @@
|
|||
<?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">
|
||||
<coverage>
|
||||
<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">
|
||||
<include>
|
||||
<directory>src/</directory>
|
||||
<directory suffix=".php">src/</directory>
|
||||
</include>
|
||||
<exclude>
|
||||
<file>src/EnumServiceProvider.php</file>
|
||||
</exclude>
|
||||
<report>
|
||||
<html outputDirectory="build/coverage"/>
|
||||
<text outputFile="build/coverage.txt"/>
|
||||
<clover outputFile="build/coverage.xml" />
|
||||
</report>
|
||||
</coverage>
|
||||
<testsuites>
|
||||
<testsuite name="Package">
|
||||
<directory suffix=".php">./tests/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<php>
|
||||
<env name="APP_ENV" value="testing"/>
|
||||
<env name="DB_CONNECTION" value="testing"/>
|
||||
</php>
|
||||
</phpunit>
|
||||
|
|
|
|||
96
readme.md
96
readme.md
|
|
@ -1,11 +1,13 @@
|
|||
# Enum
|
||||
|
||||

|
||||
[![Latest Version on Packagist][ico-version]][link-packagist]
|
||||
[![Total Downloads][ico-downloads]][link-downloads]
|
||||
[![Build Status][ico-travis]][link-travis]
|
||||
[![StyleCI][ico-styleci]][link-styleci]
|
||||

|
||||
|
||||
This is where your description should go. Take a look at [contributing.md](contributing.md) to see a to do list.
|
||||
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..).
|
||||
|
||||
You will be able to use enums in any project using a simple definition, take a look at example [Basic](examples/BasicEnum.php) or a [more sophisticated Example](examples/Days.php)
|
||||
|
||||
## Installation
|
||||
|
||||
|
|
@ -15,26 +17,110 @@ Via Composer
|
|||
$ composer require kwaadpepper/enum
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
**All enum have two properties : `label` and `value`, only value has to be unique. Each enum can have multiple options all written on class comment as static methods, these have to be unique !**
|
||||
|
||||
- On Any project, take a look on [examples](examples) to create an enum class.
|
||||
|
||||
1. **Invoke an enum value**
|
||||
``` php
|
||||
Days::mon()
|
||||
```
|
||||
|
||||
2. **Compare enums**
|
||||
``` php
|
||||
Days::mon()->equals(Days::tue()) // false
|
||||
Days::mon()->equals(Days::mon()) // true
|
||||
Days::mon()->value === Days::tue()->value // false
|
||||
Days::mon()->value === Days::mon()->value // true
|
||||
```
|
||||
|
||||
3. **Print an enum**
|
||||
``` php
|
||||
echo Days::mon(); // 2
|
||||
echo Days::tue(); // 4
|
||||
echo Days::mon()->label; // Monday
|
||||
```
|
||||
As you can see enum implements the __toString method which you can override to display the label instead of the value.
|
||||
This default behavior is set like this for a better behavior in laravel.
|
||||
|
||||
4. **Serialise an enum**
|
||||
``` php
|
||||
echo json_encode(Days::mon()); // {"label":"Monday","value":2}
|
||||
```
|
||||
Enums implement the JsonSerializable interface
|
||||
|
||||
- On a Laravel project you can use enums in multiple ways
|
||||
|
||||
1. **As a property**
|
||||
``` php
|
||||
// Add theses to your model
|
||||
use CastsEnums;
|
||||
protected $enumCasts = [
|
||||
'day' => Days::class
|
||||
];
|
||||
```
|
||||
This will allow you model to store an enum in database using its value, and then cast the property to an enum when accessing it
|
||||
|
||||
2. **As a route parameter**
|
||||
|
||||
Define a route like the following
|
||||
``` php
|
||||
Route::get('/days/{day}', function (Days $day) {
|
||||
return response()->json([$day]);
|
||||
})->middleware('bindings');
|
||||
// OR
|
||||
Route::get('/days/{day}', [DayController::class, 'getDay']);
|
||||
```
|
||||
Then on your controller for the `DayController` example
|
||||
``` php
|
||||
public function getDay(Request $request, Day $day) {
|
||||
return response()->json([$day]);
|
||||
}
|
||||
```
|
||||
|
||||
3. **As a request parameter using validation**
|
||||
|
||||
Take a look at [this request example](tests/Requests/PassDayRequest.php).
|
||||
|
||||
``` php
|
||||
new EnumIsValidRule(Days::class)
|
||||
```
|
||||
|
||||
It use EnumIsValidRule to validate the parameter as being a valid enum value.
|
||||
|
||||
**Note that you may still have to cast your parameter to int if your enum value is an int, as enum check is strict**
|
||||
|
||||
4. **As a model primary Key**
|
||||
|
||||
Take a look at [unit test](tests/BaseEnumRoutableTest.php) using [the Report enum class from tests](tests/Models/Report.php)
|
||||
|
||||
---
|
||||
## Change log
|
||||
|
||||
Please see the [changelog](changelog.md) for more information on what has changed recently.
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
``` bash
|
||||
$ composer test
|
||||
```
|
||||
|
||||
---
|
||||
## Contributing
|
||||
|
||||
Please see [contributing.md](contributing.md) for details and a todolist.
|
||||
|
||||
---
|
||||
## Security
|
||||
|
||||
If you discover any security related issues, please email github@jeremydev.ovh instead of using the issue tracker.
|
||||
|
||||
---
|
||||
## Credits
|
||||
|
||||
- [Jérémy Munsch][link-author]
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"enum::enum.isNotValid": "The field :attribute is not valid, it has to be an integer or a string.",
|
||||
"enum::enum.notInList": "The field :attribute has to be one of the followings: :values"
|
||||
}
|
||||
5
resources/lang/en/enum.php
Normal file
5
resources/lang/en/enum.php
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'notInList' => 'The field :attribute has to be one of the followings: :values'
|
||||
];
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"enum::enum.isNotValid": "Le champ :attribute n'est pas valide, il doit être un entier ou une chaine.",
|
||||
"enum::enum.notInList": "Le champ :attribute doit être une des valeurs suivantes: :values"
|
||||
}
|
||||
5
resources/lang/fr/enum.php
Normal file
5
resources/lang/fr/enum.php
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'notInList' => 'Le champ :attribute doit être une des valeurs suivantes: :values'
|
||||
];
|
||||
16
resources/templates/TemplateEnum.php
Normal file
16
resources/templates/TemplateEnum.php
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* This is an enumeration class,
|
||||
* the following methods are its possible values
|
||||
*
|
||||
* ##VALUES
|
||||
*/
|
||||
class TemplateEnum extends BaseEnumRoutable
|
||||
{
|
||||
// ##OVERRIDE
|
||||
}
|
||||
506
src/BaseEnum.php
506
src/BaseEnum.php
|
|
@ -2,34 +2,105 @@
|
|||
|
||||
namespace Kwaadpepper\Enum;
|
||||
|
||||
use BadMethodCallException;
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Routing\UrlRoutable;
|
||||
use JsonSerializable;
|
||||
use Kwaadpepper\Enum\Exceptions\DuplicateDefinitionException;
|
||||
use Kwaadpepper\Enum\Exceptions\DuplicateLabelsException;
|
||||
use Kwaadpepper\Enum\Exceptions\DuplicateValuesException;
|
||||
use Kwaadpepper\Enum\Exceptions\NotImplementedException;
|
||||
use Kwaadpepper\Enum\Exceptions\EmptyDefinitionException;
|
||||
use Kwaadpepper\Enum\Exceptions\EnumNotRoutableException;
|
||||
use Kwaadpepper\Enum\Exceptions\UnknownEnumProperty;
|
||||
use ReflectionClass;
|
||||
use TypeError;
|
||||
|
||||
abstract class BaseEnum implements JsonSerializable, UrlRoutable
|
||||
/**
|
||||
* This Base Enum is the class which should
|
||||
* be extended to create an enumeration
|
||||
*
|
||||
* @property-read int|string $value The enum value, can be string or int
|
||||
* @property-read string $label The enum label, is a string
|
||||
*/
|
||||
abstract class BaseEnum implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var string|int
|
||||
* @readonly
|
||||
* @var string|integer
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
/** @readonly */
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $label;
|
||||
|
||||
/** @var array<string, array<string, App\Enums\BaseEnumDefinition>> */
|
||||
/** @var array<string, array<string, \Kwaadpepper\Enum\BaseEnumDefinition>> */
|
||||
private static $definitionCache = [];
|
||||
|
||||
|
||||
// -- ENUM MAGIC METHODS --
|
||||
|
||||
/**
|
||||
* @return array[BaseEnum]
|
||||
* @param integer|string $value
|
||||
* @param string $label
|
||||
* @throws \TypeError If anything else than string or int
|
||||
* 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)
|
||||
{
|
||||
// phpcs:ignore
|
||||
/**
|
||||
* This cannot be allowed, happens with laravel resolver
|
||||
* when using BaseEnum instead of BaseEnumRoutable
|
||||
*/
|
||||
if ($label === null and !is_subclass_of(static::class, BaseEnumRoutable::class)) {
|
||||
throw new EnumNotRoutableException();
|
||||
}
|
||||
$this->label = $label;
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $attribute
|
||||
* @return integer|string
|
||||
* @throws \Kwaadpepper\Enum\Exceptions\UnknownEnumProperty As it could not be found.
|
||||
*/
|
||||
public function __get(string $attribute)
|
||||
{
|
||||
if ($attribute === 'value') {
|
||||
return $this->value;
|
||||
}
|
||||
if ($attribute === 'label') {
|
||||
return $this->label;
|
||||
}
|
||||
throw new UnknownEnumProperty($attribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
* @return static
|
||||
* @throws \TypeError If anything else than string or int is used.
|
||||
* @throws \BadMethodCallException If a matching definition cannot be found.
|
||||
* @throws \Kwaadpepper\Enum\Exceptions\EnumNotRoutableException If provided value are null.
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUsed
|
||||
*/
|
||||
public static function __callStatic(string $name, array $arguments)
|
||||
{
|
||||
// phpcs:enable
|
||||
return static::make($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the value as a string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string)$this->value;
|
||||
}
|
||||
|
||||
|
||||
// -- ENUM EXPORTATION METHODS --
|
||||
|
||||
/** @return array<BaseEnum> */
|
||||
public static function toArray(): array
|
||||
{
|
||||
$array = [];
|
||||
|
|
@ -39,9 +110,7 @@ abstract class BaseEnum implements JsonSerializable, UrlRoutable
|
|||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]|int[]
|
||||
*/
|
||||
/** @return array<int|string> */
|
||||
public static function toValues(): array
|
||||
{
|
||||
$array = [];
|
||||
|
|
@ -51,9 +120,7 @@ abstract class BaseEnum implements JsonSerializable, UrlRoutable
|
|||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
/** @return array<string> */
|
||||
public static function toLabels(): array
|
||||
{
|
||||
$array = [];
|
||||
|
|
@ -64,11 +131,47 @@ abstract class BaseEnum implements JsonSerializable, UrlRoutable
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the enum definition
|
||||
* Json serialize implementation.
|
||||
*
|
||||
* @return mixed|null
|
||||
* @return array
|
||||
*/
|
||||
public function getDefinition()
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return [
|
||||
'label' => $this->label,
|
||||
'value' => $this->value
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
// -- DEFINITON METHODS --
|
||||
|
||||
/**
|
||||
* Get all values
|
||||
*
|
||||
* @return array<string, string|int> | Closure(string):(int|string)
|
||||
*/
|
||||
protected static function values()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all labels
|
||||
*
|
||||
* @return array<string, string> | Closure(string):string
|
||||
*/
|
||||
protected static function labels()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the enum definition name
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getDefinition(): ?string
|
||||
{
|
||||
$className = static::class;
|
||||
foreach (self::$definitionCache[$className] as $definition => $enum) {
|
||||
|
|
@ -80,261 +183,54 @@ abstract class BaseEnum implements JsonSerializable, UrlRoutable
|
|||
}
|
||||
|
||||
/**
|
||||
* @param string|int $value
|
||||
* @throws TypeError
|
||||
* @throws BadMethodCallException
|
||||
* Parse a value to create its corresponding enumeration value.
|
||||
*
|
||||
* @param string|integer $value
|
||||
* @return static
|
||||
* @throws TypeError If anything else than string or int is used.
|
||||
* @throws \BadMethodCallException If a matching definition cannot be found.
|
||||
* @throws \Kwaadpepper\Enum\Exceptions\EnumNotRoutableException If provided value are null.
|
||||
* @phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
|
||||
*/
|
||||
public static function make($value): BaseEnum
|
||||
{
|
||||
if (!(is_string($value) || is_int($value))) {
|
||||
$enumClass = static::class;
|
||||
throw new TypeError("Only string and integer are allowed values for enum {$enumClass}.");
|
||||
}
|
||||
// phpcs:enable
|
||||
self::assertValidValue($value);
|
||||
|
||||
$definition = static::findDefinition($value);
|
||||
|
||||
if ($definition === null) {
|
||||
$enumClass = static::class;
|
||||
throw new BadMethodCallException(
|
||||
"There's no value {$value} defined for enum {$enumClass}," .
|
||||
"consider adding it in the docblock definition."
|
||||
throw new \BadMethodCallException(
|
||||
"There's no value $value defined for enum $enumClass, consider adding it in the docblock definition."
|
||||
);
|
||||
}
|
||||
|
||||
$obj = new static();
|
||||
$obj->value = $definition->value;
|
||||
$obj->label = $definition->label;
|
||||
$obj = new static(
|
||||
$definition->value,
|
||||
$definition->label
|
||||
);
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* Test if an enum values is equal to another
|
||||
*
|
||||
* @return int|string
|
||||
*
|
||||
* @throws UnknownEnumProperty
|
||||
* @param \Kwaadpepper\Enum\BaseEnum $other
|
||||
* @return boolean
|
||||
*/
|
||||
public function __get(string $name)
|
||||
public function equals(BaseEnum $other): bool
|
||||
{
|
||||
if ($name === 'label') {
|
||||
return $this->label;
|
||||
if (
|
||||
get_class($this) === get_class($other)
|
||||
&& $this->value === $other->value
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($name === 'value') {
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
throw new UnknownEnumProperty($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function __callStatic(string $name, array $arguments)
|
||||
{
|
||||
return static::make($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
*
|
||||
* @return bool|mixed
|
||||
*
|
||||
* @throws UnknownEnumMethod
|
||||
*/
|
||||
public function __call(string $name, array $arguments)
|
||||
{
|
||||
if (strpos($name, 'is') === 0) {
|
||||
$other = static::make(substr($name, 2));
|
||||
return $this->equals($other);
|
||||
}
|
||||
|
||||
return self::__callStatic($name, $arguments);
|
||||
}
|
||||
|
||||
public function equals(BaseEnum ...$others): bool
|
||||
{
|
||||
foreach ($others as $other) {
|
||||
// @phpcs:disable PSR2.ControlStructures.ControlStructureSpacing.SpacingAfterOpenBrace
|
||||
if (
|
||||
get_class($this) === get_class($other)
|
||||
&& $this->value === $other->value
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]|int[]|Closure
|
||||
* @return array<string, string|int> | Closure(string):(int|string)
|
||||
*/
|
||||
protected static function values()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]|Closure
|
||||
* @return array<string, string> | Closure(string):string
|
||||
*/
|
||||
protected static function labels()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|int $input
|
||||
*
|
||||
* @return App\Enums\BaseEnumDefinition|null
|
||||
*/
|
||||
private static function findDefinition($input): ?BaseEnumDefinition
|
||||
{
|
||||
foreach (static::resolveDefinition() as $definition) {
|
||||
if ($definition->equals($input)) {
|
||||
return $definition;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return App\Enums\BaseEnumDefinition[]
|
||||
*/
|
||||
private static function resolveDefinition(): array
|
||||
{
|
||||
$className = static::class;
|
||||
|
||||
if (self::$definitionCache[$className] ?? null) {
|
||||
return self::$definitionCache[$className];
|
||||
}
|
||||
|
||||
$reflectionClass = new ReflectionClass($className);
|
||||
|
||||
$docComment = $reflectionClass->getDocComment();
|
||||
|
||||
preg_match_all('/@method\s+static\s+self\s+([\w_]+)\(\)/', $docComment, $matches);
|
||||
|
||||
$definition = [];
|
||||
|
||||
$valueMap = static::values();
|
||||
|
||||
if ($valueMap instanceof Closure) {
|
||||
$valueMap = array_map($valueMap, array_combine($matches[1], $matches[1]));
|
||||
}
|
||||
|
||||
$labelMap = static::labels();
|
||||
|
||||
if ($labelMap instanceof Closure) {
|
||||
$labelMap = array_map($labelMap, array_combine($matches[1], $matches[1]));
|
||||
}
|
||||
|
||||
foreach ($matches[1] as $methodName) {
|
||||
$value = $valueMap[$methodName] = $valueMap[$methodName] ?? $methodName;
|
||||
|
||||
$label = $labelMap[$methodName] = $labelMap[$methodName] ?? $methodName;
|
||||
|
||||
$definition[$methodName] = new BaseEnumDefinition($methodName, $value, $label);
|
||||
}
|
||||
|
||||
if (self::arrayHasDuplicates($valueMap)) {
|
||||
throw new DuplicateValuesException();
|
||||
}
|
||||
|
||||
if (self::arrayHasDuplicates($labelMap)) {
|
||||
throw new DuplicateLabelsException();
|
||||
}
|
||||
|
||||
return self::$definitionCache[$className] = self::$definitionCache[$className] ?? $definition;
|
||||
}
|
||||
|
||||
private static function arrayHasDuplicates(array $array): bool
|
||||
{
|
||||
return count($array) > count(array_unique($array));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|string
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return [
|
||||
'label' => $this->label,
|
||||
'value' => $this->value
|
||||
];
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string) $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the model's route key.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRouteKey()
|
||||
{
|
||||
throw new NotImplementedException('getRouteKey not implemented, should not be used');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the route key for the model.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRouteKeyName()
|
||||
{
|
||||
throw new NotImplementedException('getRouteKeyName not implemented, should not be used');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the model for a bound value.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|null $field
|
||||
* @return \Illuminate\Database\Eloquent\Model|null
|
||||
*/
|
||||
public function resolveRouteBinding($value, $field = null)
|
||||
{
|
||||
// try to cast numeric value first
|
||||
try {
|
||||
return static::make(is_numeric($value) ? intval($value) : $value);
|
||||
} catch (BadMethodCallException $e) {
|
||||
}
|
||||
// try string value after that
|
||||
try {
|
||||
return static::make($value);
|
||||
} catch (BadMethodCallException $e) {
|
||||
}
|
||||
// could not find a suitable value
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the child model for a bound value.
|
||||
*
|
||||
* @param string $childType
|
||||
* @param mixed $value
|
||||
* @param string|null $field
|
||||
* @return \Illuminate\Database\Eloquent\Model|null
|
||||
* @throws NotImplementedException
|
||||
*/
|
||||
public function resolveChildRouteBinding($childType, $value, $field)
|
||||
{
|
||||
throw new NotImplementedException('resolveChildRouteBinding not implemented, should not be used');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Enum name from class name
|
||||
*
|
||||
|
|
@ -345,4 +241,108 @@ abstract class BaseEnum implements JsonSerializable, UrlRoutable
|
|||
$cls = explode('\\', static::class);
|
||||
return array_pop($cls);
|
||||
}
|
||||
|
||||
|
||||
// -- PRIVATE METHODS --
|
||||
|
||||
/**
|
||||
* @param string|integer $input
|
||||
* @return \Kwaadpepper\Enum\BaseEnumDefinition|null
|
||||
*/
|
||||
private static function findDefinition($input): ?BaseEnumDefinition
|
||||
{
|
||||
foreach (static::resolveDefinition() as $definition) {
|
||||
if ($definition->equals($input)) {
|
||||
return $definition;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve enum defintion
|
||||
*
|
||||
* @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
|
||||
{
|
||||
// phpcs:enable
|
||||
if (isset(self::$definitionCache[static::class])) {
|
||||
return self::$definitionCache[static::class];
|
||||
}
|
||||
|
||||
$reflectionClass = new \ReflectionClass(static::class);
|
||||
$docComment = $reflectionClass->getDocComment();
|
||||
|
||||
preg_match_all('/@method\s+static\s+self\s+([\w_]+)\(\)/', $docComment, $matches);
|
||||
|
||||
$definition = [];
|
||||
$valueMap = static::values();
|
||||
$labelMap = static::labels();
|
||||
|
||||
if (!count($matches[1])) {
|
||||
throw new EmptyDefinitionException('You are missing defining enum definition in comments.');
|
||||
}
|
||||
if (self::arrayHasDuplicates($matches[1])) {
|
||||
throw new DuplicateDefinitionException('You have duplicate values in comments enum definition.');
|
||||
}
|
||||
|
||||
foreach ($matches[1] as $methodName) {
|
||||
$valueMap[$methodName] = $valueMap[$methodName] ?? $methodName;
|
||||
$labelMap[$methodName] = $labelMap[$methodName] ?? $methodName;
|
||||
$definition[$methodName] = new BaseEnumDefinition(
|
||||
$methodName,
|
||||
$valueMap[$methodName],
|
||||
$labelMap[$methodName]
|
||||
);
|
||||
}
|
||||
|
||||
if (self::arrayHasDuplicates($valueMap)) {
|
||||
throw new DuplicateValuesException('You have duplicates values in enum values method.');
|
||||
}
|
||||
|
||||
if (self::arrayHasDuplicates($labelMap)) {
|
||||
throw new DuplicateLabelsException('You have duplicates values in enum labels method.');
|
||||
}
|
||||
|
||||
self::$definitionCache[static::class] = $definition;
|
||||
|
||||
return self::$definitionCache[static::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an array has duplicated values
|
||||
*
|
||||
* @param array $array
|
||||
* @return boolean True if it has duplicated value.
|
||||
*/
|
||||
private static function arrayHasDuplicates(array $array): bool
|
||||
{
|
||||
$uniqueVals = [];
|
||||
foreach ($array as $value) {
|
||||
if (!in_array($value, $uniqueVals, true)) {
|
||||
$uniqueVals[] = $value;
|
||||
}
|
||||
}
|
||||
return count($array) > count($uniqueVals);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert value is valid
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
* @throws \TypeError If anything else than string or int is used.
|
||||
*/
|
||||
private static function assertValidValue(mixed $value): void
|
||||
{
|
||||
if (!(is_string($value) || is_int($value))) {
|
||||
$enumClass = static::class;
|
||||
throw new \TypeError("Only string and integer are allowed values for enum $enumClass.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,13 @@
|
|||
|
||||
namespace Kwaadpepper\Enum;
|
||||
|
||||
/**
|
||||
* The definition of an enumeration
|
||||
* This defines it's value, label and method name
|
||||
*/
|
||||
class BaseEnumDefinition
|
||||
{
|
||||
/** @var string|int */
|
||||
/** @var string|integer */
|
||||
public $value;
|
||||
|
||||
/** @var string */
|
||||
|
|
@ -14,32 +18,29 @@ class BaseEnumDefinition
|
|||
private $methodName;
|
||||
|
||||
/**
|
||||
* @param string $methodName
|
||||
* @param string|int $value
|
||||
* @param string $label
|
||||
* @param string $methodName
|
||||
* @param string|integer $value
|
||||
* @param string $label
|
||||
*/
|
||||
public function __construct(string $methodName, $value, string $label)
|
||||
{
|
||||
$this->methodName = strtolower($methodName);
|
||||
$this->value = $value;
|
||||
$this->label = $label;
|
||||
$this->value = $value;
|
||||
$this->label = $label;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|int $input
|
||||
*
|
||||
* @return bool
|
||||
* @param string|integer $input
|
||||
* @return boolean
|
||||
*/
|
||||
public function equals($input): bool
|
||||
{
|
||||
if ($this->value === $input) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_string($input) && $this->methodName === strtolower($input)) {
|
||||
if (is_string($input) and $this->methodName === strtolower($input)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
95
src/BaseEnumRoutable.php
Normal file
95
src/BaseEnumRoutable.php
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
|
||||
namespace Kwaadpepper\Enum;
|
||||
|
||||
use BadMethodCallException;
|
||||
use Illuminate\Contracts\Routing\UrlRoutable;
|
||||
use Kwaadpepper\Enum\Exceptions\EnumNotRoutableException;
|
||||
use Kwaadpepper\Enum\Exceptions\NotImplementedException;
|
||||
use TypeError;
|
||||
|
||||
/**
|
||||
* This Base Enum will be routable with laravel.
|
||||
* So you can use it with service container passing an
|
||||
* enumeration as any route parameter directly as
|
||||
* a controller parameter.
|
||||
*/
|
||||
abstract class BaseEnumRoutable extends BaseEnum implements UrlRoutable
|
||||
{
|
||||
/**
|
||||
* Get the value of the model's route key.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRouteKey()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the route key for the model.
|
||||
*
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.InvalidNoReturn
|
||||
*
|
||||
* @return string
|
||||
* @throws \Kwaadpepper\Enum\Exceptions\NotImplementedException GetRouteKeyName not implemented,
|
||||
* should not be used.
|
||||
*/
|
||||
public function getRouteKeyName()
|
||||
{
|
||||
// phpcs:enable
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new NotImplementedException('GetRouteKeyName not implemented, should not be used.');
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the model for a bound value.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|null $field
|
||||
* @return \Kwaadpepper\Enum\BaseEnum|null
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassAfterLastUsed
|
||||
*/
|
||||
public function resolveRouteBinding(mixed $value, $field = null)
|
||||
{
|
||||
// phpcs:enable
|
||||
// Try to cast numeric value first.
|
||||
try {
|
||||
// Try cast to int.
|
||||
$iValue = (is_numeric($value) and floatval(intval($value)) === floatval($value)) ?
|
||||
(int)$value : $value;
|
||||
return static::make($iValue);
|
||||
} catch (BadMethodCallException | EnumNotRoutableException | TypeError $e) {
|
||||
// Try string value after that.
|
||||
try {
|
||||
return static::make($value);
|
||||
} catch (BadMethodCallException | EnumNotRoutableException | TypeError $e) {
|
||||
// Could not find a suitable value.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the child model for a bound value.
|
||||
*
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.InvalidNoReturn
|
||||
*
|
||||
* @param string $childType
|
||||
* @param mixed $value
|
||||
* @param string|null $field
|
||||
* @return \Illuminate\Database\Eloquent\Model|null
|
||||
* @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)
|
||||
{
|
||||
// phpcs:enable
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new NotImplementedException('ResolveChildRouteBinding not implemented, should not be used.');
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
201
src/Console/CreateEnum.php
Normal file
201
src/Console/CreateEnum.php
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
<?php
|
||||
|
||||
namespace Kwaadpepper\Enum\Console;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
class CreateEnum extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'make:enum';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Create a new enum class';
|
||||
|
||||
/**
|
||||
* Handle the command
|
||||
*
|
||||
* @return integer|void
|
||||
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
// phpcs:enable
|
||||
$validate = false;
|
||||
$info = [
|
||||
'name' => false,
|
||||
'definition' => [],
|
||||
'labels' => [],
|
||||
'values' => []
|
||||
];
|
||||
|
||||
$this->info('Enumeration Generator.');
|
||||
|
||||
do {
|
||||
do {
|
||||
$name = ucfirst($this->ask('Which name should have the enum class ? (use PascalCase, ex: UserRole)'));
|
||||
if (\strlen($name) <= 1 or \preg_match('/^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$/', $name) !== 1) {
|
||||
$this->question('You shall provide a valid class name.');
|
||||
if (!$this->confirm('Do you want to continue ?')) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (File::exists(\app_path("Enums/$name.php"))) {
|
||||
$this->question("$name.php already exists.");
|
||||
if (!$this->confirm('Do you want to continue ?')) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
$info['name'] = $name;
|
||||
}
|
||||
} while ($info['name'] === false);
|
||||
|
||||
do {
|
||||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||
$values = \trim($this->ask('Write down definitions separated with pipes (|), ex: admin|editor|user|guest'));
|
||||
|
||||
$info['definition'] = (\strlen($values) > 1 and \strpos($values, '|') !== 0) ?
|
||||
explode('|', $values) : [];
|
||||
|
||||
if (empty($info['definition'])) {
|
||||
$this->question('You have to provide a definition for your enum.');
|
||||
if (!$this->confirm('Do you want to continue ?')) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} while (empty($info['definition']));
|
||||
|
||||
if ($this->confirm('Do you want to add custom values to your enum ?')) {
|
||||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||
$values = $this->ask('Write down your values separated with pipes (|), ex: 0|1|2|3, or \'value1\'|\'value2\'|\'value3\'');
|
||||
|
||||
$info['values'] = explode('|', $values);
|
||||
}
|
||||
if ($this->confirm('Do you want to add custom labels to your enum ?')) {
|
||||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||
$values = $this->ask('Write down your labels separated with pipes (|), ex: When off|When on|When blinking');
|
||||
|
||||
$info['labels'] = explode('|', str_replace('\'', '\\\'', $values));
|
||||
}
|
||||
|
||||
$this->info('You have selected the followings :');
|
||||
$print = [];
|
||||
foreach ($info['definition'] as $k => $definition) {
|
||||
$print[] = [
|
||||
$definition => [
|
||||
'label' => $info['labels'][$k] ?? $definition,
|
||||
'value' => $info['values'][$k] ?? $definition,
|
||||
]
|
||||
];
|
||||
}
|
||||
$this->info(\json_encode($print, \JSON_PRETTY_PRINT | \JSON_NUMERIC_CHECK));
|
||||
|
||||
if ($this->confirm('Do you want to use these parameters ?', true)) {
|
||||
$validate = true;
|
||||
} elseif (!$this->confirm('Do you want to continue ?')) {
|
||||
return -1;
|
||||
}
|
||||
} while (!$validate);
|
||||
|
||||
if (!File::exists(\app_path('Enums'))) {
|
||||
$this->info('Creating Enums directory');
|
||||
File::makeDirectory(\app_path('Enums'));
|
||||
}
|
||||
|
||||
$this->info('Generating enum');
|
||||
|
||||
$templateEnum = File::get(__DIR__ . '/../../resources/templates/TemplateEnum.php');
|
||||
|
||||
$this->replaceClassName($templateEnum, $info);
|
||||
$this->replaceDefinition($templateEnum, $info);
|
||||
$this->insertLabelsAndValues($templateEnum, $info);
|
||||
|
||||
File::put(\app_path("Enums/$name.php"), $templateEnum);
|
||||
$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
|
||||
{
|
||||
$targetDefinition = "class TemplateEnum";
|
||||
$replaceDefinition = "class {$info['name']}";
|
||||
|
||||
$templateEnum = str_replace($targetDefinition, $replaceDefinition, $templateEnum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace definition
|
||||
*
|
||||
* @param string $templateEnum
|
||||
* @param array $info
|
||||
* @return void
|
||||
*/
|
||||
private function replaceDefinition(string &$templateEnum, array $info): void
|
||||
{
|
||||
$targetDefinition = " * ##VALUES\n";
|
||||
$replaceDefinition = '';
|
||||
|
||||
foreach ($info['definition'] as $definition) {
|
||||
$replaceDefinition .= " * @method static self $definition()\n";
|
||||
}
|
||||
$replaceDefinition .= " *\n";
|
||||
|
||||
$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
|
||||
{
|
||||
$targetDefinition = " // ##OVERRIDE\n";
|
||||
$replaceDefinition = '';
|
||||
$templateValues = 'public static function values()';
|
||||
$templateLabels = 'public static function labels()';
|
||||
|
||||
if (count($info['values'])) {
|
||||
$replaceDefinition = " $templateValues\n {\n return [\n";
|
||||
foreach ($info['definition'] as $k => $definition) {
|
||||
$replaceDefinition .= sprintf(
|
||||
" '%s' => %s,\n",
|
||||
$definition,
|
||||
$info['values'][$k] ?? $definition
|
||||
);
|
||||
}
|
||||
$replaceDefinition = rtrim($replaceDefinition, ',');
|
||||
$replaceDefinition .= " ];\n }\n";
|
||||
}
|
||||
if (count($info['labels'])) {
|
||||
$replaceDefinition .= "\n $templateLabels\n {\n return [\n";
|
||||
foreach ($info['definition'] as $k => $definition) {
|
||||
$replaceDefinition .= sprintf(
|
||||
" '%s' => '%s',\n",
|
||||
$definition,
|
||||
$info['labels'][$k] ?? $definition
|
||||
);
|
||||
}
|
||||
$replaceDefinition = rtrim($replaceDefinition, ',');
|
||||
$replaceDefinition .= " ];\n }\n";
|
||||
}
|
||||
$templateEnum = str_replace($targetDefinition, $replaceDefinition, $templateEnum);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
namespace Kwaadpepper\Enum;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Kwaadpepper\Enum\Console\CreateEnum;
|
||||
|
||||
class EnumServiceProvider extends ServiceProvider
|
||||
{
|
||||
|
|
@ -13,10 +14,17 @@ class EnumServiceProvider extends ServiceProvider
|
|||
*/
|
||||
public function boot()
|
||||
{
|
||||
$this->loadJsonTranslationsFrom(__DIR__ . '/../resources/lang', 'enum');
|
||||
$this->loadTranslationsFrom(__DIR__ . '/../resources/lang', 'enum');
|
||||
|
||||
$this->publishes([
|
||||
__DIR__ . '/../resources/lang' => resource_path('lang/vendor/enum'),
|
||||
]);
|
||||
|
||||
// Register the command if we are using the application via the CLI.
|
||||
if ($this->app->runningInConsole()) {
|
||||
$this->commands([
|
||||
CreateEnum::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
15
src/Exceptions/DuplicateDefinitionException.php
Normal file
15
src/Exceptions/DuplicateDefinitionException.php
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace Kwaadpepper\Enum\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Is thrown when your enum definition
|
||||
* contain multiple times the same label value
|
||||
*
|
||||
* This should happen if you have a duplication declaration
|
||||
*/
|
||||
class DuplicateDefinitionException extends Exception
|
||||
{
|
||||
}
|
||||
|
|
@ -4,7 +4,12 @@ namespace Kwaadpepper\Enum\Exceptions;
|
|||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Is thrown when your enum definition
|
||||
* contain multiple times the same label value
|
||||
*
|
||||
* This should only happen if you override the labels method
|
||||
*/
|
||||
class DuplicateLabelsException extends Exception
|
||||
{
|
||||
//
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,12 @@ namespace Kwaadpepper\Enum\Exceptions;
|
|||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Is thrown when your enum definition
|
||||
* contain multiple times the same value
|
||||
*
|
||||
* This should only happen if you override the values method
|
||||
*/
|
||||
class DuplicateValuesException extends Exception
|
||||
{
|
||||
//
|
||||
}
|
||||
|
|
|
|||
15
src/Exceptions/EmptyDefinitionException.php
Normal file
15
src/Exceptions/EmptyDefinitionException.php
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace Kwaadpepper\Enum\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Is thrown when your enum definition
|
||||
* contain multiple times the same label value
|
||||
*
|
||||
* This should happen if you have a duplication declaration
|
||||
*/
|
||||
class EmptyDefinitionException extends Exception
|
||||
{
|
||||
}
|
||||
15
src/Exceptions/EnumNotRoutableException.php
Normal file
15
src/Exceptions/EnumNotRoutableException.php
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace Kwaadpepper\Enum\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Is thrown on enum constructor
|
||||
* as it happens with laravel resolver
|
||||
* it is named like this event if it is only on
|
||||
* BaseEnum which works on any application
|
||||
*/
|
||||
class EnumNotRoutableException extends Exception
|
||||
{
|
||||
}
|
||||
|
|
@ -4,7 +4,11 @@ namespace Kwaadpepper\Enum\Exceptions;
|
|||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* This exception is used only
|
||||
* as a safe guard it should not be thrown
|
||||
* at any moment
|
||||
*/
|
||||
class NotImplementedException extends Exception
|
||||
{
|
||||
//
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,5 +6,4 @@ use Exception;
|
|||
|
||||
class UnknownEnumClass extends Exception
|
||||
{
|
||||
//
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,28 @@ namespace Kwaadpepper\Enum\Exceptions;
|
|||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Is thrown when accessing other propety than
|
||||
* label or value on a enumeration.
|
||||
*/
|
||||
class UnknownEnumProperty extends Exception
|
||||
{
|
||||
//
|
||||
/**
|
||||
* The error message
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $message;
|
||||
|
||||
/**
|
||||
* Construct the exception. Note: The message is NOT binary safe.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(string $attribute)
|
||||
{
|
||||
$this->message = "Unknown attribute $attribute, enumeration only have propeties `label` and `value`.";
|
||||
parent::__construct();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace Kwaadpepper\Enum\Rules;
|
||||
|
||||
use Illuminate\Contracts\Validation\Rule;
|
||||
use Kwaadpepper\Enum\BaseEnum;
|
||||
use Kwaadpepper\Enum\Exceptions\UnknownEnumClass;
|
||||
|
||||
abstract class BaseEnumRule implements Rule
|
||||
|
|
@ -16,10 +17,11 @@ abstract class BaseEnumRule implements Rule
|
|||
*
|
||||
* @param string $enumClass
|
||||
* @return void
|
||||
* @throws \Kwaadpepper\Enum\Exceptions\UnknownEnumClass If the class passed is not an enum.
|
||||
*/
|
||||
public function __construct(string $enumClass)
|
||||
{
|
||||
if (!class_exists($enumClass)) {
|
||||
if (!class_exists($enumClass) or !is_subclass_of($enumClass, BaseEnum::class)) {
|
||||
throw new UnknownEnumClass();
|
||||
}
|
||||
$this->enumClass = $enumClass;
|
||||
|
|
@ -28,11 +30,15 @@ abstract class BaseEnumRule implements Rule
|
|||
/**
|
||||
* Determine if the validation rule passes.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param string $attribute
|
||||
* @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;
|
||||
// phpcs:enable
|
||||
|
||||
/**
|
||||
* Get the validation error message.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -5,28 +5,30 @@ namespace Kwaadpepper\Enum\Rules;
|
|||
use BadMethodCallException;
|
||||
use TypeError;
|
||||
|
||||
/**
|
||||
* Custom Rule to validate an enum
|
||||
*/
|
||||
class EnumIsValidRule extends BaseEnumRule
|
||||
{
|
||||
private $messageType = 0;
|
||||
|
||||
/**
|
||||
* Determine if the validation rule passes.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param string $attribute
|
||||
* @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
|
||||
*/
|
||||
public function passes($attribute, $value): bool
|
||||
{
|
||||
// phpcs:enable
|
||||
try {
|
||||
// try cast to int if is int
|
||||
$value = is_numeric($value) && floatval(intval($value)) === floatval($value) ? (int)$value : $value;
|
||||
// Try cast to int if is int.
|
||||
$value = (is_numeric($value) and floatval(intval($value)) === floatval($value)) ?
|
||||
(int)$value : $value;
|
||||
forward_static_call([$this->enumClass, 'make'], $value);
|
||||
} catch (TypeError $e) {
|
||||
$this->messageType = 1;
|
||||
return false;
|
||||
} catch (BadMethodCallException $e) {
|
||||
$this->messageType = 2;
|
||||
} catch (TypeError | BadMethodCallException $e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -38,13 +40,8 @@ class EnumIsValidRule extends BaseEnumRule
|
|||
*/
|
||||
public function message(): string
|
||||
{
|
||||
switch ($this->messageType) {
|
||||
case 1:
|
||||
return trans('enum::enum.isNotValid');
|
||||
case 2:
|
||||
return trans('enum::enum.notInList', [
|
||||
'values' => implode(',', forward_static_call([$this->enumClass, 'toValues']))
|
||||
]);
|
||||
}
|
||||
return trans('enum::enum.notInList', [
|
||||
'values' => implode(',', forward_static_call([$this->enumClass, 'toValues']))
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,21 +2,27 @@
|
|||
|
||||
namespace Kwaadpepper\Enum\Traits;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Kwaadpepper\Enum\BaseEnum;
|
||||
|
||||
/**
|
||||
* @property array $attributes Laravel model attributes
|
||||
* @property array $enumCasts Map attribute names to enum classes.
|
||||
* @method bool hasCast(string $key, array|string|null $types = null)
|
||||
* @method mixed castAttribute(string $key, mixed $value)
|
||||
*/
|
||||
trait CastsEnums
|
||||
{
|
||||
/**
|
||||
* Get a plain attribute (not a relationship).
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.ScalarTypeHintMissing
|
||||
*/
|
||||
public function getAttributeValue($key)
|
||||
{
|
||||
// phpcs:enable
|
||||
$value = parent::getAttributeValue($key);
|
||||
|
||||
if ($this->hasEnumCast($key)) {
|
||||
|
|
@ -29,66 +35,83 @@ trait CastsEnums
|
|||
/**
|
||||
* Set a given attribute on the model.
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @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)
|
||||
{
|
||||
if ($value !== null && $this->hasEnumCast($key)) {
|
||||
/** @var \App\Enums\BaseEnum $enum */
|
||||
$enum = $this->enumCasts[$key];
|
||||
|
||||
if ($value instanceof $enum) {
|
||||
$this->attributes[$key] = $value->value;
|
||||
} else {
|
||||
if ($this->hasCast($key)) {
|
||||
$value = $this->castAttribute($key, $value);
|
||||
}
|
||||
// try cast to int if is int
|
||||
$value = is_numeric($value) && floatval(intval($value)) === floatval($value) ? (int)$value : $value;
|
||||
$this->attributes[$key] = $enum::make($value)->value;
|
||||
// phpcs:enable
|
||||
try {
|
||||
if ($enum = $this->castToEnum($key, $value) and $enum instanceof BaseEnum) {
|
||||
$this->attributes[$key] = $enum->value;
|
||||
return $this;
|
||||
}
|
||||
} catch (\TypeError | \BadMethodCallException $e) {
|
||||
Log::debug(\sprintf('%s : trait CastEnums error, %s', __CLASS__, $e->getMessage()));
|
||||
if (in_array(config('app.env'), ['debug', 'testing'])) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
return parent::setAttribute($key, $value);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether an attribute should be cast to a enum.
|
||||
*
|
||||
* @param string $key
|
||||
* @return bool
|
||||
* @param string $key
|
||||
* @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) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return array_key_exists($key, $this->enumCasts);
|
||||
return array_key_exists($key, $this->enumCasts) and
|
||||
is_subclass_of($this->enumCasts[$key], BaseEnum::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts the given key to an enum instance
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return \App\Enums\BaseEnum|null
|
||||
* @return \Kwaadpepper\Enum\BaseEnum|mixed|null
|
||||
* @throws TypeError — If anything else than string or int is used.
|
||||
* @throws BadMethodCallException — If a matching definition cannot be found.
|
||||
*/
|
||||
protected function castToEnum($key, $value): ?BaseEnum
|
||||
protected function castToEnum(string $key, mixed $value)
|
||||
{
|
||||
/** @var \App\Enums\BaseEnum $enum */
|
||||
if (
|
||||
$value === null or
|
||||
(\is_object($value) and \is_subclass_of($value, BaseEnum::class)) or
|
||||
!isset($this->enumCasts[$key])
|
||||
) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if ($this->hasCast($key)) {
|
||||
$value = $this->castAttribute($key, $value);
|
||||
}
|
||||
|
||||
// Try cast to int.
|
||||
$value = (is_numeric($value) and floatval(intval($value)) === floatval($value)) ?
|
||||
(int)$value : $value;
|
||||
|
||||
/** @var \Kwaadpepper\Enum\BaseEnum $enum */
|
||||
$enum = $this->enumCasts[$key];
|
||||
|
||||
if ($value === null || $value instanceof BaseEnum) {
|
||||
return $value;
|
||||
} else {
|
||||
return $enum::make($value);
|
||||
}
|
||||
return $enum::make($value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
319
tests/BaseEnumRoutableTest.php
Normal file
319
tests/BaseEnumRoutableTest.php
Normal file
|
|
@ -0,0 +1,319 @@
|
|||
<?php
|
||||
|
||||
namespace Kwaadpepper\Enum\Tests;
|
||||
|
||||
use App\Http\Requests\PassDayRequest;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Kwaadpepper\Enum\Exceptions\EnumNotRoutableException;
|
||||
use Kwaadpepper\Enum\Exceptions\UnknownEnumClass;
|
||||
use Kwaadpepper\Enum\Rules\EnumIsValidRule;
|
||||
use Kwaadpepper\Enum\Tests\Enums\ContactFormCivility;
|
||||
use Kwaadpepper\Enum\Tests\Enums\Days;
|
||||
use Kwaadpepper\Enum\Tests\Enums\ForceStringsFromInteger;
|
||||
use Kwaadpepper\Enum\Tests\Enums\NotRoutableEnum;
|
||||
use Kwaadpepper\Enum\Tests\Models\Alarm;
|
||||
use Kwaadpepper\Enum\Tests\Models\Journal;
|
||||
use Kwaadpepper\Enum\Tests\Models\Report;
|
||||
|
||||
class BaseEnumRoutableTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Defines aliases
|
||||
*
|
||||
* @param \Illuminate\Foundation\Application $app
|
||||
* @return void
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
|
||||
*/
|
||||
protected function getPackageAliases($app)
|
||||
{
|
||||
// phpcs:enable
|
||||
$app->alias(Alarm::class, 'Alarm');
|
||||
$app->alias(Journal::class, 'Journal');
|
||||
$app->alias(Report::class, 'Report');
|
||||
$app->alias(Days::class, 'Days');
|
||||
$app->alias(ContactFormCivility::class, 'ContactFormCivility');
|
||||
$app->alias(ForceStringsFromInteger::class, 'ForceStringsFromInteger');
|
||||
$app->alias(NotRoutableEnum::class, 'NotRoutableEnum');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get package providers.
|
||||
*
|
||||
* @param \Illuminate\Foundation\Application $app
|
||||
*
|
||||
* @return array
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
*/
|
||||
protected function getPackageProviders($app)
|
||||
{
|
||||
// phpcs:enable
|
||||
return [
|
||||
\Kwaadpepper\Enum\EnumServiceProvider::class,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Defines migrations
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function defineDatabaseMigrations()
|
||||
{
|
||||
Schema::create('reports', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->smallInteger('day');
|
||||
});
|
||||
Schema::create('alarms', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->smallInteger('day');
|
||||
});
|
||||
Schema::create('journals', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->smallInteger('day');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines seeders
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function defineDatabaseSeeders()
|
||||
{
|
||||
Report::create(['day' => Days::none()]);
|
||||
Report::create(['day' => Days::mon()]);
|
||||
Report::create(['day' => Days::tue()]);
|
||||
Report::create(['day' => Days::wed()]);
|
||||
Report::create(['day' => Days::thu()]);
|
||||
Report::create(['day' => Days::fri()]);
|
||||
Report::create(['day' => Days::sat()]);
|
||||
Report::create(['day' => Days::sun()]);
|
||||
Alarm::create(['day' => Days::none()]);
|
||||
Alarm::create(['day' => Days::mon()]);
|
||||
Alarm::create(['day' => Days::tue()]);
|
||||
Alarm::create(['day' => Days::wed()]);
|
||||
Alarm::create(['day' => Days::thu()]);
|
||||
Alarm::create(['day' => Days::fri()]);
|
||||
Alarm::create(['day' => Days::sat()]);
|
||||
Alarm::create(['day' => Days::sun()]);
|
||||
Journal::create(['day' => Days::none()]);
|
||||
Journal::create(['day' => Days::mon()]);
|
||||
Journal::create(['day' => Days::tue()]);
|
||||
Journal::create(['day' => Days::wed()]);
|
||||
Journal::create(['day' => Days::thu()]);
|
||||
Journal::create(['day' => Days::fri()]);
|
||||
Journal::create(['day' => Days::sat()]);
|
||||
Journal::create(['day' => Days::sun()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define routes setup.
|
||||
*
|
||||
* @param \Illuminate\Routing\Router $router
|
||||
*
|
||||
* @return void
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
|
||||
*/
|
||||
protected function defineRoutes($router)
|
||||
{
|
||||
// phpcs:enable
|
||||
$router->get('/journals/{journal}', function (Journal $journal) {
|
||||
return response()->json([$journal->day]);
|
||||
})->middleware(\Illuminate\Routing\Middleware\SubstituteBindings::class)->name('journal.view');
|
||||
$router->get('/reports/{report}', function (Report $report) {
|
||||
return response()->json([$report->day]);
|
||||
})->middleware(\Illuminate\Routing\Middleware\SubstituteBindings::class);
|
||||
$router->get('/alarms/{alarm}', function (Alarm $alarm) {
|
||||
return response()->json([$alarm->day]);
|
||||
})->middleware(\Illuminate\Routing\Middleware\SubstituteBindings::class);
|
||||
$router->get('/days/{day}', function (Days $day) {
|
||||
return response()->json([$day]);
|
||||
})->middleware(\Illuminate\Routing\Middleware\SubstituteBindings::class);
|
||||
$router->get('/day-validation', function (PassDayRequest $request) {
|
||||
return response()->json([Days::make((int)$request->day)]);
|
||||
})->middleware(\Illuminate\Routing\Middleware\SubstituteBindings::class);
|
||||
$router->get('/civilities/{civility}', function (ContactFormCivility $civility) {
|
||||
return response()->json([$civility]);
|
||||
})->middleware(\Illuminate\Routing\Middleware\SubstituteBindings::class);
|
||||
$router->get('/force/{force}', function (ForceStringsFromInteger $force) {
|
||||
return response()->json([$force]);
|
||||
})->middleware(\Illuminate\Routing\Middleware\SubstituteBindings::class);
|
||||
$router->get('/notroutable/{notroutable}', function (NotRoutableEnum $notroutable) {
|
||||
return response()->json([$notroutable]);
|
||||
})->middleware(\Illuminate\Routing\Middleware\SubstituteBindings::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test route values
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testRoutesDays()
|
||||
{
|
||||
$response = $this->json('GET', sprintf('/days/%s', Days::none()->value));
|
||||
$response->assertOk();
|
||||
$response->assertExactJson([Days::none()]);
|
||||
$response = $this->json('GET', sprintf('/days/%s', Days::mon()->value));
|
||||
$response->assertOk();
|
||||
$response->assertExactJson([Days::mon()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test route with example civilities
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testRoutesCivilities()
|
||||
{
|
||||
$response = $this->json('GET', sprintf('/civilities/%s', ContactFormCivility::mme()->value));
|
||||
$response->assertOk();
|
||||
$response->assertExactJson([ContactFormCivility::mme()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test route with enum as string
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testRoutesWithEnumIntString()
|
||||
{
|
||||
$response = $this->json('GET', sprintf('/force/%s', ForceStringsFromInteger::valueB()->value));
|
||||
$response->assertOk();
|
||||
$response->assertExactJson([ForceStringsFromInteger::valueB()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test route with enum not found
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testRoutesWithEnumNotFound()
|
||||
{
|
||||
$response = $this->json('GET', '/force/6');
|
||||
$response->assertNotFound();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test routes with enums as pk
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testRoutesWithEnumAsPrimaryKey()
|
||||
{
|
||||
$response = $this->json('GET', sprintf('/reports/%s', Days::none()->value));
|
||||
$response->assertOk();
|
||||
$response = $this->json('GET', sprintf('/reports/%s', Days::mon()->value));
|
||||
$response->assertOk();
|
||||
$response = $this->json('GET', sprintf('/reports/%s', Days::tue()->value));
|
||||
$response->assertOk();
|
||||
$response = $this->json('GET', sprintf('/reports/%s', Days::fri()->value));
|
||||
$response->assertOk();
|
||||
$response = $this->json('GET', sprintf('/reports/%s', 9999));
|
||||
$response->assertNotFound();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test routes with enum as pk without cast enums
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testRoutesWithEnumAsPrimaryKeyWithoutCastEnums()
|
||||
{
|
||||
$response = $this->json('GET', sprintf('/alarms/%s', Days::none()->value));
|
||||
$response->assertOk();
|
||||
$response = $this->json('GET', sprintf('/alarms/%s', Days::mon()->value));
|
||||
$response->assertOk();
|
||||
$response = $this->json('GET', sprintf('/alarms/%s', Days::tue()->value));
|
||||
$response->assertOk();
|
||||
$response = $this->json('GET', sprintf('/alarms/%s', Days::fri()->value));
|
||||
$response->assertOk();
|
||||
$response = $this->json('GET', sprintf('/alarms/%s', 9999));
|
||||
$response->assertNotFound();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test routes wit henum as pk without cast enums
|
||||
*
|
||||
* ! This test includes getRouteKey method for coverage
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testRoutesWithEnumAsPrimaryKeyWithoutCastEnumsAndCast()
|
||||
{
|
||||
$response = $this->json('GET', \route('journal.view', Days::none()));
|
||||
$response->assertOk();
|
||||
$response = $this->json('GET', \route('journal.view', Days::mon()));
|
||||
$response->assertOk();
|
||||
$response = $this->json('GET', \route('journal.view', Days::tue()));
|
||||
$response->assertOk();
|
||||
$response = $this->json('GET', \route('journal.view', Days::fri()));
|
||||
$response->assertOk();
|
||||
$response = $this->json('GET', \route('journal.view', 9999));
|
||||
$response->assertNotFound();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test enum is valid rule
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testRules()
|
||||
{
|
||||
$rule = new EnumIsValidRule(Days::class);
|
||||
$this->assertTrue($rule->passes('day', Days::mon()->value));
|
||||
$this->assertFalse($rule->passes('day', 9999));
|
||||
$this->assertFalse($rule->passes('day', Days::mon()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test route with enum
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testRulesRequest()
|
||||
{
|
||||
$response = $this->json('GET', sprintf('/day-validation?day=%s', Days::fri()->value));
|
||||
$response->assertOk();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test route fails on non enum
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testRulesRequestFail()
|
||||
{
|
||||
$response = $this->json('GET', sprintf('/day-validation?day=%s', '"!:'));
|
||||
$response->assertJsonValidationErrors('day');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Enum validate enum class on non enum class
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testRulesRequestInvalid()
|
||||
{
|
||||
$this->expectException(UnknownEnumClass::class);
|
||||
new EnumIsValidRule(\SplFileObject::class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test enum is not routable
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNotRoutableEnum()
|
||||
{
|
||||
$response = $this->json('GET', sprintf('/notroutable/%s', '1'));
|
||||
$response->assertStatus(500);
|
||||
$this->assertEquals(
|
||||
new EnumNotRoutableException(),
|
||||
$response->exception
|
||||
);
|
||||
}
|
||||
}
|
||||
219
tests/BaseEnumTest.php
Normal file
219
tests/BaseEnumTest.php
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
<?php
|
||||
|
||||
namespace Kwaadpepper\Enum\Tests;
|
||||
|
||||
use Kwaadpepper\Enum\Exceptions\DuplicateLabelsException;
|
||||
use Kwaadpepper\Enum\Exceptions\DuplicateValuesException;
|
||||
use Kwaadpepper\Enum\Exceptions\UnknownEnumProperty;
|
||||
use Kwaadpepper\Enum\Tests\Enums\Days;
|
||||
use Kwaadpepper\Enum\Tests\Enums\DuplicatedLabels;
|
||||
use Kwaadpepper\Enum\Tests\Enums\DuplicatedValues;
|
||||
use Kwaadpepper\Enum\Tests\Enums\ForceStringsFromInteger;
|
||||
use Kwaadpepper\Enum\Tests\Models\Report;
|
||||
|
||||
class BaseEnumTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Test enum
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testEnum()
|
||||
{
|
||||
$mon = Days::mon();
|
||||
$tue = Days::tue();
|
||||
Days::toArray();
|
||||
Days::toValues();
|
||||
Days::toLabels();
|
||||
json_encode($tue);
|
||||
|
||||
// Basic tests.
|
||||
$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->assertTrue(\property_exists(Days::class, 'value'), 'Days should have a value property');
|
||||
$this->assertTrue(\property_exists(Days::class, 'label'), 'Days should have a label property');
|
||||
|
||||
// Undef prop test.
|
||||
$exception = null;
|
||||
try {
|
||||
$mon->propthatdontexists;
|
||||
} catch (\Exception $e) {
|
||||
$exception = $e;
|
||||
} finally {
|
||||
$this->assertEquals(
|
||||
UnknownEnumProperty::class,
|
||||
\is_object($exception) ? \get_class($exception) : $exception,
|
||||
'Accessing non existent prop on base enum should throw an UnknownEnumProperty exception'
|
||||
);
|
||||
}
|
||||
|
||||
$this->assertEquals('Days', $mon->getEnumName(), 'getEnumName should return the enum class name');
|
||||
$this->assertEquals('mon', $mon->getDefinition(), 'Days::mon() definition should be `mon`');
|
||||
$this->assertFalse($mon->equals($tue), 'Days::mon() should not be equals to Days::tue()');
|
||||
$this->assertTrue($mon->equals($mon), 'Days::mon() should be equals to Days::mon()');
|
||||
$this->assertIsArray(Days::toArray(), 'toArray method should return an array');
|
||||
$this->assertIsArray(Days::toValues(), 'toValues method should return an array');
|
||||
$this->assertIsArray(Days::toLabels(), 'toLabels method should return an array');
|
||||
$this->assertEquals([
|
||||
0 => 1,
|
||||
1 => 2,
|
||||
2 => 4,
|
||||
3 => 8,
|
||||
4 => 16,
|
||||
5 => 32,
|
||||
6 => 64,
|
||||
7 => 128
|
||||
], Days::toValues(), 'Days::toValues method should return an integer array');
|
||||
$this->assertEquals([
|
||||
0 => 'None',
|
||||
1 => 'Monday',
|
||||
2 => 'Tuesday',
|
||||
3 => 'Wednesday',
|
||||
4 => 'Thursday',
|
||||
5 => 'Friday',
|
||||
6 => 'Saturday',
|
||||
7 => 'Sunday'
|
||||
], Days::toLabels(), 'Days::toLabels method should return a string array');
|
||||
$this->assertEquals([
|
||||
0 => Days::none(),
|
||||
1 => Days::mon(),
|
||||
2 => Days::tue(),
|
||||
3 => Days::wed(),
|
||||
4 => Days::thu(),
|
||||
5 => Days::fri(),
|
||||
6 => Days::sat(),
|
||||
7 => Days::sun()
|
||||
], Days::toArray(), 'Days::toLabels method should return an enum array');
|
||||
$this->assertEquals(
|
||||
(string)ForceStringsFromInteger::valueA()->value,
|
||||
(string)ForceStringsFromInteger::valueA(),
|
||||
'BaseEnum::__toString should return the value as a string'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cannot assign an enum value
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testCannotAssignAnEnumValue()
|
||||
{
|
||||
$this->expectException(\Error::class);
|
||||
$enum = Days::mon();
|
||||
$enum->value = 'anything';
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cannot assign an enum label
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testCannotAssignAnEnumLabel()
|
||||
{
|
||||
$this->expectException(\Error::class);
|
||||
$enum = Days::mon();
|
||||
$enum->label = 'anything';
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is here for code coverage
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testHackingEnumValueCouldConfuseCache()
|
||||
{
|
||||
$enum = Days::mon();
|
||||
$refClass = new \ReflectionClass($enum);
|
||||
$property = $refClass->getProperty('value');
|
||||
$property->setAccessible(true);
|
||||
$property->setValue($enum, 'anything');
|
||||
$this->assertEquals('anything', $enum->value);
|
||||
$this->assertNull(
|
||||
$enum->getDefinition(),
|
||||
'BaseEnum::getDefinition should be null when hacking var consing cache'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test setting enum value onto model prop
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testValidEnumSet()
|
||||
{
|
||||
$this->expectNotToPerformAssertions();
|
||||
$report = new Report();
|
||||
$report->day = Days::mon();
|
||||
$report->day = Days::mon()->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test setting invalid enum value onto model prop
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testInvalidEnumSet()
|
||||
{
|
||||
$this->expectException(\BadMethodCallException::class);
|
||||
$report = new Report();
|
||||
$report->day = Days::mon()->label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test setting prop enum with float (invalid)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testInvalidEnumSetWithFloat()
|
||||
{
|
||||
$this->expectException(\TypeError::class);
|
||||
$report = new Report();
|
||||
$report->day = 0.1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test setting invalid enum prop with object
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testInvalidEnumSetNotAuthorizedType()
|
||||
{
|
||||
$this->expectException(\TypeError::class);
|
||||
$report = new Report();
|
||||
$report->day = new \stdClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test setting enum prop with null as valid
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testInvalidEnumCanSetNull()
|
||||
{
|
||||
$this->expectNotToPerformAssertions();
|
||||
$report = new Report();
|
||||
$report->day = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test enum has duplicated values
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDuplicatedValues()
|
||||
{
|
||||
$this->expectException(DuplicateValuesException::class);
|
||||
DuplicatedValues::one();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test enm has duplicated labels
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDuplicatedLabels()
|
||||
{
|
||||
$this->expectException(DuplicateLabelsException::class);
|
||||
DuplicatedLabels::one();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Kwaadpepper\Enum\Tests;
|
||||
|
||||
use Kwaadpepper\Enum\Rules\EnumIsValidRule;
|
||||
use Kwaadpepper\Enum\Tests\Enums\ContactFormCivility;
|
||||
use Kwaadpepper\Enum\Tests\Enums\Days;
|
||||
use Kwaadpepper\Enum\Tests\Enums\ForceStringsFromInteger;
|
||||
use Orchestra\Testbench\TestCase;
|
||||
|
||||
class EnumTest extends TestCase
|
||||
{
|
||||
protected function getPackageAliases($app)
|
||||
{
|
||||
$app->alias(Days::class, 'Days');
|
||||
$app->alias(ContactFormCivility::class, 'ContactFormCivility');
|
||||
}
|
||||
|
||||
/**
|
||||
* Define routes setup.
|
||||
*
|
||||
* @param \Illuminate\Routing\Router $router
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function defineRoutes($router)
|
||||
{
|
||||
$router->get('/days/{day}', function (Days $day) {
|
||||
return response()->json([$day]);
|
||||
})->middleware('bindings');
|
||||
$router->get('/civilities/{civility}', function (ContactFormCivility $civility) {
|
||||
return response()->json([$civility]);
|
||||
})->middleware('bindings');
|
||||
$router->get('/force/{force}', function (ForceStringsFromInteger $force) {
|
||||
return response()->json([$force]);
|
||||
})->middleware('bindings');
|
||||
}
|
||||
|
||||
|
||||
public function testEnum()
|
||||
{
|
||||
$mon = Days::mon();
|
||||
$tue = Days::tue();
|
||||
Days::toArray();
|
||||
Days::toValues();
|
||||
Days::toLabels();
|
||||
json_encode($tue);
|
||||
$mon->getDefinition();
|
||||
$this->assertClassHasAttribute('value', Days::class);
|
||||
$this->assertClassHasAttribute('label', Days::class);
|
||||
$this->assertFalse($mon->equals($tue));
|
||||
$this->assertTrue($mon->equals($mon));
|
||||
$this->assertIsArray(Days::toArray());
|
||||
$this->assertIsArray(Days::toValues());
|
||||
$this->assertIsArray(Days::toLabels());
|
||||
$this->assertEquals([
|
||||
0 => 0,
|
||||
1 => 1,
|
||||
2 => 2,
|
||||
3 => 4,
|
||||
4 => 8,
|
||||
5 => 16,
|
||||
6 => 32,
|
||||
7 => 64
|
||||
], Days::toValues());
|
||||
$this->assertEquals([
|
||||
0 => 'None',
|
||||
1 => 'Monday',
|
||||
2 => 'Tuesday',
|
||||
3 => 'Wednesday',
|
||||
4 => 'Thursday',
|
||||
5 => 'Friday',
|
||||
6 => 'Saturday',
|
||||
7 => 'Sunday'
|
||||
], Days::toLabels());
|
||||
$this->assertEquals([
|
||||
0 => Days::none(),
|
||||
1 => Days::mon(),
|
||||
2 => Days::tue(),
|
||||
3 => Days::wed(),
|
||||
4 => Days::thu(),
|
||||
5 => Days::fri(),
|
||||
6 => Days::sat(),
|
||||
7 => Days::sun()
|
||||
], Days::toArray());
|
||||
$this->assertEquals('Monday', (string)$mon);
|
||||
}
|
||||
|
||||
public function testRoutesDays()
|
||||
{
|
||||
$response = $this->call('GET', '/days/1');
|
||||
$response->assertOk();
|
||||
$response->assertExactJson([Days::mon()]);
|
||||
$response = $this->call('GET', '/days/2');
|
||||
$response->assertOk();
|
||||
$response->assertExactJson([Days::tue()]);
|
||||
}
|
||||
|
||||
public function testRoutesCivilities()
|
||||
{
|
||||
$response = $this->call('GET', '/civilities/mme');
|
||||
$response->assertOk();
|
||||
$response->assertExactJson([ContactFormCivility::mme()]);
|
||||
}
|
||||
|
||||
public function testRoutesWithEnumIntString()
|
||||
{
|
||||
$response = $this->call('GET', '/force/1');
|
||||
$response->assertOk();
|
||||
$response->assertExactJson([ForceStringsFromInteger::valueB()]);
|
||||
}
|
||||
|
||||
public function testRules()
|
||||
{
|
||||
$rule = new EnumIsValidRule(Days::class);
|
||||
$this->assertTrue($rule->passes('day', Days::mon()->value));
|
||||
$this->assertFalse($rule->passes('day', 9999));
|
||||
$this->assertFalse($rule->passes('day', Days::mon()));
|
||||
}
|
||||
}
|
||||
|
|
@ -2,18 +2,22 @@
|
|||
|
||||
namespace Kwaadpepper\Enum\Tests\Enums;
|
||||
|
||||
use BadMethodCallException;
|
||||
use Kwaadpepper\Enum\BaseEnum;
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* @method static self m()
|
||||
* @method static self mme()
|
||||
* @method static self mlle()
|
||||
*/
|
||||
final class ContactFormCivility extends BaseEnum
|
||||
final class ContactFormCivility extends BaseEnumRoutable
|
||||
{
|
||||
/**
|
||||
* Output the value as a string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string) $this->label;
|
||||
return (string)$this->label;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Kwaadpepper\Enum\Tests\Enums;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnum;
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* @method static self none()
|
||||
|
|
@ -14,22 +14,32 @@ use Kwaadpepper\Enum\BaseEnum;
|
|||
* @method static self sat()
|
||||
* @method static self sun()
|
||||
*/
|
||||
final class Days extends BaseEnum
|
||||
final class Days extends BaseEnumRoutable
|
||||
{
|
||||
/**
|
||||
* All values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'none' => 0,
|
||||
'mon' => 1,
|
||||
'tue' => 1 << 1,
|
||||
'wed' => 1 << 2,
|
||||
'thu' => 1 << 3,
|
||||
'fri' => 1 << 4,
|
||||
'sat' => 1 << 5,
|
||||
'sun' => 1 << 6,
|
||||
'none' => 1,
|
||||
'mon' => 1 << 1,
|
||||
'tue' => 1 << 2,
|
||||
'wed' => 1 << 3,
|
||||
'thu' => 1 << 4,
|
||||
'fri' => 1 << 5,
|
||||
'sat' => 1 << 6,
|
||||
'sun' => 1 << 7,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* All labels
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
|
|
@ -44,15 +54,20 @@ final class Days extends BaseEnum
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the value as a string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string) $this->label;
|
||||
return (string)$this->label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if days contain this day
|
||||
*
|
||||
* @param int $days
|
||||
* @param integer $days
|
||||
* @return boolean
|
||||
*/
|
||||
public function has(int $days)
|
||||
|
|
|
|||
27
tests/Enums/DuplicatedLabels.php
Normal file
27
tests/Enums/DuplicatedLabels.php
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Kwaadpepper\Enum\Tests\Enums;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* @method static self one()
|
||||
* @method static self two()
|
||||
* @method static self three()
|
||||
*/
|
||||
final class DuplicatedLabels extends BaseEnumRoutable
|
||||
{
|
||||
/**
|
||||
* All labels
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'one' => 'one',
|
||||
'two' => 'two',
|
||||
'three' => 'two'
|
||||
];
|
||||
}
|
||||
}
|
||||
27
tests/Enums/DuplicatedValues.php
Normal file
27
tests/Enums/DuplicatedValues.php
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Kwaadpepper\Enum\Tests\Enums;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* @method static self one()
|
||||
* @method static self two()
|
||||
* @method static self three()
|
||||
*/
|
||||
final class DuplicatedValues extends BaseEnumRoutable
|
||||
{
|
||||
/**
|
||||
* All values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'one' => '0',
|
||||
'two' => '1',
|
||||
'three' => '1'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -2,15 +2,20 @@
|
|||
|
||||
namespace Kwaadpepper\Enum\Tests\Enums;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnum;
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* @method static self valueA()
|
||||
* @method static self valueB()
|
||||
* @method static self valueC()
|
||||
*/
|
||||
final class ForceStringsFromInteger extends BaseEnum
|
||||
final class ForceStringsFromInteger extends BaseEnumRoutable
|
||||
{
|
||||
/**
|
||||
* All values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
|
|
|
|||
27
tests/Enums/NotRoutableEnum.php
Normal file
27
tests/Enums/NotRoutableEnum.php
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Kwaadpepper\Enum\Tests\Enums;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnum;
|
||||
|
||||
/**
|
||||
* @method static self one()
|
||||
* @method static self two()
|
||||
* @method static self three()
|
||||
*/
|
||||
final class NotRoutableEnum extends BaseEnum
|
||||
{
|
||||
/**
|
||||
* All values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'one' => '0',
|
||||
'two' => '1',
|
||||
'three' => '2'
|
||||
];
|
||||
}
|
||||
}
|
||||
48
tests/Models/Alarm.php
Normal file
48
tests/Models/Alarm.php
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace Kwaadpepper\Enum\Tests\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Kwaadpepper\Enum\Traits\CastsEnums;
|
||||
|
||||
class Alarm extends Model
|
||||
{
|
||||
use CastsEnums;
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $timestamps = false;
|
||||
|
||||
/**
|
||||
* The primary key for the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'day';
|
||||
|
||||
/**
|
||||
* The "type" of the primary key ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $keyType = 'int';
|
||||
|
||||
/**
|
||||
* Indicates if the IDs are auto-incrementing.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $incrementing = false;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $fillable = [
|
||||
'day'
|
||||
];
|
||||
}
|
||||
67
tests/Models/Journal.php
Normal file
67
tests/Models/Journal.php
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
namespace Kwaadpepper\Enum\Tests\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Kwaadpepper\Enum\Tests\Enums\Days;
|
||||
use Kwaadpepper\Enum\Traits\CastsEnums;
|
||||
|
||||
class Journal extends Model
|
||||
{
|
||||
use CastsEnums;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $timestamps = false;
|
||||
|
||||
/**
|
||||
* The primary key for the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'day';
|
||||
|
||||
/**
|
||||
* The "type" of the primary key ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $keyType = 'int';
|
||||
|
||||
/**
|
||||
* Indicates if the IDs are auto-incrementing.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $incrementing = false;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $fillable = [
|
||||
'day'
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $casts = [
|
||||
'day' => 'int'
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be to enum.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $enumCasts = [
|
||||
'day' => Days::class
|
||||
];
|
||||
}
|
||||
58
tests/Models/Report.php
Normal file
58
tests/Models/Report.php
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace Kwaadpepper\Enum\Tests\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Kwaadpepper\Enum\Tests\Enums\Days;
|
||||
use Kwaadpepper\Enum\Traits\CastsEnums;
|
||||
|
||||
class Report extends Model
|
||||
{
|
||||
use CastsEnums;
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $timestamps = false;
|
||||
|
||||
/**
|
||||
* The primary key for the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'day';
|
||||
|
||||
/**
|
||||
* The "type" of the primary key ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $keyType = 'int';
|
||||
|
||||
/**
|
||||
* Indicates if the IDs are auto-incrementing.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $incrementing = false;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $fillable = [
|
||||
'day'
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be to enum.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $enumCasts = [
|
||||
'day' => Days::class
|
||||
];
|
||||
}
|
||||
32
tests/Requests/PassDayRequest.php
Normal file
32
tests/Requests/PassDayRequest.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Kwaadpepper\Enum\Rules\EnumIsValidRule;
|
||||
use Kwaadpepper\Enum\Tests\Enums\Days;
|
||||
|
||||
class PassDayRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'day' => ['required', new EnumIsValidRule(Days::class)],
|
||||
];
|
||||
}
|
||||
}
|
||||
40
tests/TestCase.php
Normal file
40
tests/TestCase.php
Normal 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();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue