2007-07-19 12:40:28 +02:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* Provides introspection information about the class tree.
|
2012-03-24 04:38:57 +01:00
|
|
|
* It's a cached wrapper around the built-in class functions. SilverStripe uses class introspection heavily
|
2007-07-19 12:40:28 +02:00
|
|
|
* and without the caching it creates an unfortunate performance hit.
|
2008-02-25 03:10:37 +01:00
|
|
|
*
|
2012-04-12 08:02:46 +02:00
|
|
|
* @package framework
|
2008-02-25 03:10:37 +01:00
|
|
|
* @subpackage core
|
2007-07-19 12:40:28 +02:00
|
|
|
*/
|
|
|
|
class ClassInfo {
|
2012-04-17 04:46:07 +02:00
|
|
|
/**
|
|
|
|
* Wrapper for classes getter.
|
2008-03-03 00:24:10 +01:00
|
|
|
*/
|
2007-07-19 12:40:28 +02:00
|
|
|
static function allClasses() {
|
2012-04-17 04:46:07 +02:00
|
|
|
return SS_ClassLoader::instance()->getManifest()->getClasses();
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2008-03-03 00:24:10 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @todo Improve documentation
|
|
|
|
*/
|
2007-07-19 12:40:28 +02:00
|
|
|
static function exists($class) {
|
2011-03-22 10:47:55 +01:00
|
|
|
return SS_ClassLoader::instance()->classExists($class);
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2008-03-03 00:24:10 +01:00
|
|
|
|
2009-03-04 04:44:11 +01:00
|
|
|
/**
|
|
|
|
* Cache for {@link hasTable()}
|
|
|
|
*/
|
|
|
|
private static $_cache_all_tables = null;
|
2012-01-02 14:01:16 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var Array Cache for {@link ancestry()}.
|
|
|
|
*/
|
|
|
|
private static $_cache_ancestry = array();
|
2009-03-04 04:44:11 +01:00
|
|
|
|
2008-03-03 00:24:10 +01:00
|
|
|
/**
|
API CHANGE: Renamed conflicting classes to have an "SS_" namespace, and renamed existing "SS" namespace to "SS_". The affected classes are: HTTPRequest, HTTPResponse, Query, Database, SSBacktrace, SSCli, SSDatetime, SSDatetimeTest, SSLog, SSLogTest, SSLogEmailWriter, SSLogErrorEmailFormatter, SSLogErrorFileFormatter, SSLogFileWriter and SSZendLog.
MINOR: Replaced usage of renamed classes with the new namespaced name.
From: Andrew Short <andrewjshort@gmail.com>
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@90075 467b73ca-7a2a-4603-9d3b-597d59a354a9
2009-10-26 04:06:31 +01:00
|
|
|
* @todo Move this to SS_Database or DB
|
2008-03-03 00:24:10 +01:00
|
|
|
*/
|
2007-07-19 12:40:28 +02:00
|
|
|
static function hasTable($class) {
|
2008-11-09 23:11:25 +01:00
|
|
|
if(DB::isActive()) {
|
2009-03-04 04:44:11 +01:00
|
|
|
// Cache the list of all table names to reduce on DB traffic
|
2010-10-13 05:59:16 +02:00
|
|
|
if(empty(self::$_cache_all_tables)) {
|
2009-03-04 04:44:11 +01:00
|
|
|
self::$_cache_all_tables = array();
|
2009-03-11 22:43:28 +01:00
|
|
|
$tables = DB::query(DB::getConn()->allTablesSQL())->column();
|
2009-03-04 04:44:11 +01:00
|
|
|
foreach($tables as $table) self::$_cache_all_tables[strtolower($table)] = true;
|
|
|
|
}
|
|
|
|
return isset(self::$_cache_all_tables[strtolower($class)]);
|
2008-11-09 23:11:25 +01:00
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
|
|
|
|
2010-04-12 04:03:16 +02:00
|
|
|
static function reset_db_cache() {
|
|
|
|
self::$_cache_all_tables = null;
|
2012-01-02 14:01:16 +01:00
|
|
|
self::$_cache_ancestry = array();
|
2010-04-12 04:03:16 +02:00
|
|
|
}
|
|
|
|
|
2007-07-19 12:40:28 +02:00
|
|
|
/**
|
|
|
|
* Returns the manifest of all classes which are present in the database.
|
2010-10-19 03:31:56 +02:00
|
|
|
* @param string $class Class name to check enum values for ClassName field
|
2007-07-19 12:40:28 +02:00
|
|
|
*/
|
2010-10-19 03:31:56 +02:00
|
|
|
static function getValidSubClasses($class = 'SiteTree') {
|
|
|
|
return DB::getConn()->enumValuesForField($class, 'ClassName');
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-02-19 05:35:59 +01:00
|
|
|
* Returns an array of the current class and all its ancestors and children
|
|
|
|
* which have a DB table.
|
2008-04-14 06:49:08 +02:00
|
|
|
*
|
2011-02-19 05:35:59 +01:00
|
|
|
* @param string|object $class
|
2008-11-06 05:51:25 +01:00
|
|
|
* @todo Move this into data object
|
2008-04-14 06:49:08 +02:00
|
|
|
* @return array
|
2007-07-19 12:40:28 +02:00
|
|
|
*/
|
2011-02-19 05:35:59 +01:00
|
|
|
public static function dataClassesFor($class) {
|
|
|
|
$result = array();
|
|
|
|
|
|
|
|
if (is_object($class)) {
|
|
|
|
$class = get_class($class);
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
|
|
|
|
2011-02-19 05:35:59 +01:00
|
|
|
$classes = array_merge(
|
|
|
|
self::ancestry($class),
|
|
|
|
self::subclassesFor($class));
|
|
|
|
|
|
|
|
foreach ($classes as $class) {
|
|
|
|
if (self::hasTable($class)) $result[$class] = $class;
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2011-02-19 05:35:59 +01:00
|
|
|
|
|
|
|
return $result;
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2011-03-24 10:14:38 +01:00
|
|
|
|
2007-07-19 12:40:28 +02:00
|
|
|
/**
|
2011-03-24 10:14:38 +01:00
|
|
|
* Returns the root class (the first to extend from DataObject) for the
|
|
|
|
* passed class.
|
|
|
|
*
|
|
|
|
* @param string|object $class
|
|
|
|
* @return string
|
2007-07-19 12:40:28 +02:00
|
|
|
*/
|
2011-03-24 10:14:38 +01:00
|
|
|
public static function baseDataClass($class) {
|
2008-04-14 06:49:08 +02:00
|
|
|
if (is_object($class)) $class = get_class($class);
|
2011-03-24 10:14:38 +01:00
|
|
|
|
2011-10-29 05:56:38 +02:00
|
|
|
if (!is_subclass_of($class, 'DataObject')) {
|
2011-12-16 23:51:40 +01:00
|
|
|
throw new InvalidArgumentException("$class is not a subclass of DataObject");
|
2011-03-24 10:14:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
while ($next = get_parent_class($class)) {
|
|
|
|
if ($next == 'DataObject') {
|
|
|
|
return $class;
|
|
|
|
}
|
|
|
|
|
|
|
|
$class = $next;
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
|
|
|
}
|
2011-03-24 10:14:38 +01:00
|
|
|
|
2008-03-03 00:24:10 +01:00
|
|
|
/**
|
2008-04-14 06:49:08 +02:00
|
|
|
* Returns a list of classes that inherit from the given class.
|
2009-02-02 00:49:53 +01:00
|
|
|
* The resulting array includes the base class passed
|
|
|
|
* through the $class parameter as the first array value.
|
|
|
|
*
|
|
|
|
* Example usage:
|
2009-03-22 23:59:14 +01:00
|
|
|
* <code>
|
2009-02-02 00:49:53 +01:00
|
|
|
* ClassInfo::subclassesFor('BaseClass');
|
|
|
|
* array(
|
|
|
|
* 0 => 'BaseClass',
|
|
|
|
* 'ChildClass' => 'ChildClass',
|
|
|
|
* 'GrandChildClass' => 'GrandChildClass'
|
|
|
|
* )
|
2009-03-22 23:59:14 +01:00
|
|
|
* </code>
|
2008-04-14 06:49:08 +02:00
|
|
|
*
|
|
|
|
* @param mixed $class string of the classname or instance of the class
|
2009-02-02 00:49:53 +01:00
|
|
|
* @return array Names of all subclasses as an associative array.
|
2008-03-03 00:24:10 +01:00
|
|
|
*/
|
2011-02-21 06:16:52 +01:00
|
|
|
public static function subclassesFor($class) {
|
2011-03-22 10:47:55 +01:00
|
|
|
$descendants = SS_ClassLoader::instance()->getManifest()->getDescendantsOf($class);
|
|
|
|
$result = array($class => $class);
|
2009-02-02 00:49:53 +01:00
|
|
|
|
2011-03-22 10:47:55 +01:00
|
|
|
if ($descendants) {
|
|
|
|
return $result + ArrayLib::valuekey($descendants);
|
|
|
|
} else {
|
|
|
|
return $result;
|
2009-02-02 00:49:53 +01:00
|
|
|
}
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2011-03-22 10:47:55 +01:00
|
|
|
|
2008-03-03 00:24:10 +01:00
|
|
|
/**
|
2011-02-19 04:18:26 +01:00
|
|
|
* Returns the passed class name along with all its parent class names in an
|
|
|
|
* array, sorted with the root class first.
|
|
|
|
*
|
|
|
|
* @param string $class
|
|
|
|
* @param bool $tablesOnly Only return classes that have a table in the db.
|
|
|
|
* @return array
|
2008-03-03 00:24:10 +01:00
|
|
|
*/
|
2011-02-19 04:18:26 +01:00
|
|
|
public static function ancestry($class, $tablesOnly = false) {
|
2012-01-02 14:01:16 +01:00
|
|
|
if (!is_string($class)) $class = get_class($class);
|
|
|
|
|
|
|
|
$cacheKey = $class . '_' . (string)$tablesOnly;
|
|
|
|
$parent = $class;
|
|
|
|
if(!isset(self::$_cache_ancestry[$cacheKey])) {
|
|
|
|
$ancestry = array();
|
|
|
|
do {
|
|
|
|
if (!$tablesOnly || DataObject::has_own_table($parent)) {
|
|
|
|
$ancestry[$parent] = $parent;
|
|
|
|
}
|
|
|
|
} while ($parent = get_parent_class($parent));
|
|
|
|
self::$_cache_ancestry[$cacheKey] = array_reverse($ancestry);
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2011-02-19 04:18:26 +01:00
|
|
|
|
2012-01-02 14:01:16 +01:00
|
|
|
return self::$_cache_ancestry[$cacheKey];
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2008-02-25 03:10:37 +01:00
|
|
|
* @return array A self-keyed array of class names. Note that this is only available with Silverstripe
|
|
|
|
* classes and not built-in PHP classes.
|
2007-07-19 12:40:28 +02:00
|
|
|
*/
|
|
|
|
static function implementorsOf($interfaceName) {
|
2011-03-22 10:47:55 +01:00
|
|
|
return SS_ClassLoader::instance()->getManifest()->getImplementorsOf($interfaceName);
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2008-08-09 04:16:46 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns true if the given class implements the given interface
|
|
|
|
*/
|
|
|
|
static function classImplements($className, $interfaceName) {
|
2011-03-22 10:47:55 +01:00
|
|
|
return in_array($className, SS_ClassLoader::instance()->getManifest()->getImplementorsOf($interfaceName));
|
2008-08-09 04:16:46 +02:00
|
|
|
}
|
2009-08-05 06:01:22 +02:00
|
|
|
|
|
|
|
/**
|
2011-02-21 05:30:54 +01:00
|
|
|
* @deprecated 3.0 Please use is_subclass_of.
|
2009-08-05 06:01:22 +02:00
|
|
|
*/
|
2011-02-21 05:30:54 +01:00
|
|
|
public static function is_subclass_of($class, $parent) {
|
2011-10-29 01:02:11 +02:00
|
|
|
Deprecation::notice('3.0', 'Use is_subclass_of() instead.');
|
2011-02-21 05:30:54 +01:00
|
|
|
return is_subclass_of($class, $parent);
|
2009-08-05 06:01:22 +02:00
|
|
|
}
|
2011-02-21 05:30:54 +01:00
|
|
|
|
2008-10-17 17:18:26 +02:00
|
|
|
/**
|
|
|
|
* Get all classes contained in a file.
|
|
|
|
* @uses ManifestBuilder
|
|
|
|
*
|
2009-07-01 00:08:59 +02:00
|
|
|
* @todo Doesn't return additional classes that only begin
|
|
|
|
* with the filename, and have additional naming separated through underscores.
|
|
|
|
*
|
2008-10-17 17:18:26 +02:00
|
|
|
* @param string $filePath Path to a PHP file (absolute or relative to webroot)
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
static function classes_for_file($filePath) {
|
2011-03-22 10:47:55 +01:00
|
|
|
$absFilePath = Director::getAbsFile($filePath);
|
2008-10-17 17:18:26 +02:00
|
|
|
$matchedClasses = array();
|
2011-03-22 10:47:55 +01:00
|
|
|
$manifest = SS_ClassLoader::instance()->getManifest()->getClasses();
|
|
|
|
|
|
|
|
foreach($manifest as $class => $compareFilePath) {
|
2008-10-17 17:18:26 +02:00
|
|
|
if($absFilePath == $compareFilePath) $matchedClasses[] = $class;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $matchedClasses;
|
|
|
|
}
|
2008-11-06 05:51:25 +01:00
|
|
|
|
2009-07-01 00:08:59 +02:00
|
|
|
/**
|
|
|
|
* Returns all classes contained in a certain folder.
|
|
|
|
*
|
|
|
|
* @todo Doesn't return additional classes that only begin
|
|
|
|
* with the filename, and have additional naming separated through underscores.
|
|
|
|
*
|
|
|
|
* @param string $folderPath Relative or absolute folder path
|
|
|
|
* @return array Array of class names
|
|
|
|
*/
|
|
|
|
static function classes_for_folder($folderPath) {
|
2011-03-22 10:47:55 +01:00
|
|
|
$absFolderPath = Director::getAbsFile($folderPath);
|
2009-07-01 00:08:59 +02:00
|
|
|
$matchedClasses = array();
|
2011-03-22 10:47:55 +01:00
|
|
|
$manifest = SS_ClassLoader::instance()->getManifest()->getClasses();
|
|
|
|
|
|
|
|
foreach($manifest as $class => $compareFilePath) {
|
2009-07-01 00:08:59 +02:00
|
|
|
if(stripos($compareFilePath, $absFolderPath) === 0) $matchedClasses[] = $class;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $matchedClasses;
|
|
|
|
}
|
2012-08-22 23:29:13 +02:00
|
|
|
|
|
|
|
private static $method_from_cache = array();
|
|
|
|
|
|
|
|
static function has_method_from($class, $method, $compclass) {
|
|
|
|
if (!isset(self::$method_from_cache[$class])) self::$method_from_cache[$class] = array();
|
|
|
|
|
|
|
|
if (!array_key_exists($method, self::$method_from_cache[$class])) {
|
|
|
|
self::$method_from_cache[$class][$method] = false;
|
|
|
|
|
|
|
|
$classRef = new ReflectionClass($class);
|
|
|
|
|
|
|
|
if ($classRef->hasMethod($method)) {
|
|
|
|
$methodRef = $classRef->getMethod($method);
|
|
|
|
self::$method_from_cache[$class][$method] = $methodRef->getDeclaringClass()->getName();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return self::$method_from_cache[$class][$method] == $compclass;
|
|
|
|
}
|
2009-07-01 00:08:59 +02:00
|
|
|
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2012-02-12 21:22:11 +01:00
|
|
|
|