Skip to content

Commit ea59601

Browse files
committed
Initial commit with current working version
0 parents  commit ea59601

15 files changed

+480
-0
lines changed

.gitattributes

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
* text=auto
2+
3+
# Ignore following folders/files.
4+
/build export-ignore
5+
/docs export-ignore
6+
/tests export-ignore
7+
/.coveralls.yml export-ignore
8+
/.gitattributes export-ignore
9+
/.gitignore export-ignore
10+
/.php_cs export-ignore
11+
/.scrutinizer.yml export-ignore
12+
/.travis.yml export-ignore
13+
/phpunit.xml export-ignore
14+
/CHANGELOG.md export-ignore
15+
/LICENSE export-ignore
16+
/README.md export-ignore

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/vendor
2+
composer.lock

.styleci.yml

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
preset: laravel
2+
3+
risky: false
4+
5+
finder:
6+
name:
7+
- "*.php"
8+
9+
exclude:
10+
- "tests"

.travis.yml

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
language: php
2+
3+
sudo: required
4+
5+
dist: trusty
6+
7+
php:
8+
- 5.6
9+
- 7.0
10+
- 7.1
11+
- 7.2
12+
13+
before_script:
14+
- composer config discard-changes true
15+
- travis_retry composer install --prefer-dist --no-interaction

LICENSE.md

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
The MIT License (MIT)
2+
3+
Copyright (C) 2017 Konsulting Ltd <http://klever.co.uk>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of
6+
this software and associated documentation files (the "Software"), to deal in
7+
the Software without restriction, including without limitation the rights to
8+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9+
the Software, and to permit persons to whom the Software is furnished to do so,
10+
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, FITNESS
17+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# JSON Diff
2+
3+
Get a readable diff from two bits of JSON.

composer.json

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "konsulting/new-package",
3+
"description": "",
4+
"require": {
5+
"php": ">=5.6",
6+
"phpunit/phpunit": "^5.6 || ^6.5 || ^7.0"
7+
},
8+
"license": "MIT",
9+
"authors": [
10+
{
11+
"name": "Keoghan Litchfield",
12+
"email": "[email protected]"
13+
}
14+
],
15+
"autoload" : {
16+
"psr-4": {
17+
"Konsulting\\": "src/"
18+
}
19+
},
20+
"autoload-dev": {
21+
"psr-4": {
22+
"Konsulting\\Tests\\": "tests/"
23+
}
24+
}
25+
}

phpunit.xml

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit backupGlobals="false"
3+
backupStaticAttributes="false"
4+
bootstrap="tests/bootstrap.php"
5+
colors="true"
6+
convertErrorsToExceptions="true"
7+
convertNoticesToExceptions="true"
8+
convertWarningsToExceptions="true"
9+
processIsolation="false"
10+
stopOnFailure="false"
11+
syntaxCheck="false">
12+
<testsuites>
13+
<testsuite name="Unit">
14+
<directory suffix="Test.php">./tests/Unit</directory>
15+
</testsuite>
16+
</testsuites>
17+
<filter>
18+
<whitelist addUncoveredFilesFromWhitelist="false">
19+
<directory suffix=".php">src/</directory>
20+
</whitelist>
21+
</filter>
22+
</phpunit>

src/Exceptions/JsonDecodeFailed.php

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
namespace Konsulting\Exceptions;
3+
4+
use Exception;
5+
6+
class JsonDecodeFailed extends Exception
7+
{
8+
9+
}

src/JsonDiff.php

+178
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
<?php
2+
3+
namespace Konsulting;
4+
5+
use Konsulting\Exceptions\JsonDecodeFailed;
6+
7+
class JsonDiff
8+
{
9+
protected $exclude = [];
10+
protected $original;
11+
protected $new;
12+
13+
/**
14+
* JsonDiff constructor.
15+
*
16+
* @param string $original
17+
*/
18+
public function __construct($original = '')
19+
{
20+
$this->original = $original;
21+
}
22+
23+
/**
24+
* @param string|array $value
25+
*
26+
* @return $this
27+
*/
28+
public function exclude($value)
29+
{
30+
$value = ! $value ? [] : $value;
31+
32+
$this->exclude = is_array($value) ? $value : [$value];
33+
34+
return $this;
35+
}
36+
37+
/**
38+
* @param string $original
39+
* @param string $new
40+
*
41+
* @return array
42+
* @throws \Exception
43+
*/
44+
public function compare($original, $new)
45+
{
46+
$this->original = $original;
47+
48+
return $this->compareTo($new);
49+
}
50+
51+
/**
52+
* @param string $new
53+
*
54+
* @return array
55+
* @throws \Konsulting\Exceptions\JsonDecodeFailed
56+
*/
57+
public function compareTo($new)
58+
{
59+
$original = $this->decode($this->original);
60+
$new = $this->decode($new);
61+
62+
$flatOriginal = $this->flatten($original);
63+
$flatNew = $this->flatten($new);
64+
65+
// array_diff_assoc only returns the values in array1 that are not in array2
66+
// so if we don't find any, we're going to check the other way around too
67+
// otherwise we may miss some important changes, that sucks big-time.
68+
$added = array_diff_assoc($flatNew, $flatOriginal);
69+
$removed = array_diff_assoc($flatOriginal, $flatNew);
70+
71+
$diff = [
72+
'added' => $this->inflate($added),
73+
'removed' => $this->inflate($removed),
74+
];
75+
76+
$changed = ! empty($added) || ! empty($removed);
77+
78+
return compact('original', 'new', 'diff', 'changed');
79+
}
80+
81+
/**
82+
* @param $json
83+
*
84+
* @return array
85+
* @throws \Konsulting\Exceptions\JsonDecodeFailed
86+
*/
87+
public function decode($json)
88+
{
89+
$array = json_decode($json, true);
90+
91+
if (json_last_error() !== 0) {
92+
throw new JsonDecodeFailed('Failed decoding json');
93+
}
94+
95+
return $this->stripColumns($this->exclude, $array);
96+
}
97+
98+
/**
99+
* @param array $columns
100+
* @param array $array
101+
*
102+
* @return array
103+
*/
104+
public function stripColumns($columns = [], $array = [])
105+
{
106+
if (! is_array($array)) {
107+
return $array;
108+
}
109+
110+
$array = array_diff_key($array, array_fill_keys($columns, null));
111+
112+
foreach($array as $k => $v) {
113+
if(is_array($v)) {
114+
$array[$k] = $this->stripColumns($columns, $v);
115+
}
116+
}
117+
118+
return $array;
119+
}
120+
121+
/**
122+
* @param $arr
123+
* @param string $base
124+
* @param string $divider_char
125+
*
126+
* @return array
127+
*/
128+
public function flatten($arr, $base = "", $divider_char = "||")
129+
{
130+
$ret = [];
131+
if (is_array($arr)) {
132+
foreach ($arr as $k => $v) {
133+
if (is_array($v)) {
134+
$tmp_array = $this->flatten($v, $base.$k.$divider_char, $divider_char);
135+
$ret = array_merge($ret, $tmp_array);
136+
} else {
137+
$ret[$base.$k] = $v;
138+
}
139+
}
140+
}
141+
return $ret;
142+
}
143+
144+
/**
145+
* @param $arr
146+
* @param string $divider_char
147+
*
148+
* @return array|bool
149+
*/
150+
public function inflate($arr, $divider_char = "||")
151+
{
152+
if (!is_array($arr)) {
153+
return false;
154+
}
155+
156+
$split = '/' . preg_quote($divider_char, '/') . '/';
157+
158+
$ret = [];
159+
foreach ($arr as $key => $val) {
160+
$parts = preg_split($split, $key, -1, PREG_SPLIT_NO_EMPTY);
161+
$leafpart = array_pop($parts);
162+
$parent = &$ret;
163+
foreach ($parts as $part) {
164+
if (!isset($parent[$part])) {
165+
$parent[$part] = [];
166+
} elseif (!is_array($parent[$part])) {
167+
$parent[$part] = [];
168+
}
169+
$parent = &$parent[$part];
170+
}
171+
172+
if (empty($parent[$leafpart])) {
173+
$parent[$leafpart] = $val;
174+
}
175+
}
176+
return $ret;
177+
}
178+
}

0 commit comments

Comments
 (0)