getVariableType() public static method

public static getVariableType ( $var ) : string
$var
return string
Example #1
0
 /**
  * @param Schema $schema
  * @param Document $ast
  * @param $rootValue
  * @param array|\ArrayAccess $variableValues
  * @param null $operationName
  * @return ExecutionResult
  */
 public static function execute(Schema $schema, Document $ast, $rootValue = null, $variableValues = null, $operationName = null)
 {
     if (!self::$UNDEFINED) {
         self::$UNDEFINED = new \stdClass();
     }
     if (null !== $variableValues) {
         Utils::invariant(is_array($variableValues) || $variableValues instanceof \ArrayAccess, "Variable values are expected to be array or instance of ArrayAccess, got " . Utils::getVariableType($variableValues));
     }
     if (null !== $operationName) {
         Utils::invariant(is_string($operationName), "Operation name is supposed to be string, got " . Utils::getVariableType($operationName));
     }
     $exeContext = self::buildExecutionContext($schema, $ast, $rootValue, $variableValues, $operationName);
     try {
         $data = self::executeOperation($exeContext, $exeContext->operation, $rootValue);
     } catch (Error $e) {
         $exeContext->addError($e);
         $data = null;
     }
     return new ExecutionResult($data, $exeContext->errors);
 }
Example #2
0
 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;
 }
Example #3
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);
         }
     }
 }
Example #4
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);
 }
Example #5
0
 /**
  * @param array $config
  */
 protected function init(array $config)
 {
     $config += ['query' => null, 'mutation' => null, 'subscription' => null, 'types' => [], 'directives' => [], 'validate' => true];
     if ($config['query'] instanceof DefinitionContainer) {
         $config['query'] = $config['query']->getDefinition();
     }
     if ($config['mutation'] instanceof DefinitionContainer) {
         $config['mutation'] = $config['mutation']->getDefinition();
     }
     if ($config['subscription'] instanceof DefinitionContainer) {
         $config['subscription'] = $config['subscription']->getDefinition();
     }
     Utils::invariant($config['query'] instanceof ObjectType, "Schema query must be Object Type but got: " . Utils::getVariableType($config['query']));
     $this->queryType = $config['query'];
     Utils::invariant(!$config['mutation'] || $config['mutation'] instanceof ObjectType, "Schema mutation must be Object Type if provided but got: " . Utils::getVariableType($config['mutation']));
     $this->mutationType = $config['mutation'];
     Utils::invariant(!$config['subscription'] || $config['subscription'] instanceof ObjectType, "Schema subscription must be Object Type if provided but got: " . Utils::getVariableType($config['subscription']));
     $this->subscriptionType = $config['subscription'];
     Utils::invariant(!$config['types'] || is_array($config['types']), "Schema types must be Array if provided but got: " . Utils::getVariableType($config['types']));
     Utils::invariant(!$config['directives'] || is_array($config['directives']) && Utils::every($config['directives'], function ($d) {
         return $d instanceof Directive;
     }), "Schema directives must be Directive[] if provided but got " . Utils::getVariableType($config['directives']));
     $this->directives = $config['directives'] ?: GraphQL::getInternalDirectives();
     // Build type map now to detect any errors within this schema.
     $initialTypes = [$config['query'], $config['mutation'], $config['subscription'], Introspection::_schema()];
     if (!empty($config['types'])) {
         $initialTypes = array_merge($initialTypes, $config['types']);
     }
     foreach ($initialTypes as $type) {
         $this->extractTypes($type);
     }
     $this->typeMap += Type::getInternalTypes();
     // Keep track of all implementations by interface name.
     $this->implementations = [];
     foreach ($this->typeMap as $typeName => $type) {
         if ($type instanceof ObjectType) {
             foreach ($type->getInterfaces() as $iface) {
                 $this->implementations[$iface->name][] = $type;
             }
         }
     }
 }
 /**
  * Given list of parent type values returns corresponding list of field values
  *
  * In particular, this
  * figures out the value that the field returns by calling its `resolve` or `map` function,
  * then calls `completeValue` on each value to serialize scalars, or execute the sub-selection-set
  * for objects.
  *
  * @param ExecutionContext $exeContext
  * @param ObjectType $parentType
  * @param $sourceValueList
  * @param $fieldASTs
  * @return array
  * @throws Error
  */
 private static function resolveField(ExecutionContext $exeContext, ObjectType $parentType, $sourceValueList, $fieldASTs, $responseName, &$resolveResult)
 {
     $fieldAST = $fieldASTs[0];
     $fieldName = $fieldAST->name->value;
     $fieldDef = self::getFieldDef($exeContext->schema, $parentType, $fieldName);
     if (!$fieldDef) {
         return;
     }
     $returnType = $fieldDef->getType();
     // Build hash of arguments from the field.arguments AST, using the
     // variables scope to fulfill any variable references.
     // TODO: find a way to memoize, in case this field is within a List type.
     $args = Values::getArgumentValues($fieldDef->args, $fieldAST->arguments, $exeContext->variableValues);
     // The resolve function's optional third argument is a collection of
     // information about the current execution state.
     $info = new ResolveInfo(['fieldName' => $fieldName, 'fieldASTs' => $fieldASTs, 'returnType' => $returnType, 'parentType' => $parentType, 'schema' => $exeContext->schema, 'fragments' => $exeContext->fragments, 'rootValue' => $exeContext->rootValue, 'operation' => $exeContext->operation, 'variableValues' => $exeContext->variableValues]);
     $mapFn = $fieldDef->mapFn;
     // If an error occurs while calling the field `map` or `resolve` function, ensure that
     // it is wrapped as a GraphQLError with locations. Log this error and return
     // null if allowed, otherwise throw the error so the parent field can handle
     // it.
     if ($mapFn) {
         try {
             $mapped = call_user_func($mapFn, $sourceValueList, $args, $info);
             $validType = is_array($mapped) || $mapped instanceof \Traversable && $mapped instanceof \Countable;
             $mappedCount = count($mapped);
             $sourceCount = count($sourceValueList);
             Utils::invariant($validType && count($mapped) === count($sourceValueList), "Function `map` of {$parentType}.{$fieldName} is expected to return array or " . "countable traversable with exact same number of items as list being mapped. " . "Got '%s' with count '{$mappedCount}' against '{$sourceCount}' expected.", Utils::getVariableType($mapped));
         } catch (\Exception $error) {
             $reportedError = Error::createLocatedError($error, $fieldASTs);
             if ($returnType instanceof NonNull) {
                 throw $reportedError;
             }
             $exeContext->addError($reportedError);
             return null;
         }
         foreach ($mapped as $index => $value) {
             $resolveResult[$index][$responseName] = self::completeValueCatchingError($exeContext, $returnType, $fieldASTs, $info, $value);
         }
     } else {
         if (isset($fieldDef->resolveFn)) {
             $resolveFn = $fieldDef->resolveFn;
         } else {
             if (isset($parentType->resolveFieldFn)) {
                 $resolveFn = $parentType->resolveFieldFn;
             } else {
                 $resolveFn = self::$defaultResolveFn;
             }
         }
         foreach ($sourceValueList as $index => $value) {
             try {
                 $resolved = call_user_func($resolveFn, $value, $args, $info);
             } catch (\Exception $error) {
                 $reportedError = Error::createLocatedError($error, $fieldASTs);
                 if ($returnType instanceof NonNull) {
                     throw $reportedError;
                 }
                 $exeContext->addError($reportedError);
                 $resolved = null;
             }
             $resolveResult[$index][$responseName] = self::completeValueCatchingError($exeContext, $returnType, $fieldASTs, $info, $resolved);
         }
     }
 }
Example #7
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 ($result instanceof \Exception) {
         throw Error::createLocatedError($result, $fieldASTs);
     }
     // 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) {
         $runtimeType = $returnType;
     } else {
         if ($returnType instanceof AbstractType) {
             $runtimeType = $returnType->getObjectType($result, $info);
             if ($runtimeType && !$returnType->isPossibleType($runtimeType)) {
                 throw new Error("Runtime Object type \"{$runtimeType}\" is not a possible type for \"{$returnType}\".");
             }
         } else {
             $runtimeType = null;
         }
     }
     if (!$runtimeType) {
         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 === $runtimeType->isTypeOf($result, $info)) {
         throw new Error("Expected value of type {$runtimeType} but got: " . Utils::getVariableType($result), $fieldASTs);
     }
     // Collect sub-fields to execute to complete this value.
     $subFieldASTs = new \ArrayObject();
     $visitedFragmentNames = new \ArrayObject();
     for ($i = 0; $i < count($fieldASTs); $i++) {
         // Get memoized value if it exists
         $uid = self::getFieldUid($fieldASTs[$i], $runtimeType);
         if (isset($exeContext->memoized['collectSubFields'][$uid])) {
             $subFieldASTs = $exeContext->memoized['collectSubFields'][$uid];
         } else {
             $selectionSet = $fieldASTs[$i]->selectionSet;
             if ($selectionSet) {
                 $subFieldASTs = self::collectFields($exeContext, $runtimeType, $selectionSet, $subFieldASTs, $visitedFragmentNames);
                 $exeContext->memoized['collectSubFields'][$uid] = $subFieldASTs;
             }
         }
     }
     return self::executeFields($exeContext, $runtimeType, $result, $subFieldASTs);
 }
Example #8
0
 private static function _validateEntry($key, $value, $def, $pathStr)
 {
     $type = Utils::getVariableType($value);
     $err = 'Expecting %s at "' . $pathStr . '", but got "' . $type . '"';
     if ($def instanceof \stdClass) {
         if ($def->flags & self::REQUIRED === 0 && $value === null) {
             return;
         }
         Utils::invariant(is_array($value), $err, 'array');
         if (!empty($def->isMap)) {
             if ($def->flags & self::KEY_AS_NAME) {
                 $value += ['name' => $key];
             }
             self::_validateMap($value, $def->definition, $pathStr);
         } else {
             if (!empty($def->isArray)) {
                 if ($def->flags & self::REQUIRED) {
                     Utils::invariant(!empty($value), "Value at '{$pathStr}' cannot be empty array");
                 }
                 $err = "Each entry at '{$pathStr}' must be an array, but '%s' is '%s'";
                 foreach ($value as $arrKey => $arrValue) {
                     if (is_array($def->definition)) {
                         Utils::invariant(is_array($arrValue), $err, $arrKey, Utils::getVariableType($arrValue));
                         if ($def->flags & self::KEY_AS_NAME) {
                             $arrValue += ['name' => $arrKey];
                         }
                         self::_validateMap($arrValue, $def->definition, "{$pathStr}:{$arrKey}");
                     } else {
                         self::_validateEntry($arrKey, $arrValue, $def->definition, "{$pathStr}:{$arrKey}");
                     }
                 }
             } else {
                 throw new \Exception("Unexpected definition: " . print_r($def, true));
             }
         }
     } else {
         Utils::invariant(is_int($def), "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);
         }
         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::INPUT_TYPE:
                 Utils::invariant(is_callable($value) || $value instanceof InputType, $err, 'callable or instance of GraphQL\\Type\\Definition\\InputType');
                 break;
             case $def & self::OUTPUT_TYPE:
                 Utils::invariant(is_callable($value) || $value instanceof OutputType, $err, 'callable or instance of GraphQL\\Type\\Definition\\OutputType');
                 break;
             case $def & self::INTERFACE_TYPE:
                 Utils::invariant(is_callable($value) || $value instanceof InterfaceType, $err, 'callable or instance of GraphQL\\Type\\Definition\\InterfaceType');
                 break;
             case $def & self::OBJECT_TYPE:
                 Utils::invariant(is_callable($value) || $value instanceof ObjectType, $err, 'callable or instance of GraphQL\\Type\\Definition\\ObjectType');
                 break;
             default:
                 throw new \Exception("Unexpected validation rule: " . $def);
         }
     }
 }
Example #9
0
 /**
  * @param $type
  * @return mixed
  */
 public static function resolve($type)
 {
     if (is_callable($type)) {
         trigger_error('Passing type as closure is deprecated (see https://github.com/webonyx/graphql-php/issues/35 for alternatives)', E_USER_DEPRECATED);
         $type = $type();
     }
     if ($type instanceof DefinitionContainer) {
         $type = $type->getDefinition();
     }
     if (!$type instanceof Type) {
         throw new InvariantViolation(sprintf('Expecting instance of ' . __CLASS__ . ', got "%s"', Utils::getVariableType($type)));
     }
     return $type;
 }
Example #10
0
 /**
  * @it prohibits putting non-Object types in unions
  */
 public function testProhibitsPuttingNonObjectTypesInUnions()
 {
     $int = Type::int();
     $badUnionTypes = [$int, new NonNull($int), new ListOfType($int), $this->interfaceType, $this->unionType, $this->enumType, $this->inputObjectType];
     // TODO: extract config validation to separate test
     Config::enableValidation();
     foreach ($badUnionTypes as $type) {
         try {
             new UnionType(['name' => 'BadUnion', 'types' => [$type]]);
             $this->fail('Expected exception not thrown');
         } catch (\Exception $e) {
             $this->assertSame('Error in "BadUnion" type definition: expecting callable or ObjectType definition at "types:0", but got "' . Utils::getVariableType($type) . '"', $e->getMessage());
         }
     }
     Config::disableValidation();
 }