diff --git a/src/core/etl/src/Flow/ETL/Row/Entry/Type/Uuid.php b/src/core/etl/src/Flow/ETL/Row/Entry/Type/Uuid.php
index 9dd364d7a..52c8e2413 100644
--- a/src/core/etl/src/Flow/ETL/Row/Entry/Type/Uuid.php
+++ b/src/core/etl/src/Flow/ETL/Row/Entry/Type/Uuid.php
@@ -5,7 +5,7 @@
use Flow\ETL\Exception\InvalidArgumentException;
use Flow\ETL\Exception\RuntimeException;
-final class Uuid
+final class Uuid implements \Stringable
{
/**
* This regexp is a port of the Uuid library,
@@ -44,6 +44,11 @@ public static function fromString(string $value) : self
return new self($value);
}
+ public function __toString() : string
+ {
+ return $this->toString();
+ }
+
public function isEqual(self $type) : bool
{
return $this->toString() === $type->toString();
diff --git a/src/core/etl/src/Flow/ETL/Row/Reference/Expression/Cast.php b/src/core/etl/src/Flow/ETL/Row/Reference/Expression/Cast.php
index c42934e61..13412db7f 100644
--- a/src/core/etl/src/Flow/ETL/Row/Reference/Expression/Cast.php
+++ b/src/core/etl/src/Flow/ETL/Row/Reference/Expression/Cast.php
@@ -44,11 +44,7 @@ public function eval(Row $row) : mixed
'int', 'integer' => (int) $value,
/** @phpstan-ignore-next-line */
'float', 'double', 'real' => (float) $value,
- 'string' => match (\gettype($value)) {
- 'object', 'array' => \json_encode($value, JSON_THROW_ON_ERROR),
- /** @phpstan-ignore-next-line */
- default => (string) $value
- },
+ 'string' => $this->toString($value),
'bool', 'boolean' => (bool) $value,
'array' => $this->toArray($value),
'object' => (object) $value,
@@ -68,6 +64,40 @@ private function toArray(mixed $data) : array
return (array) $data;
}
+ private function toString(mixed $value) : ?string
+ {
+ if ($value === null) {
+ return null;
+ }
+
+ if (\is_string($value)) {
+ return $value;
+ }
+
+ if (\is_bool($value)) {
+ return $value ? 'true' : 'false';
+ }
+
+ if (\is_array($value)) {
+ return \json_encode($value, JSON_THROW_ON_ERROR);
+ }
+
+ if ($value instanceof \DateTimeInterface) {
+ return $value->format(\DateTimeInterface::RFC3339);
+ }
+
+ if ($value instanceof \Stringable) {
+ return (string) $value;
+ }
+
+ if ($value instanceof \DOMDocument) {
+ return $value->saveXML() ?: null;
+ }
+
+ /** @phpstan-ignore-next-line */
+ return (string) $value;
+ }
+
private function toXML(mixed $value) : null|\DOMDocument
{
if (\is_string($value)) {
diff --git a/src/core/etl/tests/Flow/ETL/Tests/Unit/Row/Reference/Expression/CastTest.php b/src/core/etl/tests/Flow/ETL/Tests/Unit/Row/Reference/Expression/CastTest.php
index 3219e4a24..ea22f4c70 100644
--- a/src/core/etl/tests/Flow/ETL/Tests/Unit/Row/Reference/Expression/CastTest.php
+++ b/src/core/etl/tests/Flow/ETL/Tests/Unit/Row/Reference/Expression/CastTest.php
@@ -7,6 +7,7 @@
use function Flow\ETL\DSL\cast;
use function Flow\ETL\DSL\ref;
use Flow\ETL\Row;
+use Flow\ETL\Row\Entry\Type\Uuid;
use Flow\ETL\Row\Factory\NativeEntryFactory;
use PHPUnit\Framework\TestCase;
@@ -17,6 +18,12 @@ public static function cast_provider() : array
$xml = new \DOMDocument();
$xml->loadXML($xmlString = 'bar');
+ $fullXMLString = <<<'XML'
+
+bar
+
+XML;
+
return [
'invalid' => [null, 'int', null],
'int' => ['1', 'int', 1],
@@ -34,6 +41,10 @@ public static function cast_provider() : array
'json_pretty' => [[1], 'json_pretty', "[\n 1\n]"],
'xml_to_array' => [$xml, 'array', ['root' => ['foo' => ['@attributes' => ['baz' => 'buz'], '@value' => 'bar']]]],
'string_to_xml' => [$xmlString, 'xml', $xml],
+ 'xml_to_string' => [$xml, 'string', $fullXMLString],
+ 'datetime' => [new \DateTimeImmutable('2023-01-01 00:00:00 UTC'), 'string', '2023-01-01T00:00:00+00:00'],
+ 'uuid' => [Uuid::fromString('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'), 'string', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'],
+ 'bool_to_string' => [true, 'string', 'true'],
];
}