Inflector.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. <?php
  2. /**
  3. * Inflector helper class. Inflection is changing the form of a word based on
  4. * the context it is used in. For example, changing a word into a plural form.
  5. *
  6. * [!!] Inflection is only tested with English, and is will not work with other languages.
  7. *
  8. * @package KO7
  9. * @category Helpers
  10. *
  11. * @copyright (c) 2007-2016 Kohana Team
  12. * @copyright (c) since 2016 Koseven Team
  13. * @license https://koseven.dev/LICENSE
  14. */
  15. class KO7_Inflector {
  16. /**
  17. * @var array cached inflections
  18. */
  19. protected static $cache = [];
  20. /**
  21. * @var array uncountable words
  22. */
  23. protected static $uncountable;
  24. /**
  25. * @var array irregular words
  26. */
  27. protected static $irregular;
  28. /**
  29. * Checks if a word is defined as uncountable. An uncountable word has a
  30. * single form. For instance, one "fish" and many "fish", not "fishes".
  31. *
  32. * Inflector::uncountable('fish'); // TRUE
  33. * Inflector::uncountable('cat'); // FALSE
  34. *
  35. * If you find a word is being pluralized improperly, it has probably not
  36. * been defined as uncountable in `config/inflector.php`. If this is the
  37. * case, please report [an issue](http://koseven.dev/projects/KO7/issues).
  38. *
  39. * @param string $str word to check
  40. * @return boolean
  41. */
  42. public static function uncountable($str)
  43. {
  44. if (Inflector::$uncountable === NULL)
  45. {
  46. // Cache uncountables
  47. Inflector::$uncountable = KO7::$config->load('inflector')->uncountable;
  48. // Make uncountables mirrored
  49. Inflector::$uncountable = array_combine(Inflector::$uncountable, Inflector::$uncountable);
  50. }
  51. return isset(Inflector::$uncountable[strtolower($str)]);
  52. }
  53. /**
  54. * Makes a plural word singular.
  55. *
  56. * echo Inflector::singular('cats'); // "cat"
  57. * echo Inflector::singular('fish'); // "fish", uncountable
  58. *
  59. * You can also provide the count to make inflection more intelligent.
  60. * In this case, it will only return the singular value if the count is
  61. * greater than one and not zero.
  62. *
  63. * echo Inflector::singular('cats', 2); // "cats"
  64. *
  65. * [!!] Special inflections are defined in `config/inflector.php`.
  66. *
  67. * @param string $str word to make singular
  68. * @param integer $count count of thing
  69. * @return string
  70. * @uses Inflector::uncountable
  71. */
  72. public static function singular($str, $count = NULL)
  73. {
  74. // $count should always be a float
  75. $count = ($count === NULL) ? 1.0 : (float) $count;
  76. // Do nothing when $count is not 1
  77. if ($count != 1)
  78. return $str;
  79. // Remove garbage
  80. $str = strtolower(trim($str));
  81. // Cache key name
  82. $key = 'singular_'.$str.$count;
  83. if (isset(Inflector::$cache[$key]))
  84. return Inflector::$cache[$key];
  85. if (Inflector::uncountable($str))
  86. return Inflector::$cache[$key] = $str;
  87. if (empty(Inflector::$irregular))
  88. {
  89. // Cache irregular words
  90. Inflector::$irregular = KO7::$config->load('inflector')->irregular;
  91. }
  92. if ($irregular = array_search($str, Inflector::$irregular))
  93. {
  94. $str = $irregular;
  95. }
  96. elseif (preg_match('/us$/', $str))
  97. {
  98. // http://en.wikipedia.org/wiki/Plural_form_of_words_ending_in_-us
  99. // Already singular, do nothing
  100. }
  101. elseif (preg_match('/[sxz]es$/', $str) OR preg_match('/[^aeioudgkprt]hes$/', $str))
  102. {
  103. // Remove "es"
  104. $str = substr($str, 0, -2);
  105. }
  106. elseif (preg_match('/[^aeiou]ies$/', $str))
  107. {
  108. // Replace "ies" with "y"
  109. $str = substr($str, 0, -3).'y';
  110. }
  111. elseif (substr($str, -1) === 's' AND substr($str, -2) !== 'ss')
  112. {
  113. // Remove singular "s"
  114. $str = substr($str, 0, -1);
  115. }
  116. return Inflector::$cache[$key] = $str;
  117. }
  118. /**
  119. * Makes a singular word plural.
  120. *
  121. * echo Inflector::plural('fish'); // "fish", uncountable
  122. * echo Inflector::plural('cat'); // "cats"
  123. *
  124. * You can also provide the count to make inflection more intelligent.
  125. * In this case, it will only return the plural value if the count is
  126. * not one.
  127. *
  128. * echo Inflector::singular('cats', 3); // "cats"
  129. *
  130. * [!!] Special inflections are defined in `config/inflector.php`.
  131. *
  132. * @param string $str word to pluralize
  133. * @param integer $count count of thing
  134. * @return string
  135. * @uses Inflector::uncountable
  136. */
  137. public static function plural($str, $count = NULL)
  138. {
  139. // $count should always be a float
  140. $count = ($count === NULL) ? 0.0 : (float) $count;
  141. // Do nothing with singular
  142. if ($count == 1)
  143. return $str;
  144. // Remove garbage
  145. $str = trim($str);
  146. // Cache key name
  147. $key = 'plural_'.$str.$count;
  148. // Check uppercase
  149. $is_uppercase = ctype_upper($str);
  150. if (isset(Inflector::$cache[$key]))
  151. return Inflector::$cache[$key];
  152. if (Inflector::uncountable($str))
  153. return Inflector::$cache[$key] = $str;
  154. if (empty(Inflector::$irregular))
  155. {
  156. // Cache irregular words
  157. Inflector::$irregular = KO7::$config->load('inflector')->irregular;
  158. }
  159. if (isset(Inflector::$irregular[$str]))
  160. {
  161. $str = Inflector::$irregular[$str];
  162. }
  163. elseif (in_array($str, Inflector::$irregular))
  164. {
  165. // Do nothing
  166. }
  167. elseif (preg_match('/[sxz]$/', $str) OR preg_match('/[^aeioudgkprt]h$/', $str))
  168. {
  169. $str .= 'es';
  170. }
  171. elseif (preg_match('/[^aeiou]y$/', $str))
  172. {
  173. // Change "y" to "ies"
  174. $str = substr_replace($str, 'ies', -1);
  175. }
  176. else
  177. {
  178. $str .= 's';
  179. }
  180. // Convert to uppercase if necessary
  181. if ($is_uppercase)
  182. {
  183. $str = strtoupper($str);
  184. }
  185. // Set the cache and return
  186. return Inflector::$cache[$key] = $str;
  187. }
  188. /**
  189. * Makes a phrase camel case. Spaces and underscores will be removed.
  190. *
  191. * $str = Inflector::camelize('mother cat'); // "motherCat"
  192. * $str = Inflector::camelize('kittens in bed'); // "kittensInBed"
  193. *
  194. * @param string $str phrase to camelize
  195. * @return string
  196. */
  197. public static function camelize($str)
  198. {
  199. $str = 'x'.strtolower(trim($str));
  200. $str = ucwords(preg_replace('/[\s_]+/', ' ', $str));
  201. return substr(str_replace(' ', '', $str), 1);
  202. }
  203. /**
  204. * Converts a camel case phrase into a spaced phrase.
  205. *
  206. * $str = Inflector::decamelize('houseCat'); // "house cat"
  207. * $str = Inflector::decamelize('kingAllyCat'); // "king ally cat"
  208. *
  209. * @param string $str phrase to camelize
  210. * @param string $sep word separator
  211. * @return string
  212. */
  213. public static function decamelize($str, $sep = ' ')
  214. {
  215. return strtolower(preg_replace('/([a-z])([A-Z])/', '$1'.$sep.'$2', trim($str)));
  216. }
  217. /**
  218. * Makes a phrase underscored instead of spaced.
  219. *
  220. * $str = Inflector::underscore('five cats'); // "five_cats";
  221. *
  222. * @param string $str phrase to underscore
  223. * @return string
  224. */
  225. public static function underscore($str)
  226. {
  227. return preg_replace('/\s+/', '_', trim($str));
  228. }
  229. /**
  230. * Makes an underscored or dashed phrase human-readable.
  231. *
  232. * $str = Inflector::humanize('kittens-are-cats'); // "kittens are cats"
  233. * $str = Inflector::humanize('dogs_as_well'); // "dogs as well"
  234. *
  235. * @param string $str phrase to make human-readable
  236. * @return string
  237. */
  238. public static function humanize($str)
  239. {
  240. return preg_replace('/[_-]+/', ' ', trim($str));
  241. }
  242. }