Passed
Push — master ( 52ecf5...abf332 )
by Nikolaos
02:34
created

Str::startsWith()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2.1821

Importance

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