Passed
Pull Request — develop (#30)
by
unknown
06:52
created

SchemaValidator::objectIsValidSchemaClass()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 9
cts 9
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 8
nc 3
nop 1
crap 3
1
<?php
2
namespace Fathomminds\Rest\Schema;
3
4
use Fathomminds\Rest\Schema\TypeValidators\ValidatorFactory;
5
use Fathomminds\Rest\Exceptions\RestException;
6
7
class SchemaValidator
8
{
9
    protected $fields = [];
10
    protected $allowExtraneous = false;
11
    protected $requiredSchemaClass = null;
12
13 43
    public function __construct($requiredSchemaClass = null)
14
    {
15 43
        $this->requiredSchemaClass = $requiredSchemaClass;
16 43
    }
17
18 13
    public function validate($resource)
19
    {
20 13
        $this->expectObject($resource);
21 13
        $this->objectHasSchemaMethod($resource);
22 13
        $this->objectIsValidSchemaClass($resource);
23 13
        $extraneousCheck = [];
24 13
        if (!$this->allowExtraneous) {
25 12
            $extraneousCheck = $this->validateExtraneousFields($resource);
26
        }
27 13
        $errors = array_merge(
28 13
            $this->validateRequiredFields($resource),
29 13
            $extraneousCheck,
30 13
            $this->validateFieldTypes($resource)
31
        );
32 13
        if (!empty($errors)) {
33 8
            throw new RestException(
34 8
                'Invalid structure',
35
                [
36 8
                    'schema' => get_class($resource),
37 8
                    'errors' => $errors,
38
                ]
39
            );
40
        }
41 5
    }
42
43 38
    public function allowExtraneous($value)
44
    {
45 38
        $this->allowExtraneous = $value;
46 38
    }
47
48 14
    private function expectObject($resource)
49
    {
50 14
        if (gettype($resource) !== 'object') {
51 1
            throw new RestException(
52 1
                'Object expected',
53
                [
54 1
                    'schema' => static::class,
55 1
                    'type' => gettype($resource),
56
                ]
57
            );
58
        }
59 13
    }
60
61 13
    private function objectHasSchemaMethod($resource)
62
    {
63 13
        if (!method_exists($resource, 'schema')) {
64 1
            throw new RestException(
65 1
                'Object must be a correct RestSchema object',
66
                [
67 1
                    'schema' => static::class,
68 1
                    'type' => gettype($resource),
69
                ]
70
            );
71
        }
72 13
    }
73
74 13
    private function objectIsValidSchemaClass($resource)
75
    {
76 13
        if ($this->requiredSchemaClass === null) {
77 13
            return;
78
        }
79 3
        if (get_class($resource) !== $this->requiredSchemaClass) {
80 1
            throw new RestException(
81 1
                'Object must be an instance of the defined SchemaClass',
82
                [
83 1
                    'schema' => static::class,
84 1
                    'type' => gettype($resource),
85
                ]
86
            );
87
        }
88 2
    }
89
90 13
    private function validateRequiredFields($resource)
91
    {
92 13
        $errors = [];
93 13
        $requiredFields = $this->getRequiredFields($resource);
94 13
        foreach ($requiredFields as $fieldName) {
95 13
            if (!property_exists($resource, $fieldName)) {
96 13
                $errors[$fieldName] = 'Missing required field';
97
            }
98
        }
99 13
        return $errors;
100
    }
101
102 12
    private function validateExtraneousFields($resource)
103
    {
104 12
        $errors = [];
105 12
        foreach (array_keys(get_object_vars($resource)) as $fieldName) {
106 10
            if (!isset($resource->schema()[$fieldName])) {
107 10
                $errors[$fieldName] = 'Extraneous field';
108
            }
109
        }
110 12
        return $errors;
111
    }
112
113 13
    private function validateFieldTypes($resource)
114
    {
115 13
        $validatorFactory = new ValidatorFactory;
116 13
        $errors = [];
117 13
        foreach ($resource->schema() as $fieldName => $rules) {
118 13
            if (property_exists($resource, $fieldName)) {
119
                try {
120 11
                    $validatorFactory->create($rules)->validate($resource->{$fieldName});
121 3
                } catch (RestException $ex) {
122 3
                    $errors[$fieldName]['error'] = $ex->getMessage();
123 13
                    $errors[$fieldName]['details'] = $ex->getDetails();
124
                }
125
            }
126
        }
127 13
        return $errors;
128
    }
129
130 20
    private function filterFields($resource, $paramKey, $paramValue)
131
    {
132 20
        $fields = [];
133 20
        foreach ($resource->schema() as $fieldName => $params) {
134 20
            if (isset($params[$paramKey]) && $params[$paramKey] == $paramValue) {
135 20
                $fields[] = $fieldName;
136
            }
137
        }
138 20
        return $fields;
139
    }
140
141 2
    public function getFields($resource)
142
    {
143 2
        return $resource->schema();
144
    }
145
146 13
    public function getRequiredFields($resource)
147
    {
148 13
        return $this->filterFields($resource, 'required', true);
149
    }
150
151 9
    public function getUniqueFields($resource)
152
    {
153 9
        return $this->filterFields($resource, 'unique', true);
154
    }
155
}
156