diff --git a/assets/css/app/bs-overrides.css b/assets/css/app/bs-overrides.css
index 6043aafe..61a36bc4 100644
--- a/assets/css/app/bs-overrides.css
+++ b/assets/css/app/bs-overrides.css
@@ -105,4 +105,19 @@ form .col-form-label.required:after, form label.required:after {
position: relative;
right: -2px;
z-index: 700;
+}
+
+/****************************************
+ * HTML diff styling
+ ****************************************/
+
+/* Insertations are marked with green background and bold */
+ins {
+ background-color: #95f095;
+ font-weight: bold;
+}
+
+del {
+ background-color: #f09595;
+ font-weight: bold;
}
\ No newline at end of file
diff --git a/composer.json b/composer.json
index 1be31dc2..0f5c6450 100644
--- a/composer.json
+++ b/composer.json
@@ -4,16 +4,17 @@
"require": {
"php": "^7.4 || ^8.0",
"ext-ctype": "*",
+ "ext-dom": "*",
"ext-gd": "*",
"ext-iconv": "*",
"ext-intl": "*",
"ext-json": "*",
"ext-mbstring": "*",
- "ext-dom": "*",
"beberlei/doctrineextensions": "^1.2",
"brick/math": "^0.8.15",
"composer/package-versions-deprecated": "1.11.99.4",
"doctrine/annotations": "^1.6",
+ "doctrine/data-fixtures": "^1.6.6",
"doctrine/dbal": "^3.4.6",
"doctrine/doctrine-bundle": "^2.0",
"doctrine/doctrine-migrations-bundle": "^3.0",
@@ -25,6 +26,7 @@
"gregwar/captcha-bundle": "^2.1.0",
"hslavich/oneloginsaml-bundle": "^2.10",
"jbtronics/2fa-webauthn": "^1.0.0",
+ "jfcherng/php-diff": "^6.14",
"league/csv": "^9.8.0",
"league/html-to-markdown": "^5.0.1",
"liip/imagine-bundle": "^2.2",
@@ -78,9 +80,7 @@
"twig/intl-extra": "^3.0",
"twig/markdown-extra": "^3.0",
"web-auth/webauthn-symfony-bundle": "^3.3",
- "webmozart/assert": "^1.4",
- "doctrine/data-fixtures": "^1.6.6"
-
+ "webmozart/assert": "^1.4"
},
"require-dev": {
"dama/doctrine-test-bundle": "^7.0",
diff --git a/composer.lock b/composer.lock
index 609e595c..914a5c40 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "112549e8d6425274bb56b648d18c3878",
+ "content-hash": "51206f9aa7e372b40ef62a105c4a3f13",
"packages": [
{
"name": "beberlei/assert",
@@ -2628,6 +2628,242 @@
},
"time": "2022-10-03T22:29:32+00:00"
},
+ {
+ "name": "jfcherng/php-color-output",
+ "version": "3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/jfcherng/php-color-output.git",
+ "reference": "6c7bf16686cc6a291647fcb87491640a2d5edd20"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/jfcherng/php-color-output/zipball/6c7bf16686cc6a291647fcb87491640a2d5edd20",
+ "reference": "6c7bf16686cc6a291647fcb87491640a2d5edd20",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1.3"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^2.19",
+ "liip/rmt": "^1.6",
+ "phan/phan": "^2 || ^3 || ^4",
+ "phpunit/phpunit": ">=7 <10",
+ "squizlabs/php_codesniffer": "^3.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Jfcherng\\Utility\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jack Cherng",
+ "email": "jfcherng@gmail.com"
+ }
+ ],
+ "description": "Make your PHP command-line application colorful.",
+ "keywords": [
+ "ansi-colors",
+ "color",
+ "command-line",
+ "str-color"
+ ],
+ "support": {
+ "issues": "https://github.com/jfcherng/php-color-output/issues",
+ "source": "https://github.com/jfcherng/php-color-output/tree/3.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://www.paypal.me/jfcherng/5usd",
+ "type": "custom"
+ }
+ ],
+ "time": "2021-05-27T02:45:54+00:00"
+ },
+ {
+ "name": "jfcherng/php-diff",
+ "version": "6.14.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/jfcherng/php-diff.git",
+ "reference": "8b2bd0c987f69835a816642193d62a7c3664ca96"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/jfcherng/php-diff/zipball/8b2bd0c987f69835a816642193d62a7c3664ca96",
+ "reference": "8b2bd0c987f69835a816642193d62a7c3664ca96",
+ "shasum": ""
+ },
+ "require": {
+ "jfcherng/php-color-output": "^3",
+ "jfcherng/php-mb-string": "^1.4.6",
+ "jfcherng/php-sequence-matcher": "^3.2.9",
+ "php": ">=7.4"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^3.8",
+ "liip/rmt": "^1.6",
+ "phan/phan": "^5",
+ "phpunit/phpunit": "^9",
+ "squizlabs/php_codesniffer": "^3.6"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Jfcherng\\Diff\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Jack Cherng",
+ "email": "jfcherng@gmail.com"
+ },
+ {
+ "name": "Chris Boulton",
+ "email": "chris.boulton@interspire.com"
+ }
+ ],
+ "description": "A comprehensive library for generating differences between two strings in multiple formats (unified, side by side HTML etc).",
+ "keywords": [
+ "diff",
+ "udiff",
+ "unidiff",
+ "unified diff"
+ ],
+ "support": {
+ "issues": "https://github.com/jfcherng/php-diff/issues",
+ "source": "https://github.com/jfcherng/php-diff/tree/6.14.2"
+ },
+ "funding": [
+ {
+ "url": "https://www.paypal.me/jfcherng/5usd",
+ "type": "custom"
+ }
+ ],
+ "time": "2023-03-15T19:26:28+00:00"
+ },
+ {
+ "name": "jfcherng/php-mb-string",
+ "version": "1.4.8",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/jfcherng/php-mb-string.git",
+ "reference": "ef8926ff849863bfea234e99ee827947bedd86b0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/jfcherng/php-mb-string/zipball/ef8926ff849863bfea234e99ee827947bedd86b0",
+ "reference": "ef8926ff849863bfea234e99ee827947bedd86b0",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1.3"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^2.18",
+ "phan/phan": "^2 || ^3 || ^4",
+ "phpunit/phpunit": "^7.2 || ^8 || ^9"
+ },
+ "suggest": {
+ "ext-iconv": "Either \"ext-iconv\" or \"ext-mbstring\" is requried.",
+ "ext-mbstring": "Either \"ext-iconv\" or \"ext-mbstring\" is requried."
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Jfcherng\\Utility\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jack Cherng",
+ "email": "jfcherng@gmail.com"
+ }
+ ],
+ "description": "A high performance multibytes sting implementation for frequently reading/writing operations.",
+ "support": {
+ "issues": "https://github.com/jfcherng/php-mb-string/issues",
+ "source": "https://github.com/jfcherng/php-mb-string/tree/1.4.8"
+ },
+ "funding": [
+ {
+ "url": "https://www.paypal.me/jfcherng/5usd",
+ "type": "custom"
+ }
+ ],
+ "time": "2023-04-17T14:22:37+00:00"
+ },
+ {
+ "name": "jfcherng/php-sequence-matcher",
+ "version": "3.2.9",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/jfcherng/php-sequence-matcher.git",
+ "reference": "5de2243aa611a66395d85ba1a9169b439bd13e4d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/jfcherng/php-sequence-matcher/zipball/5de2243aa611a66395d85ba1a9169b439bd13e4d",
+ "reference": "5de2243aa611a66395d85ba1a9169b439bd13e4d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1.3"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^2.19",
+ "phan/phan": "^2.5 || ^3 || ^4 || ^5",
+ "phpunit/phpunit": ">=7 <10",
+ "squizlabs/php_codesniffer": "^3.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Jfcherng\\Diff\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Jack Cherng",
+ "email": "jfcherng@gmail.com"
+ },
+ {
+ "name": "Chris Boulton",
+ "email": "chris.boulton@interspire.com"
+ }
+ ],
+ "description": "A longest sequence matcher. The logic is primarily based on the Python difflib package.",
+ "support": {
+ "issues": "https://github.com/jfcherng/php-sequence-matcher/issues",
+ "source": "https://github.com/jfcherng/php-sequence-matcher/tree/3.2.9"
+ },
+ "funding": [
+ {
+ "url": "https://www.paypal.me/jfcherng/5usd",
+ "type": "custom"
+ }
+ ],
+ "time": "2023-03-11T06:56:44+00:00"
+ },
{
"name": "laminas/laminas-code",
"version": "4.7.1",
@@ -16233,12 +16469,12 @@
"platform": {
"php": "^7.4 || ^8.0",
"ext-ctype": "*",
+ "ext-dom": "*",
"ext-gd": "*",
"ext-iconv": "*",
"ext-intl": "*",
"ext-json": "*",
- "ext-mbstring": "*",
- "ext-dom": "*"
+ "ext-mbstring": "*"
},
"platform-dev": [],
"platform-overrides": {
diff --git a/src/Services/LogSystem/LogDataFormatter.php b/src/Services/LogSystem/LogDataFormatter.php
index c6ecd84f..7e5935e7 100644
--- a/src/Services/LogSystem/LogDataFormatter.php
+++ b/src/Services/LogSystem/LogDataFormatter.php
@@ -50,7 +50,14 @@ class LogDataFormatter
public function formatData($data, AbstractLogEntry $logEntry, string $fieldName): string
{
if (is_string($data)) {
- return '"' . mb_strimwidth(htmlspecialchars($data), 0, self::STRING_MAX_LENGTH, ) . '"';
+ $tmp = '"' . mb_strimwidth(htmlspecialchars($data), 0, self::STRING_MAX_LENGTH, ) . '"';
+
+ //Show special characters and line breaks
+ $tmp = preg_replace('/\n/', '\\n
', $tmp);
+ $tmp = preg_replace('/\r/', '\\r', $tmp);
+ $tmp = preg_replace('/\t/', '\\t', $tmp);
+
+ return $tmp;
}
if (is_bool($data)) {
diff --git a/src/Services/LogSystem/LogDiffFormatter.php b/src/Services/LogSystem/LogDiffFormatter.php
new file mode 100644
index 00000000..92b6d814
--- /dev/null
+++ b/src/Services/LogSystem/LogDiffFormatter.php
@@ -0,0 +1,76 @@
+.
+ */
+
+namespace App\Services\LogSystem;
+
+use Jfcherng\Diff\DiffHelper;
+
+class LogDiffFormatter
+{
+ /**
+ * Format the diff between the given data, depending on the type of the data.
+ * If the diff is not possible, an empty string is returned.
+ * @param $old_data
+ * @param $new_data
+ * @return string
+ */
+ public function formatDiff($old_data, $new_data): string
+ {
+ if (is_string($old_data) && is_string($new_data)) {
+ return $this->diffString($old_data, $new_data);
+ }
+
+ if (is_numeric($old_data) && is_numeric($new_data)) {
+ return $this->diffNumeric($old_data, $new_data);
+ }
+
+ return '';
+ }
+
+ private function diffString(string $old_data, string $new_data): string
+ {
+ return DiffHelper::calculate($old_data, $new_data, 'Combined',
+ [ //Diff options
+ 'context' => 2,
+ ],
+ [ //Render options
+ 'detailLevel' => 'char',
+ 'showHeader' => false,
+ ]);
+ }
+
+ private function diffNumeric($old_data, $new_data): string
+ {
+ if ((!is_numeric($old_data)) || (!is_numeric($new_data))) {
+ throw new \InvalidArgumentException('The given data is not numeric.');
+ }
+
+ $difference = $new_data - $old_data;
+
+ //Positive difference
+ if ($difference > 0) {
+ return sprintf('+%s', $difference);
+ } else if ($difference < 0) {
+ return sprintf('%s', $difference);
+ } else {
+ return sprintf('%s', $difference);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Twig/LogExtension.php b/src/Twig/LogExtension.php
index 7440a9b4..a56b9275 100644
--- a/src/Twig/LogExtension.php
+++ b/src/Twig/LogExtension.php
@@ -21,20 +21,27 @@
namespace App\Twig;
use App\Services\LogSystem\LogDataFormatter;
+use App\Services\LogSystem\LogDiffFormatter;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
-class LogExtension extends AbstractExtension
+final class LogExtension extends AbstractExtension
{
- public function __construct(LogDataFormatter $logDataFormatter)
+
+ private LogDataFormatter $logDataFormatter;
+ private LogDiffFormatter $logDiffFormatter;
+
+ public function __construct(LogDataFormatter $logDataFormatter, LogDiffFormatter $logDiffFormatter)
{
$this->logDataFormatter = $logDataFormatter;
+ $this->logDiffFormatter = $logDiffFormatter;
}
public function getFunctions()
{
return [
- new TwigFunction('format_log_data', [$this->logDataFormatter, 'formatData'], ['is_safe' => ['html']])
+ new TwigFunction('format_log_data', [$this->logDataFormatter, 'formatData'], ['is_safe' => ['html']]),
+ new TwigFunction('format_log_diff', [$this->logDiffFormatter, 'formatDiff'], ['is_safe' => ['html']]),
];
}
}
\ No newline at end of file
diff --git a/templates/log_system/details/helper.macro.html.twig b/templates/log_system/details/helper.macro.html.twig
index 97d776b8..1081cdda 100644
--- a/templates/log_system/details/helper.macro.html.twig
+++ b/templates/log_system/details/helper.macro.html.twig
@@ -46,6 +46,9 @@
{% if new_data is not empty %}