Version: current

      1 <?php
      2 /**
      3  * Provides introspection information about the class tree.
      4  * It's a cached wrapper around the built-in class functions.  Sapphire uses class introspection heavily
      5  * and without the caching it creates an unfortunate performance hit.
      6  *
      7  * @package sapphire
      8  * @subpackage core
      9  */
     10 class ClassInfo {
     11         /**
     12      * @todo Improve documentation
     13      */
     14     static function allClasses() {
     15         global $_ALL_CLASSES;
     16         return $_ALL_CLASSES['exists'];
     17     }
     18
     19     /**
     20      * @todo Improve documentation
     21      */
     22     static function exists($class) {
     23         global $_ALL_CLASSES;
     24         return isset($_ALL_CLASSES['exists'][$class]) ? $_ALL_CLASSES['exists'][$class] : null;
     25     }
     26
     27     /**
     28      * Cache for {@link hasTable()}
     29      */
     30     private static $_cache_all_tables = null;
     31
     32     /**
     33      * @todo Move this to SS_Database or DB
     34      */
     35     static function hasTable($class) {
     36         if(DB::isActive()) {
     37             // Cache the list of all table names to reduce on DB traffic
     38             if(empty(self::$_cache_all_tables)) {
     39                 self::$_cache_all_tables = array();
     40                 $tables = DB::query(DB::getConn()->allTablesSQL())->column();
     41                 foreach($tables as $table) self::$_cache_all_tables[strtolower($table)] = true;
     42             }
     43             return isset(self::$_cache_all_tables[strtolower($class)]);
     44         } else {
     45             return false;
     46         }
     47     }
     48
     49     static function reset_db_cache() {
     50         self::$_cache_all_tables = null;
     51     }
     52
     53     /**
     54      * Returns the manifest of all classes which are present in the database.
     55      */
     56     static function getValidSubClasses(){
     57         return DB::getConn()->enumValuesForField("SiteTree", "ClassName");
     58     }
     59
     60     /**
     61      * Return the database tables linked to this class.
     62      * Gets an array of the current class, it subclasses and its ancestors.  It then filters that list
     63      * to those with DB tables
     64      *
     65      * @param mixed $class string of the classname or instance of the class
     66      * @todo Move this into data object
     67      * @return array
     68      */
     69     static function dataClassesFor($class) {
     70         global $_ALL_CLASSES;
     71         if (is_object($class)) $class = get_class($class);
     72
     73         $dataClasses = array();
     74
     75         if(!$_ALL_CLASSES['parents'][$class]) user_error("ClassInfo::dataClassesFor() no parents for $class", E_USER_WARNING);
     76         foreach($_ALL_CLASSES['parents'][$class] as $subclass) {
     77             if(self::hasTable($subclass)) $dataClasses[] = $subclass;
     78         }
     79
     80         if(self::hasTable($class)) $dataClasses[] = $class;
     81
     82         if(isset($_ALL_CLASSES['children'][$class]))
     83         foreach($_ALL_CLASSES['children'][$class] as $subclass)
     84         {
     85             if(self::hasTable($subclass)) $dataClasses[] = $subclass;
     86         }
     87
     88         return $dataClasses;
     89     }
     90
     91     /**
     92      * Return the root data class for that class.
     93      * This root table has a lot of special use in the DataObject system.
     94      *
     95      * @param mixed $class string of the classname or instance of the class
     96      * @return array
     97      */
     98     static function baseDataClass($class) {
     99         global $_ALL_CLASSES;
    100         if (is_object($class)) $class = get_class($class);
    101         reset($_ALL_CLASSES['parents'][$class]);
    102         while($val = next($_ALL_CLASSES['parents'][$class])) {
    103             if($val == 'DataObject') break;
    104         }
    105         $baseDataClass = next($_ALL_CLASSES['parents'][$class]);
    106         return $baseDataClass ? $baseDataClass : $class;
    107     }
    108
    109     /**
    110      * Returns a list of classes that inherit from the given class.
    111      * The resulting array includes the base class passed
    112      * through the $class parameter as the first array value.
    113      *
    114      * Example usage:
    115      * <code>
    116      * ClassInfo::subclassesFor('BaseClass');
    117      *  array(
    118      *  0 => 'BaseClass',
    119      *  'ChildClass' => 'ChildClass',
    120      *  'GrandChildClass' => 'GrandChildClass'
    121      * )
    122      * </code>
    123      *
    124      * @param mixed $class string of the classname or instance of the class
    125      * @return array Names of all subclasses as an associative array.
    126      */
    127     static function subclassesFor($class){
    128         global $_ALL_CLASSES;
    129         if (is_object($class)) $class = get_class($class);
    130
    131         // get all classes from the manifest
    132         $subclasses = isset($_ALL_CLASSES['children'][$class]) ? $_ALL_CLASSES['children'][$class] : null;
    133
    134         // add the base class to the array
    135         if(isset($subclasses)) {
    136             array_unshift($subclasses, $class);
    137         } else {
    138             $subclasses[$class] = $class;
    139         }
    140
    141         return $subclasses;
    142     }
    143
    144     /**
    145      * @todo Improve documentation
    146      */
    147     static function ancestry($class, $onlyWithTables = false) {
    148         global $_ALL_CLASSES;
    149
    150         if(is_object($class)) $class = $class->class;
    151         else if(!is_string($class)) user_error("Bad class value " . var_export($class, true) . " passed to ClassInfo::ancestry()", E_USER_WARNING);
    152
    153         $items = $_ALL_CLASSES['parents'][$class];
    154         $items[$class] = $class;
    155         if($onlyWithTables) foreach($items as $item) {
    156             if(!DataObject::has_own_table($item)) unset($items[$item]);
    157         }
    158         return $items;
    159     }
    160
    161     /**
    162      * @return array A self-keyed array of class names. Note that this is only available with Silverstripe
    163      * classes and not built-in PHP classes.
    164      */
    165     static function implementorsOf($interfaceName) {
    166         global $_ALL_CLASSES;
    167         return (isset($_ALL_CLASSES['implementors'][$interfaceName])) ? $_ALL_CLASSES['implementors'][$interfaceName] : false;
    168     }
    169
    170     /**
    171      * Returns true if the given class implements the given interface
    172      */
    173     static function classImplements($className, $interfaceName) {
    174         global $_ALL_CLASSES;
    175         return isset($_ALL_CLASSES['implementors'][$interfaceName][$className]);
    176     }
    177
    178     /**
    179      * Returns true if $subclass is a subclass of $parentClass.
    180      * Identical to the PHP built-in function, but faster.
    181      */
    182     static function is_subclass_of($subclass, $parentClass) {
    183         global $_ALL_CLASSES;
    184         return isset($_ALL_CLASSES['parents'][$subclass][$parentClass]);
    185     }
    186
    187     /**
    188      * Get all classes contained in a file.
    189      * @uses ManifestBuilder
    190      *
    191      * @todo Doesn't return additional classes that only begin
    192      *  with the filename, and have additional naming separated through underscores.
    193      *
    194      * @param string $filePath Path to a PHP file (absolute or relative to webroot)
    195      * @return array
    196      */
    197     static function classes_for_file($filePath) {
    198         $absFilePath = Director::getAbsFile($filePath);
    199         global $_CLASS_MANIFEST;
    200
    201         $matchedClasses = array();
    202         foreach($_CLASS_MANIFEST as $class => $compareFilePath) {
    203             if($absFilePath == $compareFilePath) $matchedClasses[] = $class;
    204         }
    205
    206         return $matchedClasses;
    207     }
    208
    209     /**
    210      * Returns all classes contained in a certain folder.
    211      *
    212      * @todo Doesn't return additional classes that only begin
    213      *  with the filename, and have additional naming separated through underscores.
    214      *
    215      * @param string $folderPath Relative or absolute folder path
    216      * @return array Array of class names
    217      */
    218     static function classes_for_folder($folderPath) {
    219         $absFolderPath = Director::getAbsFile($folderPath);
    220         global $_CLASS_MANIFEST;
    221
    222         $matchedClasses = array();
    223         foreach($_CLASS_MANIFEST as $class => $compareFilePath) {
    224             if(stripos($compareFilePath, $absFolderPath) === 0) $matchedClasses[] = $class;
    225         }
    226
    227         return $matchedClasses;
    228     }
    229
    230     /////////////////////////////////////////////////////////////////////////////
    231     // DEPRECATED
    232
    233     /**
    234      * @deprecated Use Security::database_is_ready() instead.
    235      */
    236     static function ready() {
    237         user_error("ClassInfo::ready() deprectaed - use Security::database_is_ready()", E_USER_NOTICE);
    238         return Security::database_is_ready();
    239     }
    240
    241 }
    242 ?>
    243

[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -