Skip to content

Instantly share code, notes, and snippets.

@wovosoft
Last active July 4, 2023 09:58
Show Gist options
  • Save wovosoft/89811a6b5044cb48def4fd481c0c9775 to your computer and use it in GitHub Desktop.
Save wovosoft/89811a6b5044cb48def4fd481c0c9775 to your computer and use it in GitHub Desktop.
Laravel Command To convert Enums to Options
<?php
namespace Wovosoft\LaravelTypescript\Helpers;
use Composer\ClassMapGenerator\ClassMapGenerator;
use Doctrine\DBAL\Exception;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Collection;
use ReflectionMethod;
class ClassFinder
{
public static function in(string $directory): Collection
{
/**
* @link https://github.com/composer/class-map-generator
*/
return collect(array_keys(ClassMapGenerator::createMap($directory)));
}
}
<?php
/**
* Each Enum class should implement toOptions method which converts the enums to [text,value] pair
* bellow a trait is given for example
*/
namespace App\Console\Commands;
use App\Enums\EnumInterface;
use App\Helpers\ClassFinder;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
class EnumToOptions extends Command
{
private array $exports = [
'export type Option = {
text: string;
value: string;
};
'
];
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'publish:options-js';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Execute the console command.
* @throws \ReflectionException
*/
public function handle(): int
{
if (!File::isDirectory(resource_path("js/Options"))) {
File::makeDirectory(resource_path("js/Options"), 0777, true, true);
}
ClassFinder::in(app_path('Enums'))
->filter(fn($class) => !in_array($class, [EnumInterface::class]))
->each(function (string $enum) {
$reflection = new \ReflectionEnum($enum);
File::put(resource_path("js/Options/" . $reflection->getShortName() . ".ts"), $this->generateOptions($enum));
});
File::put(resource_path("js/Options/index.ts"), join("\n", $this->exports));
$this->info("Successfully Generated");
return 0;
}
/**
* @param class-string<EnumInterface|\BackedEnum|\UnitEnum> $class
* @return string
* @throws \ReflectionException
*/
private function generateOptions(string $class): string
{
$reflection = new \ReflectionEnum($class);
$name = $reflection->getShortName();
$options = json_encode($class::toOptions(), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
$method = str('get' . str($name)->ucfirst()->singular())->value();
$this->exports[] = 'export {' . $name . ', ' . $method . '} from "@/Options/' . $name . "\";";
return <<<ts
import {Option} from "@/Options";
export const $name: Option[] = $options;
export function $method(value: string): Option | null {
return $name.find((i: Option): boolean => i.value === value);
}
ts;
}
}
<?php
namespace App\Traits;
trait HasEnumExtensions
{
/**
* Access values by name using magic methods
*/
public static function __callStatic(string $name, array $arguments)
{
if (!method_exists(__CLASS__, $name)) {
try {
$options = static::flat();
if (key_exists($name, $options)) {
return $options[$name]?->value;
}
return null;
} catch (\Throwable $throwable) {
return null;
}
}
return null;
}
public static function toOptions(bool $asJson = false): array|bool|string
{
$records = array_map(fn($op) => [
"text" => str($op->name)->title()->replace("_", " "),
"value" => $op->value
], self::cases());
if ($asJson) {
return json_encode($records);
}
return $records;
}
public static function toArray(): array
{
return array_merge(...array_map(fn($op) => [$op->name => $op->value], self::cases()));
}
public static function toJson(int $flags = 0, int $depth = 512): bool|string
{
return json_encode(static::toArray(), $flags, $depth);
}
public static function values(): array
{
return array_column(self::cases(), 'value');
}
public static function keys(): array
{
return array_column(self::cases(), 'name');
}
private static function flat(): array
{
return array_merge(...array_map(fn($op) => [$op->name => $op], self::cases()));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment