├── .coveralls.yml ├── .gitignore ├── .scrutinizer.yml ├── .travis.yml ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml ├── public └── .gitkeep ├── src ├── Jaybizzle │ └── Safeurl │ │ ├── Facades │ │ └── Safeurl.php │ │ ├── Safeurl.php │ │ └── SafeurlServiceProvider.php ├── LICENSE ├── README.md └── config │ └── config.php └── tests ├── .gitkeep └── QuickTest.php /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: travis-ci 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.phar 3 | composer.lock 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | checks: 2 | php: 3 | code_rating: true 4 | duplication: true 5 | 6 | filter: 7 | excluded_paths: [tests/*] 8 | 9 | tools: 10 | php_analyzer: true 11 | php_mess_detector: true 12 | php_code_sniffer: 13 | config: 14 | standard: PSR2 15 | tab_width: 4 16 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.6 5 | - 7.0 6 | - 7.1 7 | - 7.2 8 | - 7.3 9 | - 7.4 10 | - 8.0 11 | - 8.1 12 | 13 | before_script: 14 | - travis_retry composer self-update 15 | - travis_retry composer install --prefer-source --no-interaction --dev 16 | 17 | script: phpunit 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Mark Beech 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 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Safeurl 2 | ======= 3 | [![Latest Stable Version](https://img.shields.io/packagist/v/JayBizzle/Safeurl.svg?style=flat-square)](https://packagist.org/packages/jaybizzle/safeurl) [![Total Downloads](https://img.shields.io/packagist/dt/JayBizzle/Safeurl.svg?style=flat-square)](https://packagist.org/packages/jaybizzle/safeurl) [![License](https://img.shields.io/packagist/l/JayBizzle/Safeurl.svg?style=flat-square)](https://packagist.org/packages/jaybizzle/safeurl) [![Build Status](https://img.shields.io/travis/JayBizzle/Safeurl.svg?style=flat-square)](https://travis-ci.org/JayBizzle/Safeurl) [![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/JayBizzle/Safeurl.svg?style=flat-square)](https://scrutinizer-ci.com/g/JayBizzle/Safeurl/?branch=master) [![Laravel](https://img.shields.io/badge/laravel-5.0.*-ff69b4.svg?style=flat-square)](https://laravel.com) 4 | 5 | A Laravel 5 package to create safe, SEO friendly urls 6 | 7 | For the Laravel 4 version, see the [v0.1 branch](https://github.com/JayBizzle/Safeurl/tree/v0.1) 8 | 9 | Installation 10 | ============ 11 | 12 | Run `composer require jaybizzle/safeurl 0.2.*` or add `"jaybizzle/safeurl": "0.2.*"` to your `composer.json` file 13 | 14 | Add the following to the `providers` array in your `config/app.php` file.. 15 | 16 | ```PHP 17 | 'Jaybizzle\Safeurl\SafeurlServiceProvider', 18 | ``` 19 | 20 | ...and the following to your `aliases` array... 21 | 22 | ```PHP 23 | 'Safeurl' => 'Jaybizzle\Safeurl\Facades\Safeurl', 24 | ``` 25 | 26 | Usage 27 | ================== 28 | 29 | ```PHP 30 | echo Safeurl::make('The quick brown fox jumps over the lazy dog'); 31 | 32 | // Output: the-quick-brown-fox-jumps-over-the-lazy-dog 33 | ``` 34 | 35 | Options 36 | ================== 37 | 38 | These are the default global options. If you want to define your own global options, publish the config with `php artisan vendor:publish --provider="Jaybizzle\Safeurl\SafeurlServiceProvider"` and change the settings in `config/safeurl.php`. 39 | 40 | Options can be individually overridden on each call to `Safeurl::make(string, options)` 41 | 42 | ```PHP 43 | array( 44 | 45 | 'decode' => true, // Decode html entities in string? 46 | 'decode_charset' => 'UTF-8', // Charset to use if $decode is set to true 47 | 'lowercase' => true, // Turns string into all lowercase letters 48 | 'strip' => true, // Strip out html tags from string? 49 | 'maxlength' => 50, // Maximum length of resulting title 50 | 'whole_word' => true, // If maxlength is reached, chop at nearest whole word? or hard chop? 51 | 'blank' => 'no-title', // What title to use if no alphanumeric characters can be found 52 | 'separator' => '-', // Allow a differnt character to be used as the separator. 53 | 54 | // A table of UTF-8 characters and what to make them. 55 | 'translation_table' => array( 56 | 'Š'=>'S', 'š'=>'s', 'Đ'=>'Dj','Ð'=>'Dj','đ'=>'dj', 'Ž'=>'Z', 'ž'=>'z', 'Č'=>'C', 'č'=>'c', 'Ć'=>'C', 'ć'=>'c', 57 | 'À'=>'A', 'Á'=>'A', 'Â'=>'A', 'Ã'=>'A', 'Ä'=>'A', 'Å'=>'A', 'Æ'=>'A', 'Ç'=>'C', 'È'=>'E', 'É'=>'E', 58 | 'Ê'=>'E', 'Ë'=>'E', 'Ì'=>'I', 'Í'=>'I', 'Î'=>'I', 'Ï'=>'I', 'Ñ'=>'N', 'Ò'=>'O', 'Ó'=>'O', 'Ô'=>'O', 59 | 'Õ'=>'O', 'Ö'=>'O', 'Ø'=>'O', 'Ù'=>'U', 'Ú'=>'U', 'Û'=>'U', 'Ü'=>'U', 'Ý'=>'Y', 'Þ'=>'B', 'ß'=>'Ss', 60 | 'à'=>'a', 'á'=>'a', 'â'=>'a', 'ã'=>'a', 'ä'=>'a', 'å'=>'a', 'æ'=>'a', 'ç'=>'c', 'è'=>'e', 'é'=>'e', 61 | 'ê'=>'e', 'ë'=>'e', 'ì'=>'i', 'í'=>'i', 'î'=>'i', 'ï'=>'i', 'ð'=>'o', 'ñ'=>'n', 'ò'=>'o', 'ó'=>'o', 62 | 'ô'=>'o', 'õ'=>'o', 'ö'=>'o', 'ø'=>'o', 'ù'=>'u', 'ú'=>'u', 'û'=>'u', 'ý'=>'y', 'ý'=>'y', 'þ'=>'b', 63 | 'ÿ'=>'y', 'Ŕ'=>'R', 'ŕ'=>'r', 'ē'=>'e', 64 | /** 65 | * Special characters: 66 | */ 67 | "'" => '', // Single quote 68 | '&' => ' and ', // Ampersand 69 | "\r\n" => ' ', // Newline 70 | "\n" => ' ' // Newline 71 | ) 72 | 73 | ); 74 | ``` 75 | 76 | Examples 77 | ================== 78 | 79 | ```PHP 80 | echo Safeurl::make('The quick brown fox jumps over the lazy dog', array('maxlength' => 18)); 81 | 82 | // Output: the-quick-brown 83 | // ** Notice output is only 15 characters event though we specified 18 because we don't want to truncate mid word ** 84 | ``` 85 | 86 | ```PHP 87 | echo Safeurl::make('The quick brown fox jumps over the lazy dog', array('maxlength' => 18, 'whole_word' => false)); 88 | 89 | // Output: the-quick-brown-fo 90 | // ** Notice output is now exactly 18 characters ** 91 | ``` 92 | 93 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jaybizzle/safeurl", 3 | "description": "A Laravel package to create safe, SEO friendly urls", 4 | "keywords": ["laravel","slug","SEO","url","string","safe","friendly_url"], 5 | "homepage": "http://github.com/JayBizzle/Safeurl", 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Mark Beech", 10 | "email": "mbeech@mark-beech.co.uk" 11 | } 12 | ], 13 | "require": { 14 | "php": ">=5.6", 15 | "illuminate/support": "~5.3|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", 16 | "illuminate/config": "~5.3|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0" 17 | }, 18 | "require-dev": { 19 | "orchestra/testbench": "^3.0|^4.0|^5.0|^6.0" 20 | }, 21 | "autoload": { 22 | "psr-4": { 23 | "Jaybizzle\\": "src/Jaybizzle" 24 | } 25 | }, 26 | "minimum-stability": "stable" 27 | } 28 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | ./tests/ 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /public/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JayBizzle/Safeurl/98a62eefe43aa4cdf73ec387634284988ea325fa/public/.gitkeep -------------------------------------------------------------------------------- /src/Jaybizzle/Safeurl/Facades/Safeurl.php: -------------------------------------------------------------------------------- 1 | $value) { 26 | $this->$property = $value; 27 | } 28 | } 29 | 30 | /** 31 | * the worker method. 32 | * 33 | * @param string $text 34 | * 35 | * @return string 36 | */ 37 | public function make($text, $options = null) 38 | { 39 | $this->setUserOptions($options); // set user defined options 40 | 41 | $text = $this->decode($text); // decode UTF-8 chars 42 | 43 | $text = trim($text); // trim 44 | 45 | $text = $this->lower($text); // convert to lowercase 46 | 47 | $text = $this->strip($text); // strip HTML 48 | 49 | $text = $this->filter($text); // filter the input 50 | 51 | //chop? 52 | if (strlen($text) > $this->maxlength) { 53 | $text = substr($text, 0, $this->maxlength); 54 | 55 | if ($this->whole_word) { 56 | /* 57 | * If maxlength is small and leaves us with only part of one 58 | * word ignore the "whole_word" filtering. 59 | */ 60 | $words = explode($this->separator, $text); 61 | $temp = implode($this->separator, array_diff($words, [array_pop($words)])); 62 | if ($temp != '') { 63 | $text = $temp; 64 | } 65 | } 66 | 67 | $text = rtrim($text, $this->separator); // remove any trailing separators 68 | } 69 | //return =] 70 | if ($text == '') { 71 | return $this->blank; 72 | } 73 | 74 | return $text; 75 | } 76 | 77 | /** 78 | * Set user defined options. 79 | * 80 | * @param array $options 81 | */ 82 | private function setUserOptions($options) 83 | { 84 | if (is_array($options)) { 85 | foreach ($options as $property => $value) { 86 | $this->$property = $value; 87 | } 88 | } 89 | } 90 | 91 | /** 92 | * Helper method that uses the translation table to convert 93 | * non-ascii characters to a resonalbe alternative. 94 | * 95 | * @param string $text 96 | * 97 | * @return string 98 | */ 99 | public function convertCharacters($text) 100 | { 101 | $text = html_entity_decode($text, ENT_QUOTES, $this->decode_charset); 102 | $text = strtr($text, $this->translation_table); 103 | 104 | return $text; 105 | } 106 | 107 | /** 108 | * Decode HTML entities and UTF-8 characters. 109 | * 110 | * @param string $text 111 | * 112 | * @return string 113 | */ 114 | private function decode($text) 115 | { 116 | return ($this->decode) ? $this->convertCharacters($text) : $text; 117 | } 118 | 119 | /** 120 | * Convert string to lowercase. 121 | * 122 | * @param string $text 123 | * 124 | * @return string 125 | */ 126 | private function lower($text) 127 | { 128 | return ($this->lowercase) ? strtolower($text) : $text; 129 | } 130 | 131 | /** 132 | * Strip HTML tages. 133 | * 134 | * @param string $text 135 | * 136 | * @return string 137 | */ 138 | private function strip($text) 139 | { 140 | return ($this->strip) ? strip_tags($text) : $text; 141 | } 142 | 143 | /** 144 | * Strip anything that isn't alphanumeric or an underscore. 145 | * 146 | * @param string $text 147 | * 148 | * @return string 149 | */ 150 | private function filter($text) 151 | { 152 | $text = preg_replace("/[^&a-z0-9-_\s']/i", '', $text); 153 | $text = str_replace(' ', $this->separator, $text); 154 | $text = trim(preg_replace("/{$this->separator}{2,}/", $this->separator, $text), $this->separator); 155 | 156 | return $text; 157 | } 158 | } 159 | 160 | /* 161 | * Thanks to timemachine3030 for the idea/implementation for this class. 162 | * https://github.com/timemachine3030 163 | */ 164 | -------------------------------------------------------------------------------- /src/Jaybizzle/Safeurl/SafeurlServiceProvider.php: -------------------------------------------------------------------------------- 1 | publishes([ 24 | __DIR__.'/../../config/config.php' => base_path('config/safeurl.php'), 25 | ]); 26 | 27 | $this->mergeConfigFrom(__DIR__.'/../../config/config.php', 'safeurl'); 28 | } 29 | 30 | /** 31 | * Register the service provider. 32 | * 33 | * @return void 34 | */ 35 | public function register() 36 | { 37 | $this->app->singleton('safeurl', function ($app) { 38 | return new Safeurl(); 39 | }); 40 | } 41 | 42 | /** 43 | * Get the services provided by the provider. 44 | * 45 | * @return array 46 | */ 47 | public function provides() 48 | { 49 | return []; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Mark Beech 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 | 23 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | Safeurl 2 | ======= 3 | 4 | A Laravel package to create safe, SEO friendly urls 5 | -------------------------------------------------------------------------------- /src/config/config.php: -------------------------------------------------------------------------------- 1 | true, 10 | 11 | /* 12 | * charset to use if $decode is set to true 13 | * @var string 14 | */ 15 | 'decode_charset' => 'UTF-8', 16 | 17 | /* 18 | * turns string into all lowercase letters 19 | * @var boolean 20 | */ 21 | 'lowercase' => true, 22 | 23 | /* 24 | * strip out html tags from string? 25 | * @var boolean 26 | */ 27 | 'strip' => true, 28 | 29 | /* 30 | * maximum length of resulting title 31 | * @var int 32 | */ 33 | 'maxlength' => 50, 34 | 35 | /* 36 | * if maxlength is reached, chop at nearest whole word? or hard chop? 37 | * @var boolean 38 | */ 39 | 'whole_word' => true, 40 | 41 | /* 42 | * what title to use if no alphanumeric characters can be found 43 | * @var string 44 | */ 45 | 'blank' => 'no-title', 46 | 47 | /* 48 | * Allow a differnt character to be used as the separator. 49 | * @var string 50 | */ 51 | 'separator' => '-', 52 | 53 | /* 54 | * A table of UTF-8 characters and what to make them. 55 | * @link http://www.php.net/manual/en/function.strtr.php#90925 56 | * @var array 57 | */ 58 | 'translation_table' => [ 59 | 'Š' => 'S', 'š' => 's', 'Đ' => 'Dj', 'Ð' => 'Dj', 'đ' => 'dj', 'Ž' => 'Z', 'ž' => 'z', 'Č' => 'C', 'č' => 'c', 'Ć' => 'C', 'ć' => 'c', 60 | 'À' => 'A', 'Á' => 'A', 'Â' => 'A', 'Ã' => 'A', 'Ä' => 'A', 'Å' => 'A', 'Æ' => 'A', 'Ç' => 'C', 'È' => 'E', 'É' => 'E', 61 | 'Ê' => 'E', 'Ë' => 'E', 'Ì' => 'I', 'Í' => 'I', 'Î' => 'I', 'Ï' => 'I', 'Ñ' => 'N', 'Ò' => 'O', 'Ó' => 'O', 'Ô' => 'O', 62 | 'Õ' => 'O', 'Ö' => 'O', 'Ø' => 'O', 'Ù' => 'U', 'Ú' => 'U', 'Û' => 'U', 'Ü' => 'U', 'Ý' => 'Y', 'Þ' => 'B', 'ß' => 'Ss', 63 | 'à' => 'a', 'á' => 'a', 'â' => 'a', 'ã' => 'a', 'ä' => 'a', 'å' => 'a', 'æ' => 'a', 'ç' => 'c', 'è' => 'e', 'é' => 'e', 64 | 'ê' => 'e', 'ë' => 'e', 'ì' => 'i', 'í' => 'i', 'î' => 'i', 'ï' => 'i', 'ð' => 'o', 'ñ' => 'n', 'ò' => 'o', 'ó' => 'o', 65 | 'ô' => 'o', 'õ' => 'o', 'ö' => 'o', 'ø' => 'o', 'ù' => 'u', 'ú' => 'u', 'û' => 'u', 'ý' => 'y', 'ý' => 'y', 'þ' => 'b', 66 | 'ÿ' => 'y', 'Ŕ' => 'R', 'ŕ' => 'r', 'ē' => 'e', 67 | /* 68 | * Special characters: 69 | */ 70 | "'" => '', // Single quote 71 | '&' => ' and ', // Amperstand 72 | "\r\n" => ' ', // Newline 73 | "\n" => ' ', // Newline 74 | 75 | ], 76 | 77 | ]; 78 | -------------------------------------------------------------------------------- /tests/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JayBizzle/Safeurl/98a62eefe43aa4cdf73ec387634284988ea325fa/tests/.gitkeep -------------------------------------------------------------------------------- /tests/QuickTest.php: -------------------------------------------------------------------------------- 1 | safeurl = new Safeurl(); 19 | } 20 | 21 | protected function getEnvironmentSetUp($app) 22 | { 23 | // reset base path to point to our package's src directory 24 | $app['path.base'] = __DIR__.'/../src'; 25 | } 26 | 27 | public function testBasicDefaultSetup() 28 | { 29 | $this->assertEquals('the-quick-brown-fox-jumps-over-the-lazy-dog', $this->safeurl->make('The quick brown fox jumps over the lazy dog')); 30 | } 31 | 32 | public function testCase() 33 | { 34 | $this->assertEquals('The-quick-brown-fox-jumps-over-the-lazy-dog', $this->safeurl->make('The quick brown fox jumps over the lazy dog', ['lowercase' => false])); 35 | } 36 | 37 | public function testSpecialChars() 38 | { 39 | $this->assertEquals('th-quck-brown-fox-jumps-over-the-lzy-dog', $this->safeurl->make('Th£ qu|ck brown fox jumps over the l@zy dog!!!*!@£$%^*()+')); 40 | } 41 | 42 | public function testHTML() 43 | { 44 | $this->assertEquals('the-quick-brown-fox-jumps-over-the-lazy-dog', $this->safeurl->make('The quick brown fox jumps over the lazy dog')); 45 | } 46 | 47 | public function testTruncateAtWholeWord() 48 | { 49 | $this->assertEquals('the-quick-brown', $this->safeurl->make('The quick brown fox jumps over the lazy dog', ['maxlength' => 18])); 50 | } 51 | 52 | public function testTruncateAtHardLimit() 53 | { 54 | $this->assertEquals('the-quick-brown-fo', $this->safeurl->make('The quick brown fox jumps over the lazy dog', ['maxlength' => 18, 'whole_word' => false])); 55 | } 56 | 57 | public function testTranslation() 58 | { 59 | // We are only testing UTF8 chars here, not the new lines and ampersands etc 60 | $default = config('safeurl'); 61 | 62 | $test = implode(' ', array_keys(array_slice($default['translation_table'], 0, -4))); 63 | $result = implode('-', array_slice($default['translation_table'], 0, -4)); 64 | 65 | $this->assertEquals(strtolower($result), $this->safeurl->make($test, ['maxlength' => 1000])); 66 | } 67 | 68 | public function testBigMess() 69 | { 70 | $big_mess = ' 71 |
  • \$safeurl = new safeurl();
  • \$safeurl->lowercase 74 | = false;
  • \$safeurl->whole_word = false;
  • 76 |
  •  
  • \$tests = array( 78 |
  •        \'i\span 80 | style=\"color: #ff0000;\">\'m a test string!! do u like me. or 81 | not......., billy bob!!@#\',
  •         \'some HTML in here!!~\' 84 | ,
  •       85 |   \'i!@#*#@ l#*(*(#**$*o**(*^v 86 | ^*(e d//////e\\ 87 | \\ 88 | \\\\v,,,,,,,,,,n% 90 | $#@!~e*(+=t\',
  • '; 91 | 92 | $this->assertEquals('safeurl-new-safeurl', $this->safeurl->make($big_mess, ['maxlength' => 20])); 93 | } 94 | 95 | public function testWholeWordWithOnlyOneWord() 96 | { 97 | $this->assertEquals('super', $this->safeurl->make('supercalafragalisticexpialadoshus', ['maxlength' => 5, 'whole_word' => true])); 98 | } 99 | 100 | public function testHtmlEntityDecode() 101 | { 102 | $safeString = $this->safeurl->make('The quick brown fox jumps over the lazy dog & cat', ['decode' => true, 'maxlength' => 500]); 103 | $this->assertEquals('the-quick-brown-fox-jumps-over-the-lazy-dog-and-cat', $safeString); 104 | } 105 | 106 | public function testStringWithNoAlphanumChars() 107 | { 108 | $safeString = $this->safeurl->make('!@£$%^*()+'); 109 | $this->assertEquals('no-title', $safeString); 110 | 111 | $safeString = $this->safeurl->make('!@£$%^*()+', ['blank' => null]); 112 | $this->assertEquals(null, $safeString); 113 | } 114 | } 115 | --------------------------------------------------------------------------------