Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

### Added

- `Pipe->endpoint()->{method}()` pattern

### Fixed

- `Any::from()` was erasing guarded errors
Expand Down
46 changes: 46 additions & 0 deletions proofs/pipe.php
Original file line number Diff line number Diff line change
Expand Up @@ -338,4 +338,50 @@ static function($assert, $method, $other, $protocolVersion) {
);
},
);

yield proof(
'Pipe->endpoint()->method()->handle()',
given(
Set::of(...Http\Method::cases()),
Set::of(...Http\ProtocolVersion::cases()),
),
static function($assert, $method, $protocolVersion) {
$request = Http\ServerRequest::of(
Url::of('/foo'),
$method,
$protocolVersion,
);
$expected = Http\Response::of(
Http\Response\StatusCode::ok,
$request->protocolVersion(),
);
$router = Router::of(
Pipe::new()
->endpoint('{/watev}')
->{$method->name}()
->handle(static function($in, $input) use ($assert, $request, $expected) {
$assert->same($request, $in);
$assert->same(
'foo',
$input
->get('watev')
->match(
static fn($value) => $value,
static fn() => null,
),
);

return Attempt::result($expected);
}),
);

$assert->same(
$expected,
$router($request)->match(
static fn($response) => $response,
static fn($error) => $error,
),
);
},
);
};
100 changes: 100 additions & 0 deletions src/Pipe/Endpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
Component\Like,
Handle,
Any,
Method,
};
use Innmind\Http\{
ServerRequest,
Expand Down Expand Up @@ -67,6 +68,105 @@ public function spread(): Endpoint\Spread
return Endpoint\Spread::of($this->endpoint);
}

#[\NoDiscard]
public function get(): Endpoint\Method
{
return Endpoint\Method::of(
$this->endpoint,
Method::get(),
);
}

#[\NoDiscard]
public function post(): Endpoint\Method
{
return Endpoint\Method::of(
$this->endpoint,
Method::post(),
);
}

#[\NoDiscard]
public function put(): Endpoint\Method
{
return Endpoint\Method::of(
$this->endpoint,
Method::put(),
);
}

#[\NoDiscard]
public function patch(): Endpoint\Method
{
return Endpoint\Method::of(
$this->endpoint,
Method::patch(),
);
}

#[\NoDiscard]
public function delete(): Endpoint\Method
{
return Endpoint\Method::of(
$this->endpoint,
Method::delete(),
);
}

#[\NoDiscard]
public function options(): Endpoint\Method
{
return Endpoint\Method::of(
$this->endpoint,
Method::options(),
);
}

#[\NoDiscard]
public function trace(): Endpoint\Method
{
return Endpoint\Method::of(
$this->endpoint,
Method::trace(),
);
}

#[\NoDiscard]
public function connect(): Endpoint\Method
{
return Endpoint\Method::of(
$this->endpoint,
Method::connect(),
);
}

#[\NoDiscard]
public function head(): Endpoint\Method
{
return Endpoint\Method::of(
$this->endpoint,
Method::head(),
);
}

#[\NoDiscard]
public function link(): Endpoint\Method
{
return Endpoint\Method::of(
$this->endpoint,
Method::link(),
);
}

#[\NoDiscard]
public function unlink(): Endpoint\Method
{
return Endpoint\Method::of(
$this->endpoint,
Method::unlink(),
);
}

/**
* @no-named-arguments
*
Expand Down
80 changes: 80 additions & 0 deletions src/Pipe/Endpoint/Method.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php
declare(strict_types = 1);

namespace Innmind\Router\Pipe\Endpoint;

use Innmind\Router\{
Component,
Component\Provider,
Component\Like,
Handle,
};
use Innmind\Http;
use Innmind\Immutable\{
Attempt,
Map,
};

/**
* @psalm-immutable
* @implements Provider<mixed, Map<string, string>>
*/
final class Method implements Provider
{
/** @use Like<mixed, Map<string, string>> */
use Like;

/**
* @param Component<mixed, Map<string, string>> $endpoint
* @param Component<mixed, Http\Method> $method
*/
private function __construct(
private Component $endpoint,
private Component $method,
) {
}

/**
* @internal
* @psalm-pure
*
* @param Component<mixed, Map<string, string>> $endpoint
* @param Component<mixed, Http\Method> $method
*/
#[\NoDiscard]
public static function of(Component $endpoint, Component $method): self
{
return new self($endpoint, $method);
}

/**
* @param callable(Http\ServerRequest, Map<string, string>): Attempt<Http\Response> $handle
*
* @return Component<mixed, Http\Response>
*/
#[\NoDiscard]
public function handle(callable $handle): Component
{
return $this
->toComponent()
->feed(Handle::via($handle));
}

public function spread(): Method\Spread
{
return Method\Spread::of($this->toComponent());
}

#[\Override]
public function toComponent(): Component
{
$method = $this->method;

/**
* @psalm-suppress MixedArgumentTypeCoercion
*/
return $this->endpoint->guard(
static fn($input) => $method->map(static fn() => $input),
);
}
}
52 changes: 52 additions & 0 deletions src/Pipe/Endpoint/Method/Spread.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php
declare(strict_types = 1);

namespace Innmind\Router\Pipe\Endpoint\Method;

use Innmind\Router\{
Component,
Handle,
};
use Innmind\Http;
use Innmind\Immutable\{
Attempt,
Map,
};

/**
* @psalm-immutable
*/
final class Spread
{
/**
* @param Component<mixed, Map<string, string>> $previous
*/
private function __construct(
private Component $previous,
) {
}

/**
* @internal
* @psalm-pure
*
* @param Component<mixed, Map<string, string>> $previous
*/
#[\NoDiscard]
public static function of(Component $previous): self
{
return new self($previous);
}

/**
* @param callable(...mixed): Attempt<Http\Response> $handle
*
* @return Component<mixed, Http\Response>
*/
#[\NoDiscard]
public function handle(callable $handle): Component
{
/** @psalm-suppress MixedArgumentTypeCoercion */
return $this->previous->feed(Handle::of($handle));
}
}