mirror of
https://github.com/humhub/humhub.git
synced 2025-01-17 22:28:51 +01:00
Merge pull request #6566 from metaworx/fix/invalid-argument-exceptions
Fix: invalid argument exceptions
This commit is contained in:
commit
47bed91f08
253
protected/humhub/exceptions/InvalidArgumentExceptionTrait.php
Normal file
253
protected/humhub/exceptions/InvalidArgumentExceptionTrait.php
Normal file
@ -0,0 +1,253 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2023 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\exceptions;
|
||||
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* @since 1.15
|
||||
*/
|
||||
trait InvalidArgumentExceptionTrait
|
||||
{
|
||||
protected string $methodName;
|
||||
protected ?string $parameter = null;
|
||||
protected array $valid = [];
|
||||
protected $given;
|
||||
protected string $suffix = '';
|
||||
protected bool $isInstantiating = true;
|
||||
|
||||
/**
|
||||
* @param string $parameterOrMessage Name of parameter in question, or alternatively the full message string containing at
|
||||
* least one space character (ASCII 32). In this case, `$valid` and `$given` are considered to be
|
||||
* `$code` and `$previous` respectively
|
||||
* @param string|string[] $valid (List of) valid parameter(s)
|
||||
* @param mixed $given Parameter received
|
||||
* @param int $code Optional exception code
|
||||
* @param Throwable|null $previous Optional previous exception
|
||||
*
|
||||
* @noinspection PhpDocMissingThrowsInspection
|
||||
* @noinspection PhpMissingParamTypeInspection
|
||||
*/
|
||||
public function __construct($parameterOrMessage, $valid = null, $given = null, $code = null, $previous = null)
|
||||
{
|
||||
$exception = null;
|
||||
$message = 'Invalid exception instantiation';
|
||||
|
||||
try {
|
||||
if (!is_string($parameterOrMessage)) {
|
||||
throw new InvalidArgumentTypeException('$parameterOrMessage', ['string'], $parameterOrMessage, 0, $this);
|
||||
}
|
||||
|
||||
if (empty($parameterOrMessage = trim($parameterOrMessage))) {
|
||||
throw new InvalidArgumentValueException('$parameterOrMessage', 'non-empty string', $parameterOrMessage, 0, $this);
|
||||
}
|
||||
|
||||
// check if $parameter is actually the $message
|
||||
if (strpos($parameterOrMessage, ' ') !== false) {
|
||||
$message = $parameterOrMessage;
|
||||
$code = $code ?? $valid ?? 0;
|
||||
$previous = $previous ?? $given;
|
||||
} else {
|
||||
$trace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 2);
|
||||
$trace = end($trace);
|
||||
$this->methodName = ltrim(($trace['class'] ?? '') . '::' . ($trace['function'] ?? 'unknown method'), ':');
|
||||
|
||||
$this->parameter = $parameterOrMessage;
|
||||
|
||||
try {
|
||||
$this->setValid($valid);
|
||||
} catch (InvalidArgumentTypeException $t) {
|
||||
throw $t->setMethodName($this->methodName);
|
||||
}
|
||||
|
||||
$this->given = $given;
|
||||
|
||||
$message = $this->formatMessage();
|
||||
}
|
||||
} catch (Throwable $exception) {
|
||||
}
|
||||
|
||||
parent::__construct($message, $code, $previous);
|
||||
|
||||
if ($exception) {
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
$this->isInstantiating = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see static::__construct()
|
||||
* @noinspection PhpUnhandledExceptionInspection
|
||||
* @noinspection PhpDocMissingThrowsInspection
|
||||
*/
|
||||
public static function newInstance($parameterOrMessage, $valid = null, $given = null, $code = null, $previous = null): self
|
||||
{
|
||||
return new static($parameterOrMessage, $valid, $given, $code, $previous);
|
||||
}
|
||||
|
||||
protected function formatPrologue(): string
|
||||
{
|
||||
$int = filter_var($this->parameter, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
||||
|
||||
if ($int === null) {
|
||||
return $this->parameter === null
|
||||
? 'Unknown argument'
|
||||
: "Argument \$" . ltrim($this->parameter, '$');
|
||||
}
|
||||
|
||||
return 'Argument #' . $int;
|
||||
}
|
||||
|
||||
protected function formatValid(): string
|
||||
{
|
||||
return (count($this->valid) > 1
|
||||
? 'one of '
|
||||
: '') . implode(', ', $this->valid);
|
||||
}
|
||||
|
||||
protected function formatGiven(): string
|
||||
{
|
||||
$given = $this->given ?? 'NULL';
|
||||
|
||||
/**
|
||||
* @noinspection PhpLoopNeverIteratesInspection
|
||||
* @noinspection LoopWhichDoesNotLoopInspection
|
||||
*/
|
||||
while (empty($given)) {
|
||||
if ($given === '') {
|
||||
$given = 'empty string';
|
||||
break;
|
||||
}
|
||||
|
||||
if ($given === '0') {
|
||||
$given = "'0'";
|
||||
break;
|
||||
}
|
||||
|
||||
if ($given === []) {
|
||||
$given = '[]';
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!is_string($given)) {
|
||||
try {
|
||||
$given = json_encode($given, JSON_THROW_ON_ERROR);
|
||||
} catch (\JsonException $e) {
|
||||
$given = serialize($given);
|
||||
}
|
||||
}
|
||||
|
||||
return $given;
|
||||
}
|
||||
|
||||
public function formatMessage(): string
|
||||
{
|
||||
return sprintf(
|
||||
'%s passed to %s must be %s%s - %s given.',
|
||||
$this->formatPrologue(),
|
||||
$this->methodName,
|
||||
$this->formatValid(),
|
||||
$this->getSuffix(),
|
||||
$this->formatGiven(),
|
||||
);
|
||||
}
|
||||
|
||||
protected function updateMessage(): self
|
||||
{
|
||||
if ($this->isInstantiating) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->message = $this->formatMessage();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getGiven()
|
||||
{
|
||||
return $this->given;
|
||||
}
|
||||
|
||||
public function getMethodName(): string
|
||||
{
|
||||
return $this->methodName;
|
||||
}
|
||||
|
||||
public function setMethodName(string $methodName): self
|
||||
{
|
||||
$this->methodName = $methodName;
|
||||
|
||||
return $this->updateMessage();
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
if (method_exists(parent::class, 'getName')) {
|
||||
return parent::getName() . " value";
|
||||
}
|
||||
|
||||
return 'Invalid value';
|
||||
}
|
||||
|
||||
public function getParameter(): ?string
|
||||
{
|
||||
return $this->parameter;
|
||||
}
|
||||
|
||||
public function setParameter(?string $parameter): InvalidArgumentExceptionTrait
|
||||
{
|
||||
$this->parameter = $parameter;
|
||||
|
||||
return $this->updateMessage();
|
||||
}
|
||||
|
||||
public function getSuffix(): string
|
||||
{
|
||||
return $this->suffix;
|
||||
}
|
||||
|
||||
public function setSuffix(string $suffix): self
|
||||
{
|
||||
$this->suffix = $suffix;
|
||||
|
||||
return $this->updateMessage();
|
||||
}
|
||||
|
||||
public function getValid(): array
|
||||
{
|
||||
return $this->valid;
|
||||
}
|
||||
|
||||
public function setValid($valid): self
|
||||
{
|
||||
if (is_string($valid)) {
|
||||
$this->valid = [$valid];
|
||||
return $this;
|
||||
}
|
||||
|
||||
if (is_iterable($valid)) {
|
||||
foreach ($valid as $key => $value) {
|
||||
try {
|
||||
$this->valid[] = (string)($value ?? 'NULL');
|
||||
} catch (\Error $t) {
|
||||
throw new InvalidArgumentTypeException(sprintf("\$valid[%s]", $key), ['string'], $value, 0, $this);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
throw new InvalidArgumentTypeException('$valid', ['string', 'string[]'], $valid, 0, $this);
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
/*
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2023 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
@ -8,28 +8,41 @@
|
||||
|
||||
namespace humhub\exceptions;
|
||||
|
||||
use yii\base\InvalidArgumentException;
|
||||
use yii\base\InvalidArgumentException as BaseInvalidArgumentException;
|
||||
|
||||
/**
|
||||
* @since 1.15
|
||||
*/
|
||||
class InvalidArgumentTypeException extends InvalidArgumentException
|
||||
class InvalidArgumentTypeException extends BaseInvalidArgumentException
|
||||
{
|
||||
use InvalidTypeExceptionTrait;
|
||||
use InvalidArgumentExceptionTrait {
|
||||
getName as protected InvalidArgumentExceptionTrait_getName;
|
||||
formatGiven as protected InvalidArgumentExceptionTrait_formatGiven;
|
||||
formatValid as protected InvalidArgumentExceptionTrait_formatValid;
|
||||
}
|
||||
|
||||
protected function formatPrologue(array $constructArguments): string
|
||||
protected function formatValid(): string
|
||||
{
|
||||
$argumentName = is_array($this->parameter)
|
||||
? reset($this->parameter)
|
||||
: null;
|
||||
$argumentNumber = is_array($this->parameter)
|
||||
? key($this->parameter)
|
||||
: $this->parameter;
|
||||
if (empty($this->valid)) {
|
||||
$this->valid = ['mixed'];
|
||||
}
|
||||
|
||||
$argumentName = $argumentName === null
|
||||
? ''
|
||||
: " \$" . ltrim($argumentName, '$');
|
||||
return (count($this->valid) > 1
|
||||
? 'one of the following types: '
|
||||
: 'of type ') . implode(', ', $this->valid);
|
||||
}
|
||||
|
||||
return sprintf('Argument #%d%s', $argumentNumber, $argumentName);
|
||||
protected function formatGiven(): string
|
||||
{
|
||||
return $this->given === null ? 'NULL' : get_debug_type($this->given);
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
if (method_exists(parent::class, 'getName')) {
|
||||
return $this->InvalidArgumentExceptionTrait_getName() . " Type";
|
||||
}
|
||||
|
||||
return 'Invalid Type';
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2023 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\exceptions;
|
||||
|
||||
use yii\base\InvalidArgumentException as BaseInvalidArgumentException;
|
||||
|
||||
/**
|
||||
* @since 1.15
|
||||
*/
|
||||
class InvalidArgumentValueException extends BaseInvalidArgumentException
|
||||
{
|
||||
use InvalidArgumentExceptionTrait;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
/*
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2023 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
@ -15,10 +15,35 @@ use yii\base\InvalidConfigException;
|
||||
*/
|
||||
class InvalidConfigTypeException extends InvalidConfigException
|
||||
{
|
||||
use InvalidTypeExceptionTrait;
|
||||
use InvalidArgumentExceptionTrait;
|
||||
|
||||
protected function formatPrologue(array $constructArguments): string
|
||||
protected function formatPrologue(): string
|
||||
{
|
||||
return "Parameter $this->parameter of configuration";
|
||||
return "Parameter '$this->parameter' of configuration";
|
||||
}
|
||||
|
||||
protected function formatValid(): string
|
||||
{
|
||||
if (empty($this->valid)) {
|
||||
$this->valid = ['mixed'];
|
||||
}
|
||||
|
||||
return (count($this->valid) > 1
|
||||
? 'one of the following type '
|
||||
: 'of type ') . implode(', ', $this->valid);
|
||||
}
|
||||
|
||||
protected function formatGiven(): string
|
||||
{
|
||||
return get_debug_type($this->given);
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
if (method_exists(parent::class, 'getName')) {
|
||||
return parent::getName() . " Type";
|
||||
}
|
||||
|
||||
return 'Invalid Type';
|
||||
}
|
||||
}
|
||||
|
@ -1,75 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2023 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\exceptions;
|
||||
|
||||
/**
|
||||
* @since 1.15
|
||||
*/
|
||||
trait InvalidTypeExceptionTrait
|
||||
{
|
||||
// public properties
|
||||
|
||||
public string $methodName;
|
||||
public $parameter;
|
||||
public array $validType = [];
|
||||
|
||||
/**
|
||||
* @var mixed|null
|
||||
*/
|
||||
public $givenValue;
|
||||
|
||||
/**
|
||||
* @param string $method
|
||||
* @param int|array $parameter = [
|
||||
* int => string, // position, or [ position => name ] of the argument
|
||||
* ]
|
||||
* @param array|string|null $validType
|
||||
* @param null $givenValue
|
||||
*/
|
||||
public function __construct(
|
||||
$method = '',
|
||||
$parameter = null,
|
||||
$validType = [],
|
||||
$givenValue = null,
|
||||
$nullable = false,
|
||||
$code = 0,
|
||||
$previous = null
|
||||
) {
|
||||
|
||||
$this->methodName = $method;
|
||||
$this->parameter = $parameter;
|
||||
$this->validType = (array)($validType ?? ['mixed']);
|
||||
$this->givenValue = $givenValue;
|
||||
|
||||
if ($nullable && !in_array('null', $this->validType, true)) {
|
||||
$this->validType[] = 'null';
|
||||
}
|
||||
|
||||
$message = sprintf(
|
||||
'%s passed to %s must be of type %s, %s given.',
|
||||
$this->formatPrologue(func_get_args()),
|
||||
$this->methodName,
|
||||
implode(', ', $this->validType),
|
||||
get_debug_type($this->givenValue)
|
||||
);
|
||||
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
abstract protected function formatPrologue(array $constructArguments): string;
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
if (method_exists(parent::class, 'getName')) {
|
||||
return parent::getName() . " Type";
|
||||
}
|
||||
|
||||
return 'Invalid Type';
|
||||
}
|
||||
}
|
@ -286,8 +286,7 @@ abstract class BaseSettingsManager extends Component
|
||||
}
|
||||
} elseif (!is_array($prefix)) {
|
||||
throw new InvalidArgumentTypeException(
|
||||
__METHOD__,
|
||||
[1 => '$prefix'],
|
||||
'$prefix',
|
||||
['string', 'int', 'null', \Stringable::class],
|
||||
$prefix
|
||||
);
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
/*
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
@ -8,8 +8,8 @@
|
||||
|
||||
namespace humhub\libs;
|
||||
|
||||
use humhub\exceptions\InvalidArgumentValueException;
|
||||
use Yii;
|
||||
use yii\base\InvalidArgumentException;
|
||||
use yii\base\Exception;
|
||||
|
||||
/**
|
||||
@ -19,7 +19,6 @@ use yii\base\Exception;
|
||||
*/
|
||||
class Helpers
|
||||
{
|
||||
|
||||
/**
|
||||
* Shorten a text string
|
||||
*
|
||||
@ -138,8 +137,9 @@ class Helpers
|
||||
* Source: http://php.net/manual/en/function.ini-get.php#96996
|
||||
*
|
||||
* @param string $valueString
|
||||
*
|
||||
* @return int bytes
|
||||
* @throws InvalidParamException
|
||||
* @throws InvalidArgumentValueException
|
||||
*/
|
||||
public static function getBytesOfIniValue($valueString)
|
||||
{
|
||||
@ -148,7 +148,7 @@ class Helpers
|
||||
}
|
||||
|
||||
if ($valueString === false) {
|
||||
throw new InvalidArgumentException('Your configuration option of ini_get function does not exist.');
|
||||
throw new InvalidArgumentValueException('Your configuration option of ini_get function does not exist.');
|
||||
}
|
||||
|
||||
switch (substr($valueString, -1)) {
|
||||
@ -263,5 +263,4 @@ class Helpers
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\tests\codeception\unit\exceptions;
|
||||
|
||||
use Codeception\Test\Unit;
|
||||
use humhub\exceptions\InvalidArgumentTypeException;
|
||||
use humhub\exceptions\InvalidArgumentValueException;
|
||||
use yii\base\BaseObject;
|
||||
|
||||
/**
|
||||
* Class MimeHelperTest
|
||||
*/
|
||||
class InvalidArgumentExceptionTest extends Unit
|
||||
{
|
||||
public function testInvalidArgumentValueExceptionMessageCase1()
|
||||
{
|
||||
$message = 'Hello World';
|
||||
|
||||
$this->expectException(InvalidArgumentValueException::class);
|
||||
$this->expectExceptionMessage($message);
|
||||
$this->expectExceptionCode(0);
|
||||
|
||||
throw new InvalidArgumentValueException($message);
|
||||
}
|
||||
|
||||
public function testInvalidArgumentValueExceptionMessageCase2()
|
||||
{
|
||||
$message = 'Hello World';
|
||||
|
||||
$this->expectException(InvalidArgumentValueException::class);
|
||||
$this->expectExceptionMessage($message);
|
||||
$this->expectExceptionCode(1);
|
||||
|
||||
throw new InvalidArgumentValueException($message, 1);
|
||||
}
|
||||
|
||||
public function testInvalidArgumentValueExceptionParameterCase1()
|
||||
{
|
||||
$message = 'Argument $parameter passed to ' . __METHOD__ . ' must be bool - 3 given.';
|
||||
|
||||
$this->expectException(InvalidArgumentValueException::class);
|
||||
$this->expectExceptionMessage($message);
|
||||
$this->expectExceptionCode(0);
|
||||
|
||||
throw new InvalidArgumentValueException('parameter', 'bool', 3);
|
||||
}
|
||||
|
||||
public function testInvalidArgumentValueExceptionParameterCase2()
|
||||
{
|
||||
$message = 'Argument $parameter passed to ' . __METHOD__ . ' must be bool - NULL given.';
|
||||
|
||||
$this->expectException(InvalidArgumentValueException::class);
|
||||
$this->expectExceptionMessage($message);
|
||||
$this->expectExceptionCode(0);
|
||||
|
||||
throw new InvalidArgumentValueException('parameter', 'bool');
|
||||
}
|
||||
|
||||
public function testInvalidArgumentValueExceptionParameterCase3()
|
||||
{
|
||||
$message = 'Argument $parameter passed to ' . __METHOD__ . ' must be one of bool, NULL - 2 given.';
|
||||
|
||||
$this->expectException(InvalidArgumentValueException::class);
|
||||
$this->expectExceptionMessage($message);
|
||||
$this->expectExceptionCode(0);
|
||||
|
||||
throw new InvalidArgumentValueException('parameter', ['bool', null], 2);
|
||||
}
|
||||
|
||||
public function testInvalidArgumentValueExceptionParameterCase4()
|
||||
{
|
||||
$message = 'Argument $valid passed to ' . __METHOD__ . ' must be one of the following types: string, string[] - NULL given.';
|
||||
|
||||
$this->expectException(InvalidArgumentTypeException::class);
|
||||
$this->expectExceptionMessage($message);
|
||||
$this->expectExceptionCode(0);
|
||||
|
||||
throw new InvalidArgumentValueException('parameter');
|
||||
}
|
||||
|
||||
public function testInvalidArgumentValueExceptionParameterCase5()
|
||||
{
|
||||
$message = 'Argument $valid[1] passed to ' . __METHOD__ . ' must be of type string - yii\base\BaseObject given.';
|
||||
|
||||
$this->expectException(InvalidArgumentTypeException::class);
|
||||
$this->expectExceptionMessage($message);
|
||||
$this->expectExceptionCode(0);
|
||||
|
||||
throw new InvalidArgumentValueException('parameter', ['bool', new BaseObject()]);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user