diff --git a/core/Object.php b/core/Object.php index ba445424e..124532bfb 100755 --- a/core/Object.php +++ b/core/Object.php @@ -41,10 +41,12 @@ abstract class Object { */ private static - $statics = array(), - $cached_statics = array(), - $extra_statics = array(), - $replaced_statics = array(), + $statics = array(), + $cached_statics = array(), + $uninherited_statics = array(), + $cached_uninherited_statics = array(), + $extra_statics = array(), + $replaced_statics = array(), $_cache_statics_prepared = array(); private static @@ -231,7 +233,7 @@ abstract class Object { return self::$statics[$class][$name]; } - + /** * Set a static variable * @@ -244,10 +246,12 @@ abstract class Object { Object::prepare_statics($class); } - self::$statics[$class][$name] = $value; + self::$statics[$class][$name] = $value; + self::$uninherited_statics[$class][$name] = $value; self::$cached_statics[$class][$name] = true; + self::$cached_uninherited_statics[$class][$name] = true; } - + /** * Get an uninherited static variable - a variable that is explicity set in this class, and not in the parent class. * @@ -260,25 +264,34 @@ abstract class Object { * @param string $name * @return mixed */ - public static function uninherited_static($class, $name) { - $inherited = self::get_static($class, $name); - $parent = null; + public static function uninherited_static($class, $name, $uncached = false) { + if(!isset(self::$_cache_statics_prepared[$class])) { + Object::prepare_statics($class); + } + + if(!isset(self::$cached_uninherited_statics[$class][$name]) || $uncached) { + $classRef = new ReflectionClass($class); + $classProps = $classRef->getStaticProperties(); - if($parentClass = get_parent_class($class)) { - $parent = self::get_static($parentClass, $name); - } + $parentClass = get_parent_class($class); + if($parentClass) { + $parentRef = new ReflectionClass($parentClass); + $parentProps = $parentRef->getStaticProperties(); - if(is_array($inherited) && is_array($parent)) { - return array_diff_assoc($inherited, $parent); - } + $uninheritedBuiltIn = isset($classProps[$name]) + && (!isset($parentProps[$name]) + || $classProps[$name] != $parentProps[$name]) ? $classProps[$name] : null; + } else { + $uninheritedBuiltIn = isset($classProps[$name]) ? $classProps[$name] : null; + } + + + self::$cached_uninherited_statics[$class][$name] = true; + self::$uninherited_statics[$class][$name] = $uninheritedBuiltIn; + } - return ($inherited != $parent) ? $inherited : null; + return self::$uninherited_statics[$class][$name]; } - - /** - * Cache the results of whether or not a given var is inherited. - */ - private static $cache_is_inherited = array(); /** * Traverse down a class ancestry and attempt to merge all the uninherited static values for a particular static @@ -361,7 +374,7 @@ abstract class Object { */ public static function has_extension($class, $requiredExtension) { $requiredExtension = strtolower($requiredExtension); - if($extensions = self::get_static($class, 'extensions')) foreach($extensions as $extension) { + if($extensions = self::combined_static($class, '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; @@ -404,7 +417,9 @@ abstract class Object { } // merge with existing static vars - self::add_static_var($class, 'extensions', array($extension)); + $extensions = self::uninherited_static($class, 'extensions'); + $extensions[] = $extension; + self::set_static($class, 'extensions', $extensions); // load statics now for DataObject classes if(ClassInfo::is_subclass_of($class, 'DataObject')) { @@ -423,7 +438,7 @@ abstract class Object { // load statics now for DataObject classes if(is_subclass_of($class, 'DataObject')) { - $extensions = Object::get_static($class, 'extensions'); + $extensions = Object::uninherited_static($class, 'extensions'); if($extensions) foreach($extensions as $extension) { if(preg_match('/^([^(]*)/', $extension, $matches)) { $extensionClass = $matches[1]; @@ -455,7 +470,7 @@ abstract class Object { self::set_static( $class, 'extensions', - array_diff(self::get_static($class, 'extensions'), array($extension)) + array_diff(self::uninherited_static($class, 'extensions'), array($extension)) ); } diff --git a/core/model/DataObject.php b/core/model/DataObject.php index 06adcb9de..fe6cf90c0 100644 --- a/core/model/DataObject.php +++ b/core/model/DataObject.php @@ -810,7 +810,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity $classes = array_reverse(ClassInfo::ancestry($this)); foreach($classes as $class) { - $defaults = Object::get_static($class, 'defaults'); + $defaults = Object::uninherited_static($class, 'defaults'); if($defaults && !is_array($defaults)) { user_error("Bad '$this->class' defaults given: " . var_export($defaults, true), @@ -1426,13 +1426,13 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity if(in_array($class, array('Object', 'ViewableData', 'DataObject'))) continue; if($component) { - $hasOne = Object::get_static($class, 'has_one'); + $hasOne = Object::uninherited_static($class, 'has_one'); if(isset($hasOne[$component])) { return $hasOne[$component]; } } else { - $newItems = (array) Object::get_static($class, 'has_one'); + $newItems = (array) Object::uninherited_static($class, 'has_one'); // Validate the data foreach($newItems as $k => $v) { if(!is_string($k) || is_numeric($k) || !is_string($v)) user_error("$class::\$has_one has a bad entry: " @@ -1466,13 +1466,13 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity } if($fieldName) { - $db = Object::get_static($class, 'db'); + $db = Object::uninherited_static($class, 'db'); if(isset($db[$fieldName])) { return $db[$fieldName]; } } else { - $newItems = (array) Object::get_static($class, 'db'); + $newItems = (array) Object::uninherited_static($class, 'db'); // Validate the data foreach($newItems as $k => $v) { if(!is_string($k) || is_numeric($k) || !is_string($v)) user_error("$class::\$db has a bad entry: " @@ -1500,13 +1500,13 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity if(in_array($class, array('ViewableData', 'Object', 'DataObject'))) continue; if($component) { - $hasMany = Object::get_static($class, 'has_many'); + $hasMany = Object::uninherited_static($class, 'has_many'); if(isset($hasMany[$component])) { return $hasMany[$component]; } } else { - $newItems = (array) Object::get_static($class, 'has_many'); + $newItems = (array) Object::uninherited_static($class, 'has_many'); // Validate the data foreach($newItems as $k => $v) { if(!is_string($k) || is_numeric($k) || !is_string($v)) user_error("$class::\$has_many has a bad entry: " @@ -1620,7 +1620,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity if(in_array($class, array('ViewableData', 'Object', 'DataObject'))) continue; if($component) { - $manyMany = Object::get_static($class, 'many_many'); + $manyMany = Object::uninherited_static($class, 'many_many'); // Try many_many $candidate = (isset($manyMany[$component])) ? $manyMany[$component] : null; if($candidate) { @@ -1630,13 +1630,13 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity } // Try belongs_many_many - $belongsManyMany = Object::get_static($class, 'belongs_many_many'); + $belongsManyMany = Object::uninherited_static($class, 'belongs_many_many'); $candidate = (isset($belongsManyMany[$component])) ? $belongsManyMany[$component] : null; if($candidate) { $childField = $candidate . "ID"; // We need to find the inverse component name - $otherManyMany = Object::get_static($candidate, 'many_many'); + $otherManyMany = Object::uninherited_static($candidate, 'many_many'); if(!$otherManyMany) { user_error("Inverse component of $candidate not found ({$this->class})", E_USER_ERROR); } @@ -1655,7 +1655,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity user_error("Orphaned \$belongs_many_many value for $this->class.$component", E_USER_ERROR); } } else { - $newItems = (array) Object::get_static($class, 'many_many'); + $newItems = (array) Object::uninherited_static($class, 'many_many'); // Validate the data foreach($newItems as $k => $v) { if(!is_string($k) || is_numeric($k) || !is_string($v)) user_error("$class::\$many_many has a bad entry: " @@ -1663,7 +1663,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity } $items = isset($items) ? array_merge($newItems, $items) : $newItems; - $newItems = (array) Object::get_static($class, 'belongs_many_many'); + $newItems = (array) Object::uninherited_static($class, 'belongs_many_many'); // Validate the data foreach($newItems as $k => $v) { if(!is_string($k) || is_numeric($k) || !is_string($v)) user_error("$class::\$belongs_many_many has a bad entry: " diff --git a/core/model/DataObjectDecorator.php b/core/model/DataObjectDecorator.php index dbf342323..0fef4b6ed 100755 --- a/core/model/DataObjectDecorator.php +++ b/core/model/DataObjectDecorator.php @@ -63,10 +63,10 @@ abstract class DataObjectDecorator extends Extension { if($statics) { foreach($statics as $name => $newVal) { if(isset(self::$decoratable_statics[$name])) { - $origVal = self::get_static($class, $name); // Array to be merged if(self::$decoratable_statics[$name]) { + $origVal = self::uninherited_static($class, $name); // Can't use add_static_var() here as it would merge the array rather than replacing self::set_static($class, $name, array_merge((array)$origVal, $newVal)); diff --git a/tests/ObjectStaticTest.php b/tests/ObjectStaticTest.php index e2d47bdf9..c006f6692 100644 --- a/tests/ObjectStaticTest.php +++ b/tests/ObjectStaticTest.php @@ -70,14 +70,14 @@ class ObjectStaticTest extends SapphireTest { } /** - * Check that calls to Object::add_static() will update the data returned by Object::uninherited_static() + * Confirms that Object::add_static_var() doesn't work for uninherited stats */ - public function testAddStaticFollowedByUnheritedCall() { + public function testAddStaticVarDoesntWorkFor() { Object::add_static_var('ObjectStaticTest_First', 'first', array('test_1b')); Object::add_static_var('ObjectStaticTest_Second', 'first', array('test_2b')); - $this->assertContains('test_1b', Object::uninherited_static('ObjectStaticTest_First', 'first')); - $this->assertContains('test_2b', Object::uninherited_static('ObjectStaticTest_Second', 'first')); + $this->assertNotContains('test_1b', Object::uninherited_static('ObjectStaticTest_First', 'first')); + $this->assertNotContains('test_2b', Object::uninherited_static('ObjectStaticTest_Second', 'first')); } }