Skip to content

Commit

Permalink
Merge pull request #877 from mevdschee/mapper
Browse files Browse the repository at this point in the history
add 'jsonOptions' config
  • Loading branch information
mevdschee committed May 1, 2022
2 parents 5e2058f + 014dcd3 commit 7683ece
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 45 deletions.
36 changes: 36 additions & 0 deletions README.md
Expand Up @@ -66,6 +66,7 @@ These are all the configuration options and their default value between brackets
- "cacheType": `TempFile`, `Redis`, `Memcache`, `Memcached` or `NoCache` (`TempFile`)
- "cachePath": Path/address of the cache (defaults to system's temp directory)
- "cacheTime": Number of seconds the cache is valid (`10`)
- "jsonOptions": Options used for encoding JSON (`JSON_UNESCAPED_UNICODE`)
- "debug": Show errors in the "X-Exception" headers (`false`)
- "basePath": URI base path of the API (determined using PATH_INFO by default)

Expand Down Expand Up @@ -1148,6 +1149,41 @@ You may use the "customization" middleware to modify request and response and im

The above example will add a header "X-Time-Taken" with the number of seconds the API call has taken.

### JSON encoding options

You can change the way the JSON is encoded by setting the configuration parameter "jsonOptions".

'jsonOptions' => JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES,

The above example will set JSON options to 128+256+64 = 448, as per the table of options below:

JSON_HEX_TAG (1)
All < and > are converted to \u003C and \u003E.
JSON_HEX_AMP (2)
All & are converted to \u0026.
JSON_HEX_APOS (4)
All ' are converted to \u0027.
JSON_HEX_QUOT (8)
All " are converted to \u0022.
JSON_FORCE_OBJECT (16)
Outputs an object rather than an array when a non-associative array is used. Especially useful when the recipient of the output is expecting an object and the array is empty.
JSON_NUMERIC_CHECK (32)
Encodes numeric strings as numbers.
JSON_UNESCAPED_SLASHES (64)
Don't escape /.
JSON_PRETTY_PRINT (128)
Use whitespace in returned data to format it.
JSON_UNESCAPED_UNICODE (256)
Encode multibyte Unicode characters literally (default is to escape as \uXXXX).
JSON_PARTIAL_OUTPUT_ON_ERROR (512)
Substitute some unencodable values instead of failing.
JSON_PRESERVE_ZERO_FRACTION (1024)
Ensures that float values are always encoded as a float value.
JSON_UNESCAPED_LINE_TERMINATORS (2048)
The line terminators are kept unescaped when JSON_UNESCAPED_UNICODE is supplied. It uses the same behaviour as it was before PHP 7.1 without this constant. Available as of PHP 7.1.0.

Source: [PHP's JSON constants documentation](https://www.php.net/manual/en/json.constants.php)

### JSON middleware

You may use the "json" middleware to read/write JSON strings as JSON objects and arrays.
Expand Down
36 changes: 21 additions & 15 deletions api.include.php
Expand Up @@ -4685,28 +4685,30 @@ public function read(ServerRequestInterface $request): ResponseInterface

class JsonResponder implements Responder
{
private $jsonOptions;
private $debug;

public function __construct(bool $debug)
public function __construct(int $jsonOptions, bool $debug)
{
$this->jsonOptions = $jsonOptions;
$this->debug = $debug;
}

public function error(int $error, string $argument, $details = null): ResponseInterface
{
$document = new ErrorDocument(new ErrorCode($error), $argument, $details);
return ResponseFactory::fromObject($document->getStatus(), $document);
return ResponseFactory::fromObject($document->getStatus(), $document, $this->jsonOptions);
}

public function success($result): ResponseInterface
{
return ResponseFactory::fromObject(ResponseFactory::OK, $result);
return ResponseFactory::fromObject(ResponseFactory::OK, $result, $this->jsonOptions);
}

public function exception($exception): ResponseInterface
{
$document = ErrorDocument::fromException($exception, $this->debug);
$response = ResponseFactory::fromObject($document->getStatus(), $document);
$response = ResponseFactory::fromObject($document->getStatus(), $document, $this->jsonOptions);
if ($this->debug) {
$response = ResponseUtils::addExceptionHeaders($response, $exception);
}
Expand All @@ -4730,7 +4732,7 @@ public function multi($results): ResponseInterface
}
$status = $success ? ResponseFactory::OK : ResponseFactory::FAILED_DEPENDENCY;
$document = $success ? $documents : $errors;
$response = ResponseFactory::fromObject($status, $document);
$response = ResponseFactory::fromObject($status, $document, $this->jsonOptions);
foreach ($results as $i => $result) {
if ($result instanceof \Throwable) {
if ($this->debug) {
Expand Down Expand Up @@ -8439,9 +8441,11 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
}
$response = $next->handle($request);
if (in_array($operation, ['read', 'list'])) {
$records = json_decode($response->getBody()->getContents());
$records = $this->convertJsonResponse($records, $columnNames);
$response = ResponseFactory::fromObject($response->getStatusCode(), $records);
if ($response->getStatusCode() == ResponseFactory::OK) {
$records = json_decode($response->getBody()->getContents());
$records = $this->convertJsonResponse($records, $columnNames);
$response = $this->responder->success($records);
}
}
} else {
$response = $next->handle($request);
Expand Down Expand Up @@ -11517,8 +11521,6 @@ private function setHabtmValues(ReflectedTable $t1, ReflectedTable $t2, array &$
class Api implements RequestHandlerInterface
{
private $router;
private $responder;
private $debug;

public function __construct(Config $config)
{
Expand All @@ -11535,7 +11537,7 @@ public function __construct(Config $config)
$prefix = sprintf('phpcrudapi-%s-', substr(md5(__FILE__), 0, 8));
$cache = CacheFactory::create($config->getCacheType(), $prefix, $config->getCachePath());
$reflection = new ReflectionService($db, $cache, $config->getCacheTime());
$responder = new JsonResponder($config->getDebug());
$responder = new JsonResponder($config->getJsonOptions(), $config->getDebug());
$router = new SimpleRouter($config->getBasePath(), $responder, $cache, $config->getCacheTime());
foreach ($config->getMiddlewares() as $middleware => $properties) {
switch ($middleware) {
Expand Down Expand Up @@ -11634,8 +11636,6 @@ public function __construct(Config $config)
}
}
$this->router = $router;
$this->responder = $responder;
$this->debug = $config->getDebug();
}

private function parseBody(string $body) /*: ?object*/
Expand Down Expand Up @@ -11723,6 +11723,7 @@ class Config
'cacheType' => 'TempFile',
'cachePath' => '',
'cacheTime' => 10,
'jsonOptions' => JSON_UNESCAPED_UNICODE,
'debug' => false,
'basePath' => '',
'openApiBase' => '{"info":{"title":"PHP-CRUD-API","version":"1.0.0"}}',
Expand Down Expand Up @@ -11905,6 +11906,11 @@ public function getCacheTime(): int
return $this->values['cacheTime'];
}

public function getJsonOptions(): int
{
return $this->values['jsonOptions'];
}

public function getDebug(): bool
{
return $this->values['debug'];
Expand Down Expand Up @@ -12123,9 +12129,9 @@ public static function fromHtml(int $status, string $html): ResponseInterface
return self::from($status, 'text/html', $html);
}

public static function fromObject(int $status, $body): ResponseInterface
public static function fromObject(int $status, $body, int $jsonOptions): ResponseInterface
{
$content = json_encode($body, JSON_UNESCAPED_UNICODE);
$content = json_encode($body, $jsonOptions);
return self::from($status, 'application/json', $content);
}

Expand Down
36 changes: 21 additions & 15 deletions api.php
Expand Up @@ -4685,28 +4685,30 @@ public function read(ServerRequestInterface $request): ResponseInterface

class JsonResponder implements Responder
{
private $jsonOptions;
private $debug;

public function __construct(bool $debug)
public function __construct(int $jsonOptions, bool $debug)
{
$this->jsonOptions = $jsonOptions;
$this->debug = $debug;
}

public function error(int $error, string $argument, $details = null): ResponseInterface
{
$document = new ErrorDocument(new ErrorCode($error), $argument, $details);
return ResponseFactory::fromObject($document->getStatus(), $document);
return ResponseFactory::fromObject($document->getStatus(), $document, $this->jsonOptions);
}

public function success($result): ResponseInterface
{
return ResponseFactory::fromObject(ResponseFactory::OK, $result);
return ResponseFactory::fromObject(ResponseFactory::OK, $result, $this->jsonOptions);
}

public function exception($exception): ResponseInterface
{
$document = ErrorDocument::fromException($exception, $this->debug);
$response = ResponseFactory::fromObject($document->getStatus(), $document);
$response = ResponseFactory::fromObject($document->getStatus(), $document, $this->jsonOptions);
if ($this->debug) {
$response = ResponseUtils::addExceptionHeaders($response, $exception);
}
Expand All @@ -4730,7 +4732,7 @@ public function multi($results): ResponseInterface
}
$status = $success ? ResponseFactory::OK : ResponseFactory::FAILED_DEPENDENCY;
$document = $success ? $documents : $errors;
$response = ResponseFactory::fromObject($status, $document);
$response = ResponseFactory::fromObject($status, $document, $this->jsonOptions);
foreach ($results as $i => $result) {
if ($result instanceof \Throwable) {
if ($this->debug) {
Expand Down Expand Up @@ -8439,9 +8441,11 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
}
$response = $next->handle($request);
if (in_array($operation, ['read', 'list'])) {
$records = json_decode($response->getBody()->getContents());
$records = $this->convertJsonResponse($records, $columnNames);
$response = ResponseFactory::fromObject($response->getStatusCode(), $records);
if ($response->getStatusCode() == ResponseFactory::OK) {
$records = json_decode($response->getBody()->getContents());
$records = $this->convertJsonResponse($records, $columnNames);
$response = $this->responder->success($records);
}
}
} else {
$response = $next->handle($request);
Expand Down Expand Up @@ -11517,8 +11521,6 @@ private function setHabtmValues(ReflectedTable $t1, ReflectedTable $t2, array &$
class Api implements RequestHandlerInterface
{
private $router;
private $responder;
private $debug;

public function __construct(Config $config)
{
Expand All @@ -11535,7 +11537,7 @@ public function __construct(Config $config)
$prefix = sprintf('phpcrudapi-%s-', substr(md5(__FILE__), 0, 8));
$cache = CacheFactory::create($config->getCacheType(), $prefix, $config->getCachePath());
$reflection = new ReflectionService($db, $cache, $config->getCacheTime());
$responder = new JsonResponder($config->getDebug());
$responder = new JsonResponder($config->getJsonOptions(), $config->getDebug());
$router = new SimpleRouter($config->getBasePath(), $responder, $cache, $config->getCacheTime());
foreach ($config->getMiddlewares() as $middleware => $properties) {
switch ($middleware) {
Expand Down Expand Up @@ -11634,8 +11636,6 @@ public function __construct(Config $config)
}
}
$this->router = $router;
$this->responder = $responder;
$this->debug = $config->getDebug();
}

private function parseBody(string $body) /*: ?object*/
Expand Down Expand Up @@ -11723,6 +11723,7 @@ class Config
'cacheType' => 'TempFile',
'cachePath' => '',
'cacheTime' => 10,
'jsonOptions' => JSON_UNESCAPED_UNICODE,
'debug' => false,
'basePath' => '',
'openApiBase' => '{"info":{"title":"PHP-CRUD-API","version":"1.0.0"}}',
Expand Down Expand Up @@ -11905,6 +11906,11 @@ public function getCacheTime(): int
return $this->values['cacheTime'];
}

public function getJsonOptions(): int
{
return $this->values['jsonOptions'];
}

public function getDebug(): bool
{
return $this->values['debug'];
Expand Down Expand Up @@ -12123,9 +12129,9 @@ public static function fromHtml(int $status, string $html): ResponseInterface
return self::from($status, 'text/html', $html);
}

public static function fromObject(int $status, $body): ResponseInterface
public static function fromObject(int $status, $body, int $jsonOptions): ResponseInterface
{
$content = json_encode($body, JSON_UNESCAPED_UNICODE);
$content = json_encode($body, $jsonOptions);
return self::from($status, 'application/json', $content);
}

Expand Down
6 changes: 1 addition & 5 deletions src/Tqdev/PhpCrudApi/Api.php
Expand Up @@ -46,8 +46,6 @@
class Api implements RequestHandlerInterface
{
private $router;
private $responder;
private $debug;

public function __construct(Config $config)
{
Expand All @@ -64,7 +62,7 @@ public function __construct(Config $config)
$prefix = sprintf('phpcrudapi-%s-', substr(md5(__FILE__), 0, 8));
$cache = CacheFactory::create($config->getCacheType(), $prefix, $config->getCachePath());
$reflection = new ReflectionService($db, $cache, $config->getCacheTime());
$responder = new JsonResponder($config->getDebug());
$responder = new JsonResponder($config->getJsonOptions(), $config->getDebug());
$router = new SimpleRouter($config->getBasePath(), $responder, $cache, $config->getCacheTime());
foreach ($config->getMiddlewares() as $middleware => $properties) {
switch ($middleware) {
Expand Down Expand Up @@ -163,8 +161,6 @@ public function __construct(Config $config)
}
}
$this->router = $router;
$this->responder = $responder;
$this->debug = $config->getDebug();
}

private function parseBody(string $body) /*: ?object*/
Expand Down
6 changes: 6 additions & 0 deletions src/Tqdev/PhpCrudApi/Config.php
Expand Up @@ -20,6 +20,7 @@ class Config
'cacheType' => 'TempFile',
'cachePath' => '',
'cacheTime' => 10,
'jsonOptions' => JSON_UNESCAPED_UNICODE,
'debug' => false,
'basePath' => '',
'openApiBase' => '{"info":{"title":"PHP-CRUD-API","version":"1.0.0"}}',
Expand Down Expand Up @@ -202,6 +203,11 @@ public function getCacheTime(): int
return $this->values['cacheTime'];
}

public function getJsonOptions(): int
{
return $this->values['jsonOptions'];
}

public function getDebug(): bool
{
return $this->values['debug'];
Expand Down
12 changes: 7 additions & 5 deletions src/Tqdev/PhpCrudApi/Controller/JsonResponder.php
Expand Up @@ -10,28 +10,30 @@

class JsonResponder implements Responder
{
private $jsonOptions;
private $debug;

public function __construct(bool $debug)
public function __construct(int $jsonOptions, bool $debug)
{
$this->jsonOptions = $jsonOptions;
$this->debug = $debug;
}

public function error(int $error, string $argument, $details = null): ResponseInterface
{
$document = new ErrorDocument(new ErrorCode($error), $argument, $details);
return ResponseFactory::fromObject($document->getStatus(), $document);
return ResponseFactory::fromObject($document->getStatus(), $document, $this->jsonOptions);
}

public function success($result): ResponseInterface
{
return ResponseFactory::fromObject(ResponseFactory::OK, $result);
return ResponseFactory::fromObject(ResponseFactory::OK, $result, $this->jsonOptions);
}

public function exception($exception): ResponseInterface
{
$document = ErrorDocument::fromException($exception, $this->debug);
$response = ResponseFactory::fromObject($document->getStatus(), $document);
$response = ResponseFactory::fromObject($document->getStatus(), $document, $this->jsonOptions);
if ($this->debug) {
$response = ResponseUtils::addExceptionHeaders($response, $exception);
}
Expand All @@ -55,7 +57,7 @@ public function multi($results): ResponseInterface
}
$status = $success ? ResponseFactory::OK : ResponseFactory::FAILED_DEPENDENCY;
$document = $success ? $documents : $errors;
$response = ResponseFactory::fromObject($status, $document);
$response = ResponseFactory::fromObject($status, $document, $this->jsonOptions);
foreach ($results as $i => $result) {
if ($result instanceof \Throwable) {
if ($this->debug) {
Expand Down
8 changes: 5 additions & 3 deletions src/Tqdev/PhpCrudApi/Middleware/JsonMiddleware.php
Expand Up @@ -89,9 +89,11 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
}
$response = $next->handle($request);
if (in_array($operation, ['read', 'list'])) {
$records = json_decode($response->getBody()->getContents());
$records = $this->convertJsonResponse($records, $columnNames);
$response = ResponseFactory::fromObject($response->getStatusCode(), $records);
if ($response->getStatusCode() == ResponseFactory::OK) {
$records = json_decode($response->getBody()->getContents());
$records = $this->convertJsonResponse($records, $columnNames);
$response = $this->responder->success($records);
}
}
} else {
$response = $next->handle($request);
Expand Down

0 comments on commit 7683ece

Please sign in to comment.