Completed
Push — master ( c5a357...79cf75 )
by Mehmet
07:41
created

Validator::assertDoc()   C

Complexity

Conditions 8
Paths 13

Size

Total Lines 39
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 26
nc 13
nop 3
dl 0
loc 39
rs 5.3846
c 0
b 0
f 0
1
<?php
2
3
4
namespace Selami\Entity;
5
6
use Selami\Entity\DataType;
7
use InvalidArgumentException;
8
9
class Validator
10
{
11
    static protected $constraints = [
12
        'Boolean'   => DataType\Boolean::class,
13
        'Date'      => DataType\Date::class,
14
        'Double'    => DataType\Double::class,
15
        'Email'     => DataType\Email::class,
16
        'Enum'      => DataType\Enum::class,
17
        'FilePath'  => DataType\FilePath::class,
18
        'Html'      => DataType\Html::class,
19
        'Integer'   => DataType\Integer::class,
20
        'Ipv4'      => DataType\Ipv4::class,
21
        'Ipv6'      => DataType\Ipv6::class,
22
        'MacAddress'    => DataType\MacAddress::class,
23
        'PhoneNumber'   => DataType\PhoneNumber::class,
24
        'Regex'     => DataType\Regex::class,
25
        'Slug'      => DataType\Slug::class,
26
        'Text'      => DataType\Text::class,
27
        'Url'       => DataType\Url::class,
28
        'Uuid'      => DataType\Uuid::class
29
    ];
30
31
    static protected $validTypes = [
32
        'Boolean'   => 'boolean',
33
        'Date'      => 'string',
34
        'Double'    => 'float',
35
        'Email'     => 'string',
36
        'Enum'      => 'string',
37
        'FilePath'  => 'string',
38
        'Html'      => 'string',
39
        'Integer'   => 'integer',
40
        'Ipv4'      => 'string',
41
        'Ipv6'      => 'string',
42
        'MacAddress'    => 'string',
43
        'PhoneNumber'   => 'string',
44
        'Regex'     => 'string',
45
        'Slug'      => 'string',
46
        'Text'      => 'string',
47
        'Url'       => 'string',
48
        'Uuid'      => 'string'
49
    ];
50
51
    /**
52
     * @param string $itemKey
53
     * @param array $properties
54
     * @return bool
55
     * @throws InvalidArgumentException
56
     */
57
    private function checkType(string $itemKey, array $properties)
58
    {
59
        if (!array_key_exists('type', $properties)) {
60
            throw new InvalidArgumentException(sprintf('%s must have "type" property.', $itemKey));
61
        }
62
        if (!array_key_exists(upperCamelCase($properties['type']), self::$constraints)) {
63
            throw new InvalidArgumentException(sprintf('%s is not valid DataType.', $properties['type']));
64
        }
65
        return true;
66
    }
67
68
    /**
69
     * @param string $itemKey
70
     * @param mixed $item
71
     * @param array $properties
72
     * @return bool|string
73
     * @throws InvalidArgumentException
74
     */
75
    public function assertDocItem(string $itemKey, $item, array $properties)
76
    {
77
        $this->checkType($itemKey, $properties);
78
        try {
79
            $dataType = self::$constraints[upperCamelCase($properties['type'])];
80
            unset($properties['type']);
81
            $constraint = new $dataType($itemKey, $item, $properties);
82
            return $constraint->assert();
83
        } catch (InvalidArgumentException $e) {
84
            return $e->getMessage();
85
        }
86
    }
87
88
    /**
89
     * Validate given documents
90
     *
91
     * @param array $schema
92
     * @param array $myDoc
93
     * @param string $myKey
94
     * @return array
95
     * @throws InvalidArgumentException
96
     */
97
    public function assertDoc(array $schema, array $myDoc, string $myKey = null)
98
    {
99
        $myKeys = array_keys($myDoc);
100
        foreach ($myKeys as $key) {
101
            $myDoc_key_type = getType($myDoc[$key]);
102
            $vKey = $key;
103
            if ($myKey !== null) {
104
                $vKey = $myKey.'.'.$key;
105
            }
106
            // Does doc has an array key that does not exist in model definition.
107
            if (!isset($schema[$key])) {
108
                $message = sprintf('Error for key "%s" that does not exist in the model', $vKey);
109
                throw new InvalidArgumentException($message);
110
            } // Is the value of the array[key] again another array?
111
            elseif ($myDoc_key_type === 'array') {
112
                // Validate this array too.
113
                $myDoc[$key] = $this->assertDoc($schema[$key], $myDoc[$key], $vKey);
114
                if (getType($myDoc[$key]) !== 'array') {
115
                    return $myDoc[$key];
116
                }
117
            } // Is the value of the array[key] have same variable type
118
            //that stated in the definition of the model array.
119
            elseif ($myDoc_key_type !== self::$validTypes[upperCamelCase($schema[$key]['type'])]) {
120
                $message = sprintf(
121
                    'Error for key "%s", %s given but it must be %s',
122
                    $vKey,
123
                    $myDoc_key_type,
124
                    self::$validTypes[upperCamelCase($schema[$key]['type'])]
125
                );
126
                throw new InvalidArgumentException($message);
127
            } else {
128
                $assertedItem = $this->assertDocItem($vKey, $myDoc[$key], $schema[$key]);
129
                if($assertedItem !== true) {
130
                    throw new InvalidArgumentException($assertedItem);
131
                }
132
            }
133
        }
134
        return $myDoc;
135
    }
136
}
137