Passed
Push — main ( 954b47...3e26d7 )
by Tom
01:01 queued 13s
created

InputFactory::addRequiredFields()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 26
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 12
c 1
b 0
f 0
nc 5
nop 3
dl 0
loc 26
rs 8.8333
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ApiSkeletons\Doctrine\GraphQL\Input;
6
7
use ApiSkeletons\Doctrine\GraphQL\AbstractContainer;
8
use ApiSkeletons\Doctrine\GraphQL\Config;
9
use ApiSkeletons\Doctrine\GraphQL\Metadata\Metadata;
10
use ApiSkeletons\Doctrine\GraphQL\Type\TypeManager;
11
use Doctrine\ORM\EntityManager;
12
use Exception;
13
use GraphQL\Error\Error;
14
use GraphQL\Type\Definition\InputObjectField;
15
use GraphQL\Type\Definition\InputObjectType;
16
use GraphQL\Type\Definition\Type;
17
18
use function count;
19
use function in_array;
20
21
class InputFactory extends AbstractContainer
22
{
23
    public function __construct(
24
        protected Config $config,
25
        protected EntityManager $entityManager,
26
        protected TypeManager $typeManager,
27
        protected Metadata $metadata,
28
    ) {
29
    }
30
31
    /**
32
     * @param string[]                           $optionalFields
33
     * @param array<array-key, InputObjectField> $fields
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key, InputObjectField> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key, InputObjectField>.
Loading history...
34
     *
35
     * @return array<array-key, InputObjectField>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key, InputObjectField> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key, InputObjectField>.
Loading history...
36
     */
37
    protected function addOptionalFields(
38
        mixed $targetEntity,
39
        array $optionalFields,
40
        array $fields,
41
    ): array {
42
        foreach ($this->entityManager->getClassMetadata($targetEntity->getEntityClass())->getFieldNames() as $fieldName) {
43
            if (! in_array($fieldName, $optionalFields) && $optionalFields !== ['*']) {
44
                continue;
45
            }
46
47
            if ($optionalFields === ['*'] && $this->entityManager->getClassMetadata($targetEntity->getEntityClass())->isIdentifier($fieldName)) {
48
                continue;
49
            }
50
51
            $fields[$fieldName] = new InputObjectField([
52
                'name' => $fieldName,
53
                'description' => (string) $targetEntity->getMetadataConfig()['fields'][$fieldName]['description'],
54
                'type' => $this->typeManager->get($targetEntity->getMetadataConfig()['fields'][$fieldName]['type']),
55
            ]);
56
        }
57
58
        return $fields;
59
    }
60
61
    /**
62
     * @param string[]                           $requiredFields
63
     * @param array<array-key, InputObjectField> $fields
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key, InputObjectField> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key, InputObjectField>.
Loading history...
64
     *
65
     * @return array<array-key, InputObjectField>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key, InputObjectField> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key, InputObjectField>.
Loading history...
66
     */
67
    protected function addRequiredFields(
68
        mixed $targetEntity,
69
        array $requiredFields,
70
        array $fields,
71
    ): array {
72
        foreach ($this->entityManager->getClassMetadata($targetEntity->getEntityClass())->getFieldNames() as $fieldName) {
73
            if (! in_array($fieldName, $requiredFields) && $requiredFields !== ['*']) {
74
                continue;
75
            }
76
77
            if ($requiredFields === ['*'] && $this->entityManager->getClassMetadata($targetEntity->getEntityClass())->isIdentifier($fieldName)) {
78
                continue;
79
            }
80
81
            if ($this->entityManager->getClassMetadata($targetEntity->getEntityClass())->isIdentifier($fieldName)) {
82
                throw new Exception('Identifier ' . $fieldName . ' is an invalid input.');
83
            }
84
85
            $fields[$fieldName] = new InputObjectField([
86
                'name' => $fieldName,
87
                'description' => (string) $targetEntity->getMetadataConfig()['fields'][$fieldName]['description'],
88
                'type' => Type::nonNull($this->typeManager->get($targetEntity->getMetadataConfig()['fields'][$fieldName]['type'])),
89
            ]);
90
        }
91
92
        return $fields;
93
    }
94
95
    /**
96
     * @param array<array-key, InputObjectField> $fields
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key, InputObjectField> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key, InputObjectField>.
Loading history...
97
     *
98
     * @return array<array-key, InputObjectField>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key, InputObjectField> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key, InputObjectField>.
Loading history...
99
     */
100
    protected function addAllFieldsAsRequired(mixed $targetEntity, array $fields): array
101
    {
102
        foreach ($this->entityManager->getClassMetadata($targetEntity->getEntityClass())->getFieldNames() as $fieldName) {
103
            if ($this->entityManager->getClassMetadata($targetEntity->getEntityClass())->isIdentifier($fieldName)) {
104
                continue;
105
            }
106
107
            $fields[$fieldName] = new InputObjectField([
108
                'name' => $fieldName,
109
                'description' => (string) $targetEntity->getMetadataConfig()['fields'][$fieldName]['description'],
110
                'type' => Type::nonNull($this->typeManager->get($targetEntity->getMetadataConfig()['fields'][$fieldName]['type'])),
111
            ]);
112
        }
113
114
        return $fields;
115
    }
116
117
    /**
118
     * @param string[] $requiredFields An optional list of just the required fields you want for the mutation.
119
     *                              This allows specific fields per mutation.
120
     * @param string[] $optionalFields An optional list of optional fields you want for the mutation.
121
     *                              This allows specific fields per mutation.
122
     *
123
     * @throws Error
124
     */
125
    public function get(string $id, array $requiredFields = [], array $optionalFields = []): InputObjectType
126
    {
127
        $fields       = [];
128
        $targetEntity = $this->metadata->get($id);
129
130
        /**
131
         * Do not include identifiers as input.  In the majority of cases there will be
132
         * no reason to set or update an identifier.  For the case where an identifier
133
         * should be set or updated, this facotry is not the correct solution.
134
         */
135
136
        if (! count($requiredFields) && ! count($optionalFields)) {
137
            $fields = $this->addAllFieldsAsRequired($targetEntity, $fields);
138
        } else {
139
            $fields = $this->addRequiredFields($targetEntity, $requiredFields, $fields);
140
            $fields = $this->addOptionalFields($targetEntity, $optionalFields, $fields);
141
        }
142
143
        return new InputObjectType([
144
            'name' => $targetEntity->getTypeName() . '_Input',
145
            'description' => $targetEntity->getDescription(),
146
            'fields' => static fn () => $fields,
147
        ]);
148
    }
149
}
150