mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
Merge pull request #734 from silverstripe-rebelalliance/trac/7799
API Reverse config extra statics control flow
This commit is contained in:
commit
674b52b4f7
@ -232,5 +232,24 @@ class ClassInfo {
|
|||||||
return $matchedClasses;
|
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;
|
$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 */
|
/** @var [Config_ForClass] - The list of Config_ForClass instances, keyed off class */
|
||||||
static protected $for_class_instances = array();
|
static protected $for_class_instances = array();
|
||||||
|
|
||||||
@ -371,14 +365,17 @@ class Config {
|
|||||||
|
|
||||||
// Then look at the static variables
|
// Then look at the static variables
|
||||||
$nothing = new stdClass();
|
$nothing = new stdClass();
|
||||||
$classes = array($class);
|
|
||||||
|
$sources = array($class);
|
||||||
// Include extensions only if not flagged not to, and some have been set
|
// 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])) {
|
if (($sourceOptions & self::EXCLUDE_EXTRA_SOURCES) != self::EXCLUDE_EXTRA_SOURCES) {
|
||||||
$classes = array_merge($classes, self::$extra_static_sources[$class]);
|
$extraSources = Object::get_extra_config_sources($class);
|
||||||
|
if ($extraSources) $sources = array_merge($sources, $extraSources);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($classes as $staticSource) {
|
foreach ($sources as $staticSource) {
|
||||||
$value = Object::static_lookup($staticSource, $name, $nothing);
|
if (is_array($staticSource)) $value = isset($staticSource[$name]) ? $staticSource[$name] : $nothing;
|
||||||
|
else $value = Object::static_lookup($staticSource, $name, $nothing);
|
||||||
|
|
||||||
if ($value !== $nothing) {
|
if ($value !== $nothing) {
|
||||||
self::merge_low_into_high($result, $value, $suppress);
|
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
|
* 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
|
* @static
|
||||||
* @param $class
|
* @param $class
|
||||||
*/
|
*/
|
||||||
static function add_to_class($class, $extensionClass, $args = null) {
|
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) {
|
if($subclasses) foreach($subclasses as $subclass) {
|
||||||
unset(self::$classes_constructed[$subclass]);
|
unset(self::$classes_constructed[$subclass]);
|
||||||
unset(self::$extra_methods[$subclass]);
|
unset(self::$extra_methods[$subclass]);
|
||||||
|
unset(self::$extension_sources[$subclass]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Config::inst()->update($class, 'extensions', array($extension));
|
Config::inst()->update($class, 'extensions', array($extension));
|
||||||
@ -505,6 +506,7 @@ abstract class Object {
|
|||||||
if($subclasses) foreach($subclasses as $subclass) {
|
if($subclasses) foreach($subclasses as $subclass) {
|
||||||
unset(self::$classes_constructed[$subclass]);
|
unset(self::$classes_constructed[$subclass]);
|
||||||
unset(self::$extra_methods[$subclass]);
|
unset(self::$extra_methods[$subclass]);
|
||||||
|
unset(self::$extension_sources[$subclass]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -531,35 +533,63 @@ 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() {
|
public function __construct() {
|
||||||
$this->class = get_class($this);
|
$this->class = get_class($this);
|
||||||
|
|
||||||
// Don't bother checking some classes that should never be extended
|
foreach(ClassInfo::ancestry(get_called_class()) as $class) {
|
||||||
static $notExtendable = array('Object', 'ViewableData', 'RequestHandler');
|
if(in_array($class, self::$unextendable_classes)) continue;
|
||||||
|
$extensions = Config::inst()->get($class, 'extensions', Config::UNINHERITED | Config::EXCLUDE_EXTRA_SOURCES);
|
||||||
|
|
||||||
if($extensionClasses = ClassInfo::ancestry($this->class)) foreach($extensionClasses as $class) {
|
if($extensions) foreach($extensions as $extension) {
|
||||||
if(in_array($class, $notExtendable)) continue;
|
$instance = self::create_from_string($extension);
|
||||||
if($extensions = Config::inst()->get($class, 'extensions', Config::UNINHERITED)) {
|
$instance->setOwner(null, $class);
|
||||||
foreach($extensions as $extension) {
|
$this->extension_instances[$instance->class] = $instance;
|
||||||
// Get the extension class for this extension
|
|
||||||
list($extensionClass, $extensionArgs) = self::parse_class_spec($extension);
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,32 +31,19 @@ abstract class DataExtension extends Extension {
|
|||||||
'api_access' => false,
|
'api_access' => false,
|
||||||
);
|
);
|
||||||
|
|
||||||
static function add_to_class($class, $extensionClass, $args = null) {
|
static function get_extra_config($class, $extension, $args) {
|
||||||
if(method_exists($class, 'extraDBFields')) {
|
if(method_exists($extension, 'extraDBFields')) {
|
||||||
$extraStaticsMethod = 'extraDBFields';
|
$extraStaticsMethod = 'extraDBFields';
|
||||||
} else {
|
} else {
|
||||||
$extraStaticsMethod = 'extraStatics';
|
$extraStaticsMethod = 'extraStatics';
|
||||||
}
|
}
|
||||||
|
|
||||||
$statics = Injector::inst()->get($extensionClass, true, $args)->$extraStaticsMethod($class, $extensionClass);
|
$statics = Injector::inst()->get($extension, true, $args)->$extraStaticsMethod();
|
||||||
|
|
||||||
if ($statics) {
|
if ($statics) {
|
||||||
Deprecation::notice('3.1.0', "$extraStaticsMethod deprecated. Just define statics on your extension, or use add_to_class", Deprecation::SCOPE_GLOBAL);
|
Deprecation::notice('3.1.0', "$extraStaticsMethod deprecated. Just define statics on your extension, or use get_extra_config", Deprecation::SCOPE_GLOBAL);
|
||||||
|
return $statics;
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parent::add_to_class($class, $extensionClass, $args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function unload_extra_statics($class, $extension) {
|
public static function unload_extra_statics($class, $extension) {
|
||||||
|
@ -25,9 +25,10 @@ class Hierarchy extends DataExtension {
|
|||||||
function augmentWrite(&$manipulation) {
|
function augmentWrite(&$manipulation) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static function add_to_class($class, $extensionClass, $args = null) {
|
static function get_extra_config($class, $extension, $args) {
|
||||||
Config::inst()->update($class, 'has_one', array('Parent' => $class));
|
return array(
|
||||||
parent::add_to_class($class, $extensionClass, $args);
|
'has_one' => array('Parent' => $class)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -107,9 +107,10 @@ class Versioned extends DataExtension {
|
|||||||
'Version' => 'Int'
|
'Version' => 'Int'
|
||||||
);
|
);
|
||||||
|
|
||||||
static function add_to_class($class, $extensionClass, $args = null) {
|
static function get_extra_config($class, $extension, $args) {
|
||||||
Config::inst()->update($class, 'has_many', array('Versions' => $class));
|
array(
|
||||||
parent::add_to_class($class, $extensionClass, $args);
|
'has_many' => array('Versions' => $class)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -75,14 +75,16 @@ class FulltextSearchable extends DataExtension {
|
|||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
|
|
||||||
static function add_to_class($class, $extensionClass, $args = null) {
|
static function get_extra_config($class, $extensionClass, $args) {
|
||||||
Config::inst()->update($class, 'indexes', array('SearchFields' => array(
|
return array(
|
||||||
'type' => 'fulltext',
|
'indexes' => array(
|
||||||
'name' => 'SearchFields',
|
'SearchFields' => array(
|
||||||
'value' => $args[0]
|
'type' => 'fulltext',
|
||||||
)));
|
'name' => 'SearchFields',
|
||||||
|
'value' => $args[0]
|
||||||
parent::add_to_class($class, $extensionClass, $args);
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user