예제 #1
1
파일: Utils.php 프로젝트: aeshion/ZeroPHP
 /**
  * @param $code
  * @return string
  */
 public static function printCharCode($code)
 {
     if (null === $code) {
         return '<EOF>';
     }
     return $code < 0x7f ? json_encode(Utils::chr($code)) : '"\\u' . dechex($code) . '"';
 }
예제 #2
0
 /**
  * ScalarType constructor.
  */
 public function __construct()
 {
     if (!isset($this->name)) {
         $this->name = $this->tryInferName();
     }
     Utils::invariant($this->name, 'Type must be named.');
 }
예제 #3
0
 public function parseValue($value)
 {
     if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
         throw new \Exception('Cannot represent value as email: ' . Utils::printSafe($value));
     }
     return $value;
 }
예제 #4
0
 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;
     }];
 }
예제 #5
0
 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;
 }
예제 #6
0
파일: UrlType.php 프로젝트: aeshion/ZeroPHP
 public function parseValue($value)
 {
     if (!is_string($value) || !filter_var($value, FILTER_VALIDATE_URL)) {
         throw new \Exception('Cannot represent value as URL:' . Utils::printSafe($value));
     }
     return $value;
 }
예제 #7
0
 /**
  * @param $name
  * @return FieldDefinition
  * @throws \Exception
  */
 public function getField($name)
 {
     if (null === $this->fields) {
         $this->getFields();
     }
     Utils::invariant(isset($this->fields[$name]), 'Field "%s" is not defined for type "%s"', $name, $this->name);
     return $this->fields[$name];
 }
예제 #8
0
파일: UrlType.php 프로젝트: aeshion/ZeroPHP
 /**
  * Parses an externally provided value (query variable) to use as an input
  *
  * @param mixed $value
  * @return mixed
  */
 public function parseValue($value)
 {
     if (!is_string($value) || !filter_var($value, FILTER_VALIDATE_URL)) {
         // quite naive, but after all this is example
         throw new \UnexpectedValueException("Cannot represent value as URL: " . Utils::printSafe($value));
     }
     return $value;
 }
예제 #9
0
 private function getTypeASTName(Type $typeAST)
 {
     if ($typeAST->kind === Node::NAME) {
         return $typeAST->value;
     }
     Utils::invariant($typeAST->type, 'Must be wrapping type');
     return $this->getTypeASTName($typeAST->type);
 }
예제 #10
0
 private function withModifiers($types)
 {
     return array_merge(Utils::map($types, function ($type) {
         return Type::listOf($type);
     }), Utils::map($types, function ($type) {
         return Type::nonNull($type);
     }), Utils::map($types, function ($type) {
         return Type::nonNull(Type::listOf($type));
     }));
 }
예제 #11
0
 /**
  * @param $value
  * @return float|null
  */
 private function coerceFloat($value)
 {
     if ($value === '') {
         throw new InvariantViolation('Float cannot represent non numeric value: (empty string)');
     }
     if (is_numeric($value) || $value === true || $value === false) {
         return (double) $value;
     }
     throw new InvariantViolation('Float cannot represent non numeric value: ' . Utils::printSafe($value));
 }
예제 #12
0
 public function __construct($config)
 {
     Config::validate($config, ['name' => Config::STRING | Config::REQUIRED, 'values' => Config::arrayOf(['name' => Config::STRING | Config::REQUIRED, 'value' => Config::ANY, 'deprecationReason' => Config::STRING, 'description' => Config::STRING], Config::KEY_AS_NAME), 'description' => Config::STRING]);
     $this->name = $config['name'];
     $this->description = isset($config['description']) ? $config['description'] : null;
     $this->_values = [];
     if (!empty($config['values'])) {
         foreach ($config['values'] as $name => $value) {
             $this->_values[] = Utils::assign(new EnumValueDefinition(), $value + ['name' => $name]);
         }
     }
 }
예제 #13
0
 /**
  * Return implementations of `type` that include `fieldName` as a valid field.
  *
  * @param Schema $schema
  * @param AbstractType $type
  * @param $fieldName
  * @return array
  */
 static function getImplementationsIncludingField(Schema $schema, AbstractType $type, $fieldName)
 {
     $types = $schema->getPossibleTypes($type);
     $types = Utils::filter($types, function ($t) use($fieldName) {
         return isset($t->getFields()[$fieldName]);
     });
     $types = Utils::map($types, function ($t) {
         return $t->name;
     });
     sort($types);
     return $types;
 }
예제 #14
0
파일: IntType.php 프로젝트: aeshion/ZeroPHP
 /**
  * @param $value
  * @return int|null
  */
 private function coerceInt($value)
 {
     if ($value === '') {
         throw new InvariantViolation('Int cannot represent non 32-bit signed integer value: (empty string)');
     }
     if (false === $value || true === $value) {
         return (int) $value;
     }
     if (is_numeric($value) && $value <= self::MAX_INT && $value >= self::MIN_INT) {
         return (int) $value;
     }
     throw new InvariantViolation('Int cannot represent non 32-bit signed integer value: ' . Utils::printSafe($value));
 }
예제 #15
0
 public function __invoke(ValidationContext $context)
 {
     $operationCount = 0;
     return [NodeKind::DOCUMENT => function (DocumentNode $node) use(&$operationCount) {
         $tmp = Utils::filter($node->definitions, function ($definition) {
             return $definition->kind === NodeKind::OPERATION_DEFINITION;
         });
         $operationCount = count($tmp);
     }, NodeKind::OPERATION_DEFINITION => function (OperationDefinitionNode $node) use(&$operationCount, $context) {
         if (!$node->name && $operationCount > 1) {
             $context->reportError(new Error(self::anonOperationNotAloneMessage(), [$node]));
         }
     }];
 }
예제 #16
0
 public function __construct($config)
 {
     Config::validate($config, ['name' => Config::STRING | Config::REQUIRED, 'types' => Config::arrayOf(Config::OBJECT_TYPE | Config::REQUIRED), 'resolveType' => Config::CALLBACK, 'description' => Config::STRING]);
     Utils::invariant(!empty($config['types']), "");
     /**
      * Optionally provide a custom type resolver function. If one is not provided,
      * the default implemenation will call `isTypeOf` on each implementing
      * Object type.
      */
     $this->name = $config['name'];
     $this->description = isset($config['description']) ? $config['description'] : null;
     $this->_types = $config['types'];
     $this->_resolveType = isset($config['resolveType']) ? $config['resolveType'] : null;
 }
예제 #17
0
 /**
  * @return ObjectType[]
  */
 public function getTypes()
 {
     if (null === $this->types) {
         if ($this->config['types'] instanceof \Closure) {
             $types = call_user_func($this->config['types']);
         } else {
             $types = $this->config['types'];
         }
         Utils::invariant(is_array($types), 'Option "types" of union "%s" is expected to return array of types (or closure returning array of types)', $this->name);
         $this->types = [];
         foreach ($types as $type) {
             $this->types[] = Type::resolve($type);
         }
     }
     return $this->types;
 }
예제 #18
0
 public function __invoke(ValidationContext $context)
 {
     return [Node::ARGUMENT => function (Argument $node) use($context) {
         $fieldDef = $context->getFieldDef();
         if ($fieldDef) {
             $argDef = null;
             foreach ($fieldDef->args as $arg) {
                 if ($arg->name === $node->name->value) {
                     $argDef = $arg;
                     break;
                 }
             }
             if (!$argDef) {
                 $parentType = $context->getParentType();
                 Utils::invariant($parentType);
                 return new Error(Messages::unknownArgMessage($node->name->value, $fieldDef->name, $parentType->name), [$node]);
             }
         }
     }];
 }
예제 #19
0
 public function __invoke(ValidationContext $context)
 {
     return [NodeKind::ARGUMENT => function (ArgumentNode $node, $key, $parent, $path, $ancestors) use($context) {
         $argumentOf = $ancestors[count($ancestors) - 1];
         if ($argumentOf->kind === NodeKind::FIELD) {
             $fieldDef = $context->getFieldDef();
             if ($fieldDef) {
                 $fieldArgDef = null;
                 foreach ($fieldDef->args as $arg) {
                     if ($arg->name === $node->name->value) {
                         $fieldArgDef = $arg;
                         break;
                     }
                 }
                 if (!$fieldArgDef) {
                     $parentType = $context->getParentType();
                     Utils::invariant($parentType);
                     $context->reportError(new Error(self::unknownArgMessage($node->name->value, $fieldDef->name, $parentType->name), [$node]));
                 }
             }
         } else {
             if ($argumentOf->kind === NodeKind::DIRECTIVE) {
                 $directive = $context->getDirective();
                 if ($directive) {
                     $directiveArgDef = null;
                     foreach ($directive->args as $arg) {
                         if ($arg->name === $node->name->value) {
                             $directiveArgDef = $arg;
                             break;
                         }
                     }
                     if (!$directiveArgDef) {
                         $context->reportError(new Error(self::unknownDirectiveArgMessage($node->name->value, $directive->name), [$node]));
                     }
                 }
             }
         }
     }];
 }
예제 #20
0
 private function detectCycleRecursive(FragmentDefinition $fragment, ValidationContext $context)
 {
     $fragmentName = $fragment->name->value;
     $this->visitedFrags[$fragmentName] = true;
     $spreadNodes = $context->getFragmentSpreads($fragment);
     if (empty($spreadNodes)) {
         return;
     }
     $this->spreadPathIndexByName[$fragmentName] = count($this->spreadPath);
     for ($i = 0; $i < count($spreadNodes); $i++) {
         $spreadNode = $spreadNodes[$i];
         $spreadName = $spreadNode->name->value;
         $cycleIndex = isset($this->spreadPathIndexByName[$spreadName]) ? $this->spreadPathIndexByName[$spreadName] : null;
         if ($cycleIndex === null) {
             $this->spreadPath[] = $spreadNode;
             if (empty($this->visitedFrags[$spreadName])) {
                 $spreadFragment = $context->getFragment($spreadName);
                 if ($spreadFragment) {
                     $this->detectCycleRecursive($spreadFragment, $context);
                 }
             }
             array_pop($this->spreadPath);
         } else {
             $cyclePath = array_slice($this->spreadPath, $cycleIndex);
             $nodes = $cyclePath;
             if (is_array($spreadNode)) {
                 $nodes = array_merge($nodes, $spreadNode);
             } else {
                 $nodes[] = $spreadNode;
             }
             $context->reportError(new Error(self::cycleErrorMessage($spreadName, Utils::map($cyclePath, function ($s) {
                 return $s->name->value;
             })), $nodes));
         }
     }
     $this->spreadPathIndexByName[$fragmentName] = null;
 }
예제 #21
0
파일: Type.php 프로젝트: rtuin/graphql-php
 public static function resolve($type)
 {
     if (is_callable($type)) {
         $type = $type();
     }
     Utils::invariant($type instanceof Type, 'Expecting instance of ' . __CLASS__ . ' (or callable returning instance of that type), got "%s"', Utils::getVariableType($type));
     return $type;
 }
예제 #22
0
 /**
  * @param $typeName
  * @param $key
  * @param $value
  * @param $def
  * @param $pathStr
  * @throws \Exception
  */
 private static function validateEntry($typeName, $key, $value, $def, $pathStr)
 {
     $type = Utils::getVariableType($value);
     $err = 'Error in "' . $typeName . '" type definition: expecting %s at "' . $pathStr . '", but got "' . $type . '"';
     if ($def instanceof \stdClass) {
         if ($def->flags & self::REQUIRED === 0 && $value === null) {
             return;
         }
         if (($def->flags & self::MAYBE_THUNK) > 0) {
             Utils::invariant(is_array($value) || is_callable($value), $err, 'array or callable');
         } else {
             Utils::invariant(is_array($value), $err, 'array');
         }
         if (!empty($def->isMap)) {
             if ($def->flags & self::KEY_AS_NAME) {
                 $value += ['name' => $key];
             }
             self::validateMap($typeName, $value, $def->definition, $pathStr);
         } else {
             if (!empty($def->isArray)) {
                 if ($def->flags & self::REQUIRED) {
                     Utils::invariant(!empty($value), 'Error in "' . $typeName . '" type definition: ' . "Value at '{$pathStr}' cannot be empty array");
                 }
                 $err = 'Error in "' . $typeName . '" type definition: ' . "Each entry at '{$pathStr}' must be an array, but '%s' is '%s'";
                 foreach ($value as $arrKey => $arrValue) {
                     if (is_array($def->definition)) {
                         if ($def->flags & self::MAYBE_TYPE && $arrValue instanceof Type) {
                             $arrValue = ['type' => $arrValue];
                         }
                         if ($def->flags & self::MAYBE_NAME && is_string($arrValue)) {
                             $arrValue = ['name' => $arrValue];
                         }
                         Utils::invariant(is_array($arrValue), $err, $arrKey, Utils::getVariableType($arrValue));
                         if ($def->flags & self::KEY_AS_NAME) {
                             $arrValue += ['name' => $arrKey];
                         }
                         self::validateMap($typeName, $arrValue, $def->definition, "{$pathStr}:{$arrKey}");
                     } else {
                         self::validateEntry($typeName, $arrKey, $arrValue, $def->definition, "{$pathStr}:{$arrKey}");
                     }
                 }
             } else {
                 throw new InvariantViolation('Error in "' . $typeName . '" type definition: ' . "unexpected definition: " . print_r($def, true));
             }
         }
     } else {
         Utils::invariant(is_int($def), 'Error in "' . $typeName . '" type definition: ' . "Definition for '{$pathStr}' is expected to be single integer value");
         if ($def & self::REQUIRED) {
             Utils::invariant($value !== null, 'Value at "%s" can not be null', $pathStr);
         }
         if (null === $value) {
             return;
             // Allow nulls for non-required fields
         }
         switch (true) {
             case $def & self::ANY:
                 break;
             case $def & self::BOOLEAN:
                 Utils::invariant(is_bool($value), $err, 'boolean');
                 break;
             case $def & self::STRING:
                 Utils::invariant(is_string($value), $err, 'string');
                 break;
             case $def & self::NUMERIC:
                 Utils::invariant(is_numeric($value), $err, 'numeric');
                 break;
             case $def & self::FLOAT:
                 Utils::invariant(is_float($value), $err, 'float');
                 break;
             case $def & self::INT:
                 Utils::invariant(is_int($value), $err, 'int');
                 break;
             case $def & self::CALLBACK:
                 Utils::invariant(is_callable($value), $err, 'callable');
                 break;
             case $def & self::SCALAR:
                 Utils::invariant(is_scalar($value), $err, 'scalar');
                 break;
             case $def & self::NAME:
                 Utils::invariant(preg_match('~^[_a-zA-Z][_a-zA-Z0-9]*$~', $value), 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "%s" does not.', $value);
                 break;
             case $def & self::INPUT_TYPE:
                 Utils::invariant(is_callable($value) || $value instanceof InputType, $err, 'callable or InputType definition');
                 break;
             case $def & self::OUTPUT_TYPE:
                 Utils::invariant(is_callable($value) || $value instanceof OutputType, $err, 'callable or OutputType definition');
                 break;
             case $def & self::INTERFACE_TYPE:
                 Utils::invariant(is_callable($value) || $value instanceof InterfaceType, $err, 'callable or InterfaceType definition');
                 break;
             case $def & self::OBJECT_TYPE:
                 Utils::invariant(is_callable($value) || $value instanceof ObjectType, $err, 'callable or ObjectType definition');
                 break;
             default:
                 throw new InvariantViolation("Unexpected validation rule: " . $def);
         }
     }
 }
예제 #23
0
 public function __construct(array $data)
 {
     Utils::assign($this, $data);
 }
예제 #24
0
 /**
  * @param callable|Type $type
  */
 public function __construct($type)
 {
     Utils::invariant($type instanceof Type || is_callable($type), 'Expecting instance of GraphQL\\Type\\Definition\\Type or callable returning instance of that class');
     $this->ofType = $type;
 }
예제 #25
0
 /**
  * Complete an Object value by executing all sub-selections.
  *
  * @param ExecutionContext $exeContext
  * @param ObjectType $returnType
  * @param $fieldNodes
  * @param ResolveInfo $info
  * @param array $path
  * @param $result
  * @return array|Promise|\stdClass
  * @throws Error
  */
 private static function completeObjectValue(ExecutionContext $exeContext, ObjectType $returnType, $fieldNodes, ResolveInfo $info, $path, &$result)
 {
     // If there is an isTypeOf predicate function, call it with the
     // current result. If isTypeOf returns false, then raise an error rather
     // than continuing execution.
     if (false === $returnType->isTypeOf($result, $exeContext->contextValue, $info)) {
         throw new Error("Expected value of type {$returnType} but got: " . Utils::getVariableType($result), $fieldNodes);
     }
     // Collect sub-fields to execute to complete this value.
     $subFieldNodes = new \ArrayObject();
     $visitedFragmentNames = new \ArrayObject();
     foreach ($fieldNodes as $fieldNode) {
         if (isset($fieldNode->selectionSet)) {
             $subFieldNodes = self::collectFields($exeContext, $returnType, $fieldNode->selectionSet, $subFieldNodes, $visitedFragmentNames);
         }
     }
     return self::executeFields($exeContext, $returnType, $result, $path, $subFieldNodes);
 }
예제 #26
0
 /**
  * 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');
 }
예제 #27
0
 public function getField($name)
 {
     Utils::invariant(isset($this->_fields[$name]), 'Field "%s" is not defined for type "%s"', $name, $this->name);
     return $this->_fields[$name];
 }
예제 #28
0
 /**
  * Implements the instructions for completeValue as defined in the
  * "Field entries" section of the spec.
  *
  * If the field type is Non-Null, then this recursively completes the value
  * for the inner type. It throws a field error if that completion returns null,
  * as per the "Nullability" section of the spec.
  *
  * If the field type is a List, then this recursively completes the value
  * for the inner type on each item in the list.
  *
  * If the field type is a Scalar or Enum, ensures the completed value is a legal
  * value of the type by calling the `serialize` method of GraphQL type
  * definition.
  *
  * Otherwise, the field type expects a sub-selection set, and will complete the
  * value by evaluating all sub-selections.
  */
 private static function completeValue(ExecutionContext $exeContext, Type $returnType, $fieldASTs, ResolveInfo $info, &$result)
 {
     // If field type is NonNull, complete for inner type, and throw field error
     // if result is null.
     if ($returnType instanceof NonNull) {
         $completed = self::completeValue($exeContext, $returnType->getWrappedType(), $fieldASTs, $info, $result);
         if ($completed === null) {
             throw new Error('Cannot return null for non-nullable type.', $fieldASTs instanceof \ArrayObject ? $fieldASTs->getArrayCopy() : $fieldASTs);
         }
         return $completed;
     }
     // If result is null-like, return null.
     if (null === $result) {
         return null;
     }
     // If field type is List, complete each item in the list with the inner type
     if ($returnType instanceof ListOfType) {
         $itemType = $returnType->getWrappedType();
         Utils::invariant(is_array($result) || $result instanceof \Traversable, 'User Error: expected iterable, but did not find one.');
         $tmp = [];
         foreach ($result as $item) {
             $tmp[] = self::completeValueCatchingError($exeContext, $itemType, $fieldASTs, $info, $item);
         }
         return $tmp;
     }
     // If field type is Scalar or Enum, serialize to a valid value, returning
     // null if serialization is not possible.
     if ($returnType instanceof ScalarType || $returnType instanceof EnumType) {
         Utils::invariant(method_exists($returnType, 'serialize'), 'Missing serialize method on type');
         return $returnType->serialize($result);
     }
     // Field type must be Object, Interface or Union and expect sub-selections.
     if ($returnType instanceof ObjectType) {
         $objectType = $returnType;
     } else {
         if ($returnType instanceof AbstractType) {
             $objectType = $returnType->getObjectType($result, $info);
             if ($objectType && !$returnType->isPossibleType($objectType)) {
                 throw new Error("Runtime Object type \"{$objectType}\" is not a possible type for \"{$returnType}\".");
             }
         } else {
             $objectType = null;
         }
     }
     if (!$objectType) {
         return null;
     }
     // If there is an isTypeOf predicate function, call it with the
     // current result. If isTypeOf returns false, then raise an error rather
     // than continuing execution.
     if (false === $objectType->isTypeOf($result, $info)) {
         throw new Error("Expected value of type {$objectType} but got: {$result}.", $fieldASTs);
     }
     // Collect sub-fields to execute to complete this value.
     $subFieldASTs = new \ArrayObject();
     $visitedFragmentNames = new \ArrayObject();
     for ($i = 0; $i < count($fieldASTs); $i++) {
         $selectionSet = $fieldASTs[$i]->selectionSet;
         if ($selectionSet) {
             $subFieldASTs = self::collectFields($exeContext, $objectType, $selectionSet, $subFieldASTs, $visitedFragmentNames);
         }
     }
     return self::executeFields($exeContext, $objectType, $result, $subFieldASTs);
 }
 private function subfieldConflicts(array $conflicts, $responseName, FieldNode $ast1, FieldNode $ast2)
 {
     if (!empty($conflicts)) {
         return [[$responseName, Utils::map($conflicts, function ($conflict) {
             return $conflict[0];
         })], array_reduce($conflicts, function ($allFields, $conflict) {
             return array_merge($allFields, $conflict[1]);
         }, [$ast1]), array_reduce($conflicts, function ($allFields, $conflict) {
             return array_merge($allFields, $conflict[2]);
         }, [$ast2])];
     }
 }
예제 #30
0
파일: AST.php 프로젝트: aeshion/ZeroPHP
 /**
  * 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');
 }