RuleParser::toRule()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 33
rs 9.392
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Mtolhuys\LaravelSchematics\Services;
4
5
use Mtolhuys\LaravelSchematics\Models\Migration;
6
7
class RuleParser
8
{
9
    /**
10
     * @param $rule
11
     * @return string|null
12
     */
13
    public static function parseRule($rule = null)
14
    {
15
        if (! $rule) {
16
            return 'string|max:255';
17
        }
18
19
        $valid = array_diff(explode('|', $rule), [
20
            'mediumIncrements',
21
            'smallIncrements',
22
            'tinyIncrements',
23
            'rememberToken',
24
            'softDeletesTz',
25
            'bigIncrements',
26
            'renameColumn',
27
            'softDeletes',
28
            'dropColumn',
29
            'increments',
30
            'macAddress',
31
            'unsigned',
32
        ]);
33
34
        if (empty($valid)) {
35
            return null;
36
        }
37
38
        return self::toRule(implode('|', $valid));
39
    }
40
41
    /**
42
     * @param string $rawRules
43
     * @return string
44
     */
45
    public static function toRule(string $rawRules): string
46
    {
47
        $translations = [
48
            'unsignedInteger' => 'numeric',
49
            'mediumInteger' => 'numeric',
50
            'smallInteger' => 'numeric',
51
            'tinyInteger' => 'numeric',
52
            'bigInteger' => 'numeric',
53
            'macAddress'  => 'string',
54
            'integer' => 'numeric',
55
            'decimal' => 'numeric',
56
            'dateTimeTz' => 'date',
57
            'dateTime' => 'date',
58
            'timestampTz' => 'date',
59
            'timestamp' => 'date',
60
            'string' => 'string',
61
            'ipAddress' => 'ip',
62
            'enum' => 'numeric',
63
            'point' => 'numeric',
64
            'polygon' => 'numeric',
65
            'longText' => 'string',
66
            'text' => 'string',
67
            'json' => 'json',
68
            'jsonb' => 'json',
69
            'time' => 'date_format:H:i',
70
        ];
71
72
        return str_replace(
73
            array_keys($translations),
74
            array_values($translations),
75
            $rawRules
76
        );
77
    }
78
    /**
79
     * Parse the rules to column creation methods
80
     *
81
     * @param $fields
82
     * @return string
83
     */
84
    public static function fieldsToMigrationMethods(array $fields): string
85
    {
86
        $columns = '';
87
88
        foreach ($fields as $field) {
89
            $column = key($field);
90
            $rule = $field[$column];
91
            $break = PHP_EOL . str_repeat(' ', 12);
92
93
            if (self::isMethodOnly($rule)) {
94
                $columns .= "\$table->{$rule}();{$break}";
95
96
                continue;
97
            }
98
99
            $max = self::getMax($rule);
100
            $method = self::getMethod($rule);
101
            $oldName = self::getRenameFrom($rule);
102
            $additional = self::getAdditionalUpMethods($rule);
103
104
            $columns .= "\$table->{$method}({$oldName}'$column'{$max}){$additional}{$break}";
105
        }
106
107
        return $columns;
108
    }
109
110
    /**
111
     * @param $rule
112
     * @return string
113
     */
114
    public static function getAdditionalUpMethods($rule): string
115
    {
116
        $methods = '';
117
        $methods .= self::isUnsigned($rule) ? '->unsigned()' : '';
118
        $methods .= !self::isRequired($rule) ? '->nullable()' : '';
119
        $methods .= self::isUnique($rule) ? '->unique()' : '';
120
        $methods .= self::hasChanged($rule) ? '->change()' : '';
121
122
        return "$methods;";
123
    }
124
125
    /**
126
     * Check if $rule should be handled as single method
127
     *
128
     * @param $rule
129
     * @return mixed|string
130
     */
131
    public static function isMethodOnly($rule)
132
    {
133
134
        return self::ruleContains($rule, [
135
            'softDeletes',
136
            'rememberToken',
137
            'softDeletesTz',
138
        ]);
139
    }
140
141
    /**
142
     * Check if $rule contains any of the possible methods
143
     *
144
     * @param $rule
145
     * @return mixed|string
146
     */
147
    public static function getMethod($rule)
148
    {
149
        foreach (Migration::$methods as $method) {
150
            if (stripos($rule, strtolower($method)) !== false) {
151
                return $method;
152
            }
153
        }
154
155
        return 'string';
156
    }
157
158
    /**
159
     * Parses the max:* rule
160
     *
161
     * @param $rule
162
     * @return string
163
     */
164
    public static function getMax($rule): string
165
    {
166
        $max = (int)substr($rule, strpos($rule, 'max:') + 4);
167
168
        if ($max > 0) {
169
            return ", $max";
170
        }
171
172
        return '';
173
    }
174
175
    /**
176
     * Gets old name for renaming column
177
     *
178
     * @param $rule
179
     * @return string
180
     */
181
    public static function getRenameFrom($rule): string
182
    {
183
        foreach (explode('|', $rule) as $token) {
184
            $hasRenameRule = stripos($token, 'from:') !== false;
185
186
            if ($hasRenameRule) {
187
                $from = substr($token, strpos($token, 'from:') + 5);
188
189
                return "'$from', ";
190
            }
191
        }
192
193
        return '';
194
    }
195
196
    /**
197
     * Checks if column can be set to nullable
198
     *
199
     * @param $rule
200
     * @return boolean
201
     */
202
    public static function isRequired($rule): bool
203
    {
204
        return self::ruleContains($rule, ['required'])
205
            || self::isIncrements($rule)
206
            || self::isUnique($rule);
207
    }
208
209
    /**
210
     * Checks if columns needs to be set to unique
211
     *
212
     * @param $rule
213
     * @return boolean
214
     */
215
    public static function isIncrements($rule): bool
216
    {
217
        return self::ruleContains($rule, [
218
            'increments',
219
            'bigIncrements',
220
            'mediumIncrements',
221
            'smallIncrements',
222
            'tinyIncrements',
223
        ]);
224
    }
225
226
    /**
227
     * Checks if columns needs to be set to unique
228
     *
229
     * @param $rule
230
     * @return boolean
231
     */
232
    public static function isUnique($rule): bool
233
    {
234
        return self::ruleContains($rule, ['unique']);
235
    }
236
237
    /**
238
     * Checks if columns is unsigned
239
     *
240
     * @param $rule
241
     * @return boolean
242
     */
243
    public static function isUnsigned($rule): bool
244
    {
245
        return self::ruleContains($rule, ['unsigned'])
246
            && ! self::ruleContains($rule, ['unsignedInteger']);
247
    }
248
249
250
    /**
251
     * Checks if columns has changed
252
     *
253
     * @param $rule
254
     * @return boolean
255
     */
256
    public static function hasChanged($rule): bool
257
    {
258
        return self::ruleContains($rule, ['change']);
259
    }
260
261
    /**
262
     * Checks if columns needs to be constructed as a foreign key
263
     *
264
     * @param $rule
265
     * @return boolean
266
     */
267
    public static function isForeign($rule): bool
268
    {
269
        return self::ruleContains($rule, ['foreign']);
270
    }
271
272
    /**
273
     * For aesthetic reasons
274
     *
275
     * @param $rule
276
     * @param $needles
277
     * @return bool
278
     */
279
    private static function ruleContains($rule, array $needles): bool
280
    {
281
        return !empty(array_filter(
282
            array_map(static function ($rule) use ($needles) {
283
                return in_array($rule, $needles, true);
284
            }, explode('|', $rule))
285
        ));
286
    }
287
}
288
289