Passed
Push — master ( 212cf6...f75378 )
by Nicolaas
02:00
created

DBColour   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 353
Duplicated Lines 0 %

Importance

Changes 7
Bugs 0 Features 0
Metric Value
wmc 44
eloc 128
c 7
b 0
f 0
dl 0
loc 353
rs 8.8798

24 Methods

Rating   Name   Duplication   Size   Complexity  
A my_colours() 0 3 1
A scaffoldFormField() 0 3 1
A __construct() 0 3 1
A is_light_colour() 0 4 1
A get_dropdown_field() 0 13 2
A is_dark_colour() 0 3 2
A get_colours_for_dropdown() 0 32 5
A check_colour() 0 17 5
A get_swatches_field() 0 7 1
A Inverted() 0 18 1
A getCssClass() 0 10 2
A getIsDarkColour() 0 3 2
A getIsLightColour() 0 3 1
A getRelatedColours() 0 4 1
A getCssVarLine() 0 7 2
A getRelatedColourByName() 0 5 1
A getCssClassAlternative() 0 8 3
A get_font_colour() 0 4 2
A getReadableColour() 0 4 1
A get_colour_as_db_field() 0 6 2
A getColours() 0 3 1
A classCleanup() 0 6 1
A getMyColours() 0 5 2
A getCssVariableDefinition() 0 20 3

How to fix   Complexity   

Complex Class

Complex classes like DBColour often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use DBColour, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Sunnysideup\SelectedColourPicker\Model\Fields;
4
5
use Fromholdio\ColorPalette\Fields\ColorPaletteField;
6
use SilverStripe\Forms\FormField;
7
use SilverStripe\Forms\LiteralField;
8
9
use SilverStripe\Core\Config\Config;
10
use SilverStripe\ORM\FieldType\DBField;
11
use Sunnysideup\SelectedColourPicker\Forms\SelectedColourPickerFormFieldDropdown;
12
use Sunnysideup\SelectedColourPicker\ViewableData\SelectedColourPickerFormFieldSwatches;
13
use TractorCow\Colorpicker\Color;
14
15
class DBColour extends Color
16
{
17
    private static $colour_picker_field_class_name = SelectedColourPickerFormFieldDropdown::class;
18
19
    /**
20
     * please set
21
     * must be defined as #AABB99 (hex codes).
22
     * Needs to be set like this:
23
     * ```php
24
     *     [
25
     *         '#fff000' => 'My Colour 1',
26
     *         '#fff000' => 'My Colour 2',
27
     *     ]
28
     *
29
     * ```
30
     *
31
     * @var array
32
     */
33
    private static $colours = [];
34
35
    /**
36
     * You can link colours to other colours.
37
     * e.g.
38
     * ```php
39
     *     '#ffffff' => [
40
     *          'link' => '#000000',
41
     *          'foreground' => '#000000',
42
     *          'background' => '#000000',
43
     *     ],
44
     *     '#aabbcc' => [
45
     *          'link' => '#123123',
46
     *          'foreground' => '#123312',
47
     *          'somethingelse' => '#000000',
48
     *     ],
49
     * ```
50
     *
51
     * @var array
52
     */
53
54
    private static $linked_colours = [
55
    ];
56
57
    protected const DEFAULT_COLOURS = [
58
        '#FF0000' => 'Red',
59
        '#0000FF' => 'Blue',
60
        '#00FF00' => 'Green',
61
    ];
62
63
    /**
64
     * please set.
65
     *
66
     * @var string`
67
     */
68
    protected const CSS_CLASS_PREFIX = 'db-colour';
69
70
    /**
71
     * please set.
72
     *
73
     * @var bool
74
     */
75
    protected const IS_LIMITED_TO_OPTIONS = true;
76
77
    /**
78
     * please set.
79
     *
80
     * @var bool
81
     */
82
    protected const IS_BG_COLOUR = true;
83
84
    private static $casting = [
85
        // related colours
86
        'ReadableColour' => 'Varchar',
87
        'RelatedColourByName' => 'Varchar',
88
        'Inverted' => 'Varchar',
89
        // css
90
        'CssVariableDefinition' => 'HTMLText',
91
        'CssClass' => 'Varchar',
92
        'CssClassAlternative' => 'Boolean',
93
        // booleans
94
        'IsDarkColour' => 'Boolean',
95
        'IsLightColour' => 'Boolean',
96
    ];
97
98
99
    public function __construct($name = null, $options = [])
100
    {
101
        parent::__construct($name, $options);
102
    }
103
104
105
    public static function my_colours(): array
106
    {
107
        return static::get_colour_as_db_field('')->getColours();
108
    }
109
110
    public static function get_swatches_field(string $name, string $value): LiteralField
111
    {
112
        return SelectedColourPickerFormFieldSwatches::get_swatches_field(
113
            (string) $name,
114
            (string) $value,
115
            static::my_colours(),
116
            static::IS_BG_COLOUR
117
        );
118
    }
119
120
    /**
121
     *
122
     * @param  string $name
123
     * @param  string $title
124
     * @return FormField
125
     */
126
    public static function get_dropdown_field(string $name, ?string $title = '', ?bool $isBackgroundColour = null)
127
    {
128
        if($isBackgroundColour === null) {
129
            $isBackgroundColour = static::IS_BG_COLOUR;
130
        }
131
        $className = Config::inst()->get(static::class, 'colour_picker_field_class_name');
132
        return $className::create(
133
            $name,
134
            $title
135
        )
136
            ->setSource(static::my_colours())
137
            ->setLimitedToOptions(static::IS_LIMITED_TO_OPTIONS)
138
            ->setIsBgColour($isBackgroundColour);
139
        ;
140
    }
141
142
143
    public static function get_colours_for_dropdown(?bool $isBackgroundColour = null): ?array
144
    {
145
        if($isBackgroundColour === null) {
146
            $isBackgroundColour = static::IS_BG_COLOUR;
147
        }
148
        $colours = static::my_colours();
149
        if (!empty($colours)) {
150
            $array = [];
151
152
            foreach ($colours as $code => $label) {
153
                $textcolour = static::get_font_colour($code) ;
154
                if($isBackgroundColour) {
155
                    $array[$code] = [
156
                        'label' => $label,
157
                        'background_css' => $code,
158
                        'colour_css' => $textcolour,
159
                        'sample_text' => 'Aa',
160
                    ];
161
162
                } else {
163
                    $array[$code] = [
164
                        'label' => $label,
165
                        'background_css' => $textcolour,
166
                        'colour_css' => $code,
167
                        'sample_text' => 'Aa',
168
                    ];
169
                }
170
            }
171
172
            return $array;
173
        }
174
        return null;
175
    }
176
177
178
    /**
179
     * Detects if the given colour is light
180
     * @param string $colour HEX colour code
181
     */
182
    public static function get_font_colour(string $colour, ?string $name = '')
183
    {
184
        $colour = static::is_light_colour((string) $colour) ? '#000000' : '#ffffff';
185
        return static::get_colour_as_db_field($colour, $name);
186
    }
187
188
    /**
189
     * @param string $colour HEX colour code
190
     */
191
    public static function is_dark_colour(?string $colour = ''): bool
192
    {
193
        return static::is_light_colour((string) $colour) ? false : true;
194
    }
195
196
    /**
197
     * Detects if the given colour is light
198
     * @param string $colour HEX colour code
199
     */
200
    public static function is_light_colour(?string $colour = ''): bool
201
    {
202
        return static::get_colour_as_db_field($colour)
0 ignored issues
show
Bug introduced by
It seems like $colour can also be of type null; however, parameter $colour of Sunnysideup\SelectedColo...et_colour_as_db_field() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

202
        return static::get_colour_as_db_field(/** @scrutinizer ignore-type */ $colour)
Loading history...
203
            ->Luminance() > 0.5;
204
    }
205
206
207
    public static function check_colour(?string $colour, ?bool $isBackgroundColour = false): string
208
    {
209
        $colour = strtolower($colour);
0 ignored issues
show
Bug introduced by
It seems like $colour can also be of type null; however, parameter $string of strtolower() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

209
        $colour = strtolower(/** @scrutinizer ignore-type */ $colour);
Loading history...
210
        if($colour === 'transparent') {
211
            return 'transparent';
212
        }
213
        if(! strpos($colour, '#')) {
214
            $colour = '#' . $colour;
215
        }
216
        if(! $colour) {
217
            if($isBackgroundColour) {
218
                $colour = '#ffffff';
219
            } else {
220
                $colour = '#000000';
221
            }
222
        }
223
        return $colour;
224
    }
225
226
    public function scaffoldFormField($title = null, $params = null)
227
    {
228
        return ColorPaletteField::create($this->name, $title, static::get_colours_for_dropdown());
229
    }
230
231
232
    public function getReadableColour(): static
233
    {
234
        // Remove '#' if it's present
235
        return static::get_font_colour($this->value, $this->name);
236
    }
237
238
    public function Inverted(): static
239
    {
240
        // Ensure the colour is 6 characters long
241
        $colour = str_pad(ltrim($this->value, "#"), 6, '0', STR_PAD_RIGHT);
242
243
        // Convert the colour to decimal
244
        $colour = hexdec($colour);
245
246
        // Invert the colour
247
        $colour = 0xFFFFFF - $colour;
248
249
        // Convert the colour back to hex
250
        $colour = dechex($colour);
0 ignored issues
show
Bug introduced by
$colour of type double is incompatible with the type integer expected by parameter $num of dechex(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

250
        $colour = dechex(/** @scrutinizer ignore-type */ $colour);
Loading history...
251
252
        // Ensure the colour is 6 characters long
253
        $colour = str_pad($colour, 6, '0', STR_PAD_LEFT);
254
255
        return static::get_colour_as_db_field($colour, $this->name);
256
    }
257
258
    public function getRelatedColourByName(string $relatedName): static
259
    {
260
        $relatedColours = $this->getRelatedColours($this->value);
0 ignored issues
show
Unused Code introduced by
The call to Sunnysideup\SelectedColo...ur::getRelatedColours() has too many arguments starting with $this->value. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

260
        /** @scrutinizer ignore-call */ 
261
        $relatedColours = $this->getRelatedColours($this->value);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
261
        $colour = $relatedColours[$relatedName] ?? 'error';
262
        return static::get_colour_as_db_field($colour, $this->name);
263
    }
264
265
266
    public function getCssVariableDefinition($rootElement = ':root'): string
267
    {
268
        $style = PHP_EOL . '<style>';
269
        $style .= PHP_EOL.$rootElement;
270
        $style .= PHP_EOL. '{';
271
        $style .= $this->getCssVarLine();
272
        if(static::IS_BG_COLOUR) {
273
            $readableColourObj = $this->getReadableColour();
274
            $style .= $readableColourObj->getCssVarLine('font');
275
        }
276
        foreach($this->getRelatedColours() as $name => $relatedColour) {
277
            $relatedColourObj = self::get_colour_as_db_field($relatedColour, $this->name);
278
            $style .= $relatedColourObj->getCssVarLine($name);
279
            $relatedColourObjReadable = $relatedColourObj->getReadableColour();
280
            $style .= $relatedColourObjReadable->getCssVarLine($name.'-font');
281
        }
282
        $style .= PHP_EOL . '}';
283
        $style .= PHP_EOL . '</style>';
284
285
        return $style;
286
    }
287
288
    public function getCssVarLine($name = ''): string
289
    {
290
        $start = '    --colour';
291
        if($name) {
292
            $start .= '-' . strtolower($name);
293
        }
294
        return PHP_EOL. $start.'-' . strtolower($this->getName()) . ': ' . $this->getValue() . ';';
295
    }
296
297
    public function getCssClass(?bool $isTransparent = false): string
298
    {
299
        $colours = $this->getColours();
300
        if($isTransparent) {
301
            $name = 'transparent';
302
        } else {
303
            $name = $colours[$this->value] ?? 'colour-error';
304
        }
305
306
        return $this->classCleanup($name);
307
    }
308
309
310
    public function getCssClassAlternative(?bool $isTransparent = false): string
311
    {
312
        if($isTransparent) {
313
            $name = 'ffffff00';
314
        } else {
315
            $name = $this->value ?: 'no-colour';
316
        }
317
        return $this->classCleanup($name);
318
    }
319
320
    public function getIsLightColour(): bool
321
    {
322
        return static::is_light_colour($this->value);
323
    }
324
325
    public function getIsDarkColour(): bool
326
    {
327
        return static::is_light_colour($this->value) ? false : true;
328
    }
329
330
    private function classCleanup(string $name): string
331
    {
332
        $name = str_replace('#', '', $name);
333
        $name = preg_replace('#[^A-Za-z0-9]#', '-', $name);
334
335
        return static::CSS_CLASS_PREFIX . '-' . trim(trim(strtolower($name), '-'));
336
    }
337
338
339
340
341
    protected function getColours(): array
342
    {
343
        return $this->Config()->get('colours');
344
    }
345
346
    protected function getMyColours(): array
347
    {
348
        $colours = $this->getColours();
349
350
        return empty($colours) ? static::DEFAULT_COLOURS : $colours;
351
    }
352
353
    protected function getRelatedColours(): array
354
    {
355
        $relatedColoursForAllColours = Config::inst()->get(static::class, 'linked_colours');
356
        return $relatedColoursForAllColours[$this->value] ?? [];
357
    }
358
359
360
    protected static $object_cache = [];
361
362
    protected static function get_colour_as_db_field(string $colour, ?string $name = '')
363
    {
364
        if(! isset(static::$object_cache[$colour])) {
365
            static::$object_cache[$colour] = DBField::create_field(static::class, $colour, $name);
366
        }
367
        return static::$object_cache[$colour];
368
    }
369
370
371
}
372