Skip to content

Commit

Permalink
Make start and end period properties correct at CarbonPeriod creation
Browse files Browse the repository at this point in the history
  • Loading branch information
kylekatarnls committed Mar 27, 2024
1 parent 3eaeec4 commit 873e6a3
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 18 deletions.
81 changes: 63 additions & 18 deletions src/Carbon/CarbonPeriod.php
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ public static function __callStatic(string $method, array $parameters): mixed
*/
public function __construct(...$arguments)
{
$raw = ['R1/2000-01-01T00:00:00Z/P1D'];
$raw = null;

if (isset($arguments['raw'])) {
$raw = $arguments['raw'];
Expand All @@ -608,13 +608,6 @@ public function __construct(...$arguments)
$arguments = $raw;
}

// Dummy construct, as properties are completely overridden
parent::__construct(...$raw);

if (is_a($this->dateClass, DateTimeImmutable::class, true)) {
$this->options = static::IMMUTABLE;
}

// Parse and assign arguments one by one. First argument may be an ISO 8601 spec,
// which will be first parsed into parts and then processed the same way.

Expand Down Expand Up @@ -642,13 +635,18 @@ public function __construct(...$arguments)
}
}

if (is_a($this->dateClass, DateTimeImmutable::class, true)) {
$this->options = static::IMMUTABLE;
}

$optionsSet = false;
$sortedArguments = [];

foreach ($arguments as $argument) {
$parsedDate = null;

if ($argument instanceof DateTimeZone) {
$this->setTimezone($argument);
$sortedArguments['timezone'] = $argument;
} elseif ($this->dateInterval === null &&
(
(\is_string($argument) && preg_match(
Expand All @@ -661,25 +659,72 @@ public function __construct(...$arguments)
) &&
$parsedInterval = self::makeInterval($argument)
) {
$this->setDateInterval($parsedInterval);
} elseif ($this->startDate === null && $parsedDate = $this->makeDateTime($argument)) {
$this->setStartDate($parsedDate);
} elseif ($this->endDate === null && ($parsedDate = $parsedDate ?? $this->makeDateTime($argument))) {
$this->setEndDate($parsedDate);
} elseif ($this->carbonRecurrences === null &&
$this->endDate === null &&
$sortedArguments['interval'] = $parsedInterval;
} elseif (!isset($sortedArguments['start']) && $parsedDate = $this->makeDateTime($argument)) {
$sortedArguments['start'] = $parsedDate;
} elseif (!isset($sortedArguments['end']) && ($parsedDate = $parsedDate ?? $this->makeDateTime($argument))) {
$sortedArguments['end'] = $parsedDate;
} elseif (!isset($sortedArguments['recurrences']) &&
!isset($sortedArguments['end']) &&
(\is_int($argument) || \is_float($argument))
&& $argument >= 0
) {
$this->setRecurrences($argument);
$sortedArguments['recurrences'] = $argument;
} elseif (!$optionsSet && (\is_int($argument) || $argument === null)) {
$optionsSet = true;
$this->setOptions(((int) $this->options) | ((int) $argument));
$sortedArguments['options'] = (((int) $this->options) | ((int) $argument));
} else {
throw new InvalidPeriodParameterException('Invalid constructor parameters.');
}
}

if ($raw === null && isset($sortedArguments['start'])) {
$end = $sortedArguments['end'] ?? max(1, $sortedArguments['recurrences'] ?? 1);

if (\is_float($end)) {
$end = $end === INF ? PHP_INT_MAX : (int) round($end);
}

$raw = [
$sortedArguments['start'],
$sortedArguments['interval'] ?? CarbonInterval::day(),
$end,
];
}

if ($raw === null && \is_string($arguments[0] ?? null) && substr_count($arguments[0], '/') >= 1) {
$raw = [$arguments[0]];
}

$raw ??= ['R1/2000-01-01T00:00:00Z/P1D'];

// Dummy construct, as properties are completely overridden
parent::__construct(...$raw);

if (isset($sortedArguments['start'])) {
$this->setStartDate($sortedArguments['start']);
}

if (isset($sortedArguments['end'])) {
$this->setEndDate($sortedArguments['end']);
}

if (isset($sortedArguments['recurrences'])) {
$this->setRecurrences($sortedArguments['recurrences']);
}

if (isset($sortedArguments['interval'])) {
$this->setDateInterval($sortedArguments['interval']);
}

if (isset($sortedArguments['timezone'])) {
$this->setTimezone($sortedArguments['timezone']);
}

if (isset($sortedArguments['options'])) {
$this->setOptions($sortedArguments['options']);
}

if ($this->startDate === null) {
$dateClass = $this->dateClass;
$this->setStartDate($dateClass::now());
Expand Down
21 changes: 21 additions & 0 deletions tests/CarbonPeriod/CreateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -866,5 +866,26 @@ public function testStartAndEndFallback()
Carbon::parse('Sep 1')->toPeriod('Sep 30')->start->format('Y-m-d'),
Carbon::parse('Sep 1')->toPeriod('Sep 30')->end->format('Y-m-d'),
]);

$periodClass = static::$periodClass;
$period = new $periodClass('Sep 1', 'Sep 30');

$this->assertSame([
'2024-09-01',
'2024-09-30',
], [
$period->start->format('Y-m-d'),
$period->end->format('Y-m-d'),
]);

$period = new $periodClass('Sep 1');

$this->assertSame([
'2024-09-01',
null,
], [
$period->start->format('Y-m-d'),
$period->end?->format('Y-m-d'),
]);
}
}

0 comments on commit 873e6a3

Please sign in to comment.