Skip to content

Commit

Permalink
Add docs (#8)
Browse files Browse the repository at this point in the history
Co-authored-by: Sergei Predvoditelev <sergei@predvoditelev.ru>
  • Loading branch information
samdark and vjik committed Feb 11, 2024
1 parent 9b6eb9a commit 94901c1
Show file tree
Hide file tree
Showing 26 changed files with 333 additions and 46 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# _____ Change Log
# Yii Input HTTP Change Log

## 1.0.0 under development

Expand Down
136 changes: 101 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
[![type-coverage](https://shepherd.dev/github/yiisoft/input-http/coverage.svg)](https://shepherd.dev/github/yiisoft/input-http)
[![psalm-level](https://shepherd.dev/github/yiisoft/input-http/level.svg)](https://shepherd.dev/github/yiisoft/input-http)

The package ...
The package provides [Yii Hydrator](https://github.com/yiisoft/hydrator) attributes
to get data from [PSR-7 HTTP request](https://www.php-fig.org/psr/psr-7/) and adds extra abilities to middlewares
processed by [Yii Middleware Dispatcher](https://github.com/yiisoft/middleware-dispatcher):
- maps data from PSR-7 HTTP request to PHP DTO representing user input;
- usage Yii Hydrator parameter attributes for resolve middleware parameters.

## Requirements

Expand All @@ -31,46 +35,108 @@ composer require yiisoft/input-http

## General usage

## Testing

### Unit testing

The package is tested with [PHPUnit](https://phpunit.de/). To run tests:

```shell
./vendor/bin/phpunit
```

### Mutation testing

The package tests are checked with [Infection](https://infection.github.io/) mutation framework with
[Infection Static Analysis Plugin](https://github.com/Roave/infection-static-analysis-plugin). To run it:

```shell
./vendor/bin/roave-infection-static-analysis-plugin
First of all, you need to store a request object into request provider. There are three ways to do it:

1) Add `\Yiisoft\Input\Http\Request\Catcher\RequestCatcherMiddleware` to your application middleware stack.

2) Add `\Yiisoft\Input\Http\Request\Catcher\RequestCatcherParametersResolver` to your middleware parameters resolver
in `Yiisoft\Middleware\Dispatcher\MiddlewareFactory`. It is usually used as additional parameters resolver in composite
parameters resolver. Example parameters resolver configuration for Yii DI container:

```php
use Yiisoft\Definitions\Reference;
use Yiisoft\Input\Http\Request\Catcher\RequestCatcherParametersResolver;
use Yiisoft\Middleware\Dispatcher\CompositeParametersResolver;
use Yiisoft\Middleware\Dispatcher\ParametersResolverInterface;

ParametersResolverInterface::class => [
'class' => CompositeParametersResolver::class,
'__construct()' => [
gt Reference::to(RequestCatcherParametersResolver::class),
// ...
],
],
```

3) Manually:

```php
/**
* @var \Yiisoft\Input\Http\Request\RequestProviderInterface $requestProvider
* @var \Psr\Http\Message\ServerRequestInterface $request
*/
$requestProvider->set($request);
```

To use the package, you need to create a DTO class and mark its properties with attributes:

```php
use \Yiisoft\Input\Http\Attribute\Parameter\Query;
use \Yiisoft\Input\Http\Attribute\Parameter\Body;
use \Yiisoft\Input\Http\Attribute\Parameter\UploadedFiles;

final class EditPostInput
{
public function __construct(
#[Query]
private string $id,
#[Body]
private string $title,
#[Body]
private string $content,
#[UploadedFiles('uploads')]
private $uploads,
)
{

}

// getters

}
```

### Static analysis

The code is statically analyzed with [Psalm](https://psalm.dev/). To run static analysis:

```shell
./vendor/bin/psalm
Post id will be mapped from query parameter `id`, title and content will be mapped from request body and uploads will
be mapped from request uploaded files.

Additionally, you can fill a property from request attribute using `#[Request('attributeName')]`.
This is useful when middleware prior writes the value.

Instead of mapping each property, you can use the following:

```php
use \Yiisoft\Input\Http\Attribute\Data\FromQuery;
use \Yiisoft\Input\Http\Attribute\Data\FromBody;

#[FromQuery]
final class SearchInput
{
public function __construct(
private string $query,
private string $category,
) {}

// getters
}

#[FromBody]
final class CreateUserInput
{
public function __construct(
private string $username,
private string $email,
) {}

// getters
}
```

### Code style

Use [Rector](https://github.com/rectorphp/rector) to make codebase follow some specific rules or
use either newest or any specific version of PHP:

```shell
./vendor/bin/rector
```
`SearchInput` will be mapped from query parameters, `CreateUserInput` will be mapped from parsed request body.
Both will expect request parameters in request named same as DTO properties.

### Dependencies
## Documentation

Use [ComposerRequireChecker](https://github.com/maglnet/ComposerRequireChecker) to detect transitive
[Composer](https://getcomposer.org/) dependencies.
- [Internals](docs/internals.md)

## License

Expand Down
12 changes: 8 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
{
"name": "yiisoft/input-http",
"type": "library",
"description": "_____",
"description": "Maps data from PSR-7 HTTP request to PHP DTO representing user input.",
"keywords": [
"_____"
"yii3",
"input",
"PSR-7",
"request",
"DTO",
"mapping",
"mapper"
],
"homepage": "https://www.yiiframework.com/",
"license": "BSD-3-Clause",
Expand All @@ -25,8 +31,6 @@
"url": "https://github.com/sponsors/yiisoft"
}
],
"minimum-stability": "dev",
"prefer-stable": true,
"require": {
"php": "^8.0",
"psr/container": "^1.0|^2.0",
Expand Down
40 changes: 40 additions & 0 deletions docs/internals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Internals

## Unit testing

The package is tested with [PHPUnit](https://phpunit.de/). To run tests:

```shell
./vendor/bin/phpunit
```

## Mutation testing

The package tests are checked with [Infection](https://infection.github.io/) mutation framework with
[Infection Static Analysis Plugin](https://github.com/Roave/infection-static-analysis-plugin). To run it:

```shell
./vendor/bin/roave-infection-static-analysis-plugin
```

## Static analysis

The code is statically analyzed with [Psalm](https://psalm.dev/). To run static analysis:

```shell
./vendor/bin/psalm
```

## Code style

Use [Rector](https://github.com/rectorphp/rector) to make codebase follow some specific rules or
use either newest or any specific version of PHP:

```shell
./vendor/bin/rector
```

## Dependencies

Use [ComposerRequireChecker](https://github.com/maglnet/ComposerRequireChecker) to detect transitive
[Composer](https://getcomposer.org/) dependencies.
3 changes: 3 additions & 0 deletions src/AbstractInput.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
use Yiisoft\Hydrator\Validator\ValidatedInputInterface;
use Yiisoft\Hydrator\Validator\ValidatedInputTrait;

/**
* A base class for all validated request input DTOs.
*/
abstract class AbstractInput implements RequestInputInterface, ValidatedInputInterface
{
use ValidatedInputTrait;
Expand Down
20 changes: 20 additions & 0 deletions src/Attribute/Data/FromBody.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,21 @@
use Yiisoft\Hydrator\Attribute\Data\DataAttributeInterface;

/**
* Take data for the input DTO from the request body.
* @psalm-import-type MapType from ArrayData
*/
#[Attribute(Attribute::TARGET_CLASS)]
final class FromBody implements DataAttributeInterface
{
/**
* @param array|string|null $name The field in the request body to get data from.
* Array means a path.
* For example, `['user', 'name']` will get data from `$body['user']['name']`.
* If `null`, the whole body will be used.
* @psalm-param string|list<string>|null $name
* @param array $map Map of the input DTO property names to the request body data keys.
* @psalm-param MapType $map
* @param bool $strict Whether to throw an exception if the request body contains data that isn't in the map.
*/
public function __construct(
private string|array|null $name = null,
Expand All @@ -26,6 +33,13 @@ public function __construct(
}

/**
* Get the name of the field in the request body to get data from.
*
* Array means a path.
* For example, `['user', 'name']` will get data from `$body['user']['name']`.
* If `null`, the whole body will be used.
*
* @return array|string|null The field in the request body to get data from.
* @psalm-return string|list<string>|null
*/
public function getName(): string|array|null
Expand All @@ -34,13 +48,19 @@ public function getName(): string|array|null
}

/**
* Get the map of the input DTO property names to the request body data keys.
*
* @return array Map of the input DTO property names to the request body data keys.
* @psalm-return MapType
*/
public function getMap(): array
{
return $this->map;
}

/**
* @return bool Whether to throw an exception if the request body contains data that isn't in the map.
*/
public function isStrict(): bool
{
return $this->strict;
Expand Down
6 changes: 6 additions & 0 deletions src/Attribute/Data/FromBodyResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,14 @@

use function is_array;

/**
* Resolver for {@see FromBody} attribute.
*/
final class FromBodyResolver implements DataAttributeResolverInterface
{
/**
* @param RequestProviderInterface $requestProvider The request provider.
*/
public function __construct(
private RequestProviderInterface $requestProvider,
) {
Expand Down
24 changes: 23 additions & 1 deletion src/Attribute/Data/FromQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,21 @@
use Yiisoft\Hydrator\Attribute\Data\DataAttributeInterface;

/**
* Take data for the input DTO from the query string.
*
* @psalm-import-type MapType from ArrayData
*/
#[Attribute(Attribute::TARGET_CLASS)]
final class FromQuery implements DataAttributeInterface
{
/**
* @psalm-param string|list<string>|null $name
* @psalm-param string|list<string>|null $name The field in the query string to get data from.
* Array means a path.
* For example, `['user', 'name']` will get data from `$body['user']['name']`.
* If `null`, the whole query string will be used.
* @param array $map Map of the input DTO property names to the query string data keys.
* @psalm-param MapType $map
* @param bool $strict Whether to throw an exception if the query string contains data that isn't in the map.
*/
public function __construct(
private string|array|null $name = null,
Expand All @@ -26,6 +33,13 @@ public function __construct(
}

/**
* Get the name of the field in the query string to get data from.
*
* Array means a path.
* For example, `['user', 'name']` will get data from `$body['user']['name']`.
* If `null`, the whole query string will be used.
*
* @return array|string|null The field in the query string to get data from.
* @psalm-return string|list<string>|null
*/
public function getName(): string|array|null
Expand All @@ -34,13 +48,21 @@ public function getName(): string|array|null
}

/**
* Get the map of the input DTO property names to the query string data keys.
*
* @return array Map of the input DTO property names to the query string data keys.
* @psalm-return MapType
*/
public function getMap(): array
{
return $this->map;
}

/**
* Whether to throw an exception if the query string contains data that isn't in the map.
*
* @return bool Whether to throw an exception if the query string contains data that isn't in the map.
*/
public function isStrict(): bool
{
return $this->strict;
Expand Down
6 changes: 6 additions & 0 deletions src/Attribute/Data/FromQueryResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,14 @@

use function is_array;

/**
* Resolver for {@see FromQuery} attribute.
*/
final class FromQueryResolver implements DataAttributeResolverInterface
{
/**
* @param RequestProviderInterface $requestProvider The request provider.
*/
public function __construct(
private RequestProviderInterface $requestProvider,
) {
Expand Down

0 comments on commit 94901c1

Please sign in to comment.