/**
  * A key value pair of values that should be searched for.
  * The keys should match the field names specified in {@link self::$fields}.
  * Usually these values come from a submitted searchform
  * in the form of a $_REQUEST object.
  * CAUTION: All values should be treated as insecure client input.
  *
  * @param string $modelClass The base {@link DataObject} class that search properties related to.
  * 						Also used to generate a set of result objects based on this class.
  * @param FieldList $fields Optional. FormFields mapping to {@link DataObject::$db} properties
  *	 					which are to be searched. Derived from modelclass using
  *						{@link DataObject::scaffoldSearchFields()} if left blank.
  * @param array $filters Optional. Derived from modelclass if left blank
  */
 public function __construct($modelClass, $fields = null, $filters = null)
 {
     $this->modelClass = $modelClass;
     $this->fields = $fields ? $fields : new FieldList();
     $this->filters = $filters ? $filters : array();
     parent::__construct();
 }
 public function __construct($content)
 {
     if (extension_loaded('tidy')) {
         // using the tidy php extension
         $tidy = new tidy();
         $tidy->parseString($content, array('output-xhtml' => true, 'numeric-entities' => true, 'wrap' => 0), 'utf8');
         $tidy->cleanRepair();
         $tidy = str_replace('xmlns="http://www.w3.org/1999/xhtml"', '', $tidy);
         $tidy = str_replace(' ', '', $tidy);
     } elseif (@shell_exec('which tidy')) {
         // using tiny through cli
         $CLI_content = escapeshellarg($content);
         $tidy = `echo {$CLI_content} | tidy --force-output 1 -n -q -utf8 -asxhtml -w 0 2> /dev/null`;
         $tidy = str_replace('xmlns="http://www.w3.org/1999/xhtml"', '', $tidy);
         $tidy = str_replace(' ', '', $tidy);
     } else {
         // no tidy library found, hence no sanitizing
         $tidy = $content;
     }
     $this->simpleXML = @simplexml_load_string($tidy, 'SimpleXMLElement', LIBXML_NOWARNING);
     if (!$this->simpleXML) {
         throw new Exception('CSSContentParser::__construct(): Could not parse content.' . ' Please check the PHP extension tidy is installed.');
     }
     parent::__construct();
 }
 /**
  *
  * @param integer $currentID - The ID of the current item; this button will find that item's parent
  */
 public function __construct($currentID)
 {
     parent::__construct();
     if ($currentID && is_numeric($currentID)) {
         $this->currentID = $currentID;
     }
 }
 /**
  * @param $locale
  */
 public function __construct($locale = null)
 {
     $this->defaultLocale = $locale ? $locale : i18n::get_lang_from_locale(i18n::config()->get('default_locale'));
     $this->basePath = Director::baseFolder();
     $this->baseSavePath = Director::baseFolder();
     parent::__construct();
 }
 /**
  * Create a new ValidationResult.
  * By default, it is a successful result.    Call $this->error() to record errors.
  *
  * @param bool $valid
  * @param string $message
  */
 public function __construct($valid = true, $message = null)
 {
     $this->isValid = $valid;
     if ($message) {
         $this->errorList[] = $message;
     }
     parent::__construct();
 }
 public function __construct(AssetContainer $assetContainer = null)
 {
     parent::__construct();
     $this->cache = Cache::factory('GDBackend_Manipulations');
     if ($assetContainer) {
         $this->loadFromContainer($assetContainer);
     }
 }
 /**
  * Create a new CMS Menu Item
  *
  * @param string $title
  * @param string $url
  * @param string $controller Controller class name
  * @param integer $priority The sort priority of the item
  */
 public function __construct($title, $url, $controller = null, $priority = -1)
 {
     $this->title = $title;
     $this->url = $url;
     $this->controller = $controller;
     $this->priority = $priority;
     parent::__construct();
 }
 public function __construct()
 {
     $this->options = array();
     $class = get_class($this);
     // We build our options array ourselves, because possibly no class or config manifest exists at this point
     do {
         $this->options = array_merge(Object::static_lookup($class, 'default_options'), $this->options);
     } while ($class = get_parent_class($class));
 }
 /**
  * @param string $fullName Determines the name of the field, as well as the searched database
  *  column. Can contain a relation name in dot notation, which will automatically join
  *  the necessary tables (e.g. "Comments.Name" to join the "Comments" has-many relationship and
  *  search the "Name" column when applying this filter to a SiteTree class).
  * @param mixed $value
  * @param array $modifiers
  */
 public function __construct($fullName = null, $value = false, array $modifiers = array())
 {
     parent::__construct();
     $this->fullName = $fullName;
     // sets $this->name and $this->relation
     $this->addRelation($fullName);
     $this->value = $value;
     $this->setModifiers($modifiers);
 }
 /**
  * @param array $config The configuration for the cleaner, if necessary
  */
 public function __construct($config = null)
 {
     parent::__construct();
     if ($config) {
         $config = array_merge($this->defaultConfig, $config);
     } else {
         $config = $this->defaultConfig;
     }
     $this->setConfig($config);
 }
 public function testExtraFieldsViaExtension()
 {
     // This extends ManyManyListTest_Secondary with the secondary extension that adds the relationship back
     // to the primary. The instance from the fixture is ManyManyListTest_SecondarySub, deliberately a sub-class of
     // the extended class.
     Object::add_extension('ManyManyListTest_Secondary', 'ManyManyListTest_IndirectSecondaryExtension');
     // Test from the primary (not extended) to the secondary (which is extended)
     $primary = $this->objFromFixture('ManyManyListTest_IndirectPrimary', 'manymany_extra_primary');
     $secondaries = $primary->Secondary();
     $extraFields = $secondaries->getExtraFields();
     $this->assertTrue(count($extraFields) > 0, 'has extra fields');
     $this->assertTrue(isset($extraFields['DocumentSort']), 'has DocumentSort');
     // Test from the secondary (which is extended) to the primary (not extended)
     $secondary = $this->objFromFixture('ManyManyListTest_SecondarySub', 'manymany_extra_secondary');
     $primaries = $secondary->Primary();
     $extraFields = $primaries->getExtraFields();
     $this->assertTrue(count($extraFields) > 0, 'has extra fields');
     $this->assertTrue(isset($extraFields['DocumentSort']), 'has DocumentSort');
 }
 /**
  * Create an object from a string representation.  It treats it as a PHP constructor without the
  * 'new' keyword.  It also manages to construct the object without the use of eval().
  *
  * Construction itself is done with Object::create(), so that Object::useCustomClass() calls
  * are respected.
  *
  * `Object::create_from_string("Versioned('Stage','Live')")` will return the result of
  * `Versioned::create('Stage', 'Live);`
  *
  * It is designed for simple, cloneable objects.  The first time this method is called for a given
  * string it is cached, and clones of that object are returned.
  *
  * If you pass the $firstArg argument, this will be prepended to the constructor arguments. It's
  * impossible to pass null as the firstArg argument.
  *
  * `Object::create_from_string("Varchar(50)", "MyField")` will return the result of
  * `Varchar::create('MyField', '50');`
  *
  * Arguments are always strings, although this is a quirk of the current implementation rather
  * than something that can be relied upon.
  *
  * @param string $classSpec
  * @param mixed $firstArg
  * @return object
  */
 public static function create_from_string($classSpec, $firstArg = null)
 {
     if (!isset(self::$_cache_inst_args[$classSpec . $firstArg])) {
         // an $extension value can contain parameters as a string,
         // e.g. "Versioned('Stage','Live')"
         if (strpos($classSpec, '(') === false) {
             if ($firstArg === null) {
                 self::$_cache_inst_args[$classSpec . $firstArg] = Object::create($classSpec);
             } else {
                 self::$_cache_inst_args[$classSpec . $firstArg] = Object::create($classSpec, $firstArg);
             }
         } else {
             list($class, $args) = self::parse_class_spec($classSpec);
             if ($firstArg !== null) {
                 array_unshift($args, $firstArg);
             }
             array_unshift($args, $class);
             self::$_cache_inst_args[$classSpec . $firstArg] = call_user_func_array(array('SilverStripe\\Core\\Object', 'create'), $args);
         }
     }
     return clone self::$_cache_inst_args[$classSpec . $firstArg];
 }
 /**
  * Loads the temporary file data into a File object
  *
  * @param array $tmpFile Temporary file data
  * @param string $error Error message
  * @return AssetContainer File object, or null if error
  */
 protected function saveTemporaryFile($tmpFile, &$error = null)
 {
     // Determine container object
     $error = null;
     $fileObject = null;
     if (empty($tmpFile)) {
         $error = _t('UploadField.FIELDNOTSET', 'File information not found');
         return null;
     }
     if ($tmpFile['error']) {
         $error = $tmpFile['error'];
         return null;
     }
     // Search for relations that can hold the uploaded files, but don't fallback
     // to default if there is no automatic relation
     if ($relationClass = $this->getRelationAutosetClass(null)) {
         // Allow File to be subclassed
         if ($relationClass === 'SilverStripe\\Assets\\File' && isset($tmpFile['name'])) {
             $relationClass = File::get_class_for_file_extension(File::get_file_extension($tmpFile['name']));
         }
         // Create new object explicitly. Otherwise rely on Upload::load to choose the class.
         $fileObject = Object::create($relationClass);
         if (!$fileObject instanceof DataObject || !$fileObject instanceof AssetContainer) {
             throw new InvalidArgumentException("Invalid asset container {$relationClass}");
         }
     }
     // Get the uploaded file into a new file object.
     try {
         $this->upload->loadIntoFile($tmpFile, $fileObject, $this->getFolderName());
     } catch (Exception $e) {
         // we shouldn't get an error here, but just in case
         $error = $e->getMessage();
         return null;
     }
     // Check if upload field has an error
     if ($this->upload->isError()) {
         $error = implode(' ' . PHP_EOL, $this->upload->getErrors());
         return null;
     }
     // return file
     return $this->upload->getFile();
 }
 /**
  * Get a db object for the named field
  *
  * @param string $field Field name
  * @return DBField|null
  */
 public function dbObject($field)
 {
     $fields = $this->compositeDatabaseFields();
     if (!isset($fields[$field])) {
         return null;
     }
     // Build nested field
     $key = $this->getName() . $field;
     $spec = $fields[$field];
     /** @var DBField $fieldObject */
     $fieldObject = Object::create_from_string($spec, $key);
     $fieldObject->setValue($this->getField($field), null, false);
     return $fieldObject;
 }
 /**
  *
  * @param GridField $gridField
  * @param HTTPRequest $request
  * @return GridFieldDetailForm_ItemRequest
  */
 public function handleItem($gridField, $request)
 {
     // Our getController could either give us a true Controller, if this is the top-level GridField.
     // It could also give us a RequestHandler in the form of GridFieldDetailForm_ItemRequest if this is a
     // nested GridField.
     $requestHandler = $gridField->getForm()->getController();
     /** @var DataObject $record */
     if (is_numeric($request->param('ID'))) {
         $record = $gridField->getList()->byID($request->param("ID"));
     } else {
         $record = Object::create($gridField->getModelClass());
     }
     $handler = $this->getItemRequestHandler($gridField, $record, $requestHandler);
     // if no validator has been set on the GridField and the record has a
     // CMS validator, use that.
     if (!$this->getValidator() && (method_exists($record, 'getCMSValidator') || $record instanceof Object && $record->hasMethod('getCMSValidator'))) {
         $this->setValidator($record->getCMSValidator());
     }
     return $handler->handleRequest($request, DataModel::inst());
 }
 /**
  * @param DateField $field
  */
 public function __construct($field)
 {
     parent::__construct();
     $this->field = $field;
 }
 /**
  * Safely get a DataObject from a client-supplied ID and ClassName, checking: argument
  * validity; existence; and canView permissions.
  *
  * @param int $id The ID of the DataObject
  * @param string $class The Class of the DataObject
  * @return DataObject The referenced DataObject
  * @throws HTTPResponse_Exception
  */
 protected function getObject($id, $class)
 {
     $id = (int) $id;
     $class = ClassInfo::class_name($class);
     if (!$class || !is_subclass_of($class, 'SilverStripe\\ORM\\DataObject') || !Object::has_extension($class, 'SilverStripe\\ORM\\Versioning\\Versioned')) {
         $this->controller->httpError(400, _t('AddToCampaign.ErrorGeneral', 'We apologise, but there was an error'));
         return null;
     }
     $object = DataObject::get($class)->byID($id);
     if (!$object) {
         $this->controller->httpError(404, _t('AddToCampaign.ErrorNotFound', 'That {Type} couldn\'t be found', '', ['Type' => $class]));
         return null;
     }
     if (!$object->canView()) {
         $this->controller->httpError(403, _t('AddToCampaign.ErrorItemPermissionDenied', 'It seems you don\'t have the necessary permissions to add {ObjectTitle} to a campaign', '', ['ObjectTitle' => $object->Title]));
         return null;
     }
     return $object;
 }
 public function create($class, array $params = array())
 {
     if (strpos($class, '(') === false) {
         return parent::create($class, $params);
     } else {
         list($class, $params) = Object::parse_class_spec($class);
         $params = $this->injector->convertServiceProperty($params);
         return parent::create($class, $params);
     }
 }
 /**
  * @param DataObject|DataObjectInterface $record
  */
 public function saveInto(DataObjectInterface $record)
 {
     if (!isset($_FILES[$this->name])) {
         return;
     }
     $fileClass = File::get_class_for_file_extension(File::get_file_extension($_FILES[$this->name]['name']));
     /** @var File $file */
     if ($this->relationAutoSetting) {
         // assume that the file is connected via a has-one
         $objectClass = DataObject::getSchema()->hasOneComponent(get_class($record), $this->name);
         if ($objectClass === File::class || empty($objectClass)) {
             // Create object of the appropriate file class
             $file = Object::create($fileClass);
         } else {
             // try to create a file matching the relation
             $file = Object::create($objectClass);
         }
     } else {
         if ($record instanceof File) {
             $file = $record;
         } else {
             $file = Object::create($fileClass);
         }
     }
     $this->upload->loadIntoFile($_FILES[$this->name], $file, $this->getFolderName());
     if ($this->upload->isError()) {
         return;
     }
     if ($this->relationAutoSetting) {
         if (empty($objectClass)) {
             return;
         }
         $file = $this->upload->getFile();
         $record->{$this->name . 'ID'} = $file->ID;
     }
 }
 public static function get_extra_config_sources($class = null)
 {
     if ($class === null) {
         $class = get_called_class();
     }
     // If this class is unextendable, NOP
     if (in_array($class, self::$unextendable_classes)) {
         return null;
     }
     // Variable to hold sources in
     $sources = null;
     // Get a list of extensions
     $extensions = Config::inst()->get($class, 'extensions', Config::UNINHERITED | Config::EXCLUDE_EXTRA_SOURCES);
     if (!$extensions) {
         return null;
     }
     // Build a list of all sources;
     $sources = array();
     foreach ($extensions as $extension) {
         list($extensionClass, $extensionArgs) = Object::parse_class_spec($extension);
         $sources[] = $extensionClass;
         if (!class_exists($extensionClass)) {
             throw new InvalidArgumentException("{$class} references nonexistent {$extensionClass} in \$extensions");
         }
         call_user_func(array($extensionClass, 'add_to_class'), $class, $extensionClass, $extensionArgs);
         foreach (array_reverse(ClassInfo::ancestry($extensionClass)) as $extensionClassParent) {
             if (ClassInfo::has_method_from($extensionClassParent, 'get_extra_config', $extensionClassParent)) {
                 $extras = $extensionClassParent::get_extra_config($class, $extensionClass, $extensionArgs);
                 if ($extras) {
                     $sources[] = $extras;
                 }
             }
         }
     }
     return $sources;
 }
 /**
  * Get the value of a field on this object, automatically inserting the value into any available casting objects
  * that have been specified.
  *
  * @param string $fieldName
  * @param array $arguments
  * @param bool $cache Cache this object
  * @param string $cacheName a custom cache name
  * @return Object|DBField
  */
 public function obj($fieldName, $arguments = [], $cache = false, $cacheName = null)
 {
     if (!$cacheName && $cache) {
         $cacheName = $this->objCacheName($fieldName, $arguments);
     }
     // Check pre-cached value
     $value = $cache ? $this->objCacheGet($cacheName) : null;
     if ($value !== null) {
         return $value;
     }
     // Load value from record
     if ($this->hasMethod($fieldName)) {
         $value = call_user_func_array(array($this, $fieldName), $arguments ?: []);
     } else {
         $value = $this->{$fieldName};
     }
     // Cast object
     if (!is_object($value)) {
         // Force cast
         $castingHelper = $this->castingHelper($fieldName);
         $valueObject = Object::create_from_string($castingHelper, $fieldName);
         $valueObject->setValue($value, $this);
         $value = $valueObject;
     }
     // Record in cache
     if ($cache) {
         $this->objCacheSet($cacheName, $value);
     }
     return $value;
 }
 public function testExtendedCan()
 {
     $extensions = $this->removeExtensions(Object::get_extensions('SilverStripe\\Security\\Member'));
     $member = $this->objFromFixture('SilverStripe\\Security\\Member', 'test');
     /* Normal behaviour is that you can't view a member unless canView() on an extension returns true */
     $this->assertFalse($member->canView());
     $this->assertFalse($member->canDelete());
     $this->assertFalse($member->canEdit());
     /* Apply a extension that allows viewing in any case (most likely the case for member profiles) */
     Member::add_extension('MemberTest_ViewingAllowedExtension');
     $member2 = $this->objFromFixture('SilverStripe\\Security\\Member', 'staffmember');
     $this->assertTrue($member2->canView());
     $this->assertFalse($member2->canDelete());
     $this->assertFalse($member2->canEdit());
     /* Apply a extension that denies viewing of the Member */
     Member::remove_extension('MemberTest_ViewingAllowedExtension');
     Member::add_extension('MemberTest_ViewingDeniedExtension');
     $member3 = $this->objFromFixture('SilverStripe\\Security\\Member', 'managementmember');
     $this->assertFalse($member3->canView());
     $this->assertFalse($member3->canDelete());
     $this->assertFalse($member3->canEdit());
     /* Apply a extension that allows viewing and editing but denies deletion */
     Member::remove_extension('MemberTest_ViewingDeniedExtension');
     Member::add_extension('MemberTest_EditingAllowedDeletingDeniedExtension');
     $member4 = $this->objFromFixture('SilverStripe\\Security\\Member', 'accountingmember');
     $this->assertTrue($member4->canView());
     $this->assertFalse($member4->canDelete());
     $this->assertTrue($member4->canEdit());
     Member::remove_extension('MemberTest_EditingAllowedDeletingDeniedExtension');
     $this->addExtensions($extensions);
 }
 /**
  * Create a DBField object that's not bound to any particular field.
  *
  * Useful for accessing the classes behaviour for other parts of your code.
  *
  * @param string $className class of field to construct
  * @param mixed $value value of field
  * @param string $name Name of field
  * @param mixed $object Additional parameter to pass to field constructor
  * @return DBField
  */
 public static function create_field($className, $value, $name = null, $object = null)
 {
     /** @var DBField $dbField */
     $dbField = Object::create($className, $name, $object);
     $dbField->setValue($value, null, false);
     return $dbField;
 }
 /**
  * Helper method for applicablePages() methods.  Acts as a skeleton implementation.
  *
  * @param array $ids The IDs passed to applicablePages
  * @param string $methodName The canXXX() method to call on each page to check if the action is applicable
  * @param bool $checkStagePages Set to true if you want to check stage pages
  * @param bool $checkLivePages Set to true if you want to check live pages (e.g, for deleted-from-draft)
  * @return array
  */
 public function applicablePagesHelper($ids, $methodName, $checkStagePages = true, $checkLivePages = true)
 {
     if (!is_array($ids)) {
         user_error("Bad \$ids passed to applicablePagesHelper()", E_USER_WARNING);
     }
     if (!is_string($methodName)) {
         user_error("Bad \$methodName passed to applicablePagesHelper()", E_USER_WARNING);
     }
     $applicableIDs = array();
     $managedClass = $this->managedClass;
     $draftPages = DataObject::get($managedClass)->byIDs($ids);
     // Filter out the live-only ids
     $onlyOnLive = array_fill_keys($ids, true);
     if ($checkStagePages) {
         foreach ($draftPages as $obj) {
             unset($onlyOnLive[$obj->ID]);
             if ($obj->{$methodName}()) {
                 $applicableIDs[] = $obj->ID;
             }
         }
     }
     $onlyOnLive = array_keys($onlyOnLive);
     if ($checkLivePages && $onlyOnLive && Object::has_extension($managedClass, 'SilverStripe\\ORM\\Versioning\\Versioned')) {
         // Get the pages that only exist on live (deleted from stage)
         $livePages = Versioned::get_by_stage($managedClass, "Live")->byIDs($onlyOnLive);
         foreach ($livePages as $obj) {
             if ($obj->{$methodName}()) {
                 $applicableIDs[] = $obj->ID;
             }
         }
     }
     return $applicableIDs;
 }
 public function testCreate()
 {
     /** @var DBHTMLText $field */
     $field = Object::create_from_string("HTMLFragment(['whitelist' => 'link'])", 'MyField');
     $this->assertEquals(['link'], $field->getWhitelist());
     $field = Object::create_from_string("HTMLFragment(['whitelist' => 'link,a'])", 'MyField');
     $this->assertEquals(['link', 'a'], $field->getWhitelist());
     $field = Object::create_from_string("HTMLFragment(['whitelist' => ['link', 'a']])", 'MyField');
     $this->assertEquals(['link', 'a'], $field->getWhitelist());
     $field = Object::create_from_string("HTMLFragment", 'MyField');
     $this->assertEmpty($field->getWhitelist());
     // Test shortcodes
     $field = Object::create_from_string("HTMLFragment(['shortcodes' => true])", 'MyField');
     $this->assertEquals(true, $field->getProcessShortcodes());
     $field = Object::create_from_string("HTMLFragment(['shortcodes' => false])", 'MyField');
     $this->assertEquals(false, $field->getProcessShortcodes());
     // Mix options
     $field = Object::create_from_string("HTMLFragment(['shortcodes' => true, 'whitelist' => ['a'])", 'MyField');
     $this->assertEquals(true, $field->getProcessShortcodes());
     $this->assertEquals(['a'], $field->getWhitelist());
 }
 /**
  * @param $name
  */
 public function __construct($name = null)
 {
     $this->name = $name ? $name : self::get_default_name();
     parent::__construct();
 }
 /**
  * Return the DBField object that represents the given field.
  * This works similarly to obj() with 2 key differences:
  *   - it still returns an object even when the field has no value.
  *   - it only matches fields and not methods
  *   - it matches foreign keys generated by has_one relationships, eg, "ParentID"
  *
  * @param string $fieldName Name of the field
  * @return DBField The field as a DBField object
  */
 public function dbObject($fieldName)
 {
     // Check for field in DB
     $helper = static::getSchema()->fieldSpec(static::class, $fieldName, DataObjectSchema::INCLUDE_CLASS);
     if (!$helper) {
         return null;
     }
     $value = isset($this->record[$fieldName]) ? $this->record[$fieldName] : null;
     // If we have a DBField object in $this->record, then return that
     if ($value instanceof DBField) {
         return $value;
     }
     list($table, $spec) = explode('.', $helper);
     /** @var DBField $obj */
     $obj = Object::create_from_string($spec, $fieldName);
     $obj->setTable($table);
     $obj->setValue($value, $this, false);
     return $obj;
 }
 public function __construct()
 {
     _t('i18nTestModule.OTHERENTITY', 'Other Entity');
     parent::__construct();
 }
 protected function getUncached($class, $name, $sourceOptions, &$result, $suppress, &$tags)
 {
     $tags[] = "__{$class}";
     $tags[] = "__{$class}__{$name}";
     // If result is already not something to merge into, just return it
     if ($result !== null && !is_array($result)) {
         return $result;
     }
     // First, look through the override values
     foreach ($this->overrides as $k => $overrides) {
         if (isset($overrides[$class][$name])) {
             $value = $overrides[$class][$name];
             self::merge_low_into_high($result, $value, $suppress);
             if ($result !== null && !is_array($result)) {
                 return $result;
             }
         }
         if (isset($this->suppresses[$k][$class][$name])) {
             $suppress = $suppress ? array_merge($suppress, $this->suppresses[$k][$class][$name]) : $this->suppresses[$k][$class][$name];
         }
     }
     $nothing = null;
     // Then the manifest values
     foreach ($this->manifests as $manifest) {
         $value = $manifest->get($class, $name, $nothing);
         if ($value !== $nothing) {
             self::merge_low_into_high($result, $value, $suppress);
             if ($result !== null && !is_array($result)) {
                 return $result;
             }
         }
     }
     $sources = array($class);
     // Include extensions only if not flagged not to, and some have been set
     if (($sourceOptions & self::EXCLUDE_EXTRA_SOURCES) != self::EXCLUDE_EXTRA_SOURCES) {
         // If we don't have a fresh list of extra sources, get it from the class itself
         if (!array_key_exists($class, $this->extraConfigSources)) {
             $this->extraConfigSources[$class] = Object::get_extra_config_sources($class);
         }
         // Update $sources with any extra sources
         $extraSources = $this->extraConfigSources[$class];
         if ($extraSources) {
             $sources = array_merge($sources, $extraSources);
         }
     }
     $value = $nothing = null;
     foreach ($sources as $staticSource) {
         if (is_array($staticSource)) {
             $value = isset($staticSource[$name]) ? $staticSource[$name] : $nothing;
         } else {
             foreach ($this->staticManifests as $i => $statics) {
                 $value = $statics->get($staticSource, $name, $nothing);
                 if ($value !== $nothing) {
                     break;
                 }
             }
         }
         if ($value !== $nothing) {
             self::merge_low_into_high($result, $value, $suppress);
             if ($result !== null && !is_array($result)) {
                 return $result;
             }
         }
     }
     // Finally, merge in the values from the parent class
     if (($sourceOptions & self::UNINHERITED) != self::UNINHERITED && (($sourceOptions & self::FIRST_SET) != self::FIRST_SET || $result === null)) {
         $parent = get_parent_class($class);
         if ($parent) {
             $this->getUncached($parent, $name, $sourceOptions, $result, $suppress, $tags);
         }
     }
     return $result;
 }
 public function testStaticLookup()
 {
     $this->assertEquals(Object::static_lookup('ConfigTest_DefinesFoo', 'foo'), 1);
     $this->assertEquals(Object::static_lookup('ConfigTest_DefinesFoo', 'bar'), null);
     $this->assertEquals(Object::static_lookup('ConfigTest_DefinesBar', 'foo'), null);
     $this->assertEquals(Object::static_lookup('ConfigTest_DefinesBar', 'bar'), 2);
     $this->assertEquals(Object::static_lookup('ConfigTest_DefinesFooAndBar', 'foo'), 3);
     $this->assertEquals(Object::static_lookup('ConfigTest_DefinesFooAndBar', 'bar'), 3);
     $this->assertEquals(Object::static_lookup('ConfigTest_DefinesFooDoesntExtendObject', 'foo'), 4);
     $this->assertEquals(Object::static_lookup('ConfigTest_DefinesFooDoesntExtendObject', 'bar'), null);
 }