diff --git a/src/SeriousJSON/IJsonUnflattener.php b/src/SeriousJSON/IJsonUnflattener.php index b92baf7..a95ac4c 100644 --- a/src/SeriousJSON/IJsonUnflattener.php +++ b/src/SeriousJSON/IJsonUnflattener.php @@ -12,4 +12,6 @@ interface IJsonUnflattener * @return JsonSerializable|null */ public function unflattenByID(string $className, $identifier) : JsonSerializable|null; + + public function updateIndex(IJsonIdentifiable $source, IJsonIdentifiable $dest, bool $delete); } \ No newline at end of file diff --git a/src/SeriousJSON/JsonDatabase.php b/src/SeriousJSON/JsonDatabase.php index a260c21..0395ad1 100644 --- a/src/SeriousJSON/JsonDatabase.php +++ b/src/SeriousJSON/JsonDatabase.php @@ -8,6 +8,7 @@ class JsonDatabase implements IJsonUnflattener private static $LIVE = 'live'; private static $ARCHIVE = 'archive'; private static $EXTENSION = '.json'; + private static $EXTENSION_INDEX = '.index'; private ?string $storagePath = null; private bool $nested = false; private bool $fullDomain = true; @@ -148,6 +149,87 @@ class JsonDatabase implements IJsonUnflattener return JsonSerializable::Deserialize($json, $this->nested, $this, $class); } + public function updateIndex(IJsonIdentifiable $source, IJsonIdentifiable $dest, bool $delete = false) + { + if ($source->flatIdentifier() == null || $dest->flatIdentifier() == null) + return; + + $destID = self::SanitizeIdentifier(strval($dest->flatIdentifier())); + $srcID = self::SanitizeIdentifier(strval($source->flatIdentifier())); + + if (empty($destID) || empty($srcID)) + return; + + $destPath = $this->getObjectPath(get_class($dest), $destID) . self::$EXTENSION_INDEX; + + if (strlen($destPath) > PHP_MAXPATHLEN) + throw new Exception('JsonDatabase: Specified Path ' . $destPath . ' is longer than allowed.'); + + $indexJson = []; + // Index exists + if (is_file($destPath)) + { + $indexJson = json_decode(file_get_contents($destPath), true); + + if ($indexJson == false) + $indexJson = []; + } + + // Check if entry exists + $subArray = []; + if (array_key_exists(get_class($source), $indexJson)) + $subArray = $indexJson[get_class($source)]; + + // Already indexed + if (in_array($srcID, $subArray) && !$delete) + return; + else if (in_array($srcID, $subArray) && $delete) + unset($subArray[array_search($srcID, $subArray)]); + else + $subArray[] = $srcID; + + $indexJson[get_class($source)] = $subArray; + + if (is_writable(dirname($destPath)) || mkdir(dirname($destPath), 0770, true)) + file_put_contents($destPath, json_encode($indexJson)); + else + throw new \Exception('JsonDatabase: Path ' . $destPath . ' is not writable.'); + } + + public function fromIndex(string $serClass, $serIdentifier, string $findClass): array + { + if ($serIdentifier == null) + return []; + + $serIdentifier = self::SanitizeIdentifier(strval($serIdentifier)); + if (empty($serIdentifier) || empty($serClass)) + return []; + + $serPath = $this->getObjectPath($serClass, $serIdentifier) . self::$EXTENSION_INDEX; + + if (strlen($serPath) > PHP_MAXPATHLEN) + throw new Exception('JsonDatabase: Specified Path ' . $destPath . ' is longer than allowed.'); + + $indexJson = []; + // Index exists + if (is_file($serPath)) + { + $indexJson = json_decode(file_get_contents($serPath), true); + + if ($indexJson == false) + return []; + + // TODO: Check if the referenced objects exist on disk + if (array_key_exists(get_class($findClass), $indexJson)) + return $indexJson[get_class($findClass)]; + else + return []; + } + else { + return []; + } + } + public function save(JsonSerializable $obj, ?string $name = null) { if ($name != null && !empty(trim($name))) { @@ -184,7 +266,7 @@ class JsonDatabase implements IJsonUnflattener if (is_writable(dirname($objPath)) || mkdir(dirname($objPath), 0770, true)) file_put_contents($objPath, $objJson); else - throw new \Exception('JsonDatabase: Path ' . $historyPath . ' is not writable.'); + throw new \Exception('JsonDatabase: Path ' . $objPath . ' is not writable.'); return $name; } diff --git a/src/SeriousJSON/JsonSerializable.php b/src/SeriousJSON/JsonSerializable.php index 41e6e60..bba1835 100644 --- a/src/SeriousJSON/JsonSerializable.php +++ b/src/SeriousJSON/JsonSerializable.php @@ -89,7 +89,7 @@ abstract class JsonSerializable * @param bool $to_array Do we want the result as an array instead of a json encoded string? * @return string|array Returns a json encoded string or a key value array */ - public function Serialize($nested = false, $to_array = false) + public function Serialize($nested = false, $to_array = false, IJsonUnflattener $callback = null) { // Initialize result set array $result = array(); @@ -106,18 +106,21 @@ abstract class JsonSerializable // Add var name and value to result set if (isset($value) && $value != null && $value instanceof JsonSerializable) { - if ($nested) + if ($nested) { $result[$key] = $value->Serialize(true, true); - else if ($value instanceof IJsonIdentifiable && $value->flatIdentifier() !== null) + } else if ($value instanceof IJsonIdentifiable && $value->flatIdentifier() !== null) { $result[$key] = $value->flatIdentifier(); - else - continue; + if ($this instanceof IJsonIdentifiable && $callback != null) + call_user_func([$callback, 'updateIndex'], $this, $value, false); + } else { + continue; + } } else if (isset($value) && $value != null && is_array($value)) { $arrayType = self::getPropertyArrayType(new \ReflectionProperty($this, $key)); if ($arrayType != null) - $result[$key] = self::SerializeArray($value, $nested, true); + $result[$key] = self::SerializeArray(objects: $value, nested: $nested, to_array: true, callback: $callback); else $result[$key] = $value; } @@ -139,7 +142,7 @@ abstract class JsonSerializable * @param bool $nested Indicates if we should also serialize nested object instances * @return string returns a json formatted string */ - public static function SerializeArray($objects = [], $nested = false, $to_array = false) + public static function SerializeArray($objects = [], $nested = false, $to_array = false, IJsonUnflattener $callback = null) { // Initialize a an array of results $results = array(); @@ -149,7 +152,7 @@ abstract class JsonSerializable if ($object instanceof JsonSerializable) { if ($nested) - $results[] = $object->Serialize(nested: true, to_array: true); + $results[] = $object->Serialize(nested: true, to_array: true, callback: $callback); else if ($object instanceof IJsonIdentifiable && $object->flatIdentifier() !== null) $results[] = $object->flatIdentifier(); else