Skip to content

Instantly share code, notes, and snippets.

@nathanbarrett
Last active November 28, 2023 22:57
Show Gist options
  • Save nathanbarrett/697f3c1bee740ba869b4a5a5efc0f4db to your computer and use it in GitHub Desktop.
Save nathanbarrett/697f3c1bee740ba869b4a5a5efc0f4db to your computer and use it in GitHub Desktop.
A base enum simulator for PHP versions below 8.1
<?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