diff --git a/src/main/php/util/data/Marshalling.class.php b/src/main/php/util/data/Marshalling.class.php index bddfc6d..b652c44 100755 --- a/src/main/php/util/data/Marshalling.class.php +++ b/src/main/php/util/data/Marshalling.class.php @@ -16,6 +16,31 @@ * @test util.data.unittest.ObjectsTest */ class Marshalling { + private $mappings= []; + + /** + * Maps user type marshalling + * + * @param string|lang.XPClass $type + * @param function(var): var $marshal + * @return self + */ + public function mapping($type, $marshal) { + $this->mappings[$type instanceof XPClass ? $type->literal() : $type][0]= $marshal; + return $this; + } + + /** + * Resolves user type unmarshalling + * + * @param string|lang.XPClass $type + * @param function(var, lang.XPClass): var $unmarshal + * @return self + */ + public function resolving($type, $unmarshal) { + $this->mappings[$type instanceof XPClass ? $type->literal() : $type][1]= $unmarshal; + return $this; + } /** * Applies unmarshal() to values inside an iterable @@ -44,6 +69,10 @@ public function unmarshal($value, $type= null) { $t= $type instanceof Type ? $type : Type::forName($type); if ($t instanceof XPClass) { + foreach ($this->mappings as $type => $mapping) { + if ($t->isAssignableFrom($type)) return $mapping[1]($value, $t); + } + if ($t->isInstance($value)) { return $value; } else if ($t->isEnum()) { @@ -149,6 +178,10 @@ public function marshal($value) { } else if ($value instanceof XPIterator) { return $this->iterator($value); } else if (is_object($value)) { + foreach ($this->mappings as $type => $marshal) { + if ($value instanceof $type) return $marshal[0]($value); + } + if (method_exists($value, '__serialize')) return $value->__serialize(); if (method_exists($value, '__toString')) return $value->__toString(); diff --git a/src/test/php/util/data/unittest/MarshallingTest.class.php b/src/test/php/util/data/unittest/MarshallingTest.class.php index b8a5759..a1ad63c 100755 --- a/src/test/php/util/data/unittest/MarshallingTest.class.php +++ b/src/test/php/util/data/unittest/MarshallingTest.class.php @@ -3,6 +3,7 @@ use lang\Type; use test\{Assert, Test, Values}; use util\data\Marshalling; +use util\data\unittest\fixtures\Person; class MarshallingTest { @@ -30,4 +31,24 @@ public function unmarshal($type) { public function unmarshal_without_type() { Assert::equals(1, (new Marshalling())->unmarshal(1)); } + + #[Test] + public function mapping() { + $marshalling= (new Marshalling())->mapping( + Person::class, + function($person) { return ['id' => $person->id()]; } + ); + + Assert::equals(['id' => 6100], $marshalling->marshal(new Person(6100, 'Test'))); + } + + #[Test] + public function resolving() { + $marshalling= (new Marshalling())->resolving( + Person::class, + function($value) { return new Person($value['id'], 'Test'); } + ); + + Assert::equals(new Person(6100, 'Test'), $marshalling->unmarshal(['id' => 6100], Person::class)); + } } \ No newline at end of file