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