Browse files

API CHANGE: Modify extensions system to support new config system. St…

…atics are now declared directly on extensions, and there is an add_to_class method extensions can hook into to modify class configuration
  • Loading branch information...
1 parent 0ab171d commit 876f4c5299ec50c4d53d904f79d187dc215dc2e6 @hafriedlander hafriedlander committed Dec 22, 2011
Showing with 66 additions and 83 deletions.
  1. +16 −1 core/Extension.php
  2. +30 −41 core/Object.php
  3. +20 −41 model/DataExtension.php
View
17 core/Extension.php
@@ -44,6 +44,19 @@ function __construct() {
}
/**
+ * 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) {
+ Config::add_static_source($class, $extensionClass);
+ }
+
+ /**
* Set the owner of this extension.
* @param Object $owner The owner object,
* @param string $ownerBaseClass The base class that the extension is applied to; this may be
@@ -85,6 +98,8 @@ public function getOwner() {
public static function get_classname_without_arguments($extensionStr) {
return (($p = strpos($extensionStr, '(')) !== false) ? substr($extensionStr, 0, $p) : $extensionStr;
}
-
+
+
+
}
View
71 core/Object.php
@@ -422,7 +422,9 @@ public static function add_static_var($class, $name, $value, $replace = false) {
*/
public static function has_extension($class, $requiredExtension) {
$requiredExtension = strtolower($requiredExtension);
- if($extensions = self::combined_static($class, 'extensions')) foreach($extensions as $extension) {
+ $extensions = Config::inst()->get($class, 'extensions');
+
+ if($extensions) foreach($extensions as $extension) {
$left = strtolower(Extension::get_classname_without_arguments($extension));
$right = strtolower(Extension::get_classname_without_arguments($requiredExtension));
if($left == $right) return true;
@@ -457,30 +459,19 @@ public static function add_extension($class, $extension) {
}
// unset some caches
- self::$cached_statics[$class]['extensions'] = null;
$subclasses = ClassInfo::subclassesFor($class);
$subclasses[] = $class;
+
if($subclasses) foreach($subclasses as $subclass) {
unset(self::$classes_constructed[$subclass]);
unset(self::$extra_methods[$subclass]);
}
-
- // merge with existing static vars
- $extensions = self::uninherited_static($class, 'extensions');
-
- // We use unshift rather than push so that module extensions are added before built-in ones.
- // in particular, this ensures that the Versioned rewriting is done last.
- if($extensions) array_unshift($extensions, $extension);
- else $extensions = array($extension);
-
- self::set_static($class, 'extensions', $extensions);
-
+
+ Config::inst()->update($class, 'extensions', array($extension));
+
// load statics now for DataObject classes
if(is_subclass_of($class, 'DataObject')) {
- if(is_subclass_of($extensionClass, 'DataExtension')) {
- DataExtension::load_extra_statics($class, $extension);
- }
- else {
+ if(!is_subclass_of($extensionClass, 'DataExtension')) {
user_error("$extensionClass cannot be applied to $class without being a DataExtension", E_USER_ERROR);
}
}
@@ -504,37 +495,19 @@ public static function add_extension($class, $extension) {
* @param string $extension Classname of an {@link Extension} subclass, without parameters
*/
public static function remove_extension($class, $extension) {
- // unload statics now for DataObject classes
- if(is_subclass_of($class, 'DataObject')) {
- if(!preg_match('/^([^(]*)/', $extension, $matches)) {
- user_error("Bad extension '$extension'", E_USER_WARNING);
- } else {
- $extensionClass = $matches[1];
- DataExtension::unload_extra_statics($class, $extensionClass);
- }
- }
-
- if(self::has_extension($class, $extension)) {
- self::set_static(
- $class,
- 'extensions',
- array_diff(self::uninherited_static($class, 'extensions'), array($extension))
- );
- }
-
+ Config::inst()->remove($class, 'extensions', Config::anything(), $extension);
+
// unset singletons to avoid side-effects
global $_SINGLETONS;
$_SINGLETONS = array();
// unset some caches
- self::$cached_statics[$class]['extensions'] = null;
$subclasses = ClassInfo::subclassesFor($class);
$subclasses[] = $class;
if($subclasses) foreach($subclasses as $subclass) {
unset(self::$classes_constructed[$subclass]);
unset(self::$extra_methods[$subclass]);
}
-
}
/**
@@ -545,7 +518,8 @@ public static function remove_extension($class, $extension) {
* or eval'ed classname strings with constructor arguments.
*/
function get_extensions($class, $includeArgumentString = false) {
- $extensions = self::get_static($class, 'extensions');
+ $extensions = Config::inst()->get($class, 'extensions');
+
if($includeArgumentString) {
return $extensions;
} else {
@@ -558,7 +532,9 @@ function get_extensions($class, $includeArgumentString = false) {
}
// -----------------------------------------------------------------------------------------------------------------
-
+
+ private static $_added_extensions = array();
+
public function __construct() {
$this->class = get_class($this);
@@ -567,9 +543,22 @@ public function __construct() {
if($extensionClasses = ClassInfo::ancestry($this->class)) foreach($extensionClasses as $class) {
if(in_array($class, $notExtendable)) continue;
-
- if($extensions = self::uninherited_static($class, 'extensions')) {
+
+ if($extensions = Config::inst()->get($class, 'extensions', Config::UNINHERITED)) {
foreach($extensions as $extension) {
+ // Get the extension class for this extension
+ $extensionClass = Extension::get_classname_without_arguments($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);
+
+ // 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;
View
61 model/DataExtension.php
@@ -30,59 +30,38 @@
'searchable_fields' => true,
'api_access' => false,
);
-
- private static $extra_statics_loaded = array();
-
- /**
- * Load the extra static definitions for the given extension
- * class name, called by {@link Object::add_extension()}
- *
- * @param string $class Class name of the owner class (or owner base class)
- * @param string $extension Class name of the extension class
- */
- public static function load_extra_statics($class, $extension) {
- if(!empty(self::$extra_statics_loaded[$class][$extension])) return;
- self::$extra_statics_loaded[$class][$extension] = true;
-
- if(preg_match('/^([^(]*)/', $extension, $matches)) {
- $extensionClass = $matches[1];
+
+
+ static function add_to_class($class, $extensionClass) {
+ if(method_exists($class, 'extraDBFields')) {
+ $extraStaticsMethod = 'extraDBFields';
} else {
- user_error("Bad extension '$extension' - can't find classname", E_USER_WARNING);
- return;
+ $extraStaticsMethod = 'extraStatics';
}
-
- // If the extension has been manually applied to a subclass, we should ignore that.
- if(Object::has_extension(get_parent_class($class), $extensionClass)) return;
- // If there aren't any extraStatics we shouldn't try to load them.
- if(!method_exists($extensionClass, 'extraStatics')) return;
+ $statics = singleton($extensionClass)->$extraStaticsMethod($class, $extensionClass);
+
+ if ($statics) {
+ Deprecation::notice('3.0.0', "$extraStaticsMethod deprecated. Just define statics on your extension, or use add_to_class");
- $statics = call_user_func(array(singleton($extensionClass), 'extraStatics'), $class, $extension);
-
- if($statics) {
- foreach($statics as $name => $newVal) {
- if(isset(self::$extendable_statics[$name])) {
-
- // Array to be merged
- if(self::$extendable_statics[$name]) {
- $origVal = Object::uninherited_static($class, $name);
- // Can't use add_static_var() here as it would merge the array rather than replacing
- Object::set_static($class, $name, array_merge((array)$origVal, $newVal));
-
- // Value to be overwritten
- } else {
- Object::set_static($class, $name, $newVal);
- }
+ // 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);
}
public static function unload_extra_statics($class, $extension) {
- self::$extra_statics_loaded[$class][$extension] = false;
+ throw new Exception('unload_extra_statics gone');
}
/**

0 comments on commit 876f4c5

Please sign in to comment.