Passed
Push — master ( 78328e...488bc1 )
by Nelson
03:01
created

Text   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 220
Duplicated Lines 0 %

Test Coverage

Coverage 73.58%

Importance

Changes 0
Metric Value
eloc 49
dl 0
loc 220
ccs 39
cts 53
cp 0.7358
rs 10
c 0
b 0
f 0
wmc 21

7 Methods

Rating   Name   Duplication   Size   Complexity  
A compare() 0 21 6
A format() 0 31 5
A ensureIsString() 0 8 2
A ensureIsNotEmpty() 0 8 2
A ensureIsNotNull() 0 8 2
A ensureIsNotWhiteSpaces() 0 8 2
A ensureIsValidVarName() 0 10 2
1
<?php
2
/**
3
 * PHP: Nelson Martell Library file
4
 *
5
 * Copyright © 2015-2019 Nelson Martell (http://nelson6e65.github.io)
6
 *
7
 * Licensed under The MIT License (MIT)
8
 * For full copyright and license information, please see the LICENSE
9
 * Redistributions of files must retain the above copyright notice.
10
 *
11
 * @copyright 2015-2019 Nelson Martell
12
 * @link      http://nelson6e65.github.io/php_nml/
13
 * @since     0.7.0
14
 * @license   http://www.opensource.org/licenses/mit-license.php The MIT License (MIT)
15
 * */
16
namespace NelsonMartell\Extensions;
17
18
use InvalidArgumentException;
19
use Cake\Utility\Text as TextBase;
20
21
use function NelsonMartell\msg;
22
use function NelsonMartell\typeof;
23
use NelsonMartell\IComparer;
24
use NelsonMartell\StrictObject;
25
26
/**
27
 * Provides extension methods to handle strings.
28
 * This class is based on \Cake\Utility\Text of CakePHP(tm) class.
29
 *
30
 * @since 0.7.0
31
 * @author Nelson Martell <[email protected]>
32
 * @see \Cake\Utility\Text::insert()
33
 * @link http://book.cakephp.org/3.0/en/core-libraries/text.html
34
 * */
35
class Text extends TextBase implements IComparer
36
{
37
38
    /**
39
     * Replaces format elements in a string with the string representation of an
40
     * object matching the list of arguments specified. You can give as many
41
     * params as you need, or an array with values.
42
     *
43
     * ##Usage
44
     * Using numbers as placeholders (encloses between `{` and `}`), you can get
45
     * the matching string representation of each object given. Use `{0}` for
46
     * the fist object, `{1}` for the second, and so on:
47
     *
48
     * ```php
49
     * $format = '{0} is {1} years old, and have {2} cats.';
50
     * echo Text::format($format, 'Bob', 65, 101); // 'Bob is 65 years old, and have 101 cats.'
51
     * ```
52
     *
53
     * You can also use an array to give objects values:
54
     *
55
     * ```php
56
     * $format = '{0} is {1} years old, and have {2} cats.';
57
     * $data   = ['Bob', 65, 101];
58
     * echo Text::format($format, $data); // 'Bob is 65 years old, and have 101 cats.'
59
     * ```
60
     *
61
     * This is specially useful to be able to use non-numeric placeholders (named placeholders):
62
     *
63
     * ```php
64
     * $format = '{name} is {age} years old, and have {n} cats.';
65
     * $data = ['name' => 'Bob', 'n' => 101, 'age' => 65];
66
     * echo Text::format($format, $data); // 'Bob is 65 years old, and have 101 cats.'
67
     * ```
68
     *
69
     * For numeric placeholders, yo can convert the array into a list of arguments.
70
     *
71
     * ```php
72
     * $format = '{0} is {1} years old, and have {2} cats.';
73
     * $data   = ['Bob', 65, 101];
74
     * echo Text::format($format, ...$data); // 'Bob is 65 years old, and have 101 cats.'
75
     * ```
76
     *
77
     * > Note: If objects are not convertible to string, it will throws and catchable exception
78
     * (`InvalidArgumentException`).
79
     *
80
     * @param string      $format An string containing variable placeholders to be replaced. If you provide name
81
     *   placeholders, you must pass the target array as
82
     * @param array|mixed $args   Object(s) to be replaced into $format placeholders.
83
     *   You can provide one item only of type array for named placeholders replacement. For numeric placeholders, you
84
     *   can still pass the array or convert it into arguments by using the '...' syntax instead.
85
     *
86
     * @return string
87
     * @throws InvalidArgumentException if $format is not an string or placeholder values are not string-convertibles.
88
     * @todo   Implement formatting, like IFormatProvider or something like that.
89
     * @author Nelson Martell <[email protected]>
90
     */
91 342
    public static function format($format, ...$args)
92
    {
93 342
        static $options = [
94
            'before'  => '{',
95
            'after'   => '}',
96
        ];
97
98 342
        $originalData = $args;
99
100
        // Make it compatible with named placeholders along numeric ones if passed only 1 array as argument
101 342
        if (count($args) === 1 && is_array($args[0])) {
102 333
            $originalData = $args[0];
103
        }
104
105 342
        $data = [];
106
        // Sanitize values to be convertibles into strings
107 342
        foreach ($originalData as $placeholder => $value) {
108 342
            $valueType = typeof($value);
109
110 342
            if ($valueType->canBeString() === false) {
111 3
                $msg = 'Value for "{{0}}" placeholder is not convertible to string; "{1}" type given.';
112 3
                throw new InvalidArgumentException(msg($msg, $placeholder, $valueType));
113
            }
114
115
            // This is to work-arround a bug in use of ``asort()`` function in ``Text::insert`` (at v3.2.5)
116
            // without SORT_STRING flag... by forcing value to be string.
117 342
            settype($value, 'string');
118 342
            $data[$placeholder] = $value;
119
        }
120
121 342
        return static::insert($format, $data, $options);
122
    }
123
124
    /**
125
     * Ensures that object given is not null. If is `null`, throws and exception.
126
     *
127
     * @param mixed $obj Object to validate
128
     *
129
     * @return mixed Same object
130
     * @throws InvalidArgumentException if object is `null`.
131
     */
132 190
    public static function ensureIsNotNull($obj)
133
    {
134 190
        if (is_null($obj)) {
135
            $msg = msg('Provided object must not be NULL.');
136
            throw new InvalidArgumentException($msg);
137
        }
138
139 190
        return $obj;
140
    }
141
142
    /**
143
     * Ensures that object given is an string. Else, thows an exception
144
     *
145
     * @param mixed $obj Object to validate.
146
     *
147
     * @return string Same object given, but ensured that is an string.
148
     * @throws InvalidArgumentException if object is not an `string`.
149
     */
150 190
    public static function ensureIsString($obj)
151
    {
152 190
        if (!is_string(static::ensureIsNotNull($obj))) {
153 1
            $msg = msg('Provided object must to be an string; "{0}" given.', typeof($obj));
154 1
            throw new InvalidArgumentException($msg);
155
        }
156
157 189
        return $obj;
158
    }
159
160
    /**
161
     * Ensures that given string is not empty.
162
     *
163
     * @param string $string String to validate.
164
     *
165
     * @return string Same string given, but ensured that is not empty.
166
     * @throws InvalidArgumentException if string is null or empty.
167
     */
168
    public static function ensureIsNotEmpty($string)
169
    {
170
        if (static::ensureIsString($string) === '') {
171
            $msg = msg('Provided string must not be empty.');
172
            throw new InvalidArgumentException($msg);
173
        }
174
175
        return $string;
176
    }
177
178
    /**
179
     * Ensures that given string is not empty or whitespaces.
180
     *
181
     * @param string $string String to validate.
182
     *
183
     * @return string Same string given, but ensured that is not whitespaces.
184
     * @throws InvalidArgumentException if object is not an `string`.
185
     * @see    \trim()
186
     */
187
    public static function ensureIsNotWhiteSpaces($string)
188
    {
189
        if (trim(static::ensureIsNotEmpty($string)) === '') {
190
            $msg = msg('Provided string must not be white spaces.');
191
            throw new InvalidArgumentException($msg);
192
        }
193
194
        return $string;
195
    }
196
197
    /**
198
     * Ensures that an string follows the PHP variables naming convention.
199
     *
200
     * @param string $string String to be ensured.
201
     *
202
     * @return string
203
     * @throws InvalidArgumentException if object is not an `string` or do not
204
     *   follows the PHP variables naming convention.
205
     */
206 186
    public static function ensureIsValidVarName($string)
207
    {
208 186
        $pattern = '/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/';
209
210 186
        if (!preg_match($pattern, static::ensureIsString($string))) {
211
            $msg = msg('Provided string do not follows PHP variables naming convention: "{0}".', $string);
212
            throw new InvalidArgumentException($msg);
213
        }
214
215 186
        return $string;
216
    }
217
218
219
    /**
220
     * {@inheritDoc}
221
     *
222
     * This methods is specific for the case when one of them are `string`. In other case, will fallback to
223
     * `StrictObject::compare()`.` You should use it directly instead of this method as comparation function
224
     * for `usort()`.
225
     *
226
     * @param string|mixed $left
227
     * @param string|mixed $right
228
     *
229
     * @return int|null
230
     *
231
     * @since 1.0.0
232
     * @see StrictObject::compare()
233
     */
234 36
    public static function compare($left, $right)
235
    {
236 36
        if (is_string($left)) {
237 36
            if (typeof($right)->isCustom()) { // String are minor than classes
238 7
                return -1;
239 30
            } elseif (typeof($right)->canBeString()) {
240 26
                return strnatcmp($left, $right);
241
            } else {
242 4
                return -1;
243
            }
244 8
        } elseif (is_string($right)) {
245 8
            $r = static::compare($right, $left);
246
247 8
            if ($r !== null) {
0 ignored issues
show
introduced by
The condition $r !== null is always true.
Loading history...
248 8
                $r *= -1; // Invert result
249
            }
250
251 8
            return $r;
252
        }
253
254 1
        return StrictObject::compare($left, $right);
255
    }
256
}
257