Passed
Push — master ( 5cf75b...52ecf5 )
by Nikolaos
04:27 queued 01:52
created

Str::dirSeparator()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1.037

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 3
cp 0.6667
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1.037
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
    final public static function concat(): string
87
    {
88
        $arguments = func_get_args();
89
90
        if (count($arguments) < 3) {
91
            throw new Exception(
92
                "concat needs at least three parameters"
93
            );
94
        }
95
96
        $delimiter = Arr::first($arguments);
97
        $arguments = Arr::sliceRight($arguments);
98
        $first     = Arr::first($arguments);
99
        $last      = Arr::last($arguments);
100
        $prefix    = "";
101
        $suffix    = "";
102
        $data      = [];
103
104
        if (self::startsWith($first, $delimiter)) {
105
            $prefix = $delimiter;
106
        }
107
108
        if (self::endsWith($last, $delimiter)) {
109
            $suffix = $delimiter;
110
        }
111
112
        foreach ($arguments as $argument) {
113
            $data[] = trim($argument, $delimiter);
114
        }
115
116
        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
    final public static function countVowels(string $text): int
128
    {
129
        preg_match_all("/[aeiou]/i", $text, $matches);
130
131
        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
    final public static function decapitalize(
146
        string $text,
147
        bool $upperRest = false,
148
        string $encoding = "UTF-8"
149
    ): string {
150
        $substr = mb_substr($text, 1);
151
        $suffix = ($upperRest) ? self::upper($substr, $encoding) : $substr;
152
153
        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
    final public static function decrement(
173
        string $text,
174
        string $separator = "_"
175
    ): string {
176
        $number = 0;
177
        $parts  = explode($separator, $text);
178
179
        if (isset($parts[1])) {
180
            $number = $parts[1];
181
            $number--;
182
            if ($number <= 0) {
183
                return $parts[0];
184
            }
185
        }
186
187
        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 26
    final public static function dirFromFile(string $file): string
199
    {
200 26
        $name  = pathinfo($file, PATHINFO_FILENAME);
201 26
        $start = substr($name, 0, -2);
202
203 26
        if (!$start) {
204 4
            $start = substr($name, 0, 1);
205
        }
206
207 26
        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 38
    final public static function dirSeparator(string $directory): string
219
    {
220 38
        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
    final public static function endsWith(
233
        string $haystack,
234
        string $needle,
235
        bool $ignoreCase = true
236
    ): bool {
237
        if ('' === $haystack) {
238
            return false;
239
        }
240
241
        return 0 === substr_compare(
242
            $haystack,
243
            $needle,
244
            -mb_strlen($needle),
245
            mb_strlen($needle),
246
            $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
    final public static function firstBetween(
261
        string $text,
262
        string $start,
263
        string $end
264
    ): string {
265
        $result = mb_strstr($text, $start);
266
        $result = (false === $result) ? '' : $result;
267
        $result = mb_strstr($result, $end, true);
268
        $result = (false === $result) ? '' : $result;
269
270
        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
    public function friendly(
285
        string $text,
286
        string $separator = "-",
287
        bool $lowercase = true,
288
        $replace = null
289
    ): string {
290
291
        if (null !== $replace) {
292
            if (!is_array($replace) && !is_string($replace)) {
293
                throw new Exception(
294
                    "Parameter replace must be an array or a string"
295
                );
296
            }
297
298
            if (is_string($replace)) {
299
                $replace = [$replace];
300
            }
301
302
            $text = str_replace($replace, " ", $text);
303
        }
304
305
        $friendly = preg_replace(
306
            "/[^a-zA-Z0-9\\/_|+ -]/",
307
            "",
308
            $text
309
        );
310
311
        if ($lowercase) {
312
            $friendly = strtolower($friendly);
313
        }
314
315
        $friendly = preg_replace("/[\\/_|+ -]+/", $separator, $friendly);
316
        $friendly = trim($friendly, $separator);
317
318
        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
    final public static function humanize(string $text): string
329
    {
330
        $result = preg_replace('#[_-]+#', ' ', trim($text));
331
332
        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
    final public static function includes(
344
        string $haystack,
345
        string $needle
346
    ): bool {
347
        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
    final public static function increment(
360
        string $text,
361
        string $separator = "_"
362
    ): string {
363
        $parts  = explode($separator, $text);
364
        $number = 1;
365
366
        if (isset($parts[1])) {
367
            $number = ((int) $parts[1]) + 1;
368
        }
369
370
        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
    final public static function isAnagram(string $first, string $second): bool
383
    {
384
        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
    final public static function isLower(
396
        string $text,
397
        string $encoding = "UTF-8"
398
    ): bool {
399
        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
    final public static function isPalindrome(string $text): bool
410
    {
411
        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
    final public static function isUpper(
423
        string $text,
424
        string $encoding = "UTF-8"
425
    ): bool {
426
        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
    final public static function len(
438
        string $text,
439
        string $encoding = "UTF-8"
440
    ): int {
441
        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
    final public static function lower(
454
        string $text,
455
        string $encoding = "UTF-8"
456
    ): string {
457
        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
    final public static function random(
470
        int $type = self::RANDOM_ALNUM,
471
        int $length = 8
472
    ): string {
473
        $text  = "";
474
        $type  = ($type < 0 || $type > 5) ? self::RANDOM_ALNUM : $type;
475
        $pools = [
476
            self::RANDOM_ALPHA    => array_merge(
477
                range('a', 'z'),
478
                range('A', 'Z')
479
            ),
480
            self::RANDOM_HEXDEC   => array_merge(
481
                range(0, 9),
482
                range('a', 'f')
483
            ),
484
            self::RANDOM_NUMERIC  => range(0, 9),
485
            self::RANDOM_NOZERO   => range(1, 9),
486
            self::RANDOM_DISTINCT => str_split('2345679ACDEFHJKLMNPRSTUVWXYZ'),
487
            self::RANDOM_ALNUM    => array_merge(
488
                range(0, 9),
489
                range('a', 'z'),
490
                range('A', 'Z')
491
            ),
492
        ];
493
494
        $end = count($pools[$type]) - 1;
495
496
        while (strlen($text) < $length) {
497
            $text .= $pools[$type][mt_rand(0, $end)];
498
        }
499
500
        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
    final public static function reduceSlashes(string $text): string
511
    {
512
        $result = preg_replace('#(?<!:)//+#', '/', $text);
513
514
        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 8
    final public static function startsWith(
527
        string $haystack,
528
        string $needle,
529
        bool $ignoreCase = true
530
    ): bool {
531 8
        if ("" === $haystack) {
532
            return false;
533
        }
534
535 8
        return 0 === substr_compare(
536 8
            $haystack,
537 8
            $needle,
538 8
            0,
539 8
            strlen($needle),
540 8
            $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
    final public static function ucwords(
553
        string $text,
554
        string $encoding = "UTF-8"
555
    ): string {
556
        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
    final public static function underscore(string $text): string
567
    {
568
        $result = preg_replace('#\s+#', '_', trim($text));
569
570
        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
    final public static function upper(
583
        string $text,
584
        string $encoding = "UTF-8"
585
    ): string {
586
        return mb_convert_case($text, MB_CASE_UPPER, $encoding);
587
    }
588
}
589