RuleParser   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 187
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
wmc 22
lcom 1
cbo 1
dl 0
loc 187
rs 10
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A parse() 0 17 2
A parseFieldData() 0 34 5
A getTable() 0 5 1
A getPrimaryField() 0 5 1
A getPrimaryValue() 0 5 1
A getAdditionalFields() 0 5 1
A getIgnoreValue() 0 5 1
A getIgnoreColumn() 0 5 1
A getDataFields() 0 5 1
A parseIgnore() 0 14 3
A isIgnore() 0 12 2
A parseFieldName() 0 39 2
1
<?php namespace Felixkiss\UniqueWithValidator;
2
3
use Illuminate\Support\Arr;
4
5
class RuleParser
6
{
7
    protected $table;
8
    protected $primaryField;
9
    protected $primaryValue;
10
    protected $additionalFields;
11
    protected $ignoreColumn;
12
    protected $ignoreValue;
13
    protected $dataFields;
14
15
    protected $attribute;
16
    protected $parameters;
17
    protected $data;
18
19
    protected $parsed = false;
20
21
    public function __construct($attribute = null, $value = null, array $parameters = [], array $data = [])
22
    {
23
        $this->primaryField = $this->attribute = $attribute;
24
        $this->primaryValue = $value;
25
        $this->parameters = $parameters;
26
        $this->data = $data;
27
    }
28
29
    protected function parse()
30
    {
31
        if ($this->parsed) { return; }
32
        $this->parsed = true;
33
34
        // cleaning: trim whitespace
35
        $this->parameters = array_map('trim', $this->parameters);
36
37
        // first item equals table name
38
        $this->table = array_shift($this->parameters);
39
40
        // Check if ignore data is set
41
        $this->parseIgnore();
42
43
        // Parse field data
44
        $this->parseFieldData();
45
    }
46
47
    protected function parseFieldData()
48
    {
49
        $this->additionalFields = [];
50
        $this->dataFields = [$this->primaryField];
51
52
        // Figure out whether field_name is the same as column_name
53
        // or column_name is explicitly specified.
54
        //
55
        // case 1:
56
        //     $parameter = 'last_name'
57
        //     => field_name = column_name = 'last_name'
58
        // case 2:
59
        //     $parameter = 'last_name=sur_name'
60
        //     => field_name = 'last_name', column_name = 'sur_name'
61
        foreach ($this->parameters as $parameter) {
62
            $parts = array_map('trim', explode('=', $parameter, 2));
63
            $fieldName = $this->parseFieldName($parts[0]);
64
            $columnName = count($parts) > 1 ? $parts[1] : $fieldName;
65
            $this->dataFields[] = $fieldName;
66
67
            if ($fieldName === $this->primaryField) {
68
                $this->primaryField = $columnName;
69
                continue;
70
            }
71
72
            if (!Arr::has($this->data, $fieldName)) {
73
                continue;
74
            }
75
76
            $this->additionalFields[$columnName] = Arr::get($this->data, $fieldName);
77
        }
78
79
        $this->dataFields = array_values(array_unique($this->dataFields));
80
    }
81
82
    public function getTable()
83
    {
84
        $this->parse();
85
        return $this->table;
86
    }
87
88
    public function getPrimaryField()
89
    {
90
        $this->parse();
91
        return $this->primaryField;
92
    }
93
94
    public function getPrimaryValue()
95
    {
96
        $this->parse();
97
        return $this->primaryValue;
98
    }
99
100
    public function getAdditionalFields()
101
    {
102
        $this->parse();
103
        return $this->additionalFields;
104
    }
105
106
    public function getIgnoreValue()
107
    {
108
        $this->parse();
109
        return $this->ignoreValue;
110
    }
111
112
    public function getIgnoreColumn()
113
    {
114
        $this->parse();
115
        return $this->ignoreColumn;
116
    }
117
118
    public function getDataFields()
119
    {
120
        $this->parse();
121
        return $this->dataFields;
122
    }
123
124
    protected function parseIgnore()
125
    {
126
        // Ignore has to be specified as the last parameter
127
        $lastParameter = end($this->parameters);
128
        if (!$this->isIgnore($lastParameter)) { return; }
129
130
        $lastParameter = array_map('trim', explode('=', $lastParameter));
131
132
        $this->ignoreValue = str_replace('ignore:', '', $lastParameter[0]);
133
        $this->ignoreColumn = (sizeof($lastParameter) > 1) ? end($lastParameter) : null;
134
135
        // Shave of the ignore_id from the array for later processing
136
        array_pop($this->parameters);
137
    }
138
139
    protected function isIgnore($parameter)
140
    {
141
        // An ignore_id can be specified by prefixing with 'ignore:'
142
        if (strpos($parameter, 'ignore:') !== false) {
143
            return true;
144
        }
145
146
        // An ignore_id can be specified if parameter starts with a
147
        // number greater than 1 (a valid id in the database)
148
        $parts = array_map('trim', explode('=', $parameter));
149
        return preg_match('/^[1-9][0-9]*$/', $parts[0]);
150
    }
151
152
    protected function parseFieldName($field)
153
    {
154
        if (preg_match('/^\*\.|\.\*\./', $field)) {
155
            // This rule validates multiple times, because a wildcard * was used
156
            // in order to validate all elements of an array. We now need to
157
            // figure out which element we are on, so we can replace the
158
            // wildcard with the current index in the array to access the actual
159
            // data correctly.
160
161
            // 1. Convert main attribute (Laravel has already replaced the
162
            //    wildcards with the current indizes here) to have wildcards
163
            //    instead
164
            $attributeWithWildcards = preg_replace(
165
                ['/^[0-9]+\./', '/\.[0-9]+\./'],
166
                ['*.', '.*.'],
167
                $this->attribute
168
            );
169
170
            // 2. Figure out what parts of the current field string should be
171
            //    replaced (Basically everything before the last wildcard)
172
            $positionOfLastWildcard = strrpos($attributeWithWildcards, '*.');
173
            $wildcardPartToBeReplaced = substr($attributeWithWildcards, 0, $positionOfLastWildcard + 2);
174
175
            // 3. Figure out what the substitute for the replacement in the
176
            //    current field string should be (Basically delete everything
177
            //    after the final index part in the main attribute)
178
            $endPartToDismiss = substr($attributeWithWildcards, $positionOfLastWildcard + 2);
179
            $actualIndexPartToBeSubstitute = str_replace($endPartToDismiss, '', $this->attribute);
180
181
            // 4. Do the actual replacement. The end result should be a string
182
            //    of the current field we work on, but with the wildcards
183
            //    replaced by the correct indizes for the current validation run
184
            $fieldWithActualIndizes = str_replace($wildcardPartToBeReplaced, $actualIndexPartToBeSubstitute, $field);
185
186
            return $fieldWithActualIndizes;
187
        }
188
189
        return $field;
190
    }
191
}
192