Subversion-Projekte lars-tiefland.cakephp

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/* SVN FILE: $Id: inflector.php 7945 2008-12-19 02:16:01Z gwoo $ */
3
/**
4
 * Pluralize and singularize English words.
5
 *
6
 * Used by Cake's naming conventions throughout the framework.
7
 *
8
 * PHP versions 4 and 5
9
 *
10
 * CakePHP(tm) :  Rapid Development Framework (http://www.cakephp.org)
11
 * Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
12
 *
13
 * Licensed under The MIT License
14
 * Redistributions of files must retain the above copyright notice.
15
 *
16
 * @filesource
17
 * @copyright     Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
18
 * @link          http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
19
 * @package       cake
20
 * @subpackage    cake.cake.libs
21
 * @since         CakePHP(tm) v 0.2.9
22
 * @version       $Revision: 7945 $
23
 * @modifiedby    $LastChangedBy: gwoo $
24
 * @lastmodified  $Date: 2008-12-18 18:16:01 -0800 (Thu, 18 Dec 2008) $
25
 * @license       http://www.opensource.org/licenses/mit-license.php The MIT License
26
 */
27
/**
28
 * Included libraries.
29
 *
30
 */
31
if (!class_exists('Object')) {
32
	uses('object');
33
}
34
if (!class_exists('Set')) {
35
	require LIBS . 'set.php';
36
}
37
/**
38
 * Pluralize and singularize English words.
39
 *
40
 * Inflector pluralizes and singularizes English nouns.
41
 * Used by Cake's naming conventions throughout the framework.
42
 * Test with $i = new Inflector(); $i->test();
43
 *
44
 * @package       cake
45
 * @subpackage    cake.cake.libs
46
 * @link          http://book.cakephp.org/view/491/Inflector
47
 */
48
class Inflector extends Object {
49
/**
50
 * Pluralized words.
51
 *
52
 * @var array
53
 * @access private
54
 **/
55
	var $pluralized = array();
56
/**
57
 * List of pluralization rules in the form of pattern => replacement.
58
 *
59
 * @var array
60
 * @access public
61
 * @link http://book.cakephp.org/view/47/Custom-Inflections
62
 **/
63
	var $pluralRules = array();
64
/**
65
 * Singularized words.
66
 *
67
 * @var array
68
 * @access private
69
 **/
70
	var $singularized = array();
71
/**
72
 * List of singularization rules in the form of pattern => replacement.
73
 *
74
 * @var array
75
 * @access public
76
 * @link http://book.cakephp.org/view/47/Custom-Inflections
77
 **/
78
	var $singularRules = array();
79
/**
80
 * Plural rules from inflections.php
81
 *
82
 * @var array
83
 * @access private
84
 **/
85
	var $__pluralRules = array();
86
/**
87
 * Un-inflected plural rules from inflections.php
88
 *
89
 * @var array
90
 * @access private
91
 **/
92
	var $__uninflectedPlural = array();
93
/**
94
 * Irregular plural rules from inflections.php
95
 *
96
 * @var array
97
 * @access private
98
 **/
99
	var $__irregularPlural = array();
100
/**
101
 * Singular rules from inflections.php
102
 *
103
 * @var array
104
 * @access private
105
 **/
106
	var $__singularRules = array();
107
/**
108
 * Un-inflectd singular rules from inflections.php
109
 *
110
 * @var array
111
 * @access private
112
 **/
113
	var $__uninflectedSingular = array();
114
/**
115
 * Irregular singular rules from inflections.php
116
 *
117
 * @var array
118
 * @access private
119
 **/
120
	var $__irregularSingular = array();
121
/**
122
 * Gets a reference to the Inflector object instance
123
 *
124
 * @return object
125
 * @access public
126
 */
127
	function &getInstance() {
128
		static $instance = array();
129
 
130
		if (!$instance) {
131
			$instance[0] =& new Inflector();
132
			if (file_exists(CONFIGS.'inflections.php')) {
133
				include(CONFIGS.'inflections.php');
134
				$instance[0]->__pluralRules = $pluralRules;
135
				$instance[0]->__uninflectedPlural = $uninflectedPlural;
136
				$instance[0]->__irregularPlural = $irregularPlural;
137
				$instance[0]->__singularRules = $singularRules;
138
				$instance[0]->__uninflectedSingular = $uninflectedPlural;
139
				$instance[0]->__irregularSingular = array_flip($irregularPlural);
140
			}
141
		}
142
		return $instance[0];
143
	}
144
/**
145
 * Initializes plural inflection rules.
146
 *
147
 * @return void
148
 * @access private
149
 */
150
	function __initPluralRules() {
151
		$corePluralRules = array(
152
			'/(s)tatus$/i' => '\1\2tatuses',
153
			'/(quiz)$/i' => '\1zes',
154
			'/^(ox)$/i' => '\1\2en',
155
			'/([m|l])ouse$/i' => '\1ice',
156
			'/(matr|vert|ind)(ix|ex)$/i'  => '\1ices',
157
			'/(x|ch|ss|sh)$/i' => '\1es',
158
			'/([^aeiouy]|qu)y$/i' => '\1ies',
159
			'/(hive)$/i' => '\1s',
160
			'/(?:([^f])fe|([lr])f)$/i' => '\1\2ves',
161
			'/sis$/i' => 'ses',
162
			'/([ti])um$/i' => '\1a',
163
			'/(p)erson$/i' => '\1eople',
164
			'/(m)an$/i' => '\1en',
165
			'/(c)hild$/i' => '\1hildren',
166
			'/(buffal|tomat)o$/i' => '\1\2oes',
167
			'/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|vir)us$/i' => '\1i',
168
			'/us$/' => 'uses',
169
			'/(alias)$/i' => '\1es',
170
			'/(ax|cri|test)is$/i' => '\1es',
171
			'/s$/' => 's',
172
			'/^$/' => '',
173
			'/$/' => 's');
174
 
175
		$coreUninflectedPlural = array(
176
			'.*[nrlm]ese', '.*deer', '.*fish', '.*measles', '.*ois', '.*pox', '.*sheep', 'Amoyese',
177
			'bison', 'Borghese', 'bream', 'breeches', 'britches', 'buffalo', 'cantus', 'carp', 'chassis', 'clippers',
178
			'cod', 'coitus', 'Congoese', 'contretemps', 'corps', 'debris', 'diabetes', 'djinn', 'eland', 'elk',
179
			'equipment', 'Faroese', 'flounder', 'Foochowese', 'gallows', 'Genevese', 'Genoese', 'Gilbertese', 'graffiti',
180
			'headquarters', 'herpes', 'hijinks', 'Hottentotese', 'information', 'innings', 'jackanapes', 'Kiplingese',
181
			'Kongoese', 'Lucchese', 'mackerel', 'Maltese', 'media', 'mews', 'moose', 'mumps', 'Nankingese', 'news',
182
			'nexus', 'Niasese', 'Pekingese', 'People', 'Piedmontese', 'pincers', 'Pistoiese', 'pliers', 'Portuguese', 'proceedings',
183
			'rabies', 'rice', 'rhinoceros', 'salmon', 'Sarawakese', 'scissors', 'sea[- ]bass', 'series', 'Shavese', 'shears',
184
			'siemens', 'species', 'swine', 'testes', 'trousers', 'trout', 'tuna', 'Vermontese', 'Wenchowese',
185
			'whiting', 'wildebeest', 'Yengeese');
186
 
187
		$coreIrregularPlural = array(
188
			'atlas' => 'atlases',
189
			'beef' => 'beefs',
190
			'brother' => 'brothers',
191
			'child' => 'children',
192
			'corpus' => 'corpuses',
193
			'cow' => 'cows',
194
			'ganglion' => 'ganglions',
195
			'genie' => 'genies',
196
			'genus' => 'genera',
197
			'graffito' => 'graffiti',
198
			'hoof' => 'hoofs',
199
			'loaf' => 'loaves',
200
			'man' => 'men',
201
			'money' => 'monies',
202
			'mongoose' => 'mongooses',
203
			'move' => 'moves',
204
			'mythos' => 'mythoi',
205
			'numen' => 'numina',
206
			'occiput' => 'occiputs',
207
			'octopus' => 'octopuses',
208
			'opus' => 'opuses',
209
			'ox' => 'oxen',
210
			'penis' => 'penises',
211
			'person' => 'people',
212
			'sex' => 'sexes',
213
			'soliloquy' => 'soliloquies',
214
			'testis' => 'testes',
215
			'trilby' => 'trilbys',
216
			'turf' => 'turfs');
217
 
218
		$pluralRules = Set::pushDiff($this->__pluralRules, $corePluralRules);
219
		$uninflected = Set::pushDiff($this->__uninflectedPlural, $coreUninflectedPlural);
220
		$irregular = Set::pushDiff($this->__irregularPlural, $coreIrregularPlural);
221
 
222
		$this->pluralRules = array('pluralRules' => $pluralRules, 'uninflected' => $uninflected, 'irregular' => $irregular);
223
		$this->pluralized = array();
224
	}
225
/**
226
 * Return $word in plural form.
227
 *
228
 * @param string $word Word in singular
229
 * @return string Word in plural
230
 * @access public
231
 * @static
232
 * @link http://book.cakephp.org/view/572/Class-methods
233
 */
234
	function pluralize($word) {
235
		$_this =& Inflector::getInstance();
236
		if (!isset($_this->pluralRules) || empty($_this->pluralRules)) {
237
			$_this->__initPluralRules();
238
		}
239
 
240
		if (isset($_this->pluralized[$word])) {
241
			return $_this->pluralized[$word];
242
		}
243
		extract($_this->pluralRules);
244
 
245
		if (!isset($regexUninflected) || !isset($regexIrregular)) {
246
			$regexUninflected = __enclose(join( '|', $uninflected));
247
			$regexIrregular = __enclose(join( '|', array_keys($irregular)));
248
			$_this->pluralRules['regexUninflected'] = $regexUninflected;
249
			$_this->pluralRules['regexIrregular'] = $regexIrregular;
250
		}
251
 
252
		if (preg_match('/(.*)\\b(' . $regexIrregular . ')$/i', $word, $regs)) {
253
			$_this->pluralized[$word] = $regs[1] . substr($word, 0, 1) . substr($irregular[strtolower($regs[2])], 1);
254
			return $_this->pluralized[$word];
255
		}
256
 
257
		if (preg_match('/^(' . $regexUninflected . ')$/i', $word, $regs)) {
258
			$_this->pluralized[$word] = $word;
259
			return $word;
260
		}
261
 
262
		foreach ($pluralRules as $rule => $replacement) {
263
			if (preg_match($rule, $word)) {
264
				$_this->pluralized[$word] = preg_replace($rule, $replacement, $word);
265
				return $_this->pluralized[$word];
266
			}
267
		}
268
	}
269
/**
270
 * Initializes singular inflection rules.
271
 *
272
 * @return void
273
 * @access protected
274
 */
275
	function __initSingularRules() {
276
		$coreSingularRules = array(
277
			'/(s)tatuses$/i' => '\1\2tatus',
278
			'/^(.*)(menu)s$/i' => '\1\2',
279
			'/(quiz)zes$/i' => '\\1',
280
			'/(matr)ices$/i' => '\1ix',
281
			'/(vert|ind)ices$/i' => '\1ex',
282
			'/^(ox)en/i' => '\1',
283
			'/(alias)(es)*$/i' => '\1',
284
			'/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|viri?)i$/i' => '\1us',
285
			'/(cris|ax|test)es$/i' => '\1is',
286
			'/(shoe)s$/i' => '\1',
287
			'/(o)es$/i' => '\1',
288
			'/ouses$/' => 'ouse',
289
			'/uses$/' => 'us',
290
			'/([m|l])ice$/i' => '\1ouse',
291
			'/(x|ch|ss|sh)es$/i' => '\1',
292
			'/(m)ovies$/i' => '\1\2ovie',
293
			'/(s)eries$/i' => '\1\2eries',
294
			'/([^aeiouy]|qu)ies$/i' => '\1y',
295
			'/([lr])ves$/i' => '\1f',
296
			'/(tive)s$/i' => '\1',
297
			'/(hive)s$/i' => '\1',
298
			'/(drive)s$/i' => '\1',
299
			'/([^fo])ves$/i' => '\1fe',
300
			'/(^analy)ses$/i' => '\1sis',
301
			'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => '\1\2sis',
302
			'/([ti])a$/i' => '\1um',
303
			'/(p)eople$/i' => '\1\2erson',
304
			'/(m)en$/i' => '\1an',
305
			'/(c)hildren$/i' => '\1\2hild',
306
			'/(n)ews$/i' => '\1\2ews',
307
			'/^(.*us)$/' => '\\1',
308
			'/s$/i' => '');
309
 
310
		$coreUninflectedSingular = array(
311
			'.*[nrlm]ese', '.*deer', '.*fish', '.*measles', '.*ois', '.*pox', '.*sheep', '.*ss', 'Amoyese',
312
			'bison', 'Borghese', 'bream', 'breeches', 'britches', 'buffalo', 'cantus', 'carp', 'chassis', 'clippers',
313
			'cod', 'coitus', 'Congoese', 'contretemps', 'corps', 'debris', 'diabetes', 'djinn', 'eland', 'elk',
314
			'equipment', 'Faroese', 'flounder', 'Foochowese', 'gallows', 'Genevese', 'Genoese', 'Gilbertese', 'graffiti',
315
			'headquarters', 'herpes', 'hijinks', 'Hottentotese', 'information', 'innings', 'jackanapes', 'Kiplingese',
316
			'Kongoese', 'Lucchese', 'mackerel', 'Maltese', 'media', 'mews', 'moose', 'mumps', 'Nankingese', 'news',
317
			'nexus', 'Niasese', 'Pekingese', 'Piedmontese', 'pincers', 'Pistoiese', 'pliers', 'Portuguese', 'proceedings',
318
			'rabies', 'rice', 'rhinoceros', 'salmon', 'Sarawakese', 'scissors', 'sea[- ]bass', 'series', 'Shavese', 'shears',
319
			'siemens', 'species', 'swine', 'testes', 'trousers', 'trout', 'tuna', 'Vermontese', 'Wenchowese',
320
			'whiting', 'wildebeest', 'Yengeese');
321
 
322
		$coreIrregularSingular = array(
323
			'atlases' => 'atlas',
324
			'beefs' => 'beef',
325
			'brothers' => 'brother',
326
			'children' => 'child',
327
			'corpuses' => 'corpus',
328
			'cows' => 'cow',
329
			'ganglions' => 'ganglion',
330
			'genies' => 'genie',
331
			'genera' => 'genus',
332
			'graffiti' => 'graffito',
333
			'hoofs' => 'hoof',
334
			'loaves' => 'loaf',
335
			'men' => 'man',
336
			'monies' => 'money',
337
			'mongooses' => 'mongoose',
338
			'moves' => 'move',
339
			'mythoi' => 'mythos',
340
			'numina' => 'numen',
341
			'occiputs' => 'occiput',
342
			'octopuses' => 'octopus',
343
			'opuses' => 'opus',
344
			'oxen' => 'ox',
345
			'penises' => 'penis',
346
			'people' => 'person',
347
			'sexes' => 'sex',
348
			'soliloquies' => 'soliloquy',
349
			'testes' => 'testis',
350
			'trilbys' => 'trilby',
351
			'turfs' => 'turf');
352
 
353
		$singularRules = Set::pushDiff($this->__singularRules, $coreSingularRules);
354
		$uninflected = Set::pushDiff($this->__uninflectedSingular, $coreUninflectedSingular);
355
		$irregular = Set::pushDiff($this->__irregularSingular, $coreIrregularSingular);
356
 
357
		$this->singularRules = array('singularRules' => $singularRules, 'uninflected' => $uninflected, 'irregular' => $irregular);
358
		$this->singularized = array();
359
	}
360
/**
361
 * Return $word in singular form.
362
 *
363
 * @param string $word Word in plural
364
 * @return string Word in singular
365
 * @access public
366
 * @static
367
 * @link http://book.cakephp.org/view/572/Class-methods
368
 */
369
	function singularize($word) {
370
		$_this =& Inflector::getInstance();
371
		if (!isset($_this->singularRules) || empty($_this->singularRules)) {
372
			$_this->__initSingularRules();
373
		}
374
 
375
		if (isset($_this->singularized[$word])) {
376
			return $_this->singularized[$word];
377
		}
378
		extract($_this->singularRules);
379
 
380
		if (!isset($regexUninflected) || !isset($regexIrregular)) {
381
			$regexUninflected = __enclose(join( '|', $uninflected));
382
			$regexIrregular = __enclose(join( '|', array_keys($irregular)));
383
			$_this->singularRules['regexUninflected'] = $regexUninflected;
384
			$_this->singularRules['regexIrregular'] = $regexIrregular;
385
		}
386
 
387
		if (preg_match('/(.*)\\b(' . $regexIrregular . ')$/i', $word, $regs)) {
388
			$_this->singularized[$word] = $regs[1] . substr($word, 0, 1) . substr($irregular[strtolower($regs[2])], 1);
389
			return $_this->singularized[$word];
390
		}
391
 
392
		if (preg_match('/^(' . $regexUninflected . ')$/i', $word, $regs)) {
393
			$_this->singularized[$word] = $word;
394
			return $word;
395
		}
396
 
397
		foreach ($singularRules as $rule => $replacement) {
398
			if (preg_match($rule, $word)) {
399
				$_this->singularized[$word] = preg_replace($rule, $replacement, $word);
400
				return $_this->singularized[$word];
401
			}
402
		}
403
		$_this->singularized[$word] = $word;
404
		return $word;
405
	}
406
/**
407
 * Returns the given lower_case_and_underscored_word as a CamelCased word.
408
 *
409
 * @param string $lower_case_and_underscored_word Word to camelize
410
 * @return string Camelized word. LikeThis.
411
 * @access public
412
 * @static
413
 * @link http://book.cakephp.org/view/572/Class-methods
414
 */
415
	function camelize($lowerCaseAndUnderscoredWord) {
416
		return str_replace(" ", "", ucwords(str_replace("_", " ", $lowerCaseAndUnderscoredWord)));
417
	}
418
/**
419
 * Returns the given camelCasedWord as an underscored_word.
420
 *
421
 * @param string $camelCasedWord Camel-cased word to be "underscorized"
422
 * @return string Underscore-syntaxed version of the $camelCasedWord
423
 * @access public
424
 * @static
425
 * @link http://book.cakephp.org/view/572/Class-methods
426
 */
427
	function underscore($camelCasedWord) {
428
		return strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $camelCasedWord));
429
	}
430
/**
431
 * Returns the given underscored_word_group as a Human Readable Word Group.
432
 * (Underscores are replaced by spaces and capitalized following words.)
433
 *
434
 * @param string $lower_case_and_underscored_word String to be made more readable
435
 * @return string Human-readable string
436
 * @access public
437
 * @static
438
 * @link http://book.cakephp.org/view/572/Class-methods
439
 */
440
	function humanize($lowerCaseAndUnderscoredWord) {
441
		return ucwords(str_replace("_", " ", $lowerCaseAndUnderscoredWord));
442
	}
443
/**
444
 * Returns corresponding table name for given model $className. ("people" for the model class "Person").
445
 *
446
 * @param string $className Name of class to get database table name for
447
 * @return string Name of the database table for given class
448
 * @access public
449
 * @static
450
 * @link http://book.cakephp.org/view/572/Class-methods
451
 */
452
	function tableize($className) {
453
		return Inflector::pluralize(Inflector::underscore($className));
454
	}
455
/**
456
 * Returns Cake model class name ("Person" for the database table "people".) for given database table.
457
 *
458
 * @param string $tableName Name of database table to get class name for
459
 * @return string Class name
460
 * @access public
461
 * @static
462
 * @link http://book.cakephp.org/view/572/Class-methods
463
 */
464
	function classify($tableName) {
465
		return Inflector::camelize(Inflector::singularize($tableName));
466
	}
467
/**
468
 * Returns camelBacked version of an underscored string.
469
 *
470
 * @param string $string
471
 * @return string in variable form
472
 * @access public
473
 * @static
474
 * @link http://book.cakephp.org/view/572/Class-methods
475
 */
476
	function variable($string) {
477
		$string = Inflector::camelize(Inflector::underscore($string));
478
		$replace = strtolower(substr($string, 0, 1));
479
		return preg_replace('/\\w/', $replace, $string, 1);
480
	}
481
/**
482
 * Returns a string with all spaces converted to underscores (by default), accented
483
 * characters converted to non-accented characters, and non word characters removed.
484
 *
485
 * @param string $string
486
 * @param string $replacement
487
 * @return string
488
 * @access public
489
 * @static
490
 * @link http://book.cakephp.org/view/572/Class-methods
491
 */
492
	function slug($string, $replacement = '_') {
493
		if (!class_exists('String')) {
494
			require LIBS . 'string.php';
495
		}
496
		$map = array(
497
			'/à|á|å|â/' => 'a',
498
			'/è|é|ê|ẽ|ë/' => 'e',
499
			'/ì|í|î/' => 'i',
500
			'/ò|ó|ô|ø/' => 'o',
501
			'/ù|ú|ů|û/' => 'u',
502
			'/ç/' => 'c',
503
			'/ñ/' => 'n',
504
			'/ä|æ/' => 'ae',
505
			'/ö/' => 'oe',
506
			'/ü/' => 'ue',
507
			'/Ä/' => 'Ae',
508
			'/Ü/' => 'Ue',
509
			'/Ö/' => 'Oe',
510
			'/ß/' => 'ss',
511
			'/[^\w\s]/' => ' ',
512
			'/\\s+/' => $replacement,
513
			String::insert('/^[:replacement]+|[:replacement]+$/', array('replacement' => preg_quote($replacement, '/'))) => '',
514
		);
515
		return preg_replace(array_keys($map), array_values($map), $string);
516
	}
517
}
518
/**
519
 * Enclose a string for preg matching.
520
 *
521
 * @param string $string String to enclose
522
 * @return string Enclosed string
523
 */
524
	function __enclose($string) {
525
		return '(?:' . $string . ')';
526
	}
527
?>