@@ -294,8 +294,8 @@ protected function executeOperation(OperationDefinitionNode $operation, $rootVal
294
294
// Similar to completeValueCatchingError.
295
295
try {
296
296
$ result = $ operation ->operation === 'mutation '
297
- ? $ this ->executeFieldsSerially ($ type , $ rootValue , $ path , $ fields )
298
- : $ this ->executeFields ($ type , $ rootValue , $ path , $ fields );
297
+ ? $ this ->executeFieldsSerially ($ type , $ rootValue , $ path , $ fields, $ this -> exeContext -> contextValue )
298
+ : $ this ->executeFields ($ type , $ rootValue , $ path , $ fields, $ this -> exeContext -> contextValue );
299
299
300
300
$ promise = $ this ->getPromise ($ result );
301
301
if ($ promise !== null ) {
@@ -522,22 +522,23 @@ protected function doesFragmentConditionMatch(Node $fragment, ObjectType $type):
522
522
*
523
523
* @param mixed $rootValue
524
524
* @param array<string|int> $path
525
+ * @param mixed $contextValue
525
526
*
526
527
* @phpstan-param Fields $fields
527
528
*
528
529
* @return array<mixed>|Promise|\stdClass
529
530
*/
530
- protected function executeFieldsSerially (ObjectType $ parentType , $ rootValue , array $ path , \ArrayObject $ fields )
531
+ protected function executeFieldsSerially (ObjectType $ parentType , $ rootValue , array $ path , \ArrayObject $ fields, $ contextValue )
531
532
{
532
533
$ result = $ this ->promiseReduce (
533
534
\array_keys ($ fields ->getArrayCopy ()),
534
- function ($ results , $ responseName ) use ($ path , $ parentType , $ rootValue , $ fields ) {
535
+ function ($ results , $ responseName ) use ($ contextValue , $ path , $ parentType , $ rootValue , $ fields ) {
535
536
$ fieldNodes = $ fields [$ responseName ];
536
537
assert ($ fieldNodes instanceof \ArrayObject, 'The keys of $fields populate $responseName ' );
537
538
538
539
$ fieldPath = $ path ;
539
540
$ fieldPath [] = $ responseName ;
540
- $ result = $ this ->resolveField ($ parentType , $ rootValue , $ fieldNodes , $ fieldPath );
541
+ $ result = $ this ->resolveField ($ parentType , $ rootValue , $ fieldNodes , $ fieldPath, $ contextValue );
541
542
if ($ result === static ::$ UNDEFINED ) {
542
543
return $ results ;
543
544
}
@@ -577,6 +578,7 @@ function ($results, $responseName) use ($path, $parentType, $rootValue, $fields)
577
578
*
578
579
* @param mixed $rootValue
579
580
* @param array<int, string|int> $path
581
+ * @param mixed $contextValue
580
582
*
581
583
* @phpstan-param Path $path
582
584
*
@@ -587,7 +589,7 @@ function ($results, $responseName) use ($path, $parentType, $rootValue, $fields)
587
589
*
588
590
* @return array<mixed>|\Throwable|mixed|null
589
591
*/
590
- protected function resolveField (ObjectType $ parentType , $ rootValue , \ArrayObject $ fieldNodes , array $ path )
592
+ protected function resolveField (ObjectType $ parentType , $ rootValue , \ArrayObject $ fieldNodes , array $ path, $ contextValue )
591
593
{
592
594
$ exeContext = $ this ->exeContext ;
593
595
$ fieldNode = $ fieldNodes [0 ];
@@ -631,15 +633,17 @@ protected function resolveField(ObjectType $parentType, $rootValue, \ArrayObject
631
633
$ fieldNode ,
632
634
$ resolveFn ,
633
635
$ rootValue ,
634
- $ info
636
+ $ info ,
637
+ $ contextValue
635
638
);
636
639
637
640
return $ this ->completeValueCatchingError (
638
641
$ returnType ,
639
642
$ fieldNodes ,
640
643
$ info ,
641
644
$ path ,
642
- $ result
645
+ $ result ,
646
+ $ contextValue
643
647
);
644
648
}
645
649
@@ -684,6 +688,7 @@ protected function getFieldDef(Schema $schema, ObjectType $parentType, string $f
684
688
* Returns the result of resolveFn or the abrupt-return Error object.
685
689
*
686
690
* @param mixed $rootValue
691
+ * @param mixed $contextValue
687
692
*
688
693
* @phpstan-param FieldResolver $resolveFn
689
694
*
@@ -694,7 +699,8 @@ protected function resolveFieldValueOrError(
694
699
FieldNode $ fieldNode ,
695
700
callable $ resolveFn ,
696
701
$ rootValue ,
697
- ResolveInfo $ info
702
+ ResolveInfo $ info ,
703
+ $ contextValue
698
704
) {
699
705
try {
700
706
// Build a map of arguments from the field.arguments AST, using the
@@ -704,7 +710,6 @@ protected function resolveFieldValueOrError(
704
710
$ fieldNode ,
705
711
$ this ->exeContext ->variableValues
706
712
);
707
- $ contextValue = $ this ->exeContext ->contextValue ;
708
713
709
714
return $ resolveFn ($ rootValue , $ args , $ contextValue , $ info );
710
715
} catch (\Throwable $ error ) {
@@ -718,6 +723,7 @@ protected function resolveFieldValueOrError(
718
723
*
719
724
* @param \ArrayObject<int, FieldNode> $fieldNodes
720
725
* @param array<string|int> $path
726
+ * @param mixed $contextValue
721
727
*
722
728
* @phpstan-param Path $path
723
729
*
@@ -732,18 +738,19 @@ protected function completeValueCatchingError(
732
738
\ArrayObject $ fieldNodes ,
733
739
ResolveInfo $ info ,
734
740
array $ path ,
735
- $ result
741
+ $ result ,
742
+ $ contextValue
736
743
) {
737
744
// Otherwise, error protection is applied, logging the error and resolving
738
745
// a null value for this field if one is encountered.
739
746
try {
740
747
$ promise = $ this ->getPromise ($ result );
741
748
if ($ promise !== null ) {
742
- $ completed = $ promise ->then (function (&$ resolved ) use ($ returnType , $ fieldNodes , $ info , $ path ) {
743
- return $ this ->completeValue ($ returnType , $ fieldNodes , $ info , $ path , $ resolved );
749
+ $ completed = $ promise ->then (function (&$ resolved ) use ($ contextValue , $ returnType , $ fieldNodes , $ info , $ path ) {
750
+ return $ this ->completeValue ($ returnType , $ fieldNodes , $ info , $ path , $ resolved, $ contextValue );
744
751
});
745
752
} else {
746
- $ completed = $ this ->completeValue ($ returnType , $ fieldNodes , $ info , $ path , $ result );
753
+ $ completed = $ this ->completeValue ($ returnType , $ fieldNodes , $ info , $ path , $ result, $ contextValue );
747
754
}
748
755
749
756
$ promise = $ this ->getPromise ($ completed );
@@ -811,6 +818,7 @@ protected function handleFieldError($rawError, \ArrayObject $fieldNodes, array $
811
818
* @param \ArrayObject<int, FieldNode> $fieldNodes
812
819
* @param array<string|int> $path
813
820
* @param mixed $result
821
+ * @param mixed $contextValue
814
822
*
815
823
* @throws \Throwable
816
824
* @throws Error
@@ -822,7 +830,8 @@ protected function completeValue(
822
830
\ArrayObject $ fieldNodes ,
823
831
ResolveInfo $ info ,
824
832
array $ path ,
825
- &$ result
833
+ &$ result ,
834
+ $ contextValue
826
835
) {
827
836
// If result is an Error, throw a located error.
828
837
if ($ result instanceof \Throwable) {
@@ -837,7 +846,8 @@ protected function completeValue(
837
846
$ fieldNodes ,
838
847
$ info ,
839
848
$ path ,
840
- $ result
849
+ $ result ,
850
+ $ contextValue
841
851
);
842
852
if ($ completed === null ) {
843
853
throw new InvariantViolation ("Cannot return null for non-nullable field \"{$ info ->parentType }. {$ info ->fieldName }\". " );
@@ -858,7 +868,7 @@ protected function completeValue(
858
868
throw new InvariantViolation ("Expected field {$ info ->parentType }. {$ info ->fieldName } to return iterable, but got: {$ resultType }. " );
859
869
}
860
870
861
- return $ this ->completeListValue ($ returnType , $ fieldNodes , $ info , $ path , $ result );
871
+ return $ this ->completeListValue ($ returnType , $ fieldNodes , $ info , $ path , $ result, $ contextValue );
862
872
}
863
873
864
874
assert ($ returnType instanceof NamedType, 'Wrapping types should return early ' );
@@ -875,12 +885,12 @@ protected function completeValue(
875
885
}
876
886
877
887
if ($ returnType instanceof AbstractType) {
878
- return $ this ->completeAbstractValue ($ returnType , $ fieldNodes , $ info , $ path , $ result );
888
+ return $ this ->completeAbstractValue ($ returnType , $ fieldNodes , $ info , $ path , $ result, $ contextValue );
879
889
}
880
890
881
891
// Field type must be and Object, Interface or Union and expect sub-selections.
882
892
if ($ returnType instanceof ObjectType) {
883
- return $ this ->completeObjectValue ($ returnType , $ fieldNodes , $ info , $ path , $ result );
893
+ return $ this ->completeObjectValue ($ returnType , $ fieldNodes , $ info , $ path , $ result, $ contextValue );
884
894
}
885
895
886
896
$ safeReturnType = Utils::printSafe ($ returnType );
@@ -949,17 +959,19 @@ function ($previous, $value) use ($callback) {
949
959
* @param \ArrayObject<int, FieldNode> $fieldNodes
950
960
* @param list<string|int> $path
951
961
* @param iterable<mixed> $results
952
- *
953
- * @throws Error
962
+ * @param mixed $contextValue
954
963
*
955
964
* @return array<mixed>|Promise|\stdClass
965
+ *@throws Error
966
+ *
956
967
*/
957
968
protected function completeListValue (
958
969
ListOfType $ returnType ,
959
970
\ArrayObject $ fieldNodes ,
960
971
ResolveInfo $ info ,
961
972
array $ path ,
962
- iterable &$ results
973
+ iterable &$ results ,
974
+ $ contextValue
963
975
) {
964
976
$ itemType = $ returnType ->getWrappedType ();
965
977
@@ -970,7 +982,7 @@ protected function completeListValue(
970
982
$ fieldPath = [...$ path , $ i ++];
971
983
$ info ->path = $ fieldPath ;
972
984
973
- $ completedItem = $ this ->completeValueCatchingError ($ itemType , $ fieldNodes , $ info , $ fieldPath , $ item );
985
+ $ completedItem = $ this ->completeValueCatchingError ($ itemType , $ fieldNodes , $ info , $ fieldPath , $ item, $ contextValue );
974
986
975
987
if (! $ containsPromise && $ this ->getPromise ($ completedItem ) !== null ) {
976
988
$ containsPromise = true ;
@@ -1016,6 +1028,7 @@ protected function completeLeafValue(LeafType $returnType, &$result)
1016
1028
* @param \ArrayObject<int, FieldNode> $fieldNodes
1017
1029
* @param array<string|int> $path
1018
1030
* @param array<mixed> $result
1031
+ * @param mixed $contextValue
1019
1032
*
1020
1033
* @throws \Exception
1021
1034
* @throws Error
@@ -1028,7 +1041,8 @@ protected function completeAbstractValue(
1028
1041
\ArrayObject $ fieldNodes ,
1029
1042
ResolveInfo $ info ,
1030
1043
array $ path ,
1031
- &$ result
1044
+ &$ result ,
1045
+ $ contextValue
1032
1046
) {
1033
1047
$ exeContext = $ this ->exeContext ;
1034
1048
$ typeCandidate = $ returnType ->resolveType ($ result , $ exeContext ->contextValue , $ info );
@@ -1053,7 +1067,8 @@ protected function completeAbstractValue(
1053
1067
$ fieldNodes ,
1054
1068
$ info ,
1055
1069
$ path ,
1056
- $ result
1070
+ $ result ,
1071
+ $ contextValue
1057
1072
));
1058
1073
}
1059
1074
@@ -1067,7 +1082,8 @@ protected function completeAbstractValue(
1067
1082
$ fieldNodes ,
1068
1083
$ info ,
1069
1084
$ path ,
1070
- $ result
1085
+ $ result ,
1086
+ $ contextValue
1071
1087
);
1072
1088
}
1073
1089
@@ -1143,6 +1159,7 @@ protected function defaultTypeResolver($value, $contextValue, ResolveInfo $info,
1143
1159
* @param \ArrayObject<int, FieldNode> $fieldNodes
1144
1160
* @param array<string|int> $path
1145
1161
* @param mixed $result
1162
+ * @param mixed $contextValue
1146
1163
*
1147
1164
* @throws \Exception
1148
1165
* @throws Error
@@ -1154,7 +1171,8 @@ protected function completeObjectValue(
1154
1171
\ArrayObject $ fieldNodes ,
1155
1172
ResolveInfo $ info ,
1156
1173
array $ path ,
1157
- &$ result
1174
+ &$ result ,
1175
+ $ contextValue
1158
1176
) {
1159
1177
// If there is an isTypeOf predicate function, call it with the
1160
1178
// current result. If isTypeOf returns false, then raise an error rather
@@ -1164,6 +1182,7 @@ protected function completeObjectValue(
1164
1182
$ promise = $ this ->getPromise ($ isTypeOf );
1165
1183
if ($ promise !== null ) {
1166
1184
return $ promise ->then (function ($ isTypeOfResult ) use (
1185
+ $ contextValue ,
1167
1186
$ returnType ,
1168
1187
$ fieldNodes ,
1169
1188
$ path ,
@@ -1177,7 +1196,8 @@ protected function completeObjectValue(
1177
1196
$ returnType ,
1178
1197
$ fieldNodes ,
1179
1198
$ path ,
1180
- $ result
1199
+ $ result ,
1200
+ $ contextValue
1181
1201
);
1182
1202
});
1183
1203
}
@@ -1192,7 +1212,8 @@ protected function completeObjectValue(
1192
1212
$ returnType ,
1193
1213
$ fieldNodes ,
1194
1214
$ path ,
1195
- $ result
1215
+ $ result ,
1216
+ $ contextValue
1196
1217
);
1197
1218
}
1198
1219
@@ -1217,6 +1238,7 @@ protected function invalidReturnTypeError(
1217
1238
* @param \ArrayObject<int, FieldNode> $fieldNodes
1218
1239
* @param array<string|int> $path
1219
1240
* @param mixed $result
1241
+ * @param mixed $contextValue
1220
1242
*
1221
1243
* @throws \Exception
1222
1244
* @throws Error
@@ -1227,11 +1249,12 @@ protected function collectAndExecuteSubfields(
1227
1249
ObjectType $ returnType ,
1228
1250
\ArrayObject $ fieldNodes ,
1229
1251
array $ path ,
1230
- &$ result
1252
+ &$ result ,
1253
+ $ contextValue
1231
1254
) {
1232
1255
$ subFieldNodes = $ this ->collectSubFields ($ returnType , $ fieldNodes );
1233
1256
1234
- return $ this ->executeFields ($ returnType , $ result , $ path , $ subFieldNodes );
1257
+ return $ this ->executeFields ($ returnType , $ result , $ path , $ subFieldNodes, $ contextValue );
1235
1258
}
1236
1259
1237
1260
/**
@@ -1276,6 +1299,7 @@ protected function collectSubFields(ObjectType $returnType, \ArrayObject $fieldN
1276
1299
*
1277
1300
* @param mixed $rootValue
1278
1301
* @param array<string|int> $path
1302
+ * @param mixed $contextValue
1279
1303
*
1280
1304
* @phpstan-param Fields $fields
1281
1305
*
@@ -1284,14 +1308,14 @@ protected function collectSubFields(ObjectType $returnType, \ArrayObject $fieldN
1284
1308
*
1285
1309
* @return Promise|\stdClass|array<mixed>
1286
1310
*/
1287
- protected function executeFields (ObjectType $ parentType , $ rootValue , array $ path , \ArrayObject $ fields )
1311
+ protected function executeFields (ObjectType $ parentType , $ rootValue , array $ path , \ArrayObject $ fields, $ contextValue )
1288
1312
{
1289
1313
$ containsPromise = false ;
1290
1314
$ results = [];
1291
1315
foreach ($ fields as $ responseName => $ fieldNodes ) {
1292
1316
$ fieldPath = $ path ;
1293
1317
$ fieldPath [] = $ responseName ;
1294
- $ result = $ this ->resolveField ($ parentType , $ rootValue , $ fieldNodes , $ fieldPath );
1318
+ $ result = $ this ->resolveField ($ parentType , $ rootValue , $ fieldNodes , $ fieldPath, $ this -> maybeScopeContext ( $ contextValue ) );
1295
1319
if ($ result === static ::$ UNDEFINED ) {
1296
1320
continue ;
1297
1321
}
@@ -1393,4 +1417,18 @@ protected function ensureValidRuntimeType(
1393
1417
1394
1418
return $ runtimeType ;
1395
1419
}
1420
+
1421
+ /**
1422
+ * @param mixed $contextValue
1423
+ *
1424
+ * @return mixed
1425
+ */
1426
+ private function maybeScopeContext ($ contextValue )
1427
+ {
1428
+ if ($ contextValue instanceof ScopedContext) {
1429
+ return clone $ contextValue ;
1430
+ }
1431
+
1432
+ return $ contextValue ;
1433
+ }
1396
1434
}
0 commit comments