-
-
Notifications
You must be signed in to change notification settings - Fork 440
Expand file tree
/
Copy pathCarbonCallFactory.php
More file actions
134 lines (111 loc) · 4.32 KB
/
CarbonCallFactory.php
File metadata and controls
134 lines (111 loc) · 4.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
<?php
declare(strict_types=1);
namespace Rector\Carbon\NodeFactory;
use Nette\Utils\Strings;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Scalar\Int_;
use PhpParser\Node\Scalar\String_;
final class CarbonCallFactory
{
/**
* @see https://regex101.com/r/LLMrFw/1
*/
private const string PLUS_MINUS_COUNT_REGEX = '#(?<operator>\+|-)(\\s+)?(?<count>\\d+)(\s+)?(?<unit>seconds|second|sec|minutes|minute|min|hours|hour|days|day|weeks|week|months|month|years|year)#';
/**
* @see https://regex101.com/r/IhxHTO/1
*/
private const string STATIC_DATE_REGEX = '#now|yesterday|today|tomorrow#';
public function createFromDateTimeString(
FullyQualified $carbonFullyQualified,
String_ $string
): MethodCall|StaticCall {
$carbonCall = $this->createStaticCall($carbonFullyQualified, $string);
$string->value = Strings::replace($string->value, self::STATIC_DATE_REGEX);
// Handle add/sub multiple times
while ($match = Strings::match($string->value, self::PLUS_MINUS_COUNT_REGEX)) {
$methodCall = $this->createModifyMethodCall(
$carbonCall,
new Int_((int) $match['count']),
$match['unit'],
$match['operator']
);
if ($methodCall instanceof MethodCall) {
$carbonCall = $methodCall;
$string->value = Strings::replace($string->value, self::PLUS_MINUS_COUNT_REGEX, '', 1);
}
}
// If we still have something in the string, we go back to the first method and replace this with a parse
if (($rest = Strings::trim($string->value)) !== '') {
$currentCall = $carbonCall;
$callStack = [];
while ($currentCall instanceof MethodCall) {
$callStack[] = $currentCall;
$currentCall = $currentCall->var;
}
if (! $currentCall instanceof StaticCall) {
return $carbonCall;
}
// If we fallback to a parse we want to include tomorrow/today/yesterday etc
if ($currentCall->name instanceof Identifier && $currentCall->name->name !== 'now') {
$rest .= ' ' . $currentCall->name->name;
}
$currentCall->name = new Identifier('parse');
$currentCall->args = [new Arg(new String_($rest))];
// Rebuild original call from callstack
$carbonCall = $this->rebuildCallStack($currentCall, $callStack);
}
return $carbonCall;
}
private function createStaticCall(FullyQualified $carbonFullyQualified, String_ $string): StaticCall
{
$startDate = Strings::match($string->value, self::STATIC_DATE_REGEX)[0] ?? 'now';
return new StaticCall($carbonFullyQualified, new Identifier($startDate));
}
private function createModifyMethodCall(
MethodCall|StaticCall $carbonCall,
Int_ $int,
string $unit,
string $operator
): ?MethodCall {
$unit = match ($unit) {
'sec', 'second', 'seconds' => 'seconds',
'min', 'minute', 'minutes' => 'minutes',
'hour', 'hours' => 'hours',
'day', 'days' => 'days',
'week', 'weeks' => 'weeks',
'month', 'months' => 'months',
'year', 'years' => 'years',
default => null,
};
$operator = match ($operator) {
'+' => 'add',
'-' => 'sub',
default => null,
};
if ($unit === null || $operator === null) {
return null;
}
$methodName = $operator . ucfirst($unit);
return new MethodCall($carbonCall, new Identifier($methodName), [new Arg($int)]);
}
/**
* @param MethodCall[] $callStack
*/
private function rebuildCallStack(StaticCall $staticCall, array $callStack): MethodCall|StaticCall
{
if ($callStack === []) {
return $staticCall;
}
$currentCall = $staticCall;
$callStack = array_reverse($callStack);
foreach ($callStack as $call) {
$call->var = $currentCall;
$currentCall = $call;
}
return $currentCall;
}
}