Add backed enum support and typed arrays

This commit is contained in:
root 2023-08-04 21:23:36 +02:00
parent 00eac092d0
commit 54965b401d
4 changed files with 82 additions and 7 deletions

View File

@ -32,16 +32,23 @@ $ticket->start = 1471111;
$ticket->end = 1474567;
$ticket->user = $user;
$ticket->grant = $grant;
$ticket->groups[] = new User();
$ticket->groups[0]->id = 'baaaa';
$ticket->groups[0]->cert = 'Cat';
$database->save($service);
$database->save($user);
$database->save($grant);
$database->save($ticket);
$database->save($ticket->groups[0]);
echo('<b>Start Time in microseconds: </b>' . microtime(true) . '<br><hr /><br>');
echo('<b>Serialize Ticket with Nesting on</b><br><code>');
echo($ticket->Serialize(true));
echo('</code><br><br><b>Deserialize Ticket with Nesting on (vardump)</b><br><code><');
echo($ticket->Serialize(true, false, $database));
echo('</code><br><br><b>Deserialize Ticket with Nesting on (vardump)</b><br><code>');
echo(var_dump(Ticket::Deserialize($ticket->Serialize(true), true)));
echo('</code><br><br><b>Re-Serialize Deserialized Ticket with Nesting on</b><br><code>');
echo(Ticket::Deserialize($ticket->Serialize(true), true))->Serialize(true);
@ -49,8 +56,8 @@ echo('</code><br><hr /><br><b>End Time in microseconds: </b>' . microtime(true))
echo('<br><hr><hr><br><b>Start Time in microseconds: </b>' . microtime(true) . '<br><hr /><br>');
echo('<b>Serialize Ticket with Nesting off</b><br><code>');
echo($ticket->Serialize(false));
echo('</code><br><br><b>Deserialize Ticket with Nesting off (vardump)</b><br><code><');
echo($ticket->Serialize(false, false, $database));
echo('</code><br><br><b>Deserialize Ticket with Nesting off (vardump)</b><br><code>');
echo(var_dump(Ticket::Deserialize($ticket->Serialize(false), false, $database)));
echo('</code><br><br><b>Re-Serialize Deserialized Ticket with Nesting off</b><br><code>');
echo(Ticket::Deserialize($ticket->Serialize(false), false, $database))->Serialize(false);

View File

@ -7,4 +7,8 @@ class Ticket extends BaseEntity {
public User $user;
public int $start;
public int $end;
/**
* @type SeriousJSON\ExampleEntity\User
*/
public array $groups = [];
}

View File

@ -34,7 +34,7 @@ class JsonDatabase implements IJsonUnflattener
throw new \Exception('JsonDatabase: Unable to create Directory for Path ' . $dirPath . '.');
}
private static function SanitizeIdentifier($identifier)
public static function SanitizeIdentifier($identifier)
{
return trim(preg_replace( '/[^a-zA-Z0-9 ()\-\[\]]+/', '-', strtolower($identifier)));
}
@ -302,6 +302,40 @@ class JsonDatabase implements IJsonUnflattener
return $this->delete(get_class($obj), $obj->flatIdentifier());
}
/**
* List all objects by class
* @param string name of class to search for
* @return array of identifiers or empty array
*/
public function listAll(string $className, int $time = null): array
{
if ($className == null)
return [];
$objStoragePath = $this->getObjectPath($className, '-star-', $time);
// Replace -star- with catchall * so that it becomes path/to/*.json
// TODO: Do this better
$objStoragePath = str_replace('-star-', '*', $objStoragePath);
if (strlen($objStoragePath) > PHP_MAXPATHLEN)
return [];
$files = glob($objStoragePath);
// Call the function is_file on every element
// and filter those that aren't files aka directories out
$files = array_filter($files, 'is_file');
array_walk($files, function (&$value, $key) {
// Remove .json
$value = basename($value, JsonDatabase::$EXTENSION);
// Remove invalid chars
$value = JsonDatabase::SanitizeIdentifier($value);
});
return $files;
}
/**
* Restore a JsonSerializable from the Database by using it's Identifier reference.
* @param string $className the full class name with domain of the JsonSerializable property

View File

@ -37,6 +37,32 @@ abstract class JsonSerializable
return (new \ReflectionClass($typeName))->isSubclassOf(JsonSerializable::class);
}
/**
* Check if a given property extends BackedEnum
* @param string $property Property we should check against
* @return bool returns true if type/class of property extends BackedEnum
*/
private static function isPropertyBackedEnum(\ReflectionProperty $property)
{
if (!isset($property) || $property === null || !$property->hasType())
return false;
// Get builtin type or class of given property
$type = $property->getType();
// A built-in type is any type that is not a class, interface, or trait.
// Assume false on simple types, we can only check this on classes
if ($type->isBuiltin())
return false;
// String name of property type/class
$typeName = $type->getName();
// Create an reflection instance of the found class name
// and check if it is a subclass of parent class
return (new \ReflectionClass($typeName))->isSubclassOf(\BackedEnum::class);
}
/**
* Check if is strongly typed array of type JsonSerializable and return the type
* @param string $property Property we should check against
@ -241,7 +267,11 @@ abstract class JsonSerializable
else
{
try {
$classInstance->{$key} = $value;
// Try to handle backed enums, call method "from" on enum class
if (self::isPropertyBackedEnum($property))
$classInstance->{$key} = call_user_func(array($property->getType()->getName(), 'from'), $value);
else
$classInstance->{$key} = $value;
}
catch (\TypeError $e) {
// Assignment might fail due to incompatible data types or other reasons