Passed
Push — master ( 37cafd...a8b392 )
by
unknown
07:18
created

Config   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 155
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 66
c 1
b 0
f 0
dl 0
loc 155
rs 10
wmc 18

9 Methods

Rating   Name   Duplication   Size   Complexity  
A offsetSet() 0 3 1
A getApiUrl() 0 13 4
A offsetUnset() 0 3 1
A offsetGet() 0 3 1
A __construct() 0 3 1
A offsetExists() 0 3 1
A __debugInfo() 0 7 3
A importConfigArray() 0 16 4
A __get() 0 6 2
1
<?php declare(strict_types=1);
2
3
namespace Files\Backend\Seafile\Model;
4
5
use ArrayAccess;
6
use OutOfBoundsException;
7
use UnexpectedValueException;
8
9
/**
10
 * Class Config
11
 *
12
 * @property-read string server Seafile server. FQN or IP address (v4 only).
13
 * @property-read int port TCP port of Seafile server. Default is 443.
14
 * @property-read bool ssl Use https (true) or http (false) scheme. Default is true.
15
 * @property-read string path Base path. Commonly empty.
16
 * @property-read string user Username for authentication.
17
 * @property-read string pass Password for authentication.
18
 * @property-read string sso_auth_user_token Token for SSO user authentication
19
 */
20
class Config implements ArrayAccess
21
{
22
    private const DEF = [
23
        'server' => 'server_address',
24
        'port' => 'server_port',
25
        'ssl' => 'server_ssl',
26
        'path' => 'server_path',
27
        'user' => 'user',
28
        'pass' => 'password',
29
        'sso_auth_user_token' => 'sso_auth_user_token',
30
    ];
31
32
    private const SCHEMA = [
33
        self::DEF['server'] => [
34
            'filter' => FILTER_VALIDATE_DOMAIN,
35
            'flags' => FILTER_FLAG_HOSTNAME,
36
            'options' => ['default' => 'seafile.example.com'],
37
        ],
38
        self::DEF['port'] => [
39
            'filter' => FILTER_VALIDATE_INT,
40
            'options' => ['min_range' => 0, 'max_range' => 65535, 'default' => 443],
41
        ],
42
        self::DEF['ssl'] => [
43
            'filter' => FILTER_VALIDATE_BOOLEAN,
44
            'options' => ['default' => true],
45
        ],
46
        self::DEF['path'] => [
47
            'filter' => FILTER_UNSAFE_RAW,
48
            'flags' => FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH,
49
            'options' => ['default' => ''],
50
        ],
51
        self::DEF['user'] => [
52
            'filter' => FILTER_UNSAFE_RAW,
53
            'flags' => FILTER_FLAG_STRIP_LOW,
54
            'options' => ['default' => ''],
55
        ],
56
        self::DEF['pass'] => [
57
            'filter' => FILTER_DEFAULT,
58
            'options' => ['default' => ''],
59
        ],
60
        self::DEF['sso_auth_user_token'] => [
61
            'filter' => FILTER_DEFAULT,
62
            'flags' => FILTER_FLAG_EMPTY_STRING_NULL,
63
            'options' => ['default' => null],
64
        ],
65
    ];
66
67
    private array $config = [];
68
69
    public function __construct(array $config = [])
70
    {
71
        $this->importConfigArray($config);
72
    }
73
74
    /**
75
     * Get the URL of the Seafile servers REST API
76
     *
77
     * @return string
78
     */
79
    public function getApiUrl(): string
80
    {
81
        $config = $this;
82
83
        $ssl = (bool)$config->ssl;
84
        $defaultPort = $ssl ? 443 : 80;
85
        $port = max(0, min(65535, (int)$config->port)) ?: $defaultPort;
86
        $host = rtrim($config->server, '/');
87
        $path = ltrim($config->path, '/');
88
89
        $url = sprintf('http%s://%s:%d/%s', $ssl ? 's' : '', $host, $port, $path);
90
91
        return rtrim($url, '/');
92
    }
93
94
    /**
95
     * read-only properties
96
     *
97
     * @param string $name
98
     * @return mixed
99
     *
100
     * @noinspection MagicMethodsValidityInspection
101
     * @noinspection RedundantSuppression
102
     */
103
    public function __get(string $name): mixed
104
    {
105
        if (!isset(self::DEF[$name])) {
106
            throw new OutOfBoundsException("Not a property: \"$name\"");
107
        }
108
        return $this->config[self::DEF[$name]];
109
    }
110
111
    /**
112
     * init configuration data
113
     *
114
     * set all named properties from associative array, overwriting self with defaults
115
     * from the schema.
116
     *
117
     * @param array $config
118
     * @return void
119
     */
120
    public function importConfigArray(array $config): void
121
    {
122
        $result = [];
123
        foreach (self::SCHEMA as $name => $definition) {
124
            $result[$name] =
125
                array_key_exists($name, $config)
126
                    ? $config[$name]
127
                    : $this->config[$name] ?? $definition['options']['default'] ?? null;
128
        }
129
        $filtered = filter_var_array($result, self::SCHEMA);
130
131
        if (!is_array($filtered)) {
132
            throw new UnexpectedValueException('Failed to filter Seafile configuration values.');
133
        }
134
135
        $this->config = $filtered;
136
    }
137
138
    /**
139
     * Hide its internal state from var_dump()
140
     *
141
     * Note: The xdebug extension may break this behavior.
142
     * You should not rely on it if you have debugging extensions installed.
143
     *
144
     * @return array
145
     */
146
    public function __debugInfo(): array
147
    {
148
        $info = $this->config;
149
        $info['password'] = is_string($info['password']) ? '*' : null;
150
        $info['sso_auth_user_token'] = is_string($info['sso_auth_user_token']) ? '*' : null;
151
152
        return $info;
153
    }
154
155
    /* ArrayAccess implementation */
156
157
    public function offsetExists(mixed $offset): bool
158
    {
159
        return isset($this->config[$offset]);
160
    }
161
162
    public function offsetGet(mixed $offset): mixed
163
    {
164
        return $this->config[$offset];
165
    }
166
167
    public function offsetSet(mixed $offset, mixed $value): void
168
    {
169
        trigger_error('modification by write is undefined behaviour', E_USER_WARNING);
170
    }
171
172
    public function offsetUnset(mixed $offset): void
173
    {
174
        trigger_error('modification by delete is undefined behaviour', E_USER_WARNING);
175
    }
176
}
177