Skip to content

Commit

Permalink
Change middleware stoppage and refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
thiagodp committed Nov 4, 2023
1 parent 86658b5 commit e5868a6
Show file tree
Hide file tree
Showing 15 changed files with 212 additions and 98 deletions.
19 changes: 6 additions & 13 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,6 @@
"description": "ExpressJS-like router for PHP",
"type": "library",
"license": "MIT",
"scripts": {
"test": "kahlan",
"test2": "kahlan --reporter=verbose",
"cov": "kahlan --coverage",
"check": "phpstan analyze src",
"l1": "phpstan analyze src --level=1"
},
"require": {
"php": ">=7.4",
"ext-mbstring": "*",
Expand All @@ -25,10 +18,10 @@
"phputil\\router\\": "src/"
}
},
"authors": [
{
"name": "Thiago Delgado Pinto",
"email": "[email protected]"
}
]
"scripts": {
"test": "kahlan",
"test2": "kahlan --reporter=verbose",
"cov": "kahlan --coverage",
"check": "phpstan analyze src --level=3"
}
}
3 changes: 3 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
- Unit-tested
- Mockable - it's easy to create automated tests for your API

👉 Do **NOT** use it in production yet - just for toy projects.

## Installation

> Requires PHP 7.4+
Expand Down Expand Up @@ -537,6 +539,7 @@ interface HttpResponse {
}
```


### Mocking an HTTP request

👉 Useful for API testing
Expand Down
16 changes: 16 additions & 0 deletions spec/router/router.spec.php
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,22 @@
expect( $count )->toBe( 11 );
} );


it( 'works with OPTIONS', function() {
// Faking the request
$this->fakeReq->withURL( '/foo' )->withMethod( 'OPTIONS' );

$count = 0;
$callback = function( $req, $res, &$stop ) use ( &$count ) { $count++; };
$this->router
->use( $callback )
->options( '/foo' );

list( $ok ) = $this->router->listen( [ 'req' => $this->fakeReq ] );
expect( $ok )->toBe( true );
expect( $count )->toBeGreaterThan( 0 );
} );

} );


Expand Down
11 changes: 7 additions & 4 deletions src/Entry.php
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
<?php
namespace phputil\router;

const ENTRY_HTTP = 'h';
const ENTRY_GROUP = 'g';
const ENTRY_MIDDLEWARE = 'm';
use function str_replace;
use function implode;

interface Entry {
function type();
}

const ENTRY_HTTP = 'h';
const ENTRY_GROUP = 'g';
const ENTRY_MIDDLEWARE = 'm';

/**
* Join routes in a single URL path.
*/
function joinRoutes( array $routes ) {
return \str_replace( '//', '/', \implode( '/', $routes ) );
return str_replace( '//', '/', implode( '/', $routes ) );
}

?>
9 changes: 7 additions & 2 deletions src/GroupEntry.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
require_once 'Entry.php';
require_once 'RouteBasedEntry.php';

use LogicException;

use function is_array;


class GroupEntry extends RouteBasedEntry {

function __construct( $route ) {
Expand Down Expand Up @@ -55,9 +60,9 @@ function all( $route, callable ...$callbacks ) {

protected function addEntry( $route, $httpMethod, array $callbacks ) {
if ( ! isHttpMethodValid( $httpMethod ) ) {
throw new \LogicException( "Invalid HTTP method: $httpMethod" );
throw new LogicException( "Invalid HTTP method: $httpMethod" );
}
if ( \is_array( $route ) ) {
if ( is_array( $route ) ) {
foreach ( $route as $str ) {
$this->children []= new HttpEntry( $str, $httpMethod, $callbacks );
}
Expand Down
2 changes: 1 addition & 1 deletion src/HttpResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ function json( $body ): HttpResponse;
*
* @param bool clear If it is desired to clear the headers and the body after sending them. It defaults to `true`.
*/
function end( $clear = true ): HttpResponse;
function end( bool $clear = true ): HttpResponse;
}

?>
5 changes: 4 additions & 1 deletion src/RealHttpRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
require_once 'ExtraData.php';
require_once 'request.php';

use function file_get_contents;


/**
* Real HTTP request.
*/
Expand Down Expand Up @@ -53,7 +56,7 @@ function header( $name ): ?string {

/** @inheritDoc */
function rawBody(): ?string {
$content = \file_get_contents( 'php://input' );
$content = file_get_contents( 'php://input' );
return $content === false ? null : $content;
}

Expand Down
64 changes: 42 additions & 22 deletions src/RealHttpResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,26 @@
require_once 'mime.php';
require_once 'headers.php';

use LogicException;
use RuntimeException;

use function array_key_exists;
use function array_search;
use function basename;
use function filesize;
use function get_object_vars;
use function header;
use function http_response_code;
use function is_array;
use function is_null;
use function is_object;
use function is_readable;
use function is_string;
use function json_encode;
use function mb_strlen;
use function mb_strripos;


const MSG_HEADER_VALUE_CANNOT_BE_NULL = 'Header value cannot be null.';
const MSG_HEADER_KEY_MUST_BE_STRING = 'Header key must be a string.';
const MSG_HEADER_PARAMETER_INVALID = 'Invalid header type. Accepted: string, array.';
Expand All @@ -31,7 +51,7 @@ public function __construct( $avoidOutput = false, $avoidClearing = false ) {
//

function dump() {
return \get_object_vars( $this );
return get_object_vars( $this );
}

function dumpObject() {
Expand Down Expand Up @@ -69,15 +89,15 @@ function header( $header, $value = null ): HttpResponse {
$this->setHeader( $h, $v );
}
} else {
throw new \LogicException( MSG_HEADER_PARAMETER_INVALID );
throw new LogicException( MSG_HEADER_PARAMETER_INVALID );
}
return $this;
}

/** @inheritDoc */
function redirect( $statusCode, $path = null ): HttpResponse {
$this->status( $statusCode );
if ( ! \is_null( $path ) ) {
if ( ! is_null( $path ) ) {
$this->setHeader( HEADER_LOCATION, $path );
}
return $this;
Expand All @@ -99,11 +119,11 @@ function cookie( string $name, string $value, array $options = [] ): HttpRespons

$opt = [];
foreach ( $options as $key => $value ) {
if ( \array_key_exists( $key, $fromToKeys ) ) {
if ( array_key_exists( $key, $fromToKeys ) ) {
$opt[ $fromToKeys[ $key ] ] = $value;
continue;
}
if ( \array_search( $key, $fromToKeys ) === false ) {
if ( array_search( $key, $fromToKeys ) === false ) {
continue;
}
$opt[ $key ] = $value;
Expand All @@ -130,29 +150,29 @@ function clearCookie( $name, array $options = [] ): HttpResponse {
}

private function setHeader( $header, $value ): HttpResponse {
if ( ! \is_string( $header ) ) {
throw new \LogicException( MSG_HEADER_KEY_MUST_BE_STRING );
if ( ! is_string( $header ) ) {
throw new LogicException( MSG_HEADER_KEY_MUST_BE_STRING );
}
if ( \is_null( $value ) ) {
throw new \LogicException( MSG_HEADER_VALUE_CANNOT_BE_NULL );
if ( is_null( $value ) ) {
throw new LogicException( MSG_HEADER_VALUE_CANNOT_BE_NULL );
}
$this->headers[ $header ] = $value;
return $this;
}

/** @inheritDoc */
function type( $mime, $useUTF8 = true ): HttpResponse {
$value = ( \mb_strlen( $mime ) <= 4 && isset( SHORT_MIMES[ $mime ] ) )
$value = ( mb_strlen( $mime ) <= 4 && isset( SHORT_MIMES[ $mime ] ) )
? SHORT_MIMES[ $mime ] : $mime;
if ( $useUTF8 && \mb_strripos( $value, 'text/' ) === 0 && \mb_strripos( $value, 'charset' ) !== false ) {
if ( $useUTF8 && mb_strripos( $value, 'text/' ) === 0 && mb_strripos( $value, 'charset' ) !== false ) {
$value .= ';charset=UTF-8';
}
return $this->setHeader( HEADER_CONTENT_TYPE, $value );
}

/** @inheritDoc */
function send( $body ): HttpResponse {
if ( \is_array( $body ) || \is_object( $body ) ) {
if ( is_array( $body ) || is_object( $body ) ) {
return $this->json( $body );
}
$this->body []= $body;
Expand All @@ -162,8 +182,8 @@ function send( $body ): HttpResponse {
/** @inheritDoc */
function json( $body ): HttpResponse {
$this->setHeader( HEADER_CONTENT_TYPE, MIME_JSON_UTF8 );
if ( \is_array( $body ) || \is_object( $body ) ) {
$result = \json_encode( $body );
if ( is_array( $body ) || is_object( $body ) ) {
$result = json_encode( $body );
if ( $result === false ) {
throw new HttpException( MSG_JSON_ENCODING_ERROR );
}
Expand All @@ -177,18 +197,18 @@ function json( $body ): HttpResponse {
/** @inheritDoc */
function sendFile( $path, $options = [] ): HttpResponse {

if ( ! \is_readable( $path ) ) {
throw new \RuntimeException( 'File not found or not readable.' );
if ( ! is_readable( $path ) ) {
throw new RuntimeException( 'File not found or not readable.' );
}

$mime = ( \is_array( $options ) && isset( $options[ 'mime' ] ) )
$mime = ( is_array( $options ) && isset( $options[ 'mime' ] ) )
? $options[ 'mime' ] : getFileMime( $path );
if ( ! isset( $mime ) ) {
throw new \RuntimeException( 'MIME type could not be defined. Please inform it.' );
throw new RuntimeException( 'MIME type could not be defined. Please inform it.' );
}

$fileSize = \filesize( $path );
$fileDisposition = 'attachment; path=' . \basename( $path );
$fileSize = filesize( $path );
$fileDisposition = 'attachment; path=' . basename( $path );

$this->status( 200 );
$this->header( [
Expand Down Expand Up @@ -225,10 +245,10 @@ function end( $clear = true ): HttpResponse {

protected function sendHeaders( $clear ): void {
if ( $this->statusCode !== 0 ) {
\http_response_code( $this->statusCode );
http_response_code( $this->statusCode );
}
foreach ( $this->headers as $header => $value ) {
@\header( $header . HEADER_TO_VALUE_SEPARATOR . $value );
@header( $header . HEADER_TO_VALUE_SEPARATOR . $value );
}
if ( $clear && ! $this->avoidClearing ) {
$this->headers = [];
Expand Down
Loading

0 comments on commit e5868a6

Please sign in to comment.