Last active
November 28, 2023 22:57
-
-
Save nathanbarrett/697f3c1bee740ba869b4a5a5efc0f4db to your computer and use it in GitHub Desktop.
A base enum simulator for PHP versions below 8.1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php declare(strict_types=1); | |
namespace App\Enums; | |
use Illuminate\Contracts\Database\Eloquent\CastsAttributes; | |
/** | |
* Simulator for PHP 8 enums to make it easy to upgrade to actual enums when they become available. | |
* The only thing you need to check after upgrading the child class to an enum is | |
* the equality check in the equals method in the implementation. Replace with an actual equality check | |
* | |
* You can also cast this class in your models like so: | |
* protected $casts = [ | |
* 'some_attribute' => ChildOfBaseEnum::class, | |
* ]; | |
*/ | |
abstract class BaseEnum implements CastsAttributes | |
{ | |
protected $_value; | |
/** | |
* Do not instantiate this class directly, use the static methods from or tryFrom instead | |
* Setting default value to null to make it work with Casting | |
* @param mixed $value | |
*/ | |
public function __construct($value = null) | |
{ | |
$this->_value = $value; | |
} | |
public function __toString(): string | |
{ | |
return (string)$this->_value; | |
} | |
public function __get($name) | |
{ | |
if ($name === 'value') { | |
return $this->_value; | |
} | |
throw new \InvalidArgumentException("Property {$name} does not exist"); | |
} | |
/** | |
* Because equality checks between two instantiated fake enums will always return false, | |
* even if they have the same value | |
* When converting the child class back to enum replace this method with an actual equality check | |
*/ | |
public function equals($other): bool | |
{ | |
if ($other instanceof static) { | |
return $this->_value === $other->value; | |
} | |
return $other && $this->_value === $other; | |
} | |
public static function cases(): array | |
{ | |
$cases = []; | |
foreach (static::getValues() as $value) { | |
$cases[] = new static($value); | |
} | |
return $cases; | |
} | |
public static function from($value): self | |
{ | |
$values = static::getValues(); | |
if (!in_array($value, $values)) { | |
throw new \ValueError("Value {$value} is not a valid " . static::class); | |
} | |
return new static($value); | |
} | |
public static function tryFrom($value): ?self | |
{ | |
$values = static::getValues(); | |
if (!in_array($value, $values)) { | |
return null; | |
} | |
return new static($value); | |
} | |
private static function getConstants(): array | |
{ | |
return (new \ReflectionClass(static::class))->getConstants(); | |
} | |
private static function getValues(): array | |
{ | |
return array_values(static::getConstants()); | |
} | |
/** | |
* Cast the given value. | |
* | |
* @param \Illuminate\Database\Eloquent\Model $model | |
* @param string $key | |
* @param mixed $value | |
* @param array $attributes | |
* @return static|null | |
*/ | |
public function get($model, $key, $value, $attributes) | |
{ | |
return static::tryFrom($value); | |
} | |
/** | |
* Prepare the given value for storage. | |
* | |
* @param \Illuminate\Database\Eloquent\Model $model | |
* @param string $key | |
* @param array $value | |
* @param array $attributes | |
* @return mixed | |
*/ | |
public function set($model, $key, $value, $attributes) | |
{ | |
if ($value instanceof static) { | |
return $value->value; | |
} | |
return $value; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment