phpexpertsinc/ColorSpeaker

View on GitHub
src/DTOs/CSSHexColor.php

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
<?php declare(strict_types=1);

/**
 * This file is part of ColorSpeaker, a PHP Experts, Inc., Project.
 *
 * Copyright © 2019 PHP Experts, Inc.
 * Author: Theodore R. Smith <theodore@phpexperts.pro>
 *   GPG Fingerprint: 4BF8 2613 1C34 87AC D28F  2AD8 EB24 A91D D612 5690
 *   https://www.phpexperts.pro/
 *   https://github.com/PHPExpertsInc/RGBSpeaker
 *
 * This file is licensed under the MIT License.
 *
 * It is inspired by https://stitcher.io/blog/tests-and-types
 *                   http://archive.is/99WyU
 */

namespace PHPExperts\ColorSpeaker\DTOs;

use PHPExperts\DataTypeValidator\DataTypeValidator;
use PHPExperts\DataTypeValidator\InvalidDataTypeException;
use PHPExperts\SimpleDTO\SimpleDTO;

/**
 * @property-read string $hex
 */
final class CSSHexColor extends SimpleDTO implements Color
{
    private const MY_MIN = 3; // +1 for the '#' character.
    private const MY_MAX = 6; // +1 for the '#' character.

    public function __construct(string $hex, array $options = [], DataTypeValidator $validator = null)
    {
        $input = [
            'hex' => strtoupper($hex),
        ];

        parent::__construct($input, $options, $validator);
    }

    protected function extraValidation(array $input)
    {
        if (empty($input['hex']) || $input['hex'][0] !== '#') {
            throw new InvalidDataTypeException('Hex colors must begin with "#".');
        }

        $digits = strlen($input['hex']) - 1;
        if (!($digits === static::MY_MIN || $digits === static::MY_MAX)) {
            throw new InvalidDataTypeException(
                sprintf(
                    'Hex color codes must be %d or %d digits, not %d (%s)',
                    static::MY_MIN,
                    static::MY_MAX,
                    $digits,
                    $input['hex']
                )
            );
        }

        // Ensure that it is actually a valid CSS color code.
        self::assertIsValidCSSHexColor($input['hex']);
    }

    /**
     * Asserts whether a string is a valid CSS hexadecimal color code.
     * Taken from https://stackoverflow.com/a/12837990/430062.
     *
     * @param string $hex
     *
     * @return true if valid, otherwise an InvalidDataTpeException is thrown
     *
     * @throws InvalidDataTypeException if it fails the CSS regex test
     */
    public static function assertIsValidCSSHexColor(string $hex): bool
    {
        if (preg_match('/#([a-f0-9]{3}){1,2}\b/i', $hex) !== 1) {
            throw new InvalidDataTypeException("'$hex' is not a valid CSS hexadecimal color code.");
        }

        return true;
    }

    public function __toString(): string
    {
        return $this->hex;
    }
}