Completed
Push — master ( e98ae3...0e888f )
by Matt
02:50
created

AdditionalProperties   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 74
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 3

Test Coverage

Coverage 96.55%

Importance

Changes 0
Metric Value
dl 0
loc 74
ccs 28
cts 29
cp 0.9655
rs 10
c 0
b 0
f 0
wmc 9
lcom 0
cbo 3

2 Methods

Rating   Name   Duplication   Size   Complexity  
B validate() 0 34 5
B getDiff() 0 23 4
1
<?php
2
3
namespace League\JsonGuard\Constraints;
4
5
use League\JsonGuard;
6
use League\JsonGuard\Assert;
7
use League\JsonGuard\SubSchemaValidatorFactory;
8
use League\JsonGuard\ValidationError;
9
10
class AdditionalProperties implements ParentSchemaAwareContainerInstanceConstraint
11
{
12
    const KEYWORD = 'additionalProperties';
13
14
    /**
15
     * {@inheritdoc}
16
     */
17 26
    public static function validate(
18
        $data,
19
        $schema,
20
        $parameter,
21
        SubSchemaValidatorFactory $validatorFactory,
22
        $pointer = null
23
    ) {
24 26
        Assert::type($parameter, ['object', 'boolean'], self::KEYWORD, $pointer);
25
26 24
        if (!is_object($data)) {
27 8
            return null;
28
        }
29
30
31 24
        $diff = self::getDiff($data, $schema);
32
33 24
        if (count($diff) === 0) {
34 18
            return null;
35
        }
36
37 20
        if ($parameter === false) {
38 12
            $message = 'Additional properties found which are not allowed: {diff}';
39 12
            $context = ['diff' => implode(', ', $diff)];
40 12
            return new ValidationError($message, self::KEYWORD, $data, $pointer, $context);
41 12
        } elseif (is_object($parameter)) {
42
            // If additionalProperties is an object it's a schema,
43
            // so validate all additional properties against it.
44 12
            $additionalSchema = array_fill_keys($diff, $parameter);
45
46 12
            return Properties::validate($data, $additionalSchema, $validatorFactory, $pointer);
47
        }
48
49
        return null;
50
    }
51
52
    /**
53
     * Get the properties in $data which are not in $schema 'properties' or matching 'patternProperties'.
54
     *
55
     * @param object $data
56
     * @param object $schema
57
     *
58
     * @return array
59
     */
60 24
    protected static function getDiff($data, $schema)
61
    {
62 24
        if (property_exists($schema, 'properties')) {
63 18
            $definedProperties = array_keys(get_object_vars($schema->properties));
64 18
        } else {
65 10
            $definedProperties = [];
66
        }
67
68 24
        $actualProperties = array_keys(get_object_vars($data));
69 24
        $diff             = array_diff($actualProperties, $definedProperties);
70
71
        // The diff doesn't account for patternProperties, so lets filter those out too.
72 24
        if (property_exists($schema, 'patternProperties')) {
73 8
            foreach ($schema->patternProperties as $property => $schema) {
74 8
                $matches = JsonGuard\properties_matching_pattern($property, $diff);
75 8
                $diff    = array_diff($diff, $matches);
76 8
            }
77
78 8
            return $diff;
79
        }
80
81 20
        return $diff;
82
    }
83
}
84