keyMap() public static method

public static keyMap ( $traversable, callable $keyFn ) : array
$traversable
$keyFn callable function($value, $key) => $newKey
return array
 public function __invoke(ValidationContext $context)
 {
     return [Node::FIELD => function (Field $fieldAST) use($context) {
         $fieldDef = $context->getFieldDef();
         if (!$fieldDef) {
             return Visitor::skipNode();
         }
         $errors = [];
         $argASTs = $fieldAST->arguments ?: [];
         $argASTMap = Utils::keyMap($argASTs, function (Argument $arg) {
             return $arg->name->value;
         });
         foreach ($fieldDef->args as $argDef) {
             $argAST = isset($argASTMap[$argDef->name]) ? $argASTMap[$argDef->name] : null;
             if (!$argAST && $argDef->getType() instanceof NonNull) {
                 $errors[] = new Error(Messages::missingArgMessage($fieldAST->name->value, $argDef->name, $argDef->getType()), [$fieldAST]);
             }
         }
         $argDefMap = Utils::keyMap($fieldDef->args, function ($def) {
             return $def->name;
         });
         foreach ($argASTs as $argAST) {
             $argDef = $argDefMap[$argAST->name->value];
             if ($argDef && !DocumentValidator::isValidLiteralValue($argAST->value, $argDef->getType())) {
                 $errors[] = new Error(Messages::badValueMessage($argAST->name->value, $argDef->getType(), Printer::doPrint($argAST->value)), [$argAST->value]);
             }
         }
         return !empty($errors) ? $errors : null;
     }];
 }
 private function doTypesOverlap($t1, $t2)
 {
     if ($t1 === $t2) {
         return true;
     }
     if ($t1 instanceof ObjectType) {
         if ($t2 instanceof ObjectType) {
             return false;
         }
         return in_array($t1, $t2->getPossibleTypes());
     }
     if ($t1 instanceof InterfaceType || $t1 instanceof UnionType) {
         if ($t2 instanceof ObjectType) {
             return in_array($t2, $t1->getPossibleTypes());
         }
         $t1TypeNames = Utils::keyMap($t1->getPossibleTypes(), function ($type) {
             return $type->name;
         });
         foreach ($t2->getPossibleTypes() as $type) {
             if (!empty($t1TypeNames[$type->name])) {
                 return true;
             }
         }
     }
     return false;
 }
Example #3
0
 /**
  * Prepares an object map of argument values given a list of argument
  * definitions and list of argument AST nodes.
  *
  * @param FieldArgument[] $argDefs
  * @param Argument[] $argASTs
  * @param $variableValues
  * @return array
  */
 public static function getArgumentValues($argDefs, $argASTs, $variableValues)
 {
     if (!$argDefs) {
         return [];
     }
     $argASTMap = $argASTs ? Utils::keyMap($argASTs, function ($arg) {
         return $arg->name->value;
     }) : [];
     $result = [];
     foreach ($argDefs as $argDef) {
         $name = $argDef->name;
         $valueAST = isset($argASTMap[$name]) ? $argASTMap[$name]->value : null;
         $value = Utils\AST::valueFromAST($valueAST, $argDef->getType(), $variableValues);
         if (null === $value) {
             $value = $argDef->defaultValue;
         }
         if (null !== $value) {
             $result[$name] = $value;
         }
     }
     return $result;
 }
 /**
  * Utility for validators which determines if a value literal AST is valid given
  * an input type.
  *
  * Note that this only validates literal values, variables are assumed to
  * provide values of the correct type.
  *
  * @return array
  */
 public static function isValidLiteralValue(Type $type, $valueNode)
 {
     // A value must be provided if the type is non-null.
     if ($type instanceof NonNull) {
         if (!$valueNode || $valueNode instanceof NullValueNode) {
             return ['Expected "' . Utils::printSafe($type) . '", found null.'];
         }
         return static::isValidLiteralValue($type->getWrappedType(), $valueNode);
     }
     if (!$valueNode || $valueNode instanceof NullValueNode) {
         return [];
     }
     // This function only tests literals, and assumes variables will provide
     // values of the correct type.
     if ($valueNode instanceof VariableNode) {
         return [];
     }
     // Lists accept a non-list value as a list of one.
     if ($type instanceof ListOfType) {
         $itemType = $type->getWrappedType();
         if ($valueNode instanceof ListValueNode) {
             $errors = [];
             foreach ($valueNode->values as $index => $itemNode) {
                 $tmp = static::isValidLiteralValue($itemType, $itemNode);
                 if ($tmp) {
                     $errors = array_merge($errors, Utils::map($tmp, function ($error) use($index) {
                         return "In element #{$index}: {$error}";
                     }));
                 }
             }
             return $errors;
         } else {
             return static::isValidLiteralValue($itemType, $valueNode);
         }
     }
     // Input objects check each defined field and look for undefined fields.
     if ($type instanceof InputObjectType) {
         if ($valueNode->kind !== NodeKind::OBJECT) {
             return ["Expected \"{$type->name}\", found not an object."];
         }
         $fields = $type->getFields();
         $errors = [];
         // Ensure every provided field is defined.
         $fieldNodes = $valueNode->fields;
         foreach ($fieldNodes as $providedFieldNode) {
             if (empty($fields[$providedFieldNode->name->value])) {
                 $errors[] = "In field \"{$providedFieldNode->name->value}\": Unknown field.";
             }
         }
         // Ensure every defined field is valid.
         $fieldNodeMap = Utils::keyMap($fieldNodes, function ($fieldNode) {
             return $fieldNode->name->value;
         });
         foreach ($fields as $fieldName => $field) {
             $result = static::isValidLiteralValue($field->getType(), isset($fieldNodeMap[$fieldName]) ? $fieldNodeMap[$fieldName]->value : null);
             if ($result) {
                 $errors = array_merge($errors, Utils::map($result, function ($error) use($fieldName) {
                     return "In field \"{$fieldName}\": {$error}";
                 }));
             }
         }
         return $errors;
     }
     if ($type instanceof LeafType) {
         // Scalar/Enum input checks to ensure the type can parse the value to
         // a non-null value.
         $parseResult = $type->parseLiteral($valueNode);
         if (null === $parseResult) {
             $printed = Printer::doPrint($valueNode);
             return ["Expected type \"{$type->name}\", found {$printed}."];
         }
         return [];
     }
     throw new InvariantViolation('Must be input type');
 }
Example #5
0
 /**
  * Produces a PHP value given a GraphQL Value AST.
  *
  * A GraphQL type must be provided, which will be used to interpret different
  * GraphQL Value literals.
  *
  * | GraphQL Value        | PHP Value     |
  * | -------------------- | ------------- |
  * | Input Object         | Assoc Array   |
  * | List                 | Array         |
  * | Boolean              | Boolean       |
  * | String               | String        |
  * | Int / Float          | Int / Float   |
  * | Enum Value           | Mixed         |
  *
  * @param $valueAST
  * @param InputType $type
  * @param null $variables
  * @return array|null
  * @throws \Exception
  */
 public static function valueFromAST($valueAST, InputType $type, $variables = null)
 {
     if ($type instanceof NonNull) {
         // Note: we're not checking that the result of valueFromAST is non-null.
         // We're assuming that this query has been validated and the value used
         // here is of the correct type.
         return self::valueFromAST($valueAST, $type->getWrappedType(), $variables);
     }
     if (!$valueAST) {
         return null;
     }
     if ($valueAST instanceof Variable) {
         $variableName = $valueAST->name->value;
         if (!$variables || !isset($variables[$variableName])) {
             return null;
         }
         // Note: we're not doing any checking that this variable is correct. We're
         // assuming that this query has been validated and the variable usage here
         // is of the correct type.
         return $variables[$variableName];
     }
     if ($type instanceof ListOfType) {
         $itemType = $type->getWrappedType();
         if ($valueAST instanceof ListValue) {
             return array_map(function ($itemAST) use($itemType, $variables) {
                 return self::valueFromAST($itemAST, $itemType, $variables);
             }, $valueAST->values);
         } else {
             return [self::valueFromAST($valueAST, $itemType, $variables)];
         }
     }
     if ($type instanceof InputObjectType) {
         $fields = $type->getFields();
         if (!$valueAST instanceof ObjectValue) {
             return null;
         }
         $fieldASTs = Utils::keyMap($valueAST->fields, function ($field) {
             return $field->name->value;
         });
         $values = [];
         foreach ($fields as $field) {
             $fieldAST = isset($fieldASTs[$field->name]) ? $fieldASTs[$field->name] : null;
             $fieldValue = self::valueFromAST($fieldAST ? $fieldAST->value : null, $field->getType(), $variables);
             if (null === $fieldValue) {
                 $fieldValue = $field->defaultValue;
             }
             if (null !== $fieldValue) {
                 $values[$field->name] = $fieldValue;
             }
         }
         return $values;
     }
     if ($type instanceof LeafType) {
         return $type->parseLiteral($valueAST);
     }
     throw new InvariantViolation('Must be input type');
 }
Example #6
0
 public static function valueFromAST($valueAST, InputType $type, $variables = null)
 {
     if ($type instanceof NonNull) {
         return self::valueFromAST($valueAST, $type->getWrappedType(), $variables);
     }
     if (!$valueAST) {
         return null;
     }
     if ($valueAST instanceof Variable) {
         $variableName = $valueAST->name->value;
         if (!$variables || !isset($variables[$variableName])) {
             return null;
         }
         return $variables[$variableName];
     }
     if ($type instanceof ListOfType) {
         $itemType = $type->getWrappedType();
         if ($valueAST instanceof ListValue) {
             return array_map(function ($itemAST) use($itemType, $variables) {
                 return Values::valueFromAST($itemAST, $itemType, $variables);
             }, $valueAST->values);
         } else {
             return [self::valueFromAST($valueAST, $itemType, $variables)];
         }
     }
     if ($type instanceof InputObjectType) {
         $fields = $type->getFields();
         if (!$valueAST instanceof ObjectValue) {
             return null;
         }
         $fieldASTs = Utils::keyMap($valueAST->fields, function ($field) {
             return $field->name->value;
         });
         $values = [];
         foreach ($fields as $field) {
             $fieldAST = isset($fieldASTs[$field->name]) ? $fieldASTs[$field->name] : null;
             $fieldValue = self::valueFromAST($fieldAST ? $fieldAST->value : null, $field->getType(), $variables);
             if (null === $fieldValue) {
                 $fieldValue = $field->defaultValue;
             }
             if (null !== $fieldValue) {
                 $values[$field->name] = $fieldValue;
             }
         }
         return $values;
     }
     Utils::invariant($type instanceof ScalarType || $type instanceof EnumType, 'Must be input type');
     return $type->parseLiteral($valueAST);
 }
Example #7
0
 /**
  * Produces a PHP value given a GraphQL Value AST.
  *
  * A GraphQL type must be provided, which will be used to interpret different
  * GraphQL Value literals.
  *
  * Returns `null` when the value could not be validly coerced according to
  * the provided type.
  *
  * | GraphQL Value        | PHP Value     |
  * | -------------------- | ------------- |
  * | Input Object         | Assoc Array   |
  * | List                 | Array         |
  * | Boolean              | Boolean       |
  * | String               | String        |
  * | Int / Float          | Int / Float   |
  * | Enum Value           | Mixed         |
  * | Null Value           | stdClass      | instance of NullValue::getNullValue()
  *
  * @param $valueNode
  * @param InputType $type
  * @param null $variables
  * @return array|null|\stdClass
  * @throws \Exception
  */
 public static function valueFromAST($valueNode, InputType $type, $variables = null)
 {
     $undefined = Utils::undefined();
     if (!$valueNode) {
         // When there is no AST, then there is also no value.
         // Importantly, this is different from returning the GraphQL null value.
         return $undefined;
     }
     if ($type instanceof NonNull) {
         if ($valueNode instanceof NullValueNode) {
             // Invalid: intentionally return no value.
             return $undefined;
         }
         return self::valueFromAST($valueNode, $type->getWrappedType(), $variables);
     }
     if ($valueNode instanceof NullValueNode) {
         // This is explicitly returning the value null.
         return null;
     }
     if ($valueNode instanceof VariableNode) {
         $variableName = $valueNode->name->value;
         if (!$variables || !array_key_exists($variableName, $variables)) {
             // No valid return value.
             return $undefined;
         }
         // Note: we're not doing any checking that this variable is correct. We're
         // assuming that this query has been validated and the variable usage here
         // is of the correct type.
         return $variables[$variableName];
     }
     if ($type instanceof ListOfType) {
         $itemType = $type->getWrappedType();
         if ($valueNode instanceof ListValueNode) {
             $coercedValues = [];
             $itemNodes = $valueNode->values;
             foreach ($itemNodes as $itemNode) {
                 if (self::isMissingVariable($itemNode, $variables)) {
                     // If an array contains a missing variable, it is either coerced to
                     // null or if the item type is non-null, it considered invalid.
                     if ($itemType instanceof NonNull) {
                         // Invalid: intentionally return no value.
                         return $undefined;
                     }
                     $coercedValues[] = null;
                 } else {
                     $itemValue = self::valueFromAST($itemNode, $itemType, $variables);
                     if ($undefined === $itemValue) {
                         // Invalid: intentionally return no value.
                         return $undefined;
                     }
                     $coercedValues[] = $itemValue;
                 }
             }
             return $coercedValues;
         }
         $coercedValue = self::valueFromAST($valueNode, $itemType, $variables);
         if ($undefined === $coercedValue) {
             // Invalid: intentionally return no value.
             return $undefined;
         }
         return [$coercedValue];
     }
     if ($type instanceof InputObjectType) {
         if (!$valueNode instanceof ObjectValueNode) {
             // Invalid: intentionally return no value.
             return $undefined;
         }
         $coercedObj = [];
         $fields = $type->getFields();
         $fieldNodes = Utils::keyMap($valueNode->fields, function ($field) {
             return $field->name->value;
         });
         foreach ($fields as $field) {
             /** @var ValueNode $fieldNode */
             $fieldName = $field->name;
             $fieldNode = isset($fieldNodes[$fieldName]) ? $fieldNodes[$fieldName] : null;
             if (!$fieldNode || self::isMissingVariable($fieldNode->value, $variables)) {
                 if ($field->defaultValueExists()) {
                     $coercedObj[$fieldName] = $field->defaultValue;
                 } else {
                     if ($field->getType() instanceof NonNull) {
                         // Invalid: intentionally return no value.
                         return $undefined;
                     }
                 }
                 continue;
             }
             $fieldValue = self::valueFromAST($fieldNode ? $fieldNode->value : null, $field->getType(), $variables);
             if ($undefined === $fieldValue) {
                 // Invalid: intentionally return no value.
                 return $undefined;
             }
             $coercedObj[$fieldName] = $fieldValue;
         }
         return $coercedObj;
     }
     if ($type instanceof LeafType) {
         $parsed = $type->parseLiteral($valueNode);
         if (null === $parsed) {
             // null represent a failure to parse correctly,
             // in which case no value is returned.
             return $undefined;
         }
         return $parsed;
     }
     throw new InvariantViolation('Must be input type');
 }
 static function isValidLiteralValue($valueAST, Type $type)
 {
     // A value can only be not provided if the type is nullable.
     if (!$valueAST) {
         return !$type instanceof NonNull;
     }
     // Unwrap non-null.
     if ($type instanceof NonNull) {
         return self::isValidLiteralValue($valueAST, $type->getWrappedType());
     }
     // This function only tests literals, and assumes variables will provide
     // values of the correct type.
     if ($valueAST instanceof Variable) {
         return true;
     }
     if (!$valueAST instanceof Value) {
         return false;
     }
     // Lists accept a non-list value as a list of one.
     if ($type instanceof ListOfType) {
         $itemType = $type->getWrappedType();
         if ($valueAST instanceof ListValue) {
             foreach ($valueAST->values as $itemAST) {
                 if (!self::isValidLiteralValue($itemAST, $itemType)) {
                     return false;
                 }
             }
             return true;
         } else {
             return self::isValidLiteralValue($valueAST, $itemType);
         }
     }
     // Scalar/Enum input checks to ensure the type can serialize the value to
     // a non-null value.
     if ($type instanceof ScalarType || $type instanceof EnumType) {
         return $type->parseLiteral($valueAST) !== null;
     }
     // Input objects check each defined field, ensuring it is of the correct
     // type and provided if non-nullable.
     if ($type instanceof InputObjectType) {
         $fields = $type->getFields();
         if ($valueAST->kind !== Node::OBJECT) {
             return false;
         }
         $fieldASTs = $valueAST->fields;
         $fieldASTMap = Utils::keyMap($fieldASTs, function ($field) {
             return $field->name->value;
         });
         foreach ($fields as $fieldKey => $field) {
             $fieldName = $field->name ?: $fieldKey;
             if (!isset($fieldASTMap[$fieldName]) && $field->getType() instanceof NonNull) {
                 // Required fields missing
                 return false;
             }
         }
         foreach ($fieldASTs as $fieldAST) {
             if (empty($fields[$fieldAST->name->value]) || !self::isValidLiteralValue($fieldAST->value, $fields[$fieldAST->name->value]->getType())) {
                 return false;
             }
         }
         return true;
     }
     // Any other kind of type is not an input type, and a literal cannot be used.
     return false;
 }
Example #9
0
 /**
  * Given a type and a value AST node known to match this type, build a
  * runtime value.
  */
 private static function coerceValueAST(Type $type, $valueAST, $variables)
 {
     if ($type instanceof NonNull) {
         // Note: we're not checking that the result of coerceValueAST is non-null.
         // We're assuming that this query has been validated and the value used
         // here is of the correct type.
         return self::coerceValueAST($type->getWrappedType(), $valueAST, $variables);
     }
     if (!$valueAST) {
         return null;
     }
     if ($valueAST->kind === Node::VARIABLE) {
         $variableName = $valueAST->name->value;
         if (!isset($variables, $variables[$variableName])) {
             return null;
         }
         // Note: we're not doing any checking that this variable is correct. We're
         // assuming that this query has been validated and the variable usage here
         // is of the correct type.
         return $variables[$variableName];
     }
     if ($type instanceof ListOfType) {
         $itemType = $type->getWrappedType();
         if ($valueAST->kind === Node::ARR) {
             $tmp = [];
             foreach ($valueAST->values as $itemAST) {
                 $tmp[] = self::coerceValueAST($itemType, $itemAST, $variables);
             }
             return $tmp;
         } else {
             return [self::coerceValueAST($itemType, $valueAST, $variables)];
         }
     }
     if ($type instanceof InputObjectType) {
         $fields = $type->getFields();
         if ($valueAST->kind !== Node::OBJECT) {
             return null;
         }
         $fieldASTs = Utils::keyMap($valueAST->fields, function ($field) {
             return $field->name->value;
         });
         $obj = [];
         foreach ($fields as $fieldName => $field) {
             $fieldAST = $fieldASTs[$fieldName];
             $fieldValue = self::coerceValueAST($field->getType(), $fieldAST ? $fieldAST->value : null, $variables);
             $obj[$fieldName] = $fieldValue === null ? $field->defaultValue : $fieldValue;
         }
         return $obj;
     }
     if ($type instanceof ScalarType || $type instanceof EnumType) {
         $coerced = $type->coerceLiteral($valueAST);
         if (null !== $coerced) {
             return $coerced;
         }
     }
     return null;
 }
Example #10
0
 /**
  * Prepares an object map of argument values given a list of argument
  * definitions and list of argument AST nodes.
  *
  * @param FieldDefinition|Directive $def
  * @param FieldNode|\GraphQL\Language\AST\DirectiveNode $node
  * @param $variableValues
  * @return array
  * @throws Error
  */
 public static function getArgumentValues($def, $node, $variableValues)
 {
     $argDefs = $def->args;
     $argNodes = $node->arguments;
     if (!$argDefs || null === $argNodes) {
         return [];
     }
     $coercedValues = [];
     $undefined = Utils::undefined();
     /** @var ArgumentNode[] $argNodeMap */
     $argNodeMap = $argNodes ? Utils::keyMap($argNodes, function (ArgumentNode $arg) {
         return $arg->name->value;
     }) : [];
     foreach ($argDefs as $argDef) {
         $name = $argDef->name;
         $argType = $argDef->getType();
         $argumentNode = isset($argNodeMap[$name]) ? $argNodeMap[$name] : null;
         if (!$argumentNode) {
             if ($argDef->defaultValueExists()) {
                 $coercedValues[$name] = $argDef->defaultValue;
             } else {
                 if ($argType instanceof NonNull) {
                     throw new Error('Argument "' . $name . '" of required type ' . '"' . Utils::printSafe($argType) . '" was not provided.', [$node]);
                 }
             }
         } else {
             if ($argumentNode->value instanceof VariableNode) {
                 $variableName = $argumentNode->value->name->value;
                 if ($variableValues && array_key_exists($variableName, $variableValues)) {
                     // Note: this does not check that this variable value is correct.
                     // This assumes that this query has been validated and the variable
                     // usage here is of the correct type.
                     $coercedValues[$name] = $variableValues[$variableName];
                 } else {
                     if ($argDef->defaultValueExists()) {
                         $coercedValues[$name] = $argDef->defaultValue;
                     } else {
                         if ($argType instanceof NonNull) {
                             throw new Error('Argument "' . $name . '" of required type "' . Utils::printSafe($argType) . '" was ' . 'provided the variable "$' . $variableName . '" which was not provided ' . 'a runtime value.', [$argumentNode->value]);
                         }
                     }
                 }
             } else {
                 $valueNode = $argumentNode->value;
                 $coercedValue = Utils\AST::valueFromAST($valueNode, $argType, $variableValues);
                 if ($coercedValue === $undefined) {
                     $errors = DocumentValidator::isValidLiteralValue($argType, $valueNode);
                     $message = !empty($errors) ? "\n" . implode("\n", $errors) : '';
                     throw new Error('Argument "' . $name . '" got invalid value ' . Printer::doPrint($valueNode) . '.' . $message, [$argumentNode->value]);
                 }
                 $coercedValues[$name] = $coercedValue;
             }
         }
     }
     return $coercedValues;
 }