Browse Source

more work on schema generation

dev
Cerys 3 weeks ago
parent
commit
0ee81236e3
  1. 30
      src/Attributes/SchemaDocumentField.php
  2. 171
      src/SchemaBuilder/SchemaBuilder.php

30
src/Attributes/SchemaDocumentField.php

@ -12,26 +12,34 @@ class SchemaDocumentField extends Attribute
{ {
public string $Name; public string $Name;
public SchemaFieldExistence $Existence; public ?SchemaFieldExistence $Existence;
public string $Comment; public ?string $Comment;
public array $ValidSchemas; public ?array $ValidSchemas;
public int $MaxSize; public int $MaxSize = PHP_INT_MIN;
public string $MimeType; public ?string $MimeType;
public ?SchemaDocumentField $Child;
public ?array $Children;
public function __construct( public function __construct(
string $Name, string $Name,
SchemaFieldExistence $Existence = SchemaFieldExistence::MAY, ?SchemaFieldExistence $Existence = null,
string $Comment = "", ?string $Comment = null,
array $ValidSchemas = [], ?array $ValidSchemas = null,
int $MaxSize = 0, int $MaxSize = PHP_INT_MIN,
string $MimeType = "", ?string $MimeType = null,
SchemaDocumentField $Child = null ?SchemaDocumentField $Child = null,
?array $Children = null,
) )
{ {
$this->Name = $Name;
$this->Existence = $Existence; $this->Existence = $Existence;
$this->Comment = $Comment; $this->Comment = $Comment;
$this->ValidSchemas = $ValidSchemas; $this->ValidSchemas = $ValidSchemas;
$this->MaxSize = $MaxSize;
$this->MimeType = $MimeType; $this->MimeType = $MimeType;
$this->Child = $Child;
$this->Children = $Children;
parent::__construct(new Name("SchemaDocumentField"), [], []); parent::__construct(new Name("SchemaDocumentField"), [], []);
} }

171
src/SchemaBuilder/SchemaBuilder.php

@ -10,8 +10,13 @@ use JetBrains\PhpStorm\NoReturn;
use PHPUnit\Util\Exception; use PHPUnit\Util\Exception;
use ReflectionClass; use ReflectionClass;
class SchemaBuilder class SchemaBuilder
{ {
private const CLASS_NAME_REGEX = '/^(([\\\\]*)?[a-zA-Z_][a-zA-Z0-9_]*)(([\\\\]*[a-zA-Z0-9_]*)*)$/';
private const URL_REGEX = '/^https?:\/\/[^\s$.?#].[^\s]*$/i';
/** /**
* Goes through the Attribute classes and makes a list of all the Properties they have. * Goes through the Attribute classes and makes a list of all the Properties they have.
* This is so if a user adds another variable to the Attribute constructor, it won't appear in the final Schema. * This is so if a user adds another variable to the Attribute constructor, it won't appear in the final Schema.
@ -60,94 +65,128 @@ class SchemaBuilder
return strtolower(preg_replace('/(?<!^)[A-Z]/', '_$0', $input)); return strtolower(preg_replace('/(?<!^)[A-Z]/', '_$0', $input));
} }
private static function ProcessSchemaPropertyArguments($arguments): array
/**
* @throws SchemaDocumentFieldNameUnsetException
*/
public static function GenerateSchema(string $targetSchemaClassName): array
{ {
$schema = [];
$validKeys = self::GetValidKeys();
$reflection = new ReflectionClass(new $targetSchemaClassName());
/*
* Schema "meta-data" from here...
*/
foreach($reflection->getAttributes()[0]->getArguments() as $key=>$value)
if(self::VerifyField($key, $value, $validKeys[0]))
$schema["@" . self::PascalCaseToSnakeCase(input: $key)] = $value;
/*
* Property handling from here...
*/
foreach ($reflection->getProperties() as $property)
{
$classNameRegex = '/^([\\]*)?[a-zA-Z_][a-zA-Z0-9_]*)(([\\]*[a-zA-Z0-9_]*)*)$/';
$urlRegex = '/^https?:\/\/[^\s$.?#].[^\s]*$/i';
$propertyName = ""; $propertyName = "";
$propertySchema = []; $propertySchema = [];
foreach($arguments as $key=>$value)
foreach ($property->getAttributes() as $attribute)
{
if($attribute->getName() != SchemaDocumentField::class)
continue;
foreach($attribute->getArguments() as $key=>$value)
{ {
if($key == "Name") switch($key)
{ {
case "Name":
$propertyName = $value; $propertyName = $value;
} break;
elseif($key == "Child") case "Existence":
{ if($value == null) continue;
$propertySchema["#"] = [ $propertySchema["@existence"] = $value;
"@comment" => $value->Comment, break;
"@valid_schemas" => $value->ValidSchemas, case "Comment":
]; if($value == null) continue;
$propertySchema["@comment"] = $value;
break;
case "ValidSchemas":
if($value == null) continue;
$propertySchema["@valid_schemas"] = []; $propertySchema["@valid_schemas"] = [];
foreach($value as $validSchema) foreach($value as $validSchema)
{ {
if (preg_match($classNameRegex, $validSchema)) if (preg_match(self::CLASS_NAME_REGEX, $validSchema))
$propertySchema["@valid_schemas"][] = URLHandling::GetURLForSchema($validSchema); $propertySchema["@valid_schemas"][] = URLHandling::GetURLForSchema($validSchema);
elseif (preg_match($urlRegex, $validSchema)) elseif (preg_match(self::URL_REGEX, $validSchema))
$propertySchema["@valid_schemas"][] = $validSchema; $propertySchema["@valid_schemas"][] = $validSchema;
else else
$propertySchema["@valid_schemas"][] = "test123"; throw new \Exception("Invalid schema property: " . $validSchema);
} }
} break;
elseif($key == "Existance") case "MaxSize":
{ if($value == PHP_INT_MIN) continue;
$propertySchema["#"] = $value->value; $propertySchema["@max_size"] = $value;
} break;
elseif($key == "ValidSchemas") case "MimeType":
{ if($value == null) continue;
$propertySchema["@valid_schemas"] = []; $propertySchema["@mime_type"] = $value;
foreach($value as $validSchema) break;
case "Child":
if($value == null) continue;
$temp = json_decode(json_encode($value), true);
unset($temp['nodeType']);
unset($temp['attributes']);
unset($temp['name']);
unset($temp['args']);
$propertySchema["#"] = self::ProcessSchemaPropertyArguments($temp)[1];
break;
case "Children":
if($value == null) continue;
foreach($value as $child)
{
$temp = json_decode(json_encode($child), true);
unset($temp['nodeType']);
unset($temp['attributes']);
unset($temp['name']);
unset($temp['args']);
$propertySchema[$child->Name] = self::ProcessSchemaPropertyArguments($temp)[1];
}
break;
default:
throw new \Exception("unknown property: " . $key);
}
}
return [$propertyName, $propertySchema];
}
private static function ProcessSchemaProperties($reflection): array
{ {
if (preg_match($classNameRegex, $validSchema)) $schema = [];
$propertySchema["@valid_schemas"][] = URLHandling::GetURLForSchema($validSchema); foreach ($reflection->getProperties() as $property)
elseif (preg_match($urlRegex, $validSchema))
$propertySchema["@valid_schemas"][] = $validSchema;
else
$propertySchema["@valid_schemas"][] = "test123";
}
}
elseif(self::VerifyField($key, $value, $validKeys[1]))
{ {
$propertySchema["@" . self::PascalCaseToSnakeCase(input: $key)] = $value; $targetAttribute = null;
} foreach ($property->getAttributes() as $attribute)
} if($attribute->getName() == SchemaDocumentField::class)
} $targetAttribute = $attribute;
if($targetAttribute == null)
throw new \Exception("required attribute does not exist");
$temp = self::ProcessSchemaPropertyArguments($targetAttribute->getArguments());
$propertyName = $temp[0];
$propertySchema = $temp[1];
if($propertyName == "") if($propertyName == "")
throw new SchemaDocumentFieldNameUnsetException(); throw new SchemaDocumentFieldNameUnsetException();
$schema["$propertyName"] = $propertySchema; $schema["$propertyName"] = $propertySchema;
} }
return $schema;
}
/**
* @throws SchemaDocumentFieldNameUnsetException
*/
private static function GenerateSchemaReflectionObject(ReflectionClass $reflection): array
{
$schema = [];
/*
* Schema "meta-data" from here...
*/
foreach($reflection->getAttributes()[0]->getArguments() as $key=>$value)
if(self::VerifyField($key, $value, self::GetValidKeys()[0]))
if($key != "Name")
$schema["@" . self::PascalCaseToSnakeCase(input: $key)] = $value;
/*
* Property handling from here...
*/
foreach(self::ProcessSchemaProperties($reflection) as $key=>$value)
$schema[$key] = $value;
return $schema; return $schema;
} }
public static function GenerateSchema(string $targetSchemaClassName): array
{
$reflection = new ReflectionClass(new $targetSchemaClassName());
return self::GenerateSchemaReflectionObject($reflection);
}
/** /**
* Generates the Schema using the SchemaBuilder::GenerateSchema() function, sets the http header to application/json, echos the schema as JSON, then dies. * Generates the Schema using the SchemaBuilder::GenerateSchema() function, sets the http header to application/json, echos the schema as JSON, then dies.
* *

Loading…
Cancel
Save