Passed
Push — master ( 454cf7...0d52c3 )
by Kacper
02:57
created

Validator::_matches()   C

Complexity

Conditions 8
Paths 8

Size

Total Lines 23
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 8

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 23
rs 6.1403
ccs 16
cts 16
cp 1
cc 8
eloc 15
nc 8
nop 3
crap 8
1
<?php
2
/**
3
 * Highlighter
4
 *
5
 * Copyright (C) 2016, Some right reserved.
6
 *
7
 * @author Kacper "Kadet" Donat <[email protected]>
8
 *
9
 * Contact with author:
10
 * Xmpp: [email protected]
11
 * E-mail: [email protected]
12
 *
13
 * From Kadet with love.
14
 */
15
16
namespace Kadet\Highlighter\Parser\Validator;
17
18
19
class Validator
20
{
21
    const CONTEXT_NOT_IN    = 2;
22
    const CONTEXT_IN        = 1;
23
    const CONTEXT_IN_ONE_OF = 4;
24
    const CONTEXT_EXACTLY   = 8;
25
    const CONTEXT_ON_TOP    = 16;
26
    const CONTEXT_REGEX     = 32;
27
28
    private $_rules = [];
29
30
    /**
31
     * Validator constructor.
32
     *
33
     * @param array $rules
34
     */
35 59
    public function __construct(array $rules = []) {
36 59
        $this->setRules($rules);
37 59
    }
38
39 26
    public function validate(array $context, $additional = []) {
40 26
        return $this->_validate($context, $additional + $this->_rules);
41
    }
42
43 59
    public function setRules($rules)
44
    {
45 59
        if(empty($rules)) {
46 51
            $this->_rules = [ 'none' => Validator::CONTEXT_IN_ONE_OF ];
47 51
        } else {
48 10
            foreach ($rules as $key => $rule) {
49 10
                list($plain, $type)     = $this->_parse($rule);
50 10
                $this->_rules[$plain] = $type;
51 10
            }
52
        }
53 59
    }
54
55 19
    private function _clean($rule, $type, &$required)
0 ignored issues
show
Unused Code introduced by
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
56
    {
57 19
        if (strpos($rule, '.') !== false) {
58
            foreach (array_filter(array_keys($required), function ($key) use ($rule) {
59 2
                return fnmatch($key . '.*', $rule);
60 2
            }) as $remove) {
61 1
                unset($required[$remove]);
62 2
            }
63 2
        }
64 19
    }
65
66 26
    protected function _validate($context, $rules) {
67 26
        if(empty($rules)) {
68 14
            return true;
69
        }
70
71 22
        if(empty($context)) {
72 16
            $context = ['none'];
73 16
        }
74
75 22
        $result = false; // At least one rule must match
76 22
        while(list($rule, $type) = each($rules)) {
77 22
            $matched = $this->_matches($context, $rule, $type);
78
79 22
            if ($type & Validator::CONTEXT_NOT_IN) {
80 3
                if ($matched) {
81 3
                    return false;
82
                }
83 2
                $result = true;
84 22
            } elseif ($type & Validator::CONTEXT_IN) {
85 7
                if (!$matched) {
86 4
                    return false;
87
                }
88 7
                $result = true;
89
90 7
                $this->_clean($rule, $type, $rules);
91 20
            } elseif ($type & Validator::CONTEXT_IN_ONE_OF) {
92 15
                if ($matched) {
93 14
                    $result = true;
94 14
                    $this->_clean($rule, $type, $rules);
95 14
                }
96 15
            }
97 22
        }
98
99 21
        return $result;
100
    }
101
102 10
    private function _parse($rule)
103
    {
104
        $types = [
105 10
            '!' => Validator::CONTEXT_NOT_IN,
106 10
            '+' => Validator::CONTEXT_IN,
107 10
            '*' => Validator::CONTEXT_IN_ONE_OF,
108 10
            '@' => Validator::CONTEXT_EXACTLY,
109
//            '^' => Validator::CONTEXT_ON_TOP,
110
            '~' => Validator::CONTEXT_REGEX
111 10
        ];
112
113 10
        if (!isset($types[$rule[0]])) {
114 3
            return [$rule, Validator::CONTEXT_IN];
115
        }
116
117 8
        $type = 0;
118 8
        $pos  = 0;
119 8
        foreach (str_split($rule) as $pos => $char) {
120 8
            if (!isset($types[$char])) {
121 7
                break;
122
            }
123
124 8
            $type |= $types[$char];
125 8
        }
126
127 8
        $rule = substr($rule, $pos);
128
129 8
        if($type & self::CONTEXT_REGEX) {
130 2
            $rule = "/^$rule(\\.\\w+)?/i";
131 2
        }
132
133 8
        return [$rule, $type];
134
    }
135
136 22
    private function _matches($context, $rule, $type) {
137 22
        if($type & self::CONTEXT_EXACTLY) {
138 1
            return in_array($rule, $context, true);
139 21
        } elseif($type & self::CONTEXT_REGEX) {
140 2
            foreach($context as $item) {
141 2
                if(preg_match($rule, $item)) {
142 2
                    return true;
143
                }
144 2
            }
145 2
            return false;
146
        } else {
147 19
            if(in_array($rule, $context, true)) {
148 18
                return true;
149
            }
150
151 9
            foreach($context as $item) {
152 9
                if(fnmatch("$rule.*", $item)) {
153 1
                    return true;
154
                }
155 9
            }
156 9
            return false;
157
        }
158
    }
159
160 17
    public static function everywhere()
161
    {
162 17
        static $validator;
163 17
        if (!$validator) {
164 12
            $validator = new DelegateValidator(function () {
165 12
                return true;
166 1
            });
167 1
        }
168
169 17
        return $validator;
170
    }
171
}