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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/vendor/
composer.lock
composer.lock
.idea
5 changes: 2 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
language: php

php:
- 5.6
- 7.0
- 7.1
- hhvm
- 7.2
- 7.3

env:
- DEPS=lowest
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Create instance of middleware as you want (we use [named constructors](http://ve
```php
$date = DateTime::createFromFormat('Y-m-d H:i:s', '2025-11-30 11:12:13');

$middleware = MaintenanceMiddleware::createWithRetryAsDateTime($date);
$middleware = MaintenanceMiddleware::createWithRetryAsDateTime($date, $psr17ResponseFactory);

$middlewareRunner->add(middleware);
$middlewareRunner->run();
Expand All @@ -28,4 +28,6 @@ Use composer!

```bash
composer require php-middleware/maintenance
```
```

This package require [PSR-17 message factory](https://packagist.org/providers/psr/http-factory-implementation) implementation to return SEO friendly response.
16 changes: 10 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,21 @@
"middleware",
"psr",
"psr-7",
"maintenance"
"maintenance",
"psr-15",
"psr-17"
],
"require": {
"php": ">=5.6",
"php": ">=7.1",
"psr/http-factory": "^1.0",
"psr/http-factory-implementation": "^1.0",
"psr/http-message": "^1.0",
"php-middleware/double-pass-compatibility": "^1.0",
"http-interop/http-middleware": "^0.4.1"
"psr/http-server-middleware": "^1.0",
"psr/http-server-handler": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^5.6 || ^6.1",
"zendframework/zend-diactoros": "^1.1.3"
"phpunit/phpunit": "^7.3",
"zendframework/zend-diactoros": "^2.0"
},
"autoload": {
"psr-4": {
Expand Down
2 changes: 1 addition & 1 deletion phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<phpunit bootstrap="./vendor/autoload.php" colors="true">
<testsuites>
<testsuite>
<testsuite name="Unit">
<directory>./test</directory>
</testsuite>
</testsuites>
Expand Down
78 changes: 27 additions & 51 deletions src/MaintenanceMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,14 @@

use DateTime;
use DateTimeInterface;
use Interop\Http\ServerMiddleware\DelegateInterface;
use Interop\Http\ServerMiddleware\MiddlewareInterface;
use InvalidArgumentException;
use PhpMiddleware\DoublePassCompatibilityTrait;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Zend\Diactoros\Response;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

final class MaintenanceMiddleware implements MiddlewareInterface
final class MaintenanceMiddleware implements RequestHandlerInterface, MiddlewareInterface
{
use DoublePassCompatibilityTrait;

/**
* @var string
*/
Expand All @@ -24,89 +21,68 @@ final class MaintenanceMiddleware implements MiddlewareInterface
* @var int
*/
private $refresh = 0;
private $responseFactory;

private function __construct()
private function __construct(ResponseFactoryInterface $responseFactory)
{
$this->responseFactory = $responseFactory;
}

/**
* @return self
*/
public static function create()
public static function create(ResponseFactoryInterface $responseFactory): self
{
return new self();
return new self($responseFactory);
}

/**
* @param int $seconds
*
* @return self
*/
public static function createWithRetryAsSeconds($seconds)
public static function createWithRetryAsSeconds(int $seconds, ResponseFactoryInterface $responseFactory): self
{
if (!is_int($seconds)) {
throw new InvalidArgumentException('Seconds must be integer');
}
$instance = new self();
$instance = new self($responseFactory);
$instance->retryAfter = (string) $seconds;

return $instance;
}

/**
* @param int $seconds
*
* @return self
*/
public static function createWithRetryAsSecondsAndRefresh($seconds)
public static function createWithRetryAsSecondsAndRefresh(int $seconds, ResponseFactoryInterface $responseFactory): self
{
$instance = self::createWithRetryAsSeconds($seconds);
$instance = self::createWithRetryAsSeconds($seconds, $responseFactory);
$instance->refresh = $seconds;

return $instance;
}

/**
* @param DateTimeInterface $datetime
*
* @return self
*/
public static function createWithRetryAsDateTime(DateTimeInterface $datetime)
public static function createWithRetryAsDateTime(DateTimeInterface $datetime, ResponseFactoryInterface $responseFactory): self
{
$instance = new self();

$instance = new self($responseFactory);
$instance->retryAfter = $datetime->format(DateTime::RFC2822);

return $instance;
}

/**
* @param DateTimeInterface $datetime
*
* @return self
*/
public static function createWithRetryAsDateTimeAndRefresh(DateTimeInterface $datetime)
public static function createWithRetryAsDateTimeAndRefresh(DateTimeInterface $datetime, ResponseFactoryInterface $responseFactory)
{
$instance = self::createWithRetryAsDateTime($datetime);
$instance = self::createWithRetryAsDateTime($datetime, $responseFactory);
$diff = time() - $datetime->getTimestamp();
$instance->refresh = $diff;

return $instance;
}

public function process(ServerRequestInterface $request, DelegateInterface $delegate)
public function handle(ServerRequestInterface $request): ResponseInterface
{
$headers = [];
$response = $this->responseFactory->createResponse(503);

if ($this->retryAfter !== '') {
$headers['Retry-After'] = $this->retryAfter;
$response = $response->withHeader('Retry-After', $this->retryAfter);

if ($this->refresh > 0) {
$headers['Refresh'] = (string) $this->refresh;
$response = $response->withHeader('Refresh', (string) $this->refresh);
}
}

return new Response('php://memory', 503, $headers);
return $response;
}

public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
return $this->handle($request);
}
}
80 changes: 38 additions & 42 deletions test/MaintenanceMiddlewareTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,40 +6,57 @@
use Exception;
use PhpMiddleware\Maintenance\MaintenanceMiddleware;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Zend\Diactoros\Response;
use Zend\Diactoros\ResponseFactory;
use Zend\Diactoros\ServerRequest;
use Zend\Diactoros\ServerRequestFactory;

class MaintenanceMiddlewareTest extends TestCase
{
private $request;
private $responseFactory;

protected function setUp()
{
$this->request = new ServerRequest();
$this->responseFactory = new ResponseFactory();
}

public function testWithoutRetry()
{
$request = new ServerRequest();
$response = new Response();
$middleware = MaintenanceMiddleware::create($this->responseFactory);

$middleware = MaintenanceMiddleware::create();
$response = $middleware->handle($this->request);

$next = function() {
throw new Exception('Next should not be called');
$this->assertSame(503, $response->getStatusCode());
$this->assertSame('', $response->getHeaderLine('Retry-After'));
}

public function testWithoutRetryAsMiddleware()
{
$middleware = MaintenanceMiddleware::create($this->responseFactory);

$requestHandler = new class implements RequestHandlerInterface {
public function handle(ServerRequestInterface $request): ResponseInterface
{
return new Response();
}
};

$response = $middleware->__invoke($request, $response, $next);
$response = $middleware->process($this->request, $requestHandler);

$this->assertSame(503, $response->getStatusCode());
$this->assertSame('', $response->getHeaderLine('Retry-After'));
}

public function testWithRetryAsSeconds()
{
$request = new ServerRequest();
$response = new Response();

$middleware = MaintenanceMiddleware::createWithRetryAsSeconds(3600);
$middleware = MaintenanceMiddleware::createWithRetryAsSeconds(3600, $this->responseFactory);

$next = function() {
throw new Exception('Next should not be called');
};

$response = $middleware->__invoke($request, $response, $next);
$response = $middleware->handle($this->request);

$this->assertSame(503, $response->getStatusCode());
$this->assertSame('3600', $response->getHeaderLine('Retry-After'));
Expand All @@ -48,16 +65,9 @@ public function testWithRetryAsSeconds()

public function testWithRetryAsSecondsWithRefresh()
{
$request = new ServerRequest();
$response = new Response();

$middleware = MaintenanceMiddleware::createWithRetryAsSecondsAndRefresh(3600);
$middleware = MaintenanceMiddleware::createWithRetryAsSecondsAndRefresh(3600, $this->responseFactory);

$next = function() {
throw new Exception('Next should not be called');
};

$response = $middleware->__invoke($request, $response, $next);
$response = $middleware->handle($this->request);

$this->assertSame(503, $response->getStatusCode());
$this->assertSame('3600', $response->getHeaderLine('Retry-After'));
Expand All @@ -66,18 +76,11 @@ public function testWithRetryAsSecondsWithRefresh()

public function testWithRetryAsDatetime()
{
$request = new ServerRequest();
$response = new Response();

$date = DateTime::createFromFormat('Y-m-d H:i:s', '2015-11-30 11:12:13');

$middleware = MaintenanceMiddleware::createWithRetryAsDateTime($date);
$middleware = MaintenanceMiddleware::createWithRetryAsDateTime($date, $this->responseFactory);

$next = function() {
throw new Exception('Next should not be called');
};

$response = $middleware->__invoke($request, $response, $next);
$response = $middleware->handle($this->request);

$this->assertSame(503, $response->getStatusCode());
$this->assertSame('Mon, 30 Nov 2015 11:12:13 +0000', $response->getHeaderLine('Retry-After'));
Expand All @@ -86,18 +89,11 @@ public function testWithRetryAsDatetime()

public function testWithRetryAsDatetimeWithRefresh()
{
$request = new ServerRequest();
$response = new Response();

$date = DateTime::createFromFormat('Y-m-d H:i:s', '2015-11-30 11:12:13');

$middleware = MaintenanceMiddleware::createWithRetryAsDateTimeAndRefresh($date);

$next = function() {
throw new Exception('Next should not be called');
};
$middleware = MaintenanceMiddleware::createWithRetryAsDateTimeAndRefresh($date, $this->responseFactory);

$response = $middleware->__invoke($request, $response, $next);
$response = $middleware->handle($this->request);

$this->assertSame(503, $response->getStatusCode());
$this->assertSame('Mon, 30 Nov 2015 11:12:13 +0000', $response->getHeaderLine('Retry-After'));
Expand Down