Skip to content

Commit 1fcefc4

Browse files
committed
Added JsonSerializationAdapter.php (Custom JSON implementation) and more
1 parent 60ad5c7 commit 1fcefc4

File tree

7 files changed

+244
-12
lines changed

7 files changed

+244
-12
lines changed

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<?php
77

88
use de\interaapps\jsonplus\attributes\Serialize;
9-
use de\interaapps\jsonplus\JSONModel;use de\interaapps\jsonplus\JSONPlus;
9+
use de\interaapps\jsonplus\JSONModel;use de\interaapps\jsonplus\JSONPlus;use de\interaapps\jsonplus\serializationadapter\impl\JsonSerializationAdapter;use de\interaapps\jsonplus\serializationadapter\impl\phpjson\PHPJsonSerializationAdapter;
1010

1111
class Test2 {
1212
use JSONModel;
@@ -48,6 +48,12 @@ echo $jsonPlus->fromJson($arrJson)[0];
4848
Test::setJsonPlusInstance($jsonPlus);
4949
// For all (Default instance)
5050
JSONPlus::$default = $jsonPlus;
51+
52+
/// Using other JSON-Drivers
53+
// Uses PHPs default json_encode and json_decode methods
54+
$jsonPlus = new JSONPlus(new PHPJsonSerializationAdapter());
55+
// Uses an custom implementation of JSON. This will be automatically chosen by JSONPlus::createDefault when json_decode doesn't exist
56+
$jsonPlus = new JSONPlus(new JsonSerializationAdapter());
5157
```
5258

5359
## Installation

src/main/de/interaapps/jsonplus/JSONPlus.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
<?php
22
namespace de\interaapps\jsonplus;
33

4+
use de\interaapps\jsonplus\serializationadapter\impl\JsonSerializationAdapter;
45
use de\interaapps\jsonplus\serializationadapter\impl\phpjson\PHPJsonSerializationAdapter;
56
use de\interaapps\jsonplus\serializationadapter\SerializationAdapter;
67
use de\interaapps\jsonplus\typemapper\ObjectTypeMapper;
78
use de\interaapps\jsonplus\typemapper\PassThroughTypeMapper;
9+
use de\interaapps\jsonplus\typemapper\StdClassObjectTypeMapper;
810
use de\interaapps\jsonplus\typemapper\TypeMapper;
911
use ReflectionClass;
1012

@@ -29,6 +31,8 @@ public function __construct(
2931
"bool" => $this->passThroughTypeMapper,
3032
"array" => $this->passThroughTypeMapper,
3133
"boolean" => $this->passThroughTypeMapper,
34+
"NULL" => $this->passThroughTypeMapper,
35+
"stdClass" => new StdClassObjectTypeMapper($this),
3236
];
3337
}
3438

@@ -39,8 +43,9 @@ public function fromJson($json, $type=null){
3943
public function map($o, $type = null){
4044
if ($type == null) {
4145
$type = gettype($o);
46+
4247
if ($type == "object")
43-
$type = get_class($type);
48+
$type = get_class($o);
4449
}
4550

4651
foreach ($this->typeMapper as $typeName => $typeMapper) {
@@ -58,7 +63,7 @@ public function mapToJson($o, $type = null){
5863
if ($type == null) {
5964
$type = gettype($o);
6065
if ($type == "object")
61-
$type = get_class($type);
66+
$type = get_class($o);
6267
}
6368
foreach ($this->typeMapper as $typeName => $typeMapper) {
6469
if ($type == $typeName)
@@ -77,7 +82,7 @@ public function setPrettyPrinting(bool $prettyPrinting): JSONPlus {
7782
}
7883

7984
public static function createDefault() : JSONPlus {
80-
return new JSONPlus(new PHPJsonSerializationAdapter());
85+
return new JSONPlus(function_exists("json_decode") ? new PHPJsonSerializationAdapter() : new JsonSerializationAdapter());
8186
}
8287
}
8388
JSONPlus::$default = JSONPlus::createDefault();
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
<?php
2+
namespace de\interaapps\jsonplus\parser;
3+
4+
5+
class JSONDecoder {
6+
private int $i = 0;
7+
public function __construct(
8+
private string $json
9+
) {
10+
}
11+
12+
public function jumpEmpties(){
13+
while ((trim($this->get()) == '' || $this->get()=="\n") && $this->i < strlen($this->json))
14+
$this->i++;
15+
}
16+
17+
public function get($off = 0) : string {
18+
if (strlen($this->json) > $this->i+$off && $this->i+$off >= 0)
19+
return $this->json[$this->i+$off];
20+
return "";
21+
}
22+
23+
public function readNext() : mixed {
24+
$this->jumpEmpties();
25+
26+
if ($this->get() == '{')
27+
return $this->readObject();
28+
if ($this->get() == '[')
29+
return $this->readArray();
30+
if ($this->get() == '"')
31+
return $this->readString();
32+
33+
return $this->readPrimitive();
34+
}
35+
public function readObject() : object|null {
36+
$o = (object)[];
37+
$this->i++;
38+
for (; $this->i<strlen($this->json); $this->i++) {
39+
$this->jumpEmpties();
40+
if ($this->get() == '}') {
41+
$this->i++;
42+
return $o;
43+
}
44+
45+
$key = $this->readNext();
46+
$this->jumpEmpties();
47+
if ($this->get() == ":")
48+
$this->i++;
49+
$this->jumpEmpties();
50+
$value = $this->readNext();
51+
52+
$o->{$key} = $value;
53+
54+
$this->jumpEmpties();
55+
if ($this->get() == '}') {
56+
$this->i++;
57+
return $o;
58+
}
59+
60+
if ($this->get(1) == ",")
61+
$this->i++;
62+
}
63+
64+
return null;
65+
}
66+
public function readArray() : array {
67+
$this->i++;
68+
$a = [];
69+
for (; $this->i<strlen($this->json); $this->i++) {
70+
$this->jumpEmpties();
71+
if ($this->get() == ']') {
72+
$this->i++;
73+
return $a;
74+
}
75+
76+
array_push($a, $this->readNext());
77+
78+
$this->jumpEmpties();
79+
if ($this->get() == ']') {
80+
$this->i++;
81+
return $a;
82+
}
83+
84+
if ($this->get(1) == ",")
85+
$this->i++;
86+
}
87+
return [];
88+
}
89+
90+
public function readString() : string {
91+
$s = "";
92+
$this->i++;
93+
for (; $this->i<strlen($this->json); $this->i++) {
94+
$char = $this->get();
95+
96+
if ($char == '"' && ($this->get(-1) != "\\" || $this->get(-2) == "\\")) {
97+
if ($this->get(-1) && $this->get(-2) != "\\")
98+
$this->i++;
99+
return $s;
100+
}
101+
$s .= $char;
102+
}
103+
return "";
104+
}
105+
106+
private function primitiveStringToPHP($p){
107+
if ($p == "false")
108+
return false;
109+
if ($p == "true")
110+
return true;
111+
return (double) $p;
112+
}
113+
114+
public function readPrimitive() : mixed {
115+
$p = "";
116+
for (; $this->i<strlen($this->json); $this->i++) {
117+
$char = $this->get();
118+
if ($char == '"' || $char == ',' || $char == '}' || $char == ']')
119+
return $this->primitiveStringToPHP($p);
120+
$p .= $char;
121+
}
122+
$this->i--;
123+
return $this->primitiveStringToPHP($p);
124+
}
125+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
4+
namespace de\interaapps\jsonplus\parser;
5+
6+
7+
class JSONEncoder {
8+
private bool $prettyPrint = false;
9+
public function encode($v, $tabs="") : string {
10+
$this->prettyPrintNewLine = $this->prettyPrint ? "\n": '';
11+
$identedTabs = $this->prettyPrint ? $tabs." " : '';
12+
13+
if (is_bool($v)) {
14+
return $v ? "true" : "false";
15+
} else if (is_int($v) || is_bool($v) || is_double($v)) {
16+
return strval($v);
17+
} else if (is_array($v)) {
18+
if (count($v) == 0)
19+
return "[]";
20+
return '['.$this->prettyPrintNewLine.implode(", ".$this->prettyPrintNewLine, array_map(fn($k)=>$identedTabs.$this->encode($k, $identedTabs), $v)).$this->prettyPrintNewLine.$tabs.']';
21+
} else if (is_string($v)) {
22+
return '"'.$this->escapeString($v).'"';
23+
} else if (is_object($v)) {
24+
$v = (array) $v;
25+
foreach ($v as $key=>$value) {
26+
if (!isset($value))
27+
unset($v[$key]);
28+
}
29+
if (count($v) == 0)
30+
return "{}";
31+
return '{'.$this->prettyPrintNewLine.implode(", ".$this->prettyPrintNewLine, array_map(fn($k, $val)=>$identedTabs.$this->encode($k, $identedTabs).': '.$this->encode($val, $identedTabs), array_keys($v), array_values($v))).$this->prettyPrintNewLine.$tabs.'}';
32+
}
33+
return "";
34+
}
35+
36+
private function escapeString($str) : string {
37+
return
38+
str_replace("\n", "\\n",
39+
str_replace('"', '\"',
40+
str_replace("\\","\\\\", $str)));
41+
}
42+
43+
public function setPrettyPrint(bool $prettyPrint): JSONEncoder {
44+
$this->prettyPrint = $prettyPrint;
45+
return $this;
46+
}
47+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
namespace de\interaapps\jsonplus\serializationadapter\impl;
3+
4+
use de\interaapps\jsonplus\parser\JSONDecoder;
5+
use de\interaapps\jsonplus\parser\JSONEncoder;
6+
use de\interaapps\jsonplus\serializationadapter\SerializationAdapter;
7+
8+
9+
class JsonSerializationAdapter implements SerializationAdapter {
10+
public function fromJson($json){
11+
return (new JSONDecoder($json))->readNext();
12+
}
13+
14+
public function toJson($v, bool $prettyPrint) {
15+
return (new JSONEncoder())
16+
->setPrettyPrint($prettyPrint)
17+
->encode($v, "");
18+
}
19+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
namespace de\interaapps\jsonplus\typemapper;
3+
4+
5+
use de\interaapps\jsonplus\attributes\Serialize;
6+
use de\interaapps\jsonplus\JSONPlus;
7+
use ReflectionClass;
8+
9+
class StdClassObjectTypeMapper implements TypeMapper {
10+
public function __construct(
11+
private JSONPlus $jsonPlus
12+
){
13+
}
14+
15+
public function map(mixed $o, string $type): mixed {
16+
/* Implement if CASING is implemented
17+
$oo = [];
18+
19+
foreach ($o as $k=>$v) {
20+
echo $k;
21+
$oo[$k] = $v;
22+
}*/
23+
24+
return (object) $o;
25+
}
26+
27+
public function mapToJson(mixed $o, string $type): mixed {
28+
return (object) $o;
29+
}
30+
}

src/test/testbootstrap.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use de\interaapps\jsonplus\attributes\Serialize;
55
use de\interaapps\jsonplus\JSONModel;
66
use de\interaapps\jsonplus\JSONPlus;
7+
use de\interaapps\jsonplus\serializationadapter\impl\JsonSerializationAdapter;
78

89
chdir(".");;
910
ini_set('display_errors', 1);
@@ -37,16 +38,15 @@ public function setName(string $name): Test {
3738
}
3839

3940
const JSON = '{
40-
"name_": "World!",
41+
"name_":"Wo\"\nrld!\\\",
42+
"aeef23": {},
43+
"aeef2": {"test": true},
4144
"test": false,
4245
"feef": 21,
4346
"aeef": [1,2,3],
44-
"aeef2": {},
45-
"test2": {
46-
"sheesh": "yeeeeeeeee"
47-
}
47+
"test2": "a"
4848
}';
4949

50-
Test::setJsonPlusInstance(JSONPlus::createDefault()->setPrettyPrinting(true));
51-
52-
echo Test::fromJson(JSON)->toJson();
50+
//echo Test::fromJson(JSON)->toJson();
51+
$json = new JSONPlus(new JsonSerializationAdapter());
52+
var_dump($json->fromJson(JSON, Test::class));

0 commit comments

Comments
 (0)