mirror of
https://github.com/archtechx/airwire.git
synced 2025-12-12 18:54:03 +00:00
initial
This commit is contained in:
commit
d26fa93f1e
35 changed files with 2388 additions and 0 deletions
191
src/Airwire.php
Normal file
191
src/Airwire.php
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
<?php
|
||||
|
||||
namespace Airwire;
|
||||
|
||||
use Airwire\Attributes\Encode;
|
||||
use Airwire\Testing\RequestBuilder;
|
||||
use Exception;
|
||||
use ReflectionNamedType;
|
||||
use ReflectionParameter;
|
||||
use ReflectionProperty;
|
||||
use ReflectionType;
|
||||
use ReflectionUnionType;
|
||||
|
||||
class Airwire
|
||||
{
|
||||
public static array $components = [];
|
||||
public static array $typeTransformers = [];
|
||||
|
||||
public static function component(string $alias, string $class): void
|
||||
{
|
||||
static::$components[$alias] = $class;
|
||||
}
|
||||
|
||||
public static function hasComponent(string $alias): bool
|
||||
{
|
||||
return isset(static::$components[$alias]);
|
||||
}
|
||||
|
||||
public static function typeTransformer(string $type, callable $decode, callable $encode): void
|
||||
{
|
||||
static::$typeTransformers[$type] = compact('decode', 'encode');
|
||||
}
|
||||
|
||||
public static function getDefaultDecoder(): callable
|
||||
{
|
||||
return fn (array $data, string $class) => new $class($data);
|
||||
}
|
||||
|
||||
public static function getDefaultEncoder(): callable
|
||||
{
|
||||
return fn ($object) => json_decode(json_encode($object), true);
|
||||
}
|
||||
|
||||
public static function decode(ReflectionProperty|ReflectionParameter|array $property, mixed $value): mixed
|
||||
{
|
||||
if ($value === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (is_array($property)) {
|
||||
$property = new ReflectionProperty(...$property);
|
||||
}
|
||||
|
||||
if ($property->getType() instanceof ReflectionUnionType) {
|
||||
$types = $property->getType()->getTypes();
|
||||
} else {
|
||||
$types = [$property->getType()];
|
||||
}
|
||||
|
||||
foreach ($types as $type) {
|
||||
// No type = no transformer
|
||||
if ($type === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($type->isBuiltin() && gettype($value) === $type->getName()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$class = $type->getName();
|
||||
|
||||
$decoder = static::findDecoder($class);
|
||||
|
||||
if ($decoder) {
|
||||
return $decoder($value, $class);
|
||||
}
|
||||
}
|
||||
|
||||
// No class was found
|
||||
if (! isset($class)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
return static::getDefaultDecoder()($value, $class);
|
||||
}
|
||||
|
||||
public static function encode(ReflectionProperty|ReflectionParameter|ReflectionNamedType|ReflectionUnionType|array $property, mixed $value): mixed
|
||||
{
|
||||
if ($value === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (is_array($property)) {
|
||||
$property = new ReflectionProperty(...$property);
|
||||
}
|
||||
|
||||
if (($property instanceof ReflectionProperty || $property instanceof ReflectionParameter) && count($encodeAttributes = $property->getAttributes(Encode::class))) {
|
||||
return $encodeAttributes[0]->newInstance()->encode($value);
|
||||
}
|
||||
|
||||
if ($property instanceof ReflectionType) {
|
||||
$type = $property;
|
||||
} else {
|
||||
$type = $property->getType();
|
||||
}
|
||||
|
||||
if ($type instanceof ReflectionUnionType) {
|
||||
$types = $type->getTypes();
|
||||
} else {
|
||||
$types = [$type];
|
||||
}
|
||||
|
||||
foreach ($types as $type) {
|
||||
// No type = no transformer
|
||||
if ($type === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($type->isBuiltin() && gettype($value) === $type->getName()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$class = $type->getName();
|
||||
|
||||
$encoder = static::findEncoder($class);
|
||||
|
||||
if ($encoder) {
|
||||
return $encoder($value, $class);
|
||||
}
|
||||
}
|
||||
|
||||
return static::getDefaultEncoder()($value);
|
||||
}
|
||||
|
||||
public static function findDecoder(string $class): callable|null
|
||||
{
|
||||
if (class_exists($class)) {
|
||||
return static::getTransformer($class)['decode'] ?? null;
|
||||
}
|
||||
|
||||
return match ($class) {
|
||||
'int' => fn ($val) => (int) $val,
|
||||
'string' => fn ($val) => (string) $val,
|
||||
'float' => fn ($val) => (float) $val,
|
||||
'bool' => fn ($val) => (bool) $val,
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
|
||||
public static function findEncoder(string $class): callable|null
|
||||
{
|
||||
if (class_exists($class)) {
|
||||
return static::getTransformer($class)['encode'] ?? null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function getTransformer(string $class): array|null
|
||||
{
|
||||
$transformer = null;
|
||||
|
||||
while (! $transformer) {
|
||||
if (isset(static::$typeTransformers[$class])) {
|
||||
$transformer = static::$typeTransformers[$class];
|
||||
}
|
||||
|
||||
if (! $class = get_parent_class($class)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $transformer;
|
||||
}
|
||||
|
||||
public static function test(string $component): RequestBuilder
|
||||
{
|
||||
if (isset(static::$components[$component])) {
|
||||
return new RequestBuilder($component);
|
||||
} else if (in_array($component, static::$components)) {
|
||||
return new RequestBuilder(array_search($component, static::$components));
|
||||
}
|
||||
|
||||
throw new Exception("Component {$component} not found.");
|
||||
}
|
||||
|
||||
public static function routes()
|
||||
{
|
||||
require __DIR__ . '/../routes/airwire.php';
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue