Cerys
6 months ago
10 changed files with 2089 additions and 0 deletions
@ -0,0 +1,4 @@ |
|||||
|
.idea/ |
||||
|
composer.phar |
||||
|
vendor/ |
||||
|
*.cache |
@ -0,0 +1,15 @@ |
|||||
|
<?php |
||||
|
|
||||
|
|
||||
|
namespace Darksparrow\Deegraph\examples\SchemaBuilder; |
||||
|
|
||||
|
require_once __DIR__ . "/../../../vendor/autoload.php"; |
||||
|
require_once __DIR__ . "/../../../Examples/SchemaBuilder/Schemas/Message.php"; |
||||
|
|
||||
|
use Darksparrow\Deegraph\Examples\SchemaBuilder\Schemas\Message; |
||||
|
use Darksparrow\DeegraphPHP\SchemaBuilder\SchemaBuilder; |
||||
|
|
||||
|
$example = new Message(); |
||||
|
$result = SchemaBuilder::GenerateSchema($example); |
||||
|
|
||||
|
echo json_encode($result, JSON_PRETTY_PRINT); |
@ -0,0 +1,68 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace Darksparrow\Deegraph\Examples\SchemaBuilder\Schemas; |
||||
|
require_once __DIR__ . "/../../../vendor/autoload.php"; |
||||
|
|
||||
|
use Darksparrow\DeegraphPHP\Enumerators\SchemaFieldExistence; |
||||
|
use Darksparrow\DeegraphPHP\SchemaBuilder\Attributes\SchemaDocument; |
||||
|
use Darksparrow\DeegraphPHP\SchemaBuilder\Attributes\SchemaDocumentField; |
||||
|
|
||||
|
#[SchemaDocument( |
||||
|
Name: "Message", |
||||
|
MimeType: "message/rfc822", |
||||
|
)] |
||||
|
class Message |
||||
|
{ |
||||
|
#[SchemaDocumentField( |
||||
|
Name: "sender", |
||||
|
Existence: SchemaFieldExistence::SHOULD, |
||||
|
Comment: "The sender should be attached to a user object if known", |
||||
|
ValidSchemas: [ |
||||
|
"https://schemas.auxiliumsoftware.co.uk/v1/user.json" |
||||
|
], |
||||
|
)] |
||||
|
public string $Sender; |
||||
|
|
||||
|
#[SchemaDocumentField( |
||||
|
Name: "recipients", |
||||
|
Existence: SchemaFieldExistence::SHOULD, |
||||
|
Comment: "All direct recipients that are known should be attached", |
||||
|
ValidSchemas: [ |
||||
|
"https://schemas.auxiliumsoftware.co.uk/v1/collection.json" |
||||
|
], |
||||
|
MaxSize: 0, |
||||
|
Child: [ |
||||
|
"@comment"=>"All direct recipients should be addressed", |
||||
|
"@valid_schemas"=>[ |
||||
|
"https://schemas.auxiliumsoftware.co.uk/v1/user.json" |
||||
|
] |
||||
|
] |
||||
|
)] |
||||
|
public string $Recipients; |
||||
|
|
||||
|
#[SchemaDocumentField( |
||||
|
Name: "indirect_recipients", |
||||
|
Existence: SchemaFieldExistence::SHOULD, |
||||
|
Comment: "All cc'd recipients that are known should be attached", |
||||
|
ValidSchemas: [ |
||||
|
"https://schemas.auxiliumsoftware.co.uk/v1/collection.json" |
||||
|
], |
||||
|
MaxSize: 0, |
||||
|
Child: [ |
||||
|
"@comment"=>"All direct recipients should be addressed", |
||||
|
"@valid_schemas"=>[ |
||||
|
"https://schemas.auxiliumsoftware.co.uk/v1/user.json" |
||||
|
] |
||||
|
] |
||||
|
)] |
||||
|
public string $IndirectRecipients; |
||||
|
|
||||
|
#[SchemaDocumentField( |
||||
|
Name: "sent_at", |
||||
|
Existence: SchemaFieldExistence::SHOULD, |
||||
|
Comment: "The date the message was actually sent, if supplied MUST be in ISO 8601 format", |
||||
|
MaxSize: 64, |
||||
|
MimeType: "text/plain", |
||||
|
)] |
||||
|
public string $SentAt; |
||||
|
} |
@ -0,0 +1,32 @@ |
|||||
|
{ |
||||
|
"name": "darksparrow/auxilium-schema-builder", |
||||
|
"description": "Auxilium Schema Builder", |
||||
|
"type": "library", |
||||
|
"license": "MPL-2.0", |
||||
|
"authors": [ |
||||
|
{ |
||||
|
"name": "Cerys Lewis", |
||||
|
"email": "cerys@darksparrow.uk", |
||||
|
"homepage": "https://ceryslewis.dev", |
||||
|
"role": "Lead Developer" |
||||
|
} |
||||
|
], |
||||
|
"minimum-stability": "dev", |
||||
|
"support": { |
||||
|
"email": "cerys@darksparrow.uk" |
||||
|
}, |
||||
|
"autoload": { |
||||
|
"psr-4": { |
||||
|
"Darksparrow\\AuxiliumSchemaBuilder\\": "src/" |
||||
|
} |
||||
|
}, |
||||
|
"require": { |
||||
|
"php": ">=8.1", |
||||
|
"phpunit/phpunit": "^9.5" |
||||
|
}, |
||||
|
"require-dev": { |
||||
|
}, |
||||
|
"scripts": { |
||||
|
"test": "phpunit" |
||||
|
} |
||||
|
} |
File diff suppressed because it is too large
@ -0,0 +1,29 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace Darksparrow\DeegraphPHP\SchemaBuilder\Attributes; |
||||
|
|
||||
|
|
||||
|
use PhpParser\Node\Attribute; |
||||
|
use ReflectionClass; |
||||
|
use PhpParser\Node\Name; |
||||
|
|
||||
|
#[\Attribute] |
||||
|
class SchemaDocument extends Attribute |
||||
|
{ |
||||
|
public int $MaximumSize; |
||||
|
public string $Comment; |
||||
|
public string $MimeType; |
||||
|
|
||||
|
public function __construct( |
||||
|
string $Name, |
||||
|
int $MaximumSize = 0, |
||||
|
string $Comment = "", |
||||
|
string $MimeType = "" |
||||
|
) |
||||
|
{ |
||||
|
$this->MaximumSize = $MaximumSize; |
||||
|
$this->Comment = $Comment; |
||||
|
$this->MimeType = $MimeType; |
||||
|
parent::__construct(new Name("SchemaDocument"), [], []); |
||||
|
} |
||||
|
} |
@ -0,0 +1,37 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace Darksparrow\DeegraphPHP\SchemaBuilder\Attributes; |
||||
|
|
||||
|
|
||||
|
use Darksparrow\DeegraphPHP\Enumerators\SchemaFieldExistence; |
||||
|
use PhpParser\Node\Attribute; |
||||
|
use PhpParser\Node\Name; |
||||
|
|
||||
|
#[\Attribute] |
||||
|
class SchemaDocumentField extends Attribute |
||||
|
{ |
||||
|
public string $Name; |
||||
|
|
||||
|
public SchemaFieldExistence $Existence; |
||||
|
public string $Comment; |
||||
|
public array $ValidSchemas; |
||||
|
public int $MaxSize; |
||||
|
public string $MimeType; |
||||
|
|
||||
|
public function __construct( |
||||
|
string $Name, |
||||
|
SchemaFieldExistence $Existence = SchemaFieldExistence::MAY, |
||||
|
string $Comment = "", |
||||
|
array $ValidSchemas = [], |
||||
|
int $MaxSize = 0, |
||||
|
string $MimeType = "", |
||||
|
) |
||||
|
{ |
||||
|
$this->Existence = $Existence; |
||||
|
$this->Comment = $Comment; |
||||
|
$this->ValidSchemas = $ValidSchemas; |
||||
|
$this->MimeType = $MimeType; |
||||
|
parent::__construct(new Name("SchemaDocumentField"), [], []); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,10 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace Darksparrow\DeegraphPHP\Enumerators; |
||||
|
|
||||
|
enum SchemaFieldExistence: string |
||||
|
{ |
||||
|
case MUST = "MUST"; |
||||
|
case SHOULD = "SHOULD"; |
||||
|
case MAY = "MAY"; |
||||
|
} |
@ -0,0 +1,17 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace Darksparrow\DeegraphPHP\Exceptions; |
||||
|
|
||||
|
use Exception; |
||||
|
|
||||
|
class SchemaNameUnsetException extends Exception |
||||
|
{ |
||||
|
public function __construct( |
||||
|
string $message = "The Name field is required.", |
||||
|
int $code = 422 |
||||
|
) { |
||||
|
parent::__construct($message, $code); |
||||
|
$this->message = "$message"; |
||||
|
$this->code = $code; |
||||
|
} |
||||
|
} |
@ -0,0 +1,110 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace Darksparrow\DeegraphPHP\SchemaBuilder; |
||||
|
|
||||
|
use Darksparrow\DeegraphPHP\Exceptions\SchemaNameUnsetException; |
||||
|
use Darksparrow\DeegraphPHP\SchemaBuilder\Attributes\SchemaDocument; |
||||
|
use Darksparrow\DeegraphPHP\SchemaBuilder\Attributes\SchemaDocumentField; |
||||
|
use ReflectionClass; |
||||
|
|
||||
|
class SchemaBuilder |
||||
|
{ |
||||
|
/** |
||||
|
* 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. |
||||
|
* |
||||
|
* @return array[] |
||||
|
*/ |
||||
|
private static function GetValidKeys(): array |
||||
|
{ |
||||
|
$validDocumentAttributeNames = []; |
||||
|
$validPropertyAttributeNames = []; |
||||
|
|
||||
|
foreach((new ReflectionClass(new SchemaDocument("EMPTY")))->getProperties() as $temp) |
||||
|
$validDocumentAttributeNames[] = $temp->getName(); |
||||
|
foreach((new ReflectionClass(new SchemaDocumentField("EMPTY")))->getProperties() as $temp) |
||||
|
$validPropertyAttributeNames[] = $temp->getName(); |
||||
|
|
||||
|
return [$validDocumentAttributeNames, $validPropertyAttributeNames]; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Checks to see if a value is "okay" for a Schema. |
||||
|
* |
||||
|
* @param string $key |
||||
|
* @param mixed $value |
||||
|
* @param array $valids |
||||
|
* @return bool |
||||
|
*/ |
||||
|
private static function VerifyField(string $key, mixed $value, array $valids): bool |
||||
|
{ |
||||
|
if(!in_array(needle: $key, haystack: $valids)) |
||||
|
return false; |
||||
|
if($value == "") |
||||
|
return false; |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Just converts PascalCase to snake_case. |
||||
|
* |
||||
|
* @param string $input |
||||
|
* @return string |
||||
|
*/ |
||||
|
private static function PascalCaseToSnakeCase(string $input): string |
||||
|
{ |
||||
|
return strtolower(preg_replace('/(?<!^)[A-Z]/', '_$0', $input)); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* @throws SchemaNameUnsetException |
||||
|
*/ |
||||
|
public static function GenerateSchema(object $targetSchema): array |
||||
|
{ |
||||
|
$schema = []; |
||||
|
$validKeys = self::GetValidKeys(); |
||||
|
$reflection = new ReflectionClass($targetSchema); |
||||
|
|
||||
|
/* |
||||
|
* 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) |
||||
|
{ |
||||
|
$propertyName = ""; |
||||
|
$propertySchema = []; |
||||
|
|
||||
|
foreach ($property->getAttributes() as $attribute) |
||||
|
{ |
||||
|
if($attribute->getName() != "Darksparrow\DeegraphPHP\SchemaBuilder\Attributes\SchemaDocumentField") |
||||
|
continue; |
||||
|
|
||||
|
foreach($attribute->getArguments() as $key=>$value) |
||||
|
{ |
||||
|
if($key == "Name") |
||||
|
{ |
||||
|
$propertyName = $value; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if(self::VerifyField($key, $value, $validKeys[1])) |
||||
|
$propertySchema["@" . self::PascalCaseToSnakeCase(input: $key)] = $value; |
||||
|
} |
||||
|
} |
||||
|
if($propertyName == "") |
||||
|
throw new SchemaNameUnsetException(); |
||||
|
|
||||
|
$schema["$propertyName"] = $propertySchema; |
||||
|
} |
||||
|
|
||||
|
return $schema; |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue