Compare commits

..

2 Commits

Author SHA1 Message Date
Steve Boyd
5f5cf480d0
Merge 9cc00719c7 into ebbd6427b2 2024-10-16 06:15:26 +00:00
Steve Boyd
9cc00719c7 ENH Do not output core code deprecation messages by default 2024-10-16 19:15:20 +13:00
2 changed files with 127 additions and 22 deletions

View File

@ -158,11 +158,11 @@ class Deprecation
private static function get_called_from_trace(array $backtrace, int $level): array private static function get_called_from_trace(array $backtrace, int $level): array
{ {
$newLevel = $level; $newLevel = $level;
// handle closures inside withSuppressedNotice() if (Deprecation::$insideNoticeSuppression) {
if (Deprecation::$insideNoticeSuppression // handle closures inside withSuppressedNotice()
&& substr($backtrace[$newLevel]['function'], -strlen('{closure}')) === '{closure}' if (substr($backtrace[$newLevel]['function'], -strlen('{closure}')) === '{closure}') {
) { $newLevel = $newLevel + 2;
$newLevel = $newLevel + 2; }
} }
// handle call_user_func // handle call_user_func
if ($level === 4 && strpos($backtrace[2]['function'] ?? '', 'call_user_func') !== false) { if ($level === 4 && strpos($backtrace[2]['function'] ?? '', 'call_user_func') !== false) {
@ -174,6 +174,15 @@ class Deprecation
if ($level == 4 && ($backtrace[$newLevel]['class'] ?? '') === InjectionCreator::class) { if ($level == 4 && ($backtrace[$newLevel]['class'] ?? '') === InjectionCreator::class) {
$newLevel = $newLevel + 4; $newLevel = $newLevel + 4;
} }
// handle noticeWithNoReplacment()
foreach ($backtrace as $trace) {
if (($trace['class'] ?? '') === Deprecation::class
&& ($trace['function'] ?? '') === 'noticeWithNoReplacment'
) {
$newLevel = $newLevel + 1;
break;
}
}
$called = $backtrace[$newLevel] ?? []; $called = $backtrace[$newLevel] ?? [];
return $called; return $called;
} }
@ -196,6 +205,10 @@ class Deprecation
*/ */
private static function isSupportedVendorFile(string $file): bool private static function isSupportedVendorFile(string $file): bool
{ {
// This is a special case for silverstripe-framework when running in CI
if (str_contains($file, '/silverstripe-framework/')) {
return true;
}
// Doing a fairly simple check to see if a file is in a supported vendor folder, rather than whether // Doing a fairly simple check to see if a file is in a supported vendor folder, rather than whether
// the module itself is actually supported // the module itself is actually supported
$vendors = implode('|', [ $vendors = implode('|', [
@ -291,6 +304,11 @@ class Deprecation
/** /**
* If true, deprecation warnings will be shown for deprecated code which is called by core Silverstripe modules. * If true, deprecation warnings will be shown for deprecated code which is called by core Silverstripe modules.
*/ */
public static function getShowCalledFromSupportedCodeNotices(): bool
{
return Deprecation::$showCalledFromSupportedCodeNotices;
}
public static function setShowCalledFromSupportedCodeNotices(bool $value): void public static function setShowCalledFromSupportedCodeNotices(bool $value): void
{ {
Deprecation::$showCalledFromSupportedCodeNotices = $value; Deprecation::$showCalledFromSupportedCodeNotices = $value;
@ -417,7 +435,7 @@ class Deprecation
} }
/** /**
* Shorthand method to create a suppressed notice * Shorthand method to create a suppressed notice for something with no immediate replacement.
* If $string is empty, then a standardised message will be used, which is: * If $string is empty, then a standardised message will be used, which is:
* Will be removed without equivalent functionality to replace it. * Will be removed without equivalent functionality to replace it.
*/ */

View File

@ -23,6 +23,8 @@ class DeprecationTest extends SapphireTest
private bool $noticesWereEnabled = false; private bool $noticesWereEnabled = false;
private bool $showSupportedNoticesWasEnabled = false;
protected function setup(): void protected function setup(): void
{ {
// Use custom error handler for two reasons: // Use custom error handler for two reasons:
@ -31,6 +33,7 @@ class DeprecationTest extends SapphireTest
// https://github.com/laminas/laminas-di/pull/30#issuecomment-927585210 // https://github.com/laminas/laminas-di/pull/30#issuecomment-927585210
parent::setup(); parent::setup();
$this->noticesWereEnabled = Deprecation::isEnabled(); $this->noticesWereEnabled = Deprecation::isEnabled();
$this->showSupportedNoticesWasEnabled = Deprecation::getShowCalledFromSupportedCodeNotices();
$this->oldHandler = set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline) { $this->oldHandler = set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline) {
if ($errno === E_USER_DEPRECATED) { if ($errno === E_USER_DEPRECATED) {
if (str_contains($errstr, 'SilverStripe\\Dev\\Tests\\DeprecationTest')) { if (str_contains($errstr, 'SilverStripe\\Dev\\Tests\\DeprecationTest')) {
@ -46,6 +49,10 @@ class DeprecationTest extends SapphireTest
// Fallback to default PHP error handler // Fallback to default PHP error handler
return false; return false;
}); });
// This is required to clear out the message
// 'SilverStripe\Dev\Tests\DeprecationTest\DeprecationTestObject is deprecated. Some class message. Called from
// SilverStripe\ORM\Connect\TableBuilder->buildTables."
Deprecation::outputNotices();
} }
protected function tearDown(): void protected function tearDown(): void
@ -55,6 +62,7 @@ class DeprecationTest extends SapphireTest
} else { } else {
Deprecation::disable(); Deprecation::disable();
} }
Deprecation::setShowCalledFromSupportedCodeNotices($this->showSupportedNoticesWasEnabled);
restore_error_handler(); restore_error_handler();
$this->oldHandler = null; $this->oldHandler = null;
parent::tearDown(); parent::tearDown();
@ -66,6 +74,18 @@ class DeprecationTest extends SapphireTest
return 'abc'; return 'abc';
} }
private function myDeprecatedMethodNoReplacement(): string
{
Deprecation::noticeWithNoReplacment('1.2.3');
return 'abc';
}
private function enableDeprecationNotices(bool $showNoReplacementNotices = false): void
{
Deprecation::enable($showNoReplacementNotices);
Deprecation::setShowCalledFromSupportedCodeNotices(true);
}
public function testNotice() public function testNotice()
{ {
$message = implode(' ', [ $message = implode(' ', [
@ -75,7 +95,7 @@ class DeprecationTest extends SapphireTest
]); ]);
$this->expectDeprecation(); $this->expectDeprecation();
$this->expectDeprecationMessage($message); $this->expectDeprecationMessage($message);
Deprecation::enable(); $this->enableDeprecationNotices();
$ret = $this->myDeprecatedMethod(); $ret = $this->myDeprecatedMethod();
$this->assertSame('abc', $ret); $this->assertSame('abc', $ret);
// call outputNotices() directly because the regular shutdown function that emits // call outputNotices() directly because the regular shutdown function that emits
@ -83,6 +103,29 @@ class DeprecationTest extends SapphireTest
Deprecation::outputNotices(); Deprecation::outputNotices();
} }
public function testNoticeNoReplacement()
{
$message = implode(' ', [
'SilverStripe\Dev\Tests\DeprecationTest->myDeprecatedMethodNoReplacement is deprecated.',
'Will be removed without equivalent functionality to replace it.',
'Called from SilverStripe\Dev\Tests\DeprecationTest->testNoticeNoReplacement.'
]);
$this->expectDeprecation();
$this->expectDeprecationMessage($message);
$this->enableDeprecationNotices(true);
$ret = $this->myDeprecatedMethodNoReplacement();
$this->assertSame('abc', $ret);
Deprecation::outputNotices();
}
public function testNoticeNoReplacementNoSupressed()
{
$this->enableDeprecationNotices();
$ret = $this->myDeprecatedMethodNoReplacement();
$this->assertSame('abc', $ret);
Deprecation::outputNotices();
}
public function testCallUserFunc() public function testCallUserFunc()
{ {
$message = implode(' ', [ $message = implode(' ', [
@ -92,7 +135,7 @@ class DeprecationTest extends SapphireTest
]); ]);
$this->expectDeprecation(); $this->expectDeprecation();
$this->expectDeprecationMessage($message); $this->expectDeprecationMessage($message);
Deprecation::enable(); $this->enableDeprecationNotices();
$ret = call_user_func([$this, 'myDeprecatedMethod']); $ret = call_user_func([$this, 'myDeprecatedMethod']);
$this->assertSame('abc', $ret); $this->assertSame('abc', $ret);
Deprecation::outputNotices(); Deprecation::outputNotices();
@ -107,7 +150,7 @@ class DeprecationTest extends SapphireTest
]); ]);
$this->expectDeprecation(); $this->expectDeprecation();
$this->expectDeprecationMessage($message); $this->expectDeprecationMessage($message);
Deprecation::enable(); $this->enableDeprecationNotices();
$ret = call_user_func_array([$this, 'myDeprecatedMethod'], []); $ret = call_user_func_array([$this, 'myDeprecatedMethod'], []);
$this->assertSame('abc', $ret); $this->assertSame('abc', $ret);
Deprecation::outputNotices(); Deprecation::outputNotices();
@ -115,7 +158,7 @@ class DeprecationTest extends SapphireTest
public function testwithSuppressedNoticeDefault() public function testwithSuppressedNoticeDefault()
{ {
Deprecation::enable(); $this->enableDeprecationNotices();
$ret = Deprecation::withSuppressedNotice(function () { $ret = Deprecation::withSuppressedNotice(function () {
return $this->myDeprecatedMethod(); return $this->myDeprecatedMethod();
}); });
@ -132,7 +175,7 @@ class DeprecationTest extends SapphireTest
]); ]);
$this->expectDeprecation(); $this->expectDeprecation();
$this->expectDeprecationMessage($message); $this->expectDeprecationMessage($message);
Deprecation::enable(true); $this->enableDeprecationNotices(true);
$ret = Deprecation::withSuppressedNotice(function () { $ret = Deprecation::withSuppressedNotice(function () {
return $this->myDeprecatedMethod(); return $this->myDeprecatedMethod();
}); });
@ -149,7 +192,7 @@ class DeprecationTest extends SapphireTest
]); ]);
$this->expectDeprecation(); $this->expectDeprecation();
$this->expectDeprecationMessage($message); $this->expectDeprecationMessage($message);
Deprecation::enable(true); $this->enableDeprecationNotices(true);
$ret = Deprecation::withSuppressedNotice(function () { $ret = Deprecation::withSuppressedNotice(function () {
return call_user_func([$this, 'myDeprecatedMethod']); return call_user_func([$this, 'myDeprecatedMethod']);
}); });
@ -166,7 +209,7 @@ class DeprecationTest extends SapphireTest
]); ]);
$this->expectDeprecation(); $this->expectDeprecation();
$this->expectDeprecationMessage($message); $this->expectDeprecationMessage($message);
Deprecation::enable(true); $this->enableDeprecationNotices(true);
Deprecation::withSuppressedNotice(function () { Deprecation::withSuppressedNotice(function () {
Deprecation::notice('123', 'My message.'); Deprecation::notice('123', 'My message.');
}); });
@ -182,7 +225,7 @@ class DeprecationTest extends SapphireTest
]); ]);
$this->expectDeprecation(); $this->expectDeprecation();
$this->expectDeprecationMessage($message); $this->expectDeprecationMessage($message);
Deprecation::enable(true); $this->enableDeprecationNotices(true);
// using this syntax because my IDE was complaining about DeprecationTestObject not existing // using this syntax because my IDE was complaining about DeprecationTestObject not existing
// when trying to use `new DeprecationTestObject();` // when trying to use `new DeprecationTestObject();`
$class = DeprecationTestObject::class; $class = DeprecationTestObject::class;
@ -199,7 +242,7 @@ class DeprecationTest extends SapphireTest
]); ]);
$this->expectDeprecation(); $this->expectDeprecation();
$this->expectDeprecationMessage($message); $this->expectDeprecationMessage($message);
Deprecation::enable(true); $this->enableDeprecationNotices(true);
Injector::inst()->get(DeprecationTestObject::class); Injector::inst()->get(DeprecationTestObject::class);
Deprecation::outputNotices(); Deprecation::outputNotices();
} }
@ -217,6 +260,50 @@ class DeprecationTest extends SapphireTest
Deprecation::outputNotices(); Deprecation::outputNotices();
} }
public function testShowCalledFromSupportedCodeNotices()
{
$this->expectNotToPerformAssertions();
$this->enableDeprecationNotices(true);
// showCalledFromSupportedCodeNotices is set to true by default for these unit tests
// as it is testing code within vendor/silverstripe
// This test is to ensure that the method works as expected when we disable this
// and we should expect no exceptions to be thrown
//
// Note specifically NOT testing the following because it's counted as being called
// from phpunit itself, which is not considered supported code
// Deprecation::withSuppressedNotice(function () {
// Deprecation::notice('123', 'My message.');
// });
Deprecation::setShowCalledFromSupportedCodeNotices(false);
// notice()
$this->myDeprecatedMethod();
// noticeNoReplacement()
$this->myDeprecatedMethodNoReplacement();
// callUserFunc()
call_user_func([$this, 'myDeprecatedMethod']);
// callUserFuncArray()
call_user_func_array([$this, 'myDeprecatedMethod'], []);
// withSuppressedNotice()
Deprecation::withSuppressedNotice(
fn() => $this->myDeprecatedMethod()
);
// withSuppressedNoticeTrue()
Deprecation::withSuppressedNotice(function () {
$this->myDeprecatedMethod();
});
// withSuppressedNoticeTrueCallUserFunc()
Deprecation::withSuppressedNotice(function () {
call_user_func([$this, 'myDeprecatedMethod']);
});
// classWithSuppressedNotice()
$class = DeprecationTestObject::class;
new $class();
// classWithInjectorwithSuppressedNotice()
Injector::inst()->get(DeprecationTestObject::class);
// Output notices - there should be none
Deprecation::outputNotices();
}
// The following tests would be better to put in the silverstripe/config module, however this is not // The following tests would be better to put in the silverstripe/config module, however this is not
// possible to do in a clean way as the config for the DeprecationTestObject will not load if it // possible to do in a clean way as the config for the DeprecationTestObject will not load if it
// is inside the silverstripe/config directory, as there is no _config.php file or _config folder. // is inside the silverstripe/config directory, as there is no _config.php file or _config folder.
@ -231,7 +318,7 @@ class DeprecationTest extends SapphireTest
]); ]);
$this->expectDeprecation(); $this->expectDeprecation();
$this->expectDeprecationMessage($message); $this->expectDeprecationMessage($message);
Deprecation::enable(); $this->enableDeprecationNotices();
Config::inst()->get(DeprecationTestObject::class, 'first_config'); Config::inst()->get(DeprecationTestObject::class, 'first_config');
Deprecation::outputNotices(); Deprecation::outputNotices();
} }
@ -244,7 +331,7 @@ class DeprecationTest extends SapphireTest
]); ]);
$this->expectDeprecation(); $this->expectDeprecation();
$this->expectDeprecationMessage($message); $this->expectDeprecationMessage($message);
Deprecation::enable(); $this->enableDeprecationNotices();
Config::inst()->get(DeprecationTestObject::class, 'second_config'); Config::inst()->get(DeprecationTestObject::class, 'second_config');
Deprecation::outputNotices(); Deprecation::outputNotices();
} }
@ -254,7 +341,7 @@ class DeprecationTest extends SapphireTest
$message = 'Config SilverStripe\Dev\Tests\DeprecationTest\DeprecationTestObject.third_config is deprecated.'; $message = 'Config SilverStripe\Dev\Tests\DeprecationTest\DeprecationTestObject.third_config is deprecated.';
$this->expectDeprecation(); $this->expectDeprecation();
$this->expectDeprecationMessage($message); $this->expectDeprecationMessage($message);
Deprecation::enable(); $this->enableDeprecationNotices();
Config::inst()->get(DeprecationTestObject::class, 'third_config'); Config::inst()->get(DeprecationTestObject::class, 'third_config');
Deprecation::outputNotices(); Deprecation::outputNotices();
} }
@ -267,7 +354,7 @@ class DeprecationTest extends SapphireTest
]); ]);
$this->expectDeprecation(); $this->expectDeprecation();
$this->expectDeprecationMessage($message); $this->expectDeprecationMessage($message);
Deprecation::enable(); $this->enableDeprecationNotices();
Config::modify()->set(DeprecationTestObject::class, 'first_config', 'abc'); Config::modify()->set(DeprecationTestObject::class, 'first_config', 'abc');
Deprecation::outputNotices(); Deprecation::outputNotices();
} }
@ -280,7 +367,7 @@ class DeprecationTest extends SapphireTest
]); ]);
$this->expectDeprecation(); $this->expectDeprecation();
$this->expectDeprecationMessage($message); $this->expectDeprecationMessage($message);
Deprecation::enable(); $this->enableDeprecationNotices();
Config::modify()->merge(DeprecationTestObject::class, 'array_config', ['abc']); Config::modify()->merge(DeprecationTestObject::class, 'array_config', ['abc']);
Deprecation::outputNotices(); Deprecation::outputNotices();
} }
@ -366,7 +453,7 @@ class DeprecationTest extends SapphireTest
switch ($varName) { switch ($varName) {
case 'SS_DEPRECATION_ENABLED': case 'SS_DEPRECATION_ENABLED':
if ($configVal) { if ($configVal) {
Deprecation::enable(); $this->enableDeprecationNotices();
} else { } else {
Deprecation::disable(); Deprecation::disable();
} }
@ -542,7 +629,7 @@ class DeprecationTest extends SapphireTest
private function setEnabledViaStatic(bool $enabled): void private function setEnabledViaStatic(bool $enabled): void
{ {
if ($enabled) { if ($enabled) {
Deprecation::enable(); $this->enableDeprecationNotices();
} else { } else {
Deprecation::disable(); Deprecation::disable();
} }