first commit
This commit is contained in:
81
vendor/spatie/backtrace/src/Arguments/ArgumentReducers.php
vendored
Normal file
81
vendor/spatie/backtrace/src/Arguments/ArgumentReducers.php
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace\Arguments;
|
||||
|
||||
use Spatie\Backtrace\Arguments\Reducers\ArgumentReducer;
|
||||
use Spatie\Backtrace\Arguments\Reducers\ArrayArgumentReducer;
|
||||
use Spatie\Backtrace\Arguments\Reducers\BaseTypeArgumentReducer;
|
||||
use Spatie\Backtrace\Arguments\Reducers\ClosureArgumentReducer;
|
||||
use Spatie\Backtrace\Arguments\Reducers\DateTimeArgumentReducer;
|
||||
use Spatie\Backtrace\Arguments\Reducers\DateTimeZoneArgumentReducer;
|
||||
use Spatie\Backtrace\Arguments\Reducers\EnumArgumentReducer;
|
||||
use Spatie\Backtrace\Arguments\Reducers\MinimalArrayArgumentReducer;
|
||||
use Spatie\Backtrace\Arguments\Reducers\SensitiveParameterArrayReducer;
|
||||
use Spatie\Backtrace\Arguments\Reducers\StdClassArgumentReducer;
|
||||
use Spatie\Backtrace\Arguments\Reducers\StringableArgumentReducer;
|
||||
use Spatie\Backtrace\Arguments\Reducers\SymphonyRequestArgumentReducer;
|
||||
|
||||
class ArgumentReducers
|
||||
{
|
||||
/** @var array<int, ArgumentReducer> */
|
||||
public $argumentReducers = [];
|
||||
|
||||
/**
|
||||
* @param array<ArgumentReducer|class-string<ArgumentReducer>> $argumentReducers
|
||||
*/
|
||||
public static function create(array $argumentReducers): self
|
||||
{
|
||||
return new self(array_map(
|
||||
function ($argumentReducer) {
|
||||
/** @var $argumentReducer ArgumentReducer|class-string<ArgumentReducer> */
|
||||
return $argumentReducer instanceof ArgumentReducer ? $argumentReducer : new $argumentReducer();
|
||||
},
|
||||
$argumentReducers
|
||||
));
|
||||
}
|
||||
|
||||
public static function default(array $extra = []): self
|
||||
{
|
||||
return new self(static::defaultReducers($extra));
|
||||
}
|
||||
|
||||
public static function minimal(array $extra = []): self
|
||||
{
|
||||
return new self(static::minimalReducers($extra));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, ArgumentReducer> $argumentReducers
|
||||
*/
|
||||
protected function __construct(array $argumentReducers)
|
||||
{
|
||||
$this->argumentReducers = $argumentReducers;
|
||||
}
|
||||
|
||||
protected static function defaultReducers(array $extra = []): array
|
||||
{
|
||||
return array_merge($extra, [
|
||||
new BaseTypeArgumentReducer(),
|
||||
new ArrayArgumentReducer(),
|
||||
new StdClassArgumentReducer(),
|
||||
new EnumArgumentReducer(),
|
||||
new ClosureArgumentReducer(),
|
||||
new SensitiveParameterArrayReducer(),
|
||||
new DateTimeArgumentReducer(),
|
||||
new DateTimeZoneArgumentReducer(),
|
||||
new SymphonyRequestArgumentReducer(),
|
||||
new StringableArgumentReducer(),
|
||||
]);
|
||||
}
|
||||
|
||||
protected static function minimalReducers(array $extra = []): array
|
||||
{
|
||||
return array_merge($extra, [
|
||||
new BaseTypeArgumentReducer(),
|
||||
new MinimalArrayArgumentReducer(),
|
||||
new EnumArgumentReducer(),
|
||||
new ClosureArgumentReducer(),
|
||||
new SensitiveParameterArrayReducer(),
|
||||
]);
|
||||
}
|
||||
}
|
118
vendor/spatie/backtrace/src/Arguments/ProvidedArgument.php
vendored
Normal file
118
vendor/spatie/backtrace/src/Arguments/ProvidedArgument.php
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace\Arguments;
|
||||
|
||||
use ReflectionParameter;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgument;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\TruncatedReducedArgument;
|
||||
|
||||
class ProvidedArgument
|
||||
{
|
||||
/** @var string */
|
||||
public $name;
|
||||
|
||||
/** @var bool */
|
||||
public $passedByReference = false;
|
||||
|
||||
/** @var bool */
|
||||
public $isVariadic = false;
|
||||
|
||||
/** @var bool */
|
||||
public $hasDefaultValue = false;
|
||||
|
||||
/** @var mixed */
|
||||
public $defaultValue = null;
|
||||
|
||||
/** @var bool */
|
||||
public $defaultValueUsed = false;
|
||||
|
||||
/** @var bool */
|
||||
public $truncated = false;
|
||||
|
||||
/** @var mixed */
|
||||
public $reducedValue = null;
|
||||
|
||||
/** @var string|null */
|
||||
public $originalType = null;
|
||||
|
||||
public static function fromReflectionParameter(ReflectionParameter $parameter): self
|
||||
{
|
||||
return new self(
|
||||
$parameter->getName(),
|
||||
$parameter->isPassedByReference(),
|
||||
$parameter->isVariadic(),
|
||||
$parameter->isDefaultValueAvailable(),
|
||||
$parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null,
|
||||
);
|
||||
}
|
||||
|
||||
public static function fromNonReflectableParameter(
|
||||
int $index
|
||||
): self {
|
||||
return new self(
|
||||
"arg{$index}",
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
public function __construct(
|
||||
string $name,
|
||||
bool $passedByReference = false,
|
||||
bool $isVariadic = false,
|
||||
bool $hasDefaultValue = false,
|
||||
$defaultValue = null,
|
||||
bool $defaultValueUsed = false,
|
||||
bool $truncated = false,
|
||||
$reducedValue = null,
|
||||
?string $originalType = null
|
||||
) {
|
||||
$this->originalType = $originalType;
|
||||
$this->reducedValue = $reducedValue;
|
||||
$this->truncated = $truncated;
|
||||
$this->defaultValueUsed = $defaultValueUsed;
|
||||
$this->defaultValue = $defaultValue;
|
||||
$this->hasDefaultValue = $hasDefaultValue;
|
||||
$this->isVariadic = $isVariadic;
|
||||
$this->passedByReference = $passedByReference;
|
||||
$this->name = $name;
|
||||
|
||||
if ($this->isVariadic) {
|
||||
$this->defaultValue = [];
|
||||
}
|
||||
}
|
||||
|
||||
public function setReducedArgument(
|
||||
ReducedArgument $reducedArgument
|
||||
): self {
|
||||
$this->reducedValue = $reducedArgument->value;
|
||||
$this->originalType = $reducedArgument->originalType;
|
||||
|
||||
if ($reducedArgument instanceof TruncatedReducedArgument) {
|
||||
$this->truncated = true;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function defaultValueUsed(): self
|
||||
{
|
||||
$this->defaultValueUsed = true;
|
||||
$this->originalType = get_debug_type($this->defaultValue);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'name' => $this->name,
|
||||
'value' => $this->defaultValueUsed
|
||||
? $this->defaultValue
|
||||
: $this->reducedValue,
|
||||
'original_type' => $this->originalType,
|
||||
'passed_by_reference' => $this->passedByReference,
|
||||
'is_variadic' => $this->isVariadic,
|
||||
'truncated' => $this->truncated,
|
||||
];
|
||||
}
|
||||
}
|
44
vendor/spatie/backtrace/src/Arguments/ReduceArgumentPayloadAction.php
vendored
Normal file
44
vendor/spatie/backtrace/src/Arguments/ReduceArgumentPayloadAction.php
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace\Arguments;
|
||||
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgument;
|
||||
|
||||
class ReduceArgumentPayloadAction
|
||||
{
|
||||
/** @var \Spatie\Backtrace\Arguments\ArgumentReducers */
|
||||
protected $argumentReducers;
|
||||
|
||||
public function __construct(
|
||||
ArgumentReducers $argumentReducers
|
||||
) {
|
||||
$this->argumentReducers = $argumentReducers;
|
||||
}
|
||||
|
||||
public function reduce($argument, bool $includeObjectType = false): ReducedArgument
|
||||
{
|
||||
foreach ($this->argumentReducers->argumentReducers as $reducer) {
|
||||
$reduced = $reducer->execute($argument);
|
||||
|
||||
if ($reduced instanceof ReducedArgument) {
|
||||
return $reduced;
|
||||
}
|
||||
}
|
||||
|
||||
if (gettype($argument) === 'object' && $includeObjectType) {
|
||||
return new ReducedArgument(
|
||||
'object ('.get_class($argument).')',
|
||||
get_debug_type($argument),
|
||||
);
|
||||
}
|
||||
|
||||
if (gettype($argument) === 'object') {
|
||||
return new ReducedArgument('object', get_debug_type($argument), );
|
||||
}
|
||||
|
||||
return new ReducedArgument(
|
||||
$argument,
|
||||
get_debug_type($argument),
|
||||
);
|
||||
}
|
||||
}
|
117
vendor/spatie/backtrace/src/Arguments/ReduceArgumentsAction.php
vendored
Normal file
117
vendor/spatie/backtrace/src/Arguments/ReduceArgumentsAction.php
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace\Arguments;
|
||||
|
||||
use ReflectionException;
|
||||
use ReflectionFunction;
|
||||
use ReflectionMethod;
|
||||
use ReflectionParameter;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\VariadicReducedArgument;
|
||||
use Throwable;
|
||||
|
||||
class ReduceArgumentsAction
|
||||
{
|
||||
/** @var ArgumentReducers */
|
||||
protected $argumentReducers;
|
||||
|
||||
/** @var ReduceArgumentPayloadAction */
|
||||
protected $reduceArgumentPayloadAction;
|
||||
|
||||
public function __construct(
|
||||
ArgumentReducers $argumentReducers
|
||||
) {
|
||||
$this->argumentReducers = $argumentReducers;
|
||||
$this->reduceArgumentPayloadAction = new ReduceArgumentPayloadAction($argumentReducers);
|
||||
}
|
||||
|
||||
public function execute(
|
||||
?string $class,
|
||||
?string $method,
|
||||
?array $frameArguments
|
||||
): ?array {
|
||||
try {
|
||||
if ($frameArguments === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$parameters = $this->getParameters($class, $method);
|
||||
|
||||
if ($parameters === null) {
|
||||
$arguments = [];
|
||||
|
||||
foreach ($frameArguments as $index => $argument) {
|
||||
$arguments[$index] = ProvidedArgument::fromNonReflectableParameter($index)
|
||||
->setReducedArgument($this->reduceArgumentPayloadAction->reduce($argument))
|
||||
->toArray();
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
$arguments = array_map(
|
||||
function ($argument) {
|
||||
return $this->reduceArgumentPayloadAction->reduce($argument);
|
||||
},
|
||||
$frameArguments,
|
||||
);
|
||||
|
||||
$argumentsCount = count($arguments);
|
||||
$hasVariadicParameter = false;
|
||||
|
||||
foreach ($parameters as $index => $parameter) {
|
||||
if ($index + 1 > $argumentsCount) {
|
||||
$parameter->defaultValueUsed();
|
||||
} elseif ($parameter->isVariadic) {
|
||||
$parameter->setReducedArgument(new VariadicReducedArgument(array_slice($arguments, $index)));
|
||||
|
||||
$hasVariadicParameter = true;
|
||||
} else {
|
||||
$parameter->setReducedArgument($arguments[$index]);
|
||||
}
|
||||
|
||||
$parameters[$index] = $parameter->toArray();
|
||||
}
|
||||
|
||||
if ($this->moreArgumentsProvidedThanParameters($arguments, $parameters, $hasVariadicParameter)) {
|
||||
for ($i = count($parameters); $i < count($arguments); $i++) {
|
||||
$parameters[$i] = ProvidedArgument::fromNonReflectableParameter(count($parameters))
|
||||
->setReducedArgument($arguments[$i])
|
||||
->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
return $parameters;
|
||||
} catch (Throwable $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** @return null|Array<\Spatie\Backtrace\Arguments\ProvidedArgument> */
|
||||
protected function getParameters(
|
||||
?string $class,
|
||||
?string $method
|
||||
): ?array {
|
||||
try {
|
||||
$reflection = $class !== null
|
||||
? new ReflectionMethod($class, $method)
|
||||
: new ReflectionFunction($method);
|
||||
} catch (ReflectionException $e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return array_map(
|
||||
function (ReflectionParameter $reflectionParameter) {
|
||||
return ProvidedArgument::fromReflectionParameter($reflectionParameter);
|
||||
},
|
||||
$reflection->getParameters(),
|
||||
);
|
||||
}
|
||||
|
||||
protected function moreArgumentsProvidedThanParameters(
|
||||
array $arguments,
|
||||
array $parameters,
|
||||
bool $hasVariadicParameter
|
||||
): bool {
|
||||
return count($arguments) > count($parameters) && ! $hasVariadicParameter;
|
||||
}
|
||||
}
|
23
vendor/spatie/backtrace/src/Arguments/ReducedArgument/ReducedArgument.php
vendored
Normal file
23
vendor/spatie/backtrace/src/Arguments/ReducedArgument/ReducedArgument.php
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace\Arguments\ReducedArgument;
|
||||
|
||||
class ReducedArgument implements ReducedArgumentContract
|
||||
{
|
||||
/** @var mixed */
|
||||
public $value;
|
||||
|
||||
/** @var string */
|
||||
public $originalType;
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __construct(
|
||||
$value,
|
||||
string $originalType
|
||||
) {
|
||||
$this->originalType = $originalType;
|
||||
$this->value = $value;
|
||||
}
|
||||
}
|
8
vendor/spatie/backtrace/src/Arguments/ReducedArgument/ReducedArgumentContract.php
vendored
Normal file
8
vendor/spatie/backtrace/src/Arguments/ReducedArgument/ReducedArgumentContract.php
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace\Arguments\ReducedArgument;
|
||||
|
||||
interface ReducedArgumentContract
|
||||
{
|
||||
|
||||
}
|
8
vendor/spatie/backtrace/src/Arguments/ReducedArgument/TruncatedReducedArgument.php
vendored
Normal file
8
vendor/spatie/backtrace/src/Arguments/ReducedArgument/TruncatedReducedArgument.php
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace\Arguments\ReducedArgument;
|
||||
|
||||
class TruncatedReducedArgument extends ReducedArgument
|
||||
{
|
||||
|
||||
}
|
22
vendor/spatie/backtrace/src/Arguments/ReducedArgument/UnReducedArgument.php
vendored
Normal file
22
vendor/spatie/backtrace/src/Arguments/ReducedArgument/UnReducedArgument.php
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace\Arguments\ReducedArgument;
|
||||
|
||||
class UnReducedArgument implements ReducedArgumentContract
|
||||
{
|
||||
/** @var self|null */
|
||||
private static $instance = null;
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public static function create(): self
|
||||
{
|
||||
if (self::$instance !== null) {
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
return self::$instance = new self();
|
||||
}
|
||||
}
|
21
vendor/spatie/backtrace/src/Arguments/ReducedArgument/VariadicReducedArgument.php
vendored
Normal file
21
vendor/spatie/backtrace/src/Arguments/ReducedArgument/VariadicReducedArgument.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace\Arguments\ReducedArgument;
|
||||
|
||||
use Exception;
|
||||
|
||||
class VariadicReducedArgument extends ReducedArgument
|
||||
{
|
||||
public function __construct(array $value)
|
||||
{
|
||||
foreach ($value as $key => $item) {
|
||||
if (! $item instanceof ReducedArgument) {
|
||||
throw new Exception('VariadicReducedArgument must be an array of ReducedArgument');
|
||||
}
|
||||
|
||||
$value[$key] = $item->value;
|
||||
}
|
||||
|
||||
parent::__construct($value, 'array');
|
||||
}
|
||||
}
|
13
vendor/spatie/backtrace/src/Arguments/Reducers/ArgumentReducer.php
vendored
Normal file
13
vendor/spatie/backtrace/src/Arguments/Reducers/ArgumentReducer.php
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace\Arguments\Reducers;
|
||||
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgumentContract;
|
||||
|
||||
interface ArgumentReducer
|
||||
{
|
||||
/**
|
||||
* @param mixed $argument
|
||||
*/
|
||||
public function execute($argument): ReducedArgumentContract;
|
||||
}
|
52
vendor/spatie/backtrace/src/Arguments/Reducers/ArrayArgumentReducer.php
vendored
Normal file
52
vendor/spatie/backtrace/src/Arguments/Reducers/ArrayArgumentReducer.php
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace\Arguments\Reducers;
|
||||
|
||||
use Spatie\Backtrace\Arguments\ArgumentReducers;
|
||||
use Spatie\Backtrace\Arguments\ReduceArgumentPayloadAction;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgument;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgumentContract;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\TruncatedReducedArgument;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\UnReducedArgument;
|
||||
|
||||
class ArrayArgumentReducer implements ReducedArgumentContract
|
||||
{
|
||||
/** @var int */
|
||||
protected $maxArraySize = 25;
|
||||
|
||||
/** @var \Spatie\Backtrace\Arguments\ReduceArgumentPayloadAction */
|
||||
protected $reduceArgumentPayloadAction;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->reduceArgumentPayloadAction = new ReduceArgumentPayloadAction(ArgumentReducers::minimal());
|
||||
}
|
||||
|
||||
public function execute($argument): ReducedArgumentContract
|
||||
{
|
||||
if (! is_array($argument)) {
|
||||
return UnReducedArgument::create();
|
||||
}
|
||||
|
||||
return $this->reduceArgument($argument, 'array');
|
||||
}
|
||||
|
||||
protected function reduceArgument(array $argument, string $originalType): ReducedArgumentContract
|
||||
{
|
||||
foreach ($argument as $key => $value) {
|
||||
$argument[$key] = $this->reduceArgumentPayloadAction->reduce(
|
||||
$value,
|
||||
true
|
||||
)->value;
|
||||
}
|
||||
|
||||
if (count($argument) > $this->maxArraySize) {
|
||||
return new TruncatedReducedArgument(
|
||||
array_slice($argument, 0, $this->maxArraySize),
|
||||
'array'
|
||||
);
|
||||
}
|
||||
|
||||
return new ReducedArgument($argument, $originalType);
|
||||
}
|
||||
}
|
24
vendor/spatie/backtrace/src/Arguments/Reducers/BaseTypeArgumentReducer.php
vendored
Normal file
24
vendor/spatie/backtrace/src/Arguments/Reducers/BaseTypeArgumentReducer.php
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace\Arguments\Reducers;
|
||||
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgument;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgumentContract;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\UnReducedArgument;
|
||||
|
||||
class BaseTypeArgumentReducer implements ArgumentReducer
|
||||
{
|
||||
public function execute($argument): ReducedArgumentContract
|
||||
{
|
||||
if (is_int($argument)
|
||||
|| is_float($argument)
|
||||
|| is_bool($argument)
|
||||
|| is_string($argument)
|
||||
|| $argument === null
|
||||
) {
|
||||
return new ReducedArgument($argument, get_debug_type($argument));
|
||||
}
|
||||
|
||||
return UnReducedArgument::create();
|
||||
}
|
||||
}
|
30
vendor/spatie/backtrace/src/Arguments/Reducers/ClosureArgumentReducer.php
vendored
Normal file
30
vendor/spatie/backtrace/src/Arguments/Reducers/ClosureArgumentReducer.php
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace\Arguments\Reducers;
|
||||
|
||||
use Closure;
|
||||
use ReflectionFunction;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgument;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgumentContract;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\UnReducedArgument;
|
||||
|
||||
class ClosureArgumentReducer implements ArgumentReducer
|
||||
{
|
||||
public function execute($argument): ReducedArgumentContract
|
||||
{
|
||||
if (! $argument instanceof Closure) {
|
||||
return UnReducedArgument::create();
|
||||
}
|
||||
|
||||
$reflection = new ReflectionFunction($argument);
|
||||
|
||||
if ($reflection->getFileName() && $reflection->getStartLine() && $reflection->getEndLine()) {
|
||||
return new ReducedArgument(
|
||||
"{$reflection->getFileName()}:{$reflection->getStartLine()}-{$reflection->getEndLine()}",
|
||||
'Closure'
|
||||
);
|
||||
}
|
||||
|
||||
return new ReducedArgument("{$reflection->getFileName()}", 'Closure');
|
||||
}
|
||||
}
|
23
vendor/spatie/backtrace/src/Arguments/Reducers/DateTimeArgumentReducer.php
vendored
Normal file
23
vendor/spatie/backtrace/src/Arguments/Reducers/DateTimeArgumentReducer.php
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace\Arguments\Reducers;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgument;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgumentContract;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\UnReducedArgument;
|
||||
|
||||
class DateTimeArgumentReducer implements ArgumentReducer
|
||||
{
|
||||
public function execute($argument): ReducedArgumentContract
|
||||
{
|
||||
if (! $argument instanceof DateTimeInterface) {
|
||||
return UnReducedArgument::create();
|
||||
}
|
||||
|
||||
return new ReducedArgument(
|
||||
$argument->format('d M Y H:i:s e'),
|
||||
get_class($argument),
|
||||
);
|
||||
}
|
||||
}
|
23
vendor/spatie/backtrace/src/Arguments/Reducers/DateTimeZoneArgumentReducer.php
vendored
Normal file
23
vendor/spatie/backtrace/src/Arguments/Reducers/DateTimeZoneArgumentReducer.php
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace\Arguments\Reducers;
|
||||
|
||||
use DateTimeZone;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgument;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgumentContract;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\UnReducedArgument;
|
||||
|
||||
class DateTimeZoneArgumentReducer implements ArgumentReducer
|
||||
{
|
||||
public function execute($argument): ReducedArgumentContract
|
||||
{
|
||||
if (! $argument instanceof DateTimeZone) {
|
||||
return UnReducedArgument::create();
|
||||
}
|
||||
|
||||
return new ReducedArgument(
|
||||
$argument->getName(),
|
||||
get_class($argument),
|
||||
);
|
||||
}
|
||||
}
|
23
vendor/spatie/backtrace/src/Arguments/Reducers/EnumArgumentReducer.php
vendored
Normal file
23
vendor/spatie/backtrace/src/Arguments/Reducers/EnumArgumentReducer.php
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace\Arguments\Reducers;
|
||||
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgument;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgumentContract;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\UnReducedArgument;
|
||||
use UnitEnum;
|
||||
|
||||
class EnumArgumentReducer implements ArgumentReducer
|
||||
{
|
||||
public function execute($argument): ReducedArgumentContract
|
||||
{
|
||||
if (! $argument instanceof UnitEnum) {
|
||||
return UnReducedArgument::create();
|
||||
}
|
||||
|
||||
return new ReducedArgument(
|
||||
get_class($argument).'::'.$argument->name,
|
||||
get_class($argument),
|
||||
);
|
||||
}
|
||||
}
|
22
vendor/spatie/backtrace/src/Arguments/Reducers/MinimalArrayArgumentReducer.php
vendored
Normal file
22
vendor/spatie/backtrace/src/Arguments/Reducers/MinimalArrayArgumentReducer.php
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace\Arguments\Reducers;
|
||||
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgument;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgumentContract;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\UnReducedArgument;
|
||||
|
||||
class MinimalArrayArgumentReducer implements ArgumentReducer
|
||||
{
|
||||
public function execute($argument): ReducedArgumentContract
|
||||
{
|
||||
if(! is_array($argument)) {
|
||||
return UnReducedArgument::create();
|
||||
}
|
||||
|
||||
return new ReducedArgument(
|
||||
'array (size='.count($argument).')',
|
||||
'array'
|
||||
);
|
||||
}
|
||||
}
|
23
vendor/spatie/backtrace/src/Arguments/Reducers/SensitiveParameterArrayReducer.php
vendored
Normal file
23
vendor/spatie/backtrace/src/Arguments/Reducers/SensitiveParameterArrayReducer.php
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace\Arguments\Reducers;
|
||||
|
||||
use SensitiveParameterValue;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgument;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgumentContract;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\UnReducedArgument;
|
||||
|
||||
class SensitiveParameterArrayReducer implements ArgumentReducer
|
||||
{
|
||||
public function execute($argument): ReducedArgumentContract
|
||||
{
|
||||
if (! $argument instanceof SensitiveParameterValue) {
|
||||
return UnReducedArgument::create();
|
||||
}
|
||||
|
||||
return new ReducedArgument(
|
||||
'SensitiveParameterValue('.get_debug_type($argument->getValue()).')',
|
||||
get_class($argument)
|
||||
);
|
||||
}
|
||||
}
|
19
vendor/spatie/backtrace/src/Arguments/Reducers/StdClassArgumentReducer.php
vendored
Normal file
19
vendor/spatie/backtrace/src/Arguments/Reducers/StdClassArgumentReducer.php
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace\Arguments\Reducers;
|
||||
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgumentContract;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\UnReducedArgument;
|
||||
use stdClass;
|
||||
|
||||
class StdClassArgumentReducer extends ArrayArgumentReducer
|
||||
{
|
||||
public function execute($argument): ReducedArgumentContract
|
||||
{
|
||||
if (! $argument instanceof stdClass) {
|
||||
return UnReducedArgument::create();
|
||||
}
|
||||
|
||||
return parent::reduceArgument((array) $argument, stdClass::class);
|
||||
}
|
||||
}
|
23
vendor/spatie/backtrace/src/Arguments/Reducers/StringableArgumentReducer.php
vendored
Normal file
23
vendor/spatie/backtrace/src/Arguments/Reducers/StringableArgumentReducer.php
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace\Arguments\Reducers;
|
||||
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgument;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgumentContract;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\UnReducedArgument;
|
||||
use Stringable;
|
||||
|
||||
class StringableArgumentReducer implements ArgumentReducer
|
||||
{
|
||||
public function execute($argument): ReducedArgumentContract
|
||||
{
|
||||
if (! $argument instanceof Stringable) {
|
||||
return UnReducedArgument::create();
|
||||
}
|
||||
|
||||
return new ReducedArgument(
|
||||
(string) $argument,
|
||||
get_class($argument),
|
||||
);
|
||||
}
|
||||
}
|
23
vendor/spatie/backtrace/src/Arguments/Reducers/SymphonyRequestArgumentReducer.php
vendored
Normal file
23
vendor/spatie/backtrace/src/Arguments/Reducers/SymphonyRequestArgumentReducer.php
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace\Arguments\Reducers;
|
||||
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgument;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\ReducedArgumentContract;
|
||||
use Spatie\Backtrace\Arguments\ReducedArgument\UnReducedArgument;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class SymphonyRequestArgumentReducer implements ArgumentReducer
|
||||
{
|
||||
public function execute($argument): ReducedArgumentContract
|
||||
{
|
||||
if(! $argument instanceof Request) {
|
||||
return UnReducedArgument::create();
|
||||
}
|
||||
|
||||
return new ReducedArgument(
|
||||
"{$argument->getMethod()} {$argument->getUri()}",
|
||||
get_class($argument),
|
||||
);
|
||||
}
|
||||
}
|
271
vendor/spatie/backtrace/src/Backtrace.php
vendored
Normal file
271
vendor/spatie/backtrace/src/Backtrace.php
vendored
Normal file
@ -0,0 +1,271 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace;
|
||||
|
||||
use Closure;
|
||||
use Spatie\Backtrace\Arguments\ArgumentReducers;
|
||||
use Spatie\Backtrace\Arguments\ReduceArgumentsAction;
|
||||
use Spatie\Backtrace\Arguments\Reducers\ArgumentReducer;
|
||||
use Throwable;
|
||||
|
||||
class Backtrace
|
||||
{
|
||||
/** @var bool */
|
||||
protected $withArguments = false;
|
||||
|
||||
/** @var bool */
|
||||
protected $reduceArguments = false;
|
||||
|
||||
/** @var array<class-string<ArgumentReducer>|ArgumentReducer>|ArgumentReducers|null */
|
||||
protected $argumentReducers = null;
|
||||
|
||||
/** @var bool */
|
||||
protected $withObject = false;
|
||||
|
||||
/** @var string|null */
|
||||
protected $applicationPath;
|
||||
|
||||
/** @var int */
|
||||
protected $offset = 0;
|
||||
|
||||
/** @var int */
|
||||
protected $limit = 0;
|
||||
|
||||
/** @var \Closure|null */
|
||||
protected $startingFromFrameClosure = null;
|
||||
|
||||
/** @var \Throwable|null */
|
||||
protected $throwable = null;
|
||||
|
||||
public static function create(): self
|
||||
{
|
||||
return new static();
|
||||
}
|
||||
|
||||
public static function createForThrowable(Throwable $throwable): self
|
||||
{
|
||||
return (new static())->forThrowable($throwable);
|
||||
}
|
||||
|
||||
protected function forThrowable(Throwable $throwable): self
|
||||
{
|
||||
$this->throwable = $throwable;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withArguments(
|
||||
bool $withArguments = true
|
||||
): self {
|
||||
$this->withArguments = $withArguments;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<class-string<ArgumentReducer>|ArgumentReducer>|ArgumentReducers|null $argumentReducers
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function reduceArguments(
|
||||
$argumentReducers = null
|
||||
): self {
|
||||
$this->reduceArguments = true;
|
||||
$this->argumentReducers = $argumentReducers;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withObject(): self
|
||||
{
|
||||
$this->withObject = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function applicationPath(string $applicationPath): self
|
||||
{
|
||||
$this->applicationPath = rtrim($applicationPath, '/');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function offset(int $offset): self
|
||||
{
|
||||
$this->offset = $offset;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function limit(int $limit): self
|
||||
{
|
||||
$this->limit = $limit;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function startingFromFrame(Closure $startingFromFrameClosure)
|
||||
{
|
||||
$this->startingFromFrameClosure = $startingFromFrameClosure;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Spatie\Backtrace\Frame[]
|
||||
*/
|
||||
public function frames(): array
|
||||
{
|
||||
$rawFrames = $this->getRawFrames();
|
||||
|
||||
return $this->toFrameObjects($rawFrames);
|
||||
}
|
||||
|
||||
public function firstApplicationFrameIndex(): ?int
|
||||
{
|
||||
foreach ($this->frames() as $index => $frame) {
|
||||
if ($frame->applicationFrame) {
|
||||
return $index;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function getRawFrames(): array
|
||||
{
|
||||
if ($this->throwable) {
|
||||
return $this->throwable->getTrace();
|
||||
}
|
||||
|
||||
$options = null;
|
||||
|
||||
if (! $this->withArguments) {
|
||||
$options = $options | DEBUG_BACKTRACE_IGNORE_ARGS;
|
||||
}
|
||||
|
||||
if ($this->withObject()) {
|
||||
$options = $options | DEBUG_BACKTRACE_PROVIDE_OBJECT;
|
||||
}
|
||||
|
||||
$limit = $this->limit;
|
||||
|
||||
if ($limit !== 0) {
|
||||
$limit += 3;
|
||||
}
|
||||
|
||||
return debug_backtrace($options, $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Spatie\Backtrace\Frame[]
|
||||
*/
|
||||
protected function toFrameObjects(array $rawFrames): array
|
||||
{
|
||||
$currentFile = $this->throwable ? $this->throwable->getFile() : '';
|
||||
$currentLine = $this->throwable ? $this->throwable->getLine() : 0;
|
||||
$arguments = $this->withArguments ? [] : null;
|
||||
|
||||
$frames = [];
|
||||
|
||||
$reduceArgumentsAction = new ReduceArgumentsAction($this->resolveArgumentReducers());
|
||||
|
||||
foreach ($rawFrames as $rawFrame) {
|
||||
$frames[] = new Frame(
|
||||
$currentFile,
|
||||
$currentLine,
|
||||
$arguments,
|
||||
$rawFrame['function'] ?? null,
|
||||
$rawFrame['class'] ?? null,
|
||||
$this->isApplicationFrame($currentFile)
|
||||
);
|
||||
|
||||
$arguments = $this->withArguments
|
||||
? $rawFrame['args'] ?? null
|
||||
: null;
|
||||
|
||||
if ($this->reduceArguments) {
|
||||
$arguments = $reduceArgumentsAction->execute(
|
||||
$rawFrame['class'] ?? null,
|
||||
$rawFrame['function'] ?? null,
|
||||
$arguments
|
||||
);
|
||||
}
|
||||
|
||||
$currentFile = $rawFrame['file'] ?? 'unknown';
|
||||
$currentLine = $rawFrame['line'] ?? 0;
|
||||
}
|
||||
|
||||
$frames[] = new Frame(
|
||||
$currentFile,
|
||||
$currentLine,
|
||||
[],
|
||||
'[top]'
|
||||
);
|
||||
|
||||
$frames = $this->removeBacktracePackageFrames($frames);
|
||||
|
||||
if ($closure = $this->startingFromFrameClosure) {
|
||||
$frames = $this->startAtFrameFromClosure($frames, $closure);
|
||||
}
|
||||
$frames = array_slice($frames, $this->offset, $this->limit === 0 ? PHP_INT_MAX : $this->limit);
|
||||
|
||||
return array_values($frames);
|
||||
}
|
||||
|
||||
protected function isApplicationFrame(string $frameFilename): bool
|
||||
{
|
||||
$relativeFile = str_replace('\\', DIRECTORY_SEPARATOR, $frameFilename);
|
||||
|
||||
if (! empty($this->applicationPath)) {
|
||||
$relativeFile = array_reverse(explode($this->applicationPath ?? '', $frameFilename, 2))[0];
|
||||
}
|
||||
|
||||
if (strpos($relativeFile, DIRECTORY_SEPARATOR.'vendor') === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function removeBacktracePackageFrames(array $frames): array
|
||||
{
|
||||
return $this->startAtFrameFromClosure($frames, function (Frame $frame) {
|
||||
return $frame->class !== static::class;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Spatie\Backtrace\Frame[] $frames
|
||||
* @param \Closure $closure
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function startAtFrameFromClosure(array $frames, Closure $closure): array
|
||||
{
|
||||
foreach ($frames as $i => $frame) {
|
||||
$foundStartingFrame = $closure($frame);
|
||||
|
||||
if ($foundStartingFrame) {
|
||||
return $frames;
|
||||
}
|
||||
|
||||
unset($frames[$i]);
|
||||
}
|
||||
|
||||
return $frames;
|
||||
}
|
||||
|
||||
protected function resolveArgumentReducers(): ArgumentReducers
|
||||
{
|
||||
if ($this->argumentReducers === null) {
|
||||
return ArgumentReducers::default();
|
||||
}
|
||||
|
||||
if ($this->argumentReducers instanceof ArgumentReducers) {
|
||||
return $this->argumentReducers;
|
||||
}
|
||||
|
||||
return ArgumentReducers::create($this->argumentReducers);
|
||||
}
|
||||
}
|
83
vendor/spatie/backtrace/src/CodeSnippet.php
vendored
Normal file
83
vendor/spatie/backtrace/src/CodeSnippet.php
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class CodeSnippet
|
||||
{
|
||||
/** @var int */
|
||||
protected $surroundingLine = 1;
|
||||
|
||||
/** @var int */
|
||||
protected $snippetLineCount = 9;
|
||||
|
||||
public function surroundingLine(int $surroundingLine): self
|
||||
{
|
||||
$this->surroundingLine = $surroundingLine;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function snippetLineCount(int $snippetLineCount): self
|
||||
{
|
||||
$this->snippetLineCount = $snippetLineCount;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function get(string $fileName): array
|
||||
{
|
||||
if (! file_exists($fileName)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
$file = new File($fileName);
|
||||
|
||||
[$startLineNumber, $endLineNumber] = $this->getBounds($file->numberOfLines());
|
||||
|
||||
$code = [];
|
||||
|
||||
$line = $file->getLine($startLineNumber);
|
||||
|
||||
$currentLineNumber = $startLineNumber;
|
||||
|
||||
while ($currentLineNumber <= $endLineNumber) {
|
||||
$code[$currentLineNumber] = rtrim(substr($line, 0, 250));
|
||||
|
||||
$line = $file->getNextLine();
|
||||
$currentLineNumber++;
|
||||
}
|
||||
|
||||
return $code;
|
||||
} catch (RuntimeException $exception) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
public function getAsString(string $fileName): string
|
||||
{
|
||||
$snippet = $this->get($fileName);
|
||||
|
||||
$snippetStrings = array_map(function (string $line, string $number) {
|
||||
return "{$number} {$line}";
|
||||
}, $snippet, array_keys($snippet));
|
||||
|
||||
return implode(PHP_EOL, $snippetStrings);
|
||||
}
|
||||
|
||||
protected function getBounds(int $totalNumberOfLineInFile): array
|
||||
{
|
||||
$startLine = max($this->surroundingLine - floor($this->snippetLineCount / 2), 1);
|
||||
|
||||
$endLine = $startLine + ($this->snippetLineCount - 1);
|
||||
|
||||
if ($endLine > $totalNumberOfLineInFile) {
|
||||
$endLine = $totalNumberOfLineInFile;
|
||||
$startLine = max($endLine - ($this->snippetLineCount - 1), 1);
|
||||
}
|
||||
|
||||
return [$startLine, $endLine];
|
||||
}
|
||||
}
|
41
vendor/spatie/backtrace/src/File.php
vendored
Normal file
41
vendor/spatie/backtrace/src/File.php
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace;
|
||||
|
||||
use SplFileObject;
|
||||
|
||||
class File
|
||||
{
|
||||
/** @var \SplFileObject */
|
||||
protected $file;
|
||||
|
||||
public function __construct(string $path)
|
||||
{
|
||||
$this->file = new SplFileObject($path);
|
||||
}
|
||||
|
||||
public function numberOfLines(): int
|
||||
{
|
||||
$this->file->seek(PHP_INT_MAX);
|
||||
|
||||
return $this->file->key() + 1;
|
||||
}
|
||||
|
||||
public function getLine(int $lineNumber = null): string
|
||||
{
|
||||
if (is_null($lineNumber)) {
|
||||
return $this->getNextLine();
|
||||
}
|
||||
|
||||
$this->file->seek($lineNumber - 1);
|
||||
|
||||
return $this->file->current();
|
||||
}
|
||||
|
||||
public function getNextLine(): string
|
||||
{
|
||||
$this->file->next();
|
||||
|
||||
return $this->file->current();
|
||||
}
|
||||
}
|
73
vendor/spatie/backtrace/src/Frame.php
vendored
Normal file
73
vendor/spatie/backtrace/src/Frame.php
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Spatie\Backtrace;
|
||||
|
||||
class Frame
|
||||
{
|
||||
/** @var string */
|
||||
public $file;
|
||||
|
||||
/** @var int */
|
||||
public $lineNumber;
|
||||
|
||||
/** @var array|null */
|
||||
public $arguments = null;
|
||||
|
||||
/** @var bool */
|
||||
public $applicationFrame;
|
||||
|
||||
/** @var string|null */
|
||||
public $method;
|
||||
|
||||
/** @var string|null */
|
||||
public $class;
|
||||
|
||||
public function __construct(
|
||||
string $file,
|
||||
int $lineNumber,
|
||||
?array $arguments,
|
||||
string $method = null,
|
||||
string $class = null,
|
||||
bool $isApplicationFrame = false
|
||||
) {
|
||||
$this->file = $file;
|
||||
|
||||
$this->lineNumber = $lineNumber;
|
||||
|
||||
$this->arguments = $arguments;
|
||||
|
||||
$this->method = $method;
|
||||
|
||||
$this->class = $class;
|
||||
|
||||
$this->applicationFrame = $isApplicationFrame;
|
||||
}
|
||||
|
||||
public function getSnippet(int $lineCount): array
|
||||
{
|
||||
return (new CodeSnippet())
|
||||
->surroundingLine($this->lineNumber)
|
||||
->snippetLineCount($lineCount)
|
||||
->get($this->file);
|
||||
}
|
||||
|
||||
public function getSnippetAsString(int $lineCount): string
|
||||
{
|
||||
return (new CodeSnippet())
|
||||
->surroundingLine($this->lineNumber)
|
||||
->snippetLineCount($lineCount)
|
||||
->getAsString($this->file);
|
||||
}
|
||||
|
||||
public function getSnippetProperties(int $lineCount): array
|
||||
{
|
||||
$snippet = $this->getSnippet($lineCount);
|
||||
|
||||
return array_map(function (int $lineNumber) use ($snippet) {
|
||||
return [
|
||||
'line_number' => $lineNumber,
|
||||
'text' => $snippet[$lineNumber],
|
||||
];
|
||||
}, array_keys($snippet));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user