Webylon 3.1 API Docs
  • Package
  • Class
  • Tree
  • Deprecated
  • Download
Version: current
  • 3.2
  • 3.1

Packages

  • auth
  • Booking
  • cart
    • shipping
    • steppedcheckout
  • Catalog
  • cms
    • assets
    • batchaction
    • batchactions
    • bulkloading
    • comments
    • content
    • core
    • export
    • newsletter
    • publishers
    • reports
    • security
    • tasks
  • Dashboard
  • DataObjectManager
  • event
  • faq
  • forms
    • actions
    • core
    • fields-basic
    • fields-dataless
    • fields-datetime
    • fields-files
    • fields-formatted
    • fields-formattedinput
    • fields-relational
    • fields-structural
    • transformations
    • validators
  • googlesitemaps
  • guestbook
  • installer
  • newsletter
  • None
  • photo
    • gallery
  • PHP
  • polls
  • recaptcha
  • sapphire
    • api
    • bulkloading
    • control
    • core
    • cron
    • dev
    • email
    • fields-formattedinput
    • filesystem
    • formatters
    • forms
    • i18n
    • integration
    • misc
    • model
    • parsers
    • search
    • security
    • tasks
    • testing
    • tools
    • validation
    • view
    • widgets
  • seo
    • open
      • graph
  • sfDateTimePlugin
  • spamprotection
  • stealth
    • captha
  • subsites
  • userform
    • pagetypes
  • userforms
  • webylon
  • widgets

Classes

  • Aggregate
  • Aggregate_Relationship
  • AssetAdminQuotaExtension
  • AttachedFilesExtension
  • BookingWidget
  • CheckoutPageExchangeExtension
  • ClassInfo
  • ControllerRedirectExtension
  • CSSContentParser
  • DisableJSValidation
  • Extension
  • HtmlEditorQuotaExtension
  • ManifestBuilder
  • MobileExtension
  • Object
  • PaymentMethodAutoHide
  • ProductSearchFormExtension
  • SS_Cache
  • TokenisedRegularExpression
  • ValidationResult
  • YamlFixture

Functions

  • __autoload
  • _t
  • array_fill_keys
  • getClassFile
  • getSysTempDir
  • getTempFolder
  • increase_memory_limit_to
  • increase_time_limit_to
  • project
  • singleton
  • stripslashes_recursively
  • translate_memstring
  1 <?php
  2 /**
  3  * Define a constant for the name of the manifest file
  4  */
  5 if(!defined('MANIFEST_FILE')) define("MANIFEST_FILE", TEMP_FOLDER . "/manifest-" . basename($_SERVER['SCRIPT_FILENAME']));
  6 
  7 /**
  8  * The ManifestBuilder class generates the manifest file and keeps it fresh.
  9  * 
 10  * The manifest file is a PHP include that contains global variables that
 11  * represent the collected contents of the application:
 12  *   - all classes ({@link __autoload()})
 13  *   - all templates ({@link SSViewer})
 14  *   - all _config.php files
 15  *
 16  * Traversing the filesystem to collect this information on everypage.
 17  * This information is cached so that it need not be regenerated on every
 18  * pageview.
 19  * 
 20  * @see main.php, __autoload(), SSViewer, Requirements::themedCSS()
 21  * @package sapphire
 22  * @subpackage core
 23  */
 24 class ManifestBuilder {
 25 
 26     static $restrict_to_modules = array();
 27     static $extendsArray = array();
 28     static $classArray = array();
 29     static $implementsArray = array();
 30 
 31     /**
 32      * @var array $ignore_files Full filenames (without directory-path) which
 33      * should be ignored by the manifest.
 34      */
 35     public static $ignore_files = array(
 36         'main.php',
 37         'cli-script.php',
 38         'install.php',
 39         'index.php',
 40     );
 41 
 42     /**
 43      * @var array $ignore_folders Foldernames (without path) which
 44      * should be ignored by the manifest.
 45      */
 46     public static $ignore_folders = array(
 47         'mysql',
 48         'assets',
 49         'shortstat',
 50         'HTML',
 51     );
 52     
 53     /**
 54      * Include the manifest, regenerating it if necessary
 55      */
 56     static function include_manifest() {
 57         if(isset($_REQUEST['usetestmanifest'])) {
 58             self::load_test_manifest();
 59         } else {
 60             // The dev/build reference is some coupling but it solves an annoying bug
 61             if (
 62                 !file_exists(MANIFEST_FILE)
 63                 || isset($_GET['flush']) 
 64                 || (isset($_REQUEST['url']) && ($_REQUEST['url'] == 'dev/build' || $_REQUEST['url'] == BASE_URL . '/dev/build'))
 65             ) {
 66                 self::create_manifest_file();
 67             }
 68             require_once(MANIFEST_FILE);
 69         }
 70     }
 71 
 72     /**
 73      * Load a copy of the manifest with tests/ folders included.
 74      * Only loads the ClassInfo and __autoload() globals; this assumes that _config.php files are already included.
 75      */
 76     static function load_test_manifest() {
 77         $testManifestFile = MANIFEST_FILE . '-test';
 78 
 79         // The dev/build reference is some coupling but it solves an annoying bug
 80         if(!file_exists($testManifestFile) 
 81             || (filemtime($testManifestFile) < filemtime(BASE_PATH)) 
 82             || isset($_GET['flush'])) {
 83                 
 84             // Build the manifest, including the tests/ folders
 85             $manifestInfo = self::get_manifest_info(BASE_PATH);
 86             $manifest = self::generate_php_file($manifestInfo);
 87             if($fh = fopen($testManifestFile, 'wb')) {
 88                 fwrite($fh, $manifest);
 89                 fclose($fh);
 90             } else {
 91                 user_error("Cannot write manifest file! Check permissions of " . MANIFEST_FILE, E_USER_ERROR);
 92             }
 93         }
 94         
 95         require($testManifestFile);
 96     }
 97     
 98     /**
 99      * Loads all PHP class files - actually opening them and executing them.
100      */
101     static function load_all_classes() {
102         global $_CLASS_MANIFEST;
103         foreach($_CLASS_MANIFEST as $classFile) require_once($classFile);
104     }
105 
106     /**
107      * Generates a new manifest file and saves it to {@link MANIFEST_FILE}.
108      */
109     static function create_manifest_file() {
110         // Build the manifest, ignoring the tests/ folders
111         $manifestInfo = self::get_manifest_info(BASE_PATH, array("tests"));
112 
113         $manifest = self::generate_php_file($manifestInfo);
114         if($fh = fopen(MANIFEST_FILE, 'wb')) {
115             fwrite($fh, $manifest);
116             fclose($fh);
117         } else {
118             user_error("Cannot write manifest file! Check permissions of " . MANIFEST_FILE, E_USER_ERROR);
119         }
120     }
121     
122     /**
123      * Turn an array produced by get_manifest_info() into the content of the manifest PHP include
124      */
125     static function generate_php_file($manifestInfo) {
126         $output = "<?php\n";
127         
128         foreach($manifestInfo['globals'] as $globalName => $globalVal) {
129             $output .= "global \$$globalName;\n\$$globalName = " . var_export($globalVal, true) . ";\n\n";
130         }
131         foreach($manifestInfo['require_once'] as $requireItem) {
132             $output .= "require_once('" . addslashes($requireItem) . "');\n";
133         }
134         
135         return preg_replace("!'".BASE_PATH."!", "BASE_PATH . '", $output);
136     }
137 
138  
139     /**
140      * Parse the $manifestInfo array, updating the appropriate globals and loading the appropriate _config files.
141      */
142     static function process_manifest($manifestInfo) {
143         foreach($manifestInfo['globals'] as $globalName => $globalVal) {
144             global $$globalName;
145             $$globalName = $globalVal;
146         }
147         foreach($manifestInfo['require_once'] as $requireItem) {
148             require_once("$requireItem");
149         }
150     }
151     
152     /**
153      * Get themes from a particular directory.
154      * 
155      * @param string $baseDir Optional: Absolute path to theme directory for testing e.g. "/Users/sharvey/Sites/test24/themes"
156      * @param boolean $includeSubThemes If set to TRUE, sub-themes such as "blackcandy_blog" are included too
157      * @return array Listing of theme directories
158      */
159     public static function get_themes($baseDir = null, $includeSubThemes = false) {
160         // If no base directory specified, the default is the project root
161         if(!$baseDir) $baseDir = BASE_PATH . DIRECTORY_SEPARATOR . THEMES_DIR;
162         $themes = array();
163         if(!file_exists($baseDir)) return $themes;
164 
165         $handle = opendir($baseDir);
166         if($handle) {
167             while(false !== ($file = readdir($handle))) {
168                 $fullPath = $baseDir . DIRECTORY_SEPARATOR . $file;
169                 if(strpos($file, '.') === false && is_dir($fullPath)) {
170                     $include = $includeSubThemes ? true : false;
171                     if(strpos($file, '_') === false) {
172                         $include = true;
173                     }
174                     if($include) $themes[$file] = $file;
175                 }
176             }
177             closedir($handle);
178         }
179         return $themes;
180     }
181     
182     /**
183      * Return an array containing information for the manifest
184      * @param $baseDir The root directory to analyse
185      * @param $excludedFolders An array folder names to exclude.  These don't care about where the
186      *        folder appears in the hierarchy, so be careful
187      */
188     static function get_manifest_info($baseDir, $excludedFolders = array()) {
189         global $project;
190         // locate and include the exclude files
191         $topLevel = scandir($baseDir);
192         foreach($topLevel as $file) {
193             if($file[0] == '.') continue;
194             
195             $fullPath = '';
196             $fullPath = $baseDir . '/' . $file;
197 
198             if(@is_dir($fullPath . '/') && file_exists($fullPath . '/_exclude.php')) {
199                 require_once($fullPath . '/_exclude.php');
200             }
201         }
202         
203         // Project - used to give precedence to template files
204         if (!isset($project) || !$project) $project = 'site';
205 
206         // Class, CSS, template manifest
207         $allPhpFiles = array();
208         $templateManifest = array();
209         $cssManifest = array();
210 
211 
212         if(is_array(self::$restrict_to_modules) && count(self::$restrict_to_modules)) {
213             // $restrict_to_modules is set, so we include only those specified
214             // modules
215             foreach(self::$restrict_to_modules as $module)
216                 ManifestBuilder::get_all_php_files($baseDir . '/' . $module, $excludedFolders, $allPhpFiles);
217         } else {
218             // Include all directories which have an _config.php file but don't
219             // have an _manifest_exclude file
220             $topLevel = scandir($baseDir);
221             foreach($topLevel as $filename) {
222                 if($filename[0] == '.') continue;
223                 if($filename == 'themes') continue;
224                 if($filename == 'assets') continue;
225                 if(in_array($filename, $excludedFolders)) continue;
226 
227                 if(@is_dir("$baseDir/$filename") &&
228                          file_exists("$baseDir/$filename/_config.php") &&
229                          !file_exists("$baseDir/$filename/_manifest_exclude")) {
230                             
231                     // Get classes, templates, and CSS files
232                     ManifestBuilder::get_all_php_files("$baseDir/$filename", $excludedFolders, $allPhpFiles);
233                     ManifestBuilder::getTemplateManifest($baseDir, $filename, $excludedFolders, $templateManifest, $cssManifest);
234 
235                     // List the _config.php files (project config include later)
236                     if ($filename != $project) {
237                         $manifestInfo["require_once"][] = "$baseDir/$filename/_config.php";
238                         // _00config.php - pre config files
239                         if (file_exists("$baseDir/$filename/_00config.php"))
240                             $manifestInfo["require_once00"][] = "$baseDir/$filename/_00config.php";
241                     }
242                 }
243             }
244         }
245         if (array_key_exists("require_once00", $manifestInfo) && is_array($manifestInfo["require_once00"]) && count($manifestInfo["require_once00"])) {
246             $manifestInfo["require_once"] = array_merge($manifestInfo["require_once00"],$manifestInfo["require_once"]);
247         }
248         // project configs placed before all (_00config.php) and after all (_config.php)
249         if (file_exists("$baseDir/$project/_00config.php")) 
250             array_unshift($manifestInfo["require_once"], "$baseDir/$project/_00config.php");
251 
252         $manifestInfo["require_once"][] = "$baseDir/$project/_config.php";
253 
254         // Get themes
255         if(file_exists("$baseDir/themes")) {
256             $themeDirs = self::get_themes("$baseDir/themes", true);
257             foreach($themeDirs as $themeDir) {
258                 $themeName = strtok($themeDir, '_');
259                 ManifestBuilder::getTemplateManifest($baseDir, "themes/$themeDir", $excludedFolders, $templateManifest, $cssManifest, $themeName);
260             }
261         }
262 
263         // Build class-info array from class manifest
264         $allClasses = ManifestBuilder::allClasses($allPhpFiles);
265         
266         // Pull the class filenames out
267         $classManifest = $allClasses['file'];
268         unset($allClasses['file']);
269 
270         // Ensure that any custom templates get favoured
271         if(!$project) user_error("\$project isn't set", E_USER_WARNING);
272         else if(!file_exists("$baseDir/$project")) user_error("\$project is set to '$project' but no such folder exists.", E_USER_WARNING);
273         else ManifestBuilder::getTemplateManifest($baseDir, $project, $excludedFolders, $templateManifest, $cssManifest);
274 
275         $manifestInfo["globals"]["_CLASS_MANIFEST"] = $classManifest;
276         $manifestInfo["globals"]["_ALL_CLASSES"] = $allClasses;
277         $manifestInfo["globals"]["_TEMPLATE_MANIFEST"] = $templateManifest;
278         $manifestInfo["globals"]["_CSS_MANIFEST"] = $cssManifest;
279 
280         return $manifestInfo;
281     }
282 
283 
284     /**
285      * Generates a list of all the PHP files that should be analysed by the manifest builder.
286      *
287      * @param string $folder The folder to traverse (recursively)
288      * @param array $classMap The already built class map
289      */
290     private static function get_all_php_files($folder, $excludedFolders, &$allPhpFiles) {
291         $items = scandir($folder);
292         if($items) foreach($items as $item) {
293             // Skip some specific PHP files
294             if(in_array($item, self::$ignore_files)) continue;
295 
296             // ignore hidden files and folders
297             if(substr($item,0,1) == '.') continue;
298 
299             // ignore files without php-extension
300             if(substr($item,-4) != '.php' && !@is_dir("$folder/$item")) continue;
301 
302             // ignore files and folders with underscore-prefix
303             if(substr($item,0,1) == '_') continue;
304 
305             // ignore certain directories
306             if(@is_dir("$folder/$item") && in_array($item, self::$ignore_folders)) continue;
307 
308             // ignore directories with _manifest_exlude file
309             if(@is_dir("$folder/$item") && file_exists("$folder/$item/_manifest_exclude")) continue;
310 
311             // i18n: ignore language files (loaded on demand)
312             if($item == 'lang' && @is_dir("$folder/$item") && ereg_replace("/[^/]+/\\.\\.","",$folder.'/..') == Director::baseFolder()) continue;
313 
314             if(@is_dir("$folder/$item")) {
315                 // Folder exclusion - used to skip over tests/ folders
316                 if(in_array($item, $excludedFolders)) continue;
317                 
318                 // recurse into directories (if not in $ignore_folders)
319                 ManifestBuilder::get_all_php_files("$folder/$item", $excludedFolders, $allPhpFiles);
320             } else {
321                 $allPhpFiles[] = "$folder/$item";
322             }
323 
324         }
325     }
326 
327 
328     /**
329      * Generates the template manifest - a list of all the .SS files in the
330      * application
331      */
332     private static function getTemplateManifest($baseDir, $folder, $excludedFolders, &$templateManifest, &$cssManifest, $themeName = null) {
333         $items = scandir("$baseDir/$folder");
334         if($items) foreach($items as $item) {
335             if(substr($item,0,1) == '.') continue;
336             if(substr($item,-3) == '.ss') {
337                 $templateName = substr($item, 0, -3);
338                 $templateType = substr($folder,strrpos($folder,'/')+1);
339                 if($templateType == "templates") $templateType = "main";
340 
341                 if($themeName) {
342                     $templateManifest[$templateName]['themes'][$themeName][$templateType] = "$baseDir/$folder/$item";
343                 } else {
344                     $templateManifest[$templateName][$templateType] = "$baseDir/$folder/$item";
345                 }
346 
347             } else if(substr($item,-4) == '.css') {
348                     $cssName = substr($item, 0, -4);
349                     // Debug::message($item);
350 
351                     if($themeName) {
352                         $cssManifest[$cssName]['themes'][$themeName] = "$folder/$item";
353                     } else {
354                         $cssManifest[$cssName]['unthemed'] = "$folder/$item";
355                     }
356 
357 
358             } else if(@is_dir("$baseDir/$folder/$item")) {
359                 // Folder exclusion - used to skip over tests/ folders
360                 if(in_array($item, $excludedFolders)) continue;
361 
362                 ManifestBuilder::getTemplateManifest($baseDir, "$folder/$item", $excludedFolders, $templateManifest, $cssManifest, $themeName);
363             }
364         }
365     }
366 
367 
368     /**
369      * Include everything, so that actually *all* classes are available and
370      * build a map of classes and their subclasses
371      * 
372      * @param $classManifest An array of all Sapphire classes; keys are class names and values are filenames
373      *
374      * @return array Returns an array that holds all class relevant
375      *               information.
376      */
377     private static function allClasses($classManifest) {
378         self::$classArray = array();
379         self::$extendsArray = array();
380         self::$implementsArray = array();
381         
382         // Include everything, so we actually have *all* classes
383         foreach($classManifest as $file) {
384             $b = basename($file);
385             if($b != 'cli-script.php' && $b != 'main.php')
386                 self::parse_file($file);
387         }
388 
389         $allClasses["parents"] = self::find_parents();
390         $allClasses["children"] = self::find_children();
391         $allClasses["implementors"] = self::$implementsArray;
392 
393         foreach(self::$classArray as $class => $info) {
394             $allClasses['exists'][$class] = $class;
395             $allClasses['file'][strtolower($class)] = $info['file'];
396         }
397 
398         // Build a map of classes and their subclasses
399         $_classes = get_declared_classes();
400 
401         foreach($_classes as $class) {
402             $allClasses['exists'][$class] = $class;
403             foreach($_classes as $subclass) {
404                 if(is_subclass_of($class, $subclass)) $allClasses['parents'][$class][$subclass] = $subclass;
405                 if(is_subclass_of($subclass, $class)) $allClasses['children'][$class][$subclass] = $subclass;
406             }
407         }
408         
409         return $allClasses;
410     }
411 
412     /**
413      * Parses a php file and adds any class or interface information into self::$classArray
414      *
415      * @param string $filename
416      */
417     private static function parse_file($filename) {
418         $file = file_get_contents($filename);
419 
420         $implements = "";
421         $extends = "";
422         $class="";
423 
424         if($file === null) user_error("ManifestBuilder::parse_file(): Couldn't open $filename", E_USER_ERROR);
425         if(!$file) return;
426         
427         // We cache the parse results of each file, since only a few files will have changed between flushings
428         // And, although it's accurate, TokenisedRegularExpression isn't particularly fast.
429         // We use an MD5 of the file as a part of the cache key because using datetime caused problems when users
430         // were upgrading their sites
431         $fileMD5 = md5($file);
432         $parseCacheFile = TEMP_FOLDER . "/manifestClassParse-" . str_replace(array("/", ":", "\\", "."), "_", basename($filename)) . "-${fileMD5}.php";
433         if(file_exists($parseCacheFile)) {
434             include($parseCacheFile);
435             // Check for a bad cache file
436             if(!isset($classes) || !isset($interfaces) || !is_array($classes) || !is_array($interfaces)) {
437                 unset($classes);
438                 unset($interfaces);
439             }
440         }
441         
442         // Either the parseCacheFile doesn't exist, or its bad
443         if(!isset($classes)) {
444             $tokens = token_get_all($file);
445             $classes = (array)self::getClassDefParser()->findAll($tokens);
446             $interfaces = (array)self::getInterfaceDefParser()->findAll($tokens);
447             
448             $cacheContent = '<?php
449                 $classes = ' . var_export($classes,true) . ';
450                 $interfaces = ' . var_export($interfaces,true) . ';';
451 
452             if($fh = fopen($parseCacheFile, 'wb')) {
453                 fwrite($fh, $cacheContent);
454                 fclose($fh);
455             }
456         }
457 
458         foreach($classes as $class) {
459             $className = $class['className'];
460             unset($class['className']);
461             $class['file'] = $filename;
462             if(!isset($class['extends'])) $class['extends'] = null;
463             
464             if($class['extends']) self::$extendsArray[$class['extends']][$className] = $className;
465             if(isset($class['interfaces'])) foreach($class['interfaces'] as $interface) {
466                 self::$implementsArray[$interface][$className] = $className;
467             }
468             
469             if(isset(self::$classArray[$className])) {
470                 $file1 = self::$classArray[$className]['file'];
471                 $file2 = $class['file'];
472                 user_error("There are two files both containing the same class: '$file1' and " .
473                     "'$file2'. This might mean that the wrong code is being used.", E_USER_WARNING);
474             }
475             
476             self::$classArray[$className] = $class;
477         }
478         
479         foreach($interfaces as $interface) {
480             $className = $interface['interfaceName'];
481             unset($interface['interfaceName']);
482             $interface['file'] = $filename;
483             if(!isset($interface['extends'])) $interface['extends'] = null;
484 
485             if(isset(self::$classArray[$className])) {
486                 $file1 = self::$classArray[$className]['file'];
487                 $file2 = $interface[$className];
488                 user_error("There are two files both containing the same class: '$file1' and " .
489                     "'$file2'. This might mean that the wrong code is being used.", E_USER_WARNING);
490             }
491 
492             self::$classArray[$className] = $interface;
493         }
494     }
495     
496     /**
497      * Returns a {@link TokenisedRegularExpression} object that will parse class definitions
498      * @return TokenisedRegularExpression
499      */
500     public static function getClassDefParser() {
501         require_once('core/TokenisedRegularExpression.php');
502         
503         return new TokenisedRegularExpression(array(
504             0 => T_CLASS,
505             1 => T_WHITESPACE,
506             2 => array(T_STRING, 'can_jump_to' => array(7, 14), 'save_to' => 'className'),
507             3 => T_WHITESPACE,
508             4 => T_EXTENDS,
509             5 => T_WHITESPACE,
510             6 => array(T_STRING, 'save_to' => 'extends', 'can_jump_to' => 14),
511             7 => T_WHITESPACE,
512             8 => T_IMPLEMENTS,
513             9 => T_WHITESPACE,
514             10 => array(T_STRING, 'can_jump_to' => 14, 'save_to' => 'interfaces[]'),
515             11 => array(T_WHITESPACE, 'optional' => true),
516             12 => array(',', 'can_jump_to' => 10),
517             13 => array(T_WHITESPACE, 'can_jump_to' => 10),
518             14 => array(T_WHITESPACE, 'optional' => true),
519             15 => '{',
520         ));
521     }
522 
523     /**
524      * Returns a {@link TokenisedRegularExpression} object that will parse class definitions
525      * @return TokenisedRegularExpression
526      */
527     public static function getInterfaceDefParser() {
528         require_once('core/TokenisedRegularExpression.php');
529 
530         return new TokenisedRegularExpression(array(
531             0 => T_INTERFACE,
532             1 => T_WHITESPACE,
533             2 => array(T_STRING, 'can_jump_to' => 7, 'save_to' => 'interfaceName'),
534             3 => T_WHITESPACE,
535             4 => T_EXTENDS,
536             5 => T_WHITESPACE,
537             6 => array(T_STRING, 'save_to' => 'extends'),
538             7 => array(T_WHITESPACE, 'optional' => true),
539             8 => '{',
540         ));
541     }
542     
543 
544     /**
545      * Moves through self::$classArray and creates an array containing parent data
546      *
547      * @return array
548      */
549     private static function find_parents() {
550         $parentArray = array();
551         foreach(self::$classArray as $class => $info) {
552             $extendArray = array();
553 
554             $parent = $info["extends"];
555 
556             while($parent) {
557                 $extendArray[$parent] = $parent;
558                 $parent = isset(self::$classArray[$parent]["extends"]) ? self::$classArray[$parent]["extends"] : null;
559             }
560             $parentArray[$class] = array_reverse($extendArray);
561         }
562         return $parentArray;
563     }
564 
565     /**
566      * Iterates through self::$classArray and returns an array with any descendant data
567      *
568      * @return array
569      */
570     private static function find_children() {
571         $childrenArray = array();
572         foreach(self::$extendsArray as $class => $children) {
573             $allChildren = $children;
574             foreach($children as $childName) {
575                 $allChildren = array_merge($allChildren, self::up_children($childName));
576             }
577             $childrenArray[$class] = $allChildren;
578         }
579         return $childrenArray;
580     }
581 
582     /**
583      * Helper function to find all children of give class
584      *
585      * @param string $class
586      * @return array
587      */
588     private static function get_children($class) {
589         return isset(self::$extendsArray[$class]) ? self::$extendsArray[$class] : array();
590     }
591     
592     /**
593      * Returns if the Manifest has been included
594      * 
595      * @return Boolean
596      */
597     static function has_been_included() {
598         global $_CLASS_MANIFEST, $_TEMPLATE_MANIFEST, $_CSS_MANIFEST, $_ALL_CLASSES;
599         return (bool)!(empty($_CLASS_MANIFEST) && empty($_TEMPLATE_MANIFEST) && empty($_CSS_MANIFEST) && empty($_ALL_CLASSES));
600     }
601 
602     /**
603      * Returns a flat array with all children of a given class
604      *
605      * @param string $class
606      * @param array $results
607      */
608     static function up_children($class) {
609         $children = self::get_Children($class);
610         $results = $children;
611             foreach($children as $className) {
612                 $results = array_merge($results, self::up_children($className));
613             }
614             return $results;;
615     }
616 }
[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. -
Webylon 3.1 API Docs API documentation generated by ApiGen 2.8.0