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