You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							147 lines
						
					
					
						
							5.2 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							147 lines
						
					
					
						
							5.2 KiB
						
					
					
				
								<?php
							 | 
						|
								
							 | 
						|
								namespace Darksparrow\AuxiliumSchemaBuilder\SchemaBuilder;
							 | 
						|
								
							 | 
						|
								use Darksparrow\AuxiliumSchemaBuilder\Exceptions\SchemaDocumentFieldNameUnsetException;
							 | 
						|
								use Darksparrow\AuxiliumSchemaBuilder\Attributes\SchemaDocument;
							 | 
						|
								use Darksparrow\AuxiliumSchemaBuilder\Attributes\SchemaDocumentField;
							 | 
						|
								use Darksparrow\AuxiliumSchemaBuilder\Utilities\URLHandling;
							 | 
						|
								use JetBrains\PhpStorm\NoReturn;
							 | 
						|
								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 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)
							 | 
						|
								        {
							 | 
						|
								            $propertyName = "";
							 | 
						|
								            $propertySchema = [];
							 | 
						|
								
							 | 
						|
								            foreach ($property->getAttributes() as $attribute)
							 | 
						|
								            {
							 | 
						|
								                if($attribute->getName() != SchemaDocumentField::class)
							 | 
						|
								                    continue;
							 | 
						|
								
							 | 
						|
								                foreach($attribute->getArguments() as $key=>$value)
							 | 
						|
								                {
							 | 
						|
								                    if($key == "Name")
							 | 
						|
								                    {
							 | 
						|
								                        $propertyName = $value;
							 | 
						|
								                    }
							 | 
						|
								                    elseif($key == "Child")
							 | 
						|
								                    {
							 | 
						|
								                        $propertySchema["#"] = [
							 | 
						|
								                            "@comment" => $value->Comment,
							 | 
						|
								                            "@valid_schemas" => $value->ValidSchemas,
							 | 
						|
								                        ];
							 | 
						|
								                    }
							 | 
						|
								                    elseif(self::VerifyField($key, $value, $validKeys[1]))
							 | 
						|
								                    {
							 | 
						|
								                        $propertySchema["@" . self::PascalCaseToSnakeCase(input: $key)] = $value;
							 | 
						|
								                    }
							 | 
						|
								                    elseif($key == "ValidSchemas")
							 | 
						|
								                    {
							 | 
						|
								                        $propertySchema["@valid_schemas"] = [];
							 | 
						|
								                        $classNameRegex = '/^(\\\\?[A-Z][a-zA-Z0-9_]*)((\\\\[A-Z][a-zA-Z0-9_]*)*)$/';
							 | 
						|
								                        $urlRegex = '/^https?:\/\/[^\s$.?#].[^\s]*$/i';
							 | 
						|
								                        foreach($value as $validSchema)
							 | 
						|
								                        {
							 | 
						|
								                            if (preg_match($classNameRegex, $validSchema))
							 | 
						|
								                                $propertySchema["@valid_schemas"][] = URLHandling::GetURLForSchema($validSchema);
							 | 
						|
								                            elseif (preg_match($urlRegex, $validSchema))
							 | 
						|
								                                $propertySchema["@valid_schemas"][] = $validSchema;
							 | 
						|
								                        }
							 | 
						|
								                    }
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								            if($propertyName == "")
							 | 
						|
								                throw new SchemaDocumentFieldNameUnsetException();
							 | 
						|
								
							 | 
						|
								            $schema["$propertyName"] = $propertySchema;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return $schema;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Generates the Schema using the SchemaBuilder::GenerateSchema() function, sets the http header to application/json, echos the schema as JSON, then dies.
							 | 
						|
								     *
							 | 
						|
								     * @param object $targetSchema The Schema class object to generate from.
							 | 
						|
								     * @return void
							 | 
						|
								     * @throws SchemaDocumentFieldNameUnsetException
							 | 
						|
								     */
							 | 
						|
								    #[NoReturn] public static function RenderSchema(string $targetSchemaClassName): void
							 | 
						|
								    {
							 | 
						|
								        $result = self::GenerateSchema($targetSchemaClassName);
							 | 
						|
								        header('Content-Type: application/json');
							 | 
						|
								        echo json_encode($result, JSON_PRETTY_PRINT);
							 | 
						|
								        die();
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 |