@@ -22,73 +22,59 @@ final class Encoder
22
22
/**
23
23
* Returns the NEON representation of a value.
24
24
*/
25
- public function encode ($ var , int $ flags = 0 ): string
25
+ public function encode ($ val , int $ flags = 0 ): string
26
26
{
27
- if ($ var instanceof \DateTimeInterface) {
28
- return $ var ->format ('Y-m-d H:i:s O ' );
27
+ $ node = $ this ->valueToNode ($ val , (bool ) ($ flags & self ::BLOCK ));
28
+ return $ node ->toString ();
29
+ }
29
30
30
- } elseif ($ var instanceof Entity) {
31
- if ($ var ->value === Neon::CHAIN ) {
32
- return implode ('' , array_map ([$ this , 'encode ' ], $ var ->attributes ));
33
- }
34
- return $ this ->encode ($ var ->value ) . '( '
35
- . (is_array ($ var ->attributes ) ? substr ($ this ->encode ($ var ->attributes ), 1 , -1 ) : '' ) . ') ' ;
36
- }
37
31
38
- if (is_object ($ var )) {
39
- $ obj = $ var ;
40
- $ var = [];
41
- foreach ($ obj as $ k => $ v ) {
42
- $ var [$ k ] = $ v ;
43
- }
44
- }
32
+ public function valueToNode ($ val , bool $ blockMode = false ): Node
33
+ {
34
+ if ($ val instanceof \DateTimeInterface) {
35
+ return new Node \LiteralNode ($ val );
45
36
46
- if (is_array ($ var )) {
47
- $ isList = !$ var || array_keys ($ var ) === range (0 , count ($ var ) - 1 );
48
- $ s = '' ;
49
- if ($ flags & self ::BLOCK ) {
50
- if (count ($ var ) === 0 ) {
51
- return '[] ' ;
52
- }
53
- foreach ($ var as $ k => $ v ) {
54
- $ v = $ this ->encode ($ v , self ::BLOCK );
55
- $ s .= ($ isList ? '- ' : $ this ->encode ($ k ) . ': ' )
56
- . (strpos ($ v , "\n" ) === false
57
- ? ' ' . $ v . "\n"
58
- : "\n" . preg_replace ('#^(?=.)#m ' , "\t" , $ v ) . (substr ($ v , -2 , 1 ) === "\n" ? '' : "\n" ));
59
- }
60
- return $ s ;
61
-
62
- } else {
63
- foreach ($ var as $ k => $ v ) {
64
- $ s .= ($ isList ? '' : $ this ->encode ($ k ) . ': ' ) . $ this ->encode ($ v ) . ', ' ;
65
- }
66
- return ($ isList ? '[ ' : '{ ' ) . substr ($ s , 0 , -2 ) . ($ isList ? '] ' : '} ' );
37
+ } elseif ($ val instanceof Entity && $ val ->value === Neon::CHAIN ) {
38
+ $ node = new Node \EntityChainNode ;
39
+ foreach ($ val ->attributes as $ entity ) {
40
+ $ node ->chain [] = $ this ->valueToNode ($ entity , $ blockMode );
67
41
}
42
+ return $ node ;
68
43
69
- } elseif (is_string ($ var )) {
70
- if (!Lexer::requiresDelimiters ($ var )) {
71
- return $ var ;
72
- }
44
+ } elseif ($ val instanceof Entity) {
45
+ return new Node \EntityNode (
46
+ $ this ->valueToNode ($ val ->value ),
47
+ $ this ->arrayToNodes ((array ) $ val ->attributes )
48
+ );
73
49
74
- $ res = json_encode ($ var , JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES );
75
- if ($ res === false ) {
76
- throw new Exception ('Invalid UTF-8 sequence: ' . $ var );
77
- }
78
- if (strpos ($ var , "\n" ) !== false ) {
79
- $ res = preg_replace_callback ('#[^ \\\\]| \\\\(.)#s ' , function ($ m ) {
80
- return ['n ' => "\n\t" , 't ' => "\t" , '" ' => '" ' ][$ m [1 ] ?? '' ] ?? $ m [0 ];
81
- }, $ res );
82
- $ res = '""" ' . "\n\t" . substr ($ res , 1 , -1 ) . "\n" . '""" ' ;
83
- }
84
- return $ res ;
50
+ } elseif (is_object ($ val ) || is_array ($ val )) {
51
+ $ node = new Node \ArrayNode ($ blockMode ? '' : null );
52
+ $ node ->items = $ this ->arrayToNodes ($ val , $ blockMode );
53
+ return $ node ;
85
54
86
- } elseif (is_float ($ var )) {
87
- $ var = json_encode ($ var );
88
- return strpos ($ var , '. ' ) === false ? $ var . '.0 ' : $ var ;
55
+ } elseif (is_string ($ val ) && Lexer::requiresDelimiters ($ val )) {
56
+ return new Node \StringNode ($ val );
89
57
90
58
} else {
91
- return json_encode ($ var );
59
+ return new Node \LiteralNode ($ val );
60
+ }
61
+ }
62
+
63
+
64
+ private function arrayToNodes ($ val , bool $ blockMode = false ): array
65
+ {
66
+ $ res = [];
67
+ $ counter = 0 ;
68
+ $ hide = true ;
69
+ foreach ($ val as $ k => $ v ) {
70
+ $ res [] = $ item = new Node \ArrayItemNode ;
71
+ $ item ->key = $ hide && $ k === $ counter ? null : self ::valueToNode ($ k );
72
+ $ item ->value = self ::valueToNode ($ v , $ blockMode );
73
+ if ($ hide && is_int ($ k )) {
74
+ $ hide = $ k === $ counter ;
75
+ $ counter = max ($ k + 1 , $ counter );
76
+ }
92
77
}
78
+ return $ res ;
93
79
}
94
80
}
0 commit comments