Protobuf::walking()   B
last analyzed

Complexity

Conditions 8
Paths 7

Size

Total Lines 31
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 21
nc 7
nop 2
dl 0
loc 31
rs 8.4444
c 0
b 0
f 0
1
<?php
2
/**
3
 * Sourcing by protobuf
4
 * User: moyo
5
 * Date: 2018/6/4
6
 * Time: 10:48 AM
7
 */
8
9
namespace Carno\Validator\Sourcing;
10
11
use Carno\Validator\Chips\SVChecker;
12
use Carno\Validator\Contracts\Sourcing;
13
use Carno\Validator\Exception\IllegalNestedRuleExprException;
14
use Carno\Validator\Exception\UnknownNestedTypeException;
15
use Carno\Validator\Valid\Executor;
16
use Google\Protobuf\Internal\Message;
17
use Google\Protobuf\Internal\RepeatedField;
18
use Throwable;
19
20
class Protobuf implements Sourcing
21
{
22
    use SVChecker;
23
24
    private const WK_SCALAR = 2;
25
    private const WK_ITERATE = 4;
26
27
    /**
28
     * @param Executor $executor
29
     * @param Message $input
30
     * @throws Throwable
31
     */
32
    public function validating(Executor $executor, $input)
33
    {
34
        foreach ($executor->rules() as $field => $rule) {
35
            list($type, $data) = $this->walking($field, $input);
36
            if ($type === self::WK_SCALAR) {
37
                $this->checking($rule, $data);
38
            } elseif ($type === self::WK_ITERATE) {
39
                if (empty($data)) {
40
                    $this->checking($rule, null);
41
                } else {
42
                    foreach ($data as $getter) {
43
                        $this->checking($rule, $getter());
44
                    }
45
                }
46
            }
47
        }
48
    }
49
50
    /**
51
     * @param string $field
52
     * @param Message $input
53
     * @return array
54
     */
55
    private function walking(string $field, Message $input) : array
56
    {
57
        if (count($parts = explode('.', $field)) > 1) {
58
            // has nested field
59
            $part = array_shift($parts);
60
            $nested = $this->pbGet($input, $part);
61
            if ($nested instanceof Message) {
62
                return $this->walking(implode('.', $parts), $nested);
63
            } elseif ($nested instanceof RepeatedField) {
64
                if (array_shift($parts) !== '*') {
65
                    throw new IllegalNestedRuleExprException;
66
                }
67
                $iterates = [];
68
                foreach ($nested as $data) {
69
                    $iterates[] = function () use ($parts, $data) {
70
                        return $data instanceof Message
71
                            ? $this->walking(implode('.', $parts), $data)[1]
72
                            : $data
73
                        ;
74
                    };
75
                }
76
                return [self::WK_ITERATE, $iterates];
77
            } elseif (is_null($nested)) {
78
                // maybe nested is message and have no data present
79
                return [self::WK_SCALAR, null];
80
            } else {
81
                throw new UnknownNestedTypeException;
82
            }
83
        } else {
84
            // direct val getting
85
            return [self::WK_SCALAR, $this->pbGet($input, $field)];
86
        }
87
    }
88
89
    /**
90
     * @param Message $payload
91
     * @param string $field
92
     * @return mixed
93
     */
94
    private function pbGet(Message $payload, string $field)
95
    {
96
        return call_user_func([$payload, sprintf('get%s', ucfirst($field))]);
97
    }
98
}
99