Completed
Push — feature/other-validation ( c4ebdf...a3189f )
by Narcotic
152:45 queued 146:40
created

JsonDefinitionHash::getJsonDefinition()   C

Complexity

Conditions 7
Paths 9

Size

Total Lines 23
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 23
ccs 19
cts 19
cp 1
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 15
nc 9
nop 0
crap 7
1
<?php
2
namespace Graviton\GeneratorBundle\Definition;
3
use Graviton\GeneratorBundle\Definition\Schema\Field;
4
5
/**
6
 * Represents a hash of fields as defined in the JSON format
7
 *
8
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
9
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
10
 * @link     http://swisscom.ch
11
 */
12
class JsonDefinitionHash implements DefinitionElementInterface
13
{
14
    /**
15
     * @var string Name of this hash
16
     */
17
    private $name;
18
    /**
19
     * @var JsonDefinition
20
     */
21
    private $parent;
22
    /**
23
     * @var DefinitionElementInterface[] Array of fields..
24
     */
25
    private $fields = [];
26
    /**
27
     * @var Schema\Field Field definition
28
     */
29
    private $definition;
30
31
    /**
32
     * Constructor
33
     *
34
     * @param string                       $name       Name of this hash
35
     * @param JsonDefinition               $parent     Parent definiton
36
     * @param DefinitionElementInterface[] $fields     Fields of the hash
37
     * @param Schema\Field                 $definition Field definition
0 ignored issues
show
Documentation introduced by
Should the type for parameter $definition not be null|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...
38
     */
39 42
    public function __construct($name, JsonDefinition $parent, array $fields, Schema\Field $definition = null)
40
    {
41 42
        $this->name = $name;
42 42
        $this->parent = $parent;
43 42
        $this->fields = $fields;
44 42
        $this->definition = $definition;
45 42
    }
46
47
    /**
48
     * Returns the hash name
49
     *
50
     * @return string Name
51
     */
52 22
    public function getName()
53
    {
54 22
        return $this->name;
55
    }
56
57
    /**
58
     * Returns the definition as array..
59
     *
60
     * @return array the definition
61
     */
62 6
    public function getDefAsArray()
63
    {
64 6
        return array_replace(
65
            [
66 6
                'name'              => $this->getName(),
67 6
                'type'              => $this->getType(),
68 6
                'exposedName'       => $this->getName(),
69 6
                'doctrineType'      => $this->getTypeDoctrine(),
70 6
                'serializerType'    => $this->getTypeSerializer(),
71 6
                'relType'           => self::REL_TYPE_EMBED,
72 3
                'isClassType'       => true,
73 3
                'constraints'       => [],
74 3
                'required'          => false,
75 3
                'searchable'        => false,
76 3
            ],
77 6
            $this->definition === null ? [
78 4
                'required'          => $this->getRequired()
79 2
            ] : [
80 2
                'exposedName'       => $this->definition->getExposeAs() ?: $this->getName(),
81 2
                'title'             => $this->definition->getTitle(),
82 2
                'description'       => $this->definition->getDescription(),
83 2
                'readOnly'          => $this->definition->getReadOnly(),
84 2
                'required'          => $this->definition->getRequired(),
85 2
                'searchable'        => $this->definition->getSearchable(),
86 2
                'constraints'       => array_map(
87 2
                    [Utils\ConstraintNormalizer::class, 'normalize'],
88 4
                    $this->definition->getConstraints()
89 1
                ),
90
            ]
91 3
        );
92
    }
93
94
    /**
95
     * {@inheritDoc}
96
     *
97
     * @return string type
98
     */
99 8
    public function getType()
100
    {
101 8
        return self::TYPE_HASH;
102
    }
103
104
    /**
105
     * Whether this hash is anonymous, so has no own field definition (properly only defined
106
     * by definitions such as "object.field", not an own definition)
107
     *
108
     * @return bool true if yes, false otherwise
109
     */
110 4
    public function isAnonymous()
111
    {
112 4
        return ($this->definition === null);
113
    }
114
115
    /**
116
     * in an 'anonymous' hash situation, we will check if any children are required
117
     *
118
     * @return bool if required or not
119
     */
120 4
    public function getRequired()
0 ignored issues
show
Coding Style introduced by
function getRequired() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
121
    {
122 4
        $isRequired = false;
123
124
        // see if on the first level of fields we have a required=true in the definition
125 4
        foreach ($this->fields as $field) {
126 2
            if ($field instanceof JsonDefinitionField &&
127 2
                $field->getDef() instanceof Field &&
128 2
                $field->getDef()->getRequired() === true
129 1
            ) {
130 2
                $isRequired = true;
131 1
            }
132 2
        }
133
134 4
        return $isRequired;
135
    }
136
137
    /**
138
     * {@inheritDoc}
139
     *
140
     * @return string type
141
     */
142 8
    public function getTypeDoctrine()
143
    {
144 8
        return $this->getClassName(true);
145
    }
146
147
    /**
148
     * Returns the field type in a serializer-understandable way..
149
     *
150
     * @return string Type
151
     */
152 8
    public function getTypeSerializer()
153
    {
154 8
        return $this->getClassName(true);
155
    }
156
157
    /**
158
     * Returns the field definition of this hash from "local perspective",
159
     * meaning that we only include fields inside this hash BUT with all
160
     * the stuff from the json file. this is needed to generate a Document/Model
161
     * from this hash (generate a json file again)
162
     *
163
     * @return JsonDefinition the definition of this hash in a standalone array ready to be json_encoded()
164
     */
165 10
    public function getJsonDefinition()
166
    {
167 10
        $definition = (new Schema\Definition())
168 10
            ->setId($this->getClassName())
169 10
            ->setDescription($this->definition === null ? null : $this->definition->getDescription())
170 10
            ->setTitle($this->definition === null ? null : $this->definition->getTitle())
171 10
            ->setIsSubDocument(true)
172 10
            ->setTarget(new Schema\Target());
173
174 10
        foreach ($this->fields as $field) {
175 10
            foreach ($this->processFieldDefinitionsRecursive($field) as $definitions) {
176 10
                $definition->getTarget()->addField($definitions);
177 5
            }
178 5
        }
179 10
        foreach ($this->parent->getRelations() as $relation) {
180 4
            $relation = $this->processParentRelation($relation);
181 4
            if ($relation !== null) {
182 4
                $definition->getTarget()->addRelation($relation);
183 2
            }
184 5
        }
185
186 10
        return new JsonDefinition($definition);
187
    }
188
189
    /**
190
     * Method getFieldDefinitionsRecursive
191
     *
192
     * @param DefinitionElementInterface $field
193
     * @return Schema\Field[]
194
     */
195 10
    private function processFieldDefinitionsRecursive(DefinitionElementInterface $field)
196
    {
197 10
        if ($field instanceof JsonDefinitionField) {
198 10
            return [$this->cloneFieldDefinition($field->getDef())];
199 4
        } elseif ($field instanceof JsonDefinitionArray) {
200 8
            return $this->processFieldDefinitionsRecursive($field->getElement());
201 2
        } elseif ($field instanceof JsonDefinitionHash) {
202 4
            return array_reduce(
203 4
                $field->fields,
204 4
                function (array $subfields, DefinitionElementInterface $subfield) {
205 4
                    return array_merge($subfields, $this->processFieldDefinitionsRecursive($subfield));
206 4
                },
207 4
                $field->definition === null ? [] : [$this->cloneFieldDefinition($field->definition)]
208 2
            );
209
        }
210
211
        throw new \InvalidArgumentException(sprintf('Unknown field type "%s"', get_class($field)));
212
    }
213
214
    /**
215
     * Clone field definition
216
     *
217
     * @param Schema\Field $field Field
218
     * @return Schema\Field
219
     */
220 10
    private function cloneFieldDefinition(Schema\Field $field)
221
    {
222 10
        $clone = clone $field;
223 10
        $clone->setName(preg_replace('/^'.preg_quote($this->name, '/').'\.(\d+\.)*/', '', $clone->getName()));
224 10
        return $clone;
225
    }
226
227
    /**
228
     * Process parent relation
229
     *
230
     * @param Schema\Relation $relation Parent relation
231
     * @return Schema\Relation|null
232
     */
233 4
    private function processParentRelation(Schema\Relation $relation)
234
    {
235 4
        $prefixRegex = '/^'.preg_quote($this->name, '/').'\.(\d+\.)*(?P<sub>.*)/';
236 4
        if (!preg_match($prefixRegex, $relation->getLocalProperty(), $matches)) {
237 2
            return null;
238
        }
239
240 4
        $clone = clone $relation;
241 4
        $clone->setLocalProperty($matches['sub']);
242 4
        return $clone;
243
    }
244
245
    /**
246
     * Returns the class name of this hash, possibly
247
     * taking the parent element into the name. this
248
     * string here results in the name of the generated Document.
249
     *
250
     * @param boolean $fq if true, we'll return the class name full qualified
251
     *
252
     * @return string
253
     */
254 20
    private function getClassName($fq = false)
255
    {
256 20
        $className = ucfirst($this->parent->getId()).ucfirst($this->getName());
257 20
        if ($fq) {
258 10
            $className = $this->parent->getNamespace().'\\Document\\'.$className;
259 5
        }
260
261 20
        return $className;
262
    }
263
}
264