StringOptions   A
last analyzed

Complexity

Total Complexity 20

Size/Duplication

Total Lines 181
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 181
rs 10
c 0
b 0
f 0
wmc 20

5 Methods

Rating   Name   Duplication   Size   Complexity  
A get() 0 10 2
A __construct() 0 7 2
A import() 0 10 1
C setStringOptions() 0 51 9
B export() 0 25 6
1
<?php
2
3
namespace Fwolf\Config;
4
5
use Fwolf\Config\Exception\InvalidFormatException;
6
use Fwolf\Config\Exception\KeyNotExist;
7
8
/**
9
 * StringOptions
10
 *
11
 * Special config with feature:
12
 *  - Initialize from string
13
 *  - Get un-defined option will return false(or other configure value)
14
 *
15
 * Example of option string:
16
 *  - "singleValue", will parse to bool value
17
 *  - "foo, bar=42", multiple value split by separator, default ','
18
 *  - "foo=42, bar = 24", assignment value, will parse to {key: value}
19
 *  - "foo = h e l l o", assignment value can contain whitespace
20
 *  - " foo = a b ", assignment key and value will all be trimmed, {foo: 'a b'}
21
 *  - "foo = false", explicit boolean type value
22
 *
23
 * @copyright   Copyright 2015-2017 Fwolf
24
 * @license     https://opensource.org/licenses/MIT MIT
25
 */
26
class StringOptions extends Config
27
{
28
    /**
29
     * Separator between key and value, eg: 'foo=bar' or 'foo: bar'
30
     */
31
    const KV_SEPARATOR = '=';
32
33
    /**
34
     * Separator between key or key-value pairs in option string.
35
     */
36
    const OPTION_SEPARATOR = ',';
37
38
    /**
39
     * For eye candy, whitespace may inserted after option separator.
40
     * Only for export.
41
     */
42
    const WHITESPACE_AFTER_OPTION_SEPARATOR = ' ';
43
44
    /**
45
     * Value of option only have name
46
     */
47
    const NAME_ONLY_VALUE = true;
48
49
    /**
50
     * Value of un-defined option
51
     */
52
    const FALLBACK_VALUE = false;
53
54
55
    /**
56
     * @param   string $optionString
57
     * @param   string $optionSeparator
58
     * @param   string $kvSeparator
59
     */
60
    public function __construct(
61
        $optionString = '',
62
        $optionSeparator = null,
63
        $kvSeparator = null
64
    ) {
65
        if (!empty($optionString)) {
66
            $this->import($optionString, $optionSeparator, $kvSeparator);
67
        }
68
    }
69
70
71
    /**
72
     * Export options back to string
73
     *
74
     * Whitespace is added after each separators.
75
     *
76
     * @param   string $optionSeparator
77
     * @param   string $kvSeparator
78
     * @return  string
79
     */
80
    public function export($optionSeparator = null, $kvSeparator = null)
81
    {
82
        if (is_null($optionSeparator)) {
83
            $optionSeparator = static::OPTION_SEPARATOR;
84
        }
85
86
        if (is_null($kvSeparator)) {
87
            $kvSeparator = static::KV_SEPARATOR;
88
        }
89
90
        $sections = [];
91
92
        foreach ($this->getRaw() as $key => $value) {
93
            if (true === $value) {
94
                $value = 'true';
95
            } elseif (false === $value) {
96
                $value = 'false';
97
            }
98
99
            $sections[] = "{$key}{$kvSeparator}{$value}";
100
        }
101
102
        $whitespace = static::WHITESPACE_AFTER_OPTION_SEPARATOR;
103
104
        return implode($optionSeparator . $whitespace, $sections);
105
    }
106
107
108
    /**
109
     * {@inheritdoc}
110
     */
111
    public function get($key)
112
    {
113
        try {
114
            $value = parent::get($key);
115
116
        } catch (KeyNotExist $e) {
117
            $value = static::FALLBACK_VALUE;
118
        }
119
120
        return $value;
121
    }
122
123
124
    /**
125
     * Initialize from option string
126
     *
127
     * Will clear present values.
128
     *
129
     * @param   string $optionString
130
     * @param   string $optionSeparator
131
     * @param   string $kvSeparator
132
     * @return  $this
133
     */
134
    public function import(
135
        $optionString = '',
136
        $optionSeparator = null,
137
        $kvSeparator = null
138
    ) {
139
        $this->configs = [];
140
141
        $this->setStringOptions($optionString, $optionSeparator, $kvSeparator);
142
143
        return $this;
144
    }
145
146
147
    /**
148
     * Set config/options by a string
149
     *
150
     * @param   string $optionString
151
     * @param   string $optionSeparator
152
     * @param   string $kvSeparator
153
     * @return  $this
154
     * @throws  InvalidFormatException
155
     */
156
    public function setStringOptions(
157
        $optionString = '',
158
        $optionSeparator = null,
159
        $kvSeparator = null
160
    ) {
161
        if (is_null($optionSeparator)) {
162
            $optionSeparator = static::OPTION_SEPARATOR;
163
        }
164
165
        if (is_null($kvSeparator)) {
166
            $kvSeparator = static::KV_SEPARATOR;
167
        }
168
169
        $sections = explode($optionSeparator, $optionString);
170
        foreach ($sections as $section) {
171
            $kvPair = explode($kvSeparator, $section);
172
173
            if (1 == count($kvPair)) {
174
                // Option name only
175
                $key = trim(current($kvPair));
176
177
                // Continues repeat separator will cause empty value like this
178
                if ('' === $key) {
179
                    continue;
180
                }
181
182
                // No value part
183
                $this->set($key, static::NAME_ONLY_VALUE);
184
185
            } elseif (2 == count($kvPair)) {
186
                // Normal key-value pair
187
                $key = trim(array_shift($kvPair));
188
                $value = trim(array_shift($kvPair));
189
190
                $lowerValue = strtolower($value);
191
                if ('true' === $lowerValue) {
192
                    $value = true;
193
                } elseif ('false' === $lowerValue) {
194
                    $value = false;
195
                }
196
197
                $this->set($key, $value);
198
199
            } else {
200
                throw new InvalidFormatException(
201
                    "Format error: {$section}"
202
                );
203
            }
204
        }
205
206
        return $this;
207
    }
208
}
209