Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
93.75% covered (success)
93.75%
30 / 32
83.33% covered (warning)
83.33%
5 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
SignatureTextPolicyValue
93.75% covered (success)
93.75%
30 / 32
83.33% covered (warning)
83.33%
5 / 6
11.03
0.00% covered (danger)
0.00%
0 / 1
 normalize
88.24% covered (warning)
88.24%
15 / 17
0.00% covered (danger)
0.00%
0 / 1
6.06
 encode
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 normalizeString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 normalizeFloat
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 normalizeRenderMode
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 normalizeBackgroundType
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4/**
5 * SPDX-FileCopyrightText: 2026 LibreCode coop and LibreCode contributors
6 * SPDX-License-Identifier: AGPL-3.0-or-later
7 */
8
9namespace OCA\Libresign\Service\Policy\Provider\SignatureText;
10
11final class SignatureTextPolicyValue {
12    public const DEFAULT_TEMPLATE_FONT_SIZE = 9.8;
13    public const DEFAULT_SIGNATURE_FONT_SIZE = 20.0;
14    public const DEFAULT_SIGNATURE_WIDTH = 350.0;
15    public const DEFAULT_SIGNATURE_HEIGHT = 100.0;
16
17    /**
18     * @var array{
19     *     template: string,
20     *     template_font_size: float,
21     *     signature_font_size: float,
22     *     signature_width: float,
23     *     signature_height: float,
24     *     background_type: 'default'|'custom'|'deleted',
25     *     render_mode: 'default'|'graphic'|'text'|'description_only',
26     * }
27     */
28    public const DEFAULTS = [
29        'template' => '',
30        'template_font_size' => self::DEFAULT_TEMPLATE_FONT_SIZE,
31        'signature_font_size' => self::DEFAULT_SIGNATURE_FONT_SIZE,
32        'signature_width' => self::DEFAULT_SIGNATURE_WIDTH,
33        'signature_height' => self::DEFAULT_SIGNATURE_HEIGHT,
34        'background_type' => 'default',
35        'render_mode' => 'default',
36    ];
37
38    /**
39     * @param mixed $rawValue
40     * @param null|array{
41     *     template: string,
42     *     template_font_size: float,
43     *     signature_font_size: float,
44     *     signature_width: float,
45     *     signature_height: float,
46     *     background_type: 'default'|'custom'|'deleted',
47     *     render_mode: 'default'|'graphic'|'text'|'description_only',
48     * } $defaults
49     * @return array{
50     *     template: string,
51     *     template_font_size: float,
52     *     signature_font_size: float,
53     *     signature_width: float,
54     *     signature_height: float,
55     *     background_type: 'default'|'custom'|'deleted',
56     *     render_mode: 'default'|'graphic'|'text'|'description_only',
57     * }
58     */
59    public static function normalize(mixed $rawValue, ?array $defaults = null): array {
60        $defaults = $defaults === null ? self::DEFAULTS : array_replace(self::DEFAULTS, $defaults);
61
62        if (is_string($rawValue)) {
63            try {
64                $decoded = json_decode($rawValue, true);
65                if (is_array($decoded)) {
66                    $rawValue = $decoded;
67                }
68            } catch (\JsonException) {
69                // Fallback to defaults
70            }
71        }
72
73        if (!is_array($rawValue)) {
74            return $defaults;
75        }
76
77        return [
78            'template' => self::normalizeString($rawValue['template'] ?? $defaults['template']),
79            'template_font_size' => self::normalizeFloat($rawValue['template_font_size'] ?? $defaults['template_font_size']),
80            'signature_font_size' => self::normalizeFloat($rawValue['signature_font_size'] ?? $defaults['signature_font_size']),
81            'signature_width' => self::normalizeFloat($rawValue['signature_width'] ?? $defaults['signature_width']),
82            'signature_height' => self::normalizeFloat($rawValue['signature_height'] ?? $defaults['signature_height']),
83            'background_type' => self::normalizeBackgroundType($rawValue['background_type'] ?? $defaults['background_type']),
84            'render_mode' => self::normalizeRenderMode($rawValue['render_mode'] ?? $defaults['render_mode']),
85        ];
86    }
87
88    /**
89     * @param array{
90     *     template: string,
91     *     template_font_size: float,
92     *     signature_font_size: float,
93     *     signature_width: float,
94     *     signature_height: float,
95     *     background_type: 'default'|'custom'|'deleted',
96     *     render_mode: 'default'|'graphic'|'text'|'description_only',
97     * } $value
98     */
99    public static function encode(array $value): string {
100        $normalized = self::normalize($value);
101        return json_encode($normalized, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES);
102    }
103
104    private static function normalizeString(mixed $value): string {
105        return (string)($value ?? '');
106    }
107
108    private static function normalizeFloat(mixed $value): float {
109        $float = (float)($value ?? 0);
110        return max(0.1, $float);
111    }
112
113    /** @return 'default'|'graphic'|'text'|'description_only' */
114    private static function normalizeRenderMode(mixed $value): string {
115        $mode = (string)($value ?? 'default');
116        return match ($mode) {
117            'default', 'graphic', 'text', 'description_only' => $mode,
118            default => 'default',
119        };
120    }
121
122    /** @return 'default'|'custom'|'deleted' */
123    private static function normalizeBackgroundType(mixed $value): string {
124        $mode = (string)($value ?? 'default');
125        return match ($mode) {
126            'default', 'custom', 'deleted' => $mode,
127            default => 'default',
128        };
129    }
130}