mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-17 21:38:22 +01:00
baf6792e1e
71ae13a461
Carbon use parse method (#6183)
146 lines
5.2 KiB
PHP
146 lines
5.2 KiB
PHP
<?php
|
|
|
|
declare (strict_types=1);
|
|
namespace Rector\Carbon\NodeFactory;
|
|
|
|
use RectorPrefix202407\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\LNumber;
|
|
use PhpParser\Node\Scalar\String_;
|
|
final class CarbonCallFactory
|
|
{
|
|
/**
|
|
* @var string
|
|
* @see https://regex101.com/r/LLMrFw/1
|
|
*/
|
|
private const 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)#';
|
|
/**
|
|
* @var string
|
|
* @see https://regex101.com/r/IhxHTO/1
|
|
*/
|
|
private const STATIC_DATE_REGEX = '#now|yesterday|today|tomorrow#';
|
|
/**
|
|
* @return \PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\StaticCall
|
|
*/
|
|
public function createFromDateTimeString(FullyQualified $carbonFullyQualified, String_ $string)
|
|
{
|
|
$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 LNumber((int) $match['count']), $match['unit'], $match['operator']);
|
|
if ($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) {
|
|
if ($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';
|
|
$carbonCall = new StaticCall($carbonFullyQualified, new Identifier($startDate));
|
|
return $carbonCall;
|
|
}
|
|
/**
|
|
* @param \PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\StaticCall $carbonCall
|
|
*/
|
|
private function createModifyMethodCall($carbonCall, LNumber $countLNumber, string $unit, string $operator) : ?MethodCall
|
|
{
|
|
switch ($unit) {
|
|
case 'sec':
|
|
case 'second':
|
|
case 'seconds':
|
|
$unit = 'seconds';
|
|
break;
|
|
case 'min':
|
|
case 'minute':
|
|
case 'minutes':
|
|
$unit = 'minutes';
|
|
break;
|
|
case 'hour':
|
|
case 'hours':
|
|
$unit = 'hours';
|
|
break;
|
|
case 'day':
|
|
case 'days':
|
|
$unit = 'days';
|
|
break;
|
|
case 'week':
|
|
case 'weeks':
|
|
$unit = 'weeks';
|
|
break;
|
|
case 'month':
|
|
case 'months':
|
|
$unit = 'months';
|
|
break;
|
|
case 'year':
|
|
case 'years':
|
|
$unit = 'years';
|
|
break;
|
|
default:
|
|
$unit = null;
|
|
break;
|
|
}
|
|
switch ($operator) {
|
|
case '+':
|
|
$operator = 'add';
|
|
break;
|
|
case '-':
|
|
$operator = 'sub';
|
|
break;
|
|
default:
|
|
$operator = null;
|
|
break;
|
|
}
|
|
if ($unit === null || $operator === null) {
|
|
return null;
|
|
}
|
|
$methodName = $operator . \ucfirst($unit);
|
|
return new MethodCall($carbonCall, new Identifier($methodName), [new Arg($countLNumber)]);
|
|
}
|
|
/**
|
|
* @param MethodCall[] $callStack
|
|
* @return \PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\StaticCall
|
|
*/
|
|
private function rebuildCallStack(StaticCall $carbonCall, array $callStack)
|
|
{
|
|
if (\count($callStack) === 0) {
|
|
return $carbonCall;
|
|
}
|
|
$currentCall = $carbonCall;
|
|
$callStack = \array_reverse($callStack);
|
|
foreach ($callStack as $call) {
|
|
$call->var = $currentCall;
|
|
$currentCall = $call;
|
|
}
|
|
return $currentCall;
|
|
}
|
|
}
|