diff --git a/composer.json b/composer.json index b6ff988b7..77ca6f593 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "mexitek/phpcolors": "^1.0", "microsoft/azure-storage-blob": "^1.5.4", "mlocati/ip-lib": "^1.22", - "nextcloud/lognormalizer": "^2.0.0", + "nextcloud/lognormalizer": "^3.0.0", "pear/archive_tar": "^1.4.9", "pear/pear-core-minimal": "^1.10", "php-http/guzzle7-adapter": "^1.1.0", diff --git a/composer.lock b/composer.lock index d9f822414..2c1c4bf22 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": "3c9b64cbb1cf528b4a913f0ae3ec1b54", + "content-hash": "24dd4a400d1a5e49f42b40082fb459b2", "packages": [ { "name": "aws/aws-crt-php", @@ -2188,26 +2188,27 @@ }, { "name": "nextcloud/lognormalizer", - "version": "v2.0.0", + "version": "v3.0.0", "source": { "type": "git", "url": "https://github.com/nextcloud/lognormalizer.git", - "reference": "82ba06218001a15b3bc3b50dfca32e9ce8efb93e" + "reference": "9fbc308d900d0399298b0fa76123aa856e07ea1c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nextcloud/lognormalizer/zipball/82ba06218001a15b3bc3b50dfca32e9ce8efb93e", - "reference": "82ba06218001a15b3bc3b50dfca32e9ce8efb93e", + "url": "https://api.github.com/repos/nextcloud/lognormalizer/zipball/9fbc308d900d0399298b0fa76123aa856e07ea1c", + "reference": "9fbc308d900d0399298b0fa76123aa856e07ea1c", "shasum": "" }, "require": { "ext-json": "*", - "php": ">=7.3.0" + "php": ">=8.1" }, "require-dev": { "nextcloud/coding-standard": "^1.4", "phpunit/phpunit": "^10.5", - "vimeo/psalm": "^6.13" + "symfony/polyfill-php85": "^1.33", + "vimeo/psalm": "^6.14" }, "type": "library", "autoload": { @@ -2217,7 +2218,7 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "AGPL-3.0" + "AGPL-3.0-or-later" ], "authors": [ { @@ -2244,9 +2245,9 @@ ], "support": { "issues": "https://github.com/nextcloud/lognormalizer/issues", - "source": "https://github.com/nextcloud/lognormalizer/tree/v2.0.0" + "source": "https://github.com/nextcloud/lognormalizer/tree/v3.0.0" }, - "time": "2025-10-24T13:47:11+00:00" + "time": "2025-12-17T14:56:48+00:00" }, { "name": "paragonie/constant_time_encoding", @@ -6225,5 +6226,5 @@ "platform-overrides": { "php": "8.2.0" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } diff --git a/composer/installed.json b/composer/installed.json index 2665a382d..04e0e3a08 100644 --- a/composer/installed.json +++ b/composer/installed.json @@ -2278,29 +2278,30 @@ }, { "name": "nextcloud/lognormalizer", - "version": "v2.0.0", - "version_normalized": "2.0.0.0", + "version": "v3.0.0", + "version_normalized": "3.0.0.0", "source": { "type": "git", "url": "https://github.com/nextcloud/lognormalizer.git", - "reference": "82ba06218001a15b3bc3b50dfca32e9ce8efb93e" + "reference": "9fbc308d900d0399298b0fa76123aa856e07ea1c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nextcloud/lognormalizer/zipball/82ba06218001a15b3bc3b50dfca32e9ce8efb93e", - "reference": "82ba06218001a15b3bc3b50dfca32e9ce8efb93e", + "url": "https://api.github.com/repos/nextcloud/lognormalizer/zipball/9fbc308d900d0399298b0fa76123aa856e07ea1c", + "reference": "9fbc308d900d0399298b0fa76123aa856e07ea1c", "shasum": "" }, "require": { "ext-json": "*", - "php": ">=7.3.0" + "php": ">=8.1" }, "require-dev": { "nextcloud/coding-standard": "^1.4", "phpunit/phpunit": "^10.5", - "vimeo/psalm": "^6.13" + "symfony/polyfill-php85": "^1.33", + "vimeo/psalm": "^6.14" }, - "time": "2025-10-24T13:47:11+00:00", + "time": "2025-12-17T14:56:48+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -2310,7 +2311,7 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "AGPL-3.0" + "AGPL-3.0-or-later" ], "authors": [ { @@ -2337,7 +2338,7 @@ ], "support": { "issues": "https://github.com/nextcloud/lognormalizer/issues", - "source": "https://github.com/nextcloud/lognormalizer/tree/v2.0.0" + "source": "https://github.com/nextcloud/lognormalizer/tree/v3.0.0" }, "install-path": "../nextcloud/lognormalizer" }, @@ -3976,6 +3977,9 @@ "extra": { "branch-alias": { "dev-master": "4.0.x-dev" + }, + "patches_applied": { + "fix use RDATE in time range check and use all instances": ".patches/sabre-vobject-rdate.patch" } }, "installation-source": "dist", diff --git a/composer/installed.php b/composer/installed.php index dcb0ff654..bb6bc13ca 100644 --- a/composer/installed.php +++ b/composer/installed.php @@ -308,9 +308,9 @@ 'dev_requirement' => false, ), 'nextcloud/lognormalizer' => array( - 'pretty_version' => 'v2.0.0', - 'version' => '2.0.0.0', - 'reference' => '82ba06218001a15b3bc3b50dfca32e9ce8efb93e', + 'pretty_version' => 'v3.0.0', + 'version' => '3.0.0.0', + 'reference' => '9fbc308d900d0399298b0fa76123aa856e07ea1c', 'type' => 'library', 'install_path' => __DIR__ . '/../nextcloud/lognormalizer', 'aliases' => array(), diff --git a/nextcloud/lognormalizer/src/Normalizer.php b/nextcloud/lognormalizer/src/Normalizer.php index 1d8215b8e..22db4f85c 100644 --- a/nextcloud/lognormalizer/src/Normalizer.php +++ b/nextcloud/lognormalizer/src/Normalizer.php @@ -11,7 +11,9 @@ namespace Nextcloud\LogNormalizer; +use DateTimeInterface; use Throwable; +use UnitEnum; use function is_float; use function is_scalar; @@ -22,26 +24,8 @@ * @api */ class Normalizer { - - /** - * @type string - */ private const SIMPLE_DATE = 'Y-m-d H:i:s'; - - /** - * @var int - */ - private $maxRecursionDepth; - - /** - * @var int - */ - private $maxArrayItems; - - /** - * @var string - */ - private $dateFormat; + private readonly string $dateFormat; /** * @param int $maxRecursionDepth The maximum depth at which to go when inspecting objects @@ -49,58 +33,62 @@ class Normalizer { * parsing an array * @param null|string $dateFormat The format to apply to dates */ - public function __construct($maxRecursionDepth = 4, $maxArrayItems = 20, $dateFormat = null) { - $this->maxRecursionDepth = $maxRecursionDepth; - $this->maxArrayItems = $maxArrayItems; - if ($dateFormat !== null) { - $this->dateFormat = $dateFormat; - } else { - $this->dateFormat = static::SIMPLE_DATE; - } + public function __construct( + private readonly int $maxRecursionDepth = 4, + private readonly int $maxArrayItems = 20, + ?string $dateFormat = null, + ) { + $this->dateFormat = $dateFormat ?? static::SIMPLE_DATE; } /** * Normalizes the variable, JSON encodes it if needed and cleans up the result * + * Properly supported are bool|int|float|string|resource|UnitEnum|Throwable|DateTimeInterface + * as well as nested-arrays and Traversable of those types + * * @param mixed $data * @return string|null */ #[\NoDiscard] - public function format($data): ?string { + public function format(mixed $data): ?string { $data = $this->normalize($data); return $this->convertToString($data); } /** - * Converts Objects, Arrays, Dates and Exceptions to a string or an Array - * - * @uses Nextcloud\LogNormalizer\Normalizer::normalizeTraversable - * @uses Nextcloud\LogNormalizer\Normalizer::normalizeDate - * @uses Nextcloud\LogNormalizer\Normalizer::normalizeObject - * @uses Nextcloud\LogNormalizer\Normalizer::normalizeResource + * Converts Arrays, Dates and Exceptions to a string or an Array * * @param mixed $data - * @param int $depth + * @param ?int $depth * - * @return mixed|array + * @return mixed */ - public function normalize($data, ?int $depth = 0) { + public function normalize(mixed $data, ?int $depth = 0): mixed { + $depth = $depth ?? 0; $scalar = $this->normalizeScalar($data); if ($scalar !== null) { return $scalar; } - $decisionArray = [ - 'normalizeTraversable' => [$data, $depth], - 'normalizeDate' => [$data], - 'normalizeObject' => [$data, $depth], - 'normalizeResource' => [$data], - ]; - foreach ($decisionArray as $functionName => $arguments) { - $dataType = call_user_func_array([$this, $functionName], $arguments); - if ($dataType !== null) { - return $dataType; - } + if ($data instanceof Throwable) { + return $this->normalizeException($data, $depth); + } + + if ($data instanceof DateTimeInterface) { + return $data->format($this->dateFormat); + } + + if ($data instanceof UnitEnum) { + return $data->value; + } + + if (is_resource($data)) { + return '[resource] ' . substr((string)$data, 0, 40); + } + + if (is_iterable($data)) { + return $this->normalizeTraversableElement($data, $depth); } return '[unknown(' . gettype($data) . ')]'; @@ -110,12 +98,8 @@ public function normalize($data, ?int $depth = 0) { * JSON encodes data which isn't already a string and cleans up the result * * @todo: could maybe do a better job removing slashes - * - * @param mixed $data - * - * @return string|null */ - public function convertToString($data): ?string { + public function convertToString(mixed $data): ?string { if (!is_string($data)) { $data = @json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR); // Removing null byte and double slashes from object properties @@ -127,14 +111,8 @@ public function convertToString($data): ?string { /** * Returns various, filtered, scalar elements - * - * We're returning an array here to detect failure because null is a scalar and so is false - * - * @param mixed $data - * - * @return string|mixed|null */ - private function normalizeScalar($data) { + private function normalizeScalar(mixed $data): mixed { if ($data === null) { return null; } @@ -152,12 +130,8 @@ private function normalizeScalar($data) { /** * Normalizes infinite and trigonometric floats - * - * @param float $data - * - * @return string|float */ - private function normalizeFloat(float $data) { + private function normalizeFloat(float $data): string|float { if (is_infinite($data)) { $postfix = 'INF'; if ($data < 0) { @@ -173,33 +147,10 @@ private function normalizeFloat(float $data) { return $data; } - /** - * Returns an array containing normalized elements - * - * @used-by Nextcloud\LogNormalizer\Normalizer::normalize - * - * @param mixed $data - * @param int $depth - * - * @return array|null - */ - private function normalizeTraversable($data, int $depth = 0): ?array { - if (is_array($data) || $data instanceof \Traversable) { - return $this->normalizeTraversableElement($data, $depth); - } - - return null; - } - /** * Converts each element of a traversable variable to String - * - * @param mixed $data - * @param int $depth - * - * @return array */ - private function normalizeTraversableElement($data, int $depth): array { + private function normalizeTraversableElement(iterable $data, int $depth): array { $maxObjectRecursion = $this->maxRecursionDepth; $maxArrayItems = $this->maxArrayItems; $count = 1; @@ -220,65 +171,10 @@ private function normalizeTraversableElement($data, int $depth): array { return $normalized; } - /** - * Converts a date to String - * - * @used-by Nextcloud\LogNormalizer\Normalizer::normalize - * - * @param mixed $data - * - * @return null|string - */ - private function normalizeDate($data): ?string { - if ($data instanceof \DateTimeInterface) { - return $data->format($this->dateFormat); - } - - return null; - } - - /** - * Converts an Object to an Array - * - * We don't convert to json here as we would double encode them - * - * @used-by Nextcloud\LogNormalizer\Normalizer::normalize - * - * @param mixed $data - * @param int $depth - * - * @return mixed[]|string|null - */ - private function normalizeObject($data, int $depth) { - if (is_object($data)) { - if ($data instanceof Throwable) { - return $this->normalizeException($data); - } - // We don't need to go too deep in the recursion - $maxObjectRecursion = $this->maxRecursionDepth; - $arrayObject = new \ArrayObject($data); - $serializedObject = $arrayObject->getArrayCopy(); - if ($depth < $maxObjectRecursion) { - $depth++; - $response = $this->normalize($serializedObject, $depth); - - return [$this->getObjetName($data) => $response]; - } - - return $this->getObjetName($data); - } - - return null; - } - /** * Converts an Exception to a string array - * - * @param Throwable $exception - * - * @return mixed[] */ - private function normalizeException(Throwable $exception): array { + private function normalizeException(Throwable $exception, int $depth): array { $data = [ 'class' => get_class($exception), 'message' => $exception->getMessage(), @@ -290,37 +186,13 @@ private function normalizeException(Throwable $exception): array { $previous = $exception->getPrevious(); if ($previous) { - $data['previous'] = $this->normalizeException($previous); + if ($depth < $this->maxRecursionDepth) { + $data['previous'] = $this->normalizeException($previous, $depth + 1); + } else { + $data['previous'] = '[…]'; + } } return $data; } - - /** - * Formats the output of the object parsing - * - * @param object $object - * - * @return string - */ - private function getObjetName(object $object): string { - return sprintf('[object] (%s)', get_class($object)); - } - - /** - * Converts a resource to a string - * - * @used-by Nextcloud\LogNormalizer\Normalizer::normalize - * - * @param resource|mixed $data - * - * @return string|null - */ - private function normalizeResource($data): ?string { - if (is_resource($data)) { - return '[resource] ' . substr((string)$data, 0, 40); - } - - return null; - } }