Completed
Push — feature/other-validation ( 8ac7b0...9cc7bf )
by Narcotic
65:24
created

JsonDefinitionHash::getRequired()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 16
rs 8.8571
ccs 3
cts 3
cp 1
cc 5
eloc 8
nc 3
nop 0
crap 5
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 42
     */
39
    public function __construct($name, JsonDefinition $parent, array $fields, Schema\Field $definition = null)
40 42
    {
41 42
        $this->name = $name;
42 42
        $this->parent = $parent;
43 42
        $this->fields = $fields;
44 42
        $this->definition = $definition;
45
    }
46
47
    /**
48
     * Returns the hash name
49
     *
50
     * @return string Name
51 22
     */
52
    public function getName()
53 22
    {
54
        return $this->name;
55
    }
56
57
    /**
58
     * Returns the definition as array..
59
     *
60
     * @return array the definition
61 6
     */
62
    public function getDefAsArray()
63 6
    {
64
        return array_replace(
65 6
            [
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 3
                'relType'           => self::REL_TYPE_EMBED,
72 3
                'isClassType'       => true,
73 3
                'constraints'       => [],
74 3
                'required'          => false,
75 3
                'searchable'        => false,
76 6
            ],
77 2
            $this->definition === null ? [
78
                '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 4
                'constraints'       => array_map(
87 1
                    [Utils\ConstraintNormalizer::class, 'normalize'],
88
                    $this->definition->getConstraints()
89 3
                ),
90
            ]
91
        );
92
    }
93
94
    /**
95
     * {@inheritDoc}
96
     *
97 8
     * @return string type
98
     */
99 8
    public function getType()
100
    {
101
        return self::TYPE_HASH;
102
    }
103
104
    /**
105
     * in an 'anonymous' hash situation, we will check if any children are required
106
     *
107 8
     * @return bool if required or not
108
     */
109 8
    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...
110
    {
111
        $isRequired = false;
112
113
        // see if on the first level of fields we have a required=true in the definition
114
        foreach ($this->fields as $field) {
115
            if ($field instanceof JsonDefinitionField &&
116
                $field->getDef() instanceof Field &&
117 8
                $field->getDef()->getRequired() === true
118
            ) {
119 8
                $isRequired = true;
120
            }
121
        }
122
123
        return $isRequired;
124
    }
125
126
    /**
127
     * {@inheritDoc}
128
     *
129
     * @return string type
130 10
     */
131
    public function getTypeDoctrine()
132 10
    {
133 10
        return $this->getClassName(true);
134 10
    }
135 10
136 10
    /**
137 10
     * Returns the field type in a serializer-understandable way..
138
     *
139 10
     * @return string Type
140 10
     */
141 10
    public function getTypeSerializer()
142 5
    {
143 5
        return $this->getClassName(true);
144 10
    }
145 4
146 4
    /**
147 4
     * Returns the field definition of this hash from "local perspective",
148 2
     * meaning that we only include fields inside this hash BUT with all
149 5
     * the stuff from the json file. this is needed to generate a Document/Model
150
     * from this hash (generate a json file again)
151 10
     *
152
     * @return JsonDefinition the definition of this hash in a standalone array ready to be json_encoded()
153
     */
154
    public function getJsonDefinition()
155
    {
156
        $definition = (new Schema\Definition())
157
            ->setId($this->getClassName())
158
            ->setDescription($this->definition === null ? null : $this->definition->getDescription())
159
            ->setTitle($this->definition === null ? null : $this->definition->getTitle())
160 10
            ->setIsSubDocument(true)
161
            ->setTarget(new Schema\Target());
162 10
163 10
        foreach ($this->fields as $field) {
164 4
            foreach ($this->processFieldDefinitionsRecursive($field) as $definitions) {
165 8
                $definition->getTarget()->addField($definitions);
166 2
            }
167 4
        }
168 4
        foreach ($this->parent->getRelations() as $relation) {
169 4
            $relation = $this->processParentRelation($relation);
170 4
            if ($relation !== null) {
171 4
                $definition->getTarget()->addRelation($relation);
172 4
            }
173 2
        }
174
175
        return new JsonDefinition($definition);
176
    }
177
178
    /**
179
     * Method getFieldDefinitionsRecursive
180
     *
181
     * @param DefinitionElementInterface $field
182
     * @return Schema\Field[]
183
     */
184
    private function processFieldDefinitionsRecursive(DefinitionElementInterface $field)
185 10
    {
186
        if ($field instanceof JsonDefinitionField) {
187 10
            return [$this->cloneFieldDefinition($field->getDef())];
188 10
        } elseif ($field instanceof JsonDefinitionArray) {
189 10
            return $this->processFieldDefinitionsRecursive($field->getElement());
190
        } elseif ($field instanceof JsonDefinitionHash) {
191
            return array_reduce(
192
                $field->fields,
193
                function (array $subfields, DefinitionElementInterface $subfield) {
194
                    return array_merge($subfields, $this->processFieldDefinitionsRecursive($subfield));
195
                },
196
                $field->definition === null ? [] : [$this->cloneFieldDefinition($field->definition)]
197
            );
198 4
        }
199
200 4
        throw new \InvalidArgumentException(sprintf('Unknown field type "%s"', get_class($field)));
201 4
    }
202 2
203
    /**
204
     * Clone field definition
205 4
     *
206 4
     * @param Schema\Field $field Field
207 4
     * @return Schema\Field
208
     */
209
    private function cloneFieldDefinition(Schema\Field $field)
210
    {
211
        $clone = clone $field;
212
        $clone->setName(preg_replace('/^'.preg_quote($this->name, '/').'\.(\d+\.)*/', '', $clone->getName()));
213
        return $clone;
214
    }
215
216
    /**
217
     * Process parent relation
218
     *
219 20
     * @param Schema\Relation $relation Parent relation
220
     * @return Schema\Relation|null
221 20
     */
222 20
    private function processParentRelation(Schema\Relation $relation)
223 10
    {
224 5
        $prefixRegex = '/^'.preg_quote($this->name, '/').'\.(\d+\.)*(?P<sub>.*)/';
225
        if (!preg_match($prefixRegex, $relation->getLocalProperty(), $matches)) {
226 20
            return null;
227
        }
228
229
        $clone = clone $relation;
230
        $clone->setLocalProperty($matches['sub']);
231
        return $clone;
232
    }
233
234
    /**
235
     * Returns the class name of this hash, possibly
236
     * taking the parent element into the name. this
237
     * string here results in the name of the generated Document.
238
     *
239
     * @param boolean $fq if true, we'll return the class name full qualified
240
     *
241
     * @return string
242
     */
243
    private function getClassName($fq = false)
244
    {
245
        $className = ucfirst($this->parent->getId()).ucfirst($this->getName());
246
        if ($fq) {
247
            $className = $this->parent->getNamespace().'\\Document\\'.$className;
248
        }
249
250
        return $className;
251
    }
252
}
253