mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #734 from silverstripe-rebelalliance/trac/7799
API Reverse config extra statics control flow
This commit is contained in:
commit
674b52b4f7
@ -231,6 +231,25 @@ class ClassInfo {
|
||||
|
||||
return $matchedClasses;
|
||||
}
|
||||
|
||||
private static $method_from_cache = array();
|
||||
|
||||
static function has_method_from($class, $method, $compclass) {
|
||||
if (!isset(self::$method_from_cache[$class])) self::$method_from_cache[$class] = array();
|
||||
|
||||
if (!array_key_exists($method, self::$method_from_cache[$class])) {
|
||||
self::$method_from_cache[$class][$method] = false;
|
||||
|
||||
$classRef = new ReflectionClass($class);
|
||||
|
||||
if ($classRef->hasMethod($method)) {
|
||||
$methodRef = $classRef->getMethod($method);
|
||||
self::$method_from_cache[$class][$method] = $methodRef->getDeclaringClass()->getName();
|
||||
}
|
||||
}
|
||||
|
||||
return self::$method_from_cache[$class][$method] == $compclass;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -173,12 +173,6 @@ class Config {
|
||||
$this->collectConfigPHPSettings = false;
|
||||
}
|
||||
|
||||
static $extra_static_sources = array();
|
||||
|
||||
static function add_static_source($forclass, $donorclass) {
|
||||
self::$extra_static_sources[$forclass][] = $donorclass;
|
||||
}
|
||||
|
||||
/** @var [Config_ForClass] - The list of Config_ForClass instances, keyed off class */
|
||||
static protected $for_class_instances = array();
|
||||
|
||||
@ -371,14 +365,17 @@ class Config {
|
||||
|
||||
// Then look at the static variables
|
||||
$nothing = new stdClass();
|
||||
$classes = array($class);
|
||||
|
||||
$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) && isset(self::$extra_static_sources[$class])) {
|
||||
$classes = array_merge($classes, self::$extra_static_sources[$class]);
|
||||
if (($sourceOptions & self::EXCLUDE_EXTRA_SOURCES) != self::EXCLUDE_EXTRA_SOURCES) {
|
||||
$extraSources = Object::get_extra_config_sources($class);
|
||||
if ($extraSources) $sources = array_merge($sources, $extraSources);
|
||||
}
|
||||
|
||||
foreach ($classes as $staticSource) {
|
||||
$value = Object::static_lookup($staticSource, $name, $nothing);
|
||||
foreach ($sources as $staticSource) {
|
||||
if (is_array($staticSource)) $value = isset($staticSource[$name]) ? $staticSource[$name] : $nothing;
|
||||
else $value = Object::static_lookup($staticSource, $name, $nothing);
|
||||
|
||||
if ($value !== $nothing) {
|
||||
self::merge_low_into_high($result, $value, $suppress);
|
||||
|
@ -46,14 +46,11 @@ abstract class Extension {
|
||||
/**
|
||||
* Called when this extension is added to a particular class
|
||||
*
|
||||
* TODO: This is likely to be replaced by event sytem before 3.0 final, so be aware
|
||||
* this API is fairly unstable.
|
||||
*
|
||||
* @static
|
||||
* @param $class
|
||||
*/
|
||||
static function add_to_class($class, $extensionClass, $args = null) {
|
||||
Config::add_static_source($class, $extensionClass);
|
||||
// NOP
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -463,6 +463,7 @@ abstract class Object {
|
||||
if($subclasses) foreach($subclasses as $subclass) {
|
||||
unset(self::$classes_constructed[$subclass]);
|
||||
unset(self::$extra_methods[$subclass]);
|
||||
unset(self::$extension_sources[$subclass]);
|
||||
}
|
||||
|
||||
Config::inst()->update($class, 'extensions', array($extension));
|
||||
@ -505,6 +506,7 @@ abstract class Object {
|
||||
if($subclasses) foreach($subclasses as $subclass) {
|
||||
unset(self::$classes_constructed[$subclass]);
|
||||
unset(self::$extra_methods[$subclass]);
|
||||
unset(self::$extension_sources[$subclass]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -531,38 +533,66 @@ abstract class Object {
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
private static $_added_extensions = array();
|
||||
private static $extension_sources = array();
|
||||
|
||||
// Don't bother checking some classes that should never be extended
|
||||
private static $unextendable_classes = array('Object', 'ViewableData', 'RequestHandler');
|
||||
|
||||
static public 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;
|
||||
|
||||
// If we have a pre-cached version, use that
|
||||
if(array_key_exists($class, self::$extension_sources)) return self::$extension_sources[$class];
|
||||
|
||||
// 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) {
|
||||
// Build a list of all sources;
|
||||
$sources = array();
|
||||
|
||||
foreach($extensions as $extension) {
|
||||
list($extensionClass, $extensionArgs) = self::parse_class_spec($extension);
|
||||
$sources[] = $extensionClass;
|
||||
|
||||
if(!ClassInfo::has_method_from($extensionClass, 'add_to_class', 'Extension')) {
|
||||
Deprecation::notice('3.1.0', "add_to_class deprecated on $extensionClass. Use get_extra_config instead");
|
||||
}
|
||||
|
||||
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 self::$extension_sources[$class] = $sources;
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
$this->class = get_class($this);
|
||||
|
||||
// Don't bother checking some classes that should never be extended
|
||||
static $notExtendable = array('Object', 'ViewableData', 'RequestHandler');
|
||||
|
||||
if($extensionClasses = ClassInfo::ancestry($this->class)) foreach($extensionClasses as $class) {
|
||||
if(in_array($class, $notExtendable)) continue;
|
||||
if($extensions = Config::inst()->get($class, 'extensions', Config::UNINHERITED)) {
|
||||
foreach($extensions as $extension) {
|
||||
// Get the extension class for this extension
|
||||
list($extensionClass, $extensionArgs) = self::parse_class_spec($extension);
|
||||
foreach(ClassInfo::ancestry(get_called_class()) as $class) {
|
||||
if(in_array($class, self::$unextendable_classes)) continue;
|
||||
$extensions = Config::inst()->get($class, 'extensions', Config::UNINHERITED | Config::EXCLUDE_EXTRA_SOURCES);
|
||||
|
||||
// If we haven't told that extension it's attached to this class yet, do that now
|
||||
if (!isset(self::$_added_extensions[$extensionClass][$class])) {
|
||||
// First call the add_to_class method - this will inherit down & is defined on Extension, so if not defined, no worries
|
||||
call_user_func(array($extensionClass, 'add_to_class'), $class, $extensionClass, $extensionArgs);
|
||||
|
||||
// Then register it as having been told about us
|
||||
if (!isset(self::$_added_extensions[$extensionClass])) self::$_added_extensions[$extensionClass] = array($class => true);
|
||||
else self::$_added_extensions[$extensionClass][$class] = true;
|
||||
}
|
||||
|
||||
$instance = self::create_from_string($extension);
|
||||
$instance->setOwner(null, $class);
|
||||
$this->extension_instances[$instance->class] = $instance;
|
||||
}
|
||||
if($extensions) foreach($extensions as $extension) {
|
||||
$instance = self::create_from_string($extension);
|
||||
$instance->setOwner(null, $class);
|
||||
$this->extension_instances[$instance->class] = $instance;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!isset(self::$classes_constructed[$this->class])) {
|
||||
$this->defineMethods();
|
||||
self::$classes_constructed[$this->class] = true;
|
||||
|
@ -31,34 +31,21 @@ abstract class DataExtension extends Extension {
|
||||
'api_access' => false,
|
||||
);
|
||||
|
||||
static function add_to_class($class, $extensionClass, $args = null) {
|
||||
if(method_exists($class, 'extraDBFields')) {
|
||||
static function get_extra_config($class, $extension, $args) {
|
||||
if(method_exists($extension, 'extraDBFields')) {
|
||||
$extraStaticsMethod = 'extraDBFields';
|
||||
} else {
|
||||
$extraStaticsMethod = 'extraStatics';
|
||||
}
|
||||
|
||||
$statics = Injector::inst()->get($extensionClass, true, $args)->$extraStaticsMethod($class, $extensionClass);
|
||||
$statics = Injector::inst()->get($extension, true, $args)->$extraStaticsMethod();
|
||||
|
||||
if ($statics) {
|
||||
Deprecation::notice('3.1.0', "$extraStaticsMethod deprecated. Just define statics on your extension, or use add_to_class", Deprecation::SCOPE_GLOBAL);
|
||||
|
||||
// TODO: This currently makes extraStatics the MOST IMPORTANT config layer, not the least
|
||||
foreach (self::$extendable_statics as $key => $merge) {
|
||||
if (isset($statics[$key])) {
|
||||
if (!$merge) Config::inst()->remove($class, $key);
|
||||
Config::inst()->update($class, $key, $statics[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO - remove this
|
||||
DataObject::$cache_has_own_table[$class] = null;
|
||||
DataObject::$cache_has_own_table_field[$class] = null;
|
||||
Deprecation::notice('3.1.0', "$extraStaticsMethod deprecated. Just define statics on your extension, or use get_extra_config", Deprecation::SCOPE_GLOBAL);
|
||||
return $statics;
|
||||
}
|
||||
|
||||
parent::add_to_class($class, $extensionClass, $args);
|
||||
}
|
||||
|
||||
|
||||
public static function unload_extra_statics($class, $extension) {
|
||||
throw new Exception('unload_extra_statics gone');
|
||||
}
|
||||
|
@ -25,9 +25,10 @@ class Hierarchy extends DataExtension {
|
||||
function augmentWrite(&$manipulation) {
|
||||
}
|
||||
|
||||
static function add_to_class($class, $extensionClass, $args = null) {
|
||||
Config::inst()->update($class, 'has_one', array('Parent' => $class));
|
||||
parent::add_to_class($class, $extensionClass, $args);
|
||||
static function get_extra_config($class, $extension, $args) {
|
||||
return array(
|
||||
'has_one' => array('Parent' => $class)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -107,9 +107,10 @@ class Versioned extends DataExtension {
|
||||
'Version' => 'Int'
|
||||
);
|
||||
|
||||
static function add_to_class($class, $extensionClass, $args = null) {
|
||||
Config::inst()->update($class, 'has_many', array('Versions' => $class));
|
||||
parent::add_to_class($class, $extensionClass, $args);
|
||||
static function get_extra_config($class, $extension, $args) {
|
||||
array(
|
||||
'has_many' => array('Versions' => $class)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,14 +75,16 @@ class FulltextSearchable extends DataExtension {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
static function add_to_class($class, $extensionClass, $args = null) {
|
||||
Config::inst()->update($class, 'indexes', array('SearchFields' => array(
|
||||
'type' => 'fulltext',
|
||||
'name' => 'SearchFields',
|
||||
'value' => $args[0]
|
||||
)));
|
||||
|
||||
parent::add_to_class($class, $extensionClass, $args);
|
||||
static function get_extra_config($class, $extensionClass, $args) {
|
||||
return array(
|
||||
'indexes' => array(
|
||||
'SearchFields' => array(
|
||||
'type' => 'fulltext',
|
||||
'name' => 'SearchFields',
|
||||
'value' => $args[0]
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user