Skip to content

Commit

Permalink
more footwork
Browse files Browse the repository at this point in the history
  • Loading branch information
rodber committed Dec 4, 2023
1 parent edee8b5 commit 4c2aec7
Show file tree
Hide file tree
Showing 38 changed files with 1,234 additions and 28 deletions.
20 changes: 10 additions & 10 deletions .vscode/templates.code-snippets
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"body": [
"<?php",
"",
"namespace Chevere\\%namespace%;",
"namespace Chevere\\Action;",
"",
"/**",
" * Describes the component in charge of ${1:doing}.",
Expand All @@ -22,7 +22,7 @@
"body": [
"<?php",
"",
"namespace Chevere\\%namespace%;",
"namespace Chevere\\Action;",
"",
"final class $TM_FILENAME_BASE",
"{",
Expand All @@ -36,9 +36,9 @@
"body": [
"<?php",
"",
"namespace Chevere\\%namespace%;",
"namespace Chevere\\Action;",
"",
"use Chevere\\Exceptions\\Core\\Exception;",
"use Exception;",
"",
"/**",
" * Exception thrown when ${1:description}.",
Expand All @@ -54,7 +54,7 @@
"body": [
"<?php",
"",
"namespace Chevere\\%namespace%;",
"namespace Chevere\\Action;",
"",
"trait $TM_FILENAME_BASE",
"{",
Expand All @@ -68,7 +68,7 @@
"body": [
"<?php",
"",
"namespace Chevere\\%namespace%\\\\${TM_DIRECTORY/.*src\\/(([^\\/]*)(\\/)?)|(\\/)([^\\/]*)/$2${3:+.}${5:+.}$5/g};",
"namespace Chevere\\Action\\\\${TM_DIRECTORY/.*src\\/(([^\\/]*)(\\/)?)|(\\/)([^\\/]*)/$2${3:+.}${5:+.}$5/g};",
"",
"/**",
" * Describes the component in charge of ${1:doing}.",
Expand All @@ -85,7 +85,7 @@
"body": [
"<?php",
"",
"namespace Chevere\\%namespace%\\\\${TM_DIRECTORY/.*src\\/(([^\\/]*)(\\/)?)|(\\/)([^\\/]*)/$2${3:+.}${5:+.}$5/g};",
"namespace Chevere\\Action\\\\${TM_DIRECTORY/.*src\\/(([^\\/]*)(\\/)?)|(\\/)([^\\/]*)/$2${3:+.}${5:+.}$5/g};",
"",
"final class $TM_FILENAME_BASE",
"{",
Expand All @@ -99,9 +99,9 @@
"body": [
"<?php",
"",
"namespace Chevere\\%namespace%\\\\${TM_DIRECTORY/.*src\\/(([^\\/]*)(\\/)?)|(\\/)([^\\/]*)/$2${3:+.}${5:+.}$5/g};",
"namespace Chevere\\Action\\\\${TM_DIRECTORY/.*src\\/(([^\\/]*)(\\/)?)|(\\/)([^\\/]*)/$2${3:+.}${5:+.}$5/g};",
"",
"use Chevere\\Exceptions\\Core\\Exception;",
"use Exception;",
"",
"/**",
" * Exception thrown when ${1:description}.",
Expand All @@ -117,7 +117,7 @@
"body": [
"<?php",
"",
"namespace Chevere\\%namespace%\\\\${TM_DIRECTORY/.*src\\/(([^\\/]*)(\\/)?)|(\\/)([^\\/]*)/$2${3:+.}${5:+.}$5/g};",
"namespace Chevere\\Action\\\\${TM_DIRECTORY/.*src\\/(([^\\/]*)(\\/)?)|(\\/)([^\\/]*)/$2${3:+.}${5:+.}$5/g};",
"",
"trait $TM_FILENAME_BASE",
"{",
Expand Down
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
# %namespace%
# Action

> 🔔 Subscribe to the [newsletter](https://chv.to/chevere-newsletter) to don't miss any update regarding Chevere.
![Chevere](chevere.svg)

[![Build](https://img.shields.io/github/actions/workflow/status/chevere/reponame/test.yml?branch=%branch%&style=flat-square)](https://github.com/chevere/reponame/actions)
![Code size](https://img.shields.io/github/languages/code-size/chevere/reponame?style=flat-square)
[![Apache-2.0](https://img.shields.io/github/license/chevere/reponame?style=flat-square)](LICENSE)
[![Build](https://img.shields.io/github/actions/workflow/status/chevere/action/test.yml?branch=1.0&style=flat-square)](https://github.com/chevere/action/actions)
![Code size](https://img.shields.io/github/languages/code-size/chevere/action?style=flat-square)
[![Apache-2.0](https://img.shields.io/github/license/chevere/action?style=flat-square)](LICENSE)
[![PHPStan](https://img.shields.io/badge/PHPStan-level%209-blueviolet?style=flat-square)](https://phpstan.org/)
[![Mutation testing badge](https://img.shields.io/endpoint?style=flat-square&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fchevere%2Freponame%2F%branch%)](https://dashboard.stryker-mutator.io/reports/github.com/chevere/reponame/%branch%)

[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=chevere_reponame&metric=alert_status)](https://sonarcloud.io/dashboard?id=chevere_reponame)
[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=chevere_reponame&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=chevere_reponame)
[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=chevere_reponame&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=chevere_reponame)
[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=chevere_reponame&metric=security_rating)](https://sonarcloud.io/dashboard?id=chevere_reponame)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=chevere_reponame&metric=coverage)](https://sonarcloud.io/dashboard?id=chevere_reponame)
[![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=chevere_reponame&metric=sqale_index)](https://sonarcloud.io/dashboard?id=chevere_reponame)
[![CodeFactor](https://www.codefactor.io/repository/github/chevere/reponame/badge)](https://www.codefactor.io/repository/github/chevere/reponame)
[![Mutation testing badge](https://img.shields.io/endpoint?style=flat-square&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fchevere%2Faction%2F1.0)](https://dashboard.stryker-mutator.io/reports/github.com/chevere/action/1.0)

[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=chevere_action&metric=alert_status)](https://sonarcloud.io/dashboard?id=chevere_action)
[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=chevere_action&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=chevere_action)
[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=chevere_action&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=chevere_action)
[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=chevere_action&metric=security_rating)](https://sonarcloud.io/dashboard?id=chevere_action)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=chevere_action&metric=coverage)](https://sonarcloud.io/dashboard?id=chevere_action)
[![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=chevere_action&metric=sqale_index)](https://sonarcloud.io/dashboard?id=chevere_action)
[![CodeFactor](https://www.codefactor.io/repository/github/chevere/action/badge)](https://www.codefactor.io/repository/github/chevere/action)

## Documentation

Expand Down
10 changes: 6 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "chevere/reponame",
"description": "A chevere reponame package",
"name": "chevere/action",
"description": "A chevere action package",
"homepage": "https://chevere.org",
"type": "library",
"license": "Apache-2.0",
Expand All @@ -12,7 +12,9 @@
}
],
"require": {
"chevere/chevere": "^3.0"
"php": "^8.1",
"chevere/message": "^0.1.0",
"chevere/parameter": "^1.0.x-dev"
},
"require-dev": {
"phpstan/phpstan": "^1.9",
Expand All @@ -24,7 +26,7 @@
"src/functions.php"
],
"psr-4": {
"Chevere\\%namespace%\\": "src/"
"Chevere\\Action\\": "src/"
}
},
"autoload-dev": {
Expand Down
2 changes: 1 addition & 1 deletion sonar-project.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
sonar.projectKey=chevere_reponame
sonar.projectKey=chevere_action
sonar.organization=chevere
sonar.host.url=https://sonarcloud.io
sonar.sourceEncoding=UTF-8
Expand Down
Empty file removed src/.git-keep
Empty file.
168 changes: 168 additions & 0 deletions src/Action.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
<?php

/*
* This file is part of Chevere.
*
* (c) Rodolfo Berrios <rodolfo@chevere.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Chevere\Action;

use Chevere\Action\Interfaces\ActionInterface;
use Chevere\Parameter\Cast;
use Chevere\Parameter\Interfaces\CastInterface;
use Chevere\Parameter\Interfaces\ParameterInterface;
use Chevere\Parameter\Interfaces\ParametersInterface;
use Chevere\Parameter\Interfaces\UnionParameterInterface;
use LogicException;
use ReflectionMethod;
use ReflectionNamedType;
use Throwable;
use TypeError;
use function Chevere\Message\message;
use function Chevere\Parameter\arguments;
use function Chevere\Parameter\arrayp;

/**
* @method mixed run()
*/
abstract class Action implements ActionInterface
{
public const RUN_METHOD = 'run';

protected ?ParametersInterface $parameters = null;

public static function acceptResponse(): ParameterInterface
{
return arrayp();
}

final public static function assert(): void
{
static::assertMethod();
static::assertStatic();
}

final public function getResponse(mixed ...$argument): CastInterface
{
static::assert();
$this->assertRuntime();

Check warning on line 54 in src/Action.php

View workflow job for this annotation

GitHub Actions / PHP 8.1 test on ubuntu-latest

Escaped Mutant for Mutator "MethodCallRemoval": --- Original +++ New @@ @@ public final function getResponse(mixed ...$argument) : CastInterface { static::assert(); - $this->assertRuntime(); + $arguments = arguments($this->parameters(), $argument)->toArray(); $run = $this->run(...$arguments); try {

Check warning on line 54 in src/Action.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 test on ubuntu-latest

Escaped Mutant for Mutator "MethodCallRemoval": --- Original +++ New @@ @@ public final function getResponse(mixed ...$argument) : CastInterface { static::assert(); - $this->assertRuntime(); + $arguments = arguments($this->parameters(), $argument)->toArray(); $run = $this->run(...$arguments); try {

Check warning on line 54 in src/Action.php

View workflow job for this annotation

GitHub Actions / PHP 8.3 test on ubuntu-latest

Escaped Mutant for Mutator "MethodCallRemoval": --- Original +++ New @@ @@ public final function getResponse(mixed ...$argument) : CastInterface { static::assert(); - $this->assertRuntime(); + $arguments = arguments($this->parameters(), $argument)->toArray(); $run = $this->run(...$arguments); try {
$arguments = arguments($this->parameters(), $argument)->toArray();
$run = $this->run(...$arguments);

try {
static::acceptResponse()->__invoke($run);
} catch (Throwable $e) {
$message = message(
'`%method%` → %message%',
method: static::runMethodFQN(),
message: $e->getMessage(),
)->__toString();

throw new ($e::class)($message);
}

return new Cast($run);
}

public static function assertTypes(

Check warning on line 73 in src/Action.php

View workflow job for this annotation

GitHub Actions / PHP 8.1 test on ubuntu-latest

Escaped Mutant for Mutator "PublicVisibility": --- Original +++ New @@ @@ } return new Cast($run); } - public static function assertTypes(ReflectionNamedType $reflection, ParameterInterface $response) : void + protected static function assertTypes(ReflectionNamedType $reflection, ParameterInterface $response) : void { $returnName = $reflection->getName(); $expectName = $response->type()->typeHinting();

Check warning on line 73 in src/Action.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 test on ubuntu-latest

Escaped Mutant for Mutator "PublicVisibility": --- Original +++ New @@ @@ } return new Cast($run); } - public static function assertTypes(ReflectionNamedType $reflection, ParameterInterface $response) : void + protected static function assertTypes(ReflectionNamedType $reflection, ParameterInterface $response) : void { $returnName = $reflection->getName(); $expectName = $response->type()->typeHinting();

Check warning on line 73 in src/Action.php

View workflow job for this annotation

GitHub Actions / PHP 8.3 test on ubuntu-latest

Escaped Mutant for Mutator "PublicVisibility": --- Original +++ New @@ @@ } return new Cast($run); } - public static function assertTypes(ReflectionNamedType $reflection, ParameterInterface $response) : void + protected static function assertTypes(ReflectionNamedType $reflection, ParameterInterface $response) : void { $returnName = $reflection->getName(); $expectName = $response->type()->typeHinting();
ReflectionNamedType $reflection,
ParameterInterface $response
): void {
$returnName = $reflection->getName();
$expectName = $response->type()->typeHinting();
$return = match ($returnName) {
'void' => 'null',
'ArrayAccess' => 'array',
default => $returnName,
};
$expect = [];
if ($response instanceof UnionParameterInterface) {
foreach ($response->parameters() as $parameter) {
$expect[] = $parameter->type()->typeHinting();
}
} else {
$expect[] = match ($expectName) {
'generic' => 'array',
default => $expectName,
};
}
if (! in_array($return, $expect, true)) {
throw new TypeError(
(string) message(
'Method `%method%` must declare `%type%` return type',
method: static::runMethodFQN(),
type: implode('|', $expect),
)
);
}
}

protected static function assertMethod(): void

Check warning on line 106 in src/Action.php

View workflow job for this annotation

GitHub Actions / PHP 8.1 test on ubuntu-latest

Escaped Mutant for Mutator "ProtectedVisibility": --- Original +++ New @@ @@ throw new TypeError((string) message('Method `%method%` must declare `%type%` return type', method: static::runMethodFQN(), type: implode('|', $expect))); } } - protected static function assertMethod() : void + private static function assertMethod() : void { if (!method_exists(static::class, static::RUN_METHOD)) { throw new LogicException((string) message('Action `%action%` does not define %invoke% method', action: static::class, invoke: static::RUN_METHOD));

Check warning on line 106 in src/Action.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 test on ubuntu-latest

Escaped Mutant for Mutator "ProtectedVisibility": --- Original +++ New @@ @@ throw new TypeError((string) message('Method `%method%` must declare `%type%` return type', method: static::runMethodFQN(), type: implode('|', $expect))); } } - protected static function assertMethod() : void + private static function assertMethod() : void { if (!method_exists(static::class, static::RUN_METHOD)) { throw new LogicException((string) message('Action `%action%` does not define %invoke% method', action: static::class, invoke: static::RUN_METHOD));

Check warning on line 106 in src/Action.php

View workflow job for this annotation

GitHub Actions / PHP 8.3 test on ubuntu-latest

Escaped Mutant for Mutator "ProtectedVisibility": --- Original +++ New @@ @@ throw new TypeError((string) message('Method `%method%` must declare `%type%` return type', method: static::runMethodFQN(), type: implode('|', $expect))); } } - protected static function assertMethod() : void + private static function assertMethod() : void { if (!method_exists(static::class, static::RUN_METHOD)) { throw new LogicException((string) message('Action `%action%` does not define %invoke% method', action: static::class, invoke: static::RUN_METHOD));
{
if (! method_exists(static::class, static::RUN_METHOD)) {
throw new LogicException(
(string) message(
'Action `%action%` does not define %invoke% method',
action: static::class,
invoke: static::RUN_METHOD,
)
);
}
$response = static::acceptResponse();
$method = new ReflectionMethod(static::class, static::RUN_METHOD);
if (! $method->hasReturnType()) {
if ($response->type()->typeHinting() === 'null') {
return;
}

throw new TypeError(
(string) message(
'Method `%method%` must declare `%type%` return type',
method: static::runMethodFQN(),
type: $response->type()->typeHinting(),
)
);
}
/** @var ReflectionNamedType $returnType */
$returnType = $method->getReturnType();
static::assertTypes($returnType, $response);
}

/**
* Enables to define extra parameter assertion before the run method is called.
* @codeCoverageIgnore
*/
protected static function assertStatic(): void
{
// enables extra static assertion
}

/**
* Enables to define extra parameter assertion before the run method is called.
* @codeCoverageIgnore
*/
protected function assertRuntime(): void
{
// enables extra runtime assertion
}

final protected function parameters(): ParametersInterface
{
if ($this->parameters === null) {
$this->parameters = getParameters(static::class);
}

return $this->parameters;
}

final protected static function runMethodFQN(): string
{
return static::class . '::' . static::RUN_METHOD;
}
}
44 changes: 44 additions & 0 deletions src/Controller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

/*
* This file is part of Chevere.
*
* (c) Rodolfo Berrios <rodolfo@chevere.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Chevere\Action;

use Chevere\Action\Interfaces\ControllerInterface;
use Chevere\Parameter\Interfaces\StringParameterInterface;
use InvalidArgumentException;
use function Chevere\Message\message;

abstract class Controller extends Action implements ControllerInterface
{
protected static function assertStatic(): void
{
$invalid = [];
foreach (getParameters(static::class) as $name => $parameter) {
if (! ($parameter instanceof StringParameterInterface)) {
$invalid[] = $name;
}
}
if ($invalid === []) {
return;
}

throw new InvalidArgumentException(
(string) message(
'Parameter `%parameters%` must be of type **%type%** for controller **%className%**',
parameters: implode(', ', $invalid),
type: 'string',
className: static::class
)
);
}
}
36 changes: 36 additions & 0 deletions src/ControllerName.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

/*
* This file is part of Chevere.
*
* (c) Rodolfo Berrios <rodolfo@chevere.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Chevere\Action;

use Chevere\Action\Interfaces\ControllerInterface;
use Chevere\Action\Interfaces\ControllerNameInterface;
use InvalidArgumentException;

final class ControllerName implements ControllerNameInterface
{
public function __construct(
private string $name
) {
if (is_subclass_of($this->name, ControllerInterface::class)) {
return;
}

throw new InvalidArgumentException();
}

public function __toString(): string
{
return $this->name;
}
}
Loading

0 comments on commit 4c2aec7

Please sign in to comment.