Skip to content

Commit

Permalink
improve attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
rodber committed Dec 6, 2023
1 parent 0a559cf commit c5a293c
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 26 deletions.
31 changes: 31 additions & 0 deletions src/Attributes/Description.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?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\Http\Attributes;

use Attribute;
use Stringable;

#[Attribute]
class Description implements Stringable
{
public function __construct(
public readonly string $description = '',
) {
}

public function __toString(): string
{
return $this->description;
}
}
26 changes: 20 additions & 6 deletions src/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
use Chevere\Parameter\Interfaces\ArgumentsInterface;
use Chevere\Parameter\Interfaces\ArrayParameterInterface;
use Chevere\Parameter\Interfaces\ArrayStringParameterInterface;
use LogicException;
use Throwable;
use function Chevere\Message\message;
use function Chevere\Parameter\arguments;
use function Chevere\Parameter\arrayp;
use function Chevere\Parameter\arrayString;
Expand All @@ -29,9 +32,9 @@ abstract class Controller extends BaseController implements ControllerInterface
private ?ArgumentsInterface $body = null;

/**
* @var array<ArgumentsInterface>
* @var ?array<ArgumentsInterface>
*/
private array $files = [];
private ?array $files = null;

public static function acceptQuery(): ArrayStringParameterInterface
{
Expand Down Expand Up @@ -98,13 +101,24 @@ final public function body(): ArgumentsInterface

final public function files(): array
{
return $this->files;
return $this->files
??= [];
}

protected function assertRuntime(): void
{
$this->query();
$this->body();
$this->files();
foreach (['query', 'body', 'files'] as $method) {
try {
$this->{$method}();
} catch (Throwable $e) {
throw new LogicException(
(string) message(
'%topic%: %message%',
topic: $method,
message: $e->getMessage()
)
);
}
}
}
}
36 changes: 29 additions & 7 deletions src/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,16 @@

namespace Chevere\Http;

use Chevere\Http\Attributes\Description;
use Chevere\Http\Attributes\Request;
use Chevere\Http\Attributes\Response;
use Chevere\Http\Interfaces\MiddlewaresInterface;
use ReflectionClass;
use ReflectionClassConstant;
use ReflectionFunction;
use ReflectionMethod;
use ReflectionParameter;
use ReflectionProperty;

function middlewares(string ...$middleware): MiddlewaresInterface
{
Expand All @@ -32,21 +38,37 @@ function requestAttribute(string $className): Request
{
// @phpstan-ignore-next-line
$reflection = new ReflectionClass($className);
$attributes = $reflection->getAttributes(Request::class);
if ($attributes === []) {
return new (Request::class)();
}

return $attributes[0]->newInstance();
// @phpstan-ignore-next-line
return getAttribute($reflection, Request::class);
}

function responseAttribute(string $className): Response
{
// @phpstan-ignore-next-line
$reflection = new ReflectionClass($className);
$attributes = $reflection->getAttributes(Response::class);

// @phpstan-ignore-next-line
return getAttribute($reflection, Response::class);
}

function descriptionAttribute(string $className): Description
{
// @phpstan-ignore-next-line
$reflection = new ReflectionClass($className);

// @phpstan-ignore-next-line
return getAttribute($reflection, Description::class);
}

// @phpstan-ignore-next-line
function getAttribute(
ReflectionClass|ReflectionFunction|ReflectionMethod|ReflectionProperty|ReflectionParameter|ReflectionClassConstant $reflection,
string $attribute
): object {
$attributes = $reflection->getAttributes($attribute);
if ($attributes === []) {
return new (Response::class)();
return new $attribute();
}

return $attributes[0]->newInstance();
Expand Down
50 changes: 43 additions & 7 deletions tests/ControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,20 @@
use Chevere\Tests\src\AcceptOptionalController;
use Chevere\Tests\src\NullController;
use InvalidArgumentException;
use LogicException;
use OutOfBoundsException;
use PHPUnit\Framework\TestCase;

final class ControllerTest extends TestCase
{
public function testAssertRuntime(): void
{
$controller = new AcceptController();
$this->expectException(LogicException::class);
$this->expectExceptionMessage('query: Missing required argument(s): `foo`');
$controller->getResponse();
}

public function testDefaults(): void
{
$controller = new NullController();
Expand Down Expand Up @@ -86,27 +96,53 @@ public function testAcceptBodyParametersOptional(): void
$this->assertSame('123', $controllerWith->body()->optional('bar')->string());
}

public function testAcceptFileParameters(): void
public function testAcceptFile(): void
{
$controller = new AcceptController();
$file = [
$myFile = [
'error' => UPLOAD_ERR_OK,
'name' => 'readme.txt',
'size' => 1313,
'size' => 12345,
'type' => 'text/plain',
'tmp_name' => '/tmp/file.yx5kVl',
];
$myImage = [
'error' => UPLOAD_ERR_OK,
'name' => 'image.png',
'size' => 1234,
'type' => 'image/png',
'tmp_name' => '/tmp/file.pnp4t1',
];
$this->assertSame([], $controller->files());
$controllerWith = $controller->withFiles([
'MyFile' => $file,
'myFile' => $myFile,
'myImage' => $myImage,
]);
$this->assertNotSame($controller, $controllerWith);
$this->assertNotEquals($controller, $controllerWith);
$myFile = $controllerWith->files()['MyFile'];
$this->assertSame($file, $myFile->toArray());
$theFile = $controllerWith->files()['myFile'];
$theImage = $controllerWith->files()['myImage'];
$this->assertSame($myFile, $theFile->toArray());
$this->assertSame($myImage, $theImage->toArray());
}

public function testAcceptFileInvalidArgument(): void
{
$controller = new AcceptController();
$this->expectException(ArgumentCountError::class);
$this->expectExceptionMessage('Missing required argument(s): `error, name, size, type, tmp_name`');
$controller->withFiles([
'myFile' => [],
]);
}

public function testAcceptFileMissingKey(): void
{
$controller = new AcceptController();
$this->expectException(OutOfBoundsException::class);
$this->expectExceptionMessage('Missing key(s) `404`');
$controller->withFiles([
'MyFile' => [],
'404' => [],
]);
}
}
15 changes: 10 additions & 5 deletions tests/src/AcceptController.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,16 @@ public static function acceptBody(): ArrayParameterInterface

public static function acceptFiles(): ArrayParameterInterface
{
return arrayp(
MyFile: file(
type: string('/^text\/plain$/')
)
);
return
arrayp(
myFile: file(
type: string('/^text\/plain$/')
)
)->withOptional(
myImage: file(
type: string('/^image\/png$/')
)
);
}

public function run(): array
Expand Down
2 changes: 1 addition & 1 deletion tests/src/AcceptOptionalController.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public static function acceptBody(): ArrayParameterInterface
public static function acceptFiles(): ArrayParameterInterface
{
return arrayp()->withOptional(
MyFile: file(
myFile: file(
type: string('/^text\/plain$/')
)
);
Expand Down

0 comments on commit c5a293c

Please sign in to comment.