Skip to content

Commit

Permalink
- allow mixed as consumer parsing result
Browse files Browse the repository at this point in the history
- new attribute for low level transfer
  • Loading branch information
Articus committed Mar 24, 2024
1 parent caf779e commit afce083
Show file tree
Hide file tree
Showing 19 changed files with 594 additions and 65 deletions.
11 changes: 7 additions & 4 deletions docs/topics/consuming.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ To use consumer for operation in your handler you just need to annotate operatio
```PHP
namespace My;
use Articus\PathHandler\Middleware;
use Articus\PathHandler\PhpAttribute as PHA;
use Psr\Http\Message\ServerRequestInterface;
Expand All @@ -29,7 +30,7 @@ class Handler
#[PHA\Consumer("*/*", "Json")]
public function handlePost(ServerRequestInterface $request)
{
$data = $request->getParsedBody();
$data = $request->getAttribute(Middleware::PARSED_BODY_ATTR_NAME)l
}
}
```
Expand All @@ -39,6 +40,7 @@ Each operation method can have several consumers. Just specify media range to de
```PHP
namespace My;
use Articus\PathHandler\Middleware;
use Articus\PathHandler\PhpAttribute as PHA;
use Psr\Http\Message\ServerRequestInterface;
Expand All @@ -50,7 +52,7 @@ class Handler
#[PHA\Consumer("multipart/form-data", "Internal")]
public function handlePost(ServerRequestInterface $request)
{
$data = $request->getParsedBody();
$data = $request->getAttribute(Middleware::PARSED_BODY_ATTR_NAME)l
}
}
```
Expand All @@ -60,6 +62,7 @@ If all operations in your handler need same consumer you can just annotate handl
```PHP
namespace My;
use Articus\PathHandler\Middleware;
use Articus\PathHandler\PhpAttribute as PHA;
use Psr\Http\Message\ServerRequestInterface;
Expand All @@ -70,12 +73,12 @@ class Handler
#[PHA\Post()]
public function handlePost(ServerRequestInterface $request)
{
$data = $request->getParsedBody();
$data = $request->getAttribute(Middleware::PARSED_BODY_ATTR_NAME)l
}
#[PHA\Patch()]
public function handlePatch(ServerRequestInterface $request)
{
$data = $request->getParsedBody();
$data = $request->getAttribute(Middleware::PARSED_BODY_ATTR_NAME)l
}
}
```
242 changes: 242 additions & 0 deletions spec/Articus/PathHandler/Attribute/AnonymousTransferSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
<?php
declare(strict_types=1);

namespace spec\Articus\PathHandler\Attribute;

use Articus\DataTransfer as DT;
use Articus\PathHandler as PH;
use LogicException;
use Mezzio\Router\RouteResult;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Psr\Http\Message\ServerRequestInterface as Request;
use stdClass;

class AnonymousTransferSpec extends ObjectBehavior
{
public function it_transfers_data_from_query(
DT\Service $dt,
Request $in,
Request $out,
DT\Strategy\StrategyInterface $strategy,
DT\Validator\ValidatorInterface $validator,
stdClass $object
)
{
$source = PH\Attribute\Transfer::SOURCE_GET;
$objectAttr = 'object';
$errorAttr = null;

$data = ['test' => 123];

$in->getQueryParams()->shouldBeCalledOnce()->willReturn($data);
$in->getAttribute($objectAttr)->shouldBeCalledOnce()->willReturn($object);
$in->withAttribute($objectAttr, $object)->shouldBeCalledOnce()->willReturn($out);

$dt->transfer($data, Argument::any(), $object, $strategy, $strategy, $validator, $strategy)->shouldBeCalledOnce()->willReturn([]);

$this->beConstructedWith($dt, $source, $strategy, $validator, $objectAttr, $errorAttr);
$this->__invoke($in)->shouldBe($out);
}

public function it_transfers_data_from_parsed_body(
DT\Service $dt,
Request $in,
Request $out,
DT\Strategy\StrategyInterface $strategy,
DT\Validator\ValidatorInterface $validator,
stdClass $object
)
{
$source = PH\Attribute\Transfer::SOURCE_POST;
$objectAttr = 'object';
$errorAttr = null;

$data = ['test' => 123];

$in->getAttribute(PH\Middleware::PARSED_BODY_ATTR_NAME)->shouldBeCalledOnce()->willReturn($data);
$in->getAttribute($objectAttr)->shouldBeCalledOnce()->willReturn($object);
$in->withAttribute($objectAttr, $object)->shouldBeCalledOnce()->willReturn($out);

$dt->transfer($data, Argument::any(), $object, $strategy, $strategy, $validator, $strategy)->shouldBeCalledOnce()->willReturn([]);

$this->beConstructedWith($dt, $source, $strategy, $validator, $objectAttr, $errorAttr);
$this->__invoke($in)->shouldBe($out);
}

public function it_transfers_data_from_headers(
DT\Service $dt,
Request $in,
Request $out,
DT\Strategy\StrategyInterface $strategy,
DT\Validator\ValidatorInterface $validator,
stdClass $object
)
{
$source = PH\Attribute\Transfer::SOURCE_HEADER;
$objectAttr = 'object';
$errorAttr = null;

$data = ['test1' => [123], 'test2' => [123, 456]];

$in->getHeaders()->shouldBeCalledOnce()->willReturn($data);
$in->getAttribute($objectAttr)->shouldBeCalledOnce()->willReturn($object);
$in->withAttribute($objectAttr, $object)->shouldBeCalledOnce()->willReturn($out);

$dt->transfer($data, Argument::any(), $object, $strategy, $strategy, $validator, $strategy)->shouldBeCalledOnce()->willReturn([]);

$this->beConstructedWith($dt, $source, $strategy, $validator, $objectAttr, $errorAttr);
$this->__invoke($in)->shouldBe($out);
}

public function it_transfers_data_from_routing(
DT\Service $dt,
Request $in,
Request $out,
DT\Strategy\StrategyInterface $strategy,
DT\Validator\ValidatorInterface $validator,
RouteResult $routing,
stdClass $object
)
{
$source = PH\Attribute\Transfer::SOURCE_ROUTE;
$objectAttr = 'object';
$errorAttr = null;

$data = ['test' => 123];

$routing->getMatchedParams()->shouldBeCalledOnce()->willReturn($data);

$in->getAttribute(RouteResult::class)->shouldBeCalledOnce()->willReturn($routing);
$in->getAttribute($objectAttr)->shouldBeCalledOnce()->willReturn($object);
$in->withAttribute($objectAttr, $object)->shouldBeCalledOnce()->willReturn($out);

$dt->transfer($data, Argument::any(), $object, $strategy, $strategy, $validator, $strategy)->shouldBeCalledOnce()->willReturn([]);

$this->beConstructedWith($dt, $source, $strategy, $validator, $objectAttr, $errorAttr);
$this->__invoke($in)->shouldBe($out);
}

public function it_throws_on_data_transfer_from_routing_if_there_is_no_routing_result(
DT\Service $dt,
Request $in,
DT\Strategy\StrategyInterface $strategy,
DT\Validator\ValidatorInterface $validator,
stdClass $object
)
{
$source = PH\Attribute\Transfer::SOURCE_ROUTE;
$objectAttr = 'object';
$errorAttr = null;

$data = ['test' => 123];

$in->getAttribute(RouteResult::class)->shouldBeCalledOnce()->willReturn(null);

$dt->transfer($data, Argument::any(), $object, $strategy, $strategy, $validator, $strategy)->shouldNotBeCalled();

$this->beConstructedWith($dt, $source, $strategy, $validator, $objectAttr, $errorAttr);
$this->shouldThrow(LogicException::class)->during('__invoke', [$in]);
}

public function it_saves_object_to_attribute_with_custom_name(
DT\Service $dt,
Request $in,
Request $out,
DT\Strategy\StrategyInterface $strategy,
DT\Validator\ValidatorInterface $validator,
stdClass $object
)
{
$source = PH\Attribute\Transfer::SOURCE_POST;
$objectAttr = 'test';
$errorAttr = null;

$data = ['test' => 123];

$in->getAttribute(PH\Middleware::PARSED_BODY_ATTR_NAME)->shouldBeCalledOnce()->willReturn($data);
$in->getAttribute($objectAttr)->shouldBeCalledOnce()->willReturn($object);
$in->withAttribute($objectAttr, $object)->shouldBeCalledOnce()->willReturn($out);

$dt->transfer($data, Argument::any(), $object, $strategy, $strategy, $validator, $strategy)->shouldBeCalledOnce()->willReturn([]);

$this->beConstructedWith($dt, $source, $strategy, $validator, $objectAttr, $errorAttr);
$this->__invoke($in)->shouldBe($out);
}

public function it_transfers_to_null_if_object_attribute_is_empty(
DT\Service $dt,
Request $in,
Request $out,
DT\Strategy\StrategyInterface $strategy,
DT\Validator\ValidatorInterface $validator
)
{
$source = PH\Attribute\Transfer::SOURCE_POST;
$objectAttr = 'object';
$errorAttr = null;

$data = ['test' => 123];
$object = null;

$in->getAttribute(PH\Middleware::PARSED_BODY_ATTR_NAME)->shouldBeCalledOnce()->willReturn($data);
$in->getAttribute($objectAttr)->shouldBeCalledOnce()->willReturn(null);
$in->withAttribute($objectAttr, $object)->shouldBeCalledOnce()->willReturn($out);

$dt->transfer($data, Argument::any(), $object, $strategy, $strategy, $validator, $strategy)->shouldBeCalledOnce()->willReturn([]);

$this->beConstructedWith($dt, $source, $strategy, $validator, $objectAttr, $errorAttr);
$this->__invoke($in)->shouldBe($out);
}

public function it_throws_on_transfer_error_if_error_attribute_name_is_not_set(
DT\Service $dt,
Request $in,
DT\Strategy\StrategyInterface $strategy,
DT\Validator\ValidatorInterface $validator,
stdClass $object
)
{
$source = PH\Attribute\Transfer::SOURCE_POST;
$objectAttr = 'object';
$errorAttr = null;

$data = ['test' => 123];
$error = ['wrong' => 456];
$exception = new PH\Exception\UnprocessableEntity($error);

$in->getAttribute(PH\Middleware::PARSED_BODY_ATTR_NAME)->shouldBeCalledOnce()->willReturn($data);
$in->getAttribute($objectAttr)->shouldBeCalledOnce()->willReturn($object);

$dt->transfer($data, Argument::any(), $object, $strategy, $strategy, $validator, $strategy)->shouldBeCalledOnce()->willReturn($error);

$this->beConstructedWith($dt, $source, $strategy, $validator, $objectAttr, $errorAttr);
$this->shouldThrow($exception)->during('__invoke', [$in]);
}

public function it_saves_transfer_error_to_error_attribute_if_its_name_is_set(
DT\Service $dt,
Request $in,
Request $out,
DT\Strategy\StrategyInterface $strategy,
DT\Validator\ValidatorInterface $validator,
stdClass $object
)
{
$source = PH\Attribute\Transfer::SOURCE_POST;
$objectAttr = 'object';
$errorAttr = 'test';

$data = ['test' => 123];
$error = ['wrong' => 456];

$in->getAttribute(PH\Middleware::PARSED_BODY_ATTR_NAME)->shouldBeCalledOnce()->willReturn($data);
$in->getAttribute($objectAttr)->shouldBeCalledOnce()->willReturn($object);
$in->withAttribute($errorAttr, $error)->shouldBeCalledOnce()->willReturn($out);

$dt->transfer($data, Argument::any(), $object, $strategy, $strategy, $validator, $strategy)->shouldBeCalledOnce()->willReturn($error);

$this->beConstructedWith($dt, $source, $strategy, $validator, $objectAttr, $errorAttr);
$this->__invoke($in)->shouldBe($out);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php
declare(strict_types=1);

namespace spec\Articus\PathHandler\Attribute\Factory;

use Articus\DataTransfer as DT;
use Articus\PluginManager\PluginManagerInterface;
use PhpSpec\ObjectBehavior;
use Psr\Container\ContainerInterface;

class AnonymousTransferSpec extends ObjectBehavior
{
public function it_builds_transfer_attribute_with_simple_config(
ContainerInterface $container,
DT\Service $dt,
PluginManagerInterface $strategyManager,
PluginManagerInterface $validatorManager,
DT\Strategy\StrategyInterface $strategy,
DT\Validator\ValidatorInterface $validator
)
{
$strategyName = 'test_strategy_name';
$strategyOptions = ['test_strategy_option' => 111];
$validatorName = 'test_validator_name';
$validatorOptions = ['test_validator_option' => 222];
$options = [
'strategy' => [$strategyName, $strategyOptions],
'validator' => [$validatorName, $validatorOptions],
];
$container->get(DT\Service::class)->shouldBeCalledOnce()->willReturn($dt);
$container->get(DT\Options::DEFAULT_STRATEGY_PLUGIN_MANAGER)->shouldBeCalledOnce()->willReturn($strategyManager);
$container->get(DT\Options::DEFAULT_VALIDATOR_PLUGIN_MANAGER)->shouldBeCalledOnce()->willReturn($validatorManager);
$strategyManager->__invoke($strategyName, $strategyOptions)->shouldBeCalledOnce()->willReturn($strategy);
$validatorManager->__invoke($validatorName, $validatorOptions)->shouldBeCalledOnce()->willReturn($validator);
$attribute = $this->__invoke($container, 'test', $options);
$attribute->shouldHaveProperty('strategy', $strategy);
$attribute->shouldHaveProperty('validator', $validator);
}
}
Loading

0 comments on commit afce083

Please sign in to comment.