| 1 | <?php |
|---|
| 2 | /** |
|---|
| 3 | * File containing the Inflector class |
|---|
| 4 | * |
|---|
| 5 | * (PHP 5) |
|---|
| 6 | * |
|---|
| 7 | * @package PHPonTrax |
|---|
| 8 | * @version $Id$ |
|---|
| 9 | * @copyright (c) 2005 John Peterson |
|---|
| 10 | * |
|---|
| 11 | * Permission is hereby granted, free of charge, to any person obtaining |
|---|
| 12 | * a copy of this software and associated documentation files (the |
|---|
| 13 | * "Software"), to deal in the Software without restriction, including |
|---|
| 14 | * without limitation the rights to use, copy, modify, merge, publish, |
|---|
| 15 | * distribute, sublicense, and/or sell copies of the Software, and to |
|---|
| 16 | * permit persons to whom the Software is furnished to do so, subject to |
|---|
| 17 | * the following conditions: |
|---|
| 18 | * |
|---|
| 19 | * The above copyright notice and this permission notice shall be |
|---|
| 20 | * included in all copies or substantial portions of the Software. |
|---|
| 21 | * |
|---|
| 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|---|
| 23 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|---|
| 24 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|---|
| 25 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
|---|
| 26 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
|---|
| 27 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
|---|
| 28 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|---|
| 29 | */ |
|---|
| 30 | |
|---|
| 31 | |
|---|
| 32 | include_once("inflections.php"); |
|---|
| 33 | |
|---|
| 34 | /** |
|---|
| 35 | * Implement the Trax naming convention |
|---|
| 36 | * |
|---|
| 37 | * This class provides static methods to implement the |
|---|
| 38 | * {@tutorial PHPonTrax/naming.pkg Trax naming convention}. |
|---|
| 39 | * Inflector is never instantiated. |
|---|
| 40 | * @tutorial PHPonTrax/Inflector.cls |
|---|
| 41 | */ |
|---|
| 42 | class Inflector { |
|---|
| 43 | |
|---|
| 44 | private static $cache = array( |
|---|
| 45 | 'plural' => array(), |
|---|
| 46 | 'singular' => array() |
|---|
| 47 | ); |
|---|
| 48 | |
|---|
| 49 | /** |
|---|
| 50 | * Pluralize a word according to English rules |
|---|
| 51 | * |
|---|
| 52 | * Convert a lower-case singular word to plural form. |
|---|
| 53 | * If $count > 0 then prefixes $word with the $count |
|---|
| 54 | * |
|---|
| 55 | * @param string $singular_word Word to be pluralized |
|---|
| 56 | * @param int $count How many of these $words are there |
|---|
| 57 | * @return string Plural of $singular_word |
|---|
| 58 | */ |
|---|
| 59 | function pluralize($singular_word, $count = 0, $plural_word = null) { |
|---|
| 60 | if($count != 1) { |
|---|
| 61 | if(is_null($plural_word)) { |
|---|
| 62 | $plural_word = $singular_word; |
|---|
| 63 | if(isset(self::$cache['plural'][$singular_word])) { |
|---|
| 64 | $plural_word = self::$cache['plural'][$singular_word]; |
|---|
| 65 | } elseif(!in_array($singular_word, Inflections::$uncountables)) { |
|---|
| 66 | foreach(Inflections::$plurals as $plural_rule) { |
|---|
| 67 | if(preg_match($plural_rule['rule'], $singular_word)) { |
|---|
| 68 | $plural_word = preg_replace($plural_rule['rule'], $plural_rule['replacement'], $plural_word); |
|---|
| 69 | self::$cache['plural'][$singular_word] = $plural_word; |
|---|
| 70 | break; |
|---|
| 71 | } |
|---|
| 72 | } |
|---|
| 73 | } |
|---|
| 74 | } |
|---|
| 75 | } else { |
|---|
| 76 | $plural_word = self::singularize($singular_word); |
|---|
| 77 | } |
|---|
| 78 | return $plural_word; |
|---|
| 79 | } |
|---|
| 80 | |
|---|
| 81 | /** |
|---|
| 82 | * Singularize a word according to English rules |
|---|
| 83 | * |
|---|
| 84 | * @param string $plural_word Word to be singularized |
|---|
| 85 | * @return string Singular of $plural_word |
|---|
| 86 | */ |
|---|
| 87 | function singularize($plural_word) { |
|---|
| 88 | $singular_word = $plural_word; |
|---|
| 89 | if(isset(self::$cache['singular'][$plural_word])) { |
|---|
| 90 | $singular_word = self::$cache['singular'][$plural_word]; |
|---|
| 91 | } elseif(!in_array($plural_word, Inflections::$uncountables)) { |
|---|
| 92 | foreach(Inflections::$singulars as $singular_rule) { |
|---|
| 93 | if(preg_match($singular_rule['rule'], $plural_word)) { |
|---|
| 94 | $singular_word = preg_replace($singular_rule['rule'], $singular_rule['replacement'], $singular_word); |
|---|
| 95 | self::$cache['singular'][$plural_word] = $singular_word; |
|---|
| 96 | break; |
|---|
| 97 | } |
|---|
| 98 | } |
|---|
| 99 | } |
|---|
| 100 | return $singular_word; |
|---|
| 101 | } |
|---|
| 102 | |
|---|
| 103 | /** |
|---|
| 104 | * Convert a phrase from the lower case and underscored form |
|---|
| 105 | * to the camel case form |
|---|
| 106 | * |
|---|
| 107 | * @param string $lower_case_and_underscored_word Phrase to |
|---|
| 108 | * convert |
|---|
| 109 | * @return string Camel case form of the phrase |
|---|
| 110 | */ |
|---|
| 111 | function camelize($lower_case_and_underscored_word) { |
|---|
| 112 | return str_replace(" ","",ucwords(str_replace("_"," ",$lower_case_and_underscored_word))); |
|---|
| 113 | } |
|---|
| 114 | |
|---|
| 115 | /** |
|---|
| 116 | * Convert a word or phrase into a title format "Welcome To My Site" |
|---|
| 117 | * |
|---|
| 118 | * @param string $word A word or phrase |
|---|
| 119 | * @return string A string that has all words capitalized and splits on existing caps. |
|---|
| 120 | */ |
|---|
| 121 | function titleize($word) { |
|---|
| 122 | return ucwords(self::humanize(self::underscore($word))); |
|---|
| 123 | } |
|---|
| 124 | |
|---|
| 125 | /** |
|---|
| 126 | * Convert a phrase from the camel case form to the lower case |
|---|
| 127 | * and underscored form |
|---|
| 128 | * |
|---|
| 129 | * Changes '::' to '/' to convert namespaces to paths. (php 5.3) |
|---|
| 130 | * |
|---|
| 131 | * Examples: |
|---|
| 132 | * Inflector::underscore("ActiveRecord") => "active_record" |
|---|
| 133 | * Inflector::underscore("ActiveRecord::Errors") => active_record/errors |
|---|
| 134 | * |
|---|
| 135 | * @param string $camel_cased_word Phrase to convert |
|---|
| 136 | * @return string Lower case and underscored form of the phrase |
|---|
| 137 | */ |
|---|
| 138 | function underscore($camel_cased_word) { |
|---|
| 139 | $camel_cased_word = str_replace('::','/',$camel_cased_word); |
|---|
| 140 | $camel_cased_word = preg_replace('/([A-Z]+)([A-Z])/','\1_\2',$camel_cased_word); |
|---|
| 141 | return strtolower(preg_replace('/([a-z\d])([A-Z])/','\1_\2',$camel_cased_word)); |
|---|
| 142 | } |
|---|
| 143 | |
|---|
| 144 | /** |
|---|
| 145 | * Convert a word's underscores into dashes |
|---|
| 146 | * |
|---|
| 147 | * @param string $underscored_word Word to convert |
|---|
| 148 | * @return string All underscores converted to dashes |
|---|
| 149 | */ |
|---|
| 150 | function dasherize($underscored_word) { |
|---|
| 151 | return str_replace('_', '-', self::underscore($underscored_word)); |
|---|
| 152 | } |
|---|
| 153 | |
|---|
| 154 | /** |
|---|
| 155 | * Generate a more human version of a lower case underscored word |
|---|
| 156 | * |
|---|
| 157 | * @param string $lower_case_and_underscored_word A word or phrase in |
|---|
| 158 | * lower_case_underscore form |
|---|
| 159 | * @return string The input value with underscores replaced by |
|---|
| 160 | * blanks and the first letter of each word capitalized |
|---|
| 161 | */ |
|---|
| 162 | function humanize($lower_case_and_underscored_word) { |
|---|
| 163 | if(count(Inflections::$humans) > 0) { |
|---|
| 164 | $original = $lower_case_and_underscored_word; |
|---|
| 165 | foreach(Inflections::$humans as $human_rule) { |
|---|
| 166 | $lower_case_and_underscored_word = preg_replace($human_rule['rule'], $human_rule['replacement'], $word); |
|---|
| 167 | if($original != $lower_case_and_underscored_word) break; |
|---|
| 168 | } |
|---|
| 169 | } |
|---|
| 170 | return self::capitalize(str_replace(array("_","_id"),array(" ",""),$lower_case_and_underscored_word)); |
|---|
| 171 | } |
|---|
| 172 | |
|---|
| 173 | /** |
|---|
| 174 | * Removes the module part from the expression in the string. (php 5.3) |
|---|
| 175 | * |
|---|
| 176 | * Examples: |
|---|
| 177 | * Inflector::demodulize("ActiveRecord::CoreExtensions::String::Inflections") => "Inflections" |
|---|
| 178 | * Inflector::demodulize("Inflections") => "Inflections" |
|---|
| 179 | * |
|---|
| 180 | */ |
|---|
| 181 | function demodulize($class_name_in_module) { |
|---|
| 182 | return preg_replace("/^.*::/", '', $class_name_in_module); |
|---|
| 183 | } |
|---|
| 184 | |
|---|
| 185 | /** |
|---|
| 186 | * Convert a class name to the corresponding table name |
|---|
| 187 | * |
|---|
| 188 | * The class name is a singular word or phrase in CamelCase. |
|---|
| 189 | * By convention it corresponds to a table whose name is a plural |
|---|
| 190 | * word or phrase in lower case underscore form. |
|---|
| 191 | * @param string $class_name Name of {@link ActiveRecord} sub-class |
|---|
| 192 | * @return string Pluralized lower_case_underscore form of name |
|---|
| 193 | */ |
|---|
| 194 | function tableize($class_name) { |
|---|
| 195 | return self::pluralize(self::underscore($class_name)); |
|---|
| 196 | } |
|---|
| 197 | |
|---|
| 198 | /** |
|---|
| 199 | * Convert a table name to the corresponding class name |
|---|
| 200 | * |
|---|
| 201 | * @param string $table_name Name of table in the database |
|---|
| 202 | * @return string Singular CamelCase form of $table_name |
|---|
| 203 | */ |
|---|
| 204 | function classify($table_name) { |
|---|
| 205 | return self::camelize(self::singularize($table_name)); |
|---|
| 206 | } |
|---|
| 207 | |
|---|
| 208 | /** |
|---|
| 209 | * Capitalize a word making it all lower case with first letter uppercase |
|---|
| 210 | * |
|---|
| 211 | * @param string $word Word to be capitalized |
|---|
| 212 | * @return string Capitalized $word |
|---|
| 213 | */ |
|---|
| 214 | function capitalize($word) { |
|---|
| 215 | return ucfirst(strtolower($word)); |
|---|
| 216 | } |
|---|
| 217 | |
|---|
| 218 | /** |
|---|
| 219 | * Get foreign key column corresponding to a table name |
|---|
| 220 | * |
|---|
| 221 | * @param string $table_name Name of table referenced by foreign key |
|---|
| 222 | * @return string Column name of the foreign key column |
|---|
| 223 | */ |
|---|
| 224 | function foreign_key($class_name) { |
|---|
| 225 | return self::underscore(self::demodulize($class_name)) . "_id"; |
|---|
| 226 | } |
|---|
| 227 | |
|---|
| 228 | |
|---|
| 229 | /** |
|---|
| 230 | * Add to a number st, nd, rd, th |
|---|
| 231 | * |
|---|
| 232 | * @param integer $number Number to append to key |
|---|
| 233 | * @return string Number formatted with correct st, nd, rd, or th |
|---|
| 234 | */ |
|---|
| 235 | function ordinalize($number) { |
|---|
| 236 | $number = intval($number); |
|---|
| 237 | if(in_array(($number % 100), range(11, 13))) { |
|---|
| 238 | $number = "{$number}th"; |
|---|
| 239 | } else { |
|---|
| 240 | switch(($number % 10)) { |
|---|
| 241 | case 1: |
|---|
| 242 | $number = "{$number}st"; |
|---|
| 243 | break; |
|---|
| 244 | case 2: |
|---|
| 245 | $number = "{$number}nd"; |
|---|
| 246 | break; |
|---|
| 247 | case 3: |
|---|
| 248 | $number = "{$number}rd"; |
|---|
| 249 | break; |
|---|
| 250 | default: |
|---|
| 251 | $number = "{$number}th"; |
|---|
| 252 | } |
|---|
| 253 | } |
|---|
| 254 | return $number; |
|---|
| 255 | } |
|---|
| 256 | |
|---|
| 257 | /** |
|---|
| 258 | * Clears the cached words for pluralize and singularize |
|---|
| 259 | * |
|---|
| 260 | * @param none |
|---|
| 261 | * @return nothing |
|---|
| 262 | */ |
|---|
| 263 | function clear_cache() { |
|---|
| 264 | self::$cache = array( |
|---|
| 265 | 'plural' => array(), |
|---|
| 266 | 'singular' => array() |
|---|
| 267 | ); |
|---|
| 268 | } |
|---|
| 269 | |
|---|
| 270 | } |
|---|
| 271 | |
|---|
| 272 | |
|---|
| 273 | ?> |
|---|