Skip to content

Commit b670436

Browse files
committed
v1
0 parents  commit b670436

22 files changed

+858
-0
lines changed

.editorconfig

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# More info at:
2+
# https://editorconfig.org/
3+
4+
root = true
5+
6+
[*]
7+
charset = utf-8
8+
end_of_line = lf
9+
indent_style = space
10+
indent_size = 4
11+
trim_trailing_whitespace = true
12+
insert_final_newline = true
13+
14+
[*{.json,.yml}]
15+
indent_size = 2

.gitignore

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/.php_cs.cache
2+
/.phpunit.result.cache
3+
/composer.lock
4+
/coverage.xml
5+
/phpbench.json
6+
/phpcs.xml
7+
/phpunit.xml
8+
/psalm.xml
9+
/vendor/

.scrutinizer.yml

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
build:
2+
image: default-bionic
3+
nodes:
4+
analysis:
5+
environment:
6+
php: 8.2
7+
tests:
8+
override:
9+
- php-scrutinizer-run
10+
coverage:
11+
environment:
12+
php: 8.2
13+
tests:
14+
override:
15+
- command: XDEBUG_MODE=coverage php vendor/bin/phpunit --coverage-clover coverage.xml
16+
coverage:
17+
file: coverage.xml
18+
format: clover
19+
php81:
20+
environment:
21+
php: 8.1
22+
tests:
23+
override:
24+
- command: php vendor/bin/phpunit

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Anatoly Nekhay
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Data Coder
2+
3+
## A flexible data coder for encoding and decoding formats like JSON, YAML, and more.

composer.json

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{
2+
"name": "sunrise/coder",
3+
"homepage": "https://github.com/sunrise-php/coder",
4+
"description": "A flexible data coder for encoding and decoding formats like JSON, YAML, and more.",
5+
"license": "MIT",
6+
"keywords": [
7+
"fenric",
8+
"sunrise",
9+
"data",
10+
"coder",
11+
"encoder",
12+
"decoder",
13+
"serializer"
14+
],
15+
"authors": [
16+
{
17+
"name": "Anatoly Nekhay",
18+
"email": "[email protected]",
19+
"homepage": "https://github.com/fenric"
20+
}
21+
],
22+
"require": {
23+
"php": ">=8.1"
24+
},
25+
"require-dev": {
26+
"php-di/php-di": "^7.0",
27+
"phpstan/phpstan": "^2.1",
28+
"phpunit/phpunit": "^10.5",
29+
"squizlabs/php_codesniffer": "^3.11",
30+
"vimeo/psalm": "^6.5"
31+
},
32+
"autoload": {
33+
"psr-4": {
34+
"Sunrise\\Coder\\": "src/"
35+
}
36+
},
37+
"autoload-dev": {
38+
"psr-4": {
39+
"Sunrise\\Coder\\Tests\\": "tests/"
40+
}
41+
},
42+
"scripts": {
43+
"phpcs": "@php phpcs --colors",
44+
"psalm": "@php psalm --no-cache",
45+
"phpstan": "@php phpstan analyse src --level=9 --memory-limit=-1",
46+
"phpunit": "@php phpunit --colors=always",
47+
"test": [
48+
"@phpcs",
49+
"@psalm",
50+
"@phpstan",
51+
"@phpunit"
52+
]
53+
},
54+
"config": {
55+
"sort-packages": true
56+
}
57+
}

phpcs.xml.dist

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0"?>
2+
<ruleset name="Sunrise Coding Standard">
3+
<rule ref="PSR12" />
4+
<rule ref="Generic.PHP.RequireStrictTypes" />
5+
6+
<rule ref="Generic.Files.LineLength">
7+
<exclude-pattern>resources/*</exclude-pattern>
8+
<exclude-pattern>tests/*</exclude-pattern>
9+
</rule>
10+
11+
<file>src</file>
12+
<file>tests</file>
13+
</ruleset>

phpunit.xml.dist

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0"?>
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd">
3+
<testsuites>
4+
<testsuite name="sunrise/coder">
5+
<directory>./tests/</directory>
6+
</testsuite>
7+
</testsuites>
8+
<source>
9+
<include>
10+
<directory>./src</directory>
11+
</include>
12+
</source>
13+
</phpunit>

psalm.xml.dist

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?xml version="1.0"?>
2+
<psalm
3+
errorLevel="1"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xmlns="https://getpsalm.org/schema/config"
6+
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
7+
phpVersion="8.1"
8+
>
9+
<projectFiles>
10+
<directory name="src" />
11+
<ignoreFiles>
12+
<directory name="vendor" />
13+
</ignoreFiles>
14+
</projectFiles>
15+
16+
<issueHandlers>
17+
<PossiblyUnusedMethod errorLevel="suppress" />
18+
<UnusedClass errorLevel="suppress" />
19+
</issueHandlers>
20+
</psalm>

renovate.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"extends": [
3+
"config:base"
4+
]
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Sunrise\Coder\Codec\JsonCodec;
6+
7+
use function DI\add;
8+
use function DI\create;
9+
use function DI\get;
10+
11+
return [
12+
'coder.json_codec.context' => [],
13+
14+
'coder.codecs' => add([
15+
create(JsonCodec::class)
16+
->constructor(
17+
context: get('coder.json_codec.context'),
18+
),
19+
]),
20+
];

resources/definitions/coder.php

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Sunrise\Coder\CodecManager;
6+
use Sunrise\Coder\CodecManagerInterface;
7+
8+
use function DI\create;
9+
use function DI\get;
10+
11+
return [
12+
'coder.codecs' => [],
13+
'coder.context' => [],
14+
15+
CodecManagerInterface::class => create(CodecManager::class)
16+
->constructor(
17+
codecs: get('coder.codecs'),
18+
context: get('coder.context')
19+
),
20+
];

src/Codec/JsonCodec.php

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?php
2+
3+
/**
4+
* It's free open-source software released under the MIT License.
5+
*
6+
* @author Anatoly Nekhay <[email protected]>
7+
* @copyright Copyright (c) 2025, Anatoly Nekhay
8+
* @license https://github.com/sunrise-php/coder/blob/master/LICENSE
9+
* @link https://github.com/sunrise-php/coder
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace Sunrise\Coder\Codec;
15+
16+
use JsonException;
17+
use Sunrise\Coder\CodecInterface;
18+
use Sunrise\Coder\Dictionary\MediaType;
19+
use Sunrise\Coder\Exception\CodecException;
20+
21+
use function json_decode;
22+
use function json_encode;
23+
24+
use const JSON_BIGINT_AS_STRING;
25+
use const JSON_OBJECT_AS_ARRAY;
26+
use const JSON_THROW_ON_ERROR;
27+
28+
final class JsonCodec implements CodecInterface
29+
{
30+
public const CONTEXT_KEY_DECODING_FLAGS = 'decoding_flags';
31+
public const CONTEXT_KEY_DECODING_MAX_DEPTH = 'decoding_max_depth';
32+
public const CONTEXT_KEY_ENCODING_FLAGS = 'encoding_flags';
33+
public const CONTEXT_KEY_ENCODING_MAX_DEPTH = 'encoding_max_depth';
34+
35+
private const DEFAULT_CODING_MAX_DEPTH = 512;
36+
37+
/**
38+
* @param array<array-key, mixed> $context
39+
*/
40+
public function __construct(
41+
private readonly array $context = [],
42+
) {
43+
}
44+
45+
/**
46+
* @inheritDoc
47+
*/
48+
public function getSupportedMediaTypes(): array
49+
{
50+
return [MediaType::JSON];
51+
}
52+
53+
/**
54+
* @inheritDoc
55+
*/
56+
public function decode(string $data, array $context = []): mixed
57+
{
58+
$context += $this->context;
59+
60+
/** @var int $decodingFlags */
61+
$decodingFlags = $context[self::CONTEXT_KEY_DECODING_FLAGS] ?? 0;
62+
/** @var int<1, 2147483647> $decodingMaxDepth */
63+
$decodingMaxDepth = $context[self::CONTEXT_KEY_DECODING_MAX_DEPTH] ?? self::DEFAULT_CODING_MAX_DEPTH;
64+
65+
$decodingFlags |= JSON_OBJECT_AS_ARRAY | JSON_BIGINT_AS_STRING;
66+
67+
try {
68+
return json_decode($data, depth: $decodingMaxDepth, flags: $decodingFlags | JSON_THROW_ON_ERROR);
69+
} catch (JsonException $e) {
70+
throw new CodecException($e->getMessage(), previous: $e);
71+
}
72+
}
73+
74+
/**
75+
* @inheritDoc
76+
*/
77+
public function encode(mixed $data, array $context = []): string
78+
{
79+
$context += $this->context;
80+
81+
/** @var int $encodingFlags */
82+
$encodingFlags = $context[self::CONTEXT_KEY_ENCODING_FLAGS] ?? 0;
83+
/** @var int<1, 2147483647> $encodingMaxDepth */
84+
$encodingMaxDepth = $context[self::CONTEXT_KEY_ENCODING_MAX_DEPTH] ?? self::DEFAULT_CODING_MAX_DEPTH;
85+
86+
try {
87+
/** @var non-empty-string */
88+
return json_encode($data, flags: $encodingFlags | JSON_THROW_ON_ERROR, depth: $encodingMaxDepth);
89+
} catch (JsonException $e) {
90+
throw new CodecException($e->getMessage(), previous: $e);
91+
}
92+
}
93+
}

src/CodecInterface.php

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
/**
4+
* It's free open-source software released under the MIT License.
5+
*
6+
* @author Anatoly Nekhay <[email protected]>
7+
* @copyright Copyright (c) 2025, Anatoly Nekhay
8+
* @license https://github.com/sunrise-php/coder/blob/master/LICENSE
9+
* @link https://github.com/sunrise-php/coder
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace Sunrise\Coder;
15+
16+
use Sunrise\Coder\Exception\CodecException;
17+
18+
interface CodecInterface
19+
{
20+
/**
21+
* @return array<array-key, MediaTypeInterface>
22+
*/
23+
public function getSupportedMediaTypes(): array;
24+
25+
/**
26+
* @param array<array-key, mixed> $context
27+
*
28+
* @throws CodecException
29+
*/
30+
public function decode(string $data, array $context = []): mixed;
31+
32+
/**
33+
* @param array<array-key, mixed> $context
34+
*
35+
* @throws CodecException
36+
*/
37+
public function encode(mixed $data, array $context = []): string;
38+
}

0 commit comments

Comments
 (0)