vendor/webonyx/graphql-php/src/Type/Definition/FieldDefinition.php line 98

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace GraphQL\Type\Definition;
  4. use GraphQL\Error\Error;
  5. use GraphQL\Error\InvariantViolation;
  6. use GraphQL\Error\Warning;
  7. use GraphQL\Language\AST\FieldDefinitionNode;
  8. use GraphQL\Type\Schema;
  9. use GraphQL\Utils\Utils;
  10. use function is_array;
  11. use function is_callable;
  12. use function is_iterable;
  13. use function is_string;
  14. use function sprintf;
  15. /**
  16.  * @todo Move complexity-related code to it's own place
  17.  */
  18. #[\AllowDynamicProperties]
  19. class FieldDefinition
  20. {
  21.     public const DEFAULT_COMPLEXITY_FN 'GraphQL\Type\Definition\FieldDefinition::defaultComplexity';
  22.     /** @var string */
  23.     public $name;
  24.     /** @var FieldArgument[] */
  25.     public $args;
  26.     /**
  27.      * Callback for resolving field value given parent value.
  28.      * Mutually exclusive with `map`
  29.      *
  30.      * @var callable|null
  31.      */
  32.     public $resolveFn;
  33.     /**
  34.      * Callback for mapping list of parent values to list of field values.
  35.      * Mutually exclusive with `resolve`
  36.      *
  37.      * @var callable|null
  38.      */
  39.     public $mapFn;
  40.     /** @var string|null */
  41.     public $description;
  42.     /** @var string|null */
  43.     public $deprecationReason;
  44.     /** @var FieldDefinitionNode|null */
  45.     public $astNode;
  46.     /**
  47.      * Original field definition config
  48.      *
  49.      * @var mixed[]
  50.      */
  51.     public $config;
  52.     /** @var OutputType&Type */
  53.     private $type;
  54.     /** @var callable|string */
  55.     private $complexityFn;
  56.     /**
  57.      * @param mixed[] $config
  58.      */
  59.     protected function __construct(array $config)
  60.     {
  61.         $this->name      $config['name'];
  62.         $this->resolveFn $config['resolve'] ?? null;
  63.         $this->mapFn     $config['map'] ?? null;
  64.         $this->args      = isset($config['args']) ? FieldArgument::createMap($config['args']) : [];
  65.         $this->description       $config['description'] ?? null;
  66.         $this->deprecationReason $config['deprecationReason'] ?? null;
  67.         $this->astNode           $config['astNode'] ?? null;
  68.         $this->config $config;
  69.         $this->complexityFn $config['complexity'] ?? self::DEFAULT_COMPLEXITY_FN;
  70.     }
  71.     /**
  72.      * @param (callable():mixed[])|mixed[] $fields
  73.      *
  74.      * @return array<string, self>
  75.      */
  76.     public static function defineFieldMap(Type $type$fields) : array
  77.     {
  78.         if (is_callable($fields)) {
  79.             $fields $fields();
  80.         }
  81.         if (! is_iterable($fields)) {
  82.             throw new InvariantViolation(
  83.                 sprintf('%s fields must be an iterable or a callable which returns such an iterable.'$type->name)
  84.             );
  85.         }
  86.         $map = [];
  87.         foreach ($fields as $name => $field) {
  88.             if (is_array($field)) {
  89.                 if (! isset($field['name'])) {
  90.                     if (! is_string($name)) {
  91.                         throw new InvariantViolation(
  92.                             sprintf(
  93.                                 '%s fields must be an associative array with field names as keys or a function which returns such an array.',
  94.                                 $type->name
  95.                             )
  96.                         );
  97.                     }
  98.                     $field['name'] = $name;
  99.                 }
  100.                 if (isset($field['args']) && ! is_array($field['args'])) {
  101.                     throw new InvariantViolation(
  102.                         sprintf('%s.%s args must be an array.'$type->name$name)
  103.                     );
  104.                 }
  105.                 $fieldDef self::create($field);
  106.             } elseif ($field instanceof self) {
  107.                 $fieldDef $field;
  108.             } elseif (is_callable($field)) {
  109.                 if (! is_string($name)) {
  110.                     throw new InvariantViolation(
  111.                         sprintf(
  112.                             '%s lazy fields must be an associative array with field names as keys.',
  113.                             $type->name
  114.                         )
  115.                     );
  116.                 }
  117.                 $fieldDef = new UnresolvedFieldDefinition($type$name$field);
  118.             } else {
  119.                 if (! is_string($name) || ! $field) {
  120.                     throw new InvariantViolation(
  121.                         sprintf(
  122.                             '%s.%s field config must be an array, but got: %s',
  123.                             $type->name,
  124.                             $name,
  125.                             Utils::printSafe($field)
  126.                         )
  127.                     );
  128.                 }
  129.                 $fieldDef self::create(['name' => $name'type' => $field]);
  130.             }
  131.             $map[$fieldDef->getName()] = $fieldDef;
  132.         }
  133.         return $map;
  134.     }
  135.     /**
  136.      * @param mixed[] $field
  137.      *
  138.      * @return FieldDefinition
  139.      */
  140.     public static function create($field)
  141.     {
  142.         return new self($field);
  143.     }
  144.     /**
  145.      * @param int $childrenComplexity
  146.      *
  147.      * @return mixed
  148.      */
  149.     public static function defaultComplexity($childrenComplexity)
  150.     {
  151.         return $childrenComplexity 1;
  152.     }
  153.     /**
  154.      * @param string $name
  155.      *
  156.      * @return FieldArgument|null
  157.      */
  158.     public function getArg($name)
  159.     {
  160.         foreach ($this->args ?? [] as $arg) {
  161.             /** @var FieldArgument $arg */
  162.             if ($arg->name === $name) {
  163.                 return $arg;
  164.             }
  165.         }
  166.         return null;
  167.     }
  168.     public function getName() : string
  169.     {
  170.         return $this->name;
  171.     }
  172.     public function getType() : Type
  173.     {
  174.         if (! isset($this->type)) {
  175.             /**
  176.              * TODO: replace this phpstan cast with native assert
  177.              *
  178.              * @var Type&OutputType
  179.              */
  180.             $type       Schema::resolveType($this->config['type']);
  181.             $this->type $type;
  182.         }
  183.         return $this->type;
  184.     }
  185.     public function __isset(string $name) : bool
  186.     {
  187.         switch ($name) {
  188.             case 'type':
  189.                 Warning::warnOnce(
  190.                     "The public getter for 'type' on FieldDefinition has been deprecated and will be removed" .
  191.                     " in the next major version. Please update your code to use the 'getType' method.",
  192.                     Warning::WARNING_CONFIG_DEPRECATION
  193.                 );
  194.                 return isset($this->type);
  195.         }
  196.         return isset($this->$name);
  197.     }
  198.     public function __get(string $name)
  199.     {
  200.         switch ($name) {
  201.             case 'type':
  202.                 Warning::warnOnce(
  203.                     "The public getter for 'type' on FieldDefinition has been deprecated and will be removed" .
  204.                     " in the next major version. Please update your code to use the 'getType' method.",
  205.                     Warning::WARNING_CONFIG_DEPRECATION
  206.                 );
  207.                 return $this->getType();
  208.             default:
  209.                 return $this->$name;
  210.         }
  211.         return null;
  212.     }
  213.     public function __set(string $name$value)
  214.     {
  215.         switch ($name) {
  216.             case 'type':
  217.                 Warning::warnOnce(
  218.                     "The public setter for 'type' on FieldDefinition has been deprecated and will be removed" .
  219.                     ' in the next major version.',
  220.                     Warning::WARNING_CONFIG_DEPRECATION
  221.                 );
  222.                 $this->type $value;
  223.                 break;
  224.             default:
  225.                 $this->$name $value;
  226.                 break;
  227.         }
  228.     }
  229.     /**
  230.      * @return bool
  231.      */
  232.     public function isDeprecated()
  233.     {
  234.         return (bool) $this->deprecationReason;
  235.     }
  236.     /**
  237.      * @return callable|callable
  238.      */
  239.     public function getComplexityFn()
  240.     {
  241.         return $this->complexityFn;
  242.     }
  243.     /**
  244.      * @throws InvariantViolation
  245.      */
  246.     public function assertValid(Type $parentType)
  247.     {
  248.         try {
  249.             Utils::assertValidName($this->name);
  250.         } catch (Error $e) {
  251.             throw new InvariantViolation(sprintf('%s.%s: %s'$parentType->name$this->name$e->getMessage()));
  252.         }
  253.         Utils::invariant(
  254.             ! isset($this->config['isDeprecated']),
  255.             sprintf(
  256.                 '%s.%s should provide "deprecationReason" instead of "isDeprecated".',
  257.                 $parentType->name,
  258.                 $this->name
  259.             )
  260.         );
  261.         $type $this->getType();
  262.         if ($type instanceof WrappingType) {
  263.             $type $type->getWrappedType(true);
  264.         }
  265.         Utils::invariant(
  266.             $type instanceof OutputType,
  267.             sprintf(
  268.                 '%s.%s field type must be Output Type but got: %s',
  269.                 $parentType->name,
  270.                 $this->name,
  271.                 Utils::printSafe($this->type)
  272.             )
  273.         );
  274.         Utils::invariant(
  275.             $this->resolveFn === null || is_callable($this->resolveFn),
  276.             sprintf(
  277.                 '%s.%s field resolver must be a function if provided, but got: %s',
  278.                 $parentType->name,
  279.                 $this->name,
  280.                 Utils::printSafe($this->resolveFn)
  281.             )
  282.         );
  283.         foreach ($this->args as $fieldArgument) {
  284.             $fieldArgument->assertValid($this$type);
  285.         }
  286.     }
  287. }