Completed
Push — master ( 4eff91...8ce34a )
by Marcus
01:39
created

Time::validateHours()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2
1
<?php
2
3
namespace Mbright\Validation\Rule\Validate\MySql;
4
5
use Mbright\Validation\Rule\Validate\ValidateRuleInterface;
6
7
/**
8
 * Validates that data can be inserted into one of the following column types:
9
 * - Time
10
 */
11
class Time implements ValidateRuleInterface
12
{
13
    /**
14
     * Indicates if the given field's value is a MySql safe Time.
15
     *
16
     * @param object $subject
17
     * @param string $field
18
     *
19
     * @return bool
20
     */
21 36
    public function __invoke($subject, string $field): bool
22
    {
23 36
        $value = $subject->$field;
24 36
        $timeParts = $this->extractTimeParts($value);
25
26 36
        return ! is_null($timeParts)
27 36
            && $this->validateHours($timeParts->hours)
28 36
            && $this->validateMinutes($timeParts->minutes)
29 36
            && $this->validateSeconds($timeParts->seconds);
30
    }
31
32
    /**
33
     * Extracts time parts from the given string.
34
     *
35
     * Will return an object with 3 properties, hours, minutes, seconds with the values from the string. Each property
36
     * defaults to zero. If the string cannot be parsed, return null.
37
     *
38
     * @param $value
39
     * @return ?\stdClass
0 ignored issues
show
Documentation introduced by
The doc-type ?\stdClass could not be parsed: Unknown type name "?\stdClass" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
40
     */
41 36
    protected function extractTimeParts($value): ?\stdClass
42
    {
43
        $extractedParts = (object) [
44 36
            'hours' => 0,
45
            'minutes' => 0,
46
            'seconds'=> 0
47
        ];
48
49 36
        $timeSegments = explode(':', $value);
50 36
        $numOfSegments = count($timeSegments);
51
52 36
        if ($numOfSegments === 3) {
53 24
            $extractedParts->hours = $timeSegments[0];
54 24
            $extractedParts->minutes = $timeSegments[1];
55 24
            $extractedParts->seconds = $timeSegments[2];
56 12
        } elseif ($numOfSegments === 2) {
57
            $extractedParts->hours = $timeSegments[0];
58
            $extractedParts->minutes = $timeSegments[1];
59 12
        } elseif ($numOfSegments === 1) {
60
            // if a 3rd character is present and equal to . then we have a SS format segment else it has to be HHMMSS
61 9
            $isSecondsOnly = substr($timeSegments[0], 2, 1) !== '.';
62 9
            if ($isSecondsOnly) {
63 9
                $extractedParts->seconds = $timeSegments[0];
64
            } else {
65 9
                $extractedParts = $this->handleNonDelimitedString($timeSegments[0], $extractedParts);
66
            }
67
        } else {
68 3
            $extractedParts = null;
69
        }
70
71 36
        return $extractedParts;
72
    }
73
74
    protected function handleNonDelimitedString(string $timeString, \stdClass $extractedParts)
75
    {
76
        $parsedSegments = [];
77
        preg_match('(^\d{2})(\d{2})(\d{2}\.\d+$|\d{2}$)', $timeString, $parsedSegments);
78
79
        if (count($parsedSegments) !== 4) {
80
            return null;
81
        }
82
83
        $extractedParts->hours = $parsedSegments[1];
84
        $extractedParts->minutes = $parsedSegments[2];
85
        $extractedParts->seconds = $parsedSegments[3];
86
87
        return $extractedParts;
88
    }
89
90
    /**
91
     * Validates that the string can represent seconds.
92
     *
93
     * @param string $seconds
94
     *
95
     * @return bool
96
     */
97 27
    protected function validateSeconds(string $seconds): bool
98
    {
99 27
        $precision = strlen(substr(strrchr($seconds, '.'), 1));
100
101 27
        if ($precision > 6) {
102 6
            return false;
103
        }
104
105 21
        $seconds = (float) $seconds;
106
107 21
        return $seconds >= 0 && $seconds < 60;
108
    }
109
110
    /**
111
     * Validates that the string can represent minutes.
112
     *
113
     * @param string $minutes
114
     *
115
     * @return bool
116
     */
117 27
    protected function validateMinutes(string $minutes): bool
118
    {
119 27
        $minutes = (int) $minutes;
120
121 27
        return $minutes >= 0 && $minutes < 60;
122
    }
123
124
    /**
125
     * Validates tha the string can represent hours.
126
     *
127
     * @param string $hours
128
     *
129
     * @return bool
130
     */
131 33
    protected function validateHours(string $hours): bool
132
    {
133 33
        $hours = (int) $hours;
134
135 33
        return $hours >= -838 && $hours <= 838;
136
    }
137
}
138