From 6d4542561bcb279a21d935095c2381baf40f8be4 Mon Sep 17 00:00:00 2001 From: Sabina Talipova <87288324+sabina-talipova@users.noreply.github.com> Date: Thu, 12 Jan 2023 09:37:48 +1300 Subject: [PATCH] BUG Check is_callable parent methods before invoke (#10637) --- src/View/ViewableData.php | 12 +++++++++++- tests/php/View/ViewableDataTest.php | 15 +++++++++++++++ tests/php/View/ViewableDataTestObject.php | 19 +++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 tests/php/View/ViewableDataTestObject.php diff --git a/src/View/ViewableData.php b/src/View/ViewableData.php index 9731747ee..6ba6c853b 100644 --- a/src/View/ViewableData.php +++ b/src/View/ViewableData.php @@ -7,6 +7,7 @@ use Exception; use InvalidArgumentException; use IteratorAggregate; use LogicException; +use ReflectionObject; use SilverStripe\Core\ClassInfo; use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Configurable; @@ -155,13 +156,22 @@ class ViewableData implements IteratorAggregate public function __set($property, $value) { $this->objCacheClear(); - if ($this->hasMethod($method = "set$property")) { + $method = "set$property"; + + if ($this->hasMethod($method) && !$this->isPrivate($this, $method)) { $this->$method($value); } else { $this->setField($property, $value); } } + private function isPrivate(object $class, string $method): bool + { + $class = new ReflectionObject($class); + + return $class->getMethod($method)->isPrivate(); + } + /** * Set a failover object to attempt to get data from if it is not present on this object. * diff --git a/tests/php/View/ViewableDataTest.php b/tests/php/View/ViewableDataTest.php index 99dbb97d9..9c4e3d48e 100644 --- a/tests/php/View/ViewableDataTest.php +++ b/tests/php/View/ViewableDataTest.php @@ -2,11 +2,13 @@ namespace SilverStripe\View\Tests; +use ReflectionMethod; use SilverStripe\ORM\FieldType\DBField; use SilverStripe\Dev\SapphireTest; use SilverStripe\View\ArrayData; use SilverStripe\View\SSViewer; use SilverStripe\View\ViewableData; +use SilverStripe\View\Tests\ViewableDataTestObject; /** * See {@link SSViewerTest->testCastingHelpers()} for more tests related to casting and ViewableData behaviour, @@ -205,4 +207,17 @@ class ViewableDataTest extends SapphireTest $this->assertSame($failover, $container->getFailover(), 'getFailover() returned a different object'); $this->assertFalse($container->hasMethod('testMethod'), 'testMethod() incorrectly reported as existing'); } + + public function testIsPrivate() + { + $reflectionMethod = new ReflectionMethod(ViewableData::class, 'isPrivate'); + $reflectionMethod->setAccessible(true); + $object = new ViewableDataTestObject(); + + $output = $reflectionMethod->invokeArgs($object, [$object, 'privateMethod']); + $this->assertTrue($output, 'Method is not private'); + + $output = $reflectionMethod->invokeArgs($object, [$object, 'publicMethod']); + $this->assertFalse($output, 'Method is private'); + } } diff --git a/tests/php/View/ViewableDataTestObject.php b/tests/php/View/ViewableDataTestObject.php new file mode 100644 index 000000000..08ad8fe96 --- /dev/null +++ b/tests/php/View/ViewableDataTestObject.php @@ -0,0 +1,19 @@ +