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

Packages

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