Passed
Push — master ( b9960c...3b47e8 )
by Nicolaas
08:17
created

DBColour::kebabCase()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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

210
        return static::get_colour_as_db_field(/** @scrutinizer ignore-type */ $colour)
Loading history...
211
            ->Luminance() > 0.5;
212
    }
213
214
215
    public static function check_colour(?string $colour, ?bool $isBackgroundColour = false): string
216
    {
217
        $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

217
        $colour = strtolower(/** @scrutinizer ignore-type */ $colour);
Loading history...
218
        if($colour === 'transparent') {
219
            return 'transparent';
220
        }
221
        if(! strpos($colour, '#')) {
222
            $colour = '#' . $colour;
223
        }
224
        if(! $colour) {
225
            if($isBackgroundColour) {
226
                $colour = '#ffffff';
227
            } else {
228
                $colour = '#000000';
229
            }
230
        }
231
        return $colour;
232
    }
233
234
    public function scaffoldFormField($title = null, $params = null)
235
    {
236
        $array = static::get_colours_for_dropdown();
237
        if(empty($array)) {
238
            return ColorField::create($this->name, $title);
239
        } else {
240
            return ColorPaletteField::create($this->name, $title, static::get_colours_for_dropdown());
241
        }
242
    }
243
244
245
    public function getReadableColour(): static
246
    {
247
        // Remove '#' if it's present
248
        return static::get_font_colour((string) $this->value, $this->name);
249
    }
250
251
    public function Inverted(): static
252
    {
253
        // Ensure the colour is 6 characters long
254
        $colour = str_pad(ltrim($this->value, "#"), 6, '0', STR_PAD_RIGHT);
255
256
        // Convert the colour to decimal
257
        $colour = hexdec($colour);
258
259
        // Invert the colour
260
        $colour = 0xFFFFFF - $colour;
261
262
        // Convert the colour back to hex
263
        $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

263
        $colour = dechex(/** @scrutinizer ignore-type */ $colour);
Loading history...
264
265
        // Ensure the colour is 6 characters long
266
        $colour = str_pad($colour, 6, '0', STR_PAD_LEFT);
267
268
        return static::get_colour_as_db_field($colour, $this->name);
269
    }
270
271
    public function getRelatedColourByName(string $relatedName): static
272
    {
273
        $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

273
        /** @scrutinizer ignore-call */ 
274
        $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...
274
        $colour = $relatedColours[$relatedName] ?? 'error';
275
        return static::get_colour_as_db_field($colour, $this->name);
276
    }
277
278
279
    public function getCssVariableDefinition(?string $rootElement = ':root'): string
280
    {
281
        $style = PHP_EOL . '<style>';
282
        $style .= PHP_EOL.$rootElement;
283
        $style .= PHP_EOL. '{';
284
        $style .= $this->getCssVarLine();
285
        if(static::IS_BG_COLOUR) {
286
            $readableColourObj = $this->getReadableColour();
287
            $style .= $readableColourObj->getCssVarLine('-font');
288
        }
289
        foreach($this->getRelatedColours() as $name => $relatedColour) {
290
            $relatedColourObj = self::get_colour_as_db_field($relatedColour, $this->name);
291
            $style .= $relatedColourObj->getCssVarLine($name);
292
            $relatedColourObjReadable = $relatedColourObj->getReadableColour();
293
            $style .= $relatedColourObjReadable->getCssVarLine($name.'-font');
294
        }
295
        $style .= PHP_EOL . '}';
296
        $style .= PHP_EOL . '</style>';
297
298
        return $style;
299
    }
300
301
    public function getCssVarLine(?string $name = '', ?string $prefix = '--colour-'): string
302
    {
303
        $variableName = '    '.$prefix;
304
        $variableName .= $name ?: $this->kebabCase($this->getName());
305
        return PHP_EOL. $variableName . ': ' . $this->getValue() . ';';
306
    }
307
308
    public function getCssClass(?bool $isTransparent = false): string
309
    {
310
        $colours = $this->getColours();
311
        if($isTransparent) {
312
            $name = 'transparent';
313
        } else {
314
            $name = $colours[$this->value] ?? 'colour-error';
315
        }
316
317
        return $this->classCleanup($name);
318
    }
319
320
321
    public function getCssClassAlternative(?bool $isTransparent = false): string
322
    {
323
        if($isTransparent) {
324
            $name = 'ffffff00';
325
        } else {
326
            $name = $this->value ?: 'no-colour';
327
        }
328
        return $this->classCleanup($name);
329
    }
330
331
    public function getIsLightColour(): bool
332
    {
333
        return static::is_light_colour($this->value);
334
    }
335
336
    public function getNice()
337
    {
338
        $html = '
339
            <div
340
            style="
341
                width: 40px;
342
                height: 40px;
343
                border-radius: 40px;
344
                background-color: ' . $this->getBackgroundColour() . '!important;
345
                color: '.$this->getFontColour().'!important;
346
                border: 1px solid '.$this->getFontColour().'!important;
347
                text-align: center;
348
                display: table-cell;
349
                display: flex;
350
                flex-direction: column;
351
                justify-content: center;
352
            "
353
            >Aa</div> ';
354
        return DBField::create_field('HTMLText', $html);
355
    }
356
357
    public function getIsDarkColour(): bool
358
    {
359
        return static::is_light_colour($this->value) ? false : true;
360
    }
361
362
    private function classCleanup(string $name): string
363
    {
364
        $name = str_replace('#', '', $name);
365
        $name = preg_replace('#[^A-Za-z0-9]#', '-', $name);
366
367
        return static::CSS_CLASS_PREFIX . '-' . trim(trim(strtolower($name), '-'));
368
    }
369
370
371
372
373
    protected function getColours(): array
374
    {
375
        return $this->Config()->get('colours');
376
    }
377
378
    protected function getMyColours(): array
379
    {
380
        $colours = $this->getColours();
381
382
        return empty($colours) ? static::DEFAULT_COLOURS : $colours;
383
    }
384
385
    protected function getRelatedColours(): array
386
    {
387
        $relatedColoursForAllColours = Config::inst()->get(static::class, 'linked_colours');
388
        return $relatedColoursForAllColours[$this->value] ?? [];
389
    }
390
391
392
    protected static $object_cache = [];
393
394
    protected static function get_colour_as_db_field(string $colour, ?string $name = '')
395
    {
396
        $cacheKey = $colour . '_'.  $name . '_'. static::class;
397
        if(!$colour || ! isset(static::$object_cache[$cacheKey])) {
398
            static::$object_cache[$cacheKey] = DBField::create_field(static::class, $colour, $name);
399
        }
400
        return static::$object_cache[$cacheKey];
401
    }
402
403
    public function getFontColour(): string
404
    {
405
        if(self::IS_BG_COLOUR) {
406
            return (string) self::get_font_colour($this->value);
407
        } else {
408
            return (string) $this->value;
409
        }
410
    }
411
412
    public function getBackgroundColour(): string
413
    {
414
        if(self::IS_BG_COLOUR) {
415
            return (string) $this->value;
416
        } else {
417
            return (string) self::get_font_colour($this->value);
418
        }
419
    }
420
421
422
    protected function kebabCase(string $string)
423
    {
424
        return strtolower(preg_replace('/(?<!^)[A-Z]/', '-$0', $string));
425
    }
426
427
}
428