Completed
Pull Request — master (#76)
by Simone
08:31
created

Schema   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 138
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 5

Importance

Changes 0
Metric Value
wmc 24
c 0
b 0
f 0
lcom 2
cbo 5
dl 0
loc 138
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
B parseSchema() 0 28 6
A countSubSchemas() 0 4 1
A completeSchema() 0 4 1
A schemaNames() 0 4 1
A getTitle() 0 4 1
C validate() 0 35 11
A properties() 0 4 1
A required() 0 4 1
1
<?php
2
3
/**
4
 * This file is part of sensorario/resources repository
5
 *
6
 * (c) Simone Gentili <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Sensorario\Resources\Schema;
13
14
use RuntimeException;
15
16
final class Schema
17
{
18
    const PRIMITIVE_ARRAY   = 'array';
19
    const PRIMITIVE_BOOLEAN = 'boolean';
20
    const PRIMITIVE_DEFAULT = Schema::PRIMITIVE_NULL;
21
    const PRIMITIVE_INTEGER = 'integer';
22
    const PRIMITIVE_NULL    = 'null';
23
    const PRIMITIVE_NUMBER  = 'number';
24
    const PRIMITIVE_OBJECT  = 'object';
25
    const PRIMITIVE_STRING  = 'string';
26
27
    private $completeSchema;
28
29
    private $schemaNames = [];
30
31
    private $required = [];
32
33
    private $validTypes = [
34
        self::PRIMITIVE_ARRAY,
35
        self::PRIMITIVE_BOOLEAN,
36
        self::PRIMITIVE_DEFAULT,
37
        self::PRIMITIVE_INTEGER,
38
        self::PRIMITIVE_NULL,
39
        self::PRIMITIVE_NUMBER,
40
        self::PRIMITIVE_OBJECT,
41
        self::PRIMITIVE_STRING,
42
    ];
43
44
    private $subSchemaCounter = 0;
45
46
    private $properties = [];
47
48
    public function __construct(
49
        Parser $parser,
50
        $schema
51
    ) {
52
        $this->completeSchema = $schema;
53
        $this->schemaNames[] = 'root';
54
        $this->parser = $parser;
0 ignored issues
show
Bug introduced by
The property parser does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
55
        $this->parseSchema($this->completeSchema);
56
    }
57
58
    private function parseSchema($schema)
59
    {
60
        $this->parser->setSchema($schema);
61
        $this->parser->setValidTypes($this->validTypes);
62
        $this->parser->parseSchema();
63
64
        foreach ($schema['properties'] as $name => $def) {
65
            $this->properties[$name] = $def;
66
            if (!isset($def['type'])) {
67
                throw new Exceptions\NoPropertyTypeException();
68
            }
69
        }
70
71
        if (isset($schema['required'])) {
72
            $this->required = array_merge(
73
                $this->required,
74
                $schema['required']
75
            );
76
        }
77
78
        foreach ($schema as $key => $value) {
79
            if (!in_array($key, ['required', 'properties', 'title', 'type'])) {
80
                $this->schemaNames[] = $key;
81
                $this->subSchemaCounter++;
82
                $this->parseSchema($value);
83
            }
84
        }
85
    }
86
87
    public function countSubSchemas()
88
    {
89
        return $this->subSchemaCounter;
90
    }
91
92
    public function completeSchema()
93
    {
94
        return $this->completeSchema;
95
    }
96
97
    public function schemaNames()
98
    {
99
        return $this->schemaNames;
100
    }
101
102
    public function getTitle()
103
    {
104
        return $this->completeSchema['title'];
105
    }
106
107
    /** @todo move this inside an applipcation service */
108
    public function validate($json) 
109
    {
110
        $jsonAsArray = json_decode($json, true);
111
112
        foreach ($jsonAsArray as $name => $property) {
113
            if (!isset($this->properties()[$name])) {
114
                throw new Exceptions\NotAllowedPropertyException();
115
            }
116
        }
117
118
        foreach ($this->required as $requiredProperty) {
119
            if (!isset($jsonAsArray[$requiredProperty])) {
120
                throw new Exceptions\MissingPropertyException();
121
            }
122
        }
123
124
        foreach ($jsonAsArray as $name => $property) {
125
            $prop = $this->properties()[$name];
126
            if (gettype($jsonAsArray[$name]) != $prop['type']) {
127
                if ($prop['type'] == Schema::PRIMITIVE_INTEGER && is_numeric($jsonAsArray[$name])) {
128
                    continue;
129
                }
130
131
                if ($prop['type'] == Schema::PRIMITIVE_ARRAY) {
132
                    if (!isset($prop['items'])) {
133
                        throw new Exceptions\UndefinedArrayItemsTypeException();
134
                    }
135
                }
136
137
                throw new Exceptions\NotAllowedValueException();
138
            }
139
        }
140
141
        return json_decode($json);
142
    }
143
144
    public function properties()
145
    {
146
        return $this->properties;
147
    }
148
149
    public function required()
150
    {
151
        return $this->required;
152
    }
153
}
154