diff --git a/src/BaseEnum.php b/src/BaseEnum.php index fab9fe5..fbbfbcf 100644 --- a/src/BaseEnum.php +++ b/src/BaseEnum.php @@ -6,6 +6,7 @@ use BadMethodCallException; use JsonSerializable; use Kwaadpepper\Enum\Exceptions\DuplicateLabelsException; use Kwaadpepper\Enum\Exceptions\DuplicateValuesException; +use Kwaadpepper\Enum\Exceptions\EnumNotRoutableException; use Kwaadpepper\Enum\Exceptions\UnknownEnumProperty; use ReflectionClass; use TypeError; @@ -38,6 +39,25 @@ abstract class BaseEnum implements JsonSerializable // -- ENUM MAGIC METHODS -- + /** + * @param int|string $value + * @param string $label + * @throws TypeError If anything else than string or int is used for value. + * @throws EnumNotRoutableException If provided value are null + */ + public function __construct($value = null, string $label = null) + { + /** + * 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 int|string @@ -60,6 +80,7 @@ abstract class BaseEnum implements JsonSerializable * @return static * @throws TypeError If anything else than string or int is used. * @throws BadMethodCallException If a matching definition cannot be found. + * @throws EnumNotRoutableException If provided value are null */ // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUsed public static function __callStatic(string $name, array $arguments) @@ -166,13 +187,11 @@ abstract class BaseEnum implements JsonSerializable * @return static * @throws TypeError If anything else than string or int is used. * @throws BadMethodCallException If a matching definition cannot be found. + * @throws EnumNotRoutableException If provided value are null */ 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."); - } + self::assertValidValue($value); $definition = static::findDefinition($value); @@ -183,9 +202,10 @@ abstract class BaseEnum implements JsonSerializable ); } - $obj = new static(); - $obj->value = $definition->value; - $obj->label = $definition->label; + $obj = new static( + $definition->value, + $definition->label + ); return $obj; } @@ -281,4 +301,19 @@ abstract class BaseEnum implements JsonSerializable { return count($array) > count(array_unique($array)); } + + /** + * Assert value is valid + * + * @param mixed $value + * @return void + * @throws TypeError If anything else than string or int is used. + */ + private static function assertValidValue($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."); + } + } } diff --git a/src/BaseEnumRoutable.php b/src/BaseEnumRoutable.php index d618b10..4647261 100644 --- a/src/BaseEnumRoutable.php +++ b/src/BaseEnumRoutable.php @@ -4,7 +4,9 @@ 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. @@ -54,11 +56,11 @@ abstract class BaseEnumRoutable extends BaseEnum implements UrlRoutable $iValue = (is_numeric($value) and floatval(intval($value)) === floatval($value)) ? (int)$value : $value; return static::make($iValue); - } catch (BadMethodCallException $e) { + } catch (BadMethodCallException | EnumNotRoutableException | TypeError $e) { // try string value after that try { return static::make($value); - } catch (BadMethodCallException $e) { + } catch (BadMethodCallException | EnumNotRoutableException | TypeError $e) { // could not find a suitable value return null; } diff --git a/src/Exceptions/EnumNotRoutableException.php b/src/Exceptions/EnumNotRoutableException.php new file mode 100644 index 0000000..6c4c9c6 --- /dev/null +++ b/src/Exceptions/EnumNotRoutableException.php @@ -0,0 +1,16 @@ +enumCasts[$key]) ) { return $value; diff --git a/tests/BaseEnumRoutableTest.php b/tests/BaseEnumRoutableTest.php index 9d353ed..e5b0a34 100644 --- a/tests/BaseEnumRoutableTest.php +++ b/tests/BaseEnumRoutableTest.php @@ -5,6 +5,7 @@ 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; @@ -137,79 +138,80 @@ class BaseEnumRoutableTest extends TestCase return response()->json([$force]); })->middleware('bindings'); $router->get('/notroutable/{notroutable}', function (NotRoutableEnum $notroutable) { + dd($notroutable); return response()->json([$notroutable]); })->middleware('bindings'); } public function testRoutesDays() { - $response = $this->call('GET', sprintf('/days/%s', Days::none()->value)); + $response = $this->json('GET', sprintf('/days/%s', Days::none()->value)); $response->assertOk(); $response->assertExactJson([Days::none()]); - $response = $this->call('GET', sprintf('/days/%s', Days::mon()->value)); + $response = $this->json('GET', sprintf('/days/%s', Days::mon()->value)); $response->assertOk(); $response->assertExactJson([Days::mon()]); } public function testRoutesCivilities() { - $response = $this->call('GET', sprintf('/civilities/%s', ContactFormCivility::mme()->value)); + $response = $this->json('GET', sprintf('/civilities/%s', ContactFormCivility::mme()->value)); $response->assertOk(); $response->assertExactJson([ContactFormCivility::mme()]); } public function testRoutesWithEnumIntString() { - $response = $this->call('GET', sprintf('/force/%s', ForceStringsFromInteger::valueB()->value)); + $response = $this->json('GET', sprintf('/force/%s', ForceStringsFromInteger::valueB()->value)); $response->assertOk(); $response->assertExactJson([ForceStringsFromInteger::valueB()]); } public function testRoutesWithEnumNotFound() { - $response = $this->call('GET', '/force/6'); + $response = $this->json('GET', '/force/6'); $response->assertNotFound(); } public function testRoutesWithEnumAsPrimaryKey() { - $response = $this->call('GET', sprintf('/reports/%s', Days::none()->value)); + $response = $this->json('GET', sprintf('/reports/%s', Days::none()->value)); $response->assertOk(); - $response = $this->call('GET', sprintf('/reports/%s', Days::mon()->value)); + $response = $this->json('GET', sprintf('/reports/%s', Days::mon()->value)); $response->assertOk(); - $response = $this->call('GET', sprintf('/reports/%s', Days::tue()->value)); + $response = $this->json('GET', sprintf('/reports/%s', Days::tue()->value)); $response->assertOk(); - $response = $this->call('GET', sprintf('/reports/%s', Days::fri()->value)); + $response = $this->json('GET', sprintf('/reports/%s', Days::fri()->value)); $response->assertOk(); - $response = $this->call('GET', sprintf('/reports/%s', 9999)); + $response = $this->json('GET', sprintf('/reports/%s', 9999)); $response->assertNotFound(); } public function testRoutesWithEnumAsPrimaryKeyWithoutCastEnums() { - $response = $this->call('GET', sprintf('/alarms/%s', Days::none()->value)); + $response = $this->json('GET', sprintf('/alarms/%s', Days::none()->value)); $response->assertOk(); - $response = $this->call('GET', sprintf('/alarms/%s', Days::mon()->value)); + $response = $this->json('GET', sprintf('/alarms/%s', Days::mon()->value)); $response->assertOk(); - $response = $this->call('GET', sprintf('/alarms/%s', Days::tue()->value)); + $response = $this->json('GET', sprintf('/alarms/%s', Days::tue()->value)); $response->assertOk(); - $response = $this->call('GET', sprintf('/alarms/%s', Days::fri()->value)); + $response = $this->json('GET', sprintf('/alarms/%s', Days::fri()->value)); $response->assertOk(); - $response = $this->call('GET', sprintf('/alarms/%s', 9999)); + $response = $this->json('GET', sprintf('/alarms/%s', 9999)); $response->assertNotFound(); } public function testRoutesWithEnumAsPrimaryKeyWithoutCastEnumsAndCast() { - $response = $this->call('GET', sprintf('/journals/%s', Days::none()->value)); + $response = $this->json('GET', sprintf('/journals/%s', Days::none()->value)); $response->assertOk(); - $response = $this->call('GET', sprintf('/journals/%s', Days::mon()->value)); + $response = $this->json('GET', sprintf('/journals/%s', Days::mon()->value)); $response->assertOk(); - $response = $this->call('GET', sprintf('/journals/%s', Days::tue()->value)); + $response = $this->json('GET', sprintf('/journals/%s', Days::tue()->value)); $response->assertOk(); - $response = $this->call('GET', sprintf('/journals/%s', Days::fri()->value)); + $response = $this->json('GET', sprintf('/journals/%s', Days::fri()->value)); $response->assertOk(); - $response = $this->call('GET', sprintf('/journals/%s', 9999)); + $response = $this->json('GET', sprintf('/journals/%s', 9999)); $response->assertNotFound(); } @@ -223,7 +225,7 @@ class BaseEnumRoutableTest extends TestCase public function testRulesRequest() { - $response = $this->call('GET', sprintf('/day-validation?day=%s', Days::fri()->value)); + $response = $this->json('GET', sprintf('/day-validation?day=%s', Days::fri()->value)); $response->assertOk(); } @@ -242,6 +244,10 @@ class BaseEnumRoutableTest extends TestCase public function testNotRoutableEnum() { $response = $this->json('GET', sprintf('/notroutable/%s', '1')); - $response->assertOk(); + $response->assertStatus(500); + $this->assertEquals( + new EnumNotRoutableException(), + $response->exception + ); } }