Skip to content

Commit

Permalink
Added JsonSerializationAdapter.php (Custom JSON implementation) and more
Browse files Browse the repository at this point in the history
  • Loading branch information
JulianFun123 committed Oct 5, 2021
1 parent 60ad5c7 commit 1fcefc4
Show file tree
Hide file tree
Showing 7 changed files with 244 additions and 12 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<?php

use de\interaapps\jsonplus\attributes\Serialize;
use de\interaapps\jsonplus\JSONModel;use de\interaapps\jsonplus\JSONPlus;
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;

class Test2 {
use JSONModel;
Expand Down Expand Up @@ -48,6 +48,12 @@ echo $jsonPlus->fromJson($arrJson)[0];
Test::setJsonPlusInstance($jsonPlus);
// For all (Default instance)
JSONPlus::$default = $jsonPlus;

/// Using other JSON-Drivers
// Uses PHPs default json_encode and json_decode methods
$jsonPlus = new JSONPlus(new PHPJsonSerializationAdapter());
// Uses an custom implementation of JSON. This will be automatically chosen by JSONPlus::createDefault when json_decode doesn't exist
$jsonPlus = new JSONPlus(new JsonSerializationAdapter());
```

## Installation
Expand Down
11 changes: 8 additions & 3 deletions src/main/de/interaapps/jsonplus/JSONPlus.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<?php
namespace de\interaapps\jsonplus;

use de\interaapps\jsonplus\serializationadapter\impl\JsonSerializationAdapter;
use de\interaapps\jsonplus\serializationadapter\impl\phpjson\PHPJsonSerializationAdapter;
use de\interaapps\jsonplus\serializationadapter\SerializationAdapter;
use de\interaapps\jsonplus\typemapper\ObjectTypeMapper;
use de\interaapps\jsonplus\typemapper\PassThroughTypeMapper;
use de\interaapps\jsonplus\typemapper\StdClassObjectTypeMapper;
use de\interaapps\jsonplus\typemapper\TypeMapper;
use ReflectionClass;

Expand All @@ -29,6 +31,8 @@ public function __construct(
"bool" => $this->passThroughTypeMapper,
"array" => $this->passThroughTypeMapper,
"boolean" => $this->passThroughTypeMapper,
"NULL" => $this->passThroughTypeMapper,
"stdClass" => new StdClassObjectTypeMapper($this),
];
}

Expand All @@ -39,8 +43,9 @@ public function fromJson($json, $type=null){
public function map($o, $type = null){
if ($type == null) {
$type = gettype($o);

if ($type == "object")
$type = get_class($type);
$type = get_class($o);
}

foreach ($this->typeMapper as $typeName => $typeMapper) {
Expand All @@ -58,7 +63,7 @@ public function mapToJson($o, $type = null){
if ($type == null) {
$type = gettype($o);
if ($type == "object")
$type = get_class($type);
$type = get_class($o);
}
foreach ($this->typeMapper as $typeName => $typeMapper) {
if ($type == $typeName)
Expand All @@ -77,7 +82,7 @@ public function setPrettyPrinting(bool $prettyPrinting): JSONPlus {
}

public static function createDefault() : JSONPlus {
return new JSONPlus(new PHPJsonSerializationAdapter());
return new JSONPlus(function_exists("json_decode") ? new PHPJsonSerializationAdapter() : new JsonSerializationAdapter());
}
}
JSONPlus::$default = JSONPlus::createDefault();
125 changes: 125 additions & 0 deletions src/main/de/interaapps/jsonplus/parser/JSONDecoder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<?php
namespace de\interaapps\jsonplus\parser;


class JSONDecoder {
private int $i = 0;
public function __construct(
private string $json
) {
}

public function jumpEmpties(){
while ((trim($this->get()) == '' || $this->get()=="\n") && $this->i < strlen($this->json))
$this->i++;
}

public function get($off = 0) : string {
if (strlen($this->json) > $this->i+$off && $this->i+$off >= 0)
return $this->json[$this->i+$off];
return "";
}

public function readNext() : mixed {
$this->jumpEmpties();

if ($this->get() == '{')
return $this->readObject();
if ($this->get() == '[')
return $this->readArray();
if ($this->get() == '"')
return $this->readString();

return $this->readPrimitive();
}
public function readObject() : object|null {
$o = (object)[];
$this->i++;
for (; $this->i<strlen($this->json); $this->i++) {
$this->jumpEmpties();
if ($this->get() == '}') {
$this->i++;
return $o;
}

$key = $this->readNext();
$this->jumpEmpties();
if ($this->get() == ":")
$this->i++;
$this->jumpEmpties();
$value = $this->readNext();

$o->{$key} = $value;

$this->jumpEmpties();
if ($this->get() == '}') {
$this->i++;
return $o;
}

if ($this->get(1) == ",")
$this->i++;
}

return null;
}
public function readArray() : array {
$this->i++;
$a = [];
for (; $this->i<strlen($this->json); $this->i++) {
$this->jumpEmpties();
if ($this->get() == ']') {
$this->i++;
return $a;
}

array_push($a, $this->readNext());

$this->jumpEmpties();
if ($this->get() == ']') {
$this->i++;
return $a;
}

if ($this->get(1) == ",")
$this->i++;
}
return [];
}

public function readString() : string {
$s = "";
$this->i++;
for (; $this->i<strlen($this->json); $this->i++) {
$char = $this->get();

if ($char == '"' && ($this->get(-1) != "\\" || $this->get(-2) == "\\")) {
if ($this->get(-1) && $this->get(-2) != "\\")
$this->i++;
return $s;
}
$s .= $char;
}
return "";
}

private function primitiveStringToPHP($p){
if ($p == "false")
return false;
if ($p == "true")
return true;
return (double) $p;
}

public function readPrimitive() : mixed {
$p = "";
for (; $this->i<strlen($this->json); $this->i++) {
$char = $this->get();
if ($char == '"' || $char == ',' || $char == '}' || $char == ']')
return $this->primitiveStringToPHP($p);
$p .= $char;
}
$this->i--;
return $this->primitiveStringToPHP($p);
}
}
47 changes: 47 additions & 0 deletions src/main/de/interaapps/jsonplus/parser/JSONEncoder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php


namespace de\interaapps\jsonplus\parser;


class JSONEncoder {
private bool $prettyPrint = false;
public function encode($v, $tabs="") : string {
$this->prettyPrintNewLine = $this->prettyPrint ? "\n": '';
$identedTabs = $this->prettyPrint ? $tabs." " : '';

if (is_bool($v)) {
return $v ? "true" : "false";
} else if (is_int($v) || is_bool($v) || is_double($v)) {
return strval($v);
} else if (is_array($v)) {
if (count($v) == 0)
return "[]";
return '['.$this->prettyPrintNewLine.implode(", ".$this->prettyPrintNewLine, array_map(fn($k)=>$identedTabs.$this->encode($k, $identedTabs), $v)).$this->prettyPrintNewLine.$tabs.']';
} else if (is_string($v)) {
return '"'.$this->escapeString($v).'"';
} else if (is_object($v)) {
$v = (array) $v;
foreach ($v as $key=>$value) {
if (!isset($value))
unset($v[$key]);
}
if (count($v) == 0)
return "{}";
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.'}';
}
return "";
}

private function escapeString($str) : string {
return
str_replace("\n", "\\n",
str_replace('"', '\"',
str_replace("\\","\\\\", $str)));
}

public function setPrettyPrint(bool $prettyPrint): JSONEncoder {
$this->prettyPrint = $prettyPrint;
return $this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php
namespace de\interaapps\jsonplus\serializationadapter\impl;

use de\interaapps\jsonplus\parser\JSONDecoder;
use de\interaapps\jsonplus\parser\JSONEncoder;
use de\interaapps\jsonplus\serializationadapter\SerializationAdapter;


class JsonSerializationAdapter implements SerializationAdapter {
public function fromJson($json){
return (new JSONDecoder($json))->readNext();
}

public function toJson($v, bool $prettyPrint) {
return (new JSONEncoder())
->setPrettyPrint($prettyPrint)
->encode($v, "");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php
namespace de\interaapps\jsonplus\typemapper;


use de\interaapps\jsonplus\attributes\Serialize;
use de\interaapps\jsonplus\JSONPlus;
use ReflectionClass;

class StdClassObjectTypeMapper implements TypeMapper {
public function __construct(
private JSONPlus $jsonPlus
){
}

public function map(mixed $o, string $type): mixed {
/* Implement if CASING is implemented
$oo = [];
foreach ($o as $k=>$v) {
echo $k;
$oo[$k] = $v;
}*/

return (object) $o;
}

public function mapToJson(mixed $o, string $type): mixed {
return (object) $o;
}
}
16 changes: 8 additions & 8 deletions src/test/testbootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use de\interaapps\jsonplus\attributes\Serialize;
use de\interaapps\jsonplus\JSONModel;
use de\interaapps\jsonplus\JSONPlus;
use de\interaapps\jsonplus\serializationadapter\impl\JsonSerializationAdapter;

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

const JSON = '{
"name_": "World!",
"name_":"Wo\"\nrld!\\\",
"aeef23": {},
"aeef2": {"test": true},
"test": false,
"feef": 21,
"aeef": [1,2,3],
"aeef2": {},
"test2": {
"sheesh": "yeeeeeeeee"
}
"test2": "a"
}';

Test::setJsonPlusInstance(JSONPlus::createDefault()->setPrettyPrinting(true));

echo Test::fromJson(JSON)->toJson();
//echo Test::fromJson(JSON)->toJson();
$json = new JSONPlus(new JsonSerializationAdapter());
var_dump($json->fromJson(JSON, Test::class));

0 comments on commit 1fcefc4

Please sign in to comment.