Skip to content

Commit

Permalink
Merge pull request #4 from zfegg/develop
Browse files Browse the repository at this point in the history
implement PSR-15
  • Loading branch information
Moln committed Mar 27, 2018
2 parents 01eddd1 + 095b0ca commit b0e7adb
Show file tree
Hide file tree
Showing 8 changed files with 251 additions and 93 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ language: php
matrix:
fast_finish: true
include:
- php: 7
- php: 7.1
env:
- EXECUTE_TEST_COVERALLS=true
- CS_CHECK=true
Expand Down
9 changes: 6 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@
"name": "zfegg/content-validation",
"description": "Content validation for PSR-7 http message and zend-mvc",
"require": {
"php":"^7.1",
"zendframework/zend-inputfilter": "^2.7",
"zendframework/zend-servicemanager": "^3.1"
"zendframework/zend-servicemanager": "^3.1",
"psr/http-server-middleware": "^1.0"
},
"license": "MIT",
"require-dev": {
"squizlabs/php_codesniffer": "^2.7",
"phpunit/phpunit": "^6",
"zendframework/zend-mvc": "^3.0",
"zendframework/zend-eventmanager": "^3.0",
"psr/http-message": "^1.0",
"zendframework/zend-diactoros": "^1.3"
"zendframework/zend-diactoros": "^1.3",
"zendframework/zend-expressive-router": "^3.0",
"slim/slim": "^3.9"
},
"autoload": {
"psr-4": {
Expand Down
133 changes: 75 additions & 58 deletions src/ContentValidationMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\UploadedFileInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Zend\InputFilter\InputFilterInterface;
use Zend\InputFilter\InputFilterPluginManager;

Expand All @@ -13,36 +15,15 @@
*
* @package Zfegg\Psr7Middleware
*/
class ContentValidationMiddleware
class ContentValidationMiddleware implements MiddlewareInterface
{
use ContentValidationTrait;

const INPUT_FILTER_NAME = 'Zfegg\ContentValidation\InputFilter';
const INPUT_FILTER = 'input_filter';

protected $inputFilter;

protected $requestInputFilterKeyName = self::INPUT_FILTER;

/**
* @return string
*/
public function getRequestInputFilterKeyName()
{
return $this->requestInputFilterKeyName;
}

/**
* @param string $requestInputFilterKeyName
*
* @return $this
*/
public function setRequestInputFilterKeyName($requestInputFilterKeyName)
{
$this->requestInputFilterKeyName = $requestInputFilterKeyName;

return $this;
}
protected $responseFactory;

/**
* @return InputFilterInterface
Expand All @@ -66,48 +47,43 @@ public function setInputFilter(InputFilterInterface $inputFilter)

public function __construct(
InputFilterPluginManager $inputFilters = null,
callable $invalidHandler = null
?callable $invalidHandler = null,
?callable $responseFactory = null
) {
$defaultInvalidHandler =
function ($self, $request, ResponseInterface $response, $next) {
$response = $response->withStatus(422);
$response =
$response->withHeader('Content-Type', 'application/json');
$response->getBody()->write(
json_encode(
[
'status' => 422,
'detail' => 'Failed Validation',
'validation_messages' => $this->getInputFilter()
->getMessages()
]
)
);

return $response;
};

$this->setInvalidHandler($invalidHandler ?: $defaultInvalidHandler);

if ($inputFilters) {
$this->setInputFilterManager($inputFilters);
}

$this->setInvalidHandler(
$invalidHandler ?: $this->getDefaultInvalidHandler()
);

if ($responseFactory) {
$this->setResponseFactory($responseFactory);
}
}

public function __invoke(
/**
* @param callable $responseFactory
*/
public function setResponseFactory(callable $responseFactory)
{
$this->responseFactory = $responseFactory;
}

public function process(
ServerRequestInterface $request,
ResponseInterface $response,
callable $next
) {
RequestHandlerInterface $handler
): ResponseInterface {
$inputFilterName = $request->getAttribute(self::INPUT_FILTER_NAME);

if (! $inputFilterName) {
return $next($request, $response);
return $handler->handle($request);
}

$inputFilters = $this->getInputFilterManager();
if (! $inputFilters->has($inputFilterName)) {
return $next($request, $response);
return $handler->handle($request);
}

$inputFilter = $inputFilters->get($inputFilterName);
Expand All @@ -120,7 +96,7 @@ public function __invoke(
} elseif (in_array($request->getMethod(), ['POST', 'PUT', 'PATCH'])) {
$data = $request->getParsedBody();
} else {
return $next($request, $response);
return $handler->handle($request);
}

/** @var UploadedFileInterface[] $files */
Expand All @@ -137,10 +113,15 @@ public function __invoke(
if (! $inputFilter->isValid()) {
$invalidHandler = $this->getInvalidHandler();

return $invalidHandler($this, $request, $response, $next);
return $invalidHandler(
$this,
$request,
$handler,
($this->responseFactory)()
);
}

return $next($request, $response);
return $handler->handle($request);
}


Expand All @@ -158,11 +139,11 @@ public static function psr2ArrayFiles(array $psrFiles)
foreach ($psrFiles as $name => $file) {
if ($file instanceof UploadedFileInterface) {
$files[$name] = [
'name' => $file->getClientFilename(),
'type' => $file->getClientMediaType(),
'name' => $file->getClientFilename(),
'type' => $file->getClientMediaType(),
'tmp_name' => $file->getStream()->getMetadata('uri'),
'error' => $file->getError(),
'size' => $file->getSize()
'error' => $file->getError(),
'size' => $file->getSize(),
];
} elseif (is_array($file)) {
$files[$name] = self::psr2ArrayFiles($file);
Expand Down Expand Up @@ -194,4 +175,40 @@ public function setInvalidHandler(callable $invalidHandler)

return $this;
}

public function getDefaultInvalidHandler()
{
return function (
$self,
$request,
RequestHandlerInterface $handler,
ResponseInterface $response = null
) {
if (! $response) {
throw new Exception\InvalidRequestException(
'Failed Validation.',
422,
$this->getInputFilter()
);
}

$response = $response->withStatus(422);
$response = $response->withHeader(
'Content-Type',
'application/json'
);
$response->getBody()->write(
json_encode(
[
'status' => 422,
'detail' => 'Failed Validation',
'validation_messages' => $this->getInputFilter()
->getMessages(),
]
)
);

return $response;
};
}
}
23 changes: 18 additions & 5 deletions src/ContentValidationMiddlewareFactory.php
Original file line number Diff line number Diff line change
@@ -1,18 +1,31 @@
<?php


namespace Zfegg\ContentValidation;

use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Zend\InputFilter\InputFilterPluginManager;

class ContentValidationMiddlewareFactory
{

public function __invoke(ContainerInterface $container)
{
return new ContentValidationMiddleware(
$container->get(InputFilterPluginManager::class)
public function __invoke(
ContainerInterface $container,
$requestedName = null,
array $options = null
) {
$requestedName = $requestedName ?: ContentValidationMiddleware::class;

$response = $container->has(ResponseInterface::class) ?
$container->get(ResponseInterface::class) : null;

$inputFilterManager = $container->has(InputFilterPluginManager::class) ?
$container->get(InputFilterPluginManager::class) : null;

return new $requestedName(
$inputFilterManager,
null,
$response
);
}
}
21 changes: 21 additions & 0 deletions src/Exception/InvalidRequestException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php


namespace Zfegg\ContentValidation\Exception;

class InvalidRequestException extends \RuntimeException
{
protected $inputFilter;

public function __construct($msg, $code, $inputFilter, $previous = null)
{
parent::__construct($msg, $code, $previous);

$this->inputFilter = $inputFilter;
}

public function getInputFilter()
{
return $this->inputFilter;
}
}
30 changes: 30 additions & 0 deletions src/RouteNameContentValidationMiddleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace Zfegg\ContentValidation;

use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Psr\Http\Message\ResponseInterface;

class RouteNameContentValidationMiddleware extends ContentValidationMiddleware
{
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
// Set expressive route name or slim route name
if ($route = $request->getAttribute('Zend\Expressive\Router\RouteResult')) {
$request = $request->withAttribute(
ContentValidationMiddleware::INPUT_FILTER_NAME,
$route->getMatchedRouteName()
);
} elseif ($route = $request->getAttribute('route')) {
$request = $request->withAttribute(
ContentValidationMiddleware::INPUT_FILTER_NAME,
$route->getName() ? : $route->getIdentifier()
);
}

return parent::process($request, $handler);
}
}
Loading

0 comments on commit b0e7adb

Please sign in to comment.