diff --git a/src/Dev/Deprecation.php b/src/Dev/Deprecation.php index b5e9cf935b2..c7fcb9e401e 100644 --- a/src/Dev/Deprecation.php +++ b/src/Dev/Deprecation.php @@ -77,6 +77,11 @@ class Deprecation */ private static bool $showNoReplacementNotices = false; + /** + * @internal + */ + private static bool $showCalledFromSupportedCodeNotices = false; + /** * Enable throwing deprecation warnings. By default, this excludes warnings for * deprecated code which is called by core Silverstripe modules. @@ -146,6 +151,12 @@ protected static function get_called_method_from_trace($backtrace, $level = 1) if (!$level) { $level = 1; } + $called = Deprecation::get_called_from_trace($backtrace, $level); + return ($called['class'] ?? '') . ($called['type'] ?? '') . ($called['function'] ?? ''); + } + + private static function get_called_from_trace(array $backtrace, int $level): array + { $newLevel = $level; // handle closures inside withSuppressedNotice() if (Deprecation::$insideNoticeSuppression @@ -164,7 +175,39 @@ protected static function get_called_method_from_trace($backtrace, $level = 1) $newLevel = $newLevel + 4; } $called = $backtrace[$newLevel] ?? []; - return ($called['class'] ?? '') . ($called['type'] ?? '') . ($called['function'] ?? ''); + return $called; + } + + private static function calledFromSupportedCode(array $backtrace): bool + { + $called = Deprecation::get_called_from_trace($backtrace, 1); + $file = $called['file'] ?? ''; + if ($file) { + $isSupportedVendorFile = Deprecation::isSupportedVendorFile($file); + if (!$isSupportedVendorFile) { + return false; + } + } + return true; + } + + /** + * Whether the given file is supported code + */ + private static function isSupportedVendorFile(string $file): bool + { + // 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 + $vendors = implode('|', [ + 'bringyourownideas', + 'colymba', + 'cwp', + 'dnadesign', + 'silverstripe', + 'symbiote', + 'tractorcow', + ]); + return (bool) preg_match("#/vendor/($vendors)/#", $file); } public static function isEnabled(): bool @@ -245,6 +288,14 @@ public static function shouldShowForCli(): bool return Deprecation::$shouldShowForCli; } + /** + * If true, deprecation warnings will be shown for deprecated code which is called by core Silverstripe modules. + */ + public static function setShowCalledFromSupportedCodeNotices(bool $value): void + { + Deprecation::$showCalledFromSupportedCodeNotices = $value; + } + public static function outputNotices(): void { if (!Deprecation::isEnabled()) { @@ -258,9 +309,13 @@ public static function outputNotices(): void $arr = array_shift(Deprecation::$userErrorMessageBuffer); $message = $arr['message']; $calledWithNoticeSuppression = $arr['calledWithNoticeSuppression']; + $calledFromSupportedCode = $arr['calledFromSupportedCode']; if ($calledWithNoticeSuppression && !Deprecation::$showNoReplacementNotices) { continue; } + if ($calledFromSupportedCode && !Deprecation::$showCalledFromSupportedCodeNotices) { + continue; + } Deprecation::$isTriggeringError = true; user_error($message, E_USER_DEPRECATED); Deprecation::$isTriggeringError = false; @@ -294,6 +349,7 @@ public static function notice($atVersion, $string = '', $scope = Deprecation::SC $data = [ 'key' => sha1($string), 'message' => $string, + 'calledFromSupportedCode' => false, 'calledWithNoticeSuppression' => Deprecation::$insideNoticeSuppression ]; } else { @@ -322,13 +378,13 @@ public static function notice($atVersion, $string = '', $scope = Deprecation::SC $level = Deprecation::$insideNoticeSuppression ? 4 : 2; $string .= " Called from " . Deprecation::get_called_method_from_trace($backtrace, $level) . '.'; - if ($caller) { $string = $caller . ' is deprecated.' . ($string ? ' ' . $string : ''); } $data = [ 'key' => sha1($string), 'message' => $string, + 'calledFromSupportedCode' => Deprecation::calledFromSupportedCode($backtrace), 'calledWithNoticeSuppression' => Deprecation::$insideNoticeSuppression ]; } @@ -360,6 +416,24 @@ public static function notice($atVersion, $string = '', $scope = Deprecation::SC } } + /** + * Shorthand method to create a suppressed notice + * If $string is empty, then a standardised message will be used, which is: + * Will be removed without equivalent functionality to replace it. + */ + public static function noticeWithNoReplacment( + string $atVersion, + string $string = '', + int $scope = Deprecation::SCOPE_METHOD + ): void { + if ($string === '') { + $string = 'Will be removed without equivalent functionality to replace it.'; + } + Deprecation::withSuppressedNotice( + fn() => Deprecation::notice($atVersion, $string, $scope) + ); + } + private static function varAsBoolean($val): bool { if (is_string($val)) {