Renaming more core classes, next step would be to tweek the autoloader to find only on Cake/ "namespace" (for now)

This commit is contained in:
José Lorenzo Rodríguez 2010-12-03 20:15:54 -04:30
parent 96cb90a82b
commit ca34b22dbb
4 changed files with 0 additions and 0 deletions

908
lib/Cake/Core/App.php Normal file
View file

@ -0,0 +1,908 @@
<?php
/**
* App class
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package cake
* @subpackage cake.cake.libs
* @since CakePHP(tm) v 1.2.0.6001
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* App is responsible for path managment, class location and class loading.
*
* ### Adding paths
*
* You can add paths to the search indexes App uses to find classes using `App::build()`. Adding
* additional controller paths for example would alter where CakePHP looks for controllers when you
* call App::import('Controller', 'Posts'); This allows you to split your application up across the filesystem.
*
* ### Inspecting loaded paths
*
* You can inspect the currently loaded paths using `App::path('controller')` for example to see loaded
* controller paths.
*
* ### Locating plugins and themes
*
* Plugins and Themes can be located with App as well. Using App::pluginPath('DebugKit') for example, will
* give you the full path to the DebugKit plugin. App::themePath('purple'), would give the full path to the
* `purple` theme.
*
* ### Inspecting known objects
*
* You can find out which objects App knows about using App::objects('controller') for example to find
* which application controllers App knows about.
*
* @link http://book.cakephp.org/view/933/The-App-Class
* @package cake
* @subpackage cake.cake.libs
*/
class App {
/**
* List of object types and their properties
*
* @var array
*/
public static $types = array(
'class' => array('suffix' => '.php', 'extends' => null, 'core' => true),
'file' => array('suffix' => '.php', 'extends' => null, 'core' => true),
'model' => array('suffix' => '.php', 'extends' => 'AppModel', 'core' => false),
'behavior' => array('suffix' => '.php', 'extends' => 'ModelBehavior', 'core' => true),
'controller' => array('suffix' => '_controller.php', 'extends' => 'AppController', 'core' => true),
'component' => array('suffix' => '.php', 'extends' => null, 'core' => true),
'lib' => array('suffix' => '.php', 'extends' => null, 'core' => true),
'view' => array('suffix' => '.php', 'extends' => null, 'core' => true),
'helper' => array('suffix' => '.php', 'extends' => 'AppHelper', 'core' => true),
'vendor' => array('suffix' => '', 'extends' => null, 'core' => true),
'shell' => array('suffix' => '.php', 'extends' => 'Shell', 'core' => true),
'plugin' => array('suffix' => '', 'extends' => null, 'core' => true)
);
/**
* List of additional path(s) where model files reside.
*
* @var array
*/
public static $models = array();
/**
* List of additional path(s) where behavior files reside.
*
* @var array
*/
public static $behaviors = array();
/**
* List of additional path(s) where controller files reside.
*
* @var array
*/
public static $controllers = array();
/**
* List of additional path(s) where component files reside.
*
* @var array
*/
public static $components = array();
/**
* List of additional path(s) where datasource files reside.
*
* @var array
*/
public static $datasources = array();
/**
* List of additional path(s) where libs files reside.
*
* @var array
*/
public static $libs = array();
/**
* List of additional path(s) where view files reside.
*
* @var array
*/
public static $views = array();
/**
* List of additional path(s) where helper files reside.
*
* @var array
*/
public static $helpers = array();
/**
* List of additional path(s) where plugins reside.
*
* @var array
*/
public static $plugins = array();
/**
* List of additional path(s) where vendor packages reside.
*
* @var array
*/
public static $vendors = array();
/**
* List of additional path(s) where locale files reside.
*
* @var array
*/
public static $locales = array();
/**
* List of additional path(s) where console shell files reside.
*
* @var array
*/
public static $shells = array();
/**
* Paths to search for files.
*
* @var array
*/
public static $search = array();
/**
* Whether or not to return the file that is loaded.
*
* @var boolean
*/
public static $return = false;
/**
* Determines if $__maps and $__paths cache should be written.
*
* @var boolean
*/
private static $__cache = false;
/**
* Holds key/value pairs of $type => file path.
*
* @var array
*/
private static $__map = array();
/**
* Holds paths for deep searching of files.
*
* @var array
*/
private static $__paths = array();
/**
* Holds loaded files.
*
* @var array
*/
private static $__loaded = array();
/**
* Holds and key => value array of object types.
*
* @var array
*/
private static $__objects = array();
/**
* Holds the location of each class
*
*/
private static $__classMap = array();
/**
* Used to read information stored path
*
* Usage:
*
* `App::path('models'); will return all paths for models`
*
* @param string $type type of path
* @return string array
*/
public static function path($type) {
if (!isset(self::${$type})) {
return array();
}
return self::${$type};
}
/**
* Build path references. Merges the supplied $paths
* with the base paths and the default core paths.
*
* @param array $paths paths defines in config/bootstrap.php
* @param boolean $reset true will set paths, false merges paths [default] false
* @return void
*/
public static function build($paths = array(), $reset = false) {
$defaults = array(
'models' => array(MODELS),
'behaviors' => array(BEHAVIORS),
'datasources' => array(MODELS . 'datasources'),
'controllers' => array(CONTROLLERS),
'components' => array(COMPONENTS),
'libs' => array(APPLIBS),
'views' => array(VIEWS),
'helpers' => array(HELPERS),
'locales' => array(APP . 'locale' . DS),
'shells' => array(
APP . 'console' . DS . 'shells' . DS,
APP . 'vendors' . DS . 'shells' . DS,
VENDORS . 'shells' . DS
),
'vendors' => array(APP . 'vendors' . DS, VENDORS),
'plugins' => array(APP . 'plugins' . DS)
);
if ($reset == true) {
foreach ($paths as $type => $new) {
self::${$type} = (array)$new;
}
return $paths;
}
$core = self::core();
$app = array('models' => true, 'controllers' => true, 'helpers' => true);
foreach ($defaults as $type => $default) {
$merge = array();
if (isset($app[$type])) {
$merge = array(APP);
}
if (isset($core[$type])) {
$merge = array_merge($merge, (array)$core[$type]);
}
if (empty(self::${$type}) || empty($paths)) {
self::${$type} = $default;
}
if (!empty($paths[$type])) {
$path = array_flip(array_flip(array_merge(
(array)$paths[$type], self::${$type}, $merge
)));
self::${$type} = array_values($path);
} else {
$path = array_flip(array_flip(array_merge(self::${$type}, $merge)));
self::${$type} = array_values($path);
}
}
}
/**
* Get the path that a plugin is on. Searches through the defined plugin paths.
*
* @param string $plugin CamelCased/lower_cased plugin name to find the path of.
* @return string full path to the plugin.
*/
public static function pluginPath($plugin) {
$pluginDir = Inflector::underscore($plugin);
for ($i = 0, $length = count(self::$plugins); $i < $length; $i++) {
if (is_dir(self::$plugins[$i] . $pluginDir)) {
return self::$plugins[$i] . $pluginDir . DS ;
}
}
return self::$plugins[0] . $pluginDir . DS;
}
/**
* Find the path that a theme is on. Search through the defined theme paths.
*
* @param string $theme lower_cased theme name to find the path of.
* @return string full path to the theme.
*/
public static function themePath($theme) {
$themeDir = 'themed' . DS . Inflector::underscore($theme);
for ($i = 0, $length = count(self::$views); $i < $length; $i++) {
if (is_dir(self::$views[$i] . $themeDir)) {
return self::$views[$i] . $themeDir . DS ;
}
}
return self::$views[0] . $themeDir . DS;
}
/**
* Returns a key/value list of all paths where core libs are found.
* Passing $type only returns the values for a given value of $key.
*
* @param string $type valid values are: 'model', 'behavior', 'controller', 'component',
* 'view', 'helper', 'datasource', 'libs', and 'cake'
* @return array numeric keyed array of core lib paths
*/
public static function core($type = null) {
static $paths = false;
if (!$paths) {
$paths = array();
$libs = dirname(__FILE__) . DS;
$cake = dirname($libs) . DS;
$path = dirname($cake) . DS;
$paths['cake'][] = $cake;
$paths['libs'][] = $libs;
$paths['models'][] = $libs . 'model' . DS;
$paths['datasources'][] = $libs . 'model' . DS . 'datasources' . DS;
$paths['behaviors'][] = $libs . 'model' . DS . 'behaviors' . DS;
$paths['controllers'][] = $libs . 'controller' . DS;
$paths['components'][] = $libs . 'controller' . DS . 'components' . DS;
$paths['views'][] = $libs . 'view' . DS;
$paths['helpers'][] = $libs . 'view' . DS . 'helpers' . DS;
$paths['plugins'][] = $path . 'plugins' . DS;
$paths['vendors'][] = $path . 'vendors' . DS;
$paths['shells'][] = $cake . 'console' . DS . 'shells' . DS;
// Provide BC path to vendors/shells
$paths['shells'][] = $path . 'vendors' . DS . 'shells' . DS;
}
if ($type && isset($paths[$type])) {
return $paths[$type];
}
return $paths;
}
/**
* Returns an array of objects of the given type.
*
* Example usage:
*
* `App::objects('plugin');` returns `array('DebugKit', 'Blog', 'User');`
*
* @param string $type Type of object, i.e. 'model', 'controller', 'helper', or 'plugin'
* @param mixed $path Optional Scan only the path given. If null, paths for the chosen
* type will be used.
* @param boolean $cache Set to false to rescan objects of the chosen type. Defaults to true.
* @return mixed Either false on incorrect / miss. Or an array of found objects.
*/
public static function objects($type, $path = null, $cache = true) {
$objects = array();
$extension = false;
$name = $type;
if ($type === 'file' && !$path) {
return false;
} elseif ($type === 'file') {
$extension = true;
$name = $type . str_replace(DS, '', $path);
}
if (empty(self::$__objects) && $cache === true) {
self::$__objects = Cache::read('object_map', '_cake_core_');
}
if (!isset(self::$__objects[$name]) || $cache !== true) {
$types = self::$types;
if (!isset($types[$type])) {
return false;
}
$objects = array();
if (empty($path)) {
$path = self::${"{$type}s"};
if (isset($types[$type]['core']) && $types[$type]['core'] === false) {
array_pop($path);
}
}
$items = array();
foreach ((array)$path as $dir) {
if ($dir != APP) {
$items = self::__list($dir, $types[$type]['suffix'], $extension);
$objects = array_merge($items, array_diff($objects, $items));
}
}
if ($type !== 'file') {
foreach ($objects as $key => $value) {
$objects[$key] = Inflector::camelize($value);
}
}
if ($cache === true) {
self::$__cache = true;
}
self::$__objects[$name] = $objects;
}
return self::$__objects[$name];
}
/**
* Allows you to modify the object listings that App maintains inside of it
* Useful for testing
*
* @param string $type Type of object listing you are changing
* @param array $values The values $type should be set to.
* @return void
*/
public static function setObjects($type, $values) {
self::$__objects[$type] = $values;
}
public static function uses($className, $location) {
self::$__classMap[$className] = $location;
}
public static function load($className) {
if (isset(self::$__classMap[$className])) {
return App::import(self::$__classMap[$className], $className, false);
}
return false;
}
/**
* Finds classes based on $name or specific file(s) to search. Calling App::import() will
* not construct any classes contained in the files. It will only find and require() the file.
*
* @link http://book.cakephp.org/view/934/Using-App-import
* @param mixed $type The type of Class if passed as a string, or all params can be passed as
* an single array to $type,
* @param string $name Name of the Class or a unique name for the file
* @param mixed $parent boolean true if Class Parent should be searched, accepts key => value
* array('parent' => $parent ,'file' => $file, 'search' => $search, 'ext' => '$ext');
* $ext allows setting the extension of the file name
* based on Inflector::underscore($name) . ".$ext";
* @param array $search paths to search for files, array('path 1', 'path 2', 'path 3');
* @param string $file full name of the file to search for including extension
* @param boolean $return, return the loaded file, the file must have a return
* statement in it to work: return $variable;
* @return boolean true if Class is already in memory or if file is found and loaded, false if not
*/
public static function import($type = null, $name = null, $parent = true, $search = array(), $file = null, $return = false) {
$plugin = $directory = null;
if (is_array($type)) {
extract($type, EXTR_OVERWRITE);
}
if (is_array($parent)) {
extract($parent, EXTR_OVERWRITE);
}
if ($name === null && $file === null) {
$name = $type;
$type = 'Core';
} elseif ($name === null) {
$type = 'File';
}
if (is_array($name)) {
foreach ($name as $class) {
$tempType = $type;
$plugin = null;
if (strpos($class, '.') !== false) {
$value = explode('.', $class);
$count = count($value);
if ($count > 2) {
$tempType = $value[0];
$plugin = $value[1] . '.';
$class = $value[2];
} elseif ($count === 2 && ($type === 'Core' || $type === 'File')) {
$tempType = $value[0];
$class = $value[1];
} else {
$plugin = $value[0] . '.';
$class = $value[1];
}
}
if (!App::import($tempType, $plugin . $class, $parent)) {
return false;
}
}
return true;
}
if ($name != null && strpos($name, '.') !== false) {
list($plugin, $name) = explode('.', $name);
$plugin = Inflector::camelize($plugin);
}
self::$return = $return;
if (isset($ext)) {
$file = Inflector::underscore($name) . ".{$ext}";
}
$ext = self::__settings($type, $plugin, $parent);
$className = $name;
if (strpos($className, '/') !== false) {
$className = substr($className, strrpos($className, '/') + 1);
}
if ($name != null && !class_exists($className . $ext['class'])) {
if ($load = self::__mapped($name . $ext['class'], $type, $plugin)) {
if (self::__load($load)) {
if (self::$return) {
return include($load);
}
return true;
} else {
self::__remove($name . $ext['class'], $type, $plugin);
self::$__cache = true;
}
}
if (!empty($search)) {
self::$search = $search;
} elseif ($plugin) {
self::$search = self::__paths('plugin');
} else {
self::$search = self::__paths($type);
}
$find = $file;
if ($find === null) {
$find = Inflector::underscore($name . $ext['suffix']).'.php';
if ($plugin) {
$paths = self::$search;
foreach ($paths as $key => $value) {
self::$search[$key] = $value . $ext['path'];
}
}
}
if (strtolower($type) !== 'vendor' && empty($search) && self::__load($file)) {
$directory = false;
} else {
$file = $find;
$directory = self::__find($find, true);
}
if ($directory !== null) {
self::$__cache = true;
self::__map($directory . $file, $name . $ext['class'], $type, $plugin);
if (self::$return) {
return include($directory . $file);
}
return true;
}
return false;
}
return true;
}
/**
* Initializes the cache for App, registers a shutdown function.
*
* @return void
*/
public static function init() {
self::$__map = (array)Cache::read('file_map', '_cake_core_');
register_shutdown_function(array('App', 'shutdown'));
}
/**
* Locates the $file in $__paths, searches recursively.
*
* @param string $file full file name
* @param boolean $recursive search $__paths recursively
* @return mixed boolean on fail, $file directory path on success
*/
private static function __find($file, $recursive = true) {
static $appPath = false;
if (empty(self::$search)) {
return null;
} elseif (is_string(self::$search)) {
$this->search = array(self::$search);
}
if (empty(self::$__paths)) {
self::$__paths = Cache::read('dir_map', '_cake_core_');
}
foreach (self::$search as $path) {
if ($appPath === false) {
$appPath = rtrim(APP, DS);
}
$path = rtrim($path, DS);
if ($path === $appPath) {
$recursive = false;
}
if ($recursive === false) {
if (self::__load($path . DS . $file)) {
return $path . DS;
}
continue;
}
if (!isset(self::$__paths[$path])) {
if (!class_exists('Folder')) {
require LIBS . 'folder.php';
}
$Folder = new Folder();
$directories = $Folder->tree($path, array('.svn', '.git', 'CVS', 'tests', 'templates'), 'dir');
sort($directories);
self::$__paths[$path] = $directories;
}
foreach (self::$__paths[$path] as $directory) {
if (self::__load($directory . DS . $file)) {
return $directory . DS;
}
}
}
return null;
}
/**
* Attempts to load $file.
*
* @param string $file full path to file including file name
* @return boolean
* @access private
*/
private static function __load($file) {
if (empty($file)) {
return false;
}
if (!self::$return && isset(self::$__loaded[$file])) {
return true;
}
if (file_exists($file)) {
if (!self::$return) {
require($file);
self::$__loaded[$file] = true;
}
return true;
}
return false;
}
/**
* Maps the $name to the $file.
*
* @param string $file full path to file
* @param string $name unique name for this map
* @param string $type type object being mapped
* @param string $plugin camelized if object is from a plugin, the name of the plugin
* @return void
* @access private
*/
private static function __map($file, $name, $type, $plugin) {
if ($plugin) {
self::$__map['Plugin'][$plugin][$type][$name] = $file;
} else {
self::$__map[$type][$name] = $file;
}
}
/**
* Returns a file's complete path.
*
* @param string $name unique name
* @param string $type type object
* @param string $plugin camelized if object is from a plugin, the name of the plugin
* @return mixed, file path if found, false otherwise
* @access private
*/
private static function __mapped($name, $type, $plugin) {
if ($plugin) {
if (isset(self::$__map['Plugin'][$plugin][$type]) && isset(self::$__map['Plugin'][$plugin][$type][$name])) {
return self::$__map['Plugin'][$plugin][$type][$name];
}
return false;
}
if (isset(self::$__map[$type]) && isset(self::$__map[$type][$name])) {
return self::$__map[$type][$name];
}
return false;
}
/**
* Loads parent classes based on $type.
* Returns a prefix or suffix needed for loading files.
*
* @param string $type type of object
* @param string $plugin camelized name of plugin
* @param boolean $parent false will not attempt to load parent
* @return array
* @access private
*/
private static function __settings($type, $plugin, $parent) {
if (!$parent) {
return array('class' => null, 'suffix' => null, 'path' => null);
}
if ($plugin) {
$pluginPath = Inflector::underscore($plugin);
}
$path = null;
$load = strtolower($type);
switch ($load) {
case 'model':
if (!class_exists('Model')) {
require LIBS . 'model' . DS . 'model.php';
}
if (!class_exists('AppModel')) {
App::import($type, 'AppModel', false);
}
if ($plugin) {
if (!class_exists($plugin . 'AppModel')) {
App::import($type, $plugin . '.' . $plugin . 'AppModel', false, array(), $pluginPath . DS . $pluginPath . '_app_model.php');
}
$path = $pluginPath . DS . 'models' . DS;
}
return array('class' => null, 'suffix' => null, 'path' => $path);
break;
case 'behavior':
if ($plugin) {
$path = $pluginPath . DS . 'models' . DS . 'behaviors' . DS;
}
return array('class' => $type, 'suffix' => null, 'path' => $path);
break;
case 'datasource':
if ($plugin) {
$path = $pluginPath . DS . 'models' . DS . 'datasources' . DS;
}
return array('class' => $type, 'suffix' => null, 'path' => $path);
case 'controller':
App::import($type, 'AppController', false);
if ($plugin) {
App::import($type, $plugin . '.' . $plugin . 'AppController', false, array(), $pluginPath . DS . $pluginPath . '_app_controller.php');
$path = $pluginPath . DS . 'controllers' . DS;
}
return array('class' => $type, 'suffix' => $type, 'path' => $path);
break;
case 'component':
App::import('Core', 'Component', false);
if ($plugin) {
$path = $pluginPath . DS . 'controllers' . DS . 'components' . DS;
}
return array('class' => $type, 'suffix' => null, 'path' => $path);
break;
case 'lib':
if ($plugin) {
$path = $pluginPath . DS . 'libs' . DS;
}
return array('class' => null, 'suffix' => null, 'path' => $path);
break;
case 'view':
App::import('View', 'View', false);
if ($plugin) {
$path = $pluginPath . DS . 'views' . DS;
}
return array('class' => $type, 'suffix' => null, 'path' => $path);
break;
case 'helper':
if (!class_exists('AppHelper')) {
App::import($type, 'AppHelper', false);
}
if ($plugin) {
$path = $pluginPath . DS . 'views' . DS . 'helpers' . DS;
}
return array('class' => $type, 'suffix' => null, 'path' => $path);
break;
case 'shell':
if (!class_exists('Shell')) {
App::import($type, 'Shell', false);
}
if (!class_exists('AppShell')) {
App::import($type, 'AppShell', false);
}
if ($plugin) {
$path = $pluginPath . DS . 'console' . DS . 'shells' . DS;
}
return array('class' => $type, 'suffix' => null, 'path' => $path);
break;
case 'vendor':
if ($plugin) {
$path = $pluginPath . DS . 'vendors' . DS;
}
return array('class' => null, 'suffix' => null, 'path' => $path);
break;
default:
$type = $suffix = $path = null;
break;
}
return array('class' => null, 'suffix' => null, 'path' => null);
}
/**
* Returns default search paths.
*
* @param string $type type of object to be searched
* @return array list of paths
*/
private static function __paths($type) {
$type = strtolower($type);
$paths = array();
if ($type === 'core') {
return App::core('libs');
}
if (isset(self::${$type . 's'})) {
return self::${$type . 's'};
}
return $paths;
}
/**
* Removes file location from map if the file has been deleted.
*
* @param string $name name of object
* @param string $type type of object
* @param string $plugin camelized name of plugin
* @return void
*/
private static function __remove($name, $type, $plugin) {
if ($plugin) {
unset(self::$__map['Plugin'][$plugin][$type][$name]);
} else {
unset(self::$__map[$type][$name]);
}
}
/**
* Returns an array of filenames of PHP files in the given directory.
*
* @param string $path Path to scan for files
* @param string $suffix if false, return only directories. if string, match and return files
* @return array List of directories or files in directory
*/
private static function __list($path, $suffix = false, $extension = false) {
if (!class_exists('Folder')) {
require LIBS . 'folder.php';
}
$items = array();
$Folder = new Folder($path);
$contents = $Folder->read(false, true);
if (is_array($contents)) {
if (!$suffix) {
return $contents[0];
} else {
foreach ($contents[1] as $item) {
if (substr($item, - strlen($suffix)) === $suffix) {
if ($extension) {
$items[] = $item;
} else {
$items[] = substr($item, 0, strlen($item) - strlen($suffix));
}
}
}
}
}
return $items;
}
/**
* Object destructor.
*
* Writes cache file if changes have been made to the $__map or $__paths
*
* @return void
*/
public static function shutdown() {
if (self::$__cache) {
$core = App::core('cake');
unset(self::$__paths[rtrim($core[0], DS)]);
Cache::write('dir_map', array_filter(self::$__paths), '_cake_core_');
Cache::write('file_map', array_filter(self::$__map), '_cake_core_');
Cache::write('object_map', self::$__objects, '_cake_core_');
}
}
}
spl_autoload_register(array('App', 'load'));

1216
lib/Cake/Routing/Router.php Normal file

File diff suppressed because it is too large Load diff

765
lib/Cake/Utility/Folder.php Normal file
View file

@ -0,0 +1,765 @@
<?php
/**
* Convenience class for handling directories.
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package cake
* @subpackage cake.cake.libs
* @since CakePHP(tm) v 0.2.9
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* Folder structure browser, lists folders and files.
* Provides an Object interface for Common directory related tasks.
*
* @package cake
* @subpackage cake.cake.libs
*/
class Folder {
/**
* Path to Folder.
*
* @var string
* @access public
*/
public $path = null;
/**
* Sortedness. Whether or not list results
* should be sorted by name.
*
* @var boolean
* @access public
*/
public $sort = false;
/**
* Mode to be used on create. Does nothing on windows platforms.
*
* @var integer
* @access public
*/
public $mode = 0755;
/**
* Holds messages from last method.
*
* @var array
* @access private
*/
private $__messages = array();
/**
* Holds errors from last method.
*
* @var array
* @access private
*/
private $__errors = array();
/**
* Holds array of complete directory paths.
*
* @var array
* @access private
*/
private $__directories;
/**
* Holds array of complete file paths.
*
* @var array
* @access private
*/
private $__files;
/**
* Constructor.
*
* @param string $path Path to folder
* @param boolean $create Create folder if not found
* @param mixed $mode Mode (CHMOD) to apply to created folder, false to ignore
*/
function __construct($path = false, $create = false, $mode = false) {
if (empty($path)) {
$path = TMP;
}
if ($mode) {
$this->mode = $mode;
}
if (!file_exists($path) && $create === true) {
$this->create($path, $this->mode);
}
if (!Folder::isAbsolute($path)) {
$path = realpath($path);
}
if (!empty($path)) {
$this->cd($path);
}
}
/**
* Return current path.
*
* @return string Current path
*/
public function pwd() {
return $this->path;
}
/**
* Change directory to $path.
*
* @param string $path Path to the directory to change to
* @return string The new path. Returns false on failure
*/
public function cd($path) {
$path = $this->realpath($path);
if (is_dir($path)) {
return $this->path = $path;
}
return false;
}
/**
* Returns an array of the contents of the current directory.
* The returned array holds two arrays: One of directories and one of files.
*
* @param boolean $sort Whether you want the results sorted, set this and the sort property
* to false to get unsorted results.
* @param mixed $exceptions Either an array or boolean true will not grab dot files
* @param boolean $fullPath True returns the full path
* @return mixed Contents of current directory as an array, an empty array on failure
*/
public function read($sort = true, $exceptions = false, $fullPath = false) {
$dirs = $files = array();
if (!$this->pwd()) {
return array($dirs, $files);
}
if (is_array($exceptions)) {
$exceptions = array_flip($exceptions);
}
$skipHidden = isset($exceptions['.']) || $exceptions === true;
if (false === ($dir = @opendir($this->path))) {
return array($dirs, $files);
}
while (false !== ($item = readdir($dir))) {
if ($item === '.' || $item === '..' || ($skipHidden && $item[0] === '.') || isset($exceptions[$item])) {
continue;
}
$path = Folder::addPathElement($this->path, $item);
if (is_dir($path)) {
$dirs[] = $fullPath ? $path : $item;
} else {
$files[] = $fullPath ? $path : $item;
}
}
if ($sort || $this->sort) {
sort($dirs);
sort($files);
}
closedir($dir);
return array($dirs, $files);
}
/**
* Returns an array of all matching files in current directory.
*
* @param string $pattern Preg_match pattern (Defaults to: .*)
* @param boolean $sort Whether results should be sorted.
* @return array Files that match given pattern
*/
public function find($regexpPattern = '.*', $sort = false) {
list($dirs, $files) = $this->read($sort);
return array_values(preg_grep('/^' . $regexpPattern . '$/i', $files)); ;
}
/**
* Returns an array of all matching files in and below current directory.
*
* @param string $pattern Preg_match pattern (Defaults to: .*)
* @param boolean $sort Whether results should be sorted.
* @return array Files matching $pattern
*/
public function findRecursive($pattern = '.*', $sort = false) {
if (!$this->pwd()) {
return array();
}
$startsOn = $this->path;
$out = $this->_findRecursive($pattern, $sort);
$this->cd($startsOn);
return $out;
}
/**
* Private helper function for findRecursive.
*
* @param string $pattern Pattern to match against
* @param boolean $sort Whether results should be sorted.
* @return array Files matching pattern
* @access private
*/
function _findRecursive($pattern, $sort = false) {
list($dirs, $files) = $this->read($sort);
$found = array();
foreach ($files as $file) {
if (preg_match('/^' . $pattern . '$/i', $file)) {
$found[] = Folder::addPathElement($this->path, $file);
}
}
$start = $this->path;
foreach ($dirs as $dir) {
$this->cd(Folder::addPathElement($start, $dir));
$found = array_merge($found, $this->findRecursive($pattern, $sort));
}
return $found;
}
/**
* Returns true if given $path is a Windows path.
*
* @param string $path Path to check
* @return boolean true if windows path, false otherwise
* @access public
* @static
*/
function isWindowsPath($path) {
return (preg_match('/^[A-Z]:\\\\/i', $path) || substr($path, 0, 2) == '\\\\');
}
/**
* Returns true if given $path is an absolute path.
*
* @param string $path Path to check
* @return bool true if path is absolute.
* @access public
* @static
*/
function isAbsolute($path) {
return !empty($path) && ($path[0] === '/' || preg_match('/^[A-Z]:\\\\/i', $path) || substr($path, 0, 2) == '\\\\');
}
/**
* Returns a correct set of slashes for given $path. (\\ for Windows paths and / for other paths.)
*
* @param string $path Path to check
* @return string Set of slashes ("\\" or "/")
* @access public
* @static
*/
function normalizePath($path) {
return Folder::correctSlashFor($path);
}
/**
* Returns a correct set of slashes for given $path. (\\ for Windows paths and / for other paths.)
*
* @param string $path Path to check
* @return string Set of slashes ("\\" or "/")
* @access public
* @static
*/
function correctSlashFor($path) {
return (Folder::isWindowsPath($path)) ? '\\' : '/';
}
/**
* Returns $path with added terminating slash (corrected for Windows or other OS).
*
* @param string $path Path to check
* @return string Path with ending slash
* @access public
* @static
*/
function slashTerm($path) {
if (Folder::isSlashTerm($path)) {
return $path;
}
return $path . Folder::correctSlashFor($path);
}
/**
* Returns $path with $element added, with correct slash in-between.
*
* @param string $path Path
* @param string $element Element to and at end of path
* @return string Combined path
* @access public
* @static
*/
function addPathElement($path, $element) {
return rtrim($path, DS) . DS . $element;
}
/**
* Returns true if the File is in a given CakePath.
*
* @param string $path The path to check.
* @return bool
*/
public function inCakePath($path = '') {
$dir = substr(Folder::slashTerm(ROOT), 0, -1);
$newdir = $dir . $path;
return $this->inPath($newdir);
}
/**
* Returns true if the File is in given path.
*
* @param string $path The path to check that the current pwd() resides with in.
* @param boolean $reverse
* @return bool
*/
public function inPath($path = '', $reverse = false) {
$dir = Folder::slashTerm($path);
$current = Folder::slashTerm($this->pwd());
if (!$reverse) {
$return = preg_match('/^(.*)' . preg_quote($dir, '/') . '(.*)/', $current);
} else {
$return = preg_match('/^(.*)' . preg_quote($current, '/') . '(.*)/', $dir);
}
return (bool)$return;
}
/**
* Change the mode on a directory structure recursively. This includes changing the mode on files as well.
*
* @param string $path The path to chmod
* @param integer $mode octal value 0755
* @param boolean $recursive chmod recursively, set to false to only change the current directory.
* @param array $exceptions array of files, directories to skip
* @return boolean Returns TRUE on success, FALSE on failure
*/
public function chmod($path, $mode = false, $recursive = true, $exceptions = array()) {
if (!$mode) {
$mode = $this->mode;
}
if ($recursive === false && is_dir($path)) {
if (@chmod($path, intval($mode, 8))) {
$this->__messages[] = sprintf(__('%s changed to %s'), $path, $mode);
return true;
}
$this->__errors[] = sprintf(__('%s NOT changed to %s'), $path, $mode);
return false;
}
if (is_dir($path)) {
$paths = $this->tree($path);
foreach ($paths as $type) {
foreach ($type as $key => $fullpath) {
$check = explode(DS, $fullpath);
$count = count($check);
if (in_array($check[$count - 1], $exceptions)) {
continue;
}
if (@chmod($fullpath, intval($mode, 8))) {
$this->__messages[] = sprintf(__('%s changed to %s'), $fullpath, $mode);
} else {
$this->__errors[] = sprintf(__('%s NOT changed to %s'), $fullpath, $mode);
}
}
}
if (empty($this->__errors)) {
return true;
}
}
return false;
}
/**
* Returns an array of nested directories and files in each directory
*
* @param string $path the directory path to build the tree from
* @param mixed $exceptions Array of files to exclude, defaults to excluding hidden files.
* @param string $type either file or dir. null returns both files and directories
* @return mixed array of nested directories and files in each directory
*/
public function tree($path, $exceptions = true, $type = null) {
$original = $this->path;
$path = rtrim($path, DS);
if (!$this->cd($path)) {
if ($type === null) {
return array(array(), array());
}
return array();
}
$this->__files = array();
$this->__directories = array($this->realpath($path));
$directories = array();
if ($exceptions === false) {
$exceptions = true;
}
while (!empty($this->__directories)) {
$dir = array_pop($this->__directories);
$this->__tree($dir, $exceptions);
$directories[] = $dir;
}
if ($type === null) {
return array($directories, $this->__files);
}
if ($type === 'dir') {
return $directories;
}
$this->cd($original);
return $this->__files;
}
/**
* Private method to list directories and files in each directory
*
* @param string $path The Path to read.
* @param mixed $exceptions Array of files to exclude from the read that will be performed.
* @access private
*/
function __tree($path, $exceptions) {
$this->path = $path;
list($dirs, $files) = $this->read(false, $exceptions, true);
$this->__directories = array_merge($this->__directories, $dirs);
$this->__files = array_merge($this->__files, $files);
}
/**
* Create a directory structure recursively. Can be used to create
* deep path structures like `/foo/bar/baz/shoe/horn`
*
* @param string $pathname The directory structure to create
* @param integer $mode octal value 0755
* @return boolean Returns TRUE on success, FALSE on failure
*/
public function create($pathname, $mode = false) {
if (is_dir($pathname) || empty($pathname)) {
return true;
}
if (!$mode) {
$mode = $this->mode;
}
if (is_file($pathname)) {
$this->__errors[] = sprintf(__('%s is a file'), $pathname);
return false;
}
$pathname = rtrim($pathname, DS);
$nextPathname = substr($pathname, 0, strrpos($pathname, DS));
if ($this->create($nextPathname, $mode)) {
if (!file_exists($pathname)) {
$old = umask(0);
if (mkdir($pathname, $mode)) {
umask($old);
$this->__messages[] = sprintf(__('%s created'), $pathname);
return true;
} else {
umask($old);
$this->__errors[] = sprintf(__('%s NOT created'), $pathname);
return false;
}
}
}
return false;
}
/**
* Returns the size in bytes of this Folder and its contents.
*
* @param string $directory Path to directory
* @return int size in bytes of current folder
*/
public function dirsize() {
$size = 0;
$directory = Folder::slashTerm($this->path);
$stack = array($directory);
$count = count($stack);
for ($i = 0, $j = $count; $i < $j; ++$i) {
if (is_file($stack[$i])) {
$size += filesize($stack[$i]);
} elseif (is_dir($stack[$i])) {
$dir = dir($stack[$i]);
if ($dir) {
while (false !== ($entry = $dir->read())) {
if ($entry === '.' || $entry === '..') {
continue;
}
$add = $stack[$i] . $entry;
if (is_dir($stack[$i] . $entry)) {
$add = Folder::slashTerm($add);
}
$stack[] = $add;
}
$dir->close();
}
}
$j = count($stack);
}
return $size;
}
/**
* Recursively Remove directories if the system allows.
*
* @param string $path Path of directory to delete
* @return boolean Success
*/
public function delete($path = null) {
if (!$path) {
$path = $this->pwd();
}
if (!$path) {
return null;
}
$path = Folder::slashTerm($path);
if (is_dir($path) === true) {
$normalFiles = glob($path . '*');
$hiddenFiles = glob($path . '\.?*');
$normalFiles = $normalFiles ? $normalFiles : array();
$hiddenFiles = $hiddenFiles ? $hiddenFiles : array();
$files = array_merge($normalFiles, $hiddenFiles);
if (is_array($files)) {
foreach ($files as $file) {
if (preg_match('/(\.|\.\.)$/', $file)) {
continue;
}
if (is_file($file) === true) {
if (@unlink($file)) {
$this->__messages[] = sprintf(__('%s removed'), $file);
} else {
$this->__errors[] = sprintf(__('%s NOT removed'), $file);
}
} elseif (is_dir($file) === true && $this->delete($file) === false) {
return false;
}
}
}
$path = substr($path, 0, strlen($path) - 1);
if (rmdir($path) === false) {
$this->__errors[] = sprintf(__('%s NOT removed'), $path);
return false;
} else {
$this->__messages[] = sprintf(__('%s removed'), $path);
}
}
return true;
}
/**
* Recursive directory copy.
*
* ### Options
*
* - `to` The directory to copy to.
* - `from` The directory to copy from, this will cause a cd() to occur, changing the results of pwd().
* - `chmod` The mode to copy the files/directories with.
* - `skip` Files/directories to skip.
*
* @param mixed $options Either an array of options (see above) or a string of the destination directory.
* @return bool Success
*/
public function copy($options = array()) {
if (!$this->pwd()) {
return false;
}
$to = null;
if (is_string($options)) {
$to = $options;
$options = array();
}
$options = array_merge(array('to' => $to, 'from' => $this->path, 'mode' => $this->mode, 'skip' => array()), $options);
$fromDir = $options['from'];
$toDir = $options['to'];
$mode = $options['mode'];
if (!$this->cd($fromDir)) {
$this->__errors[] = sprintf(__('%s not found'), $fromDir);
return false;
}
if (!is_dir($toDir)) {
$this->create($toDir, $mode);
}
if (!is_writable($toDir)) {
$this->__errors[] = sprintf(__('%s not writable'), $toDir);
return false;
}
$exceptions = array_merge(array('.', '..', '.svn'), $options['skip']);
if ($handle = @opendir($fromDir)) {
while (false !== ($item = readdir($handle))) {
if (!in_array($item, $exceptions)) {
$from = Folder::addPathElement($fromDir, $item);
$to = Folder::addPathElement($toDir, $item);
if (is_file($from)) {
if (copy($from, $to)) {
chmod($to, intval($mode, 8));
touch($to, filemtime($from));
$this->__messages[] = sprintf(__('%s copied to %s'), $from, $to);
} else {
$this->__errors[] = sprintf(__('%s NOT copied to %s'), $from, $to);
}
}
if (is_dir($from) && !file_exists($to)) {
$old = umask(0);
if (mkdir($to, $mode)) {
umask($old);
$old = umask(0);
chmod($to, $mode);
umask($old);
$this->__messages[] = sprintf(__('%s created'), $to);
$options = array_merge($options, array('to'=> $to, 'from'=> $from));
$this->copy($options);
} else {
$this->__errors[] = sprintf(__('%s not created'), $to);
}
}
}
}
closedir($handle);
} else {
return false;
}
if (!empty($this->__errors)) {
return false;
}
return true;
}
/**
* Recursive directory move.
*
* ### Options
*
* - `to` The directory to copy to.
* - `from` The directory to copy from, this will cause a cd() to occur, changing the results of pwd().
* - `chmod` The mode to copy the files/directories with.
* - `skip` Files/directories to skip.
*
* @param array $options (to, from, chmod, skip)
* @return boolean Success
*/
public function move($options) {
$to = null;
if (is_string($options)) {
$to = $options;
$options = (array)$options;
}
$options = array_merge(
array('to' => $to, 'from' => $this->path, 'mode' => $this->mode, 'skip' => array()),
$options
);
if ($this->copy($options)) {
if ($this->delete($options['from'])) {
return (bool)$this->cd($options['to']);
}
}
return false;
}
/**
* get messages from latest method
*
* @return array
*/
public function messages() {
return $this->__messages;
}
/**
* get error from latest method
*
* @return array
*/
public function errors() {
return $this->__errors;
}
/**
* Get the real path (taking ".." and such into account)
*
* @param string $path Path to resolve
* @return string The resolved path
*/
function realpath($path) {
$path = str_replace('/', DS, trim($path));
if (strpos($path, '..') === false) {
if (!Folder::isAbsolute($path)) {
$path = Folder::addPathElement($this->path, $path);
}
return $path;
}
$parts = explode(DS, $path);
$newparts = array();
$newpath = '';
if ($path[0] === DS) {
$newpath = DS;
}
while (($part = array_shift($parts)) !== NULL) {
if ($part === '.' || $part === '') {
continue;
}
if ($part === '..') {
if (!empty($newparts)) {
array_pop($newparts);
continue;
} else {
return false;
}
}
$newparts[] = $part;
}
$newpath .= implode(DS, $newparts);
return Folder::slashTerm($newpath);
}
/**
* Returns true if given $path ends in a slash (i.e. is slash-terminated).
*
* @param string $path Path to check
* @return boolean true if path ends with slash, false otherwise
* @access public
* @static
*/
function isSlashTerm($path) {
$lastChar = $path[strlen($path) - 1];
return $lastChar === '/' || $lastChar === '\\';
}
}

View file

@ -0,0 +1,570 @@
<?php
/**
* Pluralize and singularize English words.
*
* Used by Cake's naming conventions throughout the framework.
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package cake
* @subpackage cake.cake.libs
* @since CakePHP(tm) v 0.2.9
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* Pluralize and singularize English words.
*
* Inflector pluralizes and singularizes English nouns.
* Used by Cake's naming conventions throughout the framework.
*
* @package cake
* @subpackage cake.cake.libs
* @link http://book.cakephp.org/view/1478/Inflector
*/
class Inflector {
/**
* Plural inflector rules
*
* @var array
*/
protected static $_plural = array(
'rules' => array(
'/(s)tatus$/i' => '\1\2tatuses',
'/(quiz)$/i' => '\1zes',
'/^(ox)$/i' => '\1\2en',
'/([m|l])ouse$/i' => '\1ice',
'/(matr|vert|ind)(ix|ex)$/i' => '\1ices',
'/(x|ch|ss|sh)$/i' => '\1es',
'/([^aeiouy]|qu)y$/i' => '\1ies',
'/(hive)$/i' => '\1s',
'/(?:([^f])fe|([lr])f)$/i' => '\1\2ves',
'/sis$/i' => 'ses',
'/([ti])um$/i' => '\1a',
'/(p)erson$/i' => '\1eople',
'/(m)an$/i' => '\1en',
'/(c)hild$/i' => '\1hildren',
'/(buffal|tomat)o$/i' => '\1\2oes',
'/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|vir)us$/i' => '\1i',
'/us$/i' => 'uses',
'/(alias)$/i' => '\1es',
'/(ax|cris|test)is$/i' => '\1es',
'/s$/' => 's',
'/^$/' => '',
'/$/' => 's',
),
'uninflected' => array(
'.*[nrlm]ese', '.*deer', '.*fish', '.*measles', '.*ois', '.*pox', '.*sheep', 'people'
),
'irregular' => array(
'atlas' => 'atlases',
'beef' => 'beefs',
'brother' => 'brothers',
'child' => 'children',
'corpus' => 'corpuses',
'cow' => 'cows',
'ganglion' => 'ganglions',
'genie' => 'genies',
'genus' => 'genera',
'graffito' => 'graffiti',
'hoof' => 'hoofs',
'loaf' => 'loaves',
'man' => 'men',
'money' => 'monies',
'mongoose' => 'mongooses',
'move' => 'moves',
'mythos' => 'mythoi',
'niche' => 'niches',
'numen' => 'numina',
'occiput' => 'occiputs',
'octopus' => 'octopuses',
'opus' => 'opuses',
'ox' => 'oxen',
'penis' => 'penises',
'person' => 'people',
'sex' => 'sexes',
'soliloquy' => 'soliloquies',
'testis' => 'testes',
'trilby' => 'trilbys',
'turf' => 'turfs'
)
);
/**
* Singular inflector rules
*
* @var array
*/
protected static $_singular = array(
'rules' => array(
'/(s)tatuses$/i' => '\1\2tatus',
'/^(.*)(menu)s$/i' => '\1\2',
'/(quiz)zes$/i' => '\\1',
'/(matr)ices$/i' => '\1ix',
'/(vert|ind)ices$/i' => '\1ex',
'/^(ox)en/i' => '\1',
'/(alias)(es)*$/i' => '\1',
'/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|viri?)i$/i' => '\1us',
'/([ftw]ax)es/i' => '\1',
'/(cris|ax|test)es$/i' => '\1is',
'/(shoe|slave)s$/i' => '\1',
'/(o)es$/i' => '\1',
'/ouses$/' => 'ouse',
'/([^a])uses$/' => '\1us',
'/([m|l])ice$/i' => '\1ouse',
'/(x|ch|ss|sh)es$/i' => '\1',
'/(m)ovies$/i' => '\1\2ovie',
'/(s)eries$/i' => '\1\2eries',
'/([^aeiouy]|qu)ies$/i' => '\1y',
'/([lr])ves$/i' => '\1f',
'/(tive)s$/i' => '\1',
'/(hive)s$/i' => '\1',
'/(drive)s$/i' => '\1',
'/([^fo])ves$/i' => '\1fe',
'/(^analy)ses$/i' => '\1sis',
'/(analy|ba|diagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => '\1\2sis',
'/([ti])a$/i' => '\1um',
'/(p)eople$/i' => '\1\2erson',
'/(m)en$/i' => '\1an',
'/(c)hildren$/i' => '\1\2hild',
'/(n)ews$/i' => '\1\2ews',
'/eaus$/' => 'eau',
'/^(.*us)$/' => '\\1',
'/s$/i' => ''
),
'uninflected' => array(
'.*[nrlm]ese', '.*deer', '.*fish', '.*measles', '.*ois', '.*pox', '.*sheep', '.*ss'
),
'irregular' => array(
'waves' => 'wave'
)
);
/**
* Words that should not be inflected
*
* @var array
*/
protected static $_uninflected = array(
'Amoyese', 'bison', 'Borghese', 'bream', 'breeches', 'britches', 'buffalo', 'cantus',
'carp', 'chassis', 'clippers', 'cod', 'coitus', 'Congoese', 'contretemps', 'corps',
'debris', 'diabetes', 'djinn', 'eland', 'elk', 'equipment', 'Faroese', 'flounder',
'Foochowese', 'gallows', 'Genevese', 'Genoese', 'Gilbertese', 'graffiti',
'headquarters', 'herpes', 'hijinks', 'Hottentotese', 'information', 'innings',
'jackanapes', 'Kiplingese', 'Kongoese', 'Lucchese', 'mackerel', 'Maltese', 'media',
'mews', 'moose', 'mumps', 'Nankingese', 'news', 'nexus', 'Niasese',
'Pekingese', 'Piedmontese', 'pincers', 'Pistoiese', 'pliers', 'Portuguese',
'proceedings', 'rabies', 'rice', 'rhinoceros', 'salmon', 'Sarawakese', 'scissors',
'sea[- ]bass', 'series', 'Shavese', 'shears', 'siemens', 'species', 'swine', 'testes',
'trousers', 'trout','tuna', 'Vermontese', 'Wenchowese', 'whiting', 'wildebeest',
'Yengeese'
);
/**
* Default map of accented and special characters to ASCII characters
*
* @var array
*/
protected static $_transliteration = array(
'/ä|æ|ǽ/' => 'ae',
'/ö|œ/' => 'oe',
'/ü/' => 'ue',
'/Ä/' => 'Ae',
'/Ü/' => 'Ue',
'/Ö/' => 'Oe',
'/À|Á|Â|Ã|Ä|Å|Ǻ|Ā|Ă|Ą|Ǎ/' => 'A',
'/à|á|â|ã|å|ǻ|ā|ă|ą|ǎ|ª/' => 'a',
'/Ç|Ć|Ĉ|Ċ|Č/' => 'C',
'/ç|ć|ĉ|ċ|č/' => 'c',
'/Ð|Ď|Đ/' => 'D',
'/ð|ď|đ/' => 'd',
'/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě/' => 'E',
'/è|é|ê|ë|ē|ĕ|ė|ę|ě/' => 'e',
'/Ĝ|Ğ|Ġ|Ģ/' => 'G',
'/ĝ|ğ|ġ|ģ/' => 'g',
'/Ĥ|Ħ/' => 'H',
'/ĥ|ħ/' => 'h',
'/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ/' => 'I',
'/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı/' => 'i',
'/Ĵ/' => 'J',
'/ĵ/' => 'j',
'/Ķ/' => 'K',
'/ķ/' => 'k',
'/Ĺ|Ļ|Ľ|Ŀ|Ł/' => 'L',
'/ĺ|ļ|ľ|ŀ|ł/' => 'l',
'/Ñ|Ń|Ņ|Ň/' => 'N',
'/ñ|ń|ņ|ň|ʼn/' => 'n',
'/Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ/' => 'O',
'/ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º/' => 'o',
'/Ŕ|Ŗ|Ř/' => 'R',
'/ŕ|ŗ|ř/' => 'r',
'/Ś|Ŝ|Ş|Š/' => 'S',
'/ś|ŝ|ş|š|ſ/' => 's',
'/Ţ|Ť|Ŧ/' => 'T',
'/ţ|ť|ŧ/' => 't',
'/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ/' => 'U',
'/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ/' => 'u',
'/Ý|Ÿ|Ŷ/' => 'Y',
'/ý|ÿ|ŷ/' => 'y',
'/Ŵ/' => 'W',
'/ŵ/' => 'w',
'/Ź|Ż|Ž/' => 'Z',
'/ź|ż|ž/' => 'z',
'/Æ|Ǽ/' => 'AE',
'/ß/'=> 'ss',
'/IJ/' => 'IJ',
'/ij/' => 'ij',
'/Œ/' => 'OE',
'/ƒ/' => 'f'
);
/**
* Method cache array.
*
* @var array
*/
protected static $_cache = array();
/**
* The initial state of Inflector so reset() works.
*
* @var array
*/
protected static $_initialState = array();
/**
* Cache inflected values, and return if already available
*
* @param string $type Inflection type
* @param string $key Original value
* @param string $value Inflected value
* @return string Inflected value, from cache
*/
protected static function _cache($type, $key, $value = false) {
$key = '_' . $key;
$type = '_' . $type;
if ($value !== false) {
self::$_cache[$type][$key] = $value;
return $value;
}
if (!isset(self::$_cache[$type][$key])) {
return false;
}
return self::$_cache[$type][$key];
}
/**
* Clears Inflectors inflected value caches. And resets the inflection
* rules to the initial values.
*
* @return void
*/
public static function reset() {
if (empty(self::$_initialState)) {
self::$_initialState = get_class_vars('Inflector');
return;
}
foreach (self::$_initialState as $key => $val) {
if ($key != '_initialState') {
self::${$key} = $val;
}
}
}
/**
* Adds custom inflection $rules, of either 'plural', 'singular' or 'transliteration' $type.
*
* ### Usage:
*
* {{{
* Inflector::rules('plural', array('/^(inflect)or$/i' => '\1ables'));
* Inflector::rules('plural', array(
* 'rules' => array('/^(inflect)ors$/i' => '\1ables'),
* 'uninflected' => array('dontinflectme'),
* 'irregular' => array('red' => 'redlings')
* ));
* Inflector::rules('transliteration', array('/å/' => 'aa'));
* }}}
*
* @param string $type The type of inflection, either 'plural', 'singular' or 'transliteration'
* @param array $rules Array of rules to be added.
* @param boolean $reset If true, will unset default inflections for all
* new rules that are being defined in $rules.
* @access public
* @return void
*/
public static function rules($type, $rules, $reset = false) {
$var = '_' . $type;
switch ($type) {
case 'transliteration':
if ($reset) {
self::$_transliteration = $rules;
} else {
self::$_transliteration = $rules + self::$_transliteration;
}
break;
default:
foreach ($rules as $rule => $pattern) {
if (is_array($pattern)) {
if ($reset) {
self::${$var}[$rule] = $pattern;
} else {
self::${$var}[$rule] = array_merge($pattern, self::${$var}[$rule]);
}
unset($rules[$rule], self::${$var}['cache' . ucfirst($rule)]);
if (isset(self::${$var}['merged'][$rule])) {
unset(self::${$var}['merged'][$rule]);
}
if ($type === 'plural') {
self::$_cache['pluralize'] = self::$_cache['tableize'] = array();
} elseif ($type === 'singular') {
self::$_cache['singularize'] = array();
}
}
}
self::${$var}['rules'] = array_merge($rules, self::${$var}['rules']);
break;
}
}
/**
* Return $word in plural form.
*
* @param string $word Word in singular
* @return string Word in plural
* @access public
* @link http://book.cakephp.org/view/1479/Class-methods
*/
public static function pluralize($word) {
if (isset(self::$_cache['pluralize'][$word])) {
return self::$_cache['pluralize'][$word];
}
if (!isset(self::$_plural['merged']['irregular'])) {
self::$_plural['merged']['irregular'] = self::$_plural['irregular'];
}
if (!isset(self::$_plural['merged']['uninflected'])) {
self::$_plural['merged']['uninflected'] = array_merge(self::$_plural['uninflected'], self::$_uninflected);
}
if (!isset(self::$_plural['cacheUninflected']) || !isset(self::$_plural['cacheIrregular'])) {
self::$_plural['cacheUninflected'] = '(?:' . implode('|', self::$_plural['merged']['uninflected']) . ')';
self::$_plural['cacheIrregular'] = '(?:' . implode('|', array_keys(self::$_plural['merged']['irregular'])) . ')';
}
if (preg_match('/(.*)\\b(' . self::$_plural['cacheIrregular'] . ')$/i', $word, $regs)) {
self::$_cache['pluralize'][$word] = $regs[1] . substr($word, 0, 1) . substr(self::$_plural['merged']['irregular'][strtolower($regs[2])], 1);
return self::$_cache['pluralize'][$word];
}
if (preg_match('/^(' . self::$_plural['cacheUninflected'] . ')$/i', $word, $regs)) {
self::$_cache['pluralize'][$word] = $word;
return $word;
}
foreach (self::$_plural['rules'] as $rule => $replacement) {
if (preg_match($rule, $word)) {
self::$_cache['pluralize'][$word] = preg_replace($rule, $replacement, $word);
return self::$_cache['pluralize'][$word];
}
}
}
/**
* Return $word in singular form.
*
* @param string $word Word in plural
* @return string Word in singular
* @access public
* @link http://book.cakephp.org/view/1479/Class-methods
*/
public static function singularize($word) {
if (isset(self::$_cache['singularize'][$word])) {
return self::$_cache['singularize'][$word];
}
if (!isset(self::$_singular['merged']['uninflected'])) {
self::$_singular['merged']['uninflected'] = array_merge(
self::$_singular['uninflected'],
self::$_uninflected
);
}
if (!isset(self::$_singular['merged']['irregular'])) {
self::$_singular['merged']['irregular'] = array_merge(
self::$_singular['irregular'],
array_flip(self::$_plural['irregular'])
);
}
if (!isset(self::$_singular['cacheUninflected']) || !isset(self::$_singular['cacheIrregular'])) {
self::$_singular['cacheUninflected'] = '(?:' . join( '|', self::$_singular['merged']['uninflected']) . ')';
self::$_singular['cacheIrregular'] = '(?:' . join( '|', array_keys(self::$_singular['merged']['irregular'])) . ')';
}
if (preg_match('/(.*)\\b(' . self::$_singular['cacheIrregular'] . ')$/i', $word, $regs)) {
self::$_cache['singularize'][$word] = $regs[1] . substr($word, 0, 1) . substr(self::$_singular['merged']['irregular'][strtolower($regs[2])], 1);
return self::$_cache['singularize'][$word];
}
if (preg_match('/^(' . self::$_singular['cacheUninflected'] . ')$/i', $word, $regs)) {
self::$_cache['singularize'][$word] = $word;
return $word;
}
foreach (self::$_singular['rules'] as $rule => $replacement) {
if (preg_match($rule, $word)) {
self::$_cache['singularize'][$word] = preg_replace($rule, $replacement, $word);
return self::$_cache['singularize'][$word];
}
}
self::$_cache['singularize'][$word] = $word;
return $word;
}
/**
* Returns the given lower_case_and_underscored_word as a CamelCased word.
*
* @param string $lower_case_and_underscored_word Word to camelize
* @return string Camelized word. LikeThis.
* @access public
* @link http://book.cakephp.org/view/1479/Class-methods
*/
public static function camelize($lowerCaseAndUnderscoredWord) {
if (!($result = self::_cache(__FUNCTION__, $lowerCaseAndUnderscoredWord))) {
$result = str_replace(' ', '', Inflector::humanize($lowerCaseAndUnderscoredWord));
self::_cache(__FUNCTION__, $lowerCaseAndUnderscoredWord, $result);
}
return $result;
}
/**
* Returns the given camelCasedWord as an underscored_word.
*
* @param string $camelCasedWord Camel-cased word to be "underscorized"
* @return string Underscore-syntaxed version of the $camelCasedWord
* @access public
* @link http://book.cakephp.org/view/1479/Class-methods
*/
public static function underscore($camelCasedWord) {
if (!($result = self::_cache(__FUNCTION__, $camelCasedWord))) {
$result = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $camelCasedWord));
self::_cache(__FUNCTION__, $camelCasedWord, $result);
}
return $result;
}
/**
* Returns the given underscored_word_group as a Human Readable Word Group.
* (Underscores are replaced by spaces and capitalized following words.)
*
* @param string $lower_case_and_underscored_word String to be made more readable
* @return string Human-readable string
* @access public
* @link http://book.cakephp.org/view/1479/Class-methods
*/
public static function humanize($lowerCaseAndUnderscoredWord) {
if (!($result = self::_cache(__FUNCTION__, $lowerCaseAndUnderscoredWord))) {
$result = ucwords(str_replace('_', ' ', $lowerCaseAndUnderscoredWord));
self::_cache(__FUNCTION__, $lowerCaseAndUnderscoredWord, $result);
}
return $result;
}
/**
* Returns corresponding table name for given model $className. ("people" for the model class "Person").
*
* @param string $className Name of class to get database table name for
* @return string Name of the database table for given class
* @access public
* @link http://book.cakephp.org/view/1479/Class-methods
*/
public static function tableize($className) {
if (!($result = self::_cache(__FUNCTION__, $className))) {
$result = Inflector::pluralize(Inflector::underscore($className));
self::_cache(__FUNCTION__, $className, $result);
}
return $result;
}
/**
* Returns Cake model class name ("Person" for the database table "people".) for given database table.
*
* @param string $tableName Name of database table to get class name for
* @return string Class name
* @access public
* @link http://book.cakephp.org/view/1479/Class-methods
*/
public static function classify($tableName) {
if (!($result = self::_cache(__FUNCTION__, $tableName))) {
$result = Inflector::camelize(Inflector::singularize($tableName));
self::_cache(__FUNCTION__, $tableName, $result);
}
return $result;
}
/**
* Returns camelBacked version of an underscored string.
*
* @param string $string
* @return string in variable form
* @access public
* @link http://book.cakephp.org/view/1479/Class-methods
*/
public static function variable($string) {
if (!($result = self::_cache(__FUNCTION__, $string))) {
$string2 = Inflector::camelize(Inflector::underscore($string));
$replace = strtolower(substr($string2, 0, 1));
$result = preg_replace('/\\w/', $replace, $string2, 1);
self::_cache(__FUNCTION__, $string, $result);
}
return $result;
}
/**
* Returns a string with all spaces converted to underscores (by default), accented
* characters converted to non-accented characters, and non word characters removed.
*
* @param string $string the string you want to slug
* @param string $replacement will replace keys in map
* @param array $map extra elements to map to the replacement
* @deprecated $map param will be removed in future versions. Use Inflector::rules() instead
* @return string
* @access public
* @link http://book.cakephp.org/view/1479/Class-methods
*/
public static function slug($string, $replacement = '_', $map = array()) {
if (is_array($replacement)) {
$map = $replacement;
$replacement = '_';
}
$quotedReplacement = preg_quote($replacement, '/');
$merge = array(
'/[^\s\p{Ll}\p{Lm}\p{Lo}\p{Lt}\p{Lu}\p{Nd}]/mu' => ' ',
'/\\s+/' => $replacement,
sprintf('/^[%s]+|[%s]+$/', $quotedReplacement, $quotedReplacement) => '',
);
$map = $map + self::$_transliteration + $merge;
return preg_replace(array_keys($map), array_values($map), $string);
}
}
// Store the initial state
Inflector::reset();