Passed
Push — main ( c2190a...e8aeda )
by Dimitri
09:14 queued 01:02
created

singular()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 47
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 4.074

Importance

Changes 0
Metric Value
cc 4
eloc 37
nc 4
nop 1
dl 0
loc 47
ccs 5
cts 6
cp 0.8333
crap 4.074
rs 9.328
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * This file is part of Blitz PHP framework.
5
 *
6
 * (c) 2022 Dimitri Sitchet Tomkeu <[email protected]>
7
 *
8
 * For the full copyright and license information, please view
9
 * the LICENSE file that was distributed with this source code.
10
 */
11
12
use BlitzPHP\Utilities\String\Inflector;
13
use BlitzPHP\Utilities\String\Text;
14
15
if (! function_exists('camelize')) {
16
    /**
17
     * Camelize
18
     *
19
     * Takes multiple words separated by spaces or underscores and camelizes them
20
     *
21
     * @param string $str Input string
22
     */
23
    function camelize(string $str): string
24
    {
25
        return Inflector::camelize($str);
26
    }
27
}
28
29
if (! function_exists('classify')) {
30
    /**
31
     * Returns model class name ("Person" for the database table "people".) for given database table.
32
     *
33
     * @param string $tableName Name of database table to get class name for
34
     *
35
     * @return string Class name
36
     */
37
    function classify(string $tableName): string
38
    {
39
        return Inflector::classify($tableName);
40
    }
41
}
42
43
if (! function_exists('dasherize')) {
44
    /**
45
     * Returns the input CamelCasedString as an dashed-string.
46
     *
47
     * Also replaces underscores with dashes
48
     *
49
     * @param string $string The string to dasherize.
50
     *
51
     * @return string Dashed version of the input string
52
     */
53
    function dasherize(string $string): string
54
    {
55
        return Inflector::dasherize($string);
56
    }
57
}
58
59
if (! function_exists('delimit')) {
60
    /**
61
     * Expects a CamelCasedInputString, and produces a lower_case_delimited_string
62
     *
63
     * @param string $string    String to delimit
64
     * @param string $delimiter the character to use as a delimiter
65
     *
66
     * @return string delimited string
67
     */
68
    function delimit(string $string, string $delimiter = '_'): string
69
    {
70
        return Inflector::delimit($string, $delimiter);
71
    }
72
}
73
74
if (! function_exists('humanize')) {
75
    /**
76
     * Humanize
77
     *
78
     * Takes multiple words separated by the separator and changes them to spaces
79
     *
80
     * @param string $str       Input string
81
     * @param string $separator Input separator
82
     */
83
    function humanize(string $str, string $separator = '_'): string
84
    {
85
        return Inflector::humanize($str, $separator);
86
    }
87
}
88
89
if (! function_exists('plural')) {
90
    /**
91
     * Plural
92
     *
93
     * Takes a singular word and makes it plural
94
     */
95
    function plural(string $string): string
96
    {
97
        $result = $string;
98
99
        if (! is_pluralizable($result)) {
100
            return $result;
101
        }
102
103
        $plural_rules = [
104
            '/(quiz)$/'               => '\1zes',      // quizzes
105
            '/^(ox)$/'                => '\1\2en',     // ox
106
            '/([m|l])ouse$/'          => '\1ice',      // mouse, louse
107
            '/(matr|vert|ind)ix|ex$/' => '\1ices',     // matrix, vertex, index
108
            '/(x|ch|ss|sh)$/'         => '\1es',       // search, switch, fix, box, process, address
109
            '/([^aeiouy]|qu)y$/'      => '\1ies',      // query, ability, agency
110
            '/(hive)$/'               => '\1s',        // archive, hive
111
            '/(?:([^f])fe|([lr])f)$/' => '\1\2ves',    // half, safe, wife
112
            '/sis$/'                  => 'ses',        // basis, diagnosis
113
            '/([ti])um$/'             => '\1a',        // datum, medium
114
            '/(p)erson$/'             => '\1eople',    // person, salesperson
115
            '/(m)an$/'                => '\1en',       // man, woman, spokesman
116
            '/(c)hild$/'              => '\1hildren',  // child
117
            '/(buffal|tomat)o$/'      => '\1\2oes',    // buffalo, tomato
118
            '/(bu|campu)s$/'          => '\1\2ses',    // bus, campus
119
            '/(alias|status|virus)$/' => '\1es',       // alias
120
            '/(octop)us$/'            => '\1i',        // octopus
121
            '/(ax|cris|test)is$/'     => '\1es',       // axis, crisis
122
            '/s$/'                    => 's',          // no change (compatibility)
123
            '/$/'                     => 's',
124
        ];
125
126
        foreach ($plural_rules as $rule => $replacement) {
127
            if (preg_match($rule, $result)) {
128
                $result = preg_replace($rule, $replacement, $result);
129
                break;
130
            }
131
        }
132
133
        return $result;
134
    }
135
}
136
137
if (! function_exists('pluralize')) {
138
    /**
139
     * Return $word in plural form.
140
     *
141
     * @param string $word Word in singular
142
     *
143
     * @return string Word in plural
144
     */
145
    function pluralize(string $word): string
146
    {
147
        return Inflector::pluralize($word);
148
    }
149
}
150
151
if (! function_exists('singular')) {
152
    /**
153
     * Singular
154
     *
155
     * Takes a plural word and makes it singular
156
     */
157
    function singular(string $string): string
158
    {
159 10
        $result = $string;
160
161
        if (! is_pluralizable($result)) {
162
            return $result;
163
        }
164
165
        $singular_rules = [
166
            '/(matr)ices$/'                                                   => '\1ix',
167
            '/(vert|ind)ices$/'                                               => '\1ex',
168
            '/^(ox)en/'                                                       => '\1',
169
            '/(alias)es$/'                                                    => '\1',
170
            '/([octop|vir])i$/'                                               => '\1us',
171
            '/(cris|ax|test)es$/'                                             => '\1is',
172
            '/(shoe)s$/'                                                      => '\1',
173
            '/(o)es$/'                                                        => '\1',
174
            '/(bus|campus)es$/'                                               => '\1',
175
            '/([m|l])ice$/'                                                   => '\1ouse',
176
            '/(x|ch|ss|sh)es$/'                                               => '\1',
177
            '/(m)ovies$/'                                                     => '\1\2ovie',
178
            '/(s)eries$/'                                                     => '\1\2eries',
179
            '/([^aeiouy]|qu)ies$/'                                            => '\1y',
180
            '/([lr])ves$/'                                                    => '\1f',
181
            '/(tive)s$/'                                                      => '\1',
182
            '/(hive)s$/'                                                      => '\1',
183
            '/([^f])ves$/'                                                    => '\1fe',
184
            '/(^analy)ses$/'                                                  => '\1sis',
185
            '/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/' => '\1\2sis',
186
            '/([ti])a$/'                                                      => '\1um',
187
            '/(p)eople$/'                                                     => '\1\2erson',
188
            '/(m)en$/'                                                        => '\1an',
189
            '/(s)tatuses$/'                                                   => '\1\2tatus',
190
            '/(c)hildren$/'                                                   => '\1\2hild',
191
            '/(n)ews$/'                                                       => '\1\2ews',
192
            '/(quiz)zes$/'                                                    => '\1',
193
            '/([^us])s$/'                                                     => '\1',
194 10
        ];
195
196
        foreach ($singular_rules as $rule => $replacement) {
197
            if (preg_match($rule, $result)) {
198 2
                $result = preg_replace($rule, $replacement, $result);
199 2
                break;
200
            }
201
        }
202
203 10
        return $result;
204
    }
205
}
206
207
if (! function_exists('singularize')) {
208
    /**
209
     * Return $word in singular form.
210
     *
211
     * @param string $word Word in plural
212
     *
213
     * @return string Word in singular
214
     */
215
    function singularize(string $word): string
216
    {
217
        return Inflector::singularize($word);
218
    }
219
}
220
221
if (! function_exists('tableize')) {
222
    /**
223
     * Returns corresponding table name for given model $className. ("people" for the model class "Person").
224
     *
225
     * @param string $className Name of class to get database table name for
226
     *
227
     * @return string Name of the database table for given class
228
     */
229
    function tableize(string $className): string
230
    {
231
        return Inflector::tableize($className);
232
    }
233
}
234
235
if (! function_exists('underscore')) {
236
    /**
237
     * Underscore
238
     *
239
     * Takes multiple words separated by spaces and underscores them
240
     *
241
     * @param string $str Input string
242
     */
243
    function underscore(string $str): string
244
    {
245
        return Inflector::underscore($str);
246
    }
247
}
248
249
if (! function_exists('variable')) {
250
    /**
251
     * Returns camelBacked version of an underscored string.
252
     *
253
     * @param string $string String to convert.
254
     *
255
     * @return string in variable form
256
     */
257
    function variable(string $string): string
258
    {
259
        return Inflector::variable($string);
260
    }
261
}
262
263
if (! function_exists('counted')) {
264
    /**
265
     * Counted
266
     *
267
     * Takes a number and a word to return the plural or not
268
     * E.g. 0 cats, 1 cat, 2 cats, ...
269
     *
270
     * @param int    $count  Number of items
271
     * @param string $string Input string
272
     */
273
    function counted(int $count, string $string): string
274
    {
275
        $result = "{$count} ";
276
277
        return $result . ($count === 1 ? singular($string) : plural($string));
278
    }
279
}
280
281
if (! function_exists('pascalize')) {
282
    /**
283
     * Pascalize
284
     *
285
     * Takes multiple words separated by spaces or
286
     * underscores and converts them to Pascal case,
287
     * which is camel case with an uppercase first letter.
288
     *
289
     * @param string $string Input string
290
     */
291
    function pascalize(string $string): string
292
    {
293 6
        return Text::convertTo($string, 'pascalcase');
294
    }
295
}
296
297
if (! function_exists('is_pluralizable')) {
298
    /**
299
     * Checks if the given word has a plural version.
300
     *
301
     * @param string $word Word to check
302
     */
303
    function is_pluralizable(string $word): bool
304
    {
305
        return ! in_array(
306
            strtolower($word),
307
            [
308
                'advice',
309
                'audio',
310
                'bison',
311
                'bravery',
312
                'butter',
313
                'chaos',
314
                'chassis',
315
                'clarity',
316
                'coal',
317
                'compensation',
318
                'coreopsis',
319
                'courage',
320
                'cowardice',
321
                'curiosity',
322
                'data',
323
                'deer',
324
                'education',
325
                'emoji',
326
                'equipment',
327
                'evidence',
328
                'fish',
329
                'fun',
330
                'furniture',
331
                'gold',
332
                'greed',
333
                'help',
334
                'homework',
335
                'honesty',
336
                'information',
337
                'insurance',
338
                'jewelry',
339
                'knowledge',
340
                'livestock',
341
                'love',
342
                'luck',
343
                'marketing',
344
                'meta',
345
                'money',
346
                'moose',
347
                'mud',
348
                'news',
349
                'nutrition',
350
                'offspring',
351
                'patriotism',
352
                'plankton',
353
                'pokemon',
354
                'police',
355
                'racism',
356
                'rain',
357
                'rice',
358
                'satisfaction',
359
                'scenery',
360
                'series',
361
                'sexism',
362
                'sheep',
363
                'silence',
364
                'species',
365
                'spelling',
366
                'sugar',
367
                'swine',
368
                'traffic',
369
                'water',
370
                'weather',
371
                'wheat',
372
                'wisdom',
373
                'work',
374
            ],
375
            true
376 10
        );
377
    }
378
}
379
380
if (! function_exists('ordinal')) {
381
    /**
382
     * Returns the suffix that should be added to a
383
     * number to denote the position in an ordered
384
     * sequence such as 1st, 2nd, 3rd, 4th.
385
     *
386
     * @param int $integer The integer to determine the suffix
387
     */
388
    function ordinal(int $integer): string
389
    {
390
        $suffixes = [
391
            'th',
392
            'st',
393
            'nd',
394
            'rd',
395
            'th',
396
            'th',
397
            'th',
398
            'th',
399
            'th',
400
            'th',
401
        ];
402
403
        return $integer % 100 >= 11 && $integer % 100 <= 13 ? 'th' : $suffixes[$integer % 10];
404
    }
405
}
406
407
if (! function_exists('ordinalize')) {
408
    /**
409
     * Turns a number into an ordinal string used
410
     * to denote the position in an ordered sequence
411
     * such as 1st, 2nd, 3rd, 4th.
412
     *
413
     * @param int $integer The integer to ordinalize
414
     */
415
    function ordinalize(int $integer): string
416
    {
417
        return $integer . ordinal($integer);
418
    }
419
}
420