├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml ├── src ├── StrProxy.php ├── StringServiceProvider.php └── helpers.php └── tests └── Unit └── StrProxyTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | .phpunit.result.cache 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Drazen Vasiljevic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Right now if we want to do any manipulation with strings we face same problem like with an array before collections 2 | where we have to read the code inside out. 3 | 4 | ```php 5 | $title = Str::title(Str::replaceArray('_', [' '], Str::snake('fooBar'))); 6 | ``` 7 | 8 | Also Str object in Laravel does not accept the string that is being manipulated as the first argument across all 9 | methods like `replaceArray()`. 10 | 11 | It would be great to bring that kind of power and functionality to Laravel and surpass current language limitations. 12 | 13 | ```php 14 | $title = (new Str('fooBar'))->snake()->replaceArray('_', [' '])->title()->get(); 15 | ``` 16 | 17 | Also add helper function to make it even cleaner. 18 | 19 | ```php 20 | $title = str('fooBar')->snake()->replaceArray('_', [' '])->title()->get(); 21 | ``` 22 | 23 | Having `dd()` on that object is a must :D 24 | 25 | ```php 26 | $title = str('fooBar')->snake()->replaceArray('_', [' '])->dd()->title()->get(); 27 | ``` 28 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zendraxl/laravel-string", 3 | "description": "Laravel String Object inspired by Laravel Collections", 4 | "keywords": [ 5 | "laravel", 6 | "string" 7 | ], 8 | "license": "MIT", 9 | "authors": [ 10 | { 11 | "name": "Drazen Vasiljevic", 12 | "email": "zendraxl@gmail.com" 13 | } 14 | ], 15 | "minimum-stability": "dev", 16 | "prefer-stable": true, 17 | "require": { 18 | "php": ">=7.1.0", 19 | "illuminate/support": "^5.7.15 || ^6.0.0", 20 | "ramsey/uuid": "^3.8", 21 | "moontoast/math": "^1.1" 22 | }, 23 | "require-dev": { 24 | "phpunit/phpunit": "^8.4" 25 | }, 26 | "autoload": { 27 | "psr-4": { 28 | "Zendraxl\\LaravelString\\": "src/" 29 | }, 30 | "files": [ 31 | "src/helpers.php" 32 | ] 33 | }, 34 | "autoload-dev": { 35 | "psr-4": { 36 | "Zendraxl\\LaravelString\\Tests\\": "tests/" 37 | } 38 | }, 39 | "extra": { 40 | "laravel": { 41 | "providers": [ 42 | "Zendraxl\\LaravelString\\StringServiceProvider" 43 | ] 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | ./tests/Unit 15 | 16 | 17 | 18 | 19 | ./src 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/StrProxy.php: -------------------------------------------------------------------------------- 1 | text = $text; 58 | } 59 | 60 | public static function __callStatic($method, $parameters) 61 | { 62 | return LaravelStr::{$method}(...$parameters); 63 | } 64 | 65 | public function __call($name, $arguments) 66 | { 67 | $this->text = LaravelStr::{$name}(...$this->rearrangeParameters($name, $arguments)); 68 | 69 | if ($this->shouldReturnDifferentValue()) { 70 | return $this->text; 71 | } 72 | 73 | if (! is_string($this->text)) { 74 | throw new \Exception('Invalid change made to the text.'); 75 | } 76 | 77 | return $this; 78 | } 79 | 80 | public function __toString(): string 81 | { 82 | if (! is_string($this->text)) { 83 | return ''; 84 | } 85 | return $this->text; 86 | } 87 | 88 | public function dd(): void 89 | { 90 | dd($this->text); 91 | } 92 | 93 | public function get() 94 | { 95 | return $this->text; 96 | } 97 | 98 | protected function constructorParameterShouldBeOmitted($name): bool 99 | { 100 | return in_array($name, [ 101 | static::METHOD_RANDOM, 102 | static::METHOD_REPLACE_ARRAY, 103 | static::METHOD_REPLACE_FIRST, 104 | static::METHOD_REPLACE_LAST, 105 | ]); 106 | } 107 | 108 | protected function constructorParameterShouldBePushedToEnd($name): bool 109 | { 110 | return in_array($name, [ 111 | static::METHOD_REPLACE_ARRAY, 112 | static::METHOD_REPLACE_FIRST, 113 | static::METHOD_REPLACE_LAST, 114 | ]); 115 | } 116 | 117 | protected function parametersShouldBeReversed($name): bool 118 | { 119 | return in_array($name, [ 120 | static::METHOD_IS, 121 | ]); 122 | } 123 | 124 | protected function rearrangeParameters($name, $arguments): array 125 | { 126 | $parameters = $this->constructorParameterShouldBeOmitted($name) 127 | ? $arguments 128 | : array_merge([$this->text], $arguments); 129 | 130 | if ($this->parametersShouldBeReversed($name)) { 131 | $parameters = array_reverse($parameters); 132 | } 133 | 134 | if ($this->constructorParameterShouldBePushedToEnd($name)) { 135 | $parameters[] = $this->text; 136 | } 137 | 138 | return $parameters; 139 | } 140 | 141 | protected function shouldReturnDifferentValue(): bool 142 | { 143 | if (is_array($this->text)) { 144 | return true; 145 | } 146 | 147 | if (is_bool($this->text)) { 148 | return true; 149 | } 150 | 151 | if (is_int($this->text)) { 152 | return true; 153 | } 154 | 155 | if (is_object($this->text)) { 156 | return true; 157 | } 158 | 159 | return false; 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/StringServiceProvider.php: -------------------------------------------------------------------------------- 1 | assertSame( 15 | Str::after('This is my name', 'This is'), 16 | (new StrProxy('This is my name'))->after('This is')->get() 17 | ); 18 | } 19 | 20 | /** @test */ 21 | public function str_ascii(): void 22 | { 23 | $this->assertSame(Str::ascii('@'), (new StrProxy('@'))->ascii()->get()); 24 | $this->assertSame(Str::ascii('ü'), (new StrProxy('ü'))->ascii()->get()); 25 | $this->assertSame( 26 | Str::ascii('х Х щ Щ ъ Ъ ь Ь', 'bg'), 27 | (new StrProxy('х Х щ Щ ъ Ъ ь Ь'))->ascii('bg')->get() 28 | ); 29 | $this->assertSame( 30 | Str::ascii('ä ö ü Ä Ö Ü', 'de'), 31 | (new StrProxy('ä ö ü Ä Ö Ü'))->ascii('de')->get() 32 | ); 33 | } 34 | 35 | /** @test */ 36 | public function str_before(): void 37 | { 38 | $this->assertSame( 39 | Str::before('This is my name', 'my name'), 40 | (new StrProxy('This is my name'))->before('my name')->get() 41 | ); 42 | } 43 | 44 | /** @test */ 45 | public function str_camel(): void 46 | { 47 | $this->assertSame(Str::camel('foo_bar'), (new StrProxy('foo_bar'))->camel()->get()); 48 | } 49 | 50 | /** @test */ 51 | public function str_contains(): void 52 | { 53 | $this->assertSame( 54 | Str::contains('This is my name', 'my'), 55 | (new StrProxy('This is my name'))->contains('my') 56 | ); 57 | $this->assertSame( 58 | Str::contains('This is my name', ['my', 'foo']), 59 | (new StrProxy('This is my name'))->contains(['my', 'foo']) 60 | ); 61 | } 62 | 63 | /** @test */ 64 | public function str_contains_all(): void 65 | { 66 | $this->assertSame( 67 | Str::containsAll('This is my name', ['my', 'name']), 68 | (new StrProxy('This is my name'))->containsAll(['my', 'name']) 69 | ); 70 | } 71 | 72 | /** @test */ 73 | public function str_ends_with(): void 74 | { 75 | $this->assertSame( 76 | Str::endsWith('This is my name', 'name'), 77 | (new StrProxy('This is my name'))->endsWith('name') 78 | ); 79 | } 80 | 81 | /** @test */ 82 | public function str_finish(): void 83 | { 84 | $this->assertSame( 85 | Str::finish('this/string', '/'), 86 | (new StrProxy('this/string'))->finish('/')->get() 87 | ); 88 | $this->assertSame( 89 | Str::finish('this/string/', '/'), 90 | (new StrProxy('this/string/'))->finish('/')->get() 91 | ); 92 | } 93 | 94 | /** @test */ 95 | public function str_is(): void 96 | { 97 | $this->assertSame(Str::is('foo*', 'foobar'), (new StrProxy('foobar'))->is('foo*')); 98 | $this->assertSame(Str::is('baz*', 'foobar'), (new StrProxy('foobar'))->is('baz*')); 99 | } 100 | 101 | /** @test */ 102 | public function str_kebab(): void 103 | { 104 | $this->assertSame(Str::kebab('fooBar'), (new StrProxy('fooBar'))->kebab()->get()); 105 | } 106 | 107 | /** @test */ 108 | public function str_length(): void 109 | { 110 | $this->assertSame(Str::length('foo bar baz'), (new StrProxy('foo bar baz'))->length()); 111 | $this->assertSame( 112 | Str::length('foo bar baz', 'UTF-8'), 113 | (new StrProxy('foo bar baz'))->length('UTF-8') 114 | ); 115 | } 116 | 117 | /** @test */ 118 | public function str_limit(): void 119 | { 120 | $this->assertSame( 121 | Str::limit('The quick brown fox jumps over the lazy dog', 20), 122 | (new StrProxy('The quick brown fox jumps over the lazy dog'))->limit(20)->get() 123 | ); 124 | $this->assertSame( 125 | Str::limit('The quick brown fox jumps over the lazy dog', 20, ' (...)'), 126 | (new StrProxy('The quick brown fox jumps over the lazy dog'))->limit(20, ' (...)')->get() 127 | ); 128 | } 129 | 130 | /** @test */ 131 | public function str_lower(): void 132 | { 133 | $this->assertSame(Str::lower('FOO BAR BAZ'), (new StrProxy('FOO BAR BAZ'))->lower()->get()); 134 | $this->assertSame(Str::lower('fOo Bar bAz'), (new StrProxy('fOo Bar bAz'))->lower()->get()); 135 | } 136 | 137 | /** @test */ 138 | public function str_ordered_uuid(): void 139 | { 140 | $pattern = '/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/'; 141 | $this->assertRegExp($pattern, (string) Str::orderedUuid()); 142 | $this->assertRegExp($pattern, (string) (new StrProxy(''))->orderedUuid()); 143 | } 144 | 145 | /** @test */ 146 | public function str_parse_callback(): void 147 | { 148 | $this->assertSame( 149 | Str::parseCallback('Class@method', 'foo'), 150 | (new StrProxy('Class@method'))->parseCallback('foo') 151 | ); 152 | $this->assertSame( 153 | Str::parseCallback('Class', 'foo'), 154 | (new StrProxy('Class'))->parseCallback('foo') 155 | ); 156 | } 157 | 158 | /** @test */ 159 | public function str_plural(): void 160 | { 161 | $this->assertSame(Str::plural('car'), (new StrProxy('car'))->plural()->get()); 162 | $this->assertSame(Str::plural('child'), (new StrProxy('child'))->plural()->get()); 163 | $this->assertSame(Str::plural('child', 2), (new StrProxy('child'))->plural(2)->get()); 164 | $this->assertSame(Str::plural('child', 1), (new StrProxy('child'))->plural(1)->get()); 165 | } 166 | 167 | /** @test */ 168 | public function str_random(): void 169 | { 170 | $pattern = '/\w{40}/'; 171 | $this->assertRegExp($pattern, Str::random(40)); 172 | // StrProxy 173 | $string = new StrProxy(''); 174 | $this->assertRegExp($pattern, $string->random(40)->get()); 175 | } 176 | 177 | /** @test */ 178 | public function str_replace_array(): void 179 | { 180 | $this->assertSame( 181 | Str::replaceArray('?', ['8:30', '9:00'], 'The event will take place between ? and ?'), 182 | (new StrProxy('The event will take place between ? and ?'))->replaceArray('?', ['8:30', '9:00'])->get() 183 | ); 184 | } 185 | 186 | /** @test */ 187 | public function str_replace_first(): void 188 | { 189 | $this->assertSame( 190 | Str::replaceFirst('the', 'a', 'the quick brown fox jumps over the lazy dog'), 191 | (new StrProxy('the quick brown fox jumps over the lazy dog'))->replaceFirst('the', 'a')->get() 192 | ); 193 | } 194 | 195 | /** @test */ 196 | public function str_replace_last(): void 197 | { 198 | $this->assertSame( 199 | Str::replaceLast('the', 'a', 'the quick brown fox jumps over the lazy dog'), 200 | (new StrProxy('the quick brown fox jumps over the lazy dog'))->replaceLast('the', 'a')->get() 201 | ); 202 | } 203 | 204 | /** @test */ 205 | public function str_singular(): void 206 | { 207 | $this->assertSame(Str::singular('cars'), (new StrProxy('cars'))->singular()->get()); 208 | $this->assertSame(Str::singular('children'), (new StrProxy('children'))->singular()->get()); 209 | } 210 | 211 | /** @test */ 212 | public function str_slug(): void 213 | { 214 | $this->assertSame( 215 | Str::slug('Laravel 5 Framework', '-'), 216 | (new StrProxy('Laravel 5 Framework'))->slug('-')->get() 217 | ); 218 | } 219 | 220 | /** @test */ 221 | public function str_snake(): void 222 | { 223 | $this->assertSame(Str::snake('fooBar'), (new StrProxy('fooBar'))->snake()->get()); 224 | } 225 | 226 | /** @test */ 227 | public function str_start(): void 228 | { 229 | $this->assertSame(Str::start('this/string', '/'), (new StrProxy('this/string'))->start('/')->get()); 230 | $this->assertSame(Str::start('/this/string', '/'), (new StrProxy('/this/string'))->start('/')->get()); 231 | } 232 | 233 | /** @test */ 234 | public function str_starts_with(): void 235 | { 236 | $this->assertSame( 237 | Str::startsWith('This is my name', 'This'), 238 | (new StrProxy('This is my name'))->startsWith('This') 239 | ); 240 | } 241 | 242 | /** @test */ 243 | public function str_studly(): void 244 | { 245 | $this->assertSame(Str::studly('foo_bar'), (new StrProxy('foo_bar'))->studly()->get()); 246 | } 247 | 248 | /** @test */ 249 | public function str_substr(): void 250 | { 251 | $this->assertSame(Str::substr('foobar', -1), (new StrProxy('foobar'))->substr(-1)->get()); 252 | } 253 | 254 | /** @test */ 255 | public function str_title(): void 256 | { 257 | $this->assertSame( 258 | Str::title('a nice title uses the correct case'), 259 | (new StrProxy('a nice title uses the correct case'))->title()->get() 260 | ); 261 | } 262 | 263 | /** @test */ 264 | public function str_uc_first(): void 265 | { 266 | $this->assertSame(Str::ucfirst('laravel'), (new StrProxy('laravel'))->ucfirst()->get()); 267 | $this->assertSame(Str::ucfirst('laravel framework'), (new StrProxy('laravel framework'))->ucfirst()->get()); 268 | } 269 | 270 | /** @test */ 271 | public function str_upper(): void 272 | { 273 | $this->assertSame(Str::upper('foo bar baz'), (new StrProxy('foo bar baz'))->upper()->get()); 274 | $this->assertSame(Str::upper('foO bAr BaZ'), (new StrProxy('foO bAr BaZ'))->upper()->get()); 275 | } 276 | 277 | /** @test */ 278 | public function str_uuid(): void 279 | { 280 | $pattern = '/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/'; 281 | $this->assertRegExp($pattern, (string) Str::uuid()); 282 | $this->assertRegExp($pattern, (string) (new StrProxy(''))->uuid()); 283 | } 284 | 285 | /** @test */ 286 | public function str_words(): void 287 | { 288 | $this->assertSame( 289 | Str::words('Perfectly balanced, as all things should be.', 3, ' >>>'), 290 | (new StrProxy('Perfectly balanced, as all things should be.'))->words(3, ' >>>')->get() 291 | ); 292 | } 293 | 294 | /** @test */ 295 | public function utterly_not_so_complex_example(): void 296 | { 297 | $this->assertSame( 298 | Str::title(Str::replaceArray('_', [' '], Str::snake('fooBar'))), 299 | (new StrProxy('fooBar'))->snake()->replaceArray('_', [' '])->title()->get() 300 | ); 301 | } 302 | } 303 | --------------------------------------------------------------------------------