Passed
Push — master ( c94b6d...d25cd5 )
by Nikolaos
02:58
created

Str::countVowels()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1.0156

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 5
ccs 3
cts 4
cp 0.75
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1.0156
1
<?php
2
3
/**
4
 * This file is part of the Phalcon.
5
 *
6
 * (c) Phalcon Team <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Phalcon\Helper;
15
16
use function array_merge;
17
use function count_chars;
18
use function explode;
19
use function func_get_args;
20
use function implode;
21
use function is_array;
22
use function is_string;
23
use function mt_rand;
24
use function pathinfo;
25
use function preg_match_all;
26
use function preg_replace;
27
use function range;
28
use function rtrim;
29
use function str_replace;
30
use function str_split;
31
use function strlen;
32
use function strrev;
33
use function strtolower;
34
use function substr;
35
use function substr_compare;
36
use function trim;
37
38
use const DIRECTORY_SEPARATOR;
39
use const MB_CASE_TITLE;
40
use const MB_CASE_UPPER;
41
use const PATHINFO_FILENAME;
42
43
/**
44
 * This class offers quick string functions throughout the framework
45
 */
46
class Str
47
{
48
    // Only alpha numeric characters [a-zA-Z0-9]
49
    public const RANDOM_ALNUM = 0;
50
    // Only alphabetical characters [azAZ]
51
    public const RANDOM_ALPHA = 1;
52
    // Only alpha numeric uppercase characters exclude similar
53
    // characters [2345679ACDEFHJKLMNPRSTUVWXYZ]
54
    public const RANDOM_DISTINCT = 5;
55
    // Only hexadecimal characters [0-9a-f]
56
    public const RANDOM_HEXDEC = 2;
57
    // Only numbers without 0 [1-9]
58
    public const RANDOM_NOZERO = 4;
59
    // Only numbers [0-9]
60
    public const RANDOM_NUMERIC = 3;
61
62
    /**
63
     * Concatenates strings using the separator only once without duplication in
64
     * places concatenation
65
     *
66
     * ```php
67
     * $str = Phalcon\Helper\Str::concat(
68
     *     "/",
69
     *     "/tmp/",
70
     *     "/folder_1/",
71
     *     "/folder_2",
72
     *     "folder_3/"
73
     * );
74
     *
75
     * echo $str;   // /tmp/folder_1/folder_2/folder_3/
76
     * ```
77
     *
78
     * @param string separator
79
     * @param string a
80
     * @param string b
81
     * @param string ...N
82
     *
83
     * @return string
84
     * @throws Exception
85
     */
86 4
    final public static function concat(): string
87
    {
88 4
        $arguments = func_get_args();
89
90 4
        if (count($arguments) < 3) {
91 2
            throw new Exception(
92 2
                "concat needs at least three parameters"
93
            );
94
        }
95
96 2
        $delimiter = Arr::first($arguments);
97 2
        $arguments = Arr::sliceRight($arguments);
98 2
        $first     = Arr::first($arguments);
99 2
        $last      = Arr::last($arguments);
100 2
        $prefix    = "";
101 2
        $suffix    = "";
102 2
        $data      = [];
103
104 2
        if (self::startsWith($first, $delimiter)) {
105 2
            $prefix = $delimiter;
106
        }
107
108 2
        if (self::endsWith($last, $delimiter)) {
109 2
            $suffix = $delimiter;
110
        }
111
112 2
        foreach ($arguments as $argument) {
113 2
            $data[] = trim($argument, $delimiter);
114
        }
115
116 2
        return $prefix . implode($delimiter, $data) . $suffix;
117
    }
118
119
    /**
120
     * Returns number of vowels in provided string. Uses a regular expression
121
     * to count the number of vowels (A, E, I, O, U) in a string.
122
     *
123
     * @param string $text
124
     *
125
     * @return int
126
     */
127 2
    final public static function countVowels(string $text): int
128
    {
129 2
        preg_match_all("/[aeiou]/i", $text, $matches);
130
131 2
        return count($matches[0]);
132
    }
133
134
    /**
135
     * Decapitalizes the first letter of the string and then adds it with rest
136
     * of the string. Omit the upperRest parameter to keep the rest of the
137
     * string intact, or set it to true to convert to uppercase.
138
     *
139
     * @param string $text
140
     * @param bool   $upperRest
141
     * @param string $encoding
142
     *
143
     * @return string
144
     */
145 2
    final public static function decapitalize(
146
        string $text,
147
        bool $upperRest = false,
148
        string $encoding = "UTF-8"
149
    ): string {
150 2
        $substr = mb_substr($text, 1);
151
152 2
        if ($upperRest) {
153 2
            $suffix = mb_strtoupper($substr, $encoding);
154
        } else {
155 2
            $suffix = $substr;
156
        }
157
158 2
        return mb_strtolower(mb_substr($text, 0, 1), $encoding) . $suffix;
159
    }
160
161
    /**
162
     * Removes a number from a string or decrements that number if it is already
163
     * defined
164
     *
165
     * ```php
166
     * use Phalcon\Helper\Str;
167
     *
168
     * echo Str::decrement("a_1");    // "a"
169
     * echo Str::decrement("a_2");  // "a_1"
170
     * ```
171
     *
172
     * @param string $text
173
     * @param string $separator
174
     *
175
     * @return string
176
     */
177 2
    final public static function decrement(
178
        string $text,
179
        string $separator = "_"
180
    ): string {
181 2
        $number = 0;
182 2
        $parts  = explode($separator, $text);
183
184 2
        if (isset($parts[1])) {
185 2
            $number = $parts[1];
186 2
            $number--;
187 2
            if ($number <= 0) {
188 2
                return $parts[0];
189
            }
190
        }
191
192 2
        return $parts[0] . $separator . $number;
193
    }
194
195
    /**
196
     * Accepts a file name (without extension) and returns a calculated
197
     * directory structure with the filename in the end
198
     *
199
     * @param string $file
200
     *
201
     * @return string
202
     */
203 30
    final public static function dirFromFile(string $file): string
204
    {
205 30
        $name  = pathinfo($file, PATHINFO_FILENAME);
206 30
        $start = substr($name, 0, -2);
207
208 30
        if (!$start) {
209 6
            $start = substr($name, 0, 1);
210
        }
211
212 30
        return implode('/', str_split($start, 2)) . '/';
213
    }
214
215
    /**
216
     * Accepts a directory name and ensures that it ends with
217
     * DIRECTORY_SEPARATOR
218
     *
219
     * @param string $directory
220
     *
221
     * @return string
222
     */
223 42
    final public static function dirSeparator(string $directory): string
224
    {
225 42
        return rtrim($directory, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
226
    }
227
228
    /**
229
     * Check if a string ends with a given string
230
     *
231
     * @param string $haystack
232
     * @param string $needle
233
     * @param bool   $ignoreCase
234
     *
235
     * @return bool
236
     */
237 12
    final public static function endsWith(
238
        string $haystack,
239
        string $needle,
240
        bool $ignoreCase = true
241
    ): bool {
242 12
        if ('' === $haystack) {
243 4
            return false;
244
        }
245
246 8
        return 0 === substr_compare(
247 8
            $haystack,
248 8
            $needle,
249 8
            -strlen($needle),
250 8
            strlen($needle),
251 8
            $ignoreCase
252
        );
253
    }
254
255
    /**
256
     * Returns the first string there is between the strings from the
257
     * parameter start and end.
258
     *
259
     * @param string $text
260
     * @param string $start
261
     * @param string $end
262
     *
263
     * @return string
264
     */
265 2
    final public static function firstBetween(
266
        string $text,
267
        string $start,
268
        string $end
269
    ): string {
270 2
        $result = mb_strstr($text, $start);
271 2
        $result = (false === $result) ? '' : $result;
272 2
        $result = mb_strstr($result, $end, true);
273 2
        $result = (false === $result) ? '' : $result;
274
275 2
        return trim($result, $start . $end);
276
    }
277
278
    /**
279
     * Changes a text to a URL friendly one
280
     *
281
     * @param string     $text
282
     * @param string     $separator
283
     * @param bool       $lowercase
284
     * @param mixed|null $replace
285
     *
286
     * @return string
287
     * @throws Exception
288
     */
289 4
    public function friendly(
290
        string $text,
291
        string $separator = "-",
292
        bool $lowercase = true,
293
        $replace = null
294
    ): string {
295
296 4
        if (null !== $replace) {
297 4
            if (!is_array($replace) && !is_string($replace)) {
298 2
                throw new Exception(
299 2
                    "Parameter replace must be an array or a string"
300
                );
301
            }
302
303 2
            if (is_string($replace)) {
304 2
                $replace = [$replace];
305
            }
306
307 2
            $text = str_replace($replace, " ", $text);
308
        }
309
310 2
        $friendly = preg_replace(
311 2
            "/[^a-zA-Z0-9\\/_|+ -]/",
312 2
            "",
313 2
            $text
314
        );
315
316 2
        if ($lowercase) {
317 2
            $friendly = strtolower($friendly);
318
        }
319
320 2
        $friendly = preg_replace("/[\\/_|+ -]+/", $separator, $friendly);
321 2
        $friendly = trim($friendly, $separator);
322
323 2
        return $friendly;
324
    }
325
326
    /**
327
     * Makes an underscored or dashed phrase human-readable
328
     *
329
     * @param string $text
330
     *
331
     * @return string
332
     */
333 2
    final public static function humanize(string $text): string
334
    {
335 2
        $result = preg_replace('#[_-]+#', ' ', trim($text));
336
337 2
        return (null === $result) ? '' : $result;
338
    }
339
340
    /**
341
     * Lets you determine whether or not a string includes another string.
342
     *
343
     * @param string $haystack
344
     * @param string $needle
345
     *
346
     * @return bool
347
     */
348 48
    final public static function includes(
349
        string $haystack,
350
        string $needle
351
    ): bool {
352 48
        return false !== mb_strpos($haystack, $needle);
353
    }
354
355
    /**
356
     * Adds a number to a string or increment that number if it already is
357
     * defined
358
     *
359
     * @param string $text
360
     * @param string $separator
361
     *
362
     * @return string
363
     */
364 2
    final public static function increment(
365
        string $text,
366
        string $separator = "_"
367
    ): string {
368 2
        $parts  = explode($separator, $text);
369 2
        $number = 1;
370
371 2
        if (isset($parts[1])) {
372 2
            $number = ((int) $parts[1]) + 1;
373
        }
374
375 2
        return $parts[0] . $separator . $number;
376
    }
377
378
    /**
379
     * Compare two strings and returns true if both strings are anagram,
380
     * false otherwise.
381
     *
382
     * @param string $first
383
     * @param string $second
384
     *
385
     * @return bool
386
     */
387 2
    final public static function isAnagram(string $first, string $second): bool
388
    {
389 2
        return count_chars($first, 1) === count_chars($second, 1);
390
    }
391
392
    /**
393
     * Returns true if the given string is lower case, false otherwise.
394
     *
395
     * @param string $text
396
     * @param string $encoding
397
     *
398
     * @return bool
399
     */
400 2
    final public static function isLower(
401
        string $text,
402
        string $encoding = "UTF-8"
403
    ): bool {
404 2
        return $text === self::lower($text, $encoding);
405
    }
406
407
    /**
408
     * Returns true if the given string is a palindrome, false otherwise.
409
     *
410
     * @param string $text
411
     *
412
     * @return bool
413
     */
414 2
    final public static function isPalindrome(string $text): bool
415
    {
416 2
        return strrev($text) === $text;
417
    }
418
419
    /**
420
     * Returns true if the given string is upper case, false otherwise.
421
     *
422
     * @param string $text
423
     * @param string $encoding
424
     *
425
     * @return bool
426
     */
427 2
    final public static function isUpper(
428
        string $text,
429
        string $encoding = "UTF-8"
430
    ): bool {
431 2
        return $text === self::upper($text, $encoding);
432
    }
433
434
    /**
435
     * Calculates the length of the string. Uses mbstring if present
436
     *
437
     * @param string $text
438
     * @param string $encoding
439
     *
440
     * @return int
441
     */
442 8
    final public static function len(
443
        string $text,
444
        string $encoding = "UTF-8"
445
    ): int {
446 8
        return mb_strlen($text, $encoding);
447
    }
448
449
    /**
450
     * Lowercases a string, this function makes use of the mbstring extension if
451
     * available
452
     *
453
     * @param string $text
454
     * @param string $encoding
455
     *
456
     * @return string
457
     */
458 10
    final public static function lower(
459
        string $text,
460
        string $encoding = "UTF-8"
461
    ): string {
462 10
        return mb_convert_case($text, MB_CASE_LOWER, $encoding);
463
    }
464
465
    /**
466
     * Generates a random string based on the given type. Type is one of the
467
     * RANDOM_* constants
468
     *
469
     * @param int $type
470
     * @param int $length
471
     *
472
     * @return string
473
     */
474 12
    final public static function random(
475
        int $type = self::RANDOM_ALNUM,
476
        int $length = 8
477
    ): string {
478 12
        $text  = "";
479 12
        $type  = ($type < 0 || $type > 5) ? self::RANDOM_ALNUM : $type;
480
        $pools = [
481 12
            self::RANDOM_ALPHA    => array_merge(
482 12
                range('a', 'z'),
483 12
                range('A', 'Z')
484
            ),
485 12
            self::RANDOM_HEXDEC   => array_merge(
486 12
                range(0, 9),
487 12
                range('a', 'f')
488
            ),
489 12
            self::RANDOM_NUMERIC  => range(0, 9),
490 12
            self::RANDOM_NOZERO   => range(1, 9),
491 12
            self::RANDOM_DISTINCT => str_split('2345679ACDEFHJKLMNPRSTUVWXYZ'),
492 12
            self::RANDOM_ALNUM    => array_merge(
493 12
                range(0, 9),
494 12
                range('a', 'z'),
495 12
                range('A', 'Z')
496
            ),
497
        ];
498
499 12
        $end = count($pools[$type]) - 1;
500
501 12
        while (strlen($text) < $length) {
502 12
            $text .= $pools[$type][mt_rand(0, $end)];
503
        }
504
505 12
        return $text;
506
    }
507
508
    /**
509
     * Reduces multiple slashes in a string to single slashes
510
     *
511
     * @param string $text
512
     *
513
     * @return string
514
     */
515 2
    final public static function reduceSlashes(string $text): string
516
    {
517 2
        $result = preg_replace('#(?<!:)//+#', '/', $text);
518
519 2
        return (null === $result) ? '' : $result;
520
    }
521
522
    /**
523
     * Check if a string starts with a given string
524
     *
525
     * @param string $haystack
526
     * @param string $needle
527
     * @param bool   $ignoreCase
528
     *
529
     * @return bool
530
     */
531 130
    final public static function startsWith(
532
        string $haystack,
533
        string $needle,
534
        bool $ignoreCase = true
535
    ): bool {
536 130
        if ('' === $haystack) {
537 4
            return false;
538
        }
539
540 126
        return 0 === substr_compare(
541 126
            $haystack,
542 126
            $needle,
543 126
            0,
544 126
            strlen($needle),
545 126
            $ignoreCase
546
        );
547
    }
548
549
    /**
550
     * Makes a phrase underscored instead of spaced
551
     *
552
     * @param string $text
553
     * @param string $encoding
554
     *
555
     * @return string
556
     */
557 2
    final public static function ucwords(
558
        string $text,
559
        string $encoding = "UTF-8"
560
    ): string {
561 2
        return mb_convert_case($text, MB_CASE_TITLE, $encoding);
562
    }
563
564
    /**
565
     * Makes a phrase underscored instead of spaced
566
     *
567
     * @param string $text
568
     *
569
     * @return string
570
     */
571 2
    final public static function underscore(string $text): string
572
    {
573 2
        $result = preg_replace('#\s+#', '_', trim($text));
574
575 2
        return (null === $result) ? '' : $result;
576
    }
577
578
    /**
579
     * Uppercases a string, this function makes use of the mbstring extension if
580
     * available
581
     *
582
     * @param string $text
583
     * @param string $encoding
584
     *
585
     * @return string
586
     */
587 10
    final public static function upper(
588
        string $text,
589
        string $encoding = "UTF-8"
590
    ): string {
591 10
        return mb_convert_case($text, MB_CASE_UPPER, $encoding);
592
    }
593
}
594