Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
147 / 147
100.00% covered (success)
100.00%
10 / 10
CRAP
100.00% covered (success)
100.00%
1 / 1
Str
100.00% covered (success)
100.00%
147 / 147
100.00% covered (success)
100.00%
10 / 10
64
100.00% covered (success)
100.00%
1 / 1
 createSlug
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 createLinks
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
4
 createRandom
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
4
 createRandomAlphaNum
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
4
 createRandomAlpha
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
4
 createRandomNumeric
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 generateRandomString
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 __callStatic
100.00% covered (success)
100.00%
80 / 80
100.00% covered (success)
100.00%
1 / 1
36
 convertFromCamelCase
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
5
 convertToCamelCase
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2/**
3 * Pop PHP Framework (http://www.popphp.org/)
4 *
5 * @link       https://github.com/popphp/popphp-framework
6 * @author     Nick Sagona, III <dev@nolainteractive.com>
7 * @copyright  Copyright (c) 2009-2023 NOLA Interactive, LLC. (http://www.nolainteractive.com)
8 * @license    http://www.popphp.org/license     New BSD License
9 */
10
11/**
12 * @namespace
13 */
14namespace Pop\Utils;
15
16/**
17 * Pop utils string helper class
18 *
19 * @category   Pop
20 * @package    Pop\Utils
21 * @author     Nick Sagona, III <dev@nolainteractive.com>
22 * @copyright  Copyright (c) 2009-2023 NOLA Interactive, LLC. (http://www.nolainteractive.com)
23 * @license    http://www.popphp.org/license     New BSD License
24 * @version    1.3.0
25 */
26class Str
27{
28
29    /**
30     * Constants case type for random string generation
31     */
32    const MIXEDCASE = 0;
33    const LOWERCASE = 1;
34    const UPPERCASE = 2;
35
36    /**
37     * Characters for random string generation (certain characters omitted to eliminate confusion)
38     * @var array
39     */
40    protected static $randomChars = [
41        'abcdefghjkmnpqrstuvwxyz',
42        'ABCDEFGHJKLMNPQRSTUVWXYZ',
43        '0123456789',
44        '!?#$%&@-_+*=,.:;()[]{}',
45    ];
46
47    /**
48     * Regex patterns & replacements for links
49     * @var array
50     */
51    protected static $linksRegex = [
52        [
53            'pattern'     => '/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/m',
54            'replacement' => '<a href="$0">$0</a>'
55        ],
56        [
57            'pattern'     => '/[a-zA-Z0-9\.\-\_+%]+@[a-zA-Z0-9\-\_\.]+\.[a-zA-Z]{2,4}/m',
58            'replacement' => '<a href="mailto:$0">$0</a>'
59        ]
60    ];
61
62    /**
63     * Allowed keywords for converting cases
64     * @var array
65     */
66    protected static $allowedCases = [
67        'titlecase', 'camelcase', 'kebabcase', 'dash', 'snakecase', 'underscore', 'namespace', 'path', 'url', 'uri'
68    ];
69
70    /**
71     * Convert the string into an SEO-friendly slug.
72     *
73     * @param  string $string
74     * @param  string $separator
75     * @return string
76     */
77    public static function createSlug($string, $separator = '-')
78    {
79        $string = str_replace(' ', $separator, preg_replace('/([^a-zA-Z0-9 \-\/])/', '', strtolower($string)));
80        $regex  = '/' . $separator . '*' . $separator .'/';
81
82        return preg_replace($regex, $separator, $string);
83    }
84
85    /**
86     * Convert any links in the string to HTML links.
87     *
88     * @param  string $string
89     * @param  array  $attributes
90     * @return string
91     */
92    public static function createLinks($string, array $attributes = [])
93    {
94        foreach (self::$linksRegex as $regex) {
95            $replacement = $regex['replacement'];
96
97            if (!empty($attributes)) {
98                $attribs = [];
99                foreach ($attributes as $attrib => $value) {
100                    $attribs[] = $attrib . '="' . $value . '"';
101                }
102                $replacement = str_replace('<a ', '<a ' . implode(' ', $attribs) . ' ', $replacement);
103            }
104
105            $string = preg_replace($regex['pattern'], $replacement, $string);
106        }
107
108        return $string;
109    }
110
111    /**
112     * Generate a random string of a predefined length.
113     *
114     * @param  int $length
115     * @param  int $case
116     * @return string
117     */
118    public static function createRandom($length, $case = self::MIXEDCASE)
119    {
120        $chars    = self::$randomChars;
121        $charsets = [];
122
123        switch ($case) {
124            case 1:
125                unset($chars[1]);
126                break;
127            case 2:
128                unset($chars[0]);
129                break;
130        }
131
132        foreach ($chars as $key => $value) {
133            $charsets[] = str_split($value);
134        }
135
136        return self::generateRandomString($length, $charsets);
137    }
138
139    /**
140     * Generate a random alpha-numeric string of a predefined length.
141     *
142     * @param  int $length
143     * @param  int $case
144     * @return string
145     */
146    public static function createRandomAlphaNum($length, $case = self::MIXEDCASE)
147    {
148        $chars    = self::$randomChars;
149        $charsets = [];
150
151        switch ($case) {
152            case 1:
153                unset($chars[1]);
154                break;
155            case 2:
156                unset($chars[0]);
157                break;
158        }
159        unset($chars[3]);
160
161        foreach ($chars as $key => $value) {
162            $charsets[] = str_split($value);
163        }
164
165        return self::generateRandomString($length, $charsets);
166    }
167
168    /**
169     * Generate a random alphabetical string of a predefined length.
170     *
171     * @param  int $length
172     * @param  int $case
173     * @return string
174     */
175    public static function createRandomAlpha($length, $case = self::MIXEDCASE)
176    {
177        $chars    = self::$randomChars;
178        $charsets = [];
179
180        switch ($case) {
181            case 1:
182                unset($chars[1]);
183                break;
184            case 2:
185                unset($chars[0]);
186                break;
187        }
188        unset($chars[2]);
189        unset($chars[3]);
190
191        foreach ($chars as $key => $value) {
192            $charsets[] = str_split($value);
193        }
194
195        return self::generateRandomString($length, $charsets);
196    }
197
198    /**
199     * Generate a random numeric string of a predefined length.
200     *
201     * @param  int $length
202     * @param  int $case
203     * @return string
204     */
205    public static function createRandomNumeric($length)
206    {
207        return self::generateRandomString($length, [str_split(self::$randomChars[2])]);
208    }
209
210    /**
211     * Generate characters based on length and character sets provided
212     *
213     * @param  int   $length
214     * @param  array $charsets
215     * @return string
216     */
217    public static function generateRandomString($length, array $charsets)
218    {
219        $string  = '';
220        $indices = array_keys($charsets);
221
222        for ($i = 0; $i < $length; $i++) {
223            $index    = $indices[rand(0, (count($indices) - 1))];
224            $subIndex = rand(0, (count($charsets[$index]) - 1));
225            $string  .= $charsets[$index][$subIndex];
226        }
227
228        return $string;
229    }
230
231    /**
232     * Convert a string from one case to another
233     *
234     * @param string $name
235     * @param array  $arguments
236     * @return string
237     */
238    public static function __callStatic($name, $arguments)
239    {
240        [$from, $to]   = explode('to', strtolower($name));
241        $string        = $arguments[0] ?? null;
242        $preserveCase  = (array_key_exists(1, $arguments) && is_bool($arguments[1])) ? $arguments[1] : null;
243        $separator     = null;
244        $prevSeparator = null;
245        $result        = null;
246
247        switch ($to) {
248            case 'titlecase':
249            case 'camelcase':
250                $preserveCase = true;
251                break;
252            case 'kebabcase':
253            case 'dash':
254                $separator = '-';
255                if (null === $preserveCase) {
256                    $preserveCase = false;
257                }
258                break;
259            case 'snakecase':
260            case 'underscore':
261                $separator = '_';
262                if (null === $preserveCase) {
263                    $preserveCase = false;
264                }
265                break;
266            case 'namespace':
267                $separator = '\\';
268                if (null === $preserveCase) {
269                    $preserveCase = true;
270                }
271                break;
272            case 'path':
273                $separator = DIRECTORY_SEPARATOR;
274                if (null === $preserveCase) {
275                    $preserveCase = true;
276                }
277                break;
278            case 'uri':
279            case 'url':
280                $separator = '/';
281                if (null === $preserveCase) {
282                    $preserveCase = true;
283                }
284                break;
285        }
286
287        switch ($from) {
288            case 'titlecase':
289            case 'camelcase':
290                $result = self::convertFromCamelCase($string, $separator, $preserveCase);
291                if ($to == 'titlecase') {
292                    $result = ucfirst($result);
293                }
294                if ($to == 'camelcase') {
295                    $result = lcfirst($result);
296                }
297                break;
298            case 'kebabcase':
299            case 'dash':
300                $prevSeparator = '-';
301                break;
302            case 'snakecase':
303            case 'underscore':
304                $prevSeparator = '_';
305                break;
306            case 'namespace':
307                $prevSeparator = '\\';
308                break;
309            case 'path':
310                $prevSeparator = DIRECTORY_SEPARATOR;
311                break;
312            case 'url':
313            case 'uri':
314                $prevSeparator = '/';
315                break;
316        }
317
318        if (null === $result) {
319            switch ($to) {
320                case 'titlecase':
321                    $result = ucfirst(self::convertToCamelCase($string, $prevSeparator));
322                    break;
323                case 'camelcase':
324                    $result = lcfirst(self::convertToCamelCase($string, $prevSeparator));
325                    break;
326                default:
327                    if ($preserveCase) {
328                        $string = implode($prevSeparator, array_map('ucfirst', explode($prevSeparator, $string)));
329                    }
330                    $result = str_replace($prevSeparator, $separator, $string);
331                    if ($preserveCase === false) {
332                        $result = strtolower($result);
333                    }
334            }
335        }
336
337        return $result;
338    }
339
340    /**
341     * Convert a camelCase string using the $separator value passed
342     *
343     * @param string  $string
344     * @param string  $separator
345     * @param boolean $preserveCase
346     * @return string
347     */
348    public static function convertFromCamelCase($string, $separator, $preserveCase = false)
349    {
350        $stringAry = str_split($string);
351        $converted = null;
352
353        foreach ($stringAry as $i => $char) {
354            $converted .= ($i == 0) ?
355                $char : ((ctype_upper($char)) ? ($separator . $char) : $char);
356        }
357
358        return ($preserveCase) ? $converted : strtolower($converted);
359    }
360
361    /**
362     * Convert a camelCase string using the $separator value passed
363     *
364     * @param string $string
365     * @param string $separator
366     * @return string
367     */
368    public static function convertToCamelCase($string, $separator)
369    {
370        $stringAry = explode($separator, $string);
371        $converted = null;
372
373        foreach ($stringAry as $i => $word) {
374            $converted .= ($i == 0) ? $word : ucfirst($word);
375        }
376
377        return $converted;
378    }
379
380}
381