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;
 }
 public function testParseClassSpec()
 {
     // Simple case
     $this->assertEquals(array('SilverStripe\\ORM\\Versioning\\Versioned', array('Stage', 'Live')), Object::parse_class_spec("SilverStripe\\ORM\\Versioning\\Versioned('Stage','Live')"));
     // String with commas
     $this->assertEquals(array('SilverStripe\\ORM\\Versioning\\Versioned', array('Stage,Live', 'Stage')), Object::parse_class_spec("SilverStripe\\ORM\\Versioning\\Versioned('Stage,Live','Stage')"));
     // String with quotes
     $this->assertEquals(array('SilverStripe\\ORM\\Versioning\\Versioned', array('Stage\'Stage,Live\'Live', 'Live')), Object::parse_class_spec("SilverStripe\\ORM\\Versioning\\Versioned('Stage\\'Stage,Live\\'Live','Live')"));
     // True, false and null values
     $this->assertEquals(array('ClassName', array('string', true, array('string', false))), Object::parse_class_spec('ClassName("string", true, array("string", false))'));
     $this->assertEquals(array('ClassName', array(true, false, null)), Object::parse_class_spec('ClassName(true, false, null)'));
     // Array
     $this->assertEquals(array('Enum', array(array('Accepted', 'Pending', 'Declined', 'Unsubmitted'), 'Unsubmitted')), Object::parse_class_spec("Enum(array('Accepted', 'Pending', 'Declined', 'Unsubmitted'), 'Unsubmitted')"));
     // Nested array
     $this->assertEquals(array('Enum', array(array('Accepted', 'Pending', 'Declined', array('UnsubmittedA', 'UnsubmittedB')), 'Unsubmitted')), Object::parse_class_spec("Enum(array('Accepted', 'Pending', 'Declined', array('UnsubmittedA','UnsubmittedB')), 'Unsubmitted')"));
     // 5.4 Shorthand Array
     $this->assertEquals(array('Enum', array(array('Accepted', 'Pending', 'Declined', 'Unsubmitted'), 'Unsubmitted')), Object::parse_class_spec("Enum(['Accepted', 'Pending', 'Declined', 'Unsubmitted'], 'Unsubmitted')"));
     // 5.4 Nested shorthand array
     $this->assertEquals(array('Enum', array(array('Accepted', 'Pending', 'Declined', array('UnsubmittedA', 'UnsubmittedB')), 'Unsubmitted')), Object::parse_class_spec("Enum(['Accepted', 'Pending', 'Declined', ['UnsubmittedA','UnsubmittedB']], 'Unsubmitted')"));
     // Associative array
     $this->assertEquals(array('Varchar', array(255, array('nullifyEmpty' => false))), Object::parse_class_spec("Varchar(255, array('nullifyEmpty' => false))"));
     // Nested associative array
     $this->assertEquals(array('Test', array('string', array('nested' => array('foo' => 'bar')))), Object::parse_class_spec("Test('string', array('nested' => array('foo' => 'bar')))"));
     // 5.4 shorthand associative array
     $this->assertEquals(array('Varchar', array(255, array('nullifyEmpty' => false))), Object::parse_class_spec("Varchar(255, ['nullifyEmpty' => false])"));
     // 5.4 shorthand nested associative array
     $this->assertEquals(array('Test', array('string', array('nested' => array('foo' => 'bar')))), Object::parse_class_spec("Test('string', ['nested' => ['foo' => 'bar']])"));
     // Namespaced class
     $this->assertEquals(array('Test\\MyClass', array()), Object::parse_class_spec('Test\\MyClass'));
     // Fully qualified namespaced class
     $this->assertEquals(array('\\Test\\MyClass', array()), Object::parse_class_spec('\\Test\\MyClass'));
 }
 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);
     }
 }
 /**
  * Check that the given action is allowed to be called from a URL.
  * It will interrogate {@link self::$allowed_actions} to determine this.
  *
  * @param string $action
  * @return bool
  * @throws Exception
  */
 public function checkAccessAction($action)
 {
     $actionOrigCasing = $action;
     $action = strtolower($action);
     $isAllowed = false;
     $isDefined = false;
     // Get actions for this specific class (without inheritance)
     $definingClass = $this->definingClassForAction($actionOrigCasing);
     $allowedActions = $this->allowedActions($definingClass);
     // check if specific action is set
     if (isset($allowedActions[$action])) {
         $isDefined = true;
         $test = $allowedActions[$action];
         if ($test === true || $test === 1 || $test === '1') {
             // TRUE should always allow access
             $isAllowed = true;
         } elseif (substr($test, 0, 2) == '->') {
             // Determined by custom method with "->" prefix
             list($method, $arguments) = Object::parse_class_spec(substr($test, 2));
             $isAllowed = call_user_func_array(array($this, $method), $arguments);
         } else {
             // Value is a permission code to check the current member against
             $isAllowed = Permission::check($test);
         }
     } elseif (is_array($allowedActions) && ($key = array_search($action, $allowedActions, true)) !== false && is_numeric($key)) {
         // Allow numeric array notation (search for array value as action instead of key)
         $isDefined = true;
         $isAllowed = true;
     } elseif (is_array($allowedActions) && !count($allowedActions)) {
         // If defined as empty array, deny action
         $isAllowed = false;
     } elseif ($allowedActions === null) {
         // If undefined, allow action based on configuration
         $isAllowed = !Config::inst()->get('SilverStripe\\Control\\RequestHandler', 'require_allowed_actions');
     }
     // If we don't have a match in allowed_actions,
     // whitelist the 'index' action as well as undefined actions based on configuration.
     if (!$isDefined && ($action == 'index' || empty($action))) {
         $isAllowed = true;
     }
     return $isAllowed;
 }