mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge branch '4' into 5.0
This commit is contained in:
commit
63c2460f72
5
.github/workflows/ci.yml
vendored
5
.github/workflows/ci.yml
vendored
@ -4,15 +4,10 @@ on:
|
|||||||
push:
|
push:
|
||||||
pull_request:
|
pull_request:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
# Every Tuesday at 2:20pm UTC
|
|
||||||
schedule:
|
|
||||||
- cron: '20 14 * * 2'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ci:
|
ci:
|
||||||
name: CI
|
name: CI
|
||||||
# Only run cron on the silverstripe account
|
|
||||||
if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule')
|
|
||||||
uses: silverstripe/gha-ci/.github/workflows/ci.yml@v1
|
uses: silverstripe/gha-ci/.github/workflows/ci.yml@v1
|
||||||
with:
|
with:
|
||||||
# Turn phpcoverage off because it causes a segfault
|
# Turn phpcoverage off because it causes a segfault
|
||||||
|
16
.github/workflows/dispatch-ci.yml
vendored
Normal file
16
.github/workflows/dispatch-ci.yml
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
name: Dispatch CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
# At 2:20 PM UTC, only on Tuesday and Wednesday
|
||||||
|
schedule:
|
||||||
|
- cron: '20 14 * * 2,3'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
dispatch-ci:
|
||||||
|
name: Dispatch CI
|
||||||
|
# Only run cron on the silverstripe account
|
||||||
|
if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Dispatch CI
|
||||||
|
uses: silverstripe/gha-dispatch-ci@v1
|
@ -111,4 +111,4 @@
|
|||||||
},
|
},
|
||||||
"minimum-stability": "dev",
|
"minimum-stability": "dev",
|
||||||
"prefer-stable": true
|
"prefer-stable": true
|
||||||
}
|
}
|
@ -177,23 +177,32 @@ class Environment
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get value of environment variable
|
* Get value of environment variable.
|
||||||
|
* If the value is false, you should check Environment::hasEnv() to see
|
||||||
|
* if the value is an actual environment variable value or if the variable
|
||||||
|
* simply hasn't been set.
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @return mixed Value of the environment variable, or false if not set
|
* @return mixed Value of the environment variable, or false if not set
|
||||||
*/
|
*/
|
||||||
public static function getEnv($name)
|
public static function getEnv($name)
|
||||||
{
|
{
|
||||||
switch (true) {
|
if (array_key_exists($name, static::$env)) {
|
||||||
case is_array(static::$env) && array_key_exists($name, static::$env):
|
return static::$env[$name];
|
||||||
return static::$env[$name];
|
|
||||||
case is_array($_ENV) && array_key_exists($name, $_ENV):
|
|
||||||
return $_ENV[$name];
|
|
||||||
case is_array($_SERVER) && array_key_exists($name, $_SERVER):
|
|
||||||
return $_SERVER[$name];
|
|
||||||
default:
|
|
||||||
return getenv($name);
|
|
||||||
}
|
}
|
||||||
|
// isset() is used for $_ENV and $_SERVER instead of array_key_exists() to fix a very strange issue that
|
||||||
|
// occured in CI running silverstripe/recipe-kitchen-sink where PHP would timeout due apparently due to an
|
||||||
|
// excessively high number of array method calls. isset() is not used for static::$env above because
|
||||||
|
// values there may be null, and isset() will return false for null values
|
||||||
|
// Symfony also uses isset() for reading $_ENV and $_SERVER values
|
||||||
|
// https://github.com/symfony/dependency-injection/blob/6.2/EnvVarProcessor.php#L148
|
||||||
|
if (isset($_ENV[$name])) {
|
||||||
|
return $_ENV[$name];
|
||||||
|
}
|
||||||
|
if (isset($_SERVER[$name])) {
|
||||||
|
return $_SERVER[$name];
|
||||||
|
}
|
||||||
|
return getenv($name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -223,6 +232,18 @@ class Environment
|
|||||||
static::$env[$name] = $value;
|
static::$env[$name] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an environment variable is set
|
||||||
|
*/
|
||||||
|
public static function hasEnv(string $name): bool
|
||||||
|
{
|
||||||
|
// See getEnv() for an explanation of why isset() is used for $_ENV and $_SERVER
|
||||||
|
return array_key_exists($name, static::$env)
|
||||||
|
|| isset($_ENV[$name])
|
||||||
|
|| isset($_SERVER[$name])
|
||||||
|
|| getenv($name) !== false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this script is being run from the command line rather than the web server
|
* Returns true if this script is being run from the command line rather than the web server
|
||||||
*
|
*
|
||||||
|
@ -29,12 +29,22 @@ class Deprecation
|
|||||||
* Must be configured outside of the config API, as deprecation API
|
* Must be configured outside of the config API, as deprecation API
|
||||||
* must be available before this to avoid infinite loops.
|
* must be available before this to avoid infinite loops.
|
||||||
*
|
*
|
||||||
* This will be overriden by the SS_DEPRECATION_ENABLED environment if present
|
* This will be overriden by the SS_DEPRECATION_ENABLED environment variable if present
|
||||||
*
|
*
|
||||||
* @internal - Marked as internal so this and other private static's are not treated as config
|
* @internal - Marked as internal so this and other private static's are not treated as config
|
||||||
*/
|
*/
|
||||||
private static bool $currentlyEnabled = false;
|
private static bool $currentlyEnabled = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private static bool $shouldShowForHttp = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private static bool $shouldShowForCli = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
@ -45,6 +55,11 @@ class Deprecation
|
|||||||
*/
|
*/
|
||||||
private static bool $insideWithNoReplacement = false;
|
private static bool $insideWithNoReplacement = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private static bool $isTriggeringError = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Buffer of user_errors to be raised
|
* Buffer of user_errors to be raised
|
||||||
*
|
*
|
||||||
@ -62,12 +77,26 @@ class Deprecation
|
|||||||
*/
|
*/
|
||||||
private static bool $showNoReplacementNotices = false;
|
private static bool $showNoReplacementNotices = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable throwing deprecation warnings. By default, this excludes warnings for
|
||||||
|
* deprecated code which is called by core Silverstripe modules.
|
||||||
|
*
|
||||||
|
* This will be overriden by the SS_DEPRECATION_ENABLED environment variable if present.
|
||||||
|
*
|
||||||
|
* @param bool $showNoReplacementNotices If true, deprecation warnings will also be thrown
|
||||||
|
* for deprecated code which is called by core Silverstripe modules.
|
||||||
|
*/
|
||||||
public static function enable(bool $showNoReplacementNotices = false): void
|
public static function enable(bool $showNoReplacementNotices = false): void
|
||||||
{
|
{
|
||||||
static::$currentlyEnabled = true;
|
static::$currentlyEnabled = true;
|
||||||
static::$showNoReplacementNotices = $showNoReplacementNotices;
|
static::$showNoReplacementNotices = $showNoReplacementNotices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable throwing deprecation warnings.
|
||||||
|
*
|
||||||
|
* This will be overriden by the SS_DEPRECATION_ENABLED environment variable if present.
|
||||||
|
*/
|
||||||
public static function disable(): void
|
public static function disable(): void
|
||||||
{
|
{
|
||||||
static::$currentlyEnabled = false;
|
static::$currentlyEnabled = false;
|
||||||
@ -133,7 +162,68 @@ class Deprecation
|
|||||||
if (!Director::isDev()) {
|
if (!Director::isDev()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return static::$currentlyEnabled || Environment::getEnv('SS_DEPRECATION_ENABLED');
|
if (Environment::hasEnv('SS_DEPRECATION_ENABLED')) {
|
||||||
|
$envVar = Environment::getEnv('SS_DEPRECATION_ENABLED');
|
||||||
|
return self::varAsBoolean($envVar);
|
||||||
|
}
|
||||||
|
return static::$currentlyEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true, any E_USER_DEPRECATED errors should be treated as coming
|
||||||
|
* directly from this class.
|
||||||
|
*/
|
||||||
|
public static function isTriggeringError(): bool
|
||||||
|
{
|
||||||
|
return self::$isTriggeringError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether deprecation warnings should be included in HTTP responses.
|
||||||
|
* Does not affect logging.
|
||||||
|
*
|
||||||
|
* This will be overriden by the SS_DEPRECATION_SHOW_HTTP environment variable if present.
|
||||||
|
*/
|
||||||
|
public static function setShouldShowForHttp(bool $value): void
|
||||||
|
{
|
||||||
|
self::$shouldShowForHttp = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether deprecation warnings should be included in CLI responses.
|
||||||
|
* Does not affect logging.
|
||||||
|
*
|
||||||
|
* This will be overriden by the SS_DEPRECATION_SHOW_CLI environment variable if present.
|
||||||
|
*/
|
||||||
|
public static function setShouldShowForCli(bool $value): void
|
||||||
|
{
|
||||||
|
self::$shouldShowForCli = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true, deprecation warnings should be included in HTTP responses.
|
||||||
|
* Does not affect logging.
|
||||||
|
*/
|
||||||
|
public static function shouldShowForHttp(): bool
|
||||||
|
{
|
||||||
|
if (Environment::hasEnv('SS_DEPRECATION_SHOW_HTTP')) {
|
||||||
|
$envVar = Environment::getEnv('SS_DEPRECATION_SHOW_HTTP');
|
||||||
|
return self::varAsBoolean($envVar);
|
||||||
|
}
|
||||||
|
return self::$shouldShowForHttp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true, deprecation warnings should be included in CLI responses.
|
||||||
|
* Does not affect logging.
|
||||||
|
*/
|
||||||
|
public static function shouldShowForCli(): bool
|
||||||
|
{
|
||||||
|
if (Environment::hasEnv('SS_DEPRECATION_SHOW_CLI')) {
|
||||||
|
$envVar = Environment::getEnv('SS_DEPRECATION_SHOW_CLI');
|
||||||
|
return self::varAsBoolean($envVar);
|
||||||
|
}
|
||||||
|
return self::$shouldShowForCli;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function outputNotices(): void
|
public static function outputNotices(): void
|
||||||
@ -141,24 +231,24 @@ class Deprecation
|
|||||||
if (!self::isEnabled()) {
|
if (!self::isEnabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$outputMessages = [];
|
|
||||||
// using a while loop with array_shift() to ensure that self::$userErrorMessageBuffer will have
|
$count = 0;
|
||||||
// have values removed from it before calling user_error()
|
$origCount = count(self::$userErrorMessageBuffer);
|
||||||
while (count(self::$userErrorMessageBuffer)) {
|
while ($origCount > $count) {
|
||||||
|
$count++;
|
||||||
$arr = array_shift(self::$userErrorMessageBuffer);
|
$arr = array_shift(self::$userErrorMessageBuffer);
|
||||||
$message = $arr['message'];
|
$message = $arr['message'];
|
||||||
// often the same deprecation message appears dozens of times, which isn't helpful
|
|
||||||
// only need to show a single instance of each message
|
|
||||||
if (in_array($message, $outputMessages)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$calledInsideWithNoReplacement = $arr['calledInsideWithNoReplacement'];
|
$calledInsideWithNoReplacement = $arr['calledInsideWithNoReplacement'];
|
||||||
if ($calledInsideWithNoReplacement && !self::$showNoReplacementNotices) {
|
if ($calledInsideWithNoReplacement && !self::$showNoReplacementNotices) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
self::$isTriggeringError = true;
|
||||||
user_error($message, E_USER_DEPRECATED);
|
user_error($message, E_USER_DEPRECATED);
|
||||||
$outputMessages[] = $message;
|
self::$isTriggeringError = false;
|
||||||
}
|
}
|
||||||
|
// Make absolutely sure the buffer is empty - array_shift seems to leave an item in the array
|
||||||
|
// if we're not using numeric keys.
|
||||||
|
self::$userErrorMessageBuffer = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -178,10 +268,12 @@ 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 {
|
||||||
|
$data = null;
|
||||||
if ($scope === self::SCOPE_CONFIG) {
|
if ($scope === self::SCOPE_CONFIG) {
|
||||||
// Deprecated config set via yaml will only be shown in the browser when using ?flush=1
|
// Deprecated config set via yaml will only be shown in the browser when using ?flush=1
|
||||||
// It will not show in CLI when running dev/build flush=1
|
// It will not show in CLI when running dev/build flush=1
|
||||||
self::$userErrorMessageBuffer[] = [
|
$data = [
|
||||||
|
'key' => sha1($string),
|
||||||
'message' => $string,
|
'message' => $string,
|
||||||
'calledInsideWithNoReplacement' => self::$insideWithNoReplacement
|
'calledInsideWithNoReplacement' => self::$insideWithNoReplacement
|
||||||
];
|
];
|
||||||
@ -215,20 +307,26 @@ class Deprecation
|
|||||||
if ($caller) {
|
if ($caller) {
|
||||||
$string = $caller . ' is deprecated.' . ($string ? ' ' . $string : '');
|
$string = $caller . ' is deprecated.' . ($string ? ' ' . $string : '');
|
||||||
}
|
}
|
||||||
self::$userErrorMessageBuffer[] = [
|
$data = [
|
||||||
|
'key' => sha1($string),
|
||||||
'message' => $string,
|
'message' => $string,
|
||||||
'calledInsideWithNoReplacement' => self::$insideWithNoReplacement
|
'calledInsideWithNoReplacement' => self::$insideWithNoReplacement
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
if (!self::$haveSetShutdownFunction && self::isEnabled()) {
|
if ($data && !array_key_exists($data['key'], self::$userErrorMessageBuffer)) {
|
||||||
|
// Store de-duplicated data in a buffer to be outputted when outputNotices() is called
|
||||||
|
self::$userErrorMessageBuffer[$data['key']] = $data;
|
||||||
|
|
||||||
// Use a shutdown function rather than immediately calling user_error() so that notices
|
// Use a shutdown function rather than immediately calling user_error() so that notices
|
||||||
// do not interfere with setting session varibles i.e. headers already sent error
|
// do not interfere with setting session varibles i.e. headers already sent error
|
||||||
// it also means the deprecation notices appear below all phpunit output in CI
|
// it also means the deprecation notices appear below all phpunit output in CI
|
||||||
// which is far nicer than having it spliced between phpunit output
|
// which is far nicer than having it spliced between phpunit output
|
||||||
register_shutdown_function(function () {
|
if (!self::$haveSetShutdownFunction && self::isEnabled()) {
|
||||||
self::outputNotices();
|
register_shutdown_function(function () {
|
||||||
});
|
self::outputNotices();
|
||||||
self::$haveSetShutdownFunction = true;
|
});
|
||||||
|
self::$haveSetShutdownFunction = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (BadMethodCallException $e) {
|
} catch (BadMethodCallException $e) {
|
||||||
if ($e->getMessage() === InjectorLoader::NO_MANIFESTS_AVAILABLE) {
|
if ($e->getMessage() === InjectorLoader::NO_MANIFESTS_AVAILABLE) {
|
||||||
@ -242,4 +340,31 @@ class Deprecation
|
|||||||
static::$insideNotice = false;
|
static::$insideNotice = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function varAsBoolean($val): bool
|
||||||
|
{
|
||||||
|
if (is_string($val)) {
|
||||||
|
$truthyStrings = [
|
||||||
|
'on',
|
||||||
|
'true',
|
||||||
|
'1',
|
||||||
|
];
|
||||||
|
|
||||||
|
if (in_array(strtolower($val), $truthyStrings, true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$falsyStrings = [
|
||||||
|
'off',
|
||||||
|
'false',
|
||||||
|
'0',
|
||||||
|
];
|
||||||
|
|
||||||
|
if (in_array(strtolower($val), $falsyStrings, true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (bool) $val;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -199,21 +199,25 @@ class GridFieldFilterHeader extends AbstractGridFieldComponent implements GridFi
|
|||||||
public function canFilterAnyColumns($gridField)
|
public function canFilterAnyColumns($gridField)
|
||||||
{
|
{
|
||||||
$list = $gridField->getList();
|
$list = $gridField->getList();
|
||||||
|
if (!($list instanceof Filterable) || !$this->checkDataType($list)) {
|
||||||
if (!$this->checkDataType($list)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
$modelClass = $gridField->getModelClass();
|
||||||
$columns = $gridField->getColumns();
|
// note: searchableFields() will return summary_fields if there are no searchable_fields on the model
|
||||||
foreach ($columns as $columnField) {
|
$searchableFields = array_keys($modelClass::singleton()->searchableFields());
|
||||||
$metadata = $gridField->getColumnMetadata($columnField);
|
$summaryFields = array_keys($modelClass::singleton()->summaryFields());
|
||||||
$title = $metadata['title'];
|
sort($searchableFields);
|
||||||
|
sort($summaryFields);
|
||||||
if ($title && $list->canFilterBy($columnField)) {
|
// searchable_fields has been explictily defined i.e. searchableFields() is not falling back to summary_fields
|
||||||
|
if ($searchableFields !== $summaryFields) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// we have fallen back to summary_fields, check they are filterable
|
||||||
|
foreach ($searchableFields as $searchableField) {
|
||||||
|
if ($list->canFilterBy($searchableField)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ use Monolog\LogRecord;
|
|||||||
use SilverStripe\Control\Controller;
|
use SilverStripe\Control\Controller;
|
||||||
use SilverStripe\Control\Director;
|
use SilverStripe\Control\Director;
|
||||||
use SilverStripe\Control\HTTPResponse;
|
use SilverStripe\Control\HTTPResponse;
|
||||||
|
use SilverStripe\Dev\Deprecation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Output the error to the browser, with the given HTTP status code.
|
* Output the error to the browser, with the given HTTP status code.
|
||||||
@ -138,6 +139,16 @@ class HTTPOutputHandler extends AbstractProcessingHandler
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function shouldShowError(int $errorCode): bool
|
||||||
|
{
|
||||||
|
// show all non-E_USER_DEPRECATED errors
|
||||||
|
// or E_USER_DEPRECATED errors when not triggering from the Deprecation class
|
||||||
|
// or our deprecations when the relevant shouldShow method returns true
|
||||||
|
return $errorCode !== E_USER_DEPRECATED
|
||||||
|
|| !Deprecation::isTriggeringError()
|
||||||
|
|| ($this->isCli() ? Deprecation::shouldShowForCli() : Deprecation::shouldShowForHttp());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $record
|
* @param array $record
|
||||||
* @return bool
|
* @return bool
|
||||||
@ -146,6 +157,14 @@ class HTTPOutputHandler extends AbstractProcessingHandler
|
|||||||
{
|
{
|
||||||
ini_set('display_errors', 0);
|
ini_set('display_errors', 0);
|
||||||
|
|
||||||
|
// Suppress errors that should be suppressed
|
||||||
|
if (isset($record['context']['code'])) {
|
||||||
|
$errorCode = $record['context']['code'];
|
||||||
|
if (!$this->shouldShowError($errorCode)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: This coupling isn't ideal
|
// TODO: This coupling isn't ideal
|
||||||
// See https://github.com/silverstripe/silverstripe-framework/issues/4484
|
// See https://github.com/silverstripe/silverstripe-framework/issues/4484
|
||||||
if (Controller::has_curr()) {
|
if (Controller::has_curr()) {
|
||||||
@ -166,4 +185,12 @@ class HTTPOutputHandler extends AbstractProcessingHandler
|
|||||||
$response->setBody($record['formatted']);
|
$response->setBody($record['formatted']);
|
||||||
$response->output();
|
$response->output();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is required and must be protected for unit testing, since we can't mock static or private methods
|
||||||
|
*/
|
||||||
|
protected function isCli(): bool
|
||||||
|
{
|
||||||
|
return Director::is_cli();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ namespace SilverStripe\Logging;
|
|||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Monolog\ErrorHandler as MonologHandler;
|
use Monolog\ErrorHandler as MonologHandler;
|
||||||
|
use Psr\Log\LogLevel;
|
||||||
|
|
||||||
class MonologErrorHandler implements ErrorHandler
|
class MonologErrorHandler implements ErrorHandler
|
||||||
{
|
{
|
||||||
@ -62,7 +63,13 @@ class MonologErrorHandler implements ErrorHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($loggers as $logger) {
|
foreach ($loggers as $logger) {
|
||||||
MonologHandler::register($logger);
|
// Log deprecation warnings as WARNING, not NOTICE
|
||||||
|
// see https://github.com/Seldaek/monolog/blob/1.x/doc/01-usage.md#log-levels
|
||||||
|
$errorLevelMap = [
|
||||||
|
E_DEPRECATED => LogLevel::WARNING,
|
||||||
|
E_USER_DEPRECATED => LogLevel::WARNING,
|
||||||
|
];
|
||||||
|
MonologHandler::register($logger, $errorLevelMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -583,7 +583,7 @@ class ArrayList extends ViewableData implements SS_List, Filterable, Sortable, L
|
|||||||
|
|
||||||
$firstRecord = $this->first();
|
$firstRecord = $this->first();
|
||||||
|
|
||||||
return is_array($firstRecord) ? array_key_exists($by, $firstRecord) : property_exists($by, $firstRecord ?? '');
|
return is_array($firstRecord) ? array_key_exists($by, $firstRecord) : property_exists($firstRecord, $by ?? '');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace SilverStripe\Core\Tests;
|
namespace SilverStripe\Core\Tests;
|
||||||
|
|
||||||
|
use ReflectionProperty;
|
||||||
use SilverStripe\Core\Environment;
|
use SilverStripe\Core\Environment;
|
||||||
use SilverStripe\Dev\SapphireTest;
|
use SilverStripe\Dev\SapphireTest;
|
||||||
|
|
||||||
@ -66,4 +67,86 @@ class EnvironmentTest extends SapphireTest
|
|||||||
$this->assertEquals('fail', $vars['test']);
|
$this->assertEquals('fail', $vars['test']);
|
||||||
$this->assertEquals('global', $GLOBALS['test']);
|
$this->assertEquals('global', $GLOBALS['test']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function provideHasEnv()
|
||||||
|
{
|
||||||
|
$setAsOptions = [
|
||||||
|
'.env',
|
||||||
|
'_ENV',
|
||||||
|
'_SERVER',
|
||||||
|
'putenv',
|
||||||
|
];
|
||||||
|
$valueOptions = [
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1.75,
|
||||||
|
'',
|
||||||
|
'0',
|
||||||
|
'some-value',
|
||||||
|
];
|
||||||
|
$scenarios = [];
|
||||||
|
foreach ($setAsOptions as $setAs) {
|
||||||
|
foreach ($valueOptions as $value) {
|
||||||
|
$scenarios[] = [
|
||||||
|
'setAs' => $setAs,
|
||||||
|
'value' => $value,
|
||||||
|
'expected' => true,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// `null` isn't a supported value outside of using the `.env` option.
|
||||||
|
$scenarios[] = [
|
||||||
|
'setAs' => '.env',
|
||||||
|
'value' => null,
|
||||||
|
'expected' => true,
|
||||||
|
];
|
||||||
|
$scenarios[] = [
|
||||||
|
'setAs' => null,
|
||||||
|
'value' => null,
|
||||||
|
'expected' => false,
|
||||||
|
];
|
||||||
|
return $scenarios;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideHasEnv
|
||||||
|
*/
|
||||||
|
public function testHasEnv(?string $setAs, $value, bool $expected)
|
||||||
|
{
|
||||||
|
$name = '_ENVTEST_HAS_ENV';
|
||||||
|
|
||||||
|
// Set the value
|
||||||
|
switch ($setAs) {
|
||||||
|
case '.env':
|
||||||
|
Environment::setEnv($name, $value);
|
||||||
|
break;
|
||||||
|
case '_ENV':
|
||||||
|
$_ENV[$name] = $value;
|
||||||
|
break;
|
||||||
|
case '_SERVER':
|
||||||
|
$_SERVER[$name] = $value;
|
||||||
|
break;
|
||||||
|
case 'putenv':
|
||||||
|
$val = is_string($value) ? $value : json_encode($value);
|
||||||
|
putenv("$name=$val");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// null is no-op, to validate not setting it works as expected.
|
||||||
|
if ($setAs !== null) {
|
||||||
|
$this->fail("setAs value $setAs isn't taken into account correctly for this test.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertSame($expected, Environment::hasEnv($name));
|
||||||
|
|
||||||
|
// unset the value
|
||||||
|
$reflectionEnv = new ReflectionProperty(Environment::class, 'env');
|
||||||
|
$reflectionEnv->setAccessible(true);
|
||||||
|
$reflectionEnv->setValue(array_diff($reflectionEnv->getValue(), [$name => $value]));
|
||||||
|
unset($_ENV[$name]);
|
||||||
|
unset($_SERVER[$name]);
|
||||||
|
putenv("$name");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
namespace SilverStripe\Dev\Tests;
|
namespace SilverStripe\Dev\Tests;
|
||||||
|
|
||||||
use PHPUnit\Framework\Error\Deprecated;
|
use PHPUnit\Framework\Error\Deprecated;
|
||||||
|
use ReflectionMethod;
|
||||||
use SilverStripe\Core\Config\Config;
|
use SilverStripe\Core\Config\Config;
|
||||||
|
use SilverStripe\Core\Environment;
|
||||||
use SilverStripe\Dev\Deprecation;
|
use SilverStripe\Dev\Deprecation;
|
||||||
use SilverStripe\Dev\SapphireTest;
|
use SilverStripe\Dev\SapphireTest;
|
||||||
use SilverStripe\Dev\Tests\DeprecationTest\DeprecationTestObject;
|
use SilverStripe\Dev\Tests\DeprecationTest\DeprecationTestObject;
|
||||||
@ -22,7 +24,7 @@ class DeprecationTest extends SapphireTest
|
|||||||
protected function setup(): void
|
protected function setup(): void
|
||||||
{
|
{
|
||||||
// Use custom error handler for two reasons:
|
// Use custom error handler for two reasons:
|
||||||
// - Filter out errors for deprecated class properities unrelated to this unit test
|
// - Filter out errors for deprecated class properties unrelated to this unit test
|
||||||
// - Allow the use of expectDeprecation(), which doesn't work with E_USER_DEPRECATION by default
|
// - Allow the use of expectDeprecation(), which doesn't work with E_USER_DEPRECATION by default
|
||||||
// https://github.com/laminas/laminas-di/pull/30#issuecomment-927585210
|
// https://github.com/laminas/laminas-di/pull/30#issuecomment-927585210
|
||||||
parent::setup();
|
parent::setup();
|
||||||
@ -32,7 +34,7 @@ class DeprecationTest extends SapphireTest
|
|||||||
if (str_contains($errstr, 'SilverStripe\\Dev\\Tests\\DeprecationTest')) {
|
if (str_contains($errstr, 'SilverStripe\\Dev\\Tests\\DeprecationTest')) {
|
||||||
throw new Deprecated($errstr, $errno, '', 1);
|
throw new Deprecated($errstr, $errno, '', 1);
|
||||||
} else {
|
} else {
|
||||||
// Surpress any E_USER_DEPRECATED unrelated to this unit-test
|
// Suppress any E_USER_DEPRECATED unrelated to this unit-test
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -46,7 +48,9 @@ class DeprecationTest extends SapphireTest
|
|||||||
|
|
||||||
protected function tearDown(): void
|
protected function tearDown(): void
|
||||||
{
|
{
|
||||||
if (!$this->noticesWereEnabled) {
|
if ($this->noticesWereEnabled) {
|
||||||
|
Deprecation::enable();
|
||||||
|
} else {
|
||||||
Deprecation::disable();
|
Deprecation::disable();
|
||||||
}
|
}
|
||||||
restore_error_handler();
|
restore_error_handler();
|
||||||
@ -278,4 +282,167 @@ class DeprecationTest extends SapphireTest
|
|||||||
Config::modify()->merge(DeprecationTestObject::class, 'array_config', ['abc']);
|
Config::modify()->merge(DeprecationTestObject::class, 'array_config', ['abc']);
|
||||||
Deprecation::outputNotices();
|
Deprecation::outputNotices();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function provideConfigVsEnv()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
// env var not set - config setting is respected
|
||||||
|
[
|
||||||
|
// false is returned when the env isn't set, so this simulates simply not having
|
||||||
|
// set the variable in the first place
|
||||||
|
'envVal' => 'notset',
|
||||||
|
'configVal' => false,
|
||||||
|
'expected' => false,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'envVal' => 'notset',
|
||||||
|
'configVal' => true,
|
||||||
|
'expected' => true,
|
||||||
|
],
|
||||||
|
// env var is set and truthy, config setting is ignored
|
||||||
|
[
|
||||||
|
'envVal' => true,
|
||||||
|
'configVal' => false,
|
||||||
|
'expected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'envVal' => true,
|
||||||
|
'configVal' => true,
|
||||||
|
'expected' => true,
|
||||||
|
],
|
||||||
|
// env var is set and falsy, config setting is ignored
|
||||||
|
[
|
||||||
|
'envVal' => false,
|
||||||
|
'configVal' => false,
|
||||||
|
'expected' => false,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'envVal' => false,
|
||||||
|
'configVal' => true,
|
||||||
|
'expected' => false,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideConfigVsEnv
|
||||||
|
*/
|
||||||
|
public function testEnabledConfigVsEnv($envVal, bool $configVal, bool $expected)
|
||||||
|
{
|
||||||
|
$this->runConfigVsEnvTest('SS_DEPRECATION_ENABLED', $envVal, $configVal, $expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideConfigVsEnv
|
||||||
|
*/
|
||||||
|
public function testShowHttpConfigVsEnv($envVal, bool $configVal, bool $expected)
|
||||||
|
{
|
||||||
|
$this->runConfigVsEnvTest('SS_DEPRECATION_SHOW_HTTP', $envVal, $configVal, $expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideConfigVsEnv
|
||||||
|
*/
|
||||||
|
public function testShowCliConfigVsEnv($envVal, bool $configVal, bool $expected)
|
||||||
|
{
|
||||||
|
$this->runConfigVsEnvTest('SS_DEPRECATION_SHOW_CLI', $envVal, $configVal, $expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function runConfigVsEnvTest(string $varName, $envVal, bool $configVal, bool $expected)
|
||||||
|
{
|
||||||
|
$oldVars = Environment::getVariables();
|
||||||
|
|
||||||
|
if ($envVal === 'notset') {
|
||||||
|
if (Environment::hasEnv($varName)) {
|
||||||
|
$this->markTestSkipped("$varName is set, so we can't test behaviour when it's not");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Environment::setEnv($varName, $envVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($varName) {
|
||||||
|
case 'SS_DEPRECATION_ENABLED':
|
||||||
|
if ($configVal) {
|
||||||
|
Deprecation::enable();
|
||||||
|
} else {
|
||||||
|
Deprecation::disable();
|
||||||
|
}
|
||||||
|
$result = Deprecation::isEnabled();
|
||||||
|
break;
|
||||||
|
case 'SS_DEPRECATION_SHOW_HTTP':
|
||||||
|
$oldShouldShow = Deprecation::shouldShowForHttp();
|
||||||
|
Deprecation::setShouldShowForHttp($configVal);
|
||||||
|
$result = Deprecation::shouldShowForHttp();
|
||||||
|
Deprecation::setShouldShowForHttp($oldShouldShow);
|
||||||
|
break;
|
||||||
|
case 'SS_DEPRECATION_SHOW_CLI':
|
||||||
|
$oldShouldShow = Deprecation::shouldShowForCli();
|
||||||
|
Deprecation::setShouldShowForCli($configVal);
|
||||||
|
$result = Deprecation::shouldShowForCli();
|
||||||
|
Deprecation::setShouldShowForCli($oldShouldShow);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Environment::setVariables($oldVars);
|
||||||
|
|
||||||
|
$this->assertSame($expected, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideVarAsBoolean()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
'rawValue' => true,
|
||||||
|
'expected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'rawValue' => 'true',
|
||||||
|
'expected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'rawValue' => 1,
|
||||||
|
'expected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'rawValue' => '1',
|
||||||
|
'expected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'rawValue' => 'on',
|
||||||
|
'expected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'rawValue' => false,
|
||||||
|
'expected' => false,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'rawValue' => 'false',
|
||||||
|
'expected' => false,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'rawValue' => 0,
|
||||||
|
'expected' => false,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'rawValue' => '0',
|
||||||
|
'expected' => false,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'rawValue' => 'off',
|
||||||
|
'expected' => false,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideVarAsBoolean
|
||||||
|
*/
|
||||||
|
public function testVarAsBoolean($rawValue, bool $expected)
|
||||||
|
{
|
||||||
|
$reflectionVarAsBoolean = new ReflectionMethod(Deprecation::class, 'varAsBoolean');
|
||||||
|
$reflectionVarAsBoolean->setAccessible(true);
|
||||||
|
|
||||||
|
$this->assertSame($expected, $reflectionVarAsBoolean->invoke(null, $rawValue));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,4 +168,30 @@ class GridFieldFilterHeaderTest extends SapphireTest
|
|||||||
|
|
||||||
$this->assertEquals('ReallyCustomSearch', $this->component->getSearchField());
|
$this->assertEquals('ReallyCustomSearch', $this->component->getSearchField());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testCanFilterAnyColumns()
|
||||||
|
{
|
||||||
|
$gridField = $this->gridField;
|
||||||
|
$filterHeader = $gridField->getConfig()->getComponentByType(GridFieldFilterHeader::class);
|
||||||
|
|
||||||
|
// test that you can filter by something if searchable_fields is not defined
|
||||||
|
// silverstripe will scaffold db columns that are in the gridfield to be
|
||||||
|
// searchable by default
|
||||||
|
Config::modify()->remove(Team::class, 'searchable_fields');
|
||||||
|
$this->assertTrue($filterHeader->canFilterAnyColumns($gridField));
|
||||||
|
|
||||||
|
// test that you can filterBy if searchable_fields is defined
|
||||||
|
Config::modify()->set(Team::class, 'searchable_fields', ['Name']);
|
||||||
|
$this->assertTrue($filterHeader->canFilterAnyColumns($gridField));
|
||||||
|
|
||||||
|
// test that you can filterBy if searchable_fields even if it is not a legit field
|
||||||
|
// this is because we're making a blind assumption it will be filterable later in a SearchContext
|
||||||
|
Config::modify()->set(Team::class, 'searchable_fields', ['WhatIsThis']);
|
||||||
|
$this->assertTrue($filterHeader->canFilterAnyColumns($gridField));
|
||||||
|
|
||||||
|
// test that you cannot filter by non-db field when it falls back to summary_fields
|
||||||
|
Config::modify()->remove(Team::class, 'searchable_fields');
|
||||||
|
Config::modify()->set(Team::class, 'summary_fields', ['MySummaryField']);
|
||||||
|
$this->assertFalse($filterHeader->canFilterAnyColumns($gridField));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,4 +24,9 @@ class Team extends DataObject implements TestOnly
|
|||||||
'Cheerleader' => Cheerleader::class,
|
'Cheerleader' => Cheerleader::class,
|
||||||
'CheerleadersMom' => Mom::class
|
'CheerleadersMom' => Mom::class
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function getMySummaryField()
|
||||||
|
{
|
||||||
|
return 'MY SUMMARY FIELD';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,11 @@
|
|||||||
namespace SilverStripe\Logging\Tests;
|
namespace SilverStripe\Logging\Tests;
|
||||||
|
|
||||||
use Monolog\Handler\HandlerInterface;
|
use Monolog\Handler\HandlerInterface;
|
||||||
|
use ReflectionMethod;
|
||||||
|
use ReflectionProperty;
|
||||||
use SilverStripe\Control\Director;
|
use SilverStripe\Control\Director;
|
||||||
use SilverStripe\Core\Injector\Injector;
|
use SilverStripe\Core\Injector\Injector;
|
||||||
|
use SilverStripe\Dev\Deprecation;
|
||||||
use SilverStripe\Dev\SapphireTest;
|
use SilverStripe\Dev\SapphireTest;
|
||||||
use SilverStripe\Logging\DebugViewFriendlyErrorFormatter;
|
use SilverStripe\Logging\DebugViewFriendlyErrorFormatter;
|
||||||
use SilverStripe\Logging\DetailedErrorFormatter;
|
use SilverStripe\Logging\DetailedErrorFormatter;
|
||||||
@ -53,4 +56,131 @@ class HTTPOutputHandlerTest extends SapphireTest
|
|||||||
$this->assertInstanceOf(DetailedErrorFormatter::class, $handler->getDefaultFormatter());
|
$this->assertInstanceOf(DetailedErrorFormatter::class, $handler->getDefaultFormatter());
|
||||||
$this->assertInstanceOf(DetailedErrorFormatter::class, $handler->getFormatter());
|
$this->assertInstanceOf(DetailedErrorFormatter::class, $handler->getFormatter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function provideShouldShowError()
|
||||||
|
{
|
||||||
|
$provide = [];
|
||||||
|
// See https://www.php.net/manual/en/errorfunc.constants.php
|
||||||
|
$errors = [
|
||||||
|
E_ERROR,
|
||||||
|
E_WARNING,
|
||||||
|
E_PARSE,
|
||||||
|
E_NOTICE,
|
||||||
|
E_CORE_ERROR,
|
||||||
|
E_CORE_WARNING,
|
||||||
|
E_COMPILE_ERROR,
|
||||||
|
E_COMPILE_WARNING,
|
||||||
|
E_USER_ERROR,
|
||||||
|
E_USER_WARNING,
|
||||||
|
E_USER_NOTICE,
|
||||||
|
E_RECOVERABLE_ERROR,
|
||||||
|
E_DEPRECATED,
|
||||||
|
E_USER_DEPRECATED,
|
||||||
|
];
|
||||||
|
foreach ($errors as $errorCode) {
|
||||||
|
// Display all errors regardless of type in this scenario
|
||||||
|
$provide[] = [
|
||||||
|
'errorCode' => $errorCode,
|
||||||
|
'triggeringError' => true,
|
||||||
|
'isCli' => true,
|
||||||
|
'shouldShow' => true,
|
||||||
|
'expected' => true,
|
||||||
|
];
|
||||||
|
// Don't display E_USER_DEPRECATED that we're triggering if shouldShow is false
|
||||||
|
$provide[] = [
|
||||||
|
'errorCode' => $errorCode,
|
||||||
|
'triggeringError' => true,
|
||||||
|
'isCli' => true,
|
||||||
|
'shouldShow' => false,
|
||||||
|
'expected' => ($errorCode !== E_USER_DEPRECATED) || false
|
||||||
|
];
|
||||||
|
// Display all errors regardless of type in this scenario
|
||||||
|
$provide[] = [
|
||||||
|
'errorCode' => $errorCode,
|
||||||
|
'triggeringError' => true,
|
||||||
|
'isCli' => false,
|
||||||
|
'shouldShow' => true,
|
||||||
|
'expected' => true
|
||||||
|
];
|
||||||
|
// Don't display E_USER_DEPRECATED that we're triggering if shouldShow is false
|
||||||
|
$provide[] = [
|
||||||
|
'errorCode' => $errorCode,
|
||||||
|
'triggeringError' => true,
|
||||||
|
'isCli' => false,
|
||||||
|
'shouldShow' => false,
|
||||||
|
'expected' => ($errorCode !== E_USER_DEPRECATED) || false
|
||||||
|
];
|
||||||
|
// All of the below have triggeringError set to false, in which case
|
||||||
|
// all errors should be displayed.
|
||||||
|
$provide[] = [
|
||||||
|
'errorCode' => $errorCode,
|
||||||
|
'triggeringError' => false,
|
||||||
|
'isCli' => true,
|
||||||
|
'shouldShow' => true,
|
||||||
|
'expected' => true
|
||||||
|
];
|
||||||
|
$provide[] = [
|
||||||
|
'errorCode' => $errorCode,
|
||||||
|
'triggeringError' => false,
|
||||||
|
'isCli' => false,
|
||||||
|
'shouldShow' => true,
|
||||||
|
'expected' => true
|
||||||
|
];
|
||||||
|
$provide[] = [
|
||||||
|
'errorCode' => $errorCode,
|
||||||
|
'triggeringError' => false,
|
||||||
|
'isCli' => true,
|
||||||
|
'shouldShow' => false,
|
||||||
|
'expected' => true
|
||||||
|
];
|
||||||
|
$provide[] = [
|
||||||
|
'errorCode' => $errorCode,
|
||||||
|
'triggeringError' => false,
|
||||||
|
'isCli' => false,
|
||||||
|
'shouldShow' => false,
|
||||||
|
'expected' => true
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $provide;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideShouldShowError
|
||||||
|
*/
|
||||||
|
public function testShouldShowError(
|
||||||
|
int $errorCode,
|
||||||
|
bool $triggeringError,
|
||||||
|
bool $isCli,
|
||||||
|
bool $shouldShow,
|
||||||
|
bool $expected
|
||||||
|
) {
|
||||||
|
$reflectionShouldShow = new ReflectionMethod(HTTPOutputHandler::class, 'shouldShowError');
|
||||||
|
$reflectionShouldShow->setAccessible(true);
|
||||||
|
$reflectionTriggeringError = new ReflectionProperty(Deprecation::class, 'isTriggeringError');
|
||||||
|
$reflectionTriggeringError->setAccessible(true);
|
||||||
|
|
||||||
|
$cliShouldShowOrig = Deprecation::shouldShowForCli();
|
||||||
|
$httpShouldShowOrig = Deprecation::shouldShowForHttp();
|
||||||
|
$triggeringErrorOrig = Deprecation::isTriggeringError();
|
||||||
|
// Set the relevant item using $shouldShow, and the other always as true
|
||||||
|
// to show that these don't interfere with each other
|
||||||
|
if ($isCli) {
|
||||||
|
Deprecation::setShouldShowForCli($shouldShow);
|
||||||
|
Deprecation::setShouldShowForHttp(true);
|
||||||
|
} else {
|
||||||
|
Deprecation::setShouldShowForCli(true);
|
||||||
|
Deprecation::setShouldShowForHttp($shouldShow);
|
||||||
|
}
|
||||||
|
$reflectionTriggeringError->setValue($triggeringError);
|
||||||
|
|
||||||
|
$mockHandler = $this->getMockBuilder(HTTPOutputHandler::class)->onlyMethods(['isCli'])->getMock();
|
||||||
|
$mockHandler->method('isCli')->willReturn($isCli);
|
||||||
|
|
||||||
|
$result = $reflectionShouldShow->invoke($mockHandler, $errorCode);
|
||||||
|
$this->assertSame($expected, $result);
|
||||||
|
|
||||||
|
Deprecation::setShouldShowForCli($cliShouldShowOrig);
|
||||||
|
Deprecation::setShouldShowForHttp($httpShouldShowOrig);
|
||||||
|
$reflectionTriggeringError->setValue($triggeringErrorOrig);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user