Utils.php 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. <?php
  2. /**
  3. *
  4. * @package ActiveRecord
  5. */
  6. /*
  7. * Thanks to http://www.eval.ca/articles/php-pluralize (MIT license)
  8. * http://dev.rubyonrails.org/browser/trunk/activesupport/lib/active_support/inflections.rb (MIT license)
  9. * http://www.fortunecity.com/bally/durrus/153/gramch13.html
  10. * http://www2.gsu.edu/~wwwesl/egw/crump.htm
  11. *
  12. * Changes (12/17/07)
  13. * Major changes
  14. * --
  15. * Fixed irregular noun algorithm to use regular expressions just like the original Ruby source.
  16. * (this allows for things like fireman -> firemen
  17. * Fixed the order of the singular array, which was backwards.
  18. *
  19. * Minor changes
  20. * --
  21. * Removed incorrect pluralization rule for /([^aeiouy]|qu)ies$/ => $1y
  22. * Expanded on the list of exceptions for *o -> *oes, and removed rule for buffalo -> buffaloes
  23. * Removed dangerous singularization rule for /([^f])ves$/ => $1fe
  24. * Added more specific rules for singularizing lives, wives, knives, sheaves, loaves, and leaves and thieves
  25. * Added exception to /(us)es$/ => $1 rule for houses => house and blouses => blouse
  26. * Added excpetions for feet, geese and teeth
  27. * Added rule for deer -> deer
  28. *
  29. * Changes:
  30. * Removed rule for virus -> viri
  31. * Added rule for potato -> potatoes
  32. * Added rule for *us -> *uses
  33. */
  34. namespace ActiveRecord;
  35. use \Closure;
  36. function classify($class_name, $singularize=false)
  37. {
  38. if ($singularize)
  39. $class_name = Utils::singularize($class_name);
  40. $class_name = Inflector::instance()->camelize($class_name);
  41. return ucfirst($class_name);
  42. }
  43. // http://snippets.dzone.com/posts/show/4660
  44. function array_flatten(array $array)
  45. {
  46. $i = 0;
  47. while ($i < count($array))
  48. {
  49. if (is_array($array[$i]))
  50. array_splice($array,$i,1,$array[$i]);
  51. else
  52. ++$i;
  53. }
  54. return $array;
  55. }
  56. /**
  57. * Somewhat naive way to determine if an array is a hash.
  58. */
  59. function is_hash(&$array)
  60. {
  61. if (!is_array($array))
  62. return false;
  63. $keys = array_keys($array);
  64. return @is_string($keys[0]) ? true : false;
  65. }
  66. /**
  67. * Strips a class name of any namespaces and namespace operator.
  68. *
  69. * @param string $class
  70. * @return string stripped class name
  71. * @access public
  72. */
  73. function denamespace($class_name)
  74. {
  75. if (is_object($class_name))
  76. $class_name = get_class($class_name);
  77. if (has_namespace($class_name))
  78. {
  79. $parts = explode('\\', $class_name);
  80. return end($parts);
  81. }
  82. return $class_name;
  83. }
  84. function get_namespaces($class_name)
  85. {
  86. if (has_namespace($class_name))
  87. return explode('\\', $class_name);
  88. return null;
  89. }
  90. function has_namespace($class_name)
  91. {
  92. if (strpos($class_name, '\\') !== false)
  93. return true;
  94. return false;
  95. }
  96. /**
  97. * Returns true if all values in $haystack === $needle
  98. * @param $needle
  99. * @param $haystack
  100. * @return unknown_type
  101. */
  102. function all($needle, array $haystack)
  103. {
  104. foreach ($haystack as $value)
  105. {
  106. if ($value !== $needle)
  107. return false;
  108. }
  109. return true;
  110. }
  111. function collect(&$enumerable, $name_or_closure)
  112. {
  113. $ret = array();
  114. foreach ($enumerable as $value)
  115. {
  116. if (is_string($name_or_closure))
  117. $ret[] = is_array($value) ? $value[$name_or_closure] : $value->$name_or_closure;
  118. elseif ($name_or_closure instanceof Closure)
  119. $ret[] = $name_or_closure($value);
  120. }
  121. return $ret;
  122. }
  123. /**
  124. * Wrap string definitions (if any) into arrays.
  125. */
  126. function wrap_strings_in_arrays(&$strings)
  127. {
  128. if (!is_array($strings))
  129. $strings = array(array($strings));
  130. else
  131. {
  132. foreach ($strings as &$str)
  133. {
  134. if (!is_array($str))
  135. $str = array($str);
  136. }
  137. }
  138. return $strings;
  139. }
  140. /**
  141. * Some internal utility functions.
  142. *
  143. * @package ActiveRecord
  144. */
  145. class Utils
  146. {
  147. public static function extract_options($options)
  148. {
  149. return is_array(end($options)) ? end($options) : array();
  150. }
  151. public static function add_condition(&$conditions=array(), $condition, $conjuction='AND')
  152. {
  153. if (is_array($condition))
  154. {
  155. if (empty($conditions))
  156. $conditions = array_flatten($condition);
  157. else
  158. {
  159. $conditions[0] .= " $conjuction " . array_shift($condition);
  160. $conditions[] = array_flatten($condition);
  161. }
  162. }
  163. elseif (is_string($condition))
  164. $conditions[0] .= " $conjuction $condition";
  165. return $conditions;
  166. }
  167. public static function human_attribute($attr)
  168. {
  169. $inflector = Inflector::instance();
  170. $inflected = $inflector->variablize($attr);
  171. $normal = $inflector->uncamelize($inflected);
  172. return ucfirst(str_replace('_', ' ', $normal));
  173. }
  174. public static function is_odd($number)
  175. {
  176. return $number & 1;
  177. }
  178. public static function is_a($type, $var)
  179. {
  180. switch($type)
  181. {
  182. case 'range':
  183. if (is_array($var) && (int)$var[0] < (int)$var[1])
  184. return true;
  185. }
  186. return false;
  187. }
  188. public static function is_blank($var)
  189. {
  190. return 0 === strlen($var);
  191. }
  192. private static $plural = array(
  193. '/(quiz)$/i' => "$1zes",
  194. '/^(ox)$/i' => "$1en",
  195. '/([m|l])ouse$/i' => "$1ice",
  196. '/(matr|vert|ind)ix|ex$/i' => "$1ices",
  197. '/(x|ch|ss|sh)$/i' => "$1es",
  198. '/([^aeiouy]|qu)y$/i' => "$1ies",
  199. '/(hive)$/i' => "$1s",
  200. '/(?:([^f])fe|([lr])f)$/i' => "$1$2ves",
  201. '/(shea|lea|loa|thie)f$/i' => "$1ves",
  202. '/sis$/i' => "ses",
  203. '/([ti])um$/i' => "$1a",
  204. '/(tomat|potat|ech|her|vet)o$/i'=> "$1oes",
  205. '/(bu)s$/i' => "$1ses",
  206. '/(alias)$/i' => "$1es",
  207. '/(octop)us$/i' => "$1i",
  208. '/(ax|test)is$/i' => "$1es",
  209. '/(us)$/i' => "$1es",
  210. '/s$/i' => "s",
  211. '/$/' => "s"
  212. );
  213. private static $singular = array(
  214. '/(quiz)zes$/i' => "$1",
  215. '/(matr)ices$/i' => "$1ix",
  216. '/(vert|ind)ices$/i' => "$1ex",
  217. '/^(ox)en$/i' => "$1",
  218. '/(alias)es$/i' => "$1",
  219. '/(octop|vir)i$/i' => "$1us",
  220. '/(cris|ax|test)es$/i' => "$1is",
  221. '/(shoe)s$/i' => "$1",
  222. '/(o)es$/i' => "$1",
  223. '/(bus)es$/i' => "$1",
  224. '/([m|l])ice$/i' => "$1ouse",
  225. '/(x|ch|ss|sh)es$/i' => "$1",
  226. '/(m)ovies$/i' => "$1ovie",
  227. '/(s)eries$/i' => "$1eries",
  228. '/([^aeiouy]|qu)ies$/i' => "$1y",
  229. '/([lr])ves$/i' => "$1f",
  230. '/(tive)s$/i' => "$1",
  231. '/(hive)s$/i' => "$1",
  232. '/(li|wi|kni)ves$/i' => "$1fe",
  233. '/(shea|loa|lea|thie)ves$/i'=> "$1f",
  234. '/(^analy)ses$/i' => "$1sis",
  235. '/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => "$1$2sis",
  236. '/([ti])a$/i' => "$1um",
  237. '/(n)ews$/i' => "$1ews",
  238. '/(h|bl)ouses$/i' => "$1ouse",
  239. '/(corpse)s$/i' => "$1",
  240. '/(us)es$/i' => "$1",
  241. '/(us|ss)$/i' => "$1",
  242. '/s$/i' => ""
  243. );
  244. private static $irregular = array(
  245. 'move' => 'moves',
  246. 'foot' => 'feet',
  247. 'goose' => 'geese',
  248. 'sex' => 'sexes',
  249. 'child' => 'children',
  250. 'man' => 'men',
  251. 'tooth' => 'teeth',
  252. 'person' => 'people'
  253. );
  254. private static $uncountable = array(
  255. 'sheep',
  256. 'fish',
  257. 'deer',
  258. 'series',
  259. 'species',
  260. 'money',
  261. 'rice',
  262. 'information',
  263. 'equipment'
  264. );
  265. public static function pluralize( $string )
  266. {
  267. // save some time in the case that singular and plural are the same
  268. if ( in_array( strtolower( $string ), self::$uncountable ) )
  269. return $string;
  270. // check for irregular singular forms
  271. foreach ( self::$irregular as $pattern => $result )
  272. {
  273. $pattern = '/' . $pattern . '$/i';
  274. if ( preg_match( $pattern, $string ) )
  275. return preg_replace( $pattern, $result, $string);
  276. }
  277. // check for matches using regular expressions
  278. foreach ( self::$plural as $pattern => $result )
  279. {
  280. if ( preg_match( $pattern, $string ) )
  281. return preg_replace( $pattern, $result, $string );
  282. }
  283. return $string;
  284. }
  285. public static function singularize( $string )
  286. {
  287. // save some time in the case that singular and plural are the same
  288. if ( in_array( strtolower( $string ), self::$uncountable ) )
  289. return $string;
  290. // check for irregular plural forms
  291. foreach ( self::$irregular as $result => $pattern )
  292. {
  293. $pattern = '/' . $pattern . '$/i';
  294. if ( preg_match( $pattern, $string ) )
  295. return preg_replace( $pattern, $result, $string);
  296. }
  297. // check for matches using regular expressions
  298. foreach ( self::$singular as $pattern => $result )
  299. {
  300. if ( preg_match( $pattern, $string ) )
  301. return preg_replace( $pattern, $result, $string );
  302. }
  303. return $string;
  304. }
  305. public static function pluralize_if($count, $string)
  306. {
  307. if ($count == 1)
  308. return $string;
  309. else
  310. return self::pluralize($string);
  311. }
  312. public static function squeeze($char, $string)
  313. {
  314. return preg_replace("/$char+/",$char,$string);
  315. }
  316. };
  317. ?>