Completed
Branch feature/moar-test-optimizing (8cffd1)
by Lucas
19:31 queued 13:44
created

processFieldDefinitionsRecursive()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 5.009
Metric Value
dl 0
loc 18
ccs 13
cts 14
cp 0.9286
rs 8.8571
cc 5
eloc 12
nc 4
nop 1
crap 5.009
1
<?php
2
namespace Graviton\GeneratorBundle\Definition;
3
4
/**
5
 * Represents a hash of fields as defined in the JSON format
6
 *
7
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
8
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
9
 * @link     http://swisscom.ch
10
 */
11
class JsonDefinitionHash implements DefinitionElementInterface
12
{
13
    /**
14
     * @var string Name of this hash
15
     */
16
    private $name;
17
    /**
18
     * @var JsonDefinition
19
     */
20
    private $parent;
21
    /**
22
     * @var DefinitionElementInterface[] Array of fields..
23
     */
24
    private $fields = [];
25
    /**
26
     * @var Schema\Field Field definition
27
     */
28
    private $definition;
29
30
    /**
31
     * Constructor
32
     *
33
     * @param string                       $name       Name of this hash
34
     * @param JsonDefinition               $parent     Parent definiton
35
     * @param DefinitionElementInterface[] $fields     Fields of the hash
36
     * @param Schema\Field                 $definition Field definition
0 ignored issues
show
Documentation introduced by
Should the type for parameter $definition not be null|Schema\Field?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
37
     */
38 42
    public function __construct($name, JsonDefinition $parent, array $fields, Schema\Field $definition = null)
39
    {
40 42
        $this->name = $name;
41 42
        $this->parent = $parent;
42 42
        $this->fields = $fields;
43 42
        $this->definition = $definition;
44 42
    }
45
46
    /**
47
     * Returns the hash name
48
     *
49
     * @return string Name
50
     */
51 22
    public function getName()
52
    {
53 22
        return $this->name;
54
    }
55
56
    /**
57
     * Returns the definition as array..
58
     *
59
     * @return array the definition
60
     */
61 6
    public function getDefAsArray()
62
    {
63 6
        return array_replace(
64
            [
65 6
                'name'              => $this->getName(),
66 6
                'type'              => $this->getType(),
67 6
                'exposedName'       => $this->getName(),
68 6
                'doctrineType'      => $this->getTypeDoctrine(),
69 6
                'serializerType'    => $this->getTypeSerializer(),
70 6
                'relType'           => self::REL_TYPE_EMBED,
71 3
                'isClassType'       => true,
72 3
                'constraints'       => [],
73 3
                'required'          => true,
74 3
                'searchable'        => false,
75 3
            ],
76 6
            $this->definition === null ? [] : [
77 2
                'exposedName'       => $this->definition->getExposeAs() ?: $this->getName(),
78
79 2
                'title'             => $this->definition->getTitle(),
80 2
                'description'       => $this->definition->getDescription(),
81 2
                'readOnly'          => $this->definition->getReadOnly(),
82 2
                'required'          => $this->definition->getRequired(),
83 4
                'searchable'        => $this->definition->getSearchable(),
84
            ]
85 3
        );
86
    }
87
88
    /**
89
     * {@inheritDoc}
90
     *
91
     * @return string type
92
     */
93 8
    public function getType()
94
    {
95 8
        return self::TYPE_HASH;
96
    }
97
98
    /**
99
     * {@inheritDoc}
100
     *
101
     * @return string type
102
     */
103 8
    public function getTypeDoctrine()
104
    {
105 8
        return $this->getClassName(true);
106
    }
107
108
    /**
109
     * Returns the field type in a serializer-understandable way..
110
     *
111
     * @return string Type
112
     */
113 8
    public function getTypeSerializer()
114
    {
115 8
        return $this->getClassName(true);
116
    }
117
118
    /**
119
     * Returns the field definition of this hash from "local perspective",
120
     * meaning that we only include fields inside this hash BUT with all
121
     * the stuff from the json file. this is needed to generate a Document/Model
122
     * from this hash (generate a json file again)
123
     *
124
     * @return JsonDefinition the definition of this hash in a standalone array ready to be json_encoded()
125
     */
126 10
    public function getJsonDefinition()
127
    {
128 10
        $definition = (new Schema\Definition())
129 10
            ->setId($this->getClassName())
130 10
            ->setDescription($this->definition === null ? null : $this->definition->getDescription())
131 10
            ->setTitle($this->definition === null ? null : $this->definition->getTitle())
132 10
            ->setIsSubDocument(true)
133 10
            ->setTarget(new Schema\Target());
134
135 10
        foreach ($this->fields as $field) {
136 10
            foreach ($this->processFieldDefinitionsRecursive($field) as $definitions) {
137 10
                $definition->getTarget()->addField($definitions);
138 5
            }
139 5
        }
140 10
        foreach ($this->parent->getRelations() as $relation) {
141 4
            $relation = $this->processParentRelation($relation);
142 4
            if ($relation !== null) {
143 4
                $definition->getTarget()->addRelation($relation);
144 2
            }
145 5
        }
146
147 10
        return new JsonDefinition($definition);
148
    }
149
150
    /**
151
     * Method getFieldDefinitionsRecursive
152
     *
153
     * @param DefinitionElementInterface $field
154
     * @return Schema\Field[]
155
     */
156 10
    private function processFieldDefinitionsRecursive(DefinitionElementInterface $field)
157
    {
158 10
        if ($field instanceof JsonDefinitionField) {
159 10
            return [$this->cloneFieldDefinition($field->getDef())];
160 4
        } elseif ($field instanceof JsonDefinitionArray) {
161 8
            return $this->processFieldDefinitionsRecursive($field->getElement());
162 2
        } elseif ($field instanceof JsonDefinitionHash) {
163 4
            return array_reduce(
164 4
                $field->fields,
165 4
                function (array $subfields, DefinitionElementInterface $subfield) {
166 4
                    return array_merge($subfields, $this->processFieldDefinitionsRecursive($subfield));
167 4
                },
168 4
                $field->definition === null ? [] : [$this->cloneFieldDefinition($field->definition)]
169 2
            );
170
        }
171
172
        throw new \InvalidArgumentException(sprintf('Unknown field type "%s"', get_class($field)));
173
    }
174
175
    /**
176
     * Clone field definition
177
     *
178
     * @param Schema\Field $field Field
179
     * @return Schema\Field
180
     */
181 10
    private function cloneFieldDefinition(Schema\Field $field)
182
    {
183 10
        $clone = clone $field;
184 10
        $clone->setName(preg_replace('/^'.preg_quote($this->name, '/').'\.(\d+\.)*/', '', $clone->getName()));
185 10
        return $clone;
186
    }
187
188
    /**
189
     * Process parent relation
190
     *
191
     * @param Schema\Relation $relation Parent relation
192
     * @return Schema\Relation|null
193
     */
194 4
    private function processParentRelation(Schema\Relation $relation)
195
    {
196 4
        $prefixRegex = '/^'.preg_quote($this->name, '/').'\.(\d+\.)*(?P<sub>.*)/';
197 4
        if (!preg_match($prefixRegex, $relation->getLocalProperty(), $matches)) {
198 2
            return null;
199
        }
200
201 4
        $clone = clone $relation;
202 4
        $clone->setLocalProperty($matches['sub']);
203 4
        return $clone;
204
    }
205
206
    /**
207
     * Returns the class name of this hash, possibly
208
     * taking the parent element into the name. this
209
     * string here results in the name of the generated Document.
210
     *
211
     * @param boolean $fq if true, we'll return the class name full qualified
212
     *
213
     * @return string
214
     */
215 20
    private function getClassName($fq = false)
216
    {
217 20
        $className = ucfirst($this->parent->getId()).ucfirst($this->getName());
218 20
        if ($fq) {
219 10
            $className = $this->parent->getNamespace().'\\Document\\'.$className;
220 5
        }
221
222 20
        return $className;
223
    }
224
}
225