@@ -33,6 +33,9 @@ final class CypherObject implements TestkitResponseInterface
33
33
private $ value ;
34
34
private string $ name ;
35
35
36
+ // Store element ID mappings for relationships created from paths
37
+ private static array $ relationshipElementIdMap = [];
38
+
36
39
/**
37
40
* @param CypherList|CypherMap|int|bool|float|string|Node|Relationship|Path|null $value
38
41
*/
@@ -103,12 +106,16 @@ public static function autoDetect($value): TestkitResponseInterface
103
106
/** @psalm-suppress MixedArgumentTypeCoercion */
104
107
$ props [$ key ] = self ::autoDetect ($ property );
105
108
}
109
+ $ elementId = $ value ->getElementId ();
110
+ if ($ elementId === null ) {
111
+ $ elementId = (string ) $ value ->getId ();
112
+ }
106
113
107
114
$ tbr = new CypherNode (
108
115
new CypherObject ('CypherInt ' , $ value ->getId ()),
109
116
new CypherObject ('CypherList ' , new CypherList ($ labels )),
110
117
new CypherObject ('CypherMap ' , new CypherMap ($ props )),
111
- new CypherObject ('CypherString ' , $ value -> getElementId () )
118
+ new CypherObject ('CypherString ' , $ elementId )
112
119
);
113
120
break ;
114
121
case Relationship::class:
@@ -118,31 +125,73 @@ public static function autoDetect($value): TestkitResponseInterface
118
125
$ props [$ key ] = self ::autoDetect ($ property );
119
126
}
120
127
128
+ $ elementId = $ value ->getElementId ();
129
+ if ($ elementId === null ) {
130
+ $ elementId = (string ) $ value ->getId ();
131
+ }
132
+
133
+ $ relationshipKey = $ value ->getId ().'_ ' .$ value ->getStartNodeId ().'_ ' .$ value ->getEndNodeId ();
134
+
135
+ $ startNodeElementId = self ::$ relationshipElementIdMap [$ relationshipKey ]['startNodeElementId ' ] ?? (string ) $ value ->getStartNodeId ();
136
+ $ endNodeElementId = self ::$ relationshipElementIdMap [$ relationshipKey ]['endNodeElementId ' ] ?? (string ) $ value ->getEndNodeId ();
137
+
121
138
$ tbr = new CypherRelationship (
122
139
new CypherObject ('CypherInt ' , $ value ->getId ()),
123
140
new CypherObject ('CypherInt ' , $ value ->getStartNodeId ()),
124
141
new CypherObject ('CypherInt ' , $ value ->getEndNodeId ()),
125
142
new CypherObject ('CypherString ' , $ value ->getType ()),
126
143
new CypherObject ('CypherMap ' , new CypherMap ($ props )),
127
- new CypherObject ('CypherString ' , $ value ->getElementId ())
144
+ new CypherObject ('CypherString ' , $ elementId ),
145
+ new CypherObject ('CypherString ' , $ startNodeElementId ), // Use stored element ID
146
+ new CypherObject ('CypherString ' , $ endNodeElementId ) // Use stored element ID
128
147
);
129
148
break ;
130
149
case Path::class:
131
150
$ nodes = [];
132
151
foreach ($ value ->getNodes () as $ node ) {
133
152
$ nodes [] = self ::autoDetect ($ node );
134
153
}
154
+
135
155
$ rels = [];
156
+ $ nodesList = $ value ->getNodes ();
157
+
136
158
foreach ($ value ->getRelationships () as $ i => $ rel ) {
137
- $ rels [] = self ::autoDetect (new Relationship (
138
- $ rel ->getId (),
139
- $ value ->getNodes ()->get ($ i )->getId (),
140
- $ value ->getNodes ()->get ($ i + 1 )->getId (),
141
- $ rel ->getType (),
142
- $ rel ->getProperties (),
143
- $ rel ->getElementId ()
144
- ));
159
+ $ relElementId = $ rel ->getElementId () ?? (string ) $ rel ->getId ();
160
+
161
+ if ($ rel instanceof UnboundRelationship) {
162
+ if ($ i < $ nodesList ->count () - 1 ) {
163
+ $ startNode = $ nodesList ->get ($ i );
164
+ $ endNode = $ nodesList ->get ($ i + 1 );
165
+
166
+ $ startNodeElementId = $ startNode ->getElementId () ?? (string ) $ startNode ->getId ();
167
+ $ endNodeElementId = $ endNode ->getElementId () ?? (string ) $ endNode ->getId ();
168
+
169
+ $ boundRel = new Relationship (
170
+ $ rel ->getId (),
171
+ $ startNode ->getId (),
172
+ $ endNode ->getId (),
173
+ $ rel ->getType (),
174
+ $ rel ->getProperties (),
175
+ $ relElementId
176
+ );
177
+
178
+ $ relationshipKey = $ boundRel ->getId ().'_ ' .$ boundRel ->getStartNodeId ().'_ ' .$ boundRel ->getEndNodeId ();
179
+ self ::$ relationshipElementIdMap [$ relationshipKey ] = [
180
+ 'startNodeElementId ' => $ startNodeElementId ,
181
+ 'endNodeElementId ' => $ endNodeElementId ,
182
+ ];
183
+
184
+ error_log ('DEBUG PATH: Stored mapping for key: ' .$ relationshipKey );
185
+ error_log ('DEBUG PATH: Stored startNodeElementId: ' .$ startNodeElementId );
186
+ error_log ('DEBUG PATH: Stored endNodeElementId: ' .$ endNodeElementId );
187
+
188
+ $ rels [] = self ::autoDetect ($ boundRel );
189
+ }
190
+ } else {
191
+ $ rels [] = self ::autoDetect ($ rel );
192
+ }
145
193
}
194
+
146
195
$ tbr = new CypherPath (
147
196
new CypherObject ('CypherList ' , new CypherList ($ nodes )),
148
197
new CypherObject ('CypherList ' , new CypherList ($ rels ))
@@ -161,7 +210,9 @@ public static function autoDetect($value): TestkitResponseInterface
161
210
new CypherObject ('CypherNull ' , null ),
162
211
new CypherObject ('CypherString ' , $ value ->getType ()),
163
212
new CypherObject ('CypherMap ' , new CypherMap ($ props )),
164
- new CypherObject ('CypherString ' , $ value ->getElementId ())
213
+ new CypherObject ('CypherString ' , $ value ->getElementId ()),
214
+ new CypherObject ('CypherNull ' , null ),
215
+ new CypherObject ('CypherNull ' , null )
165
216
);
166
217
break ;
167
218
default :
0 commit comments