mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #10554 from creative-commoners/pulls/4/deprecation-api
FIX Ensure Deprecation works with 1.x branches
This commit is contained in:
commit
421b706a38
@ -4,9 +4,7 @@ namespace SilverStripe\Dev;
|
|||||||
|
|
||||||
use SilverStripe\Control\Director;
|
use SilverStripe\Control\Director;
|
||||||
use SilverStripe\Core\Environment;
|
use SilverStripe\Core\Environment;
|
||||||
use SilverStripe\Core\Manifest\ClassLoader;
|
|
||||||
use SilverStripe\Core\Manifest\Module;
|
use SilverStripe\Core\Manifest\Module;
|
||||||
use SilverStripe\Core\Manifest\ModuleLoader;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles raising an notice when accessing a deprecated method
|
* Handles raising an notice when accessing a deprecated method
|
||||||
@ -37,14 +35,13 @@ use SilverStripe\Core\Manifest\ModuleLoader;
|
|||||||
*/
|
*/
|
||||||
class Deprecation
|
class Deprecation
|
||||||
{
|
{
|
||||||
|
|
||||||
const SCOPE_METHOD = 1;
|
const SCOPE_METHOD = 1;
|
||||||
const SCOPE_CLASS = 2;
|
const SCOPE_CLASS = 2;
|
||||||
const SCOPE_GLOBAL = 4;
|
const SCOPE_GLOBAL = 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @var string
|
* @var string
|
||||||
|
* @deprecated 4.12.0 Will be removed without equivalent functionality to replace it
|
||||||
*/
|
*/
|
||||||
protected static $version;
|
protected static $version;
|
||||||
|
|
||||||
@ -58,26 +55,47 @@ class Deprecation
|
|||||||
* must be available before this to avoid infinite loops.
|
* must be available before this to avoid infinite loops.
|
||||||
*
|
*
|
||||||
* @var boolean|null
|
* @var boolean|null
|
||||||
|
* @deprecated 4.12.0 Use $is_enabled instead
|
||||||
*/
|
*/
|
||||||
protected static $enabled = null;
|
protected static $enabled = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Must be configured outside of the config API, as deprecation API
|
||||||
|
* must be available before this to avoid infinite loops.
|
||||||
*
|
*
|
||||||
|
* This will be overriden by the SS_DEPRECATION_ENABLED environment if present
|
||||||
|
*/
|
||||||
|
protected static bool $is_enabled = false;
|
||||||
|
|
||||||
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
|
* @deprecated 4.12.0 Will be removed without equivalent functionality to replace it
|
||||||
*/
|
*/
|
||||||
protected static $module_version_overrides = [];
|
protected static $module_version_overrides = [];
|
||||||
|
|
||||||
protected static bool $inside_notice = false;
|
protected static bool $inside_notice = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var int - the notice level to raise on a deprecation notice. Defaults to E_USER_DEPRECATED if that exists,
|
* Switched out by unit-testing to E_USER_NOTICE because E_USER_DEPRECATED is not
|
||||||
* E_USER_NOTICE if not
|
* caught by $this->expectDeprecated() by default
|
||||||
|
* https://github.com/laminas/laminas-di/pull/30#issuecomment-927585210
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
*/
|
*/
|
||||||
public static $notice_level = null;
|
public static $notice_level = E_USER_DEPRECATED;
|
||||||
|
|
||||||
|
public static function enable(): void
|
||||||
|
{
|
||||||
|
static::$is_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function disable(): void
|
||||||
|
{
|
||||||
|
static::$is_enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the version that is used to check against the version passed to notice. If the ::notice version is
|
* This method is no longer used
|
||||||
* greater than or equal to this version, a message will be raised
|
|
||||||
*
|
*
|
||||||
* @static
|
* @static
|
||||||
* @param $ver string -
|
* @param $ver string -
|
||||||
@ -86,32 +104,25 @@ class Deprecation
|
|||||||
* The name of a module. The passed version will be used as the check value for
|
* The name of a module. The passed version will be used as the check value for
|
||||||
* calls directly from this module rather than the global value
|
* calls directly from this module rather than the global value
|
||||||
* @return void
|
* @return void
|
||||||
|
* @deprecated 4.12.0 Use enable() instead
|
||||||
*/
|
*/
|
||||||
public static function notification_version($ver, $forModule = null)
|
public static function notification_version($ver, $forModule = null)
|
||||||
{
|
{
|
||||||
if ($forModule) {
|
static::notice('4.12.0', 'Use enable() instead');
|
||||||
self::$module_version_overrides[$forModule] = $ver;
|
// noop
|
||||||
} else {
|
|
||||||
self::$version = $ver;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a backtrace, get the module name from the caller two removed (the caller of the method that called
|
* This method is no longer used
|
||||||
* #notice)
|
|
||||||
*
|
*
|
||||||
* @param array $backtrace A backtrace as returned from debug_backtrace
|
* @param array $backtrace A backtrace as returned from debug_backtrace
|
||||||
* @return Module The module being called
|
* @return Module The module being called
|
||||||
|
* @deprecated 4.12.0 Will be removed without equivalent functionality to replace it
|
||||||
*/
|
*/
|
||||||
protected static function get_calling_module_from_trace($backtrace)
|
protected static function get_calling_module_from_trace($backtrace)
|
||||||
{
|
{
|
||||||
if (!isset($backtrace[1]['file'])) {
|
static::notice('4.12.0', 'Will be removed without equivalent functionality to replace it');
|
||||||
return null;
|
// noop
|
||||||
}
|
|
||||||
|
|
||||||
$callingfile = realpath($backtrace[1]['file'] ?? '');
|
|
||||||
|
|
||||||
return ModuleLoader::inst()->getManifest()->getModuleByPath($callingfile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -137,30 +148,38 @@ class Deprecation
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if deprecation notices should be displayed
|
* This method is no longer used
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
|
* @deprecated 4.12.0 Will be removed without equivalent functionality to replace it
|
||||||
*/
|
*/
|
||||||
public static function get_enabled()
|
public static function get_enabled()
|
||||||
{
|
{
|
||||||
// Deprecation is only available on dev
|
static::notice('4.12.0', 'Will be removed without equivalent functionality to replace it');
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function get_is_enabled(): bool
|
||||||
|
{
|
||||||
if (!Director::isDev()) {
|
if (!Director::isDev()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (isset(self::$enabled)) {
|
if (Environment::getEnv('SS_DEPRECATION_ENABLED')) {
|
||||||
return self::$enabled;
|
return true;
|
||||||
}
|
}
|
||||||
return Environment::getEnv('SS_DEPRECATION_ENABLED') ?: true;
|
return static::$is_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggle on or off deprecation notices. Will be ignored in live.
|
* This method is no longer used
|
||||||
*
|
*
|
||||||
* @param bool $enabled
|
* @param bool $enabled
|
||||||
|
* @deprecated 4.12.0 Use enable() instead
|
||||||
*/
|
*/
|
||||||
public static function set_enabled($enabled)
|
public static function set_enabled($enabled)
|
||||||
{
|
{
|
||||||
self::$enabled = $enabled;
|
static::notice('4.12.0', 'Use enable() instead');
|
||||||
|
// noop
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -180,71 +199,40 @@ class Deprecation
|
|||||||
// try block needs to wrap all code in case anything inside the try block
|
// try block needs to wrap all code in case anything inside the try block
|
||||||
// calls something else that calls Deprecation::notice()
|
// calls something else that calls Deprecation::notice()
|
||||||
try {
|
try {
|
||||||
if (!static::get_enabled()) {
|
if (!self::get_is_enabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$checkVersion = self::$version;
|
|
||||||
// Getting a backtrace is slow, so we only do it if we need it
|
|
||||||
$backtrace = null;
|
|
||||||
|
|
||||||
// If you pass #.#, assume #.#.0
|
// If you pass #.#, assume #.#.0
|
||||||
if (preg_match('/^[0-9]+\.[0-9]+$/', $atVersion ?? '')) {
|
if (preg_match('/^[0-9]+\.[0-9]+$/', $atVersion ?? '')) {
|
||||||
$atVersion .= '.0';
|
$atVersion .= '.0';
|
||||||
}
|
}
|
||||||
if (preg_match('/^[0-9]+\.[0-9]+$/', $checkVersion ?? '')) {
|
|
||||||
$checkVersion .= '.0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self::$module_version_overrides) {
|
// Getting a backtrace is slow, so we only do it if we need it
|
||||||
$module = self::get_calling_module_from_trace($backtrace = debug_backtrace(0));
|
$backtrace = null;
|
||||||
if ($module) {
|
|
||||||
if (($name = $module->getComposerName())
|
|
||||||
&& isset(self::$module_version_overrides[$name])
|
|
||||||
) {
|
|
||||||
$checkVersion = self::$module_version_overrides[$name];
|
|
||||||
} elseif (($name = $module->getShortName())
|
|
||||||
&& isset(self::$module_version_overrides[$name])
|
|
||||||
) {
|
|
||||||
$checkVersion = self::$module_version_overrides[$name];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the version against the notice version
|
|
||||||
if ($checkVersion && version_compare($checkVersion ?? '', $atVersion ?? '', '>=')) {
|
|
||||||
// Get the calling scope
|
// Get the calling scope
|
||||||
if ($scope == Deprecation::SCOPE_METHOD) {
|
if ($scope == Deprecation::SCOPE_METHOD) {
|
||||||
if (!$backtrace) {
|
|
||||||
$backtrace = debug_backtrace(0);
|
$backtrace = debug_backtrace(0);
|
||||||
}
|
|
||||||
$caller = self::get_called_method_from_trace($backtrace);
|
$caller = self::get_called_method_from_trace($backtrace);
|
||||||
} elseif ($scope == Deprecation::SCOPE_CLASS) {
|
} elseif ($scope == Deprecation::SCOPE_CLASS) {
|
||||||
if (!$backtrace) {
|
|
||||||
$backtrace = debug_backtrace(0);
|
$backtrace = debug_backtrace(0);
|
||||||
}
|
|
||||||
$caller = isset($backtrace[1]['class']) ? $backtrace[1]['class'] : '(unknown)';
|
$caller = isset($backtrace[1]['class']) ? $backtrace[1]['class'] : '(unknown)';
|
||||||
} else {
|
} else {
|
||||||
$caller = false;
|
$caller = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the level to raise the notice as
|
|
||||||
$level = self::$notice_level;
|
|
||||||
if (!$level) {
|
|
||||||
$level = E_USER_DEPRECATED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then raise the notice
|
// Then raise the notice
|
||||||
if (substr($string ?? '', -1) != '.') {
|
if (substr($string, -1) != '.') {
|
||||||
$string .= ".";
|
$string .= ".";
|
||||||
}
|
}
|
||||||
|
|
||||||
$string .= " Called from " . self::get_called_method_from_trace($backtrace, 2) . '.';
|
$string .= " Called from " . self::get_called_method_from_trace($backtrace, 2) . '.';
|
||||||
|
|
||||||
if ($caller) {
|
if ($caller) {
|
||||||
user_error($caller . ' is deprecated.' . ($string ? ' ' . $string : ''), $level ?? 0);
|
user_error($caller . ' is deprecated.' . ($string ? ' ' . $string : ''), self::$notice_level);
|
||||||
} else {
|
} else {
|
||||||
user_error($string ?? '', $level ?? 0);
|
user_error($string, self::$notice_level);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
static::$inside_notice = false;
|
static::$inside_notice = false;
|
||||||
@ -252,30 +240,26 @@ class Deprecation
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method for when testing. Dump all the current version settings to a variable for later passing to restore
|
* This method is no longer used
|
||||||
*
|
*
|
||||||
* @return array Opaque array that should only be used to pass to {@see Deprecation::restore_settings()}
|
* @return array Opaque array that should only be used to pass to {@see Deprecation::restore_settings()}
|
||||||
|
* @deprecated 4.12.0 Will be removed without equivalent functionality to replace it
|
||||||
*/
|
*/
|
||||||
public static function dump_settings()
|
public static function dump_settings()
|
||||||
{
|
{
|
||||||
return [
|
static::notice('4.12.0', 'Will be removed without equivalent functionality to replace it');
|
||||||
'level' => self::$notice_level,
|
// noop
|
||||||
'version' => self::$version,
|
|
||||||
'moduleVersions' => self::$module_version_overrides,
|
|
||||||
'enabled' => self::$enabled,
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method for when testing. Restore all the current version settings from a variable
|
* This method is no longer used
|
||||||
*
|
*
|
||||||
* @param $settings array An array as returned by {@see Deprecation::dump_settings()}
|
* @param $settings array An array as returned by {@see Deprecation::dump_settings()}
|
||||||
|
* @deprecated 4.12.0 Will be removed without equivalent functionality to replace it
|
||||||
*/
|
*/
|
||||||
public static function restore_settings($settings)
|
public static function restore_settings($settings)
|
||||||
{
|
{
|
||||||
self::$notice_level = $settings['level'];
|
static::notice('4.12.0', 'Will be removed without equivalent functionality to replace it');
|
||||||
self::$version = $settings['version'];
|
// noop
|
||||||
self::$module_version_overrides = $settings['moduleVersions'];
|
|
||||||
self::$enabled = $settings['enabled'];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,103 +8,34 @@ use SilverStripe\Dev\Tests\DeprecationTest\TestDeprecation;
|
|||||||
|
|
||||||
class DeprecationTest extends SapphireTest
|
class DeprecationTest extends SapphireTest
|
||||||
{
|
{
|
||||||
|
|
||||||
static $originalVersionInfo;
|
|
||||||
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
parent::setUp();
|
|
||||||
|
|
||||||
self::$originalVersionInfo = Deprecation::dump_settings();
|
|
||||||
Deprecation::$notice_level = E_USER_NOTICE;
|
|
||||||
Deprecation::set_enabled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function tearDown(): void
|
protected function tearDown(): void
|
||||||
{
|
{
|
||||||
Deprecation::restore_settings(self::$originalVersionInfo);
|
Deprecation::$notice_level = E_USER_DEPRECATED;
|
||||||
|
Deprecation::disable();
|
||||||
parent::tearDown();
|
parent::tearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testLesserVersionTriggersNoNotice()
|
public function testNotice()
|
||||||
{
|
|
||||||
Deprecation::notification_version('1.0.0');
|
|
||||||
$this->assertNull(Deprecation::notice('2.0', 'Deprecation test failed'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testEqualVersionTriggersNotice()
|
|
||||||
{
|
{
|
||||||
|
$message = implode(' ', [
|
||||||
|
'SilverStripe\Dev\Tests\DeprecationTest->testNotice is deprecated.',
|
||||||
|
'My message.',
|
||||||
|
'Called from PHPUnit\Framework\TestCase->runTest.'
|
||||||
|
]);
|
||||||
$this->expectError();
|
$this->expectError();
|
||||||
Deprecation::notification_version('2.0.0');
|
$this->expectErrorMessage($message);
|
||||||
Deprecation::notice('2.0.0', 'Deprecation test passed');
|
Deprecation::$notice_level = E_USER_NOTICE;
|
||||||
|
Deprecation::enable();
|
||||||
|
Deprecation::notice('1.2.3', 'My message');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testBetaVersionDoesntTriggerNoticeWhenDeprecationDoesntSpecifyReleasenum()
|
/**
|
||||||
|
* @doesNotPerformAssertions
|
||||||
|
*/
|
||||||
|
public function testDisabled()
|
||||||
{
|
{
|
||||||
Deprecation::notification_version('2.0.0-beta1');
|
Deprecation::$notice_level = E_USER_NOTICE;
|
||||||
$this->assertNull(Deprecation::notice('2.0', 'Deprecation test failed'));
|
// test that no error error is raised because by default Deprecation is disabled
|
||||||
$this->assertNull(Deprecation::notice('2.0.0', 'Deprecation test failed'));
|
Deprecation::notice('4.5.6', 'My message');
|
||||||
}
|
|
||||||
|
|
||||||
public function testGreaterVersionTriggersNotice()
|
|
||||||
{
|
|
||||||
$this->expectError();
|
|
||||||
Deprecation::notification_version('3.0.0');
|
|
||||||
Deprecation::notice('2.0', 'Deprecation test passed');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testNonMatchingModuleNotifcationVersionDoesntAffectNotice()
|
|
||||||
{
|
|
||||||
Deprecation::notification_version('1.0.0');
|
|
||||||
Deprecation::notification_version('3.0.0', 'my-unrelated-module');
|
|
||||||
$this->callThatOriginatesFromFramework();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testMatchingModuleNotifcationVersionAffectsNotice()
|
|
||||||
{
|
|
||||||
$this->expectError();
|
|
||||||
Deprecation::notification_version('1.0.0');
|
|
||||||
Deprecation::notification_version('3.0.0', 'silverstripe/framework');
|
|
||||||
$this->callThatOriginatesFromFramework();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testMethodNameCalculation()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
TestDeprecation::get_method(),
|
|
||||||
static::class . '->testMethodNameCalculation'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testScopeMethod()
|
|
||||||
{
|
|
||||||
$this->expectError();
|
|
||||||
$this->expectErrorMessage('DeprecationTest->testScopeMethod is deprecated. Method scope');
|
|
||||||
Deprecation::notification_version('2.0.0');
|
|
||||||
Deprecation::notice('2.0.0', 'Method scope', Deprecation::SCOPE_METHOD);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testScopeClass()
|
|
||||||
{
|
|
||||||
$this->expectError();
|
|
||||||
$this->expectErrorMessage('DeprecationTest is deprecated. Class scope');
|
|
||||||
Deprecation::notification_version('2.0.0');
|
|
||||||
Deprecation::notice('2.0.0', 'Class scope', Deprecation::SCOPE_CLASS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testScopeGlobal()
|
|
||||||
{
|
|
||||||
$this->expectError();
|
|
||||||
$this->expectErrorMessage('Global scope');
|
|
||||||
Deprecation::notification_version('2.0.0');
|
|
||||||
Deprecation::notice('2.0.0', 'Global scope', Deprecation::SCOPE_GLOBAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function callThatOriginatesFromFramework()
|
|
||||||
{
|
|
||||||
$module = TestDeprecation::get_module();
|
|
||||||
$this->assertNotNull($module);
|
|
||||||
$this->assertEquals('silverstripe/framework', $module->getName());
|
|
||||||
$this->assertNull(Deprecation::notice('2.0', 'Deprecation test passed'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace SilverStripe\Dev\Tests\DeprecationTest;
|
|
||||||
|
|
||||||
use SilverStripe\Dev\Deprecation;
|
|
||||||
|
|
||||||
class TestDeprecation extends Deprecation
|
|
||||||
{
|
|
||||||
public static function get_module()
|
|
||||||
{
|
|
||||||
return self::get_calling_module_from_trace(debug_backtrace(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function get_method()
|
|
||||||
{
|
|
||||||
return self::get_called_method_from_trace(debug_backtrace(0));
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user