Passed
Push — master ( 7d326c...9ae8b9 )
by Vladimir
03:29
created

testPrintsStringFieldWithStringArgWithDefault()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

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

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