Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.46% covered (success)
98.46%
128 / 130
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
GraphqlSchemaFactory
98.46% covered (success)
98.46%
128 / 130
75.00% covered (warning)
75.00%
3 / 4
16
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 createSchema
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 createMutations
97.92% covered (success)
97.92%
94 / 96
0.00% covered (danger)
0.00%
0 / 1
11
 createQuery
100.00% covered (success)
100.00%
29 / 29
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2namespace Apie\Graphql\Factories;
3
4use Apie\Common\ActionDefinitionProvider;
5use Apie\Common\ActionDefinitions\CreateResourceActionDefinition;
6use Apie\Common\ActionDefinitions\DownloadFilesActionDefinition;
7use Apie\Common\ActionDefinitions\GetResourceActionDefinition;
8use Apie\Common\ActionDefinitions\GetResourceListActionDefinition;
9use Apie\Common\ActionDefinitions\ModifyResourceActionDefinition;
10use Apie\Common\ActionDefinitions\RemoveResourceActionDefinition;
11use Apie\Common\ActionDefinitions\ReplaceResourceActionDefinition;
12use Apie\Common\ActionDefinitions\RunResourceMethodDefinition;
13use Apie\Common\Actions\CreateObjectAction;
14use Apie\Common\Actions\ModifyObjectAction;
15use Apie\Common\Actions\RemoveObjectAction;
16use Apie\Common\Actions\RunItemMethodAction;
17use Apie\Core\ApieLib;
18use Apie\Core\BoundedContext\BoundedContext;
19use Apie\Core\Context\ApieContext;
20use Apie\Core\Datalayers\Search\QuerySearch;
21use Apie\Graphql\TypeResolvers\ApieCallTypeResolver;
22use Apie\Graphql\TypeResolvers\SearchObjectTypeResolver;
23use Apie\Graphql\Types;
24use Apie\Graphql\Types\SearchObjectType;
25use GraphQL\Type\Definition\ObjectType;
26use GraphQL\Type\Definition\Type;
27use GraphQL\Type\Schema;
28
29class GraphqlSchemaFactory
30{
31    public function __construct(
32        private readonly ActionDefinitionProvider $actionDefinitionProvider,
33    ) {
34    }
35    public function createSchema(ApieContext $apieContext): Schema
36    {
37        return new Schema([
38            'query' => $this->createQuery($apieContext),
39            'mutation' => $this->createMutations($apieContext),
40        ]);
41    }
42
43    private function createMutations(ApieContext $apieContext): ObjectType
44    {
45        $fields = [
46        ];
47        $boundedContext = $apieContext->getContext(BoundedContext::class);
48        foreach ($this->actionDefinitionProvider->provideActionDefinitions($boundedContext, $apieContext) as $actionDefinition) {
49            if ($actionDefinition instanceof GetResourceListActionDefinition || $actionDefinition instanceof GetResourceActionDefinition || $actionDefinition instanceof DownloadFilesActionDefinition) {
50                continue;
51            }
52            if ($actionDefinition instanceof CreateResourceActionDefinition || $actionDefinition instanceof ReplaceResourceActionDefinition) {
53                $typeInput = Types::createMeta($actionDefinition->getResourceName());
54                $type = Types::displayMeta($actionDefinition->getResourceName());
55                $fields['create' . $actionDefinition->getResourceName()->getShortName()] = [
56                    'name' => 'create' . $actionDefinition->getResourceName()->getShortName(),
57                    'type' => $type,
58                    'args' => [
59                        'input' => [
60                            'type' => $typeInput,
61                        ],
62                    ],
63                    'description' => $type->description,
64                    'resolve' => new ApieCallTypeResolver(
65                        CreateObjectAction::class,
66                        $actionDefinition->getBoundedContextId(),
67                        $actionDefinition->getResourceName(),
68                    ),
69                ];
70            }
71            if ($actionDefinition instanceof RemoveResourceActionDefinition) {
72                $fields['remove' . $actionDefinition->getResourceName()->getShortName()] = [
73                    'name' => 'remove' . $actionDefinition->getResourceName()->getShortName(),
74                    'type' => Type::boolean(),
75                    'args' => [
76                        'id' => [
77                            'type' => Types::fromId($actionDefinition->getResourceName()),
78                        ],
79                    ],
80                    'description' => 'Remove a ' . $actionDefinition->getResourceName()->getShortName() . ' by id',
81                    'resolve' => new ApieCallTypeResolver(
82                        RemoveObjectAction::class,
83                        $actionDefinition->getBoundedContextId(),
84                        $actionDefinition->getResourceName(),
85                        setResourceId: true
86                    ),
87                ];
88            }
89            if ($actionDefinition instanceof ModifyResourceActionDefinition) {
90                $typeInput = Types::modifyMeta($actionDefinition->getResourceName());
91                $type = Types::displayMeta($actionDefinition->getResourceName());
92                $fields['modify' . $actionDefinition->getResourceName()->getShortName()] = [
93                    'name' => 'modify' . $actionDefinition->getResourceName()->getShortName(),
94                    'type' => $type,
95                    'args' => [
96                        'id' => [
97                            'type' => Types::fromId($actionDefinition->getResourceName()),
98                        ],
99                        'input' => [
100                            'type' => $typeInput
101                        ]
102                    ],
103                    'description' => 'Modifies a single ' . $actionDefinition->getResourceName()->getShortName() . ' by id',
104                    'resolve' => new ApieCallTypeResolver(
105                        ModifyObjectAction::class,
106                        $actionDefinition->getBoundedContextId(),
107                        $actionDefinition->getResourceName(),
108                        setResourceId: true
109                    ),
110                ];
111            }
112            if ($actionDefinition instanceof RunResourceMethodDefinition) {
113                $method = $actionDefinition->getMethod();
114                $typeInput = Types::methodCallMeta($method);
115                $type = Types::displayMeta($actionDefinition->getResourceName());
116
117                $args = [
118                        'id' => [
119                            'type' => Types::fromId($actionDefinition->getResourceName()),
120                        ],
121                        'input' => [
122                            'type' => $typeInput
123                        ]
124                    ];
125                $description = 'Runs ' . $method->name . ' for a ' . $actionDefinition->getResourceName()->getShortName() . ' by id';
126                if ($method->isStatic()) {
127                    unset($args['id']);
128                    $description = 'Runs ' . $method->name . ' for ' . $actionDefinition->getResourceName()->getShortName();
129                }
130
131                $fields['run' . $actionDefinition->getResourceName()->getShortName() . ucfirst($method->name)] = [
132                    'name' => 'run' . $actionDefinition->getResourceName()->getShortName() . ucfirst($method->name),
133                    'type' => $type,
134                    'args' => $args,
135                    'description' => $description,
136                    'resolve' => new ApieCallTypeResolver(
137                        RunItemMethodAction::class,
138                        $actionDefinition->getBoundedContextId(),
139                        $actionDefinition->getResourceName(),
140                        $actionDefinition->getMethod(),
141                        !$method->isStatic()
142                    ),
143                ];
144            }
145        }
146        return new ObjectType([
147            'name' => 'Mutation',
148            'fields' => $fields,
149        ]);
150    }
151
152    private function createQuery(ApieContext $apieContext): ObjectType
153    {
154        $fields = [
155            'apie_version' => [
156                'type' => Type::string(),
157                'args' => [],
158                'description' => 'Get the current version of the Apie library',
159                'resolve' => fn (ApieContext $rootValue, array $args): string => ApieLib::VERSION,
160            ],
161        ];
162        $boundedContext = $apieContext->getContext(BoundedContext::class);
163        foreach ($this->actionDefinitionProvider->provideActionDefinitions($boundedContext, $apieContext) as $actionDefinition) {
164            if ($actionDefinition instanceof GetResourceListActionDefinition) {
165                $type = new SearchObjectType($actionDefinition->getResourceName());
166                $fields[$type->name] = [
167                    'type' => $type,
168                    'args' => [
169                        'id' => [
170                            'type' => Types::fromId($actionDefinition->getResourceName()),
171                        ],
172                        'filter' => [
173                            'type' => Types::createMeta(new \ReflectionClass(QuerySearch::class)),
174                        ],
175                    ],
176                    'description' => $type->description,
177                    'resolve' => new SearchObjectTypeResolver($actionDefinition->getResourceName()->name),
178                ];
179            }
180        }
181        return new ObjectType([
182            'name' => 'Query',
183            'fields' => $fields,
184        ]);
185    }
186}