-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from Lendable/lib
Initial implementation
- Loading branch information
Showing
10 changed files
with
255 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
/vendor | ||
phpunit.xml | ||
composer.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,10 @@ | ||
Lendable JSON | ||
============= | ||
Provides an object oriented interface for handling json in php. | ||
|
||
Instead of failing silently, this lib will throw exceptions on json errors. | ||
|
||
## Installation | ||
```bash | ||
composer require lendable/json-serializer | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
{ | ||
"name": "lendable/json-serializer", | ||
"description": "JSON serializer/deserializer with an OOP interface", | ||
"type": "library", | ||
"authors": [ | ||
{ | ||
"name": "Lendable Ltd", | ||
"email": "[email protected]" | ||
} | ||
], | ||
"autoload": { | ||
"psr-4": { | ||
"Lendable\\Json\\": "lib/" | ||
} | ||
}, | ||
"autoload-dev": { | ||
"psr-4": { | ||
"Tests\\Lendable\\Json\\Unit\\": "tests/unit/" | ||
} | ||
}, | ||
"require": { | ||
"php": ">=7.1", | ||
"ext-json": "*" | ||
}, | ||
"require-dev": { | ||
"phpunit/phpunit": "^7.4" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Lendable\Json; | ||
|
||
final class DeserializationFailed extends \RuntimeException implements Failure | ||
{ | ||
public function __construct(int $errorCode, string $errorMessage, ?\Throwable $previous = null) | ||
{ | ||
parent::__construct( | ||
\sprintf( | ||
'Failed to deserialize data from JSON. Error code: %d, error message: %s.', | ||
$errorCode, | ||
$errorMessage | ||
), | ||
$errorCode, | ||
$previous | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Lendable\Json; | ||
|
||
interface Failure extends \Throwable | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Lendable\Json; | ||
|
||
class InvalidDeserializedData extends \RuntimeException implements Failure | ||
{ | ||
public function __construct(string $unexpectedType) | ||
{ | ||
parent::__construct(sprintf('Expected array when deserializing JSON, got "%s".', $unexpectedType)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Lendable\Json; | ||
|
||
final class SerializationFailed extends \RuntimeException implements Failure | ||
{ | ||
public function __construct(int $errorCode, string $errorMessage, ?\Throwable $previous = null) | ||
{ | ||
parent::__construct( | ||
\sprintf( | ||
'Failed to serialize data to JSON. Error code: %d, error message: %s.', | ||
$errorCode, | ||
$errorMessage | ||
), | ||
$errorCode, | ||
$previous | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Lendable\Json; | ||
|
||
final class Serializer | ||
{ | ||
/** | ||
* @throws SerializationFailure | ||
*/ | ||
public function serialize(array $data): string | ||
{ | ||
$serialized = \json_encode($data); | ||
|
||
if (\json_last_error() !== JSON_ERROR_NONE) { | ||
throw new SerializationFailed(\json_last_error(), \json_last_error_msg()); | ||
} | ||
|
||
\assert(\is_string($serialized)); | ||
|
||
return $serialized; | ||
} | ||
|
||
/** | ||
* @throws DeserializationFailure | ||
* @throws InvalidDeserializedData | ||
*/ | ||
public function deserialize(string $json): array | ||
{ | ||
$data = \json_decode($json, true); | ||
|
||
if (\json_last_error() !== JSON_ERROR_NONE) { | ||
throw new DeserializationFailed(\json_last_error(), \json_last_error_msg()); | ||
} | ||
|
||
if (!\is_array($data)) { | ||
throw new InvalidDeserializedData(\gettype($data)); | ||
} | ||
|
||
return $data; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<phpunit colors="true" | ||
convertErrorsToExceptions="true" | ||
convertNoticesToExceptions="true" | ||
convertWarningsToExceptions="true" | ||
processIsolation="false" | ||
stopOnFailure="false" | ||
bootstrap="vendor/autoload.php"> | ||
|
||
<php> | ||
<ini name="error_reporting" value="E_ALL" /> | ||
</php> | ||
|
||
<testsuites> | ||
<testsuite name="unit"> | ||
<directory>./tests/unit/</directory> | ||
</testsuite> | ||
</testsuites> | ||
|
||
<filter> | ||
<whitelist> | ||
<directory>./lib/</directory> | ||
</whitelist> | ||
</filter> | ||
|
||
</phpunit> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Tests\Lendable\Json\Unit; | ||
|
||
use Lendable\Json\DeserializationFailed; | ||
use Lendable\Json\InvalidDeserializedData; | ||
use Lendable\Json\SerializationFailed; | ||
use Lendable\Json\Serializer; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
/** | ||
* @covers \Lendable\Json\Serializer | ||
* @covers \Lendable\Json\SerializationFailed | ||
* @covers \Lendable\Json\DeserializationFailed | ||
* @covers \Lendable\Json\InvalidDeserializedData | ||
*/ | ||
final class SerializerTest extends TestCase | ||
{ | ||
/** | ||
* @var Serializer | ||
*/ | ||
private $serializer; | ||
|
||
/** | ||
* @test | ||
*/ | ||
public function it_can_serialize_an_array_of_scalars_to_json(): void | ||
{ | ||
$result = $this->serializer->serialize(['foo' => 'bar', 'baz' => [1.03, true, 'foobar']]); | ||
|
||
$this->assertSame('{"foo":"bar","baz":[1.03,true,"foobar"]}', $result); | ||
} | ||
|
||
/** | ||
* @test | ||
*/ | ||
public function it_throws_when_serializing_if_an_error_encountered(): void | ||
{ | ||
$this->expectException(SerializationFailed::class); | ||
$this->expectExceptionMessage('Failed to serialize data to JSON. Error code: 5, error message: Malformed UTF-8 characters, possibly incorrectly encoded.'); | ||
|
||
$this->serializer->serialize(["\xf0\x28\x8c\xbc" => 'bar']); | ||
} | ||
|
||
/** | ||
* @test | ||
*/ | ||
public function it_can_deserialize_from_a_json_string_to_php_scalars(): void | ||
{ | ||
$result = $this->serializer->deserialize('{"foo":"bar","baz":[1.03,true,"foobar"]}'); | ||
|
||
$this->assertSame(['foo' => 'bar', 'baz' => [1.03, true, 'foobar']], $result); | ||
} | ||
|
||
/** | ||
* @test | ||
*/ | ||
public function it_throws_when_deserializing_if_an_error_encountered(): void | ||
{ | ||
$this->expectException(DeserializationFailed::class); | ||
$this->expectExceptionMessage('Failed to deserialize data from JSON. Error code: 4, error message: Syntax error.'); | ||
|
||
$this->serializer->deserialize('{"unclosed":"bad","object":"json"'); | ||
} | ||
|
||
/** | ||
* @test | ||
*/ | ||
public function it_throws_when_deserializing_if_the_result_is_not_an_array(): void | ||
{ | ||
$this->expectExceptionMessage(InvalidDeserializedData::class); | ||
$this->expectExceptionMessage('Expected array when deserializing JSON, got "boolean".'); | ||
|
||
$this->serializer->deserialize('true'); | ||
} | ||
|
||
protected function setUp(): void | ||
{ | ||
$this->serializer = new Serializer(); | ||
} | ||
} |