Failed Conditions
Pull Request — master (#294)
by Daniel
05:35
created

SchemaPrinterTest::testCustomScalar()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 29
rs 9.456
c 0
b 0
f 0
cc 2
nc 1
nop 0
1
<?php
2
namespace GraphQL\Tests\Utils;
3
4
use GraphQL\Language\DirectiveLocation;
5
use GraphQL\Type\Schema;
6
use GraphQL\Type\Definition\CustomScalarType;
7
use GraphQL\Type\Definition\Directive;
8
use GraphQL\Type\Definition\InputObjectType;
9
use GraphQL\Type\Definition\InterfaceType;
10
use GraphQL\Type\Definition\ObjectType;
11
use GraphQL\Type\Definition\Type;
12
use GraphQL\Type\Definition\EnumType;
13
use GraphQL\Type\Definition\UnionType;
14
use GraphQL\Utils\BuildSchema;
15
use GraphQL\Utils\SchemaPrinter;
16
17
class SchemaPrinterTest extends \PHPUnit_Framework_TestCase
18
{
19
    // Describe: Type System Printer
20
21
    private function printForTest($schema)
22
    {
23
        return "\n" . SchemaPrinter::doPrint($schema);
24
    }
25
26
    private function printSingleFieldSchema($fieldConfig)
27
    {
28
        $query = new ObjectType([
29
            'name' => 'Query',
30
            'fields' => [
31
                'singleField' => $fieldConfig
32
            ]
33
        ]);
34
        return $this->printForTest(new Schema(['query' => $query]));
35
    }
36
37
    /**
38
     * @it Prints String Field
39
     */
40
    public function testPrintsStringField()
41
    {
42
        $output = $this->printSingleFieldSchema([
43
            'type' => Type::string()
44
        ]);
45
        $this->assertEquals('
46
type Query {
47
  singleField: String
48
}
49
', $output);
50
    }
51
52
    /**
53
     * @it Prints [String] Field
54
     */
55
    public function testPrintArrayStringField()
56
    {
57
        $output = $this->printSingleFieldSchema([
58
            'type' => Type::listOf(Type::string())
59
        ]);
60
        $this->assertEquals('
61
type Query {
62
  singleField: [String]
63
}
64
', $output);
65
    }
66
67
    /**
68
     * @it Prints String! Field
69
     */
70
    public function testPrintNonNullStringField()
71
    {
72
        $output = $this->printSingleFieldSchema([
73
            'type' => Type::nonNull(Type::string())
74
        ]);
75
        $this->assertEquals('
76
type Query {
77
  singleField: String!
78
}
79
', $output);
80
    }
81
82
    /**
83
     * @it Prints [String]! Field
84
     */
85
    public function testPrintNonNullArrayStringField()
86
    {
87
        $output = $this->printSingleFieldSchema([
88
            'type' => Type::nonNull(Type::listOf(Type::string()))
89
        ]);
90
        $this->assertEquals('
91
type Query {
92
  singleField: [String]!
93
}
94
', $output);
95
    }
96
97
    /**
98
     * @it Prints [String!] Field
99
     */
100
    public function testPrintArrayNonNullStringField()
101
    {
102
        $output = $this->printSingleFieldSchema([
103
            'type' => Type::listOf(Type::nonNull(Type::string()))
104
        ]);
105
        $this->assertEquals('
106
type Query {
107
  singleField: [String!]
108
}
109
', $output);
110
    }
111
112
    /**
113
     * @it Prints [String!]! Field
114
     */
115
    public function testPrintNonNullArrayNonNullStringField()
116
    {
117
        $output = $this->printSingleFieldSchema([
118
            'type' => Type::nonNull(Type::listOf(Type::nonNull(Type::string())))
119
        ]);
120
        $this->assertEquals('
121
type Query {
122
  singleField: [String!]!
123
}
124
', $output);
125
    }
126
127
    /**
128
     * @it Prints Object Field
129
     */
130
    public function testPrintObjectField()
131
    {
132
        $fooType = new ObjectType([
133
            'name' => 'Foo',
134
            'fields' => ['str' => ['type' => Type::string()]]
135
        ]);
136
137
        $root = new ObjectType([
138
            'name' => 'Root',
139
            'fields' => ['foo' => ['type' => $fooType]]
140
        ]);
141
142
        $schema = new Schema(['query' => $root]);
143
        $output = $this->printForTest($schema);
144
        $this->assertEquals('
145
schema {
146
  query: Root
147
}
148
149
type Foo {
150
  str: String
151
}
152
153
type Root {
154
  foo: Foo
155
}
156
', $output);
157
    }
158
159
    /**
160
     * @it Prints String Field With Int Arg
161
     */
162
    public function testPrintsStringFieldWithIntArg()
163
    {
164
        $output = $this->printSingleFieldSchema([
165
            'type' => Type::string(),
166
            'args' => ['argOne' => ['type' => Type::int()]]
167
        ]);
168
        $this->assertEquals('
169
type Query {
170
  singleField(argOne: Int): String
171
}
172
', $output);
173
    }
174
175
    /**
176
     * @it Prints String Field With Int Arg With Default
177
     */
178
    public function testPrintsStringFieldWithIntArgWithDefault()
179
    {
180
        $output = $this->printSingleFieldSchema([
181
            'type' => Type::string(),
182
            'args' => ['argOne' => ['type' => Type::int(), 'defaultValue' => 2]]
183
        ]);
184
        $this->assertEquals('
185
type Query {
186
  singleField(argOne: Int = 2): String
187
}
188
', $output);
189
    }
190
191
    /**
192
     * @it Prints String Field With Int Arg With Default Null
193
     */
194
    public function testPrintsStringFieldWithIntArgWithDefaultNull()
195
    {
196
        $output = $this->printSingleFieldSchema([
197
            'type' => Type::string(),
198
            'args' => ['argOne' => ['type' => Type::int(), 'defaultValue' => null]]
199
        ]);
200
        $this->assertEquals('
201
type Query {
202
  singleField(argOne: Int = null): String
203
}
204
', $output);
205
    }
206
207
    /**
208
     * @it Prints String Field With Int! Arg
209
     */
210
    public function testPrintsStringFieldWithNonNullIntArg()
211
    {
212
        $output = $this->printSingleFieldSchema([
213
            'type' => Type::string(),
214
            'args' => ['argOne' => ['type' => Type::nonNull(Type::int())]]
215
        ]);
216
        $this->assertEquals('
217
type Query {
218
  singleField(argOne: Int!): String
219
}
220
', $output);
221
    }
222
223
    /**
224
     * @it Prints String Field With Multiple Args
225
     */
226
    public function testPrintsStringFieldWithMultipleArgs()
227
    {
228
        $output = $this->printSingleFieldSchema([
229
            'type' => Type::string(),
230
            'args' => [
231
                'argOne' => ['type' => Type::int()],
232
                'argTwo' => ['type' => Type::string()]
233
            ]
234
        ]);
235
        $this->assertEquals('
236
type Query {
237
  singleField(argOne: Int, argTwo: String): String
238
}
239
', $output);
240
    }
241
242
    /**
243
     * @it Prints String Field With Multiple Args, First is Default
244
     */
245
    public function testPrintsStringFieldWithMultipleArgsFirstIsDefault()
246
    {
247
        $output = $this->printSingleFieldSchema([
248
            'type' => Type::string(),
249
            'args' => [
250
                'argOne' => ['type' => Type::int(), 'defaultValue' => 1],
251
                'argTwo' => ['type' => Type::string()],
252
                'argThree' => ['type' => Type::boolean()]
253
            ]
254
        ]);
255
        $this->assertEquals('
256
type Query {
257
  singleField(argOne: Int = 1, argTwo: String, argThree: Boolean): String
258
}
259
', $output);
260
    }
261
262
    /**
263
     * @it Prints String Field With Multiple Args, Second is Default
264
     */
265
    public function testPrintsStringFieldWithMultipleArgsSecondIsDefault()
266
    {
267
        $output = $this->printSingleFieldSchema([
268
            'type' => Type::string(),
269
            'args' => [
270
                'argOne' => ['type' => Type::int()],
271
                'argTwo' => ['type' => Type::string(), 'defaultValue' => 'foo'],
272
                'argThree' => ['type' => Type::boolean()]
273
            ]
274
        ]);
275
        $this->assertEquals('
276
type Query {
277
  singleField(argOne: Int, argTwo: String = "foo", argThree: Boolean): String
278
}
279
', $output);
280
    }
281
282
    /**
283
     * @it Prints String Field With Multiple Args, Last is Default
284
     */
285
    public function testPrintsStringFieldWithMultipleArgsLastIsDefault()
286
    {
287
        $output = $this->printSingleFieldSchema([
288
            'type' => Type::string(),
289
            'args' => [
290
                'argOne' => ['type' => Type::int()],
291
                'argTwo' => ['type' => Type::string()],
292
                'argThree' => ['type' => Type::boolean(), 'defaultValue' => false]
293
            ]
294
        ]);
295
        $this->assertEquals('
296
type Query {
297
  singleField(argOne: Int, argTwo: String, argThree: Boolean = false): String
298
}
299
', $output);
300
    }
301
302
    /**
303
     * @it Print Interface
304
     */
305
    public function testPrintInterface()
306
    {
307
        $fooType = new InterfaceType([
308
            'name' => 'Foo',
309
            'fields' => ['str' => ['type' => Type::string()]]
310
        ]);
311
312
        $barType = new ObjectType([
313
            'name' => 'Bar',
314
            'fields' => ['str' => ['type' => Type::string()]],
315
            'interfaces' => [$fooType]
316
        ]);
317
318
        $root = new ObjectType([
319
            'name' => 'Root',
320
            'fields' => ['bar' => ['type' => $barType]]
321
        ]);
322
323
        $schema = new Schema([
324
            'query' => $root,
325
            'types' => [$barType]
326
        ]);
327
        $output = $this->printForTest($schema);
328
        $this->assertEquals('
329
schema {
330
  query: Root
331
}
332
333
type Bar implements Foo {
334
  str: String
335
}
336
337
interface Foo {
338
  str: String
339
}
340
341
type Root {
342
  bar: Bar
343
}
344
', $output);
345
    }
346
347
    /**
348
     * @it Print Multiple Interface
349
     */
350
    public function testPrintMultipleInterface()
351
    {
352
        $fooType = new InterfaceType([
353
            'name' => 'Foo',
354
            'fields' => ['str' => ['type' => Type::string()]]
355
        ]);
356
357
        $baazType = new InterfaceType([
358
            'name' => 'Baaz',
359
            'fields' => ['int' => ['type' => Type::int()]]
360
        ]);
361
362
        $barType = new ObjectType([
363
            'name' => 'Bar',
364
            'fields' => [
365
                'str' => ['type' => Type::string()],
366
                'int' => ['type' => Type::int()]
367
            ],
368
            'interfaces' => [$fooType, $baazType]
369
        ]);
370
371
        $root = new ObjectType([
372
            'name' => 'Root',
373
            'fields' => ['bar' => ['type' => $barType]]
374
        ]);
375
376
        $schema = new Schema([
377
            'query' => $root,
378
            'types' => [$barType]
379
        ]);
380
        $output = $this->printForTest($schema);
381
        $this->assertEquals('
382
schema {
383
  query: Root
384
}
385
386
interface Baaz {
387
  int: Int
388
}
389
390
type Bar implements Foo, Baaz {
391
  str: String
392
  int: Int
393
}
394
395
interface Foo {
396
  str: String
397
}
398
399
type Root {
400
  bar: Bar
401
}
402
', $output);
403
    }
404
405
    /**
406
     * @it Print Unions
407
     */
408
    public function testPrintUnions()
409
    {
410
        $fooType = new ObjectType([
411
            'name' => 'Foo',
412
            'fields' => ['bool' => ['type' => Type::boolean()]]
413
        ]);
414
415
        $barType = new ObjectType([
416
            'name' => 'Bar',
417
            'fields' => ['str' => ['type' => Type::string()]]
418
        ]);
419
420
        $singleUnion = new UnionType([
421
            'name' => 'SingleUnion',
422
            'types' => [$fooType]
423
        ]);
424
425
        $multipleUnion = new UnionType([
426
            'name' => 'MultipleUnion',
427
            'types' => [$fooType, $barType]
428
        ]);
429
430
        $root = new ObjectType([
431
            'name' => 'Root',
432
            'fields' => [
433
                'single' => ['type' => $singleUnion],
434
                'multiple' => ['type' => $multipleUnion]
435
            ]
436
        ]);
437
438
        $schema = new Schema(['query' => $root]);
439
        $output = $this->printForTest($schema);
440
        $this->assertEquals('
441
schema {
442
  query: Root
443
}
444
445
type Bar {
446
  str: String
447
}
448
449
type Foo {
450
  bool: Boolean
451
}
452
453
union MultipleUnion = Foo | Bar
454
455
type Root {
456
  single: SingleUnion
457
  multiple: MultipleUnion
458
}
459
460
union SingleUnion = Foo
461
', $output);
462
    }
463
464
    /**
465
     * @it Print Input Type
466
     */
467
    public function testInputType()
468
    {
469
        $inputType = new InputObjectType([
470
            'name' => 'InputType',
471
            'fields' => ['int' => ['type' => Type::int()]]
472
        ]);
473
474
        $root = new ObjectType([
475
            'name' => 'Root',
476
            'fields' => [
477
                'str' => [
478
                    'type' => Type::string(),
479
                    'args' => ['argOne' => ['type' => $inputType]]
480
                ]
481
            ]
482
        ]);
483
484
        $schema = new Schema(['query' => $root]);
485
        $output = $this->printForTest($schema);
486
        $this->assertEquals('
487
schema {
488
  query: Root
489
}
490
491
input InputType {
492
  int: Int
493
}
494
495
type Root {
496
  str(argOne: InputType): String
497
}
498
', $output);
499
    }
500
501
    /**
502
     * @it Custom Scalar
503
     */
504
    public function testCustomScalar()
505
    {
506
        $oddType = new CustomScalarType([
507
            'name' => 'Odd',
508
            'serialize' => function($value) {
509
                return $value % 2 === 1 ? $value : null;
510
            }
511
        ]);
512
513
        $root = new ObjectType([
514
            'name' => 'Root',
515
            'fields' => [
516
                'odd' => ['type' => $oddType]
517
            ]
518
        ]);
519
520
        $schema = new Schema(['query' => $root]);
521
        $output = $this->printForTest($schema);
522
        $this->assertEquals('
523
schema {
524
  query: Root
525
}
526
527
scalar Odd
528
529
type Root {
530
  odd: Odd
531
}
532
', $output);
533
    }
534
535
    /**
536
     * @it Enum
537
     */
538
    public function testEnum()
539
    {
540
        $RGBType = new EnumType([
541
            'name' => 'RGB',
542
            'values' => [
543
                'RED' => ['value' => 0],
544
                'GREEN' => ['value' => 1],
545
                'BLUE' => ['value' => 2]
546
            ]
547
        ]);
548
549
        $root = new ObjectType([
550
            'name' => 'Root',
551
            'fields' => [
552
                'rgb' => ['type' => $RGBType]
553
            ]
554
        ]);
555
556
        $schema = new Schema(['query' => $root]);
557
        $output = $this->printForTest($schema);
558
        $this->assertEquals('
559
schema {
560
  query: Root
561
}
562
563
enum RGB {
564
  RED
565
  GREEN
566
  BLUE
567
}
568
569
type Root {
570
  rgb: RGB
571
}
572
', $output);
573
    }
574
575
    /**
576
     * @it Prints custom directives
577
     */
578
    public function testPrintsCustomDirectives()
579
    {
580
        $query = new ObjectType([
581
            'name' => 'Query',
582
            'fields' => [
583
                'field' => ['type' => Type::string()],
584
            ]
585
        ]);
586
587
        $customDirectives = new Directive([
588
            'name' => 'customDirective',
589
            'locations' => [
590
                DirectiveLocation::FIELD
591
            ]
592
        ]);
593
594
        $schema = new Schema([
595
            'query' => $query,
596
            'directives' => [$customDirectives],
597
        ]);
598
599
        $output = $this->printForTest($schema);
600
        $this->assertEquals('
601
directive @customDirective on FIELD
602
603
type Query {
604
  field: String
605
}
606
', $output);
607
    }
608
609
    /**
610
     * @it One-line prints a short description
611
     */
612
    public function testOneLinePrintsAShortDescription()
613
    {
614
        $description = 'This field is awesome';
615
        $output = $this->printSingleFieldSchema([
616
            "type" => Type::string(),
617
            "description" => $description
618
        ]);
619
620
        $this->assertEquals('
621
type Query {
622
  """This field is awesome"""
623
  singleField: String
624
}
625
', $output);
626
627
        $recreatedRoot = BuildSchema::build($output)->getTypeMap()['Query'];
628
        $recreatedField = $recreatedRoot->getFields()['singleField'];
0 ignored issues
show
Bug introduced by
The method getFields() does not exist on GraphQL\Type\Definition\Type. It seems like you code against a sub-type of GraphQL\Type\Definition\Type such as GraphQL\Type\Definition\InterfaceType or GraphQL\Type\Definition\ObjectType or GraphQL\Type\Definition\InputObjectType. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

628
        $recreatedField = $recreatedRoot->/** @scrutinizer ignore-call */ getFields()['singleField'];
Loading history...
629
        $this->assertEquals($description, $recreatedField->description);
630
    }
631
632
    /**
633
     * @it Does not one-line print a description that ends with a quote
634
     */
635
    public function testDoesNotOneLinePrintADescriptionThatEndsWithAQuote()
636
    {
637
        $description = 'This field is "awesome"';
638
        $output = $this->printSingleFieldSchema([
639
            "type" => Type::string(),
640
            "description" => $description
641
        ]);
642
643
        $this->assertEquals('
644
type Query {
645
  """
646
  This field is "awesome"
647
  """
648
  singleField: String
649
}
650
', $output);
651
652
        $recreatedRoot = BuildSchema::build($output)->getTypeMap()['Query'];
653
        $recreatedField = $recreatedRoot->getFields()['singleField'];
654
        $this->assertEquals($description, $recreatedField->description);
655
    }
656
657
    /**
658
     * @it Preserves leading spaces when printing a description
659
     */
660
    public function testPReservesLeadingSpacesWhenPrintingADescription()
661
    {
662
        $description = '    This field is "awesome"';
663
        $output = $this->printSingleFieldSchema([
664
            "type" => Type::string(),
665
            "description" => $description
666
        ]);
667
668
        $this->assertEquals('
669
type Query {
670
  """    This field is "awesome"
671
  """
672
  singleField: String
673
}
674
', $output);
675
676
        $recreatedRoot = BuildSchema::build($output)->getTypeMap()['Query'];
677
        $recreatedField = $recreatedRoot->getFields()['singleField'];
678
        $this->assertEquals($description, $recreatedField->description);
679
    }
680
681
    /**
682
     * @it Print Introspection Schema
683
     */
684
    public function testPrintIntrospectionSchema()
685
    {
686
        $root = new ObjectType([
687
            'name' => 'Root',
688
            'fields' => [
689
                'onlyField' => ['type' => Type::string()]
690
            ]
691
        ]);
692
693
        $schema = new Schema(['query' => $root]);
694
        $output = SchemaPrinter::printIntrosepctionSchema($schema);
695
        $introspectionSchema = <<<'EOT'
696
schema {
697
  query: Root
698
}
699
700
"""
701
Directs the executor to include this field or fragment only when the `if` argument is true.
702
"""
703
directive @include(
704
  """Included when true."""
705
  if: Boolean!
706
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
707
708
"""
709
Directs the executor to skip this field or fragment when the `if` argument is true.
710
"""
711
directive @skip(
712
  """Skipped when true."""
713
  if: Boolean!
714
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
715
716
"""Marks an element of a GraphQL schema as no longer supported."""
717
directive @deprecated(
718
  """
719
  Explains why this element was deprecated, usually also including a suggestion
720
  for how to access supported similar data. Formatted in
721
  [Markdown](https://daringfireball.net/projects/markdown/).
722
  """
723
  reason: String = "No longer supported"
724
) on FIELD_DEFINITION | ENUM_VALUE
725
726
"""
727
A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.
728
729
In some cases, you need to provide options to alter GraphQL's execution behavior
730
in ways field arguments will not suffice, such as conditionally including or
731
skipping a field. Directives provide this by describing additional information
732
to the executor.
733
"""
734
type __Directive {
735
  name: String!
736
  description: String
737
  locations: [__DirectiveLocation!]!
738
  args: [__InputValue!]!
739
  onOperation: Boolean! @deprecated(reason: "Use `locations`.")
740
  onFragment: Boolean! @deprecated(reason: "Use `locations`.")
741
  onField: Boolean! @deprecated(reason: "Use `locations`.")
742
}
743
744
"""
745
A Directive can be adjacent to many parts of the GraphQL language, a
746
__DirectiveLocation describes one such possible adjacencies.
747
"""
748
enum __DirectiveLocation {
749
  """Location adjacent to a query operation."""
750
  QUERY
751
752
  """Location adjacent to a mutation operation."""
753
  MUTATION
754
755
  """Location adjacent to a subscription operation."""
756
  SUBSCRIPTION
757
758
  """Location adjacent to a field."""
759
  FIELD
760
761
  """Location adjacent to a fragment definition."""
762
  FRAGMENT_DEFINITION
763
764
  """Location adjacent to a fragment spread."""
765
  FRAGMENT_SPREAD
766
767
  """Location adjacent to an inline fragment."""
768
  INLINE_FRAGMENT
769
770
  """Location adjacent to a schema definition."""
771
  SCHEMA
772
773
  """Location adjacent to a scalar definition."""
774
  SCALAR
775
776
  """Location adjacent to an object type definition."""
777
  OBJECT
778
779
  """Location adjacent to a field definition."""
780
  FIELD_DEFINITION
781
782
  """Location adjacent to an argument definition."""
783
  ARGUMENT_DEFINITION
784
785
  """Location adjacent to an interface definition."""
786
  INTERFACE
787
788
  """Location adjacent to a union definition."""
789
  UNION
790
791
  """Location adjacent to an enum definition."""
792
  ENUM
793
794
  """Location adjacent to an enum value definition."""
795
  ENUM_VALUE
796
797
  """Location adjacent to an input object type definition."""
798
  INPUT_OBJECT
799
800
  """Location adjacent to an input object field definition."""
801
  INPUT_FIELD_DEFINITION
802
}
803
804
"""
805
One possible value for a given Enum. Enum values are unique values, not a
806
placeholder for a string or numeric value. However an Enum value is returned in
807
a JSON response as a string.
808
"""
809
type __EnumValue {
810
  name: String!
811
  description: String
812
  isDeprecated: Boolean!
813
  deprecationReason: String
814
}
815
816
"""
817
Object and Interface types are described by a list of Fields, each of which has
818
a name, potentially a list of arguments, and a return type.
819
"""
820
type __Field {
821
  name: String!
822
  description: String
823
  args: [__InputValue!]!
824
  type: __Type!
825
  isDeprecated: Boolean!
826
  deprecationReason: String
827
}
828
829
"""
830
Arguments provided to Fields or Directives and the input fields of an
831
InputObject are represented as Input Values which describe their type and
832
optionally a default value.
833
"""
834
type __InputValue {
835
  name: String!
836
  description: String
837
  type: __Type!
838
839
  """
840
  A GraphQL-formatted string representing the default value for this input value.
841
  """
842
  defaultValue: String
843
}
844
845
"""
846
A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all
847
available types and directives on the server, as well as the entry points for
848
query, mutation, and subscription operations.
849
"""
850
type __Schema {
851
  """A list of all types supported by this server."""
852
  types: [__Type!]!
853
854
  """The type that query operations will be rooted at."""
855
  queryType: __Type!
856
857
  """
858
  If this server supports mutation, the type that mutation operations will be rooted at.
859
  """
860
  mutationType: __Type
861
862
  """
863
  If this server support subscription, the type that subscription operations will be rooted at.
864
  """
865
  subscriptionType: __Type
866
867
  """A list of all directives supported by this server."""
868
  directives: [__Directive!]!
869
}
870
871
"""
872
The fundamental unit of any GraphQL Schema is the type. There are many kinds of
873
types in GraphQL as represented by the `__TypeKind` enum.
874
875
Depending on the kind of a type, certain fields describe information about that
876
type. Scalar types provide no information beyond a name and description, while
877
Enum types provide their values. Object and Interface types provide the fields
878
they describe. Abstract types, Union and Interface, provide the Object types
879
possible at runtime. List and NonNull types compose other types.
880
"""
881
type __Type {
882
  kind: __TypeKind!
883
  name: String
884
  description: String
885
  fields(includeDeprecated: Boolean = false): [__Field!]
886
  interfaces: [__Type!]
887
  possibleTypes: [__Type!]
888
  enumValues(includeDeprecated: Boolean = false): [__EnumValue!]
889
  inputFields: [__InputValue!]
890
  ofType: __Type
891
}
892
893
"""An enum describing what kind of type a given `__Type` is."""
894
enum __TypeKind {
895
  """Indicates this type is a scalar."""
896
  SCALAR
897
898
  """
899
  Indicates this type is an object. `fields` and `interfaces` are valid fields.
900
  """
901
  OBJECT
902
903
  """
904
  Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.
905
  """
906
  INTERFACE
907
908
  """Indicates this type is a union. `possibleTypes` is a valid field."""
909
  UNION
910
911
  """Indicates this type is an enum. `enumValues` is a valid field."""
912
  ENUM
913
914
  """
915
  Indicates this type is an input object. `inputFields` is a valid field.
916
  """
917
  INPUT_OBJECT
918
919
  """Indicates this type is a list. `ofType` is a valid field."""
920
  LIST
921
922
  """Indicates this type is a non-null. `ofType` is a valid field."""
923
  NON_NULL
924
}
925
926
EOT;
927
        $this->assertEquals($introspectionSchema, $output);
928
    }
929
930
    /**
931
     * @it Print Introspection Schema with comment description
932
     */
933
    public function testPrintIntrospectionSchemaWithCommentDescription()
934
    {
935
        $root = new ObjectType([
936
            'name' => 'Root',
937
            'fields' => [
938
                'onlyField' => ['type' => Type::string()]
939
            ]
940
        ]);
941
942
        $schema = new Schema(['query' => $root]);
943
        $output = SchemaPrinter::printIntrosepctionSchema($schema, [
944
            'commentDescriptions' => true
945
        ]);
946
        $introspectionSchema = <<<'EOT'
947
schema {
948
  query: Root
949
}
950
951
# Directs the executor to include this field or fragment only when the `if` argument is true.
952
directive @include(
953
  # Included when true.
954
  if: Boolean!
955
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
956
957
# Directs the executor to skip this field or fragment when the `if` argument is true.
958
directive @skip(
959
  # Skipped when true.
960
  if: Boolean!
961
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
962
963
# Marks an element of a GraphQL schema as no longer supported.
964
directive @deprecated(
965
  # Explains why this element was deprecated, usually also including a suggestion
966
  # for how to access supported similar data. Formatted in
967
  # [Markdown](https://daringfireball.net/projects/markdown/).
968
  reason: String = "No longer supported"
969
) on FIELD_DEFINITION | ENUM_VALUE
970
971
# A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.
972
#
973
# In some cases, you need to provide options to alter GraphQL's execution behavior
974
# in ways field arguments will not suffice, such as conditionally including or
975
# skipping a field. Directives provide this by describing additional information
976
# to the executor.
977
type __Directive {
978
  name: String!
979
  description: String
980
  locations: [__DirectiveLocation!]!
981
  args: [__InputValue!]!
982
  onOperation: Boolean! @deprecated(reason: "Use `locations`.")
983
  onFragment: Boolean! @deprecated(reason: "Use `locations`.")
984
  onField: Boolean! @deprecated(reason: "Use `locations`.")
985
}
986
987
# A Directive can be adjacent to many parts of the GraphQL language, a
988
# __DirectiveLocation describes one such possible adjacencies.
989
enum __DirectiveLocation {
990
  # Location adjacent to a query operation.
991
  QUERY
992
993
  # Location adjacent to a mutation operation.
994
  MUTATION
995
996
  # Location adjacent to a subscription operation.
997
  SUBSCRIPTION
998
999
  # Location adjacent to a field.
1000
  FIELD
1001
1002
  # Location adjacent to a fragment definition.
1003
  FRAGMENT_DEFINITION
1004
1005
  # Location adjacent to a fragment spread.
1006
  FRAGMENT_SPREAD
1007
1008
  # Location adjacent to an inline fragment.
1009
  INLINE_FRAGMENT
1010
1011
  # Location adjacent to a schema definition.
1012
  SCHEMA
1013
1014
  # Location adjacent to a scalar definition.
1015
  SCALAR
1016
1017
  # Location adjacent to an object type definition.
1018
  OBJECT
1019
1020
  # Location adjacent to a field definition.
1021
  FIELD_DEFINITION
1022
1023
  # Location adjacent to an argument definition.
1024
  ARGUMENT_DEFINITION
1025
1026
  # Location adjacent to an interface definition.
1027
  INTERFACE
1028
1029
  # Location adjacent to a union definition.
1030
  UNION
1031
1032
  # Location adjacent to an enum definition.
1033
  ENUM
1034
1035
  # Location adjacent to an enum value definition.
1036
  ENUM_VALUE
1037
1038
  # Location adjacent to an input object type definition.
1039
  INPUT_OBJECT
1040
1041
  # Location adjacent to an input object field definition.
1042
  INPUT_FIELD_DEFINITION
1043
}
1044
1045
# One possible value for a given Enum. Enum values are unique values, not a
1046
# placeholder for a string or numeric value. However an Enum value is returned in
1047
# a JSON response as a string.
1048
type __EnumValue {
1049
  name: String!
1050
  description: String
1051
  isDeprecated: Boolean!
1052
  deprecationReason: String
1053
}
1054
1055
# Object and Interface types are described by a list of Fields, each of which has
1056
# a name, potentially a list of arguments, and a return type.
1057
type __Field {
1058
  name: String!
1059
  description: String
1060
  args: [__InputValue!]!
1061
  type: __Type!
1062
  isDeprecated: Boolean!
1063
  deprecationReason: String
1064
}
1065
1066
# Arguments provided to Fields or Directives and the input fields of an
1067
# InputObject are represented as Input Values which describe their type and
1068
# optionally a default value.
1069
type __InputValue {
1070
  name: String!
1071
  description: String
1072
  type: __Type!
1073
1074
  # A GraphQL-formatted string representing the default value for this input value.
1075
  defaultValue: String
1076
}
1077
1078
# A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all
1079
# available types and directives on the server, as well as the entry points for
1080
# query, mutation, and subscription operations.
1081
type __Schema {
1082
  # A list of all types supported by this server.
1083
  types: [__Type!]!
1084
1085
  # The type that query operations will be rooted at.
1086
  queryType: __Type!
1087
1088
  # If this server supports mutation, the type that mutation operations will be rooted at.
1089
  mutationType: __Type
1090
1091
  # If this server support subscription, the type that subscription operations will be rooted at.
1092
  subscriptionType: __Type
1093
1094
  # A list of all directives supported by this server.
1095
  directives: [__Directive!]!
1096
}
1097
1098
# The fundamental unit of any GraphQL Schema is the type. There are many kinds of
1099
# types in GraphQL as represented by the `__TypeKind` enum.
1100
#
1101
# Depending on the kind of a type, certain fields describe information about that
1102
# type. Scalar types provide no information beyond a name and description, while
1103
# Enum types provide their values. Object and Interface types provide the fields
1104
# they describe. Abstract types, Union and Interface, provide the Object types
1105
# possible at runtime. List and NonNull types compose other types.
1106
type __Type {
1107
  kind: __TypeKind!
1108
  name: String
1109
  description: String
1110
  fields(includeDeprecated: Boolean = false): [__Field!]
1111
  interfaces: [__Type!]
1112
  possibleTypes: [__Type!]
1113
  enumValues(includeDeprecated: Boolean = false): [__EnumValue!]
1114
  inputFields: [__InputValue!]
1115
  ofType: __Type
1116
}
1117
1118
# An enum describing what kind of type a given `__Type` is.
1119
enum __TypeKind {
1120
  # Indicates this type is a scalar.
1121
  SCALAR
1122
1123
  # Indicates this type is an object. `fields` and `interfaces` are valid fields.
1124
  OBJECT
1125
1126
  # Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.
1127
  INTERFACE
1128
1129
  # Indicates this type is a union. `possibleTypes` is a valid field.
1130
  UNION
1131
1132
  # Indicates this type is an enum. `enumValues` is a valid field.
1133
  ENUM
1134
1135
  # Indicates this type is an input object. `inputFields` is a valid field.
1136
  INPUT_OBJECT
1137
1138
  # Indicates this type is a list. `ofType` is a valid field.
1139
  LIST
1140
1141
  # Indicates this type is a non-null. `ofType` is a valid field.
1142
  NON_NULL
1143
}
1144
1145
EOT;
1146
        $this->assertEquals($introspectionSchema, $output);
1147
    }
1148
}
1149