Completed
Pull Request — master (#2003)
by Basil
02:25
created

StringHelper   A

Complexity

Total Complexity 38

Size/Duplication

Total Lines 303
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 2

Importance

Changes 0
Metric Value
wmc 38
lcom 0
cbo 2
dl 0
loc 303
rs 9.36
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A typeCast() 0 10 3
A startsWithWildcard() 0 8 2
A typeCastNumeric() 0 12 3
A isFloat() 0 8 2
A replaceFirst() 0 4 1
B contains() 0 20 6
A minify() 0 11 2
B truncateMiddle() 0 25 6
B highlightWord() 0 21 6
A mb_str_split() 0 11 2
A isNummeric() 0 16 5
1
<?php
2
3
namespace luya\helpers;
4
5
use yii\helpers\BaseStringHelper;
6
7
/**
8
 * Helper methods when dealing with Strings.
9
 *
10
 * Extends the {{yii\helpers\StringHelper}} class by some usefull functions like:
11
 *
12
 * + {{luya\helpers\StringHelper::typeCast()}}
13
 * + {{luya\helpers\StringHelper::isFloat()}}
14
 * + {{luya\helpers\StringHelper::replaceFirst()}}
15
 * + {{luya\helpers\StringHelper::contains()}}
16
 * + {{luya\helpers\StringHelper::startsWithWildcard()}}
17
 * + {{luya\helpers\StringHelper::typeCastNumeric()}}
18
 *
19
 * @author Basil Suter <[email protected]>
20
 * @since 1.0.0
21
 */
22
class StringHelper extends BaseStringHelper
23
{
24
    /**
25
     * TypeCast a string to its specific types.
26
     *
27
     * Arrays will passed to to the {{luya\helpers\ArrayHelper::typeCast()}} class.
28
     *
29
     * @param mixed $string The input string to type cast. Arrays will be passted to {{luya\helpers\ArrayHelper::typeCast()}}.
30
     * @return mixed The new type casted value, if the input is an array the output is the typecasted array.
31
     */
32
    public static function typeCast($string)
33
    {
34
        if (is_numeric($string)) {
35
            return static::typeCastNumeric($string);
36
        } elseif (is_array($string)) {
37
            return ArrayHelper::typeCast($string);
38
        }
39
        
40
        return $string;
41
    }
42
    
43
    /**
44
     * Checke whether a strings starts with the wildcard symbole and compares the string before the wild card symbol *
45
     * with the string provided, if there is NO wildcard symbold it always return false.
46
     *
47
     *
48
     * @param string $string The string which should be checked with $with comperator
49
     * @param string $with The with string which must end with the wildcard symbol * e.g. `foo*` would match string `foobar`.
50
     * @param boolean $caseSensitive Whether to compare the starts with string as case sensitive or not, defaults to true.
51
     * @return boolean Whether the string starts with the wildcard marked string or not, if no wildcard symbol is contained.
52
     * in the $with it always returns false.
53
     */
54
    public static function startsWithWildcard($string, $with, $caseSensitive = true)
55
    {
56
        if (substr($with, -1) != "*") {
57
            return false;
58
        }
59
        
60
        return self::startsWith($string, rtrim($with, '*'), $caseSensitive);
61
    }
62
    
63
    /**
64
     * TypeCast a numeric value to float or integer.
65
     *
66
     * If the given value is not a numeric or float value it will be returned as it is. In order to find out whether its float
67
     * or not use {{luya\helpers\StringHelper::isFloat()}}.
68
     *
69
     * @param mixed $value The given value to parse.
70
     * @return mixed Returns the original value if not numeric or integer, float casted value.
71
     */
72
    public static function typeCastNumeric($value)
73
    {
74
        if (!self::isFloat($value)) {
75
            return $value;
76
        }
77
        
78
        if (intval($value) == $value) {
79
            return (int) $value;
80
        }
81
        
82
        return (float) $value;
83
    }
84
    
85
    /**
86
     * Checks whether a string is a float value.
87
     *
88
     * Compared to `is_float` function of php, it only ensures whether the input variable is type float.
89
     *
90
     * @param mixed $value The value to check whether its float or not.
91
     * @return boolean Whether its a float value or not.
92
     */
93
    public static function isFloat($value)
94
    {
95
        if (is_float($value)) {
96
            return true;
97
        }
98
        
99
        return ($value == (string)(float) $value);
100
    }
101
    
102
    /**
103
     * Replace only the first occurance found inside the string.
104
     *
105
     * The replace first method is *case sensitive*.
106
     *
107
     * ```php
108
     * StringHelper::replaceFirst('abc', '123', 'abc abc abc'); // returns "123 abc abc"
109
     * ```
110
     *
111
     * @param string $search Search string to look for.
112
     * @param string $replace Replacement value for the first found occurrence.
113
     * @param string $subject The string you want to look up to replace the first element.
114
     * @return mixed Replaced string
115
     */
116
    public static function replaceFirst($search, $replace, $subject)
117
    {
118
        return preg_replace('/'.preg_quote($search, '/').'/', $replace, $subject, 1);
119
    }
120
    
121
    /**
122
     * Check whether a char or word exists in a string or not.
123
     *
124
     * This method is case sensitive. The need can be an array with multiple chars or words who
125
     * are going to look up in the haystack string.
126
     *
127
     * If an array of needle words is provided the $strict parameter defines whether all need keys must be found
128
     * in the string to get the `true` response or if just one of the keys are found the response is already `true`.
129
     *
130
     * ```php
131
     * if (StringHelper::contains('foo', 'the foo bar Bar'')) {
132
     *    echo "yes!";
133
     * }
134
     * ```
135
     *
136
     * check if one of the given needles exists:
137
     *
138
     * ```php
139
     * if (StringHelper::contains(['jungle', 'hell0], 'Welcome to the jungle!)) {
140
     *    echo "yes!";
141
     * }
142
     * ```
143
     *
144
     * @param string|array $needle The char or word to find in the $haystack. Can be an array to multi find words or char in the string.
145
     * @param string $haystack The haystack where the $needle string should be looked up. A string or phrase with words.
146
     * @param boolean $strict If an array of needles is provided the $strict parameter defines whether all keys must be found ($strict = true) or just one result must be found ($strict = false).
147
     * @return boolean If an array of values is provided the response may change depending on $findAll.
148
     */
149
    public static function contains($needle, $haystack, $strict = false)
150
    {
151
        $needles = (array) $needle;
152
        
153
        $state = false;
154
        
155
        foreach ($needles as $item) {
156
            $state = (strpos($haystack, $item) !== false);
157
            
158
            if ($strict && !$state) {
159
                return false;
160
            }
161
            
162
            if (!$strict && $state) {
163
                return true;
164
            }
165
        }
166
167
        return $state;
168
    }
169
    
170
    /**
171
     * "Minify" html content.
172
     *
173
     * + remove space
174
     * + remove tabs
175
     * + remove newlines
176
     * + remove html comments
177
     *
178
     * @param string $content The content to minify.
179
     * @param array $options Optional arguments to provide for minification:
180
     * - comments: boolean, where html comments should be removed or not. defaults to false
181
     * @return mixed Returns the minified content.
182
     * @since 1.0.7
183
     */
184
    public static function minify($content, array $options = [])
185
    {
186
        $min = preg_replace(['/[\n\r]/', '/\>[^\S ]+/s', '/[^\S ]+\</s', '/(\s)+/s', ], ['', '>', '<', '\\1'], trim($content));
187
        $min = str_replace(['> <'], ['><'], $min);
188
        
189
        if (ArrayHelper::getValue($options, 'comments', false)) {
190
            $min = preg_replace('/<!--(.*)-->/Uis', '', $min);
191
        }
192
        
193
        return $min;
194
    }
195
196
    /**
197
     * Cut the given word/string from the content. Its truncates to the left side and to the right side of the word.
198
     *
199
     * An example of how a sentenced is cut:
200
     *
201
     * ```php
202
     * $cut = StringHelper::truncateMiddle('the quick fox jumped over the lazy dog', 'jumped', 12);
203
     * echo $cut; // ..e quick fox jumped over the la..
204
     * ```
205
     *
206
     * @param string $content The content to cut the words from.
207
     * @param string $word The word which should be in the middle of the string
208
     * @param integer $length The amount of the chars to cut on the left and right side from the word.
209
     * @param string $affix The chars which should be used for prefix and suffix when string is cuted.
210
     * @param boolean $caseSensitive Whether the search word in the string even when lower/upper case is not correct.
211
     * @since 1.0.12
212
     */
213
    public static function truncateMiddle($content, $word, $length, $affix = '..', $caseSensitive = false)
214
    {
215
        $content = strip_tags($content);
216
        $array = self::mb_str_split($content);
217
        $first = mb_strpos($caseSensitive ? $content : mb_strtolower($content), $caseSensitive ? $word : mb_strtolower($word));
218
219
        // we could not find any match, therefore use casual truncate method.
220
        if ($first === false) {
221
            // as the length value in truncate middle stands for to the left and to the right, we multiple this value with 2
222
            return self::truncate($content, ($length*2), $affix);
223
        }
224
225
        $last = $first + mb_strlen($word);
226
227
        // left and right array chars from word
228
        $left = array_slice($array, 0, $first, true);
229
        $right = array_slice($array, $last, null, true);
230
        $middle = array_splice($array, $first, mb_strlen($word));
231
232
        // string before
233
        $before = (count($left) > $length) ? $affix.implode("", array_slice($left, -$length)) : implode("", $left);
234
        $after = (count($right) > $length) ? implode("", array_slice($right, 0, $length)) . $affix : implode("", $right);
235
236
        return $before . implode("", $middle) . $after;
237
    }
238
239
    /**
240
     * Highlight a word within a content.
241
     *
242
     * Since version 1.0.14 an array of words to highlight is possible.
243
     *
244
     * > This function IS NOT case sensitive!
245
     *
246
     *
247
     *
248
     * @param string $content The content to find the word.
249
     * @param string $word The word to find within the content.
250
     * @param string $markup The markup used wrap the word to highlight.
251
     * @since 1.0.12
252
     */
253
    public static function highlightWord($content, $word, $markup = '<b>%s</b>')
254
    {
255
        $word = (array) $word;
256
        $content = strip_tags($content);
257
        $latest = null;
258
        foreach ($word as $needle) {
259
            preg_match_all("/".preg_quote($needle, '/')."+/i", $content, $matches);
260
            if (is_array($matches[0]) && count($matches[0]) >= 1) {
261
                foreach ($matches[0] as $match) {
262
                    // ensure if a word is found twice we don't replace again.
263
                    if ($latest === $match) {
264
                        continue;
265
                    }
266
                    $content = str_replace($match, sprintf($markup, $match), $content);
267
                    $latest = $match;
268
                }
269
            }
270
        }
271
272
        return $content;
273
    }
274
275
    /**
276
     * Multibyte-safe str_split funciton.
277
     *
278
     * @param string $string The string to split into an array
279
     * @param integer $length The length of the chars to cut.
280
     * @since 1.0.12
281
     */
282
    public static function mb_str_split($string, $length = 1)
283
    {
284
        $array = [];
285
        $stringLength = mb_strlen($string, 'UTF-8');
286
    
287
        for ($i = 0; $i < $stringLength; $i += $length) {
288
            $array[] = mb_substr($string, $i, $length, 'UTF-8');
289
        }
290
    
291
        return $array;
292
    }
293
294
    /**
295
     * Check whether a value is numeric or not.
296
     * 
297
     * There are situations where is_numeric does not provide the desried result,
298
     * like for example `is_numeric('3e30')` would return true, as e can be considered
299
     * as exponential operator.
300
     * 
301
     * Therfore this function checks with regex whether values or 0-9 if strict is enabled,
302
     * which is default behavior.
303
     *
304
     * @param mixed $value The value to check.
305
     * @param boolean $strict
306
     * @return boolean
307
     */
308
    public static function isNummeric($value, $strict = true)
309
    {
310
        if (!is_scalar($value)) {
311
            return false;
312
        }
313
314
        if (is_bool($value)) {
315
            return false;
316
        }
317
318
        if ($strict) {
319
            return preg_match('/^[0-9]+$/', $value) == 1 ? true : false;
320
        }    
321
322
        return is_numeric($value);
323
    }
324
}
325