Passed
Push — master ( 2afdeb...b846a2 )
by Nikolaos
06:23 queued 03:51
created

Str::friendly()   A

Complexity

Conditions 6
Paths 7

Size

Total Lines 35
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 6

Importance

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