|
| 1 | +<?php |
| 2 | + |
| 3 | +namespace DevCoding\Object\Type; |
| 4 | + |
| 5 | +use DevCoding\Helper\StringHelper; |
| 6 | + |
| 7 | +/** |
| 8 | + * Object representing a string, which can be used as a string in most instances. Contains convenient methods for |
| 9 | + * modifying the string before output. |
| 10 | + * |
| 11 | + * @author AMJones <am@jonesiscoding.com> |
| 12 | + * @license https://github.com/deviscoding/objection/blob/main/LICENSE |
| 13 | + * @package DevCoding\Object\Type |
| 14 | + */ |
| 15 | +class StringLiteral |
| 16 | +{ |
| 17 | + /** @var string */ |
| 18 | + private $value; |
| 19 | + |
| 20 | + public function __construct(string $value) |
| 21 | + { |
| 22 | + $this->value = $value; |
| 23 | + } |
| 24 | + |
| 25 | + // region //////////////////////////////////////////////// Value Object Methods |
| 26 | + |
| 27 | + /** |
| 28 | + * @return string |
| 29 | + */ |
| 30 | + public function __toString(): string |
| 31 | + { |
| 32 | + return $this->toNative(); |
| 33 | + } |
| 34 | + |
| 35 | + /** |
| 36 | + * Determines if the given value is the equivalent of the given string. |
| 37 | + * |
| 38 | + * @param mixed $value |
| 39 | + */ |
| 40 | + public function equals($value): bool |
| 41 | + { |
| 42 | + if ($value instanceof StringLiteral) |
| 43 | + { |
| 44 | + $string = $value->toNative(); |
| 45 | + } |
| 46 | + elseif (StringHelper::get()->isStringable($value)) |
| 47 | + { |
| 48 | + $string = (string) $value; |
| 49 | + } |
| 50 | + |
| 51 | + return isset($string) && $string == $this->toNative(); |
| 52 | + } |
| 53 | + |
| 54 | + /** |
| 55 | + * Returns a StringLiteral object from the given value. |
| 56 | + * |
| 57 | + * @param string $val |
| 58 | + */ |
| 59 | + public static function fromNative($val): StringLiteral |
| 60 | + { |
| 61 | + return new static($val); |
| 62 | + } |
| 63 | + |
| 64 | + /** |
| 65 | + * Returns a StringLiteral generated with "random" characters. |
| 66 | + * |
| 67 | + * @param int $length |
| 68 | + * |
| 69 | + * @throws \Exception if length is over 32 characters |
| 70 | + */ |
| 71 | + public static function fromRandom($length): StringLiteral |
| 72 | + { |
| 73 | + if ($length > 32) |
| 74 | + { |
| 75 | + throw new \Exception('Max length of random string is 32.'); |
| 76 | + } |
| 77 | + |
| 78 | + $string = substr(md5(rand(100000, 999999)), 0, $length); |
| 79 | + |
| 80 | + return new static($string); |
| 81 | + } |
| 82 | + |
| 83 | + /** |
| 84 | + * @return string |
| 85 | + */ |
| 86 | + public function toNative() |
| 87 | + { |
| 88 | + return $this->value; |
| 89 | + } |
| 90 | + |
| 91 | + // endregion ///////////////////////////////////////////// End Value Object Methods |
| 92 | + |
| 93 | + // region //////////////////////////////////////////////// Other Public Methods |
| 94 | + |
| 95 | + /** |
| 96 | + * Converts this string into a CSS safe string that may be used for CSS class names or HTML5 IDs. |
| 97 | + * |
| 98 | + * @param string $sep The separator to use. Defaults to - |
| 99 | + * @param bool $spaces Allow spaces in the result. Defaults to FALSE |
| 100 | + * @param bool $force_lowercase Force the result to lowercase. Defaults to FALSE |
| 101 | + * |
| 102 | + * @return string|string[]|null |
| 103 | + * |
| 104 | + * @throws \Exception |
| 105 | + */ |
| 106 | + public function css($sep = '-', $spaces = false, $force_lowercase = false) |
| 107 | + { |
| 108 | + // Replace all accent characters with their non-accented equivalents. |
| 109 | + $string = $this->transliterate(); |
| 110 | + |
| 111 | + // Replace Spaces |
| 112 | + $add = ($spaces) ? ['\s', preg_quote($sep, '/')] : [null, preg_quote($sep, '/')]; |
| 113 | + $regex = vsprintf('/([^a-zA-Z0-9_%s%s]+)/', $add); |
| 114 | + $string = preg_replace($regex, $sep, $string); |
| 115 | + |
| 116 | + // Force Lowercase |
| 117 | + if ($force_lowercase) |
| 118 | + { |
| 119 | + $string = strtolower($string); |
| 120 | + } |
| 121 | + |
| 122 | + // Make sure first character is NOT a number. |
| 123 | + if (is_numeric(substr($string, 0, 1))) |
| 124 | + { |
| 125 | + $digits = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine']; |
| 126 | + $string = $digits[substr($string, 0, 1)].substr($string, 1); |
| 127 | + } |
| 128 | + |
| 129 | + return $string; |
| 130 | + } |
| 131 | + |
| 132 | + /** |
| 133 | + * Converts this string into the proper format for a PHP class name. IE- Converts 'table name' to 'TableName'. |
| 134 | + * |
| 135 | + * @param bool $transliterate whether to replace non-ASCII characters with non-accented equivalents where possible |
| 136 | + * |
| 137 | + * @return string |
| 138 | + * |
| 139 | + * @author Jonathan H. Wage <jonwage@gmail.com> (Borrowed from Doctrine Inflector) |
| 140 | + */ |
| 141 | + public function classify($transliterate = true) |
| 142 | + { |
| 143 | + $word = ($transliterate) ? $this->transliterate() : $this->toNative(); |
| 144 | + |
| 145 | + return str_replace([' ', '_', '-'], '', ucwords($word, ' _-')); |
| 146 | + } |
| 147 | + |
| 148 | + /** |
| 149 | + * Converts this string into camelCase. IE- Converts 'table name' to 'tableName'. |
| 150 | + * |
| 151 | + * @param bool $transliterate |
| 152 | + * |
| 153 | + * @author Jonathan H. Wage <jonwage@gmail.com> (Borrowed from Doctrine Inflector) |
| 154 | + * |
| 155 | + * @return string |
| 156 | + */ |
| 157 | + public function camelize($transliterate = true) |
| 158 | + { |
| 159 | + return lcfirst($this->classify($transliterate)); |
| 160 | + } |
| 161 | + |
| 162 | + /** |
| 163 | + * Creates a "slug" from this string by optionally any non ASCII characters, then replacing all the spacing |
| 164 | + * characters with a separator, converting the string to lower case, and removing any non-alphanumeric characters. |
| 165 | + * |
| 166 | + * @param string $sep the separator to use, a dash by default |
| 167 | + * @param bool $transliterate Whether to replace non-ASCII accented characters with non-accented equivalents. |
| 168 | + * If this option is FALSE, all non-ASCII characters are simply removed. |
| 169 | + * |
| 170 | + * @return string |
| 171 | + * |
| 172 | + * @throws \Exception |
| 173 | + */ |
| 174 | + public function slugify($sep = '-', $transliterate = true) |
| 175 | + { |
| 176 | + $string = ($transliterate) ? $this->transliterate() : $this->toNative(); |
| 177 | + |
| 178 | + return strtolower(trim(preg_replace('~[^0-9a-z]+~i', $sep, $string))); |
| 179 | + } |
| 180 | + |
| 181 | + /** |
| 182 | + * Removes and replaces accent characters, using the transliterator_transliterate function if possible. |
| 183 | + * |
| 184 | + * @return string the transliterated word or phrase |
| 185 | + */ |
| 186 | + public function transliterate() |
| 187 | + { |
| 188 | + try |
| 189 | + { |
| 190 | + if (function_exists('transliterator_transliterate')) |
| 191 | + { |
| 192 | + /* @noinspection PhpComposerExtensionStubsInspection */ |
| 193 | + return transliterator_transliterate('Any-Latin; Latin-ASCII', $this->toNative()); |
| 194 | + } |
| 195 | + } |
| 196 | + catch (\Exception $e) |
| 197 | + { |
| 198 | + // Proceed with the transliteration using the array of regex patterns and replacements below. |
| 199 | + } |
| 200 | + |
| 201 | + $string = $this->toNative(); |
| 202 | + $transliterations = [ |
| 203 | + // Alphabetical |
| 204 | + '/À/' => 'A', '/Á/' => 'A', '/Â/' => 'A', '/Ã/' => 'A', '/Ä/' => 'Ae', |
| 205 | + '/Å/' => 'A', '/Ā/' => 'A', '/Ą/' => 'A', '/Ă/' => 'A', '/Æ/' => 'Ae', |
| 206 | + '/Ç/' => 'C', '/Ć/' => 'C', '/Č/' => 'C', '/Ĉ/' => 'C', '/Ċ/' => 'C', |
| 207 | + '/Ď/' => 'D', '/Đ/' => 'D', '/Ð/' => 'D', '/È/' => 'E', '/É/' => 'E', |
| 208 | + '/Ê/' => 'E', '/Ë/' => 'E', '/Ē/' => 'E', '/Ę/' => 'E', '/Ě/' => 'E', |
| 209 | + '/Ĕ/' => 'E', '/Ė/' => 'E', '/Ĝ/' => 'G', '/Ğ/' => 'G', '/Ġ/' => 'G', |
| 210 | + '/Ģ/' => 'G', '/Ĥ/' => 'H', '/Ħ/' => 'H', '/Ì/' => 'I', '/Í/' => 'I', |
| 211 | + '/Î/' => 'I', '/Ï/' => 'I', '/Ī/' => 'I', '/Ĩ/' => 'I', '/Ĭ/' => 'I', |
| 212 | + '/Į/' => 'I', '/İ/' => 'I', '/IJ/' => 'Ij', '/Ĵ/' => 'J', '/Ķ/' => 'K', |
| 213 | + '/Ł/' => 'L', '/Ľ/' => 'L', '/Ĺ/' => 'L', '/Ļ/' => 'L', '/Ŀ/' => 'L', |
| 214 | + '/Ñ/' => 'N', '/Ń/' => 'N', '/Ň/' => 'N', '/Ņ/' => 'N', '/Ŋ/' => 'N', |
| 215 | + '/Ò/' => 'O', '/Ó/' => 'O', '/Ô/' => 'O', '/Õ/' => 'O', '/Ö/' => 'Oe', |
| 216 | + '/Ø/' => 'O', '/Ō/' => 'O', '/Ő/' => 'O', '/Ŏ/' => 'O', '/Œ/' => 'Oe', |
| 217 | + '/Ŕ/' => 'R', '/Ř/' => 'R', '/Ŗ/' => 'R', '/Ś/' => 'S', '/Š/' => 'S', |
| 218 | + '/Ş/' => 'S', '/Ŝ/' => 'S', '/Ș/' => 'S', '/Ť/' => 'T', '/Ţ/' => 'T', |
| 219 | + '/Ŧ/' => 'T', '/Ț/' => 'T', '/Ù/' => 'U', '/Ú/' => 'U', '/Û/' => 'U', |
| 220 | + '/Ü/' => 'Ue', '/Ū/' => 'U', '/Ů/' => 'U', '/Ű/' => 'U', '/Ŭ/' => 'U', |
| 221 | + '/Ũ/' => 'U', '/Ų/' => 'U', '/Ŵ/' => 'W', '/Ý/' => 'Y', '/Ŷ/' => 'Y', |
| 222 | + '/Ÿ/' => 'Y', '/Y/' => 'Y', '/Ź/' => 'Z', '/Ž/' => 'Z', '/Ż/' => 'Z', |
| 223 | + '/Þ/' => 'T', |
| 224 | + '/à/' => 'a', '/á/' => 'a', '/â/' => 'a', '/ã/' => 'a', '/ä/' => 'ae', |
| 225 | + '/å/' => 'a', '/ā/' => 'a', '/ą/' => 'a', '/ă/' => 'a', '/æ/' => 'ae', |
| 226 | + '/ç/' => 'c', '/ć/' => 'c', '/č/' => 'c', '/ĉ/' => 'c', '/ċ/' => 'c', |
| 227 | + '/ď/' => 'd', '/đ/' => 'd', '/ð/' => 'd', '/è/' => 'e', '/é/' => 'e', |
| 228 | + '/ê/' => 'e', '/ë/' => 'e', '/ē/' => 'e', '/ę/' => 'e', '/ě/' => 'e', |
| 229 | + '/ĕ/' => 'e', '/ė/' => 'e', '/ĝ/' => 'g', '/ğ/' => 'g', '/ġ/' => 'g', |
| 230 | + '/ģ/' => 'g', '/ĥ/' => 'h', '/ħ/' => 'h', '/ì/' => 'i', '/í/' => 'i', |
| 231 | + '/î/' => 'i', '/ï/' => 'i', '/ī/' => 'i', '/ĩ/' => 'i', '/ĭ/' => 'i', |
| 232 | + '/į/' => 'i', '/ı/' => 'i', '/ij/' => 'ij', '/ĵ/' => 'j', '/ķ/' => 'k', |
| 233 | + '/ł/' => 'l', '/ľ/' => 'l', '/ĺ/' => 'l', '/ļ/' => 'l', '/ŀ/' => 'l', |
| 234 | + '/ñ/' => 'n', '/ń/' => 'n', '/ň/' => 'n', '/ņ/' => 'n', '/ŋ/' => 'n', |
| 235 | + '/ò/' => 'o', '/ó/' => 'o', '/ô/' => 'o', '/õ/' => 'o', '/ö/' => 'oe', |
| 236 | + '/ø/' => 'o', '/ō/' => 'o', '/ő/' => 'o', '/ŏ/' => 'o', '/œ/' => 'oe', |
| 237 | + '/ŕ/' => 'r', '/ř/' => 'r', '/ŗ/' => 'r', '/ś/' => 's', '/š/' => 's', |
| 238 | + '/ş/' => 's', '/ŝ/' => 's', '/ș/' => 's', '/ť/' => 't', '/ţ/' => 't', |
| 239 | + '/ŧ/' => 't', '/ț/' => 't', '/ù/' => 'u', '/ú/' => 'u', '/û/' => 'u', |
| 240 | + '/ü/' => 'ue', '/ū/' => 'u', '/ů/' => 'u', '/ű/' => 'u', '/ŭ/' => 'u', |
| 241 | + '/ũ/' => 'u', '/ų/' => 'u', '/ŵ/' => 'w', '/ý/' => 'y', '/ŷ/' => 'y', |
| 242 | + '/ÿ/' => 'y', '/y/' => 'y', '/ź/' => 'z', '/ž/' => 'z', '/ż/' => 'z', |
| 243 | + '/þ/' => 't', '/ß/' => 'ss', '/ſ/' => 'ss', '/ƒ/' => 'f', '/ĸ/' => 'k', |
| 244 | + '/ʼn/' => 'n', ]; |
| 245 | + |
| 246 | + foreach ($transliterations as $key => $value) |
| 247 | + { |
| 248 | + $string = preg_replace($key, $value, $string); |
| 249 | + } |
| 250 | + |
| 251 | + return $string; |
| 252 | + } |
| 253 | + |
| 254 | + // endregion ///////////////////////////////////////////// End Other Public Methods |
| 255 | +} |
0 commit comments