SchemaValidator::validate()   A
last analyzed

Complexity

Conditions 4
Paths 6

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 9
c 1
b 0
f 0
dl 0
loc 18
rs 9.9666
cc 4
nc 6
nop 3
1
<?php
2
3
/*
4
 * This file is part of the tmilos/scim-schema package.
5
 *
6
 * (c) Milos Tomic <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace Tmilos\ScimSchema\Validator;
13
14
use Tmilos\ScimSchema\Helper;
15
use Tmilos\ScimSchema\Model\Schema\Attribute;
16
use Tmilos\ScimSchema\Model\Schema;
17
use Tmilos\ScimSchema\ScimConstants;
18
19
class SchemaValidator
20
{
21
    private static $commonAttributes = [
22
        'id' => 1,
23
        'schemas' => 1,
24
        'externalId' => 1,
25
        'meta' => 1,
26
    ];
27
28
    /**
29
     * @param array    $object
30
     * @param Schema   $schema
31
     * @param Schema[] $schemaExtensions
32
     *
33
     * @return ValidationResult
34
     */
35
    public function validate(array $object, Schema $schema, array $schemaExtensions = [])
36
    {
37
        $validationResult = new ValidationResult();
38
        /** @var Schema[] $otherSchemas */
39
        $otherSchemas = [];
40
        foreach ($schemaExtensions as $schemaExtension) {
41
            $otherSchemas[$schemaExtension->getId()] = $schemaExtension;
42
        }
43
44
        $this->validateByAttributes($object, $schema->getId(), $schema->getAttributes(), $otherSchemas, $validationResult, null);
45
46
        foreach ($otherSchemas as $schemaId => $otherSchema) {
47
            if (isset($object[$schemaId])) {
48
                $this->validateByAttributes($object[$schemaId], $otherSchema->getId(), $otherSchema->getAttributes(), [], $validationResult, null);
49
            }
50
        }
51
52
        return $validationResult;
53
    }
54
55
    /**
56
     * @param array            $object
57
     * @param string           $schemaId
58
     * @param Attribute[]      $attributes
59
     * @param array            $ignoreAttributes
60
     * @param ValidationResult $validationResult
61
     * @param string           $parentPath
62
     */
63
    private function validateByAttributes(array $object, $schemaId, $attributes, array $ignoreAttributes, ValidationResult $validationResult, $parentPath)
64
    {
65
        foreach ($object as $propertyName => $value) {
66
            if (!$parentPath && isset(self::$commonAttributes[$propertyName])) {
67
                // skip common resource attributes
68
                continue;
69
            }
70
            if (!$parentPath && isset($ignoreAttributes[$propertyName])) {
71
                continue;
72
            }
73
74
            $attribute = Helper::findAttribute($propertyName, $attributes);
75
            if (!$attribute) {
76
                $validationResult->add($propertyName, $parentPath, $schemaId, 'Attribute is not defined');
77
                continue;
78
            }
79
80
            if ($this->isArray($value)) {
81
                if (!$attribute->isMultiValued()) {
82
                    $validationResult->add($propertyName, $parentPath, $schemaId, 'Attribute is not defined in schema as multi-valued, but got array');
83
                    continue;
84
                } else {
85
                    foreach ($value as $item) {
86
                        $this->validateByAttributes($item, $schemaId, $attribute->getSubAttributes(), [], $validationResult, $propertyName);
87
                    }
88
                }
89
            } elseif ($this->isObject($value)) {
90
                if ($attribute->isMultiValued()) {
91
                    $validationResult->add($propertyName, $parentPath, $schemaId, 'Attribute is defined in schema as multi-valued, but got object');
92
                    continue;
93
                } elseif ($attribute->getType() !== ScimConstants::ATTRIBUTE_TYPE_COMPLEX) {
94
                    $validationResult->add($propertyName, $parentPath, $schemaId, 'Attribute is not defined in schema as complex, but got object');
95
                    continue;
96
                }
97
                $this->validateByAttributes($value, $schemaId, $attribute->getSubAttributes(), [], $validationResult, $propertyName);
98
            } else {
99
                if ($attribute->isMultiValued()) {
100
                    $validationResult->add($propertyName, $parentPath, $schemaId, 'Attribute is defined in schema as multi-valued, but got scalar');
101
                    continue;
102
                } elseif ($attribute->getType() === ScimConstants::ATTRIBUTE_TYPE_COMPLEX) {
103
                    $validationResult->add($propertyName, $parentPath, $schemaId, 'Attribute is defined in schema as complex, but got scalar');
104
                    continue;
105
                } elseif (!$attribute->isValueValid($value)) {
106
                    $validationResult->add($propertyName, $parentPath, $schemaId, sprintf('Attribute has invalid value for type "%s"', $attribute->getType()));
107
                    continue;
108
                }
109
            }
110
        }
111
    }
112
113
    /**
114
     * @param $value
115
     *
116
     * @return bool
117
     */
118
    private function isArray($value)
119
    {
120
        return is_array($value) && Helper::hasAllIntKeys($value);
121
    }
122
123
    /**
124
     * @param $value
125
     *
126
     * @return bool
127
     */
128
    private function isObject($value)
129
    {
130
        return is_array($value) && Helper::hasAllStringKeys($value);
131
    }
132
}
133