Passed
Push — master ( 689ec5...45f08c )
by Sebastian
05:26
created

StyleCollection::parseStylesString()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 5
c 1
b 0
f 0
dl 0
loc 12
rs 10
cc 2
nc 2
nop 1
1
<?php
2
/**
3
 * File containing the class {@see \AppUtils\StyleCollection}.
4
 *
5
 * @see \AppUtils\StyleCollection
6
 *@subpackage HTML
7
 * @package AppUtils
8
 */
9
10
declare(strict_types=1);
11
12
namespace AppUtils;
13
14
use AppUtils\StyleCollection\StyleOptions;
15
use AppUtils\StyleCollection\StylesRenderer;
16
17
/**
18
 * Utility class used to hold CSS styles, with
19
 * chainable methods and an easy-to-use API for handling
20
 * and filtering values.
21
 *
22
 * @package AppUtils
23
 * @subpackage HTML
24
 * @author Sebastian Mordziol <[email protected]>
25
 */
26
class StyleCollection implements Interface_Stringable
27
{
28
    /**
29
     * @var array<string,string>
30
     */
31
    private $styles = array();
32
33
    /**
34
     * @param array<string,string|number|NumberInfo|Interface_Stringable|NULL> $styles
35
     */
36
    public function __construct(array $styles=array())
37
    {
38
        $this->options = new StyleOptions();
39
40
        $this->setStyles($styles);
41
    }
42
43
    /**
44
     * @param array<string,string|number|NumberInfo|Interface_Stringable|NULL> $styles
45
     * @return StyleCollection
46
     */
47
    public static function create(array $styles=array()) : StyleCollection
48
    {
49
        return new StyleCollection($styles);
50
    }
51
52
    public function hasStyles() : bool
53
    {
54
        return !empty($this->styles);
55
    }
56
57
    /**
58
     * @return array<string,string>
59
     */
60
    public function getStyles() : array
61
    {
62
        return $this->styles;
63
    }
64
65
    // region: 1) Setting styles
66
67
    public function parseStylesString(string $string) : StyleCollection
68
    {
69
        $lines = explode(';', $string);
70
71
        foreach($lines as $line)
72
        {
73
            $parts = explode(':', $line);
74
75
            $this->style(trim($parts[0]), trim($parts[1]));
76
        }
77
78
        return $this;
79
    }
80
81
    /**
82
     * Adds an associative array with styles.
83
     *
84
     * NOTE: Uses {@see StyleCollection::styleAuto()} to add
85
     * the individual styles.
86
     *
87
     * @param array<string,string|number|NumberInfo|Interface_Stringable|NULL> $styles
88
     * @return $this
89
     */
90
    public function setStyles(array $styles) : StyleCollection
91
    {
92
        foreach($styles as $name => $value)
93
        {
94
            $this->styleAuto($name, $value);
95
        }
96
97
        return $this;
98
    }
99
100
    /**
101
     * Sets a style value.
102
     *
103
     * @param string $name
104
     * @param string $value
105
     * @param bool $important
106
     * @return $this
107
     */
108
    public function style(string $name, string $value, bool $important=false) : StyleCollection
109
    {
110
        if($value === '')
111
        {
112
            return $this;
113
        }
114
115
        if($important && stripos($value, '!important') === false)
116
        {
117
            $value .= ' !important';
118
        }
119
120
        $this->styles[$name] = $value;
121
122
        return $this;
123
    }
124
125
    /**
126
     * Adds a style, automatically detecting the value type.
127
     *
128
     * @param string $name
129
     * @param string|number|NumberInfo|Interface_Stringable|NULL $value
130
     * @param bool $important
131
     * @return $this
132
     */
133
    public function styleAuto(string $name, $value, bool $important=false) : StyleCollection
134
    {
135
        if($value instanceof NumberInfo)
136
        {
137
            return $this->style($name, $value->toCSS(), $important);
138
        }
139
140
        return $this->style($name, (string)$value, $important);
141
    }
142
143
    public function stylePX(string $name, int $px, bool $important=false) : StyleCollection
144
    {
145
        return $this->style($name, $px.'px', $important);
146
    }
147
148
    public function stylePercent(string $name, float $percent, bool $important) : StyleCollection
149
    {
150
        return $this->style($name, $percent.'%', $important);
151
    }
152
153
    public function styleEM(string $name, float $em, bool $important) : StyleCollection
154
    {
155
        return $this->style($name, $em.'em', $important);
156
    }
157
158
    public function styleREM(string $name, float $em, bool $important) : StyleCollection
159
    {
160
        return $this->style($name, $em.'rem', $important);
161
    }
162
163
    /**
164
     * Adds a number, using the {@see parseNumber()} function
165
     * to parse the value, and convert it to CSS.
166
     *
167
     * @param string $name
168
     * @param NumberInfo|string|int|float|NULL $value
169
     * @param bool $important
170
     * @return $this
171
     */
172
    public function styleParseNumber(string $name, $value, bool $important=false) : StyleCollection
173
    {
174
        return $this->styleNumber($name, parseNumber($value), $important);
175
    }
176
177
    /**
178
     * Adds an existing number info instance to add its CSS value.
179
     *
180
     * @param string $name
181
     * @param NumberInfo $info
182
     * @param bool $important
183
     * @return $this
184
     */
185
    public function styleNumber(string $name, NumberInfo $info, bool $important=false) : StyleCollection
186
    {
187
        $this->style($name, $info->toCSS(), $important);
188
        return $this;
189
    }
190
191
    public function remove(string $name) : StyleCollection
192
    {
193
        if(isset($this->styles[$name]))
194
        {
195
            unset($this->styles[$name]);
196
        }
197
198
        return $this;
199
    }
200
201
    /**
202
     * Merges all styles of this collection with those
203
     * from the specified collection, overwriting existing
204
     * styles.
205
     *
206
     * @param StyleCollection $collection
207
     * @return $this
208
     */
209
    public function mergeWith(StyleCollection $collection) : StyleCollection
210
    {
211
        return $this->setStyles($collection->getStyles());
212
    }
213
214
    /**
215
     * Merges all the specified style collections into
216
     * a new collection that contains all styles from
217
     * all collections.
218
     *
219
     * NOTE: Order is important, since every merge can
220
     * overwrite existing styles.
221
     *
222
     * @param StyleCollection ...$collections
223
     * @return StyleCollection
224
     */
225
    public static function merge(...$collections) : StyleCollection
226
    {
227
        $all = self::create();
228
229
        foreach($collections as $collection)
230
        {
231
            $all->mergeWith($collection);
232
        }
233
234
        return $all;
235
    }
236
237
    // endregion
238
239
    // region: 3) Rendering
240
241
    public function render() : string
242
    {
243
        return (new StylesRenderer($this))->render();
244
    }
245
246
    public function display() : StyleCollection
247
    {
248
        echo $this->render();
249
250
        return $this;
251
    }
252
253
    public function __toString()
254
    {
255
        return $this->render();
256
    }
257
258
    // endregion
259
260
    // region: 2) Options handling
261
262
    /**
263
     * @var StyleOptions
264
     */
265
    private $options;
266
267
    /**
268
     * Use the option collection to customize the way
269
     * the styles are rendered.
270
     *
271
     * @return StyleOptions
272
     */
273
    public function getOptions() : StyleOptions
274
    {
275
        return $this->options;
276
    }
277
278
    /**
279
     * Switches the rendering to stylesheet mode: This
280
     * will automatically format the styles for use in
281
     * a CSS stylesheet (newlines, indenting, etc.).
282
     *
283
     * @return $this
284
     */
285
    public function configureForStylesheet() : StyleCollection
286
    {
287
        $this->options->configureForStylesheet();
288
        return $this;
289
    }
290
291
    /**
292
     * Switches the rendering to inline mode: compact list of
293
     * styles for use in HTML attributes for example.
294
     *
295
     * (This is the default configuration)
296
     *
297
     * @return StyleCollection
298
     */
299
    public function configureForInline() : StyleCollection
300
    {
301
        $this->options->configureForInline();
302
        return $this;
303
    }
304
305
    // endregion
306
}
307