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'; } }