From 91f831cd0bfc36551d84f7c45e8652f9ea80087a Mon Sep 17 00:00:00 2001 From: Garion Herman Date: Fri, 23 Oct 2020 16:31:50 +1300 Subject: [PATCH 1/2] ENH Improve scalar response handling This resolves an issue where method_exists() was being called on scalar response values, which is not supported in PHP 8. --- src/Control/Controller.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Control/Controller.php b/src/Control/Controller.php index 3cb1b9833..29c802a95 100644 --- a/src/Control/Controller.php +++ b/src/Control/Controller.php @@ -230,7 +230,9 @@ class Controller extends RequestHandler implements TemplateGlobalProvider */ protected function prepareResponse($response) { - if ($response instanceof HTTPResponse) { + if (!is_object($response)) { + $this->getResponse()->setBody($response); + } elseif ($response instanceof HTTPResponse) { if (isset($_REQUEST['debug_request'])) { $class = static::class; Debug::message( From e89ae93ac9a236f6e1ba3a14392406980062b7de Mon Sep 17 00:00:00 2001 From: Garion Herman Date: Fri, 23 Oct 2020 16:33:56 +1300 Subject: [PATCH 2/2] FIX Harden hasMethod() against invalid values This method should typehint the incoming value once union types are available, but for now this ensures that method_exists() is not called on scalar values, which is unsupported in PHP 8. --- src/Core/ClassInfo.php | 2 +- tests/php/Core/ClassInfoTest.php | 56 ++++++++++++++++++++-- tests/php/Core/ClassInfoTest/HasMethod.php | 19 ++++++++ 3 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 tests/php/Core/ClassInfoTest/HasMethod.php diff --git a/src/Core/ClassInfo.php b/src/Core/ClassInfo.php index 377320d80..0c98e9cd8 100644 --- a/src/Core/ClassInfo.php +++ b/src/Core/ClassInfo.php @@ -400,7 +400,7 @@ class ClassInfo */ public static function hasMethod($object, $method) { - if (empty($object)) { + if (empty($object) || (!is_object($object) && !is_string($object))) { return false; } if (method_exists($object, $method)) { diff --git a/tests/php/Core/ClassInfoTest.php b/tests/php/Core/ClassInfoTest.php index 76050e34b..29721599b 100644 --- a/tests/php/Core/ClassInfoTest.php +++ b/tests/php/Core/ClassInfoTest.php @@ -2,6 +2,7 @@ namespace SilverStripe\Core\Tests; +use DateTime; use ReflectionException; use SilverStripe\Core\ClassInfo; use SilverStripe\Core\Tests\ClassInfoTest\BaseClass; @@ -15,6 +16,7 @@ use SilverStripe\Core\Tests\ClassInfoTest\ExtensionTest1; use SilverStripe\Core\Tests\ClassInfoTest\ExtensionTest2; use SilverStripe\Core\Tests\ClassInfoTest\GrandChildClass; use SilverStripe\Core\Tests\ClassInfoTest\HasFields; +use SilverStripe\Core\Tests\ClassInfoTest\HasMethod; use SilverStripe\Core\Tests\ClassInfoTest\NoFields; use SilverStripe\Core\Tests\ClassInfoTest\WithCustomTable; use SilverStripe\Core\Tests\ClassInfoTest\WithRelation; @@ -266,9 +268,57 @@ class ClassInfoTest extends SapphireTest ); } - /** - * @dataProvider provideClassSpecCases - */ + /** @dataProvider provideHasMethodCases */ + public function testHasMethod($object, $method, $output) + { + $this->assertEquals( + $output, + ClassInfo::hasMethod($object, $method) + ); + } + + public function provideHasMethodCases() + { + return [ + 'Basic object' => [ + new DateTime(), + 'format', + true, + ], + 'CustomMethod object' => [ + new HasMethod(), + 'example', + true, + ], + 'Class Name' => [ + 'DateTime', + 'format', + true, + ], + 'FQCN' => [ + '\DateTime', + 'format', + true, + ], + 'Invalid FQCN' => [ + '--GreatTime', + 'format', + false, + ], + 'Integer' => [ + 1, + 'format', + false, + ], + 'Array' => [ + ['\DateTime'], + 'format', + false, + ], + ]; + } + + /** @dataProvider provideClassSpecCases */ public function testParseClassSpec($input, $output) { $this->assertEquals( diff --git a/tests/php/Core/ClassInfoTest/HasMethod.php b/tests/php/Core/ClassInfoTest/HasMethod.php new file mode 100644 index 000000000..dbe70a7d5 --- /dev/null +++ b/tests/php/Core/ClassInfoTest/HasMethod.php @@ -0,0 +1,19 @@ +