Skip to content

Commit 7683ece

Browse files
authored
Merge pull request #877 from mevdschee/mapper
add 'jsonOptions' config
2 parents 5e2058f + 014dcd3 commit 7683ece

File tree

8 files changed

+99
-45
lines changed

8 files changed

+99
-45
lines changed

README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ These are all the configuration options and their default value between brackets
6666
- "cacheType": `TempFile`, `Redis`, `Memcache`, `Memcached` or `NoCache` (`TempFile`)
6767
- "cachePath": Path/address of the cache (defaults to system's temp directory)
6868
- "cacheTime": Number of seconds the cache is valid (`10`)
69+
- "jsonOptions": Options used for encoding JSON (`JSON_UNESCAPED_UNICODE`)
6970
- "debug": Show errors in the "X-Exception" headers (`false`)
7071
- "basePath": URI base path of the API (determined using PATH_INFO by default)
7172

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

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

1152+
### JSON encoding options
1153+
1154+
You can change the way the JSON is encoded by setting the configuration parameter "jsonOptions".
1155+
1156+
'jsonOptions' => JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES,
1157+
1158+
The above example will set JSON options to 128+256+64 = 448, as per the table of options below:
1159+
1160+
JSON_HEX_TAG (1)
1161+
All < and > are converted to \u003C and \u003E.
1162+
JSON_HEX_AMP (2)
1163+
All & are converted to \u0026.
1164+
JSON_HEX_APOS (4)
1165+
All ' are converted to \u0027.
1166+
JSON_HEX_QUOT (8)
1167+
All " are converted to \u0022.
1168+
JSON_FORCE_OBJECT (16)
1169+
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.
1170+
JSON_NUMERIC_CHECK (32)
1171+
Encodes numeric strings as numbers.
1172+
JSON_UNESCAPED_SLASHES (64)
1173+
Don't escape /.
1174+
JSON_PRETTY_PRINT (128)
1175+
Use whitespace in returned data to format it.
1176+
JSON_UNESCAPED_UNICODE (256)
1177+
Encode multibyte Unicode characters literally (default is to escape as \uXXXX).
1178+
JSON_PARTIAL_OUTPUT_ON_ERROR (512)
1179+
Substitute some unencodable values instead of failing.
1180+
JSON_PRESERVE_ZERO_FRACTION (1024)
1181+
Ensures that float values are always encoded as a float value.
1182+
JSON_UNESCAPED_LINE_TERMINATORS (2048)
1183+
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.
1184+
1185+
Source: [PHP's JSON constants documentation](https://www.php.net/manual/en/json.constants.php)
1186+
11511187
### JSON middleware
11521188

11531189
You may use the "json" middleware to read/write JSON strings as JSON objects and arrays.

api.include.php

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4685,28 +4685,30 @@ public function read(ServerRequestInterface $request): ResponseInterface
46854685

46864686
class JsonResponder implements Responder
46874687
{
4688+
private $jsonOptions;
46884689
private $debug;
46894690

4690-
public function __construct(bool $debug)
4691+
public function __construct(int $jsonOptions, bool $debug)
46914692
{
4693+
$this->jsonOptions = $jsonOptions;
46924694
$this->debug = $debug;
46934695
}
46944696

46954697
public function error(int $error, string $argument, $details = null): ResponseInterface
46964698
{
46974699
$document = new ErrorDocument(new ErrorCode($error), $argument, $details);
4698-
return ResponseFactory::fromObject($document->getStatus(), $document);
4700+
return ResponseFactory::fromObject($document->getStatus(), $document, $this->jsonOptions);
46994701
}
47004702

47014703
public function success($result): ResponseInterface
47024704
{
4703-
return ResponseFactory::fromObject(ResponseFactory::OK, $result);
4705+
return ResponseFactory::fromObject(ResponseFactory::OK, $result, $this->jsonOptions);
47044706
}
47054707

47064708
public function exception($exception): ResponseInterface
47074709
{
47084710
$document = ErrorDocument::fromException($exception, $this->debug);
4709-
$response = ResponseFactory::fromObject($document->getStatus(), $document);
4711+
$response = ResponseFactory::fromObject($document->getStatus(), $document, $this->jsonOptions);
47104712
if ($this->debug) {
47114713
$response = ResponseUtils::addExceptionHeaders($response, $exception);
47124714
}
@@ -4730,7 +4732,7 @@ public function multi($results): ResponseInterface
47304732
}
47314733
$status = $success ? ResponseFactory::OK : ResponseFactory::FAILED_DEPENDENCY;
47324734
$document = $success ? $documents : $errors;
4733-
$response = ResponseFactory::fromObject($status, $document);
4735+
$response = ResponseFactory::fromObject($status, $document, $this->jsonOptions);
47344736
foreach ($results as $i => $result) {
47354737
if ($result instanceof \Throwable) {
47364738
if ($this->debug) {
@@ -8439,9 +8441,11 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
84398441
}
84408442
$response = $next->handle($request);
84418443
if (in_array($operation, ['read', 'list'])) {
8442-
$records = json_decode($response->getBody()->getContents());
8443-
$records = $this->convertJsonResponse($records, $columnNames);
8444-
$response = ResponseFactory::fromObject($response->getStatusCode(), $records);
8444+
if ($response->getStatusCode() == ResponseFactory::OK) {
8445+
$records = json_decode($response->getBody()->getContents());
8446+
$records = $this->convertJsonResponse($records, $columnNames);
8447+
$response = $this->responder->success($records);
8448+
}
84458449
}
84468450
} else {
84478451
$response = $next->handle($request);
@@ -11517,8 +11521,6 @@ private function setHabtmValues(ReflectedTable $t1, ReflectedTable $t2, array &$
1151711521
class Api implements RequestHandlerInterface
1151811522
{
1151911523
private $router;
11520-
private $responder;
11521-
private $debug;
1152211524

1152311525
public function __construct(Config $config)
1152411526
{
@@ -11535,7 +11537,7 @@ public function __construct(Config $config)
1153511537
$prefix = sprintf('phpcrudapi-%s-', substr(md5(__FILE__), 0, 8));
1153611538
$cache = CacheFactory::create($config->getCacheType(), $prefix, $config->getCachePath());
1153711539
$reflection = new ReflectionService($db, $cache, $config->getCacheTime());
11538-
$responder = new JsonResponder($config->getDebug());
11540+
$responder = new JsonResponder($config->getJsonOptions(), $config->getDebug());
1153911541
$router = new SimpleRouter($config->getBasePath(), $responder, $cache, $config->getCacheTime());
1154011542
foreach ($config->getMiddlewares() as $middleware => $properties) {
1154111543
switch ($middleware) {
@@ -11634,8 +11636,6 @@ public function __construct(Config $config)
1163411636
}
1163511637
}
1163611638
$this->router = $router;
11637-
$this->responder = $responder;
11638-
$this->debug = $config->getDebug();
1163911639
}
1164011640

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

11909+
public function getJsonOptions(): int
11910+
{
11911+
return $this->values['jsonOptions'];
11912+
}
11913+
1190811914
public function getDebug(): bool
1190911915
{
1191011916
return $this->values['debug'];
@@ -12123,9 +12129,9 @@ public static function fromHtml(int $status, string $html): ResponseInterface
1212312129
return self::from($status, 'text/html', $html);
1212412130
}
1212512131

12126-
public static function fromObject(int $status, $body): ResponseInterface
12132+
public static function fromObject(int $status, $body, int $jsonOptions): ResponseInterface
1212712133
{
12128-
$content = json_encode($body, JSON_UNESCAPED_UNICODE);
12134+
$content = json_encode($body, $jsonOptions);
1212912135
return self::from($status, 'application/json', $content);
1213012136
}
1213112137

api.php

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4685,28 +4685,30 @@ public function read(ServerRequestInterface $request): ResponseInterface
46854685

46864686
class JsonResponder implements Responder
46874687
{
4688+
private $jsonOptions;
46884689
private $debug;
46894690

4690-
public function __construct(bool $debug)
4691+
public function __construct(int $jsonOptions, bool $debug)
46914692
{
4693+
$this->jsonOptions = $jsonOptions;
46924694
$this->debug = $debug;
46934695
}
46944696

46954697
public function error(int $error, string $argument, $details = null): ResponseInterface
46964698
{
46974699
$document = new ErrorDocument(new ErrorCode($error), $argument, $details);
4698-
return ResponseFactory::fromObject($document->getStatus(), $document);
4700+
return ResponseFactory::fromObject($document->getStatus(), $document, $this->jsonOptions);
46994701
}
47004702

47014703
public function success($result): ResponseInterface
47024704
{
4703-
return ResponseFactory::fromObject(ResponseFactory::OK, $result);
4705+
return ResponseFactory::fromObject(ResponseFactory::OK, $result, $this->jsonOptions);
47044706
}
47054707

47064708
public function exception($exception): ResponseInterface
47074709
{
47084710
$document = ErrorDocument::fromException($exception, $this->debug);
4709-
$response = ResponseFactory::fromObject($document->getStatus(), $document);
4711+
$response = ResponseFactory::fromObject($document->getStatus(), $document, $this->jsonOptions);
47104712
if ($this->debug) {
47114713
$response = ResponseUtils::addExceptionHeaders($response, $exception);
47124714
}
@@ -4730,7 +4732,7 @@ public function multi($results): ResponseInterface
47304732
}
47314733
$status = $success ? ResponseFactory::OK : ResponseFactory::FAILED_DEPENDENCY;
47324734
$document = $success ? $documents : $errors;
4733-
$response = ResponseFactory::fromObject($status, $document);
4735+
$response = ResponseFactory::fromObject($status, $document, $this->jsonOptions);
47344736
foreach ($results as $i => $result) {
47354737
if ($result instanceof \Throwable) {
47364738
if ($this->debug) {
@@ -8439,9 +8441,11 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
84398441
}
84408442
$response = $next->handle($request);
84418443
if (in_array($operation, ['read', 'list'])) {
8442-
$records = json_decode($response->getBody()->getContents());
8443-
$records = $this->convertJsonResponse($records, $columnNames);
8444-
$response = ResponseFactory::fromObject($response->getStatusCode(), $records);
8444+
if ($response->getStatusCode() == ResponseFactory::OK) {
8445+
$records = json_decode($response->getBody()->getContents());
8446+
$records = $this->convertJsonResponse($records, $columnNames);
8447+
$response = $this->responder->success($records);
8448+
}
84458449
}
84468450
} else {
84478451
$response = $next->handle($request);
@@ -11517,8 +11521,6 @@ private function setHabtmValues(ReflectedTable $t1, ReflectedTable $t2, array &$
1151711521
class Api implements RequestHandlerInterface
1151811522
{
1151911523
private $router;
11520-
private $responder;
11521-
private $debug;
1152211524

1152311525
public function __construct(Config $config)
1152411526
{
@@ -11535,7 +11537,7 @@ public function __construct(Config $config)
1153511537
$prefix = sprintf('phpcrudapi-%s-', substr(md5(__FILE__), 0, 8));
1153611538
$cache = CacheFactory::create($config->getCacheType(), $prefix, $config->getCachePath());
1153711539
$reflection = new ReflectionService($db, $cache, $config->getCacheTime());
11538-
$responder = new JsonResponder($config->getDebug());
11540+
$responder = new JsonResponder($config->getJsonOptions(), $config->getDebug());
1153911541
$router = new SimpleRouter($config->getBasePath(), $responder, $cache, $config->getCacheTime());
1154011542
foreach ($config->getMiddlewares() as $middleware => $properties) {
1154111543
switch ($middleware) {
@@ -11634,8 +11636,6 @@ public function __construct(Config $config)
1163411636
}
1163511637
}
1163611638
$this->router = $router;
11637-
$this->responder = $responder;
11638-
$this->debug = $config->getDebug();
1163911639
}
1164011640

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

11909+
public function getJsonOptions(): int
11910+
{
11911+
return $this->values['jsonOptions'];
11912+
}
11913+
1190811914
public function getDebug(): bool
1190911915
{
1191011916
return $this->values['debug'];
@@ -12123,9 +12129,9 @@ public static function fromHtml(int $status, string $html): ResponseInterface
1212312129
return self::from($status, 'text/html', $html);
1212412130
}
1212512131

12126-
public static function fromObject(int $status, $body): ResponseInterface
12132+
public static function fromObject(int $status, $body, int $jsonOptions): ResponseInterface
1212712133
{
12128-
$content = json_encode($body, JSON_UNESCAPED_UNICODE);
12134+
$content = json_encode($body, $jsonOptions);
1212912135
return self::from($status, 'application/json', $content);
1213012136
}
1213112137

src/Tqdev/PhpCrudApi/Api.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@
4646
class Api implements RequestHandlerInterface
4747
{
4848
private $router;
49-
private $responder;
50-
private $debug;
5149

5250
public function __construct(Config $config)
5351
{
@@ -64,7 +62,7 @@ public function __construct(Config $config)
6462
$prefix = sprintf('phpcrudapi-%s-', substr(md5(__FILE__), 0, 8));
6563
$cache = CacheFactory::create($config->getCacheType(), $prefix, $config->getCachePath());
6664
$reflection = new ReflectionService($db, $cache, $config->getCacheTime());
67-
$responder = new JsonResponder($config->getDebug());
65+
$responder = new JsonResponder($config->getJsonOptions(), $config->getDebug());
6866
$router = new SimpleRouter($config->getBasePath(), $responder, $cache, $config->getCacheTime());
6967
foreach ($config->getMiddlewares() as $middleware => $properties) {
7068
switch ($middleware) {
@@ -163,8 +161,6 @@ public function __construct(Config $config)
163161
}
164162
}
165163
$this->router = $router;
166-
$this->responder = $responder;
167-
$this->debug = $config->getDebug();
168164
}
169165

170166
private function parseBody(string $body) /*: ?object*/

src/Tqdev/PhpCrudApi/Config.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class Config
2020
'cacheType' => 'TempFile',
2121
'cachePath' => '',
2222
'cacheTime' => 10,
23+
'jsonOptions' => JSON_UNESCAPED_UNICODE,
2324
'debug' => false,
2425
'basePath' => '',
2526
'openApiBase' => '{"info":{"title":"PHP-CRUD-API","version":"1.0.0"}}',
@@ -202,6 +203,11 @@ public function getCacheTime(): int
202203
return $this->values['cacheTime'];
203204
}
204205

206+
public function getJsonOptions(): int
207+
{
208+
return $this->values['jsonOptions'];
209+
}
210+
205211
public function getDebug(): bool
206212
{
207213
return $this->values['debug'];

src/Tqdev/PhpCrudApi/Controller/JsonResponder.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,30 @@
1010

1111
class JsonResponder implements Responder
1212
{
13+
private $jsonOptions;
1314
private $debug;
1415

15-
public function __construct(bool $debug)
16+
public function __construct(int $jsonOptions, bool $debug)
1617
{
18+
$this->jsonOptions = $jsonOptions;
1719
$this->debug = $debug;
1820
}
1921

2022
public function error(int $error, string $argument, $details = null): ResponseInterface
2123
{
2224
$document = new ErrorDocument(new ErrorCode($error), $argument, $details);
23-
return ResponseFactory::fromObject($document->getStatus(), $document);
25+
return ResponseFactory::fromObject($document->getStatus(), $document, $this->jsonOptions);
2426
}
2527

2628
public function success($result): ResponseInterface
2729
{
28-
return ResponseFactory::fromObject(ResponseFactory::OK, $result);
30+
return ResponseFactory::fromObject(ResponseFactory::OK, $result, $this->jsonOptions);
2931
}
3032

3133
public function exception($exception): ResponseInterface
3234
{
3335
$document = ErrorDocument::fromException($exception, $this->debug);
34-
$response = ResponseFactory::fromObject($document->getStatus(), $document);
36+
$response = ResponseFactory::fromObject($document->getStatus(), $document, $this->jsonOptions);
3537
if ($this->debug) {
3638
$response = ResponseUtils::addExceptionHeaders($response, $exception);
3739
}
@@ -55,7 +57,7 @@ public function multi($results): ResponseInterface
5557
}
5658
$status = $success ? ResponseFactory::OK : ResponseFactory::FAILED_DEPENDENCY;
5759
$document = $success ? $documents : $errors;
58-
$response = ResponseFactory::fromObject($status, $document);
60+
$response = ResponseFactory::fromObject($status, $document, $this->jsonOptions);
5961
foreach ($results as $i => $result) {
6062
if ($result instanceof \Throwable) {
6163
if ($this->debug) {

src/Tqdev/PhpCrudApi/Middleware/JsonMiddleware.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,11 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
8989
}
9090
$response = $next->handle($request);
9191
if (in_array($operation, ['read', 'list'])) {
92-
$records = json_decode($response->getBody()->getContents());
93-
$records = $this->convertJsonResponse($records, $columnNames);
94-
$response = ResponseFactory::fromObject($response->getStatusCode(), $records);
92+
if ($response->getStatusCode() == ResponseFactory::OK) {
93+
$records = json_decode($response->getBody()->getContents());
94+
$records = $this->convertJsonResponse($records, $columnNames);
95+
$response = $this->responder->success($records);
96+
}
9597
}
9698
} else {
9799
$response = $next->handle($request);

0 commit comments

Comments
 (0)