-
-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Specify return type error #94
base: master
Are you sure you want to change the base?
Changes from all commits
26c59c9
64781db
3e8bf04
47876f3
7edc3a0
5420996
b828a3d
a67f916
2c963b8
f17d1ec
4196311
c26b392
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Yiisoft\Middleware\Dispatcher\Exception; | ||
|
||
use InvalidArgumentException; | ||
use Psr\Http\Server\MiddlewareInterface; | ||
use Throwable; | ||
use Yiisoft\Definitions\Exception\InvalidConfigException; | ||
use Yiisoft\Definitions\Helpers\DefinitionValidator; | ||
use Yiisoft\FriendlyException\FriendlyExceptionInterface; | ||
use Yiisoft\Middleware\Dispatcher\Helper\DefinitionHelper; | ||
|
||
use function is_array; | ||
|
||
abstract class AbstractInvalidMiddlewareException extends InvalidArgumentException implements FriendlyExceptionInterface | ||
{ | ||
protected string $definitionString; | ||
|
||
public function __construct( | ||
protected mixed $definition, | ||
string $message, | ||
?Throwable $previous = null, | ||
) { | ||
$this->definitionString = DefinitionHelper::convertDefinitionToString($definition); | ||
|
||
parent::__construct($message, 0, $previous); | ||
Check warning on line 28 in src/Exception/AbstractInvalidMiddlewareException.php GitHub Actions / mutation / PHP 8.1-ubuntu-latest
Check warning on line 28 in src/Exception/AbstractInvalidMiddlewareException.php GitHub Actions / mutation / PHP 8.1-ubuntu-latest
Check warning on line 28 in src/Exception/AbstractInvalidMiddlewareException.php GitHub Actions / mutation / PHP 8.1-ubuntu-latest
Check warning on line 28 in src/Exception/AbstractInvalidMiddlewareException.php GitHub Actions / mutation / PHP 8.1-ubuntu-latest
|
||
} | ||
|
||
public function getSolution(): ?string | ||
{ | ||
$solution = [ | ||
Check warning on line 33 in src/Exception/AbstractInvalidMiddlewareException.php GitHub Actions / mutation / PHP 8.1-ubuntu-latest
Check warning on line 33 in src/Exception/AbstractInvalidMiddlewareException.php GitHub Actions / mutation / PHP 8.1-ubuntu-latest
|
||
<<<SOLUTION | ||
## Got definition value | ||
|
||
`{$this->definitionString}` | ||
SOLUTION | ||
]; | ||
|
||
$suggestion = $this->generateSuggestion(); | ||
if ($suggestion !== null) { | ||
$solution[] = '## Suggestion'; | ||
$solution[] = $suggestion; | ||
} | ||
|
||
$solution[] = <<<SOLUTION | ||
## Middleware definition examples | ||
|
||
PSR middleware class name: | ||
|
||
```php | ||
Yiisoft\Session\SessionMiddleware::class | ||
``` | ||
|
||
PSR middleware array definition: | ||
|
||
```php | ||
[ | ||
'class' => MyMiddleware::class, | ||
'__construct()' => [ | ||
'someVar' => 42, | ||
], | ||
] | ||
``` | ||
|
||
Closure that returns `ResponseInterface`: | ||
|
||
```php | ||
static function (): ResponseInterface { | ||
return new Response(418); | ||
}, | ||
``` | ||
|
||
Closure that returns `MiddlewareInterface`: | ||
|
||
```php | ||
static function (): MiddlewareInterface { | ||
return new TestMiddleware(); | ||
} | ||
``` | ||
|
||
Action in controller: | ||
|
||
```php | ||
[App\Backend\UserController::class, 'index'] | ||
``` | ||
|
||
## Related links | ||
|
||
- [Array definition syntax](https://github.com/yiisoft/definitions#arraydefinition) | ||
- [Callable PHP documentation](https://www.php.net/manual/language.types.callable.php) | ||
SOLUTION; | ||
|
||
return implode("\n\n", $solution); | ||
} | ||
|
||
private function generateSuggestion(): ?string | ||
{ | ||
if (DefinitionHelper::isControllerWithNonExistAction($this->definition)) { | ||
return <<<SOLUTION | ||
Class `{$this->definition[0]}` exists, but does not contain method `{$this->definition[1]}()`. | ||
Check warning on line 102 in src/Exception/AbstractInvalidMiddlewareException.php GitHub Actions / mutation / PHP 8.1-ubuntu-latest
Check warning on line 102 in src/Exception/AbstractInvalidMiddlewareException.php GitHub Actions / mutation / PHP 8.1-ubuntu-latest
Check warning on line 102 in src/Exception/AbstractInvalidMiddlewareException.php GitHub Actions / mutation / PHP 8.1-ubuntu-latest
Check warning on line 102 in src/Exception/AbstractInvalidMiddlewareException.php GitHub Actions / mutation / PHP 8.1-ubuntu-latest
|
||
|
||
Try adding `{$this->definition[1]}()` action to `{$this->definition[0]}` controller: | ||
|
||
```php | ||
public function {$this->definition[1]}(): ResponseInterface | ||
Check warning on line 107 in src/Exception/AbstractInvalidMiddlewareException.php GitHub Actions / mutation / PHP 8.1-ubuntu-latest
Check warning on line 107 in src/Exception/AbstractInvalidMiddlewareException.php GitHub Actions / mutation / PHP 8.1-ubuntu-latest
|
||
{ | ||
// TODO: Implement your action | ||
} | ||
``` | ||
SOLUTION; | ||
} | ||
|
||
if (DefinitionHelper::isNotMiddlewareClassName($this->definition)) { | ||
return sprintf( | ||
'Class `%s` exists, but does not implement `%s`.', | ||
$this->definition, | ||
MiddlewareInterface::class | ||
); | ||
} | ||
|
||
if (DefinitionHelper::isStringNotClassName($this->definition)) { | ||
return sprintf( | ||
'Class `%s` not found. It may be needed to install a package with this middleware.', | ||
$this->definition | ||
); | ||
} | ||
|
||
if (is_array($this->definition)) { | ||
try { | ||
DefinitionValidator::validateArrayDefinition($this->definition); | ||
} catch (InvalidConfigException $e) { | ||
return <<<SOLUTION | ||
You may have an error in array definition. Array definition validation result: | ||
|
||
``` | ||
{$e->getMessage()} | ||
``` | ||
SOLUTION; | ||
} | ||
|
||
/** @psalm-suppress MixedArgument In valid array definition element "class" always is string */ | ||
return sprintf( | ||
'Array definition is valid, class `%s` exists, but does not implement `%s`.', | ||
$this->definition['class'], | ||
MiddlewareInterface::class | ||
); | ||
} | ||
|
||
return null; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Yiisoft\Middleware\Dispatcher\Exception; | ||
|
||
use Psr\Http\Message\ResponseInterface; | ||
use Psr\Http\Server\MiddlewareInterface; | ||
use Throwable; | ||
use Yiisoft\Middleware\Dispatcher\Helper\DefinitionHelper; | ||
use Yiisoft\Middleware\Dispatcher\Helper\ResponseHelper; | ||
|
||
final class InvalidMiddlewareReturnTypeException extends AbstractInvalidMiddlewareException | ||
{ | ||
public function __construct( | ||
mixed $definition, | ||
private readonly mixed $result, | ||
?Throwable $previous = null, | ||
) { | ||
$this->definitionString = DefinitionHelper::convertDefinitionToString($definition); | ||
|
||
parent::__construct( | ||
$definition, | ||
sprintf( | ||
'Middleware %s must return an instance of `%s` or `%s`, %s returned.', | ||
$this->definitionString, | ||
MiddlewareInterface::class, | ||
ResponseInterface::class, | ||
ResponseHelper::convertToString($this->result), | ||
), | ||
$previous, | ||
); | ||
} | ||
|
||
public function getName(): string | ||
{ | ||
return sprintf('Invalid middleware result type %s', get_debug_type($this->result)); | ||
} | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This methods need for excpetion only. May be keep thier in |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Yiisoft\Middleware\Dispatcher\Helper; | ||
|
||
use function array_slice; | ||
use function count; | ||
use function gettype; | ||
use function is_array; | ||
use function is_bool; | ||
use function is_float; | ||
use function is_int; | ||
use function is_object; | ||
use function is_string; | ||
|
||
final class DefinitionHelper | ||
{ | ||
/** | ||
* @psalm-assert-if-true string $definition | ||
*/ | ||
public static function isStringNotClassName(mixed $definition): bool | ||
{ | ||
return is_string($definition) | ||
&& !class_exists($definition); | ||
} | ||
|
||
/** | ||
* @psalm-assert-if-true class-string $definition | ||
*/ | ||
public static function isNotMiddlewareClassName(mixed $definition): bool | ||
{ | ||
return is_string($definition) | ||
&& class_exists($definition); | ||
} | ||
|
||
/** | ||
* @psalm-assert-if-true array{0:class-string,1:string} $definition | ||
*/ | ||
public static function isControllerWithNonExistAction(mixed $definition): bool | ||
{ | ||
return is_array($definition) | ||
&& array_keys($definition) === [0, 1] | ||
&& is_string($definition[0]) | ||
&& class_exists($definition[0]); | ||
} | ||
|
||
public static function convertDefinitionToString(mixed $middlewareDefinition): string | ||
{ | ||
if (is_object($middlewareDefinition)) { | ||
return 'an instance of `' . $middlewareDefinition::class . '`'; | ||
} | ||
|
||
if (is_string($middlewareDefinition)) { | ||
return '"' . $middlewareDefinition . '"'; | ||
} | ||
|
||
if (is_array($middlewareDefinition)) { | ||
$items = []; | ||
/** @var mixed $value */ | ||
foreach (array_slice($middlewareDefinition, 0, 2) as $key => $value) { | ||
$items[] = (is_string($key) ? '"' . $key . '" => ' : '') . self::convertToString($value); | ||
} | ||
return '[' . implode(', ', $items) . (count($middlewareDefinition) > 2 ? ', ...' : '') . ']'; | ||
} | ||
|
||
return self::convertToString($middlewareDefinition); | ||
} | ||
|
||
private static function convertToString(mixed $value): string | ||
{ | ||
if (is_string($value)) { | ||
return '"' . $value . '"'; | ||
} | ||
|
||
if (is_int($value) || is_float($value)) { | ||
return (string) $value; | ||
} | ||
|
||
if (is_bool($value)) { | ||
return $value ? 'true' : 'false'; | ||
} | ||
|
||
if ($value === null) { | ||
return '"null"'; | ||
} | ||
|
||
if (is_object($value)) { | ||
return sprintf('"%s"', $value::class); | ||
} | ||
|
||
return sprintf('"%s"', gettype($value)); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Yiisoft\Middleware\Dispatcher\Helper; | ||
|
||
use function gettype; | ||
use function is_array; | ||
use function is_bool; | ||
use function is_object; | ||
|
||
final class ResponseHelper | ||
{ | ||
public static function convertToString(mixed $response): string | ||
{ | ||
if (is_object($response)) { | ||
return sprintf('"%s" (object)', $response::class); | ||
} | ||
|
||
if (is_array($response)) { | ||
$items = []; | ||
|
||
if (!array_is_list($response)) { | ||
/** @var mixed $value */ | ||
foreach (array_keys($response) as $key) { | ||
$items[] = sprintf('"%s" => ...', $key); | ||
} | ||
} else { | ||
$items[] = '...'; | ||
} | ||
return sprintf( | ||
'"[%s]" (array of %d%s)', | ||
implode(', ', $items), | ||
$count = count($response), | ||
$count === 1 ? ' element' : ' elements' | ||
); | ||
} | ||
|
||
if (is_bool($response)) { | ||
return sprintf('"%s" (bool)', $response ? 'true' : 'false'); | ||
} | ||
|
||
if (is_scalar($response)) { | ||
return sprintf( | ||
'"%s" (%s)', | ||
(string)$response, | ||
match (true) { | ||
is_int($response) => 'int', | ||
is_float($response) => 'float', | ||
default => gettype($response) | ||
} | ||
); | ||
} | ||
|
||
return sprintf('"%s" (%s)', gettype($response), get_debug_type($response)); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need add solution for friendly exception also. Solution from
AbstractInvalidMiddlewareException
does not fit here.