diff --git a/README.md b/README.md
index cc88e87..b8850ad 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
[![Latest Stable Version](https://poser.pugx.org/donatj/mock-webserver/version)](https://packagist.org/packages/donatj/mock-webserver)
[![License](https://poser.pugx.org/donatj/mock-webserver/license)](https://packagist.org/packages/donatj/mock-webserver)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/donatj/mock-webserver/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/donatj/mock-webserver)
-[![Build Status](https://github.com/donatj/mock-webserver/workflows/CI/badge.svg?)](https://github.com/donatj/mock-webserver/actions?query=workflow%3ACI)
+[![CI](https://github.com/donatj/mock-webserver/workflows/CI/badge.svg?)](https://github.com/donatj/mock-webserver/actions?query=workflow%3ACI)
[![Build Status](https://travis-ci.org/donatj/mock-webserver.svg?branch=master)](https://travis-ci.org/donatj/mock-webserver)
@@ -101,7 +101,7 @@ require __DIR__ . '/../vendor/autoload.php';
$server = new MockWebServer;
$server->start();
-// We define the servers response to requests of the /definedPath endpoint
+// We define the server's response to requests of the /definedPath endpoint
$url = $server->setResponseOfPath(
'/definedPath',
new Response(
@@ -137,6 +137,53 @@ Content-type: text/html; charset=UTF-8
This is our http body response
```
+### Change Default Response
+
+```php
+start();
+
+// The default response is donatj\MockWebServer\Responses\DefaultResponse
+// which returns an HTTP 200 and a descriptive JSON payload.
+//
+// Change the default response to donatj\MockWebServer\Responses\NotFoundResponse
+// to get a standard 404.
+//
+// Any other response may be specified as default as well.
+$server->setDefaultResponse(new NotFoundResponse);
+
+$content = file_get_contents($server->getServerRoot() . '/PageDoesNotExist', false, stream_context_create([
+ 'http' => [ 'ignore_errors' => true ] // allow reading 404s
+]));
+
+// $http_response_header is a little known variable magically defined
+// in the current scope by file_get_contents with the response headers
+echo implode("\n", $http_response_header) . "\n\n";
+echo $content . "\n";
+
+```
+
+Outputs:
+
+```
+HTTP/1.0 404 Not Found
+Host: 127.0.0.1:61355
+Date: Mon, 30 Aug 2021 20:02:58 GMT
+Connection: close
+X-Powered-By: PHP/7.3.29
+Content-type: text/html; charset=UTF-8
+
+VND.DonatStudios.MockWebServer: Resource '/PageDoesNotExist' not found!
+
+```
+
### PHPUnit
```php
diff --git a/docs/docs.md b/docs/docs.md
index 3f43441..707371b 100644
--- a/docs/docs.md
+++ b/docs/docs.md
@@ -115,6 +115,24 @@ Set a specified path to provide a specific response
---
+### Method: MockWebServer->setDefaultResponse
+
+```php
+function setDefaultResponse(\donatj\MockWebServer\ResponseInterface $response)
+```
+
+Override the default server response, e.g. Fallback or 404
+
+#### Parameters:
+
+- ***\donatj\MockWebServer\ResponseInterface*** `$response`
+
+#### Returns:
+
+- ***void***
+
+---
+
### Method: MockWebServer->getLastRequest
```php
@@ -273,4 +291,16 @@ Set the Response for the Given Method
#### Parameters:
- ***string*** `$method`
-- ***\donatj\MockWebServer\ResponseInterface*** `$response`
\ No newline at end of file
+- ***\donatj\MockWebServer\ResponseInterface*** `$response`
+
+## Built-In Responses
+
+### Class: \donatj\MockWebServer\Responses\DefaultResponse
+
+The Built-In Default Response.
+
+Results in an HTTP 200 with a JSON encoded version of the incoming Request
+
+### Class: \donatj\MockWebServer\Responses\NotFoundResponse
+
+Basic Built-In 404 Response
\ No newline at end of file
diff --git a/example/simple.php b/example/simple.php
index 87d9b05..c8c940f 100644
--- a/example/simple.php
+++ b/example/simple.php
@@ -8,7 +8,7 @@
$server = new MockWebServer;
$server->start();
-// We define the servers response to requests of the /definedPath endpoint
+// We define the server's response to requests of the /definedPath endpoint
$url = $server->setResponseOfPath(
'/definedPath',
new Response(
diff --git a/mddoc.xml b/mddoc.xml
index 9fb7755..e75b67f 100644
--- a/mddoc.xml
+++ b/mddoc.xml
@@ -28,6 +28,10 @@ I would be happy to accept pull requests that correct this.
+
@@ -49,6 +53,11 @@ I would be happy to accept pull requests that correct this.
Outputs:
+
diff --git a/src/InternalServer.php b/src/InternalServer.php
index 10d83e0..0cd1f37 100644
--- a/src/InternalServer.php
+++ b/src/InternalServer.php
@@ -3,6 +3,8 @@
namespace donatj\MockWebServer;
use donatj\MockWebServer\Exceptions\ServerException;
+use donatj\MockWebServer\Responses\DefaultResponse;
+use donatj\MockWebServer\Responses\NotFoundResponse;
/**
* Class InternalServer
@@ -24,6 +26,8 @@ class InternalServer {
*/
private $header;
+ const DEFAULT_REF = 'default';
+
/**
* InternalServer constructor.
*
@@ -82,83 +86,121 @@ public static function aliasPath( $tmpPath, $path ) {
);
}
+ /**
+ * @param string $ref
+ * @return ResponseInterface|null
+ */
+ private function responseForRef( $ref ) {
+ $path = $this->tmpPath . DIRECTORY_SEPARATOR . $ref;
+ if( !is_readable($path) ) {
+ return null;
+ }
+
+ $content = file_get_contents($path);
+ $response = unserialize($content);
+ if( !$response instanceof ResponseInterface ) {
+ throw new ServerException('invalid serialized response');
+ }
+
+ return $response;
+ }
+
public function __invoke() {
- $path = $this->getDataPath();
-
- if( $path !== false ) {
- if( is_readable($path) ) {
- $content = file_get_contents($path);
- $response = unserialize($content);
- if( !$response instanceof ResponseInterface ) {
- throw new ServerException('invalid serialized response');
- }
-
- http_response_code($response->getStatus($this->request));
-
- foreach( $response->getHeaders($this->request) as $key => $header ) {
- if( is_int($key) ) {
- call_user_func($this->header, $header);
- } else {
- call_user_func($this->header, "{$key}: {$header}");
- }
- }
- $body = $response->getBody($this->request);
-
- if( $response instanceof MultiResponseInterface ) {
- $response->next();
- self::storeResponse($this->tmpPath, $response);
- }
-
- echo $body;
+ $ref = $this->getRefForUri($this->request->getParsedUri()['path']);
+
+ if( $ref !== null ) {
+ $response = $this->responseForRef($ref);
+ if( $response ) {
+ $this->sendResponse($response);
return;
}
- http_response_code(404);
- echo MockWebServer::VND . ": Resource '{$path}' not found!\n";
+ $this->sendResponse(new NotFoundResponse);
return;
}
- header('Content-Type: application/json');
+ $response = $this->responseForRef(self::DEFAULT_REF);
+ if( $response ) {
+ $this->sendResponse($response);
- echo json_encode($this->request, JSON_PRETTY_PRINT);
+ return;
+ }
+
+ $this->sendResponse(new DefaultResponse);
+ }
+
+ protected function sendResponse( ResponseInterface $response ) {
+ http_response_code($response->getStatus($this->request));
+
+ foreach( $response->getHeaders($this->request) as $key => $header ) {
+ if( is_int($key) ) {
+ call_user_func($this->header, $header);
+ } else {
+ call_user_func($this->header, "{$key}: {$header}");
+ }
+ }
+
+ echo $response->getBody($this->request);
+
+ if( $response instanceof MultiResponseInterface ) {
+ $response->next();
+ self::storeResponse($this->tmpPath, $response);
+ }
}
/**
- * @return false|string
+ * @return string|null
*/
- protected function getDataPath() {
- $path = false;
-
- $uriPath = $this->request->getParsedUri()['path'];
+ protected function getRefForUri( $uriPath ) {
$aliasPath = self::aliasPath($this->tmpPath, $uriPath);
+
if( file_exists($aliasPath) ) {
if( $path = file_get_contents($aliasPath) ) {
- $path = $this->tmpPath . DIRECTORY_SEPARATOR . $path;
+ return $path;
}
- } elseif( preg_match('%^/' . preg_quote(MockWebServer::VND) . '/([0-9a-fA-F]{32})$%', $uriPath, $matches) ) {
- $path = $this->tmpPath . DIRECTORY_SEPARATOR . $matches[1];
+ } elseif( preg_match('%^/' . preg_quote(MockWebServer::VND, '%') . '/([0-9a-fA-F]{32})$%', $uriPath, $matches) ) {
+ return $matches[1];
}
- return $path;
+ return null;
}
/**
- * @internal
* @param string $tmpPath
* @param \donatj\MockWebServer\ResponseInterface $response
* @return string
+ * @internal
*/
public static function storeResponse( $tmpPath, ResponseInterface $response ) {
- $ref = $response->getRef();
+ $ref = $response->getRef();
+ self::storeRef($response, $tmpPath, $ref);
+
+ return $ref;
+ }
+
+ /**
+ * @param string $tmpPath
+ * @param \donatj\MockWebServer\ResponseInterface $response
+ * @return void
+ * @internal
+ */
+ public static function storeDefaultResponse( $tmpPath, ResponseInterface $response ) {
+ self::storeRef($response, $tmpPath, self::DEFAULT_REF);
+ }
+
+ /**
+ * @param \donatj\MockWebServer\ResponseInterface $response
+ * @param string $tmpPath
+ * @param string $ref
+ */
+ private static function storeRef( ResponseInterface $response, $tmpPath, $ref ) {
$content = serialize($response);
if( !file_put_contents($tmpPath . DIRECTORY_SEPARATOR . $ref, $content) ) {
throw new Exceptions\RuntimeException('Failed to write temporary content');
}
-
- return $ref;
}
}
diff --git a/src/MockWebServer.php b/src/MockWebServer.php
index 91e4d9b..ca35ceb 100644
--- a/src/MockWebServer.php
+++ b/src/MockWebServer.php
@@ -178,6 +178,16 @@ public function setResponseOfPath( $path, ResponseInterface $response ) {
return $this->getServerRoot() . $path;
}
+ /**
+ * Override the default server response, e.g. Fallback or 404
+ *
+ * @param \donatj\MockWebServer\ResponseInterface $response
+ * @return void
+ */
+ public function setDefaultResponse( ResponseInterface $response ) {
+ InternalServer::storeDefaultResponse($this->tmpDir, $response);
+ }
+
/**
* @return string
* @internal
diff --git a/src/Responses/DefaultResponse.php b/src/Responses/DefaultResponse.php
new file mode 100644
index 0000000..0687df3
--- /dev/null
+++ b/src/Responses/DefaultResponse.php
@@ -0,0 +1,30 @@
+ 'application/json' ];
+ }
+
+ public function getStatus( RequestInfo $request ) {
+ return 200;
+ }
+}
diff --git a/src/Responses/NotFoundResponse.php b/src/Responses/NotFoundResponse.php
new file mode 100644
index 0000000..7b6cf40
--- /dev/null
+++ b/src/Responses/NotFoundResponse.php
@@ -0,0 +1,31 @@
+getParsedUri()['path'];
+
+ return MockWebServer::VND . ": Resource '{$path}' not found!\n";
+ }
+
+ public function getHeaders( RequestInfo $request ) {
+ return [];
+ }
+
+ public function getStatus( RequestInfo $request ) {
+ return 404;
+ }
+}
diff --git a/test/MockWebServer_ChangedDefault_IntegrationTest.php b/test/MockWebServer_ChangedDefault_IntegrationTest.php
new file mode 100644
index 0000000..bde3f55
--- /dev/null
+++ b/test/MockWebServer_ChangedDefault_IntegrationTest.php
@@ -0,0 +1,45 @@
+start();
+
+ $server->setResponseOfPath('funk', new Response('fresh'));
+ $path = $server->getUrlOfResponse(new Response('fries'));
+
+ $content = file_get_contents($server->getServerRoot() . '/PageDoesNotExist');
+ $result = json_decode($content, true);
+ $this->assertNotFalse(stripos($http_response_header[0], '200 OK', true) );
+ $this->assertSame('/PageDoesNotExist', $result['PARSED_REQUEST_URI']['path']);
+
+ // try with a 404
+ $server->setDefaultResponse(new NotFoundResponse);
+
+ $content = file_get_contents($server->getServerRoot() . '/PageDoesNotExist', false, stream_context_create([
+ 'http' => [ 'ignore_errors' => true ] // allow reading 404s
+ ]));
+
+ $this->assertNotFalse(stripos($http_response_header[0], '404 Not Found', true));
+ $this->assertSame("VND.DonatStudios.MockWebServer: Resource '/PageDoesNotExist' not found!\n", $content);
+
+ // try with a custom response
+ $server->setDefaultResponse(new Response('cool beans'));
+ $content = file_get_contents($server->getServerRoot() . '/BadUrlBadTime');
+ $this->assertSame('cool beans', $content);
+
+ // ensure non-404-ing pages countinue to work as expected
+ $content = file_get_contents($server->getServerRoot() . '/funk');
+ $this->assertSame('fresh', $content);
+
+ $content = file_get_contents($path);
+ $this->assertSame('fries', $content);
+ }
+
+}