Completed
Push — feature/other-validation ( 9cc7bf...3b2e71 )
by Narcotic
194:06 queued 128:31
created

JsonDefinitionHash::isAnonymous()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 0
cts 0
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 2
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
     * 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 8
     *
108
     * @return bool true if yes, false otherwise
109 8
     */
110
    public function isAnonymous()
111
    {
112
        return ($this->definition === null);
113
    }
114
115
    /**
116
     * in an 'anonymous' hash situation, we will check if any children are required
117 8
     *
118
     * @return bool if required or not
119 8
     */
120
    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
        $isRequired = false;
123
124
        // see if on the first level of fields we have a required=true in the definition
125
        foreach ($this->fields as $field) {
126
            if ($field instanceof JsonDefinitionField &&
127
                $field->getDef() instanceof Field &&
128
                $field->getDef()->getRequired() === true
129
            ) {
130 10
                $isRequired = true;
131
            }
132 10
        }
133 10
134 10
        return $isRequired;
135 10
    }
136 10
137 10
    /**
138
     * {@inheritDoc}
139 10
     *
140 10
     * @return string type
141 10
     */
142 5
    public function getTypeDoctrine()
143 5
    {
144 10
        return $this->getClassName(true);
145 4
    }
146 4
147 4
    /**
148 2
     * Returns the field type in a serializer-understandable way..
149 5
     *
150
     * @return string Type
151 10
     */
152
    public function getTypeSerializer()
153
    {
154
        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 10
     * the stuff from the json file. this is needed to generate a Document/Model
161
     * from this hash (generate a json file again)
162 10
     *
163 10
     * @return JsonDefinition the definition of this hash in a standalone array ready to be json_encoded()
164 4
     */
165 8
    public function getJsonDefinition()
166 2
    {
167 4
        $definition = (new Schema\Definition())
168 4
            ->setId($this->getClassName())
169 4
            ->setDescription($this->definition === null ? null : $this->definition->getDescription())
170 4
            ->setTitle($this->definition === null ? null : $this->definition->getTitle())
171 4
            ->setIsSubDocument(true)
172 4
            ->setTarget(new Schema\Target());
173 2
174
        foreach ($this->fields as $field) {
175
            foreach ($this->processFieldDefinitionsRecursive($field) as $definitions) {
176
                $definition->getTarget()->addField($definitions);
177
            }
178
        }
179
        foreach ($this->parent->getRelations() as $relation) {
180
            $relation = $this->processParentRelation($relation);
181
            if ($relation !== null) {
182
                $definition->getTarget()->addRelation($relation);
183
            }
184
        }
185 10
186
        return new JsonDefinition($definition);
187 10
    }
188 10
189 10
    /**
190
     * Method getFieldDefinitionsRecursive
191
     *
192
     * @param DefinitionElementInterface $field
193
     * @return Schema\Field[]
194
     */
195
    private function processFieldDefinitionsRecursive(DefinitionElementInterface $field)
196
    {
197
        if ($field instanceof JsonDefinitionField) {
198 4
            return [$this->cloneFieldDefinition($field->getDef())];
199
        } elseif ($field instanceof JsonDefinitionArray) {
200 4
            return $this->processFieldDefinitionsRecursive($field->getElement());
201 4
        } elseif ($field instanceof JsonDefinitionHash) {
202 2
            return array_reduce(
203
                $field->fields,
204
                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
            );
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 20
     */
220
    private function cloneFieldDefinition(Schema\Field $field)
221 20
    {
222 20
        $clone = clone $field;
223 10
        $clone->setName(preg_replace('/^'.preg_quote($this->name, '/').'\.(\d+\.)*/', '', $clone->getName()));
224 5
        return $clone;
225
    }
226 20
227
    /**
228
     * Process parent relation
229
     *
230
     * @param Schema\Relation $relation Parent relation
231
     * @return Schema\Relation|null
232
     */
233
    private function processParentRelation(Schema\Relation $relation)
234
    {
235
        $prefixRegex = '/^'.preg_quote($this->name, '/').'\.(\d+\.)*(?P<sub>.*)/';
236
        if (!preg_match($prefixRegex, $relation->getLocalProperty(), $matches)) {
237
            return null;
238
        }
239
240
        $clone = clone $relation;
241
        $clone->setLocalProperty($matches['sub']);
242
        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
    private function getClassName($fq = false)
255
    {
256
        $className = ucfirst($this->parent->getId()).ucfirst($this->getName());
257
        if ($fq) {
258
            $className = $this->parent->getNamespace().'\\Document\\'.$className;
259
        }
260
261
        return $className;
262
    }
263
}
264